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