1c8349639SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+
2c8349639SHoratiu Vultur 
3c8349639SHoratiu Vultur #include "lan966x_main.h"
4c8349639SHoratiu Vultur 
5c8349639SHoratiu Vultur static int lan966x_fdma_channel_active(struct lan966x *lan966x)
6c8349639SHoratiu Vultur {
7c8349639SHoratiu Vultur 	return lan_rd(lan966x, FDMA_CH_ACTIVE);
8c8349639SHoratiu Vultur }
9c8349639SHoratiu Vultur 
10c8349639SHoratiu Vultur static struct page *lan966x_fdma_rx_alloc_page(struct lan966x_rx *rx,
11c8349639SHoratiu Vultur 					       struct lan966x_db *db)
12c8349639SHoratiu Vultur {
13c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
14c8349639SHoratiu Vultur 	dma_addr_t dma_addr;
15c8349639SHoratiu Vultur 	struct page *page;
16c8349639SHoratiu Vultur 
17c8349639SHoratiu Vultur 	page = dev_alloc_pages(rx->page_order);
18c8349639SHoratiu Vultur 	if (unlikely(!page))
19c8349639SHoratiu Vultur 		return NULL;
20c8349639SHoratiu Vultur 
21c8349639SHoratiu Vultur 	dma_addr = dma_map_page(lan966x->dev, page, 0,
22c8349639SHoratiu Vultur 				PAGE_SIZE << rx->page_order,
23c8349639SHoratiu Vultur 				DMA_FROM_DEVICE);
24c8349639SHoratiu Vultur 	if (unlikely(dma_mapping_error(lan966x->dev, dma_addr)))
25c8349639SHoratiu Vultur 		goto free_page;
26c8349639SHoratiu Vultur 
27c8349639SHoratiu Vultur 	db->dataptr = dma_addr;
28c8349639SHoratiu Vultur 
29c8349639SHoratiu Vultur 	return page;
30c8349639SHoratiu Vultur 
31c8349639SHoratiu Vultur free_page:
32c8349639SHoratiu Vultur 	__free_pages(page, rx->page_order);
33c8349639SHoratiu Vultur 	return NULL;
34c8349639SHoratiu Vultur }
35c8349639SHoratiu Vultur 
36c8349639SHoratiu Vultur static void lan966x_fdma_rx_free_pages(struct lan966x_rx *rx)
37c8349639SHoratiu Vultur {
38c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
39c8349639SHoratiu Vultur 	struct lan966x_rx_dcb *dcb;
40c8349639SHoratiu Vultur 	struct lan966x_db *db;
41c8349639SHoratiu Vultur 	int i, j;
42c8349639SHoratiu Vultur 
43c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
44c8349639SHoratiu Vultur 		dcb = &rx->dcbs[i];
45c8349639SHoratiu Vultur 
46c8349639SHoratiu Vultur 		for (j = 0; j < FDMA_RX_DCB_MAX_DBS; ++j) {
47c8349639SHoratiu Vultur 			db = &dcb->db[j];
48c8349639SHoratiu Vultur 			dma_unmap_single(lan966x->dev,
49c8349639SHoratiu Vultur 					 (dma_addr_t)db->dataptr,
50c8349639SHoratiu Vultur 					 PAGE_SIZE << rx->page_order,
51c8349639SHoratiu Vultur 					 DMA_FROM_DEVICE);
52c8349639SHoratiu Vultur 			__free_pages(rx->page[i][j], rx->page_order);
53c8349639SHoratiu Vultur 		}
54c8349639SHoratiu Vultur 	}
55c8349639SHoratiu Vultur }
56c8349639SHoratiu Vultur 
57c8349639SHoratiu Vultur static void lan966x_fdma_rx_add_dcb(struct lan966x_rx *rx,
58c8349639SHoratiu Vultur 				    struct lan966x_rx_dcb *dcb,
59c8349639SHoratiu Vultur 				    u64 nextptr)
60c8349639SHoratiu Vultur {
61c8349639SHoratiu Vultur 	struct lan966x_db *db;
62c8349639SHoratiu Vultur 	int i;
63c8349639SHoratiu Vultur 
64c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_RX_DCB_MAX_DBS; ++i) {
65c8349639SHoratiu Vultur 		db = &dcb->db[i];
66c8349639SHoratiu Vultur 		db->status = FDMA_DCB_STATUS_INTR;
67c8349639SHoratiu Vultur 	}
68c8349639SHoratiu Vultur 
69c8349639SHoratiu Vultur 	dcb->nextptr = FDMA_DCB_INVALID_DATA;
70c8349639SHoratiu Vultur 	dcb->info = FDMA_DCB_INFO_DATAL(PAGE_SIZE << rx->page_order);
71c8349639SHoratiu Vultur 
72c8349639SHoratiu Vultur 	rx->last_entry->nextptr = nextptr;
73c8349639SHoratiu Vultur 	rx->last_entry = dcb;
74c8349639SHoratiu Vultur }
75c8349639SHoratiu Vultur 
76c8349639SHoratiu Vultur static int lan966x_fdma_rx_alloc(struct lan966x_rx *rx)
77c8349639SHoratiu Vultur {
78c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
79c8349639SHoratiu Vultur 	struct lan966x_rx_dcb *dcb;
80c8349639SHoratiu Vultur 	struct lan966x_db *db;
81c8349639SHoratiu Vultur 	struct page *page;
82c8349639SHoratiu Vultur 	int i, j;
83c8349639SHoratiu Vultur 	int size;
84c8349639SHoratiu Vultur 
85c8349639SHoratiu Vultur 	/* calculate how many pages are needed to allocate the dcbs */
86c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_rx_dcb) * FDMA_DCB_MAX;
87c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
88c8349639SHoratiu Vultur 
89c8349639SHoratiu Vultur 	rx->dcbs = dma_alloc_coherent(lan966x->dev, size, &rx->dma, GFP_KERNEL);
90c8349639SHoratiu Vultur 	if (!rx->dcbs)
91c8349639SHoratiu Vultur 		return -ENOMEM;
92c8349639SHoratiu Vultur 
93c8349639SHoratiu Vultur 	rx->last_entry = rx->dcbs;
94c8349639SHoratiu Vultur 	rx->db_index = 0;
95c8349639SHoratiu Vultur 	rx->dcb_index = 0;
96c8349639SHoratiu Vultur 
97c8349639SHoratiu Vultur 	/* Now for each dcb allocate the dbs */
98c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
99c8349639SHoratiu Vultur 		dcb = &rx->dcbs[i];
100c8349639SHoratiu Vultur 		dcb->info = 0;
101c8349639SHoratiu Vultur 
102c8349639SHoratiu Vultur 		/* For each db allocate a page and map it to the DB dataptr. */
103c8349639SHoratiu Vultur 		for (j = 0; j < FDMA_RX_DCB_MAX_DBS; ++j) {
104c8349639SHoratiu Vultur 			db = &dcb->db[j];
105c8349639SHoratiu Vultur 			page = lan966x_fdma_rx_alloc_page(rx, db);
106c8349639SHoratiu Vultur 			if (!page)
107c8349639SHoratiu Vultur 				return -ENOMEM;
108c8349639SHoratiu Vultur 
109c8349639SHoratiu Vultur 			db->status = 0;
110c8349639SHoratiu Vultur 			rx->page[i][j] = page;
111c8349639SHoratiu Vultur 		}
112c8349639SHoratiu Vultur 
113c8349639SHoratiu Vultur 		lan966x_fdma_rx_add_dcb(rx, dcb, rx->dma + sizeof(*dcb) * i);
114c8349639SHoratiu Vultur 	}
115c8349639SHoratiu Vultur 
116c8349639SHoratiu Vultur 	return 0;
117c8349639SHoratiu Vultur }
118c8349639SHoratiu Vultur 
119c8349639SHoratiu Vultur static void lan966x_fdma_rx_free(struct lan966x_rx *rx)
120c8349639SHoratiu Vultur {
121c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
122c8349639SHoratiu Vultur 	u32 size;
123c8349639SHoratiu Vultur 
124c8349639SHoratiu Vultur 	/* Now it is possible to do the cleanup of dcb */
125c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX;
126c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
127c8349639SHoratiu Vultur 	dma_free_coherent(lan966x->dev, size, rx->dcbs, rx->dma);
128c8349639SHoratiu Vultur }
129c8349639SHoratiu Vultur 
130c8349639SHoratiu Vultur static void lan966x_fdma_rx_start(struct lan966x_rx *rx)
131c8349639SHoratiu Vultur {
132c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
133c8349639SHoratiu Vultur 	u32 mask;
134c8349639SHoratiu Vultur 
135c8349639SHoratiu Vultur 	/* When activating a channel, first is required to write the first DCB
136c8349639SHoratiu Vultur 	 * address and then to activate it
137c8349639SHoratiu Vultur 	 */
138c8349639SHoratiu Vultur 	lan_wr(lower_32_bits((u64)rx->dma), lan966x,
139c8349639SHoratiu Vultur 	       FDMA_DCB_LLP(rx->channel_id));
140c8349639SHoratiu Vultur 	lan_wr(upper_32_bits((u64)rx->dma), lan966x,
141c8349639SHoratiu Vultur 	       FDMA_DCB_LLP1(rx->channel_id));
142c8349639SHoratiu Vultur 
143c8349639SHoratiu Vultur 	lan_wr(FDMA_CH_CFG_CH_DCB_DB_CNT_SET(FDMA_RX_DCB_MAX_DBS) |
144c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(1) |
145c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INJ_PORT_SET(0) |
146c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_MEM_SET(1),
147c8349639SHoratiu Vultur 	       lan966x, FDMA_CH_CFG(rx->channel_id));
148c8349639SHoratiu Vultur 
149c8349639SHoratiu Vultur 	/* Start fdma */
150c8349639SHoratiu Vultur 	lan_rmw(FDMA_PORT_CTRL_XTR_STOP_SET(0),
151c8349639SHoratiu Vultur 		FDMA_PORT_CTRL_XTR_STOP,
152c8349639SHoratiu Vultur 		lan966x, FDMA_PORT_CTRL(0));
153c8349639SHoratiu Vultur 
154c8349639SHoratiu Vultur 	/* Enable interrupts */
155c8349639SHoratiu Vultur 	mask = lan_rd(lan966x, FDMA_INTR_DB_ENA);
156c8349639SHoratiu Vultur 	mask = FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(mask);
157c8349639SHoratiu Vultur 	mask |= BIT(rx->channel_id);
158c8349639SHoratiu Vultur 	lan_rmw(FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(mask),
159c8349639SHoratiu Vultur 		FDMA_INTR_DB_ENA_INTR_DB_ENA,
160c8349639SHoratiu Vultur 		lan966x, FDMA_INTR_DB_ENA);
161c8349639SHoratiu Vultur 
162c8349639SHoratiu Vultur 	/* Activate the channel */
163c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(BIT(rx->channel_id)),
164c8349639SHoratiu Vultur 		FDMA_CH_ACTIVATE_CH_ACTIVATE,
165c8349639SHoratiu Vultur 		lan966x, FDMA_CH_ACTIVATE);
166c8349639SHoratiu Vultur }
167c8349639SHoratiu Vultur 
168c8349639SHoratiu Vultur static void lan966x_fdma_rx_disable(struct lan966x_rx *rx)
169c8349639SHoratiu Vultur {
170c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
171c8349639SHoratiu Vultur 	u32 val;
172c8349639SHoratiu Vultur 
173c8349639SHoratiu Vultur 	/* Disable the channel */
174c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DISABLE_CH_DISABLE_SET(BIT(rx->channel_id)),
175c8349639SHoratiu Vultur 		FDMA_CH_DISABLE_CH_DISABLE,
176c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DISABLE);
177c8349639SHoratiu Vultur 
178c8349639SHoratiu Vultur 	readx_poll_timeout_atomic(lan966x_fdma_channel_active, lan966x,
179c8349639SHoratiu Vultur 				  val, !(val & BIT(rx->channel_id)),
180c8349639SHoratiu Vultur 				  READL_SLEEP_US, READL_TIMEOUT_US);
181c8349639SHoratiu Vultur 
182c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DB_DISCARD_DB_DISCARD_SET(BIT(rx->channel_id)),
183c8349639SHoratiu Vultur 		FDMA_CH_DB_DISCARD_DB_DISCARD,
184c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DB_DISCARD);
185c8349639SHoratiu Vultur }
186c8349639SHoratiu Vultur 
187c8349639SHoratiu Vultur static void lan966x_fdma_rx_reload(struct lan966x_rx *rx)
188c8349639SHoratiu Vultur {
189c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
190c8349639SHoratiu Vultur 
191c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_RELOAD_CH_RELOAD_SET(BIT(rx->channel_id)),
192c8349639SHoratiu Vultur 		FDMA_CH_RELOAD_CH_RELOAD,
193c8349639SHoratiu Vultur 		lan966x, FDMA_CH_RELOAD);
194c8349639SHoratiu Vultur }
195c8349639SHoratiu Vultur 
196c8349639SHoratiu Vultur static void lan966x_fdma_tx_add_dcb(struct lan966x_tx *tx,
197c8349639SHoratiu Vultur 				    struct lan966x_tx_dcb *dcb)
198c8349639SHoratiu Vultur {
199c8349639SHoratiu Vultur 	dcb->nextptr = FDMA_DCB_INVALID_DATA;
200c8349639SHoratiu Vultur 	dcb->info = 0;
201c8349639SHoratiu Vultur }
202c8349639SHoratiu Vultur 
203c8349639SHoratiu Vultur static int lan966x_fdma_tx_alloc(struct lan966x_tx *tx)
204c8349639SHoratiu Vultur {
205c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
206c8349639SHoratiu Vultur 	struct lan966x_tx_dcb *dcb;
207c8349639SHoratiu Vultur 	struct lan966x_db *db;
208c8349639SHoratiu Vultur 	int size;
209c8349639SHoratiu Vultur 	int i, j;
210c8349639SHoratiu Vultur 
211c8349639SHoratiu Vultur 	tx->dcbs_buf = kcalloc(FDMA_DCB_MAX, sizeof(struct lan966x_tx_dcb_buf),
212c8349639SHoratiu Vultur 			       GFP_KERNEL);
213c8349639SHoratiu Vultur 	if (!tx->dcbs_buf)
214c8349639SHoratiu Vultur 		return -ENOMEM;
215c8349639SHoratiu Vultur 
216c8349639SHoratiu Vultur 	/* calculate how many pages are needed to allocate the dcbs */
217c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX;
218c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
219c8349639SHoratiu Vultur 	tx->dcbs = dma_alloc_coherent(lan966x->dev, size, &tx->dma, GFP_KERNEL);
220c8349639SHoratiu Vultur 	if (!tx->dcbs)
221c8349639SHoratiu Vultur 		goto out;
222c8349639SHoratiu Vultur 
223c8349639SHoratiu Vultur 	/* Now for each dcb allocate the db */
224c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
225c8349639SHoratiu Vultur 		dcb = &tx->dcbs[i];
226c8349639SHoratiu Vultur 
227c8349639SHoratiu Vultur 		for (j = 0; j < FDMA_TX_DCB_MAX_DBS; ++j) {
228c8349639SHoratiu Vultur 			db = &dcb->db[j];
229c8349639SHoratiu Vultur 			db->dataptr = 0;
230c8349639SHoratiu Vultur 			db->status = 0;
231c8349639SHoratiu Vultur 		}
232c8349639SHoratiu Vultur 
233c8349639SHoratiu Vultur 		lan966x_fdma_tx_add_dcb(tx, dcb);
234c8349639SHoratiu Vultur 	}
235c8349639SHoratiu Vultur 
236c8349639SHoratiu Vultur 	return 0;
237c8349639SHoratiu Vultur 
238c8349639SHoratiu Vultur out:
239c8349639SHoratiu Vultur 	kfree(tx->dcbs_buf);
240c8349639SHoratiu Vultur 	return -ENOMEM;
241c8349639SHoratiu Vultur }
242c8349639SHoratiu Vultur 
243c8349639SHoratiu Vultur static void lan966x_fdma_tx_free(struct lan966x_tx *tx)
244c8349639SHoratiu Vultur {
245c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
246c8349639SHoratiu Vultur 	int size;
247c8349639SHoratiu Vultur 
248c8349639SHoratiu Vultur 	kfree(tx->dcbs_buf);
249c8349639SHoratiu Vultur 
250c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX;
251c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
252c8349639SHoratiu Vultur 	dma_free_coherent(lan966x->dev, size, tx->dcbs, tx->dma);
253c8349639SHoratiu Vultur }
254c8349639SHoratiu Vultur 
255c8349639SHoratiu Vultur static void lan966x_fdma_tx_activate(struct lan966x_tx *tx)
256c8349639SHoratiu Vultur {
257c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
258c8349639SHoratiu Vultur 	u32 mask;
259c8349639SHoratiu Vultur 
260c8349639SHoratiu Vultur 	/* When activating a channel, first is required to write the first DCB
261c8349639SHoratiu Vultur 	 * address and then to activate it
262c8349639SHoratiu Vultur 	 */
263c8349639SHoratiu Vultur 	lan_wr(lower_32_bits((u64)tx->dma), lan966x,
264c8349639SHoratiu Vultur 	       FDMA_DCB_LLP(tx->channel_id));
265c8349639SHoratiu Vultur 	lan_wr(upper_32_bits((u64)tx->dma), lan966x,
266c8349639SHoratiu Vultur 	       FDMA_DCB_LLP1(tx->channel_id));
267c8349639SHoratiu Vultur 
268c8349639SHoratiu Vultur 	lan_wr(FDMA_CH_CFG_CH_DCB_DB_CNT_SET(FDMA_TX_DCB_MAX_DBS) |
269c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(1) |
270c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INJ_PORT_SET(0) |
271c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_MEM_SET(1),
272c8349639SHoratiu Vultur 	       lan966x, FDMA_CH_CFG(tx->channel_id));
273c8349639SHoratiu Vultur 
274c8349639SHoratiu Vultur 	/* Start fdma */
275c8349639SHoratiu Vultur 	lan_rmw(FDMA_PORT_CTRL_INJ_STOP_SET(0),
276c8349639SHoratiu Vultur 		FDMA_PORT_CTRL_INJ_STOP,
277c8349639SHoratiu Vultur 		lan966x, FDMA_PORT_CTRL(0));
278c8349639SHoratiu Vultur 
279c8349639SHoratiu Vultur 	/* Enable interrupts */
280c8349639SHoratiu Vultur 	mask = lan_rd(lan966x, FDMA_INTR_DB_ENA);
281c8349639SHoratiu Vultur 	mask = FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(mask);
282c8349639SHoratiu Vultur 	mask |= BIT(tx->channel_id);
283c8349639SHoratiu Vultur 	lan_rmw(FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(mask),
284c8349639SHoratiu Vultur 		FDMA_INTR_DB_ENA_INTR_DB_ENA,
285c8349639SHoratiu Vultur 		lan966x, FDMA_INTR_DB_ENA);
286c8349639SHoratiu Vultur 
287c8349639SHoratiu Vultur 	/* Activate the channel */
288c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(BIT(tx->channel_id)),
289c8349639SHoratiu Vultur 		FDMA_CH_ACTIVATE_CH_ACTIVATE,
290c8349639SHoratiu Vultur 		lan966x, FDMA_CH_ACTIVATE);
291c8349639SHoratiu Vultur }
292c8349639SHoratiu Vultur 
293c8349639SHoratiu Vultur static void lan966x_fdma_tx_disable(struct lan966x_tx *tx)
294c8349639SHoratiu Vultur {
295c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
296c8349639SHoratiu Vultur 	u32 val;
297c8349639SHoratiu Vultur 
298c8349639SHoratiu Vultur 	/* Disable the channel */
299c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DISABLE_CH_DISABLE_SET(BIT(tx->channel_id)),
300c8349639SHoratiu Vultur 		FDMA_CH_DISABLE_CH_DISABLE,
301c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DISABLE);
302c8349639SHoratiu Vultur 
303c8349639SHoratiu Vultur 	readx_poll_timeout_atomic(lan966x_fdma_channel_active, lan966x,
304c8349639SHoratiu Vultur 				  val, !(val & BIT(tx->channel_id)),
305c8349639SHoratiu Vultur 				  READL_SLEEP_US, READL_TIMEOUT_US);
306c8349639SHoratiu Vultur 
307c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DB_DISCARD_DB_DISCARD_SET(BIT(tx->channel_id)),
308c8349639SHoratiu Vultur 		FDMA_CH_DB_DISCARD_DB_DISCARD,
309c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DB_DISCARD);
310c8349639SHoratiu Vultur 
311c8349639SHoratiu Vultur 	tx->activated = false;
312c8349639SHoratiu Vultur }
313c8349639SHoratiu Vultur 
314c8349639SHoratiu Vultur static void lan966x_fdma_tx_reload(struct lan966x_tx *tx)
315c8349639SHoratiu Vultur {
316c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
317c8349639SHoratiu Vultur 
318c8349639SHoratiu Vultur 	/* Write the registers to reload the channel */
319c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_RELOAD_CH_RELOAD_SET(BIT(tx->channel_id)),
320c8349639SHoratiu Vultur 		FDMA_CH_RELOAD_CH_RELOAD,
321c8349639SHoratiu Vultur 		lan966x, FDMA_CH_RELOAD);
322c8349639SHoratiu Vultur }
323c8349639SHoratiu Vultur 
324c8349639SHoratiu Vultur static void lan966x_fdma_wakeup_netdev(struct lan966x *lan966x)
325c8349639SHoratiu Vultur {
326c8349639SHoratiu Vultur 	struct lan966x_port *port;
327c8349639SHoratiu Vultur 	int i;
328c8349639SHoratiu Vultur 
329c8349639SHoratiu Vultur 	for (i = 0; i < lan966x->num_phys_ports; ++i) {
330c8349639SHoratiu Vultur 		port = lan966x->ports[i];
331c8349639SHoratiu Vultur 		if (!port)
332c8349639SHoratiu Vultur 			continue;
333c8349639SHoratiu Vultur 
334c8349639SHoratiu Vultur 		if (netif_queue_stopped(port->dev))
335c8349639SHoratiu Vultur 			netif_wake_queue(port->dev);
336c8349639SHoratiu Vultur 	}
337c8349639SHoratiu Vultur }
338c8349639SHoratiu Vultur 
339*2ea1cbacSHoratiu Vultur static void lan966x_fdma_stop_netdev(struct lan966x *lan966x)
340*2ea1cbacSHoratiu Vultur {
341*2ea1cbacSHoratiu Vultur 	struct lan966x_port *port;
342*2ea1cbacSHoratiu Vultur 	int i;
343*2ea1cbacSHoratiu Vultur 
344*2ea1cbacSHoratiu Vultur 	for (i = 0; i < lan966x->num_phys_ports; ++i) {
345*2ea1cbacSHoratiu Vultur 		port = lan966x->ports[i];
346*2ea1cbacSHoratiu Vultur 		if (!port)
347*2ea1cbacSHoratiu Vultur 			continue;
348*2ea1cbacSHoratiu Vultur 
349*2ea1cbacSHoratiu Vultur 		netif_stop_queue(port->dev);
350*2ea1cbacSHoratiu Vultur 	}
351*2ea1cbacSHoratiu Vultur }
352*2ea1cbacSHoratiu Vultur 
353c8349639SHoratiu Vultur static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
354c8349639SHoratiu Vultur {
355c8349639SHoratiu Vultur 	struct lan966x_tx *tx = &lan966x->tx;
356c8349639SHoratiu Vultur 	struct lan966x_tx_dcb_buf *dcb_buf;
357c8349639SHoratiu Vultur 	struct lan966x_db *db;
358c8349639SHoratiu Vultur 	unsigned long flags;
359c8349639SHoratiu Vultur 	bool clear = false;
360c8349639SHoratiu Vultur 	int i;
361c8349639SHoratiu Vultur 
362c8349639SHoratiu Vultur 	spin_lock_irqsave(&lan966x->tx_lock, flags);
363c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
364c8349639SHoratiu Vultur 		dcb_buf = &tx->dcbs_buf[i];
365c8349639SHoratiu Vultur 
366c8349639SHoratiu Vultur 		if (!dcb_buf->used)
367c8349639SHoratiu Vultur 			continue;
368c8349639SHoratiu Vultur 
369c8349639SHoratiu Vultur 		db = &tx->dcbs[i].db[0];
370c8349639SHoratiu Vultur 		if (!(db->status & FDMA_DCB_STATUS_DONE))
371c8349639SHoratiu Vultur 			continue;
372c8349639SHoratiu Vultur 
373c8349639SHoratiu Vultur 		dcb_buf->dev->stats.tx_packets++;
374c8349639SHoratiu Vultur 		dcb_buf->dev->stats.tx_bytes += dcb_buf->skb->len;
375c8349639SHoratiu Vultur 
376c8349639SHoratiu Vultur 		dcb_buf->used = false;
377c8349639SHoratiu Vultur 		dma_unmap_single(lan966x->dev,
378c8349639SHoratiu Vultur 				 dcb_buf->dma_addr,
379c8349639SHoratiu Vultur 				 dcb_buf->skb->len,
380c8349639SHoratiu Vultur 				 DMA_TO_DEVICE);
381c8349639SHoratiu Vultur 		if (!dcb_buf->ptp)
382c8349639SHoratiu Vultur 			dev_kfree_skb_any(dcb_buf->skb);
383c8349639SHoratiu Vultur 
384c8349639SHoratiu Vultur 		clear = true;
385c8349639SHoratiu Vultur 	}
386c8349639SHoratiu Vultur 
387c8349639SHoratiu Vultur 	if (clear)
388c8349639SHoratiu Vultur 		lan966x_fdma_wakeup_netdev(lan966x);
389c8349639SHoratiu Vultur 
390c8349639SHoratiu Vultur 	spin_unlock_irqrestore(&lan966x->tx_lock, flags);
391c8349639SHoratiu Vultur }
392c8349639SHoratiu Vultur 
393c8349639SHoratiu Vultur static bool lan966x_fdma_rx_more_frames(struct lan966x_rx *rx)
394c8349639SHoratiu Vultur {
395c8349639SHoratiu Vultur 	struct lan966x_db *db;
396c8349639SHoratiu Vultur 
397c8349639SHoratiu Vultur 	/* Check if there is any data */
398c8349639SHoratiu Vultur 	db = &rx->dcbs[rx->dcb_index].db[rx->db_index];
399c8349639SHoratiu Vultur 	if (unlikely(!(db->status & FDMA_DCB_STATUS_DONE)))
400c8349639SHoratiu Vultur 		return false;
401c8349639SHoratiu Vultur 
402c8349639SHoratiu Vultur 	return true;
403c8349639SHoratiu Vultur }
404c8349639SHoratiu Vultur 
405c8349639SHoratiu Vultur static struct sk_buff *lan966x_fdma_rx_get_frame(struct lan966x_rx *rx)
406c8349639SHoratiu Vultur {
407c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
408c8349639SHoratiu Vultur 	u64 src_port, timestamp;
409c8349639SHoratiu Vultur 	struct lan966x_db *db;
410c8349639SHoratiu Vultur 	struct sk_buff *skb;
411c8349639SHoratiu Vultur 	struct page *page;
412c8349639SHoratiu Vultur 
413c8349639SHoratiu Vultur 	/* Get the received frame and unmap it */
414c8349639SHoratiu Vultur 	db = &rx->dcbs[rx->dcb_index].db[rx->db_index];
415c8349639SHoratiu Vultur 	page = rx->page[rx->dcb_index][rx->db_index];
416c8349639SHoratiu Vultur 	skb = build_skb(page_address(page), PAGE_SIZE << rx->page_order);
417c8349639SHoratiu Vultur 	if (unlikely(!skb))
418c8349639SHoratiu Vultur 		goto unmap_page;
419c8349639SHoratiu Vultur 
420c8349639SHoratiu Vultur 	dma_unmap_single(lan966x->dev, (dma_addr_t)db->dataptr,
421c8349639SHoratiu Vultur 			 FDMA_DCB_STATUS_BLOCKL(db->status),
422c8349639SHoratiu Vultur 			 DMA_FROM_DEVICE);
423c8349639SHoratiu Vultur 	skb_put(skb, FDMA_DCB_STATUS_BLOCKL(db->status));
424c8349639SHoratiu Vultur 
425c8349639SHoratiu Vultur 	lan966x_ifh_get_src_port(skb->data, &src_port);
426c8349639SHoratiu Vultur 	lan966x_ifh_get_timestamp(skb->data, &timestamp);
427c8349639SHoratiu Vultur 
428c8349639SHoratiu Vultur 	WARN_ON(src_port >= lan966x->num_phys_ports);
429c8349639SHoratiu Vultur 
430c8349639SHoratiu Vultur 	skb->dev = lan966x->ports[src_port]->dev;
431c8349639SHoratiu Vultur 	skb_pull(skb, IFH_LEN * sizeof(u32));
432c8349639SHoratiu Vultur 
433c8349639SHoratiu Vultur 	if (likely(!(skb->dev->features & NETIF_F_RXFCS)))
434c8349639SHoratiu Vultur 		skb_trim(skb, skb->len - ETH_FCS_LEN);
435c8349639SHoratiu Vultur 
436c8349639SHoratiu Vultur 	lan966x_ptp_rxtstamp(lan966x, skb, timestamp);
437c8349639SHoratiu Vultur 	skb->protocol = eth_type_trans(skb, skb->dev);
438c8349639SHoratiu Vultur 
439c8349639SHoratiu Vultur 	if (lan966x->bridge_mask & BIT(src_port)) {
440c8349639SHoratiu Vultur 		skb->offload_fwd_mark = 1;
441c8349639SHoratiu Vultur 
442c8349639SHoratiu Vultur 		skb_reset_network_header(skb);
443c8349639SHoratiu Vultur 		if (!lan966x_hw_offload(lan966x, src_port, skb))
444c8349639SHoratiu Vultur 			skb->offload_fwd_mark = 0;
445c8349639SHoratiu Vultur 	}
446c8349639SHoratiu Vultur 
447c8349639SHoratiu Vultur 	skb->dev->stats.rx_bytes += skb->len;
448c8349639SHoratiu Vultur 	skb->dev->stats.rx_packets++;
449c8349639SHoratiu Vultur 
450c8349639SHoratiu Vultur 	return skb;
451c8349639SHoratiu Vultur 
452c8349639SHoratiu Vultur unmap_page:
453c8349639SHoratiu Vultur 	dma_unmap_page(lan966x->dev, (dma_addr_t)db->dataptr,
454c8349639SHoratiu Vultur 		       FDMA_DCB_STATUS_BLOCKL(db->status),
455c8349639SHoratiu Vultur 		       DMA_FROM_DEVICE);
456c8349639SHoratiu Vultur 	__free_pages(page, rx->page_order);
457c8349639SHoratiu Vultur 
458c8349639SHoratiu Vultur 	return NULL;
459c8349639SHoratiu Vultur }
460c8349639SHoratiu Vultur 
461c8349639SHoratiu Vultur static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight)
462c8349639SHoratiu Vultur {
463c8349639SHoratiu Vultur 	struct lan966x *lan966x = container_of(napi, struct lan966x, napi);
464c8349639SHoratiu Vultur 	struct lan966x_rx *rx = &lan966x->rx;
465c8349639SHoratiu Vultur 	int dcb_reload = rx->dcb_index;
466c8349639SHoratiu Vultur 	struct lan966x_rx_dcb *old_dcb;
467c8349639SHoratiu Vultur 	struct lan966x_db *db;
468c8349639SHoratiu Vultur 	struct sk_buff *skb;
469c8349639SHoratiu Vultur 	struct page *page;
470c8349639SHoratiu Vultur 	int counter = 0;
471c8349639SHoratiu Vultur 	u64 nextptr;
472c8349639SHoratiu Vultur 
473c8349639SHoratiu Vultur 	lan966x_fdma_tx_clear_buf(lan966x, weight);
474c8349639SHoratiu Vultur 
475c8349639SHoratiu Vultur 	/* Get all received skb */
476c8349639SHoratiu Vultur 	while (counter < weight) {
477c8349639SHoratiu Vultur 		if (!lan966x_fdma_rx_more_frames(rx))
478c8349639SHoratiu Vultur 			break;
479c8349639SHoratiu Vultur 
480c8349639SHoratiu Vultur 		skb = lan966x_fdma_rx_get_frame(rx);
481c8349639SHoratiu Vultur 
482c8349639SHoratiu Vultur 		rx->page[rx->dcb_index][rx->db_index] = NULL;
483c8349639SHoratiu Vultur 		rx->dcb_index++;
484c8349639SHoratiu Vultur 		rx->dcb_index &= FDMA_DCB_MAX - 1;
485c8349639SHoratiu Vultur 
486c8349639SHoratiu Vultur 		if (!skb)
487c8349639SHoratiu Vultur 			break;
488c8349639SHoratiu Vultur 
489c8349639SHoratiu Vultur 		napi_gro_receive(&lan966x->napi, skb);
490c8349639SHoratiu Vultur 		counter++;
491c8349639SHoratiu Vultur 	}
492c8349639SHoratiu Vultur 
493c8349639SHoratiu Vultur 	/* Allocate new pages and map them */
494c8349639SHoratiu Vultur 	while (dcb_reload != rx->dcb_index) {
495c8349639SHoratiu Vultur 		db = &rx->dcbs[dcb_reload].db[rx->db_index];
496c8349639SHoratiu Vultur 		page = lan966x_fdma_rx_alloc_page(rx, db);
497c8349639SHoratiu Vultur 		if (unlikely(!page))
498c8349639SHoratiu Vultur 			break;
499c8349639SHoratiu Vultur 		rx->page[dcb_reload][rx->db_index] = page;
500c8349639SHoratiu Vultur 
501c8349639SHoratiu Vultur 		old_dcb = &rx->dcbs[dcb_reload];
502c8349639SHoratiu Vultur 		dcb_reload++;
503c8349639SHoratiu Vultur 		dcb_reload &= FDMA_DCB_MAX - 1;
504c8349639SHoratiu Vultur 
505c8349639SHoratiu Vultur 		nextptr = rx->dma + ((unsigned long)old_dcb -
506c8349639SHoratiu Vultur 				     (unsigned long)rx->dcbs);
507c8349639SHoratiu Vultur 		lan966x_fdma_rx_add_dcb(rx, old_dcb, nextptr);
508c8349639SHoratiu Vultur 		lan966x_fdma_rx_reload(rx);
509c8349639SHoratiu Vultur 	}
510c8349639SHoratiu Vultur 
511c8349639SHoratiu Vultur 	if (counter < weight && napi_complete_done(napi, counter))
512c8349639SHoratiu Vultur 		lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA);
513c8349639SHoratiu Vultur 
514c8349639SHoratiu Vultur 	return counter;
515c8349639SHoratiu Vultur }
516c8349639SHoratiu Vultur 
517c8349639SHoratiu Vultur irqreturn_t lan966x_fdma_irq_handler(int irq, void *args)
518c8349639SHoratiu Vultur {
519c8349639SHoratiu Vultur 	struct lan966x *lan966x = args;
520c8349639SHoratiu Vultur 	u32 db, err, err_type;
521c8349639SHoratiu Vultur 
522c8349639SHoratiu Vultur 	db = lan_rd(lan966x, FDMA_INTR_DB);
523c8349639SHoratiu Vultur 	err = lan_rd(lan966x, FDMA_INTR_ERR);
524c8349639SHoratiu Vultur 
525c8349639SHoratiu Vultur 	if (db) {
526c8349639SHoratiu Vultur 		lan_wr(0, lan966x, FDMA_INTR_DB_ENA);
527c8349639SHoratiu Vultur 		lan_wr(db, lan966x, FDMA_INTR_DB);
528c8349639SHoratiu Vultur 
529c8349639SHoratiu Vultur 		napi_schedule(&lan966x->napi);
530c8349639SHoratiu Vultur 	}
531c8349639SHoratiu Vultur 
532c8349639SHoratiu Vultur 	if (err) {
533c8349639SHoratiu Vultur 		err_type = lan_rd(lan966x, FDMA_ERRORS);
534c8349639SHoratiu Vultur 
535c8349639SHoratiu Vultur 		WARN(1, "Unexpected error: %d, error_type: %d\n", err, err_type);
536c8349639SHoratiu Vultur 
537c8349639SHoratiu Vultur 		lan_wr(err, lan966x, FDMA_INTR_ERR);
538c8349639SHoratiu Vultur 		lan_wr(err_type, lan966x, FDMA_ERRORS);
539c8349639SHoratiu Vultur 	}
540c8349639SHoratiu Vultur 
541c8349639SHoratiu Vultur 	return IRQ_HANDLED;
542c8349639SHoratiu Vultur }
543c8349639SHoratiu Vultur 
544c8349639SHoratiu Vultur static int lan966x_fdma_get_next_dcb(struct lan966x_tx *tx)
545c8349639SHoratiu Vultur {
546c8349639SHoratiu Vultur 	struct lan966x_tx_dcb_buf *dcb_buf;
547c8349639SHoratiu Vultur 	int i;
548c8349639SHoratiu Vultur 
549c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
550c8349639SHoratiu Vultur 		dcb_buf = &tx->dcbs_buf[i];
551c8349639SHoratiu Vultur 		if (!dcb_buf->used && i != tx->last_in_use)
552c8349639SHoratiu Vultur 			return i;
553c8349639SHoratiu Vultur 	}
554c8349639SHoratiu Vultur 
555c8349639SHoratiu Vultur 	return -1;
556c8349639SHoratiu Vultur }
557c8349639SHoratiu Vultur 
558c8349639SHoratiu Vultur int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev)
559c8349639SHoratiu Vultur {
560c8349639SHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
561c8349639SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
562c8349639SHoratiu Vultur 	struct lan966x_tx_dcb_buf *next_dcb_buf;
563c8349639SHoratiu Vultur 	struct lan966x_tx_dcb *next_dcb, *dcb;
564c8349639SHoratiu Vultur 	struct lan966x_tx *tx = &lan966x->tx;
565c8349639SHoratiu Vultur 	struct lan966x_db *next_db;
566c8349639SHoratiu Vultur 	int needed_headroom;
567c8349639SHoratiu Vultur 	int needed_tailroom;
568c8349639SHoratiu Vultur 	dma_addr_t dma_addr;
569c8349639SHoratiu Vultur 	int next_to_use;
570c8349639SHoratiu Vultur 	int err;
571c8349639SHoratiu Vultur 
572c8349639SHoratiu Vultur 	/* Get next index */
573c8349639SHoratiu Vultur 	next_to_use = lan966x_fdma_get_next_dcb(tx);
574c8349639SHoratiu Vultur 	if (next_to_use < 0) {
575c8349639SHoratiu Vultur 		netif_stop_queue(dev);
576c8349639SHoratiu Vultur 		return NETDEV_TX_BUSY;
577c8349639SHoratiu Vultur 	}
578c8349639SHoratiu Vultur 
579c8349639SHoratiu Vultur 	if (skb_put_padto(skb, ETH_ZLEN)) {
580c8349639SHoratiu Vultur 		dev->stats.tx_dropped++;
581c8349639SHoratiu Vultur 		return NETDEV_TX_OK;
582c8349639SHoratiu Vultur 	}
583c8349639SHoratiu Vultur 
584c8349639SHoratiu Vultur 	/* skb processing */
585c8349639SHoratiu Vultur 	needed_headroom = max_t(int, IFH_LEN * sizeof(u32) - skb_headroom(skb), 0);
586c8349639SHoratiu Vultur 	needed_tailroom = max_t(int, ETH_FCS_LEN - skb_tailroom(skb), 0);
587c8349639SHoratiu Vultur 	if (needed_headroom || needed_tailroom || skb_header_cloned(skb)) {
588c8349639SHoratiu Vultur 		err = pskb_expand_head(skb, needed_headroom, needed_tailroom,
589c8349639SHoratiu Vultur 				       GFP_ATOMIC);
590c8349639SHoratiu Vultur 		if (unlikely(err)) {
591c8349639SHoratiu Vultur 			dev->stats.tx_dropped++;
592c8349639SHoratiu Vultur 			err = NETDEV_TX_OK;
593c8349639SHoratiu Vultur 			goto release;
594c8349639SHoratiu Vultur 		}
595c8349639SHoratiu Vultur 	}
596c8349639SHoratiu Vultur 
597c8349639SHoratiu Vultur 	skb_tx_timestamp(skb);
598c8349639SHoratiu Vultur 	skb_push(skb, IFH_LEN * sizeof(u32));
599c8349639SHoratiu Vultur 	memcpy(skb->data, ifh, IFH_LEN * sizeof(u32));
600c8349639SHoratiu Vultur 	skb_put(skb, 4);
601c8349639SHoratiu Vultur 
602c8349639SHoratiu Vultur 	dma_addr = dma_map_single(lan966x->dev, skb->data, skb->len,
603c8349639SHoratiu Vultur 				  DMA_TO_DEVICE);
604c8349639SHoratiu Vultur 	if (dma_mapping_error(lan966x->dev, dma_addr)) {
605c8349639SHoratiu Vultur 		dev->stats.tx_dropped++;
606c8349639SHoratiu Vultur 		err = NETDEV_TX_OK;
607c8349639SHoratiu Vultur 		goto release;
608c8349639SHoratiu Vultur 	}
609c8349639SHoratiu Vultur 
610c8349639SHoratiu Vultur 	/* Setup next dcb */
611c8349639SHoratiu Vultur 	next_dcb = &tx->dcbs[next_to_use];
612c8349639SHoratiu Vultur 	next_dcb->nextptr = FDMA_DCB_INVALID_DATA;
613c8349639SHoratiu Vultur 
614c8349639SHoratiu Vultur 	next_db = &next_dcb->db[0];
615c8349639SHoratiu Vultur 	next_db->dataptr = dma_addr;
616c8349639SHoratiu Vultur 	next_db->status = FDMA_DCB_STATUS_SOF |
617c8349639SHoratiu Vultur 			  FDMA_DCB_STATUS_EOF |
618c8349639SHoratiu Vultur 			  FDMA_DCB_STATUS_INTR |
619c8349639SHoratiu Vultur 			  FDMA_DCB_STATUS_BLOCKO(0) |
620c8349639SHoratiu Vultur 			  FDMA_DCB_STATUS_BLOCKL(skb->len);
621c8349639SHoratiu Vultur 
622c8349639SHoratiu Vultur 	/* Fill up the buffer */
623c8349639SHoratiu Vultur 	next_dcb_buf = &tx->dcbs_buf[next_to_use];
624c8349639SHoratiu Vultur 	next_dcb_buf->skb = skb;
625c8349639SHoratiu Vultur 	next_dcb_buf->dma_addr = dma_addr;
626c8349639SHoratiu Vultur 	next_dcb_buf->used = true;
627c8349639SHoratiu Vultur 	next_dcb_buf->ptp = false;
628c8349639SHoratiu Vultur 	next_dcb_buf->dev = dev;
629c8349639SHoratiu Vultur 
630c8349639SHoratiu Vultur 	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
631c8349639SHoratiu Vultur 	    LAN966X_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
632c8349639SHoratiu Vultur 		next_dcb_buf->ptp = true;
633c8349639SHoratiu Vultur 
634c8349639SHoratiu Vultur 	if (likely(lan966x->tx.activated)) {
635c8349639SHoratiu Vultur 		/* Connect current dcb to the next db */
636c8349639SHoratiu Vultur 		dcb = &tx->dcbs[tx->last_in_use];
637c8349639SHoratiu Vultur 		dcb->nextptr = tx->dma + (next_to_use *
638c8349639SHoratiu Vultur 					  sizeof(struct lan966x_tx_dcb));
639c8349639SHoratiu Vultur 
640c8349639SHoratiu Vultur 		lan966x_fdma_tx_reload(tx);
641c8349639SHoratiu Vultur 	} else {
642c8349639SHoratiu Vultur 		/* Because it is first time, then just activate */
643c8349639SHoratiu Vultur 		lan966x->tx.activated = true;
644c8349639SHoratiu Vultur 		lan966x_fdma_tx_activate(tx);
645c8349639SHoratiu Vultur 	}
646c8349639SHoratiu Vultur 
647c8349639SHoratiu Vultur 	/* Move to next dcb because this last in use */
648c8349639SHoratiu Vultur 	tx->last_in_use = next_to_use;
649c8349639SHoratiu Vultur 
650c8349639SHoratiu Vultur 	return NETDEV_TX_OK;
651c8349639SHoratiu Vultur 
652c8349639SHoratiu Vultur release:
653c8349639SHoratiu Vultur 	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
654c8349639SHoratiu Vultur 	    LAN966X_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
655c8349639SHoratiu Vultur 		lan966x_ptp_txtstamp_release(port, skb);
656c8349639SHoratiu Vultur 
657c8349639SHoratiu Vultur 	dev_kfree_skb_any(skb);
658c8349639SHoratiu Vultur 	return err;
659c8349639SHoratiu Vultur }
660c8349639SHoratiu Vultur 
661*2ea1cbacSHoratiu Vultur static int lan966x_fdma_get_max_mtu(struct lan966x *lan966x)
662*2ea1cbacSHoratiu Vultur {
663*2ea1cbacSHoratiu Vultur 	int max_mtu = 0;
664*2ea1cbacSHoratiu Vultur 	int i;
665*2ea1cbacSHoratiu Vultur 
666*2ea1cbacSHoratiu Vultur 	for (i = 0; i < lan966x->num_phys_ports; ++i) {
667*2ea1cbacSHoratiu Vultur 		int mtu;
668*2ea1cbacSHoratiu Vultur 
669*2ea1cbacSHoratiu Vultur 		if (!lan966x->ports[i])
670*2ea1cbacSHoratiu Vultur 			continue;
671*2ea1cbacSHoratiu Vultur 
672*2ea1cbacSHoratiu Vultur 		mtu = lan966x->ports[i]->dev->mtu;
673*2ea1cbacSHoratiu Vultur 		if (mtu > max_mtu)
674*2ea1cbacSHoratiu Vultur 			max_mtu = mtu;
675*2ea1cbacSHoratiu Vultur 	}
676*2ea1cbacSHoratiu Vultur 
677*2ea1cbacSHoratiu Vultur 	return max_mtu;
678*2ea1cbacSHoratiu Vultur }
679*2ea1cbacSHoratiu Vultur 
680*2ea1cbacSHoratiu Vultur static int lan966x_qsys_sw_status(struct lan966x *lan966x)
681*2ea1cbacSHoratiu Vultur {
682*2ea1cbacSHoratiu Vultur 	return lan_rd(lan966x, QSYS_SW_STATUS(CPU_PORT));
683*2ea1cbacSHoratiu Vultur }
684*2ea1cbacSHoratiu Vultur 
685*2ea1cbacSHoratiu Vultur static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
686*2ea1cbacSHoratiu Vultur {
687*2ea1cbacSHoratiu Vultur 	void *rx_dcbs, *tx_dcbs, *tx_dcbs_buf;
688*2ea1cbacSHoratiu Vultur 	dma_addr_t rx_dma, tx_dma;
689*2ea1cbacSHoratiu Vultur 	u32 size;
690*2ea1cbacSHoratiu Vultur 	int err;
691*2ea1cbacSHoratiu Vultur 
692*2ea1cbacSHoratiu Vultur 	/* Store these for later to free them */
693*2ea1cbacSHoratiu Vultur 	rx_dma = lan966x->rx.dma;
694*2ea1cbacSHoratiu Vultur 	tx_dma = lan966x->tx.dma;
695*2ea1cbacSHoratiu Vultur 	rx_dcbs = lan966x->rx.dcbs;
696*2ea1cbacSHoratiu Vultur 	tx_dcbs = lan966x->tx.dcbs;
697*2ea1cbacSHoratiu Vultur 	tx_dcbs_buf = lan966x->tx.dcbs_buf;
698*2ea1cbacSHoratiu Vultur 
699*2ea1cbacSHoratiu Vultur 	napi_synchronize(&lan966x->napi);
700*2ea1cbacSHoratiu Vultur 	napi_disable(&lan966x->napi);
701*2ea1cbacSHoratiu Vultur 	lan966x_fdma_stop_netdev(lan966x);
702*2ea1cbacSHoratiu Vultur 
703*2ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_disable(&lan966x->rx);
704*2ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_free_pages(&lan966x->rx);
705*2ea1cbacSHoratiu Vultur 	lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
706*2ea1cbacSHoratiu Vultur 	err = lan966x_fdma_rx_alloc(&lan966x->rx);
707*2ea1cbacSHoratiu Vultur 	if (err)
708*2ea1cbacSHoratiu Vultur 		goto restore;
709*2ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_start(&lan966x->rx);
710*2ea1cbacSHoratiu Vultur 
711*2ea1cbacSHoratiu Vultur 	size = sizeof(struct lan966x_rx_dcb) * FDMA_DCB_MAX;
712*2ea1cbacSHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
713*2ea1cbacSHoratiu Vultur 	dma_free_coherent(lan966x->dev, size, rx_dcbs, rx_dma);
714*2ea1cbacSHoratiu Vultur 
715*2ea1cbacSHoratiu Vultur 	lan966x_fdma_tx_disable(&lan966x->tx);
716*2ea1cbacSHoratiu Vultur 	err = lan966x_fdma_tx_alloc(&lan966x->tx);
717*2ea1cbacSHoratiu Vultur 	if (err)
718*2ea1cbacSHoratiu Vultur 		goto restore_tx;
719*2ea1cbacSHoratiu Vultur 
720*2ea1cbacSHoratiu Vultur 	size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX;
721*2ea1cbacSHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
722*2ea1cbacSHoratiu Vultur 	dma_free_coherent(lan966x->dev, size, tx_dcbs, tx_dma);
723*2ea1cbacSHoratiu Vultur 
724*2ea1cbacSHoratiu Vultur 	kfree(tx_dcbs_buf);
725*2ea1cbacSHoratiu Vultur 
726*2ea1cbacSHoratiu Vultur 	lan966x_fdma_wakeup_netdev(lan966x);
727*2ea1cbacSHoratiu Vultur 	napi_enable(&lan966x->napi);
728*2ea1cbacSHoratiu Vultur 
729*2ea1cbacSHoratiu Vultur 	return err;
730*2ea1cbacSHoratiu Vultur restore:
731*2ea1cbacSHoratiu Vultur 	lan966x->rx.dma = rx_dma;
732*2ea1cbacSHoratiu Vultur 	lan966x->tx.dma = tx_dma;
733*2ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_start(&lan966x->rx);
734*2ea1cbacSHoratiu Vultur 
735*2ea1cbacSHoratiu Vultur restore_tx:
736*2ea1cbacSHoratiu Vultur 	lan966x->rx.dcbs = rx_dcbs;
737*2ea1cbacSHoratiu Vultur 	lan966x->tx.dcbs = tx_dcbs;
738*2ea1cbacSHoratiu Vultur 	lan966x->tx.dcbs_buf = tx_dcbs_buf;
739*2ea1cbacSHoratiu Vultur 
740*2ea1cbacSHoratiu Vultur 	return err;
741*2ea1cbacSHoratiu Vultur }
742*2ea1cbacSHoratiu Vultur 
743*2ea1cbacSHoratiu Vultur int lan966x_fdma_change_mtu(struct lan966x *lan966x)
744*2ea1cbacSHoratiu Vultur {
745*2ea1cbacSHoratiu Vultur 	int max_mtu;
746*2ea1cbacSHoratiu Vultur 	int err;
747*2ea1cbacSHoratiu Vultur 	u32 val;
748*2ea1cbacSHoratiu Vultur 
749*2ea1cbacSHoratiu Vultur 	max_mtu = lan966x_fdma_get_max_mtu(lan966x);
750*2ea1cbacSHoratiu Vultur 	max_mtu += IFH_LEN * sizeof(u32);
751*2ea1cbacSHoratiu Vultur 
752*2ea1cbacSHoratiu Vultur 	if (round_up(max_mtu, PAGE_SIZE) / PAGE_SIZE - 1 ==
753*2ea1cbacSHoratiu Vultur 	    lan966x->rx.page_order)
754*2ea1cbacSHoratiu Vultur 		return 0;
755*2ea1cbacSHoratiu Vultur 
756*2ea1cbacSHoratiu Vultur 	/* Disable the CPU port */
757*2ea1cbacSHoratiu Vultur 	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(0),
758*2ea1cbacSHoratiu Vultur 		QSYS_SW_PORT_MODE_PORT_ENA,
759*2ea1cbacSHoratiu Vultur 		lan966x, QSYS_SW_PORT_MODE(CPU_PORT));
760*2ea1cbacSHoratiu Vultur 
761*2ea1cbacSHoratiu Vultur 	/* Flush the CPU queues */
762*2ea1cbacSHoratiu Vultur 	readx_poll_timeout(lan966x_qsys_sw_status, lan966x,
763*2ea1cbacSHoratiu Vultur 			   val, !(QSYS_SW_STATUS_EQ_AVAIL_GET(val)),
764*2ea1cbacSHoratiu Vultur 			   READL_SLEEP_US, READL_TIMEOUT_US);
765*2ea1cbacSHoratiu Vultur 
766*2ea1cbacSHoratiu Vultur 	/* Add a sleep in case there are frames between the queues and the CPU
767*2ea1cbacSHoratiu Vultur 	 * port
768*2ea1cbacSHoratiu Vultur 	 */
769*2ea1cbacSHoratiu Vultur 	usleep_range(1000, 2000);
770*2ea1cbacSHoratiu Vultur 
771*2ea1cbacSHoratiu Vultur 	err = lan966x_fdma_reload(lan966x, max_mtu);
772*2ea1cbacSHoratiu Vultur 
773*2ea1cbacSHoratiu Vultur 	/* Enable back the CPU port */
774*2ea1cbacSHoratiu Vultur 	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(1),
775*2ea1cbacSHoratiu Vultur 		QSYS_SW_PORT_MODE_PORT_ENA,
776*2ea1cbacSHoratiu Vultur 		lan966x,  QSYS_SW_PORT_MODE(CPU_PORT));
777*2ea1cbacSHoratiu Vultur 
778*2ea1cbacSHoratiu Vultur 	return err;
779*2ea1cbacSHoratiu Vultur }
780*2ea1cbacSHoratiu Vultur 
781c8349639SHoratiu Vultur void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev)
782c8349639SHoratiu Vultur {
783c8349639SHoratiu Vultur 	if (lan966x->fdma_ndev)
784c8349639SHoratiu Vultur 		return;
785c8349639SHoratiu Vultur 
786c8349639SHoratiu Vultur 	lan966x->fdma_ndev = dev;
787c8349639SHoratiu Vultur 	netif_napi_add(dev, &lan966x->napi, lan966x_fdma_napi_poll,
788c8349639SHoratiu Vultur 		       NAPI_POLL_WEIGHT);
789c8349639SHoratiu Vultur 	napi_enable(&lan966x->napi);
790c8349639SHoratiu Vultur }
791c8349639SHoratiu Vultur 
792c8349639SHoratiu Vultur void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev)
793c8349639SHoratiu Vultur {
794c8349639SHoratiu Vultur 	if (lan966x->fdma_ndev == dev) {
795c8349639SHoratiu Vultur 		netif_napi_del(&lan966x->napi);
796c8349639SHoratiu Vultur 		lan966x->fdma_ndev = NULL;
797c8349639SHoratiu Vultur 	}
798c8349639SHoratiu Vultur }
799c8349639SHoratiu Vultur 
800c8349639SHoratiu Vultur int lan966x_fdma_init(struct lan966x *lan966x)
801c8349639SHoratiu Vultur {
802c8349639SHoratiu Vultur 	int err;
803c8349639SHoratiu Vultur 
804c8349639SHoratiu Vultur 	if (!lan966x->fdma)
805c8349639SHoratiu Vultur 		return 0;
806c8349639SHoratiu Vultur 
807c8349639SHoratiu Vultur 	lan966x->rx.lan966x = lan966x;
808c8349639SHoratiu Vultur 	lan966x->rx.channel_id = FDMA_XTR_CHANNEL;
809c8349639SHoratiu Vultur 	lan966x->tx.lan966x = lan966x;
810c8349639SHoratiu Vultur 	lan966x->tx.channel_id = FDMA_INJ_CHANNEL;
811c8349639SHoratiu Vultur 	lan966x->tx.last_in_use = -1;
812c8349639SHoratiu Vultur 
813c8349639SHoratiu Vultur 	err = lan966x_fdma_rx_alloc(&lan966x->rx);
814c8349639SHoratiu Vultur 	if (err)
815c8349639SHoratiu Vultur 		return err;
816c8349639SHoratiu Vultur 
817c8349639SHoratiu Vultur 	err = lan966x_fdma_tx_alloc(&lan966x->tx);
818c8349639SHoratiu Vultur 	if (err) {
819c8349639SHoratiu Vultur 		lan966x_fdma_rx_free(&lan966x->rx);
820c8349639SHoratiu Vultur 		return err;
821c8349639SHoratiu Vultur 	}
822c8349639SHoratiu Vultur 
823c8349639SHoratiu Vultur 	lan966x_fdma_rx_start(&lan966x->rx);
824c8349639SHoratiu Vultur 
825c8349639SHoratiu Vultur 	return 0;
826c8349639SHoratiu Vultur }
827c8349639SHoratiu Vultur 
828c8349639SHoratiu Vultur void lan966x_fdma_deinit(struct lan966x *lan966x)
829c8349639SHoratiu Vultur {
830c8349639SHoratiu Vultur 	if (!lan966x->fdma)
831c8349639SHoratiu Vultur 		return;
832c8349639SHoratiu Vultur 
833c8349639SHoratiu Vultur 	lan966x_fdma_rx_disable(&lan966x->rx);
834c8349639SHoratiu Vultur 	lan966x_fdma_tx_disable(&lan966x->tx);
835c8349639SHoratiu Vultur 
836c8349639SHoratiu Vultur 	napi_synchronize(&lan966x->napi);
837c8349639SHoratiu Vultur 	napi_disable(&lan966x->napi);
838c8349639SHoratiu Vultur 
839c8349639SHoratiu Vultur 	lan966x_fdma_rx_free_pages(&lan966x->rx);
840c8349639SHoratiu Vultur 	lan966x_fdma_rx_free(&lan966x->rx);
841c8349639SHoratiu Vultur 	lan966x_fdma_tx_free(&lan966x->tx);
842c8349639SHoratiu Vultur }
843