162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/types.h>
462306a36Sopenharmony_ci#include <linux/clk.h>
562306a36Sopenharmony_ci#include <linux/platform_device.h>
662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
762306a36Sopenharmony_ci#include <linux/acpi.h>
862306a36Sopenharmony_ci#include <linux/of_mdio.h>
962306a36Sopenharmony_ci#include <linux/of_net.h>
1062306a36Sopenharmony_ci#include <linux/etherdevice.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/netlink.h>
1462306a36Sopenharmony_ci#include <linux/bpf.h>
1562306a36Sopenharmony_ci#include <linux/bpf_trace.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <net/tcp.h>
1862306a36Sopenharmony_ci#include <net/page_pool/helpers.h>
1962306a36Sopenharmony_ci#include <net/ip6_checksum.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define NETSEC_REG_SOFT_RST			0x104
2262306a36Sopenharmony_ci#define NETSEC_REG_COM_INIT			0x120
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define NETSEC_REG_TOP_STATUS			0x200
2562306a36Sopenharmony_ci#define NETSEC_IRQ_RX				BIT(1)
2662306a36Sopenharmony_ci#define NETSEC_IRQ_TX				BIT(0)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define NETSEC_REG_TOP_INTEN			0x204
2962306a36Sopenharmony_ci#define NETSEC_REG_INTEN_SET			0x234
3062306a36Sopenharmony_ci#define NETSEC_REG_INTEN_CLR			0x238
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_STATUS		0x400
3362306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_INTEN			0x404
3462306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_INTEN_SET		0x428
3562306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_INTEN_CLR		0x42c
3662306a36Sopenharmony_ci#define NRM_TX_ST_NTOWNR	BIT(17)
3762306a36Sopenharmony_ci#define NRM_TX_ST_TR_ERR	BIT(16)
3862306a36Sopenharmony_ci#define NRM_TX_ST_TXDONE	BIT(15)
3962306a36Sopenharmony_ci#define NRM_TX_ST_TMREXP	BIT(14)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_STATUS		0x440
4262306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_INTEN			0x444
4362306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_INTEN_SET		0x468
4462306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_INTEN_CLR		0x46c
4562306a36Sopenharmony_ci#define NRM_RX_ST_RC_ERR	BIT(16)
4662306a36Sopenharmony_ci#define NRM_RX_ST_PKTCNT	BIT(15)
4762306a36Sopenharmony_ci#define NRM_RX_ST_TMREXP	BIT(14)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define NETSEC_REG_PKT_CMD_BUF			0xd0
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define NETSEC_REG_CLK_EN			0x100
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define NETSEC_REG_PKT_CTRL			0x140
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define NETSEC_REG_DMA_TMR_CTRL			0x20c
5662306a36Sopenharmony_ci#define NETSEC_REG_F_TAIKI_MC_VER		0x22c
5762306a36Sopenharmony_ci#define NETSEC_REG_F_TAIKI_VER			0x230
5862306a36Sopenharmony_ci#define NETSEC_REG_DMA_HM_CTRL			0x214
5962306a36Sopenharmony_ci#define NETSEC_REG_DMA_MH_CTRL			0x220
6062306a36Sopenharmony_ci#define NETSEC_REG_ADDR_DIS_CORE		0x218
6162306a36Sopenharmony_ci#define NETSEC_REG_DMAC_HM_CMD_BUF		0x210
6262306a36Sopenharmony_ci#define NETSEC_REG_DMAC_MH_CMD_BUF		0x21c
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_PKTCNT		0x410
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_DONE_PKTCNT		0x414
6762306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT	0x418
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_TMR			0x41c
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_PKTCNT		0x454
7262306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_RXINT_PKTCNT		0x458
7362306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_TXINT_TMR		0x420
7462306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_RXINT_TMR		0x460
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_TMR			0x45c
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_DESC_START_UP		0x434
7962306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_DESC_START_LW		0x408
8062306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_DESC_START_UP		0x474
8162306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_DESC_START_LW		0x448
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define NETSEC_REG_NRM_TX_CONFIG		0x430
8462306a36Sopenharmony_ci#define NETSEC_REG_NRM_RX_CONFIG		0x470
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define MAC_REG_STATUS				0x1024
8762306a36Sopenharmony_ci#define MAC_REG_DATA				0x11c0
8862306a36Sopenharmony_ci#define MAC_REG_CMD				0x11c4
8962306a36Sopenharmony_ci#define MAC_REG_FLOW_TH				0x11cc
9062306a36Sopenharmony_ci#define MAC_REG_INTF_SEL			0x11d4
9162306a36Sopenharmony_ci#define MAC_REG_DESC_INIT			0x11fc
9262306a36Sopenharmony_ci#define MAC_REG_DESC_SOFT_RST			0x1204
9362306a36Sopenharmony_ci#define NETSEC_REG_MODE_TRANS_COMP_STATUS	0x500
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define GMAC_REG_MCR				0x0000
9662306a36Sopenharmony_ci#define GMAC_REG_MFFR				0x0004
9762306a36Sopenharmony_ci#define GMAC_REG_GAR				0x0010
9862306a36Sopenharmony_ci#define GMAC_REG_GDR				0x0014
9962306a36Sopenharmony_ci#define GMAC_REG_FCR				0x0018
10062306a36Sopenharmony_ci#define GMAC_REG_BMR				0x1000
10162306a36Sopenharmony_ci#define GMAC_REG_RDLAR				0x100c
10262306a36Sopenharmony_ci#define GMAC_REG_TDLAR				0x1010
10362306a36Sopenharmony_ci#define GMAC_REG_OMR				0x1018
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define MHZ(n)		((n) * 1000 * 1000)
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_OWN_FIELD		31
10862306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_LD_FIELD		30
10962306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_DRID_FIELD		24
11062306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_PT_FIELD		21
11162306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_TDRID_FIELD		16
11262306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_CC_FIELD		15
11362306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_FS_FIELD		9
11462306a36Sopenharmony_ci#define NETSEC_TX_LAST				8
11562306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_CO			7
11662306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_SO			6
11762306a36Sopenharmony_ci#define NETSEC_TX_SHIFT_TRS_FIELD		4
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define NETSEC_RX_PKT_OWN_FIELD			31
12062306a36Sopenharmony_ci#define NETSEC_RX_PKT_LD_FIELD			30
12162306a36Sopenharmony_ci#define NETSEC_RX_PKT_SDRID_FIELD		24
12262306a36Sopenharmony_ci#define NETSEC_RX_PKT_FR_FIELD			23
12362306a36Sopenharmony_ci#define NETSEC_RX_PKT_ER_FIELD			21
12462306a36Sopenharmony_ci#define NETSEC_RX_PKT_ERR_FIELD			16
12562306a36Sopenharmony_ci#define NETSEC_RX_PKT_TDRID_FIELD		12
12662306a36Sopenharmony_ci#define NETSEC_RX_PKT_FS_FIELD			9
12762306a36Sopenharmony_ci#define NETSEC_RX_PKT_LS_FIELD			8
12862306a36Sopenharmony_ci#define NETSEC_RX_PKT_CO_FIELD			6
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define NETSEC_RX_PKT_ERR_MASK			3
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define NETSEC_MAX_TX_PKT_LEN			1518
13362306a36Sopenharmony_ci#define NETSEC_MAX_TX_JUMBO_PKT_LEN		9018
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define NETSEC_RING_GMAC			15
13662306a36Sopenharmony_ci#define NETSEC_RING_MAX				2
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci#define NETSEC_TCP_SEG_LEN_MAX			1460
13962306a36Sopenharmony_ci#define NETSEC_TCP_JUMBO_SEG_LEN_MAX		8960
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define NETSEC_RX_CKSUM_NOTAVAIL		0
14262306a36Sopenharmony_ci#define NETSEC_RX_CKSUM_OK			1
14362306a36Sopenharmony_ci#define NETSEC_RX_CKSUM_NG			2
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define NETSEC_TOP_IRQ_REG_CODE_LOAD_END	BIT(20)
14662306a36Sopenharmony_ci#define NETSEC_IRQ_TRANSITION_COMPLETE		BIT(4)
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci#define NETSEC_MODE_TRANS_COMP_IRQ_N2T		BIT(20)
14962306a36Sopenharmony_ci#define NETSEC_MODE_TRANS_COMP_IRQ_T2N		BIT(19)
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#define NETSEC_INT_PKTCNT_MAX			2047
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define NETSEC_FLOW_START_TH_MAX		95
15462306a36Sopenharmony_ci#define NETSEC_FLOW_STOP_TH_MAX			95
15562306a36Sopenharmony_ci#define NETSEC_FLOW_PAUSE_TIME_MIN		5
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_ALL		0x3f
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_MODE_NRM		BIT(28)
16062306a36Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_EN_JUMBO		BIT(27)
16162306a36Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_LOG_CHKSUM_ER	BIT(3)
16262306a36Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_LOG_HD_INCOMPLETE	BIT(2)
16362306a36Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_LOG_HD_ER		BIT(1)
16462306a36Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_DRP_NO_MATCH	BIT(0)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_G			BIT(5)
16762306a36Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_C			BIT(1)
16862306a36Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_D			BIT(0)
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#define NETSEC_COM_INIT_REG_DB			BIT(2)
17162306a36Sopenharmony_ci#define NETSEC_COM_INIT_REG_CLS			BIT(1)
17262306a36Sopenharmony_ci#define NETSEC_COM_INIT_REG_ALL			(NETSEC_COM_INIT_REG_CLS | \
17362306a36Sopenharmony_ci						 NETSEC_COM_INIT_REG_DB)
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#define NETSEC_SOFT_RST_REG_RESET		0
17662306a36Sopenharmony_ci#define NETSEC_SOFT_RST_REG_RUN			BIT(31)
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#define NETSEC_DMA_CTRL_REG_STOP		1
17962306a36Sopenharmony_ci#define MH_CTRL__MODE_TRANS			BIT(20)
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define NETSEC_GMAC_CMD_ST_READ			0
18262306a36Sopenharmony_ci#define NETSEC_GMAC_CMD_ST_WRITE		BIT(28)
18362306a36Sopenharmony_ci#define NETSEC_GMAC_CMD_ST_BUSY			BIT(31)
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#define NETSEC_GMAC_BMR_REG_COMMON		0x00412080
18662306a36Sopenharmony_ci#define NETSEC_GMAC_BMR_REG_RESET		0x00020181
18762306a36Sopenharmony_ci#define NETSEC_GMAC_BMR_REG_SWR			0x00000001
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci#define NETSEC_GMAC_OMR_REG_ST			BIT(13)
19062306a36Sopenharmony_ci#define NETSEC_GMAC_OMR_REG_SR			BIT(1)
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_IBN			BIT(30)
19362306a36Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_CST			BIT(25)
19462306a36Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_JE			BIT(20)
19562306a36Sopenharmony_ci#define NETSEC_MCR_PS				BIT(15)
19662306a36Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_FES			BIT(14)
19762306a36Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON	0x0000280c
19862306a36Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON	0x0001a00c
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#define NETSEC_FCR_RFE				BIT(2)
20162306a36Sopenharmony_ci#define NETSEC_FCR_TFE				BIT(1)
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_GW			BIT(1)
20462306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_GB			BIT(0)
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_SHIFT_PA		11
20762306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_SHIFT_GR		6
20862306a36Sopenharmony_ci#define GMAC_REG_SHIFT_CR_GAR			2
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_25_35_MHZ	2
21162306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_35_60_MHZ	3
21262306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_60_100_MHZ	0
21362306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_100_150_MHZ	1
21462306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_150_250_MHZ	4
21562306a36Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_250_300_MHZ	5
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci#define NETSEC_GMAC_RDLAR_REG_COMMON		0x18000
21862306a36Sopenharmony_ci#define NETSEC_GMAC_TDLAR_REG_COMMON		0x1c000
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define NETSEC_REG_NETSEC_VER_F_TAIKI		0x50000
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci#define NETSEC_REG_DESC_RING_CONFIG_CFG_UP	BIT(31)
22362306a36Sopenharmony_ci#define NETSEC_REG_DESC_RING_CONFIG_CH_RST	BIT(30)
22462306a36Sopenharmony_ci#define NETSEC_REG_DESC_TMR_MODE		4
22562306a36Sopenharmony_ci#define NETSEC_REG_DESC_ENDIAN			0
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci#define NETSEC_MAC_DESC_SOFT_RST_SOFT_RST	1
22862306a36Sopenharmony_ci#define NETSEC_MAC_DESC_INIT_REG_INIT		1
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci#define NETSEC_EEPROM_MAC_ADDRESS		0x00
23162306a36Sopenharmony_ci#define NETSEC_EEPROM_HM_ME_ADDRESS_H		0x08
23262306a36Sopenharmony_ci#define NETSEC_EEPROM_HM_ME_ADDRESS_L		0x0C
23362306a36Sopenharmony_ci#define NETSEC_EEPROM_HM_ME_SIZE		0x10
23462306a36Sopenharmony_ci#define NETSEC_EEPROM_MH_ME_ADDRESS_H		0x14
23562306a36Sopenharmony_ci#define NETSEC_EEPROM_MH_ME_ADDRESS_L		0x18
23662306a36Sopenharmony_ci#define NETSEC_EEPROM_MH_ME_SIZE		0x1C
23762306a36Sopenharmony_ci#define NETSEC_EEPROM_PKT_ME_ADDRESS		0x20
23862306a36Sopenharmony_ci#define NETSEC_EEPROM_PKT_ME_SIZE		0x24
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci#define DESC_NUM	256
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci#define NETSEC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
24362306a36Sopenharmony_ci#define NETSEC_RXBUF_HEADROOM (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + \
24462306a36Sopenharmony_ci			       NET_IP_ALIGN)
24562306a36Sopenharmony_ci#define NETSEC_RX_BUF_NON_DATA (NETSEC_RXBUF_HEADROOM + \
24662306a36Sopenharmony_ci				SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
24762306a36Sopenharmony_ci#define NETSEC_RX_BUF_SIZE	(PAGE_SIZE - NETSEC_RX_BUF_NON_DATA)
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci#define DESC_SZ	sizeof(struct netsec_de)
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci#define NETSEC_F_NETSEC_VER_MAJOR_NUM(x)	((x) & 0xffff0000)
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci#define NETSEC_XDP_PASS          0
25462306a36Sopenharmony_ci#define NETSEC_XDP_CONSUMED      BIT(0)
25562306a36Sopenharmony_ci#define NETSEC_XDP_TX            BIT(1)
25662306a36Sopenharmony_ci#define NETSEC_XDP_REDIR         BIT(2)
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cienum ring_id {
25962306a36Sopenharmony_ci	NETSEC_RING_TX = 0,
26062306a36Sopenharmony_ci	NETSEC_RING_RX
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cienum buf_type {
26462306a36Sopenharmony_ci	TYPE_NETSEC_SKB = 0,
26562306a36Sopenharmony_ci	TYPE_NETSEC_XDP_TX,
26662306a36Sopenharmony_ci	TYPE_NETSEC_XDP_NDO,
26762306a36Sopenharmony_ci};
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistruct netsec_desc {
27062306a36Sopenharmony_ci	union {
27162306a36Sopenharmony_ci		struct sk_buff *skb;
27262306a36Sopenharmony_ci		struct xdp_frame *xdpf;
27362306a36Sopenharmony_ci	};
27462306a36Sopenharmony_ci	dma_addr_t dma_addr;
27562306a36Sopenharmony_ci	void *addr;
27662306a36Sopenharmony_ci	u16 len;
27762306a36Sopenharmony_ci	u8 buf_type;
27862306a36Sopenharmony_ci};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistruct netsec_desc_ring {
28162306a36Sopenharmony_ci	dma_addr_t desc_dma;
28262306a36Sopenharmony_ci	struct netsec_desc *desc;
28362306a36Sopenharmony_ci	void *vaddr;
28462306a36Sopenharmony_ci	u16 head, tail;
28562306a36Sopenharmony_ci	u16 xdp_xmit; /* netsec_xdp_xmit packets */
28662306a36Sopenharmony_ci	struct page_pool *page_pool;
28762306a36Sopenharmony_ci	struct xdp_rxq_info xdp_rxq;
28862306a36Sopenharmony_ci	spinlock_t lock; /* XDP tx queue locking */
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistruct netsec_priv {
29262306a36Sopenharmony_ci	struct netsec_desc_ring desc_ring[NETSEC_RING_MAX];
29362306a36Sopenharmony_ci	struct ethtool_coalesce et_coalesce;
29462306a36Sopenharmony_ci	struct bpf_prog *xdp_prog;
29562306a36Sopenharmony_ci	spinlock_t reglock; /* protect reg access */
29662306a36Sopenharmony_ci	struct napi_struct napi;
29762306a36Sopenharmony_ci	phy_interface_t phy_interface;
29862306a36Sopenharmony_ci	struct net_device *ndev;
29962306a36Sopenharmony_ci	struct device_node *phy_np;
30062306a36Sopenharmony_ci	struct phy_device *phydev;
30162306a36Sopenharmony_ci	struct mii_bus *mii_bus;
30262306a36Sopenharmony_ci	void __iomem *ioaddr;
30362306a36Sopenharmony_ci	void __iomem *eeprom_base;
30462306a36Sopenharmony_ci	struct device *dev;
30562306a36Sopenharmony_ci	struct clk *clk;
30662306a36Sopenharmony_ci	u32 msg_enable;
30762306a36Sopenharmony_ci	u32 freq;
30862306a36Sopenharmony_ci	u32 phy_addr;
30962306a36Sopenharmony_ci	bool rx_cksum_offload_flag;
31062306a36Sopenharmony_ci};
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistruct netsec_de { /* Netsec Descriptor layout */
31362306a36Sopenharmony_ci	u32 attr;
31462306a36Sopenharmony_ci	u32 data_buf_addr_up;
31562306a36Sopenharmony_ci	u32 data_buf_addr_lw;
31662306a36Sopenharmony_ci	u32 buf_len_info;
31762306a36Sopenharmony_ci};
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistruct netsec_tx_pkt_ctrl {
32062306a36Sopenharmony_ci	u16 tcp_seg_len;
32162306a36Sopenharmony_ci	bool tcp_seg_offload_flag;
32262306a36Sopenharmony_ci	bool cksum_offload_flag;
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistruct netsec_rx_pkt_info {
32662306a36Sopenharmony_ci	int rx_cksum_result;
32762306a36Sopenharmony_ci	int err_code;
32862306a36Sopenharmony_ci	bool err_flag;
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic void netsec_write(struct netsec_priv *priv, u32 reg_addr, u32 val)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	writel(val, priv->ioaddr + reg_addr);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic u32 netsec_read(struct netsec_priv *priv, u32 reg_addr)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	return readl(priv->ioaddr + reg_addr);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/************* MDIO BUS OPS FOLLOW *************/
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci#define TIMEOUT_SPINS_MAC		1000
34462306a36Sopenharmony_ci#define TIMEOUT_SECONDARY_MS_MAC	100
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic u32 netsec_clk_type(u32 freq)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	if (freq < MHZ(35))
34962306a36Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_25_35_MHZ;
35062306a36Sopenharmony_ci	if (freq < MHZ(60))
35162306a36Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_35_60_MHZ;
35262306a36Sopenharmony_ci	if (freq < MHZ(100))
35362306a36Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_60_100_MHZ;
35462306a36Sopenharmony_ci	if (freq < MHZ(150))
35562306a36Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_100_150_MHZ;
35662306a36Sopenharmony_ci	if (freq < MHZ(250))
35762306a36Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_150_250_MHZ;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return NETSEC_GMAC_GAR_REG_CR_250_300_MHZ;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic int netsec_wait_while_busy(struct netsec_priv *priv, u32 addr, u32 mask)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	u32 timeout = TIMEOUT_SPINS_MAC;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	while (--timeout && netsec_read(priv, addr) & mask)
36762306a36Sopenharmony_ci		cpu_relax();
36862306a36Sopenharmony_ci	if (timeout)
36962306a36Sopenharmony_ci		return 0;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	timeout = TIMEOUT_SECONDARY_MS_MAC;
37262306a36Sopenharmony_ci	while (--timeout && netsec_read(priv, addr) & mask)
37362306a36Sopenharmony_ci		usleep_range(1000, 2000);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (timeout)
37662306a36Sopenharmony_ci		return 0;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return -ETIMEDOUT;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic int netsec_mac_write(struct netsec_priv *priv, u32 addr, u32 value)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	netsec_write(priv, MAC_REG_DATA, value);
38662306a36Sopenharmony_ci	netsec_write(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_WRITE);
38762306a36Sopenharmony_ci	return netsec_wait_while_busy(priv,
38862306a36Sopenharmony_ci				      MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic int netsec_mac_read(struct netsec_priv *priv, u32 addr, u32 *read)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	int ret;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	netsec_write(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_READ);
39662306a36Sopenharmony_ci	ret = netsec_wait_while_busy(priv,
39762306a36Sopenharmony_ci				     MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
39862306a36Sopenharmony_ci	if (ret)
39962306a36Sopenharmony_ci		return ret;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	*read = netsec_read(priv, MAC_REG_DATA);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic int netsec_mac_wait_while_busy(struct netsec_priv *priv,
40762306a36Sopenharmony_ci				      u32 addr, u32 mask)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	u32 timeout = TIMEOUT_SPINS_MAC;
41062306a36Sopenharmony_ci	int ret, data;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	do {
41362306a36Sopenharmony_ci		ret = netsec_mac_read(priv, addr, &data);
41462306a36Sopenharmony_ci		if (ret)
41562306a36Sopenharmony_ci			break;
41662306a36Sopenharmony_ci		cpu_relax();
41762306a36Sopenharmony_ci	} while (--timeout && (data & mask));
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (timeout)
42062306a36Sopenharmony_ci		return 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	timeout = TIMEOUT_SECONDARY_MS_MAC;
42362306a36Sopenharmony_ci	do {
42462306a36Sopenharmony_ci		usleep_range(1000, 2000);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		ret = netsec_mac_read(priv, addr, &data);
42762306a36Sopenharmony_ci		if (ret)
42862306a36Sopenharmony_ci			break;
42962306a36Sopenharmony_ci		cpu_relax();
43062306a36Sopenharmony_ci	} while (--timeout && (data & mask));
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (timeout && !ret)
43362306a36Sopenharmony_ci		return 0;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return -ETIMEDOUT;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int netsec_mac_update_to_phy_state(struct netsec_priv *priv)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct phy_device *phydev = priv->ndev->phydev;
44362306a36Sopenharmony_ci	u32 value = 0;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	value = phydev->duplex ? NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON :
44662306a36Sopenharmony_ci				 NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (phydev->speed != SPEED_1000)
44962306a36Sopenharmony_ci		value |= NETSEC_MCR_PS;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (priv->phy_interface != PHY_INTERFACE_MODE_GMII &&
45262306a36Sopenharmony_ci	    phydev->speed == SPEED_100)
45362306a36Sopenharmony_ci		value |= NETSEC_GMAC_MCR_REG_FES;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	value |= NETSEC_GMAC_MCR_REG_CST | NETSEC_GMAC_MCR_REG_JE;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (phy_interface_mode_is_rgmii(priv->phy_interface))
45862306a36Sopenharmony_ci		value |= NETSEC_GMAC_MCR_REG_IBN;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_MCR, value))
46162306a36Sopenharmony_ci		return -ETIMEDOUT;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return 0;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic int netsec_phy_write(struct mii_bus *bus,
46962306a36Sopenharmony_ci			    int phy_addr, int reg, u16 val)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	int status;
47262306a36Sopenharmony_ci	struct netsec_priv *priv = bus->priv;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_GDR, val))
47562306a36Sopenharmony_ci		return -ETIMEDOUT;
47662306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_GAR,
47762306a36Sopenharmony_ci			     phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
47862306a36Sopenharmony_ci			     reg << NETSEC_GMAC_GAR_REG_SHIFT_GR |
47962306a36Sopenharmony_ci			     NETSEC_GMAC_GAR_REG_GW | NETSEC_GMAC_GAR_REG_GB |
48062306a36Sopenharmony_ci			     (netsec_clk_type(priv->freq) <<
48162306a36Sopenharmony_ci			      GMAC_REG_SHIFT_CR_GAR)))
48262306a36Sopenharmony_ci		return -ETIMEDOUT;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	status = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
48562306a36Sopenharmony_ci					    NETSEC_GMAC_GAR_REG_GB);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	/* Developerbox implements RTL8211E PHY and there is
48862306a36Sopenharmony_ci	 * a compatibility problem with F_GMAC4.
48962306a36Sopenharmony_ci	 * RTL8211E expects MDC clock must be kept toggling for several
49062306a36Sopenharmony_ci	 * clock cycle with MDIO high before entering the IDLE state.
49162306a36Sopenharmony_ci	 * To meet this requirement, netsec driver needs to issue dummy
49262306a36Sopenharmony_ci	 * read(e.g. read PHYID1(offset 0x2) register) right after write.
49362306a36Sopenharmony_ci	 */
49462306a36Sopenharmony_ci	netsec_phy_read(bus, phy_addr, MII_PHYSID1);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return status;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct netsec_priv *priv = bus->priv;
50262306a36Sopenharmony_ci	u32 data;
50362306a36Sopenharmony_ci	int ret;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_GAR, NETSEC_GMAC_GAR_REG_GB |
50662306a36Sopenharmony_ci			     phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
50762306a36Sopenharmony_ci			     reg_addr << NETSEC_GMAC_GAR_REG_SHIFT_GR |
50862306a36Sopenharmony_ci			     (netsec_clk_type(priv->freq) <<
50962306a36Sopenharmony_ci			      GMAC_REG_SHIFT_CR_GAR)))
51062306a36Sopenharmony_ci		return -ETIMEDOUT;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ret = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
51362306a36Sopenharmony_ci					 NETSEC_GMAC_GAR_REG_GB);
51462306a36Sopenharmony_ci	if (ret)
51562306a36Sopenharmony_ci		return ret;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_GDR, &data);
51862306a36Sopenharmony_ci	if (ret)
51962306a36Sopenharmony_ci		return ret;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return data;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/************* ETHTOOL_OPS FOLLOW *************/
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic void netsec_et_get_drvinfo(struct net_device *net_device,
52762306a36Sopenharmony_ci				  struct ethtool_drvinfo *info)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	strscpy(info->driver, "netsec", sizeof(info->driver));
53062306a36Sopenharmony_ci	strscpy(info->bus_info, dev_name(net_device->dev.parent),
53162306a36Sopenharmony_ci		sizeof(info->bus_info));
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic int netsec_et_get_coalesce(struct net_device *net_device,
53562306a36Sopenharmony_ci				  struct ethtool_coalesce *et_coalesce,
53662306a36Sopenharmony_ci				  struct kernel_ethtool_coalesce *kernel_coal,
53762306a36Sopenharmony_ci				  struct netlink_ext_ack *extack)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(net_device);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	*et_coalesce = priv->et_coalesce;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return 0;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic int netsec_et_set_coalesce(struct net_device *net_device,
54762306a36Sopenharmony_ci				  struct ethtool_coalesce *et_coalesce,
54862306a36Sopenharmony_ci				  struct kernel_ethtool_coalesce *kernel_coal,
54962306a36Sopenharmony_ci				  struct netlink_ext_ack *extack)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(net_device);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	priv->et_coalesce = *et_coalesce;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (priv->et_coalesce.tx_coalesce_usecs < 50)
55662306a36Sopenharmony_ci		priv->et_coalesce.tx_coalesce_usecs = 50;
55762306a36Sopenharmony_ci	if (priv->et_coalesce.tx_max_coalesced_frames < 1)
55862306a36Sopenharmony_ci		priv->et_coalesce.tx_max_coalesced_frames = 1;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT,
56162306a36Sopenharmony_ci		     priv->et_coalesce.tx_max_coalesced_frames);
56262306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_TXINT_TMR,
56362306a36Sopenharmony_ci		     priv->et_coalesce.tx_coalesce_usecs);
56462306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_SET, NRM_TX_ST_TXDONE);
56562306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_SET, NRM_TX_ST_TMREXP);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (priv->et_coalesce.rx_coalesce_usecs < 50)
56862306a36Sopenharmony_ci		priv->et_coalesce.rx_coalesce_usecs = 50;
56962306a36Sopenharmony_ci	if (priv->et_coalesce.rx_max_coalesced_frames < 1)
57062306a36Sopenharmony_ci		priv->et_coalesce.rx_max_coalesced_frames = 1;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_RXINT_PKTCNT,
57362306a36Sopenharmony_ci		     priv->et_coalesce.rx_max_coalesced_frames);
57462306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_RXINT_TMR,
57562306a36Sopenharmony_ci		     priv->et_coalesce.rx_coalesce_usecs);
57662306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_SET, NRM_RX_ST_PKTCNT);
57762306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_SET, NRM_RX_ST_TMREXP);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	return 0;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic u32 netsec_et_get_msglevel(struct net_device *dev)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(dev);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	return priv->msg_enable;
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic void netsec_et_set_msglevel(struct net_device *dev, u32 datum)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(dev);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	priv->msg_enable = datum;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic const struct ethtool_ops netsec_ethtool_ops = {
59762306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
59862306a36Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES,
59962306a36Sopenharmony_ci	.get_drvinfo		= netsec_et_get_drvinfo,
60062306a36Sopenharmony_ci	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
60162306a36Sopenharmony_ci	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
60262306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
60362306a36Sopenharmony_ci	.get_coalesce		= netsec_et_get_coalesce,
60462306a36Sopenharmony_ci	.set_coalesce		= netsec_et_set_coalesce,
60562306a36Sopenharmony_ci	.get_msglevel		= netsec_et_get_msglevel,
60662306a36Sopenharmony_ci	.set_msglevel		= netsec_et_set_msglevel,
60762306a36Sopenharmony_ci};
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/************* NETDEV_OPS FOLLOW *************/
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic void netsec_set_rx_de(struct netsec_priv *priv,
61362306a36Sopenharmony_ci			     struct netsec_desc_ring *dring, u16 idx,
61462306a36Sopenharmony_ci			     const struct netsec_desc *desc)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct netsec_de *de = dring->vaddr + DESC_SZ * idx;
61762306a36Sopenharmony_ci	u32 attr = (1 << NETSEC_RX_PKT_OWN_FIELD) |
61862306a36Sopenharmony_ci		   (1 << NETSEC_RX_PKT_FS_FIELD) |
61962306a36Sopenharmony_ci		   (1 << NETSEC_RX_PKT_LS_FIELD);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	if (idx == DESC_NUM - 1)
62262306a36Sopenharmony_ci		attr |= (1 << NETSEC_RX_PKT_LD_FIELD);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
62562306a36Sopenharmony_ci	de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
62662306a36Sopenharmony_ci	de->buf_len_info = desc->len;
62762306a36Sopenharmony_ci	de->attr = attr;
62862306a36Sopenharmony_ci	dma_wmb();
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	dring->desc[idx].dma_addr = desc->dma_addr;
63162306a36Sopenharmony_ci	dring->desc[idx].addr = desc->addr;
63262306a36Sopenharmony_ci	dring->desc[idx].len = desc->len;
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic bool netsec_clean_tx_dring(struct netsec_priv *priv)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
63862306a36Sopenharmony_ci	struct xdp_frame_bulk bq;
63962306a36Sopenharmony_ci	struct netsec_de *entry;
64062306a36Sopenharmony_ci	int tail = dring->tail;
64162306a36Sopenharmony_ci	unsigned int bytes;
64262306a36Sopenharmony_ci	int cnt = 0;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	spin_lock(&dring->lock);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	bytes = 0;
64762306a36Sopenharmony_ci	xdp_frame_bulk_init(&bq);
64862306a36Sopenharmony_ci	entry = dring->vaddr + DESC_SZ * tail;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	rcu_read_lock(); /* need for xdp_return_frame_bulk */
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	while (!(entry->attr & (1U << NETSEC_TX_SHIFT_OWN_FIELD)) &&
65362306a36Sopenharmony_ci	       cnt < DESC_NUM) {
65462306a36Sopenharmony_ci		struct netsec_desc *desc;
65562306a36Sopenharmony_ci		int eop;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		desc = &dring->desc[tail];
65862306a36Sopenharmony_ci		eop = (entry->attr >> NETSEC_TX_LAST) & 1;
65962306a36Sopenharmony_ci		dma_rmb();
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		/* if buf_type is either TYPE_NETSEC_SKB or
66262306a36Sopenharmony_ci		 * TYPE_NETSEC_XDP_NDO we mapped it
66362306a36Sopenharmony_ci		 */
66462306a36Sopenharmony_ci		if (desc->buf_type != TYPE_NETSEC_XDP_TX)
66562306a36Sopenharmony_ci			dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
66662306a36Sopenharmony_ci					 DMA_TO_DEVICE);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		if (!eop)
66962306a36Sopenharmony_ci			goto next;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		if (desc->buf_type == TYPE_NETSEC_SKB) {
67262306a36Sopenharmony_ci			bytes += desc->skb->len;
67362306a36Sopenharmony_ci			dev_kfree_skb(desc->skb);
67462306a36Sopenharmony_ci		} else {
67562306a36Sopenharmony_ci			bytes += desc->xdpf->len;
67662306a36Sopenharmony_ci			if (desc->buf_type == TYPE_NETSEC_XDP_TX)
67762306a36Sopenharmony_ci				xdp_return_frame_rx_napi(desc->xdpf);
67862306a36Sopenharmony_ci			else
67962306a36Sopenharmony_ci				xdp_return_frame_bulk(desc->xdpf, &bq);
68062306a36Sopenharmony_ci		}
68162306a36Sopenharmony_cinext:
68262306a36Sopenharmony_ci		/* clean up so netsec_uninit_pkt_dring() won't free the skb
68362306a36Sopenharmony_ci		 * again
68462306a36Sopenharmony_ci		 */
68562306a36Sopenharmony_ci		*desc = (struct netsec_desc){};
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		/* entry->attr is not going to be accessed by the NIC until
68862306a36Sopenharmony_ci		 * netsec_set_tx_de() is called. No need for a dma_wmb() here
68962306a36Sopenharmony_ci		 */
69062306a36Sopenharmony_ci		entry->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
69162306a36Sopenharmony_ci		/* move tail ahead */
69262306a36Sopenharmony_ci		dring->tail = (tail + 1) % DESC_NUM;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci		tail = dring->tail;
69562306a36Sopenharmony_ci		entry = dring->vaddr + DESC_SZ * tail;
69662306a36Sopenharmony_ci		cnt++;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci	xdp_flush_frame_bulk(&bq);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	rcu_read_unlock();
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	spin_unlock(&dring->lock);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (!cnt)
70562306a36Sopenharmony_ci		return false;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/* reading the register clears the irq */
70862306a36Sopenharmony_ci	netsec_read(priv, NETSEC_REG_NRM_TX_DONE_PKTCNT);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	priv->ndev->stats.tx_packets += cnt;
71162306a36Sopenharmony_ci	priv->ndev->stats.tx_bytes += bytes;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	netdev_completed_queue(priv->ndev, cnt, bytes);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return true;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic void netsec_process_tx(struct netsec_priv *priv)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct net_device *ndev = priv->ndev;
72162306a36Sopenharmony_ci	bool cleaned;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	cleaned = netsec_clean_tx_dring(priv);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (cleaned && netif_queue_stopped(ndev)) {
72662306a36Sopenharmony_ci		/* Make sure we update the value, anyone stopping the queue
72762306a36Sopenharmony_ci		 * after this will read the proper consumer idx
72862306a36Sopenharmony_ci		 */
72962306a36Sopenharmony_ci		smp_wmb();
73062306a36Sopenharmony_ci		netif_wake_queue(ndev);
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic void *netsec_alloc_rx_data(struct netsec_priv *priv,
73562306a36Sopenharmony_ci				  dma_addr_t *dma_handle, u16 *desc_len)
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
74062306a36Sopenharmony_ci	struct page *page;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	page = page_pool_dev_alloc_pages(dring->page_pool);
74362306a36Sopenharmony_ci	if (!page)
74462306a36Sopenharmony_ci		return NULL;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* We allocate the same buffer length for XDP and non-XDP cases.
74762306a36Sopenharmony_ci	 * page_pool API will map the whole page, skip what's needed for
74862306a36Sopenharmony_ci	 * network payloads and/or XDP
74962306a36Sopenharmony_ci	 */
75062306a36Sopenharmony_ci	*dma_handle = page_pool_get_dma_addr(page) + NETSEC_RXBUF_HEADROOM;
75162306a36Sopenharmony_ci	/* Make sure the incoming payload fits in the page for XDP and non-XDP
75262306a36Sopenharmony_ci	 * cases and reserve enough space for headroom + skb_shared_info
75362306a36Sopenharmony_ci	 */
75462306a36Sopenharmony_ci	*desc_len = NETSEC_RX_BUF_SIZE;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return page_address(page);
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic void netsec_rx_fill(struct netsec_priv *priv, u16 from, u16 num)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
76262306a36Sopenharmony_ci	u16 idx = from;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	while (num) {
76562306a36Sopenharmony_ci		netsec_set_rx_de(priv, dring, idx, &dring->desc[idx]);
76662306a36Sopenharmony_ci		idx++;
76762306a36Sopenharmony_ci		if (idx >= DESC_NUM)
76862306a36Sopenharmony_ci			idx = 0;
76962306a36Sopenharmony_ci		num--;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic void netsec_xdp_ring_tx_db(struct netsec_priv *priv, u16 pkts)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	if (likely(pkts))
77662306a36Sopenharmony_ci		netsec_write(priv, NETSEC_REG_NRM_TX_PKTCNT, pkts);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic void netsec_finalize_xdp_rx(struct netsec_priv *priv, u32 xdp_res,
78062306a36Sopenharmony_ci				   u16 pkts)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	if (xdp_res & NETSEC_XDP_REDIR)
78362306a36Sopenharmony_ci		xdp_do_flush_map();
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	if (xdp_res & NETSEC_XDP_TX)
78662306a36Sopenharmony_ci		netsec_xdp_ring_tx_db(priv, pkts);
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic void netsec_set_tx_de(struct netsec_priv *priv,
79062306a36Sopenharmony_ci			     struct netsec_desc_ring *dring,
79162306a36Sopenharmony_ci			     const struct netsec_tx_pkt_ctrl *tx_ctrl,
79262306a36Sopenharmony_ci			     const struct netsec_desc *desc, void *buf)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	int idx = dring->head;
79562306a36Sopenharmony_ci	struct netsec_de *de;
79662306a36Sopenharmony_ci	u32 attr;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	de = dring->vaddr + (DESC_SZ * idx);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	attr = (1 << NETSEC_TX_SHIFT_OWN_FIELD) |
80162306a36Sopenharmony_ci	       (1 << NETSEC_TX_SHIFT_PT_FIELD) |
80262306a36Sopenharmony_ci	       (NETSEC_RING_GMAC << NETSEC_TX_SHIFT_TDRID_FIELD) |
80362306a36Sopenharmony_ci	       (1 << NETSEC_TX_SHIFT_FS_FIELD) |
80462306a36Sopenharmony_ci	       (1 << NETSEC_TX_LAST) |
80562306a36Sopenharmony_ci	       (tx_ctrl->cksum_offload_flag << NETSEC_TX_SHIFT_CO) |
80662306a36Sopenharmony_ci	       (tx_ctrl->tcp_seg_offload_flag << NETSEC_TX_SHIFT_SO) |
80762306a36Sopenharmony_ci	       (1 << NETSEC_TX_SHIFT_TRS_FIELD);
80862306a36Sopenharmony_ci	if (idx == DESC_NUM - 1)
80962306a36Sopenharmony_ci		attr |= (1 << NETSEC_TX_SHIFT_LD_FIELD);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
81262306a36Sopenharmony_ci	de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
81362306a36Sopenharmony_ci	de->buf_len_info = (tx_ctrl->tcp_seg_len << 16) | desc->len;
81462306a36Sopenharmony_ci	de->attr = attr;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	dring->desc[idx] = *desc;
81762306a36Sopenharmony_ci	if (desc->buf_type == TYPE_NETSEC_SKB)
81862306a36Sopenharmony_ci		dring->desc[idx].skb = buf;
81962306a36Sopenharmony_ci	else if (desc->buf_type == TYPE_NETSEC_XDP_TX ||
82062306a36Sopenharmony_ci		 desc->buf_type == TYPE_NETSEC_XDP_NDO)
82162306a36Sopenharmony_ci		dring->desc[idx].xdpf = buf;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* move head ahead */
82462306a36Sopenharmony_ci	dring->head = (dring->head + 1) % DESC_NUM;
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci/* The current driver only supports 1 Txq, this should run under spin_lock() */
82862306a36Sopenharmony_cistatic u32 netsec_xdp_queue_one(struct netsec_priv *priv,
82962306a36Sopenharmony_ci				struct xdp_frame *xdpf, bool is_ndo)
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
83362306a36Sopenharmony_ci	struct page *page = virt_to_page(xdpf->data);
83462306a36Sopenharmony_ci	struct netsec_tx_pkt_ctrl tx_ctrl = {};
83562306a36Sopenharmony_ci	struct netsec_desc tx_desc;
83662306a36Sopenharmony_ci	dma_addr_t dma_handle;
83762306a36Sopenharmony_ci	u16 filled;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (tx_ring->head >= tx_ring->tail)
84062306a36Sopenharmony_ci		filled = tx_ring->head - tx_ring->tail;
84162306a36Sopenharmony_ci	else
84262306a36Sopenharmony_ci		filled = tx_ring->head + DESC_NUM - tx_ring->tail;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (DESC_NUM - filled <= 1)
84562306a36Sopenharmony_ci		return NETSEC_XDP_CONSUMED;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	if (is_ndo) {
84862306a36Sopenharmony_ci		/* this is for ndo_xdp_xmit, the buffer needs mapping before
84962306a36Sopenharmony_ci		 * sending
85062306a36Sopenharmony_ci		 */
85162306a36Sopenharmony_ci		dma_handle = dma_map_single(priv->dev, xdpf->data, xdpf->len,
85262306a36Sopenharmony_ci					    DMA_TO_DEVICE);
85362306a36Sopenharmony_ci		if (dma_mapping_error(priv->dev, dma_handle))
85462306a36Sopenharmony_ci			return NETSEC_XDP_CONSUMED;
85562306a36Sopenharmony_ci		tx_desc.buf_type = TYPE_NETSEC_XDP_NDO;
85662306a36Sopenharmony_ci	} else {
85762306a36Sopenharmony_ci		/* This is the device Rx buffer from page_pool. No need to remap
85862306a36Sopenharmony_ci		 * just sync and send it
85962306a36Sopenharmony_ci		 */
86062306a36Sopenharmony_ci		struct netsec_desc_ring *rx_ring =
86162306a36Sopenharmony_ci			&priv->desc_ring[NETSEC_RING_RX];
86262306a36Sopenharmony_ci		enum dma_data_direction dma_dir =
86362306a36Sopenharmony_ci			page_pool_get_dma_dir(rx_ring->page_pool);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci		dma_handle = page_pool_get_dma_addr(page) + xdpf->headroom +
86662306a36Sopenharmony_ci			sizeof(*xdpf);
86762306a36Sopenharmony_ci		dma_sync_single_for_device(priv->dev, dma_handle, xdpf->len,
86862306a36Sopenharmony_ci					   dma_dir);
86962306a36Sopenharmony_ci		tx_desc.buf_type = TYPE_NETSEC_XDP_TX;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	tx_desc.dma_addr = dma_handle;
87362306a36Sopenharmony_ci	tx_desc.addr = xdpf->data;
87462306a36Sopenharmony_ci	tx_desc.len = xdpf->len;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	netdev_sent_queue(priv->ndev, xdpf->len);
87762306a36Sopenharmony_ci	netsec_set_tx_de(priv, tx_ring, &tx_ctrl, &tx_desc, xdpf);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	return NETSEC_XDP_TX;
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic u32 netsec_xdp_xmit_back(struct netsec_priv *priv, struct xdp_buff *xdp)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
88562306a36Sopenharmony_ci	struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
88662306a36Sopenharmony_ci	u32 ret;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	if (unlikely(!xdpf))
88962306a36Sopenharmony_ci		return NETSEC_XDP_CONSUMED;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	spin_lock(&tx_ring->lock);
89262306a36Sopenharmony_ci	ret = netsec_xdp_queue_one(priv, xdpf, false);
89362306a36Sopenharmony_ci	spin_unlock(&tx_ring->lock);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	return ret;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic u32 netsec_run_xdp(struct netsec_priv *priv, struct bpf_prog *prog,
89962306a36Sopenharmony_ci			  struct xdp_buff *xdp)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
90262306a36Sopenharmony_ci	unsigned int sync, len = xdp->data_end - xdp->data;
90362306a36Sopenharmony_ci	u32 ret = NETSEC_XDP_PASS;
90462306a36Sopenharmony_ci	struct page *page;
90562306a36Sopenharmony_ci	int err;
90662306a36Sopenharmony_ci	u32 act;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	act = bpf_prog_run_xdp(prog, xdp);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
91162306a36Sopenharmony_ci	sync = xdp->data_end - xdp->data_hard_start - NETSEC_RXBUF_HEADROOM;
91262306a36Sopenharmony_ci	sync = max(sync, len);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	switch (act) {
91562306a36Sopenharmony_ci	case XDP_PASS:
91662306a36Sopenharmony_ci		ret = NETSEC_XDP_PASS;
91762306a36Sopenharmony_ci		break;
91862306a36Sopenharmony_ci	case XDP_TX:
91962306a36Sopenharmony_ci		ret = netsec_xdp_xmit_back(priv, xdp);
92062306a36Sopenharmony_ci		if (ret != NETSEC_XDP_TX) {
92162306a36Sopenharmony_ci			page = virt_to_head_page(xdp->data);
92262306a36Sopenharmony_ci			page_pool_put_page(dring->page_pool, page, sync, true);
92362306a36Sopenharmony_ci		}
92462306a36Sopenharmony_ci		break;
92562306a36Sopenharmony_ci	case XDP_REDIRECT:
92662306a36Sopenharmony_ci		err = xdp_do_redirect(priv->ndev, xdp, prog);
92762306a36Sopenharmony_ci		if (!err) {
92862306a36Sopenharmony_ci			ret = NETSEC_XDP_REDIR;
92962306a36Sopenharmony_ci		} else {
93062306a36Sopenharmony_ci			ret = NETSEC_XDP_CONSUMED;
93162306a36Sopenharmony_ci			page = virt_to_head_page(xdp->data);
93262306a36Sopenharmony_ci			page_pool_put_page(dring->page_pool, page, sync, true);
93362306a36Sopenharmony_ci		}
93462306a36Sopenharmony_ci		break;
93562306a36Sopenharmony_ci	default:
93662306a36Sopenharmony_ci		bpf_warn_invalid_xdp_action(priv->ndev, prog, act);
93762306a36Sopenharmony_ci		fallthrough;
93862306a36Sopenharmony_ci	case XDP_ABORTED:
93962306a36Sopenharmony_ci		trace_xdp_exception(priv->ndev, prog, act);
94062306a36Sopenharmony_ci		fallthrough;	/* handle aborts by dropping packet */
94162306a36Sopenharmony_ci	case XDP_DROP:
94262306a36Sopenharmony_ci		ret = NETSEC_XDP_CONSUMED;
94362306a36Sopenharmony_ci		page = virt_to_head_page(xdp->data);
94462306a36Sopenharmony_ci		page_pool_put_page(dring->page_pool, page, sync, true);
94562306a36Sopenharmony_ci		break;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return ret;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic int netsec_process_rx(struct netsec_priv *priv, int budget)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
95462306a36Sopenharmony_ci	struct net_device *ndev = priv->ndev;
95562306a36Sopenharmony_ci	struct netsec_rx_pkt_info rx_info;
95662306a36Sopenharmony_ci	enum dma_data_direction dma_dir;
95762306a36Sopenharmony_ci	struct bpf_prog *xdp_prog;
95862306a36Sopenharmony_ci	struct xdp_buff xdp;
95962306a36Sopenharmony_ci	u16 xdp_xmit = 0;
96062306a36Sopenharmony_ci	u32 xdp_act = 0;
96162306a36Sopenharmony_ci	int done = 0;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	xdp_init_buff(&xdp, PAGE_SIZE, &dring->xdp_rxq);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	xdp_prog = READ_ONCE(priv->xdp_prog);
96662306a36Sopenharmony_ci	dma_dir = page_pool_get_dma_dir(dring->page_pool);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	while (done < budget) {
96962306a36Sopenharmony_ci		u16 idx = dring->tail;
97062306a36Sopenharmony_ci		struct netsec_de *de = dring->vaddr + (DESC_SZ * idx);
97162306a36Sopenharmony_ci		struct netsec_desc *desc = &dring->desc[idx];
97262306a36Sopenharmony_ci		struct page *page = virt_to_page(desc->addr);
97362306a36Sopenharmony_ci		u32 xdp_result = NETSEC_XDP_PASS;
97462306a36Sopenharmony_ci		struct sk_buff *skb = NULL;
97562306a36Sopenharmony_ci		u16 pkt_len, desc_len;
97662306a36Sopenharmony_ci		dma_addr_t dma_handle;
97762306a36Sopenharmony_ci		void *buf_addr;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		if (de->attr & (1U << NETSEC_RX_PKT_OWN_FIELD)) {
98062306a36Sopenharmony_ci			/* reading the register clears the irq */
98162306a36Sopenharmony_ci			netsec_read(priv, NETSEC_REG_NRM_RX_PKTCNT);
98262306a36Sopenharmony_ci			break;
98362306a36Sopenharmony_ci		}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		/* This  barrier is needed to keep us from reading
98662306a36Sopenharmony_ci		 * any other fields out of the netsec_de until we have
98762306a36Sopenharmony_ci		 * verified the descriptor has been written back
98862306a36Sopenharmony_ci		 */
98962306a36Sopenharmony_ci		dma_rmb();
99062306a36Sopenharmony_ci		done++;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		pkt_len = de->buf_len_info >> 16;
99362306a36Sopenharmony_ci		rx_info.err_code = (de->attr >> NETSEC_RX_PKT_ERR_FIELD) &
99462306a36Sopenharmony_ci			NETSEC_RX_PKT_ERR_MASK;
99562306a36Sopenharmony_ci		rx_info.err_flag = (de->attr >> NETSEC_RX_PKT_ER_FIELD) & 1;
99662306a36Sopenharmony_ci		if (rx_info.err_flag) {
99762306a36Sopenharmony_ci			netif_err(priv, drv, priv->ndev,
99862306a36Sopenharmony_ci				  "%s: rx fail err(%d)\n", __func__,
99962306a36Sopenharmony_ci				  rx_info.err_code);
100062306a36Sopenharmony_ci			ndev->stats.rx_dropped++;
100162306a36Sopenharmony_ci			dring->tail = (dring->tail + 1) % DESC_NUM;
100262306a36Sopenharmony_ci			/* reuse buffer page frag */
100362306a36Sopenharmony_ci			netsec_rx_fill(priv, idx, 1);
100462306a36Sopenharmony_ci			continue;
100562306a36Sopenharmony_ci		}
100662306a36Sopenharmony_ci		rx_info.rx_cksum_result =
100762306a36Sopenharmony_ci			(de->attr >> NETSEC_RX_PKT_CO_FIELD) & 3;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci		/* allocate a fresh buffer and map it to the hardware.
101062306a36Sopenharmony_ci		 * This will eventually replace the old buffer in the hardware
101162306a36Sopenharmony_ci		 */
101262306a36Sopenharmony_ci		buf_addr = netsec_alloc_rx_data(priv, &dma_handle, &desc_len);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		if (unlikely(!buf_addr))
101562306a36Sopenharmony_ci			break;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci		dma_sync_single_for_cpu(priv->dev, desc->dma_addr, pkt_len,
101862306a36Sopenharmony_ci					dma_dir);
101962306a36Sopenharmony_ci		prefetch(desc->addr);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		xdp_prepare_buff(&xdp, desc->addr, NETSEC_RXBUF_HEADROOM,
102262306a36Sopenharmony_ci				 pkt_len, false);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci		if (xdp_prog) {
102562306a36Sopenharmony_ci			xdp_result = netsec_run_xdp(priv, xdp_prog, &xdp);
102662306a36Sopenharmony_ci			if (xdp_result != NETSEC_XDP_PASS) {
102762306a36Sopenharmony_ci				xdp_act |= xdp_result;
102862306a36Sopenharmony_ci				if (xdp_result == NETSEC_XDP_TX)
102962306a36Sopenharmony_ci					xdp_xmit++;
103062306a36Sopenharmony_ci				goto next;
103162306a36Sopenharmony_ci			}
103262306a36Sopenharmony_ci		}
103362306a36Sopenharmony_ci		skb = build_skb(desc->addr, desc->len + NETSEC_RX_BUF_NON_DATA);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		if (unlikely(!skb)) {
103662306a36Sopenharmony_ci			/* If skb fails recycle_direct will either unmap and
103762306a36Sopenharmony_ci			 * free the page or refill the cache depending on the
103862306a36Sopenharmony_ci			 * cache state. Since we paid the allocation cost if
103962306a36Sopenharmony_ci			 * building an skb fails try to put the page into cache
104062306a36Sopenharmony_ci			 */
104162306a36Sopenharmony_ci			page_pool_put_page(dring->page_pool, page, pkt_len,
104262306a36Sopenharmony_ci					   true);
104362306a36Sopenharmony_ci			netif_err(priv, drv, priv->ndev,
104462306a36Sopenharmony_ci				  "rx failed to build skb\n");
104562306a36Sopenharmony_ci			break;
104662306a36Sopenharmony_ci		}
104762306a36Sopenharmony_ci		skb_mark_for_recycle(skb);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci		skb_reserve(skb, xdp.data - xdp.data_hard_start);
105062306a36Sopenharmony_ci		skb_put(skb, xdp.data_end - xdp.data);
105162306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, priv->ndev);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		if (priv->rx_cksum_offload_flag &&
105462306a36Sopenharmony_ci		    rx_info.rx_cksum_result == NETSEC_RX_CKSUM_OK)
105562306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cinext:
105862306a36Sopenharmony_ci		if (skb)
105962306a36Sopenharmony_ci			napi_gro_receive(&priv->napi, skb);
106062306a36Sopenharmony_ci		if (skb || xdp_result) {
106162306a36Sopenharmony_ci			ndev->stats.rx_packets++;
106262306a36Sopenharmony_ci			ndev->stats.rx_bytes += xdp.data_end - xdp.data;
106362306a36Sopenharmony_ci		}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		/* Update the descriptor with fresh buffers */
106662306a36Sopenharmony_ci		desc->len = desc_len;
106762306a36Sopenharmony_ci		desc->dma_addr = dma_handle;
106862306a36Sopenharmony_ci		desc->addr = buf_addr;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci		netsec_rx_fill(priv, idx, 1);
107162306a36Sopenharmony_ci		dring->tail = (dring->tail + 1) % DESC_NUM;
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci	netsec_finalize_xdp_rx(priv, xdp_act, xdp_xmit);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	return done;
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic int netsec_napi_poll(struct napi_struct *napi, int budget)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	struct netsec_priv *priv;
108162306a36Sopenharmony_ci	int done;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	priv = container_of(napi, struct netsec_priv, napi);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	netsec_process_tx(priv);
108662306a36Sopenharmony_ci	done = netsec_process_rx(priv, budget);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	if (done < budget && napi_complete_done(napi, done)) {
108962306a36Sopenharmony_ci		unsigned long flags;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci		spin_lock_irqsave(&priv->reglock, flags);
109262306a36Sopenharmony_ci		netsec_write(priv, NETSEC_REG_INTEN_SET,
109362306a36Sopenharmony_ci			     NETSEC_IRQ_RX | NETSEC_IRQ_TX);
109462306a36Sopenharmony_ci		spin_unlock_irqrestore(&priv->reglock, flags);
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	return done;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic int netsec_desc_used(struct netsec_desc_ring *dring)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	int used;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (dring->head >= dring->tail)
110662306a36Sopenharmony_ci		used = dring->head - dring->tail;
110762306a36Sopenharmony_ci	else
110862306a36Sopenharmony_ci		used = dring->head + DESC_NUM - dring->tail;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	return used;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int netsec_check_stop_tx(struct netsec_priv *priv, int used)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	/* keep tail from touching the queue */
111862306a36Sopenharmony_ci	if (DESC_NUM - used < 2) {
111962306a36Sopenharmony_ci		netif_stop_queue(priv->ndev);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		/* Make sure we read the updated value in case
112262306a36Sopenharmony_ci		 * descriptors got freed
112362306a36Sopenharmony_ci		 */
112462306a36Sopenharmony_ci		smp_rmb();
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci		used = netsec_desc_used(dring);
112762306a36Sopenharmony_ci		if (DESC_NUM - used < 2)
112862306a36Sopenharmony_ci			return NETDEV_TX_BUSY;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		netif_wake_queue(priv->ndev);
113162306a36Sopenharmony_ci	}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	return 0;
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb,
113762306a36Sopenharmony_ci					    struct net_device *ndev)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
114062306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
114162306a36Sopenharmony_ci	struct netsec_tx_pkt_ctrl tx_ctrl = {};
114262306a36Sopenharmony_ci	struct netsec_desc tx_desc;
114362306a36Sopenharmony_ci	u16 tso_seg_len = 0;
114462306a36Sopenharmony_ci	int filled;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	spin_lock_bh(&dring->lock);
114762306a36Sopenharmony_ci	filled = netsec_desc_used(dring);
114862306a36Sopenharmony_ci	if (netsec_check_stop_tx(priv, filled)) {
114962306a36Sopenharmony_ci		spin_unlock_bh(&dring->lock);
115062306a36Sopenharmony_ci		net_warn_ratelimited("%s %s Tx queue full\n",
115162306a36Sopenharmony_ci				     dev_name(priv->dev), ndev->name);
115262306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
115362306a36Sopenharmony_ci	}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL)
115662306a36Sopenharmony_ci		tx_ctrl.cksum_offload_flag = true;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (skb_is_gso(skb))
115962306a36Sopenharmony_ci		tso_seg_len = skb_shinfo(skb)->gso_size;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (tso_seg_len > 0) {
116262306a36Sopenharmony_ci		if (skb->protocol == htons(ETH_P_IP)) {
116362306a36Sopenharmony_ci			ip_hdr(skb)->tot_len = 0;
116462306a36Sopenharmony_ci			tcp_hdr(skb)->check =
116562306a36Sopenharmony_ci				~tcp_v4_check(0, ip_hdr(skb)->saddr,
116662306a36Sopenharmony_ci					      ip_hdr(skb)->daddr, 0);
116762306a36Sopenharmony_ci		} else {
116862306a36Sopenharmony_ci			tcp_v6_gso_csum_prep(skb);
116962306a36Sopenharmony_ci		}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		tx_ctrl.tcp_seg_offload_flag = true;
117262306a36Sopenharmony_ci		tx_ctrl.tcp_seg_len = tso_seg_len;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	tx_desc.dma_addr = dma_map_single(priv->dev, skb->data,
117662306a36Sopenharmony_ci					  skb_headlen(skb), DMA_TO_DEVICE);
117762306a36Sopenharmony_ci	if (dma_mapping_error(priv->dev, tx_desc.dma_addr)) {
117862306a36Sopenharmony_ci		spin_unlock_bh(&dring->lock);
117962306a36Sopenharmony_ci		netif_err(priv, drv, priv->ndev,
118062306a36Sopenharmony_ci			  "%s: DMA mapping failed\n", __func__);
118162306a36Sopenharmony_ci		ndev->stats.tx_dropped++;
118262306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
118362306a36Sopenharmony_ci		return NETDEV_TX_OK;
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci	tx_desc.addr = skb->data;
118662306a36Sopenharmony_ci	tx_desc.len = skb_headlen(skb);
118762306a36Sopenharmony_ci	tx_desc.buf_type = TYPE_NETSEC_SKB;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	skb_tx_timestamp(skb);
119062306a36Sopenharmony_ci	netdev_sent_queue(priv->ndev, skb->len);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	netsec_set_tx_de(priv, dring, &tx_ctrl, &tx_desc, skb);
119362306a36Sopenharmony_ci	spin_unlock_bh(&dring->lock);
119462306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_PKTCNT, 1); /* submit another tx */
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return NETDEV_TX_OK;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[id];
120262306a36Sopenharmony_ci	struct netsec_desc *desc;
120362306a36Sopenharmony_ci	u16 idx;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (!dring->vaddr || !dring->desc)
120662306a36Sopenharmony_ci		return;
120762306a36Sopenharmony_ci	for (idx = 0; idx < DESC_NUM; idx++) {
120862306a36Sopenharmony_ci		desc = &dring->desc[idx];
120962306a36Sopenharmony_ci		if (!desc->addr)
121062306a36Sopenharmony_ci			continue;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci		if (id == NETSEC_RING_RX) {
121362306a36Sopenharmony_ci			struct page *page = virt_to_page(desc->addr);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci			page_pool_put_full_page(dring->page_pool, page, false);
121662306a36Sopenharmony_ci		} else if (id == NETSEC_RING_TX) {
121762306a36Sopenharmony_ci			dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
121862306a36Sopenharmony_ci					 DMA_TO_DEVICE);
121962306a36Sopenharmony_ci			dev_kfree_skb(desc->skb);
122062306a36Sopenharmony_ci		}
122162306a36Sopenharmony_ci	}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	/* Rx is currently using page_pool */
122462306a36Sopenharmony_ci	if (id == NETSEC_RING_RX) {
122562306a36Sopenharmony_ci		if (xdp_rxq_info_is_reg(&dring->xdp_rxq))
122662306a36Sopenharmony_ci			xdp_rxq_info_unreg(&dring->xdp_rxq);
122762306a36Sopenharmony_ci		page_pool_destroy(dring->page_pool);
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	memset(dring->desc, 0, sizeof(struct netsec_desc) * DESC_NUM);
123162306a36Sopenharmony_ci	memset(dring->vaddr, 0, DESC_SZ * DESC_NUM);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	dring->head = 0;
123462306a36Sopenharmony_ci	dring->tail = 0;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	if (id == NETSEC_RING_TX)
123762306a36Sopenharmony_ci		netdev_reset_queue(priv->ndev);
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic void netsec_free_dring(struct netsec_priv *priv, int id)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[id];
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (dring->vaddr) {
124562306a36Sopenharmony_ci		dma_free_coherent(priv->dev, DESC_SZ * DESC_NUM,
124662306a36Sopenharmony_ci				  dring->vaddr, dring->desc_dma);
124762306a36Sopenharmony_ci		dring->vaddr = NULL;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	kfree(dring->desc);
125162306a36Sopenharmony_ci	dring->desc = NULL;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[id];
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	dring->vaddr = dma_alloc_coherent(priv->dev, DESC_SZ * DESC_NUM,
125962306a36Sopenharmony_ci					  &dring->desc_dma, GFP_KERNEL);
126062306a36Sopenharmony_ci	if (!dring->vaddr)
126162306a36Sopenharmony_ci		goto err;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	dring->desc = kcalloc(DESC_NUM, sizeof(*dring->desc), GFP_KERNEL);
126462306a36Sopenharmony_ci	if (!dring->desc)
126562306a36Sopenharmony_ci		goto err;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	return 0;
126862306a36Sopenharmony_cierr:
126962306a36Sopenharmony_ci	netsec_free_dring(priv, id);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	return -ENOMEM;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic void netsec_setup_tx_dring(struct netsec_priv *priv)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
127762306a36Sopenharmony_ci	int i;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	for (i = 0; i < DESC_NUM; i++) {
128062306a36Sopenharmony_ci		struct netsec_de *de;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci		de = dring->vaddr + (DESC_SZ * i);
128362306a36Sopenharmony_ci		/* de->attr is not going to be accessed by the NIC
128462306a36Sopenharmony_ci		 * until netsec_set_tx_de() is called.
128562306a36Sopenharmony_ci		 * No need for a dma_wmb() here
128662306a36Sopenharmony_ci		 */
128762306a36Sopenharmony_ci		de->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
128862306a36Sopenharmony_ci	}
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic int netsec_setup_rx_dring(struct netsec_priv *priv)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
129462306a36Sopenharmony_ci	struct bpf_prog *xdp_prog = READ_ONCE(priv->xdp_prog);
129562306a36Sopenharmony_ci	struct page_pool_params pp_params = {
129662306a36Sopenharmony_ci		.order = 0,
129762306a36Sopenharmony_ci		/* internal DMA mapping in page_pool */
129862306a36Sopenharmony_ci		.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
129962306a36Sopenharmony_ci		.pool_size = DESC_NUM,
130062306a36Sopenharmony_ci		.nid = NUMA_NO_NODE,
130162306a36Sopenharmony_ci		.dev = priv->dev,
130262306a36Sopenharmony_ci		.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE,
130362306a36Sopenharmony_ci		.offset = NETSEC_RXBUF_HEADROOM,
130462306a36Sopenharmony_ci		.max_len = NETSEC_RX_BUF_SIZE,
130562306a36Sopenharmony_ci	};
130662306a36Sopenharmony_ci	int i, err;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	dring->page_pool = page_pool_create(&pp_params);
130962306a36Sopenharmony_ci	if (IS_ERR(dring->page_pool)) {
131062306a36Sopenharmony_ci		err = PTR_ERR(dring->page_pool);
131162306a36Sopenharmony_ci		dring->page_pool = NULL;
131262306a36Sopenharmony_ci		goto err_out;
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	err = xdp_rxq_info_reg(&dring->xdp_rxq, priv->ndev, 0, priv->napi.napi_id);
131662306a36Sopenharmony_ci	if (err)
131762306a36Sopenharmony_ci		goto err_out;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	err = xdp_rxq_info_reg_mem_model(&dring->xdp_rxq, MEM_TYPE_PAGE_POOL,
132062306a36Sopenharmony_ci					 dring->page_pool);
132162306a36Sopenharmony_ci	if (err)
132262306a36Sopenharmony_ci		goto err_out;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	for (i = 0; i < DESC_NUM; i++) {
132562306a36Sopenharmony_ci		struct netsec_desc *desc = &dring->desc[i];
132662306a36Sopenharmony_ci		dma_addr_t dma_handle;
132762306a36Sopenharmony_ci		void *buf;
132862306a36Sopenharmony_ci		u16 len;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		buf = netsec_alloc_rx_data(priv, &dma_handle, &len);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci		if (!buf) {
133362306a36Sopenharmony_ci			err = -ENOMEM;
133462306a36Sopenharmony_ci			goto err_out;
133562306a36Sopenharmony_ci		}
133662306a36Sopenharmony_ci		desc->dma_addr = dma_handle;
133762306a36Sopenharmony_ci		desc->addr = buf;
133862306a36Sopenharmony_ci		desc->len = len;
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	netsec_rx_fill(priv, 0, DESC_NUM);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	return 0;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cierr_out:
134662306a36Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
134762306a36Sopenharmony_ci	return err;
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic int netsec_netdev_load_ucode_region(struct netsec_priv *priv, u32 reg,
135162306a36Sopenharmony_ci					   u32 addr_h, u32 addr_l, u32 size)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	u64 base = (u64)addr_h << 32 | addr_l;
135462306a36Sopenharmony_ci	void __iomem *ucode;
135562306a36Sopenharmony_ci	u32 i;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	ucode = ioremap(base, size * sizeof(u32));
135862306a36Sopenharmony_ci	if (!ucode)
135962306a36Sopenharmony_ci		return -ENOMEM;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	for (i = 0; i < size; i++)
136262306a36Sopenharmony_ci		netsec_write(priv, reg, readl(ucode + i * 4));
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	iounmap(ucode);
136562306a36Sopenharmony_ci	return 0;
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic int netsec_netdev_load_microcode(struct netsec_priv *priv)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	u32 addr_h, addr_l, size;
137162306a36Sopenharmony_ci	int err;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	addr_h = readl(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_H);
137462306a36Sopenharmony_ci	addr_l = readl(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_L);
137562306a36Sopenharmony_ci	size = readl(priv->eeprom_base + NETSEC_EEPROM_HM_ME_SIZE);
137662306a36Sopenharmony_ci	err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_DMAC_HM_CMD_BUF,
137762306a36Sopenharmony_ci					      addr_h, addr_l, size);
137862306a36Sopenharmony_ci	if (err)
137962306a36Sopenharmony_ci		return err;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	addr_h = readl(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_H);
138262306a36Sopenharmony_ci	addr_l = readl(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_L);
138362306a36Sopenharmony_ci	size = readl(priv->eeprom_base + NETSEC_EEPROM_MH_ME_SIZE);
138462306a36Sopenharmony_ci	err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_DMAC_MH_CMD_BUF,
138562306a36Sopenharmony_ci					      addr_h, addr_l, size);
138662306a36Sopenharmony_ci	if (err)
138762306a36Sopenharmony_ci		return err;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	addr_h = 0;
139062306a36Sopenharmony_ci	addr_l = readl(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_ADDRESS);
139162306a36Sopenharmony_ci	size = readl(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_SIZE);
139262306a36Sopenharmony_ci	err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_PKT_CMD_BUF,
139362306a36Sopenharmony_ci					      addr_h, addr_l, size);
139462306a36Sopenharmony_ci	if (err)
139562306a36Sopenharmony_ci		return err;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	return 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic int netsec_reset_hardware(struct netsec_priv *priv,
140162306a36Sopenharmony_ci				 bool load_ucode)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	u32 value;
140462306a36Sopenharmony_ci	int err;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	/* stop DMA engines */
140762306a36Sopenharmony_ci	if (!netsec_read(priv, NETSEC_REG_ADDR_DIS_CORE)) {
140862306a36Sopenharmony_ci		netsec_write(priv, NETSEC_REG_DMA_HM_CTRL,
140962306a36Sopenharmony_ci			     NETSEC_DMA_CTRL_REG_STOP);
141062306a36Sopenharmony_ci		netsec_write(priv, NETSEC_REG_DMA_MH_CTRL,
141162306a36Sopenharmony_ci			     NETSEC_DMA_CTRL_REG_STOP);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci		while (netsec_read(priv, NETSEC_REG_DMA_HM_CTRL) &
141462306a36Sopenharmony_ci		       NETSEC_DMA_CTRL_REG_STOP)
141562306a36Sopenharmony_ci			cpu_relax();
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci		while (netsec_read(priv, NETSEC_REG_DMA_MH_CTRL) &
141862306a36Sopenharmony_ci		       NETSEC_DMA_CTRL_REG_STOP)
141962306a36Sopenharmony_ci			cpu_relax();
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RESET);
142362306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RUN);
142462306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_COM_INIT, NETSEC_COM_INIT_REG_ALL);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	while (netsec_read(priv, NETSEC_REG_COM_INIT) != 0)
142762306a36Sopenharmony_ci		cpu_relax();
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	/* set desc_start addr */
143062306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_DESC_START_UP,
143162306a36Sopenharmony_ci		     upper_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_dma));
143262306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_DESC_START_LW,
143362306a36Sopenharmony_ci		     lower_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_dma));
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_DESC_START_UP,
143662306a36Sopenharmony_ci		     upper_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_dma));
143762306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_DESC_START_LW,
143862306a36Sopenharmony_ci		     lower_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_dma));
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	/* set normal tx dring ring config */
144162306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_CONFIG,
144262306a36Sopenharmony_ci		     1 << NETSEC_REG_DESC_ENDIAN);
144362306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_CONFIG,
144462306a36Sopenharmony_ci		     1 << NETSEC_REG_DESC_ENDIAN);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (load_ucode) {
144762306a36Sopenharmony_ci		err = netsec_netdev_load_microcode(priv);
144862306a36Sopenharmony_ci		if (err) {
144962306a36Sopenharmony_ci			netif_err(priv, probe, priv->ndev,
145062306a36Sopenharmony_ci				  "%s: failed to load microcode (%d)\n",
145162306a36Sopenharmony_ci				  __func__, err);
145262306a36Sopenharmony_ci			return err;
145362306a36Sopenharmony_ci		}
145462306a36Sopenharmony_ci	}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/* start DMA engines */
145762306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_DMA_TMR_CTRL, priv->freq / 1000000 - 1);
145862306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_ADDR_DIS_CORE, 0);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	usleep_range(1000, 2000);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	if (!(netsec_read(priv, NETSEC_REG_TOP_STATUS) &
146362306a36Sopenharmony_ci	      NETSEC_TOP_IRQ_REG_CODE_LOAD_END)) {
146462306a36Sopenharmony_ci		netif_err(priv, probe, priv->ndev,
146562306a36Sopenharmony_ci			  "microengine start failed\n");
146662306a36Sopenharmony_ci		return -ENXIO;
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_TOP_STATUS,
146962306a36Sopenharmony_ci		     NETSEC_TOP_IRQ_REG_CODE_LOAD_END);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	value = NETSEC_PKT_CTRL_REG_MODE_NRM;
147262306a36Sopenharmony_ci	if (priv->ndev->mtu > ETH_DATA_LEN)
147362306a36Sopenharmony_ci		value |= NETSEC_PKT_CTRL_REG_EN_JUMBO;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	/* change to normal mode */
147662306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_DMA_MH_CTRL, MH_CTRL__MODE_TRANS);
147762306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_PKT_CTRL, value);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	while ((netsec_read(priv, NETSEC_REG_MODE_TRANS_COMP_STATUS) &
148062306a36Sopenharmony_ci		NETSEC_MODE_TRANS_COMP_IRQ_T2N) == 0)
148162306a36Sopenharmony_ci		cpu_relax();
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	/* clear any pending EMPTY/ERR irq status */
148462306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_STATUS, ~0);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	/* Disable TX & RX intr */
148762306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_CLR, ~0);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	return 0;
149062306a36Sopenharmony_ci}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_cistatic int netsec_start_gmac(struct netsec_priv *priv)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	struct phy_device *phydev = priv->ndev->phydev;
149562306a36Sopenharmony_ci	u32 value = 0;
149662306a36Sopenharmony_ci	int ret;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	if (phydev->speed != SPEED_1000)
149962306a36Sopenharmony_ci		value = (NETSEC_GMAC_MCR_REG_CST |
150062306a36Sopenharmony_ci			 NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_MCR, value))
150362306a36Sopenharmony_ci		return -ETIMEDOUT;
150462306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_BMR,
150562306a36Sopenharmony_ci			     NETSEC_GMAC_BMR_REG_RESET))
150662306a36Sopenharmony_ci		return -ETIMEDOUT;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/* Wait soft reset */
150962306a36Sopenharmony_ci	usleep_range(1000, 5000);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_BMR, &value);
151262306a36Sopenharmony_ci	if (ret)
151362306a36Sopenharmony_ci		return ret;
151462306a36Sopenharmony_ci	if (value & NETSEC_GMAC_BMR_REG_SWR)
151562306a36Sopenharmony_ci		return -EAGAIN;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	netsec_write(priv, MAC_REG_DESC_SOFT_RST, 1);
151862306a36Sopenharmony_ci	if (netsec_wait_while_busy(priv, MAC_REG_DESC_SOFT_RST, 1))
151962306a36Sopenharmony_ci		return -ETIMEDOUT;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	netsec_write(priv, MAC_REG_DESC_INIT, 1);
152262306a36Sopenharmony_ci	if (netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1))
152362306a36Sopenharmony_ci		return -ETIMEDOUT;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_BMR,
152662306a36Sopenharmony_ci			     NETSEC_GMAC_BMR_REG_COMMON))
152762306a36Sopenharmony_ci		return -ETIMEDOUT;
152862306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_RDLAR,
152962306a36Sopenharmony_ci			     NETSEC_GMAC_RDLAR_REG_COMMON))
153062306a36Sopenharmony_ci		return -ETIMEDOUT;
153162306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_TDLAR,
153262306a36Sopenharmony_ci			     NETSEC_GMAC_TDLAR_REG_COMMON))
153362306a36Sopenharmony_ci		return -ETIMEDOUT;
153462306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_MFFR, 0x80000001))
153562306a36Sopenharmony_ci		return -ETIMEDOUT;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	ret = netsec_mac_update_to_phy_state(priv);
153862306a36Sopenharmony_ci	if (ret)
153962306a36Sopenharmony_ci		return ret;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
154262306a36Sopenharmony_ci	if (ret)
154362306a36Sopenharmony_ci		return ret;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	value |= NETSEC_GMAC_OMR_REG_SR;
154662306a36Sopenharmony_ci	value |= NETSEC_GMAC_OMR_REG_ST;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0);
154962306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	netsec_et_set_coalesce(priv->ndev, &priv->et_coalesce, NULL, NULL);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_OMR, value))
155462306a36Sopenharmony_ci		return -ETIMEDOUT;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	return 0;
155762306a36Sopenharmony_ci}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_cistatic int netsec_stop_gmac(struct netsec_priv *priv)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	u32 value;
156262306a36Sopenharmony_ci	int ret;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
156562306a36Sopenharmony_ci	if (ret)
156662306a36Sopenharmony_ci		return ret;
156762306a36Sopenharmony_ci	value &= ~NETSEC_GMAC_OMR_REG_SR;
156862306a36Sopenharmony_ci	value &= ~NETSEC_GMAC_OMR_REG_ST;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	/* disable all interrupts */
157162306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0);
157262306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	return netsec_mac_write(priv, GMAC_REG_OMR, value);
157562306a36Sopenharmony_ci}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_cistatic void netsec_phy_adjust_link(struct net_device *ndev)
157862306a36Sopenharmony_ci{
157962306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	if (ndev->phydev->link)
158262306a36Sopenharmony_ci		netsec_start_gmac(priv);
158362306a36Sopenharmony_ci	else
158462306a36Sopenharmony_ci		netsec_stop_gmac(priv);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	phy_print_status(ndev->phydev);
158762306a36Sopenharmony_ci}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_cistatic irqreturn_t netsec_irq_handler(int irq, void *dev_id)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	struct netsec_priv *priv = dev_id;
159262306a36Sopenharmony_ci	u32 val, status = netsec_read(priv, NETSEC_REG_TOP_STATUS);
159362306a36Sopenharmony_ci	unsigned long flags;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	/* Disable interrupts */
159662306a36Sopenharmony_ci	if (status & NETSEC_IRQ_TX) {
159762306a36Sopenharmony_ci		val = netsec_read(priv, NETSEC_REG_NRM_TX_STATUS);
159862306a36Sopenharmony_ci		netsec_write(priv, NETSEC_REG_NRM_TX_STATUS, val);
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci	if (status & NETSEC_IRQ_RX) {
160162306a36Sopenharmony_ci		val = netsec_read(priv, NETSEC_REG_NRM_RX_STATUS);
160262306a36Sopenharmony_ci		netsec_write(priv, NETSEC_REG_NRM_RX_STATUS, val);
160362306a36Sopenharmony_ci	}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	spin_lock_irqsave(&priv->reglock, flags);
160662306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_CLR, NETSEC_IRQ_RX | NETSEC_IRQ_TX);
160762306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->reglock, flags);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	napi_schedule(&priv->napi);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	return IRQ_HANDLED;
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_cistatic int netsec_netdev_open(struct net_device *ndev)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
161762306a36Sopenharmony_ci	int ret;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	pm_runtime_get_sync(priv->dev);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	netsec_setup_tx_dring(priv);
162262306a36Sopenharmony_ci	ret = netsec_setup_rx_dring(priv);
162362306a36Sopenharmony_ci	if (ret) {
162462306a36Sopenharmony_ci		netif_err(priv, probe, priv->ndev,
162562306a36Sopenharmony_ci			  "%s: fail setup ring\n", __func__);
162662306a36Sopenharmony_ci		goto err1;
162762306a36Sopenharmony_ci	}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	ret = request_irq(priv->ndev->irq, netsec_irq_handler,
163062306a36Sopenharmony_ci			  IRQF_SHARED, "netsec", priv);
163162306a36Sopenharmony_ci	if (ret) {
163262306a36Sopenharmony_ci		netif_err(priv, drv, priv->ndev, "request_irq failed\n");
163362306a36Sopenharmony_ci		goto err2;
163462306a36Sopenharmony_ci	}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	if (dev_of_node(priv->dev)) {
163762306a36Sopenharmony_ci		if (!of_phy_connect(priv->ndev, priv->phy_np,
163862306a36Sopenharmony_ci				    netsec_phy_adjust_link, 0,
163962306a36Sopenharmony_ci				    priv->phy_interface)) {
164062306a36Sopenharmony_ci			netif_err(priv, link, priv->ndev, "missing PHY\n");
164162306a36Sopenharmony_ci			ret = -ENODEV;
164262306a36Sopenharmony_ci			goto err3;
164362306a36Sopenharmony_ci		}
164462306a36Sopenharmony_ci	} else {
164562306a36Sopenharmony_ci		ret = phy_connect_direct(priv->ndev, priv->phydev,
164662306a36Sopenharmony_ci					 netsec_phy_adjust_link,
164762306a36Sopenharmony_ci					 priv->phy_interface);
164862306a36Sopenharmony_ci		if (ret) {
164962306a36Sopenharmony_ci			netif_err(priv, link, priv->ndev,
165062306a36Sopenharmony_ci				  "phy_connect_direct() failed (%d)\n", ret);
165162306a36Sopenharmony_ci			goto err3;
165262306a36Sopenharmony_ci		}
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	phy_start(ndev->phydev);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	netsec_start_gmac(priv);
165862306a36Sopenharmony_ci	napi_enable(&priv->napi);
165962306a36Sopenharmony_ci	netif_start_queue(ndev);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	/* Enable TX+RX intr. */
166262306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_SET, NETSEC_IRQ_RX | NETSEC_IRQ_TX);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	return 0;
166562306a36Sopenharmony_cierr3:
166662306a36Sopenharmony_ci	free_irq(priv->ndev->irq, priv);
166762306a36Sopenharmony_cierr2:
166862306a36Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
166962306a36Sopenharmony_cierr1:
167062306a36Sopenharmony_ci	pm_runtime_put_sync(priv->dev);
167162306a36Sopenharmony_ci	return ret;
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_cistatic int netsec_netdev_stop(struct net_device *ndev)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	int ret;
167762306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	netif_stop_queue(priv->ndev);
168062306a36Sopenharmony_ci	dma_wmb();
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	napi_disable(&priv->napi);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_CLR, ~0);
168562306a36Sopenharmony_ci	netsec_stop_gmac(priv);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	free_irq(priv->ndev->irq, priv);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_TX);
169062306a36Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	phy_stop(ndev->phydev);
169362306a36Sopenharmony_ci	phy_disconnect(ndev->phydev);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	ret = netsec_reset_hardware(priv, false);
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	pm_runtime_put_sync(priv->dev);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	return ret;
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic int netsec_netdev_init(struct net_device *ndev)
170362306a36Sopenharmony_ci{
170462306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
170562306a36Sopenharmony_ci	int ret;
170662306a36Sopenharmony_ci	u16 data;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	BUILD_BUG_ON_NOT_POWER_OF_2(DESC_NUM);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	ret = netsec_alloc_dring(priv, NETSEC_RING_TX);
171162306a36Sopenharmony_ci	if (ret)
171262306a36Sopenharmony_ci		return ret;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	ret = netsec_alloc_dring(priv, NETSEC_RING_RX);
171562306a36Sopenharmony_ci	if (ret)
171662306a36Sopenharmony_ci		goto err1;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	/* set phy power down */
171962306a36Sopenharmony_ci	data = netsec_phy_read(priv->mii_bus, priv->phy_addr, MII_BMCR);
172062306a36Sopenharmony_ci	netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR,
172162306a36Sopenharmony_ci			 data | BMCR_PDOWN);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	ret = netsec_reset_hardware(priv, true);
172462306a36Sopenharmony_ci	if (ret)
172562306a36Sopenharmony_ci		goto err2;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	/* Restore phy power state */
172862306a36Sopenharmony_ci	netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR, data);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	spin_lock_init(&priv->desc_ring[NETSEC_RING_TX].lock);
173162306a36Sopenharmony_ci	spin_lock_init(&priv->desc_ring[NETSEC_RING_RX].lock);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	return 0;
173462306a36Sopenharmony_cierr2:
173562306a36Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_RX);
173662306a36Sopenharmony_cierr1:
173762306a36Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_TX);
173862306a36Sopenharmony_ci	return ret;
173962306a36Sopenharmony_ci}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_cistatic void netsec_netdev_uninit(struct net_device *ndev)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_RX);
174662306a36Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_TX);
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cistatic int netsec_netdev_set_features(struct net_device *ndev,
175062306a36Sopenharmony_ci				      netdev_features_t features)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	priv->rx_cksum_offload_flag = !!(features & NETIF_F_RXCSUM);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	return 0;
175762306a36Sopenharmony_ci}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_cistatic int netsec_xdp_xmit(struct net_device *ndev, int n,
176062306a36Sopenharmony_ci			   struct xdp_frame **frames, u32 flags)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
176362306a36Sopenharmony_ci	struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
176462306a36Sopenharmony_ci	int i, nxmit = 0;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
176762306a36Sopenharmony_ci		return -EINVAL;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	spin_lock(&tx_ring->lock);
177062306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
177162306a36Sopenharmony_ci		struct xdp_frame *xdpf = frames[i];
177262306a36Sopenharmony_ci		int err;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci		err = netsec_xdp_queue_one(priv, xdpf, true);
177562306a36Sopenharmony_ci		if (err != NETSEC_XDP_TX)
177662306a36Sopenharmony_ci			break;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci		tx_ring->xdp_xmit++;
177962306a36Sopenharmony_ci		nxmit++;
178062306a36Sopenharmony_ci	}
178162306a36Sopenharmony_ci	spin_unlock(&tx_ring->lock);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	if (unlikely(flags & XDP_XMIT_FLUSH)) {
178462306a36Sopenharmony_ci		netsec_xdp_ring_tx_db(priv, tx_ring->xdp_xmit);
178562306a36Sopenharmony_ci		tx_ring->xdp_xmit = 0;
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	return nxmit;
178962306a36Sopenharmony_ci}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cistatic int netsec_xdp_setup(struct netsec_priv *priv, struct bpf_prog *prog,
179262306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
179362306a36Sopenharmony_ci{
179462306a36Sopenharmony_ci	struct net_device *dev = priv->ndev;
179562306a36Sopenharmony_ci	struct bpf_prog *old_prog;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	/* For now just support only the usual MTU sized frames */
179862306a36Sopenharmony_ci	if (prog && dev->mtu > 1500) {
179962306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported on XDP");
180062306a36Sopenharmony_ci		return -EOPNOTSUPP;
180162306a36Sopenharmony_ci	}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	if (netif_running(dev))
180462306a36Sopenharmony_ci		netsec_netdev_stop(dev);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	/* Detach old prog, if any */
180762306a36Sopenharmony_ci	old_prog = xchg(&priv->xdp_prog, prog);
180862306a36Sopenharmony_ci	if (old_prog)
180962306a36Sopenharmony_ci		bpf_prog_put(old_prog);
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	if (netif_running(dev))
181262306a36Sopenharmony_ci		netsec_netdev_open(dev);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	return 0;
181562306a36Sopenharmony_ci}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_cistatic int netsec_xdp(struct net_device *ndev, struct netdev_bpf *xdp)
181862306a36Sopenharmony_ci{
181962306a36Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	switch (xdp->command) {
182262306a36Sopenharmony_ci	case XDP_SETUP_PROG:
182362306a36Sopenharmony_ci		return netsec_xdp_setup(priv, xdp->prog, xdp->extack);
182462306a36Sopenharmony_ci	default:
182562306a36Sopenharmony_ci		return -EINVAL;
182662306a36Sopenharmony_ci	}
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cistatic const struct net_device_ops netsec_netdev_ops = {
183062306a36Sopenharmony_ci	.ndo_init		= netsec_netdev_init,
183162306a36Sopenharmony_ci	.ndo_uninit		= netsec_netdev_uninit,
183262306a36Sopenharmony_ci	.ndo_open		= netsec_netdev_open,
183362306a36Sopenharmony_ci	.ndo_stop		= netsec_netdev_stop,
183462306a36Sopenharmony_ci	.ndo_start_xmit		= netsec_netdev_start_xmit,
183562306a36Sopenharmony_ci	.ndo_set_features	= netsec_netdev_set_features,
183662306a36Sopenharmony_ci	.ndo_set_mac_address    = eth_mac_addr,
183762306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
183862306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl,
183962306a36Sopenharmony_ci	.ndo_xdp_xmit		= netsec_xdp_xmit,
184062306a36Sopenharmony_ci	.ndo_bpf		= netsec_xdp,
184162306a36Sopenharmony_ci};
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_cistatic int netsec_of_probe(struct platform_device *pdev,
184462306a36Sopenharmony_ci			   struct netsec_priv *priv, u32 *phy_addr)
184562306a36Sopenharmony_ci{
184662306a36Sopenharmony_ci	int err;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	err = of_get_phy_mode(pdev->dev.of_node, &priv->phy_interface);
184962306a36Sopenharmony_ci	if (err) {
185062306a36Sopenharmony_ci		dev_err(&pdev->dev, "missing required property 'phy-mode'\n");
185162306a36Sopenharmony_ci		return err;
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	/*
185562306a36Sopenharmony_ci	 * SynQuacer is physically configured with TX and RX delays
185662306a36Sopenharmony_ci	 * but the standard firmware claimed otherwise for a long
185762306a36Sopenharmony_ci	 * time, ignore it.
185862306a36Sopenharmony_ci	 */
185962306a36Sopenharmony_ci	if (of_machine_is_compatible("socionext,developer-box") &&
186062306a36Sopenharmony_ci	    priv->phy_interface != PHY_INTERFACE_MODE_RGMII_ID) {
186162306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Outdated firmware reports incorrect PHY mode, overriding\n");
186262306a36Sopenharmony_ci		priv->phy_interface = PHY_INTERFACE_MODE_RGMII_ID;
186362306a36Sopenharmony_ci	}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	priv->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
186662306a36Sopenharmony_ci	if (!priv->phy_np) {
186762306a36Sopenharmony_ci		dev_err(&pdev->dev, "missing required property 'phy-handle'\n");
186862306a36Sopenharmony_ci		return -EINVAL;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	*phy_addr = of_mdio_parse_addr(&pdev->dev, priv->phy_np);
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	priv->clk = devm_clk_get(&pdev->dev, NULL); /* get by 'phy_ref_clk' */
187462306a36Sopenharmony_ci	if (IS_ERR(priv->clk))
187562306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk),
187662306a36Sopenharmony_ci				     "phy_ref_clk not found\n");
187762306a36Sopenharmony_ci	priv->freq = clk_get_rate(priv->clk);
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	return 0;
188062306a36Sopenharmony_ci}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_cistatic int netsec_acpi_probe(struct platform_device *pdev,
188362306a36Sopenharmony_ci			     struct netsec_priv *priv, u32 *phy_addr)
188462306a36Sopenharmony_ci{
188562306a36Sopenharmony_ci	int ret;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_ACPI))
188862306a36Sopenharmony_ci		return -ENODEV;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	/* ACPI systems are assumed to configure the PHY in firmware, so
189162306a36Sopenharmony_ci	 * there is really no need to discover the PHY mode from the DSDT.
189262306a36Sopenharmony_ci	 * Since firmware is known to exist in the field that configures the
189362306a36Sopenharmony_ci	 * PHY correctly but passes the wrong mode string in the phy-mode
189462306a36Sopenharmony_ci	 * device property, we have no choice but to ignore it.
189562306a36Sopenharmony_ci	 */
189662306a36Sopenharmony_ci	priv->phy_interface = PHY_INTERFACE_MODE_NA;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "phy-channel", phy_addr);
189962306a36Sopenharmony_ci	if (ret)
190062306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, ret,
190162306a36Sopenharmony_ci				     "missing required property 'phy-channel'\n");
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev,
190462306a36Sopenharmony_ci				       "socionext,phy-clock-frequency",
190562306a36Sopenharmony_ci				       &priv->freq);
190662306a36Sopenharmony_ci	if (ret)
190762306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, ret,
190862306a36Sopenharmony_ci				     "missing required property 'socionext,phy-clock-frequency'\n");
190962306a36Sopenharmony_ci	return 0;
191062306a36Sopenharmony_ci}
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_cistatic void netsec_unregister_mdio(struct netsec_priv *priv)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci	struct phy_device *phydev = priv->phydev;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (!dev_of_node(priv->dev) && phydev) {
191762306a36Sopenharmony_ci		phy_device_remove(phydev);
191862306a36Sopenharmony_ci		phy_device_free(phydev);
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	mdiobus_unregister(priv->mii_bus);
192262306a36Sopenharmony_ci}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_cistatic int netsec_register_mdio(struct netsec_priv *priv, u32 phy_addr)
192562306a36Sopenharmony_ci{
192662306a36Sopenharmony_ci	struct mii_bus *bus;
192762306a36Sopenharmony_ci	int ret;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	bus = devm_mdiobus_alloc(priv->dev);
193062306a36Sopenharmony_ci	if (!bus)
193162306a36Sopenharmony_ci		return -ENOMEM;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(priv->dev));
193462306a36Sopenharmony_ci	bus->priv = priv;
193562306a36Sopenharmony_ci	bus->name = "SNI NETSEC MDIO";
193662306a36Sopenharmony_ci	bus->read = netsec_phy_read;
193762306a36Sopenharmony_ci	bus->write = netsec_phy_write;
193862306a36Sopenharmony_ci	bus->parent = priv->dev;
193962306a36Sopenharmony_ci	priv->mii_bus = bus;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (dev_of_node(priv->dev)) {
194262306a36Sopenharmony_ci		struct device_node *mdio_node, *parent = dev_of_node(priv->dev);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci		mdio_node = of_get_child_by_name(parent, "mdio");
194562306a36Sopenharmony_ci		if (mdio_node) {
194662306a36Sopenharmony_ci			parent = mdio_node;
194762306a36Sopenharmony_ci		} else {
194862306a36Sopenharmony_ci			/* older f/w doesn't populate the mdio subnode,
194962306a36Sopenharmony_ci			 * allow relaxed upgrade of f/w in due time.
195062306a36Sopenharmony_ci			 */
195162306a36Sopenharmony_ci			dev_info(priv->dev, "Upgrade f/w for mdio subnode!\n");
195262306a36Sopenharmony_ci		}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci		ret = of_mdiobus_register(bus, parent);
195562306a36Sopenharmony_ci		of_node_put(mdio_node);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci		if (ret) {
195862306a36Sopenharmony_ci			dev_err(priv->dev, "mdiobus register err(%d)\n", ret);
195962306a36Sopenharmony_ci			return ret;
196062306a36Sopenharmony_ci		}
196162306a36Sopenharmony_ci	} else {
196262306a36Sopenharmony_ci		/* Mask out all PHYs from auto probing. */
196362306a36Sopenharmony_ci		bus->phy_mask = ~0;
196462306a36Sopenharmony_ci		ret = mdiobus_register(bus);
196562306a36Sopenharmony_ci		if (ret) {
196662306a36Sopenharmony_ci			dev_err(priv->dev, "mdiobus register err(%d)\n", ret);
196762306a36Sopenharmony_ci			return ret;
196862306a36Sopenharmony_ci		}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		priv->phydev = get_phy_device(bus, phy_addr, false);
197162306a36Sopenharmony_ci		if (IS_ERR(priv->phydev)) {
197262306a36Sopenharmony_ci			ret = PTR_ERR(priv->phydev);
197362306a36Sopenharmony_ci			dev_err(priv->dev, "get_phy_device err(%d)\n", ret);
197462306a36Sopenharmony_ci			priv->phydev = NULL;
197562306a36Sopenharmony_ci			mdiobus_unregister(bus);
197662306a36Sopenharmony_ci			return -ENODEV;
197762306a36Sopenharmony_ci		}
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci		ret = phy_device_register(priv->phydev);
198062306a36Sopenharmony_ci		if (ret) {
198162306a36Sopenharmony_ci			phy_device_free(priv->phydev);
198262306a36Sopenharmony_ci			mdiobus_unregister(bus);
198362306a36Sopenharmony_ci			dev_err(priv->dev,
198462306a36Sopenharmony_ci				"phy_device_register err(%d)\n", ret);
198562306a36Sopenharmony_ci		}
198662306a36Sopenharmony_ci	}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	return ret;
198962306a36Sopenharmony_ci}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_cistatic int netsec_probe(struct platform_device *pdev)
199262306a36Sopenharmony_ci{
199362306a36Sopenharmony_ci	struct resource *mmio_res, *eeprom_res;
199462306a36Sopenharmony_ci	struct netsec_priv *priv;
199562306a36Sopenharmony_ci	u32 hw_ver, phy_addr = 0;
199662306a36Sopenharmony_ci	struct net_device *ndev;
199762306a36Sopenharmony_ci	int ret;
199862306a36Sopenharmony_ci	int irq;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	mmio_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
200162306a36Sopenharmony_ci	if (!mmio_res) {
200262306a36Sopenharmony_ci		dev_err(&pdev->dev, "No MMIO resource found.\n");
200362306a36Sopenharmony_ci		return -ENODEV;
200462306a36Sopenharmony_ci	}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	eeprom_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
200762306a36Sopenharmony_ci	if (!eeprom_res) {
200862306a36Sopenharmony_ci		dev_info(&pdev->dev, "No EEPROM resource found.\n");
200962306a36Sopenharmony_ci		return -ENODEV;
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
201362306a36Sopenharmony_ci	if (irq < 0)
201462306a36Sopenharmony_ci		return irq;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	ndev = alloc_etherdev(sizeof(*priv));
201762306a36Sopenharmony_ci	if (!ndev)
201862306a36Sopenharmony_ci		return -ENOMEM;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	priv = netdev_priv(ndev);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	spin_lock_init(&priv->reglock);
202362306a36Sopenharmony_ci	SET_NETDEV_DEV(ndev, &pdev->dev);
202462306a36Sopenharmony_ci	platform_set_drvdata(pdev, priv);
202562306a36Sopenharmony_ci	ndev->irq = irq;
202662306a36Sopenharmony_ci	priv->dev = &pdev->dev;
202762306a36Sopenharmony_ci	priv->ndev = ndev;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	priv->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV |
203062306a36Sopenharmony_ci			   NETIF_MSG_LINK | NETIF_MSG_PROBE;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	priv->ioaddr = devm_ioremap(&pdev->dev, mmio_res->start,
203362306a36Sopenharmony_ci				    resource_size(mmio_res));
203462306a36Sopenharmony_ci	if (!priv->ioaddr) {
203562306a36Sopenharmony_ci		dev_err(&pdev->dev, "devm_ioremap() failed\n");
203662306a36Sopenharmony_ci		ret = -ENXIO;
203762306a36Sopenharmony_ci		goto free_ndev;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	priv->eeprom_base = devm_ioremap(&pdev->dev, eeprom_res->start,
204162306a36Sopenharmony_ci					 resource_size(eeprom_res));
204262306a36Sopenharmony_ci	if (!priv->eeprom_base) {
204362306a36Sopenharmony_ci		dev_err(&pdev->dev, "devm_ioremap() failed for EEPROM\n");
204462306a36Sopenharmony_ci		ret = -ENXIO;
204562306a36Sopenharmony_ci		goto free_ndev;
204662306a36Sopenharmony_ci	}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	ret = device_get_ethdev_address(&pdev->dev, ndev);
204962306a36Sopenharmony_ci	if (ret && priv->eeprom_base) {
205062306a36Sopenharmony_ci		void __iomem *macp = priv->eeprom_base +
205162306a36Sopenharmony_ci					NETSEC_EEPROM_MAC_ADDRESS;
205262306a36Sopenharmony_ci		u8 addr[ETH_ALEN];
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci		addr[0] = readb(macp + 3);
205562306a36Sopenharmony_ci		addr[1] = readb(macp + 2);
205662306a36Sopenharmony_ci		addr[2] = readb(macp + 1);
205762306a36Sopenharmony_ci		addr[3] = readb(macp + 0);
205862306a36Sopenharmony_ci		addr[4] = readb(macp + 7);
205962306a36Sopenharmony_ci		addr[5] = readb(macp + 6);
206062306a36Sopenharmony_ci		eth_hw_addr_set(ndev, addr);
206162306a36Sopenharmony_ci	}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	if (!is_valid_ether_addr(ndev->dev_addr)) {
206462306a36Sopenharmony_ci		dev_warn(&pdev->dev, "No MAC address found, using random\n");
206562306a36Sopenharmony_ci		eth_hw_addr_random(ndev);
206662306a36Sopenharmony_ci	}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	if (dev_of_node(&pdev->dev))
206962306a36Sopenharmony_ci		ret = netsec_of_probe(pdev, priv, &phy_addr);
207062306a36Sopenharmony_ci	else
207162306a36Sopenharmony_ci		ret = netsec_acpi_probe(pdev, priv, &phy_addr);
207262306a36Sopenharmony_ci	if (ret)
207362306a36Sopenharmony_ci		goto free_ndev;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	priv->phy_addr = phy_addr;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	if (!priv->freq) {
207862306a36Sopenharmony_ci		dev_err(&pdev->dev, "missing PHY reference clock frequency\n");
207962306a36Sopenharmony_ci		ret = -ENODEV;
208062306a36Sopenharmony_ci		goto free_ndev;
208162306a36Sopenharmony_ci	}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	/* default for throughput */
208462306a36Sopenharmony_ci	priv->et_coalesce.rx_coalesce_usecs = 500;
208562306a36Sopenharmony_ci	priv->et_coalesce.rx_max_coalesced_frames = 8;
208662306a36Sopenharmony_ci	priv->et_coalesce.tx_coalesce_usecs = 500;
208762306a36Sopenharmony_ci	priv->et_coalesce.tx_max_coalesced_frames = 8;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "max-frame-size",
209062306a36Sopenharmony_ci				       &ndev->max_mtu);
209162306a36Sopenharmony_ci	if (ret < 0)
209262306a36Sopenharmony_ci		ndev->max_mtu = ETH_DATA_LEN;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	/* runtime_pm coverage just for probe, open/close also cover it */
209562306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
209662306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	hw_ver = netsec_read(priv, NETSEC_REG_F_TAIKI_VER);
209962306a36Sopenharmony_ci	/* this driver only supports F_TAIKI style NETSEC */
210062306a36Sopenharmony_ci	if (NETSEC_F_NETSEC_VER_MAJOR_NUM(hw_ver) !=
210162306a36Sopenharmony_ci	    NETSEC_F_NETSEC_VER_MAJOR_NUM(NETSEC_REG_NETSEC_VER_F_TAIKI)) {
210262306a36Sopenharmony_ci		ret = -ENODEV;
210362306a36Sopenharmony_ci		goto pm_disable;
210462306a36Sopenharmony_ci	}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	dev_info(&pdev->dev, "hardware revision %d.%d\n",
210762306a36Sopenharmony_ci		 hw_ver >> 16, hw_ver & 0xffff);
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	netif_napi_add(ndev, &priv->napi, netsec_napi_poll);
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	ndev->netdev_ops = &netsec_netdev_ops;
211262306a36Sopenharmony_ci	ndev->ethtool_ops = &netsec_ethtool_ops;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	ndev->features |= NETIF_F_HIGHDMA | NETIF_F_RXCSUM | NETIF_F_GSO |
211562306a36Sopenharmony_ci				NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
211662306a36Sopenharmony_ci	ndev->hw_features = ndev->features;
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
211962306a36Sopenharmony_ci			     NETDEV_XDP_ACT_NDO_XMIT;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	priv->rx_cksum_offload_flag = true;
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	ret = netsec_register_mdio(priv, phy_addr);
212462306a36Sopenharmony_ci	if (ret)
212562306a36Sopenharmony_ci		goto unreg_napi;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)))
212862306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Failed to set DMA mask\n");
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	ret = register_netdev(ndev);
213162306a36Sopenharmony_ci	if (ret) {
213262306a36Sopenharmony_ci		netif_err(priv, probe, ndev, "register_netdev() failed\n");
213362306a36Sopenharmony_ci		goto unreg_mii;
213462306a36Sopenharmony_ci	}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
213762306a36Sopenharmony_ci	return 0;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ciunreg_mii:
214062306a36Sopenharmony_ci	netsec_unregister_mdio(priv);
214162306a36Sopenharmony_ciunreg_napi:
214262306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
214362306a36Sopenharmony_cipm_disable:
214462306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
214562306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
214662306a36Sopenharmony_cifree_ndev:
214762306a36Sopenharmony_ci	free_netdev(ndev);
214862306a36Sopenharmony_ci	dev_err(&pdev->dev, "init failed\n");
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	return ret;
215162306a36Sopenharmony_ci}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_cistatic int netsec_remove(struct platform_device *pdev)
215462306a36Sopenharmony_ci{
215562306a36Sopenharmony_ci	struct netsec_priv *priv = platform_get_drvdata(pdev);
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	unregister_netdev(priv->ndev);
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	netsec_unregister_mdio(priv);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
216462306a36Sopenharmony_ci	free_netdev(priv->ndev);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	return 0;
216762306a36Sopenharmony_ci}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci#ifdef CONFIG_PM
217062306a36Sopenharmony_cistatic int netsec_runtime_suspend(struct device *dev)
217162306a36Sopenharmony_ci{
217262306a36Sopenharmony_ci	struct netsec_priv *priv = dev_get_drvdata(dev);
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_CLK_EN, 0);
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	clk_disable_unprepare(priv->clk);
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	return 0;
217962306a36Sopenharmony_ci}
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_cistatic int netsec_runtime_resume(struct device *dev)
218262306a36Sopenharmony_ci{
218362306a36Sopenharmony_ci	struct netsec_priv *priv = dev_get_drvdata(dev);
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	clk_prepare_enable(priv->clk);
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	netsec_write(priv, NETSEC_REG_CLK_EN, NETSEC_CLK_EN_REG_DOM_D |
218862306a36Sopenharmony_ci					       NETSEC_CLK_EN_REG_DOM_C |
218962306a36Sopenharmony_ci					       NETSEC_CLK_EN_REG_DOM_G);
219062306a36Sopenharmony_ci	return 0;
219162306a36Sopenharmony_ci}
219262306a36Sopenharmony_ci#endif
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_cistatic const struct dev_pm_ops netsec_pm_ops = {
219562306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(netsec_runtime_suspend, netsec_runtime_resume, NULL)
219662306a36Sopenharmony_ci};
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_cistatic const struct of_device_id netsec_dt_ids[] = {
219962306a36Sopenharmony_ci	{ .compatible = "socionext,synquacer-netsec" },
220062306a36Sopenharmony_ci	{ }
220162306a36Sopenharmony_ci};
220262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, netsec_dt_ids);
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci#ifdef CONFIG_ACPI
220562306a36Sopenharmony_cistatic const struct acpi_device_id netsec_acpi_ids[] = {
220662306a36Sopenharmony_ci	{ "SCX0001" },
220762306a36Sopenharmony_ci	{ }
220862306a36Sopenharmony_ci};
220962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, netsec_acpi_ids);
221062306a36Sopenharmony_ci#endif
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_cistatic struct platform_driver netsec_driver = {
221362306a36Sopenharmony_ci	.probe	= netsec_probe,
221462306a36Sopenharmony_ci	.remove	= netsec_remove,
221562306a36Sopenharmony_ci	.driver = {
221662306a36Sopenharmony_ci		.name = "netsec",
221762306a36Sopenharmony_ci		.pm = &netsec_pm_ops,
221862306a36Sopenharmony_ci		.of_match_table = netsec_dt_ids,
221962306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(netsec_acpi_ids),
222062306a36Sopenharmony_ci	},
222162306a36Sopenharmony_ci};
222262306a36Sopenharmony_cimodule_platform_driver(netsec_driver);
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ciMODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
222562306a36Sopenharmony_ciMODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
222662306a36Sopenharmony_ciMODULE_DESCRIPTION("NETSEC Ethernet driver");
222762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2228