xref: /openbmc/linux/drivers/net/ethernet/ti/icssg/icssg_prueth.c (revision f6d73b12ca9fd3b1c29a6a725cd751b972c740cf)
1128d5874SRoger Quadros // SPDX-License-Identifier: GPL-2.0
2128d5874SRoger Quadros 
3128d5874SRoger Quadros /* Texas Instruments ICSSG Ethernet Driver
4128d5874SRoger Quadros  *
5128d5874SRoger Quadros  * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
6128d5874SRoger Quadros  *
7128d5874SRoger Quadros  */
8128d5874SRoger Quadros 
9128d5874SRoger Quadros #include <linux/bitops.h>
10128d5874SRoger Quadros #include <linux/clk.h>
11c1e10d5dSMD Danish Anwar #include <linux/delay.h>
12128d5874SRoger Quadros #include <linux/dma-mapping.h>
13128d5874SRoger Quadros #include <linux/dma/ti-cppi5.h>
14128d5874SRoger Quadros #include <linux/etherdevice.h>
15128d5874SRoger Quadros #include <linux/genalloc.h>
16128d5874SRoger Quadros #include <linux/if_vlan.h>
17128d5874SRoger Quadros #include <linux/interrupt.h>
18*c67ce71dSMeghana Malladi #include <linux/io-64-nonatomic-hi-lo.h>
19128d5874SRoger Quadros #include <linux/kernel.h>
20128d5874SRoger Quadros #include <linux/mfd/syscon.h>
21128d5874SRoger Quadros #include <linux/module.h>
22128d5874SRoger Quadros #include <linux/of.h>
23128d5874SRoger Quadros #include <linux/of_irq.h>
24128d5874SRoger Quadros #include <linux/of_mdio.h>
25128d5874SRoger Quadros #include <linux/of_net.h>
26128d5874SRoger Quadros #include <linux/of_platform.h>
27128d5874SRoger Quadros #include <linux/phy.h>
28128d5874SRoger Quadros #include <linux/remoteproc/pruss.h>
29128d5874SRoger Quadros #include <linux/regmap.h>
30128d5874SRoger Quadros #include <linux/remoteproc.h>
31128d5874SRoger Quadros 
32128d5874SRoger Quadros #include "icssg_prueth.h"
33128d5874SRoger Quadros #include "icssg_mii_rt.h"
34128d5874SRoger Quadros #include "../k3-cppi-desc-pool.h"
35128d5874SRoger Quadros 
36128d5874SRoger Quadros #define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver"
37128d5874SRoger Quadros 
38128d5874SRoger Quadros /* Netif debug messages possible */
39128d5874SRoger Quadros #define PRUETH_EMAC_DEBUG       (NETIF_MSG_DRV | \
40128d5874SRoger Quadros 				 NETIF_MSG_PROBE | \
41128d5874SRoger Quadros 				 NETIF_MSG_LINK | \
42128d5874SRoger Quadros 				 NETIF_MSG_TIMER | \
43128d5874SRoger Quadros 				 NETIF_MSG_IFDOWN | \
44128d5874SRoger Quadros 				 NETIF_MSG_IFUP | \
45128d5874SRoger Quadros 				 NETIF_MSG_RX_ERR | \
46128d5874SRoger Quadros 				 NETIF_MSG_TX_ERR | \
47128d5874SRoger Quadros 				 NETIF_MSG_TX_QUEUED | \
48128d5874SRoger Quadros 				 NETIF_MSG_INTR | \
49128d5874SRoger Quadros 				 NETIF_MSG_TX_DONE | \
50128d5874SRoger Quadros 				 NETIF_MSG_RX_STATUS | \
51128d5874SRoger Quadros 				 NETIF_MSG_PKTDATA | \
52128d5874SRoger Quadros 				 NETIF_MSG_HW | \
53128d5874SRoger Quadros 				 NETIF_MSG_WOL)
54128d5874SRoger Quadros 
55128d5874SRoger Quadros #define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx)
56128d5874SRoger Quadros 
57128d5874SRoger Quadros /* CTRLMMR_ICSSG_RGMII_CTRL register bits */
58128d5874SRoger Quadros #define ICSSG_CTRL_RGMII_ID_MODE                BIT(24)
59128d5874SRoger Quadros 
60186734c1SRoger Quadros #define IEP_DEFAULT_CYCLE_TIME_NS	1000000	/* 1 ms */
61186734c1SRoger Quadros 
prueth_cleanup_rx_chns(struct prueth_emac * emac,struct prueth_rx_chn * rx_chn,int max_rflows)62128d5874SRoger Quadros static void prueth_cleanup_rx_chns(struct prueth_emac *emac,
63128d5874SRoger Quadros 				   struct prueth_rx_chn *rx_chn,
64128d5874SRoger Quadros 				   int max_rflows)
65128d5874SRoger Quadros {
66128d5874SRoger Quadros 	if (rx_chn->desc_pool)
67128d5874SRoger Quadros 		k3_cppi_desc_pool_destroy(rx_chn->desc_pool);
68128d5874SRoger Quadros 
69128d5874SRoger Quadros 	if (rx_chn->rx_chn)
70128d5874SRoger Quadros 		k3_udma_glue_release_rx_chn(rx_chn->rx_chn);
71128d5874SRoger Quadros }
72128d5874SRoger Quadros 
prueth_cleanup_tx_chns(struct prueth_emac * emac)73128d5874SRoger Quadros static void prueth_cleanup_tx_chns(struct prueth_emac *emac)
74128d5874SRoger Quadros {
75128d5874SRoger Quadros 	int i;
76128d5874SRoger Quadros 
77128d5874SRoger Quadros 	for (i = 0; i < emac->tx_ch_num; i++) {
78128d5874SRoger Quadros 		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
79128d5874SRoger Quadros 
80128d5874SRoger Quadros 		if (tx_chn->desc_pool)
81128d5874SRoger Quadros 			k3_cppi_desc_pool_destroy(tx_chn->desc_pool);
82128d5874SRoger Quadros 
83128d5874SRoger Quadros 		if (tx_chn->tx_chn)
84128d5874SRoger Quadros 			k3_udma_glue_release_tx_chn(tx_chn->tx_chn);
85128d5874SRoger Quadros 
86128d5874SRoger Quadros 		/* Assume prueth_cleanup_tx_chns() is called at the
87128d5874SRoger Quadros 		 * end after all channel resources are freed
88128d5874SRoger Quadros 		 */
89128d5874SRoger Quadros 		memset(tx_chn, 0, sizeof(*tx_chn));
90128d5874SRoger Quadros 	}
91128d5874SRoger Quadros }
92128d5874SRoger Quadros 
prueth_ndev_del_tx_napi(struct prueth_emac * emac,int num)93128d5874SRoger Quadros static void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num)
94128d5874SRoger Quadros {
95128d5874SRoger Quadros 	int i;
96128d5874SRoger Quadros 
97128d5874SRoger Quadros 	for (i = 0; i < num; i++) {
98128d5874SRoger Quadros 		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
99128d5874SRoger Quadros 
100128d5874SRoger Quadros 		if (tx_chn->irq)
101128d5874SRoger Quadros 			free_irq(tx_chn->irq, tx_chn);
102128d5874SRoger Quadros 		netif_napi_del(&tx_chn->napi_tx);
103128d5874SRoger Quadros 	}
104128d5874SRoger Quadros }
105128d5874SRoger Quadros 
prueth_xmit_free(struct prueth_tx_chn * tx_chn,struct cppi5_host_desc_t * desc)106128d5874SRoger Quadros static void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
107128d5874SRoger Quadros 			     struct cppi5_host_desc_t *desc)
108128d5874SRoger Quadros {
109128d5874SRoger Quadros 	struct cppi5_host_desc_t *first_desc, *next_desc;
110128d5874SRoger Quadros 	dma_addr_t buf_dma, next_desc_dma;
111128d5874SRoger Quadros 	u32 buf_dma_len;
112128d5874SRoger Quadros 
113128d5874SRoger Quadros 	first_desc = desc;
114128d5874SRoger Quadros 	next_desc = first_desc;
115128d5874SRoger Quadros 
116128d5874SRoger Quadros 	cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);
117128d5874SRoger Quadros 	k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
118128d5874SRoger Quadros 
119128d5874SRoger Quadros 	dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len,
120128d5874SRoger Quadros 			 DMA_TO_DEVICE);
121128d5874SRoger Quadros 
122128d5874SRoger Quadros 	next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc);
123128d5874SRoger Quadros 	k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
124128d5874SRoger Quadros 	while (next_desc_dma) {
125128d5874SRoger Quadros 		next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
126128d5874SRoger Quadros 						       next_desc_dma);
127128d5874SRoger Quadros 		cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len);
128128d5874SRoger Quadros 		k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
129128d5874SRoger Quadros 
130128d5874SRoger Quadros 		dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len,
131128d5874SRoger Quadros 			       DMA_TO_DEVICE);
132128d5874SRoger Quadros 
133128d5874SRoger Quadros 		next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc);
134128d5874SRoger Quadros 		k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
135128d5874SRoger Quadros 
136128d5874SRoger Quadros 		k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
137128d5874SRoger Quadros 	}
138128d5874SRoger Quadros 
139128d5874SRoger Quadros 	k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
140128d5874SRoger Quadros }
141128d5874SRoger Quadros 
emac_tx_complete_packets(struct prueth_emac * emac,int chn,int budget)142128d5874SRoger Quadros static int emac_tx_complete_packets(struct prueth_emac *emac, int chn,
143128d5874SRoger Quadros 				    int budget)
144128d5874SRoger Quadros {
145128d5874SRoger Quadros 	struct net_device *ndev = emac->ndev;
146128d5874SRoger Quadros 	struct cppi5_host_desc_t *desc_tx;
147128d5874SRoger Quadros 	struct netdev_queue *netif_txq;
148128d5874SRoger Quadros 	struct prueth_tx_chn *tx_chn;
149128d5874SRoger Quadros 	unsigned int total_bytes = 0;
150128d5874SRoger Quadros 	struct sk_buff *skb;
151128d5874SRoger Quadros 	dma_addr_t desc_dma;
152128d5874SRoger Quadros 	int res, num_tx = 0;
153128d5874SRoger Quadros 	void **swdata;
154128d5874SRoger Quadros 
155128d5874SRoger Quadros 	tx_chn = &emac->tx_chns[chn];
156128d5874SRoger Quadros 
157128d5874SRoger Quadros 	while (true) {
158128d5874SRoger Quadros 		res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma);
159128d5874SRoger Quadros 		if (res == -ENODATA)
160128d5874SRoger Quadros 			break;
161128d5874SRoger Quadros 
162128d5874SRoger Quadros 		/* teardown completion */
163128d5874SRoger Quadros 		if (cppi5_desc_is_tdcm(desc_dma)) {
164128d5874SRoger Quadros 			if (atomic_dec_and_test(&emac->tdown_cnt))
165128d5874SRoger Quadros 				complete(&emac->tdown_complete);
166128d5874SRoger Quadros 			break;
167128d5874SRoger Quadros 		}
168128d5874SRoger Quadros 
169128d5874SRoger Quadros 		desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
170128d5874SRoger Quadros 						     desc_dma);
171128d5874SRoger Quadros 		swdata = cppi5_hdesc_get_swdata(desc_tx);
172128d5874SRoger Quadros 
173128d5874SRoger Quadros 		skb = *(swdata);
174128d5874SRoger Quadros 		prueth_xmit_free(tx_chn, desc_tx);
175128d5874SRoger Quadros 
176128d5874SRoger Quadros 		ndev = skb->dev;
177128d5874SRoger Quadros 		ndev->stats.tx_packets++;
178128d5874SRoger Quadros 		ndev->stats.tx_bytes += skb->len;
179128d5874SRoger Quadros 		total_bytes += skb->len;
180128d5874SRoger Quadros 		napi_consume_skb(skb, budget);
181128d5874SRoger Quadros 		num_tx++;
182128d5874SRoger Quadros 	}
183128d5874SRoger Quadros 
184128d5874SRoger Quadros 	if (!num_tx)
185128d5874SRoger Quadros 		return 0;
186128d5874SRoger Quadros 
187128d5874SRoger Quadros 	netif_txq = netdev_get_tx_queue(ndev, chn);
188128d5874SRoger Quadros 	netdev_tx_completed_queue(netif_txq, num_tx, total_bytes);
189128d5874SRoger Quadros 
190128d5874SRoger Quadros 	if (netif_tx_queue_stopped(netif_txq)) {
191128d5874SRoger Quadros 		/* If the TX queue was stopped, wake it now
192128d5874SRoger Quadros 		 * if we have enough room.
193128d5874SRoger Quadros 		 */
194128d5874SRoger Quadros 		__netif_tx_lock(netif_txq, smp_processor_id());
195128d5874SRoger Quadros 		if (netif_running(ndev) &&
196128d5874SRoger Quadros 		    (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=
197128d5874SRoger Quadros 		     MAX_SKB_FRAGS))
198128d5874SRoger Quadros 			netif_tx_wake_queue(netif_txq);
199128d5874SRoger Quadros 		__netif_tx_unlock(netif_txq);
200128d5874SRoger Quadros 	}
201128d5874SRoger Quadros 
202128d5874SRoger Quadros 	return num_tx;
203128d5874SRoger Quadros }
204128d5874SRoger Quadros 
emac_napi_tx_poll(struct napi_struct * napi_tx,int budget)205128d5874SRoger Quadros static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget)
206128d5874SRoger Quadros {
207128d5874SRoger Quadros 	struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx);
208128d5874SRoger Quadros 	struct prueth_emac *emac = tx_chn->emac;
209128d5874SRoger Quadros 	int num_tx_packets;
210128d5874SRoger Quadros 
211128d5874SRoger Quadros 	num_tx_packets = emac_tx_complete_packets(emac, tx_chn->id, budget);
212128d5874SRoger Quadros 
213128d5874SRoger Quadros 	if (num_tx_packets >= budget)
214128d5874SRoger Quadros 		return budget;
215128d5874SRoger Quadros 
216128d5874SRoger Quadros 	if (napi_complete_done(napi_tx, num_tx_packets))
217128d5874SRoger Quadros 		enable_irq(tx_chn->irq);
218128d5874SRoger Quadros 
219128d5874SRoger Quadros 	return num_tx_packets;
220128d5874SRoger Quadros }
221128d5874SRoger Quadros 
prueth_tx_irq(int irq,void * dev_id)222128d5874SRoger Quadros static irqreturn_t prueth_tx_irq(int irq, void *dev_id)
223128d5874SRoger Quadros {
224128d5874SRoger Quadros 	struct prueth_tx_chn *tx_chn = dev_id;
225128d5874SRoger Quadros 
226128d5874SRoger Quadros 	disable_irq_nosync(irq);
227128d5874SRoger Quadros 	napi_schedule(&tx_chn->napi_tx);
228128d5874SRoger Quadros 
229128d5874SRoger Quadros 	return IRQ_HANDLED;
230128d5874SRoger Quadros }
231128d5874SRoger Quadros 
prueth_ndev_add_tx_napi(struct prueth_emac * emac)232128d5874SRoger Quadros static int prueth_ndev_add_tx_napi(struct prueth_emac *emac)
233128d5874SRoger Quadros {
234128d5874SRoger Quadros 	struct prueth *prueth = emac->prueth;
235128d5874SRoger Quadros 	int i, ret;
236128d5874SRoger Quadros 
237128d5874SRoger Quadros 	for (i = 0; i < emac->tx_ch_num; i++) {
238128d5874SRoger Quadros 		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
239128d5874SRoger Quadros 
240128d5874SRoger Quadros 		netif_napi_add_tx(emac->ndev, &tx_chn->napi_tx, emac_napi_tx_poll);
241128d5874SRoger Quadros 		ret = request_irq(tx_chn->irq, prueth_tx_irq,
242128d5874SRoger Quadros 				  IRQF_TRIGGER_HIGH, tx_chn->name,
243128d5874SRoger Quadros 				  tx_chn);
244128d5874SRoger Quadros 		if (ret) {
245128d5874SRoger Quadros 			netif_napi_del(&tx_chn->napi_tx);
246128d5874SRoger Quadros 			dev_err(prueth->dev, "unable to request TX IRQ %d\n",
247128d5874SRoger Quadros 				tx_chn->irq);
248128d5874SRoger Quadros 			goto fail;
249128d5874SRoger Quadros 		}
250128d5874SRoger Quadros 	}
251128d5874SRoger Quadros 
252128d5874SRoger Quadros 	return 0;
253128d5874SRoger Quadros fail:
254128d5874SRoger Quadros 	prueth_ndev_del_tx_napi(emac, i);
255128d5874SRoger Quadros 	return ret;
256128d5874SRoger Quadros }
257128d5874SRoger Quadros 
prueth_init_tx_chns(struct prueth_emac * emac)258128d5874SRoger Quadros static int prueth_init_tx_chns(struct prueth_emac *emac)
259128d5874SRoger Quadros {
260128d5874SRoger Quadros 	static const struct k3_ring_cfg ring_cfg = {
261128d5874SRoger Quadros 		.elm_size = K3_RINGACC_RING_ELSIZE_8,
262128d5874SRoger Quadros 		.mode = K3_RINGACC_RING_MODE_RING,
263128d5874SRoger Quadros 		.flags = 0,
264128d5874SRoger Quadros 		.size = PRUETH_MAX_TX_DESC,
265128d5874SRoger Quadros 	};
266128d5874SRoger Quadros 	struct k3_udma_glue_tx_channel_cfg tx_cfg;
267128d5874SRoger Quadros 	struct device *dev = emac->prueth->dev;
268128d5874SRoger Quadros 	struct net_device *ndev = emac->ndev;
269128d5874SRoger Quadros 	int ret, slice, i;
270128d5874SRoger Quadros 	u32 hdesc_size;
271128d5874SRoger Quadros 
272128d5874SRoger Quadros 	slice = prueth_emac_slice(emac);
273128d5874SRoger Quadros 	if (slice < 0)
274128d5874SRoger Quadros 		return slice;
275128d5874SRoger Quadros 
276128d5874SRoger Quadros 	init_completion(&emac->tdown_complete);
277128d5874SRoger Quadros 
278128d5874SRoger Quadros 	hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,
279128d5874SRoger Quadros 					   PRUETH_NAV_SW_DATA_SIZE);
280128d5874SRoger Quadros 	memset(&tx_cfg, 0, sizeof(tx_cfg));
281128d5874SRoger Quadros 	tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;
282128d5874SRoger Quadros 	tx_cfg.tx_cfg = ring_cfg;
283128d5874SRoger Quadros 	tx_cfg.txcq_cfg = ring_cfg;
284128d5874SRoger Quadros 
285128d5874SRoger Quadros 	for (i = 0; i < emac->tx_ch_num; i++) {
286128d5874SRoger Quadros 		struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
287128d5874SRoger Quadros 
288128d5874SRoger Quadros 		/* To differentiate channels for SLICE0 vs SLICE1 */
289128d5874SRoger Quadros 		snprintf(tx_chn->name, sizeof(tx_chn->name),
290128d5874SRoger Quadros 			 "tx%d-%d", slice, i);
291128d5874SRoger Quadros 
292128d5874SRoger Quadros 		tx_chn->emac = emac;
293128d5874SRoger Quadros 		tx_chn->id = i;
294128d5874SRoger Quadros 		tx_chn->descs_num = PRUETH_MAX_TX_DESC;
295128d5874SRoger Quadros 
296128d5874SRoger Quadros 		tx_chn->tx_chn =
297128d5874SRoger Quadros 			k3_udma_glue_request_tx_chn(dev, tx_chn->name,
298128d5874SRoger Quadros 						    &tx_cfg);
299128d5874SRoger Quadros 		if (IS_ERR(tx_chn->tx_chn)) {
300128d5874SRoger Quadros 			ret = PTR_ERR(tx_chn->tx_chn);
301128d5874SRoger Quadros 			tx_chn->tx_chn = NULL;
302128d5874SRoger Quadros 			netdev_err(ndev,
303128d5874SRoger Quadros 				   "Failed to request tx dma ch: %d\n", ret);
304128d5874SRoger Quadros 			goto fail;
305128d5874SRoger Quadros 		}
306128d5874SRoger Quadros 
307128d5874SRoger Quadros 		tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn->tx_chn);
308128d5874SRoger Quadros 		tx_chn->desc_pool =
309128d5874SRoger Quadros 			k3_cppi_desc_pool_create_name(tx_chn->dma_dev,
310128d5874SRoger Quadros 						      tx_chn->descs_num,
311128d5874SRoger Quadros 						      hdesc_size,
312128d5874SRoger Quadros 						      tx_chn->name);
313128d5874SRoger Quadros 		if (IS_ERR(tx_chn->desc_pool)) {
314128d5874SRoger Quadros 			ret = PTR_ERR(tx_chn->desc_pool);
315128d5874SRoger Quadros 			tx_chn->desc_pool = NULL;
316128d5874SRoger Quadros 			netdev_err(ndev, "Failed to create tx pool: %d\n", ret);
317128d5874SRoger Quadros 			goto fail;
318128d5874SRoger Quadros 		}
319128d5874SRoger Quadros 
320a325f174SDan Carpenter 		ret = k3_udma_glue_tx_get_irq(tx_chn->tx_chn);
321f9a1d321SDan Carpenter 		if (ret < 0) {
322128d5874SRoger Quadros 			netdev_err(ndev, "failed to get tx irq\n");
323128d5874SRoger Quadros 			goto fail;
324128d5874SRoger Quadros 		}
325a325f174SDan Carpenter 		tx_chn->irq = ret;
326128d5874SRoger Quadros 
327128d5874SRoger Quadros 		snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d",
328128d5874SRoger Quadros 			 dev_name(dev), tx_chn->id);
329128d5874SRoger Quadros 	}
330128d5874SRoger Quadros 
331128d5874SRoger Quadros 	return 0;
332128d5874SRoger Quadros 
333128d5874SRoger Quadros fail:
334128d5874SRoger Quadros 	prueth_cleanup_tx_chns(emac);
335128d5874SRoger Quadros 	return ret;
336128d5874SRoger Quadros }
337128d5874SRoger Quadros 
prueth_init_rx_chns(struct prueth_emac * emac,struct prueth_rx_chn * rx_chn,char * name,u32 max_rflows,u32 max_desc_num)338128d5874SRoger Quadros static int prueth_init_rx_chns(struct prueth_emac *emac,
339128d5874SRoger Quadros 			       struct prueth_rx_chn *rx_chn,
340128d5874SRoger Quadros 			       char *name, u32 max_rflows,
341128d5874SRoger Quadros 			       u32 max_desc_num)
342128d5874SRoger Quadros {
343128d5874SRoger Quadros 	struct k3_udma_glue_rx_channel_cfg rx_cfg;
344128d5874SRoger Quadros 	struct device *dev = emac->prueth->dev;
345128d5874SRoger Quadros 	struct net_device *ndev = emac->ndev;
346128d5874SRoger Quadros 	u32 fdqring_id, hdesc_size;
347128d5874SRoger Quadros 	int i, ret = 0, slice;
348128d5874SRoger Quadros 
349128d5874SRoger Quadros 	slice = prueth_emac_slice(emac);
350128d5874SRoger Quadros 	if (slice < 0)
351128d5874SRoger Quadros 		return slice;
352128d5874SRoger Quadros 
353128d5874SRoger Quadros 	/* To differentiate channels for SLICE0 vs SLICE1 */
354128d5874SRoger Quadros 	snprintf(rx_chn->name, sizeof(rx_chn->name), "%s%d", name, slice);
355128d5874SRoger Quadros 
356128d5874SRoger Quadros 	hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,
357128d5874SRoger Quadros 					   PRUETH_NAV_SW_DATA_SIZE);
358128d5874SRoger Quadros 	memset(&rx_cfg, 0, sizeof(rx_cfg));
359128d5874SRoger Quadros 	rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;
360128d5874SRoger Quadros 	rx_cfg.flow_id_num = max_rflows;
361128d5874SRoger Quadros 	rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */
362128d5874SRoger Quadros 
363128d5874SRoger Quadros 	/* init all flows */
364128d5874SRoger Quadros 	rx_chn->dev = dev;
365128d5874SRoger Quadros 	rx_chn->descs_num = max_desc_num;
366128d5874SRoger Quadros 
367128d5874SRoger Quadros 	rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, rx_chn->name,
368128d5874SRoger Quadros 						     &rx_cfg);
369128d5874SRoger Quadros 	if (IS_ERR(rx_chn->rx_chn)) {
370128d5874SRoger Quadros 		ret = PTR_ERR(rx_chn->rx_chn);
371128d5874SRoger Quadros 		rx_chn->rx_chn = NULL;
372128d5874SRoger Quadros 		netdev_err(ndev, "Failed to request rx dma ch: %d\n", ret);
373128d5874SRoger Quadros 		goto fail;
374128d5874SRoger Quadros 	}
375128d5874SRoger Quadros 
376128d5874SRoger Quadros 	rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn->rx_chn);
377128d5874SRoger Quadros 	rx_chn->desc_pool = k3_cppi_desc_pool_create_name(rx_chn->dma_dev,
378128d5874SRoger Quadros 							  rx_chn->descs_num,
379128d5874SRoger Quadros 							  hdesc_size,
380128d5874SRoger Quadros 							  rx_chn->name);
381128d5874SRoger Quadros 	if (IS_ERR(rx_chn->desc_pool)) {
382128d5874SRoger Quadros 		ret = PTR_ERR(rx_chn->desc_pool);
383128d5874SRoger Quadros 		rx_chn->desc_pool = NULL;
384128d5874SRoger Quadros 		netdev_err(ndev, "Failed to create rx pool: %d\n", ret);
385128d5874SRoger Quadros 		goto fail;
386128d5874SRoger Quadros 	}
387128d5874SRoger Quadros 
388128d5874SRoger Quadros 	emac->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn);
389128d5874SRoger Quadros 	netdev_dbg(ndev, "flow id base = %d\n", emac->rx_flow_id_base);
390128d5874SRoger Quadros 
391128d5874SRoger Quadros 	fdqring_id = K3_RINGACC_RING_ID_ANY;
392128d5874SRoger Quadros 	for (i = 0; i < rx_cfg.flow_id_num; i++) {
393128d5874SRoger Quadros 		struct k3_ring_cfg rxring_cfg = {
394128d5874SRoger Quadros 			.elm_size = K3_RINGACC_RING_ELSIZE_8,
395128d5874SRoger Quadros 			.mode = K3_RINGACC_RING_MODE_RING,
396128d5874SRoger Quadros 			.flags = 0,
397128d5874SRoger Quadros 		};
398128d5874SRoger Quadros 		struct k3_ring_cfg fdqring_cfg = {
399128d5874SRoger Quadros 			.elm_size = K3_RINGACC_RING_ELSIZE_8,
400128d5874SRoger Quadros 			.flags = K3_RINGACC_RING_SHARED,
401128d5874SRoger Quadros 		};
402128d5874SRoger Quadros 		struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = {
403128d5874SRoger Quadros 			.rx_cfg = rxring_cfg,
404128d5874SRoger Quadros 			.rxfdq_cfg = fdqring_cfg,
405128d5874SRoger Quadros 			.ring_rxq_id = K3_RINGACC_RING_ID_ANY,
406128d5874SRoger Quadros 			.src_tag_lo_sel =
407128d5874SRoger Quadros 				K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG,
408128d5874SRoger Quadros 		};
409128d5874SRoger Quadros 
410128d5874SRoger Quadros 		rx_flow_cfg.ring_rxfdq0_id = fdqring_id;
411128d5874SRoger Quadros 		rx_flow_cfg.rx_cfg.size = max_desc_num;
412128d5874SRoger Quadros 		rx_flow_cfg.rxfdq_cfg.size = max_desc_num;
413128d5874SRoger Quadros 		rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode;
414128d5874SRoger Quadros 
415128d5874SRoger Quadros 		ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn,
416128d5874SRoger Quadros 						i, &rx_flow_cfg);
417128d5874SRoger Quadros 		if (ret) {
418128d5874SRoger Quadros 			netdev_err(ndev, "Failed to init rx flow%d %d\n",
419128d5874SRoger Quadros 				   i, ret);
420128d5874SRoger Quadros 			goto fail;
421128d5874SRoger Quadros 		}
422128d5874SRoger Quadros 		if (!i)
423128d5874SRoger Quadros 			fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn->rx_chn,
424128d5874SRoger Quadros 								     i);
42594b00cd6SDan Carpenter 		ret = k3_udma_glue_rx_get_irq(rx_chn->rx_chn, i);
42694b00cd6SDan Carpenter 		if (ret <= 0) {
42794b00cd6SDan Carpenter 			if (!ret)
42894b00cd6SDan Carpenter 				ret = -ENXIO;
429128d5874SRoger Quadros 			netdev_err(ndev, "Failed to get rx dma irq");
430128d5874SRoger Quadros 			goto fail;
431128d5874SRoger Quadros 		}
43294b00cd6SDan Carpenter 		rx_chn->irq[i] = ret;
433128d5874SRoger Quadros 	}
434128d5874SRoger Quadros 
435128d5874SRoger Quadros 	return 0;
436128d5874SRoger Quadros 
437128d5874SRoger Quadros fail:
438128d5874SRoger Quadros 	prueth_cleanup_rx_chns(emac, rx_chn, max_rflows);
439128d5874SRoger Quadros 	return ret;
440128d5874SRoger Quadros }
441128d5874SRoger Quadros 
prueth_dma_rx_push(struct prueth_emac * emac,struct sk_buff * skb,struct prueth_rx_chn * rx_chn)442128d5874SRoger Quadros static int prueth_dma_rx_push(struct prueth_emac *emac,
443128d5874SRoger Quadros 			      struct sk_buff *skb,
444128d5874SRoger Quadros 			      struct prueth_rx_chn *rx_chn)
445128d5874SRoger Quadros {
446128d5874SRoger Quadros 	struct net_device *ndev = emac->ndev;
447128d5874SRoger Quadros 	struct cppi5_host_desc_t *desc_rx;
448128d5874SRoger Quadros 	u32 pkt_len = skb_tailroom(skb);
449128d5874SRoger Quadros 	dma_addr_t desc_dma;
450128d5874SRoger Quadros 	dma_addr_t buf_dma;
451128d5874SRoger Quadros 	void **swdata;
452128d5874SRoger Quadros 
453128d5874SRoger Quadros 	desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool);
454128d5874SRoger Quadros 	if (!desc_rx) {
455128d5874SRoger Quadros 		netdev_err(ndev, "rx push: failed to allocate descriptor\n");
456128d5874SRoger Quadros 		return -ENOMEM;
457128d5874SRoger Quadros 	}
458128d5874SRoger Quadros 	desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx);
459128d5874SRoger Quadros 
460128d5874SRoger Quadros 	buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, DMA_FROM_DEVICE);
461128d5874SRoger Quadros 	if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) {
462128d5874SRoger Quadros 		k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
463128d5874SRoger Quadros 		netdev_err(ndev, "rx push: failed to map rx pkt buffer\n");
464128d5874SRoger Quadros 		return -EINVAL;
465128d5874SRoger Quadros 	}
466128d5874SRoger Quadros 
467128d5874SRoger Quadros 	cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT,
468128d5874SRoger Quadros 			 PRUETH_NAV_PS_DATA_SIZE);
469128d5874SRoger Quadros 	k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma);
470128d5874SRoger Quadros 	cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb));
471128d5874SRoger Quadros 
472128d5874SRoger Quadros 	swdata = cppi5_hdesc_get_swdata(desc_rx);
473128d5874SRoger Quadros 	*swdata = skb;
474128d5874SRoger Quadros 
475128d5874SRoger Quadros 	return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0,
476128d5874SRoger Quadros 					desc_rx, desc_dma);
477128d5874SRoger Quadros }
478128d5874SRoger Quadros 
icssg_ts_to_ns(u32 hi_sw,u32 hi,u32 lo,u32 cycle_time_ns)479186734c1SRoger Quadros static u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns)
480186734c1SRoger Quadros {
481186734c1SRoger Quadros 	u32 iepcount_lo, iepcount_hi, hi_rollover_count;
482186734c1SRoger Quadros 	u64 ns;
483186734c1SRoger Quadros 
484186734c1SRoger Quadros 	iepcount_lo = lo & GENMASK(19, 0);
485186734c1SRoger Quadros 	iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20;
486186734c1SRoger Quadros 	hi_rollover_count = hi >> 11;
487186734c1SRoger Quadros 
488186734c1SRoger Quadros 	ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw);
489186734c1SRoger Quadros 	ns = ns * cycle_time_ns + iepcount_lo;
490186734c1SRoger Quadros 
491186734c1SRoger Quadros 	return ns;
492186734c1SRoger Quadros }
493186734c1SRoger Quadros 
emac_rx_timestamp(struct prueth_emac * emac,struct sk_buff * skb,u32 * psdata)494186734c1SRoger Quadros static void emac_rx_timestamp(struct prueth_emac *emac,
495186734c1SRoger Quadros 			      struct sk_buff *skb, u32 *psdata)
496186734c1SRoger Quadros {
497186734c1SRoger Quadros 	struct skb_shared_hwtstamps *ssh;
498186734c1SRoger Quadros 	u64 ns;
499186734c1SRoger Quadros 
500186734c1SRoger Quadros 	u32 hi_sw = readl(emac->prueth->shram.va +
501186734c1SRoger Quadros 			  TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);
502186734c1SRoger Quadros 	ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0],
503186734c1SRoger Quadros 			    IEP_DEFAULT_CYCLE_TIME_NS);
504186734c1SRoger Quadros 
505186734c1SRoger Quadros 	ssh = skb_hwtstamps(skb);
506186734c1SRoger Quadros 	memset(ssh, 0, sizeof(*ssh));
507186734c1SRoger Quadros 	ssh->hwtstamp = ns_to_ktime(ns);
508186734c1SRoger Quadros }
509186734c1SRoger Quadros 
emac_rx_packet(struct prueth_emac * emac,u32 flow_id)510128d5874SRoger Quadros static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)
511128d5874SRoger Quadros {
512128d5874SRoger Quadros 	struct prueth_rx_chn *rx_chn = &emac->rx_chns;
513128d5874SRoger Quadros 	u32 buf_dma_len, pkt_len, port_id = 0;
514128d5874SRoger Quadros 	struct net_device *ndev = emac->ndev;
515128d5874SRoger Quadros 	struct cppi5_host_desc_t *desc_rx;
516128d5874SRoger Quadros 	struct sk_buff *skb, *new_skb;
517128d5874SRoger Quadros 	dma_addr_t desc_dma, buf_dma;
518128d5874SRoger Quadros 	void **swdata;
519186734c1SRoger Quadros 	u32 *psdata;
520128d5874SRoger Quadros 	int ret;
521128d5874SRoger Quadros 
522128d5874SRoger Quadros 	ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma);
523128d5874SRoger Quadros 	if (ret) {
524128d5874SRoger Quadros 		if (ret != -ENODATA)
525128d5874SRoger Quadros 			netdev_err(ndev, "rx pop: failed: %d\n", ret);
526128d5874SRoger Quadros 		return ret;
527128d5874SRoger Quadros 	}
528128d5874SRoger Quadros 
529128d5874SRoger Quadros 	if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown ? */
530128d5874SRoger Quadros 		return 0;
531128d5874SRoger Quadros 
532128d5874SRoger Quadros 	desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
533128d5874SRoger Quadros 
534128d5874SRoger Quadros 	swdata = cppi5_hdesc_get_swdata(desc_rx);
535128d5874SRoger Quadros 	skb = *swdata;
536128d5874SRoger Quadros 
537186734c1SRoger Quadros 	psdata = cppi5_hdesc_get_psdata(desc_rx);
538186734c1SRoger Quadros 	/* RX HW timestamp */
539186734c1SRoger Quadros 	if (emac->rx_ts_enabled)
540186734c1SRoger Quadros 		emac_rx_timestamp(emac, skb, psdata);
541186734c1SRoger Quadros 
542128d5874SRoger Quadros 	cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
543128d5874SRoger Quadros 	k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
544128d5874SRoger Quadros 	pkt_len = cppi5_hdesc_get_pktlen(desc_rx);
545128d5874SRoger Quadros 	/* firmware adds 4 CRC bytes, strip them */
546128d5874SRoger Quadros 	pkt_len -= 4;
547128d5874SRoger Quadros 	cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
548128d5874SRoger Quadros 
549128d5874SRoger Quadros 	dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE);
550128d5874SRoger Quadros 	k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
551128d5874SRoger Quadros 
552128d5874SRoger Quadros 	skb->dev = ndev;
553128d5874SRoger Quadros 	new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE);
554128d5874SRoger Quadros 	/* if allocation fails we drop the packet but push the
555128d5874SRoger Quadros 	 * descriptor back to the ring with old skb to prevent a stall
556128d5874SRoger Quadros 	 */
557128d5874SRoger Quadros 	if (!new_skb) {
558128d5874SRoger Quadros 		ndev->stats.rx_dropped++;
559128d5874SRoger Quadros 		new_skb = skb;
560128d5874SRoger Quadros 	} else {
561128d5874SRoger Quadros 		/* send the filled skb up the n/w stack */
562128d5874SRoger Quadros 		skb_put(skb, pkt_len);
563128d5874SRoger Quadros 		skb->protocol = eth_type_trans(skb, ndev);
564128d5874SRoger Quadros 		napi_gro_receive(&emac->napi_rx, skb);
565128d5874SRoger Quadros 		ndev->stats.rx_bytes += pkt_len;
566128d5874SRoger Quadros 		ndev->stats.rx_packets++;
567128d5874SRoger Quadros 	}
568128d5874SRoger Quadros 
569128d5874SRoger Quadros 	/* queue another RX DMA */
570128d5874SRoger Quadros 	ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_chns);
571128d5874SRoger Quadros 	if (WARN_ON(ret < 0)) {
572128d5874SRoger Quadros 		dev_kfree_skb_any(new_skb);
573128d5874SRoger Quadros 		ndev->stats.rx_errors++;
574128d5874SRoger Quadros 		ndev->stats.rx_dropped++;
575128d5874SRoger Quadros 	}
576128d5874SRoger Quadros 
577128d5874SRoger Quadros 	return ret;
578128d5874SRoger Quadros }
579128d5874SRoger Quadros 
prueth_rx_cleanup(void * data,dma_addr_t desc_dma)580128d5874SRoger Quadros static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma)
581128d5874SRoger Quadros {
582128d5874SRoger Quadros 	struct prueth_rx_chn *rx_chn = data;
583128d5874SRoger Quadros 	struct cppi5_host_desc_t *desc_rx;
584128d5874SRoger Quadros 	struct sk_buff *skb;
585128d5874SRoger Quadros 	dma_addr_t buf_dma;
586128d5874SRoger Quadros 	u32 buf_dma_len;
587128d5874SRoger Quadros 	void **swdata;
588128d5874SRoger Quadros 
589128d5874SRoger Quadros 	desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
590128d5874SRoger Quadros 	swdata = cppi5_hdesc_get_swdata(desc_rx);
591128d5874SRoger Quadros 	skb = *swdata;
592128d5874SRoger Quadros 	cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
593128d5874SRoger Quadros 	k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
594128d5874SRoger Quadros 
595128d5874SRoger Quadros 	dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len,
596128d5874SRoger Quadros 			 DMA_FROM_DEVICE);
597128d5874SRoger Quadros 	k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
598128d5874SRoger Quadros 
599128d5874SRoger Quadros 	dev_kfree_skb_any(skb);
600128d5874SRoger Quadros }
601128d5874SRoger Quadros 
emac_get_tx_ts(struct prueth_emac * emac,struct emac_tx_ts_response * rsp)602186734c1SRoger Quadros static int emac_get_tx_ts(struct prueth_emac *emac,
603186734c1SRoger Quadros 			  struct emac_tx_ts_response *rsp)
604186734c1SRoger Quadros {
605186734c1SRoger Quadros 	struct prueth *prueth = emac->prueth;
606186734c1SRoger Quadros 	int slice = prueth_emac_slice(emac);
607186734c1SRoger Quadros 	int addr;
608186734c1SRoger Quadros 
609186734c1SRoger Quadros 	addr = icssg_queue_pop(prueth, slice == 0 ?
610186734c1SRoger Quadros 			       ICSSG_TS_POP_SLICE0 : ICSSG_TS_POP_SLICE1);
611186734c1SRoger Quadros 	if (addr < 0)
612186734c1SRoger Quadros 		return addr;
613186734c1SRoger Quadros 
614186734c1SRoger Quadros 	memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));
615186734c1SRoger Quadros 	/* return buffer back for to pool */
616186734c1SRoger Quadros 	icssg_queue_push(prueth, slice == 0 ?
617186734c1SRoger Quadros 			 ICSSG_TS_PUSH_SLICE0 : ICSSG_TS_PUSH_SLICE1, addr);
618186734c1SRoger Quadros 
619186734c1SRoger Quadros 	return 0;
620186734c1SRoger Quadros }
621186734c1SRoger Quadros 
tx_ts_work(struct prueth_emac * emac)622186734c1SRoger Quadros static void tx_ts_work(struct prueth_emac *emac)
623186734c1SRoger Quadros {
624186734c1SRoger Quadros 	struct skb_shared_hwtstamps ssh;
625186734c1SRoger Quadros 	struct emac_tx_ts_response tsr;
626186734c1SRoger Quadros 	struct sk_buff *skb;
627186734c1SRoger Quadros 	int ret = 0;
628186734c1SRoger Quadros 	u32 hi_sw;
629186734c1SRoger Quadros 	u64 ns;
630186734c1SRoger Quadros 
631186734c1SRoger Quadros 	/* There may be more than one pending requests */
632186734c1SRoger Quadros 	while (1) {
633186734c1SRoger Quadros 		ret = emac_get_tx_ts(emac, &tsr);
634186734c1SRoger Quadros 		if (ret) /* nothing more */
635186734c1SRoger Quadros 			break;
636186734c1SRoger Quadros 
637186734c1SRoger Quadros 		if (tsr.cookie >= PRUETH_MAX_TX_TS_REQUESTS ||
638186734c1SRoger Quadros 		    !emac->tx_ts_skb[tsr.cookie]) {
639186734c1SRoger Quadros 			netdev_err(emac->ndev, "Invalid TX TS cookie 0x%x\n",
640186734c1SRoger Quadros 				   tsr.cookie);
641186734c1SRoger Quadros 			break;
642186734c1SRoger Quadros 		}
643186734c1SRoger Quadros 
644186734c1SRoger Quadros 		skb = emac->tx_ts_skb[tsr.cookie];
645186734c1SRoger Quadros 		emac->tx_ts_skb[tsr.cookie] = NULL;	/* free slot */
646186734c1SRoger Quadros 		if (!skb) {
647186734c1SRoger Quadros 			netdev_err(emac->ndev, "Driver Bug! got NULL skb\n");
648186734c1SRoger Quadros 			break;
649186734c1SRoger Quadros 		}
650186734c1SRoger Quadros 
651186734c1SRoger Quadros 		hi_sw = readl(emac->prueth->shram.va +
652186734c1SRoger Quadros 			      TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);
653186734c1SRoger Quadros 		ns = icssg_ts_to_ns(hi_sw, tsr.hi_ts, tsr.lo_ts,
654186734c1SRoger Quadros 				    IEP_DEFAULT_CYCLE_TIME_NS);
655186734c1SRoger Quadros 
656186734c1SRoger Quadros 		memset(&ssh, 0, sizeof(ssh));
657186734c1SRoger Quadros 		ssh.hwtstamp = ns_to_ktime(ns);
658186734c1SRoger Quadros 
659186734c1SRoger Quadros 		skb_tstamp_tx(skb, &ssh);
660186734c1SRoger Quadros 		dev_consume_skb_any(skb);
661186734c1SRoger Quadros 
662186734c1SRoger Quadros 		if (atomic_dec_and_test(&emac->tx_ts_pending))	/* no more? */
663186734c1SRoger Quadros 			break;
664186734c1SRoger Quadros 	}
665186734c1SRoger Quadros }
666186734c1SRoger Quadros 
prueth_tx_ts_cookie_get(struct prueth_emac * emac)667186734c1SRoger Quadros static int prueth_tx_ts_cookie_get(struct prueth_emac *emac)
668186734c1SRoger Quadros {
669186734c1SRoger Quadros 	int i;
670186734c1SRoger Quadros 
671186734c1SRoger Quadros 	/* search and get the next free slot */
672186734c1SRoger Quadros 	for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {
673186734c1SRoger Quadros 		if (!emac->tx_ts_skb[i]) {
674186734c1SRoger Quadros 			emac->tx_ts_skb[i] = ERR_PTR(-EBUSY); /* reserve slot */
675186734c1SRoger Quadros 			return i;
676186734c1SRoger Quadros 		}
677186734c1SRoger Quadros 	}
678186734c1SRoger Quadros 
679186734c1SRoger Quadros 	return -EBUSY;
680186734c1SRoger Quadros }
681186734c1SRoger Quadros 
682128d5874SRoger Quadros /**
683128d5874SRoger Quadros  * emac_ndo_start_xmit - EMAC Transmit function
684128d5874SRoger Quadros  * @skb: SKB pointer
685128d5874SRoger Quadros  * @ndev: EMAC network adapter
686128d5874SRoger Quadros  *
687128d5874SRoger Quadros  * Called by the system to transmit a packet  - we queue the packet in
688128d5874SRoger Quadros  * EMAC hardware transmit queue
689128d5874SRoger Quadros  * Doesn't wait for completion we'll check for TX completion in
690128d5874SRoger Quadros  * emac_tx_complete_packets().
691128d5874SRoger Quadros  *
692128d5874SRoger Quadros  * Return: enum netdev_tx
693128d5874SRoger Quadros  */
emac_ndo_start_xmit(struct sk_buff * skb,struct net_device * ndev)694128d5874SRoger Quadros static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
695128d5874SRoger Quadros {
696128d5874SRoger Quadros 	struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc;
697128d5874SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
698128d5874SRoger Quadros 	struct netdev_queue *netif_txq;
699128d5874SRoger Quadros 	struct prueth_tx_chn *tx_chn;
700128d5874SRoger Quadros 	dma_addr_t desc_dma, buf_dma;
701128d5874SRoger Quadros 	int i, ret = 0, q_idx;
702186734c1SRoger Quadros 	bool in_tx_ts = 0;
703186734c1SRoger Quadros 	int tx_ts_cookie;
704128d5874SRoger Quadros 	void **swdata;
705128d5874SRoger Quadros 	u32 pkt_len;
706128d5874SRoger Quadros 	u32 *epib;
707128d5874SRoger Quadros 
708128d5874SRoger Quadros 	pkt_len = skb_headlen(skb);
709128d5874SRoger Quadros 	q_idx = skb_get_queue_mapping(skb);
710128d5874SRoger Quadros 
711128d5874SRoger Quadros 	tx_chn = &emac->tx_chns[q_idx];
712128d5874SRoger Quadros 	netif_txq = netdev_get_tx_queue(ndev, q_idx);
713128d5874SRoger Quadros 
714128d5874SRoger Quadros 	/* Map the linear buffer */
715128d5874SRoger Quadros 	buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE);
716128d5874SRoger Quadros 	if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {
717128d5874SRoger Quadros 		netdev_err(ndev, "tx: failed to map skb buffer\n");
718128d5874SRoger Quadros 		ret = NETDEV_TX_OK;
719128d5874SRoger Quadros 		goto drop_free_skb;
720128d5874SRoger Quadros 	}
721128d5874SRoger Quadros 
722128d5874SRoger Quadros 	first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);
723128d5874SRoger Quadros 	if (!first_desc) {
724128d5874SRoger Quadros 		netdev_dbg(ndev, "tx: failed to allocate descriptor\n");
725128d5874SRoger Quadros 		dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE);
726128d5874SRoger Quadros 		goto drop_stop_q_busy;
727128d5874SRoger Quadros 	}
728128d5874SRoger Quadros 
729128d5874SRoger Quadros 	cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT,
730128d5874SRoger Quadros 			 PRUETH_NAV_PS_DATA_SIZE);
731128d5874SRoger Quadros 	cppi5_hdesc_set_pkttype(first_desc, 0);
732128d5874SRoger Quadros 	epib = first_desc->epib;
733128d5874SRoger Quadros 	epib[0] = 0;
734128d5874SRoger Quadros 	epib[1] = 0;
735186734c1SRoger Quadros 	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
736186734c1SRoger Quadros 	    emac->tx_ts_enabled) {
737186734c1SRoger Quadros 		tx_ts_cookie = prueth_tx_ts_cookie_get(emac);
738186734c1SRoger Quadros 		if (tx_ts_cookie >= 0) {
739186734c1SRoger Quadros 			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
740186734c1SRoger Quadros 			/* Request TX timestamp */
741186734c1SRoger Quadros 			epib[0] = (u32)tx_ts_cookie;
742186734c1SRoger Quadros 			epib[1] = 0x80000000;	/* TX TS request */
743186734c1SRoger Quadros 			emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb);
744186734c1SRoger Quadros 			in_tx_ts = 1;
745186734c1SRoger Quadros 		}
746186734c1SRoger Quadros 	}
747128d5874SRoger Quadros 
748128d5874SRoger Quadros 	/* set dst tag to indicate internal qid at the firmware which is at
749128d5874SRoger Quadros 	 * bit8..bit15. bit0..bit7 indicates port num for directed
750128d5874SRoger Quadros 	 * packets in case of switch mode operation
751128d5874SRoger Quadros 	 */
752128d5874SRoger Quadros 	cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8)));
753128d5874SRoger Quadros 	k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
754128d5874SRoger Quadros 	cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len);
755128d5874SRoger Quadros 	swdata = cppi5_hdesc_get_swdata(first_desc);
756128d5874SRoger Quadros 	*swdata = skb;
757128d5874SRoger Quadros 
758128d5874SRoger Quadros 	/* Handle the case where skb is fragmented in pages */
759128d5874SRoger Quadros 	cur_desc = first_desc;
760128d5874SRoger Quadros 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
761128d5874SRoger Quadros 		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
762128d5874SRoger Quadros 		u32 frag_size = skb_frag_size(frag);
763128d5874SRoger Quadros 
764128d5874SRoger Quadros 		next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);
765128d5874SRoger Quadros 		if (!next_desc) {
766128d5874SRoger Quadros 			netdev_err(ndev,
767128d5874SRoger Quadros 				   "tx: failed to allocate frag. descriptor\n");
768186734c1SRoger Quadros 			goto free_desc_stop_q_busy_cleanup_tx_ts;
769128d5874SRoger Quadros 		}
770128d5874SRoger Quadros 
771128d5874SRoger Quadros 		buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size,
772128d5874SRoger Quadros 					   DMA_TO_DEVICE);
773128d5874SRoger Quadros 		if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {
774128d5874SRoger Quadros 			netdev_err(ndev, "tx: Failed to map skb page\n");
775128d5874SRoger Quadros 			k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
776128d5874SRoger Quadros 			ret = NETDEV_TX_OK;
777186734c1SRoger Quadros 			goto cleanup_tx_ts;
778128d5874SRoger Quadros 		}
779128d5874SRoger Quadros 
780128d5874SRoger Quadros 		cppi5_hdesc_reset_hbdesc(next_desc);
781128d5874SRoger Quadros 		k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
782128d5874SRoger Quadros 		cppi5_hdesc_attach_buf(next_desc,
783128d5874SRoger Quadros 				       buf_dma, frag_size, buf_dma, frag_size);
784128d5874SRoger Quadros 
785128d5874SRoger Quadros 		desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool,
786128d5874SRoger Quadros 						      next_desc);
787128d5874SRoger Quadros 		k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &desc_dma);
788128d5874SRoger Quadros 		cppi5_hdesc_link_hbdesc(cur_desc, desc_dma);
789128d5874SRoger Quadros 
790128d5874SRoger Quadros 		pkt_len += frag_size;
791128d5874SRoger Quadros 		cur_desc = next_desc;
792128d5874SRoger Quadros 	}
793128d5874SRoger Quadros 	WARN_ON_ONCE(pkt_len != skb->len);
794128d5874SRoger Quadros 
795128d5874SRoger Quadros 	/* report bql before sending packet */
796128d5874SRoger Quadros 	netdev_tx_sent_queue(netif_txq, pkt_len);
797128d5874SRoger Quadros 
798128d5874SRoger Quadros 	cppi5_hdesc_set_pktlen(first_desc, pkt_len);
799128d5874SRoger Quadros 	desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc);
800128d5874SRoger Quadros 	/* cppi5_desc_dump(first_desc, 64); */
801128d5874SRoger Quadros 
802128d5874SRoger Quadros 	skb_tx_timestamp(skb);  /* SW timestamp if SKBTX_IN_PROGRESS not set */
803128d5874SRoger Quadros 	ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma);
804128d5874SRoger Quadros 	if (ret) {
805128d5874SRoger Quadros 		netdev_err(ndev, "tx: push failed: %d\n", ret);
806128d5874SRoger Quadros 		goto drop_free_descs;
807128d5874SRoger Quadros 	}
808128d5874SRoger Quadros 
809186734c1SRoger Quadros 	if (in_tx_ts)
810186734c1SRoger Quadros 		atomic_inc(&emac->tx_ts_pending);
811186734c1SRoger Quadros 
812128d5874SRoger Quadros 	if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) {
813128d5874SRoger Quadros 		netif_tx_stop_queue(netif_txq);
814128d5874SRoger Quadros 		/* Barrier, so that stop_queue visible to other cpus */
815128d5874SRoger Quadros 		smp_mb__after_atomic();
816128d5874SRoger Quadros 
817128d5874SRoger Quadros 		if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=
818128d5874SRoger Quadros 		    MAX_SKB_FRAGS)
819128d5874SRoger Quadros 			netif_tx_wake_queue(netif_txq);
820128d5874SRoger Quadros 	}
821128d5874SRoger Quadros 
822128d5874SRoger Quadros 	return NETDEV_TX_OK;
823128d5874SRoger Quadros 
824186734c1SRoger Quadros cleanup_tx_ts:
825186734c1SRoger Quadros 	if (in_tx_ts) {
826186734c1SRoger Quadros 		dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);
827186734c1SRoger Quadros 		emac->tx_ts_skb[tx_ts_cookie] = NULL;
828186734c1SRoger Quadros 	}
829186734c1SRoger Quadros 
830128d5874SRoger Quadros drop_free_descs:
831128d5874SRoger Quadros 	prueth_xmit_free(tx_chn, first_desc);
832128d5874SRoger Quadros 
833128d5874SRoger Quadros drop_free_skb:
834128d5874SRoger Quadros 	dev_kfree_skb_any(skb);
835128d5874SRoger Quadros 
836128d5874SRoger Quadros 	/* error */
837128d5874SRoger Quadros 	ndev->stats.tx_dropped++;
838128d5874SRoger Quadros 	netdev_err(ndev, "tx: error: %d\n", ret);
839128d5874SRoger Quadros 
840128d5874SRoger Quadros 	return ret;
841128d5874SRoger Quadros 
842186734c1SRoger Quadros free_desc_stop_q_busy_cleanup_tx_ts:
843186734c1SRoger Quadros 	if (in_tx_ts) {
844186734c1SRoger Quadros 		dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);
845186734c1SRoger Quadros 		emac->tx_ts_skb[tx_ts_cookie] = NULL;
846186734c1SRoger Quadros 	}
847128d5874SRoger Quadros 	prueth_xmit_free(tx_chn, first_desc);
848128d5874SRoger Quadros 
849128d5874SRoger Quadros drop_stop_q_busy:
850128d5874SRoger Quadros 	netif_tx_stop_queue(netif_txq);
851128d5874SRoger Quadros 	return NETDEV_TX_BUSY;
852128d5874SRoger Quadros }
853128d5874SRoger Quadros 
prueth_tx_cleanup(void * data,dma_addr_t desc_dma)854128d5874SRoger Quadros static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma)
855128d5874SRoger Quadros {
856128d5874SRoger Quadros 	struct prueth_tx_chn *tx_chn = data;
857128d5874SRoger Quadros 	struct cppi5_host_desc_t *desc_tx;
858128d5874SRoger Quadros 	struct sk_buff *skb;
859128d5874SRoger Quadros 	void **swdata;
860128d5874SRoger Quadros 
861128d5874SRoger Quadros 	desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma);
862128d5874SRoger Quadros 	swdata = cppi5_hdesc_get_swdata(desc_tx);
863128d5874SRoger Quadros 	skb = *(swdata);
864128d5874SRoger Quadros 	prueth_xmit_free(tx_chn, desc_tx);
865128d5874SRoger Quadros 
866128d5874SRoger Quadros 	dev_kfree_skb_any(skb);
867128d5874SRoger Quadros }
868128d5874SRoger Quadros 
prueth_tx_ts_irq(int irq,void * dev_id)869186734c1SRoger Quadros static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id)
870186734c1SRoger Quadros {
871186734c1SRoger Quadros 	struct prueth_emac *emac = dev_id;
872186734c1SRoger Quadros 
873186734c1SRoger Quadros 	/* currently only TX timestamp is being returned */
874186734c1SRoger Quadros 	tx_ts_work(emac);
875186734c1SRoger Quadros 
876186734c1SRoger Quadros 	return IRQ_HANDLED;
877186734c1SRoger Quadros }
878186734c1SRoger Quadros 
prueth_rx_irq(int irq,void * dev_id)879128d5874SRoger Quadros static irqreturn_t prueth_rx_irq(int irq, void *dev_id)
880128d5874SRoger Quadros {
881128d5874SRoger Quadros 	struct prueth_emac *emac = dev_id;
882128d5874SRoger Quadros 
883128d5874SRoger Quadros 	disable_irq_nosync(irq);
884128d5874SRoger Quadros 	napi_schedule(&emac->napi_rx);
885128d5874SRoger Quadros 
886128d5874SRoger Quadros 	return IRQ_HANDLED;
887128d5874SRoger Quadros }
888128d5874SRoger Quadros 
889128d5874SRoger Quadros struct icssg_firmwares {
890128d5874SRoger Quadros 	char *pru;
891128d5874SRoger Quadros 	char *rtu;
892128d5874SRoger Quadros 	char *txpru;
893128d5874SRoger Quadros };
894128d5874SRoger Quadros 
895128d5874SRoger Quadros static struct icssg_firmwares icssg_emac_firmwares[] = {
896128d5874SRoger Quadros 	{
897128d5874SRoger Quadros 		.pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
898128d5874SRoger Quadros 		.rtu = "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
899128d5874SRoger Quadros 		.txpru = "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
900128d5874SRoger Quadros 	},
901128d5874SRoger Quadros 	{
902128d5874SRoger Quadros 		.pru = "ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
903128d5874SRoger Quadros 		.rtu = "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
904128d5874SRoger Quadros 		.txpru = "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf",
905128d5874SRoger Quadros 	}
906128d5874SRoger Quadros };
907128d5874SRoger Quadros 
prueth_emac_start(struct prueth * prueth,struct prueth_emac * emac)908128d5874SRoger Quadros static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)
909128d5874SRoger Quadros {
910128d5874SRoger Quadros 	struct icssg_firmwares *firmwares;
911128d5874SRoger Quadros 	struct device *dev = prueth->dev;
912128d5874SRoger Quadros 	int slice, ret;
913128d5874SRoger Quadros 
914128d5874SRoger Quadros 	firmwares = icssg_emac_firmwares;
915128d5874SRoger Quadros 
916128d5874SRoger Quadros 	slice = prueth_emac_slice(emac);
917128d5874SRoger Quadros 	if (slice < 0) {
918128d5874SRoger Quadros 		netdev_err(emac->ndev, "invalid port\n");
919128d5874SRoger Quadros 		return -EINVAL;
920128d5874SRoger Quadros 	}
921128d5874SRoger Quadros 
922128d5874SRoger Quadros 	ret = icssg_config(prueth, emac, slice);
923128d5874SRoger Quadros 	if (ret)
924128d5874SRoger Quadros 		return ret;
925128d5874SRoger Quadros 
926128d5874SRoger Quadros 	ret = rproc_set_firmware(prueth->pru[slice], firmwares[slice].pru);
927128d5874SRoger Quadros 	ret = rproc_boot(prueth->pru[slice]);
928128d5874SRoger Quadros 	if (ret) {
929128d5874SRoger Quadros 		dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);
930128d5874SRoger Quadros 		return -EINVAL;
931128d5874SRoger Quadros 	}
932128d5874SRoger Quadros 
933128d5874SRoger Quadros 	ret = rproc_set_firmware(prueth->rtu[slice], firmwares[slice].rtu);
934128d5874SRoger Quadros 	ret = rproc_boot(prueth->rtu[slice]);
935128d5874SRoger Quadros 	if (ret) {
936128d5874SRoger Quadros 		dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);
937128d5874SRoger Quadros 		goto halt_pru;
938128d5874SRoger Quadros 	}
939128d5874SRoger Quadros 
940128d5874SRoger Quadros 	ret = rproc_set_firmware(prueth->txpru[slice], firmwares[slice].txpru);
941128d5874SRoger Quadros 	ret = rproc_boot(prueth->txpru[slice]);
942128d5874SRoger Quadros 	if (ret) {
943128d5874SRoger Quadros 		dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret);
944128d5874SRoger Quadros 		goto halt_rtu;
945128d5874SRoger Quadros 	}
946128d5874SRoger Quadros 
947128d5874SRoger Quadros 	emac->fw_running = 1;
948128d5874SRoger Quadros 	return 0;
949128d5874SRoger Quadros 
950128d5874SRoger Quadros halt_rtu:
951128d5874SRoger Quadros 	rproc_shutdown(prueth->rtu[slice]);
952128d5874SRoger Quadros 
953128d5874SRoger Quadros halt_pru:
954128d5874SRoger Quadros 	rproc_shutdown(prueth->pru[slice]);
955128d5874SRoger Quadros 
956128d5874SRoger Quadros 	return ret;
957128d5874SRoger Quadros }
958128d5874SRoger Quadros 
prueth_emac_stop(struct prueth_emac * emac)959128d5874SRoger Quadros static void prueth_emac_stop(struct prueth_emac *emac)
960128d5874SRoger Quadros {
961128d5874SRoger Quadros 	struct prueth *prueth = emac->prueth;
962128d5874SRoger Quadros 	int slice;
963128d5874SRoger Quadros 
964128d5874SRoger Quadros 	switch (emac->port_id) {
965128d5874SRoger Quadros 	case PRUETH_PORT_MII0:
966128d5874SRoger Quadros 		slice = ICSS_SLICE0;
967128d5874SRoger Quadros 		break;
968128d5874SRoger Quadros 	case PRUETH_PORT_MII1:
969128d5874SRoger Quadros 		slice = ICSS_SLICE1;
970128d5874SRoger Quadros 		break;
971128d5874SRoger Quadros 	default:
972128d5874SRoger Quadros 		netdev_err(emac->ndev, "invalid port\n");
973128d5874SRoger Quadros 		return;
974128d5874SRoger Quadros 	}
975128d5874SRoger Quadros 
976128d5874SRoger Quadros 	emac->fw_running = 0;
977128d5874SRoger Quadros 	rproc_shutdown(prueth->txpru[slice]);
978128d5874SRoger Quadros 	rproc_shutdown(prueth->rtu[slice]);
979128d5874SRoger Quadros 	rproc_shutdown(prueth->pru[slice]);
980128d5874SRoger Quadros }
981128d5874SRoger Quadros 
prueth_cleanup_tx_ts(struct prueth_emac * emac)982186734c1SRoger Quadros static void prueth_cleanup_tx_ts(struct prueth_emac *emac)
983186734c1SRoger Quadros {
984186734c1SRoger Quadros 	int i;
985186734c1SRoger Quadros 
986186734c1SRoger Quadros 	for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {
987186734c1SRoger Quadros 		if (emac->tx_ts_skb[i]) {
988186734c1SRoger Quadros 			dev_kfree_skb_any(emac->tx_ts_skb[i]);
989186734c1SRoger Quadros 			emac->tx_ts_skb[i] = NULL;
990186734c1SRoger Quadros 		}
991186734c1SRoger Quadros 	}
992186734c1SRoger Quadros }
993186734c1SRoger Quadros 
994128d5874SRoger Quadros /* called back by PHY layer if there is change in link state of hw port*/
emac_adjust_link(struct net_device * ndev)995128d5874SRoger Quadros static void emac_adjust_link(struct net_device *ndev)
996128d5874SRoger Quadros {
997128d5874SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
998128d5874SRoger Quadros 	struct phy_device *phydev = ndev->phydev;
999128d5874SRoger Quadros 	struct prueth *prueth = emac->prueth;
1000128d5874SRoger Quadros 	bool new_state = false;
1001128d5874SRoger Quadros 	unsigned long flags;
1002128d5874SRoger Quadros 
1003128d5874SRoger Quadros 	if (phydev->link) {
1004128d5874SRoger Quadros 		/* check the mode of operation - full/half duplex */
1005128d5874SRoger Quadros 		if (phydev->duplex != emac->duplex) {
1006128d5874SRoger Quadros 			new_state = true;
1007128d5874SRoger Quadros 			emac->duplex = phydev->duplex;
1008128d5874SRoger Quadros 		}
1009128d5874SRoger Quadros 		if (phydev->speed != emac->speed) {
1010128d5874SRoger Quadros 			new_state = true;
1011128d5874SRoger Quadros 			emac->speed = phydev->speed;
1012128d5874SRoger Quadros 		}
1013128d5874SRoger Quadros 		if (!emac->link) {
1014128d5874SRoger Quadros 			new_state = true;
1015128d5874SRoger Quadros 			emac->link = 1;
1016128d5874SRoger Quadros 		}
1017128d5874SRoger Quadros 	} else if (emac->link) {
1018128d5874SRoger Quadros 		new_state = true;
1019128d5874SRoger Quadros 		emac->link = 0;
1020128d5874SRoger Quadros 
1021128d5874SRoger Quadros 		/* f/w should support 100 & 1000 */
1022128d5874SRoger Quadros 		emac->speed = SPEED_1000;
1023128d5874SRoger Quadros 
1024128d5874SRoger Quadros 		/* half duplex may not be supported by f/w */
1025128d5874SRoger Quadros 		emac->duplex = DUPLEX_FULL;
1026128d5874SRoger Quadros 	}
1027128d5874SRoger Quadros 
1028128d5874SRoger Quadros 	if (new_state) {
1029128d5874SRoger Quadros 		phy_print_status(phydev);
1030128d5874SRoger Quadros 
1031128d5874SRoger Quadros 		/* update RGMII and MII configuration based on PHY negotiated
1032128d5874SRoger Quadros 		 * values
1033128d5874SRoger Quadros 		 */
1034128d5874SRoger Quadros 		if (emac->link) {
1035128d5874SRoger Quadros 			/* Set the RGMII cfg for gig en and full duplex */
1036128d5874SRoger Quadros 			icssg_update_rgmii_cfg(prueth->miig_rt, emac);
1037128d5874SRoger Quadros 
1038128d5874SRoger Quadros 			/* update the Tx IPG based on 100M/1G speed */
1039128d5874SRoger Quadros 			spin_lock_irqsave(&emac->lock, flags);
1040128d5874SRoger Quadros 			icssg_config_ipg(emac);
1041128d5874SRoger Quadros 			spin_unlock_irqrestore(&emac->lock, flags);
1042128d5874SRoger Quadros 			icssg_config_set_speed(emac);
1043128d5874SRoger Quadros 			emac_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD);
1044128d5874SRoger Quadros 
1045128d5874SRoger Quadros 		} else {
1046128d5874SRoger Quadros 			emac_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);
1047128d5874SRoger Quadros 		}
1048128d5874SRoger Quadros 	}
1049128d5874SRoger Quadros 
1050128d5874SRoger Quadros 	if (emac->link) {
1051128d5874SRoger Quadros 		/* reactivate the transmit queue */
1052128d5874SRoger Quadros 		netif_tx_wake_all_queues(ndev);
1053128d5874SRoger Quadros 	} else {
1054128d5874SRoger Quadros 		netif_tx_stop_all_queues(ndev);
1055186734c1SRoger Quadros 		prueth_cleanup_tx_ts(emac);
1056128d5874SRoger Quadros 	}
1057128d5874SRoger Quadros }
1058128d5874SRoger Quadros 
emac_napi_rx_poll(struct napi_struct * napi_rx,int budget)1059128d5874SRoger Quadros static int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget)
1060128d5874SRoger Quadros {
1061128d5874SRoger Quadros 	struct prueth_emac *emac = prueth_napi_to_emac(napi_rx);
1062128d5874SRoger Quadros 	int rx_flow = PRUETH_RX_FLOW_DATA;
1063128d5874SRoger Quadros 	int flow = PRUETH_MAX_RX_FLOWS;
1064128d5874SRoger Quadros 	int num_rx = 0;
1065128d5874SRoger Quadros 	int cur_budget;
1066128d5874SRoger Quadros 	int ret;
1067128d5874SRoger Quadros 
1068128d5874SRoger Quadros 	while (flow--) {
1069128d5874SRoger Quadros 		cur_budget = budget - num_rx;
1070128d5874SRoger Quadros 
1071128d5874SRoger Quadros 		while (cur_budget--) {
1072128d5874SRoger Quadros 			ret = emac_rx_packet(emac, flow);
1073128d5874SRoger Quadros 			if (ret)
1074128d5874SRoger Quadros 				break;
1075128d5874SRoger Quadros 			num_rx++;
1076128d5874SRoger Quadros 		}
1077128d5874SRoger Quadros 
1078128d5874SRoger Quadros 		if (num_rx >= budget)
1079128d5874SRoger Quadros 			break;
1080128d5874SRoger Quadros 	}
1081128d5874SRoger Quadros 
1082128d5874SRoger Quadros 	if (num_rx < budget && napi_complete_done(napi_rx, num_rx))
1083128d5874SRoger Quadros 		enable_irq(emac->rx_chns.irq[rx_flow]);
1084128d5874SRoger Quadros 
1085128d5874SRoger Quadros 	return num_rx;
1086128d5874SRoger Quadros }
1087128d5874SRoger Quadros 
prueth_prepare_rx_chan(struct prueth_emac * emac,struct prueth_rx_chn * chn,int buf_size)1088128d5874SRoger Quadros static int prueth_prepare_rx_chan(struct prueth_emac *emac,
1089128d5874SRoger Quadros 				  struct prueth_rx_chn *chn,
1090128d5874SRoger Quadros 				  int buf_size)
1091128d5874SRoger Quadros {
1092128d5874SRoger Quadros 	struct sk_buff *skb;
1093128d5874SRoger Quadros 	int i, ret;
1094128d5874SRoger Quadros 
1095128d5874SRoger Quadros 	for (i = 0; i < chn->descs_num; i++) {
1096128d5874SRoger Quadros 		skb = __netdev_alloc_skb_ip_align(NULL, buf_size, GFP_KERNEL);
1097128d5874SRoger Quadros 		if (!skb)
1098128d5874SRoger Quadros 			return -ENOMEM;
1099128d5874SRoger Quadros 
1100128d5874SRoger Quadros 		ret = prueth_dma_rx_push(emac, skb, chn);
1101128d5874SRoger Quadros 		if (ret < 0) {
1102128d5874SRoger Quadros 			netdev_err(emac->ndev,
1103128d5874SRoger Quadros 				   "cannot submit skb for rx chan %s ret %d\n",
1104128d5874SRoger Quadros 				   chn->name, ret);
1105128d5874SRoger Quadros 			kfree_skb(skb);
1106128d5874SRoger Quadros 			return ret;
1107128d5874SRoger Quadros 		}
1108128d5874SRoger Quadros 	}
1109128d5874SRoger Quadros 
1110128d5874SRoger Quadros 	return 0;
1111128d5874SRoger Quadros }
1112128d5874SRoger Quadros 
prueth_reset_tx_chan(struct prueth_emac * emac,int ch_num,bool free_skb)1113128d5874SRoger Quadros static void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num,
1114128d5874SRoger Quadros 				 bool free_skb)
1115128d5874SRoger Quadros {
1116128d5874SRoger Quadros 	int i;
1117128d5874SRoger Quadros 
1118128d5874SRoger Quadros 	for (i = 0; i < ch_num; i++) {
1119128d5874SRoger Quadros 		if (free_skb)
1120128d5874SRoger Quadros 			k3_udma_glue_reset_tx_chn(emac->tx_chns[i].tx_chn,
1121128d5874SRoger Quadros 						  &emac->tx_chns[i],
1122128d5874SRoger Quadros 						  prueth_tx_cleanup);
1123128d5874SRoger Quadros 		k3_udma_glue_disable_tx_chn(emac->tx_chns[i].tx_chn);
1124128d5874SRoger Quadros 	}
1125128d5874SRoger Quadros }
1126128d5874SRoger Quadros 
prueth_reset_rx_chan(struct prueth_rx_chn * chn,int num_flows,bool disable)1127128d5874SRoger Quadros static void prueth_reset_rx_chan(struct prueth_rx_chn *chn,
1128128d5874SRoger Quadros 				 int num_flows, bool disable)
1129128d5874SRoger Quadros {
1130128d5874SRoger Quadros 	int i;
1131128d5874SRoger Quadros 
1132128d5874SRoger Quadros 	for (i = 0; i < num_flows; i++)
1133128d5874SRoger Quadros 		k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn,
1134128d5874SRoger Quadros 					  prueth_rx_cleanup, !!i);
1135128d5874SRoger Quadros 	if (disable)
1136128d5874SRoger Quadros 		k3_udma_glue_disable_rx_chn(chn->rx_chn);
1137128d5874SRoger Quadros }
1138128d5874SRoger Quadros 
emac_phy_connect(struct prueth_emac * emac)1139128d5874SRoger Quadros static int emac_phy_connect(struct prueth_emac *emac)
1140128d5874SRoger Quadros {
1141128d5874SRoger Quadros 	struct prueth *prueth = emac->prueth;
1142128d5874SRoger Quadros 	struct net_device *ndev = emac->ndev;
1143128d5874SRoger Quadros 	/* connect PHY */
1144128d5874SRoger Quadros 	ndev->phydev = of_phy_connect(emac->ndev, emac->phy_node,
1145128d5874SRoger Quadros 				      &emac_adjust_link, 0,
1146128d5874SRoger Quadros 				      emac->phy_if);
1147128d5874SRoger Quadros 	if (!ndev->phydev) {
1148128d5874SRoger Quadros 		dev_err(prueth->dev, "couldn't connect to phy %s\n",
1149128d5874SRoger Quadros 			emac->phy_node->full_name);
1150128d5874SRoger Quadros 		return -ENODEV;
1151128d5874SRoger Quadros 	}
1152128d5874SRoger Quadros 
1153128d5874SRoger Quadros 	/* remove unsupported modes */
1154128d5874SRoger Quadros 	phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
1155128d5874SRoger Quadros 	phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
1156128d5874SRoger Quadros 	phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
1157128d5874SRoger Quadros 	phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
1158128d5874SRoger Quadros 	phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
1159128d5874SRoger Quadros 
1160128d5874SRoger Quadros 	if (emac->phy_if == PHY_INTERFACE_MODE_MII)
1161128d5874SRoger Quadros 		phy_set_max_speed(ndev->phydev, SPEED_100);
1162128d5874SRoger Quadros 
1163128d5874SRoger Quadros 	return 0;
1164128d5874SRoger Quadros }
1165128d5874SRoger Quadros 
prueth_iep_gettime(void * clockops_data,struct ptp_system_timestamp * sts)1166186734c1SRoger Quadros static u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts)
1167186734c1SRoger Quadros {
1168186734c1SRoger Quadros 	u32 hi_rollover_count, hi_rollover_count_r;
1169186734c1SRoger Quadros 	struct prueth_emac *emac = clockops_data;
1170186734c1SRoger Quadros 	struct prueth *prueth = emac->prueth;
1171186734c1SRoger Quadros 	void __iomem *fw_hi_r_count_addr;
1172186734c1SRoger Quadros 	void __iomem *fw_count_hi_addr;
1173186734c1SRoger Quadros 	u32 iepcount_hi, iepcount_hi_r;
1174186734c1SRoger Quadros 	unsigned long flags;
1175186734c1SRoger Quadros 	u32 iepcount_lo;
1176186734c1SRoger Quadros 	u64 ts = 0;
1177186734c1SRoger Quadros 
1178186734c1SRoger Quadros 	fw_count_hi_addr = prueth->shram.va + TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET;
1179186734c1SRoger Quadros 	fw_hi_r_count_addr = prueth->shram.va + TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET;
1180186734c1SRoger Quadros 
1181186734c1SRoger Quadros 	local_irq_save(flags);
1182186734c1SRoger Quadros 	do {
1183186734c1SRoger Quadros 		iepcount_hi = icss_iep_get_count_hi(emac->iep);
1184186734c1SRoger Quadros 		iepcount_hi += readl(fw_count_hi_addr);
1185186734c1SRoger Quadros 		hi_rollover_count = readl(fw_hi_r_count_addr);
1186186734c1SRoger Quadros 		ptp_read_system_prets(sts);
1187186734c1SRoger Quadros 		iepcount_lo = icss_iep_get_count_low(emac->iep);
1188186734c1SRoger Quadros 		ptp_read_system_postts(sts);
1189186734c1SRoger Quadros 
1190186734c1SRoger Quadros 		iepcount_hi_r = icss_iep_get_count_hi(emac->iep);
1191186734c1SRoger Quadros 		iepcount_hi_r += readl(fw_count_hi_addr);
1192186734c1SRoger Quadros 		hi_rollover_count_r = readl(fw_hi_r_count_addr);
1193186734c1SRoger Quadros 	} while ((iepcount_hi_r != iepcount_hi) ||
1194186734c1SRoger Quadros 		 (hi_rollover_count != hi_rollover_count_r));
1195186734c1SRoger Quadros 	local_irq_restore(flags);
1196186734c1SRoger Quadros 
1197186734c1SRoger Quadros 	ts = ((u64)hi_rollover_count) << 23 | iepcount_hi;
1198186734c1SRoger Quadros 	ts = ts * (u64)IEP_DEFAULT_CYCLE_TIME_NS + iepcount_lo;
1199186734c1SRoger Quadros 
1200186734c1SRoger Quadros 	return ts;
1201186734c1SRoger Quadros }
1202186734c1SRoger Quadros 
prueth_iep_settime(void * clockops_data,u64 ns)1203186734c1SRoger Quadros static void prueth_iep_settime(void *clockops_data, u64 ns)
1204186734c1SRoger Quadros {
1205186734c1SRoger Quadros 	struct icssg_setclock_desc __iomem *sc_descp;
1206186734c1SRoger Quadros 	struct prueth_emac *emac = clockops_data;
1207186734c1SRoger Quadros 	struct icssg_setclock_desc sc_desc;
1208186734c1SRoger Quadros 	u64 cyclecount;
1209186734c1SRoger Quadros 	u32 cycletime;
1210186734c1SRoger Quadros 	int timeout;
1211186734c1SRoger Quadros 
1212186734c1SRoger Quadros 	if (!emac->fw_running)
1213186734c1SRoger Quadros 		return;
1214186734c1SRoger Quadros 
1215186734c1SRoger Quadros 	sc_descp = emac->prueth->shram.va + TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET;
1216186734c1SRoger Quadros 
1217186734c1SRoger Quadros 	cycletime = IEP_DEFAULT_CYCLE_TIME_NS;
1218186734c1SRoger Quadros 	cyclecount = ns / cycletime;
1219186734c1SRoger Quadros 
1220186734c1SRoger Quadros 	memset(&sc_desc, 0, sizeof(sc_desc));
1221186734c1SRoger Quadros 	sc_desc.margin = cycletime - 1000;
1222186734c1SRoger Quadros 	sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0);
1223186734c1SRoger Quadros 	sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32;
1224186734c1SRoger Quadros 	sc_desc.iepcount_set = ns % cycletime;
1225186734c1SRoger Quadros 	sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4
1226186734c1SRoger Quadros 
1227186734c1SRoger Quadros 	memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc));
1228186734c1SRoger Quadros 
1229186734c1SRoger Quadros 	writeb(1, &sc_descp->request);
1230186734c1SRoger Quadros 
1231186734c1SRoger Quadros 	timeout = 5;	/* fw should take 2-3 ms */
1232186734c1SRoger Quadros 	while (timeout--) {
1233186734c1SRoger Quadros 		if (readb(&sc_descp->acknowledgment))
1234186734c1SRoger Quadros 			return;
1235186734c1SRoger Quadros 
1236186734c1SRoger Quadros 		usleep_range(500, 1000);
1237186734c1SRoger Quadros 	}
1238186734c1SRoger Quadros 
1239186734c1SRoger Quadros 	dev_err(emac->prueth->dev, "settime timeout\n");
1240186734c1SRoger Quadros }
1241186734c1SRoger Quadros 
prueth_perout_enable(void * clockops_data,struct ptp_perout_request * req,int on,u64 * cmp)1242186734c1SRoger Quadros static int prueth_perout_enable(void *clockops_data,
1243186734c1SRoger Quadros 				struct ptp_perout_request *req, int on,
1244186734c1SRoger Quadros 				u64 *cmp)
1245186734c1SRoger Quadros {
1246186734c1SRoger Quadros 	struct prueth_emac *emac = clockops_data;
1247186734c1SRoger Quadros 	u32 reduction_factor = 0, offset = 0;
1248186734c1SRoger Quadros 	struct timespec64 ts;
1249*c67ce71dSMeghana Malladi 	u64 current_cycle;
1250*c67ce71dSMeghana Malladi 	u64 start_offset;
1251186734c1SRoger Quadros 	u64 ns_period;
1252186734c1SRoger Quadros 
1253186734c1SRoger Quadros 	if (!on)
1254186734c1SRoger Quadros 		return 0;
1255186734c1SRoger Quadros 
1256186734c1SRoger Quadros 	/* Any firmware specific stuff for PPS/PEROUT handling */
1257186734c1SRoger Quadros 	ts.tv_sec = req->period.sec;
1258186734c1SRoger Quadros 	ts.tv_nsec = req->period.nsec;
1259186734c1SRoger Quadros 	ns_period = timespec64_to_ns(&ts);
1260186734c1SRoger Quadros 
1261186734c1SRoger Quadros 	/* f/w doesn't support period less than cycle time */
1262186734c1SRoger Quadros 	if (ns_period < IEP_DEFAULT_CYCLE_TIME_NS)
1263186734c1SRoger Quadros 		return -ENXIO;
1264186734c1SRoger Quadros 
1265186734c1SRoger Quadros 	reduction_factor = ns_period / IEP_DEFAULT_CYCLE_TIME_NS;
1266186734c1SRoger Quadros 	offset = ns_period % IEP_DEFAULT_CYCLE_TIME_NS;
1267186734c1SRoger Quadros 
1268186734c1SRoger Quadros 	/* f/w requires at least 1uS within a cycle so CMP
1269186734c1SRoger Quadros 	 * can trigger after SYNC is enabled
1270186734c1SRoger Quadros 	 */
1271186734c1SRoger Quadros 	if (offset < 5 * NSEC_PER_USEC)
1272186734c1SRoger Quadros 		offset = 5 * NSEC_PER_USEC;
1273186734c1SRoger Quadros 
1274186734c1SRoger Quadros 	/* if offset is close to cycle time then we will miss
1275186734c1SRoger Quadros 	 * the CMP event for last tick when IEP rolls over.
1276186734c1SRoger Quadros 	 * In normal mode, IEP tick is 4ns.
1277186734c1SRoger Quadros 	 * In slow compensation it could be 0ns or 8ns at
1278186734c1SRoger Quadros 	 * every slow compensation cycle.
1279186734c1SRoger Quadros 	 */
1280186734c1SRoger Quadros 	if (offset > IEP_DEFAULT_CYCLE_TIME_NS - 8)
1281186734c1SRoger Quadros 		offset = IEP_DEFAULT_CYCLE_TIME_NS - 8;
1282186734c1SRoger Quadros 
1283186734c1SRoger Quadros 	/* we're in shadow mode so need to set upper 32-bits */
1284186734c1SRoger Quadros 	*cmp = (u64)offset << 32;
1285186734c1SRoger Quadros 
1286186734c1SRoger Quadros 	writel(reduction_factor, emac->prueth->shram.va +
1287186734c1SRoger Quadros 		TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET);
1288186734c1SRoger Quadros 
1289*c67ce71dSMeghana Malladi 	current_cycle = icssg_read_time(emac->prueth->shram.va +
1290*c67ce71dSMeghana Malladi 					TIMESYNC_FW_WC_CYCLECOUNT_OFFSET);
1291*c67ce71dSMeghana Malladi 
1292*c67ce71dSMeghana Malladi 	/* Rounding of current_cycle count to next second */
1293*c67ce71dSMeghana Malladi 	start_offset = roundup(current_cycle, MSEC_PER_SEC);
1294*c67ce71dSMeghana Malladi 
1295*c67ce71dSMeghana Malladi 	hi_lo_writeq(start_offset, emac->prueth->shram.va +
1296186734c1SRoger Quadros 		     TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET);
1297186734c1SRoger Quadros 
1298186734c1SRoger Quadros 	return 0;
1299186734c1SRoger Quadros }
1300186734c1SRoger Quadros 
1301186734c1SRoger Quadros const struct icss_iep_clockops prueth_iep_clockops = {
1302186734c1SRoger Quadros 	.settime = prueth_iep_settime,
1303186734c1SRoger Quadros 	.gettime = prueth_iep_gettime,
1304186734c1SRoger Quadros 	.perout_enable = prueth_perout_enable,
1305186734c1SRoger Quadros };
1306186734c1SRoger Quadros 
1307128d5874SRoger Quadros /**
1308128d5874SRoger Quadros  * emac_ndo_open - EMAC device open
1309128d5874SRoger Quadros  * @ndev: network adapter device
1310128d5874SRoger Quadros  *
1311128d5874SRoger Quadros  * Called when system wants to start the interface.
1312128d5874SRoger Quadros  *
1313128d5874SRoger Quadros  * Return: 0 for a successful open, or appropriate error code
1314128d5874SRoger Quadros  */
emac_ndo_open(struct net_device * ndev)1315128d5874SRoger Quadros static int emac_ndo_open(struct net_device *ndev)
1316128d5874SRoger Quadros {
1317128d5874SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
1318128d5874SRoger Quadros 	int ret, i, num_data_chn = emac->tx_ch_num;
1319128d5874SRoger Quadros 	struct prueth *prueth = emac->prueth;
1320128d5874SRoger Quadros 	int slice = prueth_emac_slice(emac);
1321128d5874SRoger Quadros 	struct device *dev = prueth->dev;
1322128d5874SRoger Quadros 	int max_rx_flows;
1323128d5874SRoger Quadros 	int rx_flow;
1324128d5874SRoger Quadros 
1325128d5874SRoger Quadros 	/* clear SMEM and MSMC settings for all slices */
1326128d5874SRoger Quadros 	if (!prueth->emacs_initialized) {
1327128d5874SRoger Quadros 		memset_io(prueth->msmcram.va, 0, prueth->msmcram.size);
1328128d5874SRoger Quadros 		memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS);
1329128d5874SRoger Quadros 	}
1330128d5874SRoger Quadros 
1331128d5874SRoger Quadros 	/* set h/w MAC as user might have re-configured */
1332128d5874SRoger Quadros 	ether_addr_copy(emac->mac_addr, ndev->dev_addr);
1333128d5874SRoger Quadros 
1334128d5874SRoger Quadros 	icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
1335128d5874SRoger Quadros 	icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
1336128d5874SRoger Quadros 
1337128d5874SRoger Quadros 	icssg_class_default(prueth->miig_rt, slice, 0);
1338128d5874SRoger Quadros 
1339128d5874SRoger Quadros 	/* Notify the stack of the actual queue counts. */
1340128d5874SRoger Quadros 	ret = netif_set_real_num_tx_queues(ndev, num_data_chn);
1341128d5874SRoger Quadros 	if (ret) {
1342128d5874SRoger Quadros 		dev_err(dev, "cannot set real number of tx queues\n");
1343128d5874SRoger Quadros 		return ret;
1344128d5874SRoger Quadros 	}
1345128d5874SRoger Quadros 
1346128d5874SRoger Quadros 	init_completion(&emac->cmd_complete);
1347128d5874SRoger Quadros 	ret = prueth_init_tx_chns(emac);
1348128d5874SRoger Quadros 	if (ret) {
1349128d5874SRoger Quadros 		dev_err(dev, "failed to init tx channel: %d\n", ret);
1350128d5874SRoger Quadros 		return ret;
1351128d5874SRoger Quadros 	}
1352128d5874SRoger Quadros 
1353128d5874SRoger Quadros 	max_rx_flows = PRUETH_MAX_RX_FLOWS;
1354128d5874SRoger Quadros 	ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx",
1355128d5874SRoger Quadros 				  max_rx_flows, PRUETH_MAX_RX_DESC);
1356128d5874SRoger Quadros 	if (ret) {
1357128d5874SRoger Quadros 		dev_err(dev, "failed to init rx channel: %d\n", ret);
1358128d5874SRoger Quadros 		goto cleanup_tx;
1359128d5874SRoger Quadros 	}
1360128d5874SRoger Quadros 
1361128d5874SRoger Quadros 	ret = prueth_ndev_add_tx_napi(emac);
1362128d5874SRoger Quadros 	if (ret)
1363128d5874SRoger Quadros 		goto cleanup_rx;
1364128d5874SRoger Quadros 
1365128d5874SRoger Quadros 	/* we use only the highest priority flow for now i.e. @irq[3] */
1366128d5874SRoger Quadros 	rx_flow = PRUETH_RX_FLOW_DATA;
1367128d5874SRoger Quadros 	ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq,
1368128d5874SRoger Quadros 			  IRQF_TRIGGER_HIGH, dev_name(dev), emac);
1369128d5874SRoger Quadros 	if (ret) {
1370128d5874SRoger Quadros 		dev_err(dev, "unable to request RX IRQ\n");
1371128d5874SRoger Quadros 		goto cleanup_napi;
1372128d5874SRoger Quadros 	}
1373128d5874SRoger Quadros 
1374128d5874SRoger Quadros 	/* reset and start PRU firmware */
1375128d5874SRoger Quadros 	ret = prueth_emac_start(prueth, emac);
1376128d5874SRoger Quadros 	if (ret)
1377128d5874SRoger Quadros 		goto free_rx_irq;
1378128d5874SRoger Quadros 
1379128d5874SRoger Quadros 	icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu);
1380128d5874SRoger Quadros 
1381186734c1SRoger Quadros 	if (!prueth->emacs_initialized) {
1382186734c1SRoger Quadros 		ret = icss_iep_init(emac->iep, &prueth_iep_clockops,
1383186734c1SRoger Quadros 				    emac, IEP_DEFAULT_CYCLE_TIME_NS);
1384186734c1SRoger Quadros 	}
1385186734c1SRoger Quadros 
1386186734c1SRoger Quadros 	ret = request_threaded_irq(emac->tx_ts_irq, NULL, prueth_tx_ts_irq,
1387186734c1SRoger Quadros 				   IRQF_ONESHOT, dev_name(dev), emac);
1388186734c1SRoger Quadros 	if (ret)
1389186734c1SRoger Quadros 		goto stop;
1390186734c1SRoger Quadros 
1391128d5874SRoger Quadros 	/* Prepare RX */
1392128d5874SRoger Quadros 	ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE);
1393128d5874SRoger Quadros 	if (ret)
1394186734c1SRoger Quadros 		goto free_tx_ts_irq;
1395128d5874SRoger Quadros 
1396128d5874SRoger Quadros 	ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn);
1397128d5874SRoger Quadros 	if (ret)
1398128d5874SRoger Quadros 		goto reset_rx_chn;
1399128d5874SRoger Quadros 
1400128d5874SRoger Quadros 	for (i = 0; i < emac->tx_ch_num; i++) {
1401128d5874SRoger Quadros 		ret = k3_udma_glue_enable_tx_chn(emac->tx_chns[i].tx_chn);
1402128d5874SRoger Quadros 		if (ret)
1403128d5874SRoger Quadros 			goto reset_tx_chan;
1404128d5874SRoger Quadros 	}
1405128d5874SRoger Quadros 
1406128d5874SRoger Quadros 	/* Enable NAPI in Tx and Rx direction */
1407128d5874SRoger Quadros 	for (i = 0; i < emac->tx_ch_num; i++)
1408128d5874SRoger Quadros 		napi_enable(&emac->tx_chns[i].napi_tx);
1409128d5874SRoger Quadros 	napi_enable(&emac->napi_rx);
1410128d5874SRoger Quadros 
1411128d5874SRoger Quadros 	/* start PHY */
1412128d5874SRoger Quadros 	phy_start(ndev->phydev);
1413128d5874SRoger Quadros 
1414128d5874SRoger Quadros 	prueth->emacs_initialized++;
1415128d5874SRoger Quadros 
1416c1e10d5dSMD Danish Anwar 	queue_work(system_long_wq, &emac->stats_work.work);
1417c1e10d5dSMD Danish Anwar 
1418128d5874SRoger Quadros 	return 0;
1419128d5874SRoger Quadros 
1420128d5874SRoger Quadros reset_tx_chan:
1421128d5874SRoger Quadros 	/* Since interface is not yet up, there is wouldn't be
1422128d5874SRoger Quadros 	 * any SKB for completion. So set false to free_skb
1423128d5874SRoger Quadros 	 */
1424128d5874SRoger Quadros 	prueth_reset_tx_chan(emac, i, false);
1425128d5874SRoger Quadros reset_rx_chn:
1426128d5874SRoger Quadros 	prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false);
1427186734c1SRoger Quadros free_tx_ts_irq:
1428186734c1SRoger Quadros 	free_irq(emac->tx_ts_irq, emac);
1429128d5874SRoger Quadros stop:
1430128d5874SRoger Quadros 	prueth_emac_stop(emac);
1431128d5874SRoger Quadros free_rx_irq:
1432128d5874SRoger Quadros 	free_irq(emac->rx_chns.irq[rx_flow], emac);
1433128d5874SRoger Quadros cleanup_napi:
1434128d5874SRoger Quadros 	prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);
1435128d5874SRoger Quadros cleanup_rx:
1436128d5874SRoger Quadros 	prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);
1437128d5874SRoger Quadros cleanup_tx:
1438128d5874SRoger Quadros 	prueth_cleanup_tx_chns(emac);
1439128d5874SRoger Quadros 
1440128d5874SRoger Quadros 	return ret;
1441128d5874SRoger Quadros }
1442128d5874SRoger Quadros 
1443128d5874SRoger Quadros /**
1444128d5874SRoger Quadros  * emac_ndo_stop - EMAC device stop
1445128d5874SRoger Quadros  * @ndev: network adapter device
1446128d5874SRoger Quadros  *
1447128d5874SRoger Quadros  * Called when system wants to stop or down the interface.
1448128d5874SRoger Quadros  *
1449128d5874SRoger Quadros  * Return: Always 0 (Success)
1450128d5874SRoger Quadros  */
emac_ndo_stop(struct net_device * ndev)1451128d5874SRoger Quadros static int emac_ndo_stop(struct net_device *ndev)
1452128d5874SRoger Quadros {
1453128d5874SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
1454128d5874SRoger Quadros 	struct prueth *prueth = emac->prueth;
1455128d5874SRoger Quadros 	int rx_flow = PRUETH_RX_FLOW_DATA;
1456128d5874SRoger Quadros 	int max_rx_flows;
1457128d5874SRoger Quadros 	int ret, i;
1458128d5874SRoger Quadros 
1459128d5874SRoger Quadros 	/* inform the upper layers. */
1460128d5874SRoger Quadros 	netif_tx_stop_all_queues(ndev);
1461128d5874SRoger Quadros 
1462128d5874SRoger Quadros 	/* block packets from wire */
1463128d5874SRoger Quadros 	if (ndev->phydev)
1464128d5874SRoger Quadros 		phy_stop(ndev->phydev);
1465128d5874SRoger Quadros 
1466128d5874SRoger Quadros 	icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac));
1467128d5874SRoger Quadros 
1468128d5874SRoger Quadros 	atomic_set(&emac->tdown_cnt, emac->tx_ch_num);
1469128d5874SRoger Quadros 	/* ensure new tdown_cnt value is visible */
1470128d5874SRoger Quadros 	smp_mb__after_atomic();
1471128d5874SRoger Quadros 	/* tear down and disable UDMA channels */
1472128d5874SRoger Quadros 	reinit_completion(&emac->tdown_complete);
1473128d5874SRoger Quadros 	for (i = 0; i < emac->tx_ch_num; i++)
1474128d5874SRoger Quadros 		k3_udma_glue_tdown_tx_chn(emac->tx_chns[i].tx_chn, false);
1475128d5874SRoger Quadros 
1476128d5874SRoger Quadros 	ret = wait_for_completion_timeout(&emac->tdown_complete,
1477128d5874SRoger Quadros 					  msecs_to_jiffies(1000));
1478128d5874SRoger Quadros 	if (!ret)
1479128d5874SRoger Quadros 		netdev_err(ndev, "tx teardown timeout\n");
1480128d5874SRoger Quadros 
1481128d5874SRoger Quadros 	prueth_reset_tx_chan(emac, emac->tx_ch_num, true);
1482128d5874SRoger Quadros 	for (i = 0; i < emac->tx_ch_num; i++)
1483128d5874SRoger Quadros 		napi_disable(&emac->tx_chns[i].napi_tx);
1484128d5874SRoger Quadros 
1485128d5874SRoger Quadros 	max_rx_flows = PRUETH_MAX_RX_FLOWS;
1486128d5874SRoger Quadros 	k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true);
1487128d5874SRoger Quadros 
1488128d5874SRoger Quadros 	prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true);
1489128d5874SRoger Quadros 
1490128d5874SRoger Quadros 	napi_disable(&emac->napi_rx);
1491128d5874SRoger Quadros 
1492128d5874SRoger Quadros 	cancel_work_sync(&emac->rx_mode_work);
1493128d5874SRoger Quadros 
1494c1e10d5dSMD Danish Anwar 	/* Destroying the queued work in ndo_stop() */
1495c1e10d5dSMD Danish Anwar 	cancel_delayed_work_sync(&emac->stats_work);
1496c1e10d5dSMD Danish Anwar 
1497128d5874SRoger Quadros 	/* stop PRUs */
1498128d5874SRoger Quadros 	prueth_emac_stop(emac);
1499128d5874SRoger Quadros 
1500186734c1SRoger Quadros 	if (prueth->emacs_initialized == 1)
1501186734c1SRoger Quadros 		icss_iep_exit(emac->iep);
1502186734c1SRoger Quadros 
1503186734c1SRoger Quadros 	/* stop PRUs */
1504186734c1SRoger Quadros 	prueth_emac_stop(emac);
1505186734c1SRoger Quadros 
1506186734c1SRoger Quadros 	free_irq(emac->tx_ts_irq, emac);
1507186734c1SRoger Quadros 
1508128d5874SRoger Quadros 	free_irq(emac->rx_chns.irq[rx_flow], emac);
1509128d5874SRoger Quadros 	prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);
1510128d5874SRoger Quadros 	prueth_cleanup_tx_chns(emac);
1511128d5874SRoger Quadros 
1512128d5874SRoger Quadros 	prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);
1513128d5874SRoger Quadros 	prueth_cleanup_tx_chns(emac);
1514128d5874SRoger Quadros 
1515128d5874SRoger Quadros 	prueth->emacs_initialized--;
1516128d5874SRoger Quadros 
1517128d5874SRoger Quadros 	return 0;
1518128d5874SRoger Quadros }
1519128d5874SRoger Quadros 
emac_ndo_tx_timeout(struct net_device * ndev,unsigned int txqueue)1520128d5874SRoger Quadros static void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue)
1521128d5874SRoger Quadros {
1522128d5874SRoger Quadros 	ndev->stats.tx_errors++;
1523128d5874SRoger Quadros }
1524128d5874SRoger Quadros 
emac_ndo_set_rx_mode_work(struct work_struct * work)1525128d5874SRoger Quadros static void emac_ndo_set_rx_mode_work(struct work_struct *work)
1526128d5874SRoger Quadros {
1527128d5874SRoger Quadros 	struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work);
1528128d5874SRoger Quadros 	struct net_device *ndev = emac->ndev;
1529128d5874SRoger Quadros 	bool promisc, allmulti;
1530128d5874SRoger Quadros 
1531128d5874SRoger Quadros 	if (!netif_running(ndev))
1532128d5874SRoger Quadros 		return;
1533128d5874SRoger Quadros 
1534128d5874SRoger Quadros 	promisc = ndev->flags & IFF_PROMISC;
1535128d5874SRoger Quadros 	allmulti = ndev->flags & IFF_ALLMULTI;
1536128d5874SRoger Quadros 	emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_DISABLE);
1537128d5874SRoger Quadros 	emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_DISABLE);
1538128d5874SRoger Quadros 
1539128d5874SRoger Quadros 	if (promisc) {
1540128d5874SRoger Quadros 		emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_ENABLE);
1541128d5874SRoger Quadros 		emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
1542128d5874SRoger Quadros 		return;
1543128d5874SRoger Quadros 	}
1544128d5874SRoger Quadros 
1545128d5874SRoger Quadros 	if (allmulti) {
1546128d5874SRoger Quadros 		emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
1547128d5874SRoger Quadros 		return;
1548128d5874SRoger Quadros 	}
1549128d5874SRoger Quadros 
1550128d5874SRoger Quadros 	if (!netdev_mc_empty(ndev)) {
1551128d5874SRoger Quadros 		emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
1552128d5874SRoger Quadros 		return;
1553128d5874SRoger Quadros 	}
1554128d5874SRoger Quadros }
1555128d5874SRoger Quadros 
1556128d5874SRoger Quadros /**
1557128d5874SRoger Quadros  * emac_ndo_set_rx_mode - EMAC set receive mode function
1558128d5874SRoger Quadros  * @ndev: The EMAC network adapter
1559128d5874SRoger Quadros  *
1560128d5874SRoger Quadros  * Called when system wants to set the receive mode of the device.
1561128d5874SRoger Quadros  *
1562128d5874SRoger Quadros  */
emac_ndo_set_rx_mode(struct net_device * ndev)1563128d5874SRoger Quadros static void emac_ndo_set_rx_mode(struct net_device *ndev)
1564128d5874SRoger Quadros {
1565128d5874SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
1566128d5874SRoger Quadros 
1567128d5874SRoger Quadros 	queue_work(emac->cmd_wq, &emac->rx_mode_work);
1568128d5874SRoger Quadros }
1569128d5874SRoger Quadros 
emac_set_ts_config(struct net_device * ndev,struct ifreq * ifr)1570186734c1SRoger Quadros static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr)
1571186734c1SRoger Quadros {
1572186734c1SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
1573186734c1SRoger Quadros 	struct hwtstamp_config config;
1574186734c1SRoger Quadros 
1575186734c1SRoger Quadros 	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
1576186734c1SRoger Quadros 		return -EFAULT;
1577186734c1SRoger Quadros 
1578186734c1SRoger Quadros 	switch (config.tx_type) {
1579186734c1SRoger Quadros 	case HWTSTAMP_TX_OFF:
1580186734c1SRoger Quadros 		emac->tx_ts_enabled = 0;
1581186734c1SRoger Quadros 		break;
1582186734c1SRoger Quadros 	case HWTSTAMP_TX_ON:
1583186734c1SRoger Quadros 		emac->tx_ts_enabled = 1;
1584186734c1SRoger Quadros 		break;
1585186734c1SRoger Quadros 	default:
1586186734c1SRoger Quadros 		return -ERANGE;
1587186734c1SRoger Quadros 	}
1588186734c1SRoger Quadros 
1589186734c1SRoger Quadros 	switch (config.rx_filter) {
1590186734c1SRoger Quadros 	case HWTSTAMP_FILTER_NONE:
1591186734c1SRoger Quadros 		emac->rx_ts_enabled = 0;
1592186734c1SRoger Quadros 		break;
1593186734c1SRoger Quadros 	case HWTSTAMP_FILTER_ALL:
1594186734c1SRoger Quadros 	case HWTSTAMP_FILTER_SOME:
1595186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
1596186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
1597186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
1598186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
1599186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
1600186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
1601186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
1602186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
1603186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
1604186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
1605186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
1606186734c1SRoger Quadros 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
1607186734c1SRoger Quadros 	case HWTSTAMP_FILTER_NTP_ALL:
1608186734c1SRoger Quadros 		emac->rx_ts_enabled = 1;
1609186734c1SRoger Quadros 		config.rx_filter = HWTSTAMP_FILTER_ALL;
1610186734c1SRoger Quadros 		break;
1611186734c1SRoger Quadros 	default:
1612186734c1SRoger Quadros 		return -ERANGE;
1613186734c1SRoger Quadros 	}
1614186734c1SRoger Quadros 
1615186734c1SRoger Quadros 	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
1616186734c1SRoger Quadros 		-EFAULT : 0;
1617186734c1SRoger Quadros }
1618186734c1SRoger Quadros 
emac_get_ts_config(struct net_device * ndev,struct ifreq * ifr)1619186734c1SRoger Quadros static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr)
1620186734c1SRoger Quadros {
1621186734c1SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
1622186734c1SRoger Quadros 	struct hwtstamp_config config;
1623186734c1SRoger Quadros 
1624186734c1SRoger Quadros 	config.flags = 0;
1625186734c1SRoger Quadros 	config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
1626186734c1SRoger Quadros 	config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
1627186734c1SRoger Quadros 
1628186734c1SRoger Quadros 	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
1629186734c1SRoger Quadros 			    -EFAULT : 0;
1630186734c1SRoger Quadros }
1631186734c1SRoger Quadros 
emac_ndo_ioctl(struct net_device * ndev,struct ifreq * ifr,int cmd)1632128d5874SRoger Quadros static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
1633128d5874SRoger Quadros {
1634186734c1SRoger Quadros 	switch (cmd) {
1635186734c1SRoger Quadros 	case SIOCGHWTSTAMP:
1636186734c1SRoger Quadros 		return emac_get_ts_config(ndev, ifr);
1637186734c1SRoger Quadros 	case SIOCSHWTSTAMP:
1638186734c1SRoger Quadros 		return emac_set_ts_config(ndev, ifr);
1639186734c1SRoger Quadros 	default:
1640186734c1SRoger Quadros 		break;
1641186734c1SRoger Quadros 	}
1642186734c1SRoger Quadros 
1643128d5874SRoger Quadros 	return phy_do_ioctl(ndev, ifr, cmd);
1644128d5874SRoger Quadros }
1645128d5874SRoger Quadros 
emac_ndo_get_stats64(struct net_device * ndev,struct rtnl_link_stats64 * stats)1646c2f67d19SMD Danish Anwar static void emac_ndo_get_stats64(struct net_device *ndev,
1647c2f67d19SMD Danish Anwar 				 struct rtnl_link_stats64 *stats)
1648c2f67d19SMD Danish Anwar {
1649c2f67d19SMD Danish Anwar 	struct prueth_emac *emac = netdev_priv(ndev);
1650c2f67d19SMD Danish Anwar 
1651c2f67d19SMD Danish Anwar 	emac_update_hardware_stats(emac);
1652c2f67d19SMD Danish Anwar 
1653c2f67d19SMD Danish Anwar 	stats->rx_packets     = emac_get_stat_by_name(emac, "rx_packets");
1654c2f67d19SMD Danish Anwar 	stats->rx_bytes       = emac_get_stat_by_name(emac, "rx_bytes");
1655c2f67d19SMD Danish Anwar 	stats->tx_packets     = emac_get_stat_by_name(emac, "tx_packets");
1656c2f67d19SMD Danish Anwar 	stats->tx_bytes       = emac_get_stat_by_name(emac, "tx_bytes");
1657c2f67d19SMD Danish Anwar 	stats->rx_crc_errors  = emac_get_stat_by_name(emac, "rx_crc_errors");
1658c2f67d19SMD Danish Anwar 	stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors");
1659c2f67d19SMD Danish Anwar 	stats->multicast      = emac_get_stat_by_name(emac, "rx_multicast_frames");
1660c2f67d19SMD Danish Anwar 
1661c2f67d19SMD Danish Anwar 	stats->rx_errors  = ndev->stats.rx_errors;
1662c2f67d19SMD Danish Anwar 	stats->rx_dropped = ndev->stats.rx_dropped;
1663c2f67d19SMD Danish Anwar 	stats->tx_errors  = ndev->stats.tx_errors;
1664c2f67d19SMD Danish Anwar 	stats->tx_dropped = ndev->stats.tx_dropped;
1665c2f67d19SMD Danish Anwar }
1666c2f67d19SMD Danish Anwar 
1667128d5874SRoger Quadros static const struct net_device_ops emac_netdev_ops = {
1668128d5874SRoger Quadros 	.ndo_open = emac_ndo_open,
1669128d5874SRoger Quadros 	.ndo_stop = emac_ndo_stop,
1670128d5874SRoger Quadros 	.ndo_start_xmit = emac_ndo_start_xmit,
1671128d5874SRoger Quadros 	.ndo_set_mac_address = eth_mac_addr,
1672128d5874SRoger Quadros 	.ndo_validate_addr = eth_validate_addr,
1673128d5874SRoger Quadros 	.ndo_tx_timeout = emac_ndo_tx_timeout,
1674128d5874SRoger Quadros 	.ndo_set_rx_mode = emac_ndo_set_rx_mode,
1675128d5874SRoger Quadros 	.ndo_eth_ioctl = emac_ndo_ioctl,
1676c2f67d19SMD Danish Anwar 	.ndo_get_stats64 = emac_ndo_get_stats64,
1677128d5874SRoger Quadros };
1678128d5874SRoger Quadros 
1679128d5874SRoger Quadros /* get emac_port corresponding to eth_node name */
prueth_node_port(struct device_node * eth_node)1680128d5874SRoger Quadros static int prueth_node_port(struct device_node *eth_node)
1681128d5874SRoger Quadros {
1682128d5874SRoger Quadros 	u32 port_id;
1683128d5874SRoger Quadros 	int ret;
1684128d5874SRoger Quadros 
1685128d5874SRoger Quadros 	ret = of_property_read_u32(eth_node, "reg", &port_id);
1686128d5874SRoger Quadros 	if (ret)
1687128d5874SRoger Quadros 		return ret;
1688128d5874SRoger Quadros 
1689128d5874SRoger Quadros 	if (port_id == 0)
1690128d5874SRoger Quadros 		return PRUETH_PORT_MII0;
1691128d5874SRoger Quadros 	else if (port_id == 1)
1692128d5874SRoger Quadros 		return PRUETH_PORT_MII1;
1693128d5874SRoger Quadros 	else
1694128d5874SRoger Quadros 		return PRUETH_PORT_INVALID;
1695128d5874SRoger Quadros }
1696128d5874SRoger Quadros 
1697128d5874SRoger Quadros /* get MAC instance corresponding to eth_node name */
prueth_node_mac(struct device_node * eth_node)1698128d5874SRoger Quadros static int prueth_node_mac(struct device_node *eth_node)
1699128d5874SRoger Quadros {
1700128d5874SRoger Quadros 	u32 port_id;
1701128d5874SRoger Quadros 	int ret;
1702128d5874SRoger Quadros 
1703128d5874SRoger Quadros 	ret = of_property_read_u32(eth_node, "reg", &port_id);
1704128d5874SRoger Quadros 	if (ret)
1705128d5874SRoger Quadros 		return ret;
1706128d5874SRoger Quadros 
1707128d5874SRoger Quadros 	if (port_id == 0)
1708128d5874SRoger Quadros 		return PRUETH_MAC0;
1709128d5874SRoger Quadros 	else if (port_id == 1)
1710128d5874SRoger Quadros 		return PRUETH_MAC1;
1711128d5874SRoger Quadros 	else
1712128d5874SRoger Quadros 		return PRUETH_MAC_INVALID;
1713128d5874SRoger Quadros }
1714128d5874SRoger Quadros 
prueth_netdev_init(struct prueth * prueth,struct device_node * eth_node)1715128d5874SRoger Quadros static int prueth_netdev_init(struct prueth *prueth,
1716128d5874SRoger Quadros 			      struct device_node *eth_node)
1717128d5874SRoger Quadros {
1718128d5874SRoger Quadros 	int ret, num_tx_chn = PRUETH_MAX_TX_QUEUES;
1719128d5874SRoger Quadros 	struct prueth_emac *emac;
1720128d5874SRoger Quadros 	struct net_device *ndev;
1721128d5874SRoger Quadros 	enum prueth_port port;
1722186734c1SRoger Quadros 	const char *irq_name;
1723128d5874SRoger Quadros 	enum prueth_mac mac;
1724128d5874SRoger Quadros 
1725128d5874SRoger Quadros 	port = prueth_node_port(eth_node);
1726128d5874SRoger Quadros 	if (port == PRUETH_PORT_INVALID)
1727128d5874SRoger Quadros 		return -EINVAL;
1728128d5874SRoger Quadros 
1729128d5874SRoger Quadros 	mac = prueth_node_mac(eth_node);
1730128d5874SRoger Quadros 	if (mac == PRUETH_MAC_INVALID)
1731128d5874SRoger Quadros 		return -EINVAL;
1732128d5874SRoger Quadros 
1733128d5874SRoger Quadros 	ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn);
1734128d5874SRoger Quadros 	if (!ndev)
1735128d5874SRoger Quadros 		return -ENOMEM;
1736128d5874SRoger Quadros 
1737128d5874SRoger Quadros 	emac = netdev_priv(ndev);
1738128d5874SRoger Quadros 	emac->prueth = prueth;
1739128d5874SRoger Quadros 	emac->ndev = ndev;
1740128d5874SRoger Quadros 	emac->port_id = port;
1741128d5874SRoger Quadros 	emac->cmd_wq = create_singlethread_workqueue("icssg_cmd_wq");
1742128d5874SRoger Quadros 	if (!emac->cmd_wq) {
1743128d5874SRoger Quadros 		ret = -ENOMEM;
1744128d5874SRoger Quadros 		goto free_ndev;
1745128d5874SRoger Quadros 	}
1746128d5874SRoger Quadros 	INIT_WORK(&emac->rx_mode_work, emac_ndo_set_rx_mode_work);
1747128d5874SRoger Quadros 
1748c1e10d5dSMD Danish Anwar 	INIT_DELAYED_WORK(&emac->stats_work, emac_stats_work_handler);
1749c1e10d5dSMD Danish Anwar 
1750128d5874SRoger Quadros 	ret = pruss_request_mem_region(prueth->pruss,
1751128d5874SRoger Quadros 				       port == PRUETH_PORT_MII0 ?
1752128d5874SRoger Quadros 				       PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1,
1753128d5874SRoger Quadros 				       &emac->dram);
1754128d5874SRoger Quadros 	if (ret) {
1755128d5874SRoger Quadros 		dev_err(prueth->dev, "unable to get DRAM: %d\n", ret);
1756128d5874SRoger Quadros 		ret = -ENOMEM;
1757128d5874SRoger Quadros 		goto free_wq;
1758128d5874SRoger Quadros 	}
1759128d5874SRoger Quadros 
1760128d5874SRoger Quadros 	emac->tx_ch_num = 1;
1761128d5874SRoger Quadros 
1762186734c1SRoger Quadros 	irq_name = "tx_ts0";
1763186734c1SRoger Quadros 	if (emac->port_id == PRUETH_PORT_MII1)
1764186734c1SRoger Quadros 		irq_name = "tx_ts1";
1765186734c1SRoger Quadros 	emac->tx_ts_irq = platform_get_irq_byname_optional(prueth->pdev, irq_name);
1766186734c1SRoger Quadros 	if (emac->tx_ts_irq < 0) {
1767186734c1SRoger Quadros 		ret = dev_err_probe(prueth->dev, emac->tx_ts_irq, "could not get tx_ts_irq\n");
1768186734c1SRoger Quadros 		goto free;
1769186734c1SRoger Quadros 	}
1770186734c1SRoger Quadros 
1771128d5874SRoger Quadros 	SET_NETDEV_DEV(ndev, prueth->dev);
1772128d5874SRoger Quadros 	spin_lock_init(&emac->lock);
1773128d5874SRoger Quadros 	mutex_init(&emac->cmd_lock);
1774128d5874SRoger Quadros 
1775128d5874SRoger Quadros 	emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0);
1776128d5874SRoger Quadros 	if (!emac->phy_node && !of_phy_is_fixed_link(eth_node)) {
1777128d5874SRoger Quadros 		dev_err(prueth->dev, "couldn't find phy-handle\n");
1778128d5874SRoger Quadros 		ret = -ENODEV;
1779128d5874SRoger Quadros 		goto free;
1780128d5874SRoger Quadros 	} else if (of_phy_is_fixed_link(eth_node)) {
1781128d5874SRoger Quadros 		ret = of_phy_register_fixed_link(eth_node);
1782128d5874SRoger Quadros 		if (ret) {
1783128d5874SRoger Quadros 			ret = dev_err_probe(prueth->dev, ret,
1784128d5874SRoger Quadros 					    "failed to register fixed-link phy\n");
1785128d5874SRoger Quadros 			goto free;
1786128d5874SRoger Quadros 		}
1787128d5874SRoger Quadros 
1788128d5874SRoger Quadros 		emac->phy_node = eth_node;
1789128d5874SRoger Quadros 	}
1790128d5874SRoger Quadros 
1791128d5874SRoger Quadros 	ret = of_get_phy_mode(eth_node, &emac->phy_if);
1792128d5874SRoger Quadros 	if (ret) {
1793128d5874SRoger Quadros 		dev_err(prueth->dev, "could not get phy-mode property\n");
1794128d5874SRoger Quadros 		goto free;
1795128d5874SRoger Quadros 	}
1796128d5874SRoger Quadros 
1797128d5874SRoger Quadros 	if (emac->phy_if != PHY_INTERFACE_MODE_MII &&
1798128d5874SRoger Quadros 	    !phy_interface_mode_is_rgmii(emac->phy_if)) {
1799128d5874SRoger Quadros 		dev_err(prueth->dev, "PHY mode unsupported %s\n", phy_modes(emac->phy_if));
1800128d5874SRoger Quadros 		ret = -EINVAL;
1801128d5874SRoger Quadros 		goto free;
1802128d5874SRoger Quadros 	}
1803128d5874SRoger Quadros 
1804128d5874SRoger Quadros 	/* AM65 SR2.0 has TX Internal delay always enabled by hardware
1805128d5874SRoger Quadros 	 * and it is not possible to disable TX Internal delay. The below
1806128d5874SRoger Quadros 	 * switch case block describes how we handle different phy modes
1807128d5874SRoger Quadros 	 * based on hardware restriction.
1808128d5874SRoger Quadros 	 */
1809128d5874SRoger Quadros 	switch (emac->phy_if) {
1810128d5874SRoger Quadros 	case PHY_INTERFACE_MODE_RGMII_ID:
1811128d5874SRoger Quadros 		emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID;
1812128d5874SRoger Quadros 		break;
1813128d5874SRoger Quadros 	case PHY_INTERFACE_MODE_RGMII_TXID:
1814128d5874SRoger Quadros 		emac->phy_if = PHY_INTERFACE_MODE_RGMII;
1815128d5874SRoger Quadros 		break;
1816128d5874SRoger Quadros 	case PHY_INTERFACE_MODE_RGMII:
1817128d5874SRoger Quadros 	case PHY_INTERFACE_MODE_RGMII_RXID:
1818128d5874SRoger Quadros 		dev_err(prueth->dev, "RGMII mode without TX delay is not supported");
1819128d5874SRoger Quadros 		ret = -EINVAL;
1820128d5874SRoger Quadros 		goto free;
1821128d5874SRoger Quadros 	default:
1822128d5874SRoger Quadros 		break;
1823128d5874SRoger Quadros 	}
1824128d5874SRoger Quadros 
1825128d5874SRoger Quadros 	/* get mac address from DT and set private and netdev addr */
1826128d5874SRoger Quadros 	ret = of_get_ethdev_address(eth_node, ndev);
1827128d5874SRoger Quadros 	if (!is_valid_ether_addr(ndev->dev_addr)) {
1828128d5874SRoger Quadros 		eth_hw_addr_random(ndev);
1829128d5874SRoger Quadros 		dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n",
1830128d5874SRoger Quadros 			 port, ndev->dev_addr);
1831128d5874SRoger Quadros 	}
1832128d5874SRoger Quadros 	ether_addr_copy(emac->mac_addr, ndev->dev_addr);
1833128d5874SRoger Quadros 
1834128d5874SRoger Quadros 	ndev->min_mtu = PRUETH_MIN_PKT_SIZE;
1835128d5874SRoger Quadros 	ndev->max_mtu = PRUETH_MAX_MTU;
1836128d5874SRoger Quadros 	ndev->netdev_ops = &emac_netdev_ops;
18378fb86b0dSMD Danish Anwar 	ndev->ethtool_ops = &icssg_ethtool_ops;
1838128d5874SRoger Quadros 	ndev->hw_features = NETIF_F_SG;
1839128d5874SRoger Quadros 	ndev->features = ndev->hw_features;
1840128d5874SRoger Quadros 
1841128d5874SRoger Quadros 	netif_napi_add(ndev, &emac->napi_rx, emac_napi_rx_poll);
1842128d5874SRoger Quadros 	prueth->emac[mac] = emac;
1843128d5874SRoger Quadros 
1844128d5874SRoger Quadros 	return 0;
1845128d5874SRoger Quadros 
1846128d5874SRoger Quadros free:
1847128d5874SRoger Quadros 	pruss_release_mem_region(prueth->pruss, &emac->dram);
1848128d5874SRoger Quadros free_wq:
1849128d5874SRoger Quadros 	destroy_workqueue(emac->cmd_wq);
1850128d5874SRoger Quadros free_ndev:
1851128d5874SRoger Quadros 	emac->ndev = NULL;
1852128d5874SRoger Quadros 	prueth->emac[mac] = NULL;
1853128d5874SRoger Quadros 	free_netdev(ndev);
1854128d5874SRoger Quadros 
1855128d5874SRoger Quadros 	return ret;
1856128d5874SRoger Quadros }
1857128d5874SRoger Quadros 
prueth_netdev_exit(struct prueth * prueth,struct device_node * eth_node)1858128d5874SRoger Quadros static void prueth_netdev_exit(struct prueth *prueth,
1859128d5874SRoger Quadros 			       struct device_node *eth_node)
1860128d5874SRoger Quadros {
1861128d5874SRoger Quadros 	struct prueth_emac *emac;
1862128d5874SRoger Quadros 	enum prueth_mac mac;
1863128d5874SRoger Quadros 
1864128d5874SRoger Quadros 	mac = prueth_node_mac(eth_node);
1865128d5874SRoger Quadros 	if (mac == PRUETH_MAC_INVALID)
1866128d5874SRoger Quadros 		return;
1867128d5874SRoger Quadros 
1868128d5874SRoger Quadros 	emac = prueth->emac[mac];
1869128d5874SRoger Quadros 	if (!emac)
1870128d5874SRoger Quadros 		return;
1871128d5874SRoger Quadros 
1872128d5874SRoger Quadros 	if (of_phy_is_fixed_link(emac->phy_node))
1873128d5874SRoger Quadros 		of_phy_deregister_fixed_link(emac->phy_node);
1874128d5874SRoger Quadros 
1875128d5874SRoger Quadros 	netif_napi_del(&emac->napi_rx);
1876128d5874SRoger Quadros 
1877128d5874SRoger Quadros 	pruss_release_mem_region(prueth->pruss, &emac->dram);
1878128d5874SRoger Quadros 	destroy_workqueue(emac->cmd_wq);
1879128d5874SRoger Quadros 	free_netdev(emac->ndev);
1880128d5874SRoger Quadros 	prueth->emac[mac] = NULL;
1881128d5874SRoger Quadros }
1882128d5874SRoger Quadros 
prueth_get_cores(struct prueth * prueth,int slice)1883128d5874SRoger Quadros static int prueth_get_cores(struct prueth *prueth, int slice)
1884128d5874SRoger Quadros {
1885128d5874SRoger Quadros 	struct device *dev = prueth->dev;
1886128d5874SRoger Quadros 	enum pruss_pru_id pruss_id;
1887128d5874SRoger Quadros 	struct device_node *np;
1888128d5874SRoger Quadros 	int idx = -1, ret;
1889128d5874SRoger Quadros 
1890128d5874SRoger Quadros 	np = dev->of_node;
1891128d5874SRoger Quadros 
1892128d5874SRoger Quadros 	switch (slice) {
1893128d5874SRoger Quadros 	case ICSS_SLICE0:
1894128d5874SRoger Quadros 		idx = 0;
1895128d5874SRoger Quadros 		break;
1896128d5874SRoger Quadros 	case ICSS_SLICE1:
1897128d5874SRoger Quadros 		idx = 3;
1898128d5874SRoger Quadros 		break;
1899128d5874SRoger Quadros 	default:
1900128d5874SRoger Quadros 		return -EINVAL;
1901128d5874SRoger Quadros 	}
1902128d5874SRoger Quadros 
1903128d5874SRoger Quadros 	prueth->pru[slice] = pru_rproc_get(np, idx, &pruss_id);
1904128d5874SRoger Quadros 	if (IS_ERR(prueth->pru[slice])) {
1905128d5874SRoger Quadros 		ret = PTR_ERR(prueth->pru[slice]);
1906128d5874SRoger Quadros 		prueth->pru[slice] = NULL;
1907128d5874SRoger Quadros 		return dev_err_probe(dev, ret, "unable to get PRU%d\n", slice);
1908128d5874SRoger Quadros 	}
1909128d5874SRoger Quadros 	prueth->pru_id[slice] = pruss_id;
1910128d5874SRoger Quadros 
1911128d5874SRoger Quadros 	idx++;
1912128d5874SRoger Quadros 	prueth->rtu[slice] = pru_rproc_get(np, idx, NULL);
1913128d5874SRoger Quadros 	if (IS_ERR(prueth->rtu[slice])) {
1914128d5874SRoger Quadros 		ret = PTR_ERR(prueth->rtu[slice]);
1915128d5874SRoger Quadros 		prueth->rtu[slice] = NULL;
1916128d5874SRoger Quadros 		return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice);
1917128d5874SRoger Quadros 	}
1918128d5874SRoger Quadros 
1919128d5874SRoger Quadros 	idx++;
1920128d5874SRoger Quadros 	prueth->txpru[slice] = pru_rproc_get(np, idx, NULL);
1921128d5874SRoger Quadros 	if (IS_ERR(prueth->txpru[slice])) {
1922128d5874SRoger Quadros 		ret = PTR_ERR(prueth->txpru[slice]);
1923128d5874SRoger Quadros 		prueth->txpru[slice] = NULL;
1924128d5874SRoger Quadros 		return dev_err_probe(dev, ret, "unable to get TX_PRU%d\n", slice);
1925128d5874SRoger Quadros 	}
1926128d5874SRoger Quadros 
1927128d5874SRoger Quadros 	return 0;
1928128d5874SRoger Quadros }
1929128d5874SRoger Quadros 
prueth_put_cores(struct prueth * prueth,int slice)1930128d5874SRoger Quadros static void prueth_put_cores(struct prueth *prueth, int slice)
1931128d5874SRoger Quadros {
1932128d5874SRoger Quadros 	if (prueth->txpru[slice])
1933128d5874SRoger Quadros 		pru_rproc_put(prueth->txpru[slice]);
1934128d5874SRoger Quadros 
1935128d5874SRoger Quadros 	if (prueth->rtu[slice])
1936128d5874SRoger Quadros 		pru_rproc_put(prueth->rtu[slice]);
1937128d5874SRoger Quadros 
1938128d5874SRoger Quadros 	if (prueth->pru[slice])
1939128d5874SRoger Quadros 		pru_rproc_put(prueth->pru[slice]);
1940128d5874SRoger Quadros }
1941128d5874SRoger Quadros 
1942128d5874SRoger Quadros static const struct of_device_id prueth_dt_match[];
1943128d5874SRoger Quadros 
prueth_probe(struct platform_device * pdev)1944128d5874SRoger Quadros static int prueth_probe(struct platform_device *pdev)
1945128d5874SRoger Quadros {
1946128d5874SRoger Quadros 	struct device_node *eth_node, *eth_ports_node;
1947128d5874SRoger Quadros 	struct device_node  *eth0_node = NULL;
1948128d5874SRoger Quadros 	struct device_node  *eth1_node = NULL;
1949128d5874SRoger Quadros 	struct genpool_data_align gp_data = {
1950128d5874SRoger Quadros 		.align = SZ_64K,
1951128d5874SRoger Quadros 	};
1952128d5874SRoger Quadros 	const struct of_device_id *match;
1953128d5874SRoger Quadros 	struct device *dev = &pdev->dev;
1954128d5874SRoger Quadros 	struct device_node *np;
1955128d5874SRoger Quadros 	struct prueth *prueth;
1956128d5874SRoger Quadros 	struct pruss *pruss;
1957128d5874SRoger Quadros 	u32 msmc_ram_size;
1958128d5874SRoger Quadros 	int i, ret;
1959128d5874SRoger Quadros 
1960128d5874SRoger Quadros 	np = dev->of_node;
1961128d5874SRoger Quadros 
1962128d5874SRoger Quadros 	match = of_match_device(prueth_dt_match, dev);
1963128d5874SRoger Quadros 	if (!match)
1964128d5874SRoger Quadros 		return -ENODEV;
1965128d5874SRoger Quadros 
1966128d5874SRoger Quadros 	prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL);
1967128d5874SRoger Quadros 	if (!prueth)
1968128d5874SRoger Quadros 		return -ENOMEM;
1969128d5874SRoger Quadros 
1970128d5874SRoger Quadros 	dev_set_drvdata(dev, prueth);
1971128d5874SRoger Quadros 	prueth->pdev = pdev;
1972128d5874SRoger Quadros 	prueth->pdata = *(const struct prueth_pdata *)match->data;
1973128d5874SRoger Quadros 
1974128d5874SRoger Quadros 	prueth->dev = dev;
1975128d5874SRoger Quadros 	eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
1976128d5874SRoger Quadros 	if (!eth_ports_node)
1977128d5874SRoger Quadros 		return -ENOENT;
1978128d5874SRoger Quadros 
1979128d5874SRoger Quadros 	for_each_child_of_node(eth_ports_node, eth_node) {
1980128d5874SRoger Quadros 		u32 reg;
1981128d5874SRoger Quadros 
1982128d5874SRoger Quadros 		if (strcmp(eth_node->name, "port"))
1983128d5874SRoger Quadros 			continue;
1984128d5874SRoger Quadros 		ret = of_property_read_u32(eth_node, "reg", &reg);
1985128d5874SRoger Quadros 		if (ret < 0) {
1986128d5874SRoger Quadros 			dev_err(dev, "%pOF error reading port_id %d\n",
1987128d5874SRoger Quadros 				eth_node, ret);
1988128d5874SRoger Quadros 		}
1989128d5874SRoger Quadros 
1990128d5874SRoger Quadros 		of_node_get(eth_node);
1991128d5874SRoger Quadros 
1992128d5874SRoger Quadros 		if (reg == 0) {
1993128d5874SRoger Quadros 			eth0_node = eth_node;
1994128d5874SRoger Quadros 			if (!of_device_is_available(eth0_node)) {
1995128d5874SRoger Quadros 				of_node_put(eth0_node);
1996128d5874SRoger Quadros 				eth0_node = NULL;
1997128d5874SRoger Quadros 			}
1998128d5874SRoger Quadros 		} else if (reg == 1) {
1999128d5874SRoger Quadros 			eth1_node = eth_node;
2000128d5874SRoger Quadros 			if (!of_device_is_available(eth1_node)) {
2001128d5874SRoger Quadros 				of_node_put(eth1_node);
2002128d5874SRoger Quadros 				eth1_node = NULL;
2003128d5874SRoger Quadros 			}
2004128d5874SRoger Quadros 		} else {
2005128d5874SRoger Quadros 			dev_err(dev, "port reg should be 0 or 1\n");
2006128d5874SRoger Quadros 		}
2007128d5874SRoger Quadros 	}
2008128d5874SRoger Quadros 
2009128d5874SRoger Quadros 	of_node_put(eth_ports_node);
2010128d5874SRoger Quadros 
2011128d5874SRoger Quadros 	/* At least one node must be present and available else we fail */
2012128d5874SRoger Quadros 	if (!eth0_node && !eth1_node) {
2013128d5874SRoger Quadros 		dev_err(dev, "neither port0 nor port1 node available\n");
2014128d5874SRoger Quadros 		return -ENODEV;
2015128d5874SRoger Quadros 	}
2016128d5874SRoger Quadros 
2017128d5874SRoger Quadros 	if (eth0_node == eth1_node) {
2018128d5874SRoger Quadros 		dev_err(dev, "port0 and port1 can't have same reg\n");
2019128d5874SRoger Quadros 		of_node_put(eth0_node);
2020128d5874SRoger Quadros 		return -ENODEV;
2021128d5874SRoger Quadros 	}
2022128d5874SRoger Quadros 
2023128d5874SRoger Quadros 	prueth->eth_node[PRUETH_MAC0] = eth0_node;
2024128d5874SRoger Quadros 	prueth->eth_node[PRUETH_MAC1] = eth1_node;
2025128d5874SRoger Quadros 
2026128d5874SRoger Quadros 	prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-g-rt");
2027128d5874SRoger Quadros 	if (IS_ERR(prueth->miig_rt)) {
2028128d5874SRoger Quadros 		dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n");
2029128d5874SRoger Quadros 		return -ENODEV;
2030128d5874SRoger Quadros 	}
2031128d5874SRoger Quadros 
2032128d5874SRoger Quadros 	prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt");
2033128d5874SRoger Quadros 	if (IS_ERR(prueth->mii_rt)) {
2034128d5874SRoger Quadros 		dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n");
2035128d5874SRoger Quadros 		return -ENODEV;
2036128d5874SRoger Quadros 	}
2037128d5874SRoger Quadros 
2038128d5874SRoger Quadros 	if (eth0_node) {
2039128d5874SRoger Quadros 		ret = prueth_get_cores(prueth, ICSS_SLICE0);
2040128d5874SRoger Quadros 		if (ret)
2041128d5874SRoger Quadros 			goto put_cores;
2042128d5874SRoger Quadros 	}
2043128d5874SRoger Quadros 
2044128d5874SRoger Quadros 	if (eth1_node) {
2045128d5874SRoger Quadros 		ret = prueth_get_cores(prueth, ICSS_SLICE1);
2046128d5874SRoger Quadros 		if (ret)
2047128d5874SRoger Quadros 			goto put_cores;
2048128d5874SRoger Quadros 	}
2049128d5874SRoger Quadros 
2050128d5874SRoger Quadros 	pruss = pruss_get(eth0_node ?
2051128d5874SRoger Quadros 			  prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]);
2052128d5874SRoger Quadros 	if (IS_ERR(pruss)) {
2053128d5874SRoger Quadros 		ret = PTR_ERR(pruss);
2054128d5874SRoger Quadros 		dev_err(dev, "unable to get pruss handle\n");
2055128d5874SRoger Quadros 		goto put_cores;
2056128d5874SRoger Quadros 	}
2057128d5874SRoger Quadros 
2058128d5874SRoger Quadros 	prueth->pruss = pruss;
2059128d5874SRoger Quadros 
2060128d5874SRoger Quadros 	ret = pruss_request_mem_region(pruss, PRUSS_MEM_SHRD_RAM2,
2061128d5874SRoger Quadros 				       &prueth->shram);
2062128d5874SRoger Quadros 	if (ret) {
2063128d5874SRoger Quadros 		dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n", ret);
2064920114bfSJan Kiszka 		goto put_pruss;
2065128d5874SRoger Quadros 	}
2066128d5874SRoger Quadros 
2067128d5874SRoger Quadros 	prueth->sram_pool = of_gen_pool_get(np, "sram", 0);
2068128d5874SRoger Quadros 	if (!prueth->sram_pool) {
2069128d5874SRoger Quadros 		dev_err(dev, "unable to get SRAM pool\n");
2070128d5874SRoger Quadros 		ret = -ENODEV;
2071128d5874SRoger Quadros 
2072128d5874SRoger Quadros 		goto put_mem;
2073128d5874SRoger Quadros 	}
2074128d5874SRoger Quadros 
2075128d5874SRoger Quadros 	msmc_ram_size = MSMC_RAM_SIZE;
2076128d5874SRoger Quadros 
2077128d5874SRoger Quadros 	/* NOTE: FW bug needs buffer base to be 64KB aligned */
2078128d5874SRoger Quadros 	prueth->msmcram.va =
2079128d5874SRoger Quadros 		(void __iomem *)gen_pool_alloc_algo(prueth->sram_pool,
2080128d5874SRoger Quadros 						    msmc_ram_size,
2081128d5874SRoger Quadros 						    gen_pool_first_fit_align,
2082128d5874SRoger Quadros 						    &gp_data);
2083128d5874SRoger Quadros 
2084128d5874SRoger Quadros 	if (!prueth->msmcram.va) {
2085128d5874SRoger Quadros 		ret = -ENOMEM;
2086128d5874SRoger Quadros 		dev_err(dev, "unable to allocate MSMC resource\n");
2087128d5874SRoger Quadros 		goto put_mem;
2088128d5874SRoger Quadros 	}
2089128d5874SRoger Quadros 	prueth->msmcram.pa = gen_pool_virt_to_phys(prueth->sram_pool,
2090128d5874SRoger Quadros 						   (unsigned long)prueth->msmcram.va);
2091128d5874SRoger Quadros 	prueth->msmcram.size = msmc_ram_size;
2092128d5874SRoger Quadros 	memset_io(prueth->msmcram.va, 0, msmc_ram_size);
2093128d5874SRoger Quadros 	dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa,
2094128d5874SRoger Quadros 		prueth->msmcram.va, prueth->msmcram.size);
2095128d5874SRoger Quadros 
2096186734c1SRoger Quadros 	prueth->iep0 = icss_iep_get_idx(np, 0);
2097186734c1SRoger Quadros 	if (IS_ERR(prueth->iep0)) {
2098186734c1SRoger Quadros 		ret = dev_err_probe(dev, PTR_ERR(prueth->iep0), "iep0 get failed\n");
2099186734c1SRoger Quadros 		prueth->iep0 = NULL;
2100186734c1SRoger Quadros 		goto free_pool;
2101186734c1SRoger Quadros 	}
2102186734c1SRoger Quadros 
2103443a2367SGrygorii Strashko 	prueth->iep1 = icss_iep_get_idx(np, 1);
2104443a2367SGrygorii Strashko 	if (IS_ERR(prueth->iep1)) {
2105443a2367SGrygorii Strashko 		ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n");
210670151949SJan Kiszka 		goto put_iep0;
2107443a2367SGrygorii Strashko 	}
2108443a2367SGrygorii Strashko 
2109443a2367SGrygorii Strashko 	if (prueth->pdata.quirk_10m_link_issue) {
2110443a2367SGrygorii Strashko 		/* Enable IEP1 for FW in 64bit mode as W/A for 10M FD link detect issue under TX
2111443a2367SGrygorii Strashko 		 * traffic.
2112443a2367SGrygorii Strashko 		 */
2113443a2367SGrygorii Strashko 		icss_iep_init_fw(prueth->iep1);
2114443a2367SGrygorii Strashko 	}
2115443a2367SGrygorii Strashko 
2116128d5874SRoger Quadros 	/* setup netdev interfaces */
2117128d5874SRoger Quadros 	if (eth0_node) {
2118128d5874SRoger Quadros 		ret = prueth_netdev_init(prueth, eth0_node);
2119128d5874SRoger Quadros 		if (ret) {
2120128d5874SRoger Quadros 			dev_err_probe(dev, ret, "netdev init %s failed\n",
2121128d5874SRoger Quadros 				      eth0_node->name);
2122443a2367SGrygorii Strashko 			goto exit_iep;
2123128d5874SRoger Quadros 		}
2124186734c1SRoger Quadros 		prueth->emac[PRUETH_MAC0]->iep = prueth->iep0;
2125128d5874SRoger Quadros 	}
2126128d5874SRoger Quadros 
2127128d5874SRoger Quadros 	if (eth1_node) {
2128128d5874SRoger Quadros 		ret = prueth_netdev_init(prueth, eth1_node);
2129128d5874SRoger Quadros 		if (ret) {
2130128d5874SRoger Quadros 			dev_err_probe(dev, ret, "netdev init %s failed\n",
2131128d5874SRoger Quadros 				      eth1_node->name);
2132128d5874SRoger Quadros 			goto netdev_exit;
2133128d5874SRoger Quadros 		}
2134186734c1SRoger Quadros 
2135186734c1SRoger Quadros 		prueth->emac[PRUETH_MAC1]->iep = prueth->iep0;
2136128d5874SRoger Quadros 	}
2137128d5874SRoger Quadros 
2138128d5874SRoger Quadros 	/* register the network devices */
2139128d5874SRoger Quadros 	if (eth0_node) {
2140128d5874SRoger Quadros 		ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev);
2141128d5874SRoger Quadros 		if (ret) {
2142128d5874SRoger Quadros 			dev_err(dev, "can't register netdev for port MII0");
2143128d5874SRoger Quadros 			goto netdev_exit;
2144128d5874SRoger Quadros 		}
2145128d5874SRoger Quadros 
2146128d5874SRoger Quadros 		prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev;
2147128d5874SRoger Quadros 
21485cd17f0eSRomain Gantois 		ret = emac_phy_connect(prueth->emac[PRUETH_MAC0]);
21495cd17f0eSRomain Gantois 		if (ret) {
21505cd17f0eSRomain Gantois 			dev_err(dev,
21515cd17f0eSRomain Gantois 				"can't connect to MII0 PHY, error -%d", ret);
21525cd17f0eSRomain Gantois 			goto netdev_unregister;
21535cd17f0eSRomain Gantois 		}
2154128d5874SRoger Quadros 		phy_attached_info(prueth->emac[PRUETH_MAC0]->ndev->phydev);
2155128d5874SRoger Quadros 	}
2156128d5874SRoger Quadros 
2157128d5874SRoger Quadros 	if (eth1_node) {
2158128d5874SRoger Quadros 		ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev);
2159128d5874SRoger Quadros 		if (ret) {
2160128d5874SRoger Quadros 			dev_err(dev, "can't register netdev for port MII1");
2161128d5874SRoger Quadros 			goto netdev_unregister;
2162128d5874SRoger Quadros 		}
2163128d5874SRoger Quadros 
2164128d5874SRoger Quadros 		prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev;
21655cd17f0eSRomain Gantois 		ret = emac_phy_connect(prueth->emac[PRUETH_MAC1]);
21665cd17f0eSRomain Gantois 		if (ret) {
21675cd17f0eSRomain Gantois 			dev_err(dev,
21685cd17f0eSRomain Gantois 				"can't connect to MII1 PHY, error %d", ret);
21695cd17f0eSRomain Gantois 			goto netdev_unregister;
21705cd17f0eSRomain Gantois 		}
2171128d5874SRoger Quadros 		phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev);
2172128d5874SRoger Quadros 	}
2173128d5874SRoger Quadros 
2174128d5874SRoger Quadros 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
2175128d5874SRoger Quadros 		 (!eth0_node || !eth1_node) ? "single" : "dual");
2176128d5874SRoger Quadros 
2177128d5874SRoger Quadros 	if (eth1_node)
2178128d5874SRoger Quadros 		of_node_put(eth1_node);
2179128d5874SRoger Quadros 	if (eth0_node)
2180128d5874SRoger Quadros 		of_node_put(eth0_node);
2181128d5874SRoger Quadros 	return 0;
2182128d5874SRoger Quadros 
2183128d5874SRoger Quadros netdev_unregister:
2184128d5874SRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
2185128d5874SRoger Quadros 		if (!prueth->registered_netdevs[i])
2186128d5874SRoger Quadros 			continue;
2187128d5874SRoger Quadros 		if (prueth->emac[i]->ndev->phydev) {
2188128d5874SRoger Quadros 			phy_disconnect(prueth->emac[i]->ndev->phydev);
2189128d5874SRoger Quadros 			prueth->emac[i]->ndev->phydev = NULL;
2190128d5874SRoger Quadros 		}
2191128d5874SRoger Quadros 		unregister_netdev(prueth->registered_netdevs[i]);
2192128d5874SRoger Quadros 	}
2193128d5874SRoger Quadros 
2194128d5874SRoger Quadros netdev_exit:
2195128d5874SRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
2196128d5874SRoger Quadros 		eth_node = prueth->eth_node[i];
2197128d5874SRoger Quadros 		if (!eth_node)
2198128d5874SRoger Quadros 			continue;
2199128d5874SRoger Quadros 
2200128d5874SRoger Quadros 		prueth_netdev_exit(prueth, eth_node);
2201128d5874SRoger Quadros 	}
2202128d5874SRoger Quadros 
2203443a2367SGrygorii Strashko exit_iep:
2204443a2367SGrygorii Strashko 	if (prueth->pdata.quirk_10m_link_issue)
2205443a2367SGrygorii Strashko 		icss_iep_exit_fw(prueth->iep1);
220670151949SJan Kiszka 	icss_iep_put(prueth->iep1);
220770151949SJan Kiszka 
220870151949SJan Kiszka put_iep0:
220970151949SJan Kiszka 	icss_iep_put(prueth->iep0);
221070151949SJan Kiszka 	prueth->iep0 = NULL;
221170151949SJan Kiszka 	prueth->iep1 = NULL;
2212443a2367SGrygorii Strashko 
2213186734c1SRoger Quadros free_pool:
2214128d5874SRoger Quadros 	gen_pool_free(prueth->sram_pool,
2215128d5874SRoger Quadros 		      (unsigned long)prueth->msmcram.va, msmc_ram_size);
2216128d5874SRoger Quadros 
2217128d5874SRoger Quadros put_mem:
2218128d5874SRoger Quadros 	pruss_release_mem_region(prueth->pruss, &prueth->shram);
2219920114bfSJan Kiszka 
2220920114bfSJan Kiszka put_pruss:
2221128d5874SRoger Quadros 	pruss_put(prueth->pruss);
2222128d5874SRoger Quadros 
2223128d5874SRoger Quadros put_cores:
2224128d5874SRoger Quadros 	if (eth1_node) {
2225128d5874SRoger Quadros 		prueth_put_cores(prueth, ICSS_SLICE1);
2226128d5874SRoger Quadros 		of_node_put(eth1_node);
2227128d5874SRoger Quadros 	}
2228128d5874SRoger Quadros 
2229128d5874SRoger Quadros 	if (eth0_node) {
2230128d5874SRoger Quadros 		prueth_put_cores(prueth, ICSS_SLICE0);
2231128d5874SRoger Quadros 		of_node_put(eth0_node);
2232128d5874SRoger Quadros 	}
2233128d5874SRoger Quadros 
2234128d5874SRoger Quadros 	return ret;
2235128d5874SRoger Quadros }
2236128d5874SRoger Quadros 
prueth_remove(struct platform_device * pdev)2237128d5874SRoger Quadros static void prueth_remove(struct platform_device *pdev)
2238128d5874SRoger Quadros {
2239128d5874SRoger Quadros 	struct prueth *prueth = platform_get_drvdata(pdev);
2240128d5874SRoger Quadros 	struct device_node *eth_node;
2241128d5874SRoger Quadros 	int i;
2242128d5874SRoger Quadros 
2243128d5874SRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
2244128d5874SRoger Quadros 		if (!prueth->registered_netdevs[i])
2245128d5874SRoger Quadros 			continue;
2246128d5874SRoger Quadros 		phy_stop(prueth->emac[i]->ndev->phydev);
2247128d5874SRoger Quadros 		phy_disconnect(prueth->emac[i]->ndev->phydev);
2248128d5874SRoger Quadros 		prueth->emac[i]->ndev->phydev = NULL;
2249128d5874SRoger Quadros 		unregister_netdev(prueth->registered_netdevs[i]);
2250128d5874SRoger Quadros 	}
2251128d5874SRoger Quadros 
2252128d5874SRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
2253128d5874SRoger Quadros 		eth_node = prueth->eth_node[i];
2254128d5874SRoger Quadros 		if (!eth_node)
2255128d5874SRoger Quadros 			continue;
2256128d5874SRoger Quadros 
2257128d5874SRoger Quadros 		prueth_netdev_exit(prueth, eth_node);
2258128d5874SRoger Quadros 	}
2259128d5874SRoger Quadros 
2260443a2367SGrygorii Strashko 	if (prueth->pdata.quirk_10m_link_issue)
2261443a2367SGrygorii Strashko 		icss_iep_exit_fw(prueth->iep1);
2262443a2367SGrygorii Strashko 
2263443a2367SGrygorii Strashko 	icss_iep_put(prueth->iep1);
2264186734c1SRoger Quadros 	icss_iep_put(prueth->iep0);
2265186734c1SRoger Quadros 
2266128d5874SRoger Quadros 	gen_pool_free(prueth->sram_pool,
2267128d5874SRoger Quadros 		      (unsigned long)prueth->msmcram.va,
2268128d5874SRoger Quadros 		      MSMC_RAM_SIZE);
2269128d5874SRoger Quadros 
2270128d5874SRoger Quadros 	pruss_release_mem_region(prueth->pruss, &prueth->shram);
2271128d5874SRoger Quadros 
2272128d5874SRoger Quadros 	pruss_put(prueth->pruss);
2273128d5874SRoger Quadros 
2274128d5874SRoger Quadros 	if (prueth->eth_node[PRUETH_MAC1])
2275128d5874SRoger Quadros 		prueth_put_cores(prueth, ICSS_SLICE1);
2276128d5874SRoger Quadros 
2277128d5874SRoger Quadros 	if (prueth->eth_node[PRUETH_MAC0])
2278128d5874SRoger Quadros 		prueth_put_cores(prueth, ICSS_SLICE0);
2279128d5874SRoger Quadros }
2280128d5874SRoger Quadros 
2281a46750a1SMD Danish Anwar #ifdef CONFIG_PM_SLEEP
prueth_suspend(struct device * dev)2282a46750a1SMD Danish Anwar static int prueth_suspend(struct device *dev)
2283a46750a1SMD Danish Anwar {
2284a46750a1SMD Danish Anwar 	struct prueth *prueth = dev_get_drvdata(dev);
2285a46750a1SMD Danish Anwar 	struct net_device *ndev;
2286a46750a1SMD Danish Anwar 	int i, ret;
2287a46750a1SMD Danish Anwar 
2288a46750a1SMD Danish Anwar 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
2289a46750a1SMD Danish Anwar 		ndev = prueth->registered_netdevs[i];
2290a46750a1SMD Danish Anwar 
2291a46750a1SMD Danish Anwar 		if (!ndev)
2292a46750a1SMD Danish Anwar 			continue;
2293a46750a1SMD Danish Anwar 
2294a46750a1SMD Danish Anwar 		if (netif_running(ndev)) {
2295a46750a1SMD Danish Anwar 			netif_device_detach(ndev);
2296a46750a1SMD Danish Anwar 			ret = emac_ndo_stop(ndev);
2297a46750a1SMD Danish Anwar 			if (ret < 0) {
2298a46750a1SMD Danish Anwar 				netdev_err(ndev, "failed to stop: %d", ret);
2299a46750a1SMD Danish Anwar 				return ret;
2300a46750a1SMD Danish Anwar 			}
2301a46750a1SMD Danish Anwar 		}
2302a46750a1SMD Danish Anwar 	}
2303a46750a1SMD Danish Anwar 
2304a46750a1SMD Danish Anwar 	return 0;
2305a46750a1SMD Danish Anwar }
2306a46750a1SMD Danish Anwar 
prueth_resume(struct device * dev)2307a46750a1SMD Danish Anwar static int prueth_resume(struct device *dev)
2308a46750a1SMD Danish Anwar {
2309a46750a1SMD Danish Anwar 	struct prueth *prueth = dev_get_drvdata(dev);
2310a46750a1SMD Danish Anwar 	struct net_device *ndev;
2311a46750a1SMD Danish Anwar 	int i, ret;
2312a46750a1SMD Danish Anwar 
2313a46750a1SMD Danish Anwar 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
2314a46750a1SMD Danish Anwar 		ndev = prueth->registered_netdevs[i];
2315a46750a1SMD Danish Anwar 
2316a46750a1SMD Danish Anwar 		if (!ndev)
2317a46750a1SMD Danish Anwar 			continue;
2318a46750a1SMD Danish Anwar 
2319a46750a1SMD Danish Anwar 		if (netif_running(ndev)) {
2320a46750a1SMD Danish Anwar 			ret = emac_ndo_open(ndev);
2321a46750a1SMD Danish Anwar 			if (ret < 0) {
2322a46750a1SMD Danish Anwar 				netdev_err(ndev, "failed to start: %d", ret);
2323a46750a1SMD Danish Anwar 				return ret;
2324a46750a1SMD Danish Anwar 			}
2325a46750a1SMD Danish Anwar 			netif_device_attach(ndev);
2326a46750a1SMD Danish Anwar 		}
2327a46750a1SMD Danish Anwar 	}
2328a46750a1SMD Danish Anwar 
2329a46750a1SMD Danish Anwar 	return 0;
2330a46750a1SMD Danish Anwar }
2331a46750a1SMD Danish Anwar #endif /* CONFIG_PM_SLEEP */
2332a46750a1SMD Danish Anwar 
2333a46750a1SMD Danish Anwar static const struct dev_pm_ops prueth_dev_pm_ops = {
2334a46750a1SMD Danish Anwar 	SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume)
2335a46750a1SMD Danish Anwar };
2336a46750a1SMD Danish Anwar 
2337128d5874SRoger Quadros static const struct prueth_pdata am654_icssg_pdata = {
2338128d5874SRoger Quadros 	.fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,
2339128d5874SRoger Quadros 	.quirk_10m_link_issue = 1,
2340128d5874SRoger Quadros };
2341128d5874SRoger Quadros 
2342128d5874SRoger Quadros static const struct of_device_id prueth_dt_match[] = {
2343128d5874SRoger Quadros 	{ .compatible = "ti,am654-icssg-prueth", .data = &am654_icssg_pdata },
2344128d5874SRoger Quadros 	{ /* sentinel */ }
2345128d5874SRoger Quadros };
2346128d5874SRoger Quadros MODULE_DEVICE_TABLE(of, prueth_dt_match);
2347128d5874SRoger Quadros 
2348128d5874SRoger Quadros static struct platform_driver prueth_driver = {
2349128d5874SRoger Quadros 	.probe = prueth_probe,
2350128d5874SRoger Quadros 	.remove_new = prueth_remove,
2351128d5874SRoger Quadros 	.driver = {
2352128d5874SRoger Quadros 		.name = "icssg-prueth",
2353128d5874SRoger Quadros 		.of_match_table = prueth_dt_match,
2354a46750a1SMD Danish Anwar 		.pm = &prueth_dev_pm_ops,
2355128d5874SRoger Quadros 	},
2356128d5874SRoger Quadros };
2357128d5874SRoger Quadros module_platform_driver(prueth_driver);
2358128d5874SRoger Quadros 
2359128d5874SRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
2360128d5874SRoger Quadros MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>");
2361128d5874SRoger Quadros MODULE_DESCRIPTION("PRUSS ICSSG Ethernet Driver");
2362128d5874SRoger Quadros MODULE_LICENSE("GPL");
2363