xref: /linux/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c (revision c771600c6af14749609b49565ffb4cac2959710d)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
257c5bc9aSZhangfei Gao /* Copyright (c) 2014 Linaro Ltd.
357c5bc9aSZhangfei Gao  * Copyright (c) 2014 Hisilicon Limited.
457c5bc9aSZhangfei Gao  */
557c5bc9aSZhangfei Gao 
657c5bc9aSZhangfei Gao #include <linux/module.h>
757c5bc9aSZhangfei Gao #include <linux/interrupt.h>
857c5bc9aSZhangfei Gao #include <linux/etherdevice.h>
957c5bc9aSZhangfei Gao #include <linux/platform_device.h>
10b0377116SRob Herring #include <linux/property.h>
11b0377116SRob Herring #include <linux/of.h>
1257c5bc9aSZhangfei Gao #include <linux/of_net.h>
1357c5bc9aSZhangfei Gao #include <linux/of_mdio.h>
147087140dSDongpo Li #include <linux/reset.h>
1557c5bc9aSZhangfei Gao #include <linux/clk.h>
1657c5bc9aSZhangfei Gao #include <linux/circ_buf.h>
1757c5bc9aSZhangfei Gao 
1857c5bc9aSZhangfei Gao #define STATION_ADDR_LOW		0x0000
1957c5bc9aSZhangfei Gao #define STATION_ADDR_HIGH		0x0004
2057c5bc9aSZhangfei Gao #define MAC_DUPLEX_HALF_CTRL		0x0008
2157c5bc9aSZhangfei Gao #define MAX_FRM_SIZE			0x003c
2257c5bc9aSZhangfei Gao #define PORT_MODE			0x0040
2357c5bc9aSZhangfei Gao #define PORT_EN				0x0044
2457c5bc9aSZhangfei Gao #define BITS_TX_EN			BIT(2)
2557c5bc9aSZhangfei Gao #define BITS_RX_EN			BIT(1)
2657c5bc9aSZhangfei Gao #define REC_FILT_CONTROL		0x0064
2757c5bc9aSZhangfei Gao #define BIT_CRC_ERR_PASS		BIT(5)
2857c5bc9aSZhangfei Gao #define BIT_PAUSE_FRM_PASS		BIT(4)
2957c5bc9aSZhangfei Gao #define BIT_VLAN_DROP_EN		BIT(3)
3057c5bc9aSZhangfei Gao #define BIT_BC_DROP_EN			BIT(2)
3157c5bc9aSZhangfei Gao #define BIT_MC_MATCH_EN			BIT(1)
3257c5bc9aSZhangfei Gao #define BIT_UC_MATCH_EN			BIT(0)
3357c5bc9aSZhangfei Gao #define PORT_MC_ADDR_LOW		0x0068
3457c5bc9aSZhangfei Gao #define PORT_MC_ADDR_HIGH		0x006C
3557c5bc9aSZhangfei Gao #define CF_CRC_STRIP			0x01b0
3657c5bc9aSZhangfei Gao #define MODE_CHANGE_EN			0x01b4
3757c5bc9aSZhangfei Gao #define BIT_MODE_CHANGE_EN		BIT(0)
3857c5bc9aSZhangfei Gao #define COL_SLOT_TIME			0x01c0
3957c5bc9aSZhangfei Gao #define RECV_CONTROL			0x01e0
4057c5bc9aSZhangfei Gao #define BIT_STRIP_PAD_EN		BIT(3)
4157c5bc9aSZhangfei Gao #define BIT_RUNT_PKT_EN			BIT(4)
4257c5bc9aSZhangfei Gao #define CONTROL_WORD			0x0214
4357c5bc9aSZhangfei Gao #define MDIO_SINGLE_CMD			0x03c0
4457c5bc9aSZhangfei Gao #define MDIO_SINGLE_DATA		0x03c4
4557c5bc9aSZhangfei Gao #define MDIO_CTRL			0x03cc
4657c5bc9aSZhangfei Gao #define MDIO_RDATA_STATUS		0x03d0
4757c5bc9aSZhangfei Gao 
4857c5bc9aSZhangfei Gao #define MDIO_START			BIT(20)
4957c5bc9aSZhangfei Gao #define MDIO_R_VALID			BIT(0)
5057c5bc9aSZhangfei Gao #define MDIO_READ			(BIT(17) | MDIO_START)
5157c5bc9aSZhangfei Gao #define MDIO_WRITE			(BIT(16) | MDIO_START)
5257c5bc9aSZhangfei Gao 
5357c5bc9aSZhangfei Gao #define RX_FQ_START_ADDR		0x0500
5457c5bc9aSZhangfei Gao #define RX_FQ_DEPTH			0x0504
5557c5bc9aSZhangfei Gao #define RX_FQ_WR_ADDR			0x0508
5657c5bc9aSZhangfei Gao #define RX_FQ_RD_ADDR			0x050c
5757c5bc9aSZhangfei Gao #define RX_FQ_VLDDESC_CNT		0x0510
5857c5bc9aSZhangfei Gao #define RX_FQ_ALEMPTY_TH		0x0514
5957c5bc9aSZhangfei Gao #define RX_FQ_REG_EN			0x0518
6057c5bc9aSZhangfei Gao #define BITS_RX_FQ_START_ADDR_EN	BIT(2)
6157c5bc9aSZhangfei Gao #define BITS_RX_FQ_DEPTH_EN		BIT(1)
6257c5bc9aSZhangfei Gao #define BITS_RX_FQ_RD_ADDR_EN		BIT(0)
6357c5bc9aSZhangfei Gao #define RX_FQ_ALFULL_TH			0x051c
6457c5bc9aSZhangfei Gao #define RX_BQ_START_ADDR		0x0520
6557c5bc9aSZhangfei Gao #define RX_BQ_DEPTH			0x0524
6657c5bc9aSZhangfei Gao #define RX_BQ_WR_ADDR			0x0528
6757c5bc9aSZhangfei Gao #define RX_BQ_RD_ADDR			0x052c
6857c5bc9aSZhangfei Gao #define RX_BQ_FREE_DESC_CNT		0x0530
6957c5bc9aSZhangfei Gao #define RX_BQ_ALEMPTY_TH		0x0534
7057c5bc9aSZhangfei Gao #define RX_BQ_REG_EN			0x0538
7157c5bc9aSZhangfei Gao #define BITS_RX_BQ_START_ADDR_EN	BIT(2)
7257c5bc9aSZhangfei Gao #define BITS_RX_BQ_DEPTH_EN		BIT(1)
7357c5bc9aSZhangfei Gao #define BITS_RX_BQ_WR_ADDR_EN		BIT(0)
7457c5bc9aSZhangfei Gao #define RX_BQ_ALFULL_TH			0x053c
7557c5bc9aSZhangfei Gao #define TX_BQ_START_ADDR		0x0580
7657c5bc9aSZhangfei Gao #define TX_BQ_DEPTH			0x0584
7757c5bc9aSZhangfei Gao #define TX_BQ_WR_ADDR			0x0588
7857c5bc9aSZhangfei Gao #define TX_BQ_RD_ADDR			0x058c
7957c5bc9aSZhangfei Gao #define TX_BQ_VLDDESC_CNT		0x0590
8057c5bc9aSZhangfei Gao #define TX_BQ_ALEMPTY_TH		0x0594
8157c5bc9aSZhangfei Gao #define TX_BQ_REG_EN			0x0598
8257c5bc9aSZhangfei Gao #define BITS_TX_BQ_START_ADDR_EN	BIT(2)
8357c5bc9aSZhangfei Gao #define BITS_TX_BQ_DEPTH_EN		BIT(1)
8457c5bc9aSZhangfei Gao #define BITS_TX_BQ_RD_ADDR_EN		BIT(0)
8557c5bc9aSZhangfei Gao #define TX_BQ_ALFULL_TH			0x059c
8657c5bc9aSZhangfei Gao #define TX_RQ_START_ADDR		0x05a0
8757c5bc9aSZhangfei Gao #define TX_RQ_DEPTH			0x05a4
8857c5bc9aSZhangfei Gao #define TX_RQ_WR_ADDR			0x05a8
8957c5bc9aSZhangfei Gao #define TX_RQ_RD_ADDR			0x05ac
9057c5bc9aSZhangfei Gao #define TX_RQ_FREE_DESC_CNT		0x05b0
9157c5bc9aSZhangfei Gao #define TX_RQ_ALEMPTY_TH		0x05b4
9257c5bc9aSZhangfei Gao #define TX_RQ_REG_EN			0x05b8
9357c5bc9aSZhangfei Gao #define BITS_TX_RQ_START_ADDR_EN	BIT(2)
9457c5bc9aSZhangfei Gao #define BITS_TX_RQ_DEPTH_EN		BIT(1)
9557c5bc9aSZhangfei Gao #define BITS_TX_RQ_WR_ADDR_EN		BIT(0)
9657c5bc9aSZhangfei Gao #define TX_RQ_ALFULL_TH			0x05bc
9757c5bc9aSZhangfei Gao #define RAW_PMU_INT			0x05c0
9857c5bc9aSZhangfei Gao #define ENA_PMU_INT			0x05c4
9957c5bc9aSZhangfei Gao #define STATUS_PMU_INT			0x05c8
10057c5bc9aSZhangfei Gao #define MAC_FIFO_ERR_IN			BIT(30)
10157c5bc9aSZhangfei Gao #define TX_RQ_IN_TIMEOUT_INT		BIT(29)
10257c5bc9aSZhangfei Gao #define RX_BQ_IN_TIMEOUT_INT		BIT(28)
10357c5bc9aSZhangfei Gao #define TXOUTCFF_FULL_INT		BIT(27)
10457c5bc9aSZhangfei Gao #define TXOUTCFF_EMPTY_INT		BIT(26)
10557c5bc9aSZhangfei Gao #define TXCFF_FULL_INT			BIT(25)
10657c5bc9aSZhangfei Gao #define TXCFF_EMPTY_INT			BIT(24)
10757c5bc9aSZhangfei Gao #define RXOUTCFF_FULL_INT		BIT(23)
10857c5bc9aSZhangfei Gao #define RXOUTCFF_EMPTY_INT		BIT(22)
10957c5bc9aSZhangfei Gao #define RXCFF_FULL_INT			BIT(21)
11057c5bc9aSZhangfei Gao #define RXCFF_EMPTY_INT			BIT(20)
11157c5bc9aSZhangfei Gao #define TX_RQ_IN_INT			BIT(19)
11257c5bc9aSZhangfei Gao #define TX_BQ_OUT_INT			BIT(18)
11357c5bc9aSZhangfei Gao #define RX_BQ_IN_INT			BIT(17)
11457c5bc9aSZhangfei Gao #define RX_FQ_OUT_INT			BIT(16)
11557c5bc9aSZhangfei Gao #define TX_RQ_EMPTY_INT			BIT(15)
11657c5bc9aSZhangfei Gao #define TX_RQ_FULL_INT			BIT(14)
11757c5bc9aSZhangfei Gao #define TX_RQ_ALEMPTY_INT		BIT(13)
11857c5bc9aSZhangfei Gao #define TX_RQ_ALFULL_INT		BIT(12)
11957c5bc9aSZhangfei Gao #define TX_BQ_EMPTY_INT			BIT(11)
12057c5bc9aSZhangfei Gao #define TX_BQ_FULL_INT			BIT(10)
12157c5bc9aSZhangfei Gao #define TX_BQ_ALEMPTY_INT		BIT(9)
12257c5bc9aSZhangfei Gao #define TX_BQ_ALFULL_INT		BIT(8)
12357c5bc9aSZhangfei Gao #define RX_BQ_EMPTY_INT			BIT(7)
12457c5bc9aSZhangfei Gao #define RX_BQ_FULL_INT			BIT(6)
12557c5bc9aSZhangfei Gao #define RX_BQ_ALEMPTY_INT		BIT(5)
12657c5bc9aSZhangfei Gao #define RX_BQ_ALFULL_INT		BIT(4)
12757c5bc9aSZhangfei Gao #define RX_FQ_EMPTY_INT			BIT(3)
12857c5bc9aSZhangfei Gao #define RX_FQ_FULL_INT			BIT(2)
12957c5bc9aSZhangfei Gao #define RX_FQ_ALEMPTY_INT		BIT(1)
13057c5bc9aSZhangfei Gao #define RX_FQ_ALFULL_INT		BIT(0)
13157c5bc9aSZhangfei Gao 
13257c5bc9aSZhangfei Gao #define DEF_INT_MASK			(RX_BQ_IN_INT | RX_BQ_IN_TIMEOUT_INT | \
13357c5bc9aSZhangfei Gao 					TX_RQ_IN_INT | TX_RQ_IN_TIMEOUT_INT)
13457c5bc9aSZhangfei Gao 
13557c5bc9aSZhangfei Gao #define DESC_WR_RD_ENA			0x05cc
13657c5bc9aSZhangfei Gao #define IN_QUEUE_TH			0x05d8
13757c5bc9aSZhangfei Gao #define OUT_QUEUE_TH			0x05dc
13857c5bc9aSZhangfei Gao #define QUEUE_TX_BQ_SHIFT		16
13957c5bc9aSZhangfei Gao #define RX_BQ_IN_TIMEOUT_TH		0x05e0
14057c5bc9aSZhangfei Gao #define TX_RQ_IN_TIMEOUT_TH		0x05e4
14157c5bc9aSZhangfei Gao #define STOP_CMD			0x05e8
14257c5bc9aSZhangfei Gao #define BITS_TX_STOP			BIT(1)
14357c5bc9aSZhangfei Gao #define BITS_RX_STOP			BIT(0)
14457c5bc9aSZhangfei Gao #define FLUSH_CMD			0x05eC
14557c5bc9aSZhangfei Gao #define BITS_TX_FLUSH_CMD		BIT(5)
14657c5bc9aSZhangfei Gao #define BITS_RX_FLUSH_CMD		BIT(4)
14757c5bc9aSZhangfei Gao #define BITS_TX_FLUSH_FLAG_DOWN		BIT(3)
14857c5bc9aSZhangfei Gao #define BITS_TX_FLUSH_FLAG_UP		BIT(2)
14957c5bc9aSZhangfei Gao #define BITS_RX_FLUSH_FLAG_DOWN		BIT(1)
15057c5bc9aSZhangfei Gao #define BITS_RX_FLUSH_FLAG_UP		BIT(0)
15157c5bc9aSZhangfei Gao #define RX_CFF_NUM_REG			0x05f0
15257c5bc9aSZhangfei Gao #define PMU_FSM_REG			0x05f8
15357c5bc9aSZhangfei Gao #define RX_FIFO_PKT_IN_NUM		0x05fc
15457c5bc9aSZhangfei Gao #define RX_FIFO_PKT_OUT_NUM		0x0600
15557c5bc9aSZhangfei Gao 
15657c5bc9aSZhangfei Gao #define RGMII_SPEED_1000		0x2c
15757c5bc9aSZhangfei Gao #define RGMII_SPEED_100			0x2f
15857c5bc9aSZhangfei Gao #define RGMII_SPEED_10			0x2d
15957c5bc9aSZhangfei Gao #define MII_SPEED_100			0x0f
16057c5bc9aSZhangfei Gao #define MII_SPEED_10			0x0d
16157c5bc9aSZhangfei Gao #define GMAC_SPEED_1000			0x05
16257c5bc9aSZhangfei Gao #define GMAC_SPEED_100			0x01
16357c5bc9aSZhangfei Gao #define GMAC_SPEED_10			0x00
16457c5bc9aSZhangfei Gao #define GMAC_FULL_DUPLEX		BIT(4)
16557c5bc9aSZhangfei Gao 
16657c5bc9aSZhangfei Gao #define RX_BQ_INT_THRESHOLD		0x01
16757c5bc9aSZhangfei Gao #define TX_RQ_INT_THRESHOLD		0x01
16857c5bc9aSZhangfei Gao #define RX_BQ_IN_TIMEOUT		0x10000
16957c5bc9aSZhangfei Gao #define TX_RQ_IN_TIMEOUT		0x50000
17057c5bc9aSZhangfei Gao 
17157c5bc9aSZhangfei Gao #define MAC_MAX_FRAME_SIZE		1600
17257c5bc9aSZhangfei Gao #define DESC_SIZE			32
17357c5bc9aSZhangfei Gao #define RX_DESC_NUM			1024
17457c5bc9aSZhangfei Gao #define TX_DESC_NUM			1024
17557c5bc9aSZhangfei Gao 
17657c5bc9aSZhangfei Gao #define DESC_VLD_FREE			0
17757c5bc9aSZhangfei Gao #define DESC_VLD_BUSY			0x80000000
17857c5bc9aSZhangfei Gao #define DESC_FL_MID			0
17957c5bc9aSZhangfei Gao #define DESC_FL_LAST			0x20000000
18057c5bc9aSZhangfei Gao #define DESC_FL_FIRST			0x40000000
18157c5bc9aSZhangfei Gao #define DESC_FL_FULL			0x60000000
18257c5bc9aSZhangfei Gao #define DESC_DATA_LEN_OFF		16
18357c5bc9aSZhangfei Gao #define DESC_BUFF_LEN_OFF		0
18457c5bc9aSZhangfei Gao #define DESC_DATA_MASK			0x7ff
185e5222b1cSDongpo Li #define DESC_SG				BIT(30)
186e5222b1cSDongpo Li #define DESC_FRAGS_NUM_OFF		11
18757c5bc9aSZhangfei Gao 
18857c5bc9aSZhangfei Gao /* DMA descriptor ring helpers */
18957c5bc9aSZhangfei Gao #define dma_ring_incr(n, s)		(((n) + 1) & ((s) - 1))
19057c5bc9aSZhangfei Gao #define dma_cnt(n)			((n) >> 5)
19157c5bc9aSZhangfei Gao #define dma_byte(n)			((n) << 5)
19257c5bc9aSZhangfei Gao 
193d0fb6ba7SDongpo Li #define HW_CAP_TSO			BIT(0)
194d0fb6ba7SDongpo Li #define GEMAC_V1			0
195d0fb6ba7SDongpo Li #define GEMAC_V2			(GEMAC_V1 | HW_CAP_TSO)
196e5222b1cSDongpo Li #define HAS_CAP_TSO(hw_cap)		((hw_cap) & HW_CAP_TSO)
197d0fb6ba7SDongpo Li 
1987087140dSDongpo Li #define PHY_RESET_DELAYS_PROPERTY	"hisilicon,phy-reset-delays-us"
1997087140dSDongpo Li 
2007087140dSDongpo Li enum phy_reset_delays {
2017087140dSDongpo Li 	PRE_DELAY,
2027087140dSDongpo Li 	PULSE,
2037087140dSDongpo Li 	POST_DELAY,
2047087140dSDongpo Li 	DELAYS_NUM,
2057087140dSDongpo Li };
2067087140dSDongpo Li 
20757c5bc9aSZhangfei Gao struct hix5hd2_desc {
20857c5bc9aSZhangfei Gao 	__le32 buff_addr;
20957c5bc9aSZhangfei Gao 	__le32 cmd;
21057c5bc9aSZhangfei Gao } __aligned(32);
21157c5bc9aSZhangfei Gao 
21257c5bc9aSZhangfei Gao struct hix5hd2_desc_sw {
21357c5bc9aSZhangfei Gao 	struct hix5hd2_desc *desc;
21457c5bc9aSZhangfei Gao 	dma_addr_t	phys_addr;
21557c5bc9aSZhangfei Gao 	unsigned int	count;
21657c5bc9aSZhangfei Gao 	unsigned int	size;
21757c5bc9aSZhangfei Gao };
21857c5bc9aSZhangfei Gao 
219e5222b1cSDongpo Li struct hix5hd2_sg_desc_ring {
220e5222b1cSDongpo Li 	struct sg_desc *desc;
221e5222b1cSDongpo Li 	dma_addr_t phys_addr;
222e5222b1cSDongpo Li };
223e5222b1cSDongpo Li 
224e5222b1cSDongpo Li struct frags_info {
225e5222b1cSDongpo Li 	__le32 addr;
226e5222b1cSDongpo Li 	__le32 size;
227e5222b1cSDongpo Li };
228e5222b1cSDongpo Li 
229e5222b1cSDongpo Li /* hardware supported max skb frags num */
230e5222b1cSDongpo Li #define SG_MAX_SKB_FRAGS	17
231e5222b1cSDongpo Li struct sg_desc {
232e5222b1cSDongpo Li 	__le32 total_len;
233e5222b1cSDongpo Li 	__le32 resvd0;
234e5222b1cSDongpo Li 	__le32 linear_addr;
235e5222b1cSDongpo Li 	__le32 linear_len;
236e5222b1cSDongpo Li 	/* reserve one more frags for memory alignment */
237e5222b1cSDongpo Li 	struct frags_info frags[SG_MAX_SKB_FRAGS + 1];
238e5222b1cSDongpo Li };
239e5222b1cSDongpo Li 
24057c5bc9aSZhangfei Gao #define QUEUE_NUMS	4
24157c5bc9aSZhangfei Gao struct hix5hd2_priv {
24257c5bc9aSZhangfei Gao 	struct hix5hd2_desc_sw pool[QUEUE_NUMS];
24357c5bc9aSZhangfei Gao #define rx_fq		pool[0]
24457c5bc9aSZhangfei Gao #define rx_bq		pool[1]
24557c5bc9aSZhangfei Gao #define tx_bq		pool[2]
24657c5bc9aSZhangfei Gao #define tx_rq		pool[3]
247e5222b1cSDongpo Li 	struct hix5hd2_sg_desc_ring tx_ring;
24857c5bc9aSZhangfei Gao 
24957c5bc9aSZhangfei Gao 	void __iomem *base;
25057c5bc9aSZhangfei Gao 	void __iomem *ctrl_base;
25157c5bc9aSZhangfei Gao 
25257c5bc9aSZhangfei Gao 	struct sk_buff *tx_skb[TX_DESC_NUM];
25357c5bc9aSZhangfei Gao 	struct sk_buff *rx_skb[RX_DESC_NUM];
25457c5bc9aSZhangfei Gao 
25557c5bc9aSZhangfei Gao 	struct device *dev;
25657c5bc9aSZhangfei Gao 	struct net_device *netdev;
25757c5bc9aSZhangfei Gao 
25857c5bc9aSZhangfei Gao 	struct device_node *phy_node;
25957c5bc9aSZhangfei Gao 	phy_interface_t	phy_mode;
26057c5bc9aSZhangfei Gao 
261e5222b1cSDongpo Li 	unsigned long hw_cap;
26257c5bc9aSZhangfei Gao 	unsigned int speed;
26357c5bc9aSZhangfei Gao 	unsigned int duplex;
26457c5bc9aSZhangfei Gao 
2657087140dSDongpo Li 	struct clk *mac_core_clk;
2667087140dSDongpo Li 	struct clk *mac_ifc_clk;
2677087140dSDongpo Li 	struct reset_control *mac_core_rst;
2687087140dSDongpo Li 	struct reset_control *mac_ifc_rst;
2697087140dSDongpo Li 	struct reset_control *phy_rst;
2707087140dSDongpo Li 	u32 phy_reset_delays[DELAYS_NUM];
27157c5bc9aSZhangfei Gao 	struct mii_bus *bus;
27257c5bc9aSZhangfei Gao 	struct napi_struct napi;
27357c5bc9aSZhangfei Gao 	struct work_struct tx_timeout_task;
27457c5bc9aSZhangfei Gao };
27557c5bc9aSZhangfei Gao 
hix5hd2_mac_interface_reset(struct hix5hd2_priv * priv)2767087140dSDongpo Li static inline void hix5hd2_mac_interface_reset(struct hix5hd2_priv *priv)
2777087140dSDongpo Li {
2787087140dSDongpo Li 	if (!priv->mac_ifc_rst)
2797087140dSDongpo Li 		return;
2807087140dSDongpo Li 
2817087140dSDongpo Li 	reset_control_assert(priv->mac_ifc_rst);
2827087140dSDongpo Li 	reset_control_deassert(priv->mac_ifc_rst);
2837087140dSDongpo Li }
2847087140dSDongpo Li 
hix5hd2_config_port(struct net_device * dev,u32 speed,u32 duplex)28557c5bc9aSZhangfei Gao static void hix5hd2_config_port(struct net_device *dev, u32 speed, u32 duplex)
28657c5bc9aSZhangfei Gao {
28757c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
28857c5bc9aSZhangfei Gao 	u32 val;
28957c5bc9aSZhangfei Gao 
29057c5bc9aSZhangfei Gao 	priv->speed = speed;
29157c5bc9aSZhangfei Gao 	priv->duplex = duplex;
29257c5bc9aSZhangfei Gao 
29357c5bc9aSZhangfei Gao 	switch (priv->phy_mode) {
29457c5bc9aSZhangfei Gao 	case PHY_INTERFACE_MODE_RGMII:
29557c5bc9aSZhangfei Gao 		if (speed == SPEED_1000)
29657c5bc9aSZhangfei Gao 			val = RGMII_SPEED_1000;
29757c5bc9aSZhangfei Gao 		else if (speed == SPEED_100)
29857c5bc9aSZhangfei Gao 			val = RGMII_SPEED_100;
29957c5bc9aSZhangfei Gao 		else
30057c5bc9aSZhangfei Gao 			val = RGMII_SPEED_10;
30157c5bc9aSZhangfei Gao 		break;
30257c5bc9aSZhangfei Gao 	case PHY_INTERFACE_MODE_MII:
30357c5bc9aSZhangfei Gao 		if (speed == SPEED_100)
30457c5bc9aSZhangfei Gao 			val = MII_SPEED_100;
30557c5bc9aSZhangfei Gao 		else
30657c5bc9aSZhangfei Gao 			val = MII_SPEED_10;
30757c5bc9aSZhangfei Gao 		break;
30857c5bc9aSZhangfei Gao 	default:
30957c5bc9aSZhangfei Gao 		netdev_warn(dev, "not supported mode\n");
31057c5bc9aSZhangfei Gao 		val = MII_SPEED_10;
31157c5bc9aSZhangfei Gao 		break;
31257c5bc9aSZhangfei Gao 	}
31357c5bc9aSZhangfei Gao 
31457c5bc9aSZhangfei Gao 	if (duplex)
31557c5bc9aSZhangfei Gao 		val |= GMAC_FULL_DUPLEX;
31657c5bc9aSZhangfei Gao 	writel_relaxed(val, priv->ctrl_base);
3177087140dSDongpo Li 	hix5hd2_mac_interface_reset(priv);
31857c5bc9aSZhangfei Gao 
31957c5bc9aSZhangfei Gao 	writel_relaxed(BIT_MODE_CHANGE_EN, priv->base + MODE_CHANGE_EN);
32057c5bc9aSZhangfei Gao 	if (speed == SPEED_1000)
32157c5bc9aSZhangfei Gao 		val = GMAC_SPEED_1000;
32257c5bc9aSZhangfei Gao 	else if (speed == SPEED_100)
32357c5bc9aSZhangfei Gao 		val = GMAC_SPEED_100;
32457c5bc9aSZhangfei Gao 	else
32557c5bc9aSZhangfei Gao 		val = GMAC_SPEED_10;
32657c5bc9aSZhangfei Gao 	writel_relaxed(val, priv->base + PORT_MODE);
32757c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + MODE_CHANGE_EN);
32857c5bc9aSZhangfei Gao 	writel_relaxed(duplex, priv->base + MAC_DUPLEX_HALF_CTRL);
32957c5bc9aSZhangfei Gao }
33057c5bc9aSZhangfei Gao 
hix5hd2_set_desc_depth(struct hix5hd2_priv * priv,int rx,int tx)33157c5bc9aSZhangfei Gao static void hix5hd2_set_desc_depth(struct hix5hd2_priv *priv, int rx, int tx)
33257c5bc9aSZhangfei Gao {
33357c5bc9aSZhangfei Gao 	writel_relaxed(BITS_RX_FQ_DEPTH_EN, priv->base + RX_FQ_REG_EN);
33457c5bc9aSZhangfei Gao 	writel_relaxed(rx << 3, priv->base + RX_FQ_DEPTH);
33557c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + RX_FQ_REG_EN);
33657c5bc9aSZhangfei Gao 
33757c5bc9aSZhangfei Gao 	writel_relaxed(BITS_RX_BQ_DEPTH_EN, priv->base + RX_BQ_REG_EN);
33857c5bc9aSZhangfei Gao 	writel_relaxed(rx << 3, priv->base + RX_BQ_DEPTH);
33957c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + RX_BQ_REG_EN);
34057c5bc9aSZhangfei Gao 
34157c5bc9aSZhangfei Gao 	writel_relaxed(BITS_TX_BQ_DEPTH_EN, priv->base + TX_BQ_REG_EN);
34257c5bc9aSZhangfei Gao 	writel_relaxed(tx << 3, priv->base + TX_BQ_DEPTH);
34357c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + TX_BQ_REG_EN);
34457c5bc9aSZhangfei Gao 
34557c5bc9aSZhangfei Gao 	writel_relaxed(BITS_TX_RQ_DEPTH_EN, priv->base + TX_RQ_REG_EN);
34657c5bc9aSZhangfei Gao 	writel_relaxed(tx << 3, priv->base + TX_RQ_DEPTH);
34757c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + TX_RQ_REG_EN);
34857c5bc9aSZhangfei Gao }
34957c5bc9aSZhangfei Gao 
hix5hd2_set_rx_fq(struct hix5hd2_priv * priv,dma_addr_t phy_addr)35057c5bc9aSZhangfei Gao static void hix5hd2_set_rx_fq(struct hix5hd2_priv *priv, dma_addr_t phy_addr)
35157c5bc9aSZhangfei Gao {
35257c5bc9aSZhangfei Gao 	writel_relaxed(BITS_RX_FQ_START_ADDR_EN, priv->base + RX_FQ_REG_EN);
35357c5bc9aSZhangfei Gao 	writel_relaxed(phy_addr, priv->base + RX_FQ_START_ADDR);
35457c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + RX_FQ_REG_EN);
35557c5bc9aSZhangfei Gao }
35657c5bc9aSZhangfei Gao 
hix5hd2_set_rx_bq(struct hix5hd2_priv * priv,dma_addr_t phy_addr)35757c5bc9aSZhangfei Gao static void hix5hd2_set_rx_bq(struct hix5hd2_priv *priv, dma_addr_t phy_addr)
35857c5bc9aSZhangfei Gao {
35957c5bc9aSZhangfei Gao 	writel_relaxed(BITS_RX_BQ_START_ADDR_EN, priv->base + RX_BQ_REG_EN);
36057c5bc9aSZhangfei Gao 	writel_relaxed(phy_addr, priv->base + RX_BQ_START_ADDR);
36157c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + RX_BQ_REG_EN);
36257c5bc9aSZhangfei Gao }
36357c5bc9aSZhangfei Gao 
hix5hd2_set_tx_bq(struct hix5hd2_priv * priv,dma_addr_t phy_addr)36457c5bc9aSZhangfei Gao static void hix5hd2_set_tx_bq(struct hix5hd2_priv *priv, dma_addr_t phy_addr)
36557c5bc9aSZhangfei Gao {
36657c5bc9aSZhangfei Gao 	writel_relaxed(BITS_TX_BQ_START_ADDR_EN, priv->base + TX_BQ_REG_EN);
36757c5bc9aSZhangfei Gao 	writel_relaxed(phy_addr, priv->base + TX_BQ_START_ADDR);
36857c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + TX_BQ_REG_EN);
36957c5bc9aSZhangfei Gao }
37057c5bc9aSZhangfei Gao 
hix5hd2_set_tx_rq(struct hix5hd2_priv * priv,dma_addr_t phy_addr)37157c5bc9aSZhangfei Gao static void hix5hd2_set_tx_rq(struct hix5hd2_priv *priv, dma_addr_t phy_addr)
37257c5bc9aSZhangfei Gao {
37357c5bc9aSZhangfei Gao 	writel_relaxed(BITS_TX_RQ_START_ADDR_EN, priv->base + TX_RQ_REG_EN);
37457c5bc9aSZhangfei Gao 	writel_relaxed(phy_addr, priv->base + TX_RQ_START_ADDR);
37557c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + TX_RQ_REG_EN);
37657c5bc9aSZhangfei Gao }
37757c5bc9aSZhangfei Gao 
hix5hd2_set_desc_addr(struct hix5hd2_priv * priv)37857c5bc9aSZhangfei Gao static void hix5hd2_set_desc_addr(struct hix5hd2_priv *priv)
37957c5bc9aSZhangfei Gao {
38057c5bc9aSZhangfei Gao 	hix5hd2_set_rx_fq(priv, priv->rx_fq.phys_addr);
38157c5bc9aSZhangfei Gao 	hix5hd2_set_rx_bq(priv, priv->rx_bq.phys_addr);
38257c5bc9aSZhangfei Gao 	hix5hd2_set_tx_rq(priv, priv->tx_rq.phys_addr);
38357c5bc9aSZhangfei Gao 	hix5hd2_set_tx_bq(priv, priv->tx_bq.phys_addr);
38457c5bc9aSZhangfei Gao }
38557c5bc9aSZhangfei Gao 
hix5hd2_hw_init(struct hix5hd2_priv * priv)38657c5bc9aSZhangfei Gao static void hix5hd2_hw_init(struct hix5hd2_priv *priv)
38757c5bc9aSZhangfei Gao {
38857c5bc9aSZhangfei Gao 	u32 val;
38957c5bc9aSZhangfei Gao 
39057c5bc9aSZhangfei Gao 	/* disable and clear all interrupts */
39157c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + ENA_PMU_INT);
39257c5bc9aSZhangfei Gao 	writel_relaxed(~0, priv->base + RAW_PMU_INT);
39357c5bc9aSZhangfei Gao 
39457c5bc9aSZhangfei Gao 	writel_relaxed(BIT_CRC_ERR_PASS, priv->base + REC_FILT_CONTROL);
39557c5bc9aSZhangfei Gao 	writel_relaxed(MAC_MAX_FRAME_SIZE, priv->base + CONTROL_WORD);
39657c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + COL_SLOT_TIME);
39757c5bc9aSZhangfei Gao 
39857c5bc9aSZhangfei Gao 	val = RX_BQ_INT_THRESHOLD | TX_RQ_INT_THRESHOLD << QUEUE_TX_BQ_SHIFT;
39957c5bc9aSZhangfei Gao 	writel_relaxed(val, priv->base + IN_QUEUE_TH);
40057c5bc9aSZhangfei Gao 
40157c5bc9aSZhangfei Gao 	writel_relaxed(RX_BQ_IN_TIMEOUT, priv->base + RX_BQ_IN_TIMEOUT_TH);
40257c5bc9aSZhangfei Gao 	writel_relaxed(TX_RQ_IN_TIMEOUT, priv->base + TX_RQ_IN_TIMEOUT_TH);
40357c5bc9aSZhangfei Gao 
40457c5bc9aSZhangfei Gao 	hix5hd2_set_desc_depth(priv, RX_DESC_NUM, TX_DESC_NUM);
40557c5bc9aSZhangfei Gao 	hix5hd2_set_desc_addr(priv);
40657c5bc9aSZhangfei Gao }
40757c5bc9aSZhangfei Gao 
hix5hd2_irq_enable(struct hix5hd2_priv * priv)40857c5bc9aSZhangfei Gao static void hix5hd2_irq_enable(struct hix5hd2_priv *priv)
40957c5bc9aSZhangfei Gao {
41057c5bc9aSZhangfei Gao 	writel_relaxed(DEF_INT_MASK, priv->base + ENA_PMU_INT);
41157c5bc9aSZhangfei Gao }
41257c5bc9aSZhangfei Gao 
hix5hd2_irq_disable(struct hix5hd2_priv * priv)41357c5bc9aSZhangfei Gao static void hix5hd2_irq_disable(struct hix5hd2_priv *priv)
41457c5bc9aSZhangfei Gao {
41557c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + ENA_PMU_INT);
41657c5bc9aSZhangfei Gao }
41757c5bc9aSZhangfei Gao 
hix5hd2_port_enable(struct hix5hd2_priv * priv)41857c5bc9aSZhangfei Gao static void hix5hd2_port_enable(struct hix5hd2_priv *priv)
41957c5bc9aSZhangfei Gao {
42057c5bc9aSZhangfei Gao 	writel_relaxed(0xf, priv->base + DESC_WR_RD_ENA);
42157c5bc9aSZhangfei Gao 	writel_relaxed(BITS_RX_EN | BITS_TX_EN, priv->base + PORT_EN);
42257c5bc9aSZhangfei Gao }
42357c5bc9aSZhangfei Gao 
hix5hd2_port_disable(struct hix5hd2_priv * priv)42457c5bc9aSZhangfei Gao static void hix5hd2_port_disable(struct hix5hd2_priv *priv)
42557c5bc9aSZhangfei Gao {
426951b5d95SArnd Bergmann 	writel_relaxed(~(u32)(BITS_RX_EN | BITS_TX_EN), priv->base + PORT_EN);
42757c5bc9aSZhangfei Gao 	writel_relaxed(0, priv->base + DESC_WR_RD_ENA);
42857c5bc9aSZhangfei Gao }
42957c5bc9aSZhangfei Gao 
hix5hd2_hw_set_mac_addr(struct net_device * dev)43057c5bc9aSZhangfei Gao static void hix5hd2_hw_set_mac_addr(struct net_device *dev)
43157c5bc9aSZhangfei Gao {
43257c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
43376660757SJakub Kicinski 	const unsigned char *mac = dev->dev_addr;
43457c5bc9aSZhangfei Gao 	u32 val;
43557c5bc9aSZhangfei Gao 
43657c5bc9aSZhangfei Gao 	val = mac[1] | (mac[0] << 8);
43757c5bc9aSZhangfei Gao 	writel_relaxed(val, priv->base + STATION_ADDR_HIGH);
43857c5bc9aSZhangfei Gao 
43957c5bc9aSZhangfei Gao 	val = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24);
44057c5bc9aSZhangfei Gao 	writel_relaxed(val, priv->base + STATION_ADDR_LOW);
44157c5bc9aSZhangfei Gao }
44257c5bc9aSZhangfei Gao 
hix5hd2_net_set_mac_address(struct net_device * dev,void * p)44357c5bc9aSZhangfei Gao static int hix5hd2_net_set_mac_address(struct net_device *dev, void *p)
44457c5bc9aSZhangfei Gao {
44557c5bc9aSZhangfei Gao 	int ret;
44657c5bc9aSZhangfei Gao 
44757c5bc9aSZhangfei Gao 	ret = eth_mac_addr(dev, p);
44857c5bc9aSZhangfei Gao 	if (!ret)
44957c5bc9aSZhangfei Gao 		hix5hd2_hw_set_mac_addr(dev);
45057c5bc9aSZhangfei Gao 
45157c5bc9aSZhangfei Gao 	return ret;
45257c5bc9aSZhangfei Gao }
45357c5bc9aSZhangfei Gao 
hix5hd2_adjust_link(struct net_device * dev)45457c5bc9aSZhangfei Gao static void hix5hd2_adjust_link(struct net_device *dev)
45557c5bc9aSZhangfei Gao {
45657c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
4576f96608eSPhilippe Reynes 	struct phy_device *phy = dev->phydev;
45857c5bc9aSZhangfei Gao 
45957c5bc9aSZhangfei Gao 	if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex)) {
46057c5bc9aSZhangfei Gao 		hix5hd2_config_port(dev, phy->speed, phy->duplex);
46157c5bc9aSZhangfei Gao 		phy_print_status(phy);
46257c5bc9aSZhangfei Gao 	}
46357c5bc9aSZhangfei Gao }
46457c5bc9aSZhangfei Gao 
hix5hd2_rx_refill(struct hix5hd2_priv * priv)46557c5bc9aSZhangfei Gao static void hix5hd2_rx_refill(struct hix5hd2_priv *priv)
46657c5bc9aSZhangfei Gao {
46757c5bc9aSZhangfei Gao 	struct hix5hd2_desc *desc;
46857c5bc9aSZhangfei Gao 	struct sk_buff *skb;
46957c5bc9aSZhangfei Gao 	u32 start, end, num, pos, i;
47057c5bc9aSZhangfei Gao 	u32 len = MAC_MAX_FRAME_SIZE;
47157c5bc9aSZhangfei Gao 	dma_addr_t addr;
47257c5bc9aSZhangfei Gao 
47357c5bc9aSZhangfei Gao 	/* software write pointer */
47457c5bc9aSZhangfei Gao 	start = dma_cnt(readl_relaxed(priv->base + RX_FQ_WR_ADDR));
47557c5bc9aSZhangfei Gao 	/* logic read pointer */
47657c5bc9aSZhangfei Gao 	end = dma_cnt(readl_relaxed(priv->base + RX_FQ_RD_ADDR));
47757c5bc9aSZhangfei Gao 	num = CIRC_SPACE(start, end, RX_DESC_NUM);
47857c5bc9aSZhangfei Gao 
47957c5bc9aSZhangfei Gao 	for (i = 0, pos = start; i < num; i++) {
48057c5bc9aSZhangfei Gao 		if (priv->rx_skb[pos]) {
48157c5bc9aSZhangfei Gao 			break;
48257c5bc9aSZhangfei Gao 		} else {
48357c5bc9aSZhangfei Gao 			skb = netdev_alloc_skb_ip_align(priv->netdev, len);
48457c5bc9aSZhangfei Gao 			if (unlikely(skb == NULL))
48557c5bc9aSZhangfei Gao 				break;
48657c5bc9aSZhangfei Gao 		}
48757c5bc9aSZhangfei Gao 
48857c5bc9aSZhangfei Gao 		addr = dma_map_single(priv->dev, skb->data, len, DMA_FROM_DEVICE);
48957c5bc9aSZhangfei Gao 		if (dma_mapping_error(priv->dev, addr)) {
49057c5bc9aSZhangfei Gao 			dev_kfree_skb_any(skb);
49157c5bc9aSZhangfei Gao 			break;
49257c5bc9aSZhangfei Gao 		}
49357c5bc9aSZhangfei Gao 
49457c5bc9aSZhangfei Gao 		desc = priv->rx_fq.desc + pos;
49557c5bc9aSZhangfei Gao 		desc->buff_addr = cpu_to_le32(addr);
49657c5bc9aSZhangfei Gao 		priv->rx_skb[pos] = skb;
49757c5bc9aSZhangfei Gao 		desc->cmd = cpu_to_le32(DESC_VLD_FREE |
49857c5bc9aSZhangfei Gao 					(len - 1) << DESC_BUFF_LEN_OFF);
49957c5bc9aSZhangfei Gao 		pos = dma_ring_incr(pos, RX_DESC_NUM);
50057c5bc9aSZhangfei Gao 	}
50157c5bc9aSZhangfei Gao 
50257c5bc9aSZhangfei Gao 	/* ensure desc updated */
50357c5bc9aSZhangfei Gao 	wmb();
50457c5bc9aSZhangfei Gao 
50557c5bc9aSZhangfei Gao 	if (pos != start)
50657c5bc9aSZhangfei Gao 		writel_relaxed(dma_byte(pos), priv->base + RX_FQ_WR_ADDR);
50757c5bc9aSZhangfei Gao }
50857c5bc9aSZhangfei Gao 
hix5hd2_rx(struct net_device * dev,int limit)50957c5bc9aSZhangfei Gao static int hix5hd2_rx(struct net_device *dev, int limit)
51057c5bc9aSZhangfei Gao {
51157c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
51257c5bc9aSZhangfei Gao 	struct sk_buff *skb;
51357c5bc9aSZhangfei Gao 	struct hix5hd2_desc *desc;
51457c5bc9aSZhangfei Gao 	dma_addr_t addr;
51557c5bc9aSZhangfei Gao 	u32 start, end, num, pos, i, len;
51657c5bc9aSZhangfei Gao 
51757c5bc9aSZhangfei Gao 	/* software read pointer */
51857c5bc9aSZhangfei Gao 	start = dma_cnt(readl_relaxed(priv->base + RX_BQ_RD_ADDR));
51957c5bc9aSZhangfei Gao 	/* logic write pointer */
52057c5bc9aSZhangfei Gao 	end = dma_cnt(readl_relaxed(priv->base + RX_BQ_WR_ADDR));
52157c5bc9aSZhangfei Gao 	num = CIRC_CNT(end, start, RX_DESC_NUM);
52257c5bc9aSZhangfei Gao 	if (num > limit)
52357c5bc9aSZhangfei Gao 		num = limit;
52457c5bc9aSZhangfei Gao 
52557c5bc9aSZhangfei Gao 	/* ensure get updated desc */
52657c5bc9aSZhangfei Gao 	rmb();
52757c5bc9aSZhangfei Gao 	for (i = 0, pos = start; i < num; i++) {
52857c5bc9aSZhangfei Gao 		skb = priv->rx_skb[pos];
52957c5bc9aSZhangfei Gao 		if (unlikely(!skb)) {
53057c5bc9aSZhangfei Gao 			netdev_err(dev, "inconsistent rx_skb\n");
53157c5bc9aSZhangfei Gao 			break;
53257c5bc9aSZhangfei Gao 		}
53357c5bc9aSZhangfei Gao 		priv->rx_skb[pos] = NULL;
53457c5bc9aSZhangfei Gao 
53557c5bc9aSZhangfei Gao 		desc = priv->rx_bq.desc + pos;
53657c5bc9aSZhangfei Gao 		len = (le32_to_cpu(desc->cmd) >> DESC_DATA_LEN_OFF) &
53757c5bc9aSZhangfei Gao 		       DESC_DATA_MASK;
53857c5bc9aSZhangfei Gao 		addr = le32_to_cpu(desc->buff_addr);
53957c5bc9aSZhangfei Gao 		dma_unmap_single(priv->dev, addr, MAC_MAX_FRAME_SIZE,
54057c5bc9aSZhangfei Gao 				 DMA_FROM_DEVICE);
54157c5bc9aSZhangfei Gao 
54257c5bc9aSZhangfei Gao 		skb_put(skb, len);
54357c5bc9aSZhangfei Gao 		if (skb->len > MAC_MAX_FRAME_SIZE) {
54457c5bc9aSZhangfei Gao 			netdev_err(dev, "rcv len err, len = %d\n", skb->len);
54557c5bc9aSZhangfei Gao 			dev->stats.rx_errors++;
54657c5bc9aSZhangfei Gao 			dev->stats.rx_length_errors++;
54757c5bc9aSZhangfei Gao 			dev_kfree_skb_any(skb);
54857c5bc9aSZhangfei Gao 			goto next;
54957c5bc9aSZhangfei Gao 		}
55057c5bc9aSZhangfei Gao 
55157c5bc9aSZhangfei Gao 		skb->protocol = eth_type_trans(skb, dev);
55257c5bc9aSZhangfei Gao 		napi_gro_receive(&priv->napi, skb);
55357c5bc9aSZhangfei Gao 		dev->stats.rx_packets++;
554433c07a1SLiu Jian 		dev->stats.rx_bytes += len;
55557c5bc9aSZhangfei Gao next:
55657c5bc9aSZhangfei Gao 		pos = dma_ring_incr(pos, RX_DESC_NUM);
55757c5bc9aSZhangfei Gao 	}
55857c5bc9aSZhangfei Gao 
55957c5bc9aSZhangfei Gao 	if (pos != start)
56057c5bc9aSZhangfei Gao 		writel_relaxed(dma_byte(pos), priv->base + RX_BQ_RD_ADDR);
56157c5bc9aSZhangfei Gao 
56257c5bc9aSZhangfei Gao 	hix5hd2_rx_refill(priv);
56357c5bc9aSZhangfei Gao 
56457c5bc9aSZhangfei Gao 	return num;
56557c5bc9aSZhangfei Gao }
56657c5bc9aSZhangfei Gao 
hix5hd2_clean_sg_desc(struct hix5hd2_priv * priv,struct sk_buff * skb,u32 pos)567e5222b1cSDongpo Li static void hix5hd2_clean_sg_desc(struct hix5hd2_priv *priv,
568e5222b1cSDongpo Li 				  struct sk_buff *skb, u32 pos)
569e5222b1cSDongpo Li {
570e5222b1cSDongpo Li 	struct sg_desc *desc;
571e5222b1cSDongpo Li 	dma_addr_t addr;
572e5222b1cSDongpo Li 	u32 len;
573e5222b1cSDongpo Li 	int i;
574e5222b1cSDongpo Li 
575e5222b1cSDongpo Li 	desc = priv->tx_ring.desc + pos;
576e5222b1cSDongpo Li 
577e5222b1cSDongpo Li 	addr = le32_to_cpu(desc->linear_addr);
578e5222b1cSDongpo Li 	len = le32_to_cpu(desc->linear_len);
579e5222b1cSDongpo Li 	dma_unmap_single(priv->dev, addr, len, DMA_TO_DEVICE);
580e5222b1cSDongpo Li 
581e5222b1cSDongpo Li 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
582e5222b1cSDongpo Li 		addr = le32_to_cpu(desc->frags[i].addr);
583e5222b1cSDongpo Li 		len = le32_to_cpu(desc->frags[i].size);
584e5222b1cSDongpo Li 		dma_unmap_page(priv->dev, addr, len, DMA_TO_DEVICE);
585e5222b1cSDongpo Li 	}
586e5222b1cSDongpo Li }
587e5222b1cSDongpo Li 
hix5hd2_xmit_reclaim(struct net_device * dev)58857c5bc9aSZhangfei Gao static void hix5hd2_xmit_reclaim(struct net_device *dev)
58957c5bc9aSZhangfei Gao {
59057c5bc9aSZhangfei Gao 	struct sk_buff *skb;
59157c5bc9aSZhangfei Gao 	struct hix5hd2_desc *desc;
59257c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
59357c5bc9aSZhangfei Gao 	unsigned int bytes_compl = 0, pkts_compl = 0;
59457c5bc9aSZhangfei Gao 	u32 start, end, num, pos, i;
59557c5bc9aSZhangfei Gao 	dma_addr_t addr;
59657c5bc9aSZhangfei Gao 
59757c5bc9aSZhangfei Gao 	netif_tx_lock(dev);
59857c5bc9aSZhangfei Gao 
59957c5bc9aSZhangfei Gao 	/* software read */
60057c5bc9aSZhangfei Gao 	start = dma_cnt(readl_relaxed(priv->base + TX_RQ_RD_ADDR));
60157c5bc9aSZhangfei Gao 	/* logic write */
60257c5bc9aSZhangfei Gao 	end = dma_cnt(readl_relaxed(priv->base + TX_RQ_WR_ADDR));
60357c5bc9aSZhangfei Gao 	num = CIRC_CNT(end, start, TX_DESC_NUM);
60457c5bc9aSZhangfei Gao 
60557c5bc9aSZhangfei Gao 	for (i = 0, pos = start; i < num; i++) {
60657c5bc9aSZhangfei Gao 		skb = priv->tx_skb[pos];
60757c5bc9aSZhangfei Gao 		if (unlikely(!skb)) {
60857c5bc9aSZhangfei Gao 			netdev_err(dev, "inconsistent tx_skb\n");
60957c5bc9aSZhangfei Gao 			break;
61057c5bc9aSZhangfei Gao 		}
61157c5bc9aSZhangfei Gao 
61257c5bc9aSZhangfei Gao 		pkts_compl++;
61357c5bc9aSZhangfei Gao 		bytes_compl += skb->len;
61457c5bc9aSZhangfei Gao 		desc = priv->tx_rq.desc + pos;
615e5222b1cSDongpo Li 
616e5222b1cSDongpo Li 		if (skb_shinfo(skb)->nr_frags) {
617e5222b1cSDongpo Li 			hix5hd2_clean_sg_desc(priv, skb, pos);
618e5222b1cSDongpo Li 		} else {
61957c5bc9aSZhangfei Gao 			addr = le32_to_cpu(desc->buff_addr);
620e5222b1cSDongpo Li 			dma_unmap_single(priv->dev, addr, skb->len,
621e5222b1cSDongpo Li 					 DMA_TO_DEVICE);
622e5222b1cSDongpo Li 		}
623e5222b1cSDongpo Li 
62457c5bc9aSZhangfei Gao 		priv->tx_skb[pos] = NULL;
62557c5bc9aSZhangfei Gao 		dev_consume_skb_any(skb);
62657c5bc9aSZhangfei Gao 		pos = dma_ring_incr(pos, TX_DESC_NUM);
62757c5bc9aSZhangfei Gao 	}
62857c5bc9aSZhangfei Gao 
62957c5bc9aSZhangfei Gao 	if (pos != start)
63057c5bc9aSZhangfei Gao 		writel_relaxed(dma_byte(pos), priv->base + TX_RQ_RD_ADDR);
63157c5bc9aSZhangfei Gao 
63257c5bc9aSZhangfei Gao 	netif_tx_unlock(dev);
63357c5bc9aSZhangfei Gao 
63457c5bc9aSZhangfei Gao 	if (pkts_compl || bytes_compl)
63557c5bc9aSZhangfei Gao 		netdev_completed_queue(dev, pkts_compl, bytes_compl);
63657c5bc9aSZhangfei Gao 
63757c5bc9aSZhangfei Gao 	if (unlikely(netif_queue_stopped(priv->netdev)) && pkts_compl)
63857c5bc9aSZhangfei Gao 		netif_wake_queue(priv->netdev);
63957c5bc9aSZhangfei Gao }
64057c5bc9aSZhangfei Gao 
hix5hd2_poll(struct napi_struct * napi,int budget)64157c5bc9aSZhangfei Gao static int hix5hd2_poll(struct napi_struct *napi, int budget)
64257c5bc9aSZhangfei Gao {
64357c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = container_of(napi,
64457c5bc9aSZhangfei Gao 				struct hix5hd2_priv, napi);
64557c5bc9aSZhangfei Gao 	struct net_device *dev = priv->netdev;
64657c5bc9aSZhangfei Gao 	int work_done = 0, task = budget;
64757c5bc9aSZhangfei Gao 	int ints, num;
64857c5bc9aSZhangfei Gao 
64957c5bc9aSZhangfei Gao 	do {
65057c5bc9aSZhangfei Gao 		hix5hd2_xmit_reclaim(dev);
65157c5bc9aSZhangfei Gao 		num = hix5hd2_rx(dev, task);
65257c5bc9aSZhangfei Gao 		work_done += num;
65357c5bc9aSZhangfei Gao 		task -= num;
65457c5bc9aSZhangfei Gao 		if ((work_done >= budget) || (num == 0))
65557c5bc9aSZhangfei Gao 			break;
65657c5bc9aSZhangfei Gao 
65757c5bc9aSZhangfei Gao 		ints = readl_relaxed(priv->base + RAW_PMU_INT);
65857c5bc9aSZhangfei Gao 		writel_relaxed(ints, priv->base + RAW_PMU_INT);
65957c5bc9aSZhangfei Gao 	} while (ints & DEF_INT_MASK);
66057c5bc9aSZhangfei Gao 
66157c5bc9aSZhangfei Gao 	if (work_done < budget) {
6626ad20165SEric Dumazet 		napi_complete_done(napi, work_done);
66357c5bc9aSZhangfei Gao 		hix5hd2_irq_enable(priv);
66457c5bc9aSZhangfei Gao 	}
66557c5bc9aSZhangfei Gao 
66657c5bc9aSZhangfei Gao 	return work_done;
66757c5bc9aSZhangfei Gao }
66857c5bc9aSZhangfei Gao 
hix5hd2_interrupt(int irq,void * dev_id)66957c5bc9aSZhangfei Gao static irqreturn_t hix5hd2_interrupt(int irq, void *dev_id)
67057c5bc9aSZhangfei Gao {
67157c5bc9aSZhangfei Gao 	struct net_device *dev = (struct net_device *)dev_id;
67257c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
67357c5bc9aSZhangfei Gao 	int ints = readl_relaxed(priv->base + RAW_PMU_INT);
67457c5bc9aSZhangfei Gao 
67557c5bc9aSZhangfei Gao 	writel_relaxed(ints, priv->base + RAW_PMU_INT);
67657c5bc9aSZhangfei Gao 	if (likely(ints & DEF_INT_MASK)) {
67757c5bc9aSZhangfei Gao 		hix5hd2_irq_disable(priv);
67857c5bc9aSZhangfei Gao 		napi_schedule(&priv->napi);
67957c5bc9aSZhangfei Gao 	}
68057c5bc9aSZhangfei Gao 
68157c5bc9aSZhangfei Gao 	return IRQ_HANDLED;
68257c5bc9aSZhangfei Gao }
68357c5bc9aSZhangfei Gao 
hix5hd2_get_desc_cmd(struct sk_buff * skb,unsigned long hw_cap)684e5222b1cSDongpo Li static u32 hix5hd2_get_desc_cmd(struct sk_buff *skb, unsigned long hw_cap)
685e5222b1cSDongpo Li {
686e5222b1cSDongpo Li 	u32 cmd = 0;
687e5222b1cSDongpo Li 
688e5222b1cSDongpo Li 	if (HAS_CAP_TSO(hw_cap)) {
689e5222b1cSDongpo Li 		if (skb_shinfo(skb)->nr_frags)
690e5222b1cSDongpo Li 			cmd |= DESC_SG;
691e5222b1cSDongpo Li 		cmd |= skb_shinfo(skb)->nr_frags << DESC_FRAGS_NUM_OFF;
692e5222b1cSDongpo Li 	} else {
693e5222b1cSDongpo Li 		cmd |= DESC_FL_FULL |
694e5222b1cSDongpo Li 			((skb->len & DESC_DATA_MASK) << DESC_BUFF_LEN_OFF);
695e5222b1cSDongpo Li 	}
696e5222b1cSDongpo Li 
697e5222b1cSDongpo Li 	cmd |= (skb->len & DESC_DATA_MASK) << DESC_DATA_LEN_OFF;
698e5222b1cSDongpo Li 	cmd |= DESC_VLD_BUSY;
699e5222b1cSDongpo Li 
700e5222b1cSDongpo Li 	return cmd;
701e5222b1cSDongpo Li }
702e5222b1cSDongpo Li 
hix5hd2_fill_sg_desc(struct hix5hd2_priv * priv,struct sk_buff * skb,u32 pos)703e5222b1cSDongpo Li static int hix5hd2_fill_sg_desc(struct hix5hd2_priv *priv,
704e5222b1cSDongpo Li 				struct sk_buff *skb, u32 pos)
705e5222b1cSDongpo Li {
706e5222b1cSDongpo Li 	struct sg_desc *desc;
707e5222b1cSDongpo Li 	dma_addr_t addr;
708e5222b1cSDongpo Li 	int ret;
709e5222b1cSDongpo Li 	int i;
710e5222b1cSDongpo Li 
711e5222b1cSDongpo Li 	desc = priv->tx_ring.desc + pos;
712e5222b1cSDongpo Li 
713e5222b1cSDongpo Li 	desc->total_len = cpu_to_le32(skb->len);
714e5222b1cSDongpo Li 	addr = dma_map_single(priv->dev, skb->data, skb_headlen(skb),
715e5222b1cSDongpo Li 			      DMA_TO_DEVICE);
716e5222b1cSDongpo Li 	if (unlikely(dma_mapping_error(priv->dev, addr)))
717e5222b1cSDongpo Li 		return -EINVAL;
718e5222b1cSDongpo Li 	desc->linear_addr = cpu_to_le32(addr);
719e5222b1cSDongpo Li 	desc->linear_len = cpu_to_le32(skb_headlen(skb));
720e5222b1cSDongpo Li 
721e5222b1cSDongpo Li 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
722e5222b1cSDongpo Li 		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
723d7840976SMatthew Wilcox (Oracle) 		int len = skb_frag_size(frag);
724e5222b1cSDongpo Li 
725e5222b1cSDongpo Li 		addr = skb_frag_dma_map(priv->dev, frag, 0, len, DMA_TO_DEVICE);
726e5222b1cSDongpo Li 		ret = dma_mapping_error(priv->dev, addr);
727e5222b1cSDongpo Li 		if (unlikely(ret))
728e5222b1cSDongpo Li 			return -EINVAL;
729e5222b1cSDongpo Li 		desc->frags[i].addr = cpu_to_le32(addr);
730e5222b1cSDongpo Li 		desc->frags[i].size = cpu_to_le32(len);
731e5222b1cSDongpo Li 	}
732e5222b1cSDongpo Li 
733e5222b1cSDongpo Li 	return 0;
734e5222b1cSDongpo Li }
735e5222b1cSDongpo Li 
hix5hd2_net_xmit(struct sk_buff * skb,struct net_device * dev)736c9c39411SYueHaibing static netdev_tx_t hix5hd2_net_xmit(struct sk_buff *skb, struct net_device *dev)
73757c5bc9aSZhangfei Gao {
73857c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
73957c5bc9aSZhangfei Gao 	struct hix5hd2_desc *desc;
74057c5bc9aSZhangfei Gao 	dma_addr_t addr;
74157c5bc9aSZhangfei Gao 	u32 pos;
742e5222b1cSDongpo Li 	u32 cmd;
743e5222b1cSDongpo Li 	int ret;
74457c5bc9aSZhangfei Gao 
74557c5bc9aSZhangfei Gao 	/* software write pointer */
74657c5bc9aSZhangfei Gao 	pos = dma_cnt(readl_relaxed(priv->base + TX_BQ_WR_ADDR));
74757c5bc9aSZhangfei Gao 	if (unlikely(priv->tx_skb[pos])) {
74857c5bc9aSZhangfei Gao 		dev->stats.tx_dropped++;
74957c5bc9aSZhangfei Gao 		dev->stats.tx_fifo_errors++;
75057c5bc9aSZhangfei Gao 		netif_stop_queue(dev);
75157c5bc9aSZhangfei Gao 		return NETDEV_TX_BUSY;
75257c5bc9aSZhangfei Gao 	}
75357c5bc9aSZhangfei Gao 
754e5222b1cSDongpo Li 	desc = priv->tx_bq.desc + pos;
755e5222b1cSDongpo Li 
756e5222b1cSDongpo Li 	cmd = hix5hd2_get_desc_cmd(skb, priv->hw_cap);
757e5222b1cSDongpo Li 	desc->cmd = cpu_to_le32(cmd);
758e5222b1cSDongpo Li 
759e5222b1cSDongpo Li 	if (skb_shinfo(skb)->nr_frags) {
760e5222b1cSDongpo Li 		ret = hix5hd2_fill_sg_desc(priv, skb, pos);
761e5222b1cSDongpo Li 		if (unlikely(ret)) {
76257c5bc9aSZhangfei Gao 			dev_kfree_skb_any(skb);
763e5222b1cSDongpo Li 			dev->stats.tx_dropped++;
76457c5bc9aSZhangfei Gao 			return NETDEV_TX_OK;
76557c5bc9aSZhangfei Gao 		}
766e5222b1cSDongpo Li 		addr = priv->tx_ring.phys_addr + pos * sizeof(struct sg_desc);
767e5222b1cSDongpo Li 	} else {
768e5222b1cSDongpo Li 		addr = dma_map_single(priv->dev, skb->data, skb->len,
769e5222b1cSDongpo Li 				      DMA_TO_DEVICE);
770e5222b1cSDongpo Li 		if (unlikely(dma_mapping_error(priv->dev, addr))) {
771e5222b1cSDongpo Li 			dev_kfree_skb_any(skb);
772e5222b1cSDongpo Li 			dev->stats.tx_dropped++;
773e5222b1cSDongpo Li 			return NETDEV_TX_OK;
774e5222b1cSDongpo Li 		}
775e5222b1cSDongpo Li 	}
77657c5bc9aSZhangfei Gao 	desc->buff_addr = cpu_to_le32(addr);
777e5222b1cSDongpo Li 
77857c5bc9aSZhangfei Gao 	priv->tx_skb[pos] = skb;
77957c5bc9aSZhangfei Gao 
78057c5bc9aSZhangfei Gao 	/* ensure desc updated */
78157c5bc9aSZhangfei Gao 	wmb();
78257c5bc9aSZhangfei Gao 
78357c5bc9aSZhangfei Gao 	pos = dma_ring_incr(pos, TX_DESC_NUM);
78457c5bc9aSZhangfei Gao 	writel_relaxed(dma_byte(pos), priv->base + TX_BQ_WR_ADDR);
78557c5bc9aSZhangfei Gao 
786860e9538SFlorian Westphal 	netif_trans_update(dev);
78757c5bc9aSZhangfei Gao 	dev->stats.tx_packets++;
78857c5bc9aSZhangfei Gao 	dev->stats.tx_bytes += skb->len;
78957c5bc9aSZhangfei Gao 	netdev_sent_queue(dev, skb->len);
79057c5bc9aSZhangfei Gao 
79157c5bc9aSZhangfei Gao 	return NETDEV_TX_OK;
79257c5bc9aSZhangfei Gao }
79357c5bc9aSZhangfei Gao 
hix5hd2_free_dma_desc_rings(struct hix5hd2_priv * priv)79457c5bc9aSZhangfei Gao static void hix5hd2_free_dma_desc_rings(struct hix5hd2_priv *priv)
79557c5bc9aSZhangfei Gao {
79657c5bc9aSZhangfei Gao 	struct hix5hd2_desc *desc;
79757c5bc9aSZhangfei Gao 	dma_addr_t addr;
79857c5bc9aSZhangfei Gao 	int i;
79957c5bc9aSZhangfei Gao 
80057c5bc9aSZhangfei Gao 	for (i = 0; i < RX_DESC_NUM; i++) {
80157c5bc9aSZhangfei Gao 		struct sk_buff *skb = priv->rx_skb[i];
80257c5bc9aSZhangfei Gao 		if (skb == NULL)
80357c5bc9aSZhangfei Gao 			continue;
80457c5bc9aSZhangfei Gao 
80557c5bc9aSZhangfei Gao 		desc = priv->rx_fq.desc + i;
80657c5bc9aSZhangfei Gao 		addr = le32_to_cpu(desc->buff_addr);
80757c5bc9aSZhangfei Gao 		dma_unmap_single(priv->dev, addr,
80857c5bc9aSZhangfei Gao 				 MAC_MAX_FRAME_SIZE, DMA_FROM_DEVICE);
80957c5bc9aSZhangfei Gao 		dev_kfree_skb_any(skb);
81057c5bc9aSZhangfei Gao 		priv->rx_skb[i] = NULL;
81157c5bc9aSZhangfei Gao 	}
81257c5bc9aSZhangfei Gao 
81357c5bc9aSZhangfei Gao 	for (i = 0; i < TX_DESC_NUM; i++) {
81457c5bc9aSZhangfei Gao 		struct sk_buff *skb = priv->tx_skb[i];
81557c5bc9aSZhangfei Gao 		if (skb == NULL)
81657c5bc9aSZhangfei Gao 			continue;
81757c5bc9aSZhangfei Gao 
81857c5bc9aSZhangfei Gao 		desc = priv->tx_rq.desc + i;
81957c5bc9aSZhangfei Gao 		addr = le32_to_cpu(desc->buff_addr);
82057c5bc9aSZhangfei Gao 		dma_unmap_single(priv->dev, addr, skb->len, DMA_TO_DEVICE);
82157c5bc9aSZhangfei Gao 		dev_kfree_skb_any(skb);
82257c5bc9aSZhangfei Gao 		priv->tx_skb[i] = NULL;
82357c5bc9aSZhangfei Gao 	}
82457c5bc9aSZhangfei Gao }
82557c5bc9aSZhangfei Gao 
hix5hd2_net_open(struct net_device * dev)82657c5bc9aSZhangfei Gao static int hix5hd2_net_open(struct net_device *dev)
82757c5bc9aSZhangfei Gao {
82857c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
8296f96608eSPhilippe Reynes 	struct phy_device *phy;
83057c5bc9aSZhangfei Gao 	int ret;
83157c5bc9aSZhangfei Gao 
8327087140dSDongpo Li 	ret = clk_prepare_enable(priv->mac_core_clk);
83357c5bc9aSZhangfei Gao 	if (ret < 0) {
8347087140dSDongpo Li 		netdev_err(dev, "failed to enable mac core clk %d\n", ret);
8357087140dSDongpo Li 		return ret;
8367087140dSDongpo Li 	}
8377087140dSDongpo Li 
8387087140dSDongpo Li 	ret = clk_prepare_enable(priv->mac_ifc_clk);
8397087140dSDongpo Li 	if (ret < 0) {
8407087140dSDongpo Li 		clk_disable_unprepare(priv->mac_core_clk);
8417087140dSDongpo Li 		netdev_err(dev, "failed to enable mac ifc clk %d\n", ret);
84257c5bc9aSZhangfei Gao 		return ret;
84357c5bc9aSZhangfei Gao 	}
84457c5bc9aSZhangfei Gao 
8456f96608eSPhilippe Reynes 	phy = of_phy_connect(dev, priv->phy_node,
84657c5bc9aSZhangfei Gao 			     &hix5hd2_adjust_link, 0, priv->phy_mode);
8477087140dSDongpo Li 	if (!phy) {
8487087140dSDongpo Li 		clk_disable_unprepare(priv->mac_ifc_clk);
8497087140dSDongpo Li 		clk_disable_unprepare(priv->mac_core_clk);
85057c5bc9aSZhangfei Gao 		return -ENODEV;
8517087140dSDongpo Li 	}
85257c5bc9aSZhangfei Gao 
8536f96608eSPhilippe Reynes 	phy_start(phy);
85457c5bc9aSZhangfei Gao 	hix5hd2_hw_init(priv);
85557c5bc9aSZhangfei Gao 	hix5hd2_rx_refill(priv);
85657c5bc9aSZhangfei Gao 
85757c5bc9aSZhangfei Gao 	netdev_reset_queue(dev);
85857c5bc9aSZhangfei Gao 	netif_start_queue(dev);
85957c5bc9aSZhangfei Gao 	napi_enable(&priv->napi);
86057c5bc9aSZhangfei Gao 
86157c5bc9aSZhangfei Gao 	hix5hd2_port_enable(priv);
86257c5bc9aSZhangfei Gao 	hix5hd2_irq_enable(priv);
86357c5bc9aSZhangfei Gao 
86457c5bc9aSZhangfei Gao 	return 0;
86557c5bc9aSZhangfei Gao }
86657c5bc9aSZhangfei Gao 
hix5hd2_net_close(struct net_device * dev)86757c5bc9aSZhangfei Gao static int hix5hd2_net_close(struct net_device *dev)
86857c5bc9aSZhangfei Gao {
86957c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
87057c5bc9aSZhangfei Gao 
87157c5bc9aSZhangfei Gao 	hix5hd2_port_disable(priv);
87257c5bc9aSZhangfei Gao 	hix5hd2_irq_disable(priv);
87357c5bc9aSZhangfei Gao 	napi_disable(&priv->napi);
87457c5bc9aSZhangfei Gao 	netif_stop_queue(dev);
87557c5bc9aSZhangfei Gao 	hix5hd2_free_dma_desc_rings(priv);
87657c5bc9aSZhangfei Gao 
8776f96608eSPhilippe Reynes 	if (dev->phydev) {
8786f96608eSPhilippe Reynes 		phy_stop(dev->phydev);
8796f96608eSPhilippe Reynes 		phy_disconnect(dev->phydev);
88057c5bc9aSZhangfei Gao 	}
88157c5bc9aSZhangfei Gao 
8827087140dSDongpo Li 	clk_disable_unprepare(priv->mac_ifc_clk);
8837087140dSDongpo Li 	clk_disable_unprepare(priv->mac_core_clk);
88457c5bc9aSZhangfei Gao 
88557c5bc9aSZhangfei Gao 	return 0;
88657c5bc9aSZhangfei Gao }
88757c5bc9aSZhangfei Gao 
hix5hd2_tx_timeout_task(struct work_struct * work)88857c5bc9aSZhangfei Gao static void hix5hd2_tx_timeout_task(struct work_struct *work)
88957c5bc9aSZhangfei Gao {
89057c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv;
89157c5bc9aSZhangfei Gao 
89257c5bc9aSZhangfei Gao 	priv = container_of(work, struct hix5hd2_priv, tx_timeout_task);
89357c5bc9aSZhangfei Gao 	hix5hd2_net_close(priv->netdev);
89457c5bc9aSZhangfei Gao 	hix5hd2_net_open(priv->netdev);
89557c5bc9aSZhangfei Gao }
89657c5bc9aSZhangfei Gao 
hix5hd2_net_timeout(struct net_device * dev,unsigned int txqueue)8970290bd29SMichael S. Tsirkin static void hix5hd2_net_timeout(struct net_device *dev, unsigned int txqueue)
89857c5bc9aSZhangfei Gao {
89957c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(dev);
90057c5bc9aSZhangfei Gao 
90157c5bc9aSZhangfei Gao 	schedule_work(&priv->tx_timeout_task);
90257c5bc9aSZhangfei Gao }
90357c5bc9aSZhangfei Gao 
90457c5bc9aSZhangfei Gao static const struct net_device_ops hix5hd2_netdev_ops = {
90557c5bc9aSZhangfei Gao 	.ndo_open		= hix5hd2_net_open,
90657c5bc9aSZhangfei Gao 	.ndo_stop		= hix5hd2_net_close,
90757c5bc9aSZhangfei Gao 	.ndo_start_xmit		= hix5hd2_net_xmit,
90857c5bc9aSZhangfei Gao 	.ndo_tx_timeout		= hix5hd2_net_timeout,
90957c5bc9aSZhangfei Gao 	.ndo_set_mac_address	= hix5hd2_net_set_mac_address,
91057c5bc9aSZhangfei Gao };
91157c5bc9aSZhangfei Gao 
912bc6f0136SJulia Lawall static const struct ethtool_ops hix5hd2_ethtools_ops = {
91357c5bc9aSZhangfei Gao 	.get_link		= ethtool_op_get_link,
914802fe79eSPhilippe Reynes 	.get_link_ksettings     = phy_ethtool_get_link_ksettings,
915802fe79eSPhilippe Reynes 	.set_link_ksettings     = phy_ethtool_set_link_ksettings,
91657c5bc9aSZhangfei Gao };
91757c5bc9aSZhangfei Gao 
hix5hd2_mdio_wait_ready(struct mii_bus * bus)91857c5bc9aSZhangfei Gao static int hix5hd2_mdio_wait_ready(struct mii_bus *bus)
91957c5bc9aSZhangfei Gao {
92057c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = bus->priv;
92157c5bc9aSZhangfei Gao 	void __iomem *base = priv->base;
92257c5bc9aSZhangfei Gao 	int i, timeout = 10000;
92357c5bc9aSZhangfei Gao 
92457c5bc9aSZhangfei Gao 	for (i = 0; readl_relaxed(base + MDIO_SINGLE_CMD) & MDIO_START; i++) {
92557c5bc9aSZhangfei Gao 		if (i == timeout)
92657c5bc9aSZhangfei Gao 			return -ETIMEDOUT;
92757c5bc9aSZhangfei Gao 		usleep_range(10, 20);
92857c5bc9aSZhangfei Gao 	}
92957c5bc9aSZhangfei Gao 
93057c5bc9aSZhangfei Gao 	return 0;
93157c5bc9aSZhangfei Gao }
93257c5bc9aSZhangfei Gao 
hix5hd2_mdio_read(struct mii_bus * bus,int phy,int reg)93357c5bc9aSZhangfei Gao static int hix5hd2_mdio_read(struct mii_bus *bus, int phy, int reg)
93457c5bc9aSZhangfei Gao {
93557c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = bus->priv;
93657c5bc9aSZhangfei Gao 	void __iomem *base = priv->base;
93757c5bc9aSZhangfei Gao 	int val, ret;
93857c5bc9aSZhangfei Gao 
93957c5bc9aSZhangfei Gao 	ret = hix5hd2_mdio_wait_ready(bus);
94057c5bc9aSZhangfei Gao 	if (ret < 0)
94157c5bc9aSZhangfei Gao 		goto out;
94257c5bc9aSZhangfei Gao 
94357c5bc9aSZhangfei Gao 	writel_relaxed(MDIO_READ | phy << 8 | reg, base + MDIO_SINGLE_CMD);
94457c5bc9aSZhangfei Gao 	ret = hix5hd2_mdio_wait_ready(bus);
94557c5bc9aSZhangfei Gao 	if (ret < 0)
94657c5bc9aSZhangfei Gao 		goto out;
94757c5bc9aSZhangfei Gao 
94857c5bc9aSZhangfei Gao 	val = readl_relaxed(base + MDIO_RDATA_STATUS);
94957c5bc9aSZhangfei Gao 	if (val & MDIO_R_VALID) {
95057c5bc9aSZhangfei Gao 		dev_err(bus->parent, "SMI bus read not valid\n");
95157c5bc9aSZhangfei Gao 		ret = -ENODEV;
95257c5bc9aSZhangfei Gao 		goto out;
95357c5bc9aSZhangfei Gao 	}
95457c5bc9aSZhangfei Gao 
95557c5bc9aSZhangfei Gao 	val = readl_relaxed(priv->base + MDIO_SINGLE_DATA);
95657c5bc9aSZhangfei Gao 	ret = (val >> 16) & 0xFFFF;
95757c5bc9aSZhangfei Gao out:
95857c5bc9aSZhangfei Gao 	return ret;
95957c5bc9aSZhangfei Gao }
96057c5bc9aSZhangfei Gao 
hix5hd2_mdio_write(struct mii_bus * bus,int phy,int reg,u16 val)96157c5bc9aSZhangfei Gao static int hix5hd2_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
96257c5bc9aSZhangfei Gao {
96357c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = bus->priv;
96457c5bc9aSZhangfei Gao 	void __iomem *base = priv->base;
96557c5bc9aSZhangfei Gao 	int ret;
96657c5bc9aSZhangfei Gao 
96757c5bc9aSZhangfei Gao 	ret = hix5hd2_mdio_wait_ready(bus);
96857c5bc9aSZhangfei Gao 	if (ret < 0)
96957c5bc9aSZhangfei Gao 		goto out;
97057c5bc9aSZhangfei Gao 
97157c5bc9aSZhangfei Gao 	writel_relaxed(val, base + MDIO_SINGLE_DATA);
97257c5bc9aSZhangfei Gao 	writel_relaxed(MDIO_WRITE | phy << 8 | reg, base + MDIO_SINGLE_CMD);
97357c5bc9aSZhangfei Gao 	ret = hix5hd2_mdio_wait_ready(bus);
97457c5bc9aSZhangfei Gao out:
97557c5bc9aSZhangfei Gao 	return ret;
97657c5bc9aSZhangfei Gao }
97757c5bc9aSZhangfei Gao 
hix5hd2_destroy_hw_desc_queue(struct hix5hd2_priv * priv)97857c5bc9aSZhangfei Gao static void hix5hd2_destroy_hw_desc_queue(struct hix5hd2_priv *priv)
97957c5bc9aSZhangfei Gao {
98057c5bc9aSZhangfei Gao 	int i;
98157c5bc9aSZhangfei Gao 
98257c5bc9aSZhangfei Gao 	for (i = 0; i < QUEUE_NUMS; i++) {
98357c5bc9aSZhangfei Gao 		if (priv->pool[i].desc) {
98457c5bc9aSZhangfei Gao 			dma_free_coherent(priv->dev, priv->pool[i].size,
98557c5bc9aSZhangfei Gao 					  priv->pool[i].desc,
98657c5bc9aSZhangfei Gao 					  priv->pool[i].phys_addr);
98757c5bc9aSZhangfei Gao 			priv->pool[i].desc = NULL;
98857c5bc9aSZhangfei Gao 		}
98957c5bc9aSZhangfei Gao 	}
99057c5bc9aSZhangfei Gao }
99157c5bc9aSZhangfei Gao 
hix5hd2_init_hw_desc_queue(struct hix5hd2_priv * priv)99257c5bc9aSZhangfei Gao static int hix5hd2_init_hw_desc_queue(struct hix5hd2_priv *priv)
99357c5bc9aSZhangfei Gao {
99457c5bc9aSZhangfei Gao 	struct device *dev = priv->dev;
99557c5bc9aSZhangfei Gao 	struct hix5hd2_desc *virt_addr;
99657c5bc9aSZhangfei Gao 	dma_addr_t phys_addr;
99757c5bc9aSZhangfei Gao 	int size, i;
99857c5bc9aSZhangfei Gao 
99957c5bc9aSZhangfei Gao 	priv->rx_fq.count = RX_DESC_NUM;
100057c5bc9aSZhangfei Gao 	priv->rx_bq.count = RX_DESC_NUM;
100157c5bc9aSZhangfei Gao 	priv->tx_bq.count = TX_DESC_NUM;
100257c5bc9aSZhangfei Gao 	priv->tx_rq.count = TX_DESC_NUM;
100357c5bc9aSZhangfei Gao 
100457c5bc9aSZhangfei Gao 	for (i = 0; i < QUEUE_NUMS; i++) {
100557c5bc9aSZhangfei Gao 		size = priv->pool[i].count * sizeof(struct hix5hd2_desc);
1006750afb08SLuis Chamberlain 		virt_addr = dma_alloc_coherent(dev, size, &phys_addr,
100757c5bc9aSZhangfei Gao 					       GFP_KERNEL);
100857c5bc9aSZhangfei Gao 		if (virt_addr == NULL)
100957c5bc9aSZhangfei Gao 			goto error_free_pool;
101057c5bc9aSZhangfei Gao 
101157c5bc9aSZhangfei Gao 		priv->pool[i].size = size;
101257c5bc9aSZhangfei Gao 		priv->pool[i].desc = virt_addr;
101357c5bc9aSZhangfei Gao 		priv->pool[i].phys_addr = phys_addr;
101457c5bc9aSZhangfei Gao 	}
101557c5bc9aSZhangfei Gao 	return 0;
101657c5bc9aSZhangfei Gao 
101757c5bc9aSZhangfei Gao error_free_pool:
101857c5bc9aSZhangfei Gao 	hix5hd2_destroy_hw_desc_queue(priv);
101957c5bc9aSZhangfei Gao 
102057c5bc9aSZhangfei Gao 	return -ENOMEM;
102157c5bc9aSZhangfei Gao }
102257c5bc9aSZhangfei Gao 
hix5hd2_init_sg_desc_queue(struct hix5hd2_priv * priv)1023e5222b1cSDongpo Li static int hix5hd2_init_sg_desc_queue(struct hix5hd2_priv *priv)
1024e5222b1cSDongpo Li {
1025e5222b1cSDongpo Li 	struct sg_desc *desc;
1026e5222b1cSDongpo Li 	dma_addr_t phys_addr;
1027e5222b1cSDongpo Li 
10289b964f16SWang Hai 	desc = dma_alloc_coherent(priv->dev,
1029e5222b1cSDongpo Li 				  TX_DESC_NUM * sizeof(struct sg_desc),
1030e5222b1cSDongpo Li 				  &phys_addr, GFP_KERNEL);
1031e5222b1cSDongpo Li 	if (!desc)
1032e5222b1cSDongpo Li 		return -ENOMEM;
1033e5222b1cSDongpo Li 
1034e5222b1cSDongpo Li 	priv->tx_ring.desc = desc;
1035e5222b1cSDongpo Li 	priv->tx_ring.phys_addr = phys_addr;
1036e5222b1cSDongpo Li 
1037e5222b1cSDongpo Li 	return 0;
1038e5222b1cSDongpo Li }
1039e5222b1cSDongpo Li 
hix5hd2_destroy_sg_desc_queue(struct hix5hd2_priv * priv)1040e5222b1cSDongpo Li static void hix5hd2_destroy_sg_desc_queue(struct hix5hd2_priv *priv)
1041e5222b1cSDongpo Li {
1042e5222b1cSDongpo Li 	if (priv->tx_ring.desc) {
1043e5222b1cSDongpo Li 		dma_free_coherent(priv->dev,
1044e5222b1cSDongpo Li 				  TX_DESC_NUM * sizeof(struct sg_desc),
1045e5222b1cSDongpo Li 				  priv->tx_ring.desc, priv->tx_ring.phys_addr);
1046e5222b1cSDongpo Li 		priv->tx_ring.desc = NULL;
1047e5222b1cSDongpo Li 	}
1048e5222b1cSDongpo Li }
1049e5222b1cSDongpo Li 
hix5hd2_mac_core_reset(struct hix5hd2_priv * priv)10507087140dSDongpo Li static inline void hix5hd2_mac_core_reset(struct hix5hd2_priv *priv)
10517087140dSDongpo Li {
10527087140dSDongpo Li 	if (!priv->mac_core_rst)
10537087140dSDongpo Li 		return;
10547087140dSDongpo Li 
10557087140dSDongpo Li 	reset_control_assert(priv->mac_core_rst);
10567087140dSDongpo Li 	reset_control_deassert(priv->mac_core_rst);
10577087140dSDongpo Li }
10587087140dSDongpo Li 
hix5hd2_sleep_us(u32 time_us)10597087140dSDongpo Li static void hix5hd2_sleep_us(u32 time_us)
10607087140dSDongpo Li {
10617087140dSDongpo Li 	u32 time_ms;
10627087140dSDongpo Li 
10637087140dSDongpo Li 	if (!time_us)
10647087140dSDongpo Li 		return;
10657087140dSDongpo Li 
10667087140dSDongpo Li 	time_ms = DIV_ROUND_UP(time_us, 1000);
10677087140dSDongpo Li 	if (time_ms < 20)
10687087140dSDongpo Li 		usleep_range(time_us, time_us + 500);
10697087140dSDongpo Li 	else
10707087140dSDongpo Li 		msleep(time_ms);
10717087140dSDongpo Li }
10727087140dSDongpo Li 
hix5hd2_phy_reset(struct hix5hd2_priv * priv)10737087140dSDongpo Li static void hix5hd2_phy_reset(struct hix5hd2_priv *priv)
10747087140dSDongpo Li {
10757087140dSDongpo Li 	/* To make sure PHY hardware reset success,
10767087140dSDongpo Li 	 * we must keep PHY in deassert state first and
10777087140dSDongpo Li 	 * then complete the hardware reset operation
10787087140dSDongpo Li 	 */
10797087140dSDongpo Li 	reset_control_deassert(priv->phy_rst);
10807087140dSDongpo Li 	hix5hd2_sleep_us(priv->phy_reset_delays[PRE_DELAY]);
10817087140dSDongpo Li 
10827087140dSDongpo Li 	reset_control_assert(priv->phy_rst);
10837087140dSDongpo Li 	/* delay some time to ensure reset ok,
10847087140dSDongpo Li 	 * this depends on PHY hardware feature
10857087140dSDongpo Li 	 */
10867087140dSDongpo Li 	hix5hd2_sleep_us(priv->phy_reset_delays[PULSE]);
10877087140dSDongpo Li 	reset_control_deassert(priv->phy_rst);
10887087140dSDongpo Li 	/* delay some time to ensure later MDIO access */
10897087140dSDongpo Li 	hix5hd2_sleep_us(priv->phy_reset_delays[POST_DELAY]);
10907087140dSDongpo Li }
10917087140dSDongpo Li 
1092e5222b1cSDongpo Li static const struct of_device_id hix5hd2_of_match[];
1093e5222b1cSDongpo Li 
hix5hd2_dev_probe(struct platform_device * pdev)109457c5bc9aSZhangfei Gao static int hix5hd2_dev_probe(struct platform_device *pdev)
109557c5bc9aSZhangfei Gao {
109657c5bc9aSZhangfei Gao 	struct device *dev = &pdev->dev;
109757c5bc9aSZhangfei Gao 	struct device_node *node = dev->of_node;
109857c5bc9aSZhangfei Gao 	struct net_device *ndev;
109957c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv;
110057c5bc9aSZhangfei Gao 	struct mii_bus *bus;
110157c5bc9aSZhangfei Gao 	int ret;
110257c5bc9aSZhangfei Gao 
110357c5bc9aSZhangfei Gao 	ndev = alloc_etherdev(sizeof(struct hix5hd2_priv));
110457c5bc9aSZhangfei Gao 	if (!ndev)
110557c5bc9aSZhangfei Gao 		return -ENOMEM;
110657c5bc9aSZhangfei Gao 
110757c5bc9aSZhangfei Gao 	platform_set_drvdata(pdev, ndev);
110857c5bc9aSZhangfei Gao 
110957c5bc9aSZhangfei Gao 	priv = netdev_priv(ndev);
111057c5bc9aSZhangfei Gao 	priv->dev = dev;
111157c5bc9aSZhangfei Gao 	priv->netdev = ndev;
111257c5bc9aSZhangfei Gao 
1113b0377116SRob Herring 	priv->hw_cap = (unsigned long)device_get_match_data(dev);
1114e5222b1cSDongpo Li 
111556170ba3SJiangfeng Xiao 	priv->base = devm_platform_ioremap_resource(pdev, 0);
111657c5bc9aSZhangfei Gao 	if (IS_ERR(priv->base)) {
111757c5bc9aSZhangfei Gao 		ret = PTR_ERR(priv->base);
111857c5bc9aSZhangfei Gao 		goto out_free_netdev;
111957c5bc9aSZhangfei Gao 	}
112057c5bc9aSZhangfei Gao 
112156170ba3SJiangfeng Xiao 	priv->ctrl_base = devm_platform_ioremap_resource(pdev, 1);
112257c5bc9aSZhangfei Gao 	if (IS_ERR(priv->ctrl_base)) {
112357c5bc9aSZhangfei Gao 		ret = PTR_ERR(priv->ctrl_base);
112457c5bc9aSZhangfei Gao 		goto out_free_netdev;
112557c5bc9aSZhangfei Gao 	}
112657c5bc9aSZhangfei Gao 
11277087140dSDongpo Li 	priv->mac_core_clk = devm_clk_get(&pdev->dev, "mac_core");
11287087140dSDongpo Li 	if (IS_ERR(priv->mac_core_clk)) {
11297087140dSDongpo Li 		netdev_err(ndev, "failed to get mac core clk\n");
113057c5bc9aSZhangfei Gao 		ret = -ENODEV;
113157c5bc9aSZhangfei Gao 		goto out_free_netdev;
113257c5bc9aSZhangfei Gao 	}
113357c5bc9aSZhangfei Gao 
11347087140dSDongpo Li 	ret = clk_prepare_enable(priv->mac_core_clk);
113557c5bc9aSZhangfei Gao 	if (ret < 0) {
11367087140dSDongpo Li 		netdev_err(ndev, "failed to enable mac core clk %d\n", ret);
113757c5bc9aSZhangfei Gao 		goto out_free_netdev;
113857c5bc9aSZhangfei Gao 	}
113957c5bc9aSZhangfei Gao 
11407087140dSDongpo Li 	priv->mac_ifc_clk = devm_clk_get(&pdev->dev, "mac_ifc");
11417087140dSDongpo Li 	if (IS_ERR(priv->mac_ifc_clk))
11427087140dSDongpo Li 		priv->mac_ifc_clk = NULL;
11437087140dSDongpo Li 
11447087140dSDongpo Li 	ret = clk_prepare_enable(priv->mac_ifc_clk);
11457087140dSDongpo Li 	if (ret < 0) {
11467087140dSDongpo Li 		netdev_err(ndev, "failed to enable mac ifc clk %d\n", ret);
11477087140dSDongpo Li 		goto out_disable_mac_core_clk;
11487087140dSDongpo Li 	}
11497087140dSDongpo Li 
11507087140dSDongpo Li 	priv->mac_core_rst = devm_reset_control_get(dev, "mac_core");
11517087140dSDongpo Li 	if (IS_ERR(priv->mac_core_rst))
11527087140dSDongpo Li 		priv->mac_core_rst = NULL;
11537087140dSDongpo Li 	hix5hd2_mac_core_reset(priv);
11547087140dSDongpo Li 
11557087140dSDongpo Li 	priv->mac_ifc_rst = devm_reset_control_get(dev, "mac_ifc");
11567087140dSDongpo Li 	if (IS_ERR(priv->mac_ifc_rst))
11577087140dSDongpo Li 		priv->mac_ifc_rst = NULL;
11587087140dSDongpo Li 
11597087140dSDongpo Li 	priv->phy_rst = devm_reset_control_get(dev, "phy");
11607087140dSDongpo Li 	if (IS_ERR(priv->phy_rst)) {
11617087140dSDongpo Li 		priv->phy_rst = NULL;
11627087140dSDongpo Li 	} else {
11637087140dSDongpo Li 		ret = of_property_read_u32_array(node,
11647087140dSDongpo Li 						 PHY_RESET_DELAYS_PROPERTY,
11657087140dSDongpo Li 						 priv->phy_reset_delays,
11667087140dSDongpo Li 						 DELAYS_NUM);
11677087140dSDongpo Li 		if (ret)
11687087140dSDongpo Li 			goto out_disable_clk;
11697087140dSDongpo Li 		hix5hd2_phy_reset(priv);
11707087140dSDongpo Li 	}
11717087140dSDongpo Li 
117257c5bc9aSZhangfei Gao 	bus = mdiobus_alloc();
117357c5bc9aSZhangfei Gao 	if (bus == NULL) {
117457c5bc9aSZhangfei Gao 		ret = -ENOMEM;
11757087140dSDongpo Li 		goto out_disable_clk;
117657c5bc9aSZhangfei Gao 	}
117757c5bc9aSZhangfei Gao 
117857c5bc9aSZhangfei Gao 	bus->priv = priv;
117957c5bc9aSZhangfei Gao 	bus->name = "hix5hd2_mii_bus";
118057c5bc9aSZhangfei Gao 	bus->read = hix5hd2_mdio_read;
118157c5bc9aSZhangfei Gao 	bus->write = hix5hd2_mdio_write;
118257c5bc9aSZhangfei Gao 	bus->parent = &pdev->dev;
118357c5bc9aSZhangfei Gao 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
118457c5bc9aSZhangfei Gao 	priv->bus = bus;
118557c5bc9aSZhangfei Gao 
118657c5bc9aSZhangfei Gao 	ret = of_mdiobus_register(bus, node);
118757c5bc9aSZhangfei Gao 	if (ret)
118857c5bc9aSZhangfei Gao 		goto err_free_mdio;
118957c5bc9aSZhangfei Gao 
11900c65b2b9SAndrew Lunn 	ret = of_get_phy_mode(node, &priv->phy_mode);
11910c65b2b9SAndrew Lunn 	if (ret) {
119257c5bc9aSZhangfei Gao 		netdev_err(ndev, "not find phy-mode\n");
119357c5bc9aSZhangfei Gao 		goto err_mdiobus;
119457c5bc9aSZhangfei Gao 	}
119557c5bc9aSZhangfei Gao 
119657c5bc9aSZhangfei Gao 	priv->phy_node = of_parse_phandle(node, "phy-handle", 0);
119757c5bc9aSZhangfei Gao 	if (!priv->phy_node) {
119857c5bc9aSZhangfei Gao 		netdev_err(ndev, "not find phy-handle\n");
119957c5bc9aSZhangfei Gao 		ret = -EINVAL;
120057c5bc9aSZhangfei Gao 		goto err_mdiobus;
120157c5bc9aSZhangfei Gao 	}
120257c5bc9aSZhangfei Gao 
120357c5bc9aSZhangfei Gao 	ndev->irq = platform_get_irq(pdev, 0);
1204ae1d60c4SRuan Jinjie 	if (ndev->irq < 0) {
1205ae1d60c4SRuan Jinjie 		ret = ndev->irq;
120657c5bc9aSZhangfei Gao 		goto out_phy_node;
120757c5bc9aSZhangfei Gao 	}
120857c5bc9aSZhangfei Gao 
120957c5bc9aSZhangfei Gao 	ret = devm_request_irq(dev, ndev->irq, hix5hd2_interrupt,
121057c5bc9aSZhangfei Gao 			       0, pdev->name, ndev);
121157c5bc9aSZhangfei Gao 	if (ret) {
121257c5bc9aSZhangfei Gao 		netdev_err(ndev, "devm_request_irq failed\n");
121357c5bc9aSZhangfei Gao 		goto out_phy_node;
121457c5bc9aSZhangfei Gao 	}
121557c5bc9aSZhangfei Gao 
12169ca01b25SJakub Kicinski 	ret = of_get_ethdev_address(node, ndev);
121783216e39SMichael Walle 	if (ret) {
121857c5bc9aSZhangfei Gao 		eth_hw_addr_random(ndev);
121957c5bc9aSZhangfei Gao 		netdev_warn(ndev, "using random MAC address %pM\n",
122057c5bc9aSZhangfei Gao 			    ndev->dev_addr);
122157c5bc9aSZhangfei Gao 	}
122257c5bc9aSZhangfei Gao 
122357c5bc9aSZhangfei Gao 	INIT_WORK(&priv->tx_timeout_task, hix5hd2_tx_timeout_task);
122457c5bc9aSZhangfei Gao 	ndev->watchdog_timeo = 6 * HZ;
122557c5bc9aSZhangfei Gao 	ndev->priv_flags |= IFF_UNICAST_FLT;
122657c5bc9aSZhangfei Gao 	ndev->netdev_ops = &hix5hd2_netdev_ops;
122757c5bc9aSZhangfei Gao 	ndev->ethtool_ops = &hix5hd2_ethtools_ops;
122857c5bc9aSZhangfei Gao 	SET_NETDEV_DEV(ndev, dev);
122957c5bc9aSZhangfei Gao 
1230e5222b1cSDongpo Li 	if (HAS_CAP_TSO(priv->hw_cap))
1231e5222b1cSDongpo Li 		ndev->hw_features |= NETIF_F_SG;
1232e5222b1cSDongpo Li 
1233e5222b1cSDongpo Li 	ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
1234e5222b1cSDongpo Li 	ndev->vlan_features |= ndev->features;
1235e5222b1cSDongpo Li 
123657c5bc9aSZhangfei Gao 	ret = hix5hd2_init_hw_desc_queue(priv);
123757c5bc9aSZhangfei Gao 	if (ret)
123857c5bc9aSZhangfei Gao 		goto out_phy_node;
123957c5bc9aSZhangfei Gao 
1240b48b89f9SJakub Kicinski 	netif_napi_add(ndev, &priv->napi, hix5hd2_poll);
1241e5222b1cSDongpo Li 
1242e5222b1cSDongpo Li 	if (HAS_CAP_TSO(priv->hw_cap)) {
1243e5222b1cSDongpo Li 		ret = hix5hd2_init_sg_desc_queue(priv);
1244e5222b1cSDongpo Li 		if (ret)
1245e5222b1cSDongpo Li 			goto out_destroy_queue;
1246e5222b1cSDongpo Li 	}
1247e5222b1cSDongpo Li 
124857c5bc9aSZhangfei Gao 	ret = register_netdev(priv->netdev);
124957c5bc9aSZhangfei Gao 	if (ret) {
125057c5bc9aSZhangfei Gao 		netdev_err(ndev, "register_netdev failed!");
125157c5bc9aSZhangfei Gao 		goto out_destroy_queue;
125257c5bc9aSZhangfei Gao 	}
125357c5bc9aSZhangfei Gao 
12547087140dSDongpo Li 	clk_disable_unprepare(priv->mac_ifc_clk);
12557087140dSDongpo Li 	clk_disable_unprepare(priv->mac_core_clk);
125657c5bc9aSZhangfei Gao 
125757c5bc9aSZhangfei Gao 	return ret;
125857c5bc9aSZhangfei Gao 
125957c5bc9aSZhangfei Gao out_destroy_queue:
1260e5222b1cSDongpo Li 	if (HAS_CAP_TSO(priv->hw_cap))
1261e5222b1cSDongpo Li 		hix5hd2_destroy_sg_desc_queue(priv);
126257c5bc9aSZhangfei Gao 	netif_napi_del(&priv->napi);
126357c5bc9aSZhangfei Gao 	hix5hd2_destroy_hw_desc_queue(priv);
126457c5bc9aSZhangfei Gao out_phy_node:
126557c5bc9aSZhangfei Gao 	of_node_put(priv->phy_node);
126657c5bc9aSZhangfei Gao err_mdiobus:
126757c5bc9aSZhangfei Gao 	mdiobus_unregister(bus);
126857c5bc9aSZhangfei Gao err_free_mdio:
126957c5bc9aSZhangfei Gao 	mdiobus_free(bus);
12707087140dSDongpo Li out_disable_clk:
12717087140dSDongpo Li 	clk_disable_unprepare(priv->mac_ifc_clk);
12727087140dSDongpo Li out_disable_mac_core_clk:
12737087140dSDongpo Li 	clk_disable_unprepare(priv->mac_core_clk);
127457c5bc9aSZhangfei Gao out_free_netdev:
127557c5bc9aSZhangfei Gao 	free_netdev(ndev);
127657c5bc9aSZhangfei Gao 
127757c5bc9aSZhangfei Gao 	return ret;
127857c5bc9aSZhangfei Gao }
127957c5bc9aSZhangfei Gao 
hix5hd2_dev_remove(struct platform_device * pdev)1280e5835a0aSUwe Kleine-König static void hix5hd2_dev_remove(struct platform_device *pdev)
128157c5bc9aSZhangfei Gao {
128257c5bc9aSZhangfei Gao 	struct net_device *ndev = platform_get_drvdata(pdev);
128357c5bc9aSZhangfei Gao 	struct hix5hd2_priv *priv = netdev_priv(ndev);
128457c5bc9aSZhangfei Gao 
128557c5bc9aSZhangfei Gao 	netif_napi_del(&priv->napi);
128657c5bc9aSZhangfei Gao 	unregister_netdev(ndev);
128757c5bc9aSZhangfei Gao 	mdiobus_unregister(priv->bus);
128857c5bc9aSZhangfei Gao 	mdiobus_free(priv->bus);
128957c5bc9aSZhangfei Gao 
1290e5222b1cSDongpo Li 	if (HAS_CAP_TSO(priv->hw_cap))
1291e5222b1cSDongpo Li 		hix5hd2_destroy_sg_desc_queue(priv);
129257c5bc9aSZhangfei Gao 	hix5hd2_destroy_hw_desc_queue(priv);
129357c5bc9aSZhangfei Gao 	of_node_put(priv->phy_node);
129457c5bc9aSZhangfei Gao 	cancel_work_sync(&priv->tx_timeout_task);
129557c5bc9aSZhangfei Gao 	free_netdev(ndev);
129657c5bc9aSZhangfei Gao }
129757c5bc9aSZhangfei Gao 
129857c5bc9aSZhangfei Gao static const struct of_device_id hix5hd2_of_match[] = {
1299f7ca8e3bSDongpo Li 	{ .compatible = "hisilicon,hisi-gmac-v1", .data = (void *)GEMAC_V1 },
1300f7ca8e3bSDongpo Li 	{ .compatible = "hisilicon,hisi-gmac-v2", .data = (void *)GEMAC_V2 },
1301f7ca8e3bSDongpo Li 	{ .compatible = "hisilicon,hix5hd2-gmac", .data = (void *)GEMAC_V1 },
1302f7ca8e3bSDongpo Li 	{ .compatible = "hisilicon,hi3798cv200-gmac", .data = (void *)GEMAC_V2 },
1303f7ca8e3bSDongpo Li 	{ .compatible = "hisilicon,hi3516a-gmac", .data = (void *)GEMAC_V2 },
130457c5bc9aSZhangfei Gao 	{},
130557c5bc9aSZhangfei Gao };
130657c5bc9aSZhangfei Gao 
130757c5bc9aSZhangfei Gao MODULE_DEVICE_TABLE(of, hix5hd2_of_match);
130857c5bc9aSZhangfei Gao 
130957c5bc9aSZhangfei Gao static struct platform_driver hix5hd2_dev_driver = {
131057c5bc9aSZhangfei Gao 	.driver = {
1311f7ca8e3bSDongpo Li 		.name = "hisi-gmac",
131257c5bc9aSZhangfei Gao 		.of_match_table = hix5hd2_of_match,
131357c5bc9aSZhangfei Gao 	},
131457c5bc9aSZhangfei Gao 	.probe = hix5hd2_dev_probe,
1315*e96321faSUwe Kleine-König 	.remove = hix5hd2_dev_remove,
131657c5bc9aSZhangfei Gao };
131757c5bc9aSZhangfei Gao 
131857c5bc9aSZhangfei Gao module_platform_driver(hix5hd2_dev_driver);
131957c5bc9aSZhangfei Gao 
1320d0fb6ba7SDongpo Li MODULE_DESCRIPTION("HISILICON Gigabit Ethernet MAC driver");
132157c5bc9aSZhangfei Gao MODULE_LICENSE("GPL v2");
1322f7ca8e3bSDongpo Li MODULE_ALIAS("platform:hisi-gmac");
1323