18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Cadence MACB/GEM Ethernet Controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2006 Atmel Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 118c2ecf20Sopenharmony_ci#include <linux/crc32.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/circ_buf.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci#include <linux/gpio.h> 218c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 228c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 238c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 248c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 258c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 268c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 278c2ecf20Sopenharmony_ci#include <linux/phylink.h> 288c2ecf20Sopenharmony_ci#include <linux/of.h> 298c2ecf20Sopenharmony_ci#include <linux/of_device.h> 308c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 318c2ecf20Sopenharmony_ci#include <linux/of_mdio.h> 328c2ecf20Sopenharmony_ci#include <linux/of_net.h> 338c2ecf20Sopenharmony_ci#include <linux/ip.h> 348c2ecf20Sopenharmony_ci#include <linux/udp.h> 358c2ecf20Sopenharmony_ci#include <linux/tcp.h> 368c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 378c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 388c2ecf20Sopenharmony_ci#include "macb.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* This structure is only used for MACB on SiFive FU540 devices */ 418c2ecf20Sopenharmony_cistruct sifive_fu540_macb_mgmt { 428c2ecf20Sopenharmony_ci void __iomem *reg; 438c2ecf20Sopenharmony_ci unsigned long rate; 448c2ecf20Sopenharmony_ci struct clk_hw hw; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define MACB_RX_BUFFER_SIZE 128 488c2ecf20Sopenharmony_ci#define RX_BUFFER_MULTIPLE 64 /* bytes */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define DEFAULT_RX_RING_SIZE 512 /* must be power of 2 */ 518c2ecf20Sopenharmony_ci#define MIN_RX_RING_SIZE 64 528c2ecf20Sopenharmony_ci#define MAX_RX_RING_SIZE 8192 538c2ecf20Sopenharmony_ci#define RX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ 548c2ecf20Sopenharmony_ci * (bp)->rx_ring_size) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define DEFAULT_TX_RING_SIZE 512 /* must be power of 2 */ 578c2ecf20Sopenharmony_ci#define MIN_TX_RING_SIZE 64 588c2ecf20Sopenharmony_ci#define MAX_TX_RING_SIZE 4096 598c2ecf20Sopenharmony_ci#define TX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ 608c2ecf20Sopenharmony_ci * (bp)->tx_ring_size) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* level of occupied TX descriptors under which we wake up TX process */ 638c2ecf20Sopenharmony_ci#define MACB_TX_WAKEUP_THRESH(bp) (3 * (bp)->tx_ring_size / 4) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(ISR_ROVR)) 668c2ecf20Sopenharmony_ci#define MACB_TX_ERR_FLAGS (MACB_BIT(ISR_TUND) \ 678c2ecf20Sopenharmony_ci | MACB_BIT(ISR_RLE) \ 688c2ecf20Sopenharmony_ci | MACB_BIT(TXERR)) 698c2ecf20Sopenharmony_ci#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP) \ 708c2ecf20Sopenharmony_ci | MACB_BIT(TXUBR)) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Max length of transmit frame must be a multiple of 8 bytes */ 738c2ecf20Sopenharmony_ci#define MACB_TX_LEN_ALIGN 8 748c2ecf20Sopenharmony_ci#define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) 758c2ecf20Sopenharmony_ci/* Limit maximum TX length as per Cadence TSO errata. This is to avoid a 768c2ecf20Sopenharmony_ci * false amba_error in TX path from the DMA assuming there is not enough 778c2ecf20Sopenharmony_ci * space in the SRAM (16KB) even when there is. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci#define GEM_MAX_TX_LEN (unsigned int)(0x3FC0) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define GEM_MTU_MIN_SIZE ETH_MIN_MTU 828c2ecf20Sopenharmony_ci#define MACB_NETIF_LSO NETIF_F_TSO 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define MACB_WOL_HAS_MAGIC_PACKET (0x1 << 0) 858c2ecf20Sopenharmony_ci#define MACB_WOL_ENABLED (0x1 << 1) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* Graceful stop timeouts in us. We should allow up to 888c2ecf20Sopenharmony_ci * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions) 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci#define MACB_HALT_TIMEOUT 1230 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define MACB_PM_TIMEOUT 100 /* ms */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define MACB_MDIO_TIMEOUT 1000000 /* in usecs */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* DMA buffer descriptor might be different size 978c2ecf20Sopenharmony_ci * depends on hardware configuration: 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * 1. dma address width 32 bits: 1008c2ecf20Sopenharmony_ci * word 1: 32 bit address of Data Buffer 1018c2ecf20Sopenharmony_ci * word 2: control 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * 2. dma address width 64 bits: 1048c2ecf20Sopenharmony_ci * word 1: 32 bit address of Data Buffer 1058c2ecf20Sopenharmony_ci * word 2: control 1068c2ecf20Sopenharmony_ci * word 3: upper 32 bit address of Data Buffer 1078c2ecf20Sopenharmony_ci * word 4: unused 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * 3. dma address width 32 bits with hardware timestamping: 1108c2ecf20Sopenharmony_ci * word 1: 32 bit address of Data Buffer 1118c2ecf20Sopenharmony_ci * word 2: control 1128c2ecf20Sopenharmony_ci * word 3: timestamp word 1 1138c2ecf20Sopenharmony_ci * word 4: timestamp word 2 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * 4. dma address width 64 bits with hardware timestamping: 1168c2ecf20Sopenharmony_ci * word 1: 32 bit address of Data Buffer 1178c2ecf20Sopenharmony_ci * word 2: control 1188c2ecf20Sopenharmony_ci * word 3: upper 32 bit address of Data Buffer 1198c2ecf20Sopenharmony_ci * word 4: unused 1208c2ecf20Sopenharmony_ci * word 5: timestamp word 1 1218c2ecf20Sopenharmony_ci * word 6: timestamp word 2 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cistatic unsigned int macb_dma_desc_get_size(struct macb *bp) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci#ifdef MACB_EXT_DESC 1268c2ecf20Sopenharmony_ci unsigned int desc_size; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci switch (bp->hw_dma_cap) { 1298c2ecf20Sopenharmony_ci case HW_DMA_CAP_64B: 1308c2ecf20Sopenharmony_ci desc_size = sizeof(struct macb_dma_desc) 1318c2ecf20Sopenharmony_ci + sizeof(struct macb_dma_desc_64); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case HW_DMA_CAP_PTP: 1348c2ecf20Sopenharmony_ci desc_size = sizeof(struct macb_dma_desc) 1358c2ecf20Sopenharmony_ci + sizeof(struct macb_dma_desc_ptp); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case HW_DMA_CAP_64B_PTP: 1388c2ecf20Sopenharmony_ci desc_size = sizeof(struct macb_dma_desc) 1398c2ecf20Sopenharmony_ci + sizeof(struct macb_dma_desc_64) 1408c2ecf20Sopenharmony_ci + sizeof(struct macb_dma_desc_ptp); 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci default: 1438c2ecf20Sopenharmony_ci desc_size = sizeof(struct macb_dma_desc); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci return desc_size; 1468c2ecf20Sopenharmony_ci#endif 1478c2ecf20Sopenharmony_ci return sizeof(struct macb_dma_desc); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int desc_idx) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci#ifdef MACB_EXT_DESC 1538c2ecf20Sopenharmony_ci switch (bp->hw_dma_cap) { 1548c2ecf20Sopenharmony_ci case HW_DMA_CAP_64B: 1558c2ecf20Sopenharmony_ci case HW_DMA_CAP_PTP: 1568c2ecf20Sopenharmony_ci desc_idx <<= 1; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case HW_DMA_CAP_64B_PTP: 1598c2ecf20Sopenharmony_ci desc_idx *= 3; 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci default: 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci#endif 1658c2ecf20Sopenharmony_ci return desc_idx; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 1698c2ecf20Sopenharmony_cistatic struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci return (struct macb_dma_desc_64 *)((void *)desc 1728c2ecf20Sopenharmony_ci + sizeof(struct macb_dma_desc)); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci#endif 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* Ring buffer accessors */ 1778c2ecf20Sopenharmony_cistatic unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci return index & (bp->tx_ring_size - 1); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue, 1838c2ecf20Sopenharmony_ci unsigned int index) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci index = macb_tx_ring_wrap(queue->bp, index); 1868c2ecf20Sopenharmony_ci index = macb_adj_dma_desc_idx(queue->bp, index); 1878c2ecf20Sopenharmony_ci return &queue->tx_ring[index]; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue, 1918c2ecf20Sopenharmony_ci unsigned int index) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return &queue->tx_skb[macb_tx_ring_wrap(queue->bp, index)]; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic dma_addr_t macb_tx_dma(struct macb_queue *queue, unsigned int index) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci dma_addr_t offset; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci offset = macb_tx_ring_wrap(queue->bp, index) * 2018c2ecf20Sopenharmony_ci macb_dma_desc_get_size(queue->bp); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return queue->tx_ring_dma + offset; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci return index & (bp->rx_ring_size - 1); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic struct macb_dma_desc *macb_rx_desc(struct macb_queue *queue, unsigned int index) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci index = macb_rx_ring_wrap(queue->bp, index); 2148c2ecf20Sopenharmony_ci index = macb_adj_dma_desc_idx(queue->bp, index); 2158c2ecf20Sopenharmony_ci return &queue->rx_ring[index]; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void *macb_rx_buffer(struct macb_queue *queue, unsigned int index) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci return queue->rx_buffers + queue->bp->rx_buffer_size * 2218c2ecf20Sopenharmony_ci macb_rx_ring_wrap(queue->bp, index); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* I/O accessors */ 2258c2ecf20Sopenharmony_cistatic u32 hw_readl_native(struct macb *bp, int offset) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci return __raw_readl(bp->regs + offset); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic void hw_writel_native(struct macb *bp, int offset, u32 value) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci __raw_writel(value, bp->regs + offset); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic u32 hw_readl(struct macb *bp, int offset) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci return readl_relaxed(bp->regs + offset); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic void hw_writel(struct macb *bp, int offset, u32 value) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci writel_relaxed(value, bp->regs + offset); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/* Find the CPU endianness by using the loopback bit of NCR register. When the 2468c2ecf20Sopenharmony_ci * CPU is in big endian we need to program swapped mode for management 2478c2ecf20Sopenharmony_ci * descriptor access. 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_cistatic bool hw_is_native_io(void __iomem *addr) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci u32 value = MACB_BIT(LLB); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci __raw_writel(value, addr + MACB_NCR); 2548c2ecf20Sopenharmony_ci value = __raw_readl(addr + MACB_NCR); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* Write 0 back to disable everything */ 2578c2ecf20Sopenharmony_ci __raw_writel(0, addr + MACB_NCR); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return value == MACB_BIT(LLB); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic bool hw_is_gem(void __iomem *addr, bool native_io) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci u32 id; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (native_io) 2678c2ecf20Sopenharmony_ci id = __raw_readl(addr + MACB_MID); 2688c2ecf20Sopenharmony_ci else 2698c2ecf20Sopenharmony_ci id = readl_relaxed(addr + MACB_MID); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return MACB_BFEXT(IDNUM, id) >= 0x2; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic void macb_set_hwaddr(struct macb *bp) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci u32 bottom; 2778c2ecf20Sopenharmony_ci u16 top; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); 2808c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA1B, bottom); 2818c2ecf20Sopenharmony_ci top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); 2828c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA1T, top); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Clear unused address register sets */ 2858c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA2B, 0); 2868c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA2T, 0); 2878c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA3B, 0); 2888c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA3T, 0); 2898c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA4B, 0); 2908c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, SA4T, 0); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void macb_get_hwaddr(struct macb *bp) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci u32 bottom; 2968c2ecf20Sopenharmony_ci u16 top; 2978c2ecf20Sopenharmony_ci u8 addr[6]; 2988c2ecf20Sopenharmony_ci int i; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Check all 4 address register for valid address */ 3018c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 3028c2ecf20Sopenharmony_ci bottom = macb_or_gem_readl(bp, SA1B + i * 8); 3038c2ecf20Sopenharmony_ci top = macb_or_gem_readl(bp, SA1T + i * 8); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci addr[0] = bottom & 0xff; 3068c2ecf20Sopenharmony_ci addr[1] = (bottom >> 8) & 0xff; 3078c2ecf20Sopenharmony_ci addr[2] = (bottom >> 16) & 0xff; 3088c2ecf20Sopenharmony_ci addr[3] = (bottom >> 24) & 0xff; 3098c2ecf20Sopenharmony_ci addr[4] = top & 0xff; 3108c2ecf20Sopenharmony_ci addr[5] = (top >> 8) & 0xff; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (is_valid_ether_addr(addr)) { 3138c2ecf20Sopenharmony_ci memcpy(bp->dev->dev_addr, addr, sizeof(addr)); 3148c2ecf20Sopenharmony_ci return; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); 3198c2ecf20Sopenharmony_ci eth_hw_addr_random(bp->dev); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int macb_mdio_wait_for_idle(struct macb *bp) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci u32 val; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE), 3278c2ecf20Sopenharmony_ci 1, MACB_MDIO_TIMEOUT); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct macb *bp = bus->priv; 3338c2ecf20Sopenharmony_ci int status; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci status = pm_runtime_get_sync(&bp->pdev->dev); 3368c2ecf20Sopenharmony_ci if (status < 0) { 3378c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&bp->pdev->dev); 3388c2ecf20Sopenharmony_ci goto mdio_pm_exit; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci status = macb_mdio_wait_for_idle(bp); 3428c2ecf20Sopenharmony_ci if (status < 0) 3438c2ecf20Sopenharmony_ci goto mdio_read_exit; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (regnum & MII_ADDR_C45) { 3468c2ecf20Sopenharmony_ci macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF) 3478c2ecf20Sopenharmony_ci | MACB_BF(RW, MACB_MAN_C45_ADDR) 3488c2ecf20Sopenharmony_ci | MACB_BF(PHYA, mii_id) 3498c2ecf20Sopenharmony_ci | MACB_BF(REGA, (regnum >> 16) & 0x1F) 3508c2ecf20Sopenharmony_ci | MACB_BF(DATA, regnum & 0xFFFF) 3518c2ecf20Sopenharmony_ci | MACB_BF(CODE, MACB_MAN_C45_CODE))); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci status = macb_mdio_wait_for_idle(bp); 3548c2ecf20Sopenharmony_ci if (status < 0) 3558c2ecf20Sopenharmony_ci goto mdio_read_exit; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF) 3588c2ecf20Sopenharmony_ci | MACB_BF(RW, MACB_MAN_C45_READ) 3598c2ecf20Sopenharmony_ci | MACB_BF(PHYA, mii_id) 3608c2ecf20Sopenharmony_ci | MACB_BF(REGA, (regnum >> 16) & 0x1F) 3618c2ecf20Sopenharmony_ci | MACB_BF(CODE, MACB_MAN_C45_CODE))); 3628c2ecf20Sopenharmony_ci } else { 3638c2ecf20Sopenharmony_ci macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF) 3648c2ecf20Sopenharmony_ci | MACB_BF(RW, MACB_MAN_C22_READ) 3658c2ecf20Sopenharmony_ci | MACB_BF(PHYA, mii_id) 3668c2ecf20Sopenharmony_ci | MACB_BF(REGA, regnum) 3678c2ecf20Sopenharmony_ci | MACB_BF(CODE, MACB_MAN_C22_CODE))); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci status = macb_mdio_wait_for_idle(bp); 3718c2ecf20Sopenharmony_ci if (status < 0) 3728c2ecf20Sopenharmony_ci goto mdio_read_exit; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci status = MACB_BFEXT(DATA, macb_readl(bp, MAN)); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cimdio_read_exit: 3778c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&bp->pdev->dev); 3788c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(&bp->pdev->dev); 3798c2ecf20Sopenharmony_cimdio_pm_exit: 3808c2ecf20Sopenharmony_ci return status; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, 3848c2ecf20Sopenharmony_ci u16 value) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct macb *bp = bus->priv; 3878c2ecf20Sopenharmony_ci int status; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci status = pm_runtime_get_sync(&bp->pdev->dev); 3908c2ecf20Sopenharmony_ci if (status < 0) { 3918c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&bp->pdev->dev); 3928c2ecf20Sopenharmony_ci goto mdio_pm_exit; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci status = macb_mdio_wait_for_idle(bp); 3968c2ecf20Sopenharmony_ci if (status < 0) 3978c2ecf20Sopenharmony_ci goto mdio_write_exit; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (regnum & MII_ADDR_C45) { 4008c2ecf20Sopenharmony_ci macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF) 4018c2ecf20Sopenharmony_ci | MACB_BF(RW, MACB_MAN_C45_ADDR) 4028c2ecf20Sopenharmony_ci | MACB_BF(PHYA, mii_id) 4038c2ecf20Sopenharmony_ci | MACB_BF(REGA, (regnum >> 16) & 0x1F) 4048c2ecf20Sopenharmony_ci | MACB_BF(DATA, regnum & 0xFFFF) 4058c2ecf20Sopenharmony_ci | MACB_BF(CODE, MACB_MAN_C45_CODE))); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci status = macb_mdio_wait_for_idle(bp); 4088c2ecf20Sopenharmony_ci if (status < 0) 4098c2ecf20Sopenharmony_ci goto mdio_write_exit; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF) 4128c2ecf20Sopenharmony_ci | MACB_BF(RW, MACB_MAN_C45_WRITE) 4138c2ecf20Sopenharmony_ci | MACB_BF(PHYA, mii_id) 4148c2ecf20Sopenharmony_ci | MACB_BF(REGA, (regnum >> 16) & 0x1F) 4158c2ecf20Sopenharmony_ci | MACB_BF(CODE, MACB_MAN_C45_CODE) 4168c2ecf20Sopenharmony_ci | MACB_BF(DATA, value))); 4178c2ecf20Sopenharmony_ci } else { 4188c2ecf20Sopenharmony_ci macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF) 4198c2ecf20Sopenharmony_ci | MACB_BF(RW, MACB_MAN_C22_WRITE) 4208c2ecf20Sopenharmony_ci | MACB_BF(PHYA, mii_id) 4218c2ecf20Sopenharmony_ci | MACB_BF(REGA, regnum) 4228c2ecf20Sopenharmony_ci | MACB_BF(CODE, MACB_MAN_C22_CODE) 4238c2ecf20Sopenharmony_ci | MACB_BF(DATA, value))); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci status = macb_mdio_wait_for_idle(bp); 4278c2ecf20Sopenharmony_ci if (status < 0) 4288c2ecf20Sopenharmony_ci goto mdio_write_exit; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cimdio_write_exit: 4318c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&bp->pdev->dev); 4328c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(&bp->pdev->dev); 4338c2ecf20Sopenharmony_cimdio_pm_exit: 4348c2ecf20Sopenharmony_ci return status; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic void macb_init_buffers(struct macb *bp) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct macb_queue *queue; 4408c2ecf20Sopenharmony_ci unsigned int q; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 4438c2ecf20Sopenharmony_ci queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma)); 4448c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 4458c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) 4468c2ecf20Sopenharmony_ci queue_writel(queue, RBQPH, 4478c2ecf20Sopenharmony_ci upper_32_bits(queue->rx_ring_dma)); 4488c2ecf20Sopenharmony_ci#endif 4498c2ecf20Sopenharmony_ci queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); 4508c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 4518c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) 4528c2ecf20Sopenharmony_ci queue_writel(queue, TBQPH, 4538c2ecf20Sopenharmony_ci upper_32_bits(queue->tx_ring_dma)); 4548c2ecf20Sopenharmony_ci#endif 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/** 4598c2ecf20Sopenharmony_ci * macb_set_tx_clk() - Set a clock to a new frequency 4608c2ecf20Sopenharmony_ci * @clk: Pointer to the clock to change 4618c2ecf20Sopenharmony_ci * @speed: New frequency in Hz 4628c2ecf20Sopenharmony_ci * @dev: Pointer to the struct net_device 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_cistatic void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci long ferr, rate, rate_rounded; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (!clk) 4698c2ecf20Sopenharmony_ci return; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci switch (speed) { 4728c2ecf20Sopenharmony_ci case SPEED_10: 4738c2ecf20Sopenharmony_ci rate = 2500000; 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci case SPEED_100: 4768c2ecf20Sopenharmony_ci rate = 25000000; 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci case SPEED_1000: 4798c2ecf20Sopenharmony_ci rate = 125000000; 4808c2ecf20Sopenharmony_ci break; 4818c2ecf20Sopenharmony_ci default: 4828c2ecf20Sopenharmony_ci return; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci rate_rounded = clk_round_rate(clk, rate); 4868c2ecf20Sopenharmony_ci if (rate_rounded < 0) 4878c2ecf20Sopenharmony_ci return; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* RGMII allows 50 ppm frequency error. Test and warn if this limit 4908c2ecf20Sopenharmony_ci * is not satisfied. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ci ferr = abs(rate_rounded - rate); 4938c2ecf20Sopenharmony_ci ferr = DIV_ROUND_UP(ferr, rate / 100000); 4948c2ecf20Sopenharmony_ci if (ferr > 5) 4958c2ecf20Sopenharmony_ci netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", 4968c2ecf20Sopenharmony_ci rate); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (clk_set_rate(clk, rate_rounded)) 4998c2ecf20Sopenharmony_ci netdev_err(dev, "adjusting tx_clk failed.\n"); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic void macb_validate(struct phylink_config *config, 5038c2ecf20Sopenharmony_ci unsigned long *supported, 5048c2ecf20Sopenharmony_ci struct phylink_link_state *state) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct net_device *ndev = to_net_dev(config->dev); 5078c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 5088c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(ndev); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* We only support MII, RMII, GMII, RGMII & SGMII. */ 5118c2ecf20Sopenharmony_ci if (state->interface != PHY_INTERFACE_MODE_NA && 5128c2ecf20Sopenharmony_ci state->interface != PHY_INTERFACE_MODE_MII && 5138c2ecf20Sopenharmony_ci state->interface != PHY_INTERFACE_MODE_RMII && 5148c2ecf20Sopenharmony_ci state->interface != PHY_INTERFACE_MODE_GMII && 5158c2ecf20Sopenharmony_ci state->interface != PHY_INTERFACE_MODE_SGMII && 5168c2ecf20Sopenharmony_ci !phy_interface_mode_is_rgmii(state->interface)) { 5178c2ecf20Sopenharmony_ci bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 5188c2ecf20Sopenharmony_ci return; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (!macb_is_gem(bp) && 5228c2ecf20Sopenharmony_ci (state->interface == PHY_INTERFACE_MODE_GMII || 5238c2ecf20Sopenharmony_ci phy_interface_mode_is_rgmii(state->interface))) { 5248c2ecf20Sopenharmony_ci bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 5258c2ecf20Sopenharmony_ci return; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci phylink_set_port_modes(mask); 5298c2ecf20Sopenharmony_ci phylink_set(mask, Autoneg); 5308c2ecf20Sopenharmony_ci phylink_set(mask, Asym_Pause); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci phylink_set(mask, 10baseT_Half); 5338c2ecf20Sopenharmony_ci phylink_set(mask, 10baseT_Full); 5348c2ecf20Sopenharmony_ci phylink_set(mask, 100baseT_Half); 5358c2ecf20Sopenharmony_ci phylink_set(mask, 100baseT_Full); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE && 5388c2ecf20Sopenharmony_ci (state->interface == PHY_INTERFACE_MODE_NA || 5398c2ecf20Sopenharmony_ci state->interface == PHY_INTERFACE_MODE_GMII || 5408c2ecf20Sopenharmony_ci state->interface == PHY_INTERFACE_MODE_SGMII || 5418c2ecf20Sopenharmony_ci phy_interface_mode_is_rgmii(state->interface))) { 5428c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Full); 5438c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseX_Full); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF)) 5468c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Half); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); 5508c2ecf20Sopenharmony_ci bitmap_and(state->advertising, state->advertising, mask, 5518c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic void macb_mac_pcs_get_state(struct phylink_config *config, 5558c2ecf20Sopenharmony_ci struct phylink_link_state *state) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci state->link = 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void macb_mac_an_restart(struct phylink_config *config) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci /* Not supported */ 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void macb_mac_config(struct phylink_config *config, unsigned int mode, 5668c2ecf20Sopenharmony_ci const struct phylink_link_state *state) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct net_device *ndev = to_net_dev(config->dev); 5698c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(ndev); 5708c2ecf20Sopenharmony_ci unsigned long flags; 5718c2ecf20Sopenharmony_ci u32 old_ctrl, ctrl; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci old_ctrl = ctrl = macb_or_gem_readl(bp, NCFGR); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_MACB_IS_EMAC) { 5788c2ecf20Sopenharmony_ci if (state->interface == PHY_INTERFACE_MODE_RMII) 5798c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(RM9200_RMII); 5808c2ecf20Sopenharmony_ci } else if (macb_is_gem(bp)) { 5818c2ecf20Sopenharmony_ci ctrl &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL)); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (state->interface == PHY_INTERFACE_MODE_SGMII) 5848c2ecf20Sopenharmony_ci ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* Apply the new configuration, if any */ 5888c2ecf20Sopenharmony_ci if (old_ctrl ^ ctrl) 5898c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, NCFGR, ctrl); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic void macb_mac_link_down(struct phylink_config *config, unsigned int mode, 5958c2ecf20Sopenharmony_ci phy_interface_t interface) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct net_device *ndev = to_net_dev(config->dev); 5988c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(ndev); 5998c2ecf20Sopenharmony_ci struct macb_queue *queue; 6008c2ecf20Sopenharmony_ci unsigned int q; 6018c2ecf20Sopenharmony_ci u32 ctrl; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) 6048c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 6058c2ecf20Sopenharmony_ci queue_writel(queue, IDR, 6068c2ecf20Sopenharmony_ci bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP)); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* Disable Rx and Tx */ 6098c2ecf20Sopenharmony_ci ctrl = macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE)); 6108c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(ndev); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic void macb_mac_link_up(struct phylink_config *config, 6168c2ecf20Sopenharmony_ci struct phy_device *phy, 6178c2ecf20Sopenharmony_ci unsigned int mode, phy_interface_t interface, 6188c2ecf20Sopenharmony_ci int speed, int duplex, 6198c2ecf20Sopenharmony_ci bool tx_pause, bool rx_pause) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct net_device *ndev = to_net_dev(config->dev); 6228c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(ndev); 6238c2ecf20Sopenharmony_ci struct macb_queue *queue; 6248c2ecf20Sopenharmony_ci unsigned long flags; 6258c2ecf20Sopenharmony_ci unsigned int q; 6268c2ecf20Sopenharmony_ci u32 ctrl; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ctrl = macb_or_gem_readl(bp, NCFGR); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ctrl &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (speed == SPEED_100) 6358c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(SPD); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (duplex) 6388c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(FD); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) { 6418c2ecf20Sopenharmony_ci ctrl &= ~MACB_BIT(PAE); 6428c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) { 6438c2ecf20Sopenharmony_ci ctrl &= ~GEM_BIT(GBE); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (speed == SPEED_1000) 6468c2ecf20Sopenharmony_ci ctrl |= GEM_BIT(GBE); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (rx_pause) 6508c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(PAE); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci macb_set_tx_clk(bp->tx_clk, speed, ndev); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down 6558c2ecf20Sopenharmony_ci * cleared the pipeline and control registers. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_init_rings(bp); 6588c2ecf20Sopenharmony_ci macb_init_buffers(bp); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 6618c2ecf20Sopenharmony_ci queue_writel(queue, IER, 6628c2ecf20Sopenharmony_ci bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP)); 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, NCFGR, ctrl); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* Enable Rx and Tx */ 6708c2ecf20Sopenharmony_ci macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE)); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(ndev); 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic const struct phylink_mac_ops macb_phylink_ops = { 6768c2ecf20Sopenharmony_ci .validate = macb_validate, 6778c2ecf20Sopenharmony_ci .mac_pcs_get_state = macb_mac_pcs_get_state, 6788c2ecf20Sopenharmony_ci .mac_an_restart = macb_mac_an_restart, 6798c2ecf20Sopenharmony_ci .mac_config = macb_mac_config, 6808c2ecf20Sopenharmony_ci .mac_link_down = macb_mac_link_down, 6818c2ecf20Sopenharmony_ci .mac_link_up = macb_mac_link_up, 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic bool macb_phy_handle_exists(struct device_node *dn) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci dn = of_parse_phandle(dn, "phy-handle", 0); 6878c2ecf20Sopenharmony_ci of_node_put(dn); 6888c2ecf20Sopenharmony_ci return dn != NULL; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int macb_phylink_connect(struct macb *bp) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct device_node *dn = bp->pdev->dev.of_node; 6948c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 6958c2ecf20Sopenharmony_ci struct phy_device *phydev; 6968c2ecf20Sopenharmony_ci int ret; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (dn) 6998c2ecf20Sopenharmony_ci ret = phylink_of_phy_connect(bp->phylink, dn, 0); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!dn || (ret && !macb_phy_handle_exists(dn))) { 7028c2ecf20Sopenharmony_ci phydev = phy_find_first(bp->mii_bus); 7038c2ecf20Sopenharmony_ci if (!phydev) { 7048c2ecf20Sopenharmony_ci netdev_err(dev, "no PHY found\n"); 7058c2ecf20Sopenharmony_ci return -ENXIO; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* attach the mac to the phy */ 7098c2ecf20Sopenharmony_ci ret = phylink_connect_phy(bp->phylink, phydev); 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (ret) { 7138c2ecf20Sopenharmony_ci netdev_err(dev, "Could not attach PHY (%d)\n", ret); 7148c2ecf20Sopenharmony_ci return ret; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci phylink_start(bp->phylink); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci/* based on au1000_eth. c*/ 7238c2ecf20Sopenharmony_cistatic int macb_mii_probe(struct net_device *dev) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci bp->phylink_config.dev = &dev->dev; 7288c2ecf20Sopenharmony_ci bp->phylink_config.type = PHYLINK_NETDEV; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci bp->phylink = phylink_create(&bp->phylink_config, bp->pdev->dev.fwnode, 7318c2ecf20Sopenharmony_ci bp->phy_interface, &macb_phylink_ops); 7328c2ecf20Sopenharmony_ci if (IS_ERR(bp->phylink)) { 7338c2ecf20Sopenharmony_ci netdev_err(dev, "Could not create a phylink instance (%ld)\n", 7348c2ecf20Sopenharmony_ci PTR_ERR(bp->phylink)); 7358c2ecf20Sopenharmony_ci return PTR_ERR(bp->phylink); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic int macb_mdiobus_register(struct macb *bp) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct device_node *child, *np = bp->pdev->dev.of_node; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (of_phy_is_fixed_link(np)) 7468c2ecf20Sopenharmony_ci return mdiobus_register(bp->mii_bus); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* Only create the PHY from the device tree if at least one PHY is 7498c2ecf20Sopenharmony_ci * described. Otherwise scan the entire MDIO bus. We do this to support 7508c2ecf20Sopenharmony_ci * old device tree that did not follow the best practices and did not 7518c2ecf20Sopenharmony_ci * describe their network PHYs. 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci for_each_available_child_of_node(np, child) 7548c2ecf20Sopenharmony_ci if (of_mdiobus_child_is_phy(child)) { 7558c2ecf20Sopenharmony_ci /* The loop increments the child refcount, 7568c2ecf20Sopenharmony_ci * decrement it before returning. 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci of_node_put(child); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return of_mdiobus_register(bp->mii_bus, np); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return mdiobus_register(bp->mii_bus); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int macb_mii_init(struct macb *bp) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci int err = -ENXIO; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Enable management port */ 7718c2ecf20Sopenharmony_ci macb_writel(bp, NCR, MACB_BIT(MPE)); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci bp->mii_bus = mdiobus_alloc(); 7748c2ecf20Sopenharmony_ci if (!bp->mii_bus) { 7758c2ecf20Sopenharmony_ci err = -ENOMEM; 7768c2ecf20Sopenharmony_ci goto err_out; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci bp->mii_bus->name = "MACB_mii_bus"; 7808c2ecf20Sopenharmony_ci bp->mii_bus->read = &macb_mdio_read; 7818c2ecf20Sopenharmony_ci bp->mii_bus->write = &macb_mdio_write; 7828c2ecf20Sopenharmony_ci snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", 7838c2ecf20Sopenharmony_ci bp->pdev->name, bp->pdev->id); 7848c2ecf20Sopenharmony_ci bp->mii_bus->priv = bp; 7858c2ecf20Sopenharmony_ci bp->mii_bus->parent = &bp->pdev->dev; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci dev_set_drvdata(&bp->dev->dev, bp->mii_bus); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci err = macb_mdiobus_register(bp); 7908c2ecf20Sopenharmony_ci if (err) 7918c2ecf20Sopenharmony_ci goto err_out_free_mdiobus; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci err = macb_mii_probe(bp->dev); 7948c2ecf20Sopenharmony_ci if (err) 7958c2ecf20Sopenharmony_ci goto err_out_unregister_bus; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci return 0; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cierr_out_unregister_bus: 8008c2ecf20Sopenharmony_ci mdiobus_unregister(bp->mii_bus); 8018c2ecf20Sopenharmony_cierr_out_free_mdiobus: 8028c2ecf20Sopenharmony_ci mdiobus_free(bp->mii_bus); 8038c2ecf20Sopenharmony_cierr_out: 8048c2ecf20Sopenharmony_ci return err; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic void macb_update_stats(struct macb *bp) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci u32 *p = &bp->hw_stats.macb.rx_pause_frames; 8108c2ecf20Sopenharmony_ci u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1; 8118c2ecf20Sopenharmony_ci int offset = MACB_PFR; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci for (; p < end; p++, offset += 4) 8168c2ecf20Sopenharmony_ci *p += bp->macb_reg_readl(bp, offset); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int macb_halt_tx(struct macb *bp) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci unsigned long halt_time, timeout; 8228c2ecf20Sopenharmony_ci u32 status; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT)); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT); 8278c2ecf20Sopenharmony_ci do { 8288c2ecf20Sopenharmony_ci halt_time = jiffies; 8298c2ecf20Sopenharmony_ci status = macb_readl(bp, TSR); 8308c2ecf20Sopenharmony_ci if (!(status & MACB_BIT(TGO))) 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci udelay(250); 8348c2ecf20Sopenharmony_ci } while (time_before(halt_time, timeout)); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return -ETIMEDOUT; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci if (tx_skb->mapping) { 8428c2ecf20Sopenharmony_ci if (tx_skb->mapped_as_page) 8438c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, tx_skb->mapping, 8448c2ecf20Sopenharmony_ci tx_skb->size, DMA_TO_DEVICE); 8458c2ecf20Sopenharmony_ci else 8468c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, 8478c2ecf20Sopenharmony_ci tx_skb->size, DMA_TO_DEVICE); 8488c2ecf20Sopenharmony_ci tx_skb->mapping = 0; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (tx_skb->skb) { 8528c2ecf20Sopenharmony_ci dev_kfree_skb_any(tx_skb->skb); 8538c2ecf20Sopenharmony_ci tx_skb->skb = NULL; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 8608c2ecf20Sopenharmony_ci struct macb_dma_desc_64 *desc_64; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) { 8638c2ecf20Sopenharmony_ci desc_64 = macb_64b_desc(bp, desc); 8648c2ecf20Sopenharmony_ci desc_64->addrh = upper_32_bits(addr); 8658c2ecf20Sopenharmony_ci /* The low bits of RX address contain the RX_USED bit, clearing 8668c2ecf20Sopenharmony_ci * of which allows packet RX. Make sure the high bits are also 8678c2ecf20Sopenharmony_ci * visible to HW at that point. 8688c2ecf20Sopenharmony_ci */ 8698c2ecf20Sopenharmony_ci dma_wmb(); 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci#endif 8728c2ecf20Sopenharmony_ci desc->addr = lower_32_bits(addr); 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci dma_addr_t addr = 0; 8788c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 8798c2ecf20Sopenharmony_ci struct macb_dma_desc_64 *desc_64; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) { 8828c2ecf20Sopenharmony_ci desc_64 = macb_64b_desc(bp, desc); 8838c2ecf20Sopenharmony_ci addr = ((u64)(desc_64->addrh) << 32); 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci#endif 8868c2ecf20Sopenharmony_ci addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); 8878c2ecf20Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP 8888c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_PTP) 8898c2ecf20Sopenharmony_ci addr &= ~GEM_BIT(DMA_RXVALID); 8908c2ecf20Sopenharmony_ci#endif 8918c2ecf20Sopenharmony_ci return addr; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic void macb_tx_error_task(struct work_struct *work) 8958c2ecf20Sopenharmony_ci{ 8968c2ecf20Sopenharmony_ci struct macb_queue *queue = container_of(work, struct macb_queue, 8978c2ecf20Sopenharmony_ci tx_error_task); 8988c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 8998c2ecf20Sopenharmony_ci struct macb_tx_skb *tx_skb; 9008c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 9018c2ecf20Sopenharmony_ci struct sk_buff *skb; 9028c2ecf20Sopenharmony_ci unsigned int tail; 9038c2ecf20Sopenharmony_ci unsigned long flags; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "macb_tx_error_task: q = %u, t = %u, h = %u\n", 9068c2ecf20Sopenharmony_ci (unsigned int)(queue - bp->queues), 9078c2ecf20Sopenharmony_ci queue->tx_tail, queue->tx_head); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* Prevent the queue IRQ handlers from running: each of them may call 9108c2ecf20Sopenharmony_ci * macb_tx_interrupt(), which in turn may call netif_wake_subqueue(). 9118c2ecf20Sopenharmony_ci * As explained below, we have to halt the transmission before updating 9128c2ecf20Sopenharmony_ci * TBQP registers so we call netif_tx_stop_all_queues() to notify the 9138c2ecf20Sopenharmony_ci * network engine about the macb/gem being halted. 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* Make sure nobody is trying to queue up new packets */ 9188c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(bp->dev); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* Stop transmission now 9218c2ecf20Sopenharmony_ci * (in case we have just queued new packets) 9228c2ecf20Sopenharmony_ci * macb/gem must be halted to write TBQP register 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_ci if (macb_halt_tx(bp)) 9258c2ecf20Sopenharmony_ci /* Just complain for now, reinitializing TX path can be good */ 9268c2ecf20Sopenharmony_ci netdev_err(bp->dev, "BUG: halt tx timed out\n"); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* Treat frames in TX queue including the ones that caused the error. 9298c2ecf20Sopenharmony_ci * Free transmit buffers in upper layer. 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_ci for (tail = queue->tx_tail; tail != queue->tx_head; tail++) { 9328c2ecf20Sopenharmony_ci u32 ctrl; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci desc = macb_tx_desc(queue, tail); 9358c2ecf20Sopenharmony_ci ctrl = desc->ctrl; 9368c2ecf20Sopenharmony_ci tx_skb = macb_tx_skb(queue, tail); 9378c2ecf20Sopenharmony_ci skb = tx_skb->skb; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (ctrl & MACB_BIT(TX_USED)) { 9408c2ecf20Sopenharmony_ci /* skb is set for the last buffer of the frame */ 9418c2ecf20Sopenharmony_ci while (!skb) { 9428c2ecf20Sopenharmony_ci macb_tx_unmap(bp, tx_skb); 9438c2ecf20Sopenharmony_ci tail++; 9448c2ecf20Sopenharmony_ci tx_skb = macb_tx_skb(queue, tail); 9458c2ecf20Sopenharmony_ci skb = tx_skb->skb; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* ctrl still refers to the first buffer descriptor 9498c2ecf20Sopenharmony_ci * since it's the only one written back by the hardware 9508c2ecf20Sopenharmony_ci */ 9518c2ecf20Sopenharmony_ci if (!(ctrl & MACB_BIT(TX_BUF_EXHAUSTED))) { 9528c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n", 9538c2ecf20Sopenharmony_ci macb_tx_ring_wrap(bp, tail), 9548c2ecf20Sopenharmony_ci skb->data); 9558c2ecf20Sopenharmony_ci bp->dev->stats.tx_packets++; 9568c2ecf20Sopenharmony_ci queue->stats.tx_packets++; 9578c2ecf20Sopenharmony_ci bp->dev->stats.tx_bytes += skb->len; 9588c2ecf20Sopenharmony_ci queue->stats.tx_bytes += skb->len; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci } else { 9618c2ecf20Sopenharmony_ci /* "Buffers exhausted mid-frame" errors may only happen 9628c2ecf20Sopenharmony_ci * if the driver is buggy, so complain loudly about 9638c2ecf20Sopenharmony_ci * those. Statistics are updated by hardware. 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_ci if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED)) 9668c2ecf20Sopenharmony_ci netdev_err(bp->dev, 9678c2ecf20Sopenharmony_ci "BUG: TX buffers exhausted mid-frame\n"); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci desc->ctrl = ctrl | MACB_BIT(TX_USED); 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci macb_tx_unmap(bp, tx_skb); 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Set end of TX queue */ 9768c2ecf20Sopenharmony_ci desc = macb_tx_desc(queue, 0); 9778c2ecf20Sopenharmony_ci macb_set_addr(bp, desc, 0); 9788c2ecf20Sopenharmony_ci desc->ctrl = MACB_BIT(TX_USED); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* Make descriptor updates visible to hardware */ 9818c2ecf20Sopenharmony_ci wmb(); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* Reinitialize the TX desc queue */ 9848c2ecf20Sopenharmony_ci queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); 9858c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 9868c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) 9878c2ecf20Sopenharmony_ci queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); 9888c2ecf20Sopenharmony_ci#endif 9898c2ecf20Sopenharmony_ci /* Make TX ring reflect state of hardware */ 9908c2ecf20Sopenharmony_ci queue->tx_head = 0; 9918c2ecf20Sopenharmony_ci queue->tx_tail = 0; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* Housework before enabling TX IRQ */ 9948c2ecf20Sopenharmony_ci macb_writel(bp, TSR, macb_readl(bp, TSR)); 9958c2ecf20Sopenharmony_ci queue_writel(queue, IER, MACB_TX_INT_FLAGS); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* Now we are ready to start transmission again */ 9988c2ecf20Sopenharmony_ci netif_tx_start_all_queues(bp->dev); 9998c2ecf20Sopenharmony_ci macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic void macb_tx_interrupt(struct macb_queue *queue) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci unsigned int tail; 10078c2ecf20Sopenharmony_ci unsigned int head; 10088c2ecf20Sopenharmony_ci u32 status; 10098c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 10108c2ecf20Sopenharmony_ci u16 queue_index = queue - bp->queues; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci status = macb_readl(bp, TSR); 10138c2ecf20Sopenharmony_ci macb_writel(bp, TSR, status); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 10168c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(TCOMP)); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n", 10198c2ecf20Sopenharmony_ci (unsigned long)status); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci head = queue->tx_head; 10228c2ecf20Sopenharmony_ci for (tail = queue->tx_tail; tail != head; tail++) { 10238c2ecf20Sopenharmony_ci struct macb_tx_skb *tx_skb; 10248c2ecf20Sopenharmony_ci struct sk_buff *skb; 10258c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 10268c2ecf20Sopenharmony_ci u32 ctrl; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci desc = macb_tx_desc(queue, tail); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Make hw descriptor updates visible to CPU */ 10318c2ecf20Sopenharmony_ci rmb(); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci ctrl = desc->ctrl; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* TX_USED bit is only set by hardware on the very first buffer 10368c2ecf20Sopenharmony_ci * descriptor of the transmitted frame. 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci if (!(ctrl & MACB_BIT(TX_USED))) 10398c2ecf20Sopenharmony_ci break; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Process all buffers of the current transmitted frame */ 10428c2ecf20Sopenharmony_ci for (;; tail++) { 10438c2ecf20Sopenharmony_ci tx_skb = macb_tx_skb(queue, tail); 10448c2ecf20Sopenharmony_ci skb = tx_skb->skb; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* First, update TX stats if needed */ 10478c2ecf20Sopenharmony_ci if (skb) { 10488c2ecf20Sopenharmony_ci if (unlikely(skb_shinfo(skb)->tx_flags & 10498c2ecf20Sopenharmony_ci SKBTX_HW_TSTAMP) && 10508c2ecf20Sopenharmony_ci gem_ptp_do_txstamp(queue, skb, desc) == 0) { 10518c2ecf20Sopenharmony_ci /* skb now belongs to timestamp buffer 10528c2ecf20Sopenharmony_ci * and will be removed later 10538c2ecf20Sopenharmony_ci */ 10548c2ecf20Sopenharmony_ci tx_skb->skb = NULL; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", 10578c2ecf20Sopenharmony_ci macb_tx_ring_wrap(bp, tail), 10588c2ecf20Sopenharmony_ci skb->data); 10598c2ecf20Sopenharmony_ci bp->dev->stats.tx_packets++; 10608c2ecf20Sopenharmony_ci queue->stats.tx_packets++; 10618c2ecf20Sopenharmony_ci bp->dev->stats.tx_bytes += skb->len; 10628c2ecf20Sopenharmony_ci queue->stats.tx_bytes += skb->len; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* Now we can safely release resources */ 10668c2ecf20Sopenharmony_ci macb_tx_unmap(bp, tx_skb); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* skb is set only for the last buffer of the frame. 10698c2ecf20Sopenharmony_ci * WARNING: at this point skb has been freed by 10708c2ecf20Sopenharmony_ci * macb_tx_unmap(). 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci if (skb) 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci queue->tx_tail = tail; 10788c2ecf20Sopenharmony_ci if (__netif_subqueue_stopped(bp->dev, queue_index) && 10798c2ecf20Sopenharmony_ci CIRC_CNT(queue->tx_head, queue->tx_tail, 10808c2ecf20Sopenharmony_ci bp->tx_ring_size) <= MACB_TX_WAKEUP_THRESH(bp)) 10818c2ecf20Sopenharmony_ci netif_wake_subqueue(bp->dev, queue_index); 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic void gem_rx_refill(struct macb_queue *queue) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci unsigned int entry; 10878c2ecf20Sopenharmony_ci struct sk_buff *skb; 10888c2ecf20Sopenharmony_ci dma_addr_t paddr; 10898c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 10908c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci while (CIRC_SPACE(queue->rx_prepared_head, queue->rx_tail, 10938c2ecf20Sopenharmony_ci bp->rx_ring_size) > 0) { 10948c2ecf20Sopenharmony_ci entry = macb_rx_ring_wrap(bp, queue->rx_prepared_head); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* Make hw descriptor updates visible to CPU */ 10978c2ecf20Sopenharmony_ci rmb(); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci desc = macb_rx_desc(queue, entry); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (!queue->rx_skbuff[entry]) { 11028c2ecf20Sopenharmony_ci /* allocate sk_buff for this free entry in ring */ 11038c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, bp->rx_buffer_size); 11048c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 11058c2ecf20Sopenharmony_ci netdev_err(bp->dev, 11068c2ecf20Sopenharmony_ci "Unable to allocate sk_buff\n"); 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* now fill corresponding descriptor entry */ 11118c2ecf20Sopenharmony_ci paddr = dma_map_single(&bp->pdev->dev, skb->data, 11128c2ecf20Sopenharmony_ci bp->rx_buffer_size, 11138c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 11148c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, paddr)) { 11158c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 11168c2ecf20Sopenharmony_ci break; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci queue->rx_skbuff[entry] = skb; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (entry == bp->rx_ring_size - 1) 11228c2ecf20Sopenharmony_ci paddr |= MACB_BIT(RX_WRAP); 11238c2ecf20Sopenharmony_ci desc->ctrl = 0; 11248c2ecf20Sopenharmony_ci /* Setting addr clears RX_USED and allows reception, 11258c2ecf20Sopenharmony_ci * make sure ctrl is cleared first to avoid a race. 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_ci dma_wmb(); 11288c2ecf20Sopenharmony_ci macb_set_addr(bp, desc, paddr); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* properly align Ethernet header */ 11318c2ecf20Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 11328c2ecf20Sopenharmony_ci } else { 11338c2ecf20Sopenharmony_ci desc->ctrl = 0; 11348c2ecf20Sopenharmony_ci dma_wmb(); 11358c2ecf20Sopenharmony_ci desc->addr &= ~MACB_BIT(RX_USED); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci queue->rx_prepared_head++; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci /* Make descriptor updates visible to hardware */ 11418c2ecf20Sopenharmony_ci wmb(); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "rx ring: queue: %p, prepared head %d, tail %d\n", 11448c2ecf20Sopenharmony_ci queue, queue->rx_prepared_head, queue->rx_tail); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci/* Mark DMA descriptors from begin up to and not including end as unused */ 11488c2ecf20Sopenharmony_cistatic void discard_partial_frame(struct macb_queue *queue, unsigned int begin, 11498c2ecf20Sopenharmony_ci unsigned int end) 11508c2ecf20Sopenharmony_ci{ 11518c2ecf20Sopenharmony_ci unsigned int frag; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci for (frag = begin; frag != end; frag++) { 11548c2ecf20Sopenharmony_ci struct macb_dma_desc *desc = macb_rx_desc(queue, frag); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci desc->addr &= ~MACB_BIT(RX_USED); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* Make descriptor updates visible to hardware */ 11608c2ecf20Sopenharmony_ci wmb(); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* When this happens, the hardware stats registers for 11638c2ecf20Sopenharmony_ci * whatever caused this is updated, so we don't have to record 11648c2ecf20Sopenharmony_ci * anything. 11658c2ecf20Sopenharmony_ci */ 11668c2ecf20Sopenharmony_ci} 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_cistatic int gem_rx(struct macb_queue *queue, struct napi_struct *napi, 11698c2ecf20Sopenharmony_ci int budget) 11708c2ecf20Sopenharmony_ci{ 11718c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 11728c2ecf20Sopenharmony_ci unsigned int len; 11738c2ecf20Sopenharmony_ci unsigned int entry; 11748c2ecf20Sopenharmony_ci struct sk_buff *skb; 11758c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 11768c2ecf20Sopenharmony_ci int count = 0; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci while (count < budget) { 11798c2ecf20Sopenharmony_ci u32 ctrl; 11808c2ecf20Sopenharmony_ci dma_addr_t addr; 11818c2ecf20Sopenharmony_ci bool rxused; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci entry = macb_rx_ring_wrap(bp, queue->rx_tail); 11848c2ecf20Sopenharmony_ci desc = macb_rx_desc(queue, entry); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* Make hw descriptor updates visible to CPU */ 11878c2ecf20Sopenharmony_ci rmb(); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false; 11908c2ecf20Sopenharmony_ci addr = macb_get_addr(bp, desc); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (!rxused) 11938c2ecf20Sopenharmony_ci break; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* Ensure ctrl is at least as up-to-date as rxused */ 11968c2ecf20Sopenharmony_ci dma_rmb(); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci ctrl = desc->ctrl; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci queue->rx_tail++; 12018c2ecf20Sopenharmony_ci count++; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (!(ctrl & MACB_BIT(RX_SOF) && ctrl & MACB_BIT(RX_EOF))) { 12048c2ecf20Sopenharmony_ci netdev_err(bp->dev, 12058c2ecf20Sopenharmony_ci "not whole frame pointed by descriptor\n"); 12068c2ecf20Sopenharmony_ci bp->dev->stats.rx_dropped++; 12078c2ecf20Sopenharmony_ci queue->stats.rx_dropped++; 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci skb = queue->rx_skbuff[entry]; 12118c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 12128c2ecf20Sopenharmony_ci netdev_err(bp->dev, 12138c2ecf20Sopenharmony_ci "inconsistent Rx descriptor chain\n"); 12148c2ecf20Sopenharmony_ci bp->dev->stats.rx_dropped++; 12158c2ecf20Sopenharmony_ci queue->stats.rx_dropped++; 12168c2ecf20Sopenharmony_ci break; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci /* now everything is ready for receiving packet */ 12198c2ecf20Sopenharmony_ci queue->rx_skbuff[entry] = NULL; 12208c2ecf20Sopenharmony_ci len = ctrl & bp->rx_frm_len_mask; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci skb_put(skb, len); 12258c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, addr, 12268c2ecf20Sopenharmony_ci bp->rx_buffer_size, DMA_FROM_DEVICE); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, bp->dev); 12298c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 12308c2ecf20Sopenharmony_ci if (bp->dev->features & NETIF_F_RXCSUM && 12318c2ecf20Sopenharmony_ci !(bp->dev->flags & IFF_PROMISC) && 12328c2ecf20Sopenharmony_ci GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK) 12338c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci bp->dev->stats.rx_packets++; 12368c2ecf20Sopenharmony_ci queue->stats.rx_packets++; 12378c2ecf20Sopenharmony_ci bp->dev->stats.rx_bytes += skb->len; 12388c2ecf20Sopenharmony_ci queue->stats.rx_bytes += skb->len; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci gem_ptp_do_rxstamp(bp, skb, desc); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci#if defined(DEBUG) && defined(VERBOSE_DEBUG) 12438c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", 12448c2ecf20Sopenharmony_ci skb->len, skb->csum); 12458c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, " mac: ", DUMP_PREFIX_ADDRESS, 16, 1, 12468c2ecf20Sopenharmony_ci skb_mac_header(skb), 16, true); 12478c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_ADDRESS, 16, 1, 12488c2ecf20Sopenharmony_ci skb->data, 32, true); 12498c2ecf20Sopenharmony_ci#endif 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci gem_rx_refill(queue); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci return count; 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic int macb_rx_frame(struct macb_queue *queue, struct napi_struct *napi, 12608c2ecf20Sopenharmony_ci unsigned int first_frag, unsigned int last_frag) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci unsigned int len; 12638c2ecf20Sopenharmony_ci unsigned int frag; 12648c2ecf20Sopenharmony_ci unsigned int offset; 12658c2ecf20Sopenharmony_ci struct sk_buff *skb; 12668c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 12678c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci desc = macb_rx_desc(queue, last_frag); 12708c2ecf20Sopenharmony_ci len = desc->ctrl & bp->rx_frm_len_mask; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n", 12738c2ecf20Sopenharmony_ci macb_rx_ring_wrap(bp, first_frag), 12748c2ecf20Sopenharmony_ci macb_rx_ring_wrap(bp, last_frag), len); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci /* The ethernet header starts NET_IP_ALIGN bytes into the 12778c2ecf20Sopenharmony_ci * first buffer. Since the header is 14 bytes, this makes the 12788c2ecf20Sopenharmony_ci * payload word-aligned. 12798c2ecf20Sopenharmony_ci * 12808c2ecf20Sopenharmony_ci * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy 12818c2ecf20Sopenharmony_ci * the two padding bytes into the skb so that we avoid hitting 12828c2ecf20Sopenharmony_ci * the slowpath in memcpy(), and pull them off afterwards. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN); 12858c2ecf20Sopenharmony_ci if (!skb) { 12868c2ecf20Sopenharmony_ci bp->dev->stats.rx_dropped++; 12878c2ecf20Sopenharmony_ci for (frag = first_frag; ; frag++) { 12888c2ecf20Sopenharmony_ci desc = macb_rx_desc(queue, frag); 12898c2ecf20Sopenharmony_ci desc->addr &= ~MACB_BIT(RX_USED); 12908c2ecf20Sopenharmony_ci if (frag == last_frag) 12918c2ecf20Sopenharmony_ci break; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* Make descriptor updates visible to hardware */ 12958c2ecf20Sopenharmony_ci wmb(); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci return 1; 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci offset = 0; 13018c2ecf20Sopenharmony_ci len += NET_IP_ALIGN; 13028c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 13038c2ecf20Sopenharmony_ci skb_put(skb, len); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci for (frag = first_frag; ; frag++) { 13068c2ecf20Sopenharmony_ci unsigned int frag_len = bp->rx_buffer_size; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (offset + frag_len > len) { 13098c2ecf20Sopenharmony_ci if (unlikely(frag != last_frag)) { 13108c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 13118c2ecf20Sopenharmony_ci return -1; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci frag_len = len - offset; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci skb_copy_to_linear_data_offset(skb, offset, 13168c2ecf20Sopenharmony_ci macb_rx_buffer(queue, frag), 13178c2ecf20Sopenharmony_ci frag_len); 13188c2ecf20Sopenharmony_ci offset += bp->rx_buffer_size; 13198c2ecf20Sopenharmony_ci desc = macb_rx_desc(queue, frag); 13208c2ecf20Sopenharmony_ci desc->addr &= ~MACB_BIT(RX_USED); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (frag == last_frag) 13238c2ecf20Sopenharmony_ci break; 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* Make descriptor updates visible to hardware */ 13278c2ecf20Sopenharmony_ci wmb(); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci __skb_pull(skb, NET_IP_ALIGN); 13308c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, bp->dev); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci bp->dev->stats.rx_packets++; 13338c2ecf20Sopenharmony_ci bp->dev->stats.rx_bytes += skb->len; 13348c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", 13358c2ecf20Sopenharmony_ci skb->len, skb->csum); 13368c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci return 0; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic inline void macb_init_rx_ring(struct macb_queue *queue) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 13448c2ecf20Sopenharmony_ci dma_addr_t addr; 13458c2ecf20Sopenharmony_ci struct macb_dma_desc *desc = NULL; 13468c2ecf20Sopenharmony_ci int i; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci addr = queue->rx_buffers_dma; 13498c2ecf20Sopenharmony_ci for (i = 0; i < bp->rx_ring_size; i++) { 13508c2ecf20Sopenharmony_ci desc = macb_rx_desc(queue, i); 13518c2ecf20Sopenharmony_ci macb_set_addr(bp, desc, addr); 13528c2ecf20Sopenharmony_ci desc->ctrl = 0; 13538c2ecf20Sopenharmony_ci addr += bp->rx_buffer_size; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci desc->addr |= MACB_BIT(RX_WRAP); 13568c2ecf20Sopenharmony_ci queue->rx_tail = 0; 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_cistatic int macb_rx(struct macb_queue *queue, struct napi_struct *napi, 13608c2ecf20Sopenharmony_ci int budget) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 13638c2ecf20Sopenharmony_ci bool reset_rx_queue = false; 13648c2ecf20Sopenharmony_ci int received = 0; 13658c2ecf20Sopenharmony_ci unsigned int tail; 13668c2ecf20Sopenharmony_ci int first_frag = -1; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci for (tail = queue->rx_tail; budget > 0; tail++) { 13698c2ecf20Sopenharmony_ci struct macb_dma_desc *desc = macb_rx_desc(queue, tail); 13708c2ecf20Sopenharmony_ci u32 ctrl; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci /* Make hw descriptor updates visible to CPU */ 13738c2ecf20Sopenharmony_ci rmb(); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (!(desc->addr & MACB_BIT(RX_USED))) 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci /* Ensure ctrl is at least as up-to-date as addr */ 13798c2ecf20Sopenharmony_ci dma_rmb(); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci ctrl = desc->ctrl; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (ctrl & MACB_BIT(RX_SOF)) { 13848c2ecf20Sopenharmony_ci if (first_frag != -1) 13858c2ecf20Sopenharmony_ci discard_partial_frame(queue, first_frag, tail); 13868c2ecf20Sopenharmony_ci first_frag = tail; 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (ctrl & MACB_BIT(RX_EOF)) { 13908c2ecf20Sopenharmony_ci int dropped; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci if (unlikely(first_frag == -1)) { 13938c2ecf20Sopenharmony_ci reset_rx_queue = true; 13948c2ecf20Sopenharmony_ci continue; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci dropped = macb_rx_frame(queue, napi, first_frag, tail); 13988c2ecf20Sopenharmony_ci first_frag = -1; 13998c2ecf20Sopenharmony_ci if (unlikely(dropped < 0)) { 14008c2ecf20Sopenharmony_ci reset_rx_queue = true; 14018c2ecf20Sopenharmony_ci continue; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci if (!dropped) { 14048c2ecf20Sopenharmony_ci received++; 14058c2ecf20Sopenharmony_ci budget--; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (unlikely(reset_rx_queue)) { 14118c2ecf20Sopenharmony_ci unsigned long flags; 14128c2ecf20Sopenharmony_ci u32 ctrl; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci netdev_err(bp->dev, "RX queue corruption: reset it\n"); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci ctrl = macb_readl(bp, NCR); 14198c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci macb_init_rx_ring(queue); 14228c2ecf20Sopenharmony_ci queue_writel(queue, RBQP, queue->rx_ring_dma); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 14278c2ecf20Sopenharmony_ci return received; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (first_frag != -1) 14318c2ecf20Sopenharmony_ci queue->rx_tail = first_frag; 14328c2ecf20Sopenharmony_ci else 14338c2ecf20Sopenharmony_ci queue->rx_tail = tail; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return received; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic int macb_poll(struct napi_struct *napi, int budget) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci struct macb_queue *queue = container_of(napi, struct macb_queue, napi); 14418c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 14428c2ecf20Sopenharmony_ci int work_done; 14438c2ecf20Sopenharmony_ci u32 status; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci status = macb_readl(bp, RSR); 14468c2ecf20Sopenharmony_ci macb_writel(bp, RSR, status); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n", 14498c2ecf20Sopenharmony_ci (unsigned long)status, budget); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci work_done = bp->macbgem_ops.mog_rx(queue, napi, budget); 14528c2ecf20Sopenharmony_ci if (work_done < budget) { 14538c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* RSR bits only seem to propagate to raise interrupts when 14568c2ecf20Sopenharmony_ci * interrupts are enabled at the time, so if bits are already 14578c2ecf20Sopenharmony_ci * set due to packets received while interrupts were disabled, 14588c2ecf20Sopenharmony_ci * they will not cause another interrupt to be generated when 14598c2ecf20Sopenharmony_ci * interrupts are re-enabled. 14608c2ecf20Sopenharmony_ci * Check for this case here. This has been seen to happen 14618c2ecf20Sopenharmony_ci * around 30% of the time under heavy network load. 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci status = macb_readl(bp, RSR); 14648c2ecf20Sopenharmony_ci if (status) { 14658c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 14668c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(RCOMP)); 14678c2ecf20Sopenharmony_ci napi_reschedule(napi); 14688c2ecf20Sopenharmony_ci } else { 14698c2ecf20Sopenharmony_ci queue_writel(queue, IER, bp->rx_intr_mask); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* In rare cases, packets could have been received in 14728c2ecf20Sopenharmony_ci * the window between the check above and re-enabling 14738c2ecf20Sopenharmony_ci * interrupts. Therefore, a double-check is required 14748c2ecf20Sopenharmony_ci * to avoid losing a wakeup. This can potentially race 14758c2ecf20Sopenharmony_ci * with the interrupt handler doing the same actions 14768c2ecf20Sopenharmony_ci * if an interrupt is raised just after enabling them, 14778c2ecf20Sopenharmony_ci * but this should be harmless. 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_ci status = macb_readl(bp, RSR); 14808c2ecf20Sopenharmony_ci if (unlikely(status)) { 14818c2ecf20Sopenharmony_ci queue_writel(queue, IDR, bp->rx_intr_mask); 14828c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 14838c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(RCOMP)); 14848c2ecf20Sopenharmony_ci napi_schedule(napi); 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci /* TODO: Handle errors */ 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci return work_done; 14928c2ecf20Sopenharmony_ci} 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_cistatic void macb_hresp_error_task(struct tasklet_struct *t) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci struct macb *bp = from_tasklet(bp, t, hresp_err_tasklet); 14978c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 14988c2ecf20Sopenharmony_ci struct macb_queue *queue; 14998c2ecf20Sopenharmony_ci unsigned int q; 15008c2ecf20Sopenharmony_ci u32 ctrl; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 15038c2ecf20Sopenharmony_ci queue_writel(queue, IDR, bp->rx_intr_mask | 15048c2ecf20Sopenharmony_ci MACB_TX_INT_FLAGS | 15058c2ecf20Sopenharmony_ci MACB_BIT(HRESP)); 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci ctrl = macb_readl(bp, NCR); 15088c2ecf20Sopenharmony_ci ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE)); 15098c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(dev); 15128c2ecf20Sopenharmony_ci netif_carrier_off(dev); 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_init_rings(bp); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* Initialize TX and RX buffers */ 15178c2ecf20Sopenharmony_ci macb_init_buffers(bp); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* Enable interrupts */ 15208c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 15218c2ecf20Sopenharmony_ci queue_writel(queue, IER, 15228c2ecf20Sopenharmony_ci bp->rx_intr_mask | 15238c2ecf20Sopenharmony_ci MACB_TX_INT_FLAGS | 15248c2ecf20Sopenharmony_ci MACB_BIT(HRESP)); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(RE) | MACB_BIT(TE); 15278c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci netif_carrier_on(dev); 15308c2ecf20Sopenharmony_ci netif_tx_start_all_queues(dev); 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic void macb_tx_restart(struct macb_queue *queue) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci unsigned int head = queue->tx_head; 15368c2ecf20Sopenharmony_ci unsigned int tail = queue->tx_tail; 15378c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 15388c2ecf20Sopenharmony_ci unsigned int head_idx, tbqp; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 15418c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(TXUBR)); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (head == tail) 15448c2ecf20Sopenharmony_ci return; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci tbqp = queue_readl(queue, TBQP) / macb_dma_desc_get_size(bp); 15478c2ecf20Sopenharmony_ci tbqp = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, tbqp)); 15488c2ecf20Sopenharmony_ci head_idx = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, head)); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (tbqp == head_idx) 15518c2ecf20Sopenharmony_ci return; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); 15548c2ecf20Sopenharmony_ci} 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_cistatic irqreturn_t macb_wol_interrupt(int irq, void *dev_id) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci struct macb_queue *queue = dev_id; 15598c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 15608c2ecf20Sopenharmony_ci u32 status; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci status = queue_readl(queue, ISR); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (unlikely(!status)) 15658c2ecf20Sopenharmony_ci return IRQ_NONE; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci spin_lock(&bp->lock); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (status & MACB_BIT(WOL)) { 15708c2ecf20Sopenharmony_ci queue_writel(queue, IDR, MACB_BIT(WOL)); 15718c2ecf20Sopenharmony_ci macb_writel(bp, WOL, 0); 15728c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "MACB WoL: queue = %u, isr = 0x%08lx\n", 15738c2ecf20Sopenharmony_ci (unsigned int)(queue - bp->queues), 15748c2ecf20Sopenharmony_ci (unsigned long)status); 15758c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 15768c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(WOL)); 15778c2ecf20Sopenharmony_ci pm_wakeup_event(&bp->pdev->dev, 0); 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci spin_unlock(&bp->lock); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci return IRQ_HANDLED; 15838c2ecf20Sopenharmony_ci} 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_cistatic irqreturn_t gem_wol_interrupt(int irq, void *dev_id) 15868c2ecf20Sopenharmony_ci{ 15878c2ecf20Sopenharmony_ci struct macb_queue *queue = dev_id; 15888c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 15898c2ecf20Sopenharmony_ci u32 status; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci status = queue_readl(queue, ISR); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (unlikely(!status)) 15948c2ecf20Sopenharmony_ci return IRQ_NONE; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci spin_lock(&bp->lock); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (status & GEM_BIT(WOL)) { 15998c2ecf20Sopenharmony_ci queue_writel(queue, IDR, GEM_BIT(WOL)); 16008c2ecf20Sopenharmony_ci gem_writel(bp, WOL, 0); 16018c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "GEM WoL: queue = %u, isr = 0x%08lx\n", 16028c2ecf20Sopenharmony_ci (unsigned int)(queue - bp->queues), 16038c2ecf20Sopenharmony_ci (unsigned long)status); 16048c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 16058c2ecf20Sopenharmony_ci queue_writel(queue, ISR, GEM_BIT(WOL)); 16068c2ecf20Sopenharmony_ci pm_wakeup_event(&bp->pdev->dev, 0); 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci spin_unlock(&bp->lock); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci return IRQ_HANDLED; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic irqreturn_t macb_interrupt(int irq, void *dev_id) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct macb_queue *queue = dev_id; 16178c2ecf20Sopenharmony_ci struct macb *bp = queue->bp; 16188c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 16198c2ecf20Sopenharmony_ci u32 status, ctrl; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci status = queue_readl(queue, ISR); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (unlikely(!status)) 16248c2ecf20Sopenharmony_ci return IRQ_NONE; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci spin_lock(&bp->lock); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci while (status) { 16298c2ecf20Sopenharmony_ci /* close possible race with dev_close */ 16308c2ecf20Sopenharmony_ci if (unlikely(!netif_running(dev))) { 16318c2ecf20Sopenharmony_ci queue_writel(queue, IDR, -1); 16328c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 16338c2ecf20Sopenharmony_ci queue_writel(queue, ISR, -1); 16348c2ecf20Sopenharmony_ci break; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "queue = %u, isr = 0x%08lx\n", 16388c2ecf20Sopenharmony_ci (unsigned int)(queue - bp->queues), 16398c2ecf20Sopenharmony_ci (unsigned long)status); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (status & bp->rx_intr_mask) { 16428c2ecf20Sopenharmony_ci /* There's no point taking any more interrupts 16438c2ecf20Sopenharmony_ci * until we have processed the buffers. The 16448c2ecf20Sopenharmony_ci * scheduling call may fail if the poll routine 16458c2ecf20Sopenharmony_ci * is already scheduled, so disable interrupts 16468c2ecf20Sopenharmony_ci * now. 16478c2ecf20Sopenharmony_ci */ 16488c2ecf20Sopenharmony_ci queue_writel(queue, IDR, bp->rx_intr_mask); 16498c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 16508c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(RCOMP)); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci if (napi_schedule_prep(&queue->napi)) { 16538c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, "scheduling RX softirq\n"); 16548c2ecf20Sopenharmony_ci __napi_schedule(&queue->napi); 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (unlikely(status & (MACB_TX_ERR_FLAGS))) { 16598c2ecf20Sopenharmony_ci queue_writel(queue, IDR, MACB_TX_INT_FLAGS); 16608c2ecf20Sopenharmony_ci schedule_work(&queue->tx_error_task); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 16638c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_TX_ERR_FLAGS); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci break; 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (status & MACB_BIT(TCOMP)) 16698c2ecf20Sopenharmony_ci macb_tx_interrupt(queue); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (status & MACB_BIT(TXUBR)) 16728c2ecf20Sopenharmony_ci macb_tx_restart(queue); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci /* Link change detection isn't possible with RMII, so we'll 16758c2ecf20Sopenharmony_ci * add that if/when we get our hands on a full-blown MII PHY. 16768c2ecf20Sopenharmony_ci */ 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci /* There is a hardware issue under heavy load where DMA can 16798c2ecf20Sopenharmony_ci * stop, this causes endless "used buffer descriptor read" 16808c2ecf20Sopenharmony_ci * interrupts but it can be cleared by re-enabling RX. See 16818c2ecf20Sopenharmony_ci * the at91rm9200 manual, section 41.3.1 or the Zynq manual 16828c2ecf20Sopenharmony_ci * section 16.7.4 for details. RXUBR is only enabled for 16838c2ecf20Sopenharmony_ci * these two versions. 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ci if (status & MACB_BIT(RXUBR)) { 16868c2ecf20Sopenharmony_ci ctrl = macb_readl(bp, NCR); 16878c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); 16888c2ecf20Sopenharmony_ci wmb(); 16898c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 16928c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(RXUBR)); 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (status & MACB_BIT(ISR_ROVR)) { 16968c2ecf20Sopenharmony_ci /* We missed at least one packet */ 16978c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) 16988c2ecf20Sopenharmony_ci bp->hw_stats.gem.rx_overruns++; 16998c2ecf20Sopenharmony_ci else 17008c2ecf20Sopenharmony_ci bp->hw_stats.macb.rx_overruns++; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 17038c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(ISR_ROVR)); 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci if (status & MACB_BIT(HRESP)) { 17078c2ecf20Sopenharmony_ci tasklet_schedule(&bp->hresp_err_tasklet); 17088c2ecf20Sopenharmony_ci netdev_err(dev, "DMA bus error: HRESP not OK\n"); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 17118c2ecf20Sopenharmony_ci queue_writel(queue, ISR, MACB_BIT(HRESP)); 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci status = queue_readl(queue, ISR); 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci spin_unlock(&bp->lock); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return IRQ_HANDLED; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 17228c2ecf20Sopenharmony_ci/* Polling receive - used by netconsole and other diagnostic tools 17238c2ecf20Sopenharmony_ci * to allow network i/o with interrupts disabled. 17248c2ecf20Sopenharmony_ci */ 17258c2ecf20Sopenharmony_cistatic void macb_poll_controller(struct net_device *dev) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 17288c2ecf20Sopenharmony_ci struct macb_queue *queue; 17298c2ecf20Sopenharmony_ci unsigned long flags; 17308c2ecf20Sopenharmony_ci unsigned int q; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci local_irq_save(flags); 17338c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 17348c2ecf20Sopenharmony_ci macb_interrupt(dev->irq, queue); 17358c2ecf20Sopenharmony_ci local_irq_restore(flags); 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci#endif 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_cistatic unsigned int macb_tx_map(struct macb *bp, 17408c2ecf20Sopenharmony_ci struct macb_queue *queue, 17418c2ecf20Sopenharmony_ci struct sk_buff *skb, 17428c2ecf20Sopenharmony_ci unsigned int hdrlen) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci dma_addr_t mapping; 17458c2ecf20Sopenharmony_ci unsigned int len, entry, i, tx_head = queue->tx_head; 17468c2ecf20Sopenharmony_ci struct macb_tx_skb *tx_skb = NULL; 17478c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 17488c2ecf20Sopenharmony_ci unsigned int offset, size, count = 0; 17498c2ecf20Sopenharmony_ci unsigned int f, nr_frags = skb_shinfo(skb)->nr_frags; 17508c2ecf20Sopenharmony_ci unsigned int eof = 1, mss_mfs = 0; 17518c2ecf20Sopenharmony_ci u32 ctrl, lso_ctrl = 0, seq_ctrl = 0; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci /* LSO */ 17548c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_size != 0) { 17558c2ecf20Sopenharmony_ci if (ip_hdr(skb)->protocol == IPPROTO_UDP) 17568c2ecf20Sopenharmony_ci /* UDP - UFO */ 17578c2ecf20Sopenharmony_ci lso_ctrl = MACB_LSO_UFO_ENABLE; 17588c2ecf20Sopenharmony_ci else 17598c2ecf20Sopenharmony_ci /* TCP - TSO */ 17608c2ecf20Sopenharmony_ci lso_ctrl = MACB_LSO_TSO_ENABLE; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci /* First, map non-paged data */ 17648c2ecf20Sopenharmony_ci len = skb_headlen(skb); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci /* first buffer length */ 17678c2ecf20Sopenharmony_ci size = hdrlen; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci offset = 0; 17708c2ecf20Sopenharmony_ci while (len) { 17718c2ecf20Sopenharmony_ci entry = macb_tx_ring_wrap(bp, tx_head); 17728c2ecf20Sopenharmony_ci tx_skb = &queue->tx_skb[entry]; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci mapping = dma_map_single(&bp->pdev->dev, 17758c2ecf20Sopenharmony_ci skb->data + offset, 17768c2ecf20Sopenharmony_ci size, DMA_TO_DEVICE); 17778c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, mapping)) 17788c2ecf20Sopenharmony_ci goto dma_error; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci /* Save info to properly release resources */ 17818c2ecf20Sopenharmony_ci tx_skb->skb = NULL; 17828c2ecf20Sopenharmony_ci tx_skb->mapping = mapping; 17838c2ecf20Sopenharmony_ci tx_skb->size = size; 17848c2ecf20Sopenharmony_ci tx_skb->mapped_as_page = false; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci len -= size; 17878c2ecf20Sopenharmony_ci offset += size; 17888c2ecf20Sopenharmony_ci count++; 17898c2ecf20Sopenharmony_ci tx_head++; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci size = min(len, bp->max_tx_length); 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci /* Then, map paged data from fragments */ 17958c2ecf20Sopenharmony_ci for (f = 0; f < nr_frags; f++) { 17968c2ecf20Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci len = skb_frag_size(frag); 17998c2ecf20Sopenharmony_ci offset = 0; 18008c2ecf20Sopenharmony_ci while (len) { 18018c2ecf20Sopenharmony_ci size = min(len, bp->max_tx_length); 18028c2ecf20Sopenharmony_ci entry = macb_tx_ring_wrap(bp, tx_head); 18038c2ecf20Sopenharmony_ci tx_skb = &queue->tx_skb[entry]; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 18068c2ecf20Sopenharmony_ci offset, size, DMA_TO_DEVICE); 18078c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, mapping)) 18088c2ecf20Sopenharmony_ci goto dma_error; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci /* Save info to properly release resources */ 18118c2ecf20Sopenharmony_ci tx_skb->skb = NULL; 18128c2ecf20Sopenharmony_ci tx_skb->mapping = mapping; 18138c2ecf20Sopenharmony_ci tx_skb->size = size; 18148c2ecf20Sopenharmony_ci tx_skb->mapped_as_page = true; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci len -= size; 18178c2ecf20Sopenharmony_ci offset += size; 18188c2ecf20Sopenharmony_ci count++; 18198c2ecf20Sopenharmony_ci tx_head++; 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* Should never happen */ 18248c2ecf20Sopenharmony_ci if (unlikely(!tx_skb)) { 18258c2ecf20Sopenharmony_ci netdev_err(bp->dev, "BUG! empty skb!\n"); 18268c2ecf20Sopenharmony_ci return 0; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci /* This is the last buffer of the frame: save socket buffer */ 18308c2ecf20Sopenharmony_ci tx_skb->skb = skb; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* Update TX ring: update buffer descriptors in reverse order 18338c2ecf20Sopenharmony_ci * to avoid race condition 18348c2ecf20Sopenharmony_ci */ 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* Set 'TX_USED' bit in buffer descriptor at tx_head position 18378c2ecf20Sopenharmony_ci * to set the end of TX queue 18388c2ecf20Sopenharmony_ci */ 18398c2ecf20Sopenharmony_ci i = tx_head; 18408c2ecf20Sopenharmony_ci entry = macb_tx_ring_wrap(bp, i); 18418c2ecf20Sopenharmony_ci ctrl = MACB_BIT(TX_USED); 18428c2ecf20Sopenharmony_ci desc = macb_tx_desc(queue, entry); 18438c2ecf20Sopenharmony_ci desc->ctrl = ctrl; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (lso_ctrl) { 18468c2ecf20Sopenharmony_ci if (lso_ctrl == MACB_LSO_UFO_ENABLE) 18478c2ecf20Sopenharmony_ci /* include header and FCS in value given to h/w */ 18488c2ecf20Sopenharmony_ci mss_mfs = skb_shinfo(skb)->gso_size + 18498c2ecf20Sopenharmony_ci skb_transport_offset(skb) + 18508c2ecf20Sopenharmony_ci ETH_FCS_LEN; 18518c2ecf20Sopenharmony_ci else /* TSO */ { 18528c2ecf20Sopenharmony_ci mss_mfs = skb_shinfo(skb)->gso_size; 18538c2ecf20Sopenharmony_ci /* TCP Sequence Number Source Select 18548c2ecf20Sopenharmony_ci * can be set only for TSO 18558c2ecf20Sopenharmony_ci */ 18568c2ecf20Sopenharmony_ci seq_ctrl = 0; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci do { 18618c2ecf20Sopenharmony_ci i--; 18628c2ecf20Sopenharmony_ci entry = macb_tx_ring_wrap(bp, i); 18638c2ecf20Sopenharmony_ci tx_skb = &queue->tx_skb[entry]; 18648c2ecf20Sopenharmony_ci desc = macb_tx_desc(queue, entry); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci ctrl = (u32)tx_skb->size; 18678c2ecf20Sopenharmony_ci if (eof) { 18688c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(TX_LAST); 18698c2ecf20Sopenharmony_ci eof = 0; 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci if (unlikely(entry == (bp->tx_ring_size - 1))) 18728c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(TX_WRAP); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci /* First descriptor is header descriptor */ 18758c2ecf20Sopenharmony_ci if (i == queue->tx_head) { 18768c2ecf20Sopenharmony_ci ctrl |= MACB_BF(TX_LSO, lso_ctrl); 18778c2ecf20Sopenharmony_ci ctrl |= MACB_BF(TX_TCP_SEQ_SRC, seq_ctrl); 18788c2ecf20Sopenharmony_ci if ((bp->dev->features & NETIF_F_HW_CSUM) && 18798c2ecf20Sopenharmony_ci skb->ip_summed != CHECKSUM_PARTIAL && !lso_ctrl) 18808c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(TX_NOCRC); 18818c2ecf20Sopenharmony_ci } else 18828c2ecf20Sopenharmony_ci /* Only set MSS/MFS on payload descriptors 18838c2ecf20Sopenharmony_ci * (second or later descriptor) 18848c2ecf20Sopenharmony_ci */ 18858c2ecf20Sopenharmony_ci ctrl |= MACB_BF(MSS_MFS, mss_mfs); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* Set TX buffer descriptor */ 18888c2ecf20Sopenharmony_ci macb_set_addr(bp, desc, tx_skb->mapping); 18898c2ecf20Sopenharmony_ci /* desc->addr must be visible to hardware before clearing 18908c2ecf20Sopenharmony_ci * 'TX_USED' bit in desc->ctrl. 18918c2ecf20Sopenharmony_ci */ 18928c2ecf20Sopenharmony_ci wmb(); 18938c2ecf20Sopenharmony_ci desc->ctrl = ctrl; 18948c2ecf20Sopenharmony_ci } while (i != queue->tx_head); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci queue->tx_head = tx_head; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci return count; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_cidma_error: 19018c2ecf20Sopenharmony_ci netdev_err(bp->dev, "TX DMA map failed\n"); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci for (i = queue->tx_head; i != tx_head; i++) { 19048c2ecf20Sopenharmony_ci tx_skb = macb_tx_skb(queue, i); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci macb_tx_unmap(bp, tx_skb); 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci return 0; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic netdev_features_t macb_features_check(struct sk_buff *skb, 19138c2ecf20Sopenharmony_ci struct net_device *dev, 19148c2ecf20Sopenharmony_ci netdev_features_t features) 19158c2ecf20Sopenharmony_ci{ 19168c2ecf20Sopenharmony_ci unsigned int nr_frags, f; 19178c2ecf20Sopenharmony_ci unsigned int hdrlen; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci /* Validate LSO compatibility */ 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci /* there is only one buffer or protocol is not UDP */ 19228c2ecf20Sopenharmony_ci if (!skb_is_nonlinear(skb) || (ip_hdr(skb)->protocol != IPPROTO_UDP)) 19238c2ecf20Sopenharmony_ci return features; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci /* length of header */ 19268c2ecf20Sopenharmony_ci hdrlen = skb_transport_offset(skb); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci /* For UFO only: 19298c2ecf20Sopenharmony_ci * When software supplies two or more payload buffers all payload buffers 19308c2ecf20Sopenharmony_ci * apart from the last must be a multiple of 8 bytes in size. 19318c2ecf20Sopenharmony_ci */ 19328c2ecf20Sopenharmony_ci if (!IS_ALIGNED(skb_headlen(skb) - hdrlen, MACB_TX_LEN_ALIGN)) 19338c2ecf20Sopenharmony_ci return features & ~MACB_NETIF_LSO; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 19368c2ecf20Sopenharmony_ci /* No need to check last fragment */ 19378c2ecf20Sopenharmony_ci nr_frags--; 19388c2ecf20Sopenharmony_ci for (f = 0; f < nr_frags; f++) { 19398c2ecf20Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci if (!IS_ALIGNED(skb_frag_size(frag), MACB_TX_LEN_ALIGN)) 19428c2ecf20Sopenharmony_ci return features & ~MACB_NETIF_LSO; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci return features; 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_cistatic inline int macb_clear_csum(struct sk_buff *skb) 19488c2ecf20Sopenharmony_ci{ 19498c2ecf20Sopenharmony_ci /* no change for packets without checksum offloading */ 19508c2ecf20Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 19518c2ecf20Sopenharmony_ci return 0; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci /* make sure we can modify the header */ 19548c2ecf20Sopenharmony_ci if (unlikely(skb_cow_head(skb, 0))) 19558c2ecf20Sopenharmony_ci return -1; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci /* initialize checksum field 19588c2ecf20Sopenharmony_ci * This is required - at least for Zynq, which otherwise calculates 19598c2ecf20Sopenharmony_ci * wrong UDP header checksums for UDP packets with UDP data len <=2 19608c2ecf20Sopenharmony_ci */ 19618c2ecf20Sopenharmony_ci *(__sum16 *)(skb_checksum_start(skb) + skb->csum_offset) = 0; 19628c2ecf20Sopenharmony_ci return 0; 19638c2ecf20Sopenharmony_ci} 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_cistatic int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) 19668c2ecf20Sopenharmony_ci{ 19678c2ecf20Sopenharmony_ci bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) || 19688c2ecf20Sopenharmony_ci skb_is_nonlinear(*skb); 19698c2ecf20Sopenharmony_ci int padlen = ETH_ZLEN - (*skb)->len; 19708c2ecf20Sopenharmony_ci int tailroom = skb_tailroom(*skb); 19718c2ecf20Sopenharmony_ci struct sk_buff *nskb; 19728c2ecf20Sopenharmony_ci u32 fcs; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if (!(ndev->features & NETIF_F_HW_CSUM) || 19758c2ecf20Sopenharmony_ci !((*skb)->ip_summed != CHECKSUM_PARTIAL) || 19768c2ecf20Sopenharmony_ci skb_shinfo(*skb)->gso_size) /* Not available for GSO */ 19778c2ecf20Sopenharmony_ci return 0; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci if (padlen <= 0) { 19808c2ecf20Sopenharmony_ci /* FCS could be appeded to tailroom. */ 19818c2ecf20Sopenharmony_ci if (tailroom >= ETH_FCS_LEN) 19828c2ecf20Sopenharmony_ci goto add_fcs; 19838c2ecf20Sopenharmony_ci /* No room for FCS, need to reallocate skb. */ 19848c2ecf20Sopenharmony_ci else 19858c2ecf20Sopenharmony_ci padlen = ETH_FCS_LEN; 19868c2ecf20Sopenharmony_ci } else { 19878c2ecf20Sopenharmony_ci /* Add room for FCS. */ 19888c2ecf20Sopenharmony_ci padlen += ETH_FCS_LEN; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (cloned || tailroom < padlen) { 19928c2ecf20Sopenharmony_ci nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC); 19938c2ecf20Sopenharmony_ci if (!nskb) 19948c2ecf20Sopenharmony_ci return -ENOMEM; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci dev_consume_skb_any(*skb); 19978c2ecf20Sopenharmony_ci *skb = nskb; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci if (padlen > ETH_FCS_LEN) 20018c2ecf20Sopenharmony_ci skb_put_zero(*skb, padlen - ETH_FCS_LEN); 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ciadd_fcs: 20048c2ecf20Sopenharmony_ci /* set FCS to packet */ 20058c2ecf20Sopenharmony_ci fcs = crc32_le(~0, (*skb)->data, (*skb)->len); 20068c2ecf20Sopenharmony_ci fcs = ~fcs; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci skb_put_u8(*skb, fcs & 0xff); 20098c2ecf20Sopenharmony_ci skb_put_u8(*skb, (fcs >> 8) & 0xff); 20108c2ecf20Sopenharmony_ci skb_put_u8(*skb, (fcs >> 16) & 0xff); 20118c2ecf20Sopenharmony_ci skb_put_u8(*skb, (fcs >> 24) & 0xff); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci return 0; 20148c2ecf20Sopenharmony_ci} 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_cistatic netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci u16 queue_index = skb_get_queue_mapping(skb); 20198c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 20208c2ecf20Sopenharmony_ci struct macb_queue *queue = &bp->queues[queue_index]; 20218c2ecf20Sopenharmony_ci unsigned long flags; 20228c2ecf20Sopenharmony_ci unsigned int desc_cnt, nr_frags, frag_size, f; 20238c2ecf20Sopenharmony_ci unsigned int hdrlen; 20248c2ecf20Sopenharmony_ci bool is_lso; 20258c2ecf20Sopenharmony_ci netdev_tx_t ret = NETDEV_TX_OK; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (macb_clear_csum(skb)) { 20288c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 20298c2ecf20Sopenharmony_ci return ret; 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci if (macb_pad_and_fcs(&skb, dev)) { 20338c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 20348c2ecf20Sopenharmony_ci return ret; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci is_lso = (skb_shinfo(skb)->gso_size != 0); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci if (is_lso) { 20408c2ecf20Sopenharmony_ci /* length of headers */ 20418c2ecf20Sopenharmony_ci if (ip_hdr(skb)->protocol == IPPROTO_UDP) 20428c2ecf20Sopenharmony_ci /* only queue eth + ip headers separately for UDP */ 20438c2ecf20Sopenharmony_ci hdrlen = skb_transport_offset(skb); 20448c2ecf20Sopenharmony_ci else 20458c2ecf20Sopenharmony_ci hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); 20468c2ecf20Sopenharmony_ci if (skb_headlen(skb) < hdrlen) { 20478c2ecf20Sopenharmony_ci netdev_err(bp->dev, "Error - LSO headers fragmented!!!\n"); 20488c2ecf20Sopenharmony_ci /* if this is required, would need to copy to single buffer */ 20498c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci } else 20528c2ecf20Sopenharmony_ci hdrlen = min(skb_headlen(skb), bp->max_tx_length); 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci#if defined(DEBUG) && defined(VERBOSE_DEBUG) 20558c2ecf20Sopenharmony_ci netdev_vdbg(bp->dev, 20568c2ecf20Sopenharmony_ci "start_xmit: queue %hu len %u head %p data %p tail %p end %p\n", 20578c2ecf20Sopenharmony_ci queue_index, skb->len, skb->head, skb->data, 20588c2ecf20Sopenharmony_ci skb_tail_pointer(skb), skb_end_pointer(skb)); 20598c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, 20608c2ecf20Sopenharmony_ci skb->data, 16, true); 20618c2ecf20Sopenharmony_ci#endif 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci /* Count how many TX buffer descriptors are needed to send this 20648c2ecf20Sopenharmony_ci * socket buffer: skb fragments of jumbo frames may need to be 20658c2ecf20Sopenharmony_ci * split into many buffer descriptors. 20668c2ecf20Sopenharmony_ci */ 20678c2ecf20Sopenharmony_ci if (is_lso && (skb_headlen(skb) > hdrlen)) 20688c2ecf20Sopenharmony_ci /* extra header descriptor if also payload in first buffer */ 20698c2ecf20Sopenharmony_ci desc_cnt = DIV_ROUND_UP((skb_headlen(skb) - hdrlen), bp->max_tx_length) + 1; 20708c2ecf20Sopenharmony_ci else 20718c2ecf20Sopenharmony_ci desc_cnt = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length); 20728c2ecf20Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 20738c2ecf20Sopenharmony_ci for (f = 0; f < nr_frags; f++) { 20748c2ecf20Sopenharmony_ci frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]); 20758c2ecf20Sopenharmony_ci desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length); 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci /* This is a hard error, log it. */ 20818c2ecf20Sopenharmony_ci if (CIRC_SPACE(queue->tx_head, queue->tx_tail, 20828c2ecf20Sopenharmony_ci bp->tx_ring_size) < desc_cnt) { 20838c2ecf20Sopenharmony_ci netif_stop_subqueue(dev, queue_index); 20848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 20858c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n", 20868c2ecf20Sopenharmony_ci queue->tx_head, queue->tx_tail); 20878c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 20888c2ecf20Sopenharmony_ci } 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci /* Map socket buffer for DMA transfer */ 20918c2ecf20Sopenharmony_ci if (!macb_tx_map(bp, queue, skb, hdrlen)) { 20928c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 20938c2ecf20Sopenharmony_ci goto unlock; 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci /* Make newly initialized descriptor visible to hardware */ 20978c2ecf20Sopenharmony_ci wmb(); 20988c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1) 21038c2ecf20Sopenharmony_ci netif_stop_subqueue(dev, queue_index); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ciunlock: 21068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci return ret; 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic void macb_init_rx_buffer_size(struct macb *bp, size_t size) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci if (!macb_is_gem(bp)) { 21148c2ecf20Sopenharmony_ci bp->rx_buffer_size = MACB_RX_BUFFER_SIZE; 21158c2ecf20Sopenharmony_ci } else { 21168c2ecf20Sopenharmony_ci bp->rx_buffer_size = size; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci if (bp->rx_buffer_size % RX_BUFFER_MULTIPLE) { 21198c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, 21208c2ecf20Sopenharmony_ci "RX buffer must be multiple of %d bytes, expanding\n", 21218c2ecf20Sopenharmony_ci RX_BUFFER_MULTIPLE); 21228c2ecf20Sopenharmony_ci bp->rx_buffer_size = 21238c2ecf20Sopenharmony_ci roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE); 21248c2ecf20Sopenharmony_ci } 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, "mtu [%u] rx_buffer_size [%zu]\n", 21288c2ecf20Sopenharmony_ci bp->dev->mtu, bp->rx_buffer_size); 21298c2ecf20Sopenharmony_ci} 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_cistatic void gem_free_rx_buffers(struct macb *bp) 21328c2ecf20Sopenharmony_ci{ 21338c2ecf20Sopenharmony_ci struct sk_buff *skb; 21348c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 21358c2ecf20Sopenharmony_ci struct macb_queue *queue; 21368c2ecf20Sopenharmony_ci dma_addr_t addr; 21378c2ecf20Sopenharmony_ci unsigned int q; 21388c2ecf20Sopenharmony_ci int i; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 21418c2ecf20Sopenharmony_ci if (!queue->rx_skbuff) 21428c2ecf20Sopenharmony_ci continue; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci for (i = 0; i < bp->rx_ring_size; i++) { 21458c2ecf20Sopenharmony_ci skb = queue->rx_skbuff[i]; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci if (!skb) 21488c2ecf20Sopenharmony_ci continue; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci desc = macb_rx_desc(queue, i); 21518c2ecf20Sopenharmony_ci addr = macb_get_addr(bp, desc); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size, 21548c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 21558c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 21568c2ecf20Sopenharmony_ci skb = NULL; 21578c2ecf20Sopenharmony_ci } 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci kfree(queue->rx_skbuff); 21608c2ecf20Sopenharmony_ci queue->rx_skbuff = NULL; 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci} 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_cistatic void macb_free_rx_buffers(struct macb *bp) 21658c2ecf20Sopenharmony_ci{ 21668c2ecf20Sopenharmony_ci struct macb_queue *queue = &bp->queues[0]; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci if (queue->rx_buffers) { 21698c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, 21708c2ecf20Sopenharmony_ci bp->rx_ring_size * bp->rx_buffer_size, 21718c2ecf20Sopenharmony_ci queue->rx_buffers, queue->rx_buffers_dma); 21728c2ecf20Sopenharmony_ci queue->rx_buffers = NULL; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci} 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_cistatic void macb_free_consistent(struct macb *bp) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci struct macb_queue *queue; 21798c2ecf20Sopenharmony_ci unsigned int q; 21808c2ecf20Sopenharmony_ci int size; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_free_rx_buffers(bp); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 21858c2ecf20Sopenharmony_ci kfree(queue->tx_skb); 21868c2ecf20Sopenharmony_ci queue->tx_skb = NULL; 21878c2ecf20Sopenharmony_ci if (queue->tx_ring) { 21888c2ecf20Sopenharmony_ci size = TX_RING_BYTES(bp) + bp->tx_bd_rd_prefetch; 21898c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, size, 21908c2ecf20Sopenharmony_ci queue->tx_ring, queue->tx_ring_dma); 21918c2ecf20Sopenharmony_ci queue->tx_ring = NULL; 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci if (queue->rx_ring) { 21948c2ecf20Sopenharmony_ci size = RX_RING_BYTES(bp) + bp->rx_bd_rd_prefetch; 21958c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, size, 21968c2ecf20Sopenharmony_ci queue->rx_ring, queue->rx_ring_dma); 21978c2ecf20Sopenharmony_ci queue->rx_ring = NULL; 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci} 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_cistatic int gem_alloc_rx_buffers(struct macb *bp) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci struct macb_queue *queue; 22058c2ecf20Sopenharmony_ci unsigned int q; 22068c2ecf20Sopenharmony_ci int size; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 22098c2ecf20Sopenharmony_ci size = bp->rx_ring_size * sizeof(struct sk_buff *); 22108c2ecf20Sopenharmony_ci queue->rx_skbuff = kzalloc(size, GFP_KERNEL); 22118c2ecf20Sopenharmony_ci if (!queue->rx_skbuff) 22128c2ecf20Sopenharmony_ci return -ENOMEM; 22138c2ecf20Sopenharmony_ci else 22148c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, 22158c2ecf20Sopenharmony_ci "Allocated %d RX struct sk_buff entries at %p\n", 22168c2ecf20Sopenharmony_ci bp->rx_ring_size, queue->rx_skbuff); 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci return 0; 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_cistatic int macb_alloc_rx_buffers(struct macb *bp) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct macb_queue *queue = &bp->queues[0]; 22248c2ecf20Sopenharmony_ci int size; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci size = bp->rx_ring_size * bp->rx_buffer_size; 22278c2ecf20Sopenharmony_ci queue->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, 22288c2ecf20Sopenharmony_ci &queue->rx_buffers_dma, GFP_KERNEL); 22298c2ecf20Sopenharmony_ci if (!queue->rx_buffers) 22308c2ecf20Sopenharmony_ci return -ENOMEM; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, 22338c2ecf20Sopenharmony_ci "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", 22348c2ecf20Sopenharmony_ci size, (unsigned long)queue->rx_buffers_dma, queue->rx_buffers); 22358c2ecf20Sopenharmony_ci return 0; 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_cistatic int macb_alloc_consistent(struct macb *bp) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci struct macb_queue *queue; 22418c2ecf20Sopenharmony_ci unsigned int q; 22428c2ecf20Sopenharmony_ci int size; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 22458c2ecf20Sopenharmony_ci size = TX_RING_BYTES(bp) + bp->tx_bd_rd_prefetch; 22468c2ecf20Sopenharmony_ci queue->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, 22478c2ecf20Sopenharmony_ci &queue->tx_ring_dma, 22488c2ecf20Sopenharmony_ci GFP_KERNEL); 22498c2ecf20Sopenharmony_ci if (!queue->tx_ring) 22508c2ecf20Sopenharmony_ci goto out_err; 22518c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, 22528c2ecf20Sopenharmony_ci "Allocated TX ring for queue %u of %d bytes at %08lx (mapped %p)\n", 22538c2ecf20Sopenharmony_ci q, size, (unsigned long)queue->tx_ring_dma, 22548c2ecf20Sopenharmony_ci queue->tx_ring); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci size = bp->tx_ring_size * sizeof(struct macb_tx_skb); 22578c2ecf20Sopenharmony_ci queue->tx_skb = kmalloc(size, GFP_KERNEL); 22588c2ecf20Sopenharmony_ci if (!queue->tx_skb) 22598c2ecf20Sopenharmony_ci goto out_err; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci size = RX_RING_BYTES(bp) + bp->rx_bd_rd_prefetch; 22628c2ecf20Sopenharmony_ci queue->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, 22638c2ecf20Sopenharmony_ci &queue->rx_ring_dma, GFP_KERNEL); 22648c2ecf20Sopenharmony_ci if (!queue->rx_ring) 22658c2ecf20Sopenharmony_ci goto out_err; 22668c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, 22678c2ecf20Sopenharmony_ci "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", 22688c2ecf20Sopenharmony_ci size, (unsigned long)queue->rx_ring_dma, queue->rx_ring); 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci if (bp->macbgem_ops.mog_alloc_rx_buffers(bp)) 22718c2ecf20Sopenharmony_ci goto out_err; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci return 0; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ciout_err: 22768c2ecf20Sopenharmony_ci macb_free_consistent(bp); 22778c2ecf20Sopenharmony_ci return -ENOMEM; 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_cistatic void gem_init_rings(struct macb *bp) 22818c2ecf20Sopenharmony_ci{ 22828c2ecf20Sopenharmony_ci struct macb_queue *queue; 22838c2ecf20Sopenharmony_ci struct macb_dma_desc *desc = NULL; 22848c2ecf20Sopenharmony_ci unsigned int q; 22858c2ecf20Sopenharmony_ci int i; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 22888c2ecf20Sopenharmony_ci for (i = 0; i < bp->tx_ring_size; i++) { 22898c2ecf20Sopenharmony_ci desc = macb_tx_desc(queue, i); 22908c2ecf20Sopenharmony_ci macb_set_addr(bp, desc, 0); 22918c2ecf20Sopenharmony_ci desc->ctrl = MACB_BIT(TX_USED); 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci desc->ctrl |= MACB_BIT(TX_WRAP); 22948c2ecf20Sopenharmony_ci queue->tx_head = 0; 22958c2ecf20Sopenharmony_ci queue->tx_tail = 0; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci queue->rx_tail = 0; 22988c2ecf20Sopenharmony_ci queue->rx_prepared_head = 0; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci gem_rx_refill(queue); 23018c2ecf20Sopenharmony_ci } 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci} 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_cistatic void macb_init_rings(struct macb *bp) 23068c2ecf20Sopenharmony_ci{ 23078c2ecf20Sopenharmony_ci int i; 23088c2ecf20Sopenharmony_ci struct macb_dma_desc *desc = NULL; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci macb_init_rx_ring(&bp->queues[0]); 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci for (i = 0; i < bp->tx_ring_size; i++) { 23138c2ecf20Sopenharmony_ci desc = macb_tx_desc(&bp->queues[0], i); 23148c2ecf20Sopenharmony_ci macb_set_addr(bp, desc, 0); 23158c2ecf20Sopenharmony_ci desc->ctrl = MACB_BIT(TX_USED); 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci bp->queues[0].tx_head = 0; 23188c2ecf20Sopenharmony_ci bp->queues[0].tx_tail = 0; 23198c2ecf20Sopenharmony_ci desc->ctrl |= MACB_BIT(TX_WRAP); 23208c2ecf20Sopenharmony_ci} 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_cistatic void macb_reset_hw(struct macb *bp) 23238c2ecf20Sopenharmony_ci{ 23248c2ecf20Sopenharmony_ci struct macb_queue *queue; 23258c2ecf20Sopenharmony_ci unsigned int q; 23268c2ecf20Sopenharmony_ci u32 ctrl = macb_readl(bp, NCR); 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci /* Disable RX and TX (XXX: Should we halt the transmission 23298c2ecf20Sopenharmony_ci * more gracefully?) 23308c2ecf20Sopenharmony_ci */ 23318c2ecf20Sopenharmony_ci ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE)); 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci /* Clear the stats registers (XXX: Update stats first?) */ 23348c2ecf20Sopenharmony_ci ctrl |= MACB_BIT(CLRSTAT); 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci macb_writel(bp, NCR, ctrl); 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci /* Clear all status flags */ 23398c2ecf20Sopenharmony_ci macb_writel(bp, TSR, -1); 23408c2ecf20Sopenharmony_ci macb_writel(bp, RSR, -1); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci /* Disable all interrupts */ 23438c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 23448c2ecf20Sopenharmony_ci queue_writel(queue, IDR, -1); 23458c2ecf20Sopenharmony_ci queue_readl(queue, ISR); 23468c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 23478c2ecf20Sopenharmony_ci queue_writel(queue, ISR, -1); 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci} 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_cistatic u32 gem_mdc_clk_div(struct macb *bp) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci u32 config; 23548c2ecf20Sopenharmony_ci unsigned long pclk_hz = clk_get_rate(bp->pclk); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci if (pclk_hz <= 20000000) 23578c2ecf20Sopenharmony_ci config = GEM_BF(CLK, GEM_CLK_DIV8); 23588c2ecf20Sopenharmony_ci else if (pclk_hz <= 40000000) 23598c2ecf20Sopenharmony_ci config = GEM_BF(CLK, GEM_CLK_DIV16); 23608c2ecf20Sopenharmony_ci else if (pclk_hz <= 80000000) 23618c2ecf20Sopenharmony_ci config = GEM_BF(CLK, GEM_CLK_DIV32); 23628c2ecf20Sopenharmony_ci else if (pclk_hz <= 120000000) 23638c2ecf20Sopenharmony_ci config = GEM_BF(CLK, GEM_CLK_DIV48); 23648c2ecf20Sopenharmony_ci else if (pclk_hz <= 160000000) 23658c2ecf20Sopenharmony_ci config = GEM_BF(CLK, GEM_CLK_DIV64); 23668c2ecf20Sopenharmony_ci else 23678c2ecf20Sopenharmony_ci config = GEM_BF(CLK, GEM_CLK_DIV96); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci return config; 23708c2ecf20Sopenharmony_ci} 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_cistatic u32 macb_mdc_clk_div(struct macb *bp) 23738c2ecf20Sopenharmony_ci{ 23748c2ecf20Sopenharmony_ci u32 config; 23758c2ecf20Sopenharmony_ci unsigned long pclk_hz; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) 23788c2ecf20Sopenharmony_ci return gem_mdc_clk_div(bp); 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci pclk_hz = clk_get_rate(bp->pclk); 23818c2ecf20Sopenharmony_ci if (pclk_hz <= 20000000) 23828c2ecf20Sopenharmony_ci config = MACB_BF(CLK, MACB_CLK_DIV8); 23838c2ecf20Sopenharmony_ci else if (pclk_hz <= 40000000) 23848c2ecf20Sopenharmony_ci config = MACB_BF(CLK, MACB_CLK_DIV16); 23858c2ecf20Sopenharmony_ci else if (pclk_hz <= 80000000) 23868c2ecf20Sopenharmony_ci config = MACB_BF(CLK, MACB_CLK_DIV32); 23878c2ecf20Sopenharmony_ci else 23888c2ecf20Sopenharmony_ci config = MACB_BF(CLK, MACB_CLK_DIV64); 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci return config; 23918c2ecf20Sopenharmony_ci} 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci/* Get the DMA bus width field of the network configuration register that we 23948c2ecf20Sopenharmony_ci * should program. We find the width from decoding the design configuration 23958c2ecf20Sopenharmony_ci * register to find the maximum supported data bus width. 23968c2ecf20Sopenharmony_ci */ 23978c2ecf20Sopenharmony_cistatic u32 macb_dbw(struct macb *bp) 23988c2ecf20Sopenharmony_ci{ 23998c2ecf20Sopenharmony_ci if (!macb_is_gem(bp)) 24008c2ecf20Sopenharmony_ci return 0; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) { 24038c2ecf20Sopenharmony_ci case 4: 24048c2ecf20Sopenharmony_ci return GEM_BF(DBW, GEM_DBW128); 24058c2ecf20Sopenharmony_ci case 2: 24068c2ecf20Sopenharmony_ci return GEM_BF(DBW, GEM_DBW64); 24078c2ecf20Sopenharmony_ci case 1: 24088c2ecf20Sopenharmony_ci default: 24098c2ecf20Sopenharmony_ci return GEM_BF(DBW, GEM_DBW32); 24108c2ecf20Sopenharmony_ci } 24118c2ecf20Sopenharmony_ci} 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci/* Configure the receive DMA engine 24148c2ecf20Sopenharmony_ci * - use the correct receive buffer size 24158c2ecf20Sopenharmony_ci * - set best burst length for DMA operations 24168c2ecf20Sopenharmony_ci * (if not supported by FIFO, it will fallback to default) 24178c2ecf20Sopenharmony_ci * - set both rx/tx packet buffers to full memory size 24188c2ecf20Sopenharmony_ci * These are configurable parameters for GEM. 24198c2ecf20Sopenharmony_ci */ 24208c2ecf20Sopenharmony_cistatic void macb_configure_dma(struct macb *bp) 24218c2ecf20Sopenharmony_ci{ 24228c2ecf20Sopenharmony_ci struct macb_queue *queue; 24238c2ecf20Sopenharmony_ci u32 buffer_size; 24248c2ecf20Sopenharmony_ci unsigned int q; 24258c2ecf20Sopenharmony_ci u32 dmacfg; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci buffer_size = bp->rx_buffer_size / RX_BUFFER_MULTIPLE; 24288c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) { 24298c2ecf20Sopenharmony_ci dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); 24308c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 24318c2ecf20Sopenharmony_ci if (q) 24328c2ecf20Sopenharmony_ci queue_writel(queue, RBQS, buffer_size); 24338c2ecf20Sopenharmony_ci else 24348c2ecf20Sopenharmony_ci dmacfg |= GEM_BF(RXBS, buffer_size); 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci if (bp->dma_burst_length) 24378c2ecf20Sopenharmony_ci dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg); 24388c2ecf20Sopenharmony_ci dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); 24398c2ecf20Sopenharmony_ci dmacfg &= ~GEM_BIT(ENDIA_PKT); 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci if (bp->native_io) 24428c2ecf20Sopenharmony_ci dmacfg &= ~GEM_BIT(ENDIA_DESC); 24438c2ecf20Sopenharmony_ci else 24448c2ecf20Sopenharmony_ci dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */ 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci if (bp->dev->features & NETIF_F_HW_CSUM) 24478c2ecf20Sopenharmony_ci dmacfg |= GEM_BIT(TXCOEN); 24488c2ecf20Sopenharmony_ci else 24498c2ecf20Sopenharmony_ci dmacfg &= ~GEM_BIT(TXCOEN); 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci dmacfg &= ~GEM_BIT(ADDR64); 24528c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 24538c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) 24548c2ecf20Sopenharmony_ci dmacfg |= GEM_BIT(ADDR64); 24558c2ecf20Sopenharmony_ci#endif 24568c2ecf20Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP 24578c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_PTP) 24588c2ecf20Sopenharmony_ci dmacfg |= GEM_BIT(RXEXT) | GEM_BIT(TXEXT); 24598c2ecf20Sopenharmony_ci#endif 24608c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", 24618c2ecf20Sopenharmony_ci dmacfg); 24628c2ecf20Sopenharmony_ci gem_writel(bp, DMACFG, dmacfg); 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci} 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_cistatic void macb_init_hw(struct macb *bp) 24678c2ecf20Sopenharmony_ci{ 24688c2ecf20Sopenharmony_ci u32 config; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci macb_reset_hw(bp); 24718c2ecf20Sopenharmony_ci macb_set_hwaddr(bp); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci config = macb_mdc_clk_div(bp); 24748c2ecf20Sopenharmony_ci config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ 24758c2ecf20Sopenharmony_ci config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ 24768c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_JUMBO) 24778c2ecf20Sopenharmony_ci config |= MACB_BIT(JFRAME); /* Enable jumbo frames */ 24788c2ecf20Sopenharmony_ci else 24798c2ecf20Sopenharmony_ci config |= MACB_BIT(BIG); /* Receive oversized frames */ 24808c2ecf20Sopenharmony_ci if (bp->dev->flags & IFF_PROMISC) 24818c2ecf20Sopenharmony_ci config |= MACB_BIT(CAF); /* Copy All Frames */ 24828c2ecf20Sopenharmony_ci else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM) 24838c2ecf20Sopenharmony_ci config |= GEM_BIT(RXCOEN); 24848c2ecf20Sopenharmony_ci if (!(bp->dev->flags & IFF_BROADCAST)) 24858c2ecf20Sopenharmony_ci config |= MACB_BIT(NBC); /* No BroadCast */ 24868c2ecf20Sopenharmony_ci config |= macb_dbw(bp); 24878c2ecf20Sopenharmony_ci macb_writel(bp, NCFGR, config); 24888c2ecf20Sopenharmony_ci if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len) 24898c2ecf20Sopenharmony_ci gem_writel(bp, JML, bp->jumbo_max_len); 24908c2ecf20Sopenharmony_ci bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK; 24918c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_JUMBO) 24928c2ecf20Sopenharmony_ci bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci macb_configure_dma(bp); 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci/* The hash address register is 64 bits long and takes up two 24988c2ecf20Sopenharmony_ci * locations in the memory map. The least significant bits are stored 24998c2ecf20Sopenharmony_ci * in EMAC_HSL and the most significant bits in EMAC_HSH. 25008c2ecf20Sopenharmony_ci * 25018c2ecf20Sopenharmony_ci * The unicast hash enable and the multicast hash enable bits in the 25028c2ecf20Sopenharmony_ci * network configuration register enable the reception of hash matched 25038c2ecf20Sopenharmony_ci * frames. The destination address is reduced to a 6 bit index into 25048c2ecf20Sopenharmony_ci * the 64 bit hash register using the following hash function. The 25058c2ecf20Sopenharmony_ci * hash function is an exclusive or of every sixth bit of the 25068c2ecf20Sopenharmony_ci * destination address. 25078c2ecf20Sopenharmony_ci * 25088c2ecf20Sopenharmony_ci * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] 25098c2ecf20Sopenharmony_ci * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] 25108c2ecf20Sopenharmony_ci * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] 25118c2ecf20Sopenharmony_ci * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] 25128c2ecf20Sopenharmony_ci * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] 25138c2ecf20Sopenharmony_ci * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] 25148c2ecf20Sopenharmony_ci * 25158c2ecf20Sopenharmony_ci * da[0] represents the least significant bit of the first byte 25168c2ecf20Sopenharmony_ci * received, that is, the multicast/unicast indicator, and da[47] 25178c2ecf20Sopenharmony_ci * represents the most significant bit of the last byte received. If 25188c2ecf20Sopenharmony_ci * the hash index, hi[n], points to a bit that is set in the hash 25198c2ecf20Sopenharmony_ci * register then the frame will be matched according to whether the 25208c2ecf20Sopenharmony_ci * frame is multicast or unicast. A multicast match will be signalled 25218c2ecf20Sopenharmony_ci * if the multicast hash enable bit is set, da[0] is 1 and the hash 25228c2ecf20Sopenharmony_ci * index points to a bit set in the hash register. A unicast match 25238c2ecf20Sopenharmony_ci * will be signalled if the unicast hash enable bit is set, da[0] is 0 25248c2ecf20Sopenharmony_ci * and the hash index points to a bit set in the hash register. To 25258c2ecf20Sopenharmony_ci * receive all multicast frames, the hash register should be set with 25268c2ecf20Sopenharmony_ci * all ones and the multicast hash enable bit should be set in the 25278c2ecf20Sopenharmony_ci * network configuration register. 25288c2ecf20Sopenharmony_ci */ 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_cistatic inline int hash_bit_value(int bitnr, __u8 *addr) 25318c2ecf20Sopenharmony_ci{ 25328c2ecf20Sopenharmony_ci if (addr[bitnr / 8] & (1 << (bitnr % 8))) 25338c2ecf20Sopenharmony_ci return 1; 25348c2ecf20Sopenharmony_ci return 0; 25358c2ecf20Sopenharmony_ci} 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci/* Return the hash index value for the specified address. */ 25388c2ecf20Sopenharmony_cistatic int hash_get_index(__u8 *addr) 25398c2ecf20Sopenharmony_ci{ 25408c2ecf20Sopenharmony_ci int i, j, bitval; 25418c2ecf20Sopenharmony_ci int hash_index = 0; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci for (j = 0; j < 6; j++) { 25448c2ecf20Sopenharmony_ci for (i = 0, bitval = 0; i < 8; i++) 25458c2ecf20Sopenharmony_ci bitval ^= hash_bit_value(i * 6 + j, addr); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci hash_index |= (bitval << j); 25488c2ecf20Sopenharmony_ci } 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci return hash_index; 25518c2ecf20Sopenharmony_ci} 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci/* Add multicast addresses to the internal multicast-hash table. */ 25548c2ecf20Sopenharmony_cistatic void macb_sethashtable(struct net_device *dev) 25558c2ecf20Sopenharmony_ci{ 25568c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 25578c2ecf20Sopenharmony_ci unsigned long mc_filter[2]; 25588c2ecf20Sopenharmony_ci unsigned int bitnr; 25598c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci mc_filter[0] = 0; 25628c2ecf20Sopenharmony_ci mc_filter[1] = 0; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 25658c2ecf20Sopenharmony_ci bitnr = hash_get_index(ha->addr); 25668c2ecf20Sopenharmony_ci mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); 25678c2ecf20Sopenharmony_ci } 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, HRB, mc_filter[0]); 25708c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, HRT, mc_filter[1]); 25718c2ecf20Sopenharmony_ci} 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci/* Enable/Disable promiscuous and multicast modes. */ 25748c2ecf20Sopenharmony_cistatic void macb_set_rx_mode(struct net_device *dev) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci unsigned long cfg; 25778c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci cfg = macb_readl(bp, NCFGR); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 25828c2ecf20Sopenharmony_ci /* Enable promiscuous mode */ 25838c2ecf20Sopenharmony_ci cfg |= MACB_BIT(CAF); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci /* Disable RX checksum offload */ 25868c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) 25878c2ecf20Sopenharmony_ci cfg &= ~GEM_BIT(RXCOEN); 25888c2ecf20Sopenharmony_ci } else { 25898c2ecf20Sopenharmony_ci /* Disable promiscuous mode */ 25908c2ecf20Sopenharmony_ci cfg &= ~MACB_BIT(CAF); 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci /* Enable RX checksum offload only if requested */ 25938c2ecf20Sopenharmony_ci if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM) 25948c2ecf20Sopenharmony_ci cfg |= GEM_BIT(RXCOEN); 25958c2ecf20Sopenharmony_ci } 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) { 25988c2ecf20Sopenharmony_ci /* Enable all multicast mode */ 25998c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, HRB, -1); 26008c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, HRT, -1); 26018c2ecf20Sopenharmony_ci cfg |= MACB_BIT(NCFGR_MTI); 26028c2ecf20Sopenharmony_ci } else if (!netdev_mc_empty(dev)) { 26038c2ecf20Sopenharmony_ci /* Enable specific multicasts */ 26048c2ecf20Sopenharmony_ci macb_sethashtable(dev); 26058c2ecf20Sopenharmony_ci cfg |= MACB_BIT(NCFGR_MTI); 26068c2ecf20Sopenharmony_ci } else if (dev->flags & (~IFF_ALLMULTI)) { 26078c2ecf20Sopenharmony_ci /* Disable all multicast mode */ 26088c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, HRB, 0); 26098c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, HRT, 0); 26108c2ecf20Sopenharmony_ci cfg &= ~MACB_BIT(NCFGR_MTI); 26118c2ecf20Sopenharmony_ci } 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci macb_writel(bp, NCFGR, cfg); 26148c2ecf20Sopenharmony_ci} 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_cistatic int macb_open(struct net_device *dev) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN; 26198c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 26208c2ecf20Sopenharmony_ci struct macb_queue *queue; 26218c2ecf20Sopenharmony_ci unsigned int q; 26228c2ecf20Sopenharmony_ci int err; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci netdev_dbg(bp->dev, "open\n"); 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(&bp->pdev->dev); 26278c2ecf20Sopenharmony_ci if (err < 0) 26288c2ecf20Sopenharmony_ci goto pm_exit; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci /* RX buffers initialization */ 26318c2ecf20Sopenharmony_ci macb_init_rx_buffer_size(bp, bufsz); 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci err = macb_alloc_consistent(bp); 26348c2ecf20Sopenharmony_ci if (err) { 26358c2ecf20Sopenharmony_ci netdev_err(dev, "Unable to allocate DMA memory (error %d)\n", 26368c2ecf20Sopenharmony_ci err); 26378c2ecf20Sopenharmony_ci goto pm_exit; 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 26418c2ecf20Sopenharmony_ci napi_enable(&queue->napi); 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci macb_init_hw(bp); 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci err = macb_phylink_connect(bp); 26468c2ecf20Sopenharmony_ci if (err) 26478c2ecf20Sopenharmony_ci goto reset_hw; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci netif_tx_start_all_queues(dev); 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci if (bp->ptp_info) 26528c2ecf20Sopenharmony_ci bp->ptp_info->ptp_init(dev); 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci return 0; 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_cireset_hw: 26578c2ecf20Sopenharmony_ci macb_reset_hw(bp); 26588c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 26598c2ecf20Sopenharmony_ci napi_disable(&queue->napi); 26608c2ecf20Sopenharmony_ci macb_free_consistent(bp); 26618c2ecf20Sopenharmony_cipm_exit: 26628c2ecf20Sopenharmony_ci pm_runtime_put_sync(&bp->pdev->dev); 26638c2ecf20Sopenharmony_ci return err; 26648c2ecf20Sopenharmony_ci} 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_cistatic int macb_close(struct net_device *dev) 26678c2ecf20Sopenharmony_ci{ 26688c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 26698c2ecf20Sopenharmony_ci struct macb_queue *queue; 26708c2ecf20Sopenharmony_ci unsigned long flags; 26718c2ecf20Sopenharmony_ci unsigned int q; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(dev); 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 26768c2ecf20Sopenharmony_ci napi_disable(&queue->napi); 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci phylink_stop(bp->phylink); 26798c2ecf20Sopenharmony_ci phylink_disconnect_phy(bp->phylink); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 26828c2ecf20Sopenharmony_ci macb_reset_hw(bp); 26838c2ecf20Sopenharmony_ci netif_carrier_off(dev); 26848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci macb_free_consistent(bp); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci if (bp->ptp_info) 26898c2ecf20Sopenharmony_ci bp->ptp_info->ptp_remove(dev); 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci pm_runtime_put(&bp->pdev->dev); 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci return 0; 26948c2ecf20Sopenharmony_ci} 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_cistatic int macb_change_mtu(struct net_device *dev, int new_mtu) 26978c2ecf20Sopenharmony_ci{ 26988c2ecf20Sopenharmony_ci if (netif_running(dev)) 26998c2ecf20Sopenharmony_ci return -EBUSY; 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci return 0; 27048c2ecf20Sopenharmony_ci} 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_cistatic void gem_update_stats(struct macb *bp) 27078c2ecf20Sopenharmony_ci{ 27088c2ecf20Sopenharmony_ci struct macb_queue *queue; 27098c2ecf20Sopenharmony_ci unsigned int i, q, idx; 27108c2ecf20Sopenharmony_ci unsigned long *stat; 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci u32 *p = &bp->hw_stats.gem.tx_octets_31_0; 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { 27158c2ecf20Sopenharmony_ci u32 offset = gem_statistics[i].offset; 27168c2ecf20Sopenharmony_ci u64 val = bp->macb_reg_readl(bp, offset); 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci bp->ethtool_stats[i] += val; 27198c2ecf20Sopenharmony_ci *p += val; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { 27228c2ecf20Sopenharmony_ci /* Add GEM_OCTTXH, GEM_OCTRXH */ 27238c2ecf20Sopenharmony_ci val = bp->macb_reg_readl(bp, offset + 4); 27248c2ecf20Sopenharmony_ci bp->ethtool_stats[i] += ((u64)val) << 32; 27258c2ecf20Sopenharmony_ci *(++p) += val; 27268c2ecf20Sopenharmony_ci } 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci idx = GEM_STATS_LEN; 27308c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) 27318c2ecf20Sopenharmony_ci for (i = 0, stat = &queue->stats.first; i < QUEUE_STATS_LEN; ++i, ++stat) 27328c2ecf20Sopenharmony_ci bp->ethtool_stats[idx++] = *stat; 27338c2ecf20Sopenharmony_ci} 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_cistatic struct net_device_stats *gem_get_stats(struct macb *bp) 27368c2ecf20Sopenharmony_ci{ 27378c2ecf20Sopenharmony_ci struct gem_stats *hwstat = &bp->hw_stats.gem; 27388c2ecf20Sopenharmony_ci struct net_device_stats *nstat = &bp->dev->stats; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 27418c2ecf20Sopenharmony_ci return nstat; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci gem_update_stats(bp); 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors + 27468c2ecf20Sopenharmony_ci hwstat->rx_alignment_errors + 27478c2ecf20Sopenharmony_ci hwstat->rx_resource_errors + 27488c2ecf20Sopenharmony_ci hwstat->rx_overruns + 27498c2ecf20Sopenharmony_ci hwstat->rx_oversize_frames + 27508c2ecf20Sopenharmony_ci hwstat->rx_jabbers + 27518c2ecf20Sopenharmony_ci hwstat->rx_undersized_frames + 27528c2ecf20Sopenharmony_ci hwstat->rx_length_field_frame_errors); 27538c2ecf20Sopenharmony_ci nstat->tx_errors = (hwstat->tx_late_collisions + 27548c2ecf20Sopenharmony_ci hwstat->tx_excessive_collisions + 27558c2ecf20Sopenharmony_ci hwstat->tx_underrun + 27568c2ecf20Sopenharmony_ci hwstat->tx_carrier_sense_errors); 27578c2ecf20Sopenharmony_ci nstat->multicast = hwstat->rx_multicast_frames; 27588c2ecf20Sopenharmony_ci nstat->collisions = (hwstat->tx_single_collision_frames + 27598c2ecf20Sopenharmony_ci hwstat->tx_multiple_collision_frames + 27608c2ecf20Sopenharmony_ci hwstat->tx_excessive_collisions); 27618c2ecf20Sopenharmony_ci nstat->rx_length_errors = (hwstat->rx_oversize_frames + 27628c2ecf20Sopenharmony_ci hwstat->rx_jabbers + 27638c2ecf20Sopenharmony_ci hwstat->rx_undersized_frames + 27648c2ecf20Sopenharmony_ci hwstat->rx_length_field_frame_errors); 27658c2ecf20Sopenharmony_ci nstat->rx_over_errors = hwstat->rx_resource_errors; 27668c2ecf20Sopenharmony_ci nstat->rx_crc_errors = hwstat->rx_frame_check_sequence_errors; 27678c2ecf20Sopenharmony_ci nstat->rx_frame_errors = hwstat->rx_alignment_errors; 27688c2ecf20Sopenharmony_ci nstat->rx_fifo_errors = hwstat->rx_overruns; 27698c2ecf20Sopenharmony_ci nstat->tx_aborted_errors = hwstat->tx_excessive_collisions; 27708c2ecf20Sopenharmony_ci nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors; 27718c2ecf20Sopenharmony_ci nstat->tx_fifo_errors = hwstat->tx_underrun; 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci return nstat; 27748c2ecf20Sopenharmony_ci} 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_cistatic void gem_get_ethtool_stats(struct net_device *dev, 27778c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci struct macb *bp; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 27828c2ecf20Sopenharmony_ci gem_update_stats(bp); 27838c2ecf20Sopenharmony_ci memcpy(data, &bp->ethtool_stats, sizeof(u64) 27848c2ecf20Sopenharmony_ci * (GEM_STATS_LEN + QUEUE_STATS_LEN * MACB_MAX_QUEUES)); 27858c2ecf20Sopenharmony_ci} 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_cistatic int gem_get_sset_count(struct net_device *dev, int sset) 27888c2ecf20Sopenharmony_ci{ 27898c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci switch (sset) { 27928c2ecf20Sopenharmony_ci case ETH_SS_STATS: 27938c2ecf20Sopenharmony_ci return GEM_STATS_LEN + bp->num_queues * QUEUE_STATS_LEN; 27948c2ecf20Sopenharmony_ci default: 27958c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci} 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_cistatic void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) 28008c2ecf20Sopenharmony_ci{ 28018c2ecf20Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 28028c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 28038c2ecf20Sopenharmony_ci struct macb_queue *queue; 28048c2ecf20Sopenharmony_ci unsigned int i; 28058c2ecf20Sopenharmony_ci unsigned int q; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci switch (sset) { 28088c2ecf20Sopenharmony_ci case ETH_SS_STATS: 28098c2ecf20Sopenharmony_ci for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN) 28108c2ecf20Sopenharmony_ci memcpy(p, gem_statistics[i].stat_string, 28118c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { 28148c2ecf20Sopenharmony_ci for (i = 0; i < QUEUE_STATS_LEN; i++, p += ETH_GSTRING_LEN) { 28158c2ecf20Sopenharmony_ci snprintf(stat_string, ETH_GSTRING_LEN, "q%d_%s", 28168c2ecf20Sopenharmony_ci q, queue_statistics[i].stat_string); 28178c2ecf20Sopenharmony_ci memcpy(p, stat_string, ETH_GSTRING_LEN); 28188c2ecf20Sopenharmony_ci } 28198c2ecf20Sopenharmony_ci } 28208c2ecf20Sopenharmony_ci break; 28218c2ecf20Sopenharmony_ci } 28228c2ecf20Sopenharmony_ci} 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_cistatic struct net_device_stats *macb_get_stats(struct net_device *dev) 28258c2ecf20Sopenharmony_ci{ 28268c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 28278c2ecf20Sopenharmony_ci struct net_device_stats *nstat = &bp->dev->stats; 28288c2ecf20Sopenharmony_ci struct macb_stats *hwstat = &bp->hw_stats.macb; 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) 28318c2ecf20Sopenharmony_ci return gem_get_stats(bp); 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci /* read stats from hardware */ 28348c2ecf20Sopenharmony_ci macb_update_stats(bp); 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci /* Convert HW stats into netdevice stats */ 28378c2ecf20Sopenharmony_ci nstat->rx_errors = (hwstat->rx_fcs_errors + 28388c2ecf20Sopenharmony_ci hwstat->rx_align_errors + 28398c2ecf20Sopenharmony_ci hwstat->rx_resource_errors + 28408c2ecf20Sopenharmony_ci hwstat->rx_overruns + 28418c2ecf20Sopenharmony_ci hwstat->rx_oversize_pkts + 28428c2ecf20Sopenharmony_ci hwstat->rx_jabbers + 28438c2ecf20Sopenharmony_ci hwstat->rx_undersize_pkts + 28448c2ecf20Sopenharmony_ci hwstat->rx_length_mismatch); 28458c2ecf20Sopenharmony_ci nstat->tx_errors = (hwstat->tx_late_cols + 28468c2ecf20Sopenharmony_ci hwstat->tx_excessive_cols + 28478c2ecf20Sopenharmony_ci hwstat->tx_underruns + 28488c2ecf20Sopenharmony_ci hwstat->tx_carrier_errors + 28498c2ecf20Sopenharmony_ci hwstat->sqe_test_errors); 28508c2ecf20Sopenharmony_ci nstat->collisions = (hwstat->tx_single_cols + 28518c2ecf20Sopenharmony_ci hwstat->tx_multiple_cols + 28528c2ecf20Sopenharmony_ci hwstat->tx_excessive_cols); 28538c2ecf20Sopenharmony_ci nstat->rx_length_errors = (hwstat->rx_oversize_pkts + 28548c2ecf20Sopenharmony_ci hwstat->rx_jabbers + 28558c2ecf20Sopenharmony_ci hwstat->rx_undersize_pkts + 28568c2ecf20Sopenharmony_ci hwstat->rx_length_mismatch); 28578c2ecf20Sopenharmony_ci nstat->rx_over_errors = hwstat->rx_resource_errors + 28588c2ecf20Sopenharmony_ci hwstat->rx_overruns; 28598c2ecf20Sopenharmony_ci nstat->rx_crc_errors = hwstat->rx_fcs_errors; 28608c2ecf20Sopenharmony_ci nstat->rx_frame_errors = hwstat->rx_align_errors; 28618c2ecf20Sopenharmony_ci nstat->rx_fifo_errors = hwstat->rx_overruns; 28628c2ecf20Sopenharmony_ci /* XXX: What does "missed" mean? */ 28638c2ecf20Sopenharmony_ci nstat->tx_aborted_errors = hwstat->tx_excessive_cols; 28648c2ecf20Sopenharmony_ci nstat->tx_carrier_errors = hwstat->tx_carrier_errors; 28658c2ecf20Sopenharmony_ci nstat->tx_fifo_errors = hwstat->tx_underruns; 28668c2ecf20Sopenharmony_ci /* Don't know about heartbeat or window errors... */ 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci return nstat; 28698c2ecf20Sopenharmony_ci} 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_cistatic int macb_get_regs_len(struct net_device *netdev) 28728c2ecf20Sopenharmony_ci{ 28738c2ecf20Sopenharmony_ci return MACB_GREGS_NBR * sizeof(u32); 28748c2ecf20Sopenharmony_ci} 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_cistatic void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs, 28778c2ecf20Sopenharmony_ci void *p) 28788c2ecf20Sopenharmony_ci{ 28798c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 28808c2ecf20Sopenharmony_ci unsigned int tail, head; 28818c2ecf20Sopenharmony_ci u32 *regs_buff = p; 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1)) 28848c2ecf20Sopenharmony_ci | MACB_GREGS_VERSION; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci tail = macb_tx_ring_wrap(bp, bp->queues[0].tx_tail); 28878c2ecf20Sopenharmony_ci head = macb_tx_ring_wrap(bp, bp->queues[0].tx_head); 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci regs_buff[0] = macb_readl(bp, NCR); 28908c2ecf20Sopenharmony_ci regs_buff[1] = macb_or_gem_readl(bp, NCFGR); 28918c2ecf20Sopenharmony_ci regs_buff[2] = macb_readl(bp, NSR); 28928c2ecf20Sopenharmony_ci regs_buff[3] = macb_readl(bp, TSR); 28938c2ecf20Sopenharmony_ci regs_buff[4] = macb_readl(bp, RBQP); 28948c2ecf20Sopenharmony_ci regs_buff[5] = macb_readl(bp, TBQP); 28958c2ecf20Sopenharmony_ci regs_buff[6] = macb_readl(bp, RSR); 28968c2ecf20Sopenharmony_ci regs_buff[7] = macb_readl(bp, IMR); 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci regs_buff[8] = tail; 28998c2ecf20Sopenharmony_ci regs_buff[9] = head; 29008c2ecf20Sopenharmony_ci regs_buff[10] = macb_tx_dma(&bp->queues[0], tail); 29018c2ecf20Sopenharmony_ci regs_buff[11] = macb_tx_dma(&bp->queues[0], head); 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) 29048c2ecf20Sopenharmony_ci regs_buff[12] = macb_or_gem_readl(bp, USRIO); 29058c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) 29068c2ecf20Sopenharmony_ci regs_buff[13] = gem_readl(bp, DMACFG); 29078c2ecf20Sopenharmony_ci} 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_cistatic void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 29108c2ecf20Sopenharmony_ci{ 29118c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) { 29148c2ecf20Sopenharmony_ci phylink_ethtool_get_wol(bp->phylink, wol); 29158c2ecf20Sopenharmony_ci wol->supported |= WAKE_MAGIC; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci if (bp->wol & MACB_WOL_ENABLED) 29188c2ecf20Sopenharmony_ci wol->wolopts |= WAKE_MAGIC; 29198c2ecf20Sopenharmony_ci } 29208c2ecf20Sopenharmony_ci} 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_cistatic int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 29238c2ecf20Sopenharmony_ci{ 29248c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 29258c2ecf20Sopenharmony_ci int ret; 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci /* Pass the order to phylink layer */ 29288c2ecf20Sopenharmony_ci ret = phylink_ethtool_set_wol(bp->phylink, wol); 29298c2ecf20Sopenharmony_ci /* Don't manage WoL on MAC if handled by the PHY 29308c2ecf20Sopenharmony_ci * or if there's a failure in talking to the PHY 29318c2ecf20Sopenharmony_ci */ 29328c2ecf20Sopenharmony_ci if (!ret || ret != -EOPNOTSUPP) 29338c2ecf20Sopenharmony_ci return ret; 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) || 29368c2ecf20Sopenharmony_ci (wol->wolopts & ~WAKE_MAGIC)) 29378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) 29408c2ecf20Sopenharmony_ci bp->wol |= MACB_WOL_ENABLED; 29418c2ecf20Sopenharmony_ci else 29428c2ecf20Sopenharmony_ci bp->wol &= ~MACB_WOL_ENABLED; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci device_set_wakeup_enable(&bp->pdev->dev, bp->wol & MACB_WOL_ENABLED); 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci return 0; 29478c2ecf20Sopenharmony_ci} 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_cistatic int macb_get_link_ksettings(struct net_device *netdev, 29508c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *kset) 29518c2ecf20Sopenharmony_ci{ 29528c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_get(bp->phylink, kset); 29558c2ecf20Sopenharmony_ci} 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_cistatic int macb_set_link_ksettings(struct net_device *netdev, 29588c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *kset) 29598c2ecf20Sopenharmony_ci{ 29608c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_set(bp->phylink, kset); 29638c2ecf20Sopenharmony_ci} 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_cistatic void macb_get_ringparam(struct net_device *netdev, 29668c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 29678c2ecf20Sopenharmony_ci{ 29688c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci ring->rx_max_pending = MAX_RX_RING_SIZE; 29718c2ecf20Sopenharmony_ci ring->tx_max_pending = MAX_TX_RING_SIZE; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci ring->rx_pending = bp->rx_ring_size; 29748c2ecf20Sopenharmony_ci ring->tx_pending = bp->tx_ring_size; 29758c2ecf20Sopenharmony_ci} 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_cistatic int macb_set_ringparam(struct net_device *netdev, 29788c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 29798c2ecf20Sopenharmony_ci{ 29808c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 29818c2ecf20Sopenharmony_ci u32 new_rx_size, new_tx_size; 29828c2ecf20Sopenharmony_ci unsigned int reset = 0; 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 29858c2ecf20Sopenharmony_ci return -EINVAL; 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci new_rx_size = clamp_t(u32, ring->rx_pending, 29888c2ecf20Sopenharmony_ci MIN_RX_RING_SIZE, MAX_RX_RING_SIZE); 29898c2ecf20Sopenharmony_ci new_rx_size = roundup_pow_of_two(new_rx_size); 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci new_tx_size = clamp_t(u32, ring->tx_pending, 29928c2ecf20Sopenharmony_ci MIN_TX_RING_SIZE, MAX_TX_RING_SIZE); 29938c2ecf20Sopenharmony_ci new_tx_size = roundup_pow_of_two(new_tx_size); 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci if ((new_tx_size == bp->tx_ring_size) && 29968c2ecf20Sopenharmony_ci (new_rx_size == bp->rx_ring_size)) { 29978c2ecf20Sopenharmony_ci /* nothing to do */ 29988c2ecf20Sopenharmony_ci return 0; 29998c2ecf20Sopenharmony_ci } 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 30028c2ecf20Sopenharmony_ci reset = 1; 30038c2ecf20Sopenharmony_ci macb_close(bp->dev); 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci bp->rx_ring_size = new_rx_size; 30078c2ecf20Sopenharmony_ci bp->tx_ring_size = new_tx_size; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci if (reset) 30108c2ecf20Sopenharmony_ci macb_open(bp->dev); 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci return 0; 30138c2ecf20Sopenharmony_ci} 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP 30168c2ecf20Sopenharmony_cistatic unsigned int gem_get_tsu_rate(struct macb *bp) 30178c2ecf20Sopenharmony_ci{ 30188c2ecf20Sopenharmony_ci struct clk *tsu_clk; 30198c2ecf20Sopenharmony_ci unsigned int tsu_rate; 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci tsu_clk = devm_clk_get(&bp->pdev->dev, "tsu_clk"); 30228c2ecf20Sopenharmony_ci if (!IS_ERR(tsu_clk)) 30238c2ecf20Sopenharmony_ci tsu_rate = clk_get_rate(tsu_clk); 30248c2ecf20Sopenharmony_ci /* try pclk instead */ 30258c2ecf20Sopenharmony_ci else if (!IS_ERR(bp->pclk)) { 30268c2ecf20Sopenharmony_ci tsu_clk = bp->pclk; 30278c2ecf20Sopenharmony_ci tsu_rate = clk_get_rate(tsu_clk); 30288c2ecf20Sopenharmony_ci } else 30298c2ecf20Sopenharmony_ci return -ENOTSUPP; 30308c2ecf20Sopenharmony_ci return tsu_rate; 30318c2ecf20Sopenharmony_ci} 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_cistatic s32 gem_get_ptp_max_adj(void) 30348c2ecf20Sopenharmony_ci{ 30358c2ecf20Sopenharmony_ci return 64000000; 30368c2ecf20Sopenharmony_ci} 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_cistatic int gem_get_ts_info(struct net_device *dev, 30398c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 30408c2ecf20Sopenharmony_ci{ 30418c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0) { 30448c2ecf20Sopenharmony_ci ethtool_op_get_ts_info(dev, info); 30458c2ecf20Sopenharmony_ci return 0; 30468c2ecf20Sopenharmony_ci } 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci info->so_timestamping = 30498c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_SOFTWARE | 30508c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 30518c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 30528c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 30538c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 30548c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 30558c2ecf20Sopenharmony_ci info->tx_types = 30568c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_ONESTEP_SYNC) | 30578c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_OFF) | 30588c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_ON); 30598c2ecf20Sopenharmony_ci info->rx_filters = 30608c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_NONE) | 30618c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_ALL); 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci info->phc_index = bp->ptp_clock ? ptp_clock_index(bp->ptp_clock) : -1; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci return 0; 30668c2ecf20Sopenharmony_ci} 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_cistatic struct macb_ptp_info gem_ptp_info = { 30698c2ecf20Sopenharmony_ci .ptp_init = gem_ptp_init, 30708c2ecf20Sopenharmony_ci .ptp_remove = gem_ptp_remove, 30718c2ecf20Sopenharmony_ci .get_ptp_max_adj = gem_get_ptp_max_adj, 30728c2ecf20Sopenharmony_ci .get_tsu_rate = gem_get_tsu_rate, 30738c2ecf20Sopenharmony_ci .get_ts_info = gem_get_ts_info, 30748c2ecf20Sopenharmony_ci .get_hwtst = gem_get_hwtst, 30758c2ecf20Sopenharmony_ci .set_hwtst = gem_set_hwtst, 30768c2ecf20Sopenharmony_ci}; 30778c2ecf20Sopenharmony_ci#endif 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_cistatic int macb_get_ts_info(struct net_device *netdev, 30808c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 30818c2ecf20Sopenharmony_ci{ 30828c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci if (bp->ptp_info) 30858c2ecf20Sopenharmony_ci return bp->ptp_info->get_ts_info(netdev, info); 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci return ethtool_op_get_ts_info(netdev, info); 30888c2ecf20Sopenharmony_ci} 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_cistatic void gem_enable_flow_filters(struct macb *bp, bool enable) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci struct net_device *netdev = bp->dev; 30938c2ecf20Sopenharmony_ci struct ethtool_rx_fs_item *item; 30948c2ecf20Sopenharmony_ci u32 t2_scr; 30958c2ecf20Sopenharmony_ci int num_t2_scr; 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci if (!(netdev->features & NETIF_F_NTUPLE)) 30988c2ecf20Sopenharmony_ci return; 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci num_t2_scr = GEM_BFEXT(T2SCR, gem_readl(bp, DCFG8)); 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci list_for_each_entry(item, &bp->rx_fs_list.list, list) { 31038c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fs = &item->fs; 31048c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *tp4sp_m; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci if (fs->location >= num_t2_scr) 31078c2ecf20Sopenharmony_ci continue; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci t2_scr = gem_readl_n(bp, SCRT2, fs->location); 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci /* enable/disable screener regs for the flow entry */ 31128c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(ETHTEN, enable, t2_scr); 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci /* only enable fields with no masking */ 31158c2ecf20Sopenharmony_ci tp4sp_m = &(fs->m_u.tcp_ip4_spec); 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci if (enable && (tp4sp_m->ip4src == 0xFFFFFFFF)) 31188c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPAEN, 1, t2_scr); 31198c2ecf20Sopenharmony_ci else 31208c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPAEN, 0, t2_scr); 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci if (enable && (tp4sp_m->ip4dst == 0xFFFFFFFF)) 31238c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPBEN, 1, t2_scr); 31248c2ecf20Sopenharmony_ci else 31258c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPBEN, 0, t2_scr); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci if (enable && ((tp4sp_m->psrc == 0xFFFF) || (tp4sp_m->pdst == 0xFFFF))) 31288c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPCEN, 1, t2_scr); 31298c2ecf20Sopenharmony_ci else 31308c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPCEN, 0, t2_scr); 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci gem_writel_n(bp, SCRT2, fs->location, t2_scr); 31338c2ecf20Sopenharmony_ci } 31348c2ecf20Sopenharmony_ci} 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_cistatic void gem_prog_cmp_regs(struct macb *bp, struct ethtool_rx_flow_spec *fs) 31378c2ecf20Sopenharmony_ci{ 31388c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *tp4sp_v, *tp4sp_m; 31398c2ecf20Sopenharmony_ci uint16_t index = fs->location; 31408c2ecf20Sopenharmony_ci u32 w0, w1, t2_scr; 31418c2ecf20Sopenharmony_ci bool cmp_a = false; 31428c2ecf20Sopenharmony_ci bool cmp_b = false; 31438c2ecf20Sopenharmony_ci bool cmp_c = false; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci if (!macb_is_gem(bp)) 31468c2ecf20Sopenharmony_ci return; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci tp4sp_v = &(fs->h_u.tcp_ip4_spec); 31498c2ecf20Sopenharmony_ci tp4sp_m = &(fs->m_u.tcp_ip4_spec); 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci /* ignore field if any masking set */ 31528c2ecf20Sopenharmony_ci if (tp4sp_m->ip4src == 0xFFFFFFFF) { 31538c2ecf20Sopenharmony_ci /* 1st compare reg - IP source address */ 31548c2ecf20Sopenharmony_ci w0 = 0; 31558c2ecf20Sopenharmony_ci w1 = 0; 31568c2ecf20Sopenharmony_ci w0 = tp4sp_v->ip4src; 31578c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2DISMSK, 1, w1); /* 32-bit compare */ 31588c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2CMPOFST, GEM_T2COMPOFST_ETYPE, w1); 31598c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2OFST, ETYPE_SRCIP_OFFSET, w1); 31608c2ecf20Sopenharmony_ci gem_writel_n(bp, T2CMPW0, T2CMP_OFST(GEM_IP4SRC_CMP(index)), w0); 31618c2ecf20Sopenharmony_ci gem_writel_n(bp, T2CMPW1, T2CMP_OFST(GEM_IP4SRC_CMP(index)), w1); 31628c2ecf20Sopenharmony_ci cmp_a = true; 31638c2ecf20Sopenharmony_ci } 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci /* ignore field if any masking set */ 31668c2ecf20Sopenharmony_ci if (tp4sp_m->ip4dst == 0xFFFFFFFF) { 31678c2ecf20Sopenharmony_ci /* 2nd compare reg - IP destination address */ 31688c2ecf20Sopenharmony_ci w0 = 0; 31698c2ecf20Sopenharmony_ci w1 = 0; 31708c2ecf20Sopenharmony_ci w0 = tp4sp_v->ip4dst; 31718c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2DISMSK, 1, w1); /* 32-bit compare */ 31728c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2CMPOFST, GEM_T2COMPOFST_ETYPE, w1); 31738c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2OFST, ETYPE_DSTIP_OFFSET, w1); 31748c2ecf20Sopenharmony_ci gem_writel_n(bp, T2CMPW0, T2CMP_OFST(GEM_IP4DST_CMP(index)), w0); 31758c2ecf20Sopenharmony_ci gem_writel_n(bp, T2CMPW1, T2CMP_OFST(GEM_IP4DST_CMP(index)), w1); 31768c2ecf20Sopenharmony_ci cmp_b = true; 31778c2ecf20Sopenharmony_ci } 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci /* ignore both port fields if masking set in both */ 31808c2ecf20Sopenharmony_ci if ((tp4sp_m->psrc == 0xFFFF) || (tp4sp_m->pdst == 0xFFFF)) { 31818c2ecf20Sopenharmony_ci /* 3rd compare reg - source port, destination port */ 31828c2ecf20Sopenharmony_ci w0 = 0; 31838c2ecf20Sopenharmony_ci w1 = 0; 31848c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2CMPOFST, GEM_T2COMPOFST_IPHDR, w1); 31858c2ecf20Sopenharmony_ci if (tp4sp_m->psrc == tp4sp_m->pdst) { 31868c2ecf20Sopenharmony_ci w0 = GEM_BFINS(T2MASK, tp4sp_v->psrc, w0); 31878c2ecf20Sopenharmony_ci w0 = GEM_BFINS(T2CMP, tp4sp_v->pdst, w0); 31888c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2DISMSK, 1, w1); /* 32-bit compare */ 31898c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2OFST, IPHDR_SRCPORT_OFFSET, w1); 31908c2ecf20Sopenharmony_ci } else { 31918c2ecf20Sopenharmony_ci /* only one port definition */ 31928c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2DISMSK, 0, w1); /* 16-bit compare */ 31938c2ecf20Sopenharmony_ci w0 = GEM_BFINS(T2MASK, 0xFFFF, w0); 31948c2ecf20Sopenharmony_ci if (tp4sp_m->psrc == 0xFFFF) { /* src port */ 31958c2ecf20Sopenharmony_ci w0 = GEM_BFINS(T2CMP, tp4sp_v->psrc, w0); 31968c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2OFST, IPHDR_SRCPORT_OFFSET, w1); 31978c2ecf20Sopenharmony_ci } else { /* dst port */ 31988c2ecf20Sopenharmony_ci w0 = GEM_BFINS(T2CMP, tp4sp_v->pdst, w0); 31998c2ecf20Sopenharmony_ci w1 = GEM_BFINS(T2OFST, IPHDR_DSTPORT_OFFSET, w1); 32008c2ecf20Sopenharmony_ci } 32018c2ecf20Sopenharmony_ci } 32028c2ecf20Sopenharmony_ci gem_writel_n(bp, T2CMPW0, T2CMP_OFST(GEM_PORT_CMP(index)), w0); 32038c2ecf20Sopenharmony_ci gem_writel_n(bp, T2CMPW1, T2CMP_OFST(GEM_PORT_CMP(index)), w1); 32048c2ecf20Sopenharmony_ci cmp_c = true; 32058c2ecf20Sopenharmony_ci } 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci t2_scr = 0; 32088c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(QUEUE, (fs->ring_cookie) & 0xFF, t2_scr); 32098c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(ETHT2IDX, SCRT2_ETHT, t2_scr); 32108c2ecf20Sopenharmony_ci if (cmp_a) 32118c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPA, GEM_IP4SRC_CMP(index), t2_scr); 32128c2ecf20Sopenharmony_ci if (cmp_b) 32138c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPB, GEM_IP4DST_CMP(index), t2_scr); 32148c2ecf20Sopenharmony_ci if (cmp_c) 32158c2ecf20Sopenharmony_ci t2_scr = GEM_BFINS(CMPC, GEM_PORT_CMP(index), t2_scr); 32168c2ecf20Sopenharmony_ci gem_writel_n(bp, SCRT2, index, t2_scr); 32178c2ecf20Sopenharmony_ci} 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_cistatic int gem_add_flow_filter(struct net_device *netdev, 32208c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 32218c2ecf20Sopenharmony_ci{ 32228c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 32238c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fs = &cmd->fs; 32248c2ecf20Sopenharmony_ci struct ethtool_rx_fs_item *item, *newfs; 32258c2ecf20Sopenharmony_ci unsigned long flags; 32268c2ecf20Sopenharmony_ci int ret = -EINVAL; 32278c2ecf20Sopenharmony_ci bool added = false; 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci newfs = kmalloc(sizeof(*newfs), GFP_KERNEL); 32308c2ecf20Sopenharmony_ci if (newfs == NULL) 32318c2ecf20Sopenharmony_ci return -ENOMEM; 32328c2ecf20Sopenharmony_ci memcpy(&newfs->fs, fs, sizeof(newfs->fs)); 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci netdev_dbg(netdev, 32358c2ecf20Sopenharmony_ci "Adding flow filter entry,type=%u,queue=%u,loc=%u,src=%08X,dst=%08X,ps=%u,pd=%u\n", 32368c2ecf20Sopenharmony_ci fs->flow_type, (int)fs->ring_cookie, fs->location, 32378c2ecf20Sopenharmony_ci htonl(fs->h_u.tcp_ip4_spec.ip4src), 32388c2ecf20Sopenharmony_ci htonl(fs->h_u.tcp_ip4_spec.ip4dst), 32398c2ecf20Sopenharmony_ci htons(fs->h_u.tcp_ip4_spec.psrc), htons(fs->h_u.tcp_ip4_spec.pdst)); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->rx_fs_lock, flags); 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci /* find correct place to add in list */ 32448c2ecf20Sopenharmony_ci list_for_each_entry(item, &bp->rx_fs_list.list, list) { 32458c2ecf20Sopenharmony_ci if (item->fs.location > newfs->fs.location) { 32468c2ecf20Sopenharmony_ci list_add_tail(&newfs->list, &item->list); 32478c2ecf20Sopenharmony_ci added = true; 32488c2ecf20Sopenharmony_ci break; 32498c2ecf20Sopenharmony_ci } else if (item->fs.location == fs->location) { 32508c2ecf20Sopenharmony_ci netdev_err(netdev, "Rule not added: location %d not free!\n", 32518c2ecf20Sopenharmony_ci fs->location); 32528c2ecf20Sopenharmony_ci ret = -EBUSY; 32538c2ecf20Sopenharmony_ci goto err; 32548c2ecf20Sopenharmony_ci } 32558c2ecf20Sopenharmony_ci } 32568c2ecf20Sopenharmony_ci if (!added) 32578c2ecf20Sopenharmony_ci list_add_tail(&newfs->list, &bp->rx_fs_list.list); 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci gem_prog_cmp_regs(bp, fs); 32608c2ecf20Sopenharmony_ci bp->rx_fs_list.count++; 32618c2ecf20Sopenharmony_ci /* enable filtering if NTUPLE on */ 32628c2ecf20Sopenharmony_ci gem_enable_flow_filters(bp, 1); 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->rx_fs_lock, flags); 32658c2ecf20Sopenharmony_ci return 0; 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_cierr: 32688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->rx_fs_lock, flags); 32698c2ecf20Sopenharmony_ci kfree(newfs); 32708c2ecf20Sopenharmony_ci return ret; 32718c2ecf20Sopenharmony_ci} 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_cistatic int gem_del_flow_filter(struct net_device *netdev, 32748c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 32758c2ecf20Sopenharmony_ci{ 32768c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 32778c2ecf20Sopenharmony_ci struct ethtool_rx_fs_item *item; 32788c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fs; 32798c2ecf20Sopenharmony_ci unsigned long flags; 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->rx_fs_lock, flags); 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci list_for_each_entry(item, &bp->rx_fs_list.list, list) { 32848c2ecf20Sopenharmony_ci if (item->fs.location == cmd->fs.location) { 32858c2ecf20Sopenharmony_ci /* disable screener regs for the flow entry */ 32868c2ecf20Sopenharmony_ci fs = &(item->fs); 32878c2ecf20Sopenharmony_ci netdev_dbg(netdev, 32888c2ecf20Sopenharmony_ci "Deleting flow filter entry,type=%u,queue=%u,loc=%u,src=%08X,dst=%08X,ps=%u,pd=%u\n", 32898c2ecf20Sopenharmony_ci fs->flow_type, (int)fs->ring_cookie, fs->location, 32908c2ecf20Sopenharmony_ci htonl(fs->h_u.tcp_ip4_spec.ip4src), 32918c2ecf20Sopenharmony_ci htonl(fs->h_u.tcp_ip4_spec.ip4dst), 32928c2ecf20Sopenharmony_ci htons(fs->h_u.tcp_ip4_spec.psrc), 32938c2ecf20Sopenharmony_ci htons(fs->h_u.tcp_ip4_spec.pdst)); 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci gem_writel_n(bp, SCRT2, fs->location, 0); 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci list_del(&item->list); 32988c2ecf20Sopenharmony_ci bp->rx_fs_list.count--; 32998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->rx_fs_lock, flags); 33008c2ecf20Sopenharmony_ci kfree(item); 33018c2ecf20Sopenharmony_ci return 0; 33028c2ecf20Sopenharmony_ci } 33038c2ecf20Sopenharmony_ci } 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->rx_fs_lock, flags); 33068c2ecf20Sopenharmony_ci return -EINVAL; 33078c2ecf20Sopenharmony_ci} 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_cistatic int gem_get_flow_entry(struct net_device *netdev, 33108c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 33118c2ecf20Sopenharmony_ci{ 33128c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 33138c2ecf20Sopenharmony_ci struct ethtool_rx_fs_item *item; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci list_for_each_entry(item, &bp->rx_fs_list.list, list) { 33168c2ecf20Sopenharmony_ci if (item->fs.location == cmd->fs.location) { 33178c2ecf20Sopenharmony_ci memcpy(&cmd->fs, &item->fs, sizeof(cmd->fs)); 33188c2ecf20Sopenharmony_ci return 0; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci } 33218c2ecf20Sopenharmony_ci return -EINVAL; 33228c2ecf20Sopenharmony_ci} 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_cistatic int gem_get_all_flow_entries(struct net_device *netdev, 33258c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd, u32 *rule_locs) 33268c2ecf20Sopenharmony_ci{ 33278c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 33288c2ecf20Sopenharmony_ci struct ethtool_rx_fs_item *item; 33298c2ecf20Sopenharmony_ci uint32_t cnt = 0; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci list_for_each_entry(item, &bp->rx_fs_list.list, list) { 33328c2ecf20Sopenharmony_ci if (cnt == cmd->rule_cnt) 33338c2ecf20Sopenharmony_ci return -EMSGSIZE; 33348c2ecf20Sopenharmony_ci rule_locs[cnt] = item->fs.location; 33358c2ecf20Sopenharmony_ci cnt++; 33368c2ecf20Sopenharmony_ci } 33378c2ecf20Sopenharmony_ci cmd->data = bp->max_tuples; 33388c2ecf20Sopenharmony_ci cmd->rule_cnt = cnt; 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci return 0; 33418c2ecf20Sopenharmony_ci} 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_cistatic int gem_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, 33448c2ecf20Sopenharmony_ci u32 *rule_locs) 33458c2ecf20Sopenharmony_ci{ 33468c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 33478c2ecf20Sopenharmony_ci int ret = 0; 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci switch (cmd->cmd) { 33508c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 33518c2ecf20Sopenharmony_ci cmd->data = bp->num_queues; 33528c2ecf20Sopenharmony_ci break; 33538c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 33548c2ecf20Sopenharmony_ci cmd->rule_cnt = bp->rx_fs_list.count; 33558c2ecf20Sopenharmony_ci break; 33568c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 33578c2ecf20Sopenharmony_ci ret = gem_get_flow_entry(netdev, cmd); 33588c2ecf20Sopenharmony_ci break; 33598c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 33608c2ecf20Sopenharmony_ci ret = gem_get_all_flow_entries(netdev, cmd, rule_locs); 33618c2ecf20Sopenharmony_ci break; 33628c2ecf20Sopenharmony_ci default: 33638c2ecf20Sopenharmony_ci netdev_err(netdev, 33648c2ecf20Sopenharmony_ci "Command parameter %d is not supported\n", cmd->cmd); 33658c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 33668c2ecf20Sopenharmony_ci } 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci return ret; 33698c2ecf20Sopenharmony_ci} 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_cistatic int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) 33728c2ecf20Sopenharmony_ci{ 33738c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 33748c2ecf20Sopenharmony_ci int ret; 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci switch (cmd->cmd) { 33778c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 33788c2ecf20Sopenharmony_ci if ((cmd->fs.location >= bp->max_tuples) 33798c2ecf20Sopenharmony_ci || (cmd->fs.ring_cookie >= bp->num_queues)) { 33808c2ecf20Sopenharmony_ci ret = -EINVAL; 33818c2ecf20Sopenharmony_ci break; 33828c2ecf20Sopenharmony_ci } 33838c2ecf20Sopenharmony_ci ret = gem_add_flow_filter(netdev, cmd); 33848c2ecf20Sopenharmony_ci break; 33858c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 33868c2ecf20Sopenharmony_ci ret = gem_del_flow_filter(netdev, cmd); 33878c2ecf20Sopenharmony_ci break; 33888c2ecf20Sopenharmony_ci default: 33898c2ecf20Sopenharmony_ci netdev_err(netdev, 33908c2ecf20Sopenharmony_ci "Command parameter %d is not supported\n", cmd->cmd); 33918c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 33928c2ecf20Sopenharmony_ci } 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci return ret; 33958c2ecf20Sopenharmony_ci} 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_cistatic const struct ethtool_ops macb_ethtool_ops = { 33988c2ecf20Sopenharmony_ci .get_regs_len = macb_get_regs_len, 33998c2ecf20Sopenharmony_ci .get_regs = macb_get_regs, 34008c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 34018c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 34028c2ecf20Sopenharmony_ci .get_wol = macb_get_wol, 34038c2ecf20Sopenharmony_ci .set_wol = macb_set_wol, 34048c2ecf20Sopenharmony_ci .get_link_ksettings = macb_get_link_ksettings, 34058c2ecf20Sopenharmony_ci .set_link_ksettings = macb_set_link_ksettings, 34068c2ecf20Sopenharmony_ci .get_ringparam = macb_get_ringparam, 34078c2ecf20Sopenharmony_ci .set_ringparam = macb_set_ringparam, 34088c2ecf20Sopenharmony_ci}; 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_cistatic const struct ethtool_ops gem_ethtool_ops = { 34118c2ecf20Sopenharmony_ci .get_regs_len = macb_get_regs_len, 34128c2ecf20Sopenharmony_ci .get_regs = macb_get_regs, 34138c2ecf20Sopenharmony_ci .get_wol = macb_get_wol, 34148c2ecf20Sopenharmony_ci .set_wol = macb_set_wol, 34158c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 34168c2ecf20Sopenharmony_ci .get_ts_info = macb_get_ts_info, 34178c2ecf20Sopenharmony_ci .get_ethtool_stats = gem_get_ethtool_stats, 34188c2ecf20Sopenharmony_ci .get_strings = gem_get_ethtool_strings, 34198c2ecf20Sopenharmony_ci .get_sset_count = gem_get_sset_count, 34208c2ecf20Sopenharmony_ci .get_link_ksettings = macb_get_link_ksettings, 34218c2ecf20Sopenharmony_ci .set_link_ksettings = macb_set_link_ksettings, 34228c2ecf20Sopenharmony_ci .get_ringparam = macb_get_ringparam, 34238c2ecf20Sopenharmony_ci .set_ringparam = macb_set_ringparam, 34248c2ecf20Sopenharmony_ci .get_rxnfc = gem_get_rxnfc, 34258c2ecf20Sopenharmony_ci .set_rxnfc = gem_set_rxnfc, 34268c2ecf20Sopenharmony_ci}; 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_cistatic int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 34298c2ecf20Sopenharmony_ci{ 34308c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci if (!netif_running(dev)) 34338c2ecf20Sopenharmony_ci return -EINVAL; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci if (bp->ptp_info) { 34368c2ecf20Sopenharmony_ci switch (cmd) { 34378c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 34388c2ecf20Sopenharmony_ci return bp->ptp_info->set_hwtst(dev, rq, cmd); 34398c2ecf20Sopenharmony_ci case SIOCGHWTSTAMP: 34408c2ecf20Sopenharmony_ci return bp->ptp_info->get_hwtst(dev, rq); 34418c2ecf20Sopenharmony_ci } 34428c2ecf20Sopenharmony_ci } 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci return phylink_mii_ioctl(bp->phylink, rq, cmd); 34458c2ecf20Sopenharmony_ci} 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_cistatic inline void macb_set_txcsum_feature(struct macb *bp, 34488c2ecf20Sopenharmony_ci netdev_features_t features) 34498c2ecf20Sopenharmony_ci{ 34508c2ecf20Sopenharmony_ci u32 val; 34518c2ecf20Sopenharmony_ci 34528c2ecf20Sopenharmony_ci if (!macb_is_gem(bp)) 34538c2ecf20Sopenharmony_ci return; 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ci val = gem_readl(bp, DMACFG); 34568c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_CSUM) 34578c2ecf20Sopenharmony_ci val |= GEM_BIT(TXCOEN); 34588c2ecf20Sopenharmony_ci else 34598c2ecf20Sopenharmony_ci val &= ~GEM_BIT(TXCOEN); 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci gem_writel(bp, DMACFG, val); 34628c2ecf20Sopenharmony_ci} 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_cistatic inline void macb_set_rxcsum_feature(struct macb *bp, 34658c2ecf20Sopenharmony_ci netdev_features_t features) 34668c2ecf20Sopenharmony_ci{ 34678c2ecf20Sopenharmony_ci struct net_device *netdev = bp->dev; 34688c2ecf20Sopenharmony_ci u32 val; 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_ci if (!macb_is_gem(bp)) 34718c2ecf20Sopenharmony_ci return; 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci val = gem_readl(bp, NCFGR); 34748c2ecf20Sopenharmony_ci if ((features & NETIF_F_RXCSUM) && !(netdev->flags & IFF_PROMISC)) 34758c2ecf20Sopenharmony_ci val |= GEM_BIT(RXCOEN); 34768c2ecf20Sopenharmony_ci else 34778c2ecf20Sopenharmony_ci val &= ~GEM_BIT(RXCOEN); 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_ci gem_writel(bp, NCFGR, val); 34808c2ecf20Sopenharmony_ci} 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_cistatic inline void macb_set_rxflow_feature(struct macb *bp, 34838c2ecf20Sopenharmony_ci netdev_features_t features) 34848c2ecf20Sopenharmony_ci{ 34858c2ecf20Sopenharmony_ci if (!macb_is_gem(bp)) 34868c2ecf20Sopenharmony_ci return; 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci gem_enable_flow_filters(bp, !!(features & NETIF_F_NTUPLE)); 34898c2ecf20Sopenharmony_ci} 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_cistatic int macb_set_features(struct net_device *netdev, 34928c2ecf20Sopenharmony_ci netdev_features_t features) 34938c2ecf20Sopenharmony_ci{ 34948c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 34958c2ecf20Sopenharmony_ci netdev_features_t changed = features ^ netdev->features; 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci /* TX checksum offload */ 34988c2ecf20Sopenharmony_ci if (changed & NETIF_F_HW_CSUM) 34998c2ecf20Sopenharmony_ci macb_set_txcsum_feature(bp, features); 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci /* RX checksum offload */ 35028c2ecf20Sopenharmony_ci if (changed & NETIF_F_RXCSUM) 35038c2ecf20Sopenharmony_ci macb_set_rxcsum_feature(bp, features); 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci /* RX Flow Filters */ 35068c2ecf20Sopenharmony_ci if (changed & NETIF_F_NTUPLE) 35078c2ecf20Sopenharmony_ci macb_set_rxflow_feature(bp, features); 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci return 0; 35108c2ecf20Sopenharmony_ci} 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_cistatic void macb_restore_features(struct macb *bp) 35138c2ecf20Sopenharmony_ci{ 35148c2ecf20Sopenharmony_ci struct net_device *netdev = bp->dev; 35158c2ecf20Sopenharmony_ci netdev_features_t features = netdev->features; 35168c2ecf20Sopenharmony_ci struct ethtool_rx_fs_item *item; 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci /* TX checksum offload */ 35198c2ecf20Sopenharmony_ci macb_set_txcsum_feature(bp, features); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci /* RX checksum offload */ 35228c2ecf20Sopenharmony_ci macb_set_rxcsum_feature(bp, features); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci /* RX Flow Filters */ 35258c2ecf20Sopenharmony_ci list_for_each_entry(item, &bp->rx_fs_list.list, list) 35268c2ecf20Sopenharmony_ci gem_prog_cmp_regs(bp, &item->fs); 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci macb_set_rxflow_feature(bp, features); 35298c2ecf20Sopenharmony_ci} 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_cistatic const struct net_device_ops macb_netdev_ops = { 35328c2ecf20Sopenharmony_ci .ndo_open = macb_open, 35338c2ecf20Sopenharmony_ci .ndo_stop = macb_close, 35348c2ecf20Sopenharmony_ci .ndo_start_xmit = macb_start_xmit, 35358c2ecf20Sopenharmony_ci .ndo_set_rx_mode = macb_set_rx_mode, 35368c2ecf20Sopenharmony_ci .ndo_get_stats = macb_get_stats, 35378c2ecf20Sopenharmony_ci .ndo_do_ioctl = macb_ioctl, 35388c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 35398c2ecf20Sopenharmony_ci .ndo_change_mtu = macb_change_mtu, 35408c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 35418c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 35428c2ecf20Sopenharmony_ci .ndo_poll_controller = macb_poll_controller, 35438c2ecf20Sopenharmony_ci#endif 35448c2ecf20Sopenharmony_ci .ndo_set_features = macb_set_features, 35458c2ecf20Sopenharmony_ci .ndo_features_check = macb_features_check, 35468c2ecf20Sopenharmony_ci}; 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci/* Configure peripheral capabilities according to device tree 35498c2ecf20Sopenharmony_ci * and integration options used 35508c2ecf20Sopenharmony_ci */ 35518c2ecf20Sopenharmony_cistatic void macb_configure_caps(struct macb *bp, 35528c2ecf20Sopenharmony_ci const struct macb_config *dt_conf) 35538c2ecf20Sopenharmony_ci{ 35548c2ecf20Sopenharmony_ci u32 dcfg; 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_ci if (dt_conf) 35578c2ecf20Sopenharmony_ci bp->caps = dt_conf->caps; 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci if (hw_is_gem(bp->regs, bp->native_io)) { 35608c2ecf20Sopenharmony_ci bp->caps |= MACB_CAPS_MACB_IS_GEM; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci dcfg = gem_readl(bp, DCFG1); 35638c2ecf20Sopenharmony_ci if (GEM_BFEXT(IRQCOR, dcfg) == 0) 35648c2ecf20Sopenharmony_ci bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; 35658c2ecf20Sopenharmony_ci dcfg = gem_readl(bp, DCFG2); 35668c2ecf20Sopenharmony_ci if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) 35678c2ecf20Sopenharmony_ci bp->caps |= MACB_CAPS_FIFO_MODE; 35688c2ecf20Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP 35698c2ecf20Sopenharmony_ci if (gem_has_ptp(bp)) { 35708c2ecf20Sopenharmony_ci if (!GEM_BFEXT(TSU, gem_readl(bp, DCFG5))) 35718c2ecf20Sopenharmony_ci dev_err(&bp->pdev->dev, 35728c2ecf20Sopenharmony_ci "GEM doesn't support hardware ptp.\n"); 35738c2ecf20Sopenharmony_ci else { 35748c2ecf20Sopenharmony_ci bp->hw_dma_cap |= HW_DMA_CAP_PTP; 35758c2ecf20Sopenharmony_ci bp->ptp_info = &gem_ptp_info; 35768c2ecf20Sopenharmony_ci } 35778c2ecf20Sopenharmony_ci } 35788c2ecf20Sopenharmony_ci#endif 35798c2ecf20Sopenharmony_ci } 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps); 35828c2ecf20Sopenharmony_ci} 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_cistatic void macb_probe_queues(void __iomem *mem, 35858c2ecf20Sopenharmony_ci bool native_io, 35868c2ecf20Sopenharmony_ci unsigned int *queue_mask, 35878c2ecf20Sopenharmony_ci unsigned int *num_queues) 35888c2ecf20Sopenharmony_ci{ 35898c2ecf20Sopenharmony_ci *queue_mask = 0x1; 35908c2ecf20Sopenharmony_ci *num_queues = 1; 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci /* is it macb or gem ? 35938c2ecf20Sopenharmony_ci * 35948c2ecf20Sopenharmony_ci * We need to read directly from the hardware here because 35958c2ecf20Sopenharmony_ci * we are early in the probe process and don't have the 35968c2ecf20Sopenharmony_ci * MACB_CAPS_MACB_IS_GEM flag positioned 35978c2ecf20Sopenharmony_ci */ 35988c2ecf20Sopenharmony_ci if (!hw_is_gem(mem, native_io)) 35998c2ecf20Sopenharmony_ci return; 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci /* bit 0 is never set but queue 0 always exists */ 36028c2ecf20Sopenharmony_ci *queue_mask |= readl_relaxed(mem + GEM_DCFG6) & 0xff; 36038c2ecf20Sopenharmony_ci *num_queues = hweight32(*queue_mask); 36048c2ecf20Sopenharmony_ci} 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_cistatic int macb_clk_init(struct platform_device *pdev, struct clk **pclk, 36078c2ecf20Sopenharmony_ci struct clk **hclk, struct clk **tx_clk, 36088c2ecf20Sopenharmony_ci struct clk **rx_clk, struct clk **tsu_clk) 36098c2ecf20Sopenharmony_ci{ 36108c2ecf20Sopenharmony_ci struct macb_platform_data *pdata; 36118c2ecf20Sopenharmony_ci int err; 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_ci pdata = dev_get_platdata(&pdev->dev); 36148c2ecf20Sopenharmony_ci if (pdata) { 36158c2ecf20Sopenharmony_ci *pclk = pdata->pclk; 36168c2ecf20Sopenharmony_ci *hclk = pdata->hclk; 36178c2ecf20Sopenharmony_ci } else { 36188c2ecf20Sopenharmony_ci *pclk = devm_clk_get(&pdev->dev, "pclk"); 36198c2ecf20Sopenharmony_ci *hclk = devm_clk_get(&pdev->dev, "hclk"); 36208c2ecf20Sopenharmony_ci } 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(*pclk)) { 36238c2ecf20Sopenharmony_ci err = PTR_ERR(*pclk); 36248c2ecf20Sopenharmony_ci if (!err) 36258c2ecf20Sopenharmony_ci err = -ENODEV; 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get macb_clk (%d)\n", err); 36288c2ecf20Sopenharmony_ci return err; 36298c2ecf20Sopenharmony_ci } 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(*hclk)) { 36328c2ecf20Sopenharmony_ci err = PTR_ERR(*hclk); 36338c2ecf20Sopenharmony_ci if (!err) 36348c2ecf20Sopenharmony_ci err = -ENODEV; 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get hclk (%d)\n", err); 36378c2ecf20Sopenharmony_ci return err; 36388c2ecf20Sopenharmony_ci } 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci *tx_clk = devm_clk_get_optional(&pdev->dev, "tx_clk"); 36418c2ecf20Sopenharmony_ci if (IS_ERR(*tx_clk)) 36428c2ecf20Sopenharmony_ci return PTR_ERR(*tx_clk); 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci *rx_clk = devm_clk_get_optional(&pdev->dev, "rx_clk"); 36458c2ecf20Sopenharmony_ci if (IS_ERR(*rx_clk)) 36468c2ecf20Sopenharmony_ci return PTR_ERR(*rx_clk); 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci *tsu_clk = devm_clk_get_optional(&pdev->dev, "tsu_clk"); 36498c2ecf20Sopenharmony_ci if (IS_ERR(*tsu_clk)) 36508c2ecf20Sopenharmony_ci return PTR_ERR(*tsu_clk); 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci err = clk_prepare_enable(*pclk); 36538c2ecf20Sopenharmony_ci if (err) { 36548c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable pclk (%d)\n", err); 36558c2ecf20Sopenharmony_ci return err; 36568c2ecf20Sopenharmony_ci } 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci err = clk_prepare_enable(*hclk); 36598c2ecf20Sopenharmony_ci if (err) { 36608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable hclk (%d)\n", err); 36618c2ecf20Sopenharmony_ci goto err_disable_pclk; 36628c2ecf20Sopenharmony_ci } 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci err = clk_prepare_enable(*tx_clk); 36658c2ecf20Sopenharmony_ci if (err) { 36668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable tx_clk (%d)\n", err); 36678c2ecf20Sopenharmony_ci goto err_disable_hclk; 36688c2ecf20Sopenharmony_ci } 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci err = clk_prepare_enable(*rx_clk); 36718c2ecf20Sopenharmony_ci if (err) { 36728c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable rx_clk (%d)\n", err); 36738c2ecf20Sopenharmony_ci goto err_disable_txclk; 36748c2ecf20Sopenharmony_ci } 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci err = clk_prepare_enable(*tsu_clk); 36778c2ecf20Sopenharmony_ci if (err) { 36788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable tsu_clk (%d)\n", err); 36798c2ecf20Sopenharmony_ci goto err_disable_rxclk; 36808c2ecf20Sopenharmony_ci } 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci return 0; 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_cierr_disable_rxclk: 36858c2ecf20Sopenharmony_ci clk_disable_unprepare(*rx_clk); 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_cierr_disable_txclk: 36888c2ecf20Sopenharmony_ci clk_disable_unprepare(*tx_clk); 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_cierr_disable_hclk: 36918c2ecf20Sopenharmony_ci clk_disable_unprepare(*hclk); 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_cierr_disable_pclk: 36948c2ecf20Sopenharmony_ci clk_disable_unprepare(*pclk); 36958c2ecf20Sopenharmony_ci 36968c2ecf20Sopenharmony_ci return err; 36978c2ecf20Sopenharmony_ci} 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_cistatic int macb_init(struct platform_device *pdev) 37008c2ecf20Sopenharmony_ci{ 37018c2ecf20Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 37028c2ecf20Sopenharmony_ci unsigned int hw_q, q; 37038c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 37048c2ecf20Sopenharmony_ci struct macb_queue *queue; 37058c2ecf20Sopenharmony_ci int err; 37068c2ecf20Sopenharmony_ci u32 val, reg; 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci bp->tx_ring_size = DEFAULT_TX_RING_SIZE; 37098c2ecf20Sopenharmony_ci bp->rx_ring_size = DEFAULT_RX_RING_SIZE; 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci /* set the queue register mapping once for all: queue0 has a special 37128c2ecf20Sopenharmony_ci * register mapping but we don't want to test the queue index then 37138c2ecf20Sopenharmony_ci * compute the corresponding register offset at run time. 37148c2ecf20Sopenharmony_ci */ 37158c2ecf20Sopenharmony_ci for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) { 37168c2ecf20Sopenharmony_ci if (!(bp->queue_mask & (1 << hw_q))) 37178c2ecf20Sopenharmony_ci continue; 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci queue = &bp->queues[q]; 37208c2ecf20Sopenharmony_ci queue->bp = bp; 37218c2ecf20Sopenharmony_ci netif_napi_add(dev, &queue->napi, macb_poll, NAPI_POLL_WEIGHT); 37228c2ecf20Sopenharmony_ci if (hw_q) { 37238c2ecf20Sopenharmony_ci queue->ISR = GEM_ISR(hw_q - 1); 37248c2ecf20Sopenharmony_ci queue->IER = GEM_IER(hw_q - 1); 37258c2ecf20Sopenharmony_ci queue->IDR = GEM_IDR(hw_q - 1); 37268c2ecf20Sopenharmony_ci queue->IMR = GEM_IMR(hw_q - 1); 37278c2ecf20Sopenharmony_ci queue->TBQP = GEM_TBQP(hw_q - 1); 37288c2ecf20Sopenharmony_ci queue->RBQP = GEM_RBQP(hw_q - 1); 37298c2ecf20Sopenharmony_ci queue->RBQS = GEM_RBQS(hw_q - 1); 37308c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 37318c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) { 37328c2ecf20Sopenharmony_ci queue->TBQPH = GEM_TBQPH(hw_q - 1); 37338c2ecf20Sopenharmony_ci queue->RBQPH = GEM_RBQPH(hw_q - 1); 37348c2ecf20Sopenharmony_ci } 37358c2ecf20Sopenharmony_ci#endif 37368c2ecf20Sopenharmony_ci } else { 37378c2ecf20Sopenharmony_ci /* queue0 uses legacy registers */ 37388c2ecf20Sopenharmony_ci queue->ISR = MACB_ISR; 37398c2ecf20Sopenharmony_ci queue->IER = MACB_IER; 37408c2ecf20Sopenharmony_ci queue->IDR = MACB_IDR; 37418c2ecf20Sopenharmony_ci queue->IMR = MACB_IMR; 37428c2ecf20Sopenharmony_ci queue->TBQP = MACB_TBQP; 37438c2ecf20Sopenharmony_ci queue->RBQP = MACB_RBQP; 37448c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 37458c2ecf20Sopenharmony_ci if (bp->hw_dma_cap & HW_DMA_CAP_64B) { 37468c2ecf20Sopenharmony_ci queue->TBQPH = MACB_TBQPH; 37478c2ecf20Sopenharmony_ci queue->RBQPH = MACB_RBQPH; 37488c2ecf20Sopenharmony_ci } 37498c2ecf20Sopenharmony_ci#endif 37508c2ecf20Sopenharmony_ci } 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci /* get irq: here we use the linux queue index, not the hardware 37538c2ecf20Sopenharmony_ci * queue index. the queue irq definitions in the device tree 37548c2ecf20Sopenharmony_ci * must remove the optional gaps that could exist in the 37558c2ecf20Sopenharmony_ci * hardware queue mask. 37568c2ecf20Sopenharmony_ci */ 37578c2ecf20Sopenharmony_ci queue->irq = platform_get_irq(pdev, q); 37588c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, queue->irq, macb_interrupt, 37598c2ecf20Sopenharmony_ci IRQF_SHARED, dev->name, queue); 37608c2ecf20Sopenharmony_ci if (err) { 37618c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 37628c2ecf20Sopenharmony_ci "Unable to request IRQ %d (error %d)\n", 37638c2ecf20Sopenharmony_ci queue->irq, err); 37648c2ecf20Sopenharmony_ci return err; 37658c2ecf20Sopenharmony_ci } 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci INIT_WORK(&queue->tx_error_task, macb_tx_error_task); 37688c2ecf20Sopenharmony_ci q++; 37698c2ecf20Sopenharmony_ci } 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci dev->netdev_ops = &macb_netdev_ops; 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci /* setup appropriated routines according to adapter type */ 37748c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) { 37758c2ecf20Sopenharmony_ci bp->max_tx_length = GEM_MAX_TX_LEN; 37768c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; 37778c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; 37788c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_init_rings = gem_init_rings; 37798c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_rx = gem_rx; 37808c2ecf20Sopenharmony_ci dev->ethtool_ops = &gem_ethtool_ops; 37818c2ecf20Sopenharmony_ci } else { 37828c2ecf20Sopenharmony_ci bp->max_tx_length = MACB_MAX_TX_LEN; 37838c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; 37848c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; 37858c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_init_rings = macb_init_rings; 37868c2ecf20Sopenharmony_ci bp->macbgem_ops.mog_rx = macb_rx; 37878c2ecf20Sopenharmony_ci dev->ethtool_ops = &macb_ethtool_ops; 37888c2ecf20Sopenharmony_ci } 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci /* Set features */ 37918c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG; 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_ci /* Check LSO capability */ 37948c2ecf20Sopenharmony_ci if (GEM_BFEXT(PBUF_LSO, gem_readl(bp, DCFG6))) 37958c2ecf20Sopenharmony_ci dev->hw_features |= MACB_NETIF_LSO; 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_ci /* Checksum offload is only available on gem with packet buffer */ 37988c2ecf20Sopenharmony_ci if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) 37998c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; 38008c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_SG_DISABLED) 38018c2ecf20Sopenharmony_ci dev->hw_features &= ~NETIF_F_SG; 38028c2ecf20Sopenharmony_ci dev->features = dev->hw_features; 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci /* Check RX Flow Filters support. 38058c2ecf20Sopenharmony_ci * Max Rx flows set by availability of screeners & compare regs: 38068c2ecf20Sopenharmony_ci * each 4-tuple define requires 1 T2 screener reg + 3 compare regs 38078c2ecf20Sopenharmony_ci */ 38088c2ecf20Sopenharmony_ci reg = gem_readl(bp, DCFG8); 38098c2ecf20Sopenharmony_ci bp->max_tuples = min((GEM_BFEXT(SCR2CMP, reg) / 3), 38108c2ecf20Sopenharmony_ci GEM_BFEXT(T2SCR, reg)); 38118c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bp->rx_fs_list.list); 38128c2ecf20Sopenharmony_ci if (bp->max_tuples > 0) { 38138c2ecf20Sopenharmony_ci /* also needs one ethtype match to check IPv4 */ 38148c2ecf20Sopenharmony_ci if (GEM_BFEXT(SCR2ETH, reg) > 0) { 38158c2ecf20Sopenharmony_ci /* program this reg now */ 38168c2ecf20Sopenharmony_ci reg = 0; 38178c2ecf20Sopenharmony_ci reg = GEM_BFINS(ETHTCMP, (uint16_t)ETH_P_IP, reg); 38188c2ecf20Sopenharmony_ci gem_writel_n(bp, ETHT, SCRT2_ETHT, reg); 38198c2ecf20Sopenharmony_ci /* Filtering is supported in hw but don't enable it in kernel now */ 38208c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_NTUPLE; 38218c2ecf20Sopenharmony_ci /* init Rx flow definitions */ 38228c2ecf20Sopenharmony_ci bp->rx_fs_list.count = 0; 38238c2ecf20Sopenharmony_ci spin_lock_init(&bp->rx_fs_lock); 38248c2ecf20Sopenharmony_ci } else 38258c2ecf20Sopenharmony_ci bp->max_tuples = 0; 38268c2ecf20Sopenharmony_ci } 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) { 38298c2ecf20Sopenharmony_ci val = 0; 38308c2ecf20Sopenharmony_ci if (phy_interface_mode_is_rgmii(bp->phy_interface)) 38318c2ecf20Sopenharmony_ci val = GEM_BIT(RGMII); 38328c2ecf20Sopenharmony_ci else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII && 38338c2ecf20Sopenharmony_ci (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) 38348c2ecf20Sopenharmony_ci val = MACB_BIT(RMII); 38358c2ecf20Sopenharmony_ci else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) 38368c2ecf20Sopenharmony_ci val = MACB_BIT(MII); 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_USRIO_HAS_CLKEN) 38398c2ecf20Sopenharmony_ci val |= MACB_BIT(CLKEN); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, USRIO, val); 38428c2ecf20Sopenharmony_ci } 38438c2ecf20Sopenharmony_ci 38448c2ecf20Sopenharmony_ci /* Set MII management clock divider */ 38458c2ecf20Sopenharmony_ci val = macb_mdc_clk_div(bp); 38468c2ecf20Sopenharmony_ci val |= macb_dbw(bp); 38478c2ecf20Sopenharmony_ci if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) 38488c2ecf20Sopenharmony_ci val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); 38498c2ecf20Sopenharmony_ci macb_writel(bp, NCFGR, val); 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci return 0; 38528c2ecf20Sopenharmony_ci} 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 38558c2ecf20Sopenharmony_ci/* 1518 rounded up */ 38568c2ecf20Sopenharmony_ci#define AT91ETHER_MAX_RBUFF_SZ 0x600 38578c2ecf20Sopenharmony_ci/* max number of receive buffers */ 38588c2ecf20Sopenharmony_ci#define AT91ETHER_MAX_RX_DESCR 9 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_cistatic struct sifive_fu540_macb_mgmt *mgmt; 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_cistatic int at91ether_alloc_coherent(struct macb *lp) 38638c2ecf20Sopenharmony_ci{ 38648c2ecf20Sopenharmony_ci struct macb_queue *q = &lp->queues[0]; 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci q->rx_ring = dma_alloc_coherent(&lp->pdev->dev, 38678c2ecf20Sopenharmony_ci (AT91ETHER_MAX_RX_DESCR * 38688c2ecf20Sopenharmony_ci macb_dma_desc_get_size(lp)), 38698c2ecf20Sopenharmony_ci &q->rx_ring_dma, GFP_KERNEL); 38708c2ecf20Sopenharmony_ci if (!q->rx_ring) 38718c2ecf20Sopenharmony_ci return -ENOMEM; 38728c2ecf20Sopenharmony_ci 38738c2ecf20Sopenharmony_ci q->rx_buffers = dma_alloc_coherent(&lp->pdev->dev, 38748c2ecf20Sopenharmony_ci AT91ETHER_MAX_RX_DESCR * 38758c2ecf20Sopenharmony_ci AT91ETHER_MAX_RBUFF_SZ, 38768c2ecf20Sopenharmony_ci &q->rx_buffers_dma, GFP_KERNEL); 38778c2ecf20Sopenharmony_ci if (!q->rx_buffers) { 38788c2ecf20Sopenharmony_ci dma_free_coherent(&lp->pdev->dev, 38798c2ecf20Sopenharmony_ci AT91ETHER_MAX_RX_DESCR * 38808c2ecf20Sopenharmony_ci macb_dma_desc_get_size(lp), 38818c2ecf20Sopenharmony_ci q->rx_ring, q->rx_ring_dma); 38828c2ecf20Sopenharmony_ci q->rx_ring = NULL; 38838c2ecf20Sopenharmony_ci return -ENOMEM; 38848c2ecf20Sopenharmony_ci } 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci return 0; 38878c2ecf20Sopenharmony_ci} 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_cistatic void at91ether_free_coherent(struct macb *lp) 38908c2ecf20Sopenharmony_ci{ 38918c2ecf20Sopenharmony_ci struct macb_queue *q = &lp->queues[0]; 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci if (q->rx_ring) { 38948c2ecf20Sopenharmony_ci dma_free_coherent(&lp->pdev->dev, 38958c2ecf20Sopenharmony_ci AT91ETHER_MAX_RX_DESCR * 38968c2ecf20Sopenharmony_ci macb_dma_desc_get_size(lp), 38978c2ecf20Sopenharmony_ci q->rx_ring, q->rx_ring_dma); 38988c2ecf20Sopenharmony_ci q->rx_ring = NULL; 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ci if (q->rx_buffers) { 39028c2ecf20Sopenharmony_ci dma_free_coherent(&lp->pdev->dev, 39038c2ecf20Sopenharmony_ci AT91ETHER_MAX_RX_DESCR * 39048c2ecf20Sopenharmony_ci AT91ETHER_MAX_RBUFF_SZ, 39058c2ecf20Sopenharmony_ci q->rx_buffers, q->rx_buffers_dma); 39068c2ecf20Sopenharmony_ci q->rx_buffers = NULL; 39078c2ecf20Sopenharmony_ci } 39088c2ecf20Sopenharmony_ci} 39098c2ecf20Sopenharmony_ci 39108c2ecf20Sopenharmony_ci/* Initialize and start the Receiver and Transmit subsystems */ 39118c2ecf20Sopenharmony_cistatic int at91ether_start(struct macb *lp) 39128c2ecf20Sopenharmony_ci{ 39138c2ecf20Sopenharmony_ci struct macb_queue *q = &lp->queues[0]; 39148c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 39158c2ecf20Sopenharmony_ci dma_addr_t addr; 39168c2ecf20Sopenharmony_ci u32 ctl; 39178c2ecf20Sopenharmony_ci int i, ret; 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci ret = at91ether_alloc_coherent(lp); 39208c2ecf20Sopenharmony_ci if (ret) 39218c2ecf20Sopenharmony_ci return ret; 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci addr = q->rx_buffers_dma; 39248c2ecf20Sopenharmony_ci for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) { 39258c2ecf20Sopenharmony_ci desc = macb_rx_desc(q, i); 39268c2ecf20Sopenharmony_ci macb_set_addr(lp, desc, addr); 39278c2ecf20Sopenharmony_ci desc->ctrl = 0; 39288c2ecf20Sopenharmony_ci addr += AT91ETHER_MAX_RBUFF_SZ; 39298c2ecf20Sopenharmony_ci } 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_ci /* Set the Wrap bit on the last descriptor */ 39328c2ecf20Sopenharmony_ci desc->addr |= MACB_BIT(RX_WRAP); 39338c2ecf20Sopenharmony_ci 39348c2ecf20Sopenharmony_ci /* Reset buffer index */ 39358c2ecf20Sopenharmony_ci q->rx_tail = 0; 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci /* Program address of descriptor list in Rx Buffer Queue register */ 39388c2ecf20Sopenharmony_ci macb_writel(lp, RBQP, q->rx_ring_dma); 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_ci /* Enable Receive and Transmit */ 39418c2ecf20Sopenharmony_ci ctl = macb_readl(lp, NCR); 39428c2ecf20Sopenharmony_ci macb_writel(lp, NCR, ctl | MACB_BIT(RE) | MACB_BIT(TE)); 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci /* Enable MAC interrupts */ 39458c2ecf20Sopenharmony_ci macb_writel(lp, IER, MACB_BIT(RCOMP) | 39468c2ecf20Sopenharmony_ci MACB_BIT(RXUBR) | 39478c2ecf20Sopenharmony_ci MACB_BIT(ISR_TUND) | 39488c2ecf20Sopenharmony_ci MACB_BIT(ISR_RLE) | 39498c2ecf20Sopenharmony_ci MACB_BIT(TCOMP) | 39508c2ecf20Sopenharmony_ci MACB_BIT(RM9200_TBRE) | 39518c2ecf20Sopenharmony_ci MACB_BIT(ISR_ROVR) | 39528c2ecf20Sopenharmony_ci MACB_BIT(HRESP)); 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci return 0; 39558c2ecf20Sopenharmony_ci} 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_cistatic void at91ether_stop(struct macb *lp) 39588c2ecf20Sopenharmony_ci{ 39598c2ecf20Sopenharmony_ci u32 ctl; 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci /* Disable MAC interrupts */ 39628c2ecf20Sopenharmony_ci macb_writel(lp, IDR, MACB_BIT(RCOMP) | 39638c2ecf20Sopenharmony_ci MACB_BIT(RXUBR) | 39648c2ecf20Sopenharmony_ci MACB_BIT(ISR_TUND) | 39658c2ecf20Sopenharmony_ci MACB_BIT(ISR_RLE) | 39668c2ecf20Sopenharmony_ci MACB_BIT(TCOMP) | 39678c2ecf20Sopenharmony_ci MACB_BIT(RM9200_TBRE) | 39688c2ecf20Sopenharmony_ci MACB_BIT(ISR_ROVR) | 39698c2ecf20Sopenharmony_ci MACB_BIT(HRESP)); 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci /* Disable Receiver and Transmitter */ 39728c2ecf20Sopenharmony_ci ctl = macb_readl(lp, NCR); 39738c2ecf20Sopenharmony_ci macb_writel(lp, NCR, ctl & ~(MACB_BIT(TE) | MACB_BIT(RE))); 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci /* Free resources. */ 39768c2ecf20Sopenharmony_ci at91ether_free_coherent(lp); 39778c2ecf20Sopenharmony_ci} 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci/* Open the ethernet interface */ 39808c2ecf20Sopenharmony_cistatic int at91ether_open(struct net_device *dev) 39818c2ecf20Sopenharmony_ci{ 39828c2ecf20Sopenharmony_ci struct macb *lp = netdev_priv(dev); 39838c2ecf20Sopenharmony_ci u32 ctl; 39848c2ecf20Sopenharmony_ci int ret; 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(&lp->pdev->dev); 39878c2ecf20Sopenharmony_ci if (ret < 0) { 39888c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&lp->pdev->dev); 39898c2ecf20Sopenharmony_ci return ret; 39908c2ecf20Sopenharmony_ci } 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci /* Clear internal statistics */ 39938c2ecf20Sopenharmony_ci ctl = macb_readl(lp, NCR); 39948c2ecf20Sopenharmony_ci macb_writel(lp, NCR, ctl | MACB_BIT(CLRSTAT)); 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci macb_set_hwaddr(lp); 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ci ret = at91ether_start(lp); 39998c2ecf20Sopenharmony_ci if (ret) 40008c2ecf20Sopenharmony_ci goto pm_exit; 40018c2ecf20Sopenharmony_ci 40028c2ecf20Sopenharmony_ci ret = macb_phylink_connect(lp); 40038c2ecf20Sopenharmony_ci if (ret) 40048c2ecf20Sopenharmony_ci goto stop; 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci netif_start_queue(dev); 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_ci return 0; 40098c2ecf20Sopenharmony_ci 40108c2ecf20Sopenharmony_cistop: 40118c2ecf20Sopenharmony_ci at91ether_stop(lp); 40128c2ecf20Sopenharmony_cipm_exit: 40138c2ecf20Sopenharmony_ci pm_runtime_put_sync(&lp->pdev->dev); 40148c2ecf20Sopenharmony_ci return ret; 40158c2ecf20Sopenharmony_ci} 40168c2ecf20Sopenharmony_ci 40178c2ecf20Sopenharmony_ci/* Close the interface */ 40188c2ecf20Sopenharmony_cistatic int at91ether_close(struct net_device *dev) 40198c2ecf20Sopenharmony_ci{ 40208c2ecf20Sopenharmony_ci struct macb *lp = netdev_priv(dev); 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci netif_stop_queue(dev); 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci phylink_stop(lp->phylink); 40258c2ecf20Sopenharmony_ci phylink_disconnect_phy(lp->phylink); 40268c2ecf20Sopenharmony_ci 40278c2ecf20Sopenharmony_ci at91ether_stop(lp); 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_ci return pm_runtime_put(&lp->pdev->dev); 40308c2ecf20Sopenharmony_ci} 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci/* Transmit packet */ 40338c2ecf20Sopenharmony_cistatic netdev_tx_t at91ether_start_xmit(struct sk_buff *skb, 40348c2ecf20Sopenharmony_ci struct net_device *dev) 40358c2ecf20Sopenharmony_ci{ 40368c2ecf20Sopenharmony_ci struct macb *lp = netdev_priv(dev); 40378c2ecf20Sopenharmony_ci unsigned long flags; 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci if (lp->rm9200_tx_len < 2) { 40408c2ecf20Sopenharmony_ci int desc = lp->rm9200_tx_tail; 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci /* Store packet information (to free when Tx completed) */ 40438c2ecf20Sopenharmony_ci lp->rm9200_txq[desc].skb = skb; 40448c2ecf20Sopenharmony_ci lp->rm9200_txq[desc].size = skb->len; 40458c2ecf20Sopenharmony_ci lp->rm9200_txq[desc].mapping = dma_map_single(&lp->pdev->dev, skb->data, 40468c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 40478c2ecf20Sopenharmony_ci if (dma_mapping_error(&lp->pdev->dev, lp->rm9200_txq[desc].mapping)) { 40488c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 40498c2ecf20Sopenharmony_ci dev->stats.tx_dropped++; 40508c2ecf20Sopenharmony_ci netdev_err(dev, "%s: DMA mapping error\n", __func__); 40518c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 40528c2ecf20Sopenharmony_ci } 40538c2ecf20Sopenharmony_ci 40548c2ecf20Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci lp->rm9200_tx_tail = (desc + 1) & 1; 40578c2ecf20Sopenharmony_ci lp->rm9200_tx_len++; 40588c2ecf20Sopenharmony_ci if (lp->rm9200_tx_len > 1) 40598c2ecf20Sopenharmony_ci netif_stop_queue(dev); 40608c2ecf20Sopenharmony_ci 40618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci /* Set address of the data in the Transmit Address register */ 40648c2ecf20Sopenharmony_ci macb_writel(lp, TAR, lp->rm9200_txq[desc].mapping); 40658c2ecf20Sopenharmony_ci /* Set length of the packet in the Transmit Control register */ 40668c2ecf20Sopenharmony_ci macb_writel(lp, TCR, skb->len); 40678c2ecf20Sopenharmony_ci 40688c2ecf20Sopenharmony_ci } else { 40698c2ecf20Sopenharmony_ci netdev_err(dev, "%s called, but device is busy!\n", __func__); 40708c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 40718c2ecf20Sopenharmony_ci } 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 40748c2ecf20Sopenharmony_ci} 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci/* Extract received frame from buffer descriptors and sent to upper layers. 40778c2ecf20Sopenharmony_ci * (Called from interrupt context) 40788c2ecf20Sopenharmony_ci */ 40798c2ecf20Sopenharmony_cistatic void at91ether_rx(struct net_device *dev) 40808c2ecf20Sopenharmony_ci{ 40818c2ecf20Sopenharmony_ci struct macb *lp = netdev_priv(dev); 40828c2ecf20Sopenharmony_ci struct macb_queue *q = &lp->queues[0]; 40838c2ecf20Sopenharmony_ci struct macb_dma_desc *desc; 40848c2ecf20Sopenharmony_ci unsigned char *p_recv; 40858c2ecf20Sopenharmony_ci struct sk_buff *skb; 40868c2ecf20Sopenharmony_ci unsigned int pktlen; 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci desc = macb_rx_desc(q, q->rx_tail); 40898c2ecf20Sopenharmony_ci while (desc->addr & MACB_BIT(RX_USED)) { 40908c2ecf20Sopenharmony_ci p_recv = q->rx_buffers + q->rx_tail * AT91ETHER_MAX_RBUFF_SZ; 40918c2ecf20Sopenharmony_ci pktlen = MACB_BF(RX_FRMLEN, desc->ctrl); 40928c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, pktlen + 2); 40938c2ecf20Sopenharmony_ci if (skb) { 40948c2ecf20Sopenharmony_ci skb_reserve(skb, 2); 40958c2ecf20Sopenharmony_ci skb_put_data(skb, p_recv, pktlen); 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 40988c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 40998c2ecf20Sopenharmony_ci dev->stats.rx_bytes += pktlen; 41008c2ecf20Sopenharmony_ci netif_rx(skb); 41018c2ecf20Sopenharmony_ci } else { 41028c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 41038c2ecf20Sopenharmony_ci } 41048c2ecf20Sopenharmony_ci 41058c2ecf20Sopenharmony_ci if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH)) 41068c2ecf20Sopenharmony_ci dev->stats.multicast++; 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_ci /* reset ownership bit */ 41098c2ecf20Sopenharmony_ci desc->addr &= ~MACB_BIT(RX_USED); 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci /* wrap after last buffer */ 41128c2ecf20Sopenharmony_ci if (q->rx_tail == AT91ETHER_MAX_RX_DESCR - 1) 41138c2ecf20Sopenharmony_ci q->rx_tail = 0; 41148c2ecf20Sopenharmony_ci else 41158c2ecf20Sopenharmony_ci q->rx_tail++; 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci desc = macb_rx_desc(q, q->rx_tail); 41188c2ecf20Sopenharmony_ci } 41198c2ecf20Sopenharmony_ci} 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_ci/* MAC interrupt handler */ 41228c2ecf20Sopenharmony_cistatic irqreturn_t at91ether_interrupt(int irq, void *dev_id) 41238c2ecf20Sopenharmony_ci{ 41248c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 41258c2ecf20Sopenharmony_ci struct macb *lp = netdev_priv(dev); 41268c2ecf20Sopenharmony_ci u32 intstatus, ctl; 41278c2ecf20Sopenharmony_ci unsigned int desc; 41288c2ecf20Sopenharmony_ci unsigned int qlen; 41298c2ecf20Sopenharmony_ci u32 tsr; 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci /* MAC Interrupt Status register indicates what interrupts are pending. 41328c2ecf20Sopenharmony_ci * It is automatically cleared once read. 41338c2ecf20Sopenharmony_ci */ 41348c2ecf20Sopenharmony_ci intstatus = macb_readl(lp, ISR); 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci /* Receive complete */ 41378c2ecf20Sopenharmony_ci if (intstatus & MACB_BIT(RCOMP)) 41388c2ecf20Sopenharmony_ci at91ether_rx(dev); 41398c2ecf20Sopenharmony_ci 41408c2ecf20Sopenharmony_ci /* Transmit complete */ 41418c2ecf20Sopenharmony_ci if (intstatus & (MACB_BIT(TCOMP) | MACB_BIT(RM9200_TBRE))) { 41428c2ecf20Sopenharmony_ci /* The TCOM bit is set even if the transmission failed */ 41438c2ecf20Sopenharmony_ci if (intstatus & (MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE))) 41448c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci spin_lock(&lp->lock); 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_ci tsr = macb_readl(lp, TSR); 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_ci /* we have three possibilities here: 41518c2ecf20Sopenharmony_ci * - all pending packets transmitted (TGO, implies BNQ) 41528c2ecf20Sopenharmony_ci * - only first packet transmitted (!TGO && BNQ) 41538c2ecf20Sopenharmony_ci * - two frames pending (!TGO && !BNQ) 41548c2ecf20Sopenharmony_ci * Note that TGO ("transmit go") is called "IDLE" on RM9200. 41558c2ecf20Sopenharmony_ci */ 41568c2ecf20Sopenharmony_ci qlen = (tsr & MACB_BIT(TGO)) ? 0 : 41578c2ecf20Sopenharmony_ci (tsr & MACB_BIT(RM9200_BNQ)) ? 1 : 2; 41588c2ecf20Sopenharmony_ci 41598c2ecf20Sopenharmony_ci while (lp->rm9200_tx_len > qlen) { 41608c2ecf20Sopenharmony_ci desc = (lp->rm9200_tx_tail - lp->rm9200_tx_len) & 1; 41618c2ecf20Sopenharmony_ci dev_consume_skb_irq(lp->rm9200_txq[desc].skb); 41628c2ecf20Sopenharmony_ci lp->rm9200_txq[desc].skb = NULL; 41638c2ecf20Sopenharmony_ci dma_unmap_single(&lp->pdev->dev, lp->rm9200_txq[desc].mapping, 41648c2ecf20Sopenharmony_ci lp->rm9200_txq[desc].size, DMA_TO_DEVICE); 41658c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 41668c2ecf20Sopenharmony_ci dev->stats.tx_bytes += lp->rm9200_txq[desc].size; 41678c2ecf20Sopenharmony_ci lp->rm9200_tx_len--; 41688c2ecf20Sopenharmony_ci } 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_ci if (lp->rm9200_tx_len < 2 && netif_queue_stopped(dev)) 41718c2ecf20Sopenharmony_ci netif_wake_queue(dev); 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_ci spin_unlock(&lp->lock); 41748c2ecf20Sopenharmony_ci } 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci /* Work-around for EMAC Errata section 41.3.1 */ 41778c2ecf20Sopenharmony_ci if (intstatus & MACB_BIT(RXUBR)) { 41788c2ecf20Sopenharmony_ci ctl = macb_readl(lp, NCR); 41798c2ecf20Sopenharmony_ci macb_writel(lp, NCR, ctl & ~MACB_BIT(RE)); 41808c2ecf20Sopenharmony_ci wmb(); 41818c2ecf20Sopenharmony_ci macb_writel(lp, NCR, ctl | MACB_BIT(RE)); 41828c2ecf20Sopenharmony_ci } 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci if (intstatus & MACB_BIT(ISR_ROVR)) 41858c2ecf20Sopenharmony_ci netdev_err(dev, "ROVR error\n"); 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_ci return IRQ_HANDLED; 41888c2ecf20Sopenharmony_ci} 41898c2ecf20Sopenharmony_ci 41908c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 41918c2ecf20Sopenharmony_cistatic void at91ether_poll_controller(struct net_device *dev) 41928c2ecf20Sopenharmony_ci{ 41938c2ecf20Sopenharmony_ci unsigned long flags; 41948c2ecf20Sopenharmony_ci 41958c2ecf20Sopenharmony_ci local_irq_save(flags); 41968c2ecf20Sopenharmony_ci at91ether_interrupt(dev->irq, dev); 41978c2ecf20Sopenharmony_ci local_irq_restore(flags); 41988c2ecf20Sopenharmony_ci} 41998c2ecf20Sopenharmony_ci#endif 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_cistatic const struct net_device_ops at91ether_netdev_ops = { 42028c2ecf20Sopenharmony_ci .ndo_open = at91ether_open, 42038c2ecf20Sopenharmony_ci .ndo_stop = at91ether_close, 42048c2ecf20Sopenharmony_ci .ndo_start_xmit = at91ether_start_xmit, 42058c2ecf20Sopenharmony_ci .ndo_get_stats = macb_get_stats, 42068c2ecf20Sopenharmony_ci .ndo_set_rx_mode = macb_set_rx_mode, 42078c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 42088c2ecf20Sopenharmony_ci .ndo_do_ioctl = macb_ioctl, 42098c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 42108c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 42118c2ecf20Sopenharmony_ci .ndo_poll_controller = at91ether_poll_controller, 42128c2ecf20Sopenharmony_ci#endif 42138c2ecf20Sopenharmony_ci}; 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_cistatic int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk, 42168c2ecf20Sopenharmony_ci struct clk **hclk, struct clk **tx_clk, 42178c2ecf20Sopenharmony_ci struct clk **rx_clk, struct clk **tsu_clk) 42188c2ecf20Sopenharmony_ci{ 42198c2ecf20Sopenharmony_ci int err; 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_ci *hclk = NULL; 42228c2ecf20Sopenharmony_ci *tx_clk = NULL; 42238c2ecf20Sopenharmony_ci *rx_clk = NULL; 42248c2ecf20Sopenharmony_ci *tsu_clk = NULL; 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci *pclk = devm_clk_get(&pdev->dev, "ether_clk"); 42278c2ecf20Sopenharmony_ci if (IS_ERR(*pclk)) 42288c2ecf20Sopenharmony_ci return PTR_ERR(*pclk); 42298c2ecf20Sopenharmony_ci 42308c2ecf20Sopenharmony_ci err = clk_prepare_enable(*pclk); 42318c2ecf20Sopenharmony_ci if (err) { 42328c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable pclk (%d)\n", err); 42338c2ecf20Sopenharmony_ci return err; 42348c2ecf20Sopenharmony_ci } 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci return 0; 42378c2ecf20Sopenharmony_ci} 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_cistatic int at91ether_init(struct platform_device *pdev) 42408c2ecf20Sopenharmony_ci{ 42418c2ecf20Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 42428c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(dev); 42438c2ecf20Sopenharmony_ci int err; 42448c2ecf20Sopenharmony_ci 42458c2ecf20Sopenharmony_ci bp->queues[0].bp = bp; 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci dev->netdev_ops = &at91ether_netdev_ops; 42488c2ecf20Sopenharmony_ci dev->ethtool_ops = &macb_ethtool_ops; 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt, 42518c2ecf20Sopenharmony_ci 0, dev->name, dev); 42528c2ecf20Sopenharmony_ci if (err) 42538c2ecf20Sopenharmony_ci return err; 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci macb_writel(bp, NCR, 0); 42568c2ecf20Sopenharmony_ci 42578c2ecf20Sopenharmony_ci macb_writel(bp, NCFGR, MACB_BF(CLK, MACB_CLK_DIV32) | MACB_BIT(BIG)); 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci return 0; 42608c2ecf20Sopenharmony_ci} 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_cistatic unsigned long fu540_macb_tx_recalc_rate(struct clk_hw *hw, 42638c2ecf20Sopenharmony_ci unsigned long parent_rate) 42648c2ecf20Sopenharmony_ci{ 42658c2ecf20Sopenharmony_ci return mgmt->rate; 42668c2ecf20Sopenharmony_ci} 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_cistatic long fu540_macb_tx_round_rate(struct clk_hw *hw, unsigned long rate, 42698c2ecf20Sopenharmony_ci unsigned long *parent_rate) 42708c2ecf20Sopenharmony_ci{ 42718c2ecf20Sopenharmony_ci if (WARN_ON(rate < 2500000)) 42728c2ecf20Sopenharmony_ci return 2500000; 42738c2ecf20Sopenharmony_ci else if (rate == 2500000) 42748c2ecf20Sopenharmony_ci return 2500000; 42758c2ecf20Sopenharmony_ci else if (WARN_ON(rate < 13750000)) 42768c2ecf20Sopenharmony_ci return 2500000; 42778c2ecf20Sopenharmony_ci else if (WARN_ON(rate < 25000000)) 42788c2ecf20Sopenharmony_ci return 25000000; 42798c2ecf20Sopenharmony_ci else if (rate == 25000000) 42808c2ecf20Sopenharmony_ci return 25000000; 42818c2ecf20Sopenharmony_ci else if (WARN_ON(rate < 75000000)) 42828c2ecf20Sopenharmony_ci return 25000000; 42838c2ecf20Sopenharmony_ci else if (WARN_ON(rate < 125000000)) 42848c2ecf20Sopenharmony_ci return 125000000; 42858c2ecf20Sopenharmony_ci else if (rate == 125000000) 42868c2ecf20Sopenharmony_ci return 125000000; 42878c2ecf20Sopenharmony_ci 42888c2ecf20Sopenharmony_ci WARN_ON(rate > 125000000); 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci return 125000000; 42918c2ecf20Sopenharmony_ci} 42928c2ecf20Sopenharmony_ci 42938c2ecf20Sopenharmony_cistatic int fu540_macb_tx_set_rate(struct clk_hw *hw, unsigned long rate, 42948c2ecf20Sopenharmony_ci unsigned long parent_rate) 42958c2ecf20Sopenharmony_ci{ 42968c2ecf20Sopenharmony_ci rate = fu540_macb_tx_round_rate(hw, rate, &parent_rate); 42978c2ecf20Sopenharmony_ci if (rate != 125000000) 42988c2ecf20Sopenharmony_ci iowrite32(1, mgmt->reg); 42998c2ecf20Sopenharmony_ci else 43008c2ecf20Sopenharmony_ci iowrite32(0, mgmt->reg); 43018c2ecf20Sopenharmony_ci mgmt->rate = rate; 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_ci return 0; 43048c2ecf20Sopenharmony_ci} 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_cistatic const struct clk_ops fu540_c000_ops = { 43078c2ecf20Sopenharmony_ci .recalc_rate = fu540_macb_tx_recalc_rate, 43088c2ecf20Sopenharmony_ci .round_rate = fu540_macb_tx_round_rate, 43098c2ecf20Sopenharmony_ci .set_rate = fu540_macb_tx_set_rate, 43108c2ecf20Sopenharmony_ci}; 43118c2ecf20Sopenharmony_ci 43128c2ecf20Sopenharmony_cistatic int fu540_c000_clk_init(struct platform_device *pdev, struct clk **pclk, 43138c2ecf20Sopenharmony_ci struct clk **hclk, struct clk **tx_clk, 43148c2ecf20Sopenharmony_ci struct clk **rx_clk, struct clk **tsu_clk) 43158c2ecf20Sopenharmony_ci{ 43168c2ecf20Sopenharmony_ci struct clk_init_data init; 43178c2ecf20Sopenharmony_ci int err = 0; 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_ci err = macb_clk_init(pdev, pclk, hclk, tx_clk, rx_clk, tsu_clk); 43208c2ecf20Sopenharmony_ci if (err) 43218c2ecf20Sopenharmony_ci return err; 43228c2ecf20Sopenharmony_ci 43238c2ecf20Sopenharmony_ci mgmt = devm_kzalloc(&pdev->dev, sizeof(*mgmt), GFP_KERNEL); 43248c2ecf20Sopenharmony_ci if (!mgmt) 43258c2ecf20Sopenharmony_ci return -ENOMEM; 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci init.name = "sifive-gemgxl-mgmt"; 43288c2ecf20Sopenharmony_ci init.ops = &fu540_c000_ops; 43298c2ecf20Sopenharmony_ci init.flags = 0; 43308c2ecf20Sopenharmony_ci init.num_parents = 0; 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_ci mgmt->rate = 0; 43338c2ecf20Sopenharmony_ci mgmt->hw.init = &init; 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_ci *tx_clk = devm_clk_register(&pdev->dev, &mgmt->hw); 43368c2ecf20Sopenharmony_ci if (IS_ERR(*tx_clk)) 43378c2ecf20Sopenharmony_ci return PTR_ERR(*tx_clk); 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci err = clk_prepare_enable(*tx_clk); 43408c2ecf20Sopenharmony_ci if (err) 43418c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); 43428c2ecf20Sopenharmony_ci else 43438c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Registered clk switch '%s'\n", init.name); 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci return 0; 43468c2ecf20Sopenharmony_ci} 43478c2ecf20Sopenharmony_ci 43488c2ecf20Sopenharmony_cistatic int fu540_c000_init(struct platform_device *pdev) 43498c2ecf20Sopenharmony_ci{ 43508c2ecf20Sopenharmony_ci mgmt->reg = devm_platform_ioremap_resource(pdev, 1); 43518c2ecf20Sopenharmony_ci if (IS_ERR(mgmt->reg)) 43528c2ecf20Sopenharmony_ci return PTR_ERR(mgmt->reg); 43538c2ecf20Sopenharmony_ci 43548c2ecf20Sopenharmony_ci return macb_init(pdev); 43558c2ecf20Sopenharmony_ci} 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_cistatic const struct macb_config fu540_c000_config = { 43588c2ecf20Sopenharmony_ci .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO | 43598c2ecf20Sopenharmony_ci MACB_CAPS_GEM_HAS_PTP, 43608c2ecf20Sopenharmony_ci .dma_burst_length = 16, 43618c2ecf20Sopenharmony_ci .clk_init = fu540_c000_clk_init, 43628c2ecf20Sopenharmony_ci .init = fu540_c000_init, 43638c2ecf20Sopenharmony_ci .jumbo_max_len = 10240, 43648c2ecf20Sopenharmony_ci}; 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_cistatic const struct macb_config at91sam9260_config = { 43678c2ecf20Sopenharmony_ci .caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, 43688c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 43698c2ecf20Sopenharmony_ci .init = macb_init, 43708c2ecf20Sopenharmony_ci}; 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_cistatic const struct macb_config sama5d3macb_config = { 43738c2ecf20Sopenharmony_ci .caps = MACB_CAPS_SG_DISABLED 43748c2ecf20Sopenharmony_ci | MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, 43758c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 43768c2ecf20Sopenharmony_ci .init = macb_init, 43778c2ecf20Sopenharmony_ci}; 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_cistatic const struct macb_config pc302gem_config = { 43808c2ecf20Sopenharmony_ci .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, 43818c2ecf20Sopenharmony_ci .dma_burst_length = 16, 43828c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 43838c2ecf20Sopenharmony_ci .init = macb_init, 43848c2ecf20Sopenharmony_ci}; 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_cistatic const struct macb_config sama5d2_config = { 43878c2ecf20Sopenharmony_ci .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, 43888c2ecf20Sopenharmony_ci .dma_burst_length = 16, 43898c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 43908c2ecf20Sopenharmony_ci .init = macb_init, 43918c2ecf20Sopenharmony_ci}; 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_cistatic const struct macb_config sama5d3_config = { 43948c2ecf20Sopenharmony_ci .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE 43958c2ecf20Sopenharmony_ci | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_JUMBO, 43968c2ecf20Sopenharmony_ci .dma_burst_length = 16, 43978c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 43988c2ecf20Sopenharmony_ci .init = macb_init, 43998c2ecf20Sopenharmony_ci .jumbo_max_len = 10240, 44008c2ecf20Sopenharmony_ci}; 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_cistatic const struct macb_config sama5d4_config = { 44038c2ecf20Sopenharmony_ci .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, 44048c2ecf20Sopenharmony_ci .dma_burst_length = 4, 44058c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 44068c2ecf20Sopenharmony_ci .init = macb_init, 44078c2ecf20Sopenharmony_ci}; 44088c2ecf20Sopenharmony_ci 44098c2ecf20Sopenharmony_cistatic const struct macb_config emac_config = { 44108c2ecf20Sopenharmony_ci .caps = MACB_CAPS_NEEDS_RSTONUBR | MACB_CAPS_MACB_IS_EMAC, 44118c2ecf20Sopenharmony_ci .clk_init = at91ether_clk_init, 44128c2ecf20Sopenharmony_ci .init = at91ether_init, 44138c2ecf20Sopenharmony_ci}; 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_cistatic const struct macb_config np4_config = { 44168c2ecf20Sopenharmony_ci .caps = MACB_CAPS_USRIO_DISABLED, 44178c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 44188c2ecf20Sopenharmony_ci .init = macb_init, 44198c2ecf20Sopenharmony_ci}; 44208c2ecf20Sopenharmony_ci 44218c2ecf20Sopenharmony_cistatic const struct macb_config zynqmp_config = { 44228c2ecf20Sopenharmony_ci .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | 44238c2ecf20Sopenharmony_ci MACB_CAPS_JUMBO | 44248c2ecf20Sopenharmony_ci MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH, 44258c2ecf20Sopenharmony_ci .dma_burst_length = 16, 44268c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 44278c2ecf20Sopenharmony_ci .init = macb_init, 44288c2ecf20Sopenharmony_ci .jumbo_max_len = 10240, 44298c2ecf20Sopenharmony_ci}; 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_cistatic const struct macb_config zynq_config = { 44328c2ecf20Sopenharmony_ci .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF | 44338c2ecf20Sopenharmony_ci MACB_CAPS_NEEDS_RSTONUBR, 44348c2ecf20Sopenharmony_ci .dma_burst_length = 16, 44358c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 44368c2ecf20Sopenharmony_ci .init = macb_init, 44378c2ecf20Sopenharmony_ci}; 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_cistatic const struct of_device_id macb_dt_ids[] = { 44408c2ecf20Sopenharmony_ci { .compatible = "cdns,at32ap7000-macb" }, 44418c2ecf20Sopenharmony_ci { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config }, 44428c2ecf20Sopenharmony_ci { .compatible = "cdns,macb" }, 44438c2ecf20Sopenharmony_ci { .compatible = "cdns,np4-macb", .data = &np4_config }, 44448c2ecf20Sopenharmony_ci { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, 44458c2ecf20Sopenharmony_ci { .compatible = "cdns,gem", .data = &pc302gem_config }, 44468c2ecf20Sopenharmony_ci { .compatible = "cdns,sam9x60-macb", .data = &at91sam9260_config }, 44478c2ecf20Sopenharmony_ci { .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config }, 44488c2ecf20Sopenharmony_ci { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config }, 44498c2ecf20Sopenharmony_ci { .compatible = "atmel,sama5d3-macb", .data = &sama5d3macb_config }, 44508c2ecf20Sopenharmony_ci { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config }, 44518c2ecf20Sopenharmony_ci { .compatible = "cdns,at91rm9200-emac", .data = &emac_config }, 44528c2ecf20Sopenharmony_ci { .compatible = "cdns,emac", .data = &emac_config }, 44538c2ecf20Sopenharmony_ci { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config}, 44548c2ecf20Sopenharmony_ci { .compatible = "cdns,zynq-gem", .data = &zynq_config }, 44558c2ecf20Sopenharmony_ci { .compatible = "sifive,fu540-c000-gem", .data = &fu540_c000_config }, 44568c2ecf20Sopenharmony_ci { /* sentinel */ } 44578c2ecf20Sopenharmony_ci}; 44588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, macb_dt_ids); 44598c2ecf20Sopenharmony_ci#endif /* CONFIG_OF */ 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_cistatic const struct macb_config default_gem_config = { 44628c2ecf20Sopenharmony_ci .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | 44638c2ecf20Sopenharmony_ci MACB_CAPS_JUMBO | 44648c2ecf20Sopenharmony_ci MACB_CAPS_GEM_HAS_PTP, 44658c2ecf20Sopenharmony_ci .dma_burst_length = 16, 44668c2ecf20Sopenharmony_ci .clk_init = macb_clk_init, 44678c2ecf20Sopenharmony_ci .init = macb_init, 44688c2ecf20Sopenharmony_ci .jumbo_max_len = 10240, 44698c2ecf20Sopenharmony_ci}; 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_cistatic int macb_probe(struct platform_device *pdev) 44728c2ecf20Sopenharmony_ci{ 44738c2ecf20Sopenharmony_ci const struct macb_config *macb_config = &default_gem_config; 44748c2ecf20Sopenharmony_ci int (*clk_init)(struct platform_device *, struct clk **, 44758c2ecf20Sopenharmony_ci struct clk **, struct clk **, struct clk **, 44768c2ecf20Sopenharmony_ci struct clk **) = macb_config->clk_init; 44778c2ecf20Sopenharmony_ci int (*init)(struct platform_device *) = macb_config->init; 44788c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 44798c2ecf20Sopenharmony_ci struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL; 44808c2ecf20Sopenharmony_ci struct clk *tsu_clk = NULL; 44818c2ecf20Sopenharmony_ci unsigned int queue_mask, num_queues; 44828c2ecf20Sopenharmony_ci bool native_io; 44838c2ecf20Sopenharmony_ci phy_interface_t interface; 44848c2ecf20Sopenharmony_ci struct net_device *dev; 44858c2ecf20Sopenharmony_ci struct resource *regs; 44868c2ecf20Sopenharmony_ci void __iomem *mem; 44878c2ecf20Sopenharmony_ci const char *mac; 44888c2ecf20Sopenharmony_ci struct macb *bp; 44898c2ecf20Sopenharmony_ci int err, val; 44908c2ecf20Sopenharmony_ci 44918c2ecf20Sopenharmony_ci regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 44928c2ecf20Sopenharmony_ci mem = devm_ioremap_resource(&pdev->dev, regs); 44938c2ecf20Sopenharmony_ci if (IS_ERR(mem)) 44948c2ecf20Sopenharmony_ci return PTR_ERR(mem); 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci if (np) { 44978c2ecf20Sopenharmony_ci const struct of_device_id *match; 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ci match = of_match_node(macb_dt_ids, np); 45008c2ecf20Sopenharmony_ci if (match && match->data) { 45018c2ecf20Sopenharmony_ci macb_config = match->data; 45028c2ecf20Sopenharmony_ci clk_init = macb_config->clk_init; 45038c2ecf20Sopenharmony_ci init = macb_config->init; 45048c2ecf20Sopenharmony_ci } 45058c2ecf20Sopenharmony_ci } 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci err = clk_init(pdev, &pclk, &hclk, &tx_clk, &rx_clk, &tsu_clk); 45088c2ecf20Sopenharmony_ci if (err) 45098c2ecf20Sopenharmony_ci return err; 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, MACB_PM_TIMEOUT); 45128c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 45138c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 45148c2ecf20Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 45158c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 45168c2ecf20Sopenharmony_ci native_io = hw_is_native_io(mem); 45178c2ecf20Sopenharmony_ci 45188c2ecf20Sopenharmony_ci macb_probe_queues(mem, native_io, &queue_mask, &num_queues); 45198c2ecf20Sopenharmony_ci dev = alloc_etherdev_mq(sizeof(*bp), num_queues); 45208c2ecf20Sopenharmony_ci if (!dev) { 45218c2ecf20Sopenharmony_ci err = -ENOMEM; 45228c2ecf20Sopenharmony_ci goto err_disable_clocks; 45238c2ecf20Sopenharmony_ci } 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci dev->base_addr = regs->start; 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 45288c2ecf20Sopenharmony_ci 45298c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 45308c2ecf20Sopenharmony_ci bp->pdev = pdev; 45318c2ecf20Sopenharmony_ci bp->dev = dev; 45328c2ecf20Sopenharmony_ci bp->regs = mem; 45338c2ecf20Sopenharmony_ci bp->native_io = native_io; 45348c2ecf20Sopenharmony_ci if (native_io) { 45358c2ecf20Sopenharmony_ci bp->macb_reg_readl = hw_readl_native; 45368c2ecf20Sopenharmony_ci bp->macb_reg_writel = hw_writel_native; 45378c2ecf20Sopenharmony_ci } else { 45388c2ecf20Sopenharmony_ci bp->macb_reg_readl = hw_readl; 45398c2ecf20Sopenharmony_ci bp->macb_reg_writel = hw_writel; 45408c2ecf20Sopenharmony_ci } 45418c2ecf20Sopenharmony_ci bp->num_queues = num_queues; 45428c2ecf20Sopenharmony_ci bp->queue_mask = queue_mask; 45438c2ecf20Sopenharmony_ci if (macb_config) 45448c2ecf20Sopenharmony_ci bp->dma_burst_length = macb_config->dma_burst_length; 45458c2ecf20Sopenharmony_ci bp->pclk = pclk; 45468c2ecf20Sopenharmony_ci bp->hclk = hclk; 45478c2ecf20Sopenharmony_ci bp->tx_clk = tx_clk; 45488c2ecf20Sopenharmony_ci bp->rx_clk = rx_clk; 45498c2ecf20Sopenharmony_ci bp->tsu_clk = tsu_clk; 45508c2ecf20Sopenharmony_ci if (macb_config) 45518c2ecf20Sopenharmony_ci bp->jumbo_max_len = macb_config->jumbo_max_len; 45528c2ecf20Sopenharmony_ci 45538c2ecf20Sopenharmony_ci bp->wol = 0; 45548c2ecf20Sopenharmony_ci if (of_get_property(np, "magic-packet", NULL)) 45558c2ecf20Sopenharmony_ci bp->wol |= MACB_WOL_HAS_MAGIC_PACKET; 45568c2ecf20Sopenharmony_ci device_set_wakeup_capable(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET); 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_ci spin_lock_init(&bp->lock); 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci /* setup capabilities */ 45618c2ecf20Sopenharmony_ci macb_configure_caps(bp, macb_config); 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 45648c2ecf20Sopenharmony_ci if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { 45658c2ecf20Sopenharmony_ci dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); 45668c2ecf20Sopenharmony_ci bp->hw_dma_cap |= HW_DMA_CAP_64B; 45678c2ecf20Sopenharmony_ci } 45688c2ecf20Sopenharmony_ci#endif 45698c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 45708c2ecf20Sopenharmony_ci 45718c2ecf20Sopenharmony_ci dev->irq = platform_get_irq(pdev, 0); 45728c2ecf20Sopenharmony_ci if (dev->irq < 0) { 45738c2ecf20Sopenharmony_ci err = dev->irq; 45748c2ecf20Sopenharmony_ci goto err_out_free_netdev; 45758c2ecf20Sopenharmony_ci } 45768c2ecf20Sopenharmony_ci 45778c2ecf20Sopenharmony_ci /* MTU range: 68 - 1500 or 10240 */ 45788c2ecf20Sopenharmony_ci dev->min_mtu = GEM_MTU_MIN_SIZE; 45798c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_JUMBO) 45808c2ecf20Sopenharmony_ci dev->max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN; 45818c2ecf20Sopenharmony_ci else 45828c2ecf20Sopenharmony_ci dev->max_mtu = ETH_DATA_LEN; 45838c2ecf20Sopenharmony_ci 45848c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_BD_RD_PREFETCH) { 45858c2ecf20Sopenharmony_ci val = GEM_BFEXT(RXBD_RDBUFF, gem_readl(bp, DCFG10)); 45868c2ecf20Sopenharmony_ci if (val) 45878c2ecf20Sopenharmony_ci bp->rx_bd_rd_prefetch = (2 << (val - 1)) * 45888c2ecf20Sopenharmony_ci macb_dma_desc_get_size(bp); 45898c2ecf20Sopenharmony_ci 45908c2ecf20Sopenharmony_ci val = GEM_BFEXT(TXBD_RDBUFF, gem_readl(bp, DCFG10)); 45918c2ecf20Sopenharmony_ci if (val) 45928c2ecf20Sopenharmony_ci bp->tx_bd_rd_prefetch = (2 << (val - 1)) * 45938c2ecf20Sopenharmony_ci macb_dma_desc_get_size(bp); 45948c2ecf20Sopenharmony_ci } 45958c2ecf20Sopenharmony_ci 45968c2ecf20Sopenharmony_ci bp->rx_intr_mask = MACB_RX_INT_FLAGS; 45978c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_NEEDS_RSTONUBR) 45988c2ecf20Sopenharmony_ci bp->rx_intr_mask |= MACB_BIT(RXUBR); 45998c2ecf20Sopenharmony_ci 46008c2ecf20Sopenharmony_ci mac = of_get_mac_address(np); 46018c2ecf20Sopenharmony_ci if (PTR_ERR(mac) == -EPROBE_DEFER) { 46028c2ecf20Sopenharmony_ci err = -EPROBE_DEFER; 46038c2ecf20Sopenharmony_ci goto err_out_free_netdev; 46048c2ecf20Sopenharmony_ci } else if (!IS_ERR_OR_NULL(mac)) { 46058c2ecf20Sopenharmony_ci ether_addr_copy(bp->dev->dev_addr, mac); 46068c2ecf20Sopenharmony_ci } else { 46078c2ecf20Sopenharmony_ci macb_get_hwaddr(bp); 46088c2ecf20Sopenharmony_ci } 46098c2ecf20Sopenharmony_ci 46108c2ecf20Sopenharmony_ci err = of_get_phy_mode(np, &interface); 46118c2ecf20Sopenharmony_ci if (err) 46128c2ecf20Sopenharmony_ci /* not found in DT, MII by default */ 46138c2ecf20Sopenharmony_ci bp->phy_interface = PHY_INTERFACE_MODE_MII; 46148c2ecf20Sopenharmony_ci else 46158c2ecf20Sopenharmony_ci bp->phy_interface = interface; 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_ci /* IP specific init */ 46188c2ecf20Sopenharmony_ci err = init(pdev); 46198c2ecf20Sopenharmony_ci if (err) 46208c2ecf20Sopenharmony_ci goto err_out_free_netdev; 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci err = macb_mii_init(bp); 46238c2ecf20Sopenharmony_ci if (err) 46248c2ecf20Sopenharmony_ci goto err_out_free_netdev; 46258c2ecf20Sopenharmony_ci 46268c2ecf20Sopenharmony_ci netif_carrier_off(dev); 46278c2ecf20Sopenharmony_ci 46288c2ecf20Sopenharmony_ci err = register_netdev(dev); 46298c2ecf20Sopenharmony_ci if (err) { 46308c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); 46318c2ecf20Sopenharmony_ci goto err_out_unregister_mdio; 46328c2ecf20Sopenharmony_ci } 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_ci tasklet_setup(&bp->hresp_err_tasklet, macb_hresp_error_task); 46358c2ecf20Sopenharmony_ci 46368c2ecf20Sopenharmony_ci netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", 46378c2ecf20Sopenharmony_ci macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), 46388c2ecf20Sopenharmony_ci dev->base_addr, dev->irq, dev->dev_addr); 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&bp->pdev->dev); 46418c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(&bp->pdev->dev); 46428c2ecf20Sopenharmony_ci 46438c2ecf20Sopenharmony_ci return 0; 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_cierr_out_unregister_mdio: 46468c2ecf20Sopenharmony_ci mdiobus_unregister(bp->mii_bus); 46478c2ecf20Sopenharmony_ci mdiobus_free(bp->mii_bus); 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_cierr_out_free_netdev: 46508c2ecf20Sopenharmony_ci free_netdev(dev); 46518c2ecf20Sopenharmony_ci 46528c2ecf20Sopenharmony_cierr_disable_clocks: 46538c2ecf20Sopenharmony_ci clk_disable_unprepare(tx_clk); 46548c2ecf20Sopenharmony_ci clk_disable_unprepare(hclk); 46558c2ecf20Sopenharmony_ci clk_disable_unprepare(pclk); 46568c2ecf20Sopenharmony_ci clk_disable_unprepare(rx_clk); 46578c2ecf20Sopenharmony_ci clk_disable_unprepare(tsu_clk); 46588c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 46598c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 46608c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci return err; 46638c2ecf20Sopenharmony_ci} 46648c2ecf20Sopenharmony_ci 46658c2ecf20Sopenharmony_cistatic int macb_remove(struct platform_device *pdev) 46668c2ecf20Sopenharmony_ci{ 46678c2ecf20Sopenharmony_ci struct net_device *dev; 46688c2ecf20Sopenharmony_ci struct macb *bp; 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci dev = platform_get_drvdata(pdev); 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci if (dev) { 46738c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 46748c2ecf20Sopenharmony_ci mdiobus_unregister(bp->mii_bus); 46758c2ecf20Sopenharmony_ci mdiobus_free(bp->mii_bus); 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci unregister_netdev(dev); 46788c2ecf20Sopenharmony_ci tasklet_kill(&bp->hresp_err_tasklet); 46798c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 46808c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 46818c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(&pdev->dev)) { 46828c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->tx_clk); 46838c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->hclk); 46848c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->pclk); 46858c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->rx_clk); 46868c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->tsu_clk); 46878c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 46888c2ecf20Sopenharmony_ci } 46898c2ecf20Sopenharmony_ci phylink_destroy(bp->phylink); 46908c2ecf20Sopenharmony_ci free_netdev(dev); 46918c2ecf20Sopenharmony_ci } 46928c2ecf20Sopenharmony_ci 46938c2ecf20Sopenharmony_ci return 0; 46948c2ecf20Sopenharmony_ci} 46958c2ecf20Sopenharmony_ci 46968c2ecf20Sopenharmony_cistatic int __maybe_unused macb_suspend(struct device *dev) 46978c2ecf20Sopenharmony_ci{ 46988c2ecf20Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 46998c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 47008c2ecf20Sopenharmony_ci struct macb_queue *queue = bp->queues; 47018c2ecf20Sopenharmony_ci unsigned long flags; 47028c2ecf20Sopenharmony_ci unsigned int q; 47038c2ecf20Sopenharmony_ci int err; 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_ci if (!netif_running(netdev)) 47068c2ecf20Sopenharmony_ci return 0; 47078c2ecf20Sopenharmony_ci 47088c2ecf20Sopenharmony_ci if (bp->wol & MACB_WOL_ENABLED) { 47098c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 47108c2ecf20Sopenharmony_ci /* Flush all status bits */ 47118c2ecf20Sopenharmony_ci macb_writel(bp, TSR, -1); 47128c2ecf20Sopenharmony_ci macb_writel(bp, RSR, -1); 47138c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; 47148c2ecf20Sopenharmony_ci ++q, ++queue) { 47158c2ecf20Sopenharmony_ci /* Disable all interrupts */ 47168c2ecf20Sopenharmony_ci queue_writel(queue, IDR, -1); 47178c2ecf20Sopenharmony_ci queue_readl(queue, ISR); 47188c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 47198c2ecf20Sopenharmony_ci queue_writel(queue, ISR, -1); 47208c2ecf20Sopenharmony_ci } 47218c2ecf20Sopenharmony_ci /* Change interrupt handler and 47228c2ecf20Sopenharmony_ci * Enable WoL IRQ on queue 0 47238c2ecf20Sopenharmony_ci */ 47248c2ecf20Sopenharmony_ci devm_free_irq(dev, bp->queues[0].irq, bp->queues); 47258c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) { 47268c2ecf20Sopenharmony_ci err = devm_request_irq(dev, bp->queues[0].irq, gem_wol_interrupt, 47278c2ecf20Sopenharmony_ci IRQF_SHARED, netdev->name, bp->queues); 47288c2ecf20Sopenharmony_ci if (err) { 47298c2ecf20Sopenharmony_ci dev_err(dev, 47308c2ecf20Sopenharmony_ci "Unable to request IRQ %d (error %d)\n", 47318c2ecf20Sopenharmony_ci bp->queues[0].irq, err); 47328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 47338c2ecf20Sopenharmony_ci return err; 47348c2ecf20Sopenharmony_ci } 47358c2ecf20Sopenharmony_ci queue_writel(bp->queues, IER, GEM_BIT(WOL)); 47368c2ecf20Sopenharmony_ci gem_writel(bp, WOL, MACB_BIT(MAG)); 47378c2ecf20Sopenharmony_ci } else { 47388c2ecf20Sopenharmony_ci err = devm_request_irq(dev, bp->queues[0].irq, macb_wol_interrupt, 47398c2ecf20Sopenharmony_ci IRQF_SHARED, netdev->name, bp->queues); 47408c2ecf20Sopenharmony_ci if (err) { 47418c2ecf20Sopenharmony_ci dev_err(dev, 47428c2ecf20Sopenharmony_ci "Unable to request IRQ %d (error %d)\n", 47438c2ecf20Sopenharmony_ci bp->queues[0].irq, err); 47448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 47458c2ecf20Sopenharmony_ci return err; 47468c2ecf20Sopenharmony_ci } 47478c2ecf20Sopenharmony_ci queue_writel(bp->queues, IER, MACB_BIT(WOL)); 47488c2ecf20Sopenharmony_ci macb_writel(bp, WOL, MACB_BIT(MAG)); 47498c2ecf20Sopenharmony_ci } 47508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_ci enable_irq_wake(bp->queues[0].irq); 47538c2ecf20Sopenharmony_ci } 47548c2ecf20Sopenharmony_ci 47558c2ecf20Sopenharmony_ci netif_device_detach(netdev); 47568c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; 47578c2ecf20Sopenharmony_ci ++q, ++queue) 47588c2ecf20Sopenharmony_ci napi_disable(&queue->napi); 47598c2ecf20Sopenharmony_ci 47608c2ecf20Sopenharmony_ci if (!(bp->wol & MACB_WOL_ENABLED)) { 47618c2ecf20Sopenharmony_ci rtnl_lock(); 47628c2ecf20Sopenharmony_ci phylink_stop(bp->phylink); 47638c2ecf20Sopenharmony_ci rtnl_unlock(); 47648c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 47658c2ecf20Sopenharmony_ci macb_reset_hw(bp); 47668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 47678c2ecf20Sopenharmony_ci } 47688c2ecf20Sopenharmony_ci 47698c2ecf20Sopenharmony_ci if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) 47708c2ecf20Sopenharmony_ci bp->pm_data.usrio = macb_or_gem_readl(bp, USRIO); 47718c2ecf20Sopenharmony_ci 47728c2ecf20Sopenharmony_ci if (netdev->hw_features & NETIF_F_NTUPLE) 47738c2ecf20Sopenharmony_ci bp->pm_data.scrt2 = gem_readl_n(bp, ETHT, SCRT2_ETHT); 47748c2ecf20Sopenharmony_ci 47758c2ecf20Sopenharmony_ci if (bp->ptp_info) 47768c2ecf20Sopenharmony_ci bp->ptp_info->ptp_remove(netdev); 47778c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev)) 47788c2ecf20Sopenharmony_ci pm_runtime_force_suspend(dev); 47798c2ecf20Sopenharmony_ci 47808c2ecf20Sopenharmony_ci return 0; 47818c2ecf20Sopenharmony_ci} 47828c2ecf20Sopenharmony_ci 47838c2ecf20Sopenharmony_cistatic int __maybe_unused macb_resume(struct device *dev) 47848c2ecf20Sopenharmony_ci{ 47858c2ecf20Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 47868c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 47878c2ecf20Sopenharmony_ci struct macb_queue *queue = bp->queues; 47888c2ecf20Sopenharmony_ci unsigned long flags; 47898c2ecf20Sopenharmony_ci unsigned int q; 47908c2ecf20Sopenharmony_ci int err; 47918c2ecf20Sopenharmony_ci 47928c2ecf20Sopenharmony_ci if (!netif_running(netdev)) 47938c2ecf20Sopenharmony_ci return 0; 47948c2ecf20Sopenharmony_ci 47958c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev)) 47968c2ecf20Sopenharmony_ci pm_runtime_force_resume(dev); 47978c2ecf20Sopenharmony_ci 47988c2ecf20Sopenharmony_ci if (bp->wol & MACB_WOL_ENABLED) { 47998c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 48008c2ecf20Sopenharmony_ci /* Disable WoL */ 48018c2ecf20Sopenharmony_ci if (macb_is_gem(bp)) { 48028c2ecf20Sopenharmony_ci queue_writel(bp->queues, IDR, GEM_BIT(WOL)); 48038c2ecf20Sopenharmony_ci gem_writel(bp, WOL, 0); 48048c2ecf20Sopenharmony_ci } else { 48058c2ecf20Sopenharmony_ci queue_writel(bp->queues, IDR, MACB_BIT(WOL)); 48068c2ecf20Sopenharmony_ci macb_writel(bp, WOL, 0); 48078c2ecf20Sopenharmony_ci } 48088c2ecf20Sopenharmony_ci /* Clear ISR on queue 0 */ 48098c2ecf20Sopenharmony_ci queue_readl(bp->queues, ISR); 48108c2ecf20Sopenharmony_ci if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) 48118c2ecf20Sopenharmony_ci queue_writel(bp->queues, ISR, -1); 48128c2ecf20Sopenharmony_ci /* Replace interrupt handler on queue 0 */ 48138c2ecf20Sopenharmony_ci devm_free_irq(dev, bp->queues[0].irq, bp->queues); 48148c2ecf20Sopenharmony_ci err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt, 48158c2ecf20Sopenharmony_ci IRQF_SHARED, netdev->name, bp->queues); 48168c2ecf20Sopenharmony_ci if (err) { 48178c2ecf20Sopenharmony_ci dev_err(dev, 48188c2ecf20Sopenharmony_ci "Unable to request IRQ %d (error %d)\n", 48198c2ecf20Sopenharmony_ci bp->queues[0].irq, err); 48208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 48218c2ecf20Sopenharmony_ci return err; 48228c2ecf20Sopenharmony_ci } 48238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 48248c2ecf20Sopenharmony_ci 48258c2ecf20Sopenharmony_ci disable_irq_wake(bp->queues[0].irq); 48268c2ecf20Sopenharmony_ci 48278c2ecf20Sopenharmony_ci /* Now make sure we disable phy before moving 48288c2ecf20Sopenharmony_ci * to common restore path 48298c2ecf20Sopenharmony_ci */ 48308c2ecf20Sopenharmony_ci rtnl_lock(); 48318c2ecf20Sopenharmony_ci phylink_stop(bp->phylink); 48328c2ecf20Sopenharmony_ci rtnl_unlock(); 48338c2ecf20Sopenharmony_ci } 48348c2ecf20Sopenharmony_ci 48358c2ecf20Sopenharmony_ci for (q = 0, queue = bp->queues; q < bp->num_queues; 48368c2ecf20Sopenharmony_ci ++q, ++queue) 48378c2ecf20Sopenharmony_ci napi_enable(&queue->napi); 48388c2ecf20Sopenharmony_ci 48398c2ecf20Sopenharmony_ci if (netdev->hw_features & NETIF_F_NTUPLE) 48408c2ecf20Sopenharmony_ci gem_writel_n(bp, ETHT, SCRT2_ETHT, bp->pm_data.scrt2); 48418c2ecf20Sopenharmony_ci 48428c2ecf20Sopenharmony_ci if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) 48438c2ecf20Sopenharmony_ci macb_or_gem_writel(bp, USRIO, bp->pm_data.usrio); 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_ci macb_writel(bp, NCR, MACB_BIT(MPE)); 48468c2ecf20Sopenharmony_ci macb_init_hw(bp); 48478c2ecf20Sopenharmony_ci macb_set_rx_mode(netdev); 48488c2ecf20Sopenharmony_ci macb_restore_features(bp); 48498c2ecf20Sopenharmony_ci rtnl_lock(); 48508c2ecf20Sopenharmony_ci phylink_start(bp->phylink); 48518c2ecf20Sopenharmony_ci rtnl_unlock(); 48528c2ecf20Sopenharmony_ci 48538c2ecf20Sopenharmony_ci netif_device_attach(netdev); 48548c2ecf20Sopenharmony_ci if (bp->ptp_info) 48558c2ecf20Sopenharmony_ci bp->ptp_info->ptp_init(netdev); 48568c2ecf20Sopenharmony_ci 48578c2ecf20Sopenharmony_ci return 0; 48588c2ecf20Sopenharmony_ci} 48598c2ecf20Sopenharmony_ci 48608c2ecf20Sopenharmony_cistatic int __maybe_unused macb_runtime_suspend(struct device *dev) 48618c2ecf20Sopenharmony_ci{ 48628c2ecf20Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 48638c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 48648c2ecf20Sopenharmony_ci 48658c2ecf20Sopenharmony_ci if (!(device_may_wakeup(dev))) { 48668c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->tx_clk); 48678c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->hclk); 48688c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->pclk); 48698c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->rx_clk); 48708c2ecf20Sopenharmony_ci } 48718c2ecf20Sopenharmony_ci clk_disable_unprepare(bp->tsu_clk); 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci return 0; 48748c2ecf20Sopenharmony_ci} 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_cistatic int __maybe_unused macb_runtime_resume(struct device *dev) 48778c2ecf20Sopenharmony_ci{ 48788c2ecf20Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 48798c2ecf20Sopenharmony_ci struct macb *bp = netdev_priv(netdev); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci if (!(device_may_wakeup(dev))) { 48828c2ecf20Sopenharmony_ci clk_prepare_enable(bp->pclk); 48838c2ecf20Sopenharmony_ci clk_prepare_enable(bp->hclk); 48848c2ecf20Sopenharmony_ci clk_prepare_enable(bp->tx_clk); 48858c2ecf20Sopenharmony_ci clk_prepare_enable(bp->rx_clk); 48868c2ecf20Sopenharmony_ci } 48878c2ecf20Sopenharmony_ci clk_prepare_enable(bp->tsu_clk); 48888c2ecf20Sopenharmony_ci 48898c2ecf20Sopenharmony_ci return 0; 48908c2ecf20Sopenharmony_ci} 48918c2ecf20Sopenharmony_ci 48928c2ecf20Sopenharmony_cistatic const struct dev_pm_ops macb_pm_ops = { 48938c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(macb_suspend, macb_resume) 48948c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(macb_runtime_suspend, macb_runtime_resume, NULL) 48958c2ecf20Sopenharmony_ci}; 48968c2ecf20Sopenharmony_ci 48978c2ecf20Sopenharmony_cistatic struct platform_driver macb_driver = { 48988c2ecf20Sopenharmony_ci .probe = macb_probe, 48998c2ecf20Sopenharmony_ci .remove = macb_remove, 49008c2ecf20Sopenharmony_ci .driver = { 49018c2ecf20Sopenharmony_ci .name = "macb", 49028c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(macb_dt_ids), 49038c2ecf20Sopenharmony_ci .pm = &macb_pm_ops, 49048c2ecf20Sopenharmony_ci }, 49058c2ecf20Sopenharmony_ci}; 49068c2ecf20Sopenharmony_ci 49078c2ecf20Sopenharmony_cimodule_platform_driver(macb_driver); 49088c2ecf20Sopenharmony_ci 49098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 49108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver"); 49118c2ecf20Sopenharmony_ciMODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); 49128c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:macb"); 4913