162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cadence MACB/GEM Ethernet Controller driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-2006 Atmel Corporation
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/clk-provider.h>
1162306a36Sopenharmony_ci#include <linux/crc32.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/moduleparam.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <linux/circ_buf.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/init.h>
1962306a36Sopenharmony_ci#include <linux/io.h>
2062306a36Sopenharmony_ci#include <linux/gpio.h>
2162306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2262306a36Sopenharmony_ci#include <linux/interrupt.h>
2362306a36Sopenharmony_ci#include <linux/netdevice.h>
2462306a36Sopenharmony_ci#include <linux/etherdevice.h>
2562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2662306a36Sopenharmony_ci#include <linux/platform_device.h>
2762306a36Sopenharmony_ci#include <linux/phylink.h>
2862306a36Sopenharmony_ci#include <linux/of.h>
2962306a36Sopenharmony_ci#include <linux/of_gpio.h>
3062306a36Sopenharmony_ci#include <linux/of_mdio.h>
3162306a36Sopenharmony_ci#include <linux/of_net.h>
3262306a36Sopenharmony_ci#include <linux/ip.h>
3362306a36Sopenharmony_ci#include <linux/udp.h>
3462306a36Sopenharmony_ci#include <linux/tcp.h>
3562306a36Sopenharmony_ci#include <linux/iopoll.h>
3662306a36Sopenharmony_ci#include <linux/phy/phy.h>
3762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3862306a36Sopenharmony_ci#include <linux/ptp_classify.h>
3962306a36Sopenharmony_ci#include <linux/reset.h>
4062306a36Sopenharmony_ci#include <linux/firmware/xlnx-zynqmp.h>
4162306a36Sopenharmony_ci#include "macb.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* This structure is only used for MACB on SiFive FU540 devices */
4462306a36Sopenharmony_cistruct sifive_fu540_macb_mgmt {
4562306a36Sopenharmony_ci	void __iomem *reg;
4662306a36Sopenharmony_ci	unsigned long rate;
4762306a36Sopenharmony_ci	struct clk_hw hw;
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define MACB_RX_BUFFER_SIZE	128
5162306a36Sopenharmony_ci#define RX_BUFFER_MULTIPLE	64  /* bytes */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define DEFAULT_RX_RING_SIZE	512 /* must be power of 2 */
5462306a36Sopenharmony_ci#define MIN_RX_RING_SIZE	64
5562306a36Sopenharmony_ci#define MAX_RX_RING_SIZE	8192
5662306a36Sopenharmony_ci#define RX_RING_BYTES(bp)	(macb_dma_desc_get_size(bp)	\
5762306a36Sopenharmony_ci				 * (bp)->rx_ring_size)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define DEFAULT_TX_RING_SIZE	512 /* must be power of 2 */
6062306a36Sopenharmony_ci#define MIN_TX_RING_SIZE	64
6162306a36Sopenharmony_ci#define MAX_TX_RING_SIZE	4096
6262306a36Sopenharmony_ci#define TX_RING_BYTES(bp)	(macb_dma_desc_get_size(bp)	\
6362306a36Sopenharmony_ci				 * (bp)->tx_ring_size)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* level of occupied TX descriptors under which we wake up TX process */
6662306a36Sopenharmony_ci#define MACB_TX_WAKEUP_THRESH(bp)	(3 * (bp)->tx_ring_size / 4)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define MACB_RX_INT_FLAGS	(MACB_BIT(RCOMP) | MACB_BIT(ISR_ROVR))
6962306a36Sopenharmony_ci#define MACB_TX_ERR_FLAGS	(MACB_BIT(ISR_TUND)			\
7062306a36Sopenharmony_ci					| MACB_BIT(ISR_RLE)		\
7162306a36Sopenharmony_ci					| MACB_BIT(TXERR))
7262306a36Sopenharmony_ci#define MACB_TX_INT_FLAGS	(MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP)	\
7362306a36Sopenharmony_ci					| MACB_BIT(TXUBR))
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* Max length of transmit frame must be a multiple of 8 bytes */
7662306a36Sopenharmony_ci#define MACB_TX_LEN_ALIGN	8
7762306a36Sopenharmony_ci#define MACB_MAX_TX_LEN		((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1)))
7862306a36Sopenharmony_ci/* Limit maximum TX length as per Cadence TSO errata. This is to avoid a
7962306a36Sopenharmony_ci * false amba_error in TX path from the DMA assuming there is not enough
8062306a36Sopenharmony_ci * space in the SRAM (16KB) even when there is.
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_ci#define GEM_MAX_TX_LEN		(unsigned int)(0x3FC0)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define GEM_MTU_MIN_SIZE	ETH_MIN_MTU
8562306a36Sopenharmony_ci#define MACB_NETIF_LSO		NETIF_F_TSO
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define MACB_WOL_HAS_MAGIC_PACKET	(0x1 << 0)
8862306a36Sopenharmony_ci#define MACB_WOL_ENABLED		(0x1 << 1)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define HS_SPEED_10000M			4
9162306a36Sopenharmony_ci#define MACB_SERDES_RATE_10G		1
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* Graceful stop timeouts in us. We should allow up to
9462306a36Sopenharmony_ci * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci#define MACB_HALT_TIMEOUT	14000
9762306a36Sopenharmony_ci#define MACB_PM_TIMEOUT  100 /* ms */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define MACB_MDIO_TIMEOUT	1000000 /* in usecs */
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* DMA buffer descriptor might be different size
10262306a36Sopenharmony_ci * depends on hardware configuration:
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * 1. dma address width 32 bits:
10562306a36Sopenharmony_ci *    word 1: 32 bit address of Data Buffer
10662306a36Sopenharmony_ci *    word 2: control
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * 2. dma address width 64 bits:
10962306a36Sopenharmony_ci *    word 1: 32 bit address of Data Buffer
11062306a36Sopenharmony_ci *    word 2: control
11162306a36Sopenharmony_ci *    word 3: upper 32 bit address of Data Buffer
11262306a36Sopenharmony_ci *    word 4: unused
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * 3. dma address width 32 bits with hardware timestamping:
11562306a36Sopenharmony_ci *    word 1: 32 bit address of Data Buffer
11662306a36Sopenharmony_ci *    word 2: control
11762306a36Sopenharmony_ci *    word 3: timestamp word 1
11862306a36Sopenharmony_ci *    word 4: timestamp word 2
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * 4. dma address width 64 bits with hardware timestamping:
12162306a36Sopenharmony_ci *    word 1: 32 bit address of Data Buffer
12262306a36Sopenharmony_ci *    word 2: control
12362306a36Sopenharmony_ci *    word 3: upper 32 bit address of Data Buffer
12462306a36Sopenharmony_ci *    word 4: unused
12562306a36Sopenharmony_ci *    word 5: timestamp word 1
12662306a36Sopenharmony_ci *    word 6: timestamp word 2
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_cistatic unsigned int macb_dma_desc_get_size(struct macb *bp)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci#ifdef MACB_EXT_DESC
13162306a36Sopenharmony_ci	unsigned int desc_size;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	switch (bp->hw_dma_cap) {
13462306a36Sopenharmony_ci	case HW_DMA_CAP_64B:
13562306a36Sopenharmony_ci		desc_size = sizeof(struct macb_dma_desc)
13662306a36Sopenharmony_ci			+ sizeof(struct macb_dma_desc_64);
13762306a36Sopenharmony_ci		break;
13862306a36Sopenharmony_ci	case HW_DMA_CAP_PTP:
13962306a36Sopenharmony_ci		desc_size = sizeof(struct macb_dma_desc)
14062306a36Sopenharmony_ci			+ sizeof(struct macb_dma_desc_ptp);
14162306a36Sopenharmony_ci		break;
14262306a36Sopenharmony_ci	case HW_DMA_CAP_64B_PTP:
14362306a36Sopenharmony_ci		desc_size = sizeof(struct macb_dma_desc)
14462306a36Sopenharmony_ci			+ sizeof(struct macb_dma_desc_64)
14562306a36Sopenharmony_ci			+ sizeof(struct macb_dma_desc_ptp);
14662306a36Sopenharmony_ci		break;
14762306a36Sopenharmony_ci	default:
14862306a36Sopenharmony_ci		desc_size = sizeof(struct macb_dma_desc);
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	return desc_size;
15162306a36Sopenharmony_ci#endif
15262306a36Sopenharmony_ci	return sizeof(struct macb_dma_desc);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int desc_idx)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci#ifdef MACB_EXT_DESC
15862306a36Sopenharmony_ci	switch (bp->hw_dma_cap) {
15962306a36Sopenharmony_ci	case HW_DMA_CAP_64B:
16062306a36Sopenharmony_ci	case HW_DMA_CAP_PTP:
16162306a36Sopenharmony_ci		desc_idx <<= 1;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci	case HW_DMA_CAP_64B_PTP:
16462306a36Sopenharmony_ci		desc_idx *= 3;
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	default:
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci#endif
17062306a36Sopenharmony_ci	return desc_idx;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
17462306a36Sopenharmony_cistatic struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	return (struct macb_dma_desc_64 *)((void *)desc
17762306a36Sopenharmony_ci		+ sizeof(struct macb_dma_desc));
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci#endif
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/* Ring buffer accessors */
18262306a36Sopenharmony_cistatic unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	return index & (bp->tx_ring_size - 1);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue,
18862306a36Sopenharmony_ci					  unsigned int index)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	index = macb_tx_ring_wrap(queue->bp, index);
19162306a36Sopenharmony_ci	index = macb_adj_dma_desc_idx(queue->bp, index);
19262306a36Sopenharmony_ci	return &queue->tx_ring[index];
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue,
19662306a36Sopenharmony_ci				       unsigned int index)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	return &queue->tx_skb[macb_tx_ring_wrap(queue->bp, index)];
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic dma_addr_t macb_tx_dma(struct macb_queue *queue, unsigned int index)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	dma_addr_t offset;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	offset = macb_tx_ring_wrap(queue->bp, index) *
20662306a36Sopenharmony_ci			macb_dma_desc_get_size(queue->bp);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return queue->tx_ring_dma + offset;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	return index & (bp->rx_ring_size - 1);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic struct macb_dma_desc *macb_rx_desc(struct macb_queue *queue, unsigned int index)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	index = macb_rx_ring_wrap(queue->bp, index);
21962306a36Sopenharmony_ci	index = macb_adj_dma_desc_idx(queue->bp, index);
22062306a36Sopenharmony_ci	return &queue->rx_ring[index];
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic void *macb_rx_buffer(struct macb_queue *queue, unsigned int index)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	return queue->rx_buffers + queue->bp->rx_buffer_size *
22662306a36Sopenharmony_ci	       macb_rx_ring_wrap(queue->bp, index);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/* I/O accessors */
23062306a36Sopenharmony_cistatic u32 hw_readl_native(struct macb *bp, int offset)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	return __raw_readl(bp->regs + offset);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void hw_writel_native(struct macb *bp, int offset, u32 value)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	__raw_writel(value, bp->regs + offset);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic u32 hw_readl(struct macb *bp, int offset)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	return readl_relaxed(bp->regs + offset);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic void hw_writel(struct macb *bp, int offset, u32 value)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	writel_relaxed(value, bp->regs + offset);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/* Find the CPU endianness by using the loopback bit of NCR register. When the
25162306a36Sopenharmony_ci * CPU is in big endian we need to program swapped mode for management
25262306a36Sopenharmony_ci * descriptor access.
25362306a36Sopenharmony_ci */
25462306a36Sopenharmony_cistatic bool hw_is_native_io(void __iomem *addr)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	u32 value = MACB_BIT(LLB);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	__raw_writel(value, addr + MACB_NCR);
25962306a36Sopenharmony_ci	value = __raw_readl(addr + MACB_NCR);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* Write 0 back to disable everything */
26262306a36Sopenharmony_ci	__raw_writel(0, addr + MACB_NCR);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return value == MACB_BIT(LLB);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic bool hw_is_gem(void __iomem *addr, bool native_io)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	u32 id;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (native_io)
27262306a36Sopenharmony_ci		id = __raw_readl(addr + MACB_MID);
27362306a36Sopenharmony_ci	else
27462306a36Sopenharmony_ci		id = readl_relaxed(addr + MACB_MID);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return MACB_BFEXT(IDNUM, id) >= 0x2;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void macb_set_hwaddr(struct macb *bp)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	u32 bottom;
28262306a36Sopenharmony_ci	u16 top;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr));
28562306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA1B, bottom);
28662306a36Sopenharmony_ci	top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4)));
28762306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA1T, top);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (gem_has_ptp(bp)) {
29062306a36Sopenharmony_ci		gem_writel(bp, RXPTPUNI, bottom);
29162306a36Sopenharmony_ci		gem_writel(bp, TXPTPUNI, bottom);
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* Clear unused address register sets */
29562306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA2B, 0);
29662306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA2T, 0);
29762306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA3B, 0);
29862306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA3T, 0);
29962306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA4B, 0);
30062306a36Sopenharmony_ci	macb_or_gem_writel(bp, SA4T, 0);
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic void macb_get_hwaddr(struct macb *bp)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	u32 bottom;
30662306a36Sopenharmony_ci	u16 top;
30762306a36Sopenharmony_ci	u8 addr[6];
30862306a36Sopenharmony_ci	int i;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* Check all 4 address register for valid address */
31162306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
31262306a36Sopenharmony_ci		bottom = macb_or_gem_readl(bp, SA1B + i * 8);
31362306a36Sopenharmony_ci		top = macb_or_gem_readl(bp, SA1T + i * 8);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		addr[0] = bottom & 0xff;
31662306a36Sopenharmony_ci		addr[1] = (bottom >> 8) & 0xff;
31762306a36Sopenharmony_ci		addr[2] = (bottom >> 16) & 0xff;
31862306a36Sopenharmony_ci		addr[3] = (bottom >> 24) & 0xff;
31962306a36Sopenharmony_ci		addr[4] = top & 0xff;
32062306a36Sopenharmony_ci		addr[5] = (top >> 8) & 0xff;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		if (is_valid_ether_addr(addr)) {
32362306a36Sopenharmony_ci			eth_hw_addr_set(bp->dev, addr);
32462306a36Sopenharmony_ci			return;
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	dev_info(&bp->pdev->dev, "invalid hw address, using random\n");
32962306a36Sopenharmony_ci	eth_hw_addr_random(bp->dev);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int macb_mdio_wait_for_idle(struct macb *bp)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	u32 val;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE),
33762306a36Sopenharmony_ci				  1, MACB_MDIO_TIMEOUT);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int macb_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct macb *bp = bus->priv;
34362306a36Sopenharmony_ci	int status;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	status = pm_runtime_resume_and_get(&bp->pdev->dev);
34662306a36Sopenharmony_ci	if (status < 0)
34762306a36Sopenharmony_ci		goto mdio_pm_exit;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
35062306a36Sopenharmony_ci	if (status < 0)
35162306a36Sopenharmony_ci		goto mdio_read_exit;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
35462306a36Sopenharmony_ci			      | MACB_BF(RW, MACB_MAN_C22_READ)
35562306a36Sopenharmony_ci			      | MACB_BF(PHYA, mii_id)
35662306a36Sopenharmony_ci			      | MACB_BF(REGA, regnum)
35762306a36Sopenharmony_ci			      | MACB_BF(CODE, MACB_MAN_C22_CODE)));
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
36062306a36Sopenharmony_ci	if (status < 0)
36162306a36Sopenharmony_ci		goto mdio_read_exit;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	status = MACB_BFEXT(DATA, macb_readl(bp, MAN));
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cimdio_read_exit:
36662306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&bp->pdev->dev);
36762306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&bp->pdev->dev);
36862306a36Sopenharmony_cimdio_pm_exit:
36962306a36Sopenharmony_ci	return status;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int macb_mdio_read_c45(struct mii_bus *bus, int mii_id, int devad,
37362306a36Sopenharmony_ci			      int regnum)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct macb *bp = bus->priv;
37662306a36Sopenharmony_ci	int status;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	status = pm_runtime_get_sync(&bp->pdev->dev);
37962306a36Sopenharmony_ci	if (status < 0) {
38062306a36Sopenharmony_ci		pm_runtime_put_noidle(&bp->pdev->dev);
38162306a36Sopenharmony_ci		goto mdio_pm_exit;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
38562306a36Sopenharmony_ci	if (status < 0)
38662306a36Sopenharmony_ci		goto mdio_read_exit;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
38962306a36Sopenharmony_ci			      | MACB_BF(RW, MACB_MAN_C45_ADDR)
39062306a36Sopenharmony_ci			      | MACB_BF(PHYA, mii_id)
39162306a36Sopenharmony_ci			      | MACB_BF(REGA, devad & 0x1F)
39262306a36Sopenharmony_ci			      | MACB_BF(DATA, regnum & 0xFFFF)
39362306a36Sopenharmony_ci			      | MACB_BF(CODE, MACB_MAN_C45_CODE)));
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
39662306a36Sopenharmony_ci	if (status < 0)
39762306a36Sopenharmony_ci		goto mdio_read_exit;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
40062306a36Sopenharmony_ci			      | MACB_BF(RW, MACB_MAN_C45_READ)
40162306a36Sopenharmony_ci			      | MACB_BF(PHYA, mii_id)
40262306a36Sopenharmony_ci			      | MACB_BF(REGA, devad & 0x1F)
40362306a36Sopenharmony_ci			      | MACB_BF(CODE, MACB_MAN_C45_CODE)));
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
40662306a36Sopenharmony_ci	if (status < 0)
40762306a36Sopenharmony_ci		goto mdio_read_exit;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	status = MACB_BFEXT(DATA, macb_readl(bp, MAN));
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cimdio_read_exit:
41262306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&bp->pdev->dev);
41362306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&bp->pdev->dev);
41462306a36Sopenharmony_cimdio_pm_exit:
41562306a36Sopenharmony_ci	return status;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic int macb_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum,
41962306a36Sopenharmony_ci			       u16 value)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct macb *bp = bus->priv;
42262306a36Sopenharmony_ci	int status;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	status = pm_runtime_resume_and_get(&bp->pdev->dev);
42562306a36Sopenharmony_ci	if (status < 0)
42662306a36Sopenharmony_ci		goto mdio_pm_exit;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
42962306a36Sopenharmony_ci	if (status < 0)
43062306a36Sopenharmony_ci		goto mdio_write_exit;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
43362306a36Sopenharmony_ci			      | MACB_BF(RW, MACB_MAN_C22_WRITE)
43462306a36Sopenharmony_ci			      | MACB_BF(PHYA, mii_id)
43562306a36Sopenharmony_ci			      | MACB_BF(REGA, regnum)
43662306a36Sopenharmony_ci			      | MACB_BF(CODE, MACB_MAN_C22_CODE)
43762306a36Sopenharmony_ci			      | MACB_BF(DATA, value)));
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
44062306a36Sopenharmony_ci	if (status < 0)
44162306a36Sopenharmony_ci		goto mdio_write_exit;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cimdio_write_exit:
44462306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&bp->pdev->dev);
44562306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&bp->pdev->dev);
44662306a36Sopenharmony_cimdio_pm_exit:
44762306a36Sopenharmony_ci	return status;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic int macb_mdio_write_c45(struct mii_bus *bus, int mii_id,
45162306a36Sopenharmony_ci			       int devad, int regnum,
45262306a36Sopenharmony_ci			       u16 value)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct macb *bp = bus->priv;
45562306a36Sopenharmony_ci	int status;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	status = pm_runtime_get_sync(&bp->pdev->dev);
45862306a36Sopenharmony_ci	if (status < 0) {
45962306a36Sopenharmony_ci		pm_runtime_put_noidle(&bp->pdev->dev);
46062306a36Sopenharmony_ci		goto mdio_pm_exit;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
46462306a36Sopenharmony_ci	if (status < 0)
46562306a36Sopenharmony_ci		goto mdio_write_exit;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
46862306a36Sopenharmony_ci			      | MACB_BF(RW, MACB_MAN_C45_ADDR)
46962306a36Sopenharmony_ci			      | MACB_BF(PHYA, mii_id)
47062306a36Sopenharmony_ci			      | MACB_BF(REGA, devad & 0x1F)
47162306a36Sopenharmony_ci			      | MACB_BF(DATA, regnum & 0xFFFF)
47262306a36Sopenharmony_ci			      | MACB_BF(CODE, MACB_MAN_C45_CODE)));
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
47562306a36Sopenharmony_ci	if (status < 0)
47662306a36Sopenharmony_ci		goto mdio_write_exit;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
47962306a36Sopenharmony_ci			      | MACB_BF(RW, MACB_MAN_C45_WRITE)
48062306a36Sopenharmony_ci			      | MACB_BF(PHYA, mii_id)
48162306a36Sopenharmony_ci			      | MACB_BF(REGA, devad & 0x1F)
48262306a36Sopenharmony_ci			      | MACB_BF(CODE, MACB_MAN_C45_CODE)
48362306a36Sopenharmony_ci			      | MACB_BF(DATA, value)));
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	status = macb_mdio_wait_for_idle(bp);
48662306a36Sopenharmony_ci	if (status < 0)
48762306a36Sopenharmony_ci		goto mdio_write_exit;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cimdio_write_exit:
49062306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&bp->pdev->dev);
49162306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&bp->pdev->dev);
49262306a36Sopenharmony_cimdio_pm_exit:
49362306a36Sopenharmony_ci	return status;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic void macb_init_buffers(struct macb *bp)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct macb_queue *queue;
49962306a36Sopenharmony_ci	unsigned int q;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
50262306a36Sopenharmony_ci		queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma));
50362306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
50462306a36Sopenharmony_ci		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
50562306a36Sopenharmony_ci			queue_writel(queue, RBQPH,
50662306a36Sopenharmony_ci				     upper_32_bits(queue->rx_ring_dma));
50762306a36Sopenharmony_ci#endif
50862306a36Sopenharmony_ci		queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
50962306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
51062306a36Sopenharmony_ci		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
51162306a36Sopenharmony_ci			queue_writel(queue, TBQPH,
51262306a36Sopenharmony_ci				     upper_32_bits(queue->tx_ring_dma));
51362306a36Sopenharmony_ci#endif
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci/**
51862306a36Sopenharmony_ci * macb_set_tx_clk() - Set a clock to a new frequency
51962306a36Sopenharmony_ci * @bp:		pointer to struct macb
52062306a36Sopenharmony_ci * @speed:	New frequency in Hz
52162306a36Sopenharmony_ci */
52262306a36Sopenharmony_cistatic void macb_set_tx_clk(struct macb *bp, int speed)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	long ferr, rate, rate_rounded;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (!bp->tx_clk || (bp->caps & MACB_CAPS_CLK_HW_CHG))
52762306a36Sopenharmony_ci		return;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* In case of MII the PHY is the clock master */
53062306a36Sopenharmony_ci	if (bp->phy_interface == PHY_INTERFACE_MODE_MII)
53162306a36Sopenharmony_ci		return;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	switch (speed) {
53462306a36Sopenharmony_ci	case SPEED_10:
53562306a36Sopenharmony_ci		rate = 2500000;
53662306a36Sopenharmony_ci		break;
53762306a36Sopenharmony_ci	case SPEED_100:
53862306a36Sopenharmony_ci		rate = 25000000;
53962306a36Sopenharmony_ci		break;
54062306a36Sopenharmony_ci	case SPEED_1000:
54162306a36Sopenharmony_ci		rate = 125000000;
54262306a36Sopenharmony_ci		break;
54362306a36Sopenharmony_ci	default:
54462306a36Sopenharmony_ci		return;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	rate_rounded = clk_round_rate(bp->tx_clk, rate);
54862306a36Sopenharmony_ci	if (rate_rounded < 0)
54962306a36Sopenharmony_ci		return;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* RGMII allows 50 ppm frequency error. Test and warn if this limit
55262306a36Sopenharmony_ci	 * is not satisfied.
55362306a36Sopenharmony_ci	 */
55462306a36Sopenharmony_ci	ferr = abs(rate_rounded - rate);
55562306a36Sopenharmony_ci	ferr = DIV_ROUND_UP(ferr, rate / 100000);
55662306a36Sopenharmony_ci	if (ferr > 5)
55762306a36Sopenharmony_ci		netdev_warn(bp->dev,
55862306a36Sopenharmony_ci			    "unable to generate target frequency: %ld Hz\n",
55962306a36Sopenharmony_ci			    rate);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (clk_set_rate(bp->tx_clk, rate_rounded))
56262306a36Sopenharmony_ci		netdev_err(bp->dev, "adjusting tx_clk failed.\n");
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void macb_usx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
56662306a36Sopenharmony_ci				 phy_interface_t interface, int speed,
56762306a36Sopenharmony_ci				 int duplex)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct macb *bp = container_of(pcs, struct macb, phylink_usx_pcs);
57062306a36Sopenharmony_ci	u32 config;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	config = gem_readl(bp, USX_CONTROL);
57362306a36Sopenharmony_ci	config = GEM_BFINS(SERDES_RATE, MACB_SERDES_RATE_10G, config);
57462306a36Sopenharmony_ci	config = GEM_BFINS(USX_CTRL_SPEED, HS_SPEED_10000M, config);
57562306a36Sopenharmony_ci	config &= ~(GEM_BIT(TX_SCR_BYPASS) | GEM_BIT(RX_SCR_BYPASS));
57662306a36Sopenharmony_ci	config |= GEM_BIT(TX_EN);
57762306a36Sopenharmony_ci	gem_writel(bp, USX_CONTROL, config);
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic void macb_usx_pcs_get_state(struct phylink_pcs *pcs,
58162306a36Sopenharmony_ci				   struct phylink_link_state *state)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct macb *bp = container_of(pcs, struct macb, phylink_usx_pcs);
58462306a36Sopenharmony_ci	u32 val;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	state->speed = SPEED_10000;
58762306a36Sopenharmony_ci	state->duplex = 1;
58862306a36Sopenharmony_ci	state->an_complete = 1;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	val = gem_readl(bp, USX_STATUS);
59162306a36Sopenharmony_ci	state->link = !!(val & GEM_BIT(USX_BLOCK_LOCK));
59262306a36Sopenharmony_ci	val = gem_readl(bp, NCFGR);
59362306a36Sopenharmony_ci	if (val & GEM_BIT(PAE))
59462306a36Sopenharmony_ci		state->pause = MLO_PAUSE_RX;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic int macb_usx_pcs_config(struct phylink_pcs *pcs,
59862306a36Sopenharmony_ci			       unsigned int neg_mode,
59962306a36Sopenharmony_ci			       phy_interface_t interface,
60062306a36Sopenharmony_ci			       const unsigned long *advertising,
60162306a36Sopenharmony_ci			       bool permit_pause_to_mac)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	struct macb *bp = container_of(pcs, struct macb, phylink_usx_pcs);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	gem_writel(bp, USX_CONTROL, gem_readl(bp, USX_CONTROL) |
60662306a36Sopenharmony_ci		   GEM_BIT(SIGNAL_OK));
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	return 0;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic void macb_pcs_get_state(struct phylink_pcs *pcs,
61262306a36Sopenharmony_ci			       struct phylink_link_state *state)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	state->link = 0;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic void macb_pcs_an_restart(struct phylink_pcs *pcs)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	/* Not supported */
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic int macb_pcs_config(struct phylink_pcs *pcs,
62362306a36Sopenharmony_ci			   unsigned int neg_mode,
62462306a36Sopenharmony_ci			   phy_interface_t interface,
62562306a36Sopenharmony_ci			   const unsigned long *advertising,
62662306a36Sopenharmony_ci			   bool permit_pause_to_mac)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic const struct phylink_pcs_ops macb_phylink_usx_pcs_ops = {
63262306a36Sopenharmony_ci	.pcs_get_state = macb_usx_pcs_get_state,
63362306a36Sopenharmony_ci	.pcs_config = macb_usx_pcs_config,
63462306a36Sopenharmony_ci	.pcs_link_up = macb_usx_pcs_link_up,
63562306a36Sopenharmony_ci};
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic const struct phylink_pcs_ops macb_phylink_pcs_ops = {
63862306a36Sopenharmony_ci	.pcs_get_state = macb_pcs_get_state,
63962306a36Sopenharmony_ci	.pcs_an_restart = macb_pcs_an_restart,
64062306a36Sopenharmony_ci	.pcs_config = macb_pcs_config,
64162306a36Sopenharmony_ci};
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic void macb_mac_config(struct phylink_config *config, unsigned int mode,
64462306a36Sopenharmony_ci			    const struct phylink_link_state *state)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct net_device *ndev = to_net_dev(config->dev);
64762306a36Sopenharmony_ci	struct macb *bp = netdev_priv(ndev);
64862306a36Sopenharmony_ci	unsigned long flags;
64962306a36Sopenharmony_ci	u32 old_ctrl, ctrl;
65062306a36Sopenharmony_ci	u32 old_ncr, ncr;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	old_ctrl = ctrl = macb_or_gem_readl(bp, NCFGR);
65562306a36Sopenharmony_ci	old_ncr = ncr = macb_or_gem_readl(bp, NCR);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (bp->caps & MACB_CAPS_MACB_IS_EMAC) {
65862306a36Sopenharmony_ci		if (state->interface == PHY_INTERFACE_MODE_RMII)
65962306a36Sopenharmony_ci			ctrl |= MACB_BIT(RM9200_RMII);
66062306a36Sopenharmony_ci	} else if (macb_is_gem(bp)) {
66162306a36Sopenharmony_ci		ctrl &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL));
66262306a36Sopenharmony_ci		ncr &= ~GEM_BIT(ENABLE_HS_MAC);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		if (state->interface == PHY_INTERFACE_MODE_SGMII) {
66562306a36Sopenharmony_ci			ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
66662306a36Sopenharmony_ci		} else if (state->interface == PHY_INTERFACE_MODE_10GBASER) {
66762306a36Sopenharmony_ci			ctrl |= GEM_BIT(PCSSEL);
66862306a36Sopenharmony_ci			ncr |= GEM_BIT(ENABLE_HS_MAC);
66962306a36Sopenharmony_ci		} else if (bp->caps & MACB_CAPS_MIIONRGMII &&
67062306a36Sopenharmony_ci			   bp->phy_interface == PHY_INTERFACE_MODE_MII) {
67162306a36Sopenharmony_ci			ncr |= MACB_BIT(MIIONRGMII);
67262306a36Sopenharmony_ci		}
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Apply the new configuration, if any */
67662306a36Sopenharmony_ci	if (old_ctrl ^ ctrl)
67762306a36Sopenharmony_ci		macb_or_gem_writel(bp, NCFGR, ctrl);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (old_ncr ^ ncr)
68062306a36Sopenharmony_ci		macb_or_gem_writel(bp, NCR, ncr);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/* Disable AN for SGMII fixed link configuration, enable otherwise.
68362306a36Sopenharmony_ci	 * Must be written after PCSSEL is set in NCFGR,
68462306a36Sopenharmony_ci	 * otherwise writes will not take effect.
68562306a36Sopenharmony_ci	 */
68662306a36Sopenharmony_ci	if (macb_is_gem(bp) && state->interface == PHY_INTERFACE_MODE_SGMII) {
68762306a36Sopenharmony_ci		u32 pcsctrl, old_pcsctrl;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		old_pcsctrl = gem_readl(bp, PCSCNTRL);
69062306a36Sopenharmony_ci		if (mode == MLO_AN_FIXED)
69162306a36Sopenharmony_ci			pcsctrl = old_pcsctrl & ~GEM_BIT(PCSAUTONEG);
69262306a36Sopenharmony_ci		else
69362306a36Sopenharmony_ci			pcsctrl = old_pcsctrl | GEM_BIT(PCSAUTONEG);
69462306a36Sopenharmony_ci		if (old_pcsctrl != pcsctrl)
69562306a36Sopenharmony_ci			gem_writel(bp, PCSCNTRL, pcsctrl);
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic void macb_mac_link_down(struct phylink_config *config, unsigned int mode,
70262306a36Sopenharmony_ci			       phy_interface_t interface)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct net_device *ndev = to_net_dev(config->dev);
70562306a36Sopenharmony_ci	struct macb *bp = netdev_priv(ndev);
70662306a36Sopenharmony_ci	struct macb_queue *queue;
70762306a36Sopenharmony_ci	unsigned int q;
70862306a36Sopenharmony_ci	u32 ctrl;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
71162306a36Sopenharmony_ci		for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
71262306a36Sopenharmony_ci			queue_writel(queue, IDR,
71362306a36Sopenharmony_ci				     bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* Disable Rx and Tx */
71662306a36Sopenharmony_ci	ctrl = macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE));
71762306a36Sopenharmony_ci	macb_writel(bp, NCR, ctrl);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	netif_tx_stop_all_queues(ndev);
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic void macb_mac_link_up(struct phylink_config *config,
72362306a36Sopenharmony_ci			     struct phy_device *phy,
72462306a36Sopenharmony_ci			     unsigned int mode, phy_interface_t interface,
72562306a36Sopenharmony_ci			     int speed, int duplex,
72662306a36Sopenharmony_ci			     bool tx_pause, bool rx_pause)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct net_device *ndev = to_net_dev(config->dev);
72962306a36Sopenharmony_ci	struct macb *bp = netdev_priv(ndev);
73062306a36Sopenharmony_ci	struct macb_queue *queue;
73162306a36Sopenharmony_ci	unsigned long flags;
73262306a36Sopenharmony_ci	unsigned int q;
73362306a36Sopenharmony_ci	u32 ctrl;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	ctrl = macb_or_gem_readl(bp, NCFGR);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	ctrl &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (speed == SPEED_100)
74262306a36Sopenharmony_ci		ctrl |= MACB_BIT(SPD);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (duplex)
74562306a36Sopenharmony_ci		ctrl |= MACB_BIT(FD);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
74862306a36Sopenharmony_ci		ctrl &= ~MACB_BIT(PAE);
74962306a36Sopenharmony_ci		if (macb_is_gem(bp)) {
75062306a36Sopenharmony_ci			ctrl &= ~GEM_BIT(GBE);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci			if (speed == SPEED_1000)
75362306a36Sopenharmony_ci				ctrl |= GEM_BIT(GBE);
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci		if (rx_pause)
75762306a36Sopenharmony_ci			ctrl |= MACB_BIT(PAE);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		/* Initialize rings & buffers as clearing MACB_BIT(TE) in link down
76062306a36Sopenharmony_ci		 * cleared the pipeline and control registers.
76162306a36Sopenharmony_ci		 */
76262306a36Sopenharmony_ci		bp->macbgem_ops.mog_init_rings(bp);
76362306a36Sopenharmony_ci		macb_init_buffers(bp);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
76662306a36Sopenharmony_ci			queue_writel(queue, IER,
76762306a36Sopenharmony_ci				     bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	macb_or_gem_writel(bp, NCFGR, ctrl);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (bp->phy_interface == PHY_INTERFACE_MODE_10GBASER)
77362306a36Sopenharmony_ci		gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, HS_SPEED_10000M,
77462306a36Sopenharmony_ci							gem_readl(bp, HS_MAC_CONFIG)));
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
77962306a36Sopenharmony_ci		macb_set_tx_clk(bp, speed);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* Enable Rx and Tx; Enable PTP unicast */
78262306a36Sopenharmony_ci	ctrl = macb_readl(bp, NCR);
78362306a36Sopenharmony_ci	if (gem_has_ptp(bp))
78462306a36Sopenharmony_ci		ctrl |= MACB_BIT(PTPUNI);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	macb_writel(bp, NCR, ctrl | MACB_BIT(RE) | MACB_BIT(TE));
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	netif_tx_wake_all_queues(ndev);
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic struct phylink_pcs *macb_mac_select_pcs(struct phylink_config *config,
79262306a36Sopenharmony_ci					       phy_interface_t interface)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	struct net_device *ndev = to_net_dev(config->dev);
79562306a36Sopenharmony_ci	struct macb *bp = netdev_priv(ndev);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (interface == PHY_INTERFACE_MODE_10GBASER)
79862306a36Sopenharmony_ci		return &bp->phylink_usx_pcs;
79962306a36Sopenharmony_ci	else if (interface == PHY_INTERFACE_MODE_SGMII)
80062306a36Sopenharmony_ci		return &bp->phylink_sgmii_pcs;
80162306a36Sopenharmony_ci	else
80262306a36Sopenharmony_ci		return NULL;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic const struct phylink_mac_ops macb_phylink_ops = {
80662306a36Sopenharmony_ci	.mac_select_pcs = macb_mac_select_pcs,
80762306a36Sopenharmony_ci	.mac_config = macb_mac_config,
80862306a36Sopenharmony_ci	.mac_link_down = macb_mac_link_down,
80962306a36Sopenharmony_ci	.mac_link_up = macb_mac_link_up,
81062306a36Sopenharmony_ci};
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic bool macb_phy_handle_exists(struct device_node *dn)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	dn = of_parse_phandle(dn, "phy-handle", 0);
81562306a36Sopenharmony_ci	of_node_put(dn);
81662306a36Sopenharmony_ci	return dn != NULL;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int macb_phylink_connect(struct macb *bp)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	struct device_node *dn = bp->pdev->dev.of_node;
82262306a36Sopenharmony_ci	struct net_device *dev = bp->dev;
82362306a36Sopenharmony_ci	struct phy_device *phydev;
82462306a36Sopenharmony_ci	int ret;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (dn)
82762306a36Sopenharmony_ci		ret = phylink_of_phy_connect(bp->phylink, dn, 0);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if (!dn || (ret && !macb_phy_handle_exists(dn))) {
83062306a36Sopenharmony_ci		phydev = phy_find_first(bp->mii_bus);
83162306a36Sopenharmony_ci		if (!phydev) {
83262306a36Sopenharmony_ci			netdev_err(dev, "no PHY found\n");
83362306a36Sopenharmony_ci			return -ENXIO;
83462306a36Sopenharmony_ci		}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci		/* attach the mac to the phy */
83762306a36Sopenharmony_ci		ret = phylink_connect_phy(bp->phylink, phydev);
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (ret) {
84162306a36Sopenharmony_ci		netdev_err(dev, "Could not attach PHY (%d)\n", ret);
84262306a36Sopenharmony_ci		return ret;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	phylink_start(bp->phylink);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return 0;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic void macb_get_pcs_fixed_state(struct phylink_config *config,
85162306a36Sopenharmony_ci				     struct phylink_link_state *state)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct net_device *ndev = to_net_dev(config->dev);
85462306a36Sopenharmony_ci	struct macb *bp = netdev_priv(ndev);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	state->link = (macb_readl(bp, NSR) & MACB_BIT(NSR_LINK)) != 0;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci/* based on au1000_eth. c*/
86062306a36Sopenharmony_cistatic int macb_mii_probe(struct net_device *dev)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	bp->phylink_sgmii_pcs.ops = &macb_phylink_pcs_ops;
86562306a36Sopenharmony_ci	bp->phylink_sgmii_pcs.neg_mode = true;
86662306a36Sopenharmony_ci	bp->phylink_usx_pcs.ops = &macb_phylink_usx_pcs_ops;
86762306a36Sopenharmony_ci	bp->phylink_usx_pcs.neg_mode = true;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	bp->phylink_config.dev = &dev->dev;
87062306a36Sopenharmony_ci	bp->phylink_config.type = PHYLINK_NETDEV;
87162306a36Sopenharmony_ci	bp->phylink_config.mac_managed_pm = true;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
87462306a36Sopenharmony_ci		bp->phylink_config.poll_fixed_state = true;
87562306a36Sopenharmony_ci		bp->phylink_config.get_fixed_state = macb_get_pcs_fixed_state;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	bp->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
87962306a36Sopenharmony_ci		MAC_10 | MAC_100;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_MII,
88262306a36Sopenharmony_ci		  bp->phylink_config.supported_interfaces);
88362306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_RMII,
88462306a36Sopenharmony_ci		  bp->phylink_config.supported_interfaces);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* Determine what modes are supported */
88762306a36Sopenharmony_ci	if (macb_is_gem(bp) && (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
88862306a36Sopenharmony_ci		bp->phylink_config.mac_capabilities |= MAC_1000FD;
88962306a36Sopenharmony_ci		if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF))
89062306a36Sopenharmony_ci			bp->phylink_config.mac_capabilities |= MAC_1000HD;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_GMII,
89362306a36Sopenharmony_ci			  bp->phylink_config.supported_interfaces);
89462306a36Sopenharmony_ci		phy_interface_set_rgmii(bp->phylink_config.supported_interfaces);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		if (bp->caps & MACB_CAPS_PCS)
89762306a36Sopenharmony_ci			__set_bit(PHY_INTERFACE_MODE_SGMII,
89862306a36Sopenharmony_ci				  bp->phylink_config.supported_interfaces);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci		if (bp->caps & MACB_CAPS_HIGH_SPEED) {
90162306a36Sopenharmony_ci			__set_bit(PHY_INTERFACE_MODE_10GBASER,
90262306a36Sopenharmony_ci				  bp->phylink_config.supported_interfaces);
90362306a36Sopenharmony_ci			bp->phylink_config.mac_capabilities |= MAC_10000FD;
90462306a36Sopenharmony_ci		}
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	bp->phylink = phylink_create(&bp->phylink_config, bp->pdev->dev.fwnode,
90862306a36Sopenharmony_ci				     bp->phy_interface, &macb_phylink_ops);
90962306a36Sopenharmony_ci	if (IS_ERR(bp->phylink)) {
91062306a36Sopenharmony_ci		netdev_err(dev, "Could not create a phylink instance (%ld)\n",
91162306a36Sopenharmony_ci			   PTR_ERR(bp->phylink));
91262306a36Sopenharmony_ci		return PTR_ERR(bp->phylink);
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	return 0;
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic int macb_mdiobus_register(struct macb *bp)
91962306a36Sopenharmony_ci{
92062306a36Sopenharmony_ci	struct device_node *child, *np = bp->pdev->dev.of_node;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	/* If we have a child named mdio, probe it instead of looking for PHYs
92362306a36Sopenharmony_ci	 * directly under the MAC node
92462306a36Sopenharmony_ci	 */
92562306a36Sopenharmony_ci	child = of_get_child_by_name(np, "mdio");
92662306a36Sopenharmony_ci	if (child) {
92762306a36Sopenharmony_ci		int ret = of_mdiobus_register(bp->mii_bus, child);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		of_node_put(child);
93062306a36Sopenharmony_ci		return ret;
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	if (of_phy_is_fixed_link(np))
93462306a36Sopenharmony_ci		return mdiobus_register(bp->mii_bus);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	/* Only create the PHY from the device tree if at least one PHY is
93762306a36Sopenharmony_ci	 * described. Otherwise scan the entire MDIO bus. We do this to support
93862306a36Sopenharmony_ci	 * old device tree that did not follow the best practices and did not
93962306a36Sopenharmony_ci	 * describe their network PHYs.
94062306a36Sopenharmony_ci	 */
94162306a36Sopenharmony_ci	for_each_available_child_of_node(np, child)
94262306a36Sopenharmony_ci		if (of_mdiobus_child_is_phy(child)) {
94362306a36Sopenharmony_ci			/* The loop increments the child refcount,
94462306a36Sopenharmony_ci			 * decrement it before returning.
94562306a36Sopenharmony_ci			 */
94662306a36Sopenharmony_ci			of_node_put(child);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci			return of_mdiobus_register(bp->mii_bus, np);
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	return mdiobus_register(bp->mii_bus);
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_cistatic int macb_mii_init(struct macb *bp)
95562306a36Sopenharmony_ci{
95662306a36Sopenharmony_ci	int err = -ENXIO;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	/* Enable management port */
95962306a36Sopenharmony_ci	macb_writel(bp, NCR, MACB_BIT(MPE));
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	bp->mii_bus = mdiobus_alloc();
96262306a36Sopenharmony_ci	if (!bp->mii_bus) {
96362306a36Sopenharmony_ci		err = -ENOMEM;
96462306a36Sopenharmony_ci		goto err_out;
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	bp->mii_bus->name = "MACB_mii_bus";
96862306a36Sopenharmony_ci	bp->mii_bus->read = &macb_mdio_read_c22;
96962306a36Sopenharmony_ci	bp->mii_bus->write = &macb_mdio_write_c22;
97062306a36Sopenharmony_ci	bp->mii_bus->read_c45 = &macb_mdio_read_c45;
97162306a36Sopenharmony_ci	bp->mii_bus->write_c45 = &macb_mdio_write_c45;
97262306a36Sopenharmony_ci	snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
97362306a36Sopenharmony_ci		 bp->pdev->name, bp->pdev->id);
97462306a36Sopenharmony_ci	bp->mii_bus->priv = bp;
97562306a36Sopenharmony_ci	bp->mii_bus->parent = &bp->pdev->dev;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	err = macb_mdiobus_register(bp);
98062306a36Sopenharmony_ci	if (err)
98162306a36Sopenharmony_ci		goto err_out_free_mdiobus;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	err = macb_mii_probe(bp->dev);
98462306a36Sopenharmony_ci	if (err)
98562306a36Sopenharmony_ci		goto err_out_unregister_bus;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	return 0;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cierr_out_unregister_bus:
99062306a36Sopenharmony_ci	mdiobus_unregister(bp->mii_bus);
99162306a36Sopenharmony_cierr_out_free_mdiobus:
99262306a36Sopenharmony_ci	mdiobus_free(bp->mii_bus);
99362306a36Sopenharmony_cierr_out:
99462306a36Sopenharmony_ci	return err;
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic void macb_update_stats(struct macb *bp)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	u32 *p = &bp->hw_stats.macb.rx_pause_frames;
100062306a36Sopenharmony_ci	u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1;
100162306a36Sopenharmony_ci	int offset = MACB_PFR;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	for (; p < end; p++, offset += 4)
100662306a36Sopenharmony_ci		*p += bp->macb_reg_readl(bp, offset);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic int macb_halt_tx(struct macb *bp)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	unsigned long	halt_time, timeout;
101262306a36Sopenharmony_ci	u32		status;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT));
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT);
101762306a36Sopenharmony_ci	do {
101862306a36Sopenharmony_ci		halt_time = jiffies;
101962306a36Sopenharmony_ci		status = macb_readl(bp, TSR);
102062306a36Sopenharmony_ci		if (!(status & MACB_BIT(TGO)))
102162306a36Sopenharmony_ci			return 0;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci		udelay(250);
102462306a36Sopenharmony_ci	} while (time_before(halt_time, timeout));
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	return -ETIMEDOUT;
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budget)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	if (tx_skb->mapping) {
103262306a36Sopenharmony_ci		if (tx_skb->mapped_as_page)
103362306a36Sopenharmony_ci			dma_unmap_page(&bp->pdev->dev, tx_skb->mapping,
103462306a36Sopenharmony_ci				       tx_skb->size, DMA_TO_DEVICE);
103562306a36Sopenharmony_ci		else
103662306a36Sopenharmony_ci			dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
103762306a36Sopenharmony_ci					 tx_skb->size, DMA_TO_DEVICE);
103862306a36Sopenharmony_ci		tx_skb->mapping = 0;
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	if (tx_skb->skb) {
104262306a36Sopenharmony_ci		napi_consume_skb(tx_skb->skb, budget);
104362306a36Sopenharmony_ci		tx_skb->skb = NULL;
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_cistatic void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
105062306a36Sopenharmony_ci	struct macb_dma_desc_64 *desc_64;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
105362306a36Sopenharmony_ci		desc_64 = macb_64b_desc(bp, desc);
105462306a36Sopenharmony_ci		desc_64->addrh = upper_32_bits(addr);
105562306a36Sopenharmony_ci		/* The low bits of RX address contain the RX_USED bit, clearing
105662306a36Sopenharmony_ci		 * of which allows packet RX. Make sure the high bits are also
105762306a36Sopenharmony_ci		 * visible to HW at that point.
105862306a36Sopenharmony_ci		 */
105962306a36Sopenharmony_ci		dma_wmb();
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci#endif
106262306a36Sopenharmony_ci	desc->addr = lower_32_bits(addr);
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	dma_addr_t addr = 0;
106862306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
106962306a36Sopenharmony_ci	struct macb_dma_desc_64 *desc_64;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
107262306a36Sopenharmony_ci		desc_64 = macb_64b_desc(bp, desc);
107362306a36Sopenharmony_ci		addr = ((u64)(desc_64->addrh) << 32);
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci#endif
107662306a36Sopenharmony_ci	addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
107762306a36Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP
107862306a36Sopenharmony_ci	if (bp->hw_dma_cap & HW_DMA_CAP_PTP)
107962306a36Sopenharmony_ci		addr &= ~GEM_BIT(DMA_RXVALID);
108062306a36Sopenharmony_ci#endif
108162306a36Sopenharmony_ci	return addr;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic void macb_tx_error_task(struct work_struct *work)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct macb_queue	*queue = container_of(work, struct macb_queue,
108762306a36Sopenharmony_ci						      tx_error_task);
108862306a36Sopenharmony_ci	bool			halt_timeout = false;
108962306a36Sopenharmony_ci	struct macb		*bp = queue->bp;
109062306a36Sopenharmony_ci	struct macb_tx_skb	*tx_skb;
109162306a36Sopenharmony_ci	struct macb_dma_desc	*desc;
109262306a36Sopenharmony_ci	struct sk_buff		*skb;
109362306a36Sopenharmony_ci	unsigned int		tail;
109462306a36Sopenharmony_ci	unsigned long		flags;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	netdev_vdbg(bp->dev, "macb_tx_error_task: q = %u, t = %u, h = %u\n",
109762306a36Sopenharmony_ci		    (unsigned int)(queue - bp->queues),
109862306a36Sopenharmony_ci		    queue->tx_tail, queue->tx_head);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* Prevent the queue NAPI TX poll from running, as it calls
110162306a36Sopenharmony_ci	 * macb_tx_complete(), which in turn may call netif_wake_subqueue().
110262306a36Sopenharmony_ci	 * As explained below, we have to halt the transmission before updating
110362306a36Sopenharmony_ci	 * TBQP registers so we call netif_tx_stop_all_queues() to notify the
110462306a36Sopenharmony_ci	 * network engine about the macb/gem being halted.
110562306a36Sopenharmony_ci	 */
110662306a36Sopenharmony_ci	napi_disable(&queue->napi_tx);
110762306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	/* Make sure nobody is trying to queue up new packets */
111062306a36Sopenharmony_ci	netif_tx_stop_all_queues(bp->dev);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/* Stop transmission now
111362306a36Sopenharmony_ci	 * (in case we have just queued new packets)
111462306a36Sopenharmony_ci	 * macb/gem must be halted to write TBQP register
111562306a36Sopenharmony_ci	 */
111662306a36Sopenharmony_ci	if (macb_halt_tx(bp)) {
111762306a36Sopenharmony_ci		netdev_err(bp->dev, "BUG: halt tx timed out\n");
111862306a36Sopenharmony_ci		macb_writel(bp, NCR, macb_readl(bp, NCR) & (~MACB_BIT(TE)));
111962306a36Sopenharmony_ci		halt_timeout = true;
112062306a36Sopenharmony_ci	}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/* Treat frames in TX queue including the ones that caused the error.
112362306a36Sopenharmony_ci	 * Free transmit buffers in upper layer.
112462306a36Sopenharmony_ci	 */
112562306a36Sopenharmony_ci	for (tail = queue->tx_tail; tail != queue->tx_head; tail++) {
112662306a36Sopenharmony_ci		u32	ctrl;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		desc = macb_tx_desc(queue, tail);
112962306a36Sopenharmony_ci		ctrl = desc->ctrl;
113062306a36Sopenharmony_ci		tx_skb = macb_tx_skb(queue, tail);
113162306a36Sopenharmony_ci		skb = tx_skb->skb;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		if (ctrl & MACB_BIT(TX_USED)) {
113462306a36Sopenharmony_ci			/* skb is set for the last buffer of the frame */
113562306a36Sopenharmony_ci			while (!skb) {
113662306a36Sopenharmony_ci				macb_tx_unmap(bp, tx_skb, 0);
113762306a36Sopenharmony_ci				tail++;
113862306a36Sopenharmony_ci				tx_skb = macb_tx_skb(queue, tail);
113962306a36Sopenharmony_ci				skb = tx_skb->skb;
114062306a36Sopenharmony_ci			}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci			/* ctrl still refers to the first buffer descriptor
114362306a36Sopenharmony_ci			 * since it's the only one written back by the hardware
114462306a36Sopenharmony_ci			 */
114562306a36Sopenharmony_ci			if (!(ctrl & MACB_BIT(TX_BUF_EXHAUSTED))) {
114662306a36Sopenharmony_ci				netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n",
114762306a36Sopenharmony_ci					    macb_tx_ring_wrap(bp, tail),
114862306a36Sopenharmony_ci					    skb->data);
114962306a36Sopenharmony_ci				bp->dev->stats.tx_packets++;
115062306a36Sopenharmony_ci				queue->stats.tx_packets++;
115162306a36Sopenharmony_ci				bp->dev->stats.tx_bytes += skb->len;
115262306a36Sopenharmony_ci				queue->stats.tx_bytes += skb->len;
115362306a36Sopenharmony_ci			}
115462306a36Sopenharmony_ci		} else {
115562306a36Sopenharmony_ci			/* "Buffers exhausted mid-frame" errors may only happen
115662306a36Sopenharmony_ci			 * if the driver is buggy, so complain loudly about
115762306a36Sopenharmony_ci			 * those. Statistics are updated by hardware.
115862306a36Sopenharmony_ci			 */
115962306a36Sopenharmony_ci			if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
116062306a36Sopenharmony_ci				netdev_err(bp->dev,
116162306a36Sopenharmony_ci					   "BUG: TX buffers exhausted mid-frame\n");
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci			desc->ctrl = ctrl | MACB_BIT(TX_USED);
116462306a36Sopenharmony_ci		}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci		macb_tx_unmap(bp, tx_skb, 0);
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	/* Set end of TX queue */
117062306a36Sopenharmony_ci	desc = macb_tx_desc(queue, 0);
117162306a36Sopenharmony_ci	macb_set_addr(bp, desc, 0);
117262306a36Sopenharmony_ci	desc->ctrl = MACB_BIT(TX_USED);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	/* Make descriptor updates visible to hardware */
117562306a36Sopenharmony_ci	wmb();
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	/* Reinitialize the TX desc queue */
117862306a36Sopenharmony_ci	queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
117962306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
118062306a36Sopenharmony_ci	if (bp->hw_dma_cap & HW_DMA_CAP_64B)
118162306a36Sopenharmony_ci		queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma));
118262306a36Sopenharmony_ci#endif
118362306a36Sopenharmony_ci	/* Make TX ring reflect state of hardware */
118462306a36Sopenharmony_ci	queue->tx_head = 0;
118562306a36Sopenharmony_ci	queue->tx_tail = 0;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	/* Housework before enabling TX IRQ */
118862306a36Sopenharmony_ci	macb_writel(bp, TSR, macb_readl(bp, TSR));
118962306a36Sopenharmony_ci	queue_writel(queue, IER, MACB_TX_INT_FLAGS);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (halt_timeout)
119262306a36Sopenharmony_ci		macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE));
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	/* Now we are ready to start transmission again */
119562306a36Sopenharmony_ci	netif_tx_start_all_queues(bp->dev);
119662306a36Sopenharmony_ci	macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
119962306a36Sopenharmony_ci	napi_enable(&queue->napi_tx);
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic bool ptp_one_step_sync(struct sk_buff *skb)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	struct ptp_header *hdr;
120562306a36Sopenharmony_ci	unsigned int ptp_class;
120662306a36Sopenharmony_ci	u8 msgtype;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	/* No need to parse packet if PTP TS is not involved */
120962306a36Sopenharmony_ci	if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)))
121062306a36Sopenharmony_ci		goto not_oss;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/* Identify and return whether PTP one step sync is being processed */
121362306a36Sopenharmony_ci	ptp_class = ptp_classify_raw(skb);
121462306a36Sopenharmony_ci	if (ptp_class == PTP_CLASS_NONE)
121562306a36Sopenharmony_ci		goto not_oss;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	hdr = ptp_parse_header(skb, ptp_class);
121862306a36Sopenharmony_ci	if (!hdr)
121962306a36Sopenharmony_ci		goto not_oss;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (hdr->flag_field[0] & PTP_FLAG_TWOSTEP)
122262306a36Sopenharmony_ci		goto not_oss;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	msgtype = ptp_get_msgtype(hdr, ptp_class);
122562306a36Sopenharmony_ci	if (msgtype == PTP_MSGTYPE_SYNC)
122662306a36Sopenharmony_ci		return true;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cinot_oss:
122962306a36Sopenharmony_ci	return false;
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_cistatic int macb_tx_complete(struct macb_queue *queue, int budget)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	struct macb *bp = queue->bp;
123562306a36Sopenharmony_ci	u16 queue_index = queue - bp->queues;
123662306a36Sopenharmony_ci	unsigned int tail;
123762306a36Sopenharmony_ci	unsigned int head;
123862306a36Sopenharmony_ci	int packets = 0;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	spin_lock(&queue->tx_ptr_lock);
124162306a36Sopenharmony_ci	head = queue->tx_head;
124262306a36Sopenharmony_ci	for (tail = queue->tx_tail; tail != head && packets < budget; tail++) {
124362306a36Sopenharmony_ci		struct macb_tx_skb	*tx_skb;
124462306a36Sopenharmony_ci		struct sk_buff		*skb;
124562306a36Sopenharmony_ci		struct macb_dma_desc	*desc;
124662306a36Sopenharmony_ci		u32			ctrl;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci		desc = macb_tx_desc(queue, tail);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci		/* Make hw descriptor updates visible to CPU */
125162306a36Sopenharmony_ci		rmb();
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci		ctrl = desc->ctrl;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci		/* TX_USED bit is only set by hardware on the very first buffer
125662306a36Sopenharmony_ci		 * descriptor of the transmitted frame.
125762306a36Sopenharmony_ci		 */
125862306a36Sopenharmony_ci		if (!(ctrl & MACB_BIT(TX_USED)))
125962306a36Sopenharmony_ci			break;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci		/* Process all buffers of the current transmitted frame */
126262306a36Sopenharmony_ci		for (;; tail++) {
126362306a36Sopenharmony_ci			tx_skb = macb_tx_skb(queue, tail);
126462306a36Sopenharmony_ci			skb = tx_skb->skb;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci			/* First, update TX stats if needed */
126762306a36Sopenharmony_ci			if (skb) {
126862306a36Sopenharmony_ci				if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
126962306a36Sopenharmony_ci				    !ptp_one_step_sync(skb))
127062306a36Sopenharmony_ci					gem_ptp_do_txstamp(bp, skb, desc);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci				netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
127362306a36Sopenharmony_ci					    macb_tx_ring_wrap(bp, tail),
127462306a36Sopenharmony_ci					    skb->data);
127562306a36Sopenharmony_ci				bp->dev->stats.tx_packets++;
127662306a36Sopenharmony_ci				queue->stats.tx_packets++;
127762306a36Sopenharmony_ci				bp->dev->stats.tx_bytes += skb->len;
127862306a36Sopenharmony_ci				queue->stats.tx_bytes += skb->len;
127962306a36Sopenharmony_ci				packets++;
128062306a36Sopenharmony_ci			}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci			/* Now we can safely release resources */
128362306a36Sopenharmony_ci			macb_tx_unmap(bp, tx_skb, budget);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci			/* skb is set only for the last buffer of the frame.
128662306a36Sopenharmony_ci			 * WARNING: at this point skb has been freed by
128762306a36Sopenharmony_ci			 * macb_tx_unmap().
128862306a36Sopenharmony_ci			 */
128962306a36Sopenharmony_ci			if (skb)
129062306a36Sopenharmony_ci				break;
129162306a36Sopenharmony_ci		}
129262306a36Sopenharmony_ci	}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	queue->tx_tail = tail;
129562306a36Sopenharmony_ci	if (__netif_subqueue_stopped(bp->dev, queue_index) &&
129662306a36Sopenharmony_ci	    CIRC_CNT(queue->tx_head, queue->tx_tail,
129762306a36Sopenharmony_ci		     bp->tx_ring_size) <= MACB_TX_WAKEUP_THRESH(bp))
129862306a36Sopenharmony_ci		netif_wake_subqueue(bp->dev, queue_index);
129962306a36Sopenharmony_ci	spin_unlock(&queue->tx_ptr_lock);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	return packets;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_cistatic void gem_rx_refill(struct macb_queue *queue)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	unsigned int		entry;
130762306a36Sopenharmony_ci	struct sk_buff		*skb;
130862306a36Sopenharmony_ci	dma_addr_t		paddr;
130962306a36Sopenharmony_ci	struct macb *bp = queue->bp;
131062306a36Sopenharmony_ci	struct macb_dma_desc *desc;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	while (CIRC_SPACE(queue->rx_prepared_head, queue->rx_tail,
131362306a36Sopenharmony_ci			bp->rx_ring_size) > 0) {
131462306a36Sopenharmony_ci		entry = macb_rx_ring_wrap(bp, queue->rx_prepared_head);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci		/* Make hw descriptor updates visible to CPU */
131762306a36Sopenharmony_ci		rmb();
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		desc = macb_rx_desc(queue, entry);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci		if (!queue->rx_skbuff[entry]) {
132262306a36Sopenharmony_ci			/* allocate sk_buff for this free entry in ring */
132362306a36Sopenharmony_ci			skb = netdev_alloc_skb(bp->dev, bp->rx_buffer_size);
132462306a36Sopenharmony_ci			if (unlikely(!skb)) {
132562306a36Sopenharmony_ci				netdev_err(bp->dev,
132662306a36Sopenharmony_ci					   "Unable to allocate sk_buff\n");
132762306a36Sopenharmony_ci				break;
132862306a36Sopenharmony_ci			}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci			/* now fill corresponding descriptor entry */
133162306a36Sopenharmony_ci			paddr = dma_map_single(&bp->pdev->dev, skb->data,
133262306a36Sopenharmony_ci					       bp->rx_buffer_size,
133362306a36Sopenharmony_ci					       DMA_FROM_DEVICE);
133462306a36Sopenharmony_ci			if (dma_mapping_error(&bp->pdev->dev, paddr)) {
133562306a36Sopenharmony_ci				dev_kfree_skb(skb);
133662306a36Sopenharmony_ci				break;
133762306a36Sopenharmony_ci			}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci			queue->rx_skbuff[entry] = skb;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci			if (entry == bp->rx_ring_size - 1)
134262306a36Sopenharmony_ci				paddr |= MACB_BIT(RX_WRAP);
134362306a36Sopenharmony_ci			desc->ctrl = 0;
134462306a36Sopenharmony_ci			/* Setting addr clears RX_USED and allows reception,
134562306a36Sopenharmony_ci			 * make sure ctrl is cleared first to avoid a race.
134662306a36Sopenharmony_ci			 */
134762306a36Sopenharmony_ci			dma_wmb();
134862306a36Sopenharmony_ci			macb_set_addr(bp, desc, paddr);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci			/* properly align Ethernet header */
135162306a36Sopenharmony_ci			skb_reserve(skb, NET_IP_ALIGN);
135262306a36Sopenharmony_ci		} else {
135362306a36Sopenharmony_ci			desc->ctrl = 0;
135462306a36Sopenharmony_ci			dma_wmb();
135562306a36Sopenharmony_ci			desc->addr &= ~MACB_BIT(RX_USED);
135662306a36Sopenharmony_ci		}
135762306a36Sopenharmony_ci		queue->rx_prepared_head++;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	/* Make descriptor updates visible to hardware */
136162306a36Sopenharmony_ci	wmb();
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	netdev_vdbg(bp->dev, "rx ring: queue: %p, prepared head %d, tail %d\n",
136462306a36Sopenharmony_ci			queue, queue->rx_prepared_head, queue->rx_tail);
136562306a36Sopenharmony_ci}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci/* Mark DMA descriptors from begin up to and not including end as unused */
136862306a36Sopenharmony_cistatic void discard_partial_frame(struct macb_queue *queue, unsigned int begin,
136962306a36Sopenharmony_ci				  unsigned int end)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	unsigned int frag;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	for (frag = begin; frag != end; frag++) {
137462306a36Sopenharmony_ci		struct macb_dma_desc *desc = macb_rx_desc(queue, frag);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci		desc->addr &= ~MACB_BIT(RX_USED);
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/* Make descriptor updates visible to hardware */
138062306a36Sopenharmony_ci	wmb();
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	/* When this happens, the hardware stats registers for
138362306a36Sopenharmony_ci	 * whatever caused this is updated, so we don't have to record
138462306a36Sopenharmony_ci	 * anything.
138562306a36Sopenharmony_ci	 */
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_cistatic int gem_rx(struct macb_queue *queue, struct napi_struct *napi,
138962306a36Sopenharmony_ci		  int budget)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct macb *bp = queue->bp;
139262306a36Sopenharmony_ci	unsigned int		len;
139362306a36Sopenharmony_ci	unsigned int		entry;
139462306a36Sopenharmony_ci	struct sk_buff		*skb;
139562306a36Sopenharmony_ci	struct macb_dma_desc	*desc;
139662306a36Sopenharmony_ci	int			count = 0;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	while (count < budget) {
139962306a36Sopenharmony_ci		u32 ctrl;
140062306a36Sopenharmony_ci		dma_addr_t addr;
140162306a36Sopenharmony_ci		bool rxused;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci		entry = macb_rx_ring_wrap(bp, queue->rx_tail);
140462306a36Sopenharmony_ci		desc = macb_rx_desc(queue, entry);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci		/* Make hw descriptor updates visible to CPU */
140762306a36Sopenharmony_ci		rmb();
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
141062306a36Sopenharmony_ci		addr = macb_get_addr(bp, desc);
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci		if (!rxused)
141362306a36Sopenharmony_ci			break;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		/* Ensure ctrl is at least as up-to-date as rxused */
141662306a36Sopenharmony_ci		dma_rmb();
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci		ctrl = desc->ctrl;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci		queue->rx_tail++;
142162306a36Sopenharmony_ci		count++;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci		if (!(ctrl & MACB_BIT(RX_SOF) && ctrl & MACB_BIT(RX_EOF))) {
142462306a36Sopenharmony_ci			netdev_err(bp->dev,
142562306a36Sopenharmony_ci				   "not whole frame pointed by descriptor\n");
142662306a36Sopenharmony_ci			bp->dev->stats.rx_dropped++;
142762306a36Sopenharmony_ci			queue->stats.rx_dropped++;
142862306a36Sopenharmony_ci			break;
142962306a36Sopenharmony_ci		}
143062306a36Sopenharmony_ci		skb = queue->rx_skbuff[entry];
143162306a36Sopenharmony_ci		if (unlikely(!skb)) {
143262306a36Sopenharmony_ci			netdev_err(bp->dev,
143362306a36Sopenharmony_ci				   "inconsistent Rx descriptor chain\n");
143462306a36Sopenharmony_ci			bp->dev->stats.rx_dropped++;
143562306a36Sopenharmony_ci			queue->stats.rx_dropped++;
143662306a36Sopenharmony_ci			break;
143762306a36Sopenharmony_ci		}
143862306a36Sopenharmony_ci		/* now everything is ready for receiving packet */
143962306a36Sopenharmony_ci		queue->rx_skbuff[entry] = NULL;
144062306a36Sopenharmony_ci		len = ctrl & bp->rx_frm_len_mask;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci		netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci		skb_put(skb, len);
144562306a36Sopenharmony_ci		dma_unmap_single(&bp->pdev->dev, addr,
144662306a36Sopenharmony_ci				 bp->rx_buffer_size, DMA_FROM_DEVICE);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, bp->dev);
144962306a36Sopenharmony_ci		skb_checksum_none_assert(skb);
145062306a36Sopenharmony_ci		if (bp->dev->features & NETIF_F_RXCSUM &&
145162306a36Sopenharmony_ci		    !(bp->dev->flags & IFF_PROMISC) &&
145262306a36Sopenharmony_ci		    GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK)
145362306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		bp->dev->stats.rx_packets++;
145662306a36Sopenharmony_ci		queue->stats.rx_packets++;
145762306a36Sopenharmony_ci		bp->dev->stats.rx_bytes += skb->len;
145862306a36Sopenharmony_ci		queue->stats.rx_bytes += skb->len;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci		gem_ptp_do_rxstamp(bp, skb, desc);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci#if defined(DEBUG) && defined(VERBOSE_DEBUG)
146362306a36Sopenharmony_ci		netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
146462306a36Sopenharmony_ci			    skb->len, skb->csum);
146562306a36Sopenharmony_ci		print_hex_dump(KERN_DEBUG, " mac: ", DUMP_PREFIX_ADDRESS, 16, 1,
146662306a36Sopenharmony_ci			       skb_mac_header(skb), 16, true);
146762306a36Sopenharmony_ci		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_ADDRESS, 16, 1,
146862306a36Sopenharmony_ci			       skb->data, 32, true);
146962306a36Sopenharmony_ci#endif
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci		napi_gro_receive(napi, skb);
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	gem_rx_refill(queue);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	return count;
147762306a36Sopenharmony_ci}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic int macb_rx_frame(struct macb_queue *queue, struct napi_struct *napi,
148062306a36Sopenharmony_ci			 unsigned int first_frag, unsigned int last_frag)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	unsigned int len;
148362306a36Sopenharmony_ci	unsigned int frag;
148462306a36Sopenharmony_ci	unsigned int offset;
148562306a36Sopenharmony_ci	struct sk_buff *skb;
148662306a36Sopenharmony_ci	struct macb_dma_desc *desc;
148762306a36Sopenharmony_ci	struct macb *bp = queue->bp;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	desc = macb_rx_desc(queue, last_frag);
149062306a36Sopenharmony_ci	len = desc->ctrl & bp->rx_frm_len_mask;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
149362306a36Sopenharmony_ci		macb_rx_ring_wrap(bp, first_frag),
149462306a36Sopenharmony_ci		macb_rx_ring_wrap(bp, last_frag), len);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	/* The ethernet header starts NET_IP_ALIGN bytes into the
149762306a36Sopenharmony_ci	 * first buffer. Since the header is 14 bytes, this makes the
149862306a36Sopenharmony_ci	 * payload word-aligned.
149962306a36Sopenharmony_ci	 *
150062306a36Sopenharmony_ci	 * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy
150162306a36Sopenharmony_ci	 * the two padding bytes into the skb so that we avoid hitting
150262306a36Sopenharmony_ci	 * the slowpath in memcpy(), and pull them off afterwards.
150362306a36Sopenharmony_ci	 */
150462306a36Sopenharmony_ci	skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN);
150562306a36Sopenharmony_ci	if (!skb) {
150662306a36Sopenharmony_ci		bp->dev->stats.rx_dropped++;
150762306a36Sopenharmony_ci		for (frag = first_frag; ; frag++) {
150862306a36Sopenharmony_ci			desc = macb_rx_desc(queue, frag);
150962306a36Sopenharmony_ci			desc->addr &= ~MACB_BIT(RX_USED);
151062306a36Sopenharmony_ci			if (frag == last_frag)
151162306a36Sopenharmony_ci				break;
151262306a36Sopenharmony_ci		}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		/* Make descriptor updates visible to hardware */
151562306a36Sopenharmony_ci		wmb();
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci		return 1;
151862306a36Sopenharmony_ci	}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	offset = 0;
152162306a36Sopenharmony_ci	len += NET_IP_ALIGN;
152262306a36Sopenharmony_ci	skb_checksum_none_assert(skb);
152362306a36Sopenharmony_ci	skb_put(skb, len);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	for (frag = first_frag; ; frag++) {
152662306a36Sopenharmony_ci		unsigned int frag_len = bp->rx_buffer_size;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci		if (offset + frag_len > len) {
152962306a36Sopenharmony_ci			if (unlikely(frag != last_frag)) {
153062306a36Sopenharmony_ci				dev_kfree_skb_any(skb);
153162306a36Sopenharmony_ci				return -1;
153262306a36Sopenharmony_ci			}
153362306a36Sopenharmony_ci			frag_len = len - offset;
153462306a36Sopenharmony_ci		}
153562306a36Sopenharmony_ci		skb_copy_to_linear_data_offset(skb, offset,
153662306a36Sopenharmony_ci					       macb_rx_buffer(queue, frag),
153762306a36Sopenharmony_ci					       frag_len);
153862306a36Sopenharmony_ci		offset += bp->rx_buffer_size;
153962306a36Sopenharmony_ci		desc = macb_rx_desc(queue, frag);
154062306a36Sopenharmony_ci		desc->addr &= ~MACB_BIT(RX_USED);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci		if (frag == last_frag)
154362306a36Sopenharmony_ci			break;
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	/* Make descriptor updates visible to hardware */
154762306a36Sopenharmony_ci	wmb();
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	__skb_pull(skb, NET_IP_ALIGN);
155062306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, bp->dev);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	bp->dev->stats.rx_packets++;
155362306a36Sopenharmony_ci	bp->dev->stats.rx_bytes += skb->len;
155462306a36Sopenharmony_ci	netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
155562306a36Sopenharmony_ci		    skb->len, skb->csum);
155662306a36Sopenharmony_ci	napi_gro_receive(napi, skb);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	return 0;
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_cistatic inline void macb_init_rx_ring(struct macb_queue *queue)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct macb *bp = queue->bp;
156462306a36Sopenharmony_ci	dma_addr_t addr;
156562306a36Sopenharmony_ci	struct macb_dma_desc *desc = NULL;
156662306a36Sopenharmony_ci	int i;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	addr = queue->rx_buffers_dma;
156962306a36Sopenharmony_ci	for (i = 0; i < bp->rx_ring_size; i++) {
157062306a36Sopenharmony_ci		desc = macb_rx_desc(queue, i);
157162306a36Sopenharmony_ci		macb_set_addr(bp, desc, addr);
157262306a36Sopenharmony_ci		desc->ctrl = 0;
157362306a36Sopenharmony_ci		addr += bp->rx_buffer_size;
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci	desc->addr |= MACB_BIT(RX_WRAP);
157662306a36Sopenharmony_ci	queue->rx_tail = 0;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic int macb_rx(struct macb_queue *queue, struct napi_struct *napi,
158062306a36Sopenharmony_ci		   int budget)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	struct macb *bp = queue->bp;
158362306a36Sopenharmony_ci	bool reset_rx_queue = false;
158462306a36Sopenharmony_ci	int received = 0;
158562306a36Sopenharmony_ci	unsigned int tail;
158662306a36Sopenharmony_ci	int first_frag = -1;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	for (tail = queue->rx_tail; budget > 0; tail++) {
158962306a36Sopenharmony_ci		struct macb_dma_desc *desc = macb_rx_desc(queue, tail);
159062306a36Sopenharmony_ci		u32 ctrl;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci		/* Make hw descriptor updates visible to CPU */
159362306a36Sopenharmony_ci		rmb();
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci		if (!(desc->addr & MACB_BIT(RX_USED)))
159662306a36Sopenharmony_ci			break;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		/* Ensure ctrl is at least as up-to-date as addr */
159962306a36Sopenharmony_ci		dma_rmb();
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci		ctrl = desc->ctrl;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		if (ctrl & MACB_BIT(RX_SOF)) {
160462306a36Sopenharmony_ci			if (first_frag != -1)
160562306a36Sopenharmony_ci				discard_partial_frame(queue, first_frag, tail);
160662306a36Sopenharmony_ci			first_frag = tail;
160762306a36Sopenharmony_ci		}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci		if (ctrl & MACB_BIT(RX_EOF)) {
161062306a36Sopenharmony_ci			int dropped;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci			if (unlikely(first_frag == -1)) {
161362306a36Sopenharmony_ci				reset_rx_queue = true;
161462306a36Sopenharmony_ci				continue;
161562306a36Sopenharmony_ci			}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci			dropped = macb_rx_frame(queue, napi, first_frag, tail);
161862306a36Sopenharmony_ci			first_frag = -1;
161962306a36Sopenharmony_ci			if (unlikely(dropped < 0)) {
162062306a36Sopenharmony_ci				reset_rx_queue = true;
162162306a36Sopenharmony_ci				continue;
162262306a36Sopenharmony_ci			}
162362306a36Sopenharmony_ci			if (!dropped) {
162462306a36Sopenharmony_ci				received++;
162562306a36Sopenharmony_ci				budget--;
162662306a36Sopenharmony_ci			}
162762306a36Sopenharmony_ci		}
162862306a36Sopenharmony_ci	}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	if (unlikely(reset_rx_queue)) {
163162306a36Sopenharmony_ci		unsigned long flags;
163262306a36Sopenharmony_ci		u32 ctrl;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci		netdev_err(bp->dev, "RX queue corruption: reset it\n");
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci		spin_lock_irqsave(&bp->lock, flags);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci		ctrl = macb_readl(bp, NCR);
163962306a36Sopenharmony_ci		macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci		macb_init_rx_ring(queue);
164262306a36Sopenharmony_ci		queue_writel(queue, RBQP, queue->rx_ring_dma);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci		macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci		spin_unlock_irqrestore(&bp->lock, flags);
164762306a36Sopenharmony_ci		return received;
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (first_frag != -1)
165162306a36Sopenharmony_ci		queue->rx_tail = first_frag;
165262306a36Sopenharmony_ci	else
165362306a36Sopenharmony_ci		queue->rx_tail = tail;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	return received;
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_cistatic bool macb_rx_pending(struct macb_queue *queue)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	struct macb *bp = queue->bp;
166162306a36Sopenharmony_ci	unsigned int		entry;
166262306a36Sopenharmony_ci	struct macb_dma_desc	*desc;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	entry = macb_rx_ring_wrap(bp, queue->rx_tail);
166562306a36Sopenharmony_ci	desc = macb_rx_desc(queue, entry);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	/* Make hw descriptor updates visible to CPU */
166862306a36Sopenharmony_ci	rmb();
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	return (desc->addr & MACB_BIT(RX_USED)) != 0;
167162306a36Sopenharmony_ci}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_cistatic int macb_rx_poll(struct napi_struct *napi, int budget)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	struct macb_queue *queue = container_of(napi, struct macb_queue, napi_rx);
167662306a36Sopenharmony_ci	struct macb *bp = queue->bp;
167762306a36Sopenharmony_ci	int work_done;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	work_done = bp->macbgem_ops.mog_rx(queue, napi, budget);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	netdev_vdbg(bp->dev, "RX poll: queue = %u, work_done = %d, budget = %d\n",
168262306a36Sopenharmony_ci		    (unsigned int)(queue - bp->queues), work_done, budget);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	if (work_done < budget && napi_complete_done(napi, work_done)) {
168562306a36Sopenharmony_ci		queue_writel(queue, IER, bp->rx_intr_mask);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci		/* Packet completions only seem to propagate to raise
168862306a36Sopenharmony_ci		 * interrupts when interrupts are enabled at the time, so if
168962306a36Sopenharmony_ci		 * packets were received while interrupts were disabled,
169062306a36Sopenharmony_ci		 * they will not cause another interrupt to be generated when
169162306a36Sopenharmony_ci		 * interrupts are re-enabled.
169262306a36Sopenharmony_ci		 * Check for this case here to avoid losing a wakeup. This can
169362306a36Sopenharmony_ci		 * potentially race with the interrupt handler doing the same
169462306a36Sopenharmony_ci		 * actions if an interrupt is raised just after enabling them,
169562306a36Sopenharmony_ci		 * but this should be harmless.
169662306a36Sopenharmony_ci		 */
169762306a36Sopenharmony_ci		if (macb_rx_pending(queue)) {
169862306a36Sopenharmony_ci			queue_writel(queue, IDR, bp->rx_intr_mask);
169962306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
170062306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_BIT(RCOMP));
170162306a36Sopenharmony_ci			netdev_vdbg(bp->dev, "poll: packets pending, reschedule\n");
170262306a36Sopenharmony_ci			napi_schedule(napi);
170362306a36Sopenharmony_ci		}
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	/* TODO: Handle errors */
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	return work_done;
170962306a36Sopenharmony_ci}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic void macb_tx_restart(struct macb_queue *queue)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct macb *bp = queue->bp;
171462306a36Sopenharmony_ci	unsigned int head_idx, tbqp;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	spin_lock(&queue->tx_ptr_lock);
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	if (queue->tx_head == queue->tx_tail)
171962306a36Sopenharmony_ci		goto out_tx_ptr_unlock;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	tbqp = queue_readl(queue, TBQP) / macb_dma_desc_get_size(bp);
172262306a36Sopenharmony_ci	tbqp = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, tbqp));
172362306a36Sopenharmony_ci	head_idx = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, queue->tx_head));
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	if (tbqp == head_idx)
172662306a36Sopenharmony_ci		goto out_tx_ptr_unlock;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	spin_lock_irq(&bp->lock);
172962306a36Sopenharmony_ci	macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
173062306a36Sopenharmony_ci	spin_unlock_irq(&bp->lock);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ciout_tx_ptr_unlock:
173362306a36Sopenharmony_ci	spin_unlock(&queue->tx_ptr_lock);
173462306a36Sopenharmony_ci}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_cistatic bool macb_tx_complete_pending(struct macb_queue *queue)
173762306a36Sopenharmony_ci{
173862306a36Sopenharmony_ci	bool retval = false;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	spin_lock(&queue->tx_ptr_lock);
174162306a36Sopenharmony_ci	if (queue->tx_head != queue->tx_tail) {
174262306a36Sopenharmony_ci		/* Make hw descriptor updates visible to CPU */
174362306a36Sopenharmony_ci		rmb();
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci		if (macb_tx_desc(queue, queue->tx_tail)->ctrl & MACB_BIT(TX_USED))
174662306a36Sopenharmony_ci			retval = true;
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci	spin_unlock(&queue->tx_ptr_lock);
174962306a36Sopenharmony_ci	return retval;
175062306a36Sopenharmony_ci}
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_cistatic int macb_tx_poll(struct napi_struct *napi, int budget)
175362306a36Sopenharmony_ci{
175462306a36Sopenharmony_ci	struct macb_queue *queue = container_of(napi, struct macb_queue, napi_tx);
175562306a36Sopenharmony_ci	struct macb *bp = queue->bp;
175662306a36Sopenharmony_ci	int work_done;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	work_done = macb_tx_complete(queue, budget);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	rmb(); // ensure txubr_pending is up to date
176162306a36Sopenharmony_ci	if (queue->txubr_pending) {
176262306a36Sopenharmony_ci		queue->txubr_pending = false;
176362306a36Sopenharmony_ci		netdev_vdbg(bp->dev, "poll: tx restart\n");
176462306a36Sopenharmony_ci		macb_tx_restart(queue);
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	netdev_vdbg(bp->dev, "TX poll: queue = %u, work_done = %d, budget = %d\n",
176862306a36Sopenharmony_ci		    (unsigned int)(queue - bp->queues), work_done, budget);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	if (work_done < budget && napi_complete_done(napi, work_done)) {
177162306a36Sopenharmony_ci		queue_writel(queue, IER, MACB_BIT(TCOMP));
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci		/* Packet completions only seem to propagate to raise
177462306a36Sopenharmony_ci		 * interrupts when interrupts are enabled at the time, so if
177562306a36Sopenharmony_ci		 * packets were sent while interrupts were disabled,
177662306a36Sopenharmony_ci		 * they will not cause another interrupt to be generated when
177762306a36Sopenharmony_ci		 * interrupts are re-enabled.
177862306a36Sopenharmony_ci		 * Check for this case here to avoid losing a wakeup. This can
177962306a36Sopenharmony_ci		 * potentially race with the interrupt handler doing the same
178062306a36Sopenharmony_ci		 * actions if an interrupt is raised just after enabling them,
178162306a36Sopenharmony_ci		 * but this should be harmless.
178262306a36Sopenharmony_ci		 */
178362306a36Sopenharmony_ci		if (macb_tx_complete_pending(queue)) {
178462306a36Sopenharmony_ci			queue_writel(queue, IDR, MACB_BIT(TCOMP));
178562306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
178662306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_BIT(TCOMP));
178762306a36Sopenharmony_ci			netdev_vdbg(bp->dev, "TX poll: packets pending, reschedule\n");
178862306a36Sopenharmony_ci			napi_schedule(napi);
178962306a36Sopenharmony_ci		}
179062306a36Sopenharmony_ci	}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	return work_done;
179362306a36Sopenharmony_ci}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_cistatic void macb_hresp_error_task(struct tasklet_struct *t)
179662306a36Sopenharmony_ci{
179762306a36Sopenharmony_ci	struct macb *bp = from_tasklet(bp, t, hresp_err_tasklet);
179862306a36Sopenharmony_ci	struct net_device *dev = bp->dev;
179962306a36Sopenharmony_ci	struct macb_queue *queue;
180062306a36Sopenharmony_ci	unsigned int q;
180162306a36Sopenharmony_ci	u32 ctrl;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
180462306a36Sopenharmony_ci		queue_writel(queue, IDR, bp->rx_intr_mask |
180562306a36Sopenharmony_ci					 MACB_TX_INT_FLAGS |
180662306a36Sopenharmony_ci					 MACB_BIT(HRESP));
180762306a36Sopenharmony_ci	}
180862306a36Sopenharmony_ci	ctrl = macb_readl(bp, NCR);
180962306a36Sopenharmony_ci	ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
181062306a36Sopenharmony_ci	macb_writel(bp, NCR, ctrl);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	netif_tx_stop_all_queues(dev);
181362306a36Sopenharmony_ci	netif_carrier_off(dev);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	bp->macbgem_ops.mog_init_rings(bp);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	/* Initialize TX and RX buffers */
181862306a36Sopenharmony_ci	macb_init_buffers(bp);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	/* Enable interrupts */
182162306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
182262306a36Sopenharmony_ci		queue_writel(queue, IER,
182362306a36Sopenharmony_ci			     bp->rx_intr_mask |
182462306a36Sopenharmony_ci			     MACB_TX_INT_FLAGS |
182562306a36Sopenharmony_ci			     MACB_BIT(HRESP));
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	ctrl |= MACB_BIT(RE) | MACB_BIT(TE);
182862306a36Sopenharmony_ci	macb_writel(bp, NCR, ctrl);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	netif_carrier_on(dev);
183162306a36Sopenharmony_ci	netif_tx_start_all_queues(dev);
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_cistatic irqreturn_t macb_wol_interrupt(int irq, void *dev_id)
183562306a36Sopenharmony_ci{
183662306a36Sopenharmony_ci	struct macb_queue *queue = dev_id;
183762306a36Sopenharmony_ci	struct macb *bp = queue->bp;
183862306a36Sopenharmony_ci	u32 status;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	status = queue_readl(queue, ISR);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	if (unlikely(!status))
184362306a36Sopenharmony_ci		return IRQ_NONE;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	spin_lock(&bp->lock);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	if (status & MACB_BIT(WOL)) {
184862306a36Sopenharmony_ci		queue_writel(queue, IDR, MACB_BIT(WOL));
184962306a36Sopenharmony_ci		macb_writel(bp, WOL, 0);
185062306a36Sopenharmony_ci		netdev_vdbg(bp->dev, "MACB WoL: queue = %u, isr = 0x%08lx\n",
185162306a36Sopenharmony_ci			    (unsigned int)(queue - bp->queues),
185262306a36Sopenharmony_ci			    (unsigned long)status);
185362306a36Sopenharmony_ci		if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
185462306a36Sopenharmony_ci			queue_writel(queue, ISR, MACB_BIT(WOL));
185562306a36Sopenharmony_ci		pm_wakeup_event(&bp->pdev->dev, 0);
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	spin_unlock(&bp->lock);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	return IRQ_HANDLED;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic irqreturn_t gem_wol_interrupt(int irq, void *dev_id)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct macb_queue *queue = dev_id;
186662306a36Sopenharmony_ci	struct macb *bp = queue->bp;
186762306a36Sopenharmony_ci	u32 status;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	status = queue_readl(queue, ISR);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (unlikely(!status))
187262306a36Sopenharmony_ci		return IRQ_NONE;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	spin_lock(&bp->lock);
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	if (status & GEM_BIT(WOL)) {
187762306a36Sopenharmony_ci		queue_writel(queue, IDR, GEM_BIT(WOL));
187862306a36Sopenharmony_ci		gem_writel(bp, WOL, 0);
187962306a36Sopenharmony_ci		netdev_vdbg(bp->dev, "GEM WoL: queue = %u, isr = 0x%08lx\n",
188062306a36Sopenharmony_ci			    (unsigned int)(queue - bp->queues),
188162306a36Sopenharmony_ci			    (unsigned long)status);
188262306a36Sopenharmony_ci		if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
188362306a36Sopenharmony_ci			queue_writel(queue, ISR, GEM_BIT(WOL));
188462306a36Sopenharmony_ci		pm_wakeup_event(&bp->pdev->dev, 0);
188562306a36Sopenharmony_ci	}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	spin_unlock(&bp->lock);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	return IRQ_HANDLED;
189062306a36Sopenharmony_ci}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_cistatic irqreturn_t macb_interrupt(int irq, void *dev_id)
189362306a36Sopenharmony_ci{
189462306a36Sopenharmony_ci	struct macb_queue *queue = dev_id;
189562306a36Sopenharmony_ci	struct macb *bp = queue->bp;
189662306a36Sopenharmony_ci	struct net_device *dev = bp->dev;
189762306a36Sopenharmony_ci	u32 status, ctrl;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	status = queue_readl(queue, ISR);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	if (unlikely(!status))
190262306a36Sopenharmony_ci		return IRQ_NONE;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	spin_lock(&bp->lock);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	while (status) {
190762306a36Sopenharmony_ci		/* close possible race with dev_close */
190862306a36Sopenharmony_ci		if (unlikely(!netif_running(dev))) {
190962306a36Sopenharmony_ci			queue_writel(queue, IDR, -1);
191062306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
191162306a36Sopenharmony_ci				queue_writel(queue, ISR, -1);
191262306a36Sopenharmony_ci			break;
191362306a36Sopenharmony_ci		}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci		netdev_vdbg(bp->dev, "queue = %u, isr = 0x%08lx\n",
191662306a36Sopenharmony_ci			    (unsigned int)(queue - bp->queues),
191762306a36Sopenharmony_ci			    (unsigned long)status);
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci		if (status & bp->rx_intr_mask) {
192062306a36Sopenharmony_ci			/* There's no point taking any more interrupts
192162306a36Sopenharmony_ci			 * until we have processed the buffers. The
192262306a36Sopenharmony_ci			 * scheduling call may fail if the poll routine
192362306a36Sopenharmony_ci			 * is already scheduled, so disable interrupts
192462306a36Sopenharmony_ci			 * now.
192562306a36Sopenharmony_ci			 */
192662306a36Sopenharmony_ci			queue_writel(queue, IDR, bp->rx_intr_mask);
192762306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
192862306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_BIT(RCOMP));
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci			if (napi_schedule_prep(&queue->napi_rx)) {
193162306a36Sopenharmony_ci				netdev_vdbg(bp->dev, "scheduling RX softirq\n");
193262306a36Sopenharmony_ci				__napi_schedule(&queue->napi_rx);
193362306a36Sopenharmony_ci			}
193462306a36Sopenharmony_ci		}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		if (status & (MACB_BIT(TCOMP) |
193762306a36Sopenharmony_ci			      MACB_BIT(TXUBR))) {
193862306a36Sopenharmony_ci			queue_writel(queue, IDR, MACB_BIT(TCOMP));
193962306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
194062306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_BIT(TCOMP) |
194162306a36Sopenharmony_ci							 MACB_BIT(TXUBR));
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci			if (status & MACB_BIT(TXUBR)) {
194462306a36Sopenharmony_ci				queue->txubr_pending = true;
194562306a36Sopenharmony_ci				wmb(); // ensure softirq can see update
194662306a36Sopenharmony_ci			}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci			if (napi_schedule_prep(&queue->napi_tx)) {
194962306a36Sopenharmony_ci				netdev_vdbg(bp->dev, "scheduling TX softirq\n");
195062306a36Sopenharmony_ci				__napi_schedule(&queue->napi_tx);
195162306a36Sopenharmony_ci			}
195262306a36Sopenharmony_ci		}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci		if (unlikely(status & (MACB_TX_ERR_FLAGS))) {
195562306a36Sopenharmony_ci			queue_writel(queue, IDR, MACB_TX_INT_FLAGS);
195662306a36Sopenharmony_ci			schedule_work(&queue->tx_error_task);
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
195962306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_TX_ERR_FLAGS);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci			break;
196262306a36Sopenharmony_ci		}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		/* Link change detection isn't possible with RMII, so we'll
196562306a36Sopenharmony_ci		 * add that if/when we get our hands on a full-blown MII PHY.
196662306a36Sopenharmony_ci		 */
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci		/* There is a hardware issue under heavy load where DMA can
196962306a36Sopenharmony_ci		 * stop, this causes endless "used buffer descriptor read"
197062306a36Sopenharmony_ci		 * interrupts but it can be cleared by re-enabling RX. See
197162306a36Sopenharmony_ci		 * the at91rm9200 manual, section 41.3.1 or the Zynq manual
197262306a36Sopenharmony_ci		 * section 16.7.4 for details. RXUBR is only enabled for
197362306a36Sopenharmony_ci		 * these two versions.
197462306a36Sopenharmony_ci		 */
197562306a36Sopenharmony_ci		if (status & MACB_BIT(RXUBR)) {
197662306a36Sopenharmony_ci			ctrl = macb_readl(bp, NCR);
197762306a36Sopenharmony_ci			macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));
197862306a36Sopenharmony_ci			wmb();
197962306a36Sopenharmony_ci			macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
198262306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_BIT(RXUBR));
198362306a36Sopenharmony_ci		}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		if (status & MACB_BIT(ISR_ROVR)) {
198662306a36Sopenharmony_ci			/* We missed at least one packet */
198762306a36Sopenharmony_ci			if (macb_is_gem(bp))
198862306a36Sopenharmony_ci				bp->hw_stats.gem.rx_overruns++;
198962306a36Sopenharmony_ci			else
199062306a36Sopenharmony_ci				bp->hw_stats.macb.rx_overruns++;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
199362306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_BIT(ISR_ROVR));
199462306a36Sopenharmony_ci		}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci		if (status & MACB_BIT(HRESP)) {
199762306a36Sopenharmony_ci			tasklet_schedule(&bp->hresp_err_tasklet);
199862306a36Sopenharmony_ci			netdev_err(dev, "DMA bus error: HRESP not OK\n");
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
200162306a36Sopenharmony_ci				queue_writel(queue, ISR, MACB_BIT(HRESP));
200262306a36Sopenharmony_ci		}
200362306a36Sopenharmony_ci		status = queue_readl(queue, ISR);
200462306a36Sopenharmony_ci	}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	spin_unlock(&bp->lock);
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	return IRQ_HANDLED;
200962306a36Sopenharmony_ci}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
201262306a36Sopenharmony_ci/* Polling receive - used by netconsole and other diagnostic tools
201362306a36Sopenharmony_ci * to allow network i/o with interrupts disabled.
201462306a36Sopenharmony_ci */
201562306a36Sopenharmony_cistatic void macb_poll_controller(struct net_device *dev)
201662306a36Sopenharmony_ci{
201762306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
201862306a36Sopenharmony_ci	struct macb_queue *queue;
201962306a36Sopenharmony_ci	unsigned long flags;
202062306a36Sopenharmony_ci	unsigned int q;
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	local_irq_save(flags);
202362306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
202462306a36Sopenharmony_ci		macb_interrupt(dev->irq, queue);
202562306a36Sopenharmony_ci	local_irq_restore(flags);
202662306a36Sopenharmony_ci}
202762306a36Sopenharmony_ci#endif
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic unsigned int macb_tx_map(struct macb *bp,
203062306a36Sopenharmony_ci				struct macb_queue *queue,
203162306a36Sopenharmony_ci				struct sk_buff *skb,
203262306a36Sopenharmony_ci				unsigned int hdrlen)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	dma_addr_t mapping;
203562306a36Sopenharmony_ci	unsigned int len, entry, i, tx_head = queue->tx_head;
203662306a36Sopenharmony_ci	struct macb_tx_skb *tx_skb = NULL;
203762306a36Sopenharmony_ci	struct macb_dma_desc *desc;
203862306a36Sopenharmony_ci	unsigned int offset, size, count = 0;
203962306a36Sopenharmony_ci	unsigned int f, nr_frags = skb_shinfo(skb)->nr_frags;
204062306a36Sopenharmony_ci	unsigned int eof = 1, mss_mfs = 0;
204162306a36Sopenharmony_ci	u32 ctrl, lso_ctrl = 0, seq_ctrl = 0;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	/* LSO */
204462306a36Sopenharmony_ci	if (skb_shinfo(skb)->gso_size != 0) {
204562306a36Sopenharmony_ci		if (ip_hdr(skb)->protocol == IPPROTO_UDP)
204662306a36Sopenharmony_ci			/* UDP - UFO */
204762306a36Sopenharmony_ci			lso_ctrl = MACB_LSO_UFO_ENABLE;
204862306a36Sopenharmony_ci		else
204962306a36Sopenharmony_ci			/* TCP - TSO */
205062306a36Sopenharmony_ci			lso_ctrl = MACB_LSO_TSO_ENABLE;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	/* First, map non-paged data */
205462306a36Sopenharmony_ci	len = skb_headlen(skb);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	/* first buffer length */
205762306a36Sopenharmony_ci	size = hdrlen;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	offset = 0;
206062306a36Sopenharmony_ci	while (len) {
206162306a36Sopenharmony_ci		entry = macb_tx_ring_wrap(bp, tx_head);
206262306a36Sopenharmony_ci		tx_skb = &queue->tx_skb[entry];
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci		mapping = dma_map_single(&bp->pdev->dev,
206562306a36Sopenharmony_ci					 skb->data + offset,
206662306a36Sopenharmony_ci					 size, DMA_TO_DEVICE);
206762306a36Sopenharmony_ci		if (dma_mapping_error(&bp->pdev->dev, mapping))
206862306a36Sopenharmony_ci			goto dma_error;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci		/* Save info to properly release resources */
207162306a36Sopenharmony_ci		tx_skb->skb = NULL;
207262306a36Sopenharmony_ci		tx_skb->mapping = mapping;
207362306a36Sopenharmony_ci		tx_skb->size = size;
207462306a36Sopenharmony_ci		tx_skb->mapped_as_page = false;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci		len -= size;
207762306a36Sopenharmony_ci		offset += size;
207862306a36Sopenharmony_ci		count++;
207962306a36Sopenharmony_ci		tx_head++;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci		size = min(len, bp->max_tx_length);
208262306a36Sopenharmony_ci	}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	/* Then, map paged data from fragments */
208562306a36Sopenharmony_ci	for (f = 0; f < nr_frags; f++) {
208662306a36Sopenharmony_ci		const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci		len = skb_frag_size(frag);
208962306a36Sopenharmony_ci		offset = 0;
209062306a36Sopenharmony_ci		while (len) {
209162306a36Sopenharmony_ci			size = min(len, bp->max_tx_length);
209262306a36Sopenharmony_ci			entry = macb_tx_ring_wrap(bp, tx_head);
209362306a36Sopenharmony_ci			tx_skb = &queue->tx_skb[entry];
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci			mapping = skb_frag_dma_map(&bp->pdev->dev, frag,
209662306a36Sopenharmony_ci						   offset, size, DMA_TO_DEVICE);
209762306a36Sopenharmony_ci			if (dma_mapping_error(&bp->pdev->dev, mapping))
209862306a36Sopenharmony_ci				goto dma_error;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci			/* Save info to properly release resources */
210162306a36Sopenharmony_ci			tx_skb->skb = NULL;
210262306a36Sopenharmony_ci			tx_skb->mapping = mapping;
210362306a36Sopenharmony_ci			tx_skb->size = size;
210462306a36Sopenharmony_ci			tx_skb->mapped_as_page = true;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci			len -= size;
210762306a36Sopenharmony_ci			offset += size;
210862306a36Sopenharmony_ci			count++;
210962306a36Sopenharmony_ci			tx_head++;
211062306a36Sopenharmony_ci		}
211162306a36Sopenharmony_ci	}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	/* Should never happen */
211462306a36Sopenharmony_ci	if (unlikely(!tx_skb)) {
211562306a36Sopenharmony_ci		netdev_err(bp->dev, "BUG! empty skb!\n");
211662306a36Sopenharmony_ci		return 0;
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	/* This is the last buffer of the frame: save socket buffer */
212062306a36Sopenharmony_ci	tx_skb->skb = skb;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	/* Update TX ring: update buffer descriptors in reverse order
212362306a36Sopenharmony_ci	 * to avoid race condition
212462306a36Sopenharmony_ci	 */
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	/* Set 'TX_USED' bit in buffer descriptor at tx_head position
212762306a36Sopenharmony_ci	 * to set the end of TX queue
212862306a36Sopenharmony_ci	 */
212962306a36Sopenharmony_ci	i = tx_head;
213062306a36Sopenharmony_ci	entry = macb_tx_ring_wrap(bp, i);
213162306a36Sopenharmony_ci	ctrl = MACB_BIT(TX_USED);
213262306a36Sopenharmony_ci	desc = macb_tx_desc(queue, entry);
213362306a36Sopenharmony_ci	desc->ctrl = ctrl;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	if (lso_ctrl) {
213662306a36Sopenharmony_ci		if (lso_ctrl == MACB_LSO_UFO_ENABLE)
213762306a36Sopenharmony_ci			/* include header and FCS in value given to h/w */
213862306a36Sopenharmony_ci			mss_mfs = skb_shinfo(skb)->gso_size +
213962306a36Sopenharmony_ci					skb_transport_offset(skb) +
214062306a36Sopenharmony_ci					ETH_FCS_LEN;
214162306a36Sopenharmony_ci		else /* TSO */ {
214262306a36Sopenharmony_ci			mss_mfs = skb_shinfo(skb)->gso_size;
214362306a36Sopenharmony_ci			/* TCP Sequence Number Source Select
214462306a36Sopenharmony_ci			 * can be set only for TSO
214562306a36Sopenharmony_ci			 */
214662306a36Sopenharmony_ci			seq_ctrl = 0;
214762306a36Sopenharmony_ci		}
214862306a36Sopenharmony_ci	}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	do {
215162306a36Sopenharmony_ci		i--;
215262306a36Sopenharmony_ci		entry = macb_tx_ring_wrap(bp, i);
215362306a36Sopenharmony_ci		tx_skb = &queue->tx_skb[entry];
215462306a36Sopenharmony_ci		desc = macb_tx_desc(queue, entry);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci		ctrl = (u32)tx_skb->size;
215762306a36Sopenharmony_ci		if (eof) {
215862306a36Sopenharmony_ci			ctrl |= MACB_BIT(TX_LAST);
215962306a36Sopenharmony_ci			eof = 0;
216062306a36Sopenharmony_ci		}
216162306a36Sopenharmony_ci		if (unlikely(entry == (bp->tx_ring_size - 1)))
216262306a36Sopenharmony_ci			ctrl |= MACB_BIT(TX_WRAP);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		/* First descriptor is header descriptor */
216562306a36Sopenharmony_ci		if (i == queue->tx_head) {
216662306a36Sopenharmony_ci			ctrl |= MACB_BF(TX_LSO, lso_ctrl);
216762306a36Sopenharmony_ci			ctrl |= MACB_BF(TX_TCP_SEQ_SRC, seq_ctrl);
216862306a36Sopenharmony_ci			if ((bp->dev->features & NETIF_F_HW_CSUM) &&
216962306a36Sopenharmony_ci			    skb->ip_summed != CHECKSUM_PARTIAL && !lso_ctrl &&
217062306a36Sopenharmony_ci			    !ptp_one_step_sync(skb))
217162306a36Sopenharmony_ci				ctrl |= MACB_BIT(TX_NOCRC);
217262306a36Sopenharmony_ci		} else
217362306a36Sopenharmony_ci			/* Only set MSS/MFS on payload descriptors
217462306a36Sopenharmony_ci			 * (second or later descriptor)
217562306a36Sopenharmony_ci			 */
217662306a36Sopenharmony_ci			ctrl |= MACB_BF(MSS_MFS, mss_mfs);
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		/* Set TX buffer descriptor */
217962306a36Sopenharmony_ci		macb_set_addr(bp, desc, tx_skb->mapping);
218062306a36Sopenharmony_ci		/* desc->addr must be visible to hardware before clearing
218162306a36Sopenharmony_ci		 * 'TX_USED' bit in desc->ctrl.
218262306a36Sopenharmony_ci		 */
218362306a36Sopenharmony_ci		wmb();
218462306a36Sopenharmony_ci		desc->ctrl = ctrl;
218562306a36Sopenharmony_ci	} while (i != queue->tx_head);
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	queue->tx_head = tx_head;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	return count;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_cidma_error:
219262306a36Sopenharmony_ci	netdev_err(bp->dev, "TX DMA map failed\n");
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	for (i = queue->tx_head; i != tx_head; i++) {
219562306a36Sopenharmony_ci		tx_skb = macb_tx_skb(queue, i);
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci		macb_tx_unmap(bp, tx_skb, 0);
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	return 0;
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_cistatic netdev_features_t macb_features_check(struct sk_buff *skb,
220462306a36Sopenharmony_ci					     struct net_device *dev,
220562306a36Sopenharmony_ci					     netdev_features_t features)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	unsigned int nr_frags, f;
220862306a36Sopenharmony_ci	unsigned int hdrlen;
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	/* Validate LSO compatibility */
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	/* there is only one buffer or protocol is not UDP */
221362306a36Sopenharmony_ci	if (!skb_is_nonlinear(skb) || (ip_hdr(skb)->protocol != IPPROTO_UDP))
221462306a36Sopenharmony_ci		return features;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	/* length of header */
221762306a36Sopenharmony_ci	hdrlen = skb_transport_offset(skb);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* For UFO only:
222062306a36Sopenharmony_ci	 * When software supplies two or more payload buffers all payload buffers
222162306a36Sopenharmony_ci	 * apart from the last must be a multiple of 8 bytes in size.
222262306a36Sopenharmony_ci	 */
222362306a36Sopenharmony_ci	if (!IS_ALIGNED(skb_headlen(skb) - hdrlen, MACB_TX_LEN_ALIGN))
222462306a36Sopenharmony_ci		return features & ~MACB_NETIF_LSO;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	nr_frags = skb_shinfo(skb)->nr_frags;
222762306a36Sopenharmony_ci	/* No need to check last fragment */
222862306a36Sopenharmony_ci	nr_frags--;
222962306a36Sopenharmony_ci	for (f = 0; f < nr_frags; f++) {
223062306a36Sopenharmony_ci		const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci		if (!IS_ALIGNED(skb_frag_size(frag), MACB_TX_LEN_ALIGN))
223362306a36Sopenharmony_ci			return features & ~MACB_NETIF_LSO;
223462306a36Sopenharmony_ci	}
223562306a36Sopenharmony_ci	return features;
223662306a36Sopenharmony_ci}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_cistatic inline int macb_clear_csum(struct sk_buff *skb)
223962306a36Sopenharmony_ci{
224062306a36Sopenharmony_ci	/* no change for packets without checksum offloading */
224162306a36Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL)
224262306a36Sopenharmony_ci		return 0;
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	/* make sure we can modify the header */
224562306a36Sopenharmony_ci	if (unlikely(skb_cow_head(skb, 0)))
224662306a36Sopenharmony_ci		return -1;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	/* initialize checksum field
224962306a36Sopenharmony_ci	 * This is required - at least for Zynq, which otherwise calculates
225062306a36Sopenharmony_ci	 * wrong UDP header checksums for UDP packets with UDP data len <=2
225162306a36Sopenharmony_ci	 */
225262306a36Sopenharmony_ci	*(__sum16 *)(skb_checksum_start(skb) + skb->csum_offset) = 0;
225362306a36Sopenharmony_ci	return 0;
225462306a36Sopenharmony_ci}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_cistatic int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
225762306a36Sopenharmony_ci{
225862306a36Sopenharmony_ci	bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) ||
225962306a36Sopenharmony_ci		      skb_is_nonlinear(*skb);
226062306a36Sopenharmony_ci	int padlen = ETH_ZLEN - (*skb)->len;
226162306a36Sopenharmony_ci	int tailroom = skb_tailroom(*skb);
226262306a36Sopenharmony_ci	struct sk_buff *nskb;
226362306a36Sopenharmony_ci	u32 fcs;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	if (!(ndev->features & NETIF_F_HW_CSUM) ||
226662306a36Sopenharmony_ci	    !((*skb)->ip_summed != CHECKSUM_PARTIAL) ||
226762306a36Sopenharmony_ci	    skb_shinfo(*skb)->gso_size || ptp_one_step_sync(*skb))
226862306a36Sopenharmony_ci		return 0;
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	if (padlen <= 0) {
227162306a36Sopenharmony_ci		/* FCS could be appeded to tailroom. */
227262306a36Sopenharmony_ci		if (tailroom >= ETH_FCS_LEN)
227362306a36Sopenharmony_ci			goto add_fcs;
227462306a36Sopenharmony_ci		/* No room for FCS, need to reallocate skb. */
227562306a36Sopenharmony_ci		else
227662306a36Sopenharmony_ci			padlen = ETH_FCS_LEN;
227762306a36Sopenharmony_ci	} else {
227862306a36Sopenharmony_ci		/* Add room for FCS. */
227962306a36Sopenharmony_ci		padlen += ETH_FCS_LEN;
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	if (cloned || tailroom < padlen) {
228362306a36Sopenharmony_ci		nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC);
228462306a36Sopenharmony_ci		if (!nskb)
228562306a36Sopenharmony_ci			return -ENOMEM;
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci		dev_consume_skb_any(*skb);
228862306a36Sopenharmony_ci		*skb = nskb;
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	if (padlen > ETH_FCS_LEN)
229262306a36Sopenharmony_ci		skb_put_zero(*skb, padlen - ETH_FCS_LEN);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ciadd_fcs:
229562306a36Sopenharmony_ci	/* set FCS to packet */
229662306a36Sopenharmony_ci	fcs = crc32_le(~0, (*skb)->data, (*skb)->len);
229762306a36Sopenharmony_ci	fcs = ~fcs;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	skb_put_u8(*skb, fcs		& 0xff);
230062306a36Sopenharmony_ci	skb_put_u8(*skb, (fcs >> 8)	& 0xff);
230162306a36Sopenharmony_ci	skb_put_u8(*skb, (fcs >> 16)	& 0xff);
230262306a36Sopenharmony_ci	skb_put_u8(*skb, (fcs >> 24)	& 0xff);
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	return 0;
230562306a36Sopenharmony_ci}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_cistatic netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
230862306a36Sopenharmony_ci{
230962306a36Sopenharmony_ci	u16 queue_index = skb_get_queue_mapping(skb);
231062306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
231162306a36Sopenharmony_ci	struct macb_queue *queue = &bp->queues[queue_index];
231262306a36Sopenharmony_ci	unsigned int desc_cnt, nr_frags, frag_size, f;
231362306a36Sopenharmony_ci	unsigned int hdrlen;
231462306a36Sopenharmony_ci	bool is_lso;
231562306a36Sopenharmony_ci	netdev_tx_t ret = NETDEV_TX_OK;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	if (macb_clear_csum(skb)) {
231862306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
231962306a36Sopenharmony_ci		return ret;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	if (macb_pad_and_fcs(&skb, dev)) {
232362306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
232462306a36Sopenharmony_ci		return ret;
232562306a36Sopenharmony_ci	}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP
232862306a36Sopenharmony_ci	if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
232962306a36Sopenharmony_ci	    (bp->hw_dma_cap & HW_DMA_CAP_PTP))
233062306a36Sopenharmony_ci		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
233162306a36Sopenharmony_ci#endif
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	is_lso = (skb_shinfo(skb)->gso_size != 0);
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	if (is_lso) {
233662306a36Sopenharmony_ci		/* length of headers */
233762306a36Sopenharmony_ci		if (ip_hdr(skb)->protocol == IPPROTO_UDP)
233862306a36Sopenharmony_ci			/* only queue eth + ip headers separately for UDP */
233962306a36Sopenharmony_ci			hdrlen = skb_transport_offset(skb);
234062306a36Sopenharmony_ci		else
234162306a36Sopenharmony_ci			hdrlen = skb_tcp_all_headers(skb);
234262306a36Sopenharmony_ci		if (skb_headlen(skb) < hdrlen) {
234362306a36Sopenharmony_ci			netdev_err(bp->dev, "Error - LSO headers fragmented!!!\n");
234462306a36Sopenharmony_ci			/* if this is required, would need to copy to single buffer */
234562306a36Sopenharmony_ci			return NETDEV_TX_BUSY;
234662306a36Sopenharmony_ci		}
234762306a36Sopenharmony_ci	} else
234862306a36Sopenharmony_ci		hdrlen = min(skb_headlen(skb), bp->max_tx_length);
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci#if defined(DEBUG) && defined(VERBOSE_DEBUG)
235162306a36Sopenharmony_ci	netdev_vdbg(bp->dev,
235262306a36Sopenharmony_ci		    "start_xmit: queue %hu len %u head %p data %p tail %p end %p\n",
235362306a36Sopenharmony_ci		    queue_index, skb->len, skb->head, skb->data,
235462306a36Sopenharmony_ci		    skb_tail_pointer(skb), skb_end_pointer(skb));
235562306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1,
235662306a36Sopenharmony_ci		       skb->data, 16, true);
235762306a36Sopenharmony_ci#endif
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	/* Count how many TX buffer descriptors are needed to send this
236062306a36Sopenharmony_ci	 * socket buffer: skb fragments of jumbo frames may need to be
236162306a36Sopenharmony_ci	 * split into many buffer descriptors.
236262306a36Sopenharmony_ci	 */
236362306a36Sopenharmony_ci	if (is_lso && (skb_headlen(skb) > hdrlen))
236462306a36Sopenharmony_ci		/* extra header descriptor if also payload in first buffer */
236562306a36Sopenharmony_ci		desc_cnt = DIV_ROUND_UP((skb_headlen(skb) - hdrlen), bp->max_tx_length) + 1;
236662306a36Sopenharmony_ci	else
236762306a36Sopenharmony_ci		desc_cnt = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length);
236862306a36Sopenharmony_ci	nr_frags = skb_shinfo(skb)->nr_frags;
236962306a36Sopenharmony_ci	for (f = 0; f < nr_frags; f++) {
237062306a36Sopenharmony_ci		frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
237162306a36Sopenharmony_ci		desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length);
237262306a36Sopenharmony_ci	}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	spin_lock_bh(&queue->tx_ptr_lock);
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	/* This is a hard error, log it. */
237762306a36Sopenharmony_ci	if (CIRC_SPACE(queue->tx_head, queue->tx_tail,
237862306a36Sopenharmony_ci		       bp->tx_ring_size) < desc_cnt) {
237962306a36Sopenharmony_ci		netif_stop_subqueue(dev, queue_index);
238062306a36Sopenharmony_ci		netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n",
238162306a36Sopenharmony_ci			   queue->tx_head, queue->tx_tail);
238262306a36Sopenharmony_ci		ret = NETDEV_TX_BUSY;
238362306a36Sopenharmony_ci		goto unlock;
238462306a36Sopenharmony_ci	}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	/* Map socket buffer for DMA transfer */
238762306a36Sopenharmony_ci	if (!macb_tx_map(bp, queue, skb, hdrlen)) {
238862306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
238962306a36Sopenharmony_ci		goto unlock;
239062306a36Sopenharmony_ci	}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	/* Make newly initialized descriptor visible to hardware */
239362306a36Sopenharmony_ci	wmb();
239462306a36Sopenharmony_ci	skb_tx_timestamp(skb);
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	spin_lock_irq(&bp->lock);
239762306a36Sopenharmony_ci	macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
239862306a36Sopenharmony_ci	spin_unlock_irq(&bp->lock);
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1)
240162306a36Sopenharmony_ci		netif_stop_subqueue(dev, queue_index);
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ciunlock:
240462306a36Sopenharmony_ci	spin_unlock_bh(&queue->tx_ptr_lock);
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	return ret;
240762306a36Sopenharmony_ci}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_cistatic void macb_init_rx_buffer_size(struct macb *bp, size_t size)
241062306a36Sopenharmony_ci{
241162306a36Sopenharmony_ci	if (!macb_is_gem(bp)) {
241262306a36Sopenharmony_ci		bp->rx_buffer_size = MACB_RX_BUFFER_SIZE;
241362306a36Sopenharmony_ci	} else {
241462306a36Sopenharmony_ci		bp->rx_buffer_size = size;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci		if (bp->rx_buffer_size % RX_BUFFER_MULTIPLE) {
241762306a36Sopenharmony_ci			netdev_dbg(bp->dev,
241862306a36Sopenharmony_ci				   "RX buffer must be multiple of %d bytes, expanding\n",
241962306a36Sopenharmony_ci				   RX_BUFFER_MULTIPLE);
242062306a36Sopenharmony_ci			bp->rx_buffer_size =
242162306a36Sopenharmony_ci				roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE);
242262306a36Sopenharmony_ci		}
242362306a36Sopenharmony_ci	}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	netdev_dbg(bp->dev, "mtu [%u] rx_buffer_size [%zu]\n",
242662306a36Sopenharmony_ci		   bp->dev->mtu, bp->rx_buffer_size);
242762306a36Sopenharmony_ci}
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_cistatic void gem_free_rx_buffers(struct macb *bp)
243062306a36Sopenharmony_ci{
243162306a36Sopenharmony_ci	struct sk_buff		*skb;
243262306a36Sopenharmony_ci	struct macb_dma_desc	*desc;
243362306a36Sopenharmony_ci	struct macb_queue *queue;
243462306a36Sopenharmony_ci	dma_addr_t		addr;
243562306a36Sopenharmony_ci	unsigned int q;
243662306a36Sopenharmony_ci	int i;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
243962306a36Sopenharmony_ci		if (!queue->rx_skbuff)
244062306a36Sopenharmony_ci			continue;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci		for (i = 0; i < bp->rx_ring_size; i++) {
244362306a36Sopenharmony_ci			skb = queue->rx_skbuff[i];
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci			if (!skb)
244662306a36Sopenharmony_ci				continue;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci			desc = macb_rx_desc(queue, i);
244962306a36Sopenharmony_ci			addr = macb_get_addr(bp, desc);
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci			dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size,
245262306a36Sopenharmony_ci					DMA_FROM_DEVICE);
245362306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
245462306a36Sopenharmony_ci			skb = NULL;
245562306a36Sopenharmony_ci		}
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci		kfree(queue->rx_skbuff);
245862306a36Sopenharmony_ci		queue->rx_skbuff = NULL;
245962306a36Sopenharmony_ci	}
246062306a36Sopenharmony_ci}
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_cistatic void macb_free_rx_buffers(struct macb *bp)
246362306a36Sopenharmony_ci{
246462306a36Sopenharmony_ci	struct macb_queue *queue = &bp->queues[0];
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci	if (queue->rx_buffers) {
246762306a36Sopenharmony_ci		dma_free_coherent(&bp->pdev->dev,
246862306a36Sopenharmony_ci				  bp->rx_ring_size * bp->rx_buffer_size,
246962306a36Sopenharmony_ci				  queue->rx_buffers, queue->rx_buffers_dma);
247062306a36Sopenharmony_ci		queue->rx_buffers = NULL;
247162306a36Sopenharmony_ci	}
247262306a36Sopenharmony_ci}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_cistatic void macb_free_consistent(struct macb *bp)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	struct macb_queue *queue;
247762306a36Sopenharmony_ci	unsigned int q;
247862306a36Sopenharmony_ci	int size;
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	bp->macbgem_ops.mog_free_rx_buffers(bp);
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
248362306a36Sopenharmony_ci		kfree(queue->tx_skb);
248462306a36Sopenharmony_ci		queue->tx_skb = NULL;
248562306a36Sopenharmony_ci		if (queue->tx_ring) {
248662306a36Sopenharmony_ci			size = TX_RING_BYTES(bp) + bp->tx_bd_rd_prefetch;
248762306a36Sopenharmony_ci			dma_free_coherent(&bp->pdev->dev, size,
248862306a36Sopenharmony_ci					  queue->tx_ring, queue->tx_ring_dma);
248962306a36Sopenharmony_ci			queue->tx_ring = NULL;
249062306a36Sopenharmony_ci		}
249162306a36Sopenharmony_ci		if (queue->rx_ring) {
249262306a36Sopenharmony_ci			size = RX_RING_BYTES(bp) + bp->rx_bd_rd_prefetch;
249362306a36Sopenharmony_ci			dma_free_coherent(&bp->pdev->dev, size,
249462306a36Sopenharmony_ci					  queue->rx_ring, queue->rx_ring_dma);
249562306a36Sopenharmony_ci			queue->rx_ring = NULL;
249662306a36Sopenharmony_ci		}
249762306a36Sopenharmony_ci	}
249862306a36Sopenharmony_ci}
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_cistatic int gem_alloc_rx_buffers(struct macb *bp)
250162306a36Sopenharmony_ci{
250262306a36Sopenharmony_ci	struct macb_queue *queue;
250362306a36Sopenharmony_ci	unsigned int q;
250462306a36Sopenharmony_ci	int size;
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
250762306a36Sopenharmony_ci		size = bp->rx_ring_size * sizeof(struct sk_buff *);
250862306a36Sopenharmony_ci		queue->rx_skbuff = kzalloc(size, GFP_KERNEL);
250962306a36Sopenharmony_ci		if (!queue->rx_skbuff)
251062306a36Sopenharmony_ci			return -ENOMEM;
251162306a36Sopenharmony_ci		else
251262306a36Sopenharmony_ci			netdev_dbg(bp->dev,
251362306a36Sopenharmony_ci				   "Allocated %d RX struct sk_buff entries at %p\n",
251462306a36Sopenharmony_ci				   bp->rx_ring_size, queue->rx_skbuff);
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci	return 0;
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_cistatic int macb_alloc_rx_buffers(struct macb *bp)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	struct macb_queue *queue = &bp->queues[0];
252262306a36Sopenharmony_ci	int size;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	size = bp->rx_ring_size * bp->rx_buffer_size;
252562306a36Sopenharmony_ci	queue->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
252662306a36Sopenharmony_ci					    &queue->rx_buffers_dma, GFP_KERNEL);
252762306a36Sopenharmony_ci	if (!queue->rx_buffers)
252862306a36Sopenharmony_ci		return -ENOMEM;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	netdev_dbg(bp->dev,
253162306a36Sopenharmony_ci		   "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n",
253262306a36Sopenharmony_ci		   size, (unsigned long)queue->rx_buffers_dma, queue->rx_buffers);
253362306a36Sopenharmony_ci	return 0;
253462306a36Sopenharmony_ci}
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_cistatic int macb_alloc_consistent(struct macb *bp)
253762306a36Sopenharmony_ci{
253862306a36Sopenharmony_ci	struct macb_queue *queue;
253962306a36Sopenharmony_ci	unsigned int q;
254062306a36Sopenharmony_ci	int size;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
254362306a36Sopenharmony_ci		size = TX_RING_BYTES(bp) + bp->tx_bd_rd_prefetch;
254462306a36Sopenharmony_ci		queue->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
254562306a36Sopenharmony_ci						    &queue->tx_ring_dma,
254662306a36Sopenharmony_ci						    GFP_KERNEL);
254762306a36Sopenharmony_ci		if (!queue->tx_ring)
254862306a36Sopenharmony_ci			goto out_err;
254962306a36Sopenharmony_ci		netdev_dbg(bp->dev,
255062306a36Sopenharmony_ci			   "Allocated TX ring for queue %u of %d bytes at %08lx (mapped %p)\n",
255162306a36Sopenharmony_ci			   q, size, (unsigned long)queue->tx_ring_dma,
255262306a36Sopenharmony_ci			   queue->tx_ring);
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci		size = bp->tx_ring_size * sizeof(struct macb_tx_skb);
255562306a36Sopenharmony_ci		queue->tx_skb = kmalloc(size, GFP_KERNEL);
255662306a36Sopenharmony_ci		if (!queue->tx_skb)
255762306a36Sopenharmony_ci			goto out_err;
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci		size = RX_RING_BYTES(bp) + bp->rx_bd_rd_prefetch;
256062306a36Sopenharmony_ci		queue->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
256162306a36Sopenharmony_ci						 &queue->rx_ring_dma, GFP_KERNEL);
256262306a36Sopenharmony_ci		if (!queue->rx_ring)
256362306a36Sopenharmony_ci			goto out_err;
256462306a36Sopenharmony_ci		netdev_dbg(bp->dev,
256562306a36Sopenharmony_ci			   "Allocated RX ring of %d bytes at %08lx (mapped %p)\n",
256662306a36Sopenharmony_ci			   size, (unsigned long)queue->rx_ring_dma, queue->rx_ring);
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci	if (bp->macbgem_ops.mog_alloc_rx_buffers(bp))
256962306a36Sopenharmony_ci		goto out_err;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	return 0;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ciout_err:
257462306a36Sopenharmony_ci	macb_free_consistent(bp);
257562306a36Sopenharmony_ci	return -ENOMEM;
257662306a36Sopenharmony_ci}
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_cistatic void gem_init_rings(struct macb *bp)
257962306a36Sopenharmony_ci{
258062306a36Sopenharmony_ci	struct macb_queue *queue;
258162306a36Sopenharmony_ci	struct macb_dma_desc *desc = NULL;
258262306a36Sopenharmony_ci	unsigned int q;
258362306a36Sopenharmony_ci	int i;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
258662306a36Sopenharmony_ci		for (i = 0; i < bp->tx_ring_size; i++) {
258762306a36Sopenharmony_ci			desc = macb_tx_desc(queue, i);
258862306a36Sopenharmony_ci			macb_set_addr(bp, desc, 0);
258962306a36Sopenharmony_ci			desc->ctrl = MACB_BIT(TX_USED);
259062306a36Sopenharmony_ci		}
259162306a36Sopenharmony_ci		desc->ctrl |= MACB_BIT(TX_WRAP);
259262306a36Sopenharmony_ci		queue->tx_head = 0;
259362306a36Sopenharmony_ci		queue->tx_tail = 0;
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci		queue->rx_tail = 0;
259662306a36Sopenharmony_ci		queue->rx_prepared_head = 0;
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci		gem_rx_refill(queue);
259962306a36Sopenharmony_ci	}
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_cistatic void macb_init_rings(struct macb *bp)
260462306a36Sopenharmony_ci{
260562306a36Sopenharmony_ci	int i;
260662306a36Sopenharmony_ci	struct macb_dma_desc *desc = NULL;
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci	macb_init_rx_ring(&bp->queues[0]);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	for (i = 0; i < bp->tx_ring_size; i++) {
261162306a36Sopenharmony_ci		desc = macb_tx_desc(&bp->queues[0], i);
261262306a36Sopenharmony_ci		macb_set_addr(bp, desc, 0);
261362306a36Sopenharmony_ci		desc->ctrl = MACB_BIT(TX_USED);
261462306a36Sopenharmony_ci	}
261562306a36Sopenharmony_ci	bp->queues[0].tx_head = 0;
261662306a36Sopenharmony_ci	bp->queues[0].tx_tail = 0;
261762306a36Sopenharmony_ci	desc->ctrl |= MACB_BIT(TX_WRAP);
261862306a36Sopenharmony_ci}
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_cistatic void macb_reset_hw(struct macb *bp)
262162306a36Sopenharmony_ci{
262262306a36Sopenharmony_ci	struct macb_queue *queue;
262362306a36Sopenharmony_ci	unsigned int q;
262462306a36Sopenharmony_ci	u32 ctrl = macb_readl(bp, NCR);
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci	/* Disable RX and TX (XXX: Should we halt the transmission
262762306a36Sopenharmony_ci	 * more gracefully?)
262862306a36Sopenharmony_ci	 */
262962306a36Sopenharmony_ci	ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	/* Clear the stats registers (XXX: Update stats first?) */
263262306a36Sopenharmony_ci	ctrl |= MACB_BIT(CLRSTAT);
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	macb_writel(bp, NCR, ctrl);
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	/* Clear all status flags */
263762306a36Sopenharmony_ci	macb_writel(bp, TSR, -1);
263862306a36Sopenharmony_ci	macb_writel(bp, RSR, -1);
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	/* Disable RX partial store and forward and reset watermark value */
264162306a36Sopenharmony_ci	gem_writel(bp, PBUFRXCUT, 0);
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	/* Disable all interrupts */
264462306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
264562306a36Sopenharmony_ci		queue_writel(queue, IDR, -1);
264662306a36Sopenharmony_ci		queue_readl(queue, ISR);
264762306a36Sopenharmony_ci		if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
264862306a36Sopenharmony_ci			queue_writel(queue, ISR, -1);
264962306a36Sopenharmony_ci	}
265062306a36Sopenharmony_ci}
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_cistatic u32 gem_mdc_clk_div(struct macb *bp)
265362306a36Sopenharmony_ci{
265462306a36Sopenharmony_ci	u32 config;
265562306a36Sopenharmony_ci	unsigned long pclk_hz = clk_get_rate(bp->pclk);
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	if (pclk_hz <= 20000000)
265862306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV8);
265962306a36Sopenharmony_ci	else if (pclk_hz <= 40000000)
266062306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV16);
266162306a36Sopenharmony_ci	else if (pclk_hz <= 80000000)
266262306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV32);
266362306a36Sopenharmony_ci	else if (pclk_hz <= 120000000)
266462306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV48);
266562306a36Sopenharmony_ci	else if (pclk_hz <= 160000000)
266662306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV64);
266762306a36Sopenharmony_ci	else if (pclk_hz <= 240000000)
266862306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV96);
266962306a36Sopenharmony_ci	else if (pclk_hz <= 320000000)
267062306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV128);
267162306a36Sopenharmony_ci	else
267262306a36Sopenharmony_ci		config = GEM_BF(CLK, GEM_CLK_DIV224);
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	return config;
267562306a36Sopenharmony_ci}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_cistatic u32 macb_mdc_clk_div(struct macb *bp)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	u32 config;
268062306a36Sopenharmony_ci	unsigned long pclk_hz;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	if (macb_is_gem(bp))
268362306a36Sopenharmony_ci		return gem_mdc_clk_div(bp);
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	pclk_hz = clk_get_rate(bp->pclk);
268662306a36Sopenharmony_ci	if (pclk_hz <= 20000000)
268762306a36Sopenharmony_ci		config = MACB_BF(CLK, MACB_CLK_DIV8);
268862306a36Sopenharmony_ci	else if (pclk_hz <= 40000000)
268962306a36Sopenharmony_ci		config = MACB_BF(CLK, MACB_CLK_DIV16);
269062306a36Sopenharmony_ci	else if (pclk_hz <= 80000000)
269162306a36Sopenharmony_ci		config = MACB_BF(CLK, MACB_CLK_DIV32);
269262306a36Sopenharmony_ci	else
269362306a36Sopenharmony_ci		config = MACB_BF(CLK, MACB_CLK_DIV64);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	return config;
269662306a36Sopenharmony_ci}
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci/* Get the DMA bus width field of the network configuration register that we
269962306a36Sopenharmony_ci * should program.  We find the width from decoding the design configuration
270062306a36Sopenharmony_ci * register to find the maximum supported data bus width.
270162306a36Sopenharmony_ci */
270262306a36Sopenharmony_cistatic u32 macb_dbw(struct macb *bp)
270362306a36Sopenharmony_ci{
270462306a36Sopenharmony_ci	if (!macb_is_gem(bp))
270562306a36Sopenharmony_ci		return 0;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) {
270862306a36Sopenharmony_ci	case 4:
270962306a36Sopenharmony_ci		return GEM_BF(DBW, GEM_DBW128);
271062306a36Sopenharmony_ci	case 2:
271162306a36Sopenharmony_ci		return GEM_BF(DBW, GEM_DBW64);
271262306a36Sopenharmony_ci	case 1:
271362306a36Sopenharmony_ci	default:
271462306a36Sopenharmony_ci		return GEM_BF(DBW, GEM_DBW32);
271562306a36Sopenharmony_ci	}
271662306a36Sopenharmony_ci}
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci/* Configure the receive DMA engine
271962306a36Sopenharmony_ci * - use the correct receive buffer size
272062306a36Sopenharmony_ci * - set best burst length for DMA operations
272162306a36Sopenharmony_ci *   (if not supported by FIFO, it will fallback to default)
272262306a36Sopenharmony_ci * - set both rx/tx packet buffers to full memory size
272362306a36Sopenharmony_ci * These are configurable parameters for GEM.
272462306a36Sopenharmony_ci */
272562306a36Sopenharmony_cistatic void macb_configure_dma(struct macb *bp)
272662306a36Sopenharmony_ci{
272762306a36Sopenharmony_ci	struct macb_queue *queue;
272862306a36Sopenharmony_ci	u32 buffer_size;
272962306a36Sopenharmony_ci	unsigned int q;
273062306a36Sopenharmony_ci	u32 dmacfg;
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	buffer_size = bp->rx_buffer_size / RX_BUFFER_MULTIPLE;
273362306a36Sopenharmony_ci	if (macb_is_gem(bp)) {
273462306a36Sopenharmony_ci		dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
273562306a36Sopenharmony_ci		for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
273662306a36Sopenharmony_ci			if (q)
273762306a36Sopenharmony_ci				queue_writel(queue, RBQS, buffer_size);
273862306a36Sopenharmony_ci			else
273962306a36Sopenharmony_ci				dmacfg |= GEM_BF(RXBS, buffer_size);
274062306a36Sopenharmony_ci		}
274162306a36Sopenharmony_ci		if (bp->dma_burst_length)
274262306a36Sopenharmony_ci			dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg);
274362306a36Sopenharmony_ci		dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
274462306a36Sopenharmony_ci		dmacfg &= ~GEM_BIT(ENDIA_PKT);
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci		if (bp->native_io)
274762306a36Sopenharmony_ci			dmacfg &= ~GEM_BIT(ENDIA_DESC);
274862306a36Sopenharmony_ci		else
274962306a36Sopenharmony_ci			dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci		if (bp->dev->features & NETIF_F_HW_CSUM)
275262306a36Sopenharmony_ci			dmacfg |= GEM_BIT(TXCOEN);
275362306a36Sopenharmony_ci		else
275462306a36Sopenharmony_ci			dmacfg &= ~GEM_BIT(TXCOEN);
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci		dmacfg &= ~GEM_BIT(ADDR64);
275762306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
275862306a36Sopenharmony_ci		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
275962306a36Sopenharmony_ci			dmacfg |= GEM_BIT(ADDR64);
276062306a36Sopenharmony_ci#endif
276162306a36Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP
276262306a36Sopenharmony_ci		if (bp->hw_dma_cap & HW_DMA_CAP_PTP)
276362306a36Sopenharmony_ci			dmacfg |= GEM_BIT(RXEXT) | GEM_BIT(TXEXT);
276462306a36Sopenharmony_ci#endif
276562306a36Sopenharmony_ci		netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n",
276662306a36Sopenharmony_ci			   dmacfg);
276762306a36Sopenharmony_ci		gem_writel(bp, DMACFG, dmacfg);
276862306a36Sopenharmony_ci	}
276962306a36Sopenharmony_ci}
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_cistatic void macb_init_hw(struct macb *bp)
277262306a36Sopenharmony_ci{
277362306a36Sopenharmony_ci	u32 config;
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	macb_reset_hw(bp);
277662306a36Sopenharmony_ci	macb_set_hwaddr(bp);
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	config = macb_mdc_clk_div(bp);
277962306a36Sopenharmony_ci	config |= MACB_BF(RBOF, NET_IP_ALIGN);	/* Make eth data aligned */
278062306a36Sopenharmony_ci	config |= MACB_BIT(DRFCS);		/* Discard Rx FCS */
278162306a36Sopenharmony_ci	if (bp->caps & MACB_CAPS_JUMBO)
278262306a36Sopenharmony_ci		config |= MACB_BIT(JFRAME);	/* Enable jumbo frames */
278362306a36Sopenharmony_ci	else
278462306a36Sopenharmony_ci		config |= MACB_BIT(BIG);	/* Receive oversized frames */
278562306a36Sopenharmony_ci	if (bp->dev->flags & IFF_PROMISC)
278662306a36Sopenharmony_ci		config |= MACB_BIT(CAF);	/* Copy All Frames */
278762306a36Sopenharmony_ci	else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM)
278862306a36Sopenharmony_ci		config |= GEM_BIT(RXCOEN);
278962306a36Sopenharmony_ci	if (!(bp->dev->flags & IFF_BROADCAST))
279062306a36Sopenharmony_ci		config |= MACB_BIT(NBC);	/* No BroadCast */
279162306a36Sopenharmony_ci	config |= macb_dbw(bp);
279262306a36Sopenharmony_ci	macb_writel(bp, NCFGR, config);
279362306a36Sopenharmony_ci	if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len)
279462306a36Sopenharmony_ci		gem_writel(bp, JML, bp->jumbo_max_len);
279562306a36Sopenharmony_ci	bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK;
279662306a36Sopenharmony_ci	if (bp->caps & MACB_CAPS_JUMBO)
279762306a36Sopenharmony_ci		bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	macb_configure_dma(bp);
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	/* Enable RX partial store and forward and set watermark */
280262306a36Sopenharmony_ci	if (bp->rx_watermark)
280362306a36Sopenharmony_ci		gem_writel(bp, PBUFRXCUT, (bp->rx_watermark | GEM_BIT(ENCUTTHRU)));
280462306a36Sopenharmony_ci}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci/* The hash address register is 64 bits long and takes up two
280762306a36Sopenharmony_ci * locations in the memory map.  The least significant bits are stored
280862306a36Sopenharmony_ci * in EMAC_HSL and the most significant bits in EMAC_HSH.
280962306a36Sopenharmony_ci *
281062306a36Sopenharmony_ci * The unicast hash enable and the multicast hash enable bits in the
281162306a36Sopenharmony_ci * network configuration register enable the reception of hash matched
281262306a36Sopenharmony_ci * frames. The destination address is reduced to a 6 bit index into
281362306a36Sopenharmony_ci * the 64 bit hash register using the following hash function.  The
281462306a36Sopenharmony_ci * hash function is an exclusive or of every sixth bit of the
281562306a36Sopenharmony_ci * destination address.
281662306a36Sopenharmony_ci *
281762306a36Sopenharmony_ci * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47]
281862306a36Sopenharmony_ci * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46]
281962306a36Sopenharmony_ci * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45]
282062306a36Sopenharmony_ci * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44]
282162306a36Sopenharmony_ci * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43]
282262306a36Sopenharmony_ci * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42]
282362306a36Sopenharmony_ci *
282462306a36Sopenharmony_ci * da[0] represents the least significant bit of the first byte
282562306a36Sopenharmony_ci * received, that is, the multicast/unicast indicator, and da[47]
282662306a36Sopenharmony_ci * represents the most significant bit of the last byte received.  If
282762306a36Sopenharmony_ci * the hash index, hi[n], points to a bit that is set in the hash
282862306a36Sopenharmony_ci * register then the frame will be matched according to whether the
282962306a36Sopenharmony_ci * frame is multicast or unicast.  A multicast match will be signalled
283062306a36Sopenharmony_ci * if the multicast hash enable bit is set, da[0] is 1 and the hash
283162306a36Sopenharmony_ci * index points to a bit set in the hash register.  A unicast match
283262306a36Sopenharmony_ci * will be signalled if the unicast hash enable bit is set, da[0] is 0
283362306a36Sopenharmony_ci * and the hash index points to a bit set in the hash register.  To
283462306a36Sopenharmony_ci * receive all multicast frames, the hash register should be set with
283562306a36Sopenharmony_ci * all ones and the multicast hash enable bit should be set in the
283662306a36Sopenharmony_ci * network configuration register.
283762306a36Sopenharmony_ci */
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_cistatic inline int hash_bit_value(int bitnr, __u8 *addr)
284062306a36Sopenharmony_ci{
284162306a36Sopenharmony_ci	if (addr[bitnr / 8] & (1 << (bitnr % 8)))
284262306a36Sopenharmony_ci		return 1;
284362306a36Sopenharmony_ci	return 0;
284462306a36Sopenharmony_ci}
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci/* Return the hash index value for the specified address. */
284762306a36Sopenharmony_cistatic int hash_get_index(__u8 *addr)
284862306a36Sopenharmony_ci{
284962306a36Sopenharmony_ci	int i, j, bitval;
285062306a36Sopenharmony_ci	int hash_index = 0;
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	for (j = 0; j < 6; j++) {
285362306a36Sopenharmony_ci		for (i = 0, bitval = 0; i < 8; i++)
285462306a36Sopenharmony_ci			bitval ^= hash_bit_value(i * 6 + j, addr);
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci		hash_index |= (bitval << j);
285762306a36Sopenharmony_ci	}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	return hash_index;
286062306a36Sopenharmony_ci}
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci/* Add multicast addresses to the internal multicast-hash table. */
286362306a36Sopenharmony_cistatic void macb_sethashtable(struct net_device *dev)
286462306a36Sopenharmony_ci{
286562306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
286662306a36Sopenharmony_ci	unsigned long mc_filter[2];
286762306a36Sopenharmony_ci	unsigned int bitnr;
286862306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	mc_filter[0] = 0;
287162306a36Sopenharmony_ci	mc_filter[1] = 0;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
287462306a36Sopenharmony_ci		bitnr = hash_get_index(ha->addr);
287562306a36Sopenharmony_ci		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
287662306a36Sopenharmony_ci	}
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	macb_or_gem_writel(bp, HRB, mc_filter[0]);
287962306a36Sopenharmony_ci	macb_or_gem_writel(bp, HRT, mc_filter[1]);
288062306a36Sopenharmony_ci}
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci/* Enable/Disable promiscuous and multicast modes. */
288362306a36Sopenharmony_cistatic void macb_set_rx_mode(struct net_device *dev)
288462306a36Sopenharmony_ci{
288562306a36Sopenharmony_ci	unsigned long cfg;
288662306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	cfg = macb_readl(bp, NCFGR);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
289162306a36Sopenharmony_ci		/* Enable promiscuous mode */
289262306a36Sopenharmony_ci		cfg |= MACB_BIT(CAF);
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci		/* Disable RX checksum offload */
289562306a36Sopenharmony_ci		if (macb_is_gem(bp))
289662306a36Sopenharmony_ci			cfg &= ~GEM_BIT(RXCOEN);
289762306a36Sopenharmony_ci	} else {
289862306a36Sopenharmony_ci		/* Disable promiscuous mode */
289962306a36Sopenharmony_ci		cfg &= ~MACB_BIT(CAF);
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci		/* Enable RX checksum offload only if requested */
290262306a36Sopenharmony_ci		if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM)
290362306a36Sopenharmony_ci			cfg |= GEM_BIT(RXCOEN);
290462306a36Sopenharmony_ci	}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI) {
290762306a36Sopenharmony_ci		/* Enable all multicast mode */
290862306a36Sopenharmony_ci		macb_or_gem_writel(bp, HRB, -1);
290962306a36Sopenharmony_ci		macb_or_gem_writel(bp, HRT, -1);
291062306a36Sopenharmony_ci		cfg |= MACB_BIT(NCFGR_MTI);
291162306a36Sopenharmony_ci	} else if (!netdev_mc_empty(dev)) {
291262306a36Sopenharmony_ci		/* Enable specific multicasts */
291362306a36Sopenharmony_ci		macb_sethashtable(dev);
291462306a36Sopenharmony_ci		cfg |= MACB_BIT(NCFGR_MTI);
291562306a36Sopenharmony_ci	} else if (dev->flags & (~IFF_ALLMULTI)) {
291662306a36Sopenharmony_ci		/* Disable all multicast mode */
291762306a36Sopenharmony_ci		macb_or_gem_writel(bp, HRB, 0);
291862306a36Sopenharmony_ci		macb_or_gem_writel(bp, HRT, 0);
291962306a36Sopenharmony_ci		cfg &= ~MACB_BIT(NCFGR_MTI);
292062306a36Sopenharmony_ci	}
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	macb_writel(bp, NCFGR, cfg);
292362306a36Sopenharmony_ci}
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_cistatic int macb_open(struct net_device *dev)
292662306a36Sopenharmony_ci{
292762306a36Sopenharmony_ci	size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN;
292862306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
292962306a36Sopenharmony_ci	struct macb_queue *queue;
293062306a36Sopenharmony_ci	unsigned int q;
293162306a36Sopenharmony_ci	int err;
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	netdev_dbg(bp->dev, "open\n");
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	err = pm_runtime_resume_and_get(&bp->pdev->dev);
293662306a36Sopenharmony_ci	if (err < 0)
293762306a36Sopenharmony_ci		return err;
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci	/* RX buffers initialization */
294062306a36Sopenharmony_ci	macb_init_rx_buffer_size(bp, bufsz);
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci	err = macb_alloc_consistent(bp);
294362306a36Sopenharmony_ci	if (err) {
294462306a36Sopenharmony_ci		netdev_err(dev, "Unable to allocate DMA memory (error %d)\n",
294562306a36Sopenharmony_ci			   err);
294662306a36Sopenharmony_ci		goto pm_exit;
294762306a36Sopenharmony_ci	}
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
295062306a36Sopenharmony_ci		napi_enable(&queue->napi_rx);
295162306a36Sopenharmony_ci		napi_enable(&queue->napi_tx);
295262306a36Sopenharmony_ci	}
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	macb_init_hw(bp);
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	err = phy_power_on(bp->sgmii_phy);
295762306a36Sopenharmony_ci	if (err)
295862306a36Sopenharmony_ci		goto reset_hw;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	err = macb_phylink_connect(bp);
296162306a36Sopenharmony_ci	if (err)
296262306a36Sopenharmony_ci		goto phy_off;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	netif_tx_start_all_queues(dev);
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	if (bp->ptp_info)
296762306a36Sopenharmony_ci		bp->ptp_info->ptp_init(dev);
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	return 0;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ciphy_off:
297262306a36Sopenharmony_ci	phy_power_off(bp->sgmii_phy);
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_cireset_hw:
297562306a36Sopenharmony_ci	macb_reset_hw(bp);
297662306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
297762306a36Sopenharmony_ci		napi_disable(&queue->napi_rx);
297862306a36Sopenharmony_ci		napi_disable(&queue->napi_tx);
297962306a36Sopenharmony_ci	}
298062306a36Sopenharmony_ci	macb_free_consistent(bp);
298162306a36Sopenharmony_cipm_exit:
298262306a36Sopenharmony_ci	pm_runtime_put_sync(&bp->pdev->dev);
298362306a36Sopenharmony_ci	return err;
298462306a36Sopenharmony_ci}
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_cistatic int macb_close(struct net_device *dev)
298762306a36Sopenharmony_ci{
298862306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
298962306a36Sopenharmony_ci	struct macb_queue *queue;
299062306a36Sopenharmony_ci	unsigned long flags;
299162306a36Sopenharmony_ci	unsigned int q;
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	netif_tx_stop_all_queues(dev);
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
299662306a36Sopenharmony_ci		napi_disable(&queue->napi_rx);
299762306a36Sopenharmony_ci		napi_disable(&queue->napi_tx);
299862306a36Sopenharmony_ci	}
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_ci	phylink_stop(bp->phylink);
300162306a36Sopenharmony_ci	phylink_disconnect_phy(bp->phylink);
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	phy_power_off(bp->sgmii_phy);
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
300662306a36Sopenharmony_ci	macb_reset_hw(bp);
300762306a36Sopenharmony_ci	netif_carrier_off(dev);
300862306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	macb_free_consistent(bp);
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	if (bp->ptp_info)
301362306a36Sopenharmony_ci		bp->ptp_info->ptp_remove(dev);
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci	pm_runtime_put(&bp->pdev->dev);
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_ci	return 0;
301862306a36Sopenharmony_ci}
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_cistatic int macb_change_mtu(struct net_device *dev, int new_mtu)
302162306a36Sopenharmony_ci{
302262306a36Sopenharmony_ci	if (netif_running(dev))
302362306a36Sopenharmony_ci		return -EBUSY;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci	dev->mtu = new_mtu;
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci	return 0;
302862306a36Sopenharmony_ci}
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_cistatic int macb_set_mac_addr(struct net_device *dev, void *addr)
303162306a36Sopenharmony_ci{
303262306a36Sopenharmony_ci	int err;
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	err = eth_mac_addr(dev, addr);
303562306a36Sopenharmony_ci	if (err < 0)
303662306a36Sopenharmony_ci		return err;
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci	macb_set_hwaddr(netdev_priv(dev));
303962306a36Sopenharmony_ci	return 0;
304062306a36Sopenharmony_ci}
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_cistatic void gem_update_stats(struct macb *bp)
304362306a36Sopenharmony_ci{
304462306a36Sopenharmony_ci	struct macb_queue *queue;
304562306a36Sopenharmony_ci	unsigned int i, q, idx;
304662306a36Sopenharmony_ci	unsigned long *stat;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	u32 *p = &bp->hw_stats.gem.tx_octets_31_0;
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	for (i = 0; i < GEM_STATS_LEN; ++i, ++p) {
305162306a36Sopenharmony_ci		u32 offset = gem_statistics[i].offset;
305262306a36Sopenharmony_ci		u64 val = bp->macb_reg_readl(bp, offset);
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci		bp->ethtool_stats[i] += val;
305562306a36Sopenharmony_ci		*p += val;
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci		if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) {
305862306a36Sopenharmony_ci			/* Add GEM_OCTTXH, GEM_OCTRXH */
305962306a36Sopenharmony_ci			val = bp->macb_reg_readl(bp, offset + 4);
306062306a36Sopenharmony_ci			bp->ethtool_stats[i] += ((u64)val) << 32;
306162306a36Sopenharmony_ci			*(++p) += val;
306262306a36Sopenharmony_ci		}
306362306a36Sopenharmony_ci	}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	idx = GEM_STATS_LEN;
306662306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
306762306a36Sopenharmony_ci		for (i = 0, stat = &queue->stats.first; i < QUEUE_STATS_LEN; ++i, ++stat)
306862306a36Sopenharmony_ci			bp->ethtool_stats[idx++] = *stat;
306962306a36Sopenharmony_ci}
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_cistatic struct net_device_stats *gem_get_stats(struct macb *bp)
307262306a36Sopenharmony_ci{
307362306a36Sopenharmony_ci	struct gem_stats *hwstat = &bp->hw_stats.gem;
307462306a36Sopenharmony_ci	struct net_device_stats *nstat = &bp->dev->stats;
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	if (!netif_running(bp->dev))
307762306a36Sopenharmony_ci		return nstat;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	gem_update_stats(bp);
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors +
308262306a36Sopenharmony_ci			    hwstat->rx_alignment_errors +
308362306a36Sopenharmony_ci			    hwstat->rx_resource_errors +
308462306a36Sopenharmony_ci			    hwstat->rx_overruns +
308562306a36Sopenharmony_ci			    hwstat->rx_oversize_frames +
308662306a36Sopenharmony_ci			    hwstat->rx_jabbers +
308762306a36Sopenharmony_ci			    hwstat->rx_undersized_frames +
308862306a36Sopenharmony_ci			    hwstat->rx_length_field_frame_errors);
308962306a36Sopenharmony_ci	nstat->tx_errors = (hwstat->tx_late_collisions +
309062306a36Sopenharmony_ci			    hwstat->tx_excessive_collisions +
309162306a36Sopenharmony_ci			    hwstat->tx_underrun +
309262306a36Sopenharmony_ci			    hwstat->tx_carrier_sense_errors);
309362306a36Sopenharmony_ci	nstat->multicast = hwstat->rx_multicast_frames;
309462306a36Sopenharmony_ci	nstat->collisions = (hwstat->tx_single_collision_frames +
309562306a36Sopenharmony_ci			     hwstat->tx_multiple_collision_frames +
309662306a36Sopenharmony_ci			     hwstat->tx_excessive_collisions);
309762306a36Sopenharmony_ci	nstat->rx_length_errors = (hwstat->rx_oversize_frames +
309862306a36Sopenharmony_ci				   hwstat->rx_jabbers +
309962306a36Sopenharmony_ci				   hwstat->rx_undersized_frames +
310062306a36Sopenharmony_ci				   hwstat->rx_length_field_frame_errors);
310162306a36Sopenharmony_ci	nstat->rx_over_errors = hwstat->rx_resource_errors;
310262306a36Sopenharmony_ci	nstat->rx_crc_errors = hwstat->rx_frame_check_sequence_errors;
310362306a36Sopenharmony_ci	nstat->rx_frame_errors = hwstat->rx_alignment_errors;
310462306a36Sopenharmony_ci	nstat->rx_fifo_errors = hwstat->rx_overruns;
310562306a36Sopenharmony_ci	nstat->tx_aborted_errors = hwstat->tx_excessive_collisions;
310662306a36Sopenharmony_ci	nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors;
310762306a36Sopenharmony_ci	nstat->tx_fifo_errors = hwstat->tx_underrun;
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	return nstat;
311062306a36Sopenharmony_ci}
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_cistatic void gem_get_ethtool_stats(struct net_device *dev,
311362306a36Sopenharmony_ci				  struct ethtool_stats *stats, u64 *data)
311462306a36Sopenharmony_ci{
311562306a36Sopenharmony_ci	struct macb *bp;
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ci	bp = netdev_priv(dev);
311862306a36Sopenharmony_ci	gem_update_stats(bp);
311962306a36Sopenharmony_ci	memcpy(data, &bp->ethtool_stats, sizeof(u64)
312062306a36Sopenharmony_ci			* (GEM_STATS_LEN + QUEUE_STATS_LEN * MACB_MAX_QUEUES));
312162306a36Sopenharmony_ci}
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_cistatic int gem_get_sset_count(struct net_device *dev, int sset)
312462306a36Sopenharmony_ci{
312562306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	switch (sset) {
312862306a36Sopenharmony_ci	case ETH_SS_STATS:
312962306a36Sopenharmony_ci		return GEM_STATS_LEN + bp->num_queues * QUEUE_STATS_LEN;
313062306a36Sopenharmony_ci	default:
313162306a36Sopenharmony_ci		return -EOPNOTSUPP;
313262306a36Sopenharmony_ci	}
313362306a36Sopenharmony_ci}
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_cistatic void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p)
313662306a36Sopenharmony_ci{
313762306a36Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
313862306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
313962306a36Sopenharmony_ci	struct macb_queue *queue;
314062306a36Sopenharmony_ci	unsigned int i;
314162306a36Sopenharmony_ci	unsigned int q;
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ci	switch (sset) {
314462306a36Sopenharmony_ci	case ETH_SS_STATS:
314562306a36Sopenharmony_ci		for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN)
314662306a36Sopenharmony_ci			memcpy(p, gem_statistics[i].stat_string,
314762306a36Sopenharmony_ci			       ETH_GSTRING_LEN);
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci		for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
315062306a36Sopenharmony_ci			for (i = 0; i < QUEUE_STATS_LEN; i++, p += ETH_GSTRING_LEN) {
315162306a36Sopenharmony_ci				snprintf(stat_string, ETH_GSTRING_LEN, "q%d_%s",
315262306a36Sopenharmony_ci						q, queue_statistics[i].stat_string);
315362306a36Sopenharmony_ci				memcpy(p, stat_string, ETH_GSTRING_LEN);
315462306a36Sopenharmony_ci			}
315562306a36Sopenharmony_ci		}
315662306a36Sopenharmony_ci		break;
315762306a36Sopenharmony_ci	}
315862306a36Sopenharmony_ci}
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_cistatic struct net_device_stats *macb_get_stats(struct net_device *dev)
316162306a36Sopenharmony_ci{
316262306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
316362306a36Sopenharmony_ci	struct net_device_stats *nstat = &bp->dev->stats;
316462306a36Sopenharmony_ci	struct macb_stats *hwstat = &bp->hw_stats.macb;
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	if (macb_is_gem(bp))
316762306a36Sopenharmony_ci		return gem_get_stats(bp);
316862306a36Sopenharmony_ci
316962306a36Sopenharmony_ci	/* read stats from hardware */
317062306a36Sopenharmony_ci	macb_update_stats(bp);
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci	/* Convert HW stats into netdevice stats */
317362306a36Sopenharmony_ci	nstat->rx_errors = (hwstat->rx_fcs_errors +
317462306a36Sopenharmony_ci			    hwstat->rx_align_errors +
317562306a36Sopenharmony_ci			    hwstat->rx_resource_errors +
317662306a36Sopenharmony_ci			    hwstat->rx_overruns +
317762306a36Sopenharmony_ci			    hwstat->rx_oversize_pkts +
317862306a36Sopenharmony_ci			    hwstat->rx_jabbers +
317962306a36Sopenharmony_ci			    hwstat->rx_undersize_pkts +
318062306a36Sopenharmony_ci			    hwstat->rx_length_mismatch);
318162306a36Sopenharmony_ci	nstat->tx_errors = (hwstat->tx_late_cols +
318262306a36Sopenharmony_ci			    hwstat->tx_excessive_cols +
318362306a36Sopenharmony_ci			    hwstat->tx_underruns +
318462306a36Sopenharmony_ci			    hwstat->tx_carrier_errors +
318562306a36Sopenharmony_ci			    hwstat->sqe_test_errors);
318662306a36Sopenharmony_ci	nstat->collisions = (hwstat->tx_single_cols +
318762306a36Sopenharmony_ci			     hwstat->tx_multiple_cols +
318862306a36Sopenharmony_ci			     hwstat->tx_excessive_cols);
318962306a36Sopenharmony_ci	nstat->rx_length_errors = (hwstat->rx_oversize_pkts +
319062306a36Sopenharmony_ci				   hwstat->rx_jabbers +
319162306a36Sopenharmony_ci				   hwstat->rx_undersize_pkts +
319262306a36Sopenharmony_ci				   hwstat->rx_length_mismatch);
319362306a36Sopenharmony_ci	nstat->rx_over_errors = hwstat->rx_resource_errors +
319462306a36Sopenharmony_ci				   hwstat->rx_overruns;
319562306a36Sopenharmony_ci	nstat->rx_crc_errors = hwstat->rx_fcs_errors;
319662306a36Sopenharmony_ci	nstat->rx_frame_errors = hwstat->rx_align_errors;
319762306a36Sopenharmony_ci	nstat->rx_fifo_errors = hwstat->rx_overruns;
319862306a36Sopenharmony_ci	/* XXX: What does "missed" mean? */
319962306a36Sopenharmony_ci	nstat->tx_aborted_errors = hwstat->tx_excessive_cols;
320062306a36Sopenharmony_ci	nstat->tx_carrier_errors = hwstat->tx_carrier_errors;
320162306a36Sopenharmony_ci	nstat->tx_fifo_errors = hwstat->tx_underruns;
320262306a36Sopenharmony_ci	/* Don't know about heartbeat or window errors... */
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	return nstat;
320562306a36Sopenharmony_ci}
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_cistatic int macb_get_regs_len(struct net_device *netdev)
320862306a36Sopenharmony_ci{
320962306a36Sopenharmony_ci	return MACB_GREGS_NBR * sizeof(u32);
321062306a36Sopenharmony_ci}
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_cistatic void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
321362306a36Sopenharmony_ci			  void *p)
321462306a36Sopenharmony_ci{
321562306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
321662306a36Sopenharmony_ci	unsigned int tail, head;
321762306a36Sopenharmony_ci	u32 *regs_buff = p;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1))
322062306a36Sopenharmony_ci			| MACB_GREGS_VERSION;
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	tail = macb_tx_ring_wrap(bp, bp->queues[0].tx_tail);
322362306a36Sopenharmony_ci	head = macb_tx_ring_wrap(bp, bp->queues[0].tx_head);
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci	regs_buff[0]  = macb_readl(bp, NCR);
322662306a36Sopenharmony_ci	regs_buff[1]  = macb_or_gem_readl(bp, NCFGR);
322762306a36Sopenharmony_ci	regs_buff[2]  = macb_readl(bp, NSR);
322862306a36Sopenharmony_ci	regs_buff[3]  = macb_readl(bp, TSR);
322962306a36Sopenharmony_ci	regs_buff[4]  = macb_readl(bp, RBQP);
323062306a36Sopenharmony_ci	regs_buff[5]  = macb_readl(bp, TBQP);
323162306a36Sopenharmony_ci	regs_buff[6]  = macb_readl(bp, RSR);
323262306a36Sopenharmony_ci	regs_buff[7]  = macb_readl(bp, IMR);
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	regs_buff[8]  = tail;
323562306a36Sopenharmony_ci	regs_buff[9]  = head;
323662306a36Sopenharmony_ci	regs_buff[10] = macb_tx_dma(&bp->queues[0], tail);
323762306a36Sopenharmony_ci	regs_buff[11] = macb_tx_dma(&bp->queues[0], head);
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
324062306a36Sopenharmony_ci		regs_buff[12] = macb_or_gem_readl(bp, USRIO);
324162306a36Sopenharmony_ci	if (macb_is_gem(bp))
324262306a36Sopenharmony_ci		regs_buff[13] = gem_readl(bp, DMACFG);
324362306a36Sopenharmony_ci}
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_cistatic void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
324662306a36Sopenharmony_ci{
324762306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) {
325062306a36Sopenharmony_ci		phylink_ethtool_get_wol(bp->phylink, wol);
325162306a36Sopenharmony_ci		wol->supported |= WAKE_MAGIC;
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci		if (bp->wol & MACB_WOL_ENABLED)
325462306a36Sopenharmony_ci			wol->wolopts |= WAKE_MAGIC;
325562306a36Sopenharmony_ci	}
325662306a36Sopenharmony_ci}
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_cistatic int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
325962306a36Sopenharmony_ci{
326062306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
326162306a36Sopenharmony_ci	int ret;
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	/* Pass the order to phylink layer */
326462306a36Sopenharmony_ci	ret = phylink_ethtool_set_wol(bp->phylink, wol);
326562306a36Sopenharmony_ci	/* Don't manage WoL on MAC if handled by the PHY
326662306a36Sopenharmony_ci	 * or if there's a failure in talking to the PHY
326762306a36Sopenharmony_ci	 */
326862306a36Sopenharmony_ci	if (!ret || ret != -EOPNOTSUPP)
326962306a36Sopenharmony_ci		return ret;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) ||
327262306a36Sopenharmony_ci	    (wol->wolopts & ~WAKE_MAGIC))
327362306a36Sopenharmony_ci		return -EOPNOTSUPP;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC)
327662306a36Sopenharmony_ci		bp->wol |= MACB_WOL_ENABLED;
327762306a36Sopenharmony_ci	else
327862306a36Sopenharmony_ci		bp->wol &= ~MACB_WOL_ENABLED;
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	device_set_wakeup_enable(&bp->pdev->dev, bp->wol & MACB_WOL_ENABLED);
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	return 0;
328362306a36Sopenharmony_ci}
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_cistatic int macb_get_link_ksettings(struct net_device *netdev,
328662306a36Sopenharmony_ci				   struct ethtool_link_ksettings *kset)
328762306a36Sopenharmony_ci{
328862306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	return phylink_ethtool_ksettings_get(bp->phylink, kset);
329162306a36Sopenharmony_ci}
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_cistatic int macb_set_link_ksettings(struct net_device *netdev,
329462306a36Sopenharmony_ci				   const struct ethtool_link_ksettings *kset)
329562306a36Sopenharmony_ci{
329662306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	return phylink_ethtool_ksettings_set(bp->phylink, kset);
329962306a36Sopenharmony_ci}
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_cistatic void macb_get_ringparam(struct net_device *netdev,
330262306a36Sopenharmony_ci			       struct ethtool_ringparam *ring,
330362306a36Sopenharmony_ci			       struct kernel_ethtool_ringparam *kernel_ring,
330462306a36Sopenharmony_ci			       struct netlink_ext_ack *extack)
330562306a36Sopenharmony_ci{
330662306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	ring->rx_max_pending = MAX_RX_RING_SIZE;
330962306a36Sopenharmony_ci	ring->tx_max_pending = MAX_TX_RING_SIZE;
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	ring->rx_pending = bp->rx_ring_size;
331262306a36Sopenharmony_ci	ring->tx_pending = bp->tx_ring_size;
331362306a36Sopenharmony_ci}
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_cistatic int macb_set_ringparam(struct net_device *netdev,
331662306a36Sopenharmony_ci			      struct ethtool_ringparam *ring,
331762306a36Sopenharmony_ci			      struct kernel_ethtool_ringparam *kernel_ring,
331862306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
331962306a36Sopenharmony_ci{
332062306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
332162306a36Sopenharmony_ci	u32 new_rx_size, new_tx_size;
332262306a36Sopenharmony_ci	unsigned int reset = 0;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
332562306a36Sopenharmony_ci		return -EINVAL;
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_ci	new_rx_size = clamp_t(u32, ring->rx_pending,
332862306a36Sopenharmony_ci			      MIN_RX_RING_SIZE, MAX_RX_RING_SIZE);
332962306a36Sopenharmony_ci	new_rx_size = roundup_pow_of_two(new_rx_size);
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	new_tx_size = clamp_t(u32, ring->tx_pending,
333262306a36Sopenharmony_ci			      MIN_TX_RING_SIZE, MAX_TX_RING_SIZE);
333362306a36Sopenharmony_ci	new_tx_size = roundup_pow_of_two(new_tx_size);
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	if ((new_tx_size == bp->tx_ring_size) &&
333662306a36Sopenharmony_ci	    (new_rx_size == bp->rx_ring_size)) {
333762306a36Sopenharmony_ci		/* nothing to do */
333862306a36Sopenharmony_ci		return 0;
333962306a36Sopenharmony_ci	}
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	if (netif_running(bp->dev)) {
334262306a36Sopenharmony_ci		reset = 1;
334362306a36Sopenharmony_ci		macb_close(bp->dev);
334462306a36Sopenharmony_ci	}
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	bp->rx_ring_size = new_rx_size;
334762306a36Sopenharmony_ci	bp->tx_ring_size = new_tx_size;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	if (reset)
335062306a36Sopenharmony_ci		macb_open(bp->dev);
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	return 0;
335362306a36Sopenharmony_ci}
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP
335662306a36Sopenharmony_cistatic unsigned int gem_get_tsu_rate(struct macb *bp)
335762306a36Sopenharmony_ci{
335862306a36Sopenharmony_ci	struct clk *tsu_clk;
335962306a36Sopenharmony_ci	unsigned int tsu_rate;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	tsu_clk = devm_clk_get(&bp->pdev->dev, "tsu_clk");
336262306a36Sopenharmony_ci	if (!IS_ERR(tsu_clk))
336362306a36Sopenharmony_ci		tsu_rate = clk_get_rate(tsu_clk);
336462306a36Sopenharmony_ci	/* try pclk instead */
336562306a36Sopenharmony_ci	else if (!IS_ERR(bp->pclk)) {
336662306a36Sopenharmony_ci		tsu_clk = bp->pclk;
336762306a36Sopenharmony_ci		tsu_rate = clk_get_rate(tsu_clk);
336862306a36Sopenharmony_ci	} else
336962306a36Sopenharmony_ci		return -ENOTSUPP;
337062306a36Sopenharmony_ci	return tsu_rate;
337162306a36Sopenharmony_ci}
337262306a36Sopenharmony_ci
337362306a36Sopenharmony_cistatic s32 gem_get_ptp_max_adj(void)
337462306a36Sopenharmony_ci{
337562306a36Sopenharmony_ci	return 64000000;
337662306a36Sopenharmony_ci}
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_cistatic int gem_get_ts_info(struct net_device *dev,
337962306a36Sopenharmony_ci			   struct ethtool_ts_info *info)
338062306a36Sopenharmony_ci{
338162306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0) {
338462306a36Sopenharmony_ci		ethtool_op_get_ts_info(dev, info);
338562306a36Sopenharmony_ci		return 0;
338662306a36Sopenharmony_ci	}
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	info->so_timestamping =
338962306a36Sopenharmony_ci		SOF_TIMESTAMPING_TX_SOFTWARE |
339062306a36Sopenharmony_ci		SOF_TIMESTAMPING_RX_SOFTWARE |
339162306a36Sopenharmony_ci		SOF_TIMESTAMPING_SOFTWARE |
339262306a36Sopenharmony_ci		SOF_TIMESTAMPING_TX_HARDWARE |
339362306a36Sopenharmony_ci		SOF_TIMESTAMPING_RX_HARDWARE |
339462306a36Sopenharmony_ci		SOF_TIMESTAMPING_RAW_HARDWARE;
339562306a36Sopenharmony_ci	info->tx_types =
339662306a36Sopenharmony_ci		(1 << HWTSTAMP_TX_ONESTEP_SYNC) |
339762306a36Sopenharmony_ci		(1 << HWTSTAMP_TX_OFF) |
339862306a36Sopenharmony_ci		(1 << HWTSTAMP_TX_ON);
339962306a36Sopenharmony_ci	info->rx_filters =
340062306a36Sopenharmony_ci		(1 << HWTSTAMP_FILTER_NONE) |
340162306a36Sopenharmony_ci		(1 << HWTSTAMP_FILTER_ALL);
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	info->phc_index = bp->ptp_clock ? ptp_clock_index(bp->ptp_clock) : -1;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	return 0;
340662306a36Sopenharmony_ci}
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_cistatic struct macb_ptp_info gem_ptp_info = {
340962306a36Sopenharmony_ci	.ptp_init	 = gem_ptp_init,
341062306a36Sopenharmony_ci	.ptp_remove	 = gem_ptp_remove,
341162306a36Sopenharmony_ci	.get_ptp_max_adj = gem_get_ptp_max_adj,
341262306a36Sopenharmony_ci	.get_tsu_rate	 = gem_get_tsu_rate,
341362306a36Sopenharmony_ci	.get_ts_info	 = gem_get_ts_info,
341462306a36Sopenharmony_ci	.get_hwtst	 = gem_get_hwtst,
341562306a36Sopenharmony_ci	.set_hwtst	 = gem_set_hwtst,
341662306a36Sopenharmony_ci};
341762306a36Sopenharmony_ci#endif
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_cistatic int macb_get_ts_info(struct net_device *netdev,
342062306a36Sopenharmony_ci			    struct ethtool_ts_info *info)
342162306a36Sopenharmony_ci{
342262306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	if (bp->ptp_info)
342562306a36Sopenharmony_ci		return bp->ptp_info->get_ts_info(netdev, info);
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	return ethtool_op_get_ts_info(netdev, info);
342862306a36Sopenharmony_ci}
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_cistatic void gem_enable_flow_filters(struct macb *bp, bool enable)
343162306a36Sopenharmony_ci{
343262306a36Sopenharmony_ci	struct net_device *netdev = bp->dev;
343362306a36Sopenharmony_ci	struct ethtool_rx_fs_item *item;
343462306a36Sopenharmony_ci	u32 t2_scr;
343562306a36Sopenharmony_ci	int num_t2_scr;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	if (!(netdev->features & NETIF_F_NTUPLE))
343862306a36Sopenharmony_ci		return;
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	num_t2_scr = GEM_BFEXT(T2SCR, gem_readl(bp, DCFG8));
344162306a36Sopenharmony_ci
344262306a36Sopenharmony_ci	list_for_each_entry(item, &bp->rx_fs_list.list, list) {
344362306a36Sopenharmony_ci		struct ethtool_rx_flow_spec *fs = &item->fs;
344462306a36Sopenharmony_ci		struct ethtool_tcpip4_spec *tp4sp_m;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		if (fs->location >= num_t2_scr)
344762306a36Sopenharmony_ci			continue;
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci		t2_scr = gem_readl_n(bp, SCRT2, fs->location);
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ci		/* enable/disable screener regs for the flow entry */
345262306a36Sopenharmony_ci		t2_scr = GEM_BFINS(ETHTEN, enable, t2_scr);
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci		/* only enable fields with no masking */
345562306a36Sopenharmony_ci		tp4sp_m = &(fs->m_u.tcp_ip4_spec);
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci		if (enable && (tp4sp_m->ip4src == 0xFFFFFFFF))
345862306a36Sopenharmony_ci			t2_scr = GEM_BFINS(CMPAEN, 1, t2_scr);
345962306a36Sopenharmony_ci		else
346062306a36Sopenharmony_ci			t2_scr = GEM_BFINS(CMPAEN, 0, t2_scr);
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci		if (enable && (tp4sp_m->ip4dst == 0xFFFFFFFF))
346362306a36Sopenharmony_ci			t2_scr = GEM_BFINS(CMPBEN, 1, t2_scr);
346462306a36Sopenharmony_ci		else
346562306a36Sopenharmony_ci			t2_scr = GEM_BFINS(CMPBEN, 0, t2_scr);
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci		if (enable && ((tp4sp_m->psrc == 0xFFFF) || (tp4sp_m->pdst == 0xFFFF)))
346862306a36Sopenharmony_ci			t2_scr = GEM_BFINS(CMPCEN, 1, t2_scr);
346962306a36Sopenharmony_ci		else
347062306a36Sopenharmony_ci			t2_scr = GEM_BFINS(CMPCEN, 0, t2_scr);
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci		gem_writel_n(bp, SCRT2, fs->location, t2_scr);
347362306a36Sopenharmony_ci	}
347462306a36Sopenharmony_ci}
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_cistatic void gem_prog_cmp_regs(struct macb *bp, struct ethtool_rx_flow_spec *fs)
347762306a36Sopenharmony_ci{
347862306a36Sopenharmony_ci	struct ethtool_tcpip4_spec *tp4sp_v, *tp4sp_m;
347962306a36Sopenharmony_ci	uint16_t index = fs->location;
348062306a36Sopenharmony_ci	u32 w0, w1, t2_scr;
348162306a36Sopenharmony_ci	bool cmp_a = false;
348262306a36Sopenharmony_ci	bool cmp_b = false;
348362306a36Sopenharmony_ci	bool cmp_c = false;
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	if (!macb_is_gem(bp))
348662306a36Sopenharmony_ci		return;
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	tp4sp_v = &(fs->h_u.tcp_ip4_spec);
348962306a36Sopenharmony_ci	tp4sp_m = &(fs->m_u.tcp_ip4_spec);
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci	/* ignore field if any masking set */
349262306a36Sopenharmony_ci	if (tp4sp_m->ip4src == 0xFFFFFFFF) {
349362306a36Sopenharmony_ci		/* 1st compare reg - IP source address */
349462306a36Sopenharmony_ci		w0 = 0;
349562306a36Sopenharmony_ci		w1 = 0;
349662306a36Sopenharmony_ci		w0 = tp4sp_v->ip4src;
349762306a36Sopenharmony_ci		w1 = GEM_BFINS(T2DISMSK, 1, w1); /* 32-bit compare */
349862306a36Sopenharmony_ci		w1 = GEM_BFINS(T2CMPOFST, GEM_T2COMPOFST_ETYPE, w1);
349962306a36Sopenharmony_ci		w1 = GEM_BFINS(T2OFST, ETYPE_SRCIP_OFFSET, w1);
350062306a36Sopenharmony_ci		gem_writel_n(bp, T2CMPW0, T2CMP_OFST(GEM_IP4SRC_CMP(index)), w0);
350162306a36Sopenharmony_ci		gem_writel_n(bp, T2CMPW1, T2CMP_OFST(GEM_IP4SRC_CMP(index)), w1);
350262306a36Sopenharmony_ci		cmp_a = true;
350362306a36Sopenharmony_ci	}
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci	/* ignore field if any masking set */
350662306a36Sopenharmony_ci	if (tp4sp_m->ip4dst == 0xFFFFFFFF) {
350762306a36Sopenharmony_ci		/* 2nd compare reg - IP destination address */
350862306a36Sopenharmony_ci		w0 = 0;
350962306a36Sopenharmony_ci		w1 = 0;
351062306a36Sopenharmony_ci		w0 = tp4sp_v->ip4dst;
351162306a36Sopenharmony_ci		w1 = GEM_BFINS(T2DISMSK, 1, w1); /* 32-bit compare */
351262306a36Sopenharmony_ci		w1 = GEM_BFINS(T2CMPOFST, GEM_T2COMPOFST_ETYPE, w1);
351362306a36Sopenharmony_ci		w1 = GEM_BFINS(T2OFST, ETYPE_DSTIP_OFFSET, w1);
351462306a36Sopenharmony_ci		gem_writel_n(bp, T2CMPW0, T2CMP_OFST(GEM_IP4DST_CMP(index)), w0);
351562306a36Sopenharmony_ci		gem_writel_n(bp, T2CMPW1, T2CMP_OFST(GEM_IP4DST_CMP(index)), w1);
351662306a36Sopenharmony_ci		cmp_b = true;
351762306a36Sopenharmony_ci	}
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	/* ignore both port fields if masking set in both */
352062306a36Sopenharmony_ci	if ((tp4sp_m->psrc == 0xFFFF) || (tp4sp_m->pdst == 0xFFFF)) {
352162306a36Sopenharmony_ci		/* 3rd compare reg - source port, destination port */
352262306a36Sopenharmony_ci		w0 = 0;
352362306a36Sopenharmony_ci		w1 = 0;
352462306a36Sopenharmony_ci		w1 = GEM_BFINS(T2CMPOFST, GEM_T2COMPOFST_IPHDR, w1);
352562306a36Sopenharmony_ci		if (tp4sp_m->psrc == tp4sp_m->pdst) {
352662306a36Sopenharmony_ci			w0 = GEM_BFINS(T2MASK, tp4sp_v->psrc, w0);
352762306a36Sopenharmony_ci			w0 = GEM_BFINS(T2CMP, tp4sp_v->pdst, w0);
352862306a36Sopenharmony_ci			w1 = GEM_BFINS(T2DISMSK, 1, w1); /* 32-bit compare */
352962306a36Sopenharmony_ci			w1 = GEM_BFINS(T2OFST, IPHDR_SRCPORT_OFFSET, w1);
353062306a36Sopenharmony_ci		} else {
353162306a36Sopenharmony_ci			/* only one port definition */
353262306a36Sopenharmony_ci			w1 = GEM_BFINS(T2DISMSK, 0, w1); /* 16-bit compare */
353362306a36Sopenharmony_ci			w0 = GEM_BFINS(T2MASK, 0xFFFF, w0);
353462306a36Sopenharmony_ci			if (tp4sp_m->psrc == 0xFFFF) { /* src port */
353562306a36Sopenharmony_ci				w0 = GEM_BFINS(T2CMP, tp4sp_v->psrc, w0);
353662306a36Sopenharmony_ci				w1 = GEM_BFINS(T2OFST, IPHDR_SRCPORT_OFFSET, w1);
353762306a36Sopenharmony_ci			} else { /* dst port */
353862306a36Sopenharmony_ci				w0 = GEM_BFINS(T2CMP, tp4sp_v->pdst, w0);
353962306a36Sopenharmony_ci				w1 = GEM_BFINS(T2OFST, IPHDR_DSTPORT_OFFSET, w1);
354062306a36Sopenharmony_ci			}
354162306a36Sopenharmony_ci		}
354262306a36Sopenharmony_ci		gem_writel_n(bp, T2CMPW0, T2CMP_OFST(GEM_PORT_CMP(index)), w0);
354362306a36Sopenharmony_ci		gem_writel_n(bp, T2CMPW1, T2CMP_OFST(GEM_PORT_CMP(index)), w1);
354462306a36Sopenharmony_ci		cmp_c = true;
354562306a36Sopenharmony_ci	}
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	t2_scr = 0;
354862306a36Sopenharmony_ci	t2_scr = GEM_BFINS(QUEUE, (fs->ring_cookie) & 0xFF, t2_scr);
354962306a36Sopenharmony_ci	t2_scr = GEM_BFINS(ETHT2IDX, SCRT2_ETHT, t2_scr);
355062306a36Sopenharmony_ci	if (cmp_a)
355162306a36Sopenharmony_ci		t2_scr = GEM_BFINS(CMPA, GEM_IP4SRC_CMP(index), t2_scr);
355262306a36Sopenharmony_ci	if (cmp_b)
355362306a36Sopenharmony_ci		t2_scr = GEM_BFINS(CMPB, GEM_IP4DST_CMP(index), t2_scr);
355462306a36Sopenharmony_ci	if (cmp_c)
355562306a36Sopenharmony_ci		t2_scr = GEM_BFINS(CMPC, GEM_PORT_CMP(index), t2_scr);
355662306a36Sopenharmony_ci	gem_writel_n(bp, SCRT2, index, t2_scr);
355762306a36Sopenharmony_ci}
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_cistatic int gem_add_flow_filter(struct net_device *netdev,
356062306a36Sopenharmony_ci		struct ethtool_rxnfc *cmd)
356162306a36Sopenharmony_ci{
356262306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
356362306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fs = &cmd->fs;
356462306a36Sopenharmony_ci	struct ethtool_rx_fs_item *item, *newfs;
356562306a36Sopenharmony_ci	unsigned long flags;
356662306a36Sopenharmony_ci	int ret = -EINVAL;
356762306a36Sopenharmony_ci	bool added = false;
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	newfs = kmalloc(sizeof(*newfs), GFP_KERNEL);
357062306a36Sopenharmony_ci	if (newfs == NULL)
357162306a36Sopenharmony_ci		return -ENOMEM;
357262306a36Sopenharmony_ci	memcpy(&newfs->fs, fs, sizeof(newfs->fs));
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci	netdev_dbg(netdev,
357562306a36Sopenharmony_ci			"Adding flow filter entry,type=%u,queue=%u,loc=%u,src=%08X,dst=%08X,ps=%u,pd=%u\n",
357662306a36Sopenharmony_ci			fs->flow_type, (int)fs->ring_cookie, fs->location,
357762306a36Sopenharmony_ci			htonl(fs->h_u.tcp_ip4_spec.ip4src),
357862306a36Sopenharmony_ci			htonl(fs->h_u.tcp_ip4_spec.ip4dst),
357962306a36Sopenharmony_ci			be16_to_cpu(fs->h_u.tcp_ip4_spec.psrc),
358062306a36Sopenharmony_ci			be16_to_cpu(fs->h_u.tcp_ip4_spec.pdst));
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	spin_lock_irqsave(&bp->rx_fs_lock, flags);
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci	/* find correct place to add in list */
358562306a36Sopenharmony_ci	list_for_each_entry(item, &bp->rx_fs_list.list, list) {
358662306a36Sopenharmony_ci		if (item->fs.location > newfs->fs.location) {
358762306a36Sopenharmony_ci			list_add_tail(&newfs->list, &item->list);
358862306a36Sopenharmony_ci			added = true;
358962306a36Sopenharmony_ci			break;
359062306a36Sopenharmony_ci		} else if (item->fs.location == fs->location) {
359162306a36Sopenharmony_ci			netdev_err(netdev, "Rule not added: location %d not free!\n",
359262306a36Sopenharmony_ci					fs->location);
359362306a36Sopenharmony_ci			ret = -EBUSY;
359462306a36Sopenharmony_ci			goto err;
359562306a36Sopenharmony_ci		}
359662306a36Sopenharmony_ci	}
359762306a36Sopenharmony_ci	if (!added)
359862306a36Sopenharmony_ci		list_add_tail(&newfs->list, &bp->rx_fs_list.list);
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci	gem_prog_cmp_regs(bp, fs);
360162306a36Sopenharmony_ci	bp->rx_fs_list.count++;
360262306a36Sopenharmony_ci	/* enable filtering if NTUPLE on */
360362306a36Sopenharmony_ci	gem_enable_flow_filters(bp, 1);
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->rx_fs_lock, flags);
360662306a36Sopenharmony_ci	return 0;
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_cierr:
360962306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->rx_fs_lock, flags);
361062306a36Sopenharmony_ci	kfree(newfs);
361162306a36Sopenharmony_ci	return ret;
361262306a36Sopenharmony_ci}
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_cistatic int gem_del_flow_filter(struct net_device *netdev,
361562306a36Sopenharmony_ci		struct ethtool_rxnfc *cmd)
361662306a36Sopenharmony_ci{
361762306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
361862306a36Sopenharmony_ci	struct ethtool_rx_fs_item *item;
361962306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fs;
362062306a36Sopenharmony_ci	unsigned long flags;
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_ci	spin_lock_irqsave(&bp->rx_fs_lock, flags);
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	list_for_each_entry(item, &bp->rx_fs_list.list, list) {
362562306a36Sopenharmony_ci		if (item->fs.location == cmd->fs.location) {
362662306a36Sopenharmony_ci			/* disable screener regs for the flow entry */
362762306a36Sopenharmony_ci			fs = &(item->fs);
362862306a36Sopenharmony_ci			netdev_dbg(netdev,
362962306a36Sopenharmony_ci					"Deleting flow filter entry,type=%u,queue=%u,loc=%u,src=%08X,dst=%08X,ps=%u,pd=%u\n",
363062306a36Sopenharmony_ci					fs->flow_type, (int)fs->ring_cookie, fs->location,
363162306a36Sopenharmony_ci					htonl(fs->h_u.tcp_ip4_spec.ip4src),
363262306a36Sopenharmony_ci					htonl(fs->h_u.tcp_ip4_spec.ip4dst),
363362306a36Sopenharmony_ci					be16_to_cpu(fs->h_u.tcp_ip4_spec.psrc),
363462306a36Sopenharmony_ci					be16_to_cpu(fs->h_u.tcp_ip4_spec.pdst));
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci			gem_writel_n(bp, SCRT2, fs->location, 0);
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci			list_del(&item->list);
363962306a36Sopenharmony_ci			bp->rx_fs_list.count--;
364062306a36Sopenharmony_ci			spin_unlock_irqrestore(&bp->rx_fs_lock, flags);
364162306a36Sopenharmony_ci			kfree(item);
364262306a36Sopenharmony_ci			return 0;
364362306a36Sopenharmony_ci		}
364462306a36Sopenharmony_ci	}
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->rx_fs_lock, flags);
364762306a36Sopenharmony_ci	return -EINVAL;
364862306a36Sopenharmony_ci}
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_cistatic int gem_get_flow_entry(struct net_device *netdev,
365162306a36Sopenharmony_ci		struct ethtool_rxnfc *cmd)
365262306a36Sopenharmony_ci{
365362306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
365462306a36Sopenharmony_ci	struct ethtool_rx_fs_item *item;
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	list_for_each_entry(item, &bp->rx_fs_list.list, list) {
365762306a36Sopenharmony_ci		if (item->fs.location == cmd->fs.location) {
365862306a36Sopenharmony_ci			memcpy(&cmd->fs, &item->fs, sizeof(cmd->fs));
365962306a36Sopenharmony_ci			return 0;
366062306a36Sopenharmony_ci		}
366162306a36Sopenharmony_ci	}
366262306a36Sopenharmony_ci	return -EINVAL;
366362306a36Sopenharmony_ci}
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_cistatic int gem_get_all_flow_entries(struct net_device *netdev,
366662306a36Sopenharmony_ci		struct ethtool_rxnfc *cmd, u32 *rule_locs)
366762306a36Sopenharmony_ci{
366862306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
366962306a36Sopenharmony_ci	struct ethtool_rx_fs_item *item;
367062306a36Sopenharmony_ci	uint32_t cnt = 0;
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	list_for_each_entry(item, &bp->rx_fs_list.list, list) {
367362306a36Sopenharmony_ci		if (cnt == cmd->rule_cnt)
367462306a36Sopenharmony_ci			return -EMSGSIZE;
367562306a36Sopenharmony_ci		rule_locs[cnt] = item->fs.location;
367662306a36Sopenharmony_ci		cnt++;
367762306a36Sopenharmony_ci	}
367862306a36Sopenharmony_ci	cmd->data = bp->max_tuples;
367962306a36Sopenharmony_ci	cmd->rule_cnt = cnt;
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	return 0;
368262306a36Sopenharmony_ci}
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_cistatic int gem_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
368562306a36Sopenharmony_ci		u32 *rule_locs)
368662306a36Sopenharmony_ci{
368762306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
368862306a36Sopenharmony_ci	int ret = 0;
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	switch (cmd->cmd) {
369162306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
369262306a36Sopenharmony_ci		cmd->data = bp->num_queues;
369362306a36Sopenharmony_ci		break;
369462306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
369562306a36Sopenharmony_ci		cmd->rule_cnt = bp->rx_fs_list.count;
369662306a36Sopenharmony_ci		break;
369762306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
369862306a36Sopenharmony_ci		ret = gem_get_flow_entry(netdev, cmd);
369962306a36Sopenharmony_ci		break;
370062306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
370162306a36Sopenharmony_ci		ret = gem_get_all_flow_entries(netdev, cmd, rule_locs);
370262306a36Sopenharmony_ci		break;
370362306a36Sopenharmony_ci	default:
370462306a36Sopenharmony_ci		netdev_err(netdev,
370562306a36Sopenharmony_ci			  "Command parameter %d is not supported\n", cmd->cmd);
370662306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
370762306a36Sopenharmony_ci	}
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	return ret;
371062306a36Sopenharmony_ci}
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_cistatic int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
371362306a36Sopenharmony_ci{
371462306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
371562306a36Sopenharmony_ci	int ret;
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci	switch (cmd->cmd) {
371862306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
371962306a36Sopenharmony_ci		if ((cmd->fs.location >= bp->max_tuples)
372062306a36Sopenharmony_ci				|| (cmd->fs.ring_cookie >= bp->num_queues)) {
372162306a36Sopenharmony_ci			ret = -EINVAL;
372262306a36Sopenharmony_ci			break;
372362306a36Sopenharmony_ci		}
372462306a36Sopenharmony_ci		ret = gem_add_flow_filter(netdev, cmd);
372562306a36Sopenharmony_ci		break;
372662306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
372762306a36Sopenharmony_ci		ret = gem_del_flow_filter(netdev, cmd);
372862306a36Sopenharmony_ci		break;
372962306a36Sopenharmony_ci	default:
373062306a36Sopenharmony_ci		netdev_err(netdev,
373162306a36Sopenharmony_ci			  "Command parameter %d is not supported\n", cmd->cmd);
373262306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
373362306a36Sopenharmony_ci	}
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	return ret;
373662306a36Sopenharmony_ci}
373762306a36Sopenharmony_ci
373862306a36Sopenharmony_cistatic const struct ethtool_ops macb_ethtool_ops = {
373962306a36Sopenharmony_ci	.get_regs_len		= macb_get_regs_len,
374062306a36Sopenharmony_ci	.get_regs		= macb_get_regs,
374162306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
374262306a36Sopenharmony_ci	.get_ts_info		= ethtool_op_get_ts_info,
374362306a36Sopenharmony_ci	.get_wol		= macb_get_wol,
374462306a36Sopenharmony_ci	.set_wol		= macb_set_wol,
374562306a36Sopenharmony_ci	.get_link_ksettings     = macb_get_link_ksettings,
374662306a36Sopenharmony_ci	.set_link_ksettings     = macb_set_link_ksettings,
374762306a36Sopenharmony_ci	.get_ringparam		= macb_get_ringparam,
374862306a36Sopenharmony_ci	.set_ringparam		= macb_set_ringparam,
374962306a36Sopenharmony_ci};
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_cistatic const struct ethtool_ops gem_ethtool_ops = {
375262306a36Sopenharmony_ci	.get_regs_len		= macb_get_regs_len,
375362306a36Sopenharmony_ci	.get_regs		= macb_get_regs,
375462306a36Sopenharmony_ci	.get_wol		= macb_get_wol,
375562306a36Sopenharmony_ci	.set_wol		= macb_set_wol,
375662306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
375762306a36Sopenharmony_ci	.get_ts_info		= macb_get_ts_info,
375862306a36Sopenharmony_ci	.get_ethtool_stats	= gem_get_ethtool_stats,
375962306a36Sopenharmony_ci	.get_strings		= gem_get_ethtool_strings,
376062306a36Sopenharmony_ci	.get_sset_count		= gem_get_sset_count,
376162306a36Sopenharmony_ci	.get_link_ksettings     = macb_get_link_ksettings,
376262306a36Sopenharmony_ci	.set_link_ksettings     = macb_set_link_ksettings,
376362306a36Sopenharmony_ci	.get_ringparam		= macb_get_ringparam,
376462306a36Sopenharmony_ci	.set_ringparam		= macb_set_ringparam,
376562306a36Sopenharmony_ci	.get_rxnfc			= gem_get_rxnfc,
376662306a36Sopenharmony_ci	.set_rxnfc			= gem_set_rxnfc,
376762306a36Sopenharmony_ci};
376862306a36Sopenharmony_ci
376962306a36Sopenharmony_cistatic int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
377062306a36Sopenharmony_ci{
377162306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ci	if (!netif_running(dev))
377462306a36Sopenharmony_ci		return -EINVAL;
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	if (bp->ptp_info) {
377762306a36Sopenharmony_ci		switch (cmd) {
377862306a36Sopenharmony_ci		case SIOCSHWTSTAMP:
377962306a36Sopenharmony_ci			return bp->ptp_info->set_hwtst(dev, rq, cmd);
378062306a36Sopenharmony_ci		case SIOCGHWTSTAMP:
378162306a36Sopenharmony_ci			return bp->ptp_info->get_hwtst(dev, rq);
378262306a36Sopenharmony_ci		}
378362306a36Sopenharmony_ci	}
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci	return phylink_mii_ioctl(bp->phylink, rq, cmd);
378662306a36Sopenharmony_ci}
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_cistatic inline void macb_set_txcsum_feature(struct macb *bp,
378962306a36Sopenharmony_ci					   netdev_features_t features)
379062306a36Sopenharmony_ci{
379162306a36Sopenharmony_ci	u32 val;
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	if (!macb_is_gem(bp))
379462306a36Sopenharmony_ci		return;
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci	val = gem_readl(bp, DMACFG);
379762306a36Sopenharmony_ci	if (features & NETIF_F_HW_CSUM)
379862306a36Sopenharmony_ci		val |= GEM_BIT(TXCOEN);
379962306a36Sopenharmony_ci	else
380062306a36Sopenharmony_ci		val &= ~GEM_BIT(TXCOEN);
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci	gem_writel(bp, DMACFG, val);
380362306a36Sopenharmony_ci}
380462306a36Sopenharmony_ci
380562306a36Sopenharmony_cistatic inline void macb_set_rxcsum_feature(struct macb *bp,
380662306a36Sopenharmony_ci					   netdev_features_t features)
380762306a36Sopenharmony_ci{
380862306a36Sopenharmony_ci	struct net_device *netdev = bp->dev;
380962306a36Sopenharmony_ci	u32 val;
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci	if (!macb_is_gem(bp))
381262306a36Sopenharmony_ci		return;
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_ci	val = gem_readl(bp, NCFGR);
381562306a36Sopenharmony_ci	if ((features & NETIF_F_RXCSUM) && !(netdev->flags & IFF_PROMISC))
381662306a36Sopenharmony_ci		val |= GEM_BIT(RXCOEN);
381762306a36Sopenharmony_ci	else
381862306a36Sopenharmony_ci		val &= ~GEM_BIT(RXCOEN);
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci	gem_writel(bp, NCFGR, val);
382162306a36Sopenharmony_ci}
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_cistatic inline void macb_set_rxflow_feature(struct macb *bp,
382462306a36Sopenharmony_ci					   netdev_features_t features)
382562306a36Sopenharmony_ci{
382662306a36Sopenharmony_ci	if (!macb_is_gem(bp))
382762306a36Sopenharmony_ci		return;
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci	gem_enable_flow_filters(bp, !!(features & NETIF_F_NTUPLE));
383062306a36Sopenharmony_ci}
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_cistatic int macb_set_features(struct net_device *netdev,
383362306a36Sopenharmony_ci			     netdev_features_t features)
383462306a36Sopenharmony_ci{
383562306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
383662306a36Sopenharmony_ci	netdev_features_t changed = features ^ netdev->features;
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci	/* TX checksum offload */
383962306a36Sopenharmony_ci	if (changed & NETIF_F_HW_CSUM)
384062306a36Sopenharmony_ci		macb_set_txcsum_feature(bp, features);
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	/* RX checksum offload */
384362306a36Sopenharmony_ci	if (changed & NETIF_F_RXCSUM)
384462306a36Sopenharmony_ci		macb_set_rxcsum_feature(bp, features);
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	/* RX Flow Filters */
384762306a36Sopenharmony_ci	if (changed & NETIF_F_NTUPLE)
384862306a36Sopenharmony_ci		macb_set_rxflow_feature(bp, features);
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci	return 0;
385162306a36Sopenharmony_ci}
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_cistatic void macb_restore_features(struct macb *bp)
385462306a36Sopenharmony_ci{
385562306a36Sopenharmony_ci	struct net_device *netdev = bp->dev;
385662306a36Sopenharmony_ci	netdev_features_t features = netdev->features;
385762306a36Sopenharmony_ci	struct ethtool_rx_fs_item *item;
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	/* TX checksum offload */
386062306a36Sopenharmony_ci	macb_set_txcsum_feature(bp, features);
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci	/* RX checksum offload */
386362306a36Sopenharmony_ci	macb_set_rxcsum_feature(bp, features);
386462306a36Sopenharmony_ci
386562306a36Sopenharmony_ci	/* RX Flow Filters */
386662306a36Sopenharmony_ci	list_for_each_entry(item, &bp->rx_fs_list.list, list)
386762306a36Sopenharmony_ci		gem_prog_cmp_regs(bp, &item->fs);
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci	macb_set_rxflow_feature(bp, features);
387062306a36Sopenharmony_ci}
387162306a36Sopenharmony_ci
387262306a36Sopenharmony_cistatic const struct net_device_ops macb_netdev_ops = {
387362306a36Sopenharmony_ci	.ndo_open		= macb_open,
387462306a36Sopenharmony_ci	.ndo_stop		= macb_close,
387562306a36Sopenharmony_ci	.ndo_start_xmit		= macb_start_xmit,
387662306a36Sopenharmony_ci	.ndo_set_rx_mode	= macb_set_rx_mode,
387762306a36Sopenharmony_ci	.ndo_get_stats		= macb_get_stats,
387862306a36Sopenharmony_ci	.ndo_eth_ioctl		= macb_ioctl,
387962306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
388062306a36Sopenharmony_ci	.ndo_change_mtu		= macb_change_mtu,
388162306a36Sopenharmony_ci	.ndo_set_mac_address	= macb_set_mac_addr,
388262306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
388362306a36Sopenharmony_ci	.ndo_poll_controller	= macb_poll_controller,
388462306a36Sopenharmony_ci#endif
388562306a36Sopenharmony_ci	.ndo_set_features	= macb_set_features,
388662306a36Sopenharmony_ci	.ndo_features_check	= macb_features_check,
388762306a36Sopenharmony_ci};
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci/* Configure peripheral capabilities according to device tree
389062306a36Sopenharmony_ci * and integration options used
389162306a36Sopenharmony_ci */
389262306a36Sopenharmony_cistatic void macb_configure_caps(struct macb *bp,
389362306a36Sopenharmony_ci				const struct macb_config *dt_conf)
389462306a36Sopenharmony_ci{
389562306a36Sopenharmony_ci	u32 dcfg;
389662306a36Sopenharmony_ci
389762306a36Sopenharmony_ci	if (dt_conf)
389862306a36Sopenharmony_ci		bp->caps = dt_conf->caps;
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci	if (hw_is_gem(bp->regs, bp->native_io)) {
390162306a36Sopenharmony_ci		bp->caps |= MACB_CAPS_MACB_IS_GEM;
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci		dcfg = gem_readl(bp, DCFG1);
390462306a36Sopenharmony_ci		if (GEM_BFEXT(IRQCOR, dcfg) == 0)
390562306a36Sopenharmony_ci			bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
390662306a36Sopenharmony_ci		if (GEM_BFEXT(NO_PCS, dcfg) == 0)
390762306a36Sopenharmony_ci			bp->caps |= MACB_CAPS_PCS;
390862306a36Sopenharmony_ci		dcfg = gem_readl(bp, DCFG12);
390962306a36Sopenharmony_ci		if (GEM_BFEXT(HIGH_SPEED, dcfg) == 1)
391062306a36Sopenharmony_ci			bp->caps |= MACB_CAPS_HIGH_SPEED;
391162306a36Sopenharmony_ci		dcfg = gem_readl(bp, DCFG2);
391262306a36Sopenharmony_ci		if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0)
391362306a36Sopenharmony_ci			bp->caps |= MACB_CAPS_FIFO_MODE;
391462306a36Sopenharmony_ci		if (gem_has_ptp(bp)) {
391562306a36Sopenharmony_ci			if (!GEM_BFEXT(TSU, gem_readl(bp, DCFG5)))
391662306a36Sopenharmony_ci				dev_err(&bp->pdev->dev,
391762306a36Sopenharmony_ci					"GEM doesn't support hardware ptp.\n");
391862306a36Sopenharmony_ci			else {
391962306a36Sopenharmony_ci#ifdef CONFIG_MACB_USE_HWSTAMP
392062306a36Sopenharmony_ci				bp->hw_dma_cap |= HW_DMA_CAP_PTP;
392162306a36Sopenharmony_ci				bp->ptp_info = &gem_ptp_info;
392262306a36Sopenharmony_ci#endif
392362306a36Sopenharmony_ci			}
392462306a36Sopenharmony_ci		}
392562306a36Sopenharmony_ci	}
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci	dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps);
392862306a36Sopenharmony_ci}
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_cistatic void macb_probe_queues(void __iomem *mem,
393162306a36Sopenharmony_ci			      bool native_io,
393262306a36Sopenharmony_ci			      unsigned int *queue_mask,
393362306a36Sopenharmony_ci			      unsigned int *num_queues)
393462306a36Sopenharmony_ci{
393562306a36Sopenharmony_ci	*queue_mask = 0x1;
393662306a36Sopenharmony_ci	*num_queues = 1;
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci	/* is it macb or gem ?
393962306a36Sopenharmony_ci	 *
394062306a36Sopenharmony_ci	 * We need to read directly from the hardware here because
394162306a36Sopenharmony_ci	 * we are early in the probe process and don't have the
394262306a36Sopenharmony_ci	 * MACB_CAPS_MACB_IS_GEM flag positioned
394362306a36Sopenharmony_ci	 */
394462306a36Sopenharmony_ci	if (!hw_is_gem(mem, native_io))
394562306a36Sopenharmony_ci		return;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	/* bit 0 is never set but queue 0 always exists */
394862306a36Sopenharmony_ci	*queue_mask |= readl_relaxed(mem + GEM_DCFG6) & 0xff;
394962306a36Sopenharmony_ci	*num_queues = hweight32(*queue_mask);
395062306a36Sopenharmony_ci}
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_cistatic void macb_clks_disable(struct clk *pclk, struct clk *hclk, struct clk *tx_clk,
395362306a36Sopenharmony_ci			      struct clk *rx_clk, struct clk *tsu_clk)
395462306a36Sopenharmony_ci{
395562306a36Sopenharmony_ci	struct clk_bulk_data clks[] = {
395662306a36Sopenharmony_ci		{ .clk = tsu_clk, },
395762306a36Sopenharmony_ci		{ .clk = rx_clk, },
395862306a36Sopenharmony_ci		{ .clk = pclk, },
395962306a36Sopenharmony_ci		{ .clk = hclk, },
396062306a36Sopenharmony_ci		{ .clk = tx_clk },
396162306a36Sopenharmony_ci	};
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ci	clk_bulk_disable_unprepare(ARRAY_SIZE(clks), clks);
396462306a36Sopenharmony_ci}
396562306a36Sopenharmony_ci
396662306a36Sopenharmony_cistatic int macb_clk_init(struct platform_device *pdev, struct clk **pclk,
396762306a36Sopenharmony_ci			 struct clk **hclk, struct clk **tx_clk,
396862306a36Sopenharmony_ci			 struct clk **rx_clk, struct clk **tsu_clk)
396962306a36Sopenharmony_ci{
397062306a36Sopenharmony_ci	struct macb_platform_data *pdata;
397162306a36Sopenharmony_ci	int err;
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci	pdata = dev_get_platdata(&pdev->dev);
397462306a36Sopenharmony_ci	if (pdata) {
397562306a36Sopenharmony_ci		*pclk = pdata->pclk;
397662306a36Sopenharmony_ci		*hclk = pdata->hclk;
397762306a36Sopenharmony_ci	} else {
397862306a36Sopenharmony_ci		*pclk = devm_clk_get(&pdev->dev, "pclk");
397962306a36Sopenharmony_ci		*hclk = devm_clk_get(&pdev->dev, "hclk");
398062306a36Sopenharmony_ci	}
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(*pclk))
398362306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev,
398462306a36Sopenharmony_ci				     IS_ERR(*pclk) ? PTR_ERR(*pclk) : -ENODEV,
398562306a36Sopenharmony_ci				     "failed to get pclk\n");
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(*hclk))
398862306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev,
398962306a36Sopenharmony_ci				     IS_ERR(*hclk) ? PTR_ERR(*hclk) : -ENODEV,
399062306a36Sopenharmony_ci				     "failed to get hclk\n");
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	*tx_clk = devm_clk_get_optional(&pdev->dev, "tx_clk");
399362306a36Sopenharmony_ci	if (IS_ERR(*tx_clk))
399462306a36Sopenharmony_ci		return PTR_ERR(*tx_clk);
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci	*rx_clk = devm_clk_get_optional(&pdev->dev, "rx_clk");
399762306a36Sopenharmony_ci	if (IS_ERR(*rx_clk))
399862306a36Sopenharmony_ci		return PTR_ERR(*rx_clk);
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ci	*tsu_clk = devm_clk_get_optional(&pdev->dev, "tsu_clk");
400162306a36Sopenharmony_ci	if (IS_ERR(*tsu_clk))
400262306a36Sopenharmony_ci		return PTR_ERR(*tsu_clk);
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci	err = clk_prepare_enable(*pclk);
400562306a36Sopenharmony_ci	if (err) {
400662306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable pclk (%d)\n", err);
400762306a36Sopenharmony_ci		return err;
400862306a36Sopenharmony_ci	}
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ci	err = clk_prepare_enable(*hclk);
401162306a36Sopenharmony_ci	if (err) {
401262306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable hclk (%d)\n", err);
401362306a36Sopenharmony_ci		goto err_disable_pclk;
401462306a36Sopenharmony_ci	}
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci	err = clk_prepare_enable(*tx_clk);
401762306a36Sopenharmony_ci	if (err) {
401862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable tx_clk (%d)\n", err);
401962306a36Sopenharmony_ci		goto err_disable_hclk;
402062306a36Sopenharmony_ci	}
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci	err = clk_prepare_enable(*rx_clk);
402362306a36Sopenharmony_ci	if (err) {
402462306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable rx_clk (%d)\n", err);
402562306a36Sopenharmony_ci		goto err_disable_txclk;
402662306a36Sopenharmony_ci	}
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	err = clk_prepare_enable(*tsu_clk);
402962306a36Sopenharmony_ci	if (err) {
403062306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable tsu_clk (%d)\n", err);
403162306a36Sopenharmony_ci		goto err_disable_rxclk;
403262306a36Sopenharmony_ci	}
403362306a36Sopenharmony_ci
403462306a36Sopenharmony_ci	return 0;
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_cierr_disable_rxclk:
403762306a36Sopenharmony_ci	clk_disable_unprepare(*rx_clk);
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_cierr_disable_txclk:
404062306a36Sopenharmony_ci	clk_disable_unprepare(*tx_clk);
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_cierr_disable_hclk:
404362306a36Sopenharmony_ci	clk_disable_unprepare(*hclk);
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_cierr_disable_pclk:
404662306a36Sopenharmony_ci	clk_disable_unprepare(*pclk);
404762306a36Sopenharmony_ci
404862306a36Sopenharmony_ci	return err;
404962306a36Sopenharmony_ci}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_cistatic int macb_init(struct platform_device *pdev)
405262306a36Sopenharmony_ci{
405362306a36Sopenharmony_ci	struct net_device *dev = platform_get_drvdata(pdev);
405462306a36Sopenharmony_ci	unsigned int hw_q, q;
405562306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
405662306a36Sopenharmony_ci	struct macb_queue *queue;
405762306a36Sopenharmony_ci	int err;
405862306a36Sopenharmony_ci	u32 val, reg;
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci	bp->tx_ring_size = DEFAULT_TX_RING_SIZE;
406162306a36Sopenharmony_ci	bp->rx_ring_size = DEFAULT_RX_RING_SIZE;
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	/* set the queue register mapping once for all: queue0 has a special
406462306a36Sopenharmony_ci	 * register mapping but we don't want to test the queue index then
406562306a36Sopenharmony_ci	 * compute the corresponding register offset at run time.
406662306a36Sopenharmony_ci	 */
406762306a36Sopenharmony_ci	for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) {
406862306a36Sopenharmony_ci		if (!(bp->queue_mask & (1 << hw_q)))
406962306a36Sopenharmony_ci			continue;
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_ci		queue = &bp->queues[q];
407262306a36Sopenharmony_ci		queue->bp = bp;
407362306a36Sopenharmony_ci		spin_lock_init(&queue->tx_ptr_lock);
407462306a36Sopenharmony_ci		netif_napi_add(dev, &queue->napi_rx, macb_rx_poll);
407562306a36Sopenharmony_ci		netif_napi_add(dev, &queue->napi_tx, macb_tx_poll);
407662306a36Sopenharmony_ci		if (hw_q) {
407762306a36Sopenharmony_ci			queue->ISR  = GEM_ISR(hw_q - 1);
407862306a36Sopenharmony_ci			queue->IER  = GEM_IER(hw_q - 1);
407962306a36Sopenharmony_ci			queue->IDR  = GEM_IDR(hw_q - 1);
408062306a36Sopenharmony_ci			queue->IMR  = GEM_IMR(hw_q - 1);
408162306a36Sopenharmony_ci			queue->TBQP = GEM_TBQP(hw_q - 1);
408262306a36Sopenharmony_ci			queue->RBQP = GEM_RBQP(hw_q - 1);
408362306a36Sopenharmony_ci			queue->RBQS = GEM_RBQS(hw_q - 1);
408462306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
408562306a36Sopenharmony_ci			if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
408662306a36Sopenharmony_ci				queue->TBQPH = GEM_TBQPH(hw_q - 1);
408762306a36Sopenharmony_ci				queue->RBQPH = GEM_RBQPH(hw_q - 1);
408862306a36Sopenharmony_ci			}
408962306a36Sopenharmony_ci#endif
409062306a36Sopenharmony_ci		} else {
409162306a36Sopenharmony_ci			/* queue0 uses legacy registers */
409262306a36Sopenharmony_ci			queue->ISR  = MACB_ISR;
409362306a36Sopenharmony_ci			queue->IER  = MACB_IER;
409462306a36Sopenharmony_ci			queue->IDR  = MACB_IDR;
409562306a36Sopenharmony_ci			queue->IMR  = MACB_IMR;
409662306a36Sopenharmony_ci			queue->TBQP = MACB_TBQP;
409762306a36Sopenharmony_ci			queue->RBQP = MACB_RBQP;
409862306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
409962306a36Sopenharmony_ci			if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
410062306a36Sopenharmony_ci				queue->TBQPH = MACB_TBQPH;
410162306a36Sopenharmony_ci				queue->RBQPH = MACB_RBQPH;
410262306a36Sopenharmony_ci			}
410362306a36Sopenharmony_ci#endif
410462306a36Sopenharmony_ci		}
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci		/* get irq: here we use the linux queue index, not the hardware
410762306a36Sopenharmony_ci		 * queue index. the queue irq definitions in the device tree
410862306a36Sopenharmony_ci		 * must remove the optional gaps that could exist in the
410962306a36Sopenharmony_ci		 * hardware queue mask.
411062306a36Sopenharmony_ci		 */
411162306a36Sopenharmony_ci		queue->irq = platform_get_irq(pdev, q);
411262306a36Sopenharmony_ci		err = devm_request_irq(&pdev->dev, queue->irq, macb_interrupt,
411362306a36Sopenharmony_ci				       IRQF_SHARED, dev->name, queue);
411462306a36Sopenharmony_ci		if (err) {
411562306a36Sopenharmony_ci			dev_err(&pdev->dev,
411662306a36Sopenharmony_ci				"Unable to request IRQ %d (error %d)\n",
411762306a36Sopenharmony_ci				queue->irq, err);
411862306a36Sopenharmony_ci			return err;
411962306a36Sopenharmony_ci		}
412062306a36Sopenharmony_ci
412162306a36Sopenharmony_ci		INIT_WORK(&queue->tx_error_task, macb_tx_error_task);
412262306a36Sopenharmony_ci		q++;
412362306a36Sopenharmony_ci	}
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	dev->netdev_ops = &macb_netdev_ops;
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	/* setup appropriated routines according to adapter type */
412862306a36Sopenharmony_ci	if (macb_is_gem(bp)) {
412962306a36Sopenharmony_ci		bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers;
413062306a36Sopenharmony_ci		bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers;
413162306a36Sopenharmony_ci		bp->macbgem_ops.mog_init_rings = gem_init_rings;
413262306a36Sopenharmony_ci		bp->macbgem_ops.mog_rx = gem_rx;
413362306a36Sopenharmony_ci		dev->ethtool_ops = &gem_ethtool_ops;
413462306a36Sopenharmony_ci	} else {
413562306a36Sopenharmony_ci		bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers;
413662306a36Sopenharmony_ci		bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers;
413762306a36Sopenharmony_ci		bp->macbgem_ops.mog_init_rings = macb_init_rings;
413862306a36Sopenharmony_ci		bp->macbgem_ops.mog_rx = macb_rx;
413962306a36Sopenharmony_ci		dev->ethtool_ops = &macb_ethtool_ops;
414062306a36Sopenharmony_ci	}
414162306a36Sopenharmony_ci
414262306a36Sopenharmony_ci	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_ci	/* Set features */
414562306a36Sopenharmony_ci	dev->hw_features = NETIF_F_SG;
414662306a36Sopenharmony_ci
414762306a36Sopenharmony_ci	/* Check LSO capability */
414862306a36Sopenharmony_ci	if (GEM_BFEXT(PBUF_LSO, gem_readl(bp, DCFG6)))
414962306a36Sopenharmony_ci		dev->hw_features |= MACB_NETIF_LSO;
415062306a36Sopenharmony_ci
415162306a36Sopenharmony_ci	/* Checksum offload is only available on gem with packet buffer */
415262306a36Sopenharmony_ci	if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE))
415362306a36Sopenharmony_ci		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
415462306a36Sopenharmony_ci	if (bp->caps & MACB_CAPS_SG_DISABLED)
415562306a36Sopenharmony_ci		dev->hw_features &= ~NETIF_F_SG;
415662306a36Sopenharmony_ci	dev->features = dev->hw_features;
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci	/* Check RX Flow Filters support.
415962306a36Sopenharmony_ci	 * Max Rx flows set by availability of screeners & compare regs:
416062306a36Sopenharmony_ci	 * each 4-tuple define requires 1 T2 screener reg + 3 compare regs
416162306a36Sopenharmony_ci	 */
416262306a36Sopenharmony_ci	reg = gem_readl(bp, DCFG8);
416362306a36Sopenharmony_ci	bp->max_tuples = min((GEM_BFEXT(SCR2CMP, reg) / 3),
416462306a36Sopenharmony_ci			GEM_BFEXT(T2SCR, reg));
416562306a36Sopenharmony_ci	INIT_LIST_HEAD(&bp->rx_fs_list.list);
416662306a36Sopenharmony_ci	if (bp->max_tuples > 0) {
416762306a36Sopenharmony_ci		/* also needs one ethtype match to check IPv4 */
416862306a36Sopenharmony_ci		if (GEM_BFEXT(SCR2ETH, reg) > 0) {
416962306a36Sopenharmony_ci			/* program this reg now */
417062306a36Sopenharmony_ci			reg = 0;
417162306a36Sopenharmony_ci			reg = GEM_BFINS(ETHTCMP, (uint16_t)ETH_P_IP, reg);
417262306a36Sopenharmony_ci			gem_writel_n(bp, ETHT, SCRT2_ETHT, reg);
417362306a36Sopenharmony_ci			/* Filtering is supported in hw but don't enable it in kernel now */
417462306a36Sopenharmony_ci			dev->hw_features |= NETIF_F_NTUPLE;
417562306a36Sopenharmony_ci			/* init Rx flow definitions */
417662306a36Sopenharmony_ci			bp->rx_fs_list.count = 0;
417762306a36Sopenharmony_ci			spin_lock_init(&bp->rx_fs_lock);
417862306a36Sopenharmony_ci		} else
417962306a36Sopenharmony_ci			bp->max_tuples = 0;
418062306a36Sopenharmony_ci	}
418162306a36Sopenharmony_ci
418262306a36Sopenharmony_ci	if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) {
418362306a36Sopenharmony_ci		val = 0;
418462306a36Sopenharmony_ci		if (phy_interface_mode_is_rgmii(bp->phy_interface))
418562306a36Sopenharmony_ci			val = bp->usrio->rgmii;
418662306a36Sopenharmony_ci		else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII &&
418762306a36Sopenharmony_ci			 (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII))
418862306a36Sopenharmony_ci			val = bp->usrio->rmii;
418962306a36Sopenharmony_ci		else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII))
419062306a36Sopenharmony_ci			val = bp->usrio->mii;
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_ci		if (bp->caps & MACB_CAPS_USRIO_HAS_CLKEN)
419362306a36Sopenharmony_ci			val |= bp->usrio->refclk;
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci		macb_or_gem_writel(bp, USRIO, val);
419662306a36Sopenharmony_ci	}
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci	/* Set MII management clock divider */
419962306a36Sopenharmony_ci	val = macb_mdc_clk_div(bp);
420062306a36Sopenharmony_ci	val |= macb_dbw(bp);
420162306a36Sopenharmony_ci	if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
420262306a36Sopenharmony_ci		val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
420362306a36Sopenharmony_ci	macb_writel(bp, NCFGR, val);
420462306a36Sopenharmony_ci
420562306a36Sopenharmony_ci	return 0;
420662306a36Sopenharmony_ci}
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_cistatic const struct macb_usrio_config macb_default_usrio = {
420962306a36Sopenharmony_ci	.mii = MACB_BIT(MII),
421062306a36Sopenharmony_ci	.rmii = MACB_BIT(RMII),
421162306a36Sopenharmony_ci	.rgmii = GEM_BIT(RGMII),
421262306a36Sopenharmony_ci	.refclk = MACB_BIT(CLKEN),
421362306a36Sopenharmony_ci};
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_ci#if defined(CONFIG_OF)
421662306a36Sopenharmony_ci/* 1518 rounded up */
421762306a36Sopenharmony_ci#define AT91ETHER_MAX_RBUFF_SZ	0x600
421862306a36Sopenharmony_ci/* max number of receive buffers */
421962306a36Sopenharmony_ci#define AT91ETHER_MAX_RX_DESCR	9
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_cistatic struct sifive_fu540_macb_mgmt *mgmt;
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_cistatic int at91ether_alloc_coherent(struct macb *lp)
422462306a36Sopenharmony_ci{
422562306a36Sopenharmony_ci	struct macb_queue *q = &lp->queues[0];
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	q->rx_ring = dma_alloc_coherent(&lp->pdev->dev,
422862306a36Sopenharmony_ci					 (AT91ETHER_MAX_RX_DESCR *
422962306a36Sopenharmony_ci					  macb_dma_desc_get_size(lp)),
423062306a36Sopenharmony_ci					 &q->rx_ring_dma, GFP_KERNEL);
423162306a36Sopenharmony_ci	if (!q->rx_ring)
423262306a36Sopenharmony_ci		return -ENOMEM;
423362306a36Sopenharmony_ci
423462306a36Sopenharmony_ci	q->rx_buffers = dma_alloc_coherent(&lp->pdev->dev,
423562306a36Sopenharmony_ci					    AT91ETHER_MAX_RX_DESCR *
423662306a36Sopenharmony_ci					    AT91ETHER_MAX_RBUFF_SZ,
423762306a36Sopenharmony_ci					    &q->rx_buffers_dma, GFP_KERNEL);
423862306a36Sopenharmony_ci	if (!q->rx_buffers) {
423962306a36Sopenharmony_ci		dma_free_coherent(&lp->pdev->dev,
424062306a36Sopenharmony_ci				  AT91ETHER_MAX_RX_DESCR *
424162306a36Sopenharmony_ci				  macb_dma_desc_get_size(lp),
424262306a36Sopenharmony_ci				  q->rx_ring, q->rx_ring_dma);
424362306a36Sopenharmony_ci		q->rx_ring = NULL;
424462306a36Sopenharmony_ci		return -ENOMEM;
424562306a36Sopenharmony_ci	}
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_ci	return 0;
424862306a36Sopenharmony_ci}
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_cistatic void at91ether_free_coherent(struct macb *lp)
425162306a36Sopenharmony_ci{
425262306a36Sopenharmony_ci	struct macb_queue *q = &lp->queues[0];
425362306a36Sopenharmony_ci
425462306a36Sopenharmony_ci	if (q->rx_ring) {
425562306a36Sopenharmony_ci		dma_free_coherent(&lp->pdev->dev,
425662306a36Sopenharmony_ci				  AT91ETHER_MAX_RX_DESCR *
425762306a36Sopenharmony_ci				  macb_dma_desc_get_size(lp),
425862306a36Sopenharmony_ci				  q->rx_ring, q->rx_ring_dma);
425962306a36Sopenharmony_ci		q->rx_ring = NULL;
426062306a36Sopenharmony_ci	}
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci	if (q->rx_buffers) {
426362306a36Sopenharmony_ci		dma_free_coherent(&lp->pdev->dev,
426462306a36Sopenharmony_ci				  AT91ETHER_MAX_RX_DESCR *
426562306a36Sopenharmony_ci				  AT91ETHER_MAX_RBUFF_SZ,
426662306a36Sopenharmony_ci				  q->rx_buffers, q->rx_buffers_dma);
426762306a36Sopenharmony_ci		q->rx_buffers = NULL;
426862306a36Sopenharmony_ci	}
426962306a36Sopenharmony_ci}
427062306a36Sopenharmony_ci
427162306a36Sopenharmony_ci/* Initialize and start the Receiver and Transmit subsystems */
427262306a36Sopenharmony_cistatic int at91ether_start(struct macb *lp)
427362306a36Sopenharmony_ci{
427462306a36Sopenharmony_ci	struct macb_queue *q = &lp->queues[0];
427562306a36Sopenharmony_ci	struct macb_dma_desc *desc;
427662306a36Sopenharmony_ci	dma_addr_t addr;
427762306a36Sopenharmony_ci	u32 ctl;
427862306a36Sopenharmony_ci	int i, ret;
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci	ret = at91ether_alloc_coherent(lp);
428162306a36Sopenharmony_ci	if (ret)
428262306a36Sopenharmony_ci		return ret;
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	addr = q->rx_buffers_dma;
428562306a36Sopenharmony_ci	for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) {
428662306a36Sopenharmony_ci		desc = macb_rx_desc(q, i);
428762306a36Sopenharmony_ci		macb_set_addr(lp, desc, addr);
428862306a36Sopenharmony_ci		desc->ctrl = 0;
428962306a36Sopenharmony_ci		addr += AT91ETHER_MAX_RBUFF_SZ;
429062306a36Sopenharmony_ci	}
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	/* Set the Wrap bit on the last descriptor */
429362306a36Sopenharmony_ci	desc->addr |= MACB_BIT(RX_WRAP);
429462306a36Sopenharmony_ci
429562306a36Sopenharmony_ci	/* Reset buffer index */
429662306a36Sopenharmony_ci	q->rx_tail = 0;
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ci	/* Program address of descriptor list in Rx Buffer Queue register */
429962306a36Sopenharmony_ci	macb_writel(lp, RBQP, q->rx_ring_dma);
430062306a36Sopenharmony_ci
430162306a36Sopenharmony_ci	/* Enable Receive and Transmit */
430262306a36Sopenharmony_ci	ctl = macb_readl(lp, NCR);
430362306a36Sopenharmony_ci	macb_writel(lp, NCR, ctl | MACB_BIT(RE) | MACB_BIT(TE));
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	/* Enable MAC interrupts */
430662306a36Sopenharmony_ci	macb_writel(lp, IER, MACB_BIT(RCOMP)	|
430762306a36Sopenharmony_ci			     MACB_BIT(RXUBR)	|
430862306a36Sopenharmony_ci			     MACB_BIT(ISR_TUND)	|
430962306a36Sopenharmony_ci			     MACB_BIT(ISR_RLE)	|
431062306a36Sopenharmony_ci			     MACB_BIT(TCOMP)	|
431162306a36Sopenharmony_ci			     MACB_BIT(ISR_ROVR)	|
431262306a36Sopenharmony_ci			     MACB_BIT(HRESP));
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci	return 0;
431562306a36Sopenharmony_ci}
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_cistatic void at91ether_stop(struct macb *lp)
431862306a36Sopenharmony_ci{
431962306a36Sopenharmony_ci	u32 ctl;
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_ci	/* Disable MAC interrupts */
432262306a36Sopenharmony_ci	macb_writel(lp, IDR, MACB_BIT(RCOMP)	|
432362306a36Sopenharmony_ci			     MACB_BIT(RXUBR)	|
432462306a36Sopenharmony_ci			     MACB_BIT(ISR_TUND)	|
432562306a36Sopenharmony_ci			     MACB_BIT(ISR_RLE)	|
432662306a36Sopenharmony_ci			     MACB_BIT(TCOMP)	|
432762306a36Sopenharmony_ci			     MACB_BIT(ISR_ROVR) |
432862306a36Sopenharmony_ci			     MACB_BIT(HRESP));
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci	/* Disable Receiver and Transmitter */
433162306a36Sopenharmony_ci	ctl = macb_readl(lp, NCR);
433262306a36Sopenharmony_ci	macb_writel(lp, NCR, ctl & ~(MACB_BIT(TE) | MACB_BIT(RE)));
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	/* Free resources. */
433562306a36Sopenharmony_ci	at91ether_free_coherent(lp);
433662306a36Sopenharmony_ci}
433762306a36Sopenharmony_ci
433862306a36Sopenharmony_ci/* Open the ethernet interface */
433962306a36Sopenharmony_cistatic int at91ether_open(struct net_device *dev)
434062306a36Sopenharmony_ci{
434162306a36Sopenharmony_ci	struct macb *lp = netdev_priv(dev);
434262306a36Sopenharmony_ci	u32 ctl;
434362306a36Sopenharmony_ci	int ret;
434462306a36Sopenharmony_ci
434562306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(&lp->pdev->dev);
434662306a36Sopenharmony_ci	if (ret < 0)
434762306a36Sopenharmony_ci		return ret;
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci	/* Clear internal statistics */
435062306a36Sopenharmony_ci	ctl = macb_readl(lp, NCR);
435162306a36Sopenharmony_ci	macb_writel(lp, NCR, ctl | MACB_BIT(CLRSTAT));
435262306a36Sopenharmony_ci
435362306a36Sopenharmony_ci	macb_set_hwaddr(lp);
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci	ret = at91ether_start(lp);
435662306a36Sopenharmony_ci	if (ret)
435762306a36Sopenharmony_ci		goto pm_exit;
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	ret = macb_phylink_connect(lp);
436062306a36Sopenharmony_ci	if (ret)
436162306a36Sopenharmony_ci		goto stop;
436262306a36Sopenharmony_ci
436362306a36Sopenharmony_ci	netif_start_queue(dev);
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci	return 0;
436662306a36Sopenharmony_ci
436762306a36Sopenharmony_cistop:
436862306a36Sopenharmony_ci	at91ether_stop(lp);
436962306a36Sopenharmony_cipm_exit:
437062306a36Sopenharmony_ci	pm_runtime_put_sync(&lp->pdev->dev);
437162306a36Sopenharmony_ci	return ret;
437262306a36Sopenharmony_ci}
437362306a36Sopenharmony_ci
437462306a36Sopenharmony_ci/* Close the interface */
437562306a36Sopenharmony_cistatic int at91ether_close(struct net_device *dev)
437662306a36Sopenharmony_ci{
437762306a36Sopenharmony_ci	struct macb *lp = netdev_priv(dev);
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci	netif_stop_queue(dev);
438062306a36Sopenharmony_ci
438162306a36Sopenharmony_ci	phylink_stop(lp->phylink);
438262306a36Sopenharmony_ci	phylink_disconnect_phy(lp->phylink);
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci	at91ether_stop(lp);
438562306a36Sopenharmony_ci
438662306a36Sopenharmony_ci	return pm_runtime_put(&lp->pdev->dev);
438762306a36Sopenharmony_ci}
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci/* Transmit packet */
439062306a36Sopenharmony_cistatic netdev_tx_t at91ether_start_xmit(struct sk_buff *skb,
439162306a36Sopenharmony_ci					struct net_device *dev)
439262306a36Sopenharmony_ci{
439362306a36Sopenharmony_ci	struct macb *lp = netdev_priv(dev);
439462306a36Sopenharmony_ci
439562306a36Sopenharmony_ci	if (macb_readl(lp, TSR) & MACB_BIT(RM9200_BNQ)) {
439662306a36Sopenharmony_ci		int desc = 0;
439762306a36Sopenharmony_ci
439862306a36Sopenharmony_ci		netif_stop_queue(dev);
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci		/* Store packet information (to free when Tx completed) */
440162306a36Sopenharmony_ci		lp->rm9200_txq[desc].skb = skb;
440262306a36Sopenharmony_ci		lp->rm9200_txq[desc].size = skb->len;
440362306a36Sopenharmony_ci		lp->rm9200_txq[desc].mapping = dma_map_single(&lp->pdev->dev, skb->data,
440462306a36Sopenharmony_ci							      skb->len, DMA_TO_DEVICE);
440562306a36Sopenharmony_ci		if (dma_mapping_error(&lp->pdev->dev, lp->rm9200_txq[desc].mapping)) {
440662306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
440762306a36Sopenharmony_ci			dev->stats.tx_dropped++;
440862306a36Sopenharmony_ci			netdev_err(dev, "%s: DMA mapping error\n", __func__);
440962306a36Sopenharmony_ci			return NETDEV_TX_OK;
441062306a36Sopenharmony_ci		}
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci		/* Set address of the data in the Transmit Address register */
441362306a36Sopenharmony_ci		macb_writel(lp, TAR, lp->rm9200_txq[desc].mapping);
441462306a36Sopenharmony_ci		/* Set length of the packet in the Transmit Control register */
441562306a36Sopenharmony_ci		macb_writel(lp, TCR, skb->len);
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	} else {
441862306a36Sopenharmony_ci		netdev_err(dev, "%s called, but device is busy!\n", __func__);
441962306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
442062306a36Sopenharmony_ci	}
442162306a36Sopenharmony_ci
442262306a36Sopenharmony_ci	return NETDEV_TX_OK;
442362306a36Sopenharmony_ci}
442462306a36Sopenharmony_ci
442562306a36Sopenharmony_ci/* Extract received frame from buffer descriptors and sent to upper layers.
442662306a36Sopenharmony_ci * (Called from interrupt context)
442762306a36Sopenharmony_ci */
442862306a36Sopenharmony_cistatic void at91ether_rx(struct net_device *dev)
442962306a36Sopenharmony_ci{
443062306a36Sopenharmony_ci	struct macb *lp = netdev_priv(dev);
443162306a36Sopenharmony_ci	struct macb_queue *q = &lp->queues[0];
443262306a36Sopenharmony_ci	struct macb_dma_desc *desc;
443362306a36Sopenharmony_ci	unsigned char *p_recv;
443462306a36Sopenharmony_ci	struct sk_buff *skb;
443562306a36Sopenharmony_ci	unsigned int pktlen;
443662306a36Sopenharmony_ci
443762306a36Sopenharmony_ci	desc = macb_rx_desc(q, q->rx_tail);
443862306a36Sopenharmony_ci	while (desc->addr & MACB_BIT(RX_USED)) {
443962306a36Sopenharmony_ci		p_recv = q->rx_buffers + q->rx_tail * AT91ETHER_MAX_RBUFF_SZ;
444062306a36Sopenharmony_ci		pktlen = MACB_BF(RX_FRMLEN, desc->ctrl);
444162306a36Sopenharmony_ci		skb = netdev_alloc_skb(dev, pktlen + 2);
444262306a36Sopenharmony_ci		if (skb) {
444362306a36Sopenharmony_ci			skb_reserve(skb, 2);
444462306a36Sopenharmony_ci			skb_put_data(skb, p_recv, pktlen);
444562306a36Sopenharmony_ci
444662306a36Sopenharmony_ci			skb->protocol = eth_type_trans(skb, dev);
444762306a36Sopenharmony_ci			dev->stats.rx_packets++;
444862306a36Sopenharmony_ci			dev->stats.rx_bytes += pktlen;
444962306a36Sopenharmony_ci			netif_rx(skb);
445062306a36Sopenharmony_ci		} else {
445162306a36Sopenharmony_ci			dev->stats.rx_dropped++;
445262306a36Sopenharmony_ci		}
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci		if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH))
445562306a36Sopenharmony_ci			dev->stats.multicast++;
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ci		/* reset ownership bit */
445862306a36Sopenharmony_ci		desc->addr &= ~MACB_BIT(RX_USED);
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_ci		/* wrap after last buffer */
446162306a36Sopenharmony_ci		if (q->rx_tail == AT91ETHER_MAX_RX_DESCR - 1)
446262306a36Sopenharmony_ci			q->rx_tail = 0;
446362306a36Sopenharmony_ci		else
446462306a36Sopenharmony_ci			q->rx_tail++;
446562306a36Sopenharmony_ci
446662306a36Sopenharmony_ci		desc = macb_rx_desc(q, q->rx_tail);
446762306a36Sopenharmony_ci	}
446862306a36Sopenharmony_ci}
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci/* MAC interrupt handler */
447162306a36Sopenharmony_cistatic irqreturn_t at91ether_interrupt(int irq, void *dev_id)
447262306a36Sopenharmony_ci{
447362306a36Sopenharmony_ci	struct net_device *dev = dev_id;
447462306a36Sopenharmony_ci	struct macb *lp = netdev_priv(dev);
447562306a36Sopenharmony_ci	u32 intstatus, ctl;
447662306a36Sopenharmony_ci	unsigned int desc;
447762306a36Sopenharmony_ci
447862306a36Sopenharmony_ci	/* MAC Interrupt Status register indicates what interrupts are pending.
447962306a36Sopenharmony_ci	 * It is automatically cleared once read.
448062306a36Sopenharmony_ci	 */
448162306a36Sopenharmony_ci	intstatus = macb_readl(lp, ISR);
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ci	/* Receive complete */
448462306a36Sopenharmony_ci	if (intstatus & MACB_BIT(RCOMP))
448562306a36Sopenharmony_ci		at91ether_rx(dev);
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	/* Transmit complete */
448862306a36Sopenharmony_ci	if (intstatus & MACB_BIT(TCOMP)) {
448962306a36Sopenharmony_ci		/* The TCOM bit is set even if the transmission failed */
449062306a36Sopenharmony_ci		if (intstatus & (MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE)))
449162306a36Sopenharmony_ci			dev->stats.tx_errors++;
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci		desc = 0;
449462306a36Sopenharmony_ci		if (lp->rm9200_txq[desc].skb) {
449562306a36Sopenharmony_ci			dev_consume_skb_irq(lp->rm9200_txq[desc].skb);
449662306a36Sopenharmony_ci			lp->rm9200_txq[desc].skb = NULL;
449762306a36Sopenharmony_ci			dma_unmap_single(&lp->pdev->dev, lp->rm9200_txq[desc].mapping,
449862306a36Sopenharmony_ci					 lp->rm9200_txq[desc].size, DMA_TO_DEVICE);
449962306a36Sopenharmony_ci			dev->stats.tx_packets++;
450062306a36Sopenharmony_ci			dev->stats.tx_bytes += lp->rm9200_txq[desc].size;
450162306a36Sopenharmony_ci		}
450262306a36Sopenharmony_ci		netif_wake_queue(dev);
450362306a36Sopenharmony_ci	}
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	/* Work-around for EMAC Errata section 41.3.1 */
450662306a36Sopenharmony_ci	if (intstatus & MACB_BIT(RXUBR)) {
450762306a36Sopenharmony_ci		ctl = macb_readl(lp, NCR);
450862306a36Sopenharmony_ci		macb_writel(lp, NCR, ctl & ~MACB_BIT(RE));
450962306a36Sopenharmony_ci		wmb();
451062306a36Sopenharmony_ci		macb_writel(lp, NCR, ctl | MACB_BIT(RE));
451162306a36Sopenharmony_ci	}
451262306a36Sopenharmony_ci
451362306a36Sopenharmony_ci	if (intstatus & MACB_BIT(ISR_ROVR))
451462306a36Sopenharmony_ci		netdev_err(dev, "ROVR error\n");
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ci	return IRQ_HANDLED;
451762306a36Sopenharmony_ci}
451862306a36Sopenharmony_ci
451962306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
452062306a36Sopenharmony_cistatic void at91ether_poll_controller(struct net_device *dev)
452162306a36Sopenharmony_ci{
452262306a36Sopenharmony_ci	unsigned long flags;
452362306a36Sopenharmony_ci
452462306a36Sopenharmony_ci	local_irq_save(flags);
452562306a36Sopenharmony_ci	at91ether_interrupt(dev->irq, dev);
452662306a36Sopenharmony_ci	local_irq_restore(flags);
452762306a36Sopenharmony_ci}
452862306a36Sopenharmony_ci#endif
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_cistatic const struct net_device_ops at91ether_netdev_ops = {
453162306a36Sopenharmony_ci	.ndo_open		= at91ether_open,
453262306a36Sopenharmony_ci	.ndo_stop		= at91ether_close,
453362306a36Sopenharmony_ci	.ndo_start_xmit		= at91ether_start_xmit,
453462306a36Sopenharmony_ci	.ndo_get_stats		= macb_get_stats,
453562306a36Sopenharmony_ci	.ndo_set_rx_mode	= macb_set_rx_mode,
453662306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
453762306a36Sopenharmony_ci	.ndo_eth_ioctl		= macb_ioctl,
453862306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
453962306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
454062306a36Sopenharmony_ci	.ndo_poll_controller	= at91ether_poll_controller,
454162306a36Sopenharmony_ci#endif
454262306a36Sopenharmony_ci};
454362306a36Sopenharmony_ci
454462306a36Sopenharmony_cistatic int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk,
454562306a36Sopenharmony_ci			      struct clk **hclk, struct clk **tx_clk,
454662306a36Sopenharmony_ci			      struct clk **rx_clk, struct clk **tsu_clk)
454762306a36Sopenharmony_ci{
454862306a36Sopenharmony_ci	int err;
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	*hclk = NULL;
455162306a36Sopenharmony_ci	*tx_clk = NULL;
455262306a36Sopenharmony_ci	*rx_clk = NULL;
455362306a36Sopenharmony_ci	*tsu_clk = NULL;
455462306a36Sopenharmony_ci
455562306a36Sopenharmony_ci	*pclk = devm_clk_get(&pdev->dev, "ether_clk");
455662306a36Sopenharmony_ci	if (IS_ERR(*pclk))
455762306a36Sopenharmony_ci		return PTR_ERR(*pclk);
455862306a36Sopenharmony_ci
455962306a36Sopenharmony_ci	err = clk_prepare_enable(*pclk);
456062306a36Sopenharmony_ci	if (err) {
456162306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable pclk (%d)\n", err);
456262306a36Sopenharmony_ci		return err;
456362306a36Sopenharmony_ci	}
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	return 0;
456662306a36Sopenharmony_ci}
456762306a36Sopenharmony_ci
456862306a36Sopenharmony_cistatic int at91ether_init(struct platform_device *pdev)
456962306a36Sopenharmony_ci{
457062306a36Sopenharmony_ci	struct net_device *dev = platform_get_drvdata(pdev);
457162306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
457262306a36Sopenharmony_ci	int err;
457362306a36Sopenharmony_ci
457462306a36Sopenharmony_ci	bp->queues[0].bp = bp;
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci	dev->netdev_ops = &at91ether_netdev_ops;
457762306a36Sopenharmony_ci	dev->ethtool_ops = &macb_ethtool_ops;
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt,
458062306a36Sopenharmony_ci			       0, dev->name, dev);
458162306a36Sopenharmony_ci	if (err)
458262306a36Sopenharmony_ci		return err;
458362306a36Sopenharmony_ci
458462306a36Sopenharmony_ci	macb_writel(bp, NCR, 0);
458562306a36Sopenharmony_ci
458662306a36Sopenharmony_ci	macb_writel(bp, NCFGR, MACB_BF(CLK, MACB_CLK_DIV32) | MACB_BIT(BIG));
458762306a36Sopenharmony_ci
458862306a36Sopenharmony_ci	return 0;
458962306a36Sopenharmony_ci}
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_cistatic unsigned long fu540_macb_tx_recalc_rate(struct clk_hw *hw,
459262306a36Sopenharmony_ci					       unsigned long parent_rate)
459362306a36Sopenharmony_ci{
459462306a36Sopenharmony_ci	return mgmt->rate;
459562306a36Sopenharmony_ci}
459662306a36Sopenharmony_ci
459762306a36Sopenharmony_cistatic long fu540_macb_tx_round_rate(struct clk_hw *hw, unsigned long rate,
459862306a36Sopenharmony_ci				     unsigned long *parent_rate)
459962306a36Sopenharmony_ci{
460062306a36Sopenharmony_ci	if (WARN_ON(rate < 2500000))
460162306a36Sopenharmony_ci		return 2500000;
460262306a36Sopenharmony_ci	else if (rate == 2500000)
460362306a36Sopenharmony_ci		return 2500000;
460462306a36Sopenharmony_ci	else if (WARN_ON(rate < 13750000))
460562306a36Sopenharmony_ci		return 2500000;
460662306a36Sopenharmony_ci	else if (WARN_ON(rate < 25000000))
460762306a36Sopenharmony_ci		return 25000000;
460862306a36Sopenharmony_ci	else if (rate == 25000000)
460962306a36Sopenharmony_ci		return 25000000;
461062306a36Sopenharmony_ci	else if (WARN_ON(rate < 75000000))
461162306a36Sopenharmony_ci		return 25000000;
461262306a36Sopenharmony_ci	else if (WARN_ON(rate < 125000000))
461362306a36Sopenharmony_ci		return 125000000;
461462306a36Sopenharmony_ci	else if (rate == 125000000)
461562306a36Sopenharmony_ci		return 125000000;
461662306a36Sopenharmony_ci
461762306a36Sopenharmony_ci	WARN_ON(rate > 125000000);
461862306a36Sopenharmony_ci
461962306a36Sopenharmony_ci	return 125000000;
462062306a36Sopenharmony_ci}
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_cistatic int fu540_macb_tx_set_rate(struct clk_hw *hw, unsigned long rate,
462362306a36Sopenharmony_ci				  unsigned long parent_rate)
462462306a36Sopenharmony_ci{
462562306a36Sopenharmony_ci	rate = fu540_macb_tx_round_rate(hw, rate, &parent_rate);
462662306a36Sopenharmony_ci	if (rate != 125000000)
462762306a36Sopenharmony_ci		iowrite32(1, mgmt->reg);
462862306a36Sopenharmony_ci	else
462962306a36Sopenharmony_ci		iowrite32(0, mgmt->reg);
463062306a36Sopenharmony_ci	mgmt->rate = rate;
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci	return 0;
463362306a36Sopenharmony_ci}
463462306a36Sopenharmony_ci
463562306a36Sopenharmony_cistatic const struct clk_ops fu540_c000_ops = {
463662306a36Sopenharmony_ci	.recalc_rate = fu540_macb_tx_recalc_rate,
463762306a36Sopenharmony_ci	.round_rate = fu540_macb_tx_round_rate,
463862306a36Sopenharmony_ci	.set_rate = fu540_macb_tx_set_rate,
463962306a36Sopenharmony_ci};
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_cistatic int fu540_c000_clk_init(struct platform_device *pdev, struct clk **pclk,
464262306a36Sopenharmony_ci			       struct clk **hclk, struct clk **tx_clk,
464362306a36Sopenharmony_ci			       struct clk **rx_clk, struct clk **tsu_clk)
464462306a36Sopenharmony_ci{
464562306a36Sopenharmony_ci	struct clk_init_data init;
464662306a36Sopenharmony_ci	int err = 0;
464762306a36Sopenharmony_ci
464862306a36Sopenharmony_ci	err = macb_clk_init(pdev, pclk, hclk, tx_clk, rx_clk, tsu_clk);
464962306a36Sopenharmony_ci	if (err)
465062306a36Sopenharmony_ci		return err;
465162306a36Sopenharmony_ci
465262306a36Sopenharmony_ci	mgmt = devm_kzalloc(&pdev->dev, sizeof(*mgmt), GFP_KERNEL);
465362306a36Sopenharmony_ci	if (!mgmt) {
465462306a36Sopenharmony_ci		err = -ENOMEM;
465562306a36Sopenharmony_ci		goto err_disable_clks;
465662306a36Sopenharmony_ci	}
465762306a36Sopenharmony_ci
465862306a36Sopenharmony_ci	init.name = "sifive-gemgxl-mgmt";
465962306a36Sopenharmony_ci	init.ops = &fu540_c000_ops;
466062306a36Sopenharmony_ci	init.flags = 0;
466162306a36Sopenharmony_ci	init.num_parents = 0;
466262306a36Sopenharmony_ci
466362306a36Sopenharmony_ci	mgmt->rate = 0;
466462306a36Sopenharmony_ci	mgmt->hw.init = &init;
466562306a36Sopenharmony_ci
466662306a36Sopenharmony_ci	*tx_clk = devm_clk_register(&pdev->dev, &mgmt->hw);
466762306a36Sopenharmony_ci	if (IS_ERR(*tx_clk)) {
466862306a36Sopenharmony_ci		err = PTR_ERR(*tx_clk);
466962306a36Sopenharmony_ci		goto err_disable_clks;
467062306a36Sopenharmony_ci	}
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci	err = clk_prepare_enable(*tx_clk);
467362306a36Sopenharmony_ci	if (err) {
467462306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
467562306a36Sopenharmony_ci		*tx_clk = NULL;
467662306a36Sopenharmony_ci		goto err_disable_clks;
467762306a36Sopenharmony_ci	} else {
467862306a36Sopenharmony_ci		dev_info(&pdev->dev, "Registered clk switch '%s'\n", init.name);
467962306a36Sopenharmony_ci	}
468062306a36Sopenharmony_ci
468162306a36Sopenharmony_ci	return 0;
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_cierr_disable_clks:
468462306a36Sopenharmony_ci	macb_clks_disable(*pclk, *hclk, *tx_clk, *rx_clk, *tsu_clk);
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_ci	return err;
468762306a36Sopenharmony_ci}
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_cistatic int fu540_c000_init(struct platform_device *pdev)
469062306a36Sopenharmony_ci{
469162306a36Sopenharmony_ci	mgmt->reg = devm_platform_ioremap_resource(pdev, 1);
469262306a36Sopenharmony_ci	if (IS_ERR(mgmt->reg))
469362306a36Sopenharmony_ci		return PTR_ERR(mgmt->reg);
469462306a36Sopenharmony_ci
469562306a36Sopenharmony_ci	return macb_init(pdev);
469662306a36Sopenharmony_ci}
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_cistatic int init_reset_optional(struct platform_device *pdev)
469962306a36Sopenharmony_ci{
470062306a36Sopenharmony_ci	struct net_device *dev = platform_get_drvdata(pdev);
470162306a36Sopenharmony_ci	struct macb *bp = netdev_priv(dev);
470262306a36Sopenharmony_ci	int ret;
470362306a36Sopenharmony_ci
470462306a36Sopenharmony_ci	if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
470562306a36Sopenharmony_ci		/* Ensure PHY device used in SGMII mode is ready */
470662306a36Sopenharmony_ci		bp->sgmii_phy = devm_phy_optional_get(&pdev->dev, NULL);
470762306a36Sopenharmony_ci
470862306a36Sopenharmony_ci		if (IS_ERR(bp->sgmii_phy))
470962306a36Sopenharmony_ci			return dev_err_probe(&pdev->dev, PTR_ERR(bp->sgmii_phy),
471062306a36Sopenharmony_ci					     "failed to get SGMII PHY\n");
471162306a36Sopenharmony_ci
471262306a36Sopenharmony_ci		ret = phy_init(bp->sgmii_phy);
471362306a36Sopenharmony_ci		if (ret)
471462306a36Sopenharmony_ci			return dev_err_probe(&pdev->dev, ret,
471562306a36Sopenharmony_ci					     "failed to init SGMII PHY\n");
471662306a36Sopenharmony_ci
471762306a36Sopenharmony_ci		ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_GEM_CONFIG);
471862306a36Sopenharmony_ci		if (!ret) {
471962306a36Sopenharmony_ci			u32 pm_info[2];
472062306a36Sopenharmony_ci
472162306a36Sopenharmony_ci			ret = of_property_read_u32_array(pdev->dev.of_node, "power-domains",
472262306a36Sopenharmony_ci							 pm_info, ARRAY_SIZE(pm_info));
472362306a36Sopenharmony_ci			if (ret) {
472462306a36Sopenharmony_ci				dev_err(&pdev->dev, "Failed to read power management information\n");
472562306a36Sopenharmony_ci				goto err_out_phy_exit;
472662306a36Sopenharmony_ci			}
472762306a36Sopenharmony_ci			ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_FIXED, 0);
472862306a36Sopenharmony_ci			if (ret)
472962306a36Sopenharmony_ci				goto err_out_phy_exit;
473062306a36Sopenharmony_ci
473162306a36Sopenharmony_ci			ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_SGMII_MODE, 1);
473262306a36Sopenharmony_ci			if (ret)
473362306a36Sopenharmony_ci				goto err_out_phy_exit;
473462306a36Sopenharmony_ci		}
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	}
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci	/* Fully reset controller at hardware level if mapped in device tree */
473962306a36Sopenharmony_ci	ret = device_reset_optional(&pdev->dev);
474062306a36Sopenharmony_ci	if (ret) {
474162306a36Sopenharmony_ci		phy_exit(bp->sgmii_phy);
474262306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, ret, "failed to reset controller");
474362306a36Sopenharmony_ci	}
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	ret = macb_init(pdev);
474662306a36Sopenharmony_ci
474762306a36Sopenharmony_cierr_out_phy_exit:
474862306a36Sopenharmony_ci	if (ret)
474962306a36Sopenharmony_ci		phy_exit(bp->sgmii_phy);
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	return ret;
475262306a36Sopenharmony_ci}
475362306a36Sopenharmony_ci
475462306a36Sopenharmony_cistatic const struct macb_usrio_config sama7g5_usrio = {
475562306a36Sopenharmony_ci	.mii = 0,
475662306a36Sopenharmony_ci	.rmii = 1,
475762306a36Sopenharmony_ci	.rgmii = 2,
475862306a36Sopenharmony_ci	.refclk = BIT(2),
475962306a36Sopenharmony_ci	.hdfctlen = BIT(6),
476062306a36Sopenharmony_ci};
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_cistatic const struct macb_config fu540_c000_config = {
476362306a36Sopenharmony_ci	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO |
476462306a36Sopenharmony_ci		MACB_CAPS_GEM_HAS_PTP,
476562306a36Sopenharmony_ci	.dma_burst_length = 16,
476662306a36Sopenharmony_ci	.clk_init = fu540_c000_clk_init,
476762306a36Sopenharmony_ci	.init = fu540_c000_init,
476862306a36Sopenharmony_ci	.jumbo_max_len = 10240,
476962306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
477062306a36Sopenharmony_ci};
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_cistatic const struct macb_config at91sam9260_config = {
477362306a36Sopenharmony_ci	.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
477462306a36Sopenharmony_ci	.clk_init = macb_clk_init,
477562306a36Sopenharmony_ci	.init = macb_init,
477662306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
477762306a36Sopenharmony_ci};
477862306a36Sopenharmony_ci
477962306a36Sopenharmony_cistatic const struct macb_config sama5d3macb_config = {
478062306a36Sopenharmony_ci	.caps = MACB_CAPS_SG_DISABLED |
478162306a36Sopenharmony_ci		MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
478262306a36Sopenharmony_ci	.clk_init = macb_clk_init,
478362306a36Sopenharmony_ci	.init = macb_init,
478462306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
478562306a36Sopenharmony_ci};
478662306a36Sopenharmony_ci
478762306a36Sopenharmony_cistatic const struct macb_config pc302gem_config = {
478862306a36Sopenharmony_ci	.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
478962306a36Sopenharmony_ci	.dma_burst_length = 16,
479062306a36Sopenharmony_ci	.clk_init = macb_clk_init,
479162306a36Sopenharmony_ci	.init = macb_init,
479262306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
479362306a36Sopenharmony_ci};
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_cistatic const struct macb_config sama5d2_config = {
479662306a36Sopenharmony_ci	.caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
479762306a36Sopenharmony_ci	.dma_burst_length = 16,
479862306a36Sopenharmony_ci	.clk_init = macb_clk_init,
479962306a36Sopenharmony_ci	.init = macb_init,
480062306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
480162306a36Sopenharmony_ci};
480262306a36Sopenharmony_ci
480362306a36Sopenharmony_cistatic const struct macb_config sama5d29_config = {
480462306a36Sopenharmony_ci	.caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_GEM_HAS_PTP,
480562306a36Sopenharmony_ci	.dma_burst_length = 16,
480662306a36Sopenharmony_ci	.clk_init = macb_clk_init,
480762306a36Sopenharmony_ci	.init = macb_init,
480862306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
480962306a36Sopenharmony_ci};
481062306a36Sopenharmony_ci
481162306a36Sopenharmony_cistatic const struct macb_config sama5d3_config = {
481262306a36Sopenharmony_ci	.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE |
481362306a36Sopenharmony_ci		MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_JUMBO,
481462306a36Sopenharmony_ci	.dma_burst_length = 16,
481562306a36Sopenharmony_ci	.clk_init = macb_clk_init,
481662306a36Sopenharmony_ci	.init = macb_init,
481762306a36Sopenharmony_ci	.jumbo_max_len = 10240,
481862306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
481962306a36Sopenharmony_ci};
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_cistatic const struct macb_config sama5d4_config = {
482262306a36Sopenharmony_ci	.caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
482362306a36Sopenharmony_ci	.dma_burst_length = 4,
482462306a36Sopenharmony_ci	.clk_init = macb_clk_init,
482562306a36Sopenharmony_ci	.init = macb_init,
482662306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
482762306a36Sopenharmony_ci};
482862306a36Sopenharmony_ci
482962306a36Sopenharmony_cistatic const struct macb_config emac_config = {
483062306a36Sopenharmony_ci	.caps = MACB_CAPS_NEEDS_RSTONUBR | MACB_CAPS_MACB_IS_EMAC,
483162306a36Sopenharmony_ci	.clk_init = at91ether_clk_init,
483262306a36Sopenharmony_ci	.init = at91ether_init,
483362306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
483462306a36Sopenharmony_ci};
483562306a36Sopenharmony_ci
483662306a36Sopenharmony_cistatic const struct macb_config np4_config = {
483762306a36Sopenharmony_ci	.caps = MACB_CAPS_USRIO_DISABLED,
483862306a36Sopenharmony_ci	.clk_init = macb_clk_init,
483962306a36Sopenharmony_ci	.init = macb_init,
484062306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
484162306a36Sopenharmony_ci};
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_cistatic const struct macb_config zynqmp_config = {
484462306a36Sopenharmony_ci	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE |
484562306a36Sopenharmony_ci		MACB_CAPS_JUMBO |
484662306a36Sopenharmony_ci		MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH,
484762306a36Sopenharmony_ci	.dma_burst_length = 16,
484862306a36Sopenharmony_ci	.clk_init = macb_clk_init,
484962306a36Sopenharmony_ci	.init = init_reset_optional,
485062306a36Sopenharmony_ci	.jumbo_max_len = 10240,
485162306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
485262306a36Sopenharmony_ci};
485362306a36Sopenharmony_ci
485462306a36Sopenharmony_cistatic const struct macb_config zynq_config = {
485562306a36Sopenharmony_ci	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF |
485662306a36Sopenharmony_ci		MACB_CAPS_NEEDS_RSTONUBR,
485762306a36Sopenharmony_ci	.dma_burst_length = 16,
485862306a36Sopenharmony_ci	.clk_init = macb_clk_init,
485962306a36Sopenharmony_ci	.init = macb_init,
486062306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
486162306a36Sopenharmony_ci};
486262306a36Sopenharmony_ci
486362306a36Sopenharmony_cistatic const struct macb_config mpfs_config = {
486462306a36Sopenharmony_ci	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE |
486562306a36Sopenharmony_ci		MACB_CAPS_JUMBO |
486662306a36Sopenharmony_ci		MACB_CAPS_GEM_HAS_PTP,
486762306a36Sopenharmony_ci	.dma_burst_length = 16,
486862306a36Sopenharmony_ci	.clk_init = macb_clk_init,
486962306a36Sopenharmony_ci	.init = init_reset_optional,
487062306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
487162306a36Sopenharmony_ci	.max_tx_length = 4040, /* Cadence Erratum 1686 */
487262306a36Sopenharmony_ci	.jumbo_max_len = 4040,
487362306a36Sopenharmony_ci};
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_cistatic const struct macb_config sama7g5_gem_config = {
487662306a36Sopenharmony_ci	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_CLK_HW_CHG |
487762306a36Sopenharmony_ci		MACB_CAPS_MIIONRGMII | MACB_CAPS_GEM_HAS_PTP,
487862306a36Sopenharmony_ci	.dma_burst_length = 16,
487962306a36Sopenharmony_ci	.clk_init = macb_clk_init,
488062306a36Sopenharmony_ci	.init = macb_init,
488162306a36Sopenharmony_ci	.usrio = &sama7g5_usrio,
488262306a36Sopenharmony_ci};
488362306a36Sopenharmony_ci
488462306a36Sopenharmony_cistatic const struct macb_config sama7g5_emac_config = {
488562306a36Sopenharmony_ci	.caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII |
488662306a36Sopenharmony_ci		MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_MIIONRGMII |
488762306a36Sopenharmony_ci		MACB_CAPS_GEM_HAS_PTP,
488862306a36Sopenharmony_ci	.dma_burst_length = 16,
488962306a36Sopenharmony_ci	.clk_init = macb_clk_init,
489062306a36Sopenharmony_ci	.init = macb_init,
489162306a36Sopenharmony_ci	.usrio = &sama7g5_usrio,
489262306a36Sopenharmony_ci};
489362306a36Sopenharmony_ci
489462306a36Sopenharmony_cistatic const struct macb_config versal_config = {
489562306a36Sopenharmony_ci	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO |
489662306a36Sopenharmony_ci		MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH | MACB_CAPS_NEED_TSUCLK,
489762306a36Sopenharmony_ci	.dma_burst_length = 16,
489862306a36Sopenharmony_ci	.clk_init = macb_clk_init,
489962306a36Sopenharmony_ci	.init = init_reset_optional,
490062306a36Sopenharmony_ci	.jumbo_max_len = 10240,
490162306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
490262306a36Sopenharmony_ci};
490362306a36Sopenharmony_ci
490462306a36Sopenharmony_cistatic const struct of_device_id macb_dt_ids[] = {
490562306a36Sopenharmony_ci	{ .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config },
490662306a36Sopenharmony_ci	{ .compatible = "cdns,macb" },
490762306a36Sopenharmony_ci	{ .compatible = "cdns,np4-macb", .data = &np4_config },
490862306a36Sopenharmony_ci	{ .compatible = "cdns,pc302-gem", .data = &pc302gem_config },
490962306a36Sopenharmony_ci	{ .compatible = "cdns,gem", .data = &pc302gem_config },
491062306a36Sopenharmony_ci	{ .compatible = "cdns,sam9x60-macb", .data = &at91sam9260_config },
491162306a36Sopenharmony_ci	{ .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config },
491262306a36Sopenharmony_ci	{ .compatible = "atmel,sama5d29-gem", .data = &sama5d29_config },
491362306a36Sopenharmony_ci	{ .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
491462306a36Sopenharmony_ci	{ .compatible = "atmel,sama5d3-macb", .data = &sama5d3macb_config },
491562306a36Sopenharmony_ci	{ .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config },
491662306a36Sopenharmony_ci	{ .compatible = "cdns,at91rm9200-emac", .data = &emac_config },
491762306a36Sopenharmony_ci	{ .compatible = "cdns,emac", .data = &emac_config },
491862306a36Sopenharmony_ci	{ .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config}, /* deprecated */
491962306a36Sopenharmony_ci	{ .compatible = "cdns,zynq-gem", .data = &zynq_config }, /* deprecated */
492062306a36Sopenharmony_ci	{ .compatible = "sifive,fu540-c000-gem", .data = &fu540_c000_config },
492162306a36Sopenharmony_ci	{ .compatible = "microchip,mpfs-macb", .data = &mpfs_config },
492262306a36Sopenharmony_ci	{ .compatible = "microchip,sama7g5-gem", .data = &sama7g5_gem_config },
492362306a36Sopenharmony_ci	{ .compatible = "microchip,sama7g5-emac", .data = &sama7g5_emac_config },
492462306a36Sopenharmony_ci	{ .compatible = "xlnx,zynqmp-gem", .data = &zynqmp_config},
492562306a36Sopenharmony_ci	{ .compatible = "xlnx,zynq-gem", .data = &zynq_config },
492662306a36Sopenharmony_ci	{ .compatible = "xlnx,versal-gem", .data = &versal_config},
492762306a36Sopenharmony_ci	{ /* sentinel */ }
492862306a36Sopenharmony_ci};
492962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, macb_dt_ids);
493062306a36Sopenharmony_ci#endif /* CONFIG_OF */
493162306a36Sopenharmony_ci
493262306a36Sopenharmony_cistatic const struct macb_config default_gem_config = {
493362306a36Sopenharmony_ci	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE |
493462306a36Sopenharmony_ci		MACB_CAPS_JUMBO |
493562306a36Sopenharmony_ci		MACB_CAPS_GEM_HAS_PTP,
493662306a36Sopenharmony_ci	.dma_burst_length = 16,
493762306a36Sopenharmony_ci	.clk_init = macb_clk_init,
493862306a36Sopenharmony_ci	.init = macb_init,
493962306a36Sopenharmony_ci	.usrio = &macb_default_usrio,
494062306a36Sopenharmony_ci	.jumbo_max_len = 10240,
494162306a36Sopenharmony_ci};
494262306a36Sopenharmony_ci
494362306a36Sopenharmony_cistatic int macb_probe(struct platform_device *pdev)
494462306a36Sopenharmony_ci{
494562306a36Sopenharmony_ci	const struct macb_config *macb_config = &default_gem_config;
494662306a36Sopenharmony_ci	int (*clk_init)(struct platform_device *, struct clk **,
494762306a36Sopenharmony_ci			struct clk **, struct clk **,  struct clk **,
494862306a36Sopenharmony_ci			struct clk **) = macb_config->clk_init;
494962306a36Sopenharmony_ci	int (*init)(struct platform_device *) = macb_config->init;
495062306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
495162306a36Sopenharmony_ci	struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL;
495262306a36Sopenharmony_ci	struct clk *tsu_clk = NULL;
495362306a36Sopenharmony_ci	unsigned int queue_mask, num_queues;
495462306a36Sopenharmony_ci	bool native_io;
495562306a36Sopenharmony_ci	phy_interface_t interface;
495662306a36Sopenharmony_ci	struct net_device *dev;
495762306a36Sopenharmony_ci	struct resource *regs;
495862306a36Sopenharmony_ci	u32 wtrmrk_rst_val;
495962306a36Sopenharmony_ci	void __iomem *mem;
496062306a36Sopenharmony_ci	struct macb *bp;
496162306a36Sopenharmony_ci	int err, val;
496262306a36Sopenharmony_ci
496362306a36Sopenharmony_ci	mem = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
496462306a36Sopenharmony_ci	if (IS_ERR(mem))
496562306a36Sopenharmony_ci		return PTR_ERR(mem);
496662306a36Sopenharmony_ci
496762306a36Sopenharmony_ci	if (np) {
496862306a36Sopenharmony_ci		const struct of_device_id *match;
496962306a36Sopenharmony_ci
497062306a36Sopenharmony_ci		match = of_match_node(macb_dt_ids, np);
497162306a36Sopenharmony_ci		if (match && match->data) {
497262306a36Sopenharmony_ci			macb_config = match->data;
497362306a36Sopenharmony_ci			clk_init = macb_config->clk_init;
497462306a36Sopenharmony_ci			init = macb_config->init;
497562306a36Sopenharmony_ci		}
497662306a36Sopenharmony_ci	}
497762306a36Sopenharmony_ci
497862306a36Sopenharmony_ci	err = clk_init(pdev, &pclk, &hclk, &tx_clk, &rx_clk, &tsu_clk);
497962306a36Sopenharmony_ci	if (err)
498062306a36Sopenharmony_ci		return err;
498162306a36Sopenharmony_ci
498262306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev, MACB_PM_TIMEOUT);
498362306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
498462306a36Sopenharmony_ci	pm_runtime_get_noresume(&pdev->dev);
498562306a36Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
498662306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
498762306a36Sopenharmony_ci	native_io = hw_is_native_io(mem);
498862306a36Sopenharmony_ci
498962306a36Sopenharmony_ci	macb_probe_queues(mem, native_io, &queue_mask, &num_queues);
499062306a36Sopenharmony_ci	dev = alloc_etherdev_mq(sizeof(*bp), num_queues);
499162306a36Sopenharmony_ci	if (!dev) {
499262306a36Sopenharmony_ci		err = -ENOMEM;
499362306a36Sopenharmony_ci		goto err_disable_clocks;
499462306a36Sopenharmony_ci	}
499562306a36Sopenharmony_ci
499662306a36Sopenharmony_ci	dev->base_addr = regs->start;
499762306a36Sopenharmony_ci
499862306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
499962306a36Sopenharmony_ci
500062306a36Sopenharmony_ci	bp = netdev_priv(dev);
500162306a36Sopenharmony_ci	bp->pdev = pdev;
500262306a36Sopenharmony_ci	bp->dev = dev;
500362306a36Sopenharmony_ci	bp->regs = mem;
500462306a36Sopenharmony_ci	bp->native_io = native_io;
500562306a36Sopenharmony_ci	if (native_io) {
500662306a36Sopenharmony_ci		bp->macb_reg_readl = hw_readl_native;
500762306a36Sopenharmony_ci		bp->macb_reg_writel = hw_writel_native;
500862306a36Sopenharmony_ci	} else {
500962306a36Sopenharmony_ci		bp->macb_reg_readl = hw_readl;
501062306a36Sopenharmony_ci		bp->macb_reg_writel = hw_writel;
501162306a36Sopenharmony_ci	}
501262306a36Sopenharmony_ci	bp->num_queues = num_queues;
501362306a36Sopenharmony_ci	bp->queue_mask = queue_mask;
501462306a36Sopenharmony_ci	if (macb_config)
501562306a36Sopenharmony_ci		bp->dma_burst_length = macb_config->dma_burst_length;
501662306a36Sopenharmony_ci	bp->pclk = pclk;
501762306a36Sopenharmony_ci	bp->hclk = hclk;
501862306a36Sopenharmony_ci	bp->tx_clk = tx_clk;
501962306a36Sopenharmony_ci	bp->rx_clk = rx_clk;
502062306a36Sopenharmony_ci	bp->tsu_clk = tsu_clk;
502162306a36Sopenharmony_ci	if (macb_config)
502262306a36Sopenharmony_ci		bp->jumbo_max_len = macb_config->jumbo_max_len;
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_ci	if (!hw_is_gem(bp->regs, bp->native_io))
502562306a36Sopenharmony_ci		bp->max_tx_length = MACB_MAX_TX_LEN;
502662306a36Sopenharmony_ci	else if (macb_config->max_tx_length)
502762306a36Sopenharmony_ci		bp->max_tx_length = macb_config->max_tx_length;
502862306a36Sopenharmony_ci	else
502962306a36Sopenharmony_ci		bp->max_tx_length = GEM_MAX_TX_LEN;
503062306a36Sopenharmony_ci
503162306a36Sopenharmony_ci	bp->wol = 0;
503262306a36Sopenharmony_ci	if (of_property_read_bool(np, "magic-packet"))
503362306a36Sopenharmony_ci		bp->wol |= MACB_WOL_HAS_MAGIC_PACKET;
503462306a36Sopenharmony_ci	device_set_wakeup_capable(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);
503562306a36Sopenharmony_ci
503662306a36Sopenharmony_ci	bp->usrio = macb_config->usrio;
503762306a36Sopenharmony_ci
503862306a36Sopenharmony_ci	/* By default we set to partial store and forward mode for zynqmp.
503962306a36Sopenharmony_ci	 * Disable if not set in devicetree.
504062306a36Sopenharmony_ci	 */
504162306a36Sopenharmony_ci	if (GEM_BFEXT(PBUF_CUTTHRU, gem_readl(bp, DCFG6))) {
504262306a36Sopenharmony_ci		err = of_property_read_u32(bp->pdev->dev.of_node,
504362306a36Sopenharmony_ci					   "cdns,rx-watermark",
504462306a36Sopenharmony_ci					   &bp->rx_watermark);
504562306a36Sopenharmony_ci
504662306a36Sopenharmony_ci		if (!err) {
504762306a36Sopenharmony_ci			/* Disable partial store and forward in case of error or
504862306a36Sopenharmony_ci			 * invalid watermark value
504962306a36Sopenharmony_ci			 */
505062306a36Sopenharmony_ci			wtrmrk_rst_val = (1 << (GEM_BFEXT(RX_PBUF_ADDR, gem_readl(bp, DCFG2)))) - 1;
505162306a36Sopenharmony_ci			if (bp->rx_watermark > wtrmrk_rst_val || !bp->rx_watermark) {
505262306a36Sopenharmony_ci				dev_info(&bp->pdev->dev, "Invalid watermark value\n");
505362306a36Sopenharmony_ci				bp->rx_watermark = 0;
505462306a36Sopenharmony_ci			}
505562306a36Sopenharmony_ci		}
505662306a36Sopenharmony_ci	}
505762306a36Sopenharmony_ci	spin_lock_init(&bp->lock);
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_ci	/* setup capabilities */
506062306a36Sopenharmony_ci	macb_configure_caps(bp, macb_config);
506162306a36Sopenharmony_ci
506262306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
506362306a36Sopenharmony_ci	if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) {
506462306a36Sopenharmony_ci		dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
506562306a36Sopenharmony_ci		bp->hw_dma_cap |= HW_DMA_CAP_64B;
506662306a36Sopenharmony_ci	}
506762306a36Sopenharmony_ci#endif
506862306a36Sopenharmony_ci	platform_set_drvdata(pdev, dev);
506962306a36Sopenharmony_ci
507062306a36Sopenharmony_ci	dev->irq = platform_get_irq(pdev, 0);
507162306a36Sopenharmony_ci	if (dev->irq < 0) {
507262306a36Sopenharmony_ci		err = dev->irq;
507362306a36Sopenharmony_ci		goto err_out_free_netdev;
507462306a36Sopenharmony_ci	}
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci	/* MTU range: 68 - 1500 or 10240 */
507762306a36Sopenharmony_ci	dev->min_mtu = GEM_MTU_MIN_SIZE;
507862306a36Sopenharmony_ci	if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len)
507962306a36Sopenharmony_ci		dev->max_mtu = bp->jumbo_max_len - ETH_HLEN - ETH_FCS_LEN;
508062306a36Sopenharmony_ci	else
508162306a36Sopenharmony_ci		dev->max_mtu = ETH_DATA_LEN;
508262306a36Sopenharmony_ci
508362306a36Sopenharmony_ci	if (bp->caps & MACB_CAPS_BD_RD_PREFETCH) {
508462306a36Sopenharmony_ci		val = GEM_BFEXT(RXBD_RDBUFF, gem_readl(bp, DCFG10));
508562306a36Sopenharmony_ci		if (val)
508662306a36Sopenharmony_ci			bp->rx_bd_rd_prefetch = (2 << (val - 1)) *
508762306a36Sopenharmony_ci						macb_dma_desc_get_size(bp);
508862306a36Sopenharmony_ci
508962306a36Sopenharmony_ci		val = GEM_BFEXT(TXBD_RDBUFF, gem_readl(bp, DCFG10));
509062306a36Sopenharmony_ci		if (val)
509162306a36Sopenharmony_ci			bp->tx_bd_rd_prefetch = (2 << (val - 1)) *
509262306a36Sopenharmony_ci						macb_dma_desc_get_size(bp);
509362306a36Sopenharmony_ci	}
509462306a36Sopenharmony_ci
509562306a36Sopenharmony_ci	bp->rx_intr_mask = MACB_RX_INT_FLAGS;
509662306a36Sopenharmony_ci	if (bp->caps & MACB_CAPS_NEEDS_RSTONUBR)
509762306a36Sopenharmony_ci		bp->rx_intr_mask |= MACB_BIT(RXUBR);
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci	err = of_get_ethdev_address(np, bp->dev);
510062306a36Sopenharmony_ci	if (err == -EPROBE_DEFER)
510162306a36Sopenharmony_ci		goto err_out_free_netdev;
510262306a36Sopenharmony_ci	else if (err)
510362306a36Sopenharmony_ci		macb_get_hwaddr(bp);
510462306a36Sopenharmony_ci
510562306a36Sopenharmony_ci	err = of_get_phy_mode(np, &interface);
510662306a36Sopenharmony_ci	if (err)
510762306a36Sopenharmony_ci		/* not found in DT, MII by default */
510862306a36Sopenharmony_ci		bp->phy_interface = PHY_INTERFACE_MODE_MII;
510962306a36Sopenharmony_ci	else
511062306a36Sopenharmony_ci		bp->phy_interface = interface;
511162306a36Sopenharmony_ci
511262306a36Sopenharmony_ci	/* IP specific init */
511362306a36Sopenharmony_ci	err = init(pdev);
511462306a36Sopenharmony_ci	if (err)
511562306a36Sopenharmony_ci		goto err_out_free_netdev;
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_ci	err = macb_mii_init(bp);
511862306a36Sopenharmony_ci	if (err)
511962306a36Sopenharmony_ci		goto err_out_phy_exit;
512062306a36Sopenharmony_ci
512162306a36Sopenharmony_ci	netif_carrier_off(dev);
512262306a36Sopenharmony_ci
512362306a36Sopenharmony_ci	err = register_netdev(dev);
512462306a36Sopenharmony_ci	if (err) {
512562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
512662306a36Sopenharmony_ci		goto err_out_unregister_mdio;
512762306a36Sopenharmony_ci	}
512862306a36Sopenharmony_ci
512962306a36Sopenharmony_ci	tasklet_setup(&bp->hresp_err_tasklet, macb_hresp_error_task);
513062306a36Sopenharmony_ci
513162306a36Sopenharmony_ci	netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
513262306a36Sopenharmony_ci		    macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
513362306a36Sopenharmony_ci		    dev->base_addr, dev->irq, dev->dev_addr);
513462306a36Sopenharmony_ci
513562306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&bp->pdev->dev);
513662306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&bp->pdev->dev);
513762306a36Sopenharmony_ci
513862306a36Sopenharmony_ci	return 0;
513962306a36Sopenharmony_ci
514062306a36Sopenharmony_cierr_out_unregister_mdio:
514162306a36Sopenharmony_ci	mdiobus_unregister(bp->mii_bus);
514262306a36Sopenharmony_ci	mdiobus_free(bp->mii_bus);
514362306a36Sopenharmony_ci
514462306a36Sopenharmony_cierr_out_phy_exit:
514562306a36Sopenharmony_ci	phy_exit(bp->sgmii_phy);
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_cierr_out_free_netdev:
514862306a36Sopenharmony_ci	free_netdev(dev);
514962306a36Sopenharmony_ci
515062306a36Sopenharmony_cierr_disable_clocks:
515162306a36Sopenharmony_ci	macb_clks_disable(pclk, hclk, tx_clk, rx_clk, tsu_clk);
515262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
515362306a36Sopenharmony_ci	pm_runtime_set_suspended(&pdev->dev);
515462306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
515562306a36Sopenharmony_ci
515662306a36Sopenharmony_ci	return err;
515762306a36Sopenharmony_ci}
515862306a36Sopenharmony_ci
515962306a36Sopenharmony_cistatic int macb_remove(struct platform_device *pdev)
516062306a36Sopenharmony_ci{
516162306a36Sopenharmony_ci	struct net_device *dev;
516262306a36Sopenharmony_ci	struct macb *bp;
516362306a36Sopenharmony_ci
516462306a36Sopenharmony_ci	dev = platform_get_drvdata(pdev);
516562306a36Sopenharmony_ci
516662306a36Sopenharmony_ci	if (dev) {
516762306a36Sopenharmony_ci		bp = netdev_priv(dev);
516862306a36Sopenharmony_ci		phy_exit(bp->sgmii_phy);
516962306a36Sopenharmony_ci		mdiobus_unregister(bp->mii_bus);
517062306a36Sopenharmony_ci		mdiobus_free(bp->mii_bus);
517162306a36Sopenharmony_ci
517262306a36Sopenharmony_ci		unregister_netdev(dev);
517362306a36Sopenharmony_ci		tasklet_kill(&bp->hresp_err_tasklet);
517462306a36Sopenharmony_ci		pm_runtime_disable(&pdev->dev);
517562306a36Sopenharmony_ci		pm_runtime_dont_use_autosuspend(&pdev->dev);
517662306a36Sopenharmony_ci		if (!pm_runtime_suspended(&pdev->dev)) {
517762306a36Sopenharmony_ci			macb_clks_disable(bp->pclk, bp->hclk, bp->tx_clk,
517862306a36Sopenharmony_ci					  bp->rx_clk, bp->tsu_clk);
517962306a36Sopenharmony_ci			pm_runtime_set_suspended(&pdev->dev);
518062306a36Sopenharmony_ci		}
518162306a36Sopenharmony_ci		phylink_destroy(bp->phylink);
518262306a36Sopenharmony_ci		free_netdev(dev);
518362306a36Sopenharmony_ci	}
518462306a36Sopenharmony_ci
518562306a36Sopenharmony_ci	return 0;
518662306a36Sopenharmony_ci}
518762306a36Sopenharmony_ci
518862306a36Sopenharmony_cistatic int __maybe_unused macb_suspend(struct device *dev)
518962306a36Sopenharmony_ci{
519062306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
519162306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
519262306a36Sopenharmony_ci	struct macb_queue *queue;
519362306a36Sopenharmony_ci	unsigned long flags;
519462306a36Sopenharmony_ci	unsigned int q;
519562306a36Sopenharmony_ci	int err;
519662306a36Sopenharmony_ci
519762306a36Sopenharmony_ci	if (!device_may_wakeup(&bp->dev->dev))
519862306a36Sopenharmony_ci		phy_exit(bp->sgmii_phy);
519962306a36Sopenharmony_ci
520062306a36Sopenharmony_ci	if (!netif_running(netdev))
520162306a36Sopenharmony_ci		return 0;
520262306a36Sopenharmony_ci
520362306a36Sopenharmony_ci	if (bp->wol & MACB_WOL_ENABLED) {
520462306a36Sopenharmony_ci		spin_lock_irqsave(&bp->lock, flags);
520562306a36Sopenharmony_ci		/* Flush all status bits */
520662306a36Sopenharmony_ci		macb_writel(bp, TSR, -1);
520762306a36Sopenharmony_ci		macb_writel(bp, RSR, -1);
520862306a36Sopenharmony_ci		for (q = 0, queue = bp->queues; q < bp->num_queues;
520962306a36Sopenharmony_ci		     ++q, ++queue) {
521062306a36Sopenharmony_ci			/* Disable all interrupts */
521162306a36Sopenharmony_ci			queue_writel(queue, IDR, -1);
521262306a36Sopenharmony_ci			queue_readl(queue, ISR);
521362306a36Sopenharmony_ci			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
521462306a36Sopenharmony_ci				queue_writel(queue, ISR, -1);
521562306a36Sopenharmony_ci		}
521662306a36Sopenharmony_ci		/* Change interrupt handler and
521762306a36Sopenharmony_ci		 * Enable WoL IRQ on queue 0
521862306a36Sopenharmony_ci		 */
521962306a36Sopenharmony_ci		devm_free_irq(dev, bp->queues[0].irq, bp->queues);
522062306a36Sopenharmony_ci		if (macb_is_gem(bp)) {
522162306a36Sopenharmony_ci			err = devm_request_irq(dev, bp->queues[0].irq, gem_wol_interrupt,
522262306a36Sopenharmony_ci					       IRQF_SHARED, netdev->name, bp->queues);
522362306a36Sopenharmony_ci			if (err) {
522462306a36Sopenharmony_ci				dev_err(dev,
522562306a36Sopenharmony_ci					"Unable to request IRQ %d (error %d)\n",
522662306a36Sopenharmony_ci					bp->queues[0].irq, err);
522762306a36Sopenharmony_ci				spin_unlock_irqrestore(&bp->lock, flags);
522862306a36Sopenharmony_ci				return err;
522962306a36Sopenharmony_ci			}
523062306a36Sopenharmony_ci			queue_writel(bp->queues, IER, GEM_BIT(WOL));
523162306a36Sopenharmony_ci			gem_writel(bp, WOL, MACB_BIT(MAG));
523262306a36Sopenharmony_ci		} else {
523362306a36Sopenharmony_ci			err = devm_request_irq(dev, bp->queues[0].irq, macb_wol_interrupt,
523462306a36Sopenharmony_ci					       IRQF_SHARED, netdev->name, bp->queues);
523562306a36Sopenharmony_ci			if (err) {
523662306a36Sopenharmony_ci				dev_err(dev,
523762306a36Sopenharmony_ci					"Unable to request IRQ %d (error %d)\n",
523862306a36Sopenharmony_ci					bp->queues[0].irq, err);
523962306a36Sopenharmony_ci				spin_unlock_irqrestore(&bp->lock, flags);
524062306a36Sopenharmony_ci				return err;
524162306a36Sopenharmony_ci			}
524262306a36Sopenharmony_ci			queue_writel(bp->queues, IER, MACB_BIT(WOL));
524362306a36Sopenharmony_ci			macb_writel(bp, WOL, MACB_BIT(MAG));
524462306a36Sopenharmony_ci		}
524562306a36Sopenharmony_ci		spin_unlock_irqrestore(&bp->lock, flags);
524662306a36Sopenharmony_ci
524762306a36Sopenharmony_ci		enable_irq_wake(bp->queues[0].irq);
524862306a36Sopenharmony_ci	}
524962306a36Sopenharmony_ci
525062306a36Sopenharmony_ci	netif_device_detach(netdev);
525162306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues;
525262306a36Sopenharmony_ci	     ++q, ++queue) {
525362306a36Sopenharmony_ci		napi_disable(&queue->napi_rx);
525462306a36Sopenharmony_ci		napi_disable(&queue->napi_tx);
525562306a36Sopenharmony_ci	}
525662306a36Sopenharmony_ci
525762306a36Sopenharmony_ci	if (!(bp->wol & MACB_WOL_ENABLED)) {
525862306a36Sopenharmony_ci		rtnl_lock();
525962306a36Sopenharmony_ci		phylink_stop(bp->phylink);
526062306a36Sopenharmony_ci		rtnl_unlock();
526162306a36Sopenharmony_ci		spin_lock_irqsave(&bp->lock, flags);
526262306a36Sopenharmony_ci		macb_reset_hw(bp);
526362306a36Sopenharmony_ci		spin_unlock_irqrestore(&bp->lock, flags);
526462306a36Sopenharmony_ci	}
526562306a36Sopenharmony_ci
526662306a36Sopenharmony_ci	if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
526762306a36Sopenharmony_ci		bp->pm_data.usrio = macb_or_gem_readl(bp, USRIO);
526862306a36Sopenharmony_ci
526962306a36Sopenharmony_ci	if (netdev->hw_features & NETIF_F_NTUPLE)
527062306a36Sopenharmony_ci		bp->pm_data.scrt2 = gem_readl_n(bp, ETHT, SCRT2_ETHT);
527162306a36Sopenharmony_ci
527262306a36Sopenharmony_ci	if (bp->ptp_info)
527362306a36Sopenharmony_ci		bp->ptp_info->ptp_remove(netdev);
527462306a36Sopenharmony_ci	if (!device_may_wakeup(dev))
527562306a36Sopenharmony_ci		pm_runtime_force_suspend(dev);
527662306a36Sopenharmony_ci
527762306a36Sopenharmony_ci	return 0;
527862306a36Sopenharmony_ci}
527962306a36Sopenharmony_ci
528062306a36Sopenharmony_cistatic int __maybe_unused macb_resume(struct device *dev)
528162306a36Sopenharmony_ci{
528262306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
528362306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
528462306a36Sopenharmony_ci	struct macb_queue *queue;
528562306a36Sopenharmony_ci	unsigned long flags;
528662306a36Sopenharmony_ci	unsigned int q;
528762306a36Sopenharmony_ci	int err;
528862306a36Sopenharmony_ci
528962306a36Sopenharmony_ci	if (!device_may_wakeup(&bp->dev->dev))
529062306a36Sopenharmony_ci		phy_init(bp->sgmii_phy);
529162306a36Sopenharmony_ci
529262306a36Sopenharmony_ci	if (!netif_running(netdev))
529362306a36Sopenharmony_ci		return 0;
529462306a36Sopenharmony_ci
529562306a36Sopenharmony_ci	if (!device_may_wakeup(dev))
529662306a36Sopenharmony_ci		pm_runtime_force_resume(dev);
529762306a36Sopenharmony_ci
529862306a36Sopenharmony_ci	if (bp->wol & MACB_WOL_ENABLED) {
529962306a36Sopenharmony_ci		spin_lock_irqsave(&bp->lock, flags);
530062306a36Sopenharmony_ci		/* Disable WoL */
530162306a36Sopenharmony_ci		if (macb_is_gem(bp)) {
530262306a36Sopenharmony_ci			queue_writel(bp->queues, IDR, GEM_BIT(WOL));
530362306a36Sopenharmony_ci			gem_writel(bp, WOL, 0);
530462306a36Sopenharmony_ci		} else {
530562306a36Sopenharmony_ci			queue_writel(bp->queues, IDR, MACB_BIT(WOL));
530662306a36Sopenharmony_ci			macb_writel(bp, WOL, 0);
530762306a36Sopenharmony_ci		}
530862306a36Sopenharmony_ci		/* Clear ISR on queue 0 */
530962306a36Sopenharmony_ci		queue_readl(bp->queues, ISR);
531062306a36Sopenharmony_ci		if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
531162306a36Sopenharmony_ci			queue_writel(bp->queues, ISR, -1);
531262306a36Sopenharmony_ci		/* Replace interrupt handler on queue 0 */
531362306a36Sopenharmony_ci		devm_free_irq(dev, bp->queues[0].irq, bp->queues);
531462306a36Sopenharmony_ci		err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt,
531562306a36Sopenharmony_ci				       IRQF_SHARED, netdev->name, bp->queues);
531662306a36Sopenharmony_ci		if (err) {
531762306a36Sopenharmony_ci			dev_err(dev,
531862306a36Sopenharmony_ci				"Unable to request IRQ %d (error %d)\n",
531962306a36Sopenharmony_ci				bp->queues[0].irq, err);
532062306a36Sopenharmony_ci			spin_unlock_irqrestore(&bp->lock, flags);
532162306a36Sopenharmony_ci			return err;
532262306a36Sopenharmony_ci		}
532362306a36Sopenharmony_ci		spin_unlock_irqrestore(&bp->lock, flags);
532462306a36Sopenharmony_ci
532562306a36Sopenharmony_ci		disable_irq_wake(bp->queues[0].irq);
532662306a36Sopenharmony_ci
532762306a36Sopenharmony_ci		/* Now make sure we disable phy before moving
532862306a36Sopenharmony_ci		 * to common restore path
532962306a36Sopenharmony_ci		 */
533062306a36Sopenharmony_ci		rtnl_lock();
533162306a36Sopenharmony_ci		phylink_stop(bp->phylink);
533262306a36Sopenharmony_ci		rtnl_unlock();
533362306a36Sopenharmony_ci	}
533462306a36Sopenharmony_ci
533562306a36Sopenharmony_ci	for (q = 0, queue = bp->queues; q < bp->num_queues;
533662306a36Sopenharmony_ci	     ++q, ++queue) {
533762306a36Sopenharmony_ci		napi_enable(&queue->napi_rx);
533862306a36Sopenharmony_ci		napi_enable(&queue->napi_tx);
533962306a36Sopenharmony_ci	}
534062306a36Sopenharmony_ci
534162306a36Sopenharmony_ci	if (netdev->hw_features & NETIF_F_NTUPLE)
534262306a36Sopenharmony_ci		gem_writel_n(bp, ETHT, SCRT2_ETHT, bp->pm_data.scrt2);
534362306a36Sopenharmony_ci
534462306a36Sopenharmony_ci	if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
534562306a36Sopenharmony_ci		macb_or_gem_writel(bp, USRIO, bp->pm_data.usrio);
534662306a36Sopenharmony_ci
534762306a36Sopenharmony_ci	macb_writel(bp, NCR, MACB_BIT(MPE));
534862306a36Sopenharmony_ci	macb_init_hw(bp);
534962306a36Sopenharmony_ci	macb_set_rx_mode(netdev);
535062306a36Sopenharmony_ci	macb_restore_features(bp);
535162306a36Sopenharmony_ci	rtnl_lock();
535262306a36Sopenharmony_ci
535362306a36Sopenharmony_ci	phylink_start(bp->phylink);
535462306a36Sopenharmony_ci	rtnl_unlock();
535562306a36Sopenharmony_ci
535662306a36Sopenharmony_ci	netif_device_attach(netdev);
535762306a36Sopenharmony_ci	if (bp->ptp_info)
535862306a36Sopenharmony_ci		bp->ptp_info->ptp_init(netdev);
535962306a36Sopenharmony_ci
536062306a36Sopenharmony_ci	return 0;
536162306a36Sopenharmony_ci}
536262306a36Sopenharmony_ci
536362306a36Sopenharmony_cistatic int __maybe_unused macb_runtime_suspend(struct device *dev)
536462306a36Sopenharmony_ci{
536562306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
536662306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
536762306a36Sopenharmony_ci
536862306a36Sopenharmony_ci	if (!(device_may_wakeup(dev)))
536962306a36Sopenharmony_ci		macb_clks_disable(bp->pclk, bp->hclk, bp->tx_clk, bp->rx_clk, bp->tsu_clk);
537062306a36Sopenharmony_ci	else if (!(bp->caps & MACB_CAPS_NEED_TSUCLK))
537162306a36Sopenharmony_ci		macb_clks_disable(NULL, NULL, NULL, NULL, bp->tsu_clk);
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci	return 0;
537462306a36Sopenharmony_ci}
537562306a36Sopenharmony_ci
537662306a36Sopenharmony_cistatic int __maybe_unused macb_runtime_resume(struct device *dev)
537762306a36Sopenharmony_ci{
537862306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
537962306a36Sopenharmony_ci	struct macb *bp = netdev_priv(netdev);
538062306a36Sopenharmony_ci
538162306a36Sopenharmony_ci	if (!(device_may_wakeup(dev))) {
538262306a36Sopenharmony_ci		clk_prepare_enable(bp->pclk);
538362306a36Sopenharmony_ci		clk_prepare_enable(bp->hclk);
538462306a36Sopenharmony_ci		clk_prepare_enable(bp->tx_clk);
538562306a36Sopenharmony_ci		clk_prepare_enable(bp->rx_clk);
538662306a36Sopenharmony_ci		clk_prepare_enable(bp->tsu_clk);
538762306a36Sopenharmony_ci	} else if (!(bp->caps & MACB_CAPS_NEED_TSUCLK)) {
538862306a36Sopenharmony_ci		clk_prepare_enable(bp->tsu_clk);
538962306a36Sopenharmony_ci	}
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci	return 0;
539262306a36Sopenharmony_ci}
539362306a36Sopenharmony_ci
539462306a36Sopenharmony_cistatic const struct dev_pm_ops macb_pm_ops = {
539562306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(macb_suspend, macb_resume)
539662306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(macb_runtime_suspend, macb_runtime_resume, NULL)
539762306a36Sopenharmony_ci};
539862306a36Sopenharmony_ci
539962306a36Sopenharmony_cistatic struct platform_driver macb_driver = {
540062306a36Sopenharmony_ci	.probe		= macb_probe,
540162306a36Sopenharmony_ci	.remove		= macb_remove,
540262306a36Sopenharmony_ci	.driver		= {
540362306a36Sopenharmony_ci		.name		= "macb",
540462306a36Sopenharmony_ci		.of_match_table	= of_match_ptr(macb_dt_ids),
540562306a36Sopenharmony_ci		.pm	= &macb_pm_ops,
540662306a36Sopenharmony_ci	},
540762306a36Sopenharmony_ci};
540862306a36Sopenharmony_ci
540962306a36Sopenharmony_cimodule_platform_driver(macb_driver);
541062306a36Sopenharmony_ci
541162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
541262306a36Sopenharmony_ciMODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver");
541362306a36Sopenharmony_ciMODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
541462306a36Sopenharmony_ciMODULE_ALIAS("platform:macb");
5415