1de6e0b19SCristian Ciocaltea // SPDX-License-Identifier: GPL-2.0-or-later
2de6e0b19SCristian Ciocaltea /*
3de6e0b19SCristian Ciocaltea  * Actions Semi Owl SoCs Ethernet MAC driver
4de6e0b19SCristian Ciocaltea  *
5de6e0b19SCristian Ciocaltea  * Copyright (c) 2012 Actions Semi Inc.
6de6e0b19SCristian Ciocaltea  * Copyright (c) 2021 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
7de6e0b19SCristian Ciocaltea  */
8de6e0b19SCristian Ciocaltea 
9de6e0b19SCristian Ciocaltea #include <linux/circ_buf.h>
10de6e0b19SCristian Ciocaltea #include <linux/clk.h>
11de6e0b19SCristian Ciocaltea #include <linux/dma-mapping.h>
12de6e0b19SCristian Ciocaltea #include <linux/etherdevice.h>
13de6e0b19SCristian Ciocaltea #include <linux/of_mdio.h>
14de6e0b19SCristian Ciocaltea #include <linux/of_net.h>
15de6e0b19SCristian Ciocaltea #include <linux/platform_device.h>
16de6e0b19SCristian Ciocaltea #include <linux/pm.h>
17de6e0b19SCristian Ciocaltea #include <linux/reset.h>
18de6e0b19SCristian Ciocaltea 
19de6e0b19SCristian Ciocaltea #include "owl-emac.h"
20de6e0b19SCristian Ciocaltea 
21de6e0b19SCristian Ciocaltea #define OWL_EMAC_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV | \
22de6e0b19SCristian Ciocaltea 					 NETIF_MSG_PROBE | \
23de6e0b19SCristian Ciocaltea 					 NETIF_MSG_LINK)
24de6e0b19SCristian Ciocaltea 
owl_emac_reg_read(struct owl_emac_priv * priv,u32 reg)25de6e0b19SCristian Ciocaltea static u32 owl_emac_reg_read(struct owl_emac_priv *priv, u32 reg)
26de6e0b19SCristian Ciocaltea {
27de6e0b19SCristian Ciocaltea 	return readl(priv->base + reg);
28de6e0b19SCristian Ciocaltea }
29de6e0b19SCristian Ciocaltea 
owl_emac_reg_write(struct owl_emac_priv * priv,u32 reg,u32 data)30de6e0b19SCristian Ciocaltea static void owl_emac_reg_write(struct owl_emac_priv *priv, u32 reg, u32 data)
31de6e0b19SCristian Ciocaltea {
32de6e0b19SCristian Ciocaltea 	writel(data, priv->base + reg);
33de6e0b19SCristian Ciocaltea }
34de6e0b19SCristian Ciocaltea 
owl_emac_reg_update(struct owl_emac_priv * priv,u32 reg,u32 mask,u32 val)35de6e0b19SCristian Ciocaltea static u32 owl_emac_reg_update(struct owl_emac_priv *priv,
36de6e0b19SCristian Ciocaltea 			       u32 reg, u32 mask, u32 val)
37de6e0b19SCristian Ciocaltea {
38de6e0b19SCristian Ciocaltea 	u32 data, old_val;
39de6e0b19SCristian Ciocaltea 
40de6e0b19SCristian Ciocaltea 	data = owl_emac_reg_read(priv, reg);
41de6e0b19SCristian Ciocaltea 	old_val = data & mask;
42de6e0b19SCristian Ciocaltea 
43de6e0b19SCristian Ciocaltea 	data &= ~mask;
44de6e0b19SCristian Ciocaltea 	data |= val & mask;
45de6e0b19SCristian Ciocaltea 
46de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, reg, data);
47de6e0b19SCristian Ciocaltea 
48de6e0b19SCristian Ciocaltea 	return old_val;
49de6e0b19SCristian Ciocaltea }
50de6e0b19SCristian Ciocaltea 
owl_emac_reg_set(struct owl_emac_priv * priv,u32 reg,u32 bits)51de6e0b19SCristian Ciocaltea static void owl_emac_reg_set(struct owl_emac_priv *priv, u32 reg, u32 bits)
52de6e0b19SCristian Ciocaltea {
53de6e0b19SCristian Ciocaltea 	owl_emac_reg_update(priv, reg, bits, bits);
54de6e0b19SCristian Ciocaltea }
55de6e0b19SCristian Ciocaltea 
owl_emac_reg_clear(struct owl_emac_priv * priv,u32 reg,u32 bits)56de6e0b19SCristian Ciocaltea static void owl_emac_reg_clear(struct owl_emac_priv *priv, u32 reg, u32 bits)
57de6e0b19SCristian Ciocaltea {
58de6e0b19SCristian Ciocaltea 	owl_emac_reg_update(priv, reg, bits, 0);
59de6e0b19SCristian Ciocaltea }
60de6e0b19SCristian Ciocaltea 
owl_emac_get_dev(struct owl_emac_priv * priv)61de6e0b19SCristian Ciocaltea static struct device *owl_emac_get_dev(struct owl_emac_priv *priv)
62de6e0b19SCristian Ciocaltea {
63de6e0b19SCristian Ciocaltea 	return priv->netdev->dev.parent;
64de6e0b19SCristian Ciocaltea }
65de6e0b19SCristian Ciocaltea 
owl_emac_irq_enable(struct owl_emac_priv * priv)66de6e0b19SCristian Ciocaltea static void owl_emac_irq_enable(struct owl_emac_priv *priv)
67de6e0b19SCristian Ciocaltea {
68de6e0b19SCristian Ciocaltea 	/* Enable all interrupts except TU.
69de6e0b19SCristian Ciocaltea 	 *
70de6e0b19SCristian Ciocaltea 	 * Note the NIE and AIE bits shall also be set in order to actually
71de6e0b19SCristian Ciocaltea 	 * enable the selected interrupts.
72de6e0b19SCristian Ciocaltea 	 */
73de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR7,
74de6e0b19SCristian Ciocaltea 			   OWL_EMAC_BIT_MAC_CSR7_NIE |
75de6e0b19SCristian Ciocaltea 			   OWL_EMAC_BIT_MAC_CSR7_AIE |
76de6e0b19SCristian Ciocaltea 			   OWL_EMAC_BIT_MAC_CSR7_ALL_NOT_TUE);
77de6e0b19SCristian Ciocaltea }
78de6e0b19SCristian Ciocaltea 
owl_emac_irq_disable(struct owl_emac_priv * priv)79de6e0b19SCristian Ciocaltea static void owl_emac_irq_disable(struct owl_emac_priv *priv)
80de6e0b19SCristian Ciocaltea {
81de6e0b19SCristian Ciocaltea 	/* Disable all interrupts.
82de6e0b19SCristian Ciocaltea 	 *
83de6e0b19SCristian Ciocaltea 	 * WARNING: Unset only the NIE and AIE bits in CSR7 to workaround an
84de6e0b19SCristian Ciocaltea 	 * unexpected side effect (MAC hardware bug?!) where some bits in the
85de6e0b19SCristian Ciocaltea 	 * status register (CSR5) are cleared automatically before being able
86de6e0b19SCristian Ciocaltea 	 * to read them via owl_emac_irq_clear().
87de6e0b19SCristian Ciocaltea 	 */
88de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR7,
89de6e0b19SCristian Ciocaltea 			   OWL_EMAC_BIT_MAC_CSR7_ALL_NOT_TUE);
90de6e0b19SCristian Ciocaltea }
91de6e0b19SCristian Ciocaltea 
owl_emac_irq_status(struct owl_emac_priv * priv)92de6e0b19SCristian Ciocaltea static u32 owl_emac_irq_status(struct owl_emac_priv *priv)
93de6e0b19SCristian Ciocaltea {
94de6e0b19SCristian Ciocaltea 	return owl_emac_reg_read(priv, OWL_EMAC_REG_MAC_CSR5);
95de6e0b19SCristian Ciocaltea }
96de6e0b19SCristian Ciocaltea 
owl_emac_irq_clear(struct owl_emac_priv * priv)97de6e0b19SCristian Ciocaltea static u32 owl_emac_irq_clear(struct owl_emac_priv *priv)
98de6e0b19SCristian Ciocaltea {
99de6e0b19SCristian Ciocaltea 	u32 val = owl_emac_irq_status(priv);
100de6e0b19SCristian Ciocaltea 
101de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR5, val);
102de6e0b19SCristian Ciocaltea 
103de6e0b19SCristian Ciocaltea 	return val;
104de6e0b19SCristian Ciocaltea }
105de6e0b19SCristian Ciocaltea 
owl_emac_dma_map_rx(struct owl_emac_priv * priv,struct sk_buff * skb)106de6e0b19SCristian Ciocaltea static dma_addr_t owl_emac_dma_map_rx(struct owl_emac_priv *priv,
107de6e0b19SCristian Ciocaltea 				      struct sk_buff *skb)
108de6e0b19SCristian Ciocaltea {
109de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
110de6e0b19SCristian Ciocaltea 
111de6e0b19SCristian Ciocaltea 	/* Buffer pointer for the RX DMA descriptor must be word aligned. */
112de6e0b19SCristian Ciocaltea 	return dma_map_single(dev, skb_tail_pointer(skb),
113de6e0b19SCristian Ciocaltea 			      skb_tailroom(skb), DMA_FROM_DEVICE);
114de6e0b19SCristian Ciocaltea }
115de6e0b19SCristian Ciocaltea 
owl_emac_dma_unmap_rx(struct owl_emac_priv * priv,struct sk_buff * skb,dma_addr_t dma_addr)116de6e0b19SCristian Ciocaltea static void owl_emac_dma_unmap_rx(struct owl_emac_priv *priv,
117de6e0b19SCristian Ciocaltea 				  struct sk_buff *skb, dma_addr_t dma_addr)
118de6e0b19SCristian Ciocaltea {
119de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
120de6e0b19SCristian Ciocaltea 
121de6e0b19SCristian Ciocaltea 	dma_unmap_single(dev, dma_addr, skb_tailroom(skb), DMA_FROM_DEVICE);
122de6e0b19SCristian Ciocaltea }
123de6e0b19SCristian Ciocaltea 
owl_emac_dma_map_tx(struct owl_emac_priv * priv,struct sk_buff * skb)124de6e0b19SCristian Ciocaltea static dma_addr_t owl_emac_dma_map_tx(struct owl_emac_priv *priv,
125de6e0b19SCristian Ciocaltea 				      struct sk_buff *skb)
126de6e0b19SCristian Ciocaltea {
127de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
128de6e0b19SCristian Ciocaltea 
129de6e0b19SCristian Ciocaltea 	return dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
130de6e0b19SCristian Ciocaltea }
131de6e0b19SCristian Ciocaltea 
owl_emac_dma_unmap_tx(struct owl_emac_priv * priv,struct sk_buff * skb,dma_addr_t dma_addr)132de6e0b19SCristian Ciocaltea static void owl_emac_dma_unmap_tx(struct owl_emac_priv *priv,
133de6e0b19SCristian Ciocaltea 				  struct sk_buff *skb, dma_addr_t dma_addr)
134de6e0b19SCristian Ciocaltea {
135de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
136de6e0b19SCristian Ciocaltea 
137de6e0b19SCristian Ciocaltea 	dma_unmap_single(dev, dma_addr, skb_headlen(skb), DMA_TO_DEVICE);
138de6e0b19SCristian Ciocaltea }
139de6e0b19SCristian Ciocaltea 
owl_emac_ring_num_unused(struct owl_emac_ring * ring)140de6e0b19SCristian Ciocaltea static unsigned int owl_emac_ring_num_unused(struct owl_emac_ring *ring)
141de6e0b19SCristian Ciocaltea {
142de6e0b19SCristian Ciocaltea 	return CIRC_SPACE(ring->head, ring->tail, ring->size);
143de6e0b19SCristian Ciocaltea }
144de6e0b19SCristian Ciocaltea 
owl_emac_ring_get_next(struct owl_emac_ring * ring,unsigned int cur)145de6e0b19SCristian Ciocaltea static unsigned int owl_emac_ring_get_next(struct owl_emac_ring *ring,
146de6e0b19SCristian Ciocaltea 					   unsigned int cur)
147de6e0b19SCristian Ciocaltea {
148de6e0b19SCristian Ciocaltea 	return (cur + 1) & (ring->size - 1);
149de6e0b19SCristian Ciocaltea }
150de6e0b19SCristian Ciocaltea 
owl_emac_ring_push_head(struct owl_emac_ring * ring)151de6e0b19SCristian Ciocaltea static void owl_emac_ring_push_head(struct owl_emac_ring *ring)
152de6e0b19SCristian Ciocaltea {
153de6e0b19SCristian Ciocaltea 	ring->head = owl_emac_ring_get_next(ring, ring->head);
154de6e0b19SCristian Ciocaltea }
155de6e0b19SCristian Ciocaltea 
owl_emac_ring_pop_tail(struct owl_emac_ring * ring)156de6e0b19SCristian Ciocaltea static void owl_emac_ring_pop_tail(struct owl_emac_ring *ring)
157de6e0b19SCristian Ciocaltea {
158de6e0b19SCristian Ciocaltea 	ring->tail = owl_emac_ring_get_next(ring, ring->tail);
159de6e0b19SCristian Ciocaltea }
160de6e0b19SCristian Ciocaltea 
owl_emac_alloc_skb(struct net_device * netdev)161de6e0b19SCristian Ciocaltea static struct sk_buff *owl_emac_alloc_skb(struct net_device *netdev)
162de6e0b19SCristian Ciocaltea {
163de6e0b19SCristian Ciocaltea 	struct sk_buff *skb;
164de6e0b19SCristian Ciocaltea 	int offset;
165de6e0b19SCristian Ciocaltea 
166de6e0b19SCristian Ciocaltea 	skb = netdev_alloc_skb(netdev, OWL_EMAC_RX_FRAME_MAX_LEN +
167de6e0b19SCristian Ciocaltea 			       OWL_EMAC_SKB_RESERVE);
168de6e0b19SCristian Ciocaltea 	if (unlikely(!skb))
169de6e0b19SCristian Ciocaltea 		return NULL;
170de6e0b19SCristian Ciocaltea 
171de6e0b19SCristian Ciocaltea 	/* Ensure 4 bytes DMA alignment. */
172de6e0b19SCristian Ciocaltea 	offset = ((uintptr_t)skb->data) & (OWL_EMAC_SKB_ALIGN - 1);
173de6e0b19SCristian Ciocaltea 	if (unlikely(offset))
174de6e0b19SCristian Ciocaltea 		skb_reserve(skb, OWL_EMAC_SKB_ALIGN - offset);
175de6e0b19SCristian Ciocaltea 
176de6e0b19SCristian Ciocaltea 	return skb;
177de6e0b19SCristian Ciocaltea }
178de6e0b19SCristian Ciocaltea 
owl_emac_ring_prepare_rx(struct owl_emac_priv * priv)179de6e0b19SCristian Ciocaltea static int owl_emac_ring_prepare_rx(struct owl_emac_priv *priv)
180de6e0b19SCristian Ciocaltea {
181de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->rx_ring;
182de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
183de6e0b19SCristian Ciocaltea 	struct net_device *netdev = priv->netdev;
184de6e0b19SCristian Ciocaltea 	struct owl_emac_ring_desc *desc;
185de6e0b19SCristian Ciocaltea 	struct sk_buff *skb;
186de6e0b19SCristian Ciocaltea 	dma_addr_t dma_addr;
187de6e0b19SCristian Ciocaltea 	int i;
188de6e0b19SCristian Ciocaltea 
189de6e0b19SCristian Ciocaltea 	for (i = 0; i < ring->size; i++) {
190de6e0b19SCristian Ciocaltea 		skb = owl_emac_alloc_skb(netdev);
191de6e0b19SCristian Ciocaltea 		if (!skb)
192de6e0b19SCristian Ciocaltea 			return -ENOMEM;
193de6e0b19SCristian Ciocaltea 
194de6e0b19SCristian Ciocaltea 		dma_addr = owl_emac_dma_map_rx(priv, skb);
195de6e0b19SCristian Ciocaltea 		if (dma_mapping_error(dev, dma_addr)) {
196de6e0b19SCristian Ciocaltea 			dev_kfree_skb(skb);
197de6e0b19SCristian Ciocaltea 			return -ENOMEM;
198de6e0b19SCristian Ciocaltea 		}
199de6e0b19SCristian Ciocaltea 
200de6e0b19SCristian Ciocaltea 		desc = &ring->descs[i];
201de6e0b19SCristian Ciocaltea 		desc->status = OWL_EMAC_BIT_RDES0_OWN;
202de6e0b19SCristian Ciocaltea 		desc->control = skb_tailroom(skb) & OWL_EMAC_MSK_RDES1_RBS1;
203de6e0b19SCristian Ciocaltea 		desc->buf_addr = dma_addr;
204de6e0b19SCristian Ciocaltea 		desc->reserved = 0;
205de6e0b19SCristian Ciocaltea 
206de6e0b19SCristian Ciocaltea 		ring->skbs[i] = skb;
207de6e0b19SCristian Ciocaltea 		ring->skbs_dma[i] = dma_addr;
208de6e0b19SCristian Ciocaltea 	}
209de6e0b19SCristian Ciocaltea 
210de6e0b19SCristian Ciocaltea 	desc->control |= OWL_EMAC_BIT_RDES1_RER;
211de6e0b19SCristian Ciocaltea 
212de6e0b19SCristian Ciocaltea 	ring->head = 0;
213de6e0b19SCristian Ciocaltea 	ring->tail = 0;
214de6e0b19SCristian Ciocaltea 
215de6e0b19SCristian Ciocaltea 	return 0;
216de6e0b19SCristian Ciocaltea }
217de6e0b19SCristian Ciocaltea 
owl_emac_ring_prepare_tx(struct owl_emac_priv * priv)218de6e0b19SCristian Ciocaltea static void owl_emac_ring_prepare_tx(struct owl_emac_priv *priv)
219de6e0b19SCristian Ciocaltea {
220de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->tx_ring;
221de6e0b19SCristian Ciocaltea 	struct owl_emac_ring_desc *desc;
222de6e0b19SCristian Ciocaltea 	int i;
223de6e0b19SCristian Ciocaltea 
224de6e0b19SCristian Ciocaltea 	for (i = 0; i < ring->size; i++) {
225de6e0b19SCristian Ciocaltea 		desc = &ring->descs[i];
226de6e0b19SCristian Ciocaltea 
227de6e0b19SCristian Ciocaltea 		desc->status = 0;
228de6e0b19SCristian Ciocaltea 		desc->control = OWL_EMAC_BIT_TDES1_IC;
229de6e0b19SCristian Ciocaltea 		desc->buf_addr = 0;
230de6e0b19SCristian Ciocaltea 		desc->reserved = 0;
231de6e0b19SCristian Ciocaltea 	}
232de6e0b19SCristian Ciocaltea 
233de6e0b19SCristian Ciocaltea 	desc->control |= OWL_EMAC_BIT_TDES1_TER;
234de6e0b19SCristian Ciocaltea 
235de6e0b19SCristian Ciocaltea 	memset(ring->skbs_dma, 0, sizeof(dma_addr_t) * ring->size);
236de6e0b19SCristian Ciocaltea 
237de6e0b19SCristian Ciocaltea 	ring->head = 0;
238de6e0b19SCristian Ciocaltea 	ring->tail = 0;
239de6e0b19SCristian Ciocaltea }
240de6e0b19SCristian Ciocaltea 
owl_emac_ring_unprepare_rx(struct owl_emac_priv * priv)241de6e0b19SCristian Ciocaltea static void owl_emac_ring_unprepare_rx(struct owl_emac_priv *priv)
242de6e0b19SCristian Ciocaltea {
243de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->rx_ring;
244de6e0b19SCristian Ciocaltea 	int i;
245de6e0b19SCristian Ciocaltea 
246de6e0b19SCristian Ciocaltea 	for (i = 0; i < ring->size; i++) {
247de6e0b19SCristian Ciocaltea 		ring->descs[i].status = 0;
248de6e0b19SCristian Ciocaltea 
249de6e0b19SCristian Ciocaltea 		if (!ring->skbs_dma[i])
250de6e0b19SCristian Ciocaltea 			continue;
251de6e0b19SCristian Ciocaltea 
252de6e0b19SCristian Ciocaltea 		owl_emac_dma_unmap_rx(priv, ring->skbs[i], ring->skbs_dma[i]);
253de6e0b19SCristian Ciocaltea 		ring->skbs_dma[i] = 0;
254de6e0b19SCristian Ciocaltea 
255de6e0b19SCristian Ciocaltea 		dev_kfree_skb(ring->skbs[i]);
256de6e0b19SCristian Ciocaltea 		ring->skbs[i] = NULL;
257de6e0b19SCristian Ciocaltea 	}
258de6e0b19SCristian Ciocaltea }
259de6e0b19SCristian Ciocaltea 
owl_emac_ring_unprepare_tx(struct owl_emac_priv * priv)260de6e0b19SCristian Ciocaltea static void owl_emac_ring_unprepare_tx(struct owl_emac_priv *priv)
261de6e0b19SCristian Ciocaltea {
262de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->tx_ring;
263de6e0b19SCristian Ciocaltea 	int i;
264de6e0b19SCristian Ciocaltea 
265de6e0b19SCristian Ciocaltea 	for (i = 0; i < ring->size; i++) {
266de6e0b19SCristian Ciocaltea 		ring->descs[i].status = 0;
267de6e0b19SCristian Ciocaltea 
268de6e0b19SCristian Ciocaltea 		if (!ring->skbs_dma[i])
269de6e0b19SCristian Ciocaltea 			continue;
270de6e0b19SCristian Ciocaltea 
271de6e0b19SCristian Ciocaltea 		owl_emac_dma_unmap_tx(priv, ring->skbs[i], ring->skbs_dma[i]);
272de6e0b19SCristian Ciocaltea 		ring->skbs_dma[i] = 0;
273de6e0b19SCristian Ciocaltea 
274de6e0b19SCristian Ciocaltea 		dev_kfree_skb(ring->skbs[i]);
275de6e0b19SCristian Ciocaltea 		ring->skbs[i] = NULL;
276de6e0b19SCristian Ciocaltea 	}
277de6e0b19SCristian Ciocaltea }
278de6e0b19SCristian Ciocaltea 
owl_emac_ring_alloc(struct device * dev,struct owl_emac_ring * ring,unsigned int size)279de6e0b19SCristian Ciocaltea static int owl_emac_ring_alloc(struct device *dev, struct owl_emac_ring *ring,
280de6e0b19SCristian Ciocaltea 			       unsigned int size)
281de6e0b19SCristian Ciocaltea {
282de6e0b19SCristian Ciocaltea 	ring->descs = dmam_alloc_coherent(dev,
283de6e0b19SCristian Ciocaltea 					  sizeof(struct owl_emac_ring_desc) * size,
284de6e0b19SCristian Ciocaltea 					  &ring->descs_dma, GFP_KERNEL);
285de6e0b19SCristian Ciocaltea 	if (!ring->descs)
286de6e0b19SCristian Ciocaltea 		return -ENOMEM;
287de6e0b19SCristian Ciocaltea 
288de6e0b19SCristian Ciocaltea 	ring->skbs = devm_kcalloc(dev, size, sizeof(struct sk_buff *),
289de6e0b19SCristian Ciocaltea 				  GFP_KERNEL);
290de6e0b19SCristian Ciocaltea 	if (!ring->skbs)
291de6e0b19SCristian Ciocaltea 		return -ENOMEM;
292de6e0b19SCristian Ciocaltea 
293de6e0b19SCristian Ciocaltea 	ring->skbs_dma = devm_kcalloc(dev, size, sizeof(dma_addr_t),
294de6e0b19SCristian Ciocaltea 				      GFP_KERNEL);
295de6e0b19SCristian Ciocaltea 	if (!ring->skbs_dma)
296de6e0b19SCristian Ciocaltea 		return -ENOMEM;
297de6e0b19SCristian Ciocaltea 
298de6e0b19SCristian Ciocaltea 	ring->size = size;
299de6e0b19SCristian Ciocaltea 
300de6e0b19SCristian Ciocaltea 	return 0;
301de6e0b19SCristian Ciocaltea }
302de6e0b19SCristian Ciocaltea 
owl_emac_dma_cmd_resume_rx(struct owl_emac_priv * priv)303de6e0b19SCristian Ciocaltea static void owl_emac_dma_cmd_resume_rx(struct owl_emac_priv *priv)
304de6e0b19SCristian Ciocaltea {
305de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR2,
306de6e0b19SCristian Ciocaltea 			   OWL_EMAC_VAL_MAC_CSR2_RPD);
307de6e0b19SCristian Ciocaltea }
308de6e0b19SCristian Ciocaltea 
owl_emac_dma_cmd_resume_tx(struct owl_emac_priv * priv)309de6e0b19SCristian Ciocaltea static void owl_emac_dma_cmd_resume_tx(struct owl_emac_priv *priv)
310de6e0b19SCristian Ciocaltea {
311de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR1,
312de6e0b19SCristian Ciocaltea 			   OWL_EMAC_VAL_MAC_CSR1_TPD);
313de6e0b19SCristian Ciocaltea }
314de6e0b19SCristian Ciocaltea 
owl_emac_dma_cmd_set_tx(struct owl_emac_priv * priv,u32 status)315de6e0b19SCristian Ciocaltea static u32 owl_emac_dma_cmd_set_tx(struct owl_emac_priv *priv, u32 status)
316de6e0b19SCristian Ciocaltea {
317de6e0b19SCristian Ciocaltea 	return owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6,
318de6e0b19SCristian Ciocaltea 				   OWL_EMAC_BIT_MAC_CSR6_ST, status);
319de6e0b19SCristian Ciocaltea }
320de6e0b19SCristian Ciocaltea 
owl_emac_dma_cmd_start_tx(struct owl_emac_priv * priv)321de6e0b19SCristian Ciocaltea static u32 owl_emac_dma_cmd_start_tx(struct owl_emac_priv *priv)
322de6e0b19SCristian Ciocaltea {
323de6e0b19SCristian Ciocaltea 	return owl_emac_dma_cmd_set_tx(priv, ~0);
324de6e0b19SCristian Ciocaltea }
325de6e0b19SCristian Ciocaltea 
owl_emac_dma_cmd_set(struct owl_emac_priv * priv,u32 status)326de6e0b19SCristian Ciocaltea static u32 owl_emac_dma_cmd_set(struct owl_emac_priv *priv, u32 status)
327de6e0b19SCristian Ciocaltea {
328de6e0b19SCristian Ciocaltea 	return owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6,
329de6e0b19SCristian Ciocaltea 				   OWL_EMAC_MSK_MAC_CSR6_STSR, status);
330de6e0b19SCristian Ciocaltea }
331de6e0b19SCristian Ciocaltea 
owl_emac_dma_cmd_start(struct owl_emac_priv * priv)332de6e0b19SCristian Ciocaltea static u32 owl_emac_dma_cmd_start(struct owl_emac_priv *priv)
333de6e0b19SCristian Ciocaltea {
334de6e0b19SCristian Ciocaltea 	return owl_emac_dma_cmd_set(priv, ~0);
335de6e0b19SCristian Ciocaltea }
336de6e0b19SCristian Ciocaltea 
owl_emac_dma_cmd_stop(struct owl_emac_priv * priv)337de6e0b19SCristian Ciocaltea static u32 owl_emac_dma_cmd_stop(struct owl_emac_priv *priv)
338de6e0b19SCristian Ciocaltea {
339de6e0b19SCristian Ciocaltea 	return owl_emac_dma_cmd_set(priv, 0);
340de6e0b19SCristian Ciocaltea }
341de6e0b19SCristian Ciocaltea 
owl_emac_set_hw_mac_addr(struct net_device * netdev)342de6e0b19SCristian Ciocaltea static void owl_emac_set_hw_mac_addr(struct net_device *netdev)
343de6e0b19SCristian Ciocaltea {
344de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
34576660757SJakub Kicinski 	const u8 *mac_addr = netdev->dev_addr;
346de6e0b19SCristian Ciocaltea 	u32 addr_high, addr_low;
347de6e0b19SCristian Ciocaltea 
348de6e0b19SCristian Ciocaltea 	addr_high = mac_addr[0] << 8 | mac_addr[1];
349de6e0b19SCristian Ciocaltea 	addr_low = mac_addr[2] << 24 | mac_addr[3] << 16 |
350de6e0b19SCristian Ciocaltea 		   mac_addr[4] << 8 | mac_addr[5];
351de6e0b19SCristian Ciocaltea 
352de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR17, addr_high);
353de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR16, addr_low);
354de6e0b19SCristian Ciocaltea }
355de6e0b19SCristian Ciocaltea 
owl_emac_update_link_state(struct owl_emac_priv * priv)356de6e0b19SCristian Ciocaltea static void owl_emac_update_link_state(struct owl_emac_priv *priv)
357de6e0b19SCristian Ciocaltea {
358de6e0b19SCristian Ciocaltea 	u32 val, status;
359de6e0b19SCristian Ciocaltea 
360de6e0b19SCristian Ciocaltea 	if (priv->pause) {
361de6e0b19SCristian Ciocaltea 		val = OWL_EMAC_BIT_MAC_CSR20_FCE | OWL_EMAC_BIT_MAC_CSR20_TUE;
362de6e0b19SCristian Ciocaltea 		val |= OWL_EMAC_BIT_MAC_CSR20_TPE | OWL_EMAC_BIT_MAC_CSR20_RPE;
363de6e0b19SCristian Ciocaltea 		val |= OWL_EMAC_BIT_MAC_CSR20_BPE;
364de6e0b19SCristian Ciocaltea 	} else {
365de6e0b19SCristian Ciocaltea 		val = 0;
366de6e0b19SCristian Ciocaltea 	}
367de6e0b19SCristian Ciocaltea 
368de6e0b19SCristian Ciocaltea 	/* Update flow control. */
369de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR20, val);
370de6e0b19SCristian Ciocaltea 
371de6e0b19SCristian Ciocaltea 	val = (priv->speed == SPEED_100) ? OWL_EMAC_VAL_MAC_CSR6_SPEED_100M :
372de6e0b19SCristian Ciocaltea 					   OWL_EMAC_VAL_MAC_CSR6_SPEED_10M;
373de6e0b19SCristian Ciocaltea 	val <<= OWL_EMAC_OFF_MAC_CSR6_SPEED;
374de6e0b19SCristian Ciocaltea 
375de6e0b19SCristian Ciocaltea 	if (priv->duplex == DUPLEX_FULL)
376de6e0b19SCristian Ciocaltea 		val |= OWL_EMAC_BIT_MAC_CSR6_FD;
377de6e0b19SCristian Ciocaltea 
378de6e0b19SCristian Ciocaltea 	spin_lock_bh(&priv->lock);
379de6e0b19SCristian Ciocaltea 
380de6e0b19SCristian Ciocaltea 	/* Temporarily stop DMA TX & RX. */
381de6e0b19SCristian Ciocaltea 	status = owl_emac_dma_cmd_stop(priv);
382de6e0b19SCristian Ciocaltea 
383de6e0b19SCristian Ciocaltea 	/* Update operation modes. */
384de6e0b19SCristian Ciocaltea 	owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6,
385de6e0b19SCristian Ciocaltea 			    OWL_EMAC_MSK_MAC_CSR6_SPEED |
386de6e0b19SCristian Ciocaltea 			    OWL_EMAC_BIT_MAC_CSR6_FD, val);
387de6e0b19SCristian Ciocaltea 
388de6e0b19SCristian Ciocaltea 	/* Restore DMA TX & RX status. */
389de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_set(priv, status);
390de6e0b19SCristian Ciocaltea 
391de6e0b19SCristian Ciocaltea 	spin_unlock_bh(&priv->lock);
392de6e0b19SCristian Ciocaltea }
393de6e0b19SCristian Ciocaltea 
owl_emac_adjust_link(struct net_device * netdev)394de6e0b19SCristian Ciocaltea static void owl_emac_adjust_link(struct net_device *netdev)
395de6e0b19SCristian Ciocaltea {
396de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
397de6e0b19SCristian Ciocaltea 	struct phy_device *phydev = netdev->phydev;
398de6e0b19SCristian Ciocaltea 	bool state_changed = false;
399de6e0b19SCristian Ciocaltea 
400de6e0b19SCristian Ciocaltea 	if (phydev->link) {
401de6e0b19SCristian Ciocaltea 		if (!priv->link) {
402de6e0b19SCristian Ciocaltea 			priv->link = phydev->link;
403de6e0b19SCristian Ciocaltea 			state_changed = true;
404de6e0b19SCristian Ciocaltea 		}
405de6e0b19SCristian Ciocaltea 
406de6e0b19SCristian Ciocaltea 		if (priv->speed != phydev->speed) {
407de6e0b19SCristian Ciocaltea 			priv->speed = phydev->speed;
408de6e0b19SCristian Ciocaltea 			state_changed = true;
409de6e0b19SCristian Ciocaltea 		}
410de6e0b19SCristian Ciocaltea 
411de6e0b19SCristian Ciocaltea 		if (priv->duplex != phydev->duplex) {
412de6e0b19SCristian Ciocaltea 			priv->duplex = phydev->duplex;
413de6e0b19SCristian Ciocaltea 			state_changed = true;
414de6e0b19SCristian Ciocaltea 		}
415de6e0b19SCristian Ciocaltea 
416de6e0b19SCristian Ciocaltea 		if (priv->pause != phydev->pause) {
417de6e0b19SCristian Ciocaltea 			priv->pause = phydev->pause;
418de6e0b19SCristian Ciocaltea 			state_changed = true;
419de6e0b19SCristian Ciocaltea 		}
420de6e0b19SCristian Ciocaltea 	} else {
421de6e0b19SCristian Ciocaltea 		if (priv->link) {
422de6e0b19SCristian Ciocaltea 			priv->link = phydev->link;
423de6e0b19SCristian Ciocaltea 			state_changed = true;
424de6e0b19SCristian Ciocaltea 		}
425de6e0b19SCristian Ciocaltea 	}
426de6e0b19SCristian Ciocaltea 
427de6e0b19SCristian Ciocaltea 	if (state_changed) {
428de6e0b19SCristian Ciocaltea 		if (phydev->link)
429de6e0b19SCristian Ciocaltea 			owl_emac_update_link_state(priv);
430de6e0b19SCristian Ciocaltea 
431de6e0b19SCristian Ciocaltea 		if (netif_msg_link(priv))
432de6e0b19SCristian Ciocaltea 			phy_print_status(phydev);
433de6e0b19SCristian Ciocaltea 	}
434de6e0b19SCristian Ciocaltea }
435de6e0b19SCristian Ciocaltea 
owl_emac_handle_irq(int irq,void * data)436de6e0b19SCristian Ciocaltea static irqreturn_t owl_emac_handle_irq(int irq, void *data)
437de6e0b19SCristian Ciocaltea {
438de6e0b19SCristian Ciocaltea 	struct net_device *netdev = data;
439de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
440de6e0b19SCristian Ciocaltea 
441de6e0b19SCristian Ciocaltea 	if (netif_running(netdev)) {
442de6e0b19SCristian Ciocaltea 		owl_emac_irq_disable(priv);
443de6e0b19SCristian Ciocaltea 		napi_schedule(&priv->napi);
444de6e0b19SCristian Ciocaltea 	}
445de6e0b19SCristian Ciocaltea 
446de6e0b19SCristian Ciocaltea 	return IRQ_HANDLED;
447de6e0b19SCristian Ciocaltea }
448de6e0b19SCristian Ciocaltea 
owl_emac_ether_addr_push(u8 ** dst,const u8 * src)449de6e0b19SCristian Ciocaltea static void owl_emac_ether_addr_push(u8 **dst, const u8 *src)
450de6e0b19SCristian Ciocaltea {
451de6e0b19SCristian Ciocaltea 	u32 *a = (u32 *)(*dst);
452de6e0b19SCristian Ciocaltea 	const u16 *b = (const u16 *)src;
453de6e0b19SCristian Ciocaltea 
454de6e0b19SCristian Ciocaltea 	a[0] = b[0];
455de6e0b19SCristian Ciocaltea 	a[1] = b[1];
456de6e0b19SCristian Ciocaltea 	a[2] = b[2];
457de6e0b19SCristian Ciocaltea 
458de6e0b19SCristian Ciocaltea 	*dst += 12;
459de6e0b19SCristian Ciocaltea }
460de6e0b19SCristian Ciocaltea 
461de6e0b19SCristian Ciocaltea static void
owl_emac_setup_frame_prepare(struct owl_emac_priv * priv,struct sk_buff * skb)462de6e0b19SCristian Ciocaltea owl_emac_setup_frame_prepare(struct owl_emac_priv *priv, struct sk_buff *skb)
463de6e0b19SCristian Ciocaltea {
464de6e0b19SCristian Ciocaltea 	const u8 bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
465de6e0b19SCristian Ciocaltea 	const u8 *mac_addr = priv->netdev->dev_addr;
466de6e0b19SCristian Ciocaltea 	u8 *frame;
467de6e0b19SCristian Ciocaltea 	int i;
468de6e0b19SCristian Ciocaltea 
469de6e0b19SCristian Ciocaltea 	skb_put(skb, OWL_EMAC_SETUP_FRAME_LEN);
470de6e0b19SCristian Ciocaltea 
471de6e0b19SCristian Ciocaltea 	frame = skb->data;
472de6e0b19SCristian Ciocaltea 	memset(frame, 0, skb->len);
473de6e0b19SCristian Ciocaltea 
474de6e0b19SCristian Ciocaltea 	owl_emac_ether_addr_push(&frame, mac_addr);
475de6e0b19SCristian Ciocaltea 	owl_emac_ether_addr_push(&frame, bcast_addr);
476de6e0b19SCristian Ciocaltea 
477de6e0b19SCristian Ciocaltea 	/* Fill multicast addresses. */
478de6e0b19SCristian Ciocaltea 	WARN_ON(priv->mcaddr_list.count >= OWL_EMAC_MAX_MULTICAST_ADDRS);
479de6e0b19SCristian Ciocaltea 	for (i = 0; i < priv->mcaddr_list.count; i++) {
480de6e0b19SCristian Ciocaltea 		mac_addr = priv->mcaddr_list.addrs[i];
481de6e0b19SCristian Ciocaltea 		owl_emac_ether_addr_push(&frame, mac_addr);
482de6e0b19SCristian Ciocaltea 	}
483de6e0b19SCristian Ciocaltea }
484de6e0b19SCristian Ciocaltea 
485de6e0b19SCristian Ciocaltea /* The setup frame is a special descriptor which is used to provide physical
486de6e0b19SCristian Ciocaltea  * addresses (i.e. mac, broadcast and multicast) to the MAC hardware for
487de6e0b19SCristian Ciocaltea  * filtering purposes. To be recognized as a setup frame, the TDES1_SET bit
488de6e0b19SCristian Ciocaltea  * must be set in the TX descriptor control field.
489de6e0b19SCristian Ciocaltea  */
owl_emac_setup_frame_xmit(struct owl_emac_priv * priv)490de6e0b19SCristian Ciocaltea static int owl_emac_setup_frame_xmit(struct owl_emac_priv *priv)
491de6e0b19SCristian Ciocaltea {
492de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->tx_ring;
493de6e0b19SCristian Ciocaltea 	struct net_device *netdev = priv->netdev;
494de6e0b19SCristian Ciocaltea 	struct owl_emac_ring_desc *desc;
495de6e0b19SCristian Ciocaltea 	struct sk_buff *skb;
496de6e0b19SCristian Ciocaltea 	unsigned int tx_head;
497de6e0b19SCristian Ciocaltea 	u32 status, control;
498de6e0b19SCristian Ciocaltea 	dma_addr_t dma_addr;
499de6e0b19SCristian Ciocaltea 	int ret;
500de6e0b19SCristian Ciocaltea 
501de6e0b19SCristian Ciocaltea 	skb = owl_emac_alloc_skb(netdev);
502de6e0b19SCristian Ciocaltea 	if (!skb)
503de6e0b19SCristian Ciocaltea 		return -ENOMEM;
504de6e0b19SCristian Ciocaltea 
505de6e0b19SCristian Ciocaltea 	owl_emac_setup_frame_prepare(priv, skb);
506de6e0b19SCristian Ciocaltea 
507de6e0b19SCristian Ciocaltea 	dma_addr = owl_emac_dma_map_tx(priv, skb);
508de6e0b19SCristian Ciocaltea 	if (dma_mapping_error(owl_emac_get_dev(priv), dma_addr)) {
509de6e0b19SCristian Ciocaltea 		ret = -ENOMEM;
510de6e0b19SCristian Ciocaltea 		goto err_free_skb;
511de6e0b19SCristian Ciocaltea 	}
512de6e0b19SCristian Ciocaltea 
513de6e0b19SCristian Ciocaltea 	spin_lock_bh(&priv->lock);
514de6e0b19SCristian Ciocaltea 
515de6e0b19SCristian Ciocaltea 	tx_head = ring->head;
516de6e0b19SCristian Ciocaltea 	desc = &ring->descs[tx_head];
517de6e0b19SCristian Ciocaltea 
518de6e0b19SCristian Ciocaltea 	status = READ_ONCE(desc->status);
519de6e0b19SCristian Ciocaltea 	control = READ_ONCE(desc->control);
520de6e0b19SCristian Ciocaltea 	dma_rmb(); /* Ensure data has been read before used. */
521de6e0b19SCristian Ciocaltea 
522de6e0b19SCristian Ciocaltea 	if (unlikely(status & OWL_EMAC_BIT_TDES0_OWN) ||
523de6e0b19SCristian Ciocaltea 	    !owl_emac_ring_num_unused(ring)) {
524de6e0b19SCristian Ciocaltea 		spin_unlock_bh(&priv->lock);
525de6e0b19SCristian Ciocaltea 		owl_emac_dma_unmap_tx(priv, skb, dma_addr);
526de6e0b19SCristian Ciocaltea 		ret = -EBUSY;
527de6e0b19SCristian Ciocaltea 		goto err_free_skb;
528de6e0b19SCristian Ciocaltea 	}
529de6e0b19SCristian Ciocaltea 
530de6e0b19SCristian Ciocaltea 	ring->skbs[tx_head] = skb;
531de6e0b19SCristian Ciocaltea 	ring->skbs_dma[tx_head] = dma_addr;
532de6e0b19SCristian Ciocaltea 
533de6e0b19SCristian Ciocaltea 	control &= OWL_EMAC_BIT_TDES1_IC | OWL_EMAC_BIT_TDES1_TER; /* Maintain bits */
534de6e0b19SCristian Ciocaltea 	control |= OWL_EMAC_BIT_TDES1_SET;
535de6e0b19SCristian Ciocaltea 	control |= OWL_EMAC_MSK_TDES1_TBS1 & skb->len;
536de6e0b19SCristian Ciocaltea 
537de6e0b19SCristian Ciocaltea 	WRITE_ONCE(desc->control, control);
538de6e0b19SCristian Ciocaltea 	WRITE_ONCE(desc->buf_addr, dma_addr);
539de6e0b19SCristian Ciocaltea 	dma_wmb(); /* Flush descriptor before changing ownership. */
540de6e0b19SCristian Ciocaltea 	WRITE_ONCE(desc->status, OWL_EMAC_BIT_TDES0_OWN);
541de6e0b19SCristian Ciocaltea 
542de6e0b19SCristian Ciocaltea 	owl_emac_ring_push_head(ring);
543de6e0b19SCristian Ciocaltea 
544de6e0b19SCristian Ciocaltea 	/* Temporarily enable DMA TX. */
545de6e0b19SCristian Ciocaltea 	status = owl_emac_dma_cmd_start_tx(priv);
546de6e0b19SCristian Ciocaltea 
547de6e0b19SCristian Ciocaltea 	/* Trigger setup frame processing. */
548de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_resume_tx(priv);
549de6e0b19SCristian Ciocaltea 
550de6e0b19SCristian Ciocaltea 	/* Restore DMA TX status. */
551de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_set_tx(priv, status);
552de6e0b19SCristian Ciocaltea 
553de6e0b19SCristian Ciocaltea 	/* Stop regular TX until setup frame is processed. */
554de6e0b19SCristian Ciocaltea 	netif_stop_queue(netdev);
555de6e0b19SCristian Ciocaltea 
556de6e0b19SCristian Ciocaltea 	spin_unlock_bh(&priv->lock);
557de6e0b19SCristian Ciocaltea 
558de6e0b19SCristian Ciocaltea 	return 0;
559de6e0b19SCristian Ciocaltea 
560de6e0b19SCristian Ciocaltea err_free_skb:
561de6e0b19SCristian Ciocaltea 	dev_kfree_skb(skb);
562de6e0b19SCristian Ciocaltea 	return ret;
563de6e0b19SCristian Ciocaltea }
564de6e0b19SCristian Ciocaltea 
owl_emac_ndo_start_xmit(struct sk_buff * skb,struct net_device * netdev)565de6e0b19SCristian Ciocaltea static netdev_tx_t owl_emac_ndo_start_xmit(struct sk_buff *skb,
566de6e0b19SCristian Ciocaltea 					   struct net_device *netdev)
567de6e0b19SCristian Ciocaltea {
568de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
569de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
570de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->tx_ring;
571de6e0b19SCristian Ciocaltea 	struct owl_emac_ring_desc *desc;
572de6e0b19SCristian Ciocaltea 	unsigned int tx_head;
573de6e0b19SCristian Ciocaltea 	u32 status, control;
574de6e0b19SCristian Ciocaltea 	dma_addr_t dma_addr;
575de6e0b19SCristian Ciocaltea 
576de6e0b19SCristian Ciocaltea 	dma_addr = owl_emac_dma_map_tx(priv, skb);
577de6e0b19SCristian Ciocaltea 	if (dma_mapping_error(dev, dma_addr)) {
578de6e0b19SCristian Ciocaltea 		dev_err_ratelimited(&netdev->dev, "TX DMA mapping failed\n");
579de6e0b19SCristian Ciocaltea 		dev_kfree_skb(skb);
580de6e0b19SCristian Ciocaltea 		netdev->stats.tx_dropped++;
581de6e0b19SCristian Ciocaltea 		return NETDEV_TX_OK;
582de6e0b19SCristian Ciocaltea 	}
583de6e0b19SCristian Ciocaltea 
584de6e0b19SCristian Ciocaltea 	spin_lock_bh(&priv->lock);
585de6e0b19SCristian Ciocaltea 
586de6e0b19SCristian Ciocaltea 	tx_head = ring->head;
587de6e0b19SCristian Ciocaltea 	desc = &ring->descs[tx_head];
588de6e0b19SCristian Ciocaltea 
589de6e0b19SCristian Ciocaltea 	status = READ_ONCE(desc->status);
590de6e0b19SCristian Ciocaltea 	control = READ_ONCE(desc->control);
591de6e0b19SCristian Ciocaltea 	dma_rmb(); /* Ensure data has been read before used. */
592de6e0b19SCristian Ciocaltea 
593de6e0b19SCristian Ciocaltea 	if (!owl_emac_ring_num_unused(ring) ||
594de6e0b19SCristian Ciocaltea 	    unlikely(status & OWL_EMAC_BIT_TDES0_OWN)) {
595de6e0b19SCristian Ciocaltea 		netif_stop_queue(netdev);
596de6e0b19SCristian Ciocaltea 		spin_unlock_bh(&priv->lock);
597de6e0b19SCristian Ciocaltea 
598de6e0b19SCristian Ciocaltea 		dev_dbg_ratelimited(&netdev->dev, "TX buffer full, status=0x%08x\n",
599de6e0b19SCristian Ciocaltea 				    owl_emac_irq_status(priv));
600de6e0b19SCristian Ciocaltea 		owl_emac_dma_unmap_tx(priv, skb, dma_addr);
601de6e0b19SCristian Ciocaltea 		netdev->stats.tx_dropped++;
602de6e0b19SCristian Ciocaltea 		return NETDEV_TX_BUSY;
603de6e0b19SCristian Ciocaltea 	}
604de6e0b19SCristian Ciocaltea 
605de6e0b19SCristian Ciocaltea 	ring->skbs[tx_head] = skb;
606de6e0b19SCristian Ciocaltea 	ring->skbs_dma[tx_head] = dma_addr;
607de6e0b19SCristian Ciocaltea 
608de6e0b19SCristian Ciocaltea 	control &= OWL_EMAC_BIT_TDES1_IC | OWL_EMAC_BIT_TDES1_TER; /* Maintain bits */
609de6e0b19SCristian Ciocaltea 	control |= OWL_EMAC_BIT_TDES1_FS | OWL_EMAC_BIT_TDES1_LS;
610de6e0b19SCristian Ciocaltea 	control |= OWL_EMAC_MSK_TDES1_TBS1 & skb->len;
611de6e0b19SCristian Ciocaltea 
612de6e0b19SCristian Ciocaltea 	WRITE_ONCE(desc->control, control);
613de6e0b19SCristian Ciocaltea 	WRITE_ONCE(desc->buf_addr, dma_addr);
614de6e0b19SCristian Ciocaltea 	dma_wmb(); /* Flush descriptor before changing ownership. */
615de6e0b19SCristian Ciocaltea 	WRITE_ONCE(desc->status, OWL_EMAC_BIT_TDES0_OWN);
616de6e0b19SCristian Ciocaltea 
617de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_resume_tx(priv);
618de6e0b19SCristian Ciocaltea 	owl_emac_ring_push_head(ring);
619de6e0b19SCristian Ciocaltea 
620de6e0b19SCristian Ciocaltea 	/* FIXME: The transmission is currently restricted to a single frame
621de6e0b19SCristian Ciocaltea 	 * at a time as a workaround for a MAC hardware bug that causes random
622de6e0b19SCristian Ciocaltea 	 * freeze of the TX queue processor.
623de6e0b19SCristian Ciocaltea 	 */
624de6e0b19SCristian Ciocaltea 	netif_stop_queue(netdev);
625de6e0b19SCristian Ciocaltea 
626de6e0b19SCristian Ciocaltea 	spin_unlock_bh(&priv->lock);
627de6e0b19SCristian Ciocaltea 
628de6e0b19SCristian Ciocaltea 	return NETDEV_TX_OK;
629de6e0b19SCristian Ciocaltea }
630de6e0b19SCristian Ciocaltea 
owl_emac_tx_complete_tail(struct owl_emac_priv * priv)631de6e0b19SCristian Ciocaltea static bool owl_emac_tx_complete_tail(struct owl_emac_priv *priv)
632de6e0b19SCristian Ciocaltea {
633de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->tx_ring;
634de6e0b19SCristian Ciocaltea 	struct net_device *netdev = priv->netdev;
635de6e0b19SCristian Ciocaltea 	struct owl_emac_ring_desc *desc;
636de6e0b19SCristian Ciocaltea 	struct sk_buff *skb;
637de6e0b19SCristian Ciocaltea 	unsigned int tx_tail;
638de6e0b19SCristian Ciocaltea 	u32 status;
639de6e0b19SCristian Ciocaltea 
640de6e0b19SCristian Ciocaltea 	tx_tail = ring->tail;
641de6e0b19SCristian Ciocaltea 	desc = &ring->descs[tx_tail];
642de6e0b19SCristian Ciocaltea 
643de6e0b19SCristian Ciocaltea 	status = READ_ONCE(desc->status);
644de6e0b19SCristian Ciocaltea 	dma_rmb(); /* Ensure data has been read before used. */
645de6e0b19SCristian Ciocaltea 
646de6e0b19SCristian Ciocaltea 	if (status & OWL_EMAC_BIT_TDES0_OWN)
647de6e0b19SCristian Ciocaltea 		return false;
648de6e0b19SCristian Ciocaltea 
649de6e0b19SCristian Ciocaltea 	/* Check for errors. */
650de6e0b19SCristian Ciocaltea 	if (status & OWL_EMAC_BIT_TDES0_ES) {
651de6e0b19SCristian Ciocaltea 		dev_dbg_ratelimited(&netdev->dev,
652de6e0b19SCristian Ciocaltea 				    "TX complete error status: 0x%08x\n",
653de6e0b19SCristian Ciocaltea 				    status);
654de6e0b19SCristian Ciocaltea 
655de6e0b19SCristian Ciocaltea 		netdev->stats.tx_errors++;
656de6e0b19SCristian Ciocaltea 
657de6e0b19SCristian Ciocaltea 		if (status & OWL_EMAC_BIT_TDES0_UF)
658de6e0b19SCristian Ciocaltea 			netdev->stats.tx_fifo_errors++;
659de6e0b19SCristian Ciocaltea 
660de6e0b19SCristian Ciocaltea 		if (status & OWL_EMAC_BIT_TDES0_EC)
661de6e0b19SCristian Ciocaltea 			netdev->stats.tx_aborted_errors++;
662de6e0b19SCristian Ciocaltea 
663de6e0b19SCristian Ciocaltea 		if (status & OWL_EMAC_BIT_TDES0_LC)
664de6e0b19SCristian Ciocaltea 			netdev->stats.tx_window_errors++;
665de6e0b19SCristian Ciocaltea 
666de6e0b19SCristian Ciocaltea 		if (status & OWL_EMAC_BIT_TDES0_NC)
667de6e0b19SCristian Ciocaltea 			netdev->stats.tx_heartbeat_errors++;
668de6e0b19SCristian Ciocaltea 
669de6e0b19SCristian Ciocaltea 		if (status & OWL_EMAC_BIT_TDES0_LO)
670de6e0b19SCristian Ciocaltea 			netdev->stats.tx_carrier_errors++;
671de6e0b19SCristian Ciocaltea 	} else {
672de6e0b19SCristian Ciocaltea 		netdev->stats.tx_packets++;
673de6e0b19SCristian Ciocaltea 		netdev->stats.tx_bytes += ring->skbs[tx_tail]->len;
674de6e0b19SCristian Ciocaltea 	}
675de6e0b19SCristian Ciocaltea 
676de6e0b19SCristian Ciocaltea 	/* Some collisions occurred, but pkt has been transmitted. */
677de6e0b19SCristian Ciocaltea 	if (status & OWL_EMAC_BIT_TDES0_DE)
678de6e0b19SCristian Ciocaltea 		netdev->stats.collisions++;
679de6e0b19SCristian Ciocaltea 
680de6e0b19SCristian Ciocaltea 	skb = ring->skbs[tx_tail];
681de6e0b19SCristian Ciocaltea 	owl_emac_dma_unmap_tx(priv, skb, ring->skbs_dma[tx_tail]);
682de6e0b19SCristian Ciocaltea 	dev_kfree_skb(skb);
683de6e0b19SCristian Ciocaltea 
684de6e0b19SCristian Ciocaltea 	ring->skbs[tx_tail] = NULL;
685de6e0b19SCristian Ciocaltea 	ring->skbs_dma[tx_tail] = 0;
686de6e0b19SCristian Ciocaltea 
687de6e0b19SCristian Ciocaltea 	owl_emac_ring_pop_tail(ring);
688de6e0b19SCristian Ciocaltea 
689de6e0b19SCristian Ciocaltea 	if (unlikely(netif_queue_stopped(netdev)))
690de6e0b19SCristian Ciocaltea 		netif_wake_queue(netdev);
691de6e0b19SCristian Ciocaltea 
692de6e0b19SCristian Ciocaltea 	return true;
693de6e0b19SCristian Ciocaltea }
694de6e0b19SCristian Ciocaltea 
owl_emac_tx_complete(struct owl_emac_priv * priv)695de6e0b19SCristian Ciocaltea static void owl_emac_tx_complete(struct owl_emac_priv *priv)
696de6e0b19SCristian Ciocaltea {
697de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->tx_ring;
698de6e0b19SCristian Ciocaltea 	struct net_device *netdev = priv->netdev;
699de6e0b19SCristian Ciocaltea 	unsigned int tx_next;
700de6e0b19SCristian Ciocaltea 	u32 status;
701de6e0b19SCristian Ciocaltea 
702de6e0b19SCristian Ciocaltea 	spin_lock(&priv->lock);
703de6e0b19SCristian Ciocaltea 
704de6e0b19SCristian Ciocaltea 	while (ring->tail != ring->head) {
705de6e0b19SCristian Ciocaltea 		if (!owl_emac_tx_complete_tail(priv))
706de6e0b19SCristian Ciocaltea 			break;
707de6e0b19SCristian Ciocaltea 	}
708de6e0b19SCristian Ciocaltea 
709de6e0b19SCristian Ciocaltea 	/* FIXME: This is a workaround for a MAC hardware bug not clearing
710de6e0b19SCristian Ciocaltea 	 * (sometimes) the OWN bit for a transmitted frame descriptor.
711de6e0b19SCristian Ciocaltea 	 *
712de6e0b19SCristian Ciocaltea 	 * At this point, when TX queue is full, the tail descriptor has the
713de6e0b19SCristian Ciocaltea 	 * OWN bit set, which normally means the frame has not been processed
714de6e0b19SCristian Ciocaltea 	 * or transmitted yet. But if there is at least one descriptor in the
715de6e0b19SCristian Ciocaltea 	 * queue having the OWN bit cleared, we can safely assume the tail
716de6e0b19SCristian Ciocaltea 	 * frame has been also processed by the MAC hardware.
717de6e0b19SCristian Ciocaltea 	 *
718de6e0b19SCristian Ciocaltea 	 * If that's the case, let's force the frame completion by manually
719de6e0b19SCristian Ciocaltea 	 * clearing the OWN bit.
720de6e0b19SCristian Ciocaltea 	 */
721de6e0b19SCristian Ciocaltea 	if (unlikely(!owl_emac_ring_num_unused(ring))) {
722de6e0b19SCristian Ciocaltea 		tx_next = ring->tail;
723de6e0b19SCristian Ciocaltea 
724de6e0b19SCristian Ciocaltea 		while ((tx_next = owl_emac_ring_get_next(ring, tx_next)) != ring->head) {
725de6e0b19SCristian Ciocaltea 			status = READ_ONCE(ring->descs[tx_next].status);
726de6e0b19SCristian Ciocaltea 			dma_rmb(); /* Ensure data has been read before used. */
727de6e0b19SCristian Ciocaltea 
728de6e0b19SCristian Ciocaltea 			if (status & OWL_EMAC_BIT_TDES0_OWN)
729de6e0b19SCristian Ciocaltea 				continue;
730de6e0b19SCristian Ciocaltea 
731de6e0b19SCristian Ciocaltea 			netdev_dbg(netdev, "Found uncleared TX desc OWN bit\n");
732de6e0b19SCristian Ciocaltea 
733de6e0b19SCristian Ciocaltea 			status = READ_ONCE(ring->descs[ring->tail].status);
734de6e0b19SCristian Ciocaltea 			dma_rmb(); /* Ensure data has been read before used. */
735de6e0b19SCristian Ciocaltea 			status &= ~OWL_EMAC_BIT_TDES0_OWN;
736de6e0b19SCristian Ciocaltea 			WRITE_ONCE(ring->descs[ring->tail].status, status);
737de6e0b19SCristian Ciocaltea 
738de6e0b19SCristian Ciocaltea 			owl_emac_tx_complete_tail(priv);
739de6e0b19SCristian Ciocaltea 			break;
740de6e0b19SCristian Ciocaltea 		}
741de6e0b19SCristian Ciocaltea 	}
742de6e0b19SCristian Ciocaltea 
743de6e0b19SCristian Ciocaltea 	spin_unlock(&priv->lock);
744de6e0b19SCristian Ciocaltea }
745de6e0b19SCristian Ciocaltea 
owl_emac_rx_process(struct owl_emac_priv * priv,int budget)746de6e0b19SCristian Ciocaltea static int owl_emac_rx_process(struct owl_emac_priv *priv, int budget)
747de6e0b19SCristian Ciocaltea {
748de6e0b19SCristian Ciocaltea 	struct owl_emac_ring *ring = &priv->rx_ring;
749de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
750de6e0b19SCristian Ciocaltea 	struct net_device *netdev = priv->netdev;
751de6e0b19SCristian Ciocaltea 	struct owl_emac_ring_desc *desc;
752de6e0b19SCristian Ciocaltea 	struct sk_buff *curr_skb, *new_skb;
753de6e0b19SCristian Ciocaltea 	dma_addr_t curr_dma, new_dma;
754de6e0b19SCristian Ciocaltea 	unsigned int rx_tail, len;
755de6e0b19SCristian Ciocaltea 	u32 status;
756de6e0b19SCristian Ciocaltea 	int recv = 0;
757de6e0b19SCristian Ciocaltea 
758de6e0b19SCristian Ciocaltea 	while (recv < budget) {
759de6e0b19SCristian Ciocaltea 		spin_lock(&priv->lock);
760de6e0b19SCristian Ciocaltea 
761de6e0b19SCristian Ciocaltea 		rx_tail = ring->tail;
762de6e0b19SCristian Ciocaltea 		desc = &ring->descs[rx_tail];
763de6e0b19SCristian Ciocaltea 
764de6e0b19SCristian Ciocaltea 		status = READ_ONCE(desc->status);
765de6e0b19SCristian Ciocaltea 		dma_rmb(); /* Ensure data has been read before used. */
766de6e0b19SCristian Ciocaltea 
767de6e0b19SCristian Ciocaltea 		if (status & OWL_EMAC_BIT_RDES0_OWN) {
768de6e0b19SCristian Ciocaltea 			spin_unlock(&priv->lock);
769de6e0b19SCristian Ciocaltea 			break;
770de6e0b19SCristian Ciocaltea 		}
771de6e0b19SCristian Ciocaltea 
772de6e0b19SCristian Ciocaltea 		curr_skb = ring->skbs[rx_tail];
773de6e0b19SCristian Ciocaltea 		curr_dma = ring->skbs_dma[rx_tail];
774de6e0b19SCristian Ciocaltea 		owl_emac_ring_pop_tail(ring);
775de6e0b19SCristian Ciocaltea 
776de6e0b19SCristian Ciocaltea 		spin_unlock(&priv->lock);
777de6e0b19SCristian Ciocaltea 
778de6e0b19SCristian Ciocaltea 		if (status & (OWL_EMAC_BIT_RDES0_DE | OWL_EMAC_BIT_RDES0_RF |
779de6e0b19SCristian Ciocaltea 		    OWL_EMAC_BIT_RDES0_TL | OWL_EMAC_BIT_RDES0_CS |
780de6e0b19SCristian Ciocaltea 		    OWL_EMAC_BIT_RDES0_DB | OWL_EMAC_BIT_RDES0_CE |
781de6e0b19SCristian Ciocaltea 		    OWL_EMAC_BIT_RDES0_ZERO)) {
782de6e0b19SCristian Ciocaltea 			dev_dbg_ratelimited(&netdev->dev,
783de6e0b19SCristian Ciocaltea 					    "RX desc error status: 0x%08x\n",
784de6e0b19SCristian Ciocaltea 					    status);
785de6e0b19SCristian Ciocaltea 
786de6e0b19SCristian Ciocaltea 			if (status & OWL_EMAC_BIT_RDES0_DE)
787de6e0b19SCristian Ciocaltea 				netdev->stats.rx_over_errors++;
788de6e0b19SCristian Ciocaltea 
789de6e0b19SCristian Ciocaltea 			if (status & (OWL_EMAC_BIT_RDES0_RF | OWL_EMAC_BIT_RDES0_DB))
790de6e0b19SCristian Ciocaltea 				netdev->stats.rx_frame_errors++;
791de6e0b19SCristian Ciocaltea 
792de6e0b19SCristian Ciocaltea 			if (status & OWL_EMAC_BIT_RDES0_TL)
793de6e0b19SCristian Ciocaltea 				netdev->stats.rx_length_errors++;
794de6e0b19SCristian Ciocaltea 
795de6e0b19SCristian Ciocaltea 			if (status & OWL_EMAC_BIT_RDES0_CS)
796de6e0b19SCristian Ciocaltea 				netdev->stats.collisions++;
797de6e0b19SCristian Ciocaltea 
798de6e0b19SCristian Ciocaltea 			if (status & OWL_EMAC_BIT_RDES0_CE)
799de6e0b19SCristian Ciocaltea 				netdev->stats.rx_crc_errors++;
800de6e0b19SCristian Ciocaltea 
801de6e0b19SCristian Ciocaltea 			if (status & OWL_EMAC_BIT_RDES0_ZERO)
802de6e0b19SCristian Ciocaltea 				netdev->stats.rx_fifo_errors++;
803de6e0b19SCristian Ciocaltea 
804de6e0b19SCristian Ciocaltea 			goto drop_skb;
805de6e0b19SCristian Ciocaltea 		}
806de6e0b19SCristian Ciocaltea 
807de6e0b19SCristian Ciocaltea 		len = (status & OWL_EMAC_MSK_RDES0_FL) >> OWL_EMAC_OFF_RDES0_FL;
808de6e0b19SCristian Ciocaltea 		if (unlikely(len > OWL_EMAC_RX_FRAME_MAX_LEN)) {
809de6e0b19SCristian Ciocaltea 			netdev->stats.rx_length_errors++;
810de6e0b19SCristian Ciocaltea 			netdev_err(netdev, "invalid RX frame len: %u\n", len);
811de6e0b19SCristian Ciocaltea 			goto drop_skb;
812de6e0b19SCristian Ciocaltea 		}
813de6e0b19SCristian Ciocaltea 
814de6e0b19SCristian Ciocaltea 		/* Prepare new skb before receiving the current one. */
815de6e0b19SCristian Ciocaltea 		new_skb = owl_emac_alloc_skb(netdev);
816de6e0b19SCristian Ciocaltea 		if (unlikely(!new_skb))
817de6e0b19SCristian Ciocaltea 			goto drop_skb;
818de6e0b19SCristian Ciocaltea 
819de6e0b19SCristian Ciocaltea 		new_dma = owl_emac_dma_map_rx(priv, new_skb);
820de6e0b19SCristian Ciocaltea 		if (dma_mapping_error(dev, new_dma)) {
821de6e0b19SCristian Ciocaltea 			dev_kfree_skb(new_skb);
822de6e0b19SCristian Ciocaltea 			netdev_err(netdev, "RX DMA mapping failed\n");
823de6e0b19SCristian Ciocaltea 			goto drop_skb;
824de6e0b19SCristian Ciocaltea 		}
825de6e0b19SCristian Ciocaltea 
826de6e0b19SCristian Ciocaltea 		owl_emac_dma_unmap_rx(priv, curr_skb, curr_dma);
827de6e0b19SCristian Ciocaltea 
828de6e0b19SCristian Ciocaltea 		skb_put(curr_skb, len - ETH_FCS_LEN);
829de6e0b19SCristian Ciocaltea 		curr_skb->ip_summed = CHECKSUM_NONE;
830de6e0b19SCristian Ciocaltea 		curr_skb->protocol = eth_type_trans(curr_skb, netdev);
831de6e0b19SCristian Ciocaltea 		curr_skb->dev = netdev;
832de6e0b19SCristian Ciocaltea 
833de6e0b19SCristian Ciocaltea 		netif_receive_skb(curr_skb);
834de6e0b19SCristian Ciocaltea 
835de6e0b19SCristian Ciocaltea 		netdev->stats.rx_packets++;
836de6e0b19SCristian Ciocaltea 		netdev->stats.rx_bytes += len;
837de6e0b19SCristian Ciocaltea 		recv++;
838de6e0b19SCristian Ciocaltea 		goto push_skb;
839de6e0b19SCristian Ciocaltea 
840de6e0b19SCristian Ciocaltea drop_skb:
841de6e0b19SCristian Ciocaltea 		netdev->stats.rx_dropped++;
842de6e0b19SCristian Ciocaltea 		netdev->stats.rx_errors++;
843de6e0b19SCristian Ciocaltea 		/* Reuse the current skb. */
844de6e0b19SCristian Ciocaltea 		new_skb = curr_skb;
845de6e0b19SCristian Ciocaltea 		new_dma = curr_dma;
846de6e0b19SCristian Ciocaltea 
847de6e0b19SCristian Ciocaltea push_skb:
848de6e0b19SCristian Ciocaltea 		spin_lock(&priv->lock);
849de6e0b19SCristian Ciocaltea 
850de6e0b19SCristian Ciocaltea 		ring->skbs[ring->head] = new_skb;
851de6e0b19SCristian Ciocaltea 		ring->skbs_dma[ring->head] = new_dma;
852de6e0b19SCristian Ciocaltea 
853de6e0b19SCristian Ciocaltea 		WRITE_ONCE(desc->buf_addr, new_dma);
854de6e0b19SCristian Ciocaltea 		dma_wmb(); /* Flush descriptor before changing ownership. */
855de6e0b19SCristian Ciocaltea 		WRITE_ONCE(desc->status, OWL_EMAC_BIT_RDES0_OWN);
856de6e0b19SCristian Ciocaltea 
857de6e0b19SCristian Ciocaltea 		owl_emac_ring_push_head(ring);
858de6e0b19SCristian Ciocaltea 
859de6e0b19SCristian Ciocaltea 		spin_unlock(&priv->lock);
860de6e0b19SCristian Ciocaltea 	}
861de6e0b19SCristian Ciocaltea 
862de6e0b19SCristian Ciocaltea 	return recv;
863de6e0b19SCristian Ciocaltea }
864de6e0b19SCristian Ciocaltea 
owl_emac_poll(struct napi_struct * napi,int budget)865de6e0b19SCristian Ciocaltea static int owl_emac_poll(struct napi_struct *napi, int budget)
866de6e0b19SCristian Ciocaltea {
867de6e0b19SCristian Ciocaltea 	int work_done = 0, ru_cnt = 0, recv;
868de6e0b19SCristian Ciocaltea 	static int tx_err_cnt, rx_err_cnt;
869de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv;
870de6e0b19SCristian Ciocaltea 	u32 status, proc_status;
871de6e0b19SCristian Ciocaltea 
872de6e0b19SCristian Ciocaltea 	priv = container_of(napi, struct owl_emac_priv, napi);
873de6e0b19SCristian Ciocaltea 
874de6e0b19SCristian Ciocaltea 	while ((status = owl_emac_irq_clear(priv)) &
875de6e0b19SCristian Ciocaltea 	       (OWL_EMAC_BIT_MAC_CSR5_NIS | OWL_EMAC_BIT_MAC_CSR5_AIS)) {
876de6e0b19SCristian Ciocaltea 		recv = 0;
877de6e0b19SCristian Ciocaltea 
878de6e0b19SCristian Ciocaltea 		/* TX setup frame raises ETI instead of TI. */
879de6e0b19SCristian Ciocaltea 		if (status & (OWL_EMAC_BIT_MAC_CSR5_TI | OWL_EMAC_BIT_MAC_CSR5_ETI)) {
880de6e0b19SCristian Ciocaltea 			owl_emac_tx_complete(priv);
881de6e0b19SCristian Ciocaltea 			tx_err_cnt = 0;
882de6e0b19SCristian Ciocaltea 
883de6e0b19SCristian Ciocaltea 			/* Count MAC internal RX errors. */
884de6e0b19SCristian Ciocaltea 			proc_status = status & OWL_EMAC_MSK_MAC_CSR5_RS;
885de6e0b19SCristian Ciocaltea 			proc_status >>= OWL_EMAC_OFF_MAC_CSR5_RS;
886de6e0b19SCristian Ciocaltea 			if (proc_status == OWL_EMAC_VAL_MAC_CSR5_RS_DATA ||
887de6e0b19SCristian Ciocaltea 			    proc_status == OWL_EMAC_VAL_MAC_CSR5_RS_CDES ||
888de6e0b19SCristian Ciocaltea 			    proc_status == OWL_EMAC_VAL_MAC_CSR5_RS_FDES)
889de6e0b19SCristian Ciocaltea 				rx_err_cnt++;
890de6e0b19SCristian Ciocaltea 		}
891de6e0b19SCristian Ciocaltea 
892de6e0b19SCristian Ciocaltea 		if (status & OWL_EMAC_BIT_MAC_CSR5_RI) {
893de6e0b19SCristian Ciocaltea 			recv = owl_emac_rx_process(priv, budget - work_done);
894de6e0b19SCristian Ciocaltea 			rx_err_cnt = 0;
895de6e0b19SCristian Ciocaltea 
896de6e0b19SCristian Ciocaltea 			/* Count MAC internal TX errors. */
897de6e0b19SCristian Ciocaltea 			proc_status = status & OWL_EMAC_MSK_MAC_CSR5_TS;
898de6e0b19SCristian Ciocaltea 			proc_status >>= OWL_EMAC_OFF_MAC_CSR5_TS;
899de6e0b19SCristian Ciocaltea 			if (proc_status == OWL_EMAC_VAL_MAC_CSR5_TS_DATA ||
900de6e0b19SCristian Ciocaltea 			    proc_status == OWL_EMAC_VAL_MAC_CSR5_TS_CDES)
901de6e0b19SCristian Ciocaltea 				tx_err_cnt++;
902de6e0b19SCristian Ciocaltea 		} else if (status & OWL_EMAC_BIT_MAC_CSR5_RU) {
903de6e0b19SCristian Ciocaltea 			/* MAC AHB is in suspended state, will return to RX
904de6e0b19SCristian Ciocaltea 			 * descriptor processing when the host changes ownership
905de6e0b19SCristian Ciocaltea 			 * of the descriptor and either an RX poll demand CMD is
906de6e0b19SCristian Ciocaltea 			 * issued or a new frame is recognized by the MAC AHB.
907de6e0b19SCristian Ciocaltea 			 */
908de6e0b19SCristian Ciocaltea 			if (++ru_cnt == 2)
909de6e0b19SCristian Ciocaltea 				owl_emac_dma_cmd_resume_rx(priv);
910de6e0b19SCristian Ciocaltea 
911de6e0b19SCristian Ciocaltea 			recv = owl_emac_rx_process(priv, budget - work_done);
912de6e0b19SCristian Ciocaltea 
913de6e0b19SCristian Ciocaltea 			/* Guard against too many RU interrupts. */
914de6e0b19SCristian Ciocaltea 			if (ru_cnt > 3)
915de6e0b19SCristian Ciocaltea 				break;
916de6e0b19SCristian Ciocaltea 		}
917de6e0b19SCristian Ciocaltea 
918de6e0b19SCristian Ciocaltea 		work_done += recv;
919de6e0b19SCristian Ciocaltea 		if (work_done >= budget)
920de6e0b19SCristian Ciocaltea 			break;
921de6e0b19SCristian Ciocaltea 	}
922de6e0b19SCristian Ciocaltea 
923de6e0b19SCristian Ciocaltea 	if (work_done < budget) {
924de6e0b19SCristian Ciocaltea 		napi_complete_done(napi, work_done);
925de6e0b19SCristian Ciocaltea 		owl_emac_irq_enable(priv);
926de6e0b19SCristian Ciocaltea 	}
927de6e0b19SCristian Ciocaltea 
928de6e0b19SCristian Ciocaltea 	/* Reset MAC when getting too many internal TX or RX errors. */
929de6e0b19SCristian Ciocaltea 	if (tx_err_cnt > 10 || rx_err_cnt > 10) {
930de6e0b19SCristian Ciocaltea 		netdev_dbg(priv->netdev, "%s error status: 0x%08x\n",
931de6e0b19SCristian Ciocaltea 			   tx_err_cnt > 10 ? "TX" : "RX", status);
932de6e0b19SCristian Ciocaltea 		rx_err_cnt = 0;
933de6e0b19SCristian Ciocaltea 		tx_err_cnt = 0;
934de6e0b19SCristian Ciocaltea 		schedule_work(&priv->mac_reset_task);
935de6e0b19SCristian Ciocaltea 	}
936de6e0b19SCristian Ciocaltea 
937de6e0b19SCristian Ciocaltea 	return work_done;
938de6e0b19SCristian Ciocaltea }
939de6e0b19SCristian Ciocaltea 
owl_emac_mdio_clock_enable(struct owl_emac_priv * priv)940de6e0b19SCristian Ciocaltea static void owl_emac_mdio_clock_enable(struct owl_emac_priv *priv)
941de6e0b19SCristian Ciocaltea {
942de6e0b19SCristian Ciocaltea 	u32 val;
943de6e0b19SCristian Ciocaltea 
944de6e0b19SCristian Ciocaltea 	/* Enable MDC clock generation by adjusting CLKDIV according to
945de6e0b19SCristian Ciocaltea 	 * the vendor implementation of the original driver.
946de6e0b19SCristian Ciocaltea 	 */
947de6e0b19SCristian Ciocaltea 	val = owl_emac_reg_read(priv, OWL_EMAC_REG_MAC_CSR10);
948de6e0b19SCristian Ciocaltea 	val &= OWL_EMAC_MSK_MAC_CSR10_CLKDIV;
949de6e0b19SCristian Ciocaltea 	val |= OWL_EMAC_VAL_MAC_CSR10_CLKDIV_128 << OWL_EMAC_OFF_MAC_CSR10_CLKDIV;
950de6e0b19SCristian Ciocaltea 
951de6e0b19SCristian Ciocaltea 	val |= OWL_EMAC_BIT_MAC_CSR10_SB;
952de6e0b19SCristian Ciocaltea 	val |= OWL_EMAC_VAL_MAC_CSR10_OPCODE_CDS << OWL_EMAC_OFF_MAC_CSR10_OPCODE;
953de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR10, val);
954de6e0b19SCristian Ciocaltea }
955de6e0b19SCristian Ciocaltea 
owl_emac_core_hw_reset(struct owl_emac_priv * priv)956de6e0b19SCristian Ciocaltea static void owl_emac_core_hw_reset(struct owl_emac_priv *priv)
957de6e0b19SCristian Ciocaltea {
958de6e0b19SCristian Ciocaltea 	/* Trigger hardware reset. */
959de6e0b19SCristian Ciocaltea 	reset_control_assert(priv->reset);
960de6e0b19SCristian Ciocaltea 	usleep_range(10, 20);
961de6e0b19SCristian Ciocaltea 	reset_control_deassert(priv->reset);
962de6e0b19SCristian Ciocaltea 	usleep_range(100, 200);
963de6e0b19SCristian Ciocaltea }
964de6e0b19SCristian Ciocaltea 
owl_emac_core_sw_reset(struct owl_emac_priv * priv)965de6e0b19SCristian Ciocaltea static int owl_emac_core_sw_reset(struct owl_emac_priv *priv)
966de6e0b19SCristian Ciocaltea {
967de6e0b19SCristian Ciocaltea 	u32 val;
968de6e0b19SCristian Ciocaltea 	int ret;
969de6e0b19SCristian Ciocaltea 
970de6e0b19SCristian Ciocaltea 	/* Trigger software reset. */
971de6e0b19SCristian Ciocaltea 	owl_emac_reg_set(priv, OWL_EMAC_REG_MAC_CSR0, OWL_EMAC_BIT_MAC_CSR0_SWR);
972de6e0b19SCristian Ciocaltea 	ret = readl_poll_timeout(priv->base + OWL_EMAC_REG_MAC_CSR0,
973de6e0b19SCristian Ciocaltea 				 val, !(val & OWL_EMAC_BIT_MAC_CSR0_SWR),
974de6e0b19SCristian Ciocaltea 				 OWL_EMAC_POLL_DELAY_USEC,
975de6e0b19SCristian Ciocaltea 				 OWL_EMAC_RESET_POLL_TIMEOUT_USEC);
976de6e0b19SCristian Ciocaltea 	if (ret)
977de6e0b19SCristian Ciocaltea 		return ret;
978de6e0b19SCristian Ciocaltea 
979de6e0b19SCristian Ciocaltea 	if (priv->phy_mode == PHY_INTERFACE_MODE_RMII) {
980de6e0b19SCristian Ciocaltea 		/* Enable RMII and use the 50MHz rmii clk as output to PHY. */
981de6e0b19SCristian Ciocaltea 		val = 0;
982de6e0b19SCristian Ciocaltea 	} else {
983de6e0b19SCristian Ciocaltea 		/* Enable SMII and use the 125MHz rmii clk as output to PHY.
984de6e0b19SCristian Ciocaltea 		 * Additionally set SMII SYNC delay to 4 half cycle.
985de6e0b19SCristian Ciocaltea 		 */
986de6e0b19SCristian Ciocaltea 		val = 0x04 << OWL_EMAC_OFF_MAC_CTRL_SSDC;
987de6e0b19SCristian Ciocaltea 		val |= OWL_EMAC_BIT_MAC_CTRL_RSIS;
988de6e0b19SCristian Ciocaltea 	}
989de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CTRL, val);
990de6e0b19SCristian Ciocaltea 
991de6e0b19SCristian Ciocaltea 	/* MDC is disabled after reset. */
992de6e0b19SCristian Ciocaltea 	owl_emac_mdio_clock_enable(priv);
993de6e0b19SCristian Ciocaltea 
994de6e0b19SCristian Ciocaltea 	/* Set FIFO pause & restart threshold levels. */
995de6e0b19SCristian Ciocaltea 	val = 0x40 << OWL_EMAC_OFF_MAC_CSR19_FPTL;
996de6e0b19SCristian Ciocaltea 	val |= 0x10 << OWL_EMAC_OFF_MAC_CSR19_FRTL;
997de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR19, val);
998de6e0b19SCristian Ciocaltea 
999de6e0b19SCristian Ciocaltea 	/* Set flow control pause quanta time to ~100 ms. */
1000de6e0b19SCristian Ciocaltea 	val = 0x4FFF << OWL_EMAC_OFF_MAC_CSR18_PQT;
1001de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR18, val);
1002de6e0b19SCristian Ciocaltea 
1003de6e0b19SCristian Ciocaltea 	/* Setup interrupt mitigation. */
1004de6e0b19SCristian Ciocaltea 	val = 7 << OWL_EMAC_OFF_MAC_CSR11_NRP;
1005de6e0b19SCristian Ciocaltea 	val |= 4 << OWL_EMAC_OFF_MAC_CSR11_RT;
1006de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR11, val);
1007de6e0b19SCristian Ciocaltea 
1008de6e0b19SCristian Ciocaltea 	/* Set RX/TX rings base addresses. */
1009de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR3,
1010de6e0b19SCristian Ciocaltea 			   (u32)(priv->rx_ring.descs_dma));
1011de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR4,
1012de6e0b19SCristian Ciocaltea 			   (u32)(priv->tx_ring.descs_dma));
1013de6e0b19SCristian Ciocaltea 
1014de6e0b19SCristian Ciocaltea 	/* Setup initial operation mode. */
1015de6e0b19SCristian Ciocaltea 	val = OWL_EMAC_VAL_MAC_CSR6_SPEED_100M << OWL_EMAC_OFF_MAC_CSR6_SPEED;
1016de6e0b19SCristian Ciocaltea 	val |= OWL_EMAC_BIT_MAC_CSR6_FD;
1017de6e0b19SCristian Ciocaltea 	owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6,
1018de6e0b19SCristian Ciocaltea 			    OWL_EMAC_MSK_MAC_CSR6_SPEED |
1019de6e0b19SCristian Ciocaltea 			    OWL_EMAC_BIT_MAC_CSR6_FD, val);
1020de6e0b19SCristian Ciocaltea 	owl_emac_reg_clear(priv, OWL_EMAC_REG_MAC_CSR6,
1021de6e0b19SCristian Ciocaltea 			   OWL_EMAC_BIT_MAC_CSR6_PR | OWL_EMAC_BIT_MAC_CSR6_PM);
1022de6e0b19SCristian Ciocaltea 
1023de6e0b19SCristian Ciocaltea 	priv->link = 0;
1024de6e0b19SCristian Ciocaltea 	priv->speed = SPEED_UNKNOWN;
1025de6e0b19SCristian Ciocaltea 	priv->duplex = DUPLEX_UNKNOWN;
1026de6e0b19SCristian Ciocaltea 	priv->pause = 0;
1027de6e0b19SCristian Ciocaltea 	priv->mcaddr_list.count = 0;
1028de6e0b19SCristian Ciocaltea 
1029de6e0b19SCristian Ciocaltea 	return 0;
1030de6e0b19SCristian Ciocaltea }
1031de6e0b19SCristian Ciocaltea 
owl_emac_enable(struct net_device * netdev,bool start_phy)1032de6e0b19SCristian Ciocaltea static int owl_emac_enable(struct net_device *netdev, bool start_phy)
1033de6e0b19SCristian Ciocaltea {
1034de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1035de6e0b19SCristian Ciocaltea 	int ret;
1036de6e0b19SCristian Ciocaltea 
1037de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_stop(priv);
1038de6e0b19SCristian Ciocaltea 	owl_emac_irq_disable(priv);
1039de6e0b19SCristian Ciocaltea 	owl_emac_irq_clear(priv);
1040de6e0b19SCristian Ciocaltea 
1041de6e0b19SCristian Ciocaltea 	owl_emac_ring_prepare_tx(priv);
1042de6e0b19SCristian Ciocaltea 	ret = owl_emac_ring_prepare_rx(priv);
1043de6e0b19SCristian Ciocaltea 	if (ret)
1044de6e0b19SCristian Ciocaltea 		goto err_unprep;
1045de6e0b19SCristian Ciocaltea 
1046de6e0b19SCristian Ciocaltea 	ret = owl_emac_core_sw_reset(priv);
1047de6e0b19SCristian Ciocaltea 	if (ret) {
1048de6e0b19SCristian Ciocaltea 		netdev_err(netdev, "failed to soft reset MAC core: %d\n", ret);
1049de6e0b19SCristian Ciocaltea 		goto err_unprep;
1050de6e0b19SCristian Ciocaltea 	}
1051de6e0b19SCristian Ciocaltea 
1052de6e0b19SCristian Ciocaltea 	owl_emac_set_hw_mac_addr(netdev);
1053de6e0b19SCristian Ciocaltea 	owl_emac_setup_frame_xmit(priv);
1054de6e0b19SCristian Ciocaltea 
1055de6e0b19SCristian Ciocaltea 	netdev_reset_queue(netdev);
1056de6e0b19SCristian Ciocaltea 	napi_enable(&priv->napi);
1057de6e0b19SCristian Ciocaltea 
1058de6e0b19SCristian Ciocaltea 	owl_emac_irq_enable(priv);
1059de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_start(priv);
1060de6e0b19SCristian Ciocaltea 
1061de6e0b19SCristian Ciocaltea 	if (start_phy)
1062de6e0b19SCristian Ciocaltea 		phy_start(netdev->phydev);
1063de6e0b19SCristian Ciocaltea 
1064de6e0b19SCristian Ciocaltea 	netif_start_queue(netdev);
1065de6e0b19SCristian Ciocaltea 
1066de6e0b19SCristian Ciocaltea 	return 0;
1067de6e0b19SCristian Ciocaltea 
1068de6e0b19SCristian Ciocaltea err_unprep:
1069de6e0b19SCristian Ciocaltea 	owl_emac_ring_unprepare_rx(priv);
1070de6e0b19SCristian Ciocaltea 	owl_emac_ring_unprepare_tx(priv);
1071de6e0b19SCristian Ciocaltea 
1072de6e0b19SCristian Ciocaltea 	return ret;
1073de6e0b19SCristian Ciocaltea }
1074de6e0b19SCristian Ciocaltea 
owl_emac_disable(struct net_device * netdev,bool stop_phy)1075de6e0b19SCristian Ciocaltea static void owl_emac_disable(struct net_device *netdev, bool stop_phy)
1076de6e0b19SCristian Ciocaltea {
1077de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1078de6e0b19SCristian Ciocaltea 
1079de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_stop(priv);
1080de6e0b19SCristian Ciocaltea 	owl_emac_irq_disable(priv);
1081de6e0b19SCristian Ciocaltea 
1082de6e0b19SCristian Ciocaltea 	netif_stop_queue(netdev);
1083de6e0b19SCristian Ciocaltea 	napi_disable(&priv->napi);
1084de6e0b19SCristian Ciocaltea 
1085de6e0b19SCristian Ciocaltea 	if (stop_phy)
1086de6e0b19SCristian Ciocaltea 		phy_stop(netdev->phydev);
1087de6e0b19SCristian Ciocaltea 
1088de6e0b19SCristian Ciocaltea 	owl_emac_ring_unprepare_rx(priv);
1089de6e0b19SCristian Ciocaltea 	owl_emac_ring_unprepare_tx(priv);
1090de6e0b19SCristian Ciocaltea }
1091de6e0b19SCristian Ciocaltea 
owl_emac_ndo_open(struct net_device * netdev)1092de6e0b19SCristian Ciocaltea static int owl_emac_ndo_open(struct net_device *netdev)
1093de6e0b19SCristian Ciocaltea {
1094de6e0b19SCristian Ciocaltea 	return owl_emac_enable(netdev, true);
1095de6e0b19SCristian Ciocaltea }
1096de6e0b19SCristian Ciocaltea 
owl_emac_ndo_stop(struct net_device * netdev)1097de6e0b19SCristian Ciocaltea static int owl_emac_ndo_stop(struct net_device *netdev)
1098de6e0b19SCristian Ciocaltea {
1099de6e0b19SCristian Ciocaltea 	owl_emac_disable(netdev, true);
1100de6e0b19SCristian Ciocaltea 
1101de6e0b19SCristian Ciocaltea 	return 0;
1102de6e0b19SCristian Ciocaltea }
1103de6e0b19SCristian Ciocaltea 
owl_emac_set_multicast(struct net_device * netdev,int count)1104de6e0b19SCristian Ciocaltea static void owl_emac_set_multicast(struct net_device *netdev, int count)
1105de6e0b19SCristian Ciocaltea {
1106de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1107de6e0b19SCristian Ciocaltea 	struct netdev_hw_addr *ha;
1108de6e0b19SCristian Ciocaltea 	int index = 0;
1109de6e0b19SCristian Ciocaltea 
1110de6e0b19SCristian Ciocaltea 	if (count <= 0) {
1111de6e0b19SCristian Ciocaltea 		priv->mcaddr_list.count = 0;
1112de6e0b19SCristian Ciocaltea 		return;
1113de6e0b19SCristian Ciocaltea 	}
1114de6e0b19SCristian Ciocaltea 
1115de6e0b19SCristian Ciocaltea 	netdev_for_each_mc_addr(ha, netdev) {
1116de6e0b19SCristian Ciocaltea 		if (!is_multicast_ether_addr(ha->addr))
1117de6e0b19SCristian Ciocaltea 			continue;
1118de6e0b19SCristian Ciocaltea 
1119de6e0b19SCristian Ciocaltea 		WARN_ON(index >= OWL_EMAC_MAX_MULTICAST_ADDRS);
1120de6e0b19SCristian Ciocaltea 		ether_addr_copy(priv->mcaddr_list.addrs[index++], ha->addr);
1121de6e0b19SCristian Ciocaltea 	}
1122de6e0b19SCristian Ciocaltea 
1123de6e0b19SCristian Ciocaltea 	priv->mcaddr_list.count = index;
1124de6e0b19SCristian Ciocaltea 
1125de6e0b19SCristian Ciocaltea 	owl_emac_setup_frame_xmit(priv);
1126de6e0b19SCristian Ciocaltea }
1127de6e0b19SCristian Ciocaltea 
owl_emac_ndo_set_rx_mode(struct net_device * netdev)1128de6e0b19SCristian Ciocaltea static void owl_emac_ndo_set_rx_mode(struct net_device *netdev)
1129de6e0b19SCristian Ciocaltea {
1130de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1131de6e0b19SCristian Ciocaltea 	u32 status, val = 0;
1132de6e0b19SCristian Ciocaltea 	int mcast_count = 0;
1133de6e0b19SCristian Ciocaltea 
1134de6e0b19SCristian Ciocaltea 	if (netdev->flags & IFF_PROMISC) {
1135de6e0b19SCristian Ciocaltea 		val = OWL_EMAC_BIT_MAC_CSR6_PR;
1136de6e0b19SCristian Ciocaltea 	} else if (netdev->flags & IFF_ALLMULTI) {
1137de6e0b19SCristian Ciocaltea 		val = OWL_EMAC_BIT_MAC_CSR6_PM;
1138de6e0b19SCristian Ciocaltea 	} else if (netdev->flags & IFF_MULTICAST) {
1139de6e0b19SCristian Ciocaltea 		mcast_count = netdev_mc_count(netdev);
1140de6e0b19SCristian Ciocaltea 
1141de6e0b19SCristian Ciocaltea 		if (mcast_count > OWL_EMAC_MAX_MULTICAST_ADDRS) {
1142de6e0b19SCristian Ciocaltea 			val = OWL_EMAC_BIT_MAC_CSR6_PM;
1143de6e0b19SCristian Ciocaltea 			mcast_count = 0;
1144de6e0b19SCristian Ciocaltea 		}
1145de6e0b19SCristian Ciocaltea 	}
1146de6e0b19SCristian Ciocaltea 
1147de6e0b19SCristian Ciocaltea 	spin_lock_bh(&priv->lock);
1148de6e0b19SCristian Ciocaltea 
1149de6e0b19SCristian Ciocaltea 	/* Temporarily stop DMA TX & RX. */
1150de6e0b19SCristian Ciocaltea 	status = owl_emac_dma_cmd_stop(priv);
1151de6e0b19SCristian Ciocaltea 
1152de6e0b19SCristian Ciocaltea 	/* Update operation modes. */
1153de6e0b19SCristian Ciocaltea 	owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6,
1154de6e0b19SCristian Ciocaltea 			    OWL_EMAC_BIT_MAC_CSR6_PR | OWL_EMAC_BIT_MAC_CSR6_PM,
1155de6e0b19SCristian Ciocaltea 			    val);
1156de6e0b19SCristian Ciocaltea 
1157de6e0b19SCristian Ciocaltea 	/* Restore DMA TX & RX status. */
1158de6e0b19SCristian Ciocaltea 	owl_emac_dma_cmd_set(priv, status);
1159de6e0b19SCristian Ciocaltea 
1160de6e0b19SCristian Ciocaltea 	spin_unlock_bh(&priv->lock);
1161de6e0b19SCristian Ciocaltea 
1162de6e0b19SCristian Ciocaltea 	/* Set/reset multicast addr list. */
1163de6e0b19SCristian Ciocaltea 	owl_emac_set_multicast(netdev, mcast_count);
1164de6e0b19SCristian Ciocaltea }
1165de6e0b19SCristian Ciocaltea 
owl_emac_ndo_set_mac_addr(struct net_device * netdev,void * addr)1166de6e0b19SCristian Ciocaltea static int owl_emac_ndo_set_mac_addr(struct net_device *netdev, void *addr)
1167de6e0b19SCristian Ciocaltea {
1168de6e0b19SCristian Ciocaltea 	struct sockaddr *skaddr = addr;
1169de6e0b19SCristian Ciocaltea 
1170de6e0b19SCristian Ciocaltea 	if (!is_valid_ether_addr(skaddr->sa_data))
1171de6e0b19SCristian Ciocaltea 		return -EADDRNOTAVAIL;
1172de6e0b19SCristian Ciocaltea 
1173de6e0b19SCristian Ciocaltea 	if (netif_running(netdev))
1174de6e0b19SCristian Ciocaltea 		return -EBUSY;
1175de6e0b19SCristian Ciocaltea 
1176a05e4c0aSJakub Kicinski 	eth_hw_addr_set(netdev, skaddr->sa_data);
1177de6e0b19SCristian Ciocaltea 	owl_emac_set_hw_mac_addr(netdev);
1178de6e0b19SCristian Ciocaltea 
1179de6e0b19SCristian Ciocaltea 	return owl_emac_setup_frame_xmit(netdev_priv(netdev));
1180de6e0b19SCristian Ciocaltea }
1181de6e0b19SCristian Ciocaltea 
owl_emac_ndo_eth_ioctl(struct net_device * netdev,struct ifreq * req,int cmd)1182a7605370SArnd Bergmann static int owl_emac_ndo_eth_ioctl(struct net_device *netdev,
1183de6e0b19SCristian Ciocaltea 				  struct ifreq *req, int cmd)
1184de6e0b19SCristian Ciocaltea {
1185de6e0b19SCristian Ciocaltea 	if (!netif_running(netdev))
1186de6e0b19SCristian Ciocaltea 		return -EINVAL;
1187de6e0b19SCristian Ciocaltea 
1188de6e0b19SCristian Ciocaltea 	return phy_mii_ioctl(netdev->phydev, req, cmd);
1189de6e0b19SCristian Ciocaltea }
1190de6e0b19SCristian Ciocaltea 
owl_emac_ndo_tx_timeout(struct net_device * netdev,unsigned int txqueue)1191de6e0b19SCristian Ciocaltea static void owl_emac_ndo_tx_timeout(struct net_device *netdev,
1192de6e0b19SCristian Ciocaltea 				    unsigned int txqueue)
1193de6e0b19SCristian Ciocaltea {
1194de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1195de6e0b19SCristian Ciocaltea 
1196de6e0b19SCristian Ciocaltea 	schedule_work(&priv->mac_reset_task);
1197de6e0b19SCristian Ciocaltea }
1198de6e0b19SCristian Ciocaltea 
owl_emac_reset_task(struct work_struct * work)1199de6e0b19SCristian Ciocaltea static void owl_emac_reset_task(struct work_struct *work)
1200de6e0b19SCristian Ciocaltea {
1201de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv;
1202de6e0b19SCristian Ciocaltea 
1203de6e0b19SCristian Ciocaltea 	priv = container_of(work, struct owl_emac_priv, mac_reset_task);
1204de6e0b19SCristian Ciocaltea 
1205de6e0b19SCristian Ciocaltea 	netdev_dbg(priv->netdev, "resetting MAC\n");
1206de6e0b19SCristian Ciocaltea 	owl_emac_disable(priv->netdev, false);
1207de6e0b19SCristian Ciocaltea 	owl_emac_enable(priv->netdev, false);
1208de6e0b19SCristian Ciocaltea }
1209de6e0b19SCristian Ciocaltea 
1210de6e0b19SCristian Ciocaltea static struct net_device_stats *
owl_emac_ndo_get_stats(struct net_device * netdev)1211de6e0b19SCristian Ciocaltea owl_emac_ndo_get_stats(struct net_device *netdev)
1212de6e0b19SCristian Ciocaltea {
1213de6e0b19SCristian Ciocaltea 	/* FIXME: If possible, try to get stats from MAC hardware registers
1214de6e0b19SCristian Ciocaltea 	 * instead of tracking them manually in the driver.
1215de6e0b19SCristian Ciocaltea 	 */
1216de6e0b19SCristian Ciocaltea 
1217de6e0b19SCristian Ciocaltea 	return &netdev->stats;
1218de6e0b19SCristian Ciocaltea }
1219de6e0b19SCristian Ciocaltea 
1220de6e0b19SCristian Ciocaltea static const struct net_device_ops owl_emac_netdev_ops = {
1221de6e0b19SCristian Ciocaltea 	.ndo_open		= owl_emac_ndo_open,
1222de6e0b19SCristian Ciocaltea 	.ndo_stop		= owl_emac_ndo_stop,
1223de6e0b19SCristian Ciocaltea 	.ndo_start_xmit		= owl_emac_ndo_start_xmit,
1224de6e0b19SCristian Ciocaltea 	.ndo_set_rx_mode	= owl_emac_ndo_set_rx_mode,
1225de6e0b19SCristian Ciocaltea 	.ndo_set_mac_address	= owl_emac_ndo_set_mac_addr,
1226de6e0b19SCristian Ciocaltea 	.ndo_validate_addr	= eth_validate_addr,
1227a7605370SArnd Bergmann 	.ndo_eth_ioctl		= owl_emac_ndo_eth_ioctl,
1228de6e0b19SCristian Ciocaltea 	.ndo_tx_timeout         = owl_emac_ndo_tx_timeout,
1229de6e0b19SCristian Ciocaltea 	.ndo_get_stats		= owl_emac_ndo_get_stats,
1230de6e0b19SCristian Ciocaltea };
1231de6e0b19SCristian Ciocaltea 
owl_emac_ethtool_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)1232de6e0b19SCristian Ciocaltea static void owl_emac_ethtool_get_drvinfo(struct net_device *dev,
1233de6e0b19SCristian Ciocaltea 					 struct ethtool_drvinfo *info)
1234de6e0b19SCristian Ciocaltea {
1235de6e0b19SCristian Ciocaltea 	strscpy(info->driver, OWL_EMAC_DRVNAME, sizeof(info->driver));
1236de6e0b19SCristian Ciocaltea }
1237de6e0b19SCristian Ciocaltea 
owl_emac_ethtool_get_msglevel(struct net_device * netdev)1238de6e0b19SCristian Ciocaltea static u32 owl_emac_ethtool_get_msglevel(struct net_device *netdev)
1239de6e0b19SCristian Ciocaltea {
1240de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1241de6e0b19SCristian Ciocaltea 
1242de6e0b19SCristian Ciocaltea 	return priv->msg_enable;
1243de6e0b19SCristian Ciocaltea }
1244de6e0b19SCristian Ciocaltea 
owl_emac_ethtool_set_msglevel(struct net_device * ndev,u32 val)1245de6e0b19SCristian Ciocaltea static void owl_emac_ethtool_set_msglevel(struct net_device *ndev, u32 val)
1246de6e0b19SCristian Ciocaltea {
1247de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(ndev);
1248de6e0b19SCristian Ciocaltea 
1249de6e0b19SCristian Ciocaltea 	priv->msg_enable = val;
1250de6e0b19SCristian Ciocaltea }
1251de6e0b19SCristian Ciocaltea 
1252de6e0b19SCristian Ciocaltea static const struct ethtool_ops owl_emac_ethtool_ops = {
1253de6e0b19SCristian Ciocaltea 	.get_drvinfo		= owl_emac_ethtool_get_drvinfo,
1254de6e0b19SCristian Ciocaltea 	.get_link		= ethtool_op_get_link,
1255de6e0b19SCristian Ciocaltea 	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
1256de6e0b19SCristian Ciocaltea 	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
1257de6e0b19SCristian Ciocaltea 	.get_msglevel		= owl_emac_ethtool_get_msglevel,
1258de6e0b19SCristian Ciocaltea 	.set_msglevel		= owl_emac_ethtool_set_msglevel,
1259de6e0b19SCristian Ciocaltea };
1260de6e0b19SCristian Ciocaltea 
owl_emac_mdio_wait(struct owl_emac_priv * priv)1261de6e0b19SCristian Ciocaltea static int owl_emac_mdio_wait(struct owl_emac_priv *priv)
1262de6e0b19SCristian Ciocaltea {
1263de6e0b19SCristian Ciocaltea 	u32 val;
1264de6e0b19SCristian Ciocaltea 
1265de6e0b19SCristian Ciocaltea 	/* Wait while data transfer is in progress. */
1266de6e0b19SCristian Ciocaltea 	return readl_poll_timeout(priv->base + OWL_EMAC_REG_MAC_CSR10,
1267de6e0b19SCristian Ciocaltea 				  val, !(val & OWL_EMAC_BIT_MAC_CSR10_SB),
1268de6e0b19SCristian Ciocaltea 				  OWL_EMAC_POLL_DELAY_USEC,
1269de6e0b19SCristian Ciocaltea 				  OWL_EMAC_MDIO_POLL_TIMEOUT_USEC);
1270de6e0b19SCristian Ciocaltea }
1271de6e0b19SCristian Ciocaltea 
owl_emac_mdio_read(struct mii_bus * bus,int addr,int regnum)1272de6e0b19SCristian Ciocaltea static int owl_emac_mdio_read(struct mii_bus *bus, int addr, int regnum)
1273de6e0b19SCristian Ciocaltea {
1274de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = bus->priv;
1275de6e0b19SCristian Ciocaltea 	u32 data, tmp;
1276de6e0b19SCristian Ciocaltea 	int ret;
1277de6e0b19SCristian Ciocaltea 
1278de6e0b19SCristian Ciocaltea 	data = OWL_EMAC_BIT_MAC_CSR10_SB;
1279de6e0b19SCristian Ciocaltea 	data |= OWL_EMAC_VAL_MAC_CSR10_OPCODE_RD << OWL_EMAC_OFF_MAC_CSR10_OPCODE;
1280de6e0b19SCristian Ciocaltea 
1281de6e0b19SCristian Ciocaltea 	tmp = addr << OWL_EMAC_OFF_MAC_CSR10_PHYADD;
1282de6e0b19SCristian Ciocaltea 	data |= tmp & OWL_EMAC_MSK_MAC_CSR10_PHYADD;
1283de6e0b19SCristian Ciocaltea 
1284de6e0b19SCristian Ciocaltea 	tmp = regnum << OWL_EMAC_OFF_MAC_CSR10_REGADD;
1285de6e0b19SCristian Ciocaltea 	data |= tmp & OWL_EMAC_MSK_MAC_CSR10_REGADD;
1286de6e0b19SCristian Ciocaltea 
1287de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR10, data);
1288de6e0b19SCristian Ciocaltea 
1289de6e0b19SCristian Ciocaltea 	ret = owl_emac_mdio_wait(priv);
1290de6e0b19SCristian Ciocaltea 	if (ret)
1291de6e0b19SCristian Ciocaltea 		return ret;
1292de6e0b19SCristian Ciocaltea 
1293de6e0b19SCristian Ciocaltea 	data = owl_emac_reg_read(priv, OWL_EMAC_REG_MAC_CSR10);
1294de6e0b19SCristian Ciocaltea 	data &= OWL_EMAC_MSK_MAC_CSR10_DATA;
1295de6e0b19SCristian Ciocaltea 
1296de6e0b19SCristian Ciocaltea 	return data;
1297de6e0b19SCristian Ciocaltea }
1298de6e0b19SCristian Ciocaltea 
1299de6e0b19SCristian Ciocaltea static int
owl_emac_mdio_write(struct mii_bus * bus,int addr,int regnum,u16 val)1300de6e0b19SCristian Ciocaltea owl_emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
1301de6e0b19SCristian Ciocaltea {
1302de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = bus->priv;
1303de6e0b19SCristian Ciocaltea 	u32 data, tmp;
1304de6e0b19SCristian Ciocaltea 
1305de6e0b19SCristian Ciocaltea 	data = OWL_EMAC_BIT_MAC_CSR10_SB;
1306de6e0b19SCristian Ciocaltea 	data |= OWL_EMAC_VAL_MAC_CSR10_OPCODE_WR << OWL_EMAC_OFF_MAC_CSR10_OPCODE;
1307de6e0b19SCristian Ciocaltea 
1308de6e0b19SCristian Ciocaltea 	tmp = addr << OWL_EMAC_OFF_MAC_CSR10_PHYADD;
1309de6e0b19SCristian Ciocaltea 	data |= tmp & OWL_EMAC_MSK_MAC_CSR10_PHYADD;
1310de6e0b19SCristian Ciocaltea 
1311de6e0b19SCristian Ciocaltea 	tmp = regnum << OWL_EMAC_OFF_MAC_CSR10_REGADD;
1312de6e0b19SCristian Ciocaltea 	data |= tmp & OWL_EMAC_MSK_MAC_CSR10_REGADD;
1313de6e0b19SCristian Ciocaltea 
1314de6e0b19SCristian Ciocaltea 	data |= val & OWL_EMAC_MSK_MAC_CSR10_DATA;
1315de6e0b19SCristian Ciocaltea 
1316de6e0b19SCristian Ciocaltea 	owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR10, data);
1317de6e0b19SCristian Ciocaltea 
1318de6e0b19SCristian Ciocaltea 	return owl_emac_mdio_wait(priv);
1319de6e0b19SCristian Ciocaltea }
1320de6e0b19SCristian Ciocaltea 
owl_emac_mdio_init(struct net_device * netdev)1321de6e0b19SCristian Ciocaltea static int owl_emac_mdio_init(struct net_device *netdev)
1322de6e0b19SCristian Ciocaltea {
1323de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1324de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
1325de6e0b19SCristian Ciocaltea 	struct device_node *mdio_node;
1326de6e0b19SCristian Ciocaltea 	int ret;
1327de6e0b19SCristian Ciocaltea 
1328de6e0b19SCristian Ciocaltea 	mdio_node = of_get_child_by_name(dev->of_node, "mdio");
1329de6e0b19SCristian Ciocaltea 	if (!mdio_node)
1330de6e0b19SCristian Ciocaltea 		return -ENODEV;
1331de6e0b19SCristian Ciocaltea 
1332de6e0b19SCristian Ciocaltea 	if (!of_device_is_available(mdio_node)) {
1333de6e0b19SCristian Ciocaltea 		ret = -ENODEV;
1334de6e0b19SCristian Ciocaltea 		goto err_put_node;
1335de6e0b19SCristian Ciocaltea 	}
1336de6e0b19SCristian Ciocaltea 
1337de6e0b19SCristian Ciocaltea 	priv->mii = devm_mdiobus_alloc(dev);
1338de6e0b19SCristian Ciocaltea 	if (!priv->mii) {
1339de6e0b19SCristian Ciocaltea 		ret = -ENOMEM;
1340de6e0b19SCristian Ciocaltea 		goto err_put_node;
1341de6e0b19SCristian Ciocaltea 	}
1342de6e0b19SCristian Ciocaltea 
1343de6e0b19SCristian Ciocaltea 	snprintf(priv->mii->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
1344de6e0b19SCristian Ciocaltea 	priv->mii->name = "owl-emac-mdio";
1345de6e0b19SCristian Ciocaltea 	priv->mii->parent = dev;
1346de6e0b19SCristian Ciocaltea 	priv->mii->read = owl_emac_mdio_read;
1347de6e0b19SCristian Ciocaltea 	priv->mii->write = owl_emac_mdio_write;
1348de6e0b19SCristian Ciocaltea 	priv->mii->phy_mask = ~0; /* Mask out all PHYs from auto probing. */
1349de6e0b19SCristian Ciocaltea 	priv->mii->priv = priv;
1350de6e0b19SCristian Ciocaltea 
1351de6e0b19SCristian Ciocaltea 	ret = devm_of_mdiobus_register(dev, priv->mii, mdio_node);
1352de6e0b19SCristian Ciocaltea 
1353de6e0b19SCristian Ciocaltea err_put_node:
1354de6e0b19SCristian Ciocaltea 	of_node_put(mdio_node);
1355de6e0b19SCristian Ciocaltea 	return ret;
1356de6e0b19SCristian Ciocaltea }
1357de6e0b19SCristian Ciocaltea 
owl_emac_phy_init(struct net_device * netdev)1358de6e0b19SCristian Ciocaltea static int owl_emac_phy_init(struct net_device *netdev)
1359de6e0b19SCristian Ciocaltea {
1360de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1361de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
1362de6e0b19SCristian Ciocaltea 	struct phy_device *phy;
1363de6e0b19SCristian Ciocaltea 
1364de6e0b19SCristian Ciocaltea 	phy = of_phy_get_and_connect(netdev, dev->of_node,
1365de6e0b19SCristian Ciocaltea 				     owl_emac_adjust_link);
1366de6e0b19SCristian Ciocaltea 	if (!phy)
1367de6e0b19SCristian Ciocaltea 		return -ENODEV;
1368de6e0b19SCristian Ciocaltea 
1369de6e0b19SCristian Ciocaltea 	phy_set_sym_pause(phy, true, true, true);
1370de6e0b19SCristian Ciocaltea 
1371de6e0b19SCristian Ciocaltea 	if (netif_msg_link(priv))
1372de6e0b19SCristian Ciocaltea 		phy_attached_info(phy);
1373de6e0b19SCristian Ciocaltea 
1374de6e0b19SCristian Ciocaltea 	return 0;
1375de6e0b19SCristian Ciocaltea }
1376de6e0b19SCristian Ciocaltea 
owl_emac_get_mac_addr(struct net_device * netdev)1377de6e0b19SCristian Ciocaltea static void owl_emac_get_mac_addr(struct net_device *netdev)
1378de6e0b19SCristian Ciocaltea {
1379de6e0b19SCristian Ciocaltea 	struct device *dev = netdev->dev.parent;
1380de6e0b19SCristian Ciocaltea 	int ret;
1381de6e0b19SCristian Ciocaltea 
13824d04cdc5SJakub Kicinski 	ret = platform_get_ethdev_address(dev, netdev);
1383de6e0b19SCristian Ciocaltea 	if (!ret && is_valid_ether_addr(netdev->dev_addr))
1384de6e0b19SCristian Ciocaltea 		return;
1385de6e0b19SCristian Ciocaltea 
1386de6e0b19SCristian Ciocaltea 	eth_hw_addr_random(netdev);
1387de6e0b19SCristian Ciocaltea 	dev_warn(dev, "using random MAC address %pM\n", netdev->dev_addr);
1388de6e0b19SCristian Ciocaltea }
1389de6e0b19SCristian Ciocaltea 
owl_emac_suspend(struct device * dev)1390de6e0b19SCristian Ciocaltea static __maybe_unused int owl_emac_suspend(struct device *dev)
1391de6e0b19SCristian Ciocaltea {
1392de6e0b19SCristian Ciocaltea 	struct net_device *netdev = dev_get_drvdata(dev);
1393de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1394de6e0b19SCristian Ciocaltea 
1395de6e0b19SCristian Ciocaltea 	disable_irq(netdev->irq);
1396de6e0b19SCristian Ciocaltea 
1397de6e0b19SCristian Ciocaltea 	if (netif_running(netdev)) {
1398de6e0b19SCristian Ciocaltea 		owl_emac_disable(netdev, true);
1399de6e0b19SCristian Ciocaltea 		netif_device_detach(netdev);
1400de6e0b19SCristian Ciocaltea 	}
1401de6e0b19SCristian Ciocaltea 
1402de6e0b19SCristian Ciocaltea 	clk_bulk_disable_unprepare(OWL_EMAC_NCLKS, priv->clks);
1403de6e0b19SCristian Ciocaltea 
1404de6e0b19SCristian Ciocaltea 	return 0;
1405de6e0b19SCristian Ciocaltea }
1406de6e0b19SCristian Ciocaltea 
owl_emac_resume(struct device * dev)1407de6e0b19SCristian Ciocaltea static __maybe_unused int owl_emac_resume(struct device *dev)
1408de6e0b19SCristian Ciocaltea {
1409de6e0b19SCristian Ciocaltea 	struct net_device *netdev = dev_get_drvdata(dev);
1410de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = netdev_priv(netdev);
1411de6e0b19SCristian Ciocaltea 	int ret;
1412de6e0b19SCristian Ciocaltea 
1413de6e0b19SCristian Ciocaltea 	ret = clk_bulk_prepare_enable(OWL_EMAC_NCLKS, priv->clks);
1414de6e0b19SCristian Ciocaltea 	if (ret)
1415de6e0b19SCristian Ciocaltea 		return ret;
1416de6e0b19SCristian Ciocaltea 
1417de6e0b19SCristian Ciocaltea 	if (netif_running(netdev)) {
1418de6e0b19SCristian Ciocaltea 		owl_emac_core_hw_reset(priv);
1419de6e0b19SCristian Ciocaltea 		owl_emac_core_sw_reset(priv);
1420de6e0b19SCristian Ciocaltea 
1421de6e0b19SCristian Ciocaltea 		ret = owl_emac_enable(netdev, true);
1422de6e0b19SCristian Ciocaltea 		if (ret) {
1423de6e0b19SCristian Ciocaltea 			clk_bulk_disable_unprepare(OWL_EMAC_NCLKS, priv->clks);
1424de6e0b19SCristian Ciocaltea 			return ret;
1425de6e0b19SCristian Ciocaltea 		}
1426de6e0b19SCristian Ciocaltea 
1427de6e0b19SCristian Ciocaltea 		netif_device_attach(netdev);
1428de6e0b19SCristian Ciocaltea 	}
1429de6e0b19SCristian Ciocaltea 
1430de6e0b19SCristian Ciocaltea 	enable_irq(netdev->irq);
1431de6e0b19SCristian Ciocaltea 
1432de6e0b19SCristian Ciocaltea 	return 0;
1433de6e0b19SCristian Ciocaltea }
1434de6e0b19SCristian Ciocaltea 
owl_emac_clk_disable_unprepare(void * data)1435de6e0b19SCristian Ciocaltea static void owl_emac_clk_disable_unprepare(void *data)
1436de6e0b19SCristian Ciocaltea {
1437de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = data;
1438de6e0b19SCristian Ciocaltea 
1439de6e0b19SCristian Ciocaltea 	clk_bulk_disable_unprepare(OWL_EMAC_NCLKS, priv->clks);
1440de6e0b19SCristian Ciocaltea }
1441de6e0b19SCristian Ciocaltea 
owl_emac_clk_set_rate(struct owl_emac_priv * priv)1442de6e0b19SCristian Ciocaltea static int owl_emac_clk_set_rate(struct owl_emac_priv *priv)
1443de6e0b19SCristian Ciocaltea {
1444de6e0b19SCristian Ciocaltea 	struct device *dev = owl_emac_get_dev(priv);
1445de6e0b19SCristian Ciocaltea 	unsigned long rate;
1446de6e0b19SCristian Ciocaltea 	int ret;
1447de6e0b19SCristian Ciocaltea 
1448de6e0b19SCristian Ciocaltea 	switch (priv->phy_mode) {
1449de6e0b19SCristian Ciocaltea 	case PHY_INTERFACE_MODE_RMII:
1450de6e0b19SCristian Ciocaltea 		rate = 50000000;
1451de6e0b19SCristian Ciocaltea 		break;
1452de6e0b19SCristian Ciocaltea 
1453de6e0b19SCristian Ciocaltea 	case PHY_INTERFACE_MODE_SMII:
1454de6e0b19SCristian Ciocaltea 		rate = 125000000;
1455de6e0b19SCristian Ciocaltea 		break;
1456de6e0b19SCristian Ciocaltea 
1457de6e0b19SCristian Ciocaltea 	default:
1458de6e0b19SCristian Ciocaltea 		dev_err(dev, "unsupported phy interface mode %d\n",
1459de6e0b19SCristian Ciocaltea 			priv->phy_mode);
1460de6e0b19SCristian Ciocaltea 		return -EOPNOTSUPP;
1461de6e0b19SCristian Ciocaltea 	}
1462de6e0b19SCristian Ciocaltea 
1463de6e0b19SCristian Ciocaltea 	ret = clk_set_rate(priv->clks[OWL_EMAC_CLK_RMII].clk, rate);
1464de6e0b19SCristian Ciocaltea 	if (ret)
1465de6e0b19SCristian Ciocaltea 		dev_err(dev, "failed to set RMII clock rate: %d\n", ret);
1466de6e0b19SCristian Ciocaltea 
1467de6e0b19SCristian Ciocaltea 	return ret;
1468de6e0b19SCristian Ciocaltea }
1469de6e0b19SCristian Ciocaltea 
owl_emac_probe(struct platform_device * pdev)1470de6e0b19SCristian Ciocaltea static int owl_emac_probe(struct platform_device *pdev)
1471de6e0b19SCristian Ciocaltea {
1472de6e0b19SCristian Ciocaltea 	struct device *dev = &pdev->dev;
1473de6e0b19SCristian Ciocaltea 	struct net_device *netdev;
1474de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv;
1475de6e0b19SCristian Ciocaltea 	int ret, i;
1476de6e0b19SCristian Ciocaltea 
1477de6e0b19SCristian Ciocaltea 	netdev = devm_alloc_etherdev(dev, sizeof(*priv));
1478de6e0b19SCristian Ciocaltea 	if (!netdev)
1479de6e0b19SCristian Ciocaltea 		return -ENOMEM;
1480de6e0b19SCristian Ciocaltea 
1481de6e0b19SCristian Ciocaltea 	platform_set_drvdata(pdev, netdev);
1482de6e0b19SCristian Ciocaltea 	SET_NETDEV_DEV(netdev, dev);
1483de6e0b19SCristian Ciocaltea 
1484de6e0b19SCristian Ciocaltea 	priv = netdev_priv(netdev);
1485de6e0b19SCristian Ciocaltea 	priv->netdev = netdev;
1486de6e0b19SCristian Ciocaltea 	priv->msg_enable = netif_msg_init(-1, OWL_EMAC_DEFAULT_MSG_ENABLE);
1487de6e0b19SCristian Ciocaltea 
1488de6e0b19SCristian Ciocaltea 	ret = of_get_phy_mode(dev->of_node, &priv->phy_mode);
1489de6e0b19SCristian Ciocaltea 	if (ret) {
1490de6e0b19SCristian Ciocaltea 		dev_err(dev, "failed to get phy mode: %d\n", ret);
1491de6e0b19SCristian Ciocaltea 		return ret;
1492de6e0b19SCristian Ciocaltea 	}
1493de6e0b19SCristian Ciocaltea 
1494de6e0b19SCristian Ciocaltea 	spin_lock_init(&priv->lock);
1495de6e0b19SCristian Ciocaltea 
1496de6e0b19SCristian Ciocaltea 	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
1497de6e0b19SCristian Ciocaltea 	if (ret) {
1498de6e0b19SCristian Ciocaltea 		dev_err(dev, "unsupported DMA mask\n");
1499de6e0b19SCristian Ciocaltea 		return ret;
1500de6e0b19SCristian Ciocaltea 	}
1501de6e0b19SCristian Ciocaltea 
1502de6e0b19SCristian Ciocaltea 	ret = owl_emac_ring_alloc(dev, &priv->rx_ring, OWL_EMAC_RX_RING_SIZE);
1503de6e0b19SCristian Ciocaltea 	if (ret)
1504de6e0b19SCristian Ciocaltea 		return ret;
1505de6e0b19SCristian Ciocaltea 
1506de6e0b19SCristian Ciocaltea 	ret = owl_emac_ring_alloc(dev, &priv->tx_ring, OWL_EMAC_TX_RING_SIZE);
1507de6e0b19SCristian Ciocaltea 	if (ret)
1508de6e0b19SCristian Ciocaltea 		return ret;
1509de6e0b19SCristian Ciocaltea 
1510de6e0b19SCristian Ciocaltea 	priv->base = devm_platform_ioremap_resource(pdev, 0);
1511de6e0b19SCristian Ciocaltea 	if (IS_ERR(priv->base))
1512de6e0b19SCristian Ciocaltea 		return PTR_ERR(priv->base);
1513de6e0b19SCristian Ciocaltea 
1514de6e0b19SCristian Ciocaltea 	netdev->irq = platform_get_irq(pdev, 0);
1515de6e0b19SCristian Ciocaltea 	if (netdev->irq < 0)
1516de6e0b19SCristian Ciocaltea 		return netdev->irq;
1517de6e0b19SCristian Ciocaltea 
1518de6e0b19SCristian Ciocaltea 	ret = devm_request_irq(dev, netdev->irq, owl_emac_handle_irq,
1519de6e0b19SCristian Ciocaltea 			       IRQF_SHARED, netdev->name, netdev);
1520de6e0b19SCristian Ciocaltea 	if (ret) {
1521de6e0b19SCristian Ciocaltea 		dev_err(dev, "failed to request irq: %d\n", netdev->irq);
1522de6e0b19SCristian Ciocaltea 		return ret;
1523de6e0b19SCristian Ciocaltea 	}
1524de6e0b19SCristian Ciocaltea 
1525de6e0b19SCristian Ciocaltea 	for (i = 0; i < OWL_EMAC_NCLKS; i++)
1526de6e0b19SCristian Ciocaltea 		priv->clks[i].id = owl_emac_clk_names[i];
1527de6e0b19SCristian Ciocaltea 
1528de6e0b19SCristian Ciocaltea 	ret = devm_clk_bulk_get(dev, OWL_EMAC_NCLKS, priv->clks);
1529de6e0b19SCristian Ciocaltea 	if (ret)
1530de6e0b19SCristian Ciocaltea 		return ret;
1531de6e0b19SCristian Ciocaltea 
1532de6e0b19SCristian Ciocaltea 	ret = clk_bulk_prepare_enable(OWL_EMAC_NCLKS, priv->clks);
1533de6e0b19SCristian Ciocaltea 	if (ret)
1534de6e0b19SCristian Ciocaltea 		return ret;
1535de6e0b19SCristian Ciocaltea 
1536de6e0b19SCristian Ciocaltea 	ret = devm_add_action_or_reset(dev, owl_emac_clk_disable_unprepare, priv);
1537de6e0b19SCristian Ciocaltea 	if (ret)
1538de6e0b19SCristian Ciocaltea 		return ret;
1539de6e0b19SCristian Ciocaltea 
1540de6e0b19SCristian Ciocaltea 	ret = owl_emac_clk_set_rate(priv);
1541de6e0b19SCristian Ciocaltea 	if (ret)
1542de6e0b19SCristian Ciocaltea 		return ret;
1543de6e0b19SCristian Ciocaltea 
1544de6e0b19SCristian Ciocaltea 	priv->reset = devm_reset_control_get_exclusive(dev, NULL);
1545de6e0b19SCristian Ciocaltea 	if (IS_ERR(priv->reset))
1546de6e0b19SCristian Ciocaltea 		return dev_err_probe(dev, PTR_ERR(priv->reset),
1547de6e0b19SCristian Ciocaltea 				     "failed to get reset control");
1548de6e0b19SCristian Ciocaltea 
1549de6e0b19SCristian Ciocaltea 	owl_emac_get_mac_addr(netdev);
1550de6e0b19SCristian Ciocaltea 
1551de6e0b19SCristian Ciocaltea 	owl_emac_core_hw_reset(priv);
1552de6e0b19SCristian Ciocaltea 	owl_emac_mdio_clock_enable(priv);
1553de6e0b19SCristian Ciocaltea 
1554de6e0b19SCristian Ciocaltea 	ret = owl_emac_mdio_init(netdev);
1555de6e0b19SCristian Ciocaltea 	if (ret) {
1556de6e0b19SCristian Ciocaltea 		dev_err(dev, "failed to initialize MDIO bus\n");
1557de6e0b19SCristian Ciocaltea 		return ret;
1558de6e0b19SCristian Ciocaltea 	}
1559de6e0b19SCristian Ciocaltea 
1560de6e0b19SCristian Ciocaltea 	ret = owl_emac_phy_init(netdev);
1561de6e0b19SCristian Ciocaltea 	if (ret) {
1562de6e0b19SCristian Ciocaltea 		dev_err(dev, "failed to initialize PHY\n");
1563de6e0b19SCristian Ciocaltea 		return ret;
1564de6e0b19SCristian Ciocaltea 	}
1565de6e0b19SCristian Ciocaltea 
1566de6e0b19SCristian Ciocaltea 	INIT_WORK(&priv->mac_reset_task, owl_emac_reset_task);
1567de6e0b19SCristian Ciocaltea 
1568de6e0b19SCristian Ciocaltea 	netdev->min_mtu = OWL_EMAC_MTU_MIN;
1569de6e0b19SCristian Ciocaltea 	netdev->max_mtu = OWL_EMAC_MTU_MAX;
1570de6e0b19SCristian Ciocaltea 	netdev->watchdog_timeo = OWL_EMAC_TX_TIMEOUT;
1571de6e0b19SCristian Ciocaltea 	netdev->netdev_ops = &owl_emac_netdev_ops;
1572de6e0b19SCristian Ciocaltea 	netdev->ethtool_ops = &owl_emac_ethtool_ops;
1573*b48b89f9SJakub Kicinski 	netif_napi_add(netdev, &priv->napi, owl_emac_poll);
1574de6e0b19SCristian Ciocaltea 
1575de6e0b19SCristian Ciocaltea 	ret = devm_register_netdev(dev, netdev);
1576de6e0b19SCristian Ciocaltea 	if (ret) {
1577de6e0b19SCristian Ciocaltea 		netif_napi_del(&priv->napi);
1578de6e0b19SCristian Ciocaltea 		phy_disconnect(netdev->phydev);
1579de6e0b19SCristian Ciocaltea 		return ret;
1580de6e0b19SCristian Ciocaltea 	}
1581de6e0b19SCristian Ciocaltea 
1582de6e0b19SCristian Ciocaltea 	return 0;
1583de6e0b19SCristian Ciocaltea }
1584de6e0b19SCristian Ciocaltea 
owl_emac_remove(struct platform_device * pdev)1585de6e0b19SCristian Ciocaltea static int owl_emac_remove(struct platform_device *pdev)
1586de6e0b19SCristian Ciocaltea {
1587de6e0b19SCristian Ciocaltea 	struct owl_emac_priv *priv = platform_get_drvdata(pdev);
1588de6e0b19SCristian Ciocaltea 
1589de6e0b19SCristian Ciocaltea 	netif_napi_del(&priv->napi);
1590de6e0b19SCristian Ciocaltea 	phy_disconnect(priv->netdev->phydev);
1591de6e0b19SCristian Ciocaltea 	cancel_work_sync(&priv->mac_reset_task);
1592de6e0b19SCristian Ciocaltea 
1593de6e0b19SCristian Ciocaltea 	return 0;
1594de6e0b19SCristian Ciocaltea }
1595de6e0b19SCristian Ciocaltea 
1596de6e0b19SCristian Ciocaltea static const struct of_device_id owl_emac_of_match[] = {
1597de6e0b19SCristian Ciocaltea 	{ .compatible = "actions,owl-emac", },
1598de6e0b19SCristian Ciocaltea 	{ }
1599de6e0b19SCristian Ciocaltea };
1600de6e0b19SCristian Ciocaltea MODULE_DEVICE_TABLE(of, owl_emac_of_match);
1601de6e0b19SCristian Ciocaltea 
1602de6e0b19SCristian Ciocaltea static SIMPLE_DEV_PM_OPS(owl_emac_pm_ops,
1603de6e0b19SCristian Ciocaltea 			 owl_emac_suspend, owl_emac_resume);
1604de6e0b19SCristian Ciocaltea 
1605de6e0b19SCristian Ciocaltea static struct platform_driver owl_emac_driver = {
1606de6e0b19SCristian Ciocaltea 	.driver = {
1607de6e0b19SCristian Ciocaltea 		.name = OWL_EMAC_DRVNAME,
1608de6e0b19SCristian Ciocaltea 		.of_match_table = owl_emac_of_match,
1609de6e0b19SCristian Ciocaltea 		.pm = &owl_emac_pm_ops,
1610de6e0b19SCristian Ciocaltea 	},
1611de6e0b19SCristian Ciocaltea 	.probe = owl_emac_probe,
1612de6e0b19SCristian Ciocaltea 	.remove = owl_emac_remove,
1613de6e0b19SCristian Ciocaltea };
1614de6e0b19SCristian Ciocaltea module_platform_driver(owl_emac_driver);
1615de6e0b19SCristian Ciocaltea 
1616de6e0b19SCristian Ciocaltea MODULE_DESCRIPTION("Actions Semi Owl SoCs Ethernet MAC Driver");
1617de6e0b19SCristian Ciocaltea MODULE_AUTHOR("Actions Semi Inc.");
1618de6e0b19SCristian Ciocaltea MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
1619de6e0b19SCristian Ciocaltea MODULE_LICENSE("GPL");
1620