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