162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*  Atheros AR71xx built-in ethernet mac driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 2019 Oleksij Rempel <o.rempel@pengutronix.de>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  List of authors contributed to this driver before mainlining:
762306a36Sopenharmony_ci *  Alexander Couzens <lynxis@fe80.eu>
862306a36Sopenharmony_ci *  Christian Lamparter <chunkeey@gmail.com>
962306a36Sopenharmony_ci *  Chuanhong Guo <gch981213@gmail.com>
1062306a36Sopenharmony_ci *  Daniel F. Dickinson <cshored@thecshore.com>
1162306a36Sopenharmony_ci *  David Bauer <mail@david-bauer.net>
1262306a36Sopenharmony_ci *  Felix Fietkau <nbd@nbd.name>
1362306a36Sopenharmony_ci *  Gabor Juhos <juhosg@freemail.hu>
1462306a36Sopenharmony_ci *  Hauke Mehrtens <hauke@hauke-m.de>
1562306a36Sopenharmony_ci *  Johann Neuhauser <johann@it-neuhauser.de>
1662306a36Sopenharmony_ci *  John Crispin <john@phrozen.org>
1762306a36Sopenharmony_ci *  Jo-Philipp Wich <jo@mein.io>
1862306a36Sopenharmony_ci *  Koen Vandeputte <koen.vandeputte@ncentric.com>
1962306a36Sopenharmony_ci *  Lucian Cristian <lucian.cristian@gmail.com>
2062306a36Sopenharmony_ci *  Matt Merhar <mattmerhar@protonmail.com>
2162306a36Sopenharmony_ci *  Milan Krstic <milan.krstic@gmail.com>
2262306a36Sopenharmony_ci *  Petr Štetiar <ynezz@true.cz>
2362306a36Sopenharmony_ci *  Rosen Penev <rosenp@gmail.com>
2462306a36Sopenharmony_ci *  Stephen Walker <stephendwalker+github@gmail.com>
2562306a36Sopenharmony_ci *  Vittorio Gambaletta <openwrt@vittgam.net>
2662306a36Sopenharmony_ci *  Weijie Gao <hackpascal@gmail.com>
2762306a36Sopenharmony_ci *  Imre Kaloz <kaloz@openwrt.org>
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/if_vlan.h>
3162306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
3262306a36Sopenharmony_ci#include <linux/of.h>
3362306a36Sopenharmony_ci#include <linux/of_mdio.h>
3462306a36Sopenharmony_ci#include <linux/of_net.h>
3562306a36Sopenharmony_ci#include <linux/platform_device.h>
3662306a36Sopenharmony_ci#include <linux/phylink.h>
3762306a36Sopenharmony_ci#include <linux/regmap.h>
3862306a36Sopenharmony_ci#include <linux/reset.h>
3962306a36Sopenharmony_ci#include <linux/clk.h>
4062306a36Sopenharmony_ci#include <linux/io.h>
4162306a36Sopenharmony_ci#include <net/selftests.h>
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* For our NAPI weight bigger does *NOT* mean better - it means more
4462306a36Sopenharmony_ci * D-cache misses and lots more wasted cycles than we'll ever
4562306a36Sopenharmony_ci * possibly gain from saving instructions.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci#define AG71XX_NAPI_WEIGHT	32
4862306a36Sopenharmony_ci#define AG71XX_OOM_REFILL	(1 + HZ / 10)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define AG71XX_INT_ERR	(AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
5162306a36Sopenharmony_ci#define AG71XX_INT_TX	(AG71XX_INT_TX_PS)
5262306a36Sopenharmony_ci#define AG71XX_INT_RX	(AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define AG71XX_INT_POLL	(AG71XX_INT_RX | AG71XX_INT_TX)
5562306a36Sopenharmony_ci#define AG71XX_INT_INIT	(AG71XX_INT_ERR | AG71XX_INT_POLL)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define AG71XX_TX_MTU_LEN	1540
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define AG71XX_TX_RING_SPLIT		512
6062306a36Sopenharmony_ci#define AG71XX_TX_RING_DS_PER_PKT	DIV_ROUND_UP(AG71XX_TX_MTU_LEN, \
6162306a36Sopenharmony_ci						     AG71XX_TX_RING_SPLIT)
6262306a36Sopenharmony_ci#define AG71XX_TX_RING_SIZE_DEFAULT	128
6362306a36Sopenharmony_ci#define AG71XX_RX_RING_SIZE_DEFAULT	256
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define AG71XX_MDIO_RETRY	1000
6662306a36Sopenharmony_ci#define AG71XX_MDIO_DELAY	5
6762306a36Sopenharmony_ci#define AG71XX_MDIO_MAX_CLK	5000000
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* Register offsets */
7062306a36Sopenharmony_ci#define AG71XX_REG_MAC_CFG1	0x0000
7162306a36Sopenharmony_ci#define MAC_CFG1_TXE		BIT(0)	/* Tx Enable */
7262306a36Sopenharmony_ci#define MAC_CFG1_STX		BIT(1)	/* Synchronize Tx Enable */
7362306a36Sopenharmony_ci#define MAC_CFG1_RXE		BIT(2)	/* Rx Enable */
7462306a36Sopenharmony_ci#define MAC_CFG1_SRX		BIT(3)	/* Synchronize Rx Enable */
7562306a36Sopenharmony_ci#define MAC_CFG1_TFC		BIT(4)	/* Tx Flow Control Enable */
7662306a36Sopenharmony_ci#define MAC_CFG1_RFC		BIT(5)	/* Rx Flow Control Enable */
7762306a36Sopenharmony_ci#define MAC_CFG1_SR		BIT(31)	/* Soft Reset */
7862306a36Sopenharmony_ci#define MAC_CFG1_INIT	(MAC_CFG1_RXE | MAC_CFG1_TXE | \
7962306a36Sopenharmony_ci			 MAC_CFG1_SRX | MAC_CFG1_STX)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define AG71XX_REG_MAC_CFG2	0x0004
8262306a36Sopenharmony_ci#define MAC_CFG2_FDX		BIT(0)
8362306a36Sopenharmony_ci#define MAC_CFG2_PAD_CRC_EN	BIT(2)
8462306a36Sopenharmony_ci#define MAC_CFG2_LEN_CHECK	BIT(4)
8562306a36Sopenharmony_ci#define MAC_CFG2_IF_1000	BIT(9)
8662306a36Sopenharmony_ci#define MAC_CFG2_IF_10_100	BIT(8)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define AG71XX_REG_MAC_MFL	0x0010
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define AG71XX_REG_MII_CFG	0x0020
9162306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_4	0
9262306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_6	2
9362306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_8	3
9462306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_10	4
9562306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_14	5
9662306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_20	6
9762306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_28	7
9862306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_34	8
9962306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_42	9
10062306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_50	10
10162306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_58	11
10262306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_66	12
10362306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_74	13
10462306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_82	14
10562306a36Sopenharmony_ci#define MII_CFG_CLK_DIV_98	15
10662306a36Sopenharmony_ci#define MII_CFG_RESET		BIT(31)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define AG71XX_REG_MII_CMD	0x0024
10962306a36Sopenharmony_ci#define MII_CMD_READ		BIT(0)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define AG71XX_REG_MII_ADDR	0x0028
11262306a36Sopenharmony_ci#define MII_ADDR_SHIFT		8
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define AG71XX_REG_MII_CTRL	0x002c
11562306a36Sopenharmony_ci#define AG71XX_REG_MII_STATUS	0x0030
11662306a36Sopenharmony_ci#define AG71XX_REG_MII_IND	0x0034
11762306a36Sopenharmony_ci#define MII_IND_BUSY		BIT(0)
11862306a36Sopenharmony_ci#define MII_IND_INVALID		BIT(2)
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define AG71XX_REG_MAC_IFCTL	0x0038
12162306a36Sopenharmony_ci#define MAC_IFCTL_SPEED		BIT(16)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define AG71XX_REG_MAC_ADDR1	0x0040
12462306a36Sopenharmony_ci#define AG71XX_REG_MAC_ADDR2	0x0044
12562306a36Sopenharmony_ci#define AG71XX_REG_FIFO_CFG0	0x0048
12662306a36Sopenharmony_ci#define FIFO_CFG0_WTM		BIT(0)	/* Watermark Module */
12762306a36Sopenharmony_ci#define FIFO_CFG0_RXS		BIT(1)	/* Rx System Module */
12862306a36Sopenharmony_ci#define FIFO_CFG0_RXF		BIT(2)	/* Rx Fabric Module */
12962306a36Sopenharmony_ci#define FIFO_CFG0_TXS		BIT(3)	/* Tx System Module */
13062306a36Sopenharmony_ci#define FIFO_CFG0_TXF		BIT(4)	/* Tx Fabric Module */
13162306a36Sopenharmony_ci#define FIFO_CFG0_ALL	(FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
13262306a36Sopenharmony_ci			| FIFO_CFG0_TXS | FIFO_CFG0_TXF)
13362306a36Sopenharmony_ci#define FIFO_CFG0_INIT	(FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define FIFO_CFG0_ENABLE_SHIFT	8
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define AG71XX_REG_FIFO_CFG1	0x004c
13862306a36Sopenharmony_ci#define AG71XX_REG_FIFO_CFG2	0x0050
13962306a36Sopenharmony_ci#define AG71XX_REG_FIFO_CFG3	0x0054
14062306a36Sopenharmony_ci#define AG71XX_REG_FIFO_CFG4	0x0058
14162306a36Sopenharmony_ci#define FIFO_CFG4_DE		BIT(0)	/* Drop Event */
14262306a36Sopenharmony_ci#define FIFO_CFG4_DV		BIT(1)	/* RX_DV Event */
14362306a36Sopenharmony_ci#define FIFO_CFG4_FC		BIT(2)	/* False Carrier */
14462306a36Sopenharmony_ci#define FIFO_CFG4_CE		BIT(3)	/* Code Error */
14562306a36Sopenharmony_ci#define FIFO_CFG4_CR		BIT(4)	/* CRC error */
14662306a36Sopenharmony_ci#define FIFO_CFG4_LM		BIT(5)	/* Length Mismatch */
14762306a36Sopenharmony_ci#define FIFO_CFG4_LO		BIT(6)	/* Length out of range */
14862306a36Sopenharmony_ci#define FIFO_CFG4_OK		BIT(7)	/* Packet is OK */
14962306a36Sopenharmony_ci#define FIFO_CFG4_MC		BIT(8)	/* Multicast Packet */
15062306a36Sopenharmony_ci#define FIFO_CFG4_BC		BIT(9)	/* Broadcast Packet */
15162306a36Sopenharmony_ci#define FIFO_CFG4_DR		BIT(10)	/* Dribble */
15262306a36Sopenharmony_ci#define FIFO_CFG4_LE		BIT(11)	/* Long Event */
15362306a36Sopenharmony_ci#define FIFO_CFG4_CF		BIT(12)	/* Control Frame */
15462306a36Sopenharmony_ci#define FIFO_CFG4_PF		BIT(13)	/* Pause Frame */
15562306a36Sopenharmony_ci#define FIFO_CFG4_UO		BIT(14)	/* Unsupported Opcode */
15662306a36Sopenharmony_ci#define FIFO_CFG4_VT		BIT(15)	/* VLAN tag detected */
15762306a36Sopenharmony_ci#define FIFO_CFG4_FT		BIT(16)	/* Frame Truncated */
15862306a36Sopenharmony_ci#define FIFO_CFG4_UC		BIT(17)	/* Unicast Packet */
15962306a36Sopenharmony_ci#define FIFO_CFG4_INIT	(FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \
16062306a36Sopenharmony_ci			 FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \
16162306a36Sopenharmony_ci			 FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \
16262306a36Sopenharmony_ci			 FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \
16362306a36Sopenharmony_ci			 FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \
16462306a36Sopenharmony_ci			 FIFO_CFG4_VT)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define AG71XX_REG_FIFO_CFG5	0x005c
16762306a36Sopenharmony_ci#define FIFO_CFG5_DE		BIT(0)	/* Drop Event */
16862306a36Sopenharmony_ci#define FIFO_CFG5_DV		BIT(1)	/* RX_DV Event */
16962306a36Sopenharmony_ci#define FIFO_CFG5_FC		BIT(2)	/* False Carrier */
17062306a36Sopenharmony_ci#define FIFO_CFG5_CE		BIT(3)	/* Code Error */
17162306a36Sopenharmony_ci#define FIFO_CFG5_LM		BIT(4)	/* Length Mismatch */
17262306a36Sopenharmony_ci#define FIFO_CFG5_LO		BIT(5)	/* Length Out of Range */
17362306a36Sopenharmony_ci#define FIFO_CFG5_OK		BIT(6)	/* Packet is OK */
17462306a36Sopenharmony_ci#define FIFO_CFG5_MC		BIT(7)	/* Multicast Packet */
17562306a36Sopenharmony_ci#define FIFO_CFG5_BC		BIT(8)	/* Broadcast Packet */
17662306a36Sopenharmony_ci#define FIFO_CFG5_DR		BIT(9)	/* Dribble */
17762306a36Sopenharmony_ci#define FIFO_CFG5_CF		BIT(10)	/* Control Frame */
17862306a36Sopenharmony_ci#define FIFO_CFG5_PF		BIT(11)	/* Pause Frame */
17962306a36Sopenharmony_ci#define FIFO_CFG5_UO		BIT(12)	/* Unsupported Opcode */
18062306a36Sopenharmony_ci#define FIFO_CFG5_VT		BIT(13)	/* VLAN tag detected */
18162306a36Sopenharmony_ci#define FIFO_CFG5_LE		BIT(14)	/* Long Event */
18262306a36Sopenharmony_ci#define FIFO_CFG5_FT		BIT(15)	/* Frame Truncated */
18362306a36Sopenharmony_ci#define FIFO_CFG5_16		BIT(16)	/* unknown */
18462306a36Sopenharmony_ci#define FIFO_CFG5_17		BIT(17)	/* unknown */
18562306a36Sopenharmony_ci#define FIFO_CFG5_SF		BIT(18)	/* Short Frame */
18662306a36Sopenharmony_ci#define FIFO_CFG5_BM		BIT(19)	/* Byte Mode */
18762306a36Sopenharmony_ci#define FIFO_CFG5_INIT	(FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \
18862306a36Sopenharmony_ci			 FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \
18962306a36Sopenharmony_ci			 FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \
19062306a36Sopenharmony_ci			 FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \
19162306a36Sopenharmony_ci			 FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
19262306a36Sopenharmony_ci			 FIFO_CFG5_17 | FIFO_CFG5_SF)
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci#define AG71XX_REG_TX_CTRL	0x0180
19562306a36Sopenharmony_ci#define TX_CTRL_TXE		BIT(0)	/* Tx Enable */
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci#define AG71XX_REG_TX_DESC	0x0184
19862306a36Sopenharmony_ci#define AG71XX_REG_TX_STATUS	0x0188
19962306a36Sopenharmony_ci#define TX_STATUS_PS		BIT(0)	/* Packet Sent */
20062306a36Sopenharmony_ci#define TX_STATUS_UR		BIT(1)	/* Tx Underrun */
20162306a36Sopenharmony_ci#define TX_STATUS_BE		BIT(3)	/* Bus Error */
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci#define AG71XX_REG_RX_CTRL	0x018c
20462306a36Sopenharmony_ci#define RX_CTRL_RXE		BIT(0)	/* Rx Enable */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#define AG71XX_DMA_RETRY	10
20762306a36Sopenharmony_ci#define AG71XX_DMA_DELAY	1
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define AG71XX_REG_RX_DESC	0x0190
21062306a36Sopenharmony_ci#define AG71XX_REG_RX_STATUS	0x0194
21162306a36Sopenharmony_ci#define RX_STATUS_PR		BIT(0)	/* Packet Received */
21262306a36Sopenharmony_ci#define RX_STATUS_OF		BIT(2)	/* Rx Overflow */
21362306a36Sopenharmony_ci#define RX_STATUS_BE		BIT(3)	/* Bus Error */
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#define AG71XX_REG_INT_ENABLE	0x0198
21662306a36Sopenharmony_ci#define AG71XX_REG_INT_STATUS	0x019c
21762306a36Sopenharmony_ci#define AG71XX_INT_TX_PS	BIT(0)
21862306a36Sopenharmony_ci#define AG71XX_INT_TX_UR	BIT(1)
21962306a36Sopenharmony_ci#define AG71XX_INT_TX_BE	BIT(3)
22062306a36Sopenharmony_ci#define AG71XX_INT_RX_PR	BIT(4)
22162306a36Sopenharmony_ci#define AG71XX_INT_RX_OF	BIT(6)
22262306a36Sopenharmony_ci#define AG71XX_INT_RX_BE	BIT(7)
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci#define AG71XX_REG_FIFO_DEPTH	0x01a8
22562306a36Sopenharmony_ci#define AG71XX_REG_RX_SM	0x01b0
22662306a36Sopenharmony_ci#define AG71XX_REG_TX_SM	0x01b4
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define AG71XX_DEFAULT_MSG_ENABLE	\
22962306a36Sopenharmony_ci	(NETIF_MSG_DRV			\
23062306a36Sopenharmony_ci	| NETIF_MSG_PROBE		\
23162306a36Sopenharmony_ci	| NETIF_MSG_LINK		\
23262306a36Sopenharmony_ci	| NETIF_MSG_TIMER		\
23362306a36Sopenharmony_ci	| NETIF_MSG_IFDOWN		\
23462306a36Sopenharmony_ci	| NETIF_MSG_IFUP		\
23562306a36Sopenharmony_ci	| NETIF_MSG_RX_ERR		\
23662306a36Sopenharmony_ci	| NETIF_MSG_TX_ERR)
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistruct ag71xx_statistic {
23962306a36Sopenharmony_ci	unsigned short offset;
24062306a36Sopenharmony_ci	u32 mask;
24162306a36Sopenharmony_ci	const char name[ETH_GSTRING_LEN];
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic const struct ag71xx_statistic ag71xx_statistics[] = {
24562306a36Sopenharmony_ci	{ 0x0080, GENMASK(17, 0), "Tx/Rx 64 Byte", },
24662306a36Sopenharmony_ci	{ 0x0084, GENMASK(17, 0), "Tx/Rx 65-127 Byte", },
24762306a36Sopenharmony_ci	{ 0x0088, GENMASK(17, 0), "Tx/Rx 128-255 Byte", },
24862306a36Sopenharmony_ci	{ 0x008C, GENMASK(17, 0), "Tx/Rx 256-511 Byte", },
24962306a36Sopenharmony_ci	{ 0x0090, GENMASK(17, 0), "Tx/Rx 512-1023 Byte", },
25062306a36Sopenharmony_ci	{ 0x0094, GENMASK(17, 0), "Tx/Rx 1024-1518 Byte", },
25162306a36Sopenharmony_ci	{ 0x0098, GENMASK(17, 0), "Tx/Rx 1519-1522 Byte VLAN", },
25262306a36Sopenharmony_ci	{ 0x009C, GENMASK(23, 0), "Rx Byte", },
25362306a36Sopenharmony_ci	{ 0x00A0, GENMASK(17, 0), "Rx Packet", },
25462306a36Sopenharmony_ci	{ 0x00A4, GENMASK(11, 0), "Rx FCS Error", },
25562306a36Sopenharmony_ci	{ 0x00A8, GENMASK(17, 0), "Rx Multicast Packet", },
25662306a36Sopenharmony_ci	{ 0x00AC, GENMASK(21, 0), "Rx Broadcast Packet", },
25762306a36Sopenharmony_ci	{ 0x00B0, GENMASK(17, 0), "Rx Control Frame Packet", },
25862306a36Sopenharmony_ci	{ 0x00B4, GENMASK(11, 0), "Rx Pause Frame Packet", },
25962306a36Sopenharmony_ci	{ 0x00B8, GENMASK(11, 0), "Rx Unknown OPCode Packet", },
26062306a36Sopenharmony_ci	{ 0x00BC, GENMASK(11, 0), "Rx Alignment Error", },
26162306a36Sopenharmony_ci	{ 0x00C0, GENMASK(15, 0), "Rx Frame Length Error", },
26262306a36Sopenharmony_ci	{ 0x00C4, GENMASK(11, 0), "Rx Code Error", },
26362306a36Sopenharmony_ci	{ 0x00C8, GENMASK(11, 0), "Rx Carrier Sense Error", },
26462306a36Sopenharmony_ci	{ 0x00CC, GENMASK(11, 0), "Rx Undersize Packet", },
26562306a36Sopenharmony_ci	{ 0x00D0, GENMASK(11, 0), "Rx Oversize Packet", },
26662306a36Sopenharmony_ci	{ 0x00D4, GENMASK(11, 0), "Rx Fragments", },
26762306a36Sopenharmony_ci	{ 0x00D8, GENMASK(11, 0), "Rx Jabber", },
26862306a36Sopenharmony_ci	{ 0x00DC, GENMASK(11, 0), "Rx Dropped Packet", },
26962306a36Sopenharmony_ci	{ 0x00E0, GENMASK(23, 0), "Tx Byte", },
27062306a36Sopenharmony_ci	{ 0x00E4, GENMASK(17, 0), "Tx Packet", },
27162306a36Sopenharmony_ci	{ 0x00E8, GENMASK(17, 0), "Tx Multicast Packet", },
27262306a36Sopenharmony_ci	{ 0x00EC, GENMASK(17, 0), "Tx Broadcast Packet", },
27362306a36Sopenharmony_ci	{ 0x00F0, GENMASK(11, 0), "Tx Pause Control Frame", },
27462306a36Sopenharmony_ci	{ 0x00F4, GENMASK(11, 0), "Tx Deferral Packet", },
27562306a36Sopenharmony_ci	{ 0x00F8, GENMASK(11, 0), "Tx Excessive Deferral Packet", },
27662306a36Sopenharmony_ci	{ 0x00FC, GENMASK(11, 0), "Tx Single Collision Packet", },
27762306a36Sopenharmony_ci	{ 0x0100, GENMASK(11, 0), "Tx Multiple Collision", },
27862306a36Sopenharmony_ci	{ 0x0104, GENMASK(11, 0), "Tx Late Collision Packet", },
27962306a36Sopenharmony_ci	{ 0x0108, GENMASK(11, 0), "Tx Excessive Collision Packet", },
28062306a36Sopenharmony_ci	{ 0x010C, GENMASK(12, 0), "Tx Total Collision", },
28162306a36Sopenharmony_ci	{ 0x0110, GENMASK(11, 0), "Tx Pause Frames Honored", },
28262306a36Sopenharmony_ci	{ 0x0114, GENMASK(11, 0), "Tx Drop Frame", },
28362306a36Sopenharmony_ci	{ 0x0118, GENMASK(11, 0), "Tx Jabber Frame", },
28462306a36Sopenharmony_ci	{ 0x011C, GENMASK(11, 0), "Tx FCS Error", },
28562306a36Sopenharmony_ci	{ 0x0120, GENMASK(11, 0), "Tx Control Frame", },
28662306a36Sopenharmony_ci	{ 0x0124, GENMASK(11, 0), "Tx Oversize Frame", },
28762306a36Sopenharmony_ci	{ 0x0128, GENMASK(11, 0), "Tx Undersize Frame", },
28862306a36Sopenharmony_ci	{ 0x012C, GENMASK(11, 0), "Tx Fragment", },
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci#define DESC_EMPTY		BIT(31)
29262306a36Sopenharmony_ci#define DESC_MORE		BIT(24)
29362306a36Sopenharmony_ci#define DESC_PKTLEN_M		0xfff
29462306a36Sopenharmony_cistruct ag71xx_desc {
29562306a36Sopenharmony_ci	u32 data;
29662306a36Sopenharmony_ci	u32 ctrl;
29762306a36Sopenharmony_ci	u32 next;
29862306a36Sopenharmony_ci	u32 pad;
29962306a36Sopenharmony_ci} __aligned(4);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci#define AG71XX_DESC_SIZE	roundup(sizeof(struct ag71xx_desc), \
30262306a36Sopenharmony_ci					L1_CACHE_BYTES)
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistruct ag71xx_buf {
30562306a36Sopenharmony_ci	union {
30662306a36Sopenharmony_ci		struct {
30762306a36Sopenharmony_ci			struct sk_buff *skb;
30862306a36Sopenharmony_ci			unsigned int len;
30962306a36Sopenharmony_ci		} tx;
31062306a36Sopenharmony_ci		struct {
31162306a36Sopenharmony_ci			dma_addr_t dma_addr;
31262306a36Sopenharmony_ci			void *rx_buf;
31362306a36Sopenharmony_ci		} rx;
31462306a36Sopenharmony_ci	};
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistruct ag71xx_ring {
31862306a36Sopenharmony_ci	/* "Hot" fields in the data path. */
31962306a36Sopenharmony_ci	unsigned int curr;
32062306a36Sopenharmony_ci	unsigned int dirty;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* "Cold" fields - not used in the data path. */
32362306a36Sopenharmony_ci	struct ag71xx_buf *buf;
32462306a36Sopenharmony_ci	u16 order;
32562306a36Sopenharmony_ci	u16 desc_split;
32662306a36Sopenharmony_ci	dma_addr_t descs_dma;
32762306a36Sopenharmony_ci	u8 *descs_cpu;
32862306a36Sopenharmony_ci};
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cienum ag71xx_type {
33162306a36Sopenharmony_ci	AR7100,
33262306a36Sopenharmony_ci	AR7240,
33362306a36Sopenharmony_ci	AR9130,
33462306a36Sopenharmony_ci	AR9330,
33562306a36Sopenharmony_ci	AR9340,
33662306a36Sopenharmony_ci	QCA9530,
33762306a36Sopenharmony_ci	QCA9550,
33862306a36Sopenharmony_ci};
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistruct ag71xx_dcfg {
34162306a36Sopenharmony_ci	u32 max_frame_len;
34262306a36Sopenharmony_ci	const u32 *fifodata;
34362306a36Sopenharmony_ci	u16 desc_pktlen_mask;
34462306a36Sopenharmony_ci	bool tx_hang_workaround;
34562306a36Sopenharmony_ci	enum ag71xx_type type;
34662306a36Sopenharmony_ci};
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistruct ag71xx {
34962306a36Sopenharmony_ci	/* Critical data related to the per-packet data path are clustered
35062306a36Sopenharmony_ci	 * early in this structure to help improve the D-cache footprint.
35162306a36Sopenharmony_ci	 */
35262306a36Sopenharmony_ci	struct ag71xx_ring rx_ring ____cacheline_aligned;
35362306a36Sopenharmony_ci	struct ag71xx_ring tx_ring ____cacheline_aligned;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	u16 rx_buf_size;
35662306a36Sopenharmony_ci	u8 rx_buf_offset;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	struct net_device *ndev;
35962306a36Sopenharmony_ci	struct platform_device *pdev;
36062306a36Sopenharmony_ci	struct napi_struct napi;
36162306a36Sopenharmony_ci	u32 msg_enable;
36262306a36Sopenharmony_ci	const struct ag71xx_dcfg *dcfg;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* From this point onwards we're not looking at per-packet fields. */
36562306a36Sopenharmony_ci	void __iomem *mac_base;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	struct ag71xx_desc *stop_desc;
36862306a36Sopenharmony_ci	dma_addr_t stop_desc_dma;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	phy_interface_t phy_if_mode;
37162306a36Sopenharmony_ci	struct phylink *phylink;
37262306a36Sopenharmony_ci	struct phylink_config phylink_config;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	struct delayed_work restart_work;
37562306a36Sopenharmony_ci	struct timer_list oom_timer;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	struct reset_control *mac_reset;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	u32 fifodata[3];
38062306a36Sopenharmony_ci	int mac_idx;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	struct reset_control *mdio_reset;
38362306a36Sopenharmony_ci	struct mii_bus *mii_bus;
38462306a36Sopenharmony_ci	struct clk *clk_mdio;
38562306a36Sopenharmony_ci	struct clk *clk_eth;
38662306a36Sopenharmony_ci};
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic int ag71xx_desc_empty(struct ag71xx_desc *desc)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	return (desc->ctrl & DESC_EMPTY) != 0;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic struct ag71xx_desc *ag71xx_ring_desc(struct ag71xx_ring *ring, int idx)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	return (struct ag71xx_desc *)&ring->descs_cpu[idx * AG71XX_DESC_SIZE];
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int ag71xx_ring_size_order(int size)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	return fls(size - 1);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic bool ag71xx_is(struct ag71xx *ag, enum ag71xx_type type)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	return ag->dcfg->type == type;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void ag71xx_wr(struct ag71xx *ag, unsigned int reg, u32 value)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	iowrite32(value, ag->mac_base + reg);
41162306a36Sopenharmony_ci	/* flush write */
41262306a36Sopenharmony_ci	(void)ioread32(ag->mac_base + reg);
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic u32 ag71xx_rr(struct ag71xx *ag, unsigned int reg)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	return ioread32(ag->mac_base + reg);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic void ag71xx_sb(struct ag71xx *ag, unsigned int reg, u32 mask)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	void __iomem *r;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	r = ag->mac_base + reg;
42562306a36Sopenharmony_ci	iowrite32(ioread32(r) | mask, r);
42662306a36Sopenharmony_ci	/* flush write */
42762306a36Sopenharmony_ci	(void)ioread32(r);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void ag71xx_cb(struct ag71xx *ag, unsigned int reg, u32 mask)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	void __iomem *r;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	r = ag->mac_base + reg;
43562306a36Sopenharmony_ci	iowrite32(ioread32(r) & ~mask, r);
43662306a36Sopenharmony_ci	/* flush write */
43762306a36Sopenharmony_ci	(void)ioread32(r);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void ag71xx_get_drvinfo(struct net_device *ndev,
45162306a36Sopenharmony_ci			       struct ethtool_drvinfo *info)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	strscpy(info->driver, "ag71xx", sizeof(info->driver));
45662306a36Sopenharmony_ci	strscpy(info->bus_info, of_node_full_name(ag->pdev->dev.of_node),
45762306a36Sopenharmony_ci		sizeof(info->bus_info));
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic int ag71xx_get_link_ksettings(struct net_device *ndev,
46162306a36Sopenharmony_ci				   struct ethtool_link_ksettings *kset)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	return phylink_ethtool_ksettings_get(ag->phylink, kset);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic int ag71xx_set_link_ksettings(struct net_device *ndev,
46962306a36Sopenharmony_ci				   const struct ethtool_link_ksettings *kset)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	return phylink_ethtool_ksettings_set(ag->phylink, kset);
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int ag71xx_ethtool_nway_reset(struct net_device *ndev)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return phylink_ethtool_nway_reset(ag->phylink);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic void ag71xx_ethtool_get_pauseparam(struct net_device *ndev,
48462306a36Sopenharmony_ci					  struct ethtool_pauseparam *pause)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	phylink_ethtool_get_pauseparam(ag->phylink, pause);
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic int ag71xx_ethtool_set_pauseparam(struct net_device *ndev,
49262306a36Sopenharmony_ci					 struct ethtool_pauseparam *pause)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return phylink_ethtool_set_pauseparam(ag->phylink, pause);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic void ag71xx_ethtool_get_strings(struct net_device *netdev, u32 sset,
50062306a36Sopenharmony_ci				       u8 *data)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	int i;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	switch (sset) {
50562306a36Sopenharmony_ci	case ETH_SS_STATS:
50662306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ag71xx_statistics); i++)
50762306a36Sopenharmony_ci			memcpy(data + i * ETH_GSTRING_LEN,
50862306a36Sopenharmony_ci			       ag71xx_statistics[i].name, ETH_GSTRING_LEN);
50962306a36Sopenharmony_ci		break;
51062306a36Sopenharmony_ci	case ETH_SS_TEST:
51162306a36Sopenharmony_ci		net_selftest_get_strings(data);
51262306a36Sopenharmony_ci		break;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic void ag71xx_ethtool_get_stats(struct net_device *ndev,
51762306a36Sopenharmony_ci				     struct ethtool_stats *stats, u64 *data)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
52062306a36Sopenharmony_ci	int i;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ag71xx_statistics); i++)
52362306a36Sopenharmony_ci		*data++ = ag71xx_rr(ag, ag71xx_statistics[i].offset)
52462306a36Sopenharmony_ci				& ag71xx_statistics[i].mask;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic int ag71xx_ethtool_get_sset_count(struct net_device *ndev, int sset)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	switch (sset) {
53062306a36Sopenharmony_ci	case ETH_SS_STATS:
53162306a36Sopenharmony_ci		return ARRAY_SIZE(ag71xx_statistics);
53262306a36Sopenharmony_ci	case ETH_SS_TEST:
53362306a36Sopenharmony_ci		return net_selftest_get_count();
53462306a36Sopenharmony_ci	default:
53562306a36Sopenharmony_ci		return -EOPNOTSUPP;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic const struct ethtool_ops ag71xx_ethtool_ops = {
54062306a36Sopenharmony_ci	.get_drvinfo			= ag71xx_get_drvinfo,
54162306a36Sopenharmony_ci	.get_link			= ethtool_op_get_link,
54262306a36Sopenharmony_ci	.get_ts_info			= ethtool_op_get_ts_info,
54362306a36Sopenharmony_ci	.get_link_ksettings		= ag71xx_get_link_ksettings,
54462306a36Sopenharmony_ci	.set_link_ksettings		= ag71xx_set_link_ksettings,
54562306a36Sopenharmony_ci	.nway_reset			= ag71xx_ethtool_nway_reset,
54662306a36Sopenharmony_ci	.get_pauseparam			= ag71xx_ethtool_get_pauseparam,
54762306a36Sopenharmony_ci	.set_pauseparam			= ag71xx_ethtool_set_pauseparam,
54862306a36Sopenharmony_ci	.get_strings			= ag71xx_ethtool_get_strings,
54962306a36Sopenharmony_ci	.get_ethtool_stats		= ag71xx_ethtool_get_stats,
55062306a36Sopenharmony_ci	.get_sset_count			= ag71xx_ethtool_get_sset_count,
55162306a36Sopenharmony_ci	.self_test			= net_selftest,
55262306a36Sopenharmony_ci};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic int ag71xx_mdio_wait_busy(struct ag71xx *ag)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
55762306a36Sopenharmony_ci	int i;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	for (i = 0; i < AG71XX_MDIO_RETRY; i++) {
56062306a36Sopenharmony_ci		u32 busy;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		udelay(AG71XX_MDIO_DELAY);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		busy = ag71xx_rr(ag, AG71XX_REG_MII_IND);
56562306a36Sopenharmony_ci		if (!busy)
56662306a36Sopenharmony_ci			return 0;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		udelay(AG71XX_MDIO_DELAY);
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	netif_err(ag, link, ndev, "MDIO operation timed out\n");
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return -ETIMEDOUT;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct ag71xx *ag = bus->priv;
57962306a36Sopenharmony_ci	int err, val;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	err = ag71xx_mdio_wait_busy(ag);
58262306a36Sopenharmony_ci	if (err)
58362306a36Sopenharmony_ci		return err;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
58662306a36Sopenharmony_ci		  ((addr & 0x1f) << MII_ADDR_SHIFT) | (reg & 0xff));
58762306a36Sopenharmony_ci	/* enable read mode */
58862306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_READ);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	err = ag71xx_mdio_wait_busy(ag);
59162306a36Sopenharmony_ci	if (err)
59262306a36Sopenharmony_ci		return err;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	val = ag71xx_rr(ag, AG71XX_REG_MII_STATUS);
59562306a36Sopenharmony_ci	/* disable read mode */
59662306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_CMD, 0);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	netif_dbg(ag, link, ag->ndev, "mii_read: addr=%04x, reg=%04x, value=%04x\n",
59962306a36Sopenharmony_ci		  addr, reg, val);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	return val;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg,
60562306a36Sopenharmony_ci				 u16 val)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct ag71xx *ag = bus->priv;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	netif_dbg(ag, link, ag->ndev, "mii_write: addr=%04x, reg=%04x, value=%04x\n",
61062306a36Sopenharmony_ci		  addr, reg, val);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
61362306a36Sopenharmony_ci		  ((addr & 0x1f) << MII_ADDR_SHIFT) | (reg & 0xff));
61462306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_CTRL, val);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	return ag71xx_mdio_wait_busy(ag);
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic const u32 ar71xx_mdio_div_table[] = {
62062306a36Sopenharmony_ci	4, 4, 6, 8, 10, 14, 20, 28,
62162306a36Sopenharmony_ci};
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic const u32 ar7240_mdio_div_table[] = {
62462306a36Sopenharmony_ci	2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96,
62562306a36Sopenharmony_ci};
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic const u32 ar933x_mdio_div_table[] = {
62862306a36Sopenharmony_ci	4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98,
62962306a36Sopenharmony_ci};
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int ag71xx_mdio_get_divider(struct ag71xx *ag, u32 *div)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	unsigned long ref_clock;
63462306a36Sopenharmony_ci	const u32 *table;
63562306a36Sopenharmony_ci	int ndivs, i;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	ref_clock = clk_get_rate(ag->clk_mdio);
63862306a36Sopenharmony_ci	if (!ref_clock)
63962306a36Sopenharmony_ci		return -EINVAL;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340)) {
64262306a36Sopenharmony_ci		table = ar933x_mdio_div_table;
64362306a36Sopenharmony_ci		ndivs = ARRAY_SIZE(ar933x_mdio_div_table);
64462306a36Sopenharmony_ci	} else if (ag71xx_is(ag, AR7240)) {
64562306a36Sopenharmony_ci		table = ar7240_mdio_div_table;
64662306a36Sopenharmony_ci		ndivs = ARRAY_SIZE(ar7240_mdio_div_table);
64762306a36Sopenharmony_ci	} else {
64862306a36Sopenharmony_ci		table = ar71xx_mdio_div_table;
64962306a36Sopenharmony_ci		ndivs = ARRAY_SIZE(ar71xx_mdio_div_table);
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	for (i = 0; i < ndivs; i++) {
65362306a36Sopenharmony_ci		unsigned long t;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		t = ref_clock / table[i];
65662306a36Sopenharmony_ci		if (t <= AG71XX_MDIO_MAX_CLK) {
65762306a36Sopenharmony_ci			*div = i;
65862306a36Sopenharmony_ci			return 0;
65962306a36Sopenharmony_ci		}
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	return -ENOENT;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic int ag71xx_mdio_reset(struct mii_bus *bus)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	struct ag71xx *ag = bus->priv;
66862306a36Sopenharmony_ci	int err;
66962306a36Sopenharmony_ci	u32 t;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	err = ag71xx_mdio_get_divider(ag, &t);
67262306a36Sopenharmony_ci	if (err)
67362306a36Sopenharmony_ci		return err;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
67662306a36Sopenharmony_ci	usleep_range(100, 200);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_CFG, t);
67962306a36Sopenharmony_ci	usleep_range(100, 200);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	return 0;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cistatic int ag71xx_mdio_probe(struct ag71xx *ag)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	struct device *dev = &ag->pdev->dev;
68762306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
68862306a36Sopenharmony_ci	static struct mii_bus *mii_bus;
68962306a36Sopenharmony_ci	struct device_node *np, *mnp;
69062306a36Sopenharmony_ci	int err;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	np = dev->of_node;
69362306a36Sopenharmony_ci	ag->mii_bus = NULL;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	ag->clk_mdio = devm_clk_get(dev, "mdio");
69662306a36Sopenharmony_ci	if (IS_ERR(ag->clk_mdio)) {
69762306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "Failed to get mdio clk.\n");
69862306a36Sopenharmony_ci		return PTR_ERR(ag->clk_mdio);
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	err = clk_prepare_enable(ag->clk_mdio);
70262306a36Sopenharmony_ci	if (err) {
70362306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "Failed to enable mdio clk.\n");
70462306a36Sopenharmony_ci		return err;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	mii_bus = devm_mdiobus_alloc(dev);
70862306a36Sopenharmony_ci	if (!mii_bus) {
70962306a36Sopenharmony_ci		err = -ENOMEM;
71062306a36Sopenharmony_ci		goto mdio_err_put_clk;
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio");
71462306a36Sopenharmony_ci	if (IS_ERR(ag->mdio_reset)) {
71562306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "Failed to get reset mdio.\n");
71662306a36Sopenharmony_ci		err = PTR_ERR(ag->mdio_reset);
71762306a36Sopenharmony_ci		goto mdio_err_put_clk;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	mii_bus->name = "ag71xx_mdio";
72162306a36Sopenharmony_ci	mii_bus->read = ag71xx_mdio_mii_read;
72262306a36Sopenharmony_ci	mii_bus->write = ag71xx_mdio_mii_write;
72362306a36Sopenharmony_ci	mii_bus->reset = ag71xx_mdio_reset;
72462306a36Sopenharmony_ci	mii_bus->priv = ag;
72562306a36Sopenharmony_ci	mii_bus->parent = dev;
72662306a36Sopenharmony_ci	snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s.%d", np->name, ag->mac_idx);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (!IS_ERR(ag->mdio_reset)) {
72962306a36Sopenharmony_ci		reset_control_assert(ag->mdio_reset);
73062306a36Sopenharmony_ci		msleep(100);
73162306a36Sopenharmony_ci		reset_control_deassert(ag->mdio_reset);
73262306a36Sopenharmony_ci		msleep(200);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	mnp = of_get_child_by_name(np, "mdio");
73662306a36Sopenharmony_ci	err = of_mdiobus_register(mii_bus, mnp);
73762306a36Sopenharmony_ci	of_node_put(mnp);
73862306a36Sopenharmony_ci	if (err)
73962306a36Sopenharmony_ci		goto mdio_err_put_clk;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	ag->mii_bus = mii_bus;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	return 0;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cimdio_err_put_clk:
74662306a36Sopenharmony_ci	clk_disable_unprepare(ag->clk_mdio);
74762306a36Sopenharmony_ci	return err;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic void ag71xx_mdio_remove(struct ag71xx *ag)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	if (ag->mii_bus)
75362306a36Sopenharmony_ci		mdiobus_unregister(ag->mii_bus);
75462306a36Sopenharmony_ci	clk_disable_unprepare(ag->clk_mdio);
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic void ag71xx_hw_stop(struct ag71xx *ag)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	/* disable all interrupts and stop the rx/tx engine */
76062306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
76162306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
76262306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cistatic bool ag71xx_check_dma_stuck(struct ag71xx *ag)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	unsigned long timestamp;
76862306a36Sopenharmony_ci	u32 rx_sm, tx_sm, rx_fd;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	timestamp = READ_ONCE(netdev_get_tx_queue(ag->ndev, 0)->trans_start);
77162306a36Sopenharmony_ci	if (likely(time_before(jiffies, timestamp + HZ / 10)))
77262306a36Sopenharmony_ci		return false;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (!netif_carrier_ok(ag->ndev))
77562306a36Sopenharmony_ci		return false;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM);
77862306a36Sopenharmony_ci	if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6)
77962306a36Sopenharmony_ci		return true;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM);
78262306a36Sopenharmony_ci	rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH);
78362306a36Sopenharmony_ci	if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) &&
78462306a36Sopenharmony_ci	    ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0)
78562306a36Sopenharmony_ci		return true;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	return false;
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic int ag71xx_tx_packets(struct ag71xx *ag, bool flush, int budget)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	struct ag71xx_ring *ring = &ag->tx_ring;
79362306a36Sopenharmony_ci	int sent = 0, bytes_compl = 0, n = 0;
79462306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
79562306a36Sopenharmony_ci	int ring_mask, ring_size;
79662306a36Sopenharmony_ci	bool dma_stuck = false;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	ring_mask = BIT(ring->order) - 1;
79962306a36Sopenharmony_ci	ring_size = BIT(ring->order);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	netif_dbg(ag, tx_queued, ndev, "processing TX ring\n");
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	while (ring->dirty + n != ring->curr) {
80462306a36Sopenharmony_ci		struct ag71xx_desc *desc;
80562306a36Sopenharmony_ci		struct sk_buff *skb;
80662306a36Sopenharmony_ci		unsigned int i;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		i = (ring->dirty + n) & ring_mask;
80962306a36Sopenharmony_ci		desc = ag71xx_ring_desc(ring, i);
81062306a36Sopenharmony_ci		skb = ring->buf[i].tx.skb;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		if (!flush && !ag71xx_desc_empty(desc)) {
81362306a36Sopenharmony_ci			if (ag->dcfg->tx_hang_workaround &&
81462306a36Sopenharmony_ci			    ag71xx_check_dma_stuck(ag)) {
81562306a36Sopenharmony_ci				schedule_delayed_work(&ag->restart_work,
81662306a36Sopenharmony_ci						      HZ / 2);
81762306a36Sopenharmony_ci				dma_stuck = true;
81862306a36Sopenharmony_ci			}
81962306a36Sopenharmony_ci			break;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		if (flush)
82362306a36Sopenharmony_ci			desc->ctrl |= DESC_EMPTY;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		n++;
82662306a36Sopenharmony_ci		if (!skb)
82762306a36Sopenharmony_ci			continue;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		napi_consume_skb(skb, budget);
83062306a36Sopenharmony_ci		ring->buf[i].tx.skb = NULL;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		bytes_compl += ring->buf[i].tx.len;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		sent++;
83562306a36Sopenharmony_ci		ring->dirty += n;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		while (n > 0) {
83862306a36Sopenharmony_ci			ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
83962306a36Sopenharmony_ci			n--;
84062306a36Sopenharmony_ci		}
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	netif_dbg(ag, tx_done, ndev, "%d packets sent out\n", sent);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (!sent)
84662306a36Sopenharmony_ci		return 0;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	ag->ndev->stats.tx_bytes += bytes_compl;
84962306a36Sopenharmony_ci	ag->ndev->stats.tx_packets += sent;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	netdev_completed_queue(ag->ndev, sent, bytes_compl);
85262306a36Sopenharmony_ci	if ((ring->curr - ring->dirty) < (ring_size * 3) / 4)
85362306a36Sopenharmony_ci		netif_wake_queue(ag->ndev);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	if (!dma_stuck)
85662306a36Sopenharmony_ci		cancel_delayed_work(&ag->restart_work);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	return sent;
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_cistatic void ag71xx_dma_wait_stop(struct ag71xx *ag)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
86462306a36Sopenharmony_ci	int i;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	for (i = 0; i < AG71XX_DMA_RETRY; i++) {
86762306a36Sopenharmony_ci		u32 rx, tx;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		mdelay(AG71XX_DMA_DELAY);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		rx = ag71xx_rr(ag, AG71XX_REG_RX_CTRL) & RX_CTRL_RXE;
87262306a36Sopenharmony_ci		tx = ag71xx_rr(ag, AG71XX_REG_TX_CTRL) & TX_CTRL_TXE;
87362306a36Sopenharmony_ci		if (!rx && !tx)
87462306a36Sopenharmony_ci			return;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	netif_err(ag, hw, ndev, "DMA stop operation timed out\n");
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic void ag71xx_dma_reset(struct ag71xx *ag)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
88362306a36Sopenharmony_ci	u32 val;
88462306a36Sopenharmony_ci	int i;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* stop RX and TX */
88762306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
88862306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	/* give the hardware some time to really stop all rx/tx activity
89162306a36Sopenharmony_ci	 * clearing the descriptors too early causes random memory corruption
89262306a36Sopenharmony_ci	 */
89362306a36Sopenharmony_ci	ag71xx_dma_wait_stop(ag);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* clear descriptor addresses */
89662306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->stop_desc_dma);
89762306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->stop_desc_dma);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	/* clear pending RX/TX interrupts */
90062306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
90162306a36Sopenharmony_ci		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
90262306a36Sopenharmony_ci		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	/* clear pending errors */
90662306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF);
90762306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
91062306a36Sopenharmony_ci	if (val)
91162306a36Sopenharmony_ci		netif_err(ag, hw, ndev, "unable to clear DMA Rx status: %08x\n",
91262306a36Sopenharmony_ci			  val);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* mask out reserved bits */
91762306a36Sopenharmony_ci	val &= ~0xff000000;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if (val)
92062306a36Sopenharmony_ci		netif_err(ag, hw, ndev, "unable to clear DMA Tx status: %08x\n",
92162306a36Sopenharmony_ci			  val);
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic void ag71xx_hw_setup(struct ag71xx *ag)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	u32 init = MAC_CFG1_INIT;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	/* setup MAC configuration registers */
92962306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, init);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
93262306a36Sopenharmony_ci		  MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/* setup max frame length to zero */
93562306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_MFL, 0);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	/* setup FIFO configuration registers */
93862306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT);
93962306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, ag->fifodata[0]);
94062306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, ag->fifodata[1]);
94162306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
94262306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic unsigned int ag71xx_max_frame_len(unsigned int mtu)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	return ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic void ag71xx_hw_set_macaddr(struct ag71xx *ag, const unsigned char *mac)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	u32 t;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	t = (((u32)mac[5]) << 24) | (((u32)mac[4]) << 16)
95562306a36Sopenharmony_ci	  | (((u32)mac[3]) << 8) | ((u32)mac[2]);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	t = (((u32)mac[1]) << 24) | (((u32)mac[0]) << 16);
96062306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic void ag71xx_fast_reset(struct ag71xx *ag)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct net_device *dev = ag->ndev;
96662306a36Sopenharmony_ci	u32 rx_ds;
96762306a36Sopenharmony_ci	u32 mii_reg;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	ag71xx_hw_stop(ag);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG);
97262306a36Sopenharmony_ci	rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	ag71xx_tx_packets(ag, true, 0);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	reset_control_assert(ag->mac_reset);
97762306a36Sopenharmony_ci	usleep_range(10, 20);
97862306a36Sopenharmony_ci	reset_control_deassert(ag->mac_reset);
97962306a36Sopenharmony_ci	usleep_range(10, 20);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	ag71xx_dma_reset(ag);
98262306a36Sopenharmony_ci	ag71xx_hw_setup(ag);
98362306a36Sopenharmony_ci	ag->tx_ring.curr = 0;
98462306a36Sopenharmony_ci	ag->tx_ring.dirty = 0;
98562306a36Sopenharmony_ci	netdev_reset_queue(ag->ndev);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* setup max frame length */
98862306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_MFL,
98962306a36Sopenharmony_ci		  ag71xx_max_frame_len(ag->ndev->mtu));
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds);
99262306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
99362306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	ag71xx_hw_set_macaddr(ag, dev->dev_addr);
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic void ag71xx_hw_start(struct ag71xx *ag)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	/* start RX engine */
100162306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/* enable interrupts */
100462306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	netif_wake_queue(ag->ndev);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void ag71xx_mac_config(struct phylink_config *config, unsigned int mode,
101062306a36Sopenharmony_ci			      const struct phylink_link_state *state)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(to_net_dev(config->dev));
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if (phylink_autoneg_inband(mode))
101562306a36Sopenharmony_ci		return;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130))
101862306a36Sopenharmony_ci		ag71xx_fast_reset(ag);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (ag->tx_ring.desc_split) {
102162306a36Sopenharmony_ci		ag->fifodata[2] &= 0xffff;
102262306a36Sopenharmony_ci		ag->fifodata[2] |= ((2048 - ag->tx_ring.desc_split) / 4) << 16;
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, ag->fifodata[2]);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic void ag71xx_mac_link_down(struct phylink_config *config,
102962306a36Sopenharmony_ci				 unsigned int mode, phy_interface_t interface)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(to_net_dev(config->dev));
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	ag71xx_hw_stop(ag);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic void ag71xx_mac_link_up(struct phylink_config *config,
103762306a36Sopenharmony_ci			       struct phy_device *phy,
103862306a36Sopenharmony_ci			       unsigned int mode, phy_interface_t interface,
103962306a36Sopenharmony_ci			       int speed, int duplex,
104062306a36Sopenharmony_ci			       bool tx_pause, bool rx_pause)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(to_net_dev(config->dev));
104362306a36Sopenharmony_ci	u32 cfg1, cfg2;
104462306a36Sopenharmony_ci	u32 ifctl;
104562306a36Sopenharmony_ci	u32 fifo5;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
104862306a36Sopenharmony_ci	cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
104962306a36Sopenharmony_ci	cfg2 |= duplex ? MAC_CFG2_FDX : 0;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
105262306a36Sopenharmony_ci	ifctl &= ~(MAC_IFCTL_SPEED);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
105562306a36Sopenharmony_ci	fifo5 &= ~FIFO_CFG5_BM;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	switch (speed) {
105862306a36Sopenharmony_ci	case SPEED_1000:
105962306a36Sopenharmony_ci		cfg2 |= MAC_CFG2_IF_1000;
106062306a36Sopenharmony_ci		fifo5 |= FIFO_CFG5_BM;
106162306a36Sopenharmony_ci		break;
106262306a36Sopenharmony_ci	case SPEED_100:
106362306a36Sopenharmony_ci		cfg2 |= MAC_CFG2_IF_10_100;
106462306a36Sopenharmony_ci		ifctl |= MAC_IFCTL_SPEED;
106562306a36Sopenharmony_ci		break;
106662306a36Sopenharmony_ci	case SPEED_10:
106762306a36Sopenharmony_ci		cfg2 |= MAC_CFG2_IF_10_100;
106862306a36Sopenharmony_ci		break;
106962306a36Sopenharmony_ci	default:
107062306a36Sopenharmony_ci		return;
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
107462306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
107562306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	cfg1 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG1);
107862306a36Sopenharmony_ci	cfg1 &= ~(MAC_CFG1_TFC | MAC_CFG1_RFC);
107962306a36Sopenharmony_ci	if (tx_pause)
108062306a36Sopenharmony_ci		cfg1 |= MAC_CFG1_TFC;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (rx_pause)
108362306a36Sopenharmony_ci		cfg1 |= MAC_CFG1_RFC;
108462306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, cfg1);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	ag71xx_hw_start(ag);
108762306a36Sopenharmony_ci}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_cistatic const struct phylink_mac_ops ag71xx_phylink_mac_ops = {
109062306a36Sopenharmony_ci	.mac_config = ag71xx_mac_config,
109162306a36Sopenharmony_ci	.mac_link_down = ag71xx_mac_link_down,
109262306a36Sopenharmony_ci	.mac_link_up = ag71xx_mac_link_up,
109362306a36Sopenharmony_ci};
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_cistatic int ag71xx_phylink_setup(struct ag71xx *ag)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct phylink *phylink;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	ag->phylink_config.dev = &ag->ndev->dev;
110062306a36Sopenharmony_ci	ag->phylink_config.type = PHYLINK_NETDEV;
110162306a36Sopenharmony_ci	ag->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
110262306a36Sopenharmony_ci		MAC_10 | MAC_100 | MAC_1000FD;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	if ((ag71xx_is(ag, AR9330) && ag->mac_idx == 0) ||
110562306a36Sopenharmony_ci	    ag71xx_is(ag, AR9340) ||
110662306a36Sopenharmony_ci	    ag71xx_is(ag, QCA9530) ||
110762306a36Sopenharmony_ci	    (ag71xx_is(ag, QCA9550) && ag->mac_idx == 1))
110862306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_MII,
110962306a36Sopenharmony_ci			  ag->phylink_config.supported_interfaces);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if ((ag71xx_is(ag, AR9330) && ag->mac_idx == 1) ||
111262306a36Sopenharmony_ci	    (ag71xx_is(ag, AR9340) && ag->mac_idx == 1) ||
111362306a36Sopenharmony_ci	    (ag71xx_is(ag, QCA9530) && ag->mac_idx == 1))
111462306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_GMII,
111562306a36Sopenharmony_ci			  ag->phylink_config.supported_interfaces);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (ag71xx_is(ag, QCA9550) && ag->mac_idx == 0)
111862306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_SGMII,
111962306a36Sopenharmony_ci			  ag->phylink_config.supported_interfaces);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	if (ag71xx_is(ag, AR9340) && ag->mac_idx == 0)
112262306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RMII,
112362306a36Sopenharmony_ci			  ag->phylink_config.supported_interfaces);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	if ((ag71xx_is(ag, AR9340) && ag->mac_idx == 0) ||
112662306a36Sopenharmony_ci	    (ag71xx_is(ag, QCA9550) && ag->mac_idx == 1))
112762306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_RGMII,
112862306a36Sopenharmony_ci			  ag->phylink_config.supported_interfaces);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	phylink = phylink_create(&ag->phylink_config, ag->pdev->dev.fwnode,
113162306a36Sopenharmony_ci				 ag->phy_if_mode, &ag71xx_phylink_mac_ops);
113262306a36Sopenharmony_ci	if (IS_ERR(phylink))
113362306a36Sopenharmony_ci		return PTR_ERR(phylink);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	ag->phylink = phylink;
113662306a36Sopenharmony_ci	return 0;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_cistatic void ag71xx_ring_tx_clean(struct ag71xx *ag)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	struct ag71xx_ring *ring = &ag->tx_ring;
114262306a36Sopenharmony_ci	int ring_mask = BIT(ring->order) - 1;
114362306a36Sopenharmony_ci	u32 bytes_compl = 0, pkts_compl = 0;
114462306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	while (ring->curr != ring->dirty) {
114762306a36Sopenharmony_ci		struct ag71xx_desc *desc;
114862306a36Sopenharmony_ci		u32 i = ring->dirty & ring_mask;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci		desc = ag71xx_ring_desc(ring, i);
115162306a36Sopenharmony_ci		if (!ag71xx_desc_empty(desc)) {
115262306a36Sopenharmony_ci			desc->ctrl = 0;
115362306a36Sopenharmony_ci			ndev->stats.tx_errors++;
115462306a36Sopenharmony_ci		}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci		if (ring->buf[i].tx.skb) {
115762306a36Sopenharmony_ci			bytes_compl += ring->buf[i].tx.len;
115862306a36Sopenharmony_ci			pkts_compl++;
115962306a36Sopenharmony_ci			dev_kfree_skb_any(ring->buf[i].tx.skb);
116062306a36Sopenharmony_ci		}
116162306a36Sopenharmony_ci		ring->buf[i].tx.skb = NULL;
116262306a36Sopenharmony_ci		ring->dirty++;
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* flush descriptors */
116662306a36Sopenharmony_ci	wmb();
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	netdev_completed_queue(ndev, pkts_compl, bytes_compl);
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic void ag71xx_ring_tx_init(struct ag71xx *ag)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	struct ag71xx_ring *ring = &ag->tx_ring;
117462306a36Sopenharmony_ci	int ring_size = BIT(ring->order);
117562306a36Sopenharmony_ci	int ring_mask = ring_size - 1;
117662306a36Sopenharmony_ci	int i;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	for (i = 0; i < ring_size; i++) {
117962306a36Sopenharmony_ci		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci		desc->next = (u32)(ring->descs_dma +
118262306a36Sopenharmony_ci			AG71XX_DESC_SIZE * ((i + 1) & ring_mask));
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci		desc->ctrl = DESC_EMPTY;
118562306a36Sopenharmony_ci		ring->buf[i].tx.skb = NULL;
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	/* flush descriptors */
118962306a36Sopenharmony_ci	wmb();
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	ring->curr = 0;
119262306a36Sopenharmony_ci	ring->dirty = 0;
119362306a36Sopenharmony_ci	netdev_reset_queue(ag->ndev);
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_cistatic void ag71xx_ring_rx_clean(struct ag71xx *ag)
119762306a36Sopenharmony_ci{
119862306a36Sopenharmony_ci	struct ag71xx_ring *ring = &ag->rx_ring;
119962306a36Sopenharmony_ci	int ring_size = BIT(ring->order);
120062306a36Sopenharmony_ci	int i;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	if (!ring->buf)
120362306a36Sopenharmony_ci		return;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	for (i = 0; i < ring_size; i++)
120662306a36Sopenharmony_ci		if (ring->buf[i].rx.rx_buf) {
120762306a36Sopenharmony_ci			dma_unmap_single(&ag->pdev->dev,
120862306a36Sopenharmony_ci					 ring->buf[i].rx.dma_addr,
120962306a36Sopenharmony_ci					 ag->rx_buf_size, DMA_FROM_DEVICE);
121062306a36Sopenharmony_ci			skb_free_frag(ring->buf[i].rx.rx_buf);
121162306a36Sopenharmony_ci		}
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic int ag71xx_buffer_size(struct ag71xx *ag)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	return ag->rx_buf_size +
121762306a36Sopenharmony_ci	       SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_cistatic bool ag71xx_fill_rx_buf(struct ag71xx *ag, struct ag71xx_buf *buf,
122162306a36Sopenharmony_ci			       int offset,
122262306a36Sopenharmony_ci			       void *(*alloc)(unsigned int size))
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	struct ag71xx_ring *ring = &ag->rx_ring;
122562306a36Sopenharmony_ci	struct ag71xx_desc *desc;
122662306a36Sopenharmony_ci	void *data;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	desc = ag71xx_ring_desc(ring, buf - &ring->buf[0]);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	data = alloc(ag71xx_buffer_size(ag));
123162306a36Sopenharmony_ci	if (!data)
123262306a36Sopenharmony_ci		return false;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	buf->rx.rx_buf = data;
123562306a36Sopenharmony_ci	buf->rx.dma_addr = dma_map_single(&ag->pdev->dev, data, ag->rx_buf_size,
123662306a36Sopenharmony_ci					  DMA_FROM_DEVICE);
123762306a36Sopenharmony_ci	desc->data = (u32)buf->rx.dma_addr + offset;
123862306a36Sopenharmony_ci	return true;
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_cistatic int ag71xx_ring_rx_init(struct ag71xx *ag)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	struct ag71xx_ring *ring = &ag->rx_ring;
124462306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
124562306a36Sopenharmony_ci	int ring_mask = BIT(ring->order) - 1;
124662306a36Sopenharmony_ci	int ring_size = BIT(ring->order);
124762306a36Sopenharmony_ci	unsigned int i;
124862306a36Sopenharmony_ci	int ret;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	ret = 0;
125162306a36Sopenharmony_ci	for (i = 0; i < ring_size; i++) {
125262306a36Sopenharmony_ci		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci		desc->next = (u32)(ring->descs_dma +
125562306a36Sopenharmony_ci			AG71XX_DESC_SIZE * ((i + 1) & ring_mask));
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci		netif_dbg(ag, rx_status, ndev, "RX desc at %p, next is %08x\n",
125862306a36Sopenharmony_ci			  desc, desc->next);
125962306a36Sopenharmony_ci	}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	for (i = 0; i < ring_size; i++) {
126262306a36Sopenharmony_ci		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		if (!ag71xx_fill_rx_buf(ag, &ring->buf[i], ag->rx_buf_offset,
126562306a36Sopenharmony_ci					netdev_alloc_frag)) {
126662306a36Sopenharmony_ci			ret = -ENOMEM;
126762306a36Sopenharmony_ci			break;
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		desc->ctrl = DESC_EMPTY;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	/* flush descriptors */
127462306a36Sopenharmony_ci	wmb();
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	ring->curr = 0;
127762306a36Sopenharmony_ci	ring->dirty = 0;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	return ret;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int ag71xx_ring_rx_refill(struct ag71xx *ag)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	struct ag71xx_ring *ring = &ag->rx_ring;
128562306a36Sopenharmony_ci	int ring_mask = BIT(ring->order) - 1;
128662306a36Sopenharmony_ci	int offset = ag->rx_buf_offset;
128762306a36Sopenharmony_ci	unsigned int count;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	count = 0;
129062306a36Sopenharmony_ci	for (; ring->curr - ring->dirty > 0; ring->dirty++) {
129162306a36Sopenharmony_ci		struct ag71xx_desc *desc;
129262306a36Sopenharmony_ci		unsigned int i;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci		i = ring->dirty & ring_mask;
129562306a36Sopenharmony_ci		desc = ag71xx_ring_desc(ring, i);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		if (!ring->buf[i].rx.rx_buf &&
129862306a36Sopenharmony_ci		    !ag71xx_fill_rx_buf(ag, &ring->buf[i], offset,
129962306a36Sopenharmony_ci					napi_alloc_frag))
130062306a36Sopenharmony_ci			break;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		desc->ctrl = DESC_EMPTY;
130362306a36Sopenharmony_ci		count++;
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* flush descriptors */
130762306a36Sopenharmony_ci	wmb();
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	netif_dbg(ag, rx_status, ag->ndev, "%u rx descriptors refilled\n",
131062306a36Sopenharmony_ci		  count);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	return count;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic int ag71xx_rings_init(struct ag71xx *ag)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct ag71xx_ring *tx = &ag->tx_ring;
131862306a36Sopenharmony_ci	struct ag71xx_ring *rx = &ag->rx_ring;
131962306a36Sopenharmony_ci	int ring_size, tx_size;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	ring_size = BIT(tx->order) + BIT(rx->order);
132262306a36Sopenharmony_ci	tx_size = BIT(tx->order);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	tx->buf = kcalloc(ring_size, sizeof(*tx->buf), GFP_KERNEL);
132562306a36Sopenharmony_ci	if (!tx->buf)
132662306a36Sopenharmony_ci		return -ENOMEM;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	tx->descs_cpu = dma_alloc_coherent(&ag->pdev->dev,
132962306a36Sopenharmony_ci					   ring_size * AG71XX_DESC_SIZE,
133062306a36Sopenharmony_ci					   &tx->descs_dma, GFP_KERNEL);
133162306a36Sopenharmony_ci	if (!tx->descs_cpu) {
133262306a36Sopenharmony_ci		kfree(tx->buf);
133362306a36Sopenharmony_ci		tx->buf = NULL;
133462306a36Sopenharmony_ci		return -ENOMEM;
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	rx->buf = &tx->buf[tx_size];
133862306a36Sopenharmony_ci	rx->descs_cpu = ((void *)tx->descs_cpu) + tx_size * AG71XX_DESC_SIZE;
133962306a36Sopenharmony_ci	rx->descs_dma = tx->descs_dma + tx_size * AG71XX_DESC_SIZE;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	ag71xx_ring_tx_init(ag);
134262306a36Sopenharmony_ci	return ag71xx_ring_rx_init(ag);
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic void ag71xx_rings_free(struct ag71xx *ag)
134662306a36Sopenharmony_ci{
134762306a36Sopenharmony_ci	struct ag71xx_ring *tx = &ag->tx_ring;
134862306a36Sopenharmony_ci	struct ag71xx_ring *rx = &ag->rx_ring;
134962306a36Sopenharmony_ci	int ring_size;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	ring_size = BIT(tx->order) + BIT(rx->order);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	if (tx->descs_cpu)
135462306a36Sopenharmony_ci		dma_free_coherent(&ag->pdev->dev, ring_size * AG71XX_DESC_SIZE,
135562306a36Sopenharmony_ci				  tx->descs_cpu, tx->descs_dma);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	kfree(tx->buf);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	tx->descs_cpu = NULL;
136062306a36Sopenharmony_ci	rx->descs_cpu = NULL;
136162306a36Sopenharmony_ci	tx->buf = NULL;
136262306a36Sopenharmony_ci	rx->buf = NULL;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic void ag71xx_rings_cleanup(struct ag71xx *ag)
136662306a36Sopenharmony_ci{
136762306a36Sopenharmony_ci	ag71xx_ring_rx_clean(ag);
136862306a36Sopenharmony_ci	ag71xx_ring_tx_clean(ag);
136962306a36Sopenharmony_ci	ag71xx_rings_free(ag);
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	netdev_reset_queue(ag->ndev);
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_cistatic void ag71xx_hw_init(struct ag71xx *ag)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	ag71xx_hw_stop(ag);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
137962306a36Sopenharmony_ci	usleep_range(20, 30);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	reset_control_assert(ag->mac_reset);
138262306a36Sopenharmony_ci	msleep(100);
138362306a36Sopenharmony_ci	reset_control_deassert(ag->mac_reset);
138462306a36Sopenharmony_ci	msleep(200);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	ag71xx_hw_setup(ag);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	ag71xx_dma_reset(ag);
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistatic int ag71xx_hw_enable(struct ag71xx *ag)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	int ret;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	ret = ag71xx_rings_init(ag);
139662306a36Sopenharmony_ci	if (ret)
139762306a36Sopenharmony_ci		return ret;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	napi_enable(&ag->napi);
140062306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
140162306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
140262306a36Sopenharmony_ci	netif_start_queue(ag->ndev);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	return 0;
140562306a36Sopenharmony_ci}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_cistatic void ag71xx_hw_disable(struct ag71xx *ag)
140862306a36Sopenharmony_ci{
140962306a36Sopenharmony_ci	netif_stop_queue(ag->ndev);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	ag71xx_hw_stop(ag);
141262306a36Sopenharmony_ci	ag71xx_dma_reset(ag);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	napi_disable(&ag->napi);
141562306a36Sopenharmony_ci	del_timer_sync(&ag->oom_timer);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	ag71xx_rings_cleanup(ag);
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_cistatic int ag71xx_open(struct net_device *ndev)
142162306a36Sopenharmony_ci{
142262306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
142362306a36Sopenharmony_ci	unsigned int max_frame_len;
142462306a36Sopenharmony_ci	int ret;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	ret = phylink_of_phy_connect(ag->phylink, ag->pdev->dev.of_node, 0);
142762306a36Sopenharmony_ci	if (ret) {
142862306a36Sopenharmony_ci		netif_err(ag, link, ndev, "phylink_of_phy_connect filed with err: %i\n",
142962306a36Sopenharmony_ci			  ret);
143062306a36Sopenharmony_ci		return ret;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	max_frame_len = ag71xx_max_frame_len(ndev->mtu);
143462306a36Sopenharmony_ci	ag->rx_buf_size =
143562306a36Sopenharmony_ci		SKB_DATA_ALIGN(max_frame_len + NET_SKB_PAD + NET_IP_ALIGN);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* setup max frame length */
143862306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len);
143962306a36Sopenharmony_ci	ag71xx_hw_set_macaddr(ag, ndev->dev_addr);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	ret = ag71xx_hw_enable(ag);
144262306a36Sopenharmony_ci	if (ret)
144362306a36Sopenharmony_ci		goto err;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	phylink_start(ag->phylink);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	return 0;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cierr:
145062306a36Sopenharmony_ci	ag71xx_rings_cleanup(ag);
145162306a36Sopenharmony_ci	phylink_disconnect_phy(ag->phylink);
145262306a36Sopenharmony_ci	return ret;
145362306a36Sopenharmony_ci}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_cistatic int ag71xx_stop(struct net_device *ndev)
145662306a36Sopenharmony_ci{
145762306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	phylink_stop(ag->phylink);
146062306a36Sopenharmony_ci	phylink_disconnect_phy(ag->phylink);
146162306a36Sopenharmony_ci	ag71xx_hw_disable(ag);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	return 0;
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_cistatic int ag71xx_fill_dma_desc(struct ag71xx_ring *ring, u32 addr, int len)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	int i, ring_mask, ndesc, split;
146962306a36Sopenharmony_ci	struct ag71xx_desc *desc;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	ring_mask = BIT(ring->order) - 1;
147262306a36Sopenharmony_ci	ndesc = 0;
147362306a36Sopenharmony_ci	split = ring->desc_split;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	if (!split)
147662306a36Sopenharmony_ci		split = len;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	while (len > 0) {
147962306a36Sopenharmony_ci		unsigned int cur_len = len;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		i = (ring->curr + ndesc) & ring_mask;
148262306a36Sopenharmony_ci		desc = ag71xx_ring_desc(ring, i);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci		if (!ag71xx_desc_empty(desc))
148562306a36Sopenharmony_ci			return -1;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		if (cur_len > split) {
148862306a36Sopenharmony_ci			cur_len = split;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci			/*  TX will hang if DMA transfers <= 4 bytes,
149162306a36Sopenharmony_ci			 * make sure next segment is more than 4 bytes long.
149262306a36Sopenharmony_ci			 */
149362306a36Sopenharmony_ci			if (len <= split + 4)
149462306a36Sopenharmony_ci				cur_len -= 4;
149562306a36Sopenharmony_ci		}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci		desc->data = addr;
149862306a36Sopenharmony_ci		addr += cur_len;
149962306a36Sopenharmony_ci		len -= cur_len;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci		if (len > 0)
150262306a36Sopenharmony_ci			cur_len |= DESC_MORE;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci		/* prevent early tx attempt of this descriptor */
150562306a36Sopenharmony_ci		if (!ndesc)
150662306a36Sopenharmony_ci			cur_len |= DESC_EMPTY;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci		desc->ctrl = cur_len;
150962306a36Sopenharmony_ci		ndesc++;
151062306a36Sopenharmony_ci	}
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	return ndesc;
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_cistatic netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb,
151662306a36Sopenharmony_ci					  struct net_device *ndev)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	int i, n, ring_min, ring_mask, ring_size;
151962306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
152062306a36Sopenharmony_ci	struct ag71xx_ring *ring;
152162306a36Sopenharmony_ci	struct ag71xx_desc *desc;
152262306a36Sopenharmony_ci	dma_addr_t dma_addr;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	ring = &ag->tx_ring;
152562306a36Sopenharmony_ci	ring_mask = BIT(ring->order) - 1;
152662306a36Sopenharmony_ci	ring_size = BIT(ring->order);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (skb->len <= 4) {
152962306a36Sopenharmony_ci		netif_dbg(ag, tx_err, ndev, "packet len is too small\n");
153062306a36Sopenharmony_ci		goto err_drop;
153162306a36Sopenharmony_ci	}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	dma_addr = dma_map_single(&ag->pdev->dev, skb->data, skb->len,
153462306a36Sopenharmony_ci				  DMA_TO_DEVICE);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	i = ring->curr & ring_mask;
153762306a36Sopenharmony_ci	desc = ag71xx_ring_desc(ring, i);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	/* setup descriptor fields */
154062306a36Sopenharmony_ci	n = ag71xx_fill_dma_desc(ring, (u32)dma_addr,
154162306a36Sopenharmony_ci				 skb->len & ag->dcfg->desc_pktlen_mask);
154262306a36Sopenharmony_ci	if (n < 0)
154362306a36Sopenharmony_ci		goto err_drop_unmap;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	i = (ring->curr + n - 1) & ring_mask;
154662306a36Sopenharmony_ci	ring->buf[i].tx.len = skb->len;
154762306a36Sopenharmony_ci	ring->buf[i].tx.skb = skb;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	netdev_sent_queue(ndev, skb->len);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	skb_tx_timestamp(skb);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	desc->ctrl &= ~DESC_EMPTY;
155462306a36Sopenharmony_ci	ring->curr += n;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	/* flush descriptor */
155762306a36Sopenharmony_ci	wmb();
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	ring_min = 2;
156062306a36Sopenharmony_ci	if (ring->desc_split)
156162306a36Sopenharmony_ci		ring_min *= AG71XX_TX_RING_DS_PER_PKT;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (ring->curr - ring->dirty >= ring_size - ring_min) {
156462306a36Sopenharmony_ci		netif_dbg(ag, tx_err, ndev, "tx queue full\n");
156562306a36Sopenharmony_ci		netif_stop_queue(ndev);
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	netif_dbg(ag, tx_queued, ndev, "packet injected into TX queue\n");
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	/* enable TX engine */
157162306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	return NETDEV_TX_OK;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cierr_drop_unmap:
157662306a36Sopenharmony_ci	dma_unmap_single(&ag->pdev->dev, dma_addr, skb->len, DMA_TO_DEVICE);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_cierr_drop:
157962306a36Sopenharmony_ci	ndev->stats.tx_dropped++;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	dev_kfree_skb(skb);
158262306a36Sopenharmony_ci	return NETDEV_TX_OK;
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_cistatic void ag71xx_oom_timer_handler(struct timer_list *t)
158662306a36Sopenharmony_ci{
158762306a36Sopenharmony_ci	struct ag71xx *ag = from_timer(ag, t, oom_timer);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	napi_schedule(&ag->napi);
159062306a36Sopenharmony_ci}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_cistatic void ag71xx_tx_timeout(struct net_device *ndev, unsigned int txqueue)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	netif_err(ag, tx_err, ndev, "tx timeout\n");
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	schedule_delayed_work(&ag->restart_work, 1);
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic void ag71xx_restart_work_func(struct work_struct *work)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	struct ag71xx *ag = container_of(work, struct ag71xx,
160462306a36Sopenharmony_ci					 restart_work.work);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	rtnl_lock();
160762306a36Sopenharmony_ci	ag71xx_hw_disable(ag);
160862306a36Sopenharmony_ci	ag71xx_hw_enable(ag);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	phylink_stop(ag->phylink);
161162306a36Sopenharmony_ci	phylink_start(ag->phylink);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	rtnl_unlock();
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_cistatic int ag71xx_rx_packets(struct ag71xx *ag, int limit)
161762306a36Sopenharmony_ci{
161862306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
161962306a36Sopenharmony_ci	int ring_mask, ring_size, done = 0;
162062306a36Sopenharmony_ci	unsigned int pktlen_mask, offset;
162162306a36Sopenharmony_ci	struct ag71xx_ring *ring;
162262306a36Sopenharmony_ci	struct list_head rx_list;
162362306a36Sopenharmony_ci	struct sk_buff *skb;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	ring = &ag->rx_ring;
162662306a36Sopenharmony_ci	pktlen_mask = ag->dcfg->desc_pktlen_mask;
162762306a36Sopenharmony_ci	offset = ag->rx_buf_offset;
162862306a36Sopenharmony_ci	ring_mask = BIT(ring->order) - 1;
162962306a36Sopenharmony_ci	ring_size = BIT(ring->order);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	netif_dbg(ag, rx_status, ndev, "rx packets, limit=%d, curr=%u, dirty=%u\n",
163262306a36Sopenharmony_ci		  limit, ring->curr, ring->dirty);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	INIT_LIST_HEAD(&rx_list);
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	while (done < limit) {
163762306a36Sopenharmony_ci		unsigned int i = ring->curr & ring_mask;
163862306a36Sopenharmony_ci		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
163962306a36Sopenharmony_ci		int pktlen;
164062306a36Sopenharmony_ci		int err = 0;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci		if (ag71xx_desc_empty(desc))
164362306a36Sopenharmony_ci			break;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		if ((ring->dirty + ring_size) == ring->curr) {
164662306a36Sopenharmony_ci			WARN_ONCE(1, "RX out of ring");
164762306a36Sopenharmony_ci			break;
164862306a36Sopenharmony_ci		}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci		pktlen = desc->ctrl & pktlen_mask;
165362306a36Sopenharmony_ci		pktlen -= ETH_FCS_LEN;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		dma_unmap_single(&ag->pdev->dev, ring->buf[i].rx.dma_addr,
165662306a36Sopenharmony_ci				 ag->rx_buf_size, DMA_FROM_DEVICE);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci		ndev->stats.rx_packets++;
165962306a36Sopenharmony_ci		ndev->stats.rx_bytes += pktlen;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci		skb = napi_build_skb(ring->buf[i].rx.rx_buf, ag71xx_buffer_size(ag));
166262306a36Sopenharmony_ci		if (!skb) {
166362306a36Sopenharmony_ci			skb_free_frag(ring->buf[i].rx.rx_buf);
166462306a36Sopenharmony_ci			goto next;
166562306a36Sopenharmony_ci		}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci		skb_reserve(skb, offset);
166862306a36Sopenharmony_ci		skb_put(skb, pktlen);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci		if (err) {
167162306a36Sopenharmony_ci			ndev->stats.rx_dropped++;
167262306a36Sopenharmony_ci			kfree_skb(skb);
167362306a36Sopenharmony_ci		} else {
167462306a36Sopenharmony_ci			skb->dev = ndev;
167562306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_NONE;
167662306a36Sopenharmony_ci			list_add_tail(&skb->list, &rx_list);
167762306a36Sopenharmony_ci		}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_cinext:
168062306a36Sopenharmony_ci		ring->buf[i].rx.rx_buf = NULL;
168162306a36Sopenharmony_ci		done++;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci		ring->curr++;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	ag71xx_ring_rx_refill(ag);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	list_for_each_entry(skb, &rx_list, list)
168962306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, ndev);
169062306a36Sopenharmony_ci	netif_receive_skb_list(&rx_list);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	netif_dbg(ag, rx_status, ndev, "rx finish, curr=%u, dirty=%u, done=%d\n",
169362306a36Sopenharmony_ci		  ring->curr, ring->dirty, done);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	return done;
169662306a36Sopenharmony_ci}
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_cistatic int ag71xx_poll(struct napi_struct *napi, int limit)
169962306a36Sopenharmony_ci{
170062306a36Sopenharmony_ci	struct ag71xx *ag = container_of(napi, struct ag71xx, napi);
170162306a36Sopenharmony_ci	struct ag71xx_ring *rx_ring = &ag->rx_ring;
170262306a36Sopenharmony_ci	int rx_ring_size = BIT(rx_ring->order);
170362306a36Sopenharmony_ci	struct net_device *ndev = ag->ndev;
170462306a36Sopenharmony_ci	int tx_done, rx_done;
170562306a36Sopenharmony_ci	u32 status;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	tx_done = ag71xx_tx_packets(ag, false, limit);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	netif_dbg(ag, rx_status, ndev, "processing RX ring\n");
171062306a36Sopenharmony_ci	rx_done = ag71xx_rx_packets(ag, limit);
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	if (!rx_ring->buf[rx_ring->dirty % rx_ring_size].rx.rx_buf)
171362306a36Sopenharmony_ci		goto oom;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
171662306a36Sopenharmony_ci	if (unlikely(status & RX_STATUS_OF)) {
171762306a36Sopenharmony_ci		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF);
171862306a36Sopenharmony_ci		ndev->stats.rx_fifo_errors++;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci		/* restart RX */
172162306a36Sopenharmony_ci		ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
172262306a36Sopenharmony_ci	}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	if (rx_done < limit) {
172562306a36Sopenharmony_ci		if (status & RX_STATUS_PR)
172662306a36Sopenharmony_ci			goto more;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci		status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
172962306a36Sopenharmony_ci		if (status & TX_STATUS_PS)
173062306a36Sopenharmony_ci			goto more;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci		netif_dbg(ag, rx_status, ndev, "disable polling mode, rx=%d, tx=%d,limit=%d\n",
173362306a36Sopenharmony_ci			  rx_done, tx_done, limit);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci		napi_complete(napi);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci		/* enable interrupts */
173862306a36Sopenharmony_ci		ag71xx_int_enable(ag, AG71XX_INT_POLL);
173962306a36Sopenharmony_ci		return rx_done;
174062306a36Sopenharmony_ci	}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_cimore:
174362306a36Sopenharmony_ci	netif_dbg(ag, rx_status, ndev, "stay in polling mode, rx=%d, tx=%d, limit=%d\n",
174462306a36Sopenharmony_ci		  rx_done, tx_done, limit);
174562306a36Sopenharmony_ci	return limit;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cioom:
174862306a36Sopenharmony_ci	netif_err(ag, rx_err, ndev, "out of memory\n");
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL);
175162306a36Sopenharmony_ci	napi_complete(napi);
175262306a36Sopenharmony_ci	return 0;
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistatic irqreturn_t ag71xx_interrupt(int irq, void *dev_id)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	struct net_device *ndev = dev_id;
175862306a36Sopenharmony_ci	struct ag71xx *ag;
175962306a36Sopenharmony_ci	u32 status;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	ag = netdev_priv(ndev);
176262306a36Sopenharmony_ci	status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (unlikely(!status))
176562306a36Sopenharmony_ci		return IRQ_NONE;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (unlikely(status & AG71XX_INT_ERR)) {
176862306a36Sopenharmony_ci		if (status & AG71XX_INT_TX_BE) {
176962306a36Sopenharmony_ci			ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE);
177062306a36Sopenharmony_ci			netif_err(ag, intr, ndev, "TX BUS error\n");
177162306a36Sopenharmony_ci		}
177262306a36Sopenharmony_ci		if (status & AG71XX_INT_RX_BE) {
177362306a36Sopenharmony_ci			ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE);
177462306a36Sopenharmony_ci			netif_err(ag, intr, ndev, "RX BUS error\n");
177562306a36Sopenharmony_ci		}
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	if (likely(status & AG71XX_INT_POLL)) {
177962306a36Sopenharmony_ci		ag71xx_int_disable(ag, AG71XX_INT_POLL);
178062306a36Sopenharmony_ci		netif_dbg(ag, intr, ndev, "enable polling mode\n");
178162306a36Sopenharmony_ci		napi_schedule(&ag->napi);
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	return IRQ_HANDLED;
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_cistatic int ag71xx_change_mtu(struct net_device *ndev, int new_mtu)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	struct ag71xx *ag = netdev_priv(ndev);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	ndev->mtu = new_mtu;
179262306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_MFL,
179362306a36Sopenharmony_ci		  ag71xx_max_frame_len(ndev->mtu));
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	return 0;
179662306a36Sopenharmony_ci}
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_cistatic const struct net_device_ops ag71xx_netdev_ops = {
179962306a36Sopenharmony_ci	.ndo_open		= ag71xx_open,
180062306a36Sopenharmony_ci	.ndo_stop		= ag71xx_stop,
180162306a36Sopenharmony_ci	.ndo_start_xmit		= ag71xx_hard_start_xmit,
180262306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl,
180362306a36Sopenharmony_ci	.ndo_tx_timeout		= ag71xx_tx_timeout,
180462306a36Sopenharmony_ci	.ndo_change_mtu		= ag71xx_change_mtu,
180562306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
180662306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
180762306a36Sopenharmony_ci};
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_cistatic const u32 ar71xx_addr_ar7100[] = {
181062306a36Sopenharmony_ci	0x19000000, 0x1a000000,
181162306a36Sopenharmony_ci};
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_cistatic int ag71xx_probe(struct platform_device *pdev)
181462306a36Sopenharmony_ci{
181562306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
181662306a36Sopenharmony_ci	const struct ag71xx_dcfg *dcfg;
181762306a36Sopenharmony_ci	struct net_device *ndev;
181862306a36Sopenharmony_ci	struct resource *res;
181962306a36Sopenharmony_ci	int tx_size, err, i;
182062306a36Sopenharmony_ci	struct ag71xx *ag;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	if (!np)
182362306a36Sopenharmony_ci		return -ENODEV;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*ag));
182662306a36Sopenharmony_ci	if (!ndev)
182762306a36Sopenharmony_ci		return -ENOMEM;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
183062306a36Sopenharmony_ci	if (!res)
183162306a36Sopenharmony_ci		return -EINVAL;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	dcfg = of_device_get_match_data(&pdev->dev);
183462306a36Sopenharmony_ci	if (!dcfg)
183562306a36Sopenharmony_ci		return -EINVAL;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	ag = netdev_priv(ndev);
183862306a36Sopenharmony_ci	ag->mac_idx = -1;
183962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ar71xx_addr_ar7100); i++) {
184062306a36Sopenharmony_ci		if (ar71xx_addr_ar7100[i] == res->start)
184162306a36Sopenharmony_ci			ag->mac_idx = i;
184262306a36Sopenharmony_ci	}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	if (ag->mac_idx < 0) {
184562306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "unknown mac idx\n");
184662306a36Sopenharmony_ci		return -EINVAL;
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	ag->clk_eth = devm_clk_get(&pdev->dev, "eth");
185062306a36Sopenharmony_ci	if (IS_ERR(ag->clk_eth)) {
185162306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "Failed to get eth clk.\n");
185262306a36Sopenharmony_ci		return PTR_ERR(ag->clk_eth);
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	SET_NETDEV_DEV(ndev, &pdev->dev);
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	ag->pdev = pdev;
185862306a36Sopenharmony_ci	ag->ndev = ndev;
185962306a36Sopenharmony_ci	ag->dcfg = dcfg;
186062306a36Sopenharmony_ci	ag->msg_enable = netif_msg_init(-1, AG71XX_DEFAULT_MSG_ENABLE);
186162306a36Sopenharmony_ci	memcpy(ag->fifodata, dcfg->fifodata, sizeof(ag->fifodata));
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac");
186462306a36Sopenharmony_ci	if (IS_ERR(ag->mac_reset)) {
186562306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "missing mac reset\n");
186662306a36Sopenharmony_ci		return PTR_ERR(ag->mac_reset);
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	ag->mac_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
187062306a36Sopenharmony_ci	if (!ag->mac_base)
187162306a36Sopenharmony_ci		return -ENOMEM;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	ndev->irq = platform_get_irq(pdev, 0);
187462306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, ndev->irq, ag71xx_interrupt,
187562306a36Sopenharmony_ci			       0x0, dev_name(&pdev->dev), ndev);
187662306a36Sopenharmony_ci	if (err) {
187762306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "unable to request IRQ %d\n",
187862306a36Sopenharmony_ci			  ndev->irq);
187962306a36Sopenharmony_ci		return err;
188062306a36Sopenharmony_ci	}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	ndev->netdev_ops = &ag71xx_netdev_ops;
188362306a36Sopenharmony_ci	ndev->ethtool_ops = &ag71xx_ethtool_ops;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	INIT_DELAYED_WORK(&ag->restart_work, ag71xx_restart_work_func);
188662306a36Sopenharmony_ci	timer_setup(&ag->oom_timer, ag71xx_oom_timer_handler, 0);
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	tx_size = AG71XX_TX_RING_SIZE_DEFAULT;
188962306a36Sopenharmony_ci	ag->rx_ring.order = ag71xx_ring_size_order(AG71XX_RX_RING_SIZE_DEFAULT);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	ndev->min_mtu = 68;
189262306a36Sopenharmony_ci	ndev->max_mtu = dcfg->max_frame_len - ag71xx_max_frame_len(0);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	ag->rx_buf_offset = NET_SKB_PAD;
189562306a36Sopenharmony_ci	if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130))
189662306a36Sopenharmony_ci		ag->rx_buf_offset += NET_IP_ALIGN;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	if (ag71xx_is(ag, AR7100)) {
189962306a36Sopenharmony_ci		ag->tx_ring.desc_split = AG71XX_TX_RING_SPLIT;
190062306a36Sopenharmony_ci		tx_size *= AG71XX_TX_RING_DS_PER_PKT;
190162306a36Sopenharmony_ci	}
190262306a36Sopenharmony_ci	ag->tx_ring.order = ag71xx_ring_size_order(tx_size);
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	ag->stop_desc = dmam_alloc_coherent(&pdev->dev,
190562306a36Sopenharmony_ci					    sizeof(struct ag71xx_desc),
190662306a36Sopenharmony_ci					    &ag->stop_desc_dma, GFP_KERNEL);
190762306a36Sopenharmony_ci	if (!ag->stop_desc)
190862306a36Sopenharmony_ci		return -ENOMEM;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	ag->stop_desc->data = 0;
191162306a36Sopenharmony_ci	ag->stop_desc->ctrl = 0;
191262306a36Sopenharmony_ci	ag->stop_desc->next = (u32)ag->stop_desc_dma;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	err = of_get_ethdev_address(np, ndev);
191562306a36Sopenharmony_ci	if (err) {
191662306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "invalid MAC address, using random address\n");
191762306a36Sopenharmony_ci		eth_hw_addr_random(ndev);
191862306a36Sopenharmony_ci	}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	err = of_get_phy_mode(np, &ag->phy_if_mode);
192162306a36Sopenharmony_ci	if (err) {
192262306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "missing phy-mode property in DT\n");
192362306a36Sopenharmony_ci		return err;
192462306a36Sopenharmony_ci	}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	netif_napi_add_weight(ndev, &ag->napi, ag71xx_poll,
192762306a36Sopenharmony_ci			      AG71XX_NAPI_WEIGHT);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	err = clk_prepare_enable(ag->clk_eth);
193062306a36Sopenharmony_ci	if (err) {
193162306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "Failed to enable eth clk.\n");
193262306a36Sopenharmony_ci		return err;
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0);
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	ag71xx_hw_init(ag);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	err = ag71xx_mdio_probe(ag);
194062306a36Sopenharmony_ci	if (err)
194162306a36Sopenharmony_ci		goto err_put_clk;
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	err = ag71xx_phylink_setup(ag);
194662306a36Sopenharmony_ci	if (err) {
194762306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "failed to setup phylink (%d)\n", err);
194862306a36Sopenharmony_ci		goto err_mdio_remove;
194962306a36Sopenharmony_ci	}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	err = register_netdev(ndev);
195262306a36Sopenharmony_ci	if (err) {
195362306a36Sopenharmony_ci		netif_err(ag, probe, ndev, "unable to register net device\n");
195462306a36Sopenharmony_ci		platform_set_drvdata(pdev, NULL);
195562306a36Sopenharmony_ci		goto err_mdio_remove;
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	netif_info(ag, probe, ndev, "Atheros AG71xx at 0x%08lx, irq %d, mode:%s\n",
195962306a36Sopenharmony_ci		   (unsigned long)ag->mac_base, ndev->irq,
196062306a36Sopenharmony_ci		   phy_modes(ag->phy_if_mode));
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	return 0;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_cierr_mdio_remove:
196562306a36Sopenharmony_ci	ag71xx_mdio_remove(ag);
196662306a36Sopenharmony_cierr_put_clk:
196762306a36Sopenharmony_ci	clk_disable_unprepare(ag->clk_eth);
196862306a36Sopenharmony_ci	return err;
196962306a36Sopenharmony_ci}
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_cistatic int ag71xx_remove(struct platform_device *pdev)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
197462306a36Sopenharmony_ci	struct ag71xx *ag;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	if (!ndev)
197762306a36Sopenharmony_ci		return 0;
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	ag = netdev_priv(ndev);
198062306a36Sopenharmony_ci	unregister_netdev(ndev);
198162306a36Sopenharmony_ci	ag71xx_mdio_remove(ag);
198262306a36Sopenharmony_ci	clk_disable_unprepare(ag->clk_eth);
198362306a36Sopenharmony_ci	platform_set_drvdata(pdev, NULL);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	return 0;
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_cistatic const u32 ar71xx_fifo_ar7100[] = {
198962306a36Sopenharmony_ci	0x0fff0000, 0x00001fff, 0x00780fff,
199062306a36Sopenharmony_ci};
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_cistatic const u32 ar71xx_fifo_ar9130[] = {
199362306a36Sopenharmony_ci	0x0fff0000, 0x00001fff, 0x008001ff,
199462306a36Sopenharmony_ci};
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_cistatic const u32 ar71xx_fifo_ar9330[] = {
199762306a36Sopenharmony_ci	0x0010ffff, 0x015500aa, 0x01f00140,
199862306a36Sopenharmony_ci};
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar7100 = {
200162306a36Sopenharmony_ci	.type = AR7100,
200262306a36Sopenharmony_ci	.fifodata = ar71xx_fifo_ar7100,
200362306a36Sopenharmony_ci	.max_frame_len = 1540,
200462306a36Sopenharmony_ci	.desc_pktlen_mask = SZ_4K - 1,
200562306a36Sopenharmony_ci	.tx_hang_workaround = false,
200662306a36Sopenharmony_ci};
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar7240 = {
200962306a36Sopenharmony_ci	.type = AR7240,
201062306a36Sopenharmony_ci	.fifodata = ar71xx_fifo_ar7100,
201162306a36Sopenharmony_ci	.max_frame_len = 1540,
201262306a36Sopenharmony_ci	.desc_pktlen_mask = SZ_4K - 1,
201362306a36Sopenharmony_ci	.tx_hang_workaround = true,
201462306a36Sopenharmony_ci};
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar9130 = {
201762306a36Sopenharmony_ci	.type = AR9130,
201862306a36Sopenharmony_ci	.fifodata = ar71xx_fifo_ar9130,
201962306a36Sopenharmony_ci	.max_frame_len = 1540,
202062306a36Sopenharmony_ci	.desc_pktlen_mask = SZ_4K - 1,
202162306a36Sopenharmony_ci	.tx_hang_workaround = false,
202262306a36Sopenharmony_ci};
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar9330 = {
202562306a36Sopenharmony_ci	.type = AR9330,
202662306a36Sopenharmony_ci	.fifodata = ar71xx_fifo_ar9330,
202762306a36Sopenharmony_ci	.max_frame_len = 1540,
202862306a36Sopenharmony_ci	.desc_pktlen_mask = SZ_4K - 1,
202962306a36Sopenharmony_ci	.tx_hang_workaround = true,
203062306a36Sopenharmony_ci};
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar9340 = {
203362306a36Sopenharmony_ci	.type = AR9340,
203462306a36Sopenharmony_ci	.fifodata = ar71xx_fifo_ar9330,
203562306a36Sopenharmony_ci	.max_frame_len = SZ_16K - 1,
203662306a36Sopenharmony_ci	.desc_pktlen_mask = SZ_16K - 1,
203762306a36Sopenharmony_ci	.tx_hang_workaround = true,
203862306a36Sopenharmony_ci};
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_qca9530 = {
204162306a36Sopenharmony_ci	.type = QCA9530,
204262306a36Sopenharmony_ci	.fifodata = ar71xx_fifo_ar9330,
204362306a36Sopenharmony_ci	.max_frame_len = SZ_16K - 1,
204462306a36Sopenharmony_ci	.desc_pktlen_mask = SZ_16K - 1,
204562306a36Sopenharmony_ci	.tx_hang_workaround = true,
204662306a36Sopenharmony_ci};
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_qca9550 = {
204962306a36Sopenharmony_ci	.type = QCA9550,
205062306a36Sopenharmony_ci	.fifodata = ar71xx_fifo_ar9330,
205162306a36Sopenharmony_ci	.max_frame_len = 1540,
205262306a36Sopenharmony_ci	.desc_pktlen_mask = SZ_16K - 1,
205362306a36Sopenharmony_ci	.tx_hang_workaround = true,
205462306a36Sopenharmony_ci};
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic const struct of_device_id ag71xx_match[] = {
205762306a36Sopenharmony_ci	{ .compatible = "qca,ar7100-eth", .data = &ag71xx_dcfg_ar7100 },
205862306a36Sopenharmony_ci	{ .compatible = "qca,ar7240-eth", .data = &ag71xx_dcfg_ar7240 },
205962306a36Sopenharmony_ci	{ .compatible = "qca,ar7241-eth", .data = &ag71xx_dcfg_ar7240 },
206062306a36Sopenharmony_ci	{ .compatible = "qca,ar7242-eth", .data = &ag71xx_dcfg_ar7240 },
206162306a36Sopenharmony_ci	{ .compatible = "qca,ar9130-eth", .data = &ag71xx_dcfg_ar9130 },
206262306a36Sopenharmony_ci	{ .compatible = "qca,ar9330-eth", .data = &ag71xx_dcfg_ar9330 },
206362306a36Sopenharmony_ci	{ .compatible = "qca,ar9340-eth", .data = &ag71xx_dcfg_ar9340 },
206462306a36Sopenharmony_ci	{ .compatible = "qca,qca9530-eth", .data = &ag71xx_dcfg_qca9530 },
206562306a36Sopenharmony_ci	{ .compatible = "qca,qca9550-eth", .data = &ag71xx_dcfg_qca9550 },
206662306a36Sopenharmony_ci	{ .compatible = "qca,qca9560-eth", .data = &ag71xx_dcfg_qca9550 },
206762306a36Sopenharmony_ci	{}
206862306a36Sopenharmony_ci};
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_cistatic struct platform_driver ag71xx_driver = {
207162306a36Sopenharmony_ci	.probe		= ag71xx_probe,
207262306a36Sopenharmony_ci	.remove		= ag71xx_remove,
207362306a36Sopenharmony_ci	.driver = {
207462306a36Sopenharmony_ci		.name	= "ag71xx",
207562306a36Sopenharmony_ci		.of_match_table = ag71xx_match,
207662306a36Sopenharmony_ci	}
207762306a36Sopenharmony_ci};
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_cimodule_platform_driver(ag71xx_driver);
208062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2081