xref: /openbmc/linux/drivers/net/ethernet/hisilicon/hisi_femac.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2542ae60aSDongpo Li /*
3542ae60aSDongpo Li  * Hisilicon Fast Ethernet MAC Driver
4542ae60aSDongpo Li  *
5542ae60aSDongpo Li  * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
6542ae60aSDongpo Li  */
7542ae60aSDongpo Li 
8542ae60aSDongpo Li #include <linux/circ_buf.h>
9542ae60aSDongpo Li #include <linux/clk.h>
10542ae60aSDongpo Li #include <linux/etherdevice.h>
11542ae60aSDongpo Li #include <linux/interrupt.h>
12542ae60aSDongpo Li #include <linux/module.h>
13542ae60aSDongpo Li #include <linux/of_mdio.h>
14542ae60aSDongpo Li #include <linux/of_net.h>
15542ae60aSDongpo Li #include <linux/platform_device.h>
16542ae60aSDongpo Li #include <linux/reset.h>
17542ae60aSDongpo Li 
18542ae60aSDongpo Li /* MAC control register list */
19542ae60aSDongpo Li #define MAC_PORTSEL			0x0200
20542ae60aSDongpo Li #define MAC_PORTSEL_STAT_CPU		BIT(0)
21542ae60aSDongpo Li #define MAC_PORTSEL_RMII		BIT(1)
22542ae60aSDongpo Li #define MAC_PORTSET			0x0208
23542ae60aSDongpo Li #define MAC_PORTSET_DUPLEX_FULL		BIT(0)
24542ae60aSDongpo Li #define MAC_PORTSET_LINKED		BIT(1)
25542ae60aSDongpo Li #define MAC_PORTSET_SPEED_100M		BIT(2)
26542ae60aSDongpo Li #define MAC_SET				0x0210
27542ae60aSDongpo Li #define MAX_FRAME_SIZE			1600
28542ae60aSDongpo Li #define MAX_FRAME_SIZE_MASK		GENMASK(10, 0)
29542ae60aSDongpo Li #define BIT_PAUSE_EN			BIT(18)
30542ae60aSDongpo Li #define RX_COALESCE_SET			0x0340
31542ae60aSDongpo Li #define RX_COALESCED_FRAME_OFFSET	24
32542ae60aSDongpo Li #define RX_COALESCED_FRAMES		8
33542ae60aSDongpo Li #define RX_COALESCED_TIMER		0x74
34542ae60aSDongpo Li #define QLEN_SET			0x0344
35542ae60aSDongpo Li #define RX_DEPTH_OFFSET			8
36542ae60aSDongpo Li #define MAX_HW_FIFO_DEPTH		64
37542ae60aSDongpo Li #define HW_TX_FIFO_DEPTH		12
38542ae60aSDongpo Li #define HW_RX_FIFO_DEPTH		(MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH)
39542ae60aSDongpo Li #define IQFRM_DES			0x0354
40542ae60aSDongpo Li #define RX_FRAME_LEN_MASK		GENMASK(11, 0)
41542ae60aSDongpo Li #define IQ_ADDR				0x0358
42542ae60aSDongpo Li #define EQ_ADDR				0x0360
43542ae60aSDongpo Li #define EQFRM_LEN			0x0364
44542ae60aSDongpo Li #define ADDRQ_STAT			0x036C
45542ae60aSDongpo Li #define TX_CNT_INUSE_MASK		GENMASK(5, 0)
46542ae60aSDongpo Li #define BIT_TX_READY			BIT(24)
47542ae60aSDongpo Li #define BIT_RX_READY			BIT(25)
48542ae60aSDongpo Li /* global control register list */
49542ae60aSDongpo Li #define GLB_HOSTMAC_L32			0x0000
50542ae60aSDongpo Li #define GLB_HOSTMAC_H16			0x0004
51542ae60aSDongpo Li #define GLB_SOFT_RESET			0x0008
52542ae60aSDongpo Li #define SOFT_RESET_ALL			BIT(0)
53542ae60aSDongpo Li #define GLB_FWCTRL			0x0010
54542ae60aSDongpo Li #define FWCTRL_VLAN_ENABLE		BIT(0)
55542ae60aSDongpo Li #define FWCTRL_FW2CPU_ENA		BIT(5)
56542ae60aSDongpo Li #define FWCTRL_FWALL2CPU		BIT(7)
57542ae60aSDongpo Li #define GLB_MACTCTRL			0x0014
58542ae60aSDongpo Li #define MACTCTRL_UNI2CPU		BIT(1)
59542ae60aSDongpo Li #define MACTCTRL_MULTI2CPU		BIT(3)
60542ae60aSDongpo Li #define MACTCTRL_BROAD2CPU		BIT(5)
61542ae60aSDongpo Li #define MACTCTRL_MACT_ENA		BIT(7)
62542ae60aSDongpo Li #define GLB_IRQ_STAT			0x0030
63542ae60aSDongpo Li #define GLB_IRQ_ENA			0x0034
64542ae60aSDongpo Li #define IRQ_ENA_PORT0_MASK		GENMASK(7, 0)
65542ae60aSDongpo Li #define IRQ_ENA_PORT0			BIT(18)
66542ae60aSDongpo Li #define IRQ_ENA_ALL			BIT(19)
67542ae60aSDongpo Li #define GLB_IRQ_RAW			0x0038
68542ae60aSDongpo Li #define IRQ_INT_RX_RDY			BIT(0)
69542ae60aSDongpo Li #define IRQ_INT_TX_PER_PACKET		BIT(1)
70542ae60aSDongpo Li #define IRQ_INT_TX_FIFO_EMPTY		BIT(6)
71542ae60aSDongpo Li #define IRQ_INT_MULTI_RXRDY		BIT(7)
72542ae60aSDongpo Li #define DEF_INT_MASK			(IRQ_INT_MULTI_RXRDY | \
73542ae60aSDongpo Li 					IRQ_INT_TX_PER_PACKET | \
74542ae60aSDongpo Li 					IRQ_INT_TX_FIFO_EMPTY)
75542ae60aSDongpo Li #define GLB_MAC_L32_BASE		0x0100
76542ae60aSDongpo Li #define GLB_MAC_H16_BASE		0x0104
77542ae60aSDongpo Li #define MACFLT_HI16_MASK		GENMASK(15, 0)
78542ae60aSDongpo Li #define BIT_MACFLT_ENA			BIT(17)
79542ae60aSDongpo Li #define BIT_MACFLT_FW2CPU		BIT(21)
80542ae60aSDongpo Li #define GLB_MAC_H16(reg)		(GLB_MAC_H16_BASE + ((reg) * 0x8))
81542ae60aSDongpo Li #define GLB_MAC_L32(reg)		(GLB_MAC_L32_BASE + ((reg) * 0x8))
82542ae60aSDongpo Li #define MAX_MAC_FILTER_NUM		8
83542ae60aSDongpo Li #define MAX_UNICAST_ADDRESSES		2
84542ae60aSDongpo Li #define MAX_MULTICAST_ADDRESSES		(MAX_MAC_FILTER_NUM - \
85542ae60aSDongpo Li 					MAX_UNICAST_ADDRESSES)
86542ae60aSDongpo Li /* software tx and rx queue number, should be power of 2 */
87542ae60aSDongpo Li #define TXQ_NUM				64
88542ae60aSDongpo Li #define RXQ_NUM				128
89542ae60aSDongpo Li #define FEMAC_POLL_WEIGHT		16
90542ae60aSDongpo Li 
91542ae60aSDongpo Li #define PHY_RESET_DELAYS_PROPERTY	"hisilicon,phy-reset-delays-us"
92542ae60aSDongpo Li 
93542ae60aSDongpo Li enum phy_reset_delays {
94542ae60aSDongpo Li 	PRE_DELAY,
95542ae60aSDongpo Li 	PULSE,
96542ae60aSDongpo Li 	POST_DELAY,
97542ae60aSDongpo Li 	DELAYS_NUM,
98542ae60aSDongpo Li };
99542ae60aSDongpo Li 
100542ae60aSDongpo Li struct hisi_femac_queue {
101542ae60aSDongpo Li 	struct sk_buff **skb;
102542ae60aSDongpo Li 	dma_addr_t *dma_phys;
103542ae60aSDongpo Li 	int num;
104542ae60aSDongpo Li 	unsigned int head;
105542ae60aSDongpo Li 	unsigned int tail;
106542ae60aSDongpo Li };
107542ae60aSDongpo Li 
108542ae60aSDongpo Li struct hisi_femac_priv {
109542ae60aSDongpo Li 	void __iomem *port_base;
110542ae60aSDongpo Li 	void __iomem *glb_base;
111542ae60aSDongpo Li 	struct clk *clk;
112542ae60aSDongpo Li 	struct reset_control *mac_rst;
113542ae60aSDongpo Li 	struct reset_control *phy_rst;
114542ae60aSDongpo Li 	u32 phy_reset_delays[DELAYS_NUM];
115542ae60aSDongpo Li 	u32 link_status;
116542ae60aSDongpo Li 
117542ae60aSDongpo Li 	struct device *dev;
118542ae60aSDongpo Li 	struct net_device *ndev;
119542ae60aSDongpo Li 
120542ae60aSDongpo Li 	struct hisi_femac_queue txq;
121542ae60aSDongpo Li 	struct hisi_femac_queue rxq;
122542ae60aSDongpo Li 	u32 tx_fifo_used_cnt;
123542ae60aSDongpo Li 	struct napi_struct napi;
124542ae60aSDongpo Li };
125542ae60aSDongpo Li 
hisi_femac_irq_enable(struct hisi_femac_priv * priv,int irqs)126542ae60aSDongpo Li static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs)
127542ae60aSDongpo Li {
128542ae60aSDongpo Li 	u32 val;
129542ae60aSDongpo Li 
130542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_IRQ_ENA);
131542ae60aSDongpo Li 	writel(val | irqs, priv->glb_base + GLB_IRQ_ENA);
132542ae60aSDongpo Li }
133542ae60aSDongpo Li 
hisi_femac_irq_disable(struct hisi_femac_priv * priv,int irqs)134542ae60aSDongpo Li static void hisi_femac_irq_disable(struct hisi_femac_priv *priv, int irqs)
135542ae60aSDongpo Li {
136542ae60aSDongpo Li 	u32 val;
137542ae60aSDongpo Li 
138542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_IRQ_ENA);
139542ae60aSDongpo Li 	writel(val & (~irqs), priv->glb_base + GLB_IRQ_ENA);
140542ae60aSDongpo Li }
141542ae60aSDongpo Li 
hisi_femac_tx_dma_unmap(struct hisi_femac_priv * priv,struct sk_buff * skb,unsigned int pos)142542ae60aSDongpo Li static void hisi_femac_tx_dma_unmap(struct hisi_femac_priv *priv,
143542ae60aSDongpo Li 				    struct sk_buff *skb, unsigned int pos)
144542ae60aSDongpo Li {
145542ae60aSDongpo Li 	dma_addr_t dma_addr;
146542ae60aSDongpo Li 
147542ae60aSDongpo Li 	dma_addr = priv->txq.dma_phys[pos];
148542ae60aSDongpo Li 	dma_unmap_single(priv->dev, dma_addr, skb->len, DMA_TO_DEVICE);
149542ae60aSDongpo Li }
150542ae60aSDongpo Li 
hisi_femac_xmit_reclaim(struct net_device * dev)151542ae60aSDongpo Li static void hisi_femac_xmit_reclaim(struct net_device *dev)
152542ae60aSDongpo Li {
153542ae60aSDongpo Li 	struct sk_buff *skb;
154542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
155542ae60aSDongpo Li 	struct hisi_femac_queue *txq = &priv->txq;
156542ae60aSDongpo Li 	unsigned int bytes_compl = 0, pkts_compl = 0;
157542ae60aSDongpo Li 	u32 val;
158542ae60aSDongpo Li 
159542ae60aSDongpo Li 	netif_tx_lock(dev);
160542ae60aSDongpo Li 
161542ae60aSDongpo Li 	val = readl(priv->port_base + ADDRQ_STAT) & TX_CNT_INUSE_MASK;
162542ae60aSDongpo Li 	while (val < priv->tx_fifo_used_cnt) {
163542ae60aSDongpo Li 		skb = txq->skb[txq->tail];
164542ae60aSDongpo Li 		if (unlikely(!skb)) {
165542ae60aSDongpo Li 			netdev_err(dev, "xmitq_cnt_inuse=%d, tx_fifo_used=%d\n",
166542ae60aSDongpo Li 				   val, priv->tx_fifo_used_cnt);
167542ae60aSDongpo Li 			break;
168542ae60aSDongpo Li 		}
169542ae60aSDongpo Li 		hisi_femac_tx_dma_unmap(priv, skb, txq->tail);
170542ae60aSDongpo Li 		pkts_compl++;
171542ae60aSDongpo Li 		bytes_compl += skb->len;
172542ae60aSDongpo Li 		dev_kfree_skb_any(skb);
173542ae60aSDongpo Li 
174542ae60aSDongpo Li 		priv->tx_fifo_used_cnt--;
175542ae60aSDongpo Li 
176542ae60aSDongpo Li 		val = readl(priv->port_base + ADDRQ_STAT) & TX_CNT_INUSE_MASK;
177542ae60aSDongpo Li 		txq->skb[txq->tail] = NULL;
178542ae60aSDongpo Li 		txq->tail = (txq->tail + 1) % txq->num;
179542ae60aSDongpo Li 	}
180542ae60aSDongpo Li 
181542ae60aSDongpo Li 	netdev_completed_queue(dev, pkts_compl, bytes_compl);
182542ae60aSDongpo Li 
183542ae60aSDongpo Li 	if (unlikely(netif_queue_stopped(dev)) && pkts_compl)
184542ae60aSDongpo Li 		netif_wake_queue(dev);
185542ae60aSDongpo Li 
186542ae60aSDongpo Li 	netif_tx_unlock(dev);
187542ae60aSDongpo Li }
188542ae60aSDongpo Li 
hisi_femac_adjust_link(struct net_device * dev)189542ae60aSDongpo Li static void hisi_femac_adjust_link(struct net_device *dev)
190542ae60aSDongpo Li {
191542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
192542ae60aSDongpo Li 	struct phy_device *phy = dev->phydev;
193542ae60aSDongpo Li 	u32 status = 0;
194542ae60aSDongpo Li 
195542ae60aSDongpo Li 	if (phy->link)
196542ae60aSDongpo Li 		status |= MAC_PORTSET_LINKED;
197542ae60aSDongpo Li 	if (phy->duplex == DUPLEX_FULL)
198542ae60aSDongpo Li 		status |= MAC_PORTSET_DUPLEX_FULL;
199542ae60aSDongpo Li 	if (phy->speed == SPEED_100)
200542ae60aSDongpo Li 		status |= MAC_PORTSET_SPEED_100M;
201542ae60aSDongpo Li 
202542ae60aSDongpo Li 	if ((status != priv->link_status) &&
203542ae60aSDongpo Li 	    ((status | priv->link_status) & MAC_PORTSET_LINKED)) {
204542ae60aSDongpo Li 		writel(status, priv->port_base + MAC_PORTSET);
205542ae60aSDongpo Li 		priv->link_status = status;
206542ae60aSDongpo Li 		phy_print_status(phy);
207542ae60aSDongpo Li 	}
208542ae60aSDongpo Li }
209542ae60aSDongpo Li 
hisi_femac_rx_refill(struct hisi_femac_priv * priv)210542ae60aSDongpo Li static void hisi_femac_rx_refill(struct hisi_femac_priv *priv)
211542ae60aSDongpo Li {
212542ae60aSDongpo Li 	struct hisi_femac_queue *rxq = &priv->rxq;
213542ae60aSDongpo Li 	struct sk_buff *skb;
214542ae60aSDongpo Li 	u32 pos;
215542ae60aSDongpo Li 	u32 len = MAX_FRAME_SIZE;
216542ae60aSDongpo Li 	dma_addr_t addr;
217542ae60aSDongpo Li 
218542ae60aSDongpo Li 	pos = rxq->head;
219542ae60aSDongpo Li 	while (readl(priv->port_base + ADDRQ_STAT) & BIT_RX_READY) {
220542ae60aSDongpo Li 		if (!CIRC_SPACE(pos, rxq->tail, rxq->num))
221542ae60aSDongpo Li 			break;
222542ae60aSDongpo Li 		if (unlikely(rxq->skb[pos])) {
223542ae60aSDongpo Li 			netdev_err(priv->ndev, "err skb[%d]=%p\n",
224542ae60aSDongpo Li 				   pos, rxq->skb[pos]);
225542ae60aSDongpo Li 			break;
226542ae60aSDongpo Li 		}
227542ae60aSDongpo Li 		skb = netdev_alloc_skb_ip_align(priv->ndev, len);
228542ae60aSDongpo Li 		if (unlikely(!skb))
229542ae60aSDongpo Li 			break;
230542ae60aSDongpo Li 
231542ae60aSDongpo Li 		addr = dma_map_single(priv->dev, skb->data, len,
232542ae60aSDongpo Li 				      DMA_FROM_DEVICE);
233542ae60aSDongpo Li 		if (dma_mapping_error(priv->dev, addr)) {
234542ae60aSDongpo Li 			dev_kfree_skb_any(skb);
235542ae60aSDongpo Li 			break;
236542ae60aSDongpo Li 		}
237542ae60aSDongpo Li 		rxq->dma_phys[pos] = addr;
238542ae60aSDongpo Li 		rxq->skb[pos] = skb;
239542ae60aSDongpo Li 		writel(addr, priv->port_base + IQ_ADDR);
240542ae60aSDongpo Li 		pos = (pos + 1) % rxq->num;
241542ae60aSDongpo Li 	}
242542ae60aSDongpo Li 	rxq->head = pos;
243542ae60aSDongpo Li }
244542ae60aSDongpo Li 
hisi_femac_rx(struct net_device * dev,int limit)245542ae60aSDongpo Li static int hisi_femac_rx(struct net_device *dev, int limit)
246542ae60aSDongpo Li {
247542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
248542ae60aSDongpo Li 	struct hisi_femac_queue *rxq = &priv->rxq;
249542ae60aSDongpo Li 	struct sk_buff *skb;
250542ae60aSDongpo Li 	dma_addr_t addr;
251542ae60aSDongpo Li 	u32 rx_pkt_info, pos, len, rx_pkts_num = 0;
252542ae60aSDongpo Li 
253542ae60aSDongpo Li 	pos = rxq->tail;
254542ae60aSDongpo Li 	while (readl(priv->glb_base + GLB_IRQ_RAW) & IRQ_INT_RX_RDY) {
255542ae60aSDongpo Li 		rx_pkt_info = readl(priv->port_base + IQFRM_DES);
256542ae60aSDongpo Li 		len = rx_pkt_info & RX_FRAME_LEN_MASK;
257542ae60aSDongpo Li 		len -= ETH_FCS_LEN;
258542ae60aSDongpo Li 
259542ae60aSDongpo Li 		/* tell hardware we will deal with this packet */
260542ae60aSDongpo Li 		writel(IRQ_INT_RX_RDY, priv->glb_base + GLB_IRQ_RAW);
261542ae60aSDongpo Li 
262542ae60aSDongpo Li 		rx_pkts_num++;
263542ae60aSDongpo Li 
264542ae60aSDongpo Li 		skb = rxq->skb[pos];
265542ae60aSDongpo Li 		if (unlikely(!skb)) {
266542ae60aSDongpo Li 			netdev_err(dev, "rx skb NULL. pos=%d\n", pos);
267542ae60aSDongpo Li 			break;
268542ae60aSDongpo Li 		}
269542ae60aSDongpo Li 		rxq->skb[pos] = NULL;
270542ae60aSDongpo Li 
271542ae60aSDongpo Li 		addr = rxq->dma_phys[pos];
272542ae60aSDongpo Li 		dma_unmap_single(priv->dev, addr, MAX_FRAME_SIZE,
273542ae60aSDongpo Li 				 DMA_FROM_DEVICE);
274542ae60aSDongpo Li 		skb_put(skb, len);
275542ae60aSDongpo Li 		if (unlikely(skb->len > MAX_FRAME_SIZE)) {
276542ae60aSDongpo Li 			netdev_err(dev, "rcv len err, len = %d\n", skb->len);
277542ae60aSDongpo Li 			dev->stats.rx_errors++;
278542ae60aSDongpo Li 			dev->stats.rx_length_errors++;
279542ae60aSDongpo Li 			dev_kfree_skb_any(skb);
280542ae60aSDongpo Li 			goto next;
281542ae60aSDongpo Li 		}
282542ae60aSDongpo Li 
283542ae60aSDongpo Li 		skb->protocol = eth_type_trans(skb, dev);
284542ae60aSDongpo Li 		napi_gro_receive(&priv->napi, skb);
285542ae60aSDongpo Li 		dev->stats.rx_packets++;
28646401770SLiu Jian 		dev->stats.rx_bytes += len;
287542ae60aSDongpo Li next:
288542ae60aSDongpo Li 		pos = (pos + 1) % rxq->num;
289542ae60aSDongpo Li 		if (rx_pkts_num >= limit)
290542ae60aSDongpo Li 			break;
291542ae60aSDongpo Li 	}
292542ae60aSDongpo Li 	rxq->tail = pos;
293542ae60aSDongpo Li 
294542ae60aSDongpo Li 	hisi_femac_rx_refill(priv);
295542ae60aSDongpo Li 
296542ae60aSDongpo Li 	return rx_pkts_num;
297542ae60aSDongpo Li }
298542ae60aSDongpo Li 
hisi_femac_poll(struct napi_struct * napi,int budget)299542ae60aSDongpo Li static int hisi_femac_poll(struct napi_struct *napi, int budget)
300542ae60aSDongpo Li {
301542ae60aSDongpo Li 	struct hisi_femac_priv *priv = container_of(napi,
302542ae60aSDongpo Li 					struct hisi_femac_priv, napi);
303542ae60aSDongpo Li 	struct net_device *dev = priv->ndev;
304542ae60aSDongpo Li 	int work_done = 0, task = budget;
305542ae60aSDongpo Li 	int ints, num;
306542ae60aSDongpo Li 
307542ae60aSDongpo Li 	do {
308542ae60aSDongpo Li 		hisi_femac_xmit_reclaim(dev);
309542ae60aSDongpo Li 		num = hisi_femac_rx(dev, task);
310542ae60aSDongpo Li 		work_done += num;
311542ae60aSDongpo Li 		task -= num;
312542ae60aSDongpo Li 		if (work_done >= budget)
313542ae60aSDongpo Li 			break;
314542ae60aSDongpo Li 
315542ae60aSDongpo Li 		ints = readl(priv->glb_base + GLB_IRQ_RAW);
316542ae60aSDongpo Li 		writel(ints & DEF_INT_MASK,
317542ae60aSDongpo Li 		       priv->glb_base + GLB_IRQ_RAW);
318542ae60aSDongpo Li 	} while (ints & DEF_INT_MASK);
319542ae60aSDongpo Li 
320542ae60aSDongpo Li 	if (work_done < budget) {
3216ad20165SEric Dumazet 		napi_complete_done(napi, work_done);
322542ae60aSDongpo Li 		hisi_femac_irq_enable(priv, DEF_INT_MASK &
323542ae60aSDongpo Li 					(~IRQ_INT_TX_PER_PACKET));
324542ae60aSDongpo Li 	}
325542ae60aSDongpo Li 
326542ae60aSDongpo Li 	return work_done;
327542ae60aSDongpo Li }
328542ae60aSDongpo Li 
hisi_femac_interrupt(int irq,void * dev_id)329542ae60aSDongpo Li static irqreturn_t hisi_femac_interrupt(int irq, void *dev_id)
330542ae60aSDongpo Li {
331542ae60aSDongpo Li 	int ints;
332542ae60aSDongpo Li 	struct net_device *dev = (struct net_device *)dev_id;
333542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
334542ae60aSDongpo Li 
335542ae60aSDongpo Li 	ints = readl(priv->glb_base + GLB_IRQ_RAW);
336542ae60aSDongpo Li 
337542ae60aSDongpo Li 	if (likely(ints & DEF_INT_MASK)) {
338542ae60aSDongpo Li 		writel(ints & DEF_INT_MASK,
339542ae60aSDongpo Li 		       priv->glb_base + GLB_IRQ_RAW);
340542ae60aSDongpo Li 		hisi_femac_irq_disable(priv, DEF_INT_MASK);
341542ae60aSDongpo Li 		napi_schedule(&priv->napi);
342542ae60aSDongpo Li 	}
343542ae60aSDongpo Li 
344542ae60aSDongpo Li 	return IRQ_HANDLED;
345542ae60aSDongpo Li }
346542ae60aSDongpo Li 
hisi_femac_init_queue(struct device * dev,struct hisi_femac_queue * queue,unsigned int num)347542ae60aSDongpo Li static int hisi_femac_init_queue(struct device *dev,
348542ae60aSDongpo Li 				 struct hisi_femac_queue *queue,
349542ae60aSDongpo Li 				 unsigned int num)
350542ae60aSDongpo Li {
351542ae60aSDongpo Li 	queue->skb = devm_kcalloc(dev, num, sizeof(struct sk_buff *),
352542ae60aSDongpo Li 				  GFP_KERNEL);
353542ae60aSDongpo Li 	if (!queue->skb)
354542ae60aSDongpo Li 		return -ENOMEM;
355542ae60aSDongpo Li 
356542ae60aSDongpo Li 	queue->dma_phys = devm_kcalloc(dev, num, sizeof(dma_addr_t),
357542ae60aSDongpo Li 				       GFP_KERNEL);
358542ae60aSDongpo Li 	if (!queue->dma_phys)
359542ae60aSDongpo Li 		return -ENOMEM;
360542ae60aSDongpo Li 
361542ae60aSDongpo Li 	queue->num = num;
362542ae60aSDongpo Li 	queue->head = 0;
363542ae60aSDongpo Li 	queue->tail = 0;
364542ae60aSDongpo Li 
365542ae60aSDongpo Li 	return 0;
366542ae60aSDongpo Li }
367542ae60aSDongpo Li 
hisi_femac_init_tx_and_rx_queues(struct hisi_femac_priv * priv)368542ae60aSDongpo Li static int hisi_femac_init_tx_and_rx_queues(struct hisi_femac_priv *priv)
369542ae60aSDongpo Li {
370542ae60aSDongpo Li 	int ret;
371542ae60aSDongpo Li 
372542ae60aSDongpo Li 	ret = hisi_femac_init_queue(priv->dev, &priv->txq, TXQ_NUM);
373542ae60aSDongpo Li 	if (ret)
374542ae60aSDongpo Li 		return ret;
375542ae60aSDongpo Li 
376542ae60aSDongpo Li 	ret = hisi_femac_init_queue(priv->dev, &priv->rxq, RXQ_NUM);
377542ae60aSDongpo Li 	if (ret)
378542ae60aSDongpo Li 		return ret;
379542ae60aSDongpo Li 
380542ae60aSDongpo Li 	priv->tx_fifo_used_cnt = 0;
381542ae60aSDongpo Li 
382542ae60aSDongpo Li 	return 0;
383542ae60aSDongpo Li }
384542ae60aSDongpo Li 
hisi_femac_free_skb_rings(struct hisi_femac_priv * priv)385542ae60aSDongpo Li static void hisi_femac_free_skb_rings(struct hisi_femac_priv *priv)
386542ae60aSDongpo Li {
387542ae60aSDongpo Li 	struct hisi_femac_queue *txq = &priv->txq;
388542ae60aSDongpo Li 	struct hisi_femac_queue *rxq = &priv->rxq;
389542ae60aSDongpo Li 	struct sk_buff *skb;
390542ae60aSDongpo Li 	dma_addr_t dma_addr;
391542ae60aSDongpo Li 	u32 pos;
392542ae60aSDongpo Li 
393542ae60aSDongpo Li 	pos = rxq->tail;
394542ae60aSDongpo Li 	while (pos != rxq->head) {
395542ae60aSDongpo Li 		skb = rxq->skb[pos];
396542ae60aSDongpo Li 		if (unlikely(!skb)) {
397542ae60aSDongpo Li 			netdev_err(priv->ndev, "NULL rx skb. pos=%d, head=%d\n",
398542ae60aSDongpo Li 				   pos, rxq->head);
399542ae60aSDongpo Li 			continue;
400542ae60aSDongpo Li 		}
401542ae60aSDongpo Li 
402542ae60aSDongpo Li 		dma_addr = rxq->dma_phys[pos];
403542ae60aSDongpo Li 		dma_unmap_single(priv->dev, dma_addr, MAX_FRAME_SIZE,
404542ae60aSDongpo Li 				 DMA_FROM_DEVICE);
405542ae60aSDongpo Li 
406542ae60aSDongpo Li 		dev_kfree_skb_any(skb);
407542ae60aSDongpo Li 		rxq->skb[pos] = NULL;
408542ae60aSDongpo Li 		pos = (pos + 1) % rxq->num;
409542ae60aSDongpo Li 	}
410542ae60aSDongpo Li 	rxq->tail = pos;
411542ae60aSDongpo Li 
412542ae60aSDongpo Li 	pos = txq->tail;
413542ae60aSDongpo Li 	while (pos != txq->head) {
414542ae60aSDongpo Li 		skb = txq->skb[pos];
415542ae60aSDongpo Li 		if (unlikely(!skb)) {
416542ae60aSDongpo Li 			netdev_err(priv->ndev, "NULL tx skb. pos=%d, head=%d\n",
417542ae60aSDongpo Li 				   pos, txq->head);
418542ae60aSDongpo Li 			continue;
419542ae60aSDongpo Li 		}
420542ae60aSDongpo Li 		hisi_femac_tx_dma_unmap(priv, skb, pos);
421542ae60aSDongpo Li 		dev_kfree_skb_any(skb);
422542ae60aSDongpo Li 		txq->skb[pos] = NULL;
423542ae60aSDongpo Li 		pos = (pos + 1) % txq->num;
424542ae60aSDongpo Li 	}
425542ae60aSDongpo Li 	txq->tail = pos;
426542ae60aSDongpo Li 	priv->tx_fifo_used_cnt = 0;
427542ae60aSDongpo Li }
428542ae60aSDongpo Li 
hisi_femac_set_hw_mac_addr(struct hisi_femac_priv * priv,const unsigned char * mac)429542ae60aSDongpo Li static int hisi_femac_set_hw_mac_addr(struct hisi_femac_priv *priv,
43076660757SJakub Kicinski 				      const unsigned char *mac)
431542ae60aSDongpo Li {
432542ae60aSDongpo Li 	u32 reg;
433542ae60aSDongpo Li 
434542ae60aSDongpo Li 	reg = mac[1] | (mac[0] << 8);
435542ae60aSDongpo Li 	writel(reg, priv->glb_base + GLB_HOSTMAC_H16);
436542ae60aSDongpo Li 
437542ae60aSDongpo Li 	reg = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24);
438542ae60aSDongpo Li 	writel(reg, priv->glb_base + GLB_HOSTMAC_L32);
439542ae60aSDongpo Li 
440542ae60aSDongpo Li 	return 0;
441542ae60aSDongpo Li }
442542ae60aSDongpo Li 
hisi_femac_port_reset(struct hisi_femac_priv * priv)443542ae60aSDongpo Li static int hisi_femac_port_reset(struct hisi_femac_priv *priv)
444542ae60aSDongpo Li {
445542ae60aSDongpo Li 	u32 val;
446542ae60aSDongpo Li 
447542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_SOFT_RESET);
448542ae60aSDongpo Li 	val |= SOFT_RESET_ALL;
449542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_SOFT_RESET);
450542ae60aSDongpo Li 
451542ae60aSDongpo Li 	usleep_range(500, 800);
452542ae60aSDongpo Li 
453542ae60aSDongpo Li 	val &= ~SOFT_RESET_ALL;
454542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_SOFT_RESET);
455542ae60aSDongpo Li 
456542ae60aSDongpo Li 	return 0;
457542ae60aSDongpo Li }
458542ae60aSDongpo Li 
hisi_femac_net_open(struct net_device * dev)459542ae60aSDongpo Li static int hisi_femac_net_open(struct net_device *dev)
460542ae60aSDongpo Li {
461542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
462542ae60aSDongpo Li 
463542ae60aSDongpo Li 	hisi_femac_port_reset(priv);
464542ae60aSDongpo Li 	hisi_femac_set_hw_mac_addr(priv, dev->dev_addr);
465542ae60aSDongpo Li 	hisi_femac_rx_refill(priv);
466542ae60aSDongpo Li 
467542ae60aSDongpo Li 	netif_carrier_off(dev);
468542ae60aSDongpo Li 	netdev_reset_queue(dev);
469542ae60aSDongpo Li 	netif_start_queue(dev);
470542ae60aSDongpo Li 	napi_enable(&priv->napi);
471542ae60aSDongpo Li 
472542ae60aSDongpo Li 	priv->link_status = 0;
473542ae60aSDongpo Li 	if (dev->phydev)
474542ae60aSDongpo Li 		phy_start(dev->phydev);
475542ae60aSDongpo Li 
476542ae60aSDongpo Li 	writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
477542ae60aSDongpo Li 	hisi_femac_irq_enable(priv, IRQ_ENA_ALL | IRQ_ENA_PORT0 | DEF_INT_MASK);
478542ae60aSDongpo Li 
479542ae60aSDongpo Li 	return 0;
480542ae60aSDongpo Li }
481542ae60aSDongpo Li 
hisi_femac_net_close(struct net_device * dev)482542ae60aSDongpo Li static int hisi_femac_net_close(struct net_device *dev)
483542ae60aSDongpo Li {
484542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
485542ae60aSDongpo Li 
486542ae60aSDongpo Li 	hisi_femac_irq_disable(priv, IRQ_ENA_PORT0);
487542ae60aSDongpo Li 
488542ae60aSDongpo Li 	if (dev->phydev)
489542ae60aSDongpo Li 		phy_stop(dev->phydev);
490542ae60aSDongpo Li 
491542ae60aSDongpo Li 	netif_stop_queue(dev);
492542ae60aSDongpo Li 	napi_disable(&priv->napi);
493542ae60aSDongpo Li 
494542ae60aSDongpo Li 	hisi_femac_free_skb_rings(priv);
495542ae60aSDongpo Li 
496542ae60aSDongpo Li 	return 0;
497542ae60aSDongpo Li }
498542ae60aSDongpo Li 
hisi_femac_net_xmit(struct sk_buff * skb,struct net_device * dev)499542ae60aSDongpo Li static netdev_tx_t hisi_femac_net_xmit(struct sk_buff *skb,
500542ae60aSDongpo Li 				       struct net_device *dev)
501542ae60aSDongpo Li {
502542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
503542ae60aSDongpo Li 	struct hisi_femac_queue *txq = &priv->txq;
504542ae60aSDongpo Li 	dma_addr_t addr;
505542ae60aSDongpo Li 	u32 val;
506542ae60aSDongpo Li 
507542ae60aSDongpo Li 	val = readl(priv->port_base + ADDRQ_STAT);
508542ae60aSDongpo Li 	val &= BIT_TX_READY;
509542ae60aSDongpo Li 	if (!val) {
510542ae60aSDongpo Li 		hisi_femac_irq_enable(priv, IRQ_INT_TX_PER_PACKET);
511542ae60aSDongpo Li 		dev->stats.tx_dropped++;
512542ae60aSDongpo Li 		dev->stats.tx_fifo_errors++;
513542ae60aSDongpo Li 		netif_stop_queue(dev);
514542ae60aSDongpo Li 		return NETDEV_TX_BUSY;
515542ae60aSDongpo Li 	}
516542ae60aSDongpo Li 
517542ae60aSDongpo Li 	if (unlikely(!CIRC_SPACE(txq->head, txq->tail,
518542ae60aSDongpo Li 				 txq->num))) {
519542ae60aSDongpo Li 		hisi_femac_irq_enable(priv, IRQ_INT_TX_PER_PACKET);
520542ae60aSDongpo Li 		dev->stats.tx_dropped++;
521542ae60aSDongpo Li 		dev->stats.tx_fifo_errors++;
522542ae60aSDongpo Li 		netif_stop_queue(dev);
523542ae60aSDongpo Li 		return NETDEV_TX_BUSY;
524542ae60aSDongpo Li 	}
525542ae60aSDongpo Li 
526542ae60aSDongpo Li 	addr = dma_map_single(priv->dev, skb->data,
527542ae60aSDongpo Li 			      skb->len, DMA_TO_DEVICE);
528542ae60aSDongpo Li 	if (unlikely(dma_mapping_error(priv->dev, addr))) {
529542ae60aSDongpo Li 		dev_kfree_skb_any(skb);
530542ae60aSDongpo Li 		dev->stats.tx_dropped++;
531542ae60aSDongpo Li 		return NETDEV_TX_OK;
532542ae60aSDongpo Li 	}
533542ae60aSDongpo Li 	txq->dma_phys[txq->head] = addr;
534542ae60aSDongpo Li 
535542ae60aSDongpo Li 	txq->skb[txq->head] = skb;
536542ae60aSDongpo Li 	txq->head = (txq->head + 1) % txq->num;
537542ae60aSDongpo Li 
538542ae60aSDongpo Li 	writel(addr, priv->port_base + EQ_ADDR);
539542ae60aSDongpo Li 	writel(skb->len + ETH_FCS_LEN, priv->port_base + EQFRM_LEN);
540542ae60aSDongpo Li 
541542ae60aSDongpo Li 	priv->tx_fifo_used_cnt++;
542542ae60aSDongpo Li 
543542ae60aSDongpo Li 	dev->stats.tx_packets++;
544542ae60aSDongpo Li 	dev->stats.tx_bytes += skb->len;
545542ae60aSDongpo Li 	netdev_sent_queue(dev, skb->len);
546542ae60aSDongpo Li 
547542ae60aSDongpo Li 	return NETDEV_TX_OK;
548542ae60aSDongpo Li }
549542ae60aSDongpo Li 
hisi_femac_set_mac_address(struct net_device * dev,void * p)550542ae60aSDongpo Li static int hisi_femac_set_mac_address(struct net_device *dev, void *p)
551542ae60aSDongpo Li {
552542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
553542ae60aSDongpo Li 	struct sockaddr *skaddr = p;
554542ae60aSDongpo Li 
555542ae60aSDongpo Li 	if (!is_valid_ether_addr(skaddr->sa_data))
556542ae60aSDongpo Li 		return -EADDRNOTAVAIL;
557542ae60aSDongpo Li 
558a05e4c0aSJakub Kicinski 	eth_hw_addr_set(dev, skaddr->sa_data);
559542ae60aSDongpo Li 	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
560542ae60aSDongpo Li 
561542ae60aSDongpo Li 	hisi_femac_set_hw_mac_addr(priv, dev->dev_addr);
562542ae60aSDongpo Li 
563542ae60aSDongpo Li 	return 0;
564542ae60aSDongpo Li }
565542ae60aSDongpo Li 
hisi_femac_enable_hw_addr_filter(struct hisi_femac_priv * priv,unsigned int reg_n,bool enable)566542ae60aSDongpo Li static void hisi_femac_enable_hw_addr_filter(struct hisi_femac_priv *priv,
567542ae60aSDongpo Li 					     unsigned int reg_n, bool enable)
568542ae60aSDongpo Li {
569542ae60aSDongpo Li 	u32 val;
570542ae60aSDongpo Li 
571542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_MAC_H16(reg_n));
572542ae60aSDongpo Li 	if (enable)
573542ae60aSDongpo Li 		val |= BIT_MACFLT_ENA;
574542ae60aSDongpo Li 	else
575542ae60aSDongpo Li 		val &= ~BIT_MACFLT_ENA;
576542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_MAC_H16(reg_n));
577542ae60aSDongpo Li }
578542ae60aSDongpo Li 
hisi_femac_set_hw_addr_filter(struct hisi_femac_priv * priv,unsigned char * addr,unsigned int reg_n)579542ae60aSDongpo Li static void hisi_femac_set_hw_addr_filter(struct hisi_femac_priv *priv,
580542ae60aSDongpo Li 					  unsigned char *addr,
581542ae60aSDongpo Li 					  unsigned int reg_n)
582542ae60aSDongpo Li {
583542ae60aSDongpo Li 	unsigned int high, low;
584542ae60aSDongpo Li 	u32 val;
585542ae60aSDongpo Li 
586542ae60aSDongpo Li 	high = GLB_MAC_H16(reg_n);
587542ae60aSDongpo Li 	low = GLB_MAC_L32(reg_n);
588542ae60aSDongpo Li 
589542ae60aSDongpo Li 	val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
590542ae60aSDongpo Li 	writel(val, priv->glb_base + low);
591542ae60aSDongpo Li 
592542ae60aSDongpo Li 	val = readl(priv->glb_base + high);
593542ae60aSDongpo Li 	val &= ~MACFLT_HI16_MASK;
594542ae60aSDongpo Li 	val |= ((addr[0] << 8) | addr[1]);
595542ae60aSDongpo Li 	val |= (BIT_MACFLT_ENA | BIT_MACFLT_FW2CPU);
596542ae60aSDongpo Li 	writel(val, priv->glb_base + high);
597542ae60aSDongpo Li }
598542ae60aSDongpo Li 
hisi_femac_set_promisc_mode(struct hisi_femac_priv * priv,bool promisc_mode)599542ae60aSDongpo Li static void hisi_femac_set_promisc_mode(struct hisi_femac_priv *priv,
600542ae60aSDongpo Li 					bool promisc_mode)
601542ae60aSDongpo Li {
602542ae60aSDongpo Li 	u32 val;
603542ae60aSDongpo Li 
604542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_FWCTRL);
605542ae60aSDongpo Li 	if (promisc_mode)
606542ae60aSDongpo Li 		val |= FWCTRL_FWALL2CPU;
607542ae60aSDongpo Li 	else
608542ae60aSDongpo Li 		val &= ~FWCTRL_FWALL2CPU;
609542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_FWCTRL);
610542ae60aSDongpo Li }
611542ae60aSDongpo Li 
612542ae60aSDongpo Li /* Handle multiple multicast addresses (perfect filtering)*/
hisi_femac_set_mc_addr_filter(struct hisi_femac_priv * priv)613542ae60aSDongpo Li static void hisi_femac_set_mc_addr_filter(struct hisi_femac_priv *priv)
614542ae60aSDongpo Li {
615542ae60aSDongpo Li 	struct net_device *dev = priv->ndev;
616542ae60aSDongpo Li 	u32 val;
617542ae60aSDongpo Li 
618542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_MACTCTRL);
619542ae60aSDongpo Li 	if ((netdev_mc_count(dev) > MAX_MULTICAST_ADDRESSES) ||
620542ae60aSDongpo Li 	    (dev->flags & IFF_ALLMULTI)) {
621542ae60aSDongpo Li 		val |= MACTCTRL_MULTI2CPU;
622542ae60aSDongpo Li 	} else {
623542ae60aSDongpo Li 		int reg = MAX_UNICAST_ADDRESSES;
624542ae60aSDongpo Li 		int i;
625542ae60aSDongpo Li 		struct netdev_hw_addr *ha;
626542ae60aSDongpo Li 
627542ae60aSDongpo Li 		for (i = reg; i < MAX_MAC_FILTER_NUM; i++)
628542ae60aSDongpo Li 			hisi_femac_enable_hw_addr_filter(priv, i, false);
629542ae60aSDongpo Li 
630542ae60aSDongpo Li 		netdev_for_each_mc_addr(ha, dev) {
631542ae60aSDongpo Li 			hisi_femac_set_hw_addr_filter(priv, ha->addr, reg);
632542ae60aSDongpo Li 			reg++;
633542ae60aSDongpo Li 		}
634542ae60aSDongpo Li 		val &= ~MACTCTRL_MULTI2CPU;
635542ae60aSDongpo Li 	}
636542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_MACTCTRL);
637542ae60aSDongpo Li }
638542ae60aSDongpo Li 
639542ae60aSDongpo Li /* Handle multiple unicast addresses (perfect filtering)*/
hisi_femac_set_uc_addr_filter(struct hisi_femac_priv * priv)640542ae60aSDongpo Li static void hisi_femac_set_uc_addr_filter(struct hisi_femac_priv *priv)
641542ae60aSDongpo Li {
642542ae60aSDongpo Li 	struct net_device *dev = priv->ndev;
643542ae60aSDongpo Li 	u32 val;
644542ae60aSDongpo Li 
645542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_MACTCTRL);
646542ae60aSDongpo Li 	if (netdev_uc_count(dev) > MAX_UNICAST_ADDRESSES) {
647542ae60aSDongpo Li 		val |= MACTCTRL_UNI2CPU;
648542ae60aSDongpo Li 	} else {
649542ae60aSDongpo Li 		int reg = 0;
650542ae60aSDongpo Li 		int i;
651542ae60aSDongpo Li 		struct netdev_hw_addr *ha;
652542ae60aSDongpo Li 
653542ae60aSDongpo Li 		for (i = reg; i < MAX_UNICAST_ADDRESSES; i++)
654542ae60aSDongpo Li 			hisi_femac_enable_hw_addr_filter(priv, i, false);
655542ae60aSDongpo Li 
656542ae60aSDongpo Li 		netdev_for_each_uc_addr(ha, dev) {
657542ae60aSDongpo Li 			hisi_femac_set_hw_addr_filter(priv, ha->addr, reg);
658542ae60aSDongpo Li 			reg++;
659542ae60aSDongpo Li 		}
660542ae60aSDongpo Li 		val &= ~MACTCTRL_UNI2CPU;
661542ae60aSDongpo Li 	}
662542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_MACTCTRL);
663542ae60aSDongpo Li }
664542ae60aSDongpo Li 
hisi_femac_net_set_rx_mode(struct net_device * dev)665542ae60aSDongpo Li static void hisi_femac_net_set_rx_mode(struct net_device *dev)
666542ae60aSDongpo Li {
667542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(dev);
668542ae60aSDongpo Li 
669542ae60aSDongpo Li 	if (dev->flags & IFF_PROMISC) {
670542ae60aSDongpo Li 		hisi_femac_set_promisc_mode(priv, true);
671542ae60aSDongpo Li 	} else {
672542ae60aSDongpo Li 		hisi_femac_set_promisc_mode(priv, false);
673542ae60aSDongpo Li 		hisi_femac_set_mc_addr_filter(priv);
674542ae60aSDongpo Li 		hisi_femac_set_uc_addr_filter(priv);
675542ae60aSDongpo Li 	}
676542ae60aSDongpo Li }
677542ae60aSDongpo Li 
678bc6f0136SJulia Lawall static const struct ethtool_ops hisi_femac_ethtools_ops = {
679542ae60aSDongpo Li 	.get_link		= ethtool_op_get_link,
680542ae60aSDongpo Li 	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
681542ae60aSDongpo Li 	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
682542ae60aSDongpo Li };
683542ae60aSDongpo Li 
684542ae60aSDongpo Li static const struct net_device_ops hisi_femac_netdev_ops = {
685542ae60aSDongpo Li 	.ndo_open		= hisi_femac_net_open,
686542ae60aSDongpo Li 	.ndo_stop		= hisi_femac_net_close,
687542ae60aSDongpo Li 	.ndo_start_xmit		= hisi_femac_net_xmit,
688a7605370SArnd Bergmann 	.ndo_eth_ioctl		= phy_do_ioctl_running,
689542ae60aSDongpo Li 	.ndo_set_mac_address	= hisi_femac_set_mac_address,
690542ae60aSDongpo Li 	.ndo_set_rx_mode	= hisi_femac_net_set_rx_mode,
691542ae60aSDongpo Li };
692542ae60aSDongpo Li 
hisi_femac_core_reset(struct hisi_femac_priv * priv)693542ae60aSDongpo Li static void hisi_femac_core_reset(struct hisi_femac_priv *priv)
694542ae60aSDongpo Li {
695542ae60aSDongpo Li 	reset_control_assert(priv->mac_rst);
696542ae60aSDongpo Li 	reset_control_deassert(priv->mac_rst);
697542ae60aSDongpo Li }
698542ae60aSDongpo Li 
hisi_femac_sleep_us(u32 time_us)699542ae60aSDongpo Li static void hisi_femac_sleep_us(u32 time_us)
700542ae60aSDongpo Li {
701542ae60aSDongpo Li 	u32 time_ms;
702542ae60aSDongpo Li 
703542ae60aSDongpo Li 	if (!time_us)
704542ae60aSDongpo Li 		return;
705542ae60aSDongpo Li 
706542ae60aSDongpo Li 	time_ms = DIV_ROUND_UP(time_us, 1000);
707542ae60aSDongpo Li 	if (time_ms < 20)
708542ae60aSDongpo Li 		usleep_range(time_us, time_us + 500);
709542ae60aSDongpo Li 	else
710542ae60aSDongpo Li 		msleep(time_ms);
711542ae60aSDongpo Li }
712542ae60aSDongpo Li 
hisi_femac_phy_reset(struct hisi_femac_priv * priv)713542ae60aSDongpo Li static void hisi_femac_phy_reset(struct hisi_femac_priv *priv)
714542ae60aSDongpo Li {
715542ae60aSDongpo Li 	/* To make sure PHY hardware reset success,
716542ae60aSDongpo Li 	 * we must keep PHY in deassert state first and
717542ae60aSDongpo Li 	 * then complete the hardware reset operation
718542ae60aSDongpo Li 	 */
719542ae60aSDongpo Li 	reset_control_deassert(priv->phy_rst);
720542ae60aSDongpo Li 	hisi_femac_sleep_us(priv->phy_reset_delays[PRE_DELAY]);
721542ae60aSDongpo Li 
722542ae60aSDongpo Li 	reset_control_assert(priv->phy_rst);
723542ae60aSDongpo Li 	/* delay some time to ensure reset ok,
724542ae60aSDongpo Li 	 * this depends on PHY hardware feature
725542ae60aSDongpo Li 	 */
726542ae60aSDongpo Li 	hisi_femac_sleep_us(priv->phy_reset_delays[PULSE]);
727542ae60aSDongpo Li 	reset_control_deassert(priv->phy_rst);
728542ae60aSDongpo Li 	/* delay some time to ensure later MDIO access */
729542ae60aSDongpo Li 	hisi_femac_sleep_us(priv->phy_reset_delays[POST_DELAY]);
730542ae60aSDongpo Li }
731542ae60aSDongpo Li 
hisi_femac_port_init(struct hisi_femac_priv * priv)732542ae60aSDongpo Li static void hisi_femac_port_init(struct hisi_femac_priv *priv)
733542ae60aSDongpo Li {
734542ae60aSDongpo Li 	u32 val;
735542ae60aSDongpo Li 
736542ae60aSDongpo Li 	/* MAC gets link status info and phy mode by software config */
737542ae60aSDongpo Li 	val = MAC_PORTSEL_STAT_CPU;
738542ae60aSDongpo Li 	if (priv->ndev->phydev->interface == PHY_INTERFACE_MODE_RMII)
739542ae60aSDongpo Li 		val |= MAC_PORTSEL_RMII;
740542ae60aSDongpo Li 	writel(val, priv->port_base + MAC_PORTSEL);
741542ae60aSDongpo Li 
742542ae60aSDongpo Li 	/*clear all interrupt status */
743542ae60aSDongpo Li 	writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
744542ae60aSDongpo Li 	hisi_femac_irq_disable(priv, IRQ_ENA_PORT0_MASK | IRQ_ENA_PORT0);
745542ae60aSDongpo Li 
746542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_FWCTRL);
747542ae60aSDongpo Li 	val &= ~(FWCTRL_VLAN_ENABLE | FWCTRL_FWALL2CPU);
748542ae60aSDongpo Li 	val |= FWCTRL_FW2CPU_ENA;
749542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_FWCTRL);
750542ae60aSDongpo Li 
751542ae60aSDongpo Li 	val = readl(priv->glb_base + GLB_MACTCTRL);
752542ae60aSDongpo Li 	val |= (MACTCTRL_BROAD2CPU | MACTCTRL_MACT_ENA);
753542ae60aSDongpo Li 	writel(val, priv->glb_base + GLB_MACTCTRL);
754542ae60aSDongpo Li 
755542ae60aSDongpo Li 	val = readl(priv->port_base + MAC_SET);
756542ae60aSDongpo Li 	val &= ~MAX_FRAME_SIZE_MASK;
757542ae60aSDongpo Li 	val |= MAX_FRAME_SIZE;
758542ae60aSDongpo Li 	writel(val, priv->port_base + MAC_SET);
759542ae60aSDongpo Li 
760542ae60aSDongpo Li 	val = RX_COALESCED_TIMER |
761542ae60aSDongpo Li 		(RX_COALESCED_FRAMES << RX_COALESCED_FRAME_OFFSET);
762542ae60aSDongpo Li 	writel(val, priv->port_base + RX_COALESCE_SET);
763542ae60aSDongpo Li 
764542ae60aSDongpo Li 	val = (HW_RX_FIFO_DEPTH << RX_DEPTH_OFFSET) | HW_TX_FIFO_DEPTH;
765542ae60aSDongpo Li 	writel(val, priv->port_base + QLEN_SET);
766542ae60aSDongpo Li }
767542ae60aSDongpo Li 
hisi_femac_drv_probe(struct platform_device * pdev)768542ae60aSDongpo Li static int hisi_femac_drv_probe(struct platform_device *pdev)
769542ae60aSDongpo Li {
770542ae60aSDongpo Li 	struct device *dev = &pdev->dev;
771542ae60aSDongpo Li 	struct device_node *node = dev->of_node;
772542ae60aSDongpo Li 	struct net_device *ndev;
773542ae60aSDongpo Li 	struct hisi_femac_priv *priv;
774542ae60aSDongpo Li 	struct phy_device *phy;
775542ae60aSDongpo Li 	int ret;
776542ae60aSDongpo Li 
777542ae60aSDongpo Li 	ndev = alloc_etherdev(sizeof(*priv));
778542ae60aSDongpo Li 	if (!ndev)
779542ae60aSDongpo Li 		return -ENOMEM;
780542ae60aSDongpo Li 
781542ae60aSDongpo Li 	platform_set_drvdata(pdev, ndev);
7822087d421SDongpo Li 	SET_NETDEV_DEV(ndev, &pdev->dev);
783542ae60aSDongpo Li 
784542ae60aSDongpo Li 	priv = netdev_priv(ndev);
785542ae60aSDongpo Li 	priv->dev = dev;
786542ae60aSDongpo Li 	priv->ndev = ndev;
787542ae60aSDongpo Li 
78856170ba3SJiangfeng Xiao 	priv->port_base = devm_platform_ioremap_resource(pdev, 0);
789542ae60aSDongpo Li 	if (IS_ERR(priv->port_base)) {
790542ae60aSDongpo Li 		ret = PTR_ERR(priv->port_base);
791542ae60aSDongpo Li 		goto out_free_netdev;
792542ae60aSDongpo Li 	}
793542ae60aSDongpo Li 
79456170ba3SJiangfeng Xiao 	priv->glb_base = devm_platform_ioremap_resource(pdev, 1);
795542ae60aSDongpo Li 	if (IS_ERR(priv->glb_base)) {
796542ae60aSDongpo Li 		ret = PTR_ERR(priv->glb_base);
797542ae60aSDongpo Li 		goto out_free_netdev;
798542ae60aSDongpo Li 	}
799542ae60aSDongpo Li 
800542ae60aSDongpo Li 	priv->clk = devm_clk_get(&pdev->dev, NULL);
801542ae60aSDongpo Li 	if (IS_ERR(priv->clk)) {
802542ae60aSDongpo Li 		dev_err(dev, "failed to get clk\n");
803542ae60aSDongpo Li 		ret = -ENODEV;
804542ae60aSDongpo Li 		goto out_free_netdev;
805542ae60aSDongpo Li 	}
806542ae60aSDongpo Li 
807542ae60aSDongpo Li 	ret = clk_prepare_enable(priv->clk);
808542ae60aSDongpo Li 	if (ret) {
809542ae60aSDongpo Li 		dev_err(dev, "failed to enable clk %d\n", ret);
810542ae60aSDongpo Li 		goto out_free_netdev;
811542ae60aSDongpo Li 	}
812542ae60aSDongpo Li 
813542ae60aSDongpo Li 	priv->mac_rst = devm_reset_control_get(dev, "mac");
814542ae60aSDongpo Li 	if (IS_ERR(priv->mac_rst)) {
815542ae60aSDongpo Li 		ret = PTR_ERR(priv->mac_rst);
816542ae60aSDongpo Li 		goto out_disable_clk;
817542ae60aSDongpo Li 	}
818542ae60aSDongpo Li 	hisi_femac_core_reset(priv);
819542ae60aSDongpo Li 
820542ae60aSDongpo Li 	priv->phy_rst = devm_reset_control_get(dev, "phy");
821542ae60aSDongpo Li 	if (IS_ERR(priv->phy_rst)) {
822542ae60aSDongpo Li 		priv->phy_rst = NULL;
823542ae60aSDongpo Li 	} else {
824542ae60aSDongpo Li 		ret = of_property_read_u32_array(node,
825542ae60aSDongpo Li 						 PHY_RESET_DELAYS_PROPERTY,
826542ae60aSDongpo Li 						 priv->phy_reset_delays,
827542ae60aSDongpo Li 						 DELAYS_NUM);
828542ae60aSDongpo Li 		if (ret)
829542ae60aSDongpo Li 			goto out_disable_clk;
830542ae60aSDongpo Li 		hisi_femac_phy_reset(priv);
831542ae60aSDongpo Li 	}
832542ae60aSDongpo Li 
833542ae60aSDongpo Li 	phy = of_phy_get_and_connect(ndev, node, hisi_femac_adjust_link);
834542ae60aSDongpo Li 	if (!phy) {
835542ae60aSDongpo Li 		dev_err(dev, "connect to PHY failed!\n");
836542ae60aSDongpo Li 		ret = -ENODEV;
837542ae60aSDongpo Li 		goto out_disable_clk;
838542ae60aSDongpo Li 	}
839542ae60aSDongpo Li 
840542ae60aSDongpo Li 	phy_attached_print(phy, "phy_id=0x%.8lx, phy_mode=%s\n",
841542ae60aSDongpo Li 			   (unsigned long)phy->phy_id,
842542ae60aSDongpo Li 			   phy_modes(phy->interface));
843542ae60aSDongpo Li 
8449ca01b25SJakub Kicinski 	ret = of_get_ethdev_address(node, ndev);
84583216e39SMichael Walle 	if (ret) {
846542ae60aSDongpo Li 		eth_hw_addr_random(ndev);
847542ae60aSDongpo Li 		dev_warn(dev, "using random MAC address %pM\n",
848542ae60aSDongpo Li 			 ndev->dev_addr);
849542ae60aSDongpo Li 	}
850542ae60aSDongpo Li 
851542ae60aSDongpo Li 	ndev->watchdog_timeo = 6 * HZ;
852542ae60aSDongpo Li 	ndev->priv_flags |= IFF_UNICAST_FLT;
853542ae60aSDongpo Li 	ndev->netdev_ops = &hisi_femac_netdev_ops;
854542ae60aSDongpo Li 	ndev->ethtool_ops = &hisi_femac_ethtools_ops;
855b707b89fSJakub Kicinski 	netif_napi_add_weight(ndev, &priv->napi, hisi_femac_poll,
856b707b89fSJakub Kicinski 			      FEMAC_POLL_WEIGHT);
857542ae60aSDongpo Li 
858542ae60aSDongpo Li 	hisi_femac_port_init(priv);
859542ae60aSDongpo Li 
860542ae60aSDongpo Li 	ret = hisi_femac_init_tx_and_rx_queues(priv);
861542ae60aSDongpo Li 	if (ret)
862542ae60aSDongpo Li 		goto out_disconnect_phy;
863542ae60aSDongpo Li 
864542ae60aSDongpo Li 	ndev->irq = platform_get_irq(pdev, 0);
865*ae1d60c4SRuan Jinjie 	if (ndev->irq < 0) {
866*ae1d60c4SRuan Jinjie 		ret = ndev->irq;
867542ae60aSDongpo Li 		goto out_disconnect_phy;
868542ae60aSDongpo Li 	}
869542ae60aSDongpo Li 
870542ae60aSDongpo Li 	ret = devm_request_irq(dev, ndev->irq, hisi_femac_interrupt,
871542ae60aSDongpo Li 			       IRQF_SHARED, pdev->name, ndev);
872542ae60aSDongpo Li 	if (ret) {
873542ae60aSDongpo Li 		dev_err(dev, "devm_request_irq %d failed!\n", ndev->irq);
874542ae60aSDongpo Li 		goto out_disconnect_phy;
875542ae60aSDongpo Li 	}
876542ae60aSDongpo Li 
877542ae60aSDongpo Li 	ret = register_netdev(ndev);
878542ae60aSDongpo Li 	if (ret) {
879542ae60aSDongpo Li 		dev_err(dev, "register_netdev failed!\n");
880542ae60aSDongpo Li 		goto out_disconnect_phy;
881542ae60aSDongpo Li 	}
882542ae60aSDongpo Li 
883542ae60aSDongpo Li 	return ret;
884542ae60aSDongpo Li 
885542ae60aSDongpo Li out_disconnect_phy:
886542ae60aSDongpo Li 	netif_napi_del(&priv->napi);
887542ae60aSDongpo Li 	phy_disconnect(phy);
888542ae60aSDongpo Li out_disable_clk:
889542ae60aSDongpo Li 	clk_disable_unprepare(priv->clk);
890542ae60aSDongpo Li out_free_netdev:
891542ae60aSDongpo Li 	free_netdev(ndev);
892542ae60aSDongpo Li 
893542ae60aSDongpo Li 	return ret;
894542ae60aSDongpo Li }
895542ae60aSDongpo Li 
hisi_femac_drv_remove(struct platform_device * pdev)896542ae60aSDongpo Li static int hisi_femac_drv_remove(struct platform_device *pdev)
897542ae60aSDongpo Li {
898542ae60aSDongpo Li 	struct net_device *ndev = platform_get_drvdata(pdev);
899542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(ndev);
900542ae60aSDongpo Li 
901542ae60aSDongpo Li 	netif_napi_del(&priv->napi);
902542ae60aSDongpo Li 	unregister_netdev(ndev);
903542ae60aSDongpo Li 
904542ae60aSDongpo Li 	phy_disconnect(ndev->phydev);
905542ae60aSDongpo Li 	clk_disable_unprepare(priv->clk);
906542ae60aSDongpo Li 	free_netdev(ndev);
907542ae60aSDongpo Li 
908542ae60aSDongpo Li 	return 0;
909542ae60aSDongpo Li }
910542ae60aSDongpo Li 
911542ae60aSDongpo Li #ifdef CONFIG_PM
hisi_femac_drv_suspend(struct platform_device * pdev,pm_message_t state)912ecdad234SBaoyou Xie static int hisi_femac_drv_suspend(struct platform_device *pdev,
913542ae60aSDongpo Li 				  pm_message_t state)
914542ae60aSDongpo Li {
915542ae60aSDongpo Li 	struct net_device *ndev = platform_get_drvdata(pdev);
916542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(ndev);
917542ae60aSDongpo Li 
918542ae60aSDongpo Li 	disable_irq(ndev->irq);
919542ae60aSDongpo Li 	if (netif_running(ndev)) {
920542ae60aSDongpo Li 		hisi_femac_net_close(ndev);
921542ae60aSDongpo Li 		netif_device_detach(ndev);
922542ae60aSDongpo Li 	}
923542ae60aSDongpo Li 
924542ae60aSDongpo Li 	clk_disable_unprepare(priv->clk);
925542ae60aSDongpo Li 
926542ae60aSDongpo Li 	return 0;
927542ae60aSDongpo Li }
928542ae60aSDongpo Li 
hisi_femac_drv_resume(struct platform_device * pdev)929ecdad234SBaoyou Xie static int hisi_femac_drv_resume(struct platform_device *pdev)
930542ae60aSDongpo Li {
931542ae60aSDongpo Li 	struct net_device *ndev = platform_get_drvdata(pdev);
932542ae60aSDongpo Li 	struct hisi_femac_priv *priv = netdev_priv(ndev);
933542ae60aSDongpo Li 
934542ae60aSDongpo Li 	clk_prepare_enable(priv->clk);
935542ae60aSDongpo Li 	if (priv->phy_rst)
936542ae60aSDongpo Li 		hisi_femac_phy_reset(priv);
937542ae60aSDongpo Li 
938542ae60aSDongpo Li 	if (netif_running(ndev)) {
939542ae60aSDongpo Li 		hisi_femac_port_init(priv);
940542ae60aSDongpo Li 		hisi_femac_net_open(ndev);
941542ae60aSDongpo Li 		netif_device_attach(ndev);
942542ae60aSDongpo Li 	}
943542ae60aSDongpo Li 	enable_irq(ndev->irq);
944542ae60aSDongpo Li 
945542ae60aSDongpo Li 	return 0;
946542ae60aSDongpo Li }
947542ae60aSDongpo Li #endif
948542ae60aSDongpo Li 
949542ae60aSDongpo Li static const struct of_device_id hisi_femac_match[] = {
950542ae60aSDongpo Li 	{.compatible = "hisilicon,hisi-femac-v1",},
951542ae60aSDongpo Li 	{.compatible = "hisilicon,hisi-femac-v2",},
952542ae60aSDongpo Li 	{.compatible = "hisilicon,hi3516cv300-femac",},
953542ae60aSDongpo Li 	{},
954542ae60aSDongpo Li };
955542ae60aSDongpo Li 
956542ae60aSDongpo Li MODULE_DEVICE_TABLE(of, hisi_femac_match);
957542ae60aSDongpo Li 
958542ae60aSDongpo Li static struct platform_driver hisi_femac_driver = {
959542ae60aSDongpo Li 	.driver = {
960542ae60aSDongpo Li 		.name = "hisi-femac",
961542ae60aSDongpo Li 		.of_match_table = hisi_femac_match,
962542ae60aSDongpo Li 	},
963542ae60aSDongpo Li 	.probe = hisi_femac_drv_probe,
964542ae60aSDongpo Li 	.remove = hisi_femac_drv_remove,
965542ae60aSDongpo Li #ifdef CONFIG_PM
966542ae60aSDongpo Li 	.suspend = hisi_femac_drv_suspend,
967542ae60aSDongpo Li 	.resume = hisi_femac_drv_resume,
968542ae60aSDongpo Li #endif
969542ae60aSDongpo Li };
970542ae60aSDongpo Li 
971542ae60aSDongpo Li module_platform_driver(hisi_femac_driver);
972542ae60aSDongpo Li 
973542ae60aSDongpo Li MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC driver");
974542ae60aSDongpo Li MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>");
975542ae60aSDongpo Li MODULE_LICENSE("GPL v2");
976542ae60aSDongpo Li MODULE_ALIAS("platform:hisi-femac");
977