18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/types.h>
48c2ecf20Sopenharmony_ci#include <linux/clk.h>
58c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
68c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
78c2ecf20Sopenharmony_ci#include <linux/acpi.h>
88c2ecf20Sopenharmony_ci#include <linux/of_mdio.h>
98c2ecf20Sopenharmony_ci#include <linux/of_net.h>
108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/netlink.h>
148c2ecf20Sopenharmony_ci#include <linux/bpf.h>
158c2ecf20Sopenharmony_ci#include <linux/bpf_trace.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <net/tcp.h>
188c2ecf20Sopenharmony_ci#include <net/page_pool.h>
198c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define NETSEC_REG_SOFT_RST			0x104
228c2ecf20Sopenharmony_ci#define NETSEC_REG_COM_INIT			0x120
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define NETSEC_REG_TOP_STATUS			0x200
258c2ecf20Sopenharmony_ci#define NETSEC_IRQ_RX				BIT(1)
268c2ecf20Sopenharmony_ci#define NETSEC_IRQ_TX				BIT(0)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define NETSEC_REG_TOP_INTEN			0x204
298c2ecf20Sopenharmony_ci#define NETSEC_REG_INTEN_SET			0x234
308c2ecf20Sopenharmony_ci#define NETSEC_REG_INTEN_CLR			0x238
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_STATUS		0x400
338c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_INTEN			0x404
348c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_INTEN_SET		0x428
358c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_INTEN_CLR		0x42c
368c2ecf20Sopenharmony_ci#define NRM_TX_ST_NTOWNR	BIT(17)
378c2ecf20Sopenharmony_ci#define NRM_TX_ST_TR_ERR	BIT(16)
388c2ecf20Sopenharmony_ci#define NRM_TX_ST_TXDONE	BIT(15)
398c2ecf20Sopenharmony_ci#define NRM_TX_ST_TMREXP	BIT(14)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_STATUS		0x440
428c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_INTEN			0x444
438c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_INTEN_SET		0x468
448c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_INTEN_CLR		0x46c
458c2ecf20Sopenharmony_ci#define NRM_RX_ST_RC_ERR	BIT(16)
468c2ecf20Sopenharmony_ci#define NRM_RX_ST_PKTCNT	BIT(15)
478c2ecf20Sopenharmony_ci#define NRM_RX_ST_TMREXP	BIT(14)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define NETSEC_REG_PKT_CMD_BUF			0xd0
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define NETSEC_REG_CLK_EN			0x100
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define NETSEC_REG_PKT_CTRL			0x140
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define NETSEC_REG_DMA_TMR_CTRL			0x20c
568c2ecf20Sopenharmony_ci#define NETSEC_REG_F_TAIKI_MC_VER		0x22c
578c2ecf20Sopenharmony_ci#define NETSEC_REG_F_TAIKI_VER			0x230
588c2ecf20Sopenharmony_ci#define NETSEC_REG_DMA_HM_CTRL			0x214
598c2ecf20Sopenharmony_ci#define NETSEC_REG_DMA_MH_CTRL			0x220
608c2ecf20Sopenharmony_ci#define NETSEC_REG_ADDR_DIS_CORE		0x218
618c2ecf20Sopenharmony_ci#define NETSEC_REG_DMAC_HM_CMD_BUF		0x210
628c2ecf20Sopenharmony_ci#define NETSEC_REG_DMAC_MH_CMD_BUF		0x21c
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_PKTCNT		0x410
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_DONE_PKTCNT		0x414
678c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT	0x418
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_TMR			0x41c
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_PKTCNT		0x454
728c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_RXINT_PKTCNT		0x458
738c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_TXINT_TMR		0x420
748c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_RXINT_TMR		0x460
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_TMR			0x45c
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_DESC_START_UP		0x434
798c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_DESC_START_LW		0x408
808c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_DESC_START_UP		0x474
818c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_DESC_START_LW		0x448
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_TX_CONFIG		0x430
848c2ecf20Sopenharmony_ci#define NETSEC_REG_NRM_RX_CONFIG		0x470
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define MAC_REG_STATUS				0x1024
878c2ecf20Sopenharmony_ci#define MAC_REG_DATA				0x11c0
888c2ecf20Sopenharmony_ci#define MAC_REG_CMD				0x11c4
898c2ecf20Sopenharmony_ci#define MAC_REG_FLOW_TH				0x11cc
908c2ecf20Sopenharmony_ci#define MAC_REG_INTF_SEL			0x11d4
918c2ecf20Sopenharmony_ci#define MAC_REG_DESC_INIT			0x11fc
928c2ecf20Sopenharmony_ci#define MAC_REG_DESC_SOFT_RST			0x1204
938c2ecf20Sopenharmony_ci#define NETSEC_REG_MODE_TRANS_COMP_STATUS	0x500
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#define GMAC_REG_MCR				0x0000
968c2ecf20Sopenharmony_ci#define GMAC_REG_MFFR				0x0004
978c2ecf20Sopenharmony_ci#define GMAC_REG_GAR				0x0010
988c2ecf20Sopenharmony_ci#define GMAC_REG_GDR				0x0014
998c2ecf20Sopenharmony_ci#define GMAC_REG_FCR				0x0018
1008c2ecf20Sopenharmony_ci#define GMAC_REG_BMR				0x1000
1018c2ecf20Sopenharmony_ci#define GMAC_REG_RDLAR				0x100c
1028c2ecf20Sopenharmony_ci#define GMAC_REG_TDLAR				0x1010
1038c2ecf20Sopenharmony_ci#define GMAC_REG_OMR				0x1018
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#define MHZ(n)		((n) * 1000 * 1000)
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_OWN_FIELD		31
1088c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_LD_FIELD		30
1098c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_DRID_FIELD		24
1108c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_PT_FIELD		21
1118c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_TDRID_FIELD		16
1128c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_CC_FIELD		15
1138c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_FS_FIELD		9
1148c2ecf20Sopenharmony_ci#define NETSEC_TX_LAST				8
1158c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_CO			7
1168c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_SO			6
1178c2ecf20Sopenharmony_ci#define NETSEC_TX_SHIFT_TRS_FIELD		4
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_OWN_FIELD			31
1208c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_LD_FIELD			30
1218c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_SDRID_FIELD		24
1228c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_FR_FIELD			23
1238c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_ER_FIELD			21
1248c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_ERR_FIELD			16
1258c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_TDRID_FIELD		12
1268c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_FS_FIELD			9
1278c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_LS_FIELD			8
1288c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_CO_FIELD			6
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#define NETSEC_RX_PKT_ERR_MASK			3
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#define NETSEC_MAX_TX_PKT_LEN			1518
1338c2ecf20Sopenharmony_ci#define NETSEC_MAX_TX_JUMBO_PKT_LEN		9018
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#define NETSEC_RING_GMAC			15
1368c2ecf20Sopenharmony_ci#define NETSEC_RING_MAX				2
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci#define NETSEC_TCP_SEG_LEN_MAX			1460
1398c2ecf20Sopenharmony_ci#define NETSEC_TCP_JUMBO_SEG_LEN_MAX		8960
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci#define NETSEC_RX_CKSUM_NOTAVAIL		0
1428c2ecf20Sopenharmony_ci#define NETSEC_RX_CKSUM_OK			1
1438c2ecf20Sopenharmony_ci#define NETSEC_RX_CKSUM_NG			2
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#define NETSEC_TOP_IRQ_REG_CODE_LOAD_END	BIT(20)
1468c2ecf20Sopenharmony_ci#define NETSEC_IRQ_TRANSITION_COMPLETE		BIT(4)
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#define NETSEC_MODE_TRANS_COMP_IRQ_N2T		BIT(20)
1498c2ecf20Sopenharmony_ci#define NETSEC_MODE_TRANS_COMP_IRQ_T2N		BIT(19)
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define NETSEC_INT_PKTCNT_MAX			2047
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci#define NETSEC_FLOW_START_TH_MAX		95
1548c2ecf20Sopenharmony_ci#define NETSEC_FLOW_STOP_TH_MAX			95
1558c2ecf20Sopenharmony_ci#define NETSEC_FLOW_PAUSE_TIME_MIN		5
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_ALL		0x3f
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_MODE_NRM		BIT(28)
1608c2ecf20Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_EN_JUMBO		BIT(27)
1618c2ecf20Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_LOG_CHKSUM_ER	BIT(3)
1628c2ecf20Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_LOG_HD_INCOMPLETE	BIT(2)
1638c2ecf20Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_LOG_HD_ER		BIT(1)
1648c2ecf20Sopenharmony_ci#define NETSEC_PKT_CTRL_REG_DRP_NO_MATCH	BIT(0)
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_G			BIT(5)
1678c2ecf20Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_C			BIT(1)
1688c2ecf20Sopenharmony_ci#define NETSEC_CLK_EN_REG_DOM_D			BIT(0)
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#define NETSEC_COM_INIT_REG_DB			BIT(2)
1718c2ecf20Sopenharmony_ci#define NETSEC_COM_INIT_REG_CLS			BIT(1)
1728c2ecf20Sopenharmony_ci#define NETSEC_COM_INIT_REG_ALL			(NETSEC_COM_INIT_REG_CLS | \
1738c2ecf20Sopenharmony_ci						 NETSEC_COM_INIT_REG_DB)
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci#define NETSEC_SOFT_RST_REG_RESET		0
1768c2ecf20Sopenharmony_ci#define NETSEC_SOFT_RST_REG_RUN			BIT(31)
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci#define NETSEC_DMA_CTRL_REG_STOP		1
1798c2ecf20Sopenharmony_ci#define MH_CTRL__MODE_TRANS			BIT(20)
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci#define NETSEC_GMAC_CMD_ST_READ			0
1828c2ecf20Sopenharmony_ci#define NETSEC_GMAC_CMD_ST_WRITE		BIT(28)
1838c2ecf20Sopenharmony_ci#define NETSEC_GMAC_CMD_ST_BUSY			BIT(31)
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci#define NETSEC_GMAC_BMR_REG_COMMON		0x00412080
1868c2ecf20Sopenharmony_ci#define NETSEC_GMAC_BMR_REG_RESET		0x00020181
1878c2ecf20Sopenharmony_ci#define NETSEC_GMAC_BMR_REG_SWR			0x00000001
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci#define NETSEC_GMAC_OMR_REG_ST			BIT(13)
1908c2ecf20Sopenharmony_ci#define NETSEC_GMAC_OMR_REG_SR			BIT(1)
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_IBN			BIT(30)
1938c2ecf20Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_CST			BIT(25)
1948c2ecf20Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_JE			BIT(20)
1958c2ecf20Sopenharmony_ci#define NETSEC_MCR_PS				BIT(15)
1968c2ecf20Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_FES			BIT(14)
1978c2ecf20Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON	0x0000280c
1988c2ecf20Sopenharmony_ci#define NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON	0x0001a00c
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci#define NETSEC_FCR_RFE				BIT(2)
2018c2ecf20Sopenharmony_ci#define NETSEC_FCR_TFE				BIT(1)
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_GW			BIT(1)
2048c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_GB			BIT(0)
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_SHIFT_PA		11
2078c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_SHIFT_GR		6
2088c2ecf20Sopenharmony_ci#define GMAC_REG_SHIFT_CR_GAR			2
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_25_35_MHZ	2
2118c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_35_60_MHZ	3
2128c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_60_100_MHZ	0
2138c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_100_150_MHZ	1
2148c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_150_250_MHZ	4
2158c2ecf20Sopenharmony_ci#define NETSEC_GMAC_GAR_REG_CR_250_300_MHZ	5
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci#define NETSEC_GMAC_RDLAR_REG_COMMON		0x18000
2188c2ecf20Sopenharmony_ci#define NETSEC_GMAC_TDLAR_REG_COMMON		0x1c000
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#define NETSEC_REG_NETSEC_VER_F_TAIKI		0x50000
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci#define NETSEC_REG_DESC_RING_CONFIG_CFG_UP	BIT(31)
2238c2ecf20Sopenharmony_ci#define NETSEC_REG_DESC_RING_CONFIG_CH_RST	BIT(30)
2248c2ecf20Sopenharmony_ci#define NETSEC_REG_DESC_TMR_MODE		4
2258c2ecf20Sopenharmony_ci#define NETSEC_REG_DESC_ENDIAN			0
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci#define NETSEC_MAC_DESC_SOFT_RST_SOFT_RST	1
2288c2ecf20Sopenharmony_ci#define NETSEC_MAC_DESC_INIT_REG_INIT		1
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_MAC_ADDRESS		0x00
2318c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_HM_ME_ADDRESS_H		0x08
2328c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_HM_ME_ADDRESS_L		0x0C
2338c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_HM_ME_SIZE		0x10
2348c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_MH_ME_ADDRESS_H		0x14
2358c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_MH_ME_ADDRESS_L		0x18
2368c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_MH_ME_SIZE		0x1C
2378c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_PKT_ME_ADDRESS		0x20
2388c2ecf20Sopenharmony_ci#define NETSEC_EEPROM_PKT_ME_SIZE		0x24
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci#define DESC_NUM	256
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci#define NETSEC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
2438c2ecf20Sopenharmony_ci#define NETSEC_RXBUF_HEADROOM (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + \
2448c2ecf20Sopenharmony_ci			       NET_IP_ALIGN)
2458c2ecf20Sopenharmony_ci#define NETSEC_RX_BUF_NON_DATA (NETSEC_RXBUF_HEADROOM + \
2468c2ecf20Sopenharmony_ci				SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
2478c2ecf20Sopenharmony_ci#define NETSEC_RX_BUF_SIZE	(PAGE_SIZE - NETSEC_RX_BUF_NON_DATA)
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci#define DESC_SZ	sizeof(struct netsec_de)
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci#define NETSEC_F_NETSEC_VER_MAJOR_NUM(x)	((x) & 0xffff0000)
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci#define NETSEC_XDP_PASS          0
2548c2ecf20Sopenharmony_ci#define NETSEC_XDP_CONSUMED      BIT(0)
2558c2ecf20Sopenharmony_ci#define NETSEC_XDP_TX            BIT(1)
2568c2ecf20Sopenharmony_ci#define NETSEC_XDP_REDIR         BIT(2)
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cienum ring_id {
2598c2ecf20Sopenharmony_ci	NETSEC_RING_TX = 0,
2608c2ecf20Sopenharmony_ci	NETSEC_RING_RX
2618c2ecf20Sopenharmony_ci};
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cienum buf_type {
2648c2ecf20Sopenharmony_ci	TYPE_NETSEC_SKB = 0,
2658c2ecf20Sopenharmony_ci	TYPE_NETSEC_XDP_TX,
2668c2ecf20Sopenharmony_ci	TYPE_NETSEC_XDP_NDO,
2678c2ecf20Sopenharmony_ci};
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistruct netsec_desc {
2708c2ecf20Sopenharmony_ci	union {
2718c2ecf20Sopenharmony_ci		struct sk_buff *skb;
2728c2ecf20Sopenharmony_ci		struct xdp_frame *xdpf;
2738c2ecf20Sopenharmony_ci	};
2748c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
2758c2ecf20Sopenharmony_ci	void *addr;
2768c2ecf20Sopenharmony_ci	u16 len;
2778c2ecf20Sopenharmony_ci	u8 buf_type;
2788c2ecf20Sopenharmony_ci};
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistruct netsec_desc_ring {
2818c2ecf20Sopenharmony_ci	dma_addr_t desc_dma;
2828c2ecf20Sopenharmony_ci	struct netsec_desc *desc;
2838c2ecf20Sopenharmony_ci	void *vaddr;
2848c2ecf20Sopenharmony_ci	u16 head, tail;
2858c2ecf20Sopenharmony_ci	u16 xdp_xmit; /* netsec_xdp_xmit packets */
2868c2ecf20Sopenharmony_ci	struct page_pool *page_pool;
2878c2ecf20Sopenharmony_ci	struct xdp_rxq_info xdp_rxq;
2888c2ecf20Sopenharmony_ci	spinlock_t lock; /* XDP tx queue locking */
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistruct netsec_priv {
2928c2ecf20Sopenharmony_ci	struct netsec_desc_ring desc_ring[NETSEC_RING_MAX];
2938c2ecf20Sopenharmony_ci	struct ethtool_coalesce et_coalesce;
2948c2ecf20Sopenharmony_ci	struct bpf_prog *xdp_prog;
2958c2ecf20Sopenharmony_ci	spinlock_t reglock; /* protect reg access */
2968c2ecf20Sopenharmony_ci	struct napi_struct napi;
2978c2ecf20Sopenharmony_ci	phy_interface_t phy_interface;
2988c2ecf20Sopenharmony_ci	struct net_device *ndev;
2998c2ecf20Sopenharmony_ci	struct device_node *phy_np;
3008c2ecf20Sopenharmony_ci	struct phy_device *phydev;
3018c2ecf20Sopenharmony_ci	struct mii_bus *mii_bus;
3028c2ecf20Sopenharmony_ci	void __iomem *ioaddr;
3038c2ecf20Sopenharmony_ci	void __iomem *eeprom_base;
3048c2ecf20Sopenharmony_ci	struct device *dev;
3058c2ecf20Sopenharmony_ci	struct clk *clk;
3068c2ecf20Sopenharmony_ci	u32 msg_enable;
3078c2ecf20Sopenharmony_ci	u32 freq;
3088c2ecf20Sopenharmony_ci	u32 phy_addr;
3098c2ecf20Sopenharmony_ci	bool rx_cksum_offload_flag;
3108c2ecf20Sopenharmony_ci};
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistruct netsec_de { /* Netsec Descriptor layout */
3138c2ecf20Sopenharmony_ci	u32 attr;
3148c2ecf20Sopenharmony_ci	u32 data_buf_addr_up;
3158c2ecf20Sopenharmony_ci	u32 data_buf_addr_lw;
3168c2ecf20Sopenharmony_ci	u32 buf_len_info;
3178c2ecf20Sopenharmony_ci};
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistruct netsec_tx_pkt_ctrl {
3208c2ecf20Sopenharmony_ci	u16 tcp_seg_len;
3218c2ecf20Sopenharmony_ci	bool tcp_seg_offload_flag;
3228c2ecf20Sopenharmony_ci	bool cksum_offload_flag;
3238c2ecf20Sopenharmony_ci};
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistruct netsec_rx_pkt_info {
3268c2ecf20Sopenharmony_ci	int rx_cksum_result;
3278c2ecf20Sopenharmony_ci	int err_code;
3288c2ecf20Sopenharmony_ci	bool err_flag;
3298c2ecf20Sopenharmony_ci};
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic void netsec_write(struct netsec_priv *priv, u32 reg_addr, u32 val)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	writel(val, priv->ioaddr + reg_addr);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic u32 netsec_read(struct netsec_priv *priv, u32 reg_addr)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	return readl(priv->ioaddr + reg_addr);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci/************* MDIO BUS OPS FOLLOW *************/
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci#define TIMEOUT_SPINS_MAC		1000
3448c2ecf20Sopenharmony_ci#define TIMEOUT_SECONDARY_MS_MAC	100
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic u32 netsec_clk_type(u32 freq)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	if (freq < MHZ(35))
3498c2ecf20Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_25_35_MHZ;
3508c2ecf20Sopenharmony_ci	if (freq < MHZ(60))
3518c2ecf20Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_35_60_MHZ;
3528c2ecf20Sopenharmony_ci	if (freq < MHZ(100))
3538c2ecf20Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_60_100_MHZ;
3548c2ecf20Sopenharmony_ci	if (freq < MHZ(150))
3558c2ecf20Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_100_150_MHZ;
3568c2ecf20Sopenharmony_ci	if (freq < MHZ(250))
3578c2ecf20Sopenharmony_ci		return NETSEC_GMAC_GAR_REG_CR_150_250_MHZ;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return NETSEC_GMAC_GAR_REG_CR_250_300_MHZ;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic int netsec_wait_while_busy(struct netsec_priv *priv, u32 addr, u32 mask)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	u32 timeout = TIMEOUT_SPINS_MAC;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	while (--timeout && netsec_read(priv, addr) & mask)
3678c2ecf20Sopenharmony_ci		cpu_relax();
3688c2ecf20Sopenharmony_ci	if (timeout)
3698c2ecf20Sopenharmony_ci		return 0;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	timeout = TIMEOUT_SECONDARY_MS_MAC;
3728c2ecf20Sopenharmony_ci	while (--timeout && netsec_read(priv, addr) & mask)
3738c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (timeout)
3768c2ecf20Sopenharmony_ci		return 0;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int netsec_mac_write(struct netsec_priv *priv, u32 addr, u32 value)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	netsec_write(priv, MAC_REG_DATA, value);
3868c2ecf20Sopenharmony_ci	netsec_write(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_WRITE);
3878c2ecf20Sopenharmony_ci	return netsec_wait_while_busy(priv,
3888c2ecf20Sopenharmony_ci				      MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic int netsec_mac_read(struct netsec_priv *priv, u32 addr, u32 *read)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	int ret;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	netsec_write(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_READ);
3968c2ecf20Sopenharmony_ci	ret = netsec_wait_while_busy(priv,
3978c2ecf20Sopenharmony_ci				     MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
3988c2ecf20Sopenharmony_ci	if (ret)
3998c2ecf20Sopenharmony_ci		return ret;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	*read = netsec_read(priv, MAC_REG_DATA);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return 0;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic int netsec_mac_wait_while_busy(struct netsec_priv *priv,
4078c2ecf20Sopenharmony_ci				      u32 addr, u32 mask)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	u32 timeout = TIMEOUT_SPINS_MAC;
4108c2ecf20Sopenharmony_ci	int ret, data;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	do {
4138c2ecf20Sopenharmony_ci		ret = netsec_mac_read(priv, addr, &data);
4148c2ecf20Sopenharmony_ci		if (ret)
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		cpu_relax();
4178c2ecf20Sopenharmony_ci	} while (--timeout && (data & mask));
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (timeout)
4208c2ecf20Sopenharmony_ci		return 0;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	timeout = TIMEOUT_SECONDARY_MS_MAC;
4238c2ecf20Sopenharmony_ci	do {
4248c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		ret = netsec_mac_read(priv, addr, &data);
4278c2ecf20Sopenharmony_ci		if (ret)
4288c2ecf20Sopenharmony_ci			break;
4298c2ecf20Sopenharmony_ci		cpu_relax();
4308c2ecf20Sopenharmony_ci	} while (--timeout && (data & mask));
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if (timeout && !ret)
4338c2ecf20Sopenharmony_ci		return 0;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int netsec_mac_update_to_phy_state(struct netsec_priv *priv)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct phy_device *phydev = priv->ndev->phydev;
4438c2ecf20Sopenharmony_ci	u32 value = 0;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	value = phydev->duplex ? NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON :
4468c2ecf20Sopenharmony_ci				 NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (phydev->speed != SPEED_1000)
4498c2ecf20Sopenharmony_ci		value |= NETSEC_MCR_PS;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (priv->phy_interface != PHY_INTERFACE_MODE_GMII &&
4528c2ecf20Sopenharmony_ci	    phydev->speed == SPEED_100)
4538c2ecf20Sopenharmony_ci		value |= NETSEC_GMAC_MCR_REG_FES;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	value |= NETSEC_GMAC_MCR_REG_CST | NETSEC_GMAC_MCR_REG_JE;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (phy_interface_mode_is_rgmii(priv->phy_interface))
4588c2ecf20Sopenharmony_ci		value |= NETSEC_GMAC_MCR_REG_IBN;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_MCR, value))
4618c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	return 0;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic int netsec_phy_write(struct mii_bus *bus,
4698c2ecf20Sopenharmony_ci			    int phy_addr, int reg, u16 val)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	int status;
4728c2ecf20Sopenharmony_ci	struct netsec_priv *priv = bus->priv;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_GDR, val))
4758c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
4768c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_GAR,
4778c2ecf20Sopenharmony_ci			     phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
4788c2ecf20Sopenharmony_ci			     reg << NETSEC_GMAC_GAR_REG_SHIFT_GR |
4798c2ecf20Sopenharmony_ci			     NETSEC_GMAC_GAR_REG_GW | NETSEC_GMAC_GAR_REG_GB |
4808c2ecf20Sopenharmony_ci			     (netsec_clk_type(priv->freq) <<
4818c2ecf20Sopenharmony_ci			      GMAC_REG_SHIFT_CR_GAR)))
4828c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	status = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
4858c2ecf20Sopenharmony_ci					    NETSEC_GMAC_GAR_REG_GB);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* Developerbox implements RTL8211E PHY and there is
4888c2ecf20Sopenharmony_ci	 * a compatibility problem with F_GMAC4.
4898c2ecf20Sopenharmony_ci	 * RTL8211E expects MDC clock must be kept toggling for several
4908c2ecf20Sopenharmony_ci	 * clock cycle with MDIO high before entering the IDLE state.
4918c2ecf20Sopenharmony_ci	 * To meet this requirement, netsec driver needs to issue dummy
4928c2ecf20Sopenharmony_ci	 * read(e.g. read PHYID1(offset 0x2) register) right after write.
4938c2ecf20Sopenharmony_ci	 */
4948c2ecf20Sopenharmony_ci	netsec_phy_read(bus, phy_addr, MII_PHYSID1);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	return status;
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_cistatic int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct netsec_priv *priv = bus->priv;
5028c2ecf20Sopenharmony_ci	u32 data;
5038c2ecf20Sopenharmony_ci	int ret;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_GAR, NETSEC_GMAC_GAR_REG_GB |
5068c2ecf20Sopenharmony_ci			     phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
5078c2ecf20Sopenharmony_ci			     reg_addr << NETSEC_GMAC_GAR_REG_SHIFT_GR |
5088c2ecf20Sopenharmony_ci			     (netsec_clk_type(priv->freq) <<
5098c2ecf20Sopenharmony_ci			      GMAC_REG_SHIFT_CR_GAR)))
5108c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	ret = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
5138c2ecf20Sopenharmony_ci					 NETSEC_GMAC_GAR_REG_GB);
5148c2ecf20Sopenharmony_ci	if (ret)
5158c2ecf20Sopenharmony_ci		return ret;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_GDR, &data);
5188c2ecf20Sopenharmony_ci	if (ret)
5198c2ecf20Sopenharmony_ci		return ret;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return data;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci/************* ETHTOOL_OPS FOLLOW *************/
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic void netsec_et_get_drvinfo(struct net_device *net_device,
5278c2ecf20Sopenharmony_ci				  struct ethtool_drvinfo *info)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	strlcpy(info->driver, "netsec", sizeof(info->driver));
5308c2ecf20Sopenharmony_ci	strlcpy(info->bus_info, dev_name(net_device->dev.parent),
5318c2ecf20Sopenharmony_ci		sizeof(info->bus_info));
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic int netsec_et_get_coalesce(struct net_device *net_device,
5358c2ecf20Sopenharmony_ci				  struct ethtool_coalesce *et_coalesce)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(net_device);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	*et_coalesce = priv->et_coalesce;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return 0;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int netsec_et_set_coalesce(struct net_device *net_device,
5458c2ecf20Sopenharmony_ci				  struct ethtool_coalesce *et_coalesce)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(net_device);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	priv->et_coalesce = *et_coalesce;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	if (priv->et_coalesce.tx_coalesce_usecs < 50)
5528c2ecf20Sopenharmony_ci		priv->et_coalesce.tx_coalesce_usecs = 50;
5538c2ecf20Sopenharmony_ci	if (priv->et_coalesce.tx_max_coalesced_frames < 1)
5548c2ecf20Sopenharmony_ci		priv->et_coalesce.tx_max_coalesced_frames = 1;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT,
5578c2ecf20Sopenharmony_ci		     priv->et_coalesce.tx_max_coalesced_frames);
5588c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_TXINT_TMR,
5598c2ecf20Sopenharmony_ci		     priv->et_coalesce.tx_coalesce_usecs);
5608c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_SET, NRM_TX_ST_TXDONE);
5618c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_SET, NRM_TX_ST_TMREXP);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if (priv->et_coalesce.rx_coalesce_usecs < 50)
5648c2ecf20Sopenharmony_ci		priv->et_coalesce.rx_coalesce_usecs = 50;
5658c2ecf20Sopenharmony_ci	if (priv->et_coalesce.rx_max_coalesced_frames < 1)
5668c2ecf20Sopenharmony_ci		priv->et_coalesce.rx_max_coalesced_frames = 1;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_RXINT_PKTCNT,
5698c2ecf20Sopenharmony_ci		     priv->et_coalesce.rx_max_coalesced_frames);
5708c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_RXINT_TMR,
5718c2ecf20Sopenharmony_ci		     priv->et_coalesce.rx_coalesce_usecs);
5728c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_SET, NRM_RX_ST_PKTCNT);
5738c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_SET, NRM_RX_ST_TMREXP);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	return 0;
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic u32 netsec_et_get_msglevel(struct net_device *dev)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(dev);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	return priv->msg_enable;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic void netsec_et_set_msglevel(struct net_device *dev, u32 datum)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(dev);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	priv->msg_enable = datum;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic const struct ethtool_ops netsec_ethtool_ops = {
5938c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
5948c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES,
5958c2ecf20Sopenharmony_ci	.get_drvinfo		= netsec_et_get_drvinfo,
5968c2ecf20Sopenharmony_ci	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
5978c2ecf20Sopenharmony_ci	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
5988c2ecf20Sopenharmony_ci	.get_link		= ethtool_op_get_link,
5998c2ecf20Sopenharmony_ci	.get_coalesce		= netsec_et_get_coalesce,
6008c2ecf20Sopenharmony_ci	.set_coalesce		= netsec_et_set_coalesce,
6018c2ecf20Sopenharmony_ci	.get_msglevel		= netsec_et_get_msglevel,
6028c2ecf20Sopenharmony_ci	.set_msglevel		= netsec_et_set_msglevel,
6038c2ecf20Sopenharmony_ci};
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci/************* NETDEV_OPS FOLLOW *************/
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic void netsec_set_rx_de(struct netsec_priv *priv,
6098c2ecf20Sopenharmony_ci			     struct netsec_desc_ring *dring, u16 idx,
6108c2ecf20Sopenharmony_ci			     const struct netsec_desc *desc)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	struct netsec_de *de = dring->vaddr + DESC_SZ * idx;
6138c2ecf20Sopenharmony_ci	u32 attr = (1 << NETSEC_RX_PKT_OWN_FIELD) |
6148c2ecf20Sopenharmony_ci		   (1 << NETSEC_RX_PKT_FS_FIELD) |
6158c2ecf20Sopenharmony_ci		   (1 << NETSEC_RX_PKT_LS_FIELD);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	if (idx == DESC_NUM - 1)
6188c2ecf20Sopenharmony_ci		attr |= (1 << NETSEC_RX_PKT_LD_FIELD);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
6218c2ecf20Sopenharmony_ci	de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
6228c2ecf20Sopenharmony_ci	de->buf_len_info = desc->len;
6238c2ecf20Sopenharmony_ci	de->attr = attr;
6248c2ecf20Sopenharmony_ci	dma_wmb();
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	dring->desc[idx].dma_addr = desc->dma_addr;
6278c2ecf20Sopenharmony_ci	dring->desc[idx].addr = desc->addr;
6288c2ecf20Sopenharmony_ci	dring->desc[idx].len = desc->len;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic bool netsec_clean_tx_dring(struct netsec_priv *priv)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
6348c2ecf20Sopenharmony_ci	struct netsec_de *entry;
6358c2ecf20Sopenharmony_ci	int tail = dring->tail;
6368c2ecf20Sopenharmony_ci	unsigned int bytes;
6378c2ecf20Sopenharmony_ci	int cnt = 0;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	spin_lock(&dring->lock);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	bytes = 0;
6428c2ecf20Sopenharmony_ci	entry = dring->vaddr + DESC_SZ * tail;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	while (!(entry->attr & (1U << NETSEC_TX_SHIFT_OWN_FIELD)) &&
6458c2ecf20Sopenharmony_ci	       cnt < DESC_NUM) {
6468c2ecf20Sopenharmony_ci		struct netsec_desc *desc;
6478c2ecf20Sopenharmony_ci		int eop;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		desc = &dring->desc[tail];
6508c2ecf20Sopenharmony_ci		eop = (entry->attr >> NETSEC_TX_LAST) & 1;
6518c2ecf20Sopenharmony_ci		dma_rmb();
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		/* if buf_type is either TYPE_NETSEC_SKB or
6548c2ecf20Sopenharmony_ci		 * TYPE_NETSEC_XDP_NDO we mapped it
6558c2ecf20Sopenharmony_ci		 */
6568c2ecf20Sopenharmony_ci		if (desc->buf_type != TYPE_NETSEC_XDP_TX)
6578c2ecf20Sopenharmony_ci			dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
6588c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		if (!eop)
6618c2ecf20Sopenharmony_ci			goto next;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		if (desc->buf_type == TYPE_NETSEC_SKB) {
6648c2ecf20Sopenharmony_ci			bytes += desc->skb->len;
6658c2ecf20Sopenharmony_ci			dev_kfree_skb(desc->skb);
6668c2ecf20Sopenharmony_ci		} else {
6678c2ecf20Sopenharmony_ci			bytes += desc->xdpf->len;
6688c2ecf20Sopenharmony_ci			xdp_return_frame(desc->xdpf);
6698c2ecf20Sopenharmony_ci		}
6708c2ecf20Sopenharmony_cinext:
6718c2ecf20Sopenharmony_ci		/* clean up so netsec_uninit_pkt_dring() won't free the skb
6728c2ecf20Sopenharmony_ci		 * again
6738c2ecf20Sopenharmony_ci		 */
6748c2ecf20Sopenharmony_ci		*desc = (struct netsec_desc){};
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci		/* entry->attr is not going to be accessed by the NIC until
6778c2ecf20Sopenharmony_ci		 * netsec_set_tx_de() is called. No need for a dma_wmb() here
6788c2ecf20Sopenharmony_ci		 */
6798c2ecf20Sopenharmony_ci		entry->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
6808c2ecf20Sopenharmony_ci		/* move tail ahead */
6818c2ecf20Sopenharmony_ci		dring->tail = (tail + 1) % DESC_NUM;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci		tail = dring->tail;
6848c2ecf20Sopenharmony_ci		entry = dring->vaddr + DESC_SZ * tail;
6858c2ecf20Sopenharmony_ci		cnt++;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	spin_unlock(&dring->lock);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (!cnt)
6918c2ecf20Sopenharmony_ci		return false;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	/* reading the register clears the irq */
6948c2ecf20Sopenharmony_ci	netsec_read(priv, NETSEC_REG_NRM_TX_DONE_PKTCNT);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	priv->ndev->stats.tx_packets += cnt;
6978c2ecf20Sopenharmony_ci	priv->ndev->stats.tx_bytes += bytes;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	netdev_completed_queue(priv->ndev, cnt, bytes);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	return true;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic void netsec_process_tx(struct netsec_priv *priv)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct net_device *ndev = priv->ndev;
7078c2ecf20Sopenharmony_ci	bool cleaned;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	cleaned = netsec_clean_tx_dring(priv);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (cleaned && netif_queue_stopped(ndev)) {
7128c2ecf20Sopenharmony_ci		/* Make sure we update the value, anyone stopping the queue
7138c2ecf20Sopenharmony_ci		 * after this will read the proper consumer idx
7148c2ecf20Sopenharmony_ci		 */
7158c2ecf20Sopenharmony_ci		smp_wmb();
7168c2ecf20Sopenharmony_ci		netif_wake_queue(ndev);
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic void *netsec_alloc_rx_data(struct netsec_priv *priv,
7218c2ecf20Sopenharmony_ci				  dma_addr_t *dma_handle, u16 *desc_len)
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
7268c2ecf20Sopenharmony_ci	struct page *page;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	page = page_pool_dev_alloc_pages(dring->page_pool);
7298c2ecf20Sopenharmony_ci	if (!page)
7308c2ecf20Sopenharmony_ci		return NULL;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	/* We allocate the same buffer length for XDP and non-XDP cases.
7338c2ecf20Sopenharmony_ci	 * page_pool API will map the whole page, skip what's needed for
7348c2ecf20Sopenharmony_ci	 * network payloads and/or XDP
7358c2ecf20Sopenharmony_ci	 */
7368c2ecf20Sopenharmony_ci	*dma_handle = page_pool_get_dma_addr(page) + NETSEC_RXBUF_HEADROOM;
7378c2ecf20Sopenharmony_ci	/* Make sure the incoming payload fits in the page for XDP and non-XDP
7388c2ecf20Sopenharmony_ci	 * cases and reserve enough space for headroom + skb_shared_info
7398c2ecf20Sopenharmony_ci	 */
7408c2ecf20Sopenharmony_ci	*desc_len = NETSEC_RX_BUF_SIZE;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	return page_address(page);
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic void netsec_rx_fill(struct netsec_priv *priv, u16 from, u16 num)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
7488c2ecf20Sopenharmony_ci	u16 idx = from;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	while (num) {
7518c2ecf20Sopenharmony_ci		netsec_set_rx_de(priv, dring, idx, &dring->desc[idx]);
7528c2ecf20Sopenharmony_ci		idx++;
7538c2ecf20Sopenharmony_ci		if (idx >= DESC_NUM)
7548c2ecf20Sopenharmony_ci			idx = 0;
7558c2ecf20Sopenharmony_ci		num--;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic void netsec_xdp_ring_tx_db(struct netsec_priv *priv, u16 pkts)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	if (likely(pkts))
7628c2ecf20Sopenharmony_ci		netsec_write(priv, NETSEC_REG_NRM_TX_PKTCNT, pkts);
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic void netsec_finalize_xdp_rx(struct netsec_priv *priv, u32 xdp_res,
7668c2ecf20Sopenharmony_ci				   u16 pkts)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	if (xdp_res & NETSEC_XDP_REDIR)
7698c2ecf20Sopenharmony_ci		xdp_do_flush_map();
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	if (xdp_res & NETSEC_XDP_TX)
7728c2ecf20Sopenharmony_ci		netsec_xdp_ring_tx_db(priv, pkts);
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic void netsec_set_tx_de(struct netsec_priv *priv,
7768c2ecf20Sopenharmony_ci			     struct netsec_desc_ring *dring,
7778c2ecf20Sopenharmony_ci			     const struct netsec_tx_pkt_ctrl *tx_ctrl,
7788c2ecf20Sopenharmony_ci			     const struct netsec_desc *desc, void *buf)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	int idx = dring->head;
7818c2ecf20Sopenharmony_ci	struct netsec_de *de;
7828c2ecf20Sopenharmony_ci	u32 attr;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	de = dring->vaddr + (DESC_SZ * idx);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	attr = (1 << NETSEC_TX_SHIFT_OWN_FIELD) |
7878c2ecf20Sopenharmony_ci	       (1 << NETSEC_TX_SHIFT_PT_FIELD) |
7888c2ecf20Sopenharmony_ci	       (NETSEC_RING_GMAC << NETSEC_TX_SHIFT_TDRID_FIELD) |
7898c2ecf20Sopenharmony_ci	       (1 << NETSEC_TX_SHIFT_FS_FIELD) |
7908c2ecf20Sopenharmony_ci	       (1 << NETSEC_TX_LAST) |
7918c2ecf20Sopenharmony_ci	       (tx_ctrl->cksum_offload_flag << NETSEC_TX_SHIFT_CO) |
7928c2ecf20Sopenharmony_ci	       (tx_ctrl->tcp_seg_offload_flag << NETSEC_TX_SHIFT_SO) |
7938c2ecf20Sopenharmony_ci	       (1 << NETSEC_TX_SHIFT_TRS_FIELD);
7948c2ecf20Sopenharmony_ci	if (idx == DESC_NUM - 1)
7958c2ecf20Sopenharmony_ci		attr |= (1 << NETSEC_TX_SHIFT_LD_FIELD);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
7988c2ecf20Sopenharmony_ci	de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
7998c2ecf20Sopenharmony_ci	de->buf_len_info = (tx_ctrl->tcp_seg_len << 16) | desc->len;
8008c2ecf20Sopenharmony_ci	de->attr = attr;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	dring->desc[idx] = *desc;
8038c2ecf20Sopenharmony_ci	if (desc->buf_type == TYPE_NETSEC_SKB)
8048c2ecf20Sopenharmony_ci		dring->desc[idx].skb = buf;
8058c2ecf20Sopenharmony_ci	else if (desc->buf_type == TYPE_NETSEC_XDP_TX ||
8068c2ecf20Sopenharmony_ci		 desc->buf_type == TYPE_NETSEC_XDP_NDO)
8078c2ecf20Sopenharmony_ci		dring->desc[idx].xdpf = buf;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	/* move head ahead */
8108c2ecf20Sopenharmony_ci	dring->head = (dring->head + 1) % DESC_NUM;
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci/* The current driver only supports 1 Txq, this should run under spin_lock() */
8148c2ecf20Sopenharmony_cistatic u32 netsec_xdp_queue_one(struct netsec_priv *priv,
8158c2ecf20Sopenharmony_ci				struct xdp_frame *xdpf, bool is_ndo)
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
8198c2ecf20Sopenharmony_ci	struct page *page = virt_to_page(xdpf->data);
8208c2ecf20Sopenharmony_ci	struct netsec_tx_pkt_ctrl tx_ctrl = {};
8218c2ecf20Sopenharmony_ci	struct netsec_desc tx_desc;
8228c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
8238c2ecf20Sopenharmony_ci	u16 filled;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (tx_ring->head >= tx_ring->tail)
8268c2ecf20Sopenharmony_ci		filled = tx_ring->head - tx_ring->tail;
8278c2ecf20Sopenharmony_ci	else
8288c2ecf20Sopenharmony_ci		filled = tx_ring->head + DESC_NUM - tx_ring->tail;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (DESC_NUM - filled <= 1)
8318c2ecf20Sopenharmony_ci		return NETSEC_XDP_CONSUMED;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (is_ndo) {
8348c2ecf20Sopenharmony_ci		/* this is for ndo_xdp_xmit, the buffer needs mapping before
8358c2ecf20Sopenharmony_ci		 * sending
8368c2ecf20Sopenharmony_ci		 */
8378c2ecf20Sopenharmony_ci		dma_handle = dma_map_single(priv->dev, xdpf->data, xdpf->len,
8388c2ecf20Sopenharmony_ci					    DMA_TO_DEVICE);
8398c2ecf20Sopenharmony_ci		if (dma_mapping_error(priv->dev, dma_handle))
8408c2ecf20Sopenharmony_ci			return NETSEC_XDP_CONSUMED;
8418c2ecf20Sopenharmony_ci		tx_desc.buf_type = TYPE_NETSEC_XDP_NDO;
8428c2ecf20Sopenharmony_ci	} else {
8438c2ecf20Sopenharmony_ci		/* This is the device Rx buffer from page_pool. No need to remap
8448c2ecf20Sopenharmony_ci		 * just sync and send it
8458c2ecf20Sopenharmony_ci		 */
8468c2ecf20Sopenharmony_ci		struct netsec_desc_ring *rx_ring =
8478c2ecf20Sopenharmony_ci			&priv->desc_ring[NETSEC_RING_RX];
8488c2ecf20Sopenharmony_ci		enum dma_data_direction dma_dir =
8498c2ecf20Sopenharmony_ci			page_pool_get_dma_dir(rx_ring->page_pool);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci		dma_handle = page_pool_get_dma_addr(page) + xdpf->headroom +
8528c2ecf20Sopenharmony_ci			sizeof(*xdpf);
8538c2ecf20Sopenharmony_ci		dma_sync_single_for_device(priv->dev, dma_handle, xdpf->len,
8548c2ecf20Sopenharmony_ci					   dma_dir);
8558c2ecf20Sopenharmony_ci		tx_desc.buf_type = TYPE_NETSEC_XDP_TX;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	tx_desc.dma_addr = dma_handle;
8598c2ecf20Sopenharmony_ci	tx_desc.addr = xdpf->data;
8608c2ecf20Sopenharmony_ci	tx_desc.len = xdpf->len;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	netdev_sent_queue(priv->ndev, xdpf->len);
8638c2ecf20Sopenharmony_ci	netsec_set_tx_de(priv, tx_ring, &tx_ctrl, &tx_desc, xdpf);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	return NETSEC_XDP_TX;
8668c2ecf20Sopenharmony_ci}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic u32 netsec_xdp_xmit_back(struct netsec_priv *priv, struct xdp_buff *xdp)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
8718c2ecf20Sopenharmony_ci	struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
8728c2ecf20Sopenharmony_ci	u32 ret;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	if (unlikely(!xdpf))
8758c2ecf20Sopenharmony_ci		return NETSEC_XDP_CONSUMED;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	spin_lock(&tx_ring->lock);
8788c2ecf20Sopenharmony_ci	ret = netsec_xdp_queue_one(priv, xdpf, false);
8798c2ecf20Sopenharmony_ci	spin_unlock(&tx_ring->lock);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	return ret;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic u32 netsec_run_xdp(struct netsec_priv *priv, struct bpf_prog *prog,
8858c2ecf20Sopenharmony_ci			  struct xdp_buff *xdp)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
8888c2ecf20Sopenharmony_ci	unsigned int sync, len = xdp->data_end - xdp->data;
8898c2ecf20Sopenharmony_ci	u32 ret = NETSEC_XDP_PASS;
8908c2ecf20Sopenharmony_ci	struct page *page;
8918c2ecf20Sopenharmony_ci	int err;
8928c2ecf20Sopenharmony_ci	u32 act;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	act = bpf_prog_run_xdp(prog, xdp);
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	/* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
8978c2ecf20Sopenharmony_ci	sync = xdp->data_end - xdp->data_hard_start - NETSEC_RXBUF_HEADROOM;
8988c2ecf20Sopenharmony_ci	sync = max(sync, len);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	switch (act) {
9018c2ecf20Sopenharmony_ci	case XDP_PASS:
9028c2ecf20Sopenharmony_ci		ret = NETSEC_XDP_PASS;
9038c2ecf20Sopenharmony_ci		break;
9048c2ecf20Sopenharmony_ci	case XDP_TX:
9058c2ecf20Sopenharmony_ci		ret = netsec_xdp_xmit_back(priv, xdp);
9068c2ecf20Sopenharmony_ci		if (ret != NETSEC_XDP_TX) {
9078c2ecf20Sopenharmony_ci			page = virt_to_head_page(xdp->data);
9088c2ecf20Sopenharmony_ci			page_pool_put_page(dring->page_pool, page, sync, true);
9098c2ecf20Sopenharmony_ci		}
9108c2ecf20Sopenharmony_ci		break;
9118c2ecf20Sopenharmony_ci	case XDP_REDIRECT:
9128c2ecf20Sopenharmony_ci		err = xdp_do_redirect(priv->ndev, xdp, prog);
9138c2ecf20Sopenharmony_ci		if (!err) {
9148c2ecf20Sopenharmony_ci			ret = NETSEC_XDP_REDIR;
9158c2ecf20Sopenharmony_ci		} else {
9168c2ecf20Sopenharmony_ci			ret = NETSEC_XDP_CONSUMED;
9178c2ecf20Sopenharmony_ci			page = virt_to_head_page(xdp->data);
9188c2ecf20Sopenharmony_ci			page_pool_put_page(dring->page_pool, page, sync, true);
9198c2ecf20Sopenharmony_ci		}
9208c2ecf20Sopenharmony_ci		break;
9218c2ecf20Sopenharmony_ci	default:
9228c2ecf20Sopenharmony_ci		bpf_warn_invalid_xdp_action(act);
9238c2ecf20Sopenharmony_ci		fallthrough;
9248c2ecf20Sopenharmony_ci	case XDP_ABORTED:
9258c2ecf20Sopenharmony_ci		trace_xdp_exception(priv->ndev, prog, act);
9268c2ecf20Sopenharmony_ci		fallthrough;	/* handle aborts by dropping packet */
9278c2ecf20Sopenharmony_ci	case XDP_DROP:
9288c2ecf20Sopenharmony_ci		ret = NETSEC_XDP_CONSUMED;
9298c2ecf20Sopenharmony_ci		page = virt_to_head_page(xdp->data);
9308c2ecf20Sopenharmony_ci		page_pool_put_page(dring->page_pool, page, sync, true);
9318c2ecf20Sopenharmony_ci		break;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	return ret;
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic int netsec_process_rx(struct netsec_priv *priv, int budget)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
9408c2ecf20Sopenharmony_ci	struct net_device *ndev = priv->ndev;
9418c2ecf20Sopenharmony_ci	struct netsec_rx_pkt_info rx_info;
9428c2ecf20Sopenharmony_ci	enum dma_data_direction dma_dir;
9438c2ecf20Sopenharmony_ci	struct bpf_prog *xdp_prog;
9448c2ecf20Sopenharmony_ci	struct xdp_buff xdp;
9458c2ecf20Sopenharmony_ci	u16 xdp_xmit = 0;
9468c2ecf20Sopenharmony_ci	u32 xdp_act = 0;
9478c2ecf20Sopenharmony_ci	int done = 0;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	xdp.rxq = &dring->xdp_rxq;
9508c2ecf20Sopenharmony_ci	xdp.frame_sz = PAGE_SIZE;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	rcu_read_lock();
9538c2ecf20Sopenharmony_ci	xdp_prog = READ_ONCE(priv->xdp_prog);
9548c2ecf20Sopenharmony_ci	dma_dir = page_pool_get_dma_dir(dring->page_pool);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	while (done < budget) {
9578c2ecf20Sopenharmony_ci		u16 idx = dring->tail;
9588c2ecf20Sopenharmony_ci		struct netsec_de *de = dring->vaddr + (DESC_SZ * idx);
9598c2ecf20Sopenharmony_ci		struct netsec_desc *desc = &dring->desc[idx];
9608c2ecf20Sopenharmony_ci		struct page *page = virt_to_page(desc->addr);
9618c2ecf20Sopenharmony_ci		u32 xdp_result = NETSEC_XDP_PASS;
9628c2ecf20Sopenharmony_ci		struct sk_buff *skb = NULL;
9638c2ecf20Sopenharmony_ci		u16 pkt_len, desc_len;
9648c2ecf20Sopenharmony_ci		dma_addr_t dma_handle;
9658c2ecf20Sopenharmony_ci		void *buf_addr;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		if (de->attr & (1U << NETSEC_RX_PKT_OWN_FIELD)) {
9688c2ecf20Sopenharmony_ci			/* reading the register clears the irq */
9698c2ecf20Sopenharmony_ci			netsec_read(priv, NETSEC_REG_NRM_RX_PKTCNT);
9708c2ecf20Sopenharmony_ci			break;
9718c2ecf20Sopenharmony_ci		}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci		/* This  barrier is needed to keep us from reading
9748c2ecf20Sopenharmony_ci		 * any other fields out of the netsec_de until we have
9758c2ecf20Sopenharmony_ci		 * verified the descriptor has been written back
9768c2ecf20Sopenharmony_ci		 */
9778c2ecf20Sopenharmony_ci		dma_rmb();
9788c2ecf20Sopenharmony_ci		done++;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci		pkt_len = de->buf_len_info >> 16;
9818c2ecf20Sopenharmony_ci		rx_info.err_code = (de->attr >> NETSEC_RX_PKT_ERR_FIELD) &
9828c2ecf20Sopenharmony_ci			NETSEC_RX_PKT_ERR_MASK;
9838c2ecf20Sopenharmony_ci		rx_info.err_flag = (de->attr >> NETSEC_RX_PKT_ER_FIELD) & 1;
9848c2ecf20Sopenharmony_ci		if (rx_info.err_flag) {
9858c2ecf20Sopenharmony_ci			netif_err(priv, drv, priv->ndev,
9868c2ecf20Sopenharmony_ci				  "%s: rx fail err(%d)\n", __func__,
9878c2ecf20Sopenharmony_ci				  rx_info.err_code);
9888c2ecf20Sopenharmony_ci			ndev->stats.rx_dropped++;
9898c2ecf20Sopenharmony_ci			dring->tail = (dring->tail + 1) % DESC_NUM;
9908c2ecf20Sopenharmony_ci			/* reuse buffer page frag */
9918c2ecf20Sopenharmony_ci			netsec_rx_fill(priv, idx, 1);
9928c2ecf20Sopenharmony_ci			continue;
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci		rx_info.rx_cksum_result =
9958c2ecf20Sopenharmony_ci			(de->attr >> NETSEC_RX_PKT_CO_FIELD) & 3;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci		/* allocate a fresh buffer and map it to the hardware.
9988c2ecf20Sopenharmony_ci		 * This will eventually replace the old buffer in the hardware
9998c2ecf20Sopenharmony_ci		 */
10008c2ecf20Sopenharmony_ci		buf_addr = netsec_alloc_rx_data(priv, &dma_handle, &desc_len);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci		if (unlikely(!buf_addr))
10038c2ecf20Sopenharmony_ci			break;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci		dma_sync_single_for_cpu(priv->dev, desc->dma_addr, pkt_len,
10068c2ecf20Sopenharmony_ci					dma_dir);
10078c2ecf20Sopenharmony_ci		prefetch(desc->addr);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		xdp.data_hard_start = desc->addr;
10108c2ecf20Sopenharmony_ci		xdp.data = desc->addr + NETSEC_RXBUF_HEADROOM;
10118c2ecf20Sopenharmony_ci		xdp_set_data_meta_invalid(&xdp);
10128c2ecf20Sopenharmony_ci		xdp.data_end = xdp.data + pkt_len;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		if (xdp_prog) {
10158c2ecf20Sopenharmony_ci			xdp_result = netsec_run_xdp(priv, xdp_prog, &xdp);
10168c2ecf20Sopenharmony_ci			if (xdp_result != NETSEC_XDP_PASS) {
10178c2ecf20Sopenharmony_ci				xdp_act |= xdp_result;
10188c2ecf20Sopenharmony_ci				if (xdp_result == NETSEC_XDP_TX)
10198c2ecf20Sopenharmony_ci					xdp_xmit++;
10208c2ecf20Sopenharmony_ci				goto next;
10218c2ecf20Sopenharmony_ci			}
10228c2ecf20Sopenharmony_ci		}
10238c2ecf20Sopenharmony_ci		skb = build_skb(desc->addr, desc->len + NETSEC_RX_BUF_NON_DATA);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci		if (unlikely(!skb)) {
10268c2ecf20Sopenharmony_ci			/* If skb fails recycle_direct will either unmap and
10278c2ecf20Sopenharmony_ci			 * free the page or refill the cache depending on the
10288c2ecf20Sopenharmony_ci			 * cache state. Since we paid the allocation cost if
10298c2ecf20Sopenharmony_ci			 * building an skb fails try to put the page into cache
10308c2ecf20Sopenharmony_ci			 */
10318c2ecf20Sopenharmony_ci			page_pool_put_page(dring->page_pool, page, pkt_len,
10328c2ecf20Sopenharmony_ci					   true);
10338c2ecf20Sopenharmony_ci			netif_err(priv, drv, priv->ndev,
10348c2ecf20Sopenharmony_ci				  "rx failed to build skb\n");
10358c2ecf20Sopenharmony_ci			break;
10368c2ecf20Sopenharmony_ci		}
10378c2ecf20Sopenharmony_ci		page_pool_release_page(dring->page_pool, page);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci		skb_reserve(skb, xdp.data - xdp.data_hard_start);
10408c2ecf20Sopenharmony_ci		skb_put(skb, xdp.data_end - xdp.data);
10418c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, priv->ndev);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci		if (priv->rx_cksum_offload_flag &&
10448c2ecf20Sopenharmony_ci		    rx_info.rx_cksum_result == NETSEC_RX_CKSUM_OK)
10458c2ecf20Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_cinext:
10488c2ecf20Sopenharmony_ci		if (skb)
10498c2ecf20Sopenharmony_ci			napi_gro_receive(&priv->napi, skb);
10508c2ecf20Sopenharmony_ci		if (skb || xdp_result) {
10518c2ecf20Sopenharmony_ci			ndev->stats.rx_packets++;
10528c2ecf20Sopenharmony_ci			ndev->stats.rx_bytes += xdp.data_end - xdp.data;
10538c2ecf20Sopenharmony_ci		}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci		/* Update the descriptor with fresh buffers */
10568c2ecf20Sopenharmony_ci		desc->len = desc_len;
10578c2ecf20Sopenharmony_ci		desc->dma_addr = dma_handle;
10588c2ecf20Sopenharmony_ci		desc->addr = buf_addr;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci		netsec_rx_fill(priv, idx, 1);
10618c2ecf20Sopenharmony_ci		dring->tail = (dring->tail + 1) % DESC_NUM;
10628c2ecf20Sopenharmony_ci	}
10638c2ecf20Sopenharmony_ci	netsec_finalize_xdp_rx(priv, xdp_act, xdp_xmit);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	rcu_read_unlock();
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	return done;
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic int netsec_napi_poll(struct napi_struct *napi, int budget)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	struct netsec_priv *priv;
10738c2ecf20Sopenharmony_ci	int done;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	priv = container_of(napi, struct netsec_priv, napi);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	netsec_process_tx(priv);
10788c2ecf20Sopenharmony_ci	done = netsec_process_rx(priv, budget);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (done < budget && napi_complete_done(napi, done)) {
10818c2ecf20Sopenharmony_ci		unsigned long flags;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci		spin_lock_irqsave(&priv->reglock, flags);
10848c2ecf20Sopenharmony_ci		netsec_write(priv, NETSEC_REG_INTEN_SET,
10858c2ecf20Sopenharmony_ci			     NETSEC_IRQ_RX | NETSEC_IRQ_TX);
10868c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&priv->reglock, flags);
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	return done;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic int netsec_desc_used(struct netsec_desc_ring *dring)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	int used;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	if (dring->head >= dring->tail)
10988c2ecf20Sopenharmony_ci		used = dring->head - dring->tail;
10998c2ecf20Sopenharmony_ci	else
11008c2ecf20Sopenharmony_ci		used = dring->head + DESC_NUM - dring->tail;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	return used;
11038c2ecf20Sopenharmony_ci}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_cistatic int netsec_check_stop_tx(struct netsec_priv *priv, int used)
11068c2ecf20Sopenharmony_ci{
11078c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/* keep tail from touching the queue */
11108c2ecf20Sopenharmony_ci	if (DESC_NUM - used < 2) {
11118c2ecf20Sopenharmony_ci		netif_stop_queue(priv->ndev);
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci		/* Make sure we read the updated value in case
11148c2ecf20Sopenharmony_ci		 * descriptors got freed
11158c2ecf20Sopenharmony_ci		 */
11168c2ecf20Sopenharmony_ci		smp_rmb();
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		used = netsec_desc_used(dring);
11198c2ecf20Sopenharmony_ci		if (DESC_NUM - used < 2)
11208c2ecf20Sopenharmony_ci			return NETDEV_TX_BUSY;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci		netif_wake_queue(priv->ndev);
11238c2ecf20Sopenharmony_ci	}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	return 0;
11268c2ecf20Sopenharmony_ci}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_cistatic netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb,
11298c2ecf20Sopenharmony_ci					    struct net_device *ndev)
11308c2ecf20Sopenharmony_ci{
11318c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
11328c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
11338c2ecf20Sopenharmony_ci	struct netsec_tx_pkt_ctrl tx_ctrl = {};
11348c2ecf20Sopenharmony_ci	struct netsec_desc tx_desc;
11358c2ecf20Sopenharmony_ci	u16 tso_seg_len = 0;
11368c2ecf20Sopenharmony_ci	int filled;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	spin_lock_bh(&dring->lock);
11398c2ecf20Sopenharmony_ci	filled = netsec_desc_used(dring);
11408c2ecf20Sopenharmony_ci	if (netsec_check_stop_tx(priv, filled)) {
11418c2ecf20Sopenharmony_ci		spin_unlock_bh(&dring->lock);
11428c2ecf20Sopenharmony_ci		net_warn_ratelimited("%s %s Tx queue full\n",
11438c2ecf20Sopenharmony_ci				     dev_name(priv->dev), ndev->name);
11448c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL)
11488c2ecf20Sopenharmony_ci		tx_ctrl.cksum_offload_flag = true;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	if (skb_is_gso(skb))
11518c2ecf20Sopenharmony_ci		tso_seg_len = skb_shinfo(skb)->gso_size;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	if (tso_seg_len > 0) {
11548c2ecf20Sopenharmony_ci		if (skb->protocol == htons(ETH_P_IP)) {
11558c2ecf20Sopenharmony_ci			ip_hdr(skb)->tot_len = 0;
11568c2ecf20Sopenharmony_ci			tcp_hdr(skb)->check =
11578c2ecf20Sopenharmony_ci				~tcp_v4_check(0, ip_hdr(skb)->saddr,
11588c2ecf20Sopenharmony_ci					      ip_hdr(skb)->daddr, 0);
11598c2ecf20Sopenharmony_ci		} else {
11608c2ecf20Sopenharmony_ci			tcp_v6_gso_csum_prep(skb);
11618c2ecf20Sopenharmony_ci		}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci		tx_ctrl.tcp_seg_offload_flag = true;
11648c2ecf20Sopenharmony_ci		tx_ctrl.tcp_seg_len = tso_seg_len;
11658c2ecf20Sopenharmony_ci	}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	tx_desc.dma_addr = dma_map_single(priv->dev, skb->data,
11688c2ecf20Sopenharmony_ci					  skb_headlen(skb), DMA_TO_DEVICE);
11698c2ecf20Sopenharmony_ci	if (dma_mapping_error(priv->dev, tx_desc.dma_addr)) {
11708c2ecf20Sopenharmony_ci		spin_unlock_bh(&dring->lock);
11718c2ecf20Sopenharmony_ci		netif_err(priv, drv, priv->ndev,
11728c2ecf20Sopenharmony_ci			  "%s: DMA mapping failed\n", __func__);
11738c2ecf20Sopenharmony_ci		ndev->stats.tx_dropped++;
11748c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
11758c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci	tx_desc.addr = skb->data;
11788c2ecf20Sopenharmony_ci	tx_desc.len = skb_headlen(skb);
11798c2ecf20Sopenharmony_ci	tx_desc.buf_type = TYPE_NETSEC_SKB;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	skb_tx_timestamp(skb);
11828c2ecf20Sopenharmony_ci	netdev_sent_queue(priv->ndev, skb->len);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	netsec_set_tx_de(priv, dring, &tx_ctrl, &tx_desc, skb);
11858c2ecf20Sopenharmony_ci	spin_unlock_bh(&dring->lock);
11868c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_PKTCNT, 1); /* submit another tx */
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
11898c2ecf20Sopenharmony_ci}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_cistatic void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id)
11928c2ecf20Sopenharmony_ci{
11938c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[id];
11948c2ecf20Sopenharmony_ci	struct netsec_desc *desc;
11958c2ecf20Sopenharmony_ci	u16 idx;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	if (!dring->vaddr || !dring->desc)
11988c2ecf20Sopenharmony_ci		return;
11998c2ecf20Sopenharmony_ci	for (idx = 0; idx < DESC_NUM; idx++) {
12008c2ecf20Sopenharmony_ci		desc = &dring->desc[idx];
12018c2ecf20Sopenharmony_ci		if (!desc->addr)
12028c2ecf20Sopenharmony_ci			continue;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci		if (id == NETSEC_RING_RX) {
12058c2ecf20Sopenharmony_ci			struct page *page = virt_to_page(desc->addr);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci			page_pool_put_full_page(dring->page_pool, page, false);
12088c2ecf20Sopenharmony_ci		} else if (id == NETSEC_RING_TX) {
12098c2ecf20Sopenharmony_ci			dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
12108c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
12118c2ecf20Sopenharmony_ci			dev_kfree_skb(desc->skb);
12128c2ecf20Sopenharmony_ci		}
12138c2ecf20Sopenharmony_ci	}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	/* Rx is currently using page_pool */
12168c2ecf20Sopenharmony_ci	if (id == NETSEC_RING_RX) {
12178c2ecf20Sopenharmony_ci		if (xdp_rxq_info_is_reg(&dring->xdp_rxq))
12188c2ecf20Sopenharmony_ci			xdp_rxq_info_unreg(&dring->xdp_rxq);
12198c2ecf20Sopenharmony_ci		page_pool_destroy(dring->page_pool);
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	memset(dring->desc, 0, sizeof(struct netsec_desc) * DESC_NUM);
12238c2ecf20Sopenharmony_ci	memset(dring->vaddr, 0, DESC_SZ * DESC_NUM);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	dring->head = 0;
12268c2ecf20Sopenharmony_ci	dring->tail = 0;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	if (id == NETSEC_RING_TX)
12298c2ecf20Sopenharmony_ci		netdev_reset_queue(priv->ndev);
12308c2ecf20Sopenharmony_ci}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_cistatic void netsec_free_dring(struct netsec_priv *priv, int id)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[id];
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	if (dring->vaddr) {
12378c2ecf20Sopenharmony_ci		dma_free_coherent(priv->dev, DESC_SZ * DESC_NUM,
12388c2ecf20Sopenharmony_ci				  dring->vaddr, dring->desc_dma);
12398c2ecf20Sopenharmony_ci		dring->vaddr = NULL;
12408c2ecf20Sopenharmony_ci	}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	kfree(dring->desc);
12438c2ecf20Sopenharmony_ci	dring->desc = NULL;
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[id];
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	dring->vaddr = dma_alloc_coherent(priv->dev, DESC_SZ * DESC_NUM,
12518c2ecf20Sopenharmony_ci					  &dring->desc_dma, GFP_KERNEL);
12528c2ecf20Sopenharmony_ci	if (!dring->vaddr)
12538c2ecf20Sopenharmony_ci		goto err;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	dring->desc = kcalloc(DESC_NUM, sizeof(*dring->desc), GFP_KERNEL);
12568c2ecf20Sopenharmony_ci	if (!dring->desc)
12578c2ecf20Sopenharmony_ci		goto err;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	return 0;
12608c2ecf20Sopenharmony_cierr:
12618c2ecf20Sopenharmony_ci	netsec_free_dring(priv, id);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	return -ENOMEM;
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic void netsec_setup_tx_dring(struct netsec_priv *priv)
12678c2ecf20Sopenharmony_ci{
12688c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
12698c2ecf20Sopenharmony_ci	int i;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	for (i = 0; i < DESC_NUM; i++) {
12728c2ecf20Sopenharmony_ci		struct netsec_de *de;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci		de = dring->vaddr + (DESC_SZ * i);
12758c2ecf20Sopenharmony_ci		/* de->attr is not going to be accessed by the NIC
12768c2ecf20Sopenharmony_ci		 * until netsec_set_tx_de() is called.
12778c2ecf20Sopenharmony_ci		 * No need for a dma_wmb() here
12788c2ecf20Sopenharmony_ci		 */
12798c2ecf20Sopenharmony_ci		de->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
12808c2ecf20Sopenharmony_ci	}
12818c2ecf20Sopenharmony_ci}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_cistatic int netsec_setup_rx_dring(struct netsec_priv *priv)
12848c2ecf20Sopenharmony_ci{
12858c2ecf20Sopenharmony_ci	struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
12868c2ecf20Sopenharmony_ci	struct bpf_prog *xdp_prog = READ_ONCE(priv->xdp_prog);
12878c2ecf20Sopenharmony_ci	struct page_pool_params pp_params = {
12888c2ecf20Sopenharmony_ci		.order = 0,
12898c2ecf20Sopenharmony_ci		/* internal DMA mapping in page_pool */
12908c2ecf20Sopenharmony_ci		.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
12918c2ecf20Sopenharmony_ci		.pool_size = DESC_NUM,
12928c2ecf20Sopenharmony_ci		.nid = NUMA_NO_NODE,
12938c2ecf20Sopenharmony_ci		.dev = priv->dev,
12948c2ecf20Sopenharmony_ci		.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE,
12958c2ecf20Sopenharmony_ci		.offset = NETSEC_RXBUF_HEADROOM,
12968c2ecf20Sopenharmony_ci		.max_len = NETSEC_RX_BUF_SIZE,
12978c2ecf20Sopenharmony_ci	};
12988c2ecf20Sopenharmony_ci	int i, err;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	dring->page_pool = page_pool_create(&pp_params);
13018c2ecf20Sopenharmony_ci	if (IS_ERR(dring->page_pool)) {
13028c2ecf20Sopenharmony_ci		err = PTR_ERR(dring->page_pool);
13038c2ecf20Sopenharmony_ci		dring->page_pool = NULL;
13048c2ecf20Sopenharmony_ci		goto err_out;
13058c2ecf20Sopenharmony_ci	}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	err = xdp_rxq_info_reg(&dring->xdp_rxq, priv->ndev, 0);
13088c2ecf20Sopenharmony_ci	if (err)
13098c2ecf20Sopenharmony_ci		goto err_out;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	err = xdp_rxq_info_reg_mem_model(&dring->xdp_rxq, MEM_TYPE_PAGE_POOL,
13128c2ecf20Sopenharmony_ci					 dring->page_pool);
13138c2ecf20Sopenharmony_ci	if (err)
13148c2ecf20Sopenharmony_ci		goto err_out;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	for (i = 0; i < DESC_NUM; i++) {
13178c2ecf20Sopenharmony_ci		struct netsec_desc *desc = &dring->desc[i];
13188c2ecf20Sopenharmony_ci		dma_addr_t dma_handle;
13198c2ecf20Sopenharmony_ci		void *buf;
13208c2ecf20Sopenharmony_ci		u16 len;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		buf = netsec_alloc_rx_data(priv, &dma_handle, &len);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci		if (!buf) {
13258c2ecf20Sopenharmony_ci			err = -ENOMEM;
13268c2ecf20Sopenharmony_ci			goto err_out;
13278c2ecf20Sopenharmony_ci		}
13288c2ecf20Sopenharmony_ci		desc->dma_addr = dma_handle;
13298c2ecf20Sopenharmony_ci		desc->addr = buf;
13308c2ecf20Sopenharmony_ci		desc->len = len;
13318c2ecf20Sopenharmony_ci	}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	netsec_rx_fill(priv, 0, DESC_NUM);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	return 0;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_cierr_out:
13388c2ecf20Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
13398c2ecf20Sopenharmony_ci	return err;
13408c2ecf20Sopenharmony_ci}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_cistatic int netsec_netdev_load_ucode_region(struct netsec_priv *priv, u32 reg,
13438c2ecf20Sopenharmony_ci					   u32 addr_h, u32 addr_l, u32 size)
13448c2ecf20Sopenharmony_ci{
13458c2ecf20Sopenharmony_ci	u64 base = (u64)addr_h << 32 | addr_l;
13468c2ecf20Sopenharmony_ci	void __iomem *ucode;
13478c2ecf20Sopenharmony_ci	u32 i;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	ucode = ioremap(base, size * sizeof(u32));
13508c2ecf20Sopenharmony_ci	if (!ucode)
13518c2ecf20Sopenharmony_ci		return -ENOMEM;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++)
13548c2ecf20Sopenharmony_ci		netsec_write(priv, reg, readl(ucode + i * 4));
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	iounmap(ucode);
13578c2ecf20Sopenharmony_ci	return 0;
13588c2ecf20Sopenharmony_ci}
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_cistatic int netsec_netdev_load_microcode(struct netsec_priv *priv)
13618c2ecf20Sopenharmony_ci{
13628c2ecf20Sopenharmony_ci	u32 addr_h, addr_l, size;
13638c2ecf20Sopenharmony_ci	int err;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	addr_h = readl(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_H);
13668c2ecf20Sopenharmony_ci	addr_l = readl(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_L);
13678c2ecf20Sopenharmony_ci	size = readl(priv->eeprom_base + NETSEC_EEPROM_HM_ME_SIZE);
13688c2ecf20Sopenharmony_ci	err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_DMAC_HM_CMD_BUF,
13698c2ecf20Sopenharmony_ci					      addr_h, addr_l, size);
13708c2ecf20Sopenharmony_ci	if (err)
13718c2ecf20Sopenharmony_ci		return err;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	addr_h = readl(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_H);
13748c2ecf20Sopenharmony_ci	addr_l = readl(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_L);
13758c2ecf20Sopenharmony_ci	size = readl(priv->eeprom_base + NETSEC_EEPROM_MH_ME_SIZE);
13768c2ecf20Sopenharmony_ci	err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_DMAC_MH_CMD_BUF,
13778c2ecf20Sopenharmony_ci					      addr_h, addr_l, size);
13788c2ecf20Sopenharmony_ci	if (err)
13798c2ecf20Sopenharmony_ci		return err;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	addr_h = 0;
13828c2ecf20Sopenharmony_ci	addr_l = readl(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_ADDRESS);
13838c2ecf20Sopenharmony_ci	size = readl(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_SIZE);
13848c2ecf20Sopenharmony_ci	err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_PKT_CMD_BUF,
13858c2ecf20Sopenharmony_ci					      addr_h, addr_l, size);
13868c2ecf20Sopenharmony_ci	if (err)
13878c2ecf20Sopenharmony_ci		return err;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	return 0;
13908c2ecf20Sopenharmony_ci}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_cistatic int netsec_reset_hardware(struct netsec_priv *priv,
13938c2ecf20Sopenharmony_ci				 bool load_ucode)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	u32 value;
13968c2ecf20Sopenharmony_ci	int err;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	/* stop DMA engines */
13998c2ecf20Sopenharmony_ci	if (!netsec_read(priv, NETSEC_REG_ADDR_DIS_CORE)) {
14008c2ecf20Sopenharmony_ci		netsec_write(priv, NETSEC_REG_DMA_HM_CTRL,
14018c2ecf20Sopenharmony_ci			     NETSEC_DMA_CTRL_REG_STOP);
14028c2ecf20Sopenharmony_ci		netsec_write(priv, NETSEC_REG_DMA_MH_CTRL,
14038c2ecf20Sopenharmony_ci			     NETSEC_DMA_CTRL_REG_STOP);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci		while (netsec_read(priv, NETSEC_REG_DMA_HM_CTRL) &
14068c2ecf20Sopenharmony_ci		       NETSEC_DMA_CTRL_REG_STOP)
14078c2ecf20Sopenharmony_ci			cpu_relax();
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci		while (netsec_read(priv, NETSEC_REG_DMA_MH_CTRL) &
14108c2ecf20Sopenharmony_ci		       NETSEC_DMA_CTRL_REG_STOP)
14118c2ecf20Sopenharmony_ci			cpu_relax();
14128c2ecf20Sopenharmony_ci	}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RESET);
14158c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RUN);
14168c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_COM_INIT, NETSEC_COM_INIT_REG_ALL);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	while (netsec_read(priv, NETSEC_REG_COM_INIT) != 0)
14198c2ecf20Sopenharmony_ci		cpu_relax();
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	/* set desc_start addr */
14228c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_DESC_START_UP,
14238c2ecf20Sopenharmony_ci		     upper_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_dma));
14248c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_DESC_START_LW,
14258c2ecf20Sopenharmony_ci		     lower_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_dma));
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_DESC_START_UP,
14288c2ecf20Sopenharmony_ci		     upper_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_dma));
14298c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_DESC_START_LW,
14308c2ecf20Sopenharmony_ci		     lower_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_dma));
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	/* set normal tx dring ring config */
14338c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_CONFIG,
14348c2ecf20Sopenharmony_ci		     1 << NETSEC_REG_DESC_ENDIAN);
14358c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_CONFIG,
14368c2ecf20Sopenharmony_ci		     1 << NETSEC_REG_DESC_ENDIAN);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	if (load_ucode) {
14398c2ecf20Sopenharmony_ci		err = netsec_netdev_load_microcode(priv);
14408c2ecf20Sopenharmony_ci		if (err) {
14418c2ecf20Sopenharmony_ci			netif_err(priv, probe, priv->ndev,
14428c2ecf20Sopenharmony_ci				  "%s: failed to load microcode (%d)\n",
14438c2ecf20Sopenharmony_ci				  __func__, err);
14448c2ecf20Sopenharmony_ci			return err;
14458c2ecf20Sopenharmony_ci		}
14468c2ecf20Sopenharmony_ci	}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	/* start DMA engines */
14498c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_DMA_TMR_CTRL, priv->freq / 1000000 - 1);
14508c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_ADDR_DIS_CORE, 0);
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	if (!(netsec_read(priv, NETSEC_REG_TOP_STATUS) &
14558c2ecf20Sopenharmony_ci	      NETSEC_TOP_IRQ_REG_CODE_LOAD_END)) {
14568c2ecf20Sopenharmony_ci		netif_err(priv, probe, priv->ndev,
14578c2ecf20Sopenharmony_ci			  "microengine start failed\n");
14588c2ecf20Sopenharmony_ci		return -ENXIO;
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_TOP_STATUS,
14618c2ecf20Sopenharmony_ci		     NETSEC_TOP_IRQ_REG_CODE_LOAD_END);
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	value = NETSEC_PKT_CTRL_REG_MODE_NRM;
14648c2ecf20Sopenharmony_ci	if (priv->ndev->mtu > ETH_DATA_LEN)
14658c2ecf20Sopenharmony_ci		value |= NETSEC_PKT_CTRL_REG_EN_JUMBO;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	/* change to normal mode */
14688c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_DMA_MH_CTRL, MH_CTRL__MODE_TRANS);
14698c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_PKT_CTRL, value);
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	while ((netsec_read(priv, NETSEC_REG_MODE_TRANS_COMP_STATUS) &
14728c2ecf20Sopenharmony_ci		NETSEC_MODE_TRANS_COMP_IRQ_T2N) == 0)
14738c2ecf20Sopenharmony_ci		cpu_relax();
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/* clear any pending EMPTY/ERR irq status */
14768c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_STATUS, ~0);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	/* Disable TX & RX intr */
14798c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_CLR, ~0);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	return 0;
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_cistatic int netsec_start_gmac(struct netsec_priv *priv)
14858c2ecf20Sopenharmony_ci{
14868c2ecf20Sopenharmony_ci	struct phy_device *phydev = priv->ndev->phydev;
14878c2ecf20Sopenharmony_ci	u32 value = 0;
14888c2ecf20Sopenharmony_ci	int ret;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	if (phydev->speed != SPEED_1000)
14918c2ecf20Sopenharmony_ci		value = (NETSEC_GMAC_MCR_REG_CST |
14928c2ecf20Sopenharmony_ci			 NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_MCR, value))
14958c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
14968c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_BMR,
14978c2ecf20Sopenharmony_ci			     NETSEC_GMAC_BMR_REG_RESET))
14988c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	/* Wait soft reset */
15018c2ecf20Sopenharmony_ci	usleep_range(1000, 5000);
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_BMR, &value);
15048c2ecf20Sopenharmony_ci	if (ret)
15058c2ecf20Sopenharmony_ci		return ret;
15068c2ecf20Sopenharmony_ci	if (value & NETSEC_GMAC_BMR_REG_SWR)
15078c2ecf20Sopenharmony_ci		return -EAGAIN;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	netsec_write(priv, MAC_REG_DESC_SOFT_RST, 1);
15108c2ecf20Sopenharmony_ci	if (netsec_wait_while_busy(priv, MAC_REG_DESC_SOFT_RST, 1))
15118c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	netsec_write(priv, MAC_REG_DESC_INIT, 1);
15148c2ecf20Sopenharmony_ci	if (netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1))
15158c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_BMR,
15188c2ecf20Sopenharmony_ci			     NETSEC_GMAC_BMR_REG_COMMON))
15198c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
15208c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_RDLAR,
15218c2ecf20Sopenharmony_ci			     NETSEC_GMAC_RDLAR_REG_COMMON))
15228c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
15238c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_TDLAR,
15248c2ecf20Sopenharmony_ci			     NETSEC_GMAC_TDLAR_REG_COMMON))
15258c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
15268c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_MFFR, 0x80000001))
15278c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	ret = netsec_mac_update_to_phy_state(priv);
15308c2ecf20Sopenharmony_ci	if (ret)
15318c2ecf20Sopenharmony_ci		return ret;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
15348c2ecf20Sopenharmony_ci	if (ret)
15358c2ecf20Sopenharmony_ci		return ret;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	value |= NETSEC_GMAC_OMR_REG_SR;
15388c2ecf20Sopenharmony_ci	value |= NETSEC_GMAC_OMR_REG_ST;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0);
15418c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	netsec_et_set_coalesce(priv->ndev, &priv->et_coalesce);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	if (netsec_mac_write(priv, GMAC_REG_OMR, value))
15468c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	return 0;
15498c2ecf20Sopenharmony_ci}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_cistatic int netsec_stop_gmac(struct netsec_priv *priv)
15528c2ecf20Sopenharmony_ci{
15538c2ecf20Sopenharmony_ci	u32 value;
15548c2ecf20Sopenharmony_ci	int ret;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
15578c2ecf20Sopenharmony_ci	if (ret)
15588c2ecf20Sopenharmony_ci		return ret;
15598c2ecf20Sopenharmony_ci	value &= ~NETSEC_GMAC_OMR_REG_SR;
15608c2ecf20Sopenharmony_ci	value &= ~NETSEC_GMAC_OMR_REG_ST;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	/* disable all interrupts */
15638c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0);
15648c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0);
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	return netsec_mac_write(priv, GMAC_REG_OMR, value);
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic void netsec_phy_adjust_link(struct net_device *ndev)
15708c2ecf20Sopenharmony_ci{
15718c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (ndev->phydev->link)
15748c2ecf20Sopenharmony_ci		netsec_start_gmac(priv);
15758c2ecf20Sopenharmony_ci	else
15768c2ecf20Sopenharmony_ci		netsec_stop_gmac(priv);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	phy_print_status(ndev->phydev);
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_cistatic irqreturn_t netsec_irq_handler(int irq, void *dev_id)
15828c2ecf20Sopenharmony_ci{
15838c2ecf20Sopenharmony_ci	struct netsec_priv *priv = dev_id;
15848c2ecf20Sopenharmony_ci	u32 val, status = netsec_read(priv, NETSEC_REG_TOP_STATUS);
15858c2ecf20Sopenharmony_ci	unsigned long flags;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	/* Disable interrupts */
15888c2ecf20Sopenharmony_ci	if (status & NETSEC_IRQ_TX) {
15898c2ecf20Sopenharmony_ci		val = netsec_read(priv, NETSEC_REG_NRM_TX_STATUS);
15908c2ecf20Sopenharmony_ci		netsec_write(priv, NETSEC_REG_NRM_TX_STATUS, val);
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci	if (status & NETSEC_IRQ_RX) {
15938c2ecf20Sopenharmony_ci		val = netsec_read(priv, NETSEC_REG_NRM_RX_STATUS);
15948c2ecf20Sopenharmony_ci		netsec_write(priv, NETSEC_REG_NRM_RX_STATUS, val);
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->reglock, flags);
15988c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_CLR, NETSEC_IRQ_RX | NETSEC_IRQ_TX);
15998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->reglock, flags);
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	napi_schedule(&priv->napi);
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_cistatic int netsec_netdev_open(struct net_device *ndev)
16078c2ecf20Sopenharmony_ci{
16088c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
16098c2ecf20Sopenharmony_ci	int ret;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	pm_runtime_get_sync(priv->dev);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	netsec_setup_tx_dring(priv);
16148c2ecf20Sopenharmony_ci	ret = netsec_setup_rx_dring(priv);
16158c2ecf20Sopenharmony_ci	if (ret) {
16168c2ecf20Sopenharmony_ci		netif_err(priv, probe, priv->ndev,
16178c2ecf20Sopenharmony_ci			  "%s: fail setup ring\n", __func__);
16188c2ecf20Sopenharmony_ci		goto err1;
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	ret = request_irq(priv->ndev->irq, netsec_irq_handler,
16228c2ecf20Sopenharmony_ci			  IRQF_SHARED, "netsec", priv);
16238c2ecf20Sopenharmony_ci	if (ret) {
16248c2ecf20Sopenharmony_ci		netif_err(priv, drv, priv->ndev, "request_irq failed\n");
16258c2ecf20Sopenharmony_ci		goto err2;
16268c2ecf20Sopenharmony_ci	}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if (dev_of_node(priv->dev)) {
16298c2ecf20Sopenharmony_ci		if (!of_phy_connect(priv->ndev, priv->phy_np,
16308c2ecf20Sopenharmony_ci				    netsec_phy_adjust_link, 0,
16318c2ecf20Sopenharmony_ci				    priv->phy_interface)) {
16328c2ecf20Sopenharmony_ci			netif_err(priv, link, priv->ndev, "missing PHY\n");
16338c2ecf20Sopenharmony_ci			ret = -ENODEV;
16348c2ecf20Sopenharmony_ci			goto err3;
16358c2ecf20Sopenharmony_ci		}
16368c2ecf20Sopenharmony_ci	} else {
16378c2ecf20Sopenharmony_ci		ret = phy_connect_direct(priv->ndev, priv->phydev,
16388c2ecf20Sopenharmony_ci					 netsec_phy_adjust_link,
16398c2ecf20Sopenharmony_ci					 priv->phy_interface);
16408c2ecf20Sopenharmony_ci		if (ret) {
16418c2ecf20Sopenharmony_ci			netif_err(priv, link, priv->ndev,
16428c2ecf20Sopenharmony_ci				  "phy_connect_direct() failed (%d)\n", ret);
16438c2ecf20Sopenharmony_ci			goto err3;
16448c2ecf20Sopenharmony_ci		}
16458c2ecf20Sopenharmony_ci	}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	phy_start(ndev->phydev);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	netsec_start_gmac(priv);
16508c2ecf20Sopenharmony_ci	napi_enable(&priv->napi);
16518c2ecf20Sopenharmony_ci	netif_start_queue(ndev);
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	/* Enable TX+RX intr. */
16548c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_SET, NETSEC_IRQ_RX | NETSEC_IRQ_TX);
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	return 0;
16578c2ecf20Sopenharmony_cierr3:
16588c2ecf20Sopenharmony_ci	free_irq(priv->ndev->irq, priv);
16598c2ecf20Sopenharmony_cierr2:
16608c2ecf20Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
16618c2ecf20Sopenharmony_cierr1:
16628c2ecf20Sopenharmony_ci	pm_runtime_put_sync(priv->dev);
16638c2ecf20Sopenharmony_ci	return ret;
16648c2ecf20Sopenharmony_ci}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_cistatic int netsec_netdev_stop(struct net_device *ndev)
16678c2ecf20Sopenharmony_ci{
16688c2ecf20Sopenharmony_ci	int ret;
16698c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	netif_stop_queue(priv->ndev);
16728c2ecf20Sopenharmony_ci	dma_wmb();
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	napi_disable(&priv->napi);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_INTEN_CLR, ~0);
16778c2ecf20Sopenharmony_ci	netsec_stop_gmac(priv);
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	free_irq(priv->ndev->irq, priv);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_TX);
16828c2ecf20Sopenharmony_ci	netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	phy_stop(ndev->phydev);
16858c2ecf20Sopenharmony_ci	phy_disconnect(ndev->phydev);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	ret = netsec_reset_hardware(priv, false);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	pm_runtime_put_sync(priv->dev);
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	return ret;
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic int netsec_netdev_init(struct net_device *ndev)
16958c2ecf20Sopenharmony_ci{
16968c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
16978c2ecf20Sopenharmony_ci	int ret;
16988c2ecf20Sopenharmony_ci	u16 data;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	BUILD_BUG_ON_NOT_POWER_OF_2(DESC_NUM);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	ret = netsec_alloc_dring(priv, NETSEC_RING_TX);
17038c2ecf20Sopenharmony_ci	if (ret)
17048c2ecf20Sopenharmony_ci		return ret;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	ret = netsec_alloc_dring(priv, NETSEC_RING_RX);
17078c2ecf20Sopenharmony_ci	if (ret)
17088c2ecf20Sopenharmony_ci		goto err1;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	/* set phy power down */
17118c2ecf20Sopenharmony_ci	data = netsec_phy_read(priv->mii_bus, priv->phy_addr, MII_BMCR);
17128c2ecf20Sopenharmony_ci	netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR,
17138c2ecf20Sopenharmony_ci			 data | BMCR_PDOWN);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	ret = netsec_reset_hardware(priv, true);
17168c2ecf20Sopenharmony_ci	if (ret)
17178c2ecf20Sopenharmony_ci		goto err2;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	/* Restore phy power state */
17208c2ecf20Sopenharmony_ci	netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR, data);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	spin_lock_init(&priv->desc_ring[NETSEC_RING_TX].lock);
17238c2ecf20Sopenharmony_ci	spin_lock_init(&priv->desc_ring[NETSEC_RING_RX].lock);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	return 0;
17268c2ecf20Sopenharmony_cierr2:
17278c2ecf20Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_RX);
17288c2ecf20Sopenharmony_cierr1:
17298c2ecf20Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_TX);
17308c2ecf20Sopenharmony_ci	return ret;
17318c2ecf20Sopenharmony_ci}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_cistatic void netsec_netdev_uninit(struct net_device *ndev)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_RX);
17388c2ecf20Sopenharmony_ci	netsec_free_dring(priv, NETSEC_RING_TX);
17398c2ecf20Sopenharmony_ci}
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_cistatic int netsec_netdev_set_features(struct net_device *ndev,
17428c2ecf20Sopenharmony_ci				      netdev_features_t features)
17438c2ecf20Sopenharmony_ci{
17448c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	priv->rx_cksum_offload_flag = !!(features & NETIF_F_RXCSUM);
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	return 0;
17498c2ecf20Sopenharmony_ci}
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_cistatic int netsec_xdp_xmit(struct net_device *ndev, int n,
17528c2ecf20Sopenharmony_ci			   struct xdp_frame **frames, u32 flags)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
17558c2ecf20Sopenharmony_ci	struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
17568c2ecf20Sopenharmony_ci	int drops = 0;
17578c2ecf20Sopenharmony_ci	int i;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
17608c2ecf20Sopenharmony_ci		return -EINVAL;
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	spin_lock(&tx_ring->lock);
17638c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++) {
17648c2ecf20Sopenharmony_ci		struct xdp_frame *xdpf = frames[i];
17658c2ecf20Sopenharmony_ci		int err;
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci		err = netsec_xdp_queue_one(priv, xdpf, true);
17688c2ecf20Sopenharmony_ci		if (err != NETSEC_XDP_TX) {
17698c2ecf20Sopenharmony_ci			xdp_return_frame_rx_napi(xdpf);
17708c2ecf20Sopenharmony_ci			drops++;
17718c2ecf20Sopenharmony_ci		} else {
17728c2ecf20Sopenharmony_ci			tx_ring->xdp_xmit++;
17738c2ecf20Sopenharmony_ci		}
17748c2ecf20Sopenharmony_ci	}
17758c2ecf20Sopenharmony_ci	spin_unlock(&tx_ring->lock);
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	if (unlikely(flags & XDP_XMIT_FLUSH)) {
17788c2ecf20Sopenharmony_ci		netsec_xdp_ring_tx_db(priv, tx_ring->xdp_xmit);
17798c2ecf20Sopenharmony_ci		tx_ring->xdp_xmit = 0;
17808c2ecf20Sopenharmony_ci	}
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	return n - drops;
17838c2ecf20Sopenharmony_ci}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_cistatic int netsec_xdp_setup(struct netsec_priv *priv, struct bpf_prog *prog,
17868c2ecf20Sopenharmony_ci			    struct netlink_ext_ack *extack)
17878c2ecf20Sopenharmony_ci{
17888c2ecf20Sopenharmony_ci	struct net_device *dev = priv->ndev;
17898c2ecf20Sopenharmony_ci	struct bpf_prog *old_prog;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	/* For now just support only the usual MTU sized frames */
17928c2ecf20Sopenharmony_ci	if (prog && dev->mtu > 1500) {
17938c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported on XDP");
17948c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17958c2ecf20Sopenharmony_ci	}
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	if (netif_running(dev))
17988c2ecf20Sopenharmony_ci		netsec_netdev_stop(dev);
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	/* Detach old prog, if any */
18018c2ecf20Sopenharmony_ci	old_prog = xchg(&priv->xdp_prog, prog);
18028c2ecf20Sopenharmony_ci	if (old_prog)
18038c2ecf20Sopenharmony_ci		bpf_prog_put(old_prog);
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	if (netif_running(dev))
18068c2ecf20Sopenharmony_ci		netsec_netdev_open(dev);
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	return 0;
18098c2ecf20Sopenharmony_ci}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_cistatic int netsec_xdp(struct net_device *ndev, struct netdev_bpf *xdp)
18128c2ecf20Sopenharmony_ci{
18138c2ecf20Sopenharmony_ci	struct netsec_priv *priv = netdev_priv(ndev);
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	switch (xdp->command) {
18168c2ecf20Sopenharmony_ci	case XDP_SETUP_PROG:
18178c2ecf20Sopenharmony_ci		return netsec_xdp_setup(priv, xdp->prog, xdp->extack);
18188c2ecf20Sopenharmony_ci	default:
18198c2ecf20Sopenharmony_ci		return -EINVAL;
18208c2ecf20Sopenharmony_ci	}
18218c2ecf20Sopenharmony_ci}
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_cistatic const struct net_device_ops netsec_netdev_ops = {
18248c2ecf20Sopenharmony_ci	.ndo_init		= netsec_netdev_init,
18258c2ecf20Sopenharmony_ci	.ndo_uninit		= netsec_netdev_uninit,
18268c2ecf20Sopenharmony_ci	.ndo_open		= netsec_netdev_open,
18278c2ecf20Sopenharmony_ci	.ndo_stop		= netsec_netdev_stop,
18288c2ecf20Sopenharmony_ci	.ndo_start_xmit		= netsec_netdev_start_xmit,
18298c2ecf20Sopenharmony_ci	.ndo_set_features	= netsec_netdev_set_features,
18308c2ecf20Sopenharmony_ci	.ndo_set_mac_address    = eth_mac_addr,
18318c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
18328c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= phy_do_ioctl,
18338c2ecf20Sopenharmony_ci	.ndo_xdp_xmit		= netsec_xdp_xmit,
18348c2ecf20Sopenharmony_ci	.ndo_bpf		= netsec_xdp,
18358c2ecf20Sopenharmony_ci};
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_cistatic int netsec_of_probe(struct platform_device *pdev,
18388c2ecf20Sopenharmony_ci			   struct netsec_priv *priv, u32 *phy_addr)
18398c2ecf20Sopenharmony_ci{
18408c2ecf20Sopenharmony_ci	int err;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	err = of_get_phy_mode(pdev->dev.of_node, &priv->phy_interface);
18438c2ecf20Sopenharmony_ci	if (err) {
18448c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing required property 'phy-mode'\n");
18458c2ecf20Sopenharmony_ci		return err;
18468c2ecf20Sopenharmony_ci	}
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	/*
18498c2ecf20Sopenharmony_ci	 * SynQuacer is physically configured with TX and RX delays
18508c2ecf20Sopenharmony_ci	 * but the standard firmware claimed otherwise for a long
18518c2ecf20Sopenharmony_ci	 * time, ignore it.
18528c2ecf20Sopenharmony_ci	 */
18538c2ecf20Sopenharmony_ci	if (of_machine_is_compatible("socionext,developer-box") &&
18548c2ecf20Sopenharmony_ci	    priv->phy_interface != PHY_INTERFACE_MODE_RGMII_ID) {
18558c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "Outdated firmware reports incorrect PHY mode, overriding\n");
18568c2ecf20Sopenharmony_ci		priv->phy_interface = PHY_INTERFACE_MODE_RGMII_ID;
18578c2ecf20Sopenharmony_ci	}
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	priv->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
18608c2ecf20Sopenharmony_ci	if (!priv->phy_np) {
18618c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing required property 'phy-handle'\n");
18628c2ecf20Sopenharmony_ci		return -EINVAL;
18638c2ecf20Sopenharmony_ci	}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	*phy_addr = of_mdio_parse_addr(&pdev->dev, priv->phy_np);
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	priv->clk = devm_clk_get(&pdev->dev, NULL); /* get by 'phy_ref_clk' */
18688c2ecf20Sopenharmony_ci	if (IS_ERR(priv->clk)) {
18698c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "phy_ref_clk not found\n");
18708c2ecf20Sopenharmony_ci		return PTR_ERR(priv->clk);
18718c2ecf20Sopenharmony_ci	}
18728c2ecf20Sopenharmony_ci	priv->freq = clk_get_rate(priv->clk);
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	return 0;
18758c2ecf20Sopenharmony_ci}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_cistatic int netsec_acpi_probe(struct platform_device *pdev,
18788c2ecf20Sopenharmony_ci			     struct netsec_priv *priv, u32 *phy_addr)
18798c2ecf20Sopenharmony_ci{
18808c2ecf20Sopenharmony_ci	int ret;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_ACPI))
18838c2ecf20Sopenharmony_ci		return -ENODEV;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	/* ACPI systems are assumed to configure the PHY in firmware, so
18868c2ecf20Sopenharmony_ci	 * there is really no need to discover the PHY mode from the DSDT.
18878c2ecf20Sopenharmony_ci	 * Since firmware is known to exist in the field that configures the
18888c2ecf20Sopenharmony_ci	 * PHY correctly but passes the wrong mode string in the phy-mode
18898c2ecf20Sopenharmony_ci	 * device property, we have no choice but to ignore it.
18908c2ecf20Sopenharmony_ci	 */
18918c2ecf20Sopenharmony_ci	priv->phy_interface = PHY_INTERFACE_MODE_NA;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "phy-channel", phy_addr);
18948c2ecf20Sopenharmony_ci	if (ret) {
18958c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
18968c2ecf20Sopenharmony_ci			"missing required property 'phy-channel'\n");
18978c2ecf20Sopenharmony_ci		return ret;
18988c2ecf20Sopenharmony_ci	}
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev,
19018c2ecf20Sopenharmony_ci				       "socionext,phy-clock-frequency",
19028c2ecf20Sopenharmony_ci				       &priv->freq);
19038c2ecf20Sopenharmony_ci	if (ret)
19048c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
19058c2ecf20Sopenharmony_ci			"missing required property 'socionext,phy-clock-frequency'\n");
19068c2ecf20Sopenharmony_ci	return ret;
19078c2ecf20Sopenharmony_ci}
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_cistatic void netsec_unregister_mdio(struct netsec_priv *priv)
19108c2ecf20Sopenharmony_ci{
19118c2ecf20Sopenharmony_ci	struct phy_device *phydev = priv->phydev;
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	if (!dev_of_node(priv->dev) && phydev) {
19148c2ecf20Sopenharmony_ci		phy_device_remove(phydev);
19158c2ecf20Sopenharmony_ci		phy_device_free(phydev);
19168c2ecf20Sopenharmony_ci	}
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	mdiobus_unregister(priv->mii_bus);
19198c2ecf20Sopenharmony_ci}
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_cistatic int netsec_register_mdio(struct netsec_priv *priv, u32 phy_addr)
19228c2ecf20Sopenharmony_ci{
19238c2ecf20Sopenharmony_ci	struct mii_bus *bus;
19248c2ecf20Sopenharmony_ci	int ret;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	bus = devm_mdiobus_alloc(priv->dev);
19278c2ecf20Sopenharmony_ci	if (!bus)
19288c2ecf20Sopenharmony_ci		return -ENOMEM;
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(priv->dev));
19318c2ecf20Sopenharmony_ci	bus->priv = priv;
19328c2ecf20Sopenharmony_ci	bus->name = "SNI NETSEC MDIO";
19338c2ecf20Sopenharmony_ci	bus->read = netsec_phy_read;
19348c2ecf20Sopenharmony_ci	bus->write = netsec_phy_write;
19358c2ecf20Sopenharmony_ci	bus->parent = priv->dev;
19368c2ecf20Sopenharmony_ci	priv->mii_bus = bus;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	if (dev_of_node(priv->dev)) {
19398c2ecf20Sopenharmony_ci		struct device_node *mdio_node, *parent = dev_of_node(priv->dev);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci		mdio_node = of_get_child_by_name(parent, "mdio");
19428c2ecf20Sopenharmony_ci		if (mdio_node) {
19438c2ecf20Sopenharmony_ci			parent = mdio_node;
19448c2ecf20Sopenharmony_ci		} else {
19458c2ecf20Sopenharmony_ci			/* older f/w doesn't populate the mdio subnode,
19468c2ecf20Sopenharmony_ci			 * allow relaxed upgrade of f/w in due time.
19478c2ecf20Sopenharmony_ci			 */
19488c2ecf20Sopenharmony_ci			dev_info(priv->dev, "Upgrade f/w for mdio subnode!\n");
19498c2ecf20Sopenharmony_ci		}
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci		ret = of_mdiobus_register(bus, parent);
19528c2ecf20Sopenharmony_ci		of_node_put(mdio_node);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci		if (ret) {
19558c2ecf20Sopenharmony_ci			dev_err(priv->dev, "mdiobus register err(%d)\n", ret);
19568c2ecf20Sopenharmony_ci			return ret;
19578c2ecf20Sopenharmony_ci		}
19588c2ecf20Sopenharmony_ci	} else {
19598c2ecf20Sopenharmony_ci		/* Mask out all PHYs from auto probing. */
19608c2ecf20Sopenharmony_ci		bus->phy_mask = ~0;
19618c2ecf20Sopenharmony_ci		ret = mdiobus_register(bus);
19628c2ecf20Sopenharmony_ci		if (ret) {
19638c2ecf20Sopenharmony_ci			dev_err(priv->dev, "mdiobus register err(%d)\n", ret);
19648c2ecf20Sopenharmony_ci			return ret;
19658c2ecf20Sopenharmony_ci		}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci		priv->phydev = get_phy_device(bus, phy_addr, false);
19688c2ecf20Sopenharmony_ci		if (IS_ERR(priv->phydev)) {
19698c2ecf20Sopenharmony_ci			ret = PTR_ERR(priv->phydev);
19708c2ecf20Sopenharmony_ci			dev_err(priv->dev, "get_phy_device err(%d)\n", ret);
19718c2ecf20Sopenharmony_ci			priv->phydev = NULL;
19728c2ecf20Sopenharmony_ci			mdiobus_unregister(bus);
19738c2ecf20Sopenharmony_ci			return -ENODEV;
19748c2ecf20Sopenharmony_ci		}
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci		ret = phy_device_register(priv->phydev);
19778c2ecf20Sopenharmony_ci		if (ret) {
19788c2ecf20Sopenharmony_ci			phy_device_free(priv->phydev);
19798c2ecf20Sopenharmony_ci			mdiobus_unregister(bus);
19808c2ecf20Sopenharmony_ci			dev_err(priv->dev,
19818c2ecf20Sopenharmony_ci				"phy_device_register err(%d)\n", ret);
19828c2ecf20Sopenharmony_ci		}
19838c2ecf20Sopenharmony_ci	}
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	return ret;
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_cistatic int netsec_probe(struct platform_device *pdev)
19898c2ecf20Sopenharmony_ci{
19908c2ecf20Sopenharmony_ci	struct resource *mmio_res, *eeprom_res, *irq_res;
19918c2ecf20Sopenharmony_ci	u8 *mac, macbuf[ETH_ALEN];
19928c2ecf20Sopenharmony_ci	struct netsec_priv *priv;
19938c2ecf20Sopenharmony_ci	u32 hw_ver, phy_addr = 0;
19948c2ecf20Sopenharmony_ci	struct net_device *ndev;
19958c2ecf20Sopenharmony_ci	int ret;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	mmio_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
19988c2ecf20Sopenharmony_ci	if (!mmio_res) {
19998c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "No MMIO resource found.\n");
20008c2ecf20Sopenharmony_ci		return -ENODEV;
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	eeprom_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
20048c2ecf20Sopenharmony_ci	if (!eeprom_res) {
20058c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "No EEPROM resource found.\n");
20068c2ecf20Sopenharmony_ci		return -ENODEV;
20078c2ecf20Sopenharmony_ci	}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
20108c2ecf20Sopenharmony_ci	if (!irq_res) {
20118c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "No IRQ resource found.\n");
20128c2ecf20Sopenharmony_ci		return -ENODEV;
20138c2ecf20Sopenharmony_ci	}
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	ndev = alloc_etherdev(sizeof(*priv));
20168c2ecf20Sopenharmony_ci	if (!ndev)
20178c2ecf20Sopenharmony_ci		return -ENOMEM;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	priv = netdev_priv(ndev);
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	spin_lock_init(&priv->reglock);
20228c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(ndev, &pdev->dev);
20238c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
20248c2ecf20Sopenharmony_ci	ndev->irq = irq_res->start;
20258c2ecf20Sopenharmony_ci	priv->dev = &pdev->dev;
20268c2ecf20Sopenharmony_ci	priv->ndev = ndev;
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci	priv->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV |
20298c2ecf20Sopenharmony_ci			   NETIF_MSG_LINK | NETIF_MSG_PROBE;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	priv->ioaddr = devm_ioremap(&pdev->dev, mmio_res->start,
20328c2ecf20Sopenharmony_ci				    resource_size(mmio_res));
20338c2ecf20Sopenharmony_ci	if (!priv->ioaddr) {
20348c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "devm_ioremap() failed\n");
20358c2ecf20Sopenharmony_ci		ret = -ENXIO;
20368c2ecf20Sopenharmony_ci		goto free_ndev;
20378c2ecf20Sopenharmony_ci	}
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	priv->eeprom_base = devm_ioremap(&pdev->dev, eeprom_res->start,
20408c2ecf20Sopenharmony_ci					 resource_size(eeprom_res));
20418c2ecf20Sopenharmony_ci	if (!priv->eeprom_base) {
20428c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "devm_ioremap() failed for EEPROM\n");
20438c2ecf20Sopenharmony_ci		ret = -ENXIO;
20448c2ecf20Sopenharmony_ci		goto free_ndev;
20458c2ecf20Sopenharmony_ci	}
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	mac = device_get_mac_address(&pdev->dev, macbuf, sizeof(macbuf));
20488c2ecf20Sopenharmony_ci	if (mac)
20498c2ecf20Sopenharmony_ci		ether_addr_copy(ndev->dev_addr, mac);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	if (priv->eeprom_base &&
20528c2ecf20Sopenharmony_ci	    (!mac || !is_valid_ether_addr(ndev->dev_addr))) {
20538c2ecf20Sopenharmony_ci		void __iomem *macp = priv->eeprom_base +
20548c2ecf20Sopenharmony_ci					NETSEC_EEPROM_MAC_ADDRESS;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci		ndev->dev_addr[0] = readb(macp + 3);
20578c2ecf20Sopenharmony_ci		ndev->dev_addr[1] = readb(macp + 2);
20588c2ecf20Sopenharmony_ci		ndev->dev_addr[2] = readb(macp + 1);
20598c2ecf20Sopenharmony_ci		ndev->dev_addr[3] = readb(macp + 0);
20608c2ecf20Sopenharmony_ci		ndev->dev_addr[4] = readb(macp + 7);
20618c2ecf20Sopenharmony_ci		ndev->dev_addr[5] = readb(macp + 6);
20628c2ecf20Sopenharmony_ci	}
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(ndev->dev_addr)) {
20658c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "No MAC address found, using random\n");
20668c2ecf20Sopenharmony_ci		eth_hw_addr_random(ndev);
20678c2ecf20Sopenharmony_ci	}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci	if (dev_of_node(&pdev->dev))
20708c2ecf20Sopenharmony_ci		ret = netsec_of_probe(pdev, priv, &phy_addr);
20718c2ecf20Sopenharmony_ci	else
20728c2ecf20Sopenharmony_ci		ret = netsec_acpi_probe(pdev, priv, &phy_addr);
20738c2ecf20Sopenharmony_ci	if (ret)
20748c2ecf20Sopenharmony_ci		goto free_ndev;
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	priv->phy_addr = phy_addr;
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	if (!priv->freq) {
20798c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing PHY reference clock frequency\n");
20808c2ecf20Sopenharmony_ci		ret = -ENODEV;
20818c2ecf20Sopenharmony_ci		goto free_ndev;
20828c2ecf20Sopenharmony_ci	}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	/* default for throughput */
20858c2ecf20Sopenharmony_ci	priv->et_coalesce.rx_coalesce_usecs = 500;
20868c2ecf20Sopenharmony_ci	priv->et_coalesce.rx_max_coalesced_frames = 8;
20878c2ecf20Sopenharmony_ci	priv->et_coalesce.tx_coalesce_usecs = 500;
20888c2ecf20Sopenharmony_ci	priv->et_coalesce.tx_max_coalesced_frames = 8;
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "max-frame-size",
20918c2ecf20Sopenharmony_ci				       &ndev->max_mtu);
20928c2ecf20Sopenharmony_ci	if (ret < 0)
20938c2ecf20Sopenharmony_ci		ndev->max_mtu = ETH_DATA_LEN;
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	/* runtime_pm coverage just for probe, open/close also cover it */
20968c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
20978c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci	hw_ver = netsec_read(priv, NETSEC_REG_F_TAIKI_VER);
21008c2ecf20Sopenharmony_ci	/* this driver only supports F_TAIKI style NETSEC */
21018c2ecf20Sopenharmony_ci	if (NETSEC_F_NETSEC_VER_MAJOR_NUM(hw_ver) !=
21028c2ecf20Sopenharmony_ci	    NETSEC_F_NETSEC_VER_MAJOR_NUM(NETSEC_REG_NETSEC_VER_F_TAIKI)) {
21038c2ecf20Sopenharmony_ci		ret = -ENODEV;
21048c2ecf20Sopenharmony_ci		goto pm_disable;
21058c2ecf20Sopenharmony_ci	}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "hardware revision %d.%d\n",
21088c2ecf20Sopenharmony_ci		 hw_ver >> 16, hw_ver & 0xffff);
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	netif_napi_add(ndev, &priv->napi, netsec_napi_poll, NAPI_POLL_WEIGHT);
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	ndev->netdev_ops = &netsec_netdev_ops;
21138c2ecf20Sopenharmony_ci	ndev->ethtool_ops = &netsec_ethtool_ops;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	ndev->features |= NETIF_F_HIGHDMA | NETIF_F_RXCSUM | NETIF_F_GSO |
21168c2ecf20Sopenharmony_ci				NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
21178c2ecf20Sopenharmony_ci	ndev->hw_features = ndev->features;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	priv->rx_cksum_offload_flag = true;
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	ret = netsec_register_mdio(priv, phy_addr);
21228c2ecf20Sopenharmony_ci	if (ret)
21238c2ecf20Sopenharmony_ci		goto unreg_napi;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)))
21268c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "Failed to set DMA mask\n");
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	ret = register_netdev(ndev);
21298c2ecf20Sopenharmony_ci	if (ret) {
21308c2ecf20Sopenharmony_ci		netif_err(priv, probe, ndev, "register_netdev() failed\n");
21318c2ecf20Sopenharmony_ci		goto unreg_mii;
21328c2ecf20Sopenharmony_ci	}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
21358c2ecf20Sopenharmony_ci	return 0;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ciunreg_mii:
21388c2ecf20Sopenharmony_ci	netsec_unregister_mdio(priv);
21398c2ecf20Sopenharmony_ciunreg_napi:
21408c2ecf20Sopenharmony_ci	netif_napi_del(&priv->napi);
21418c2ecf20Sopenharmony_cipm_disable:
21428c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
21438c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
21448c2ecf20Sopenharmony_cifree_ndev:
21458c2ecf20Sopenharmony_ci	free_netdev(ndev);
21468c2ecf20Sopenharmony_ci	dev_err(&pdev->dev, "init failed\n");
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	return ret;
21498c2ecf20Sopenharmony_ci}
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_cistatic int netsec_remove(struct platform_device *pdev)
21528c2ecf20Sopenharmony_ci{
21538c2ecf20Sopenharmony_ci	struct netsec_priv *priv = platform_get_drvdata(pdev);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	unregister_netdev(priv->ndev);
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	netsec_unregister_mdio(priv);
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	netif_napi_del(&priv->napi);
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
21628c2ecf20Sopenharmony_ci	free_netdev(priv->ndev);
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	return 0;
21658c2ecf20Sopenharmony_ci}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
21688c2ecf20Sopenharmony_cistatic int netsec_runtime_suspend(struct device *dev)
21698c2ecf20Sopenharmony_ci{
21708c2ecf20Sopenharmony_ci	struct netsec_priv *priv = dev_get_drvdata(dev);
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_CLK_EN, 0);
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->clk);
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	return 0;
21778c2ecf20Sopenharmony_ci}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_cistatic int netsec_runtime_resume(struct device *dev)
21808c2ecf20Sopenharmony_ci{
21818c2ecf20Sopenharmony_ci	struct netsec_priv *priv = dev_get_drvdata(dev);
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	clk_prepare_enable(priv->clk);
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	netsec_write(priv, NETSEC_REG_CLK_EN, NETSEC_CLK_EN_REG_DOM_D |
21868c2ecf20Sopenharmony_ci					       NETSEC_CLK_EN_REG_DOM_C |
21878c2ecf20Sopenharmony_ci					       NETSEC_CLK_EN_REG_DOM_G);
21888c2ecf20Sopenharmony_ci	return 0;
21898c2ecf20Sopenharmony_ci}
21908c2ecf20Sopenharmony_ci#endif
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_cistatic const struct dev_pm_ops netsec_pm_ops = {
21938c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(netsec_runtime_suspend, netsec_runtime_resume, NULL)
21948c2ecf20Sopenharmony_ci};
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_cistatic const struct of_device_id netsec_dt_ids[] = {
21978c2ecf20Sopenharmony_ci	{ .compatible = "socionext,synquacer-netsec" },
21988c2ecf20Sopenharmony_ci	{ }
21998c2ecf20Sopenharmony_ci};
22008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, netsec_dt_ids);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
22038c2ecf20Sopenharmony_cistatic const struct acpi_device_id netsec_acpi_ids[] = {
22048c2ecf20Sopenharmony_ci	{ "SCX0001" },
22058c2ecf20Sopenharmony_ci	{ }
22068c2ecf20Sopenharmony_ci};
22078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, netsec_acpi_ids);
22088c2ecf20Sopenharmony_ci#endif
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_cistatic struct platform_driver netsec_driver = {
22118c2ecf20Sopenharmony_ci	.probe	= netsec_probe,
22128c2ecf20Sopenharmony_ci	.remove	= netsec_remove,
22138c2ecf20Sopenharmony_ci	.driver = {
22148c2ecf20Sopenharmony_ci		.name = "netsec",
22158c2ecf20Sopenharmony_ci		.pm = &netsec_pm_ops,
22168c2ecf20Sopenharmony_ci		.of_match_table = netsec_dt_ids,
22178c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(netsec_acpi_ids),
22188c2ecf20Sopenharmony_ci	},
22198c2ecf20Sopenharmony_ci};
22208c2ecf20Sopenharmony_cimodule_platform_driver(netsec_driver);
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
22238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
22248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NETSEC Ethernet driver");
22258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2226