1c8349639SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+
2c8349639SHoratiu Vultur 
37292bb06SHoratiu Vultur #include <linux/bpf.h>
4a825b611SHoratiu Vultur #include <linux/filter.h>
5*a9ca9f9cSYunsheng Lin #include <net/page_pool/helpers.h>
67292bb06SHoratiu Vultur 
7c8349639SHoratiu Vultur #include "lan966x_main.h"
8c8349639SHoratiu Vultur 
lan966x_fdma_channel_active(struct lan966x * lan966x)9c8349639SHoratiu Vultur static int lan966x_fdma_channel_active(struct lan966x *lan966x)
10c8349639SHoratiu Vultur {
11c8349639SHoratiu Vultur 	return lan_rd(lan966x, FDMA_CH_ACTIVE);
12c8349639SHoratiu Vultur }
13c8349639SHoratiu Vultur 
lan966x_fdma_rx_alloc_page(struct lan966x_rx * rx,struct lan966x_db * db)14c8349639SHoratiu Vultur static struct page *lan966x_fdma_rx_alloc_page(struct lan966x_rx *rx,
15c8349639SHoratiu Vultur 					       struct lan966x_db *db)
16c8349639SHoratiu Vultur {
17c8349639SHoratiu Vultur 	struct page *page;
18c8349639SHoratiu Vultur 
1911871abaSHoratiu Vultur 	page = page_pool_dev_alloc_pages(rx->page_pool);
20c8349639SHoratiu Vultur 	if (unlikely(!page))
21c8349639SHoratiu Vultur 		return NULL;
22c8349639SHoratiu Vultur 
237292bb06SHoratiu Vultur 	db->dataptr = page_pool_get_dma_addr(page) + XDP_PACKET_HEADROOM;
24c8349639SHoratiu Vultur 
25c8349639SHoratiu Vultur 	return page;
26c8349639SHoratiu Vultur }
27c8349639SHoratiu Vultur 
lan966x_fdma_rx_free_pages(struct lan966x_rx * rx)28c8349639SHoratiu Vultur static void lan966x_fdma_rx_free_pages(struct lan966x_rx *rx)
29c8349639SHoratiu Vultur {
30c8349639SHoratiu Vultur 	int i, j;
31c8349639SHoratiu Vultur 
32c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
3311871abaSHoratiu Vultur 		for (j = 0; j < FDMA_RX_DCB_MAX_DBS; ++j)
3411871abaSHoratiu Vultur 			page_pool_put_full_page(rx->page_pool,
3511871abaSHoratiu Vultur 						rx->page[i][j], false);
36c8349639SHoratiu Vultur 	}
37c8349639SHoratiu Vultur }
38c8349639SHoratiu Vultur 
lan966x_fdma_rx_free_page(struct lan966x_rx * rx)394a00b0c7SHoratiu Vultur static void lan966x_fdma_rx_free_page(struct lan966x_rx *rx)
404a00b0c7SHoratiu Vultur {
414a00b0c7SHoratiu Vultur 	struct page *page;
424a00b0c7SHoratiu Vultur 
434a00b0c7SHoratiu Vultur 	page = rx->page[rx->dcb_index][rx->db_index];
444a00b0c7SHoratiu Vultur 	if (unlikely(!page))
454a00b0c7SHoratiu Vultur 		return;
464a00b0c7SHoratiu Vultur 
4711871abaSHoratiu Vultur 	page_pool_recycle_direct(rx->page_pool, page);
484a00b0c7SHoratiu Vultur }
494a00b0c7SHoratiu Vultur 
lan966x_fdma_rx_add_dcb(struct lan966x_rx * rx,struct lan966x_rx_dcb * dcb,u64 nextptr)50c8349639SHoratiu Vultur static void lan966x_fdma_rx_add_dcb(struct lan966x_rx *rx,
51c8349639SHoratiu Vultur 				    struct lan966x_rx_dcb *dcb,
52c8349639SHoratiu Vultur 				    u64 nextptr)
53c8349639SHoratiu Vultur {
54c8349639SHoratiu Vultur 	struct lan966x_db *db;
55c8349639SHoratiu Vultur 	int i;
56c8349639SHoratiu Vultur 
57c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_RX_DCB_MAX_DBS; ++i) {
58c8349639SHoratiu Vultur 		db = &dcb->db[i];
59c8349639SHoratiu Vultur 		db->status = FDMA_DCB_STATUS_INTR;
60c8349639SHoratiu Vultur 	}
61c8349639SHoratiu Vultur 
62c8349639SHoratiu Vultur 	dcb->nextptr = FDMA_DCB_INVALID_DATA;
63c8349639SHoratiu Vultur 	dcb->info = FDMA_DCB_INFO_DATAL(PAGE_SIZE << rx->page_order);
64c8349639SHoratiu Vultur 
65c8349639SHoratiu Vultur 	rx->last_entry->nextptr = nextptr;
66c8349639SHoratiu Vultur 	rx->last_entry = dcb;
67c8349639SHoratiu Vultur }
68c8349639SHoratiu Vultur 
lan966x_fdma_rx_alloc_page_pool(struct lan966x_rx * rx)6911871abaSHoratiu Vultur static int lan966x_fdma_rx_alloc_page_pool(struct lan966x_rx *rx)
7011871abaSHoratiu Vultur {
7111871abaSHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
7211871abaSHoratiu Vultur 	struct page_pool_params pp_params = {
7311871abaSHoratiu Vultur 		.order = rx->page_order,
7411871abaSHoratiu Vultur 		.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
7511871abaSHoratiu Vultur 		.pool_size = FDMA_DCB_MAX,
7611871abaSHoratiu Vultur 		.nid = NUMA_NO_NODE,
7711871abaSHoratiu Vultur 		.dev = lan966x->dev,
7811871abaSHoratiu Vultur 		.dma_dir = DMA_FROM_DEVICE,
797292bb06SHoratiu Vultur 		.offset = XDP_PACKET_HEADROOM,
8011871abaSHoratiu Vultur 		.max_len = rx->max_mtu -
8111871abaSHoratiu Vultur 			   SKB_DATA_ALIGN(sizeof(struct skb_shared_info)),
8211871abaSHoratiu Vultur 	};
8311871abaSHoratiu Vultur 
84560c7223SHoratiu Vultur 	if (lan966x_xdp_present(lan966x))
85560c7223SHoratiu Vultur 		pp_params.dma_dir = DMA_BIDIRECTIONAL;
86560c7223SHoratiu Vultur 
8711871abaSHoratiu Vultur 	rx->page_pool = page_pool_create(&pp_params);
8877ddda44SHoratiu Vultur 
8977ddda44SHoratiu Vultur 	for (int i = 0; i < lan966x->num_phys_ports; ++i) {
9077ddda44SHoratiu Vultur 		struct lan966x_port *port;
9177ddda44SHoratiu Vultur 
9277ddda44SHoratiu Vultur 		if (!lan966x->ports[i])
9377ddda44SHoratiu Vultur 			continue;
9477ddda44SHoratiu Vultur 
9577ddda44SHoratiu Vultur 		port = lan966x->ports[i];
9677ddda44SHoratiu Vultur 		xdp_rxq_info_unreg_mem_model(&port->xdp_rxq);
9777ddda44SHoratiu Vultur 		xdp_rxq_info_reg_mem_model(&port->xdp_rxq, MEM_TYPE_PAGE_POOL,
9877ddda44SHoratiu Vultur 					   rx->page_pool);
9977ddda44SHoratiu Vultur 	}
10077ddda44SHoratiu Vultur 
10111871abaSHoratiu Vultur 	return PTR_ERR_OR_ZERO(rx->page_pool);
10211871abaSHoratiu Vultur }
10311871abaSHoratiu Vultur 
lan966x_fdma_rx_alloc(struct lan966x_rx * rx)104c8349639SHoratiu Vultur static int lan966x_fdma_rx_alloc(struct lan966x_rx *rx)
105c8349639SHoratiu Vultur {
106c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
107c8349639SHoratiu Vultur 	struct lan966x_rx_dcb *dcb;
108c8349639SHoratiu Vultur 	struct lan966x_db *db;
109c8349639SHoratiu Vultur 	struct page *page;
110c8349639SHoratiu Vultur 	int i, j;
111c8349639SHoratiu Vultur 	int size;
112c8349639SHoratiu Vultur 
11311871abaSHoratiu Vultur 	if (lan966x_fdma_rx_alloc_page_pool(rx))
11411871abaSHoratiu Vultur 		return PTR_ERR(rx->page_pool);
11511871abaSHoratiu Vultur 
116c8349639SHoratiu Vultur 	/* calculate how many pages are needed to allocate the dcbs */
117c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_rx_dcb) * FDMA_DCB_MAX;
118c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
119c8349639SHoratiu Vultur 
120c8349639SHoratiu Vultur 	rx->dcbs = dma_alloc_coherent(lan966x->dev, size, &rx->dma, GFP_KERNEL);
121c8349639SHoratiu Vultur 	if (!rx->dcbs)
122c8349639SHoratiu Vultur 		return -ENOMEM;
123c8349639SHoratiu Vultur 
124c8349639SHoratiu Vultur 	rx->last_entry = rx->dcbs;
125c8349639SHoratiu Vultur 	rx->db_index = 0;
126c8349639SHoratiu Vultur 	rx->dcb_index = 0;
127c8349639SHoratiu Vultur 
128c8349639SHoratiu Vultur 	/* Now for each dcb allocate the dbs */
129c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
130c8349639SHoratiu Vultur 		dcb = &rx->dcbs[i];
131c8349639SHoratiu Vultur 		dcb->info = 0;
132c8349639SHoratiu Vultur 
133c8349639SHoratiu Vultur 		/* For each db allocate a page and map it to the DB dataptr. */
134c8349639SHoratiu Vultur 		for (j = 0; j < FDMA_RX_DCB_MAX_DBS; ++j) {
135c8349639SHoratiu Vultur 			db = &dcb->db[j];
136c8349639SHoratiu Vultur 			page = lan966x_fdma_rx_alloc_page(rx, db);
137c8349639SHoratiu Vultur 			if (!page)
138c8349639SHoratiu Vultur 				return -ENOMEM;
139c8349639SHoratiu Vultur 
140c8349639SHoratiu Vultur 			db->status = 0;
141c8349639SHoratiu Vultur 			rx->page[i][j] = page;
142c8349639SHoratiu Vultur 		}
143c8349639SHoratiu Vultur 
144c8349639SHoratiu Vultur 		lan966x_fdma_rx_add_dcb(rx, dcb, rx->dma + sizeof(*dcb) * i);
145c8349639SHoratiu Vultur 	}
146c8349639SHoratiu Vultur 
147c8349639SHoratiu Vultur 	return 0;
148c8349639SHoratiu Vultur }
149c8349639SHoratiu Vultur 
lan966x_fdma_rx_advance_dcb(struct lan966x_rx * rx)1504a00b0c7SHoratiu Vultur static void lan966x_fdma_rx_advance_dcb(struct lan966x_rx *rx)
1514a00b0c7SHoratiu Vultur {
1524a00b0c7SHoratiu Vultur 	rx->dcb_index++;
1534a00b0c7SHoratiu Vultur 	rx->dcb_index &= FDMA_DCB_MAX - 1;
1544a00b0c7SHoratiu Vultur }
1554a00b0c7SHoratiu Vultur 
lan966x_fdma_rx_free(struct lan966x_rx * rx)156c8349639SHoratiu Vultur static void lan966x_fdma_rx_free(struct lan966x_rx *rx)
157c8349639SHoratiu Vultur {
158c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
159c8349639SHoratiu Vultur 	u32 size;
160c8349639SHoratiu Vultur 
161c8349639SHoratiu Vultur 	/* Now it is possible to do the cleanup of dcb */
162c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX;
163c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
164c8349639SHoratiu Vultur 	dma_free_coherent(lan966x->dev, size, rx->dcbs, rx->dma);
165c8349639SHoratiu Vultur }
166c8349639SHoratiu Vultur 
lan966x_fdma_rx_start(struct lan966x_rx * rx)167c8349639SHoratiu Vultur static void lan966x_fdma_rx_start(struct lan966x_rx *rx)
168c8349639SHoratiu Vultur {
169c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
170c8349639SHoratiu Vultur 	u32 mask;
171c8349639SHoratiu Vultur 
172c8349639SHoratiu Vultur 	/* When activating a channel, first is required to write the first DCB
173c8349639SHoratiu Vultur 	 * address and then to activate it
174c8349639SHoratiu Vultur 	 */
175c8349639SHoratiu Vultur 	lan_wr(lower_32_bits((u64)rx->dma), lan966x,
176c8349639SHoratiu Vultur 	       FDMA_DCB_LLP(rx->channel_id));
177c8349639SHoratiu Vultur 	lan_wr(upper_32_bits((u64)rx->dma), lan966x,
178c8349639SHoratiu Vultur 	       FDMA_DCB_LLP1(rx->channel_id));
179c8349639SHoratiu Vultur 
180c8349639SHoratiu Vultur 	lan_wr(FDMA_CH_CFG_CH_DCB_DB_CNT_SET(FDMA_RX_DCB_MAX_DBS) |
181c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(1) |
182c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INJ_PORT_SET(0) |
183c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_MEM_SET(1),
184c8349639SHoratiu Vultur 	       lan966x, FDMA_CH_CFG(rx->channel_id));
185c8349639SHoratiu Vultur 
186c8349639SHoratiu Vultur 	/* Start fdma */
187c8349639SHoratiu Vultur 	lan_rmw(FDMA_PORT_CTRL_XTR_STOP_SET(0),
188c8349639SHoratiu Vultur 		FDMA_PORT_CTRL_XTR_STOP,
189c8349639SHoratiu Vultur 		lan966x, FDMA_PORT_CTRL(0));
190c8349639SHoratiu Vultur 
191c8349639SHoratiu Vultur 	/* Enable interrupts */
192c8349639SHoratiu Vultur 	mask = lan_rd(lan966x, FDMA_INTR_DB_ENA);
193c8349639SHoratiu Vultur 	mask = FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(mask);
194c8349639SHoratiu Vultur 	mask |= BIT(rx->channel_id);
195c8349639SHoratiu Vultur 	lan_rmw(FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(mask),
196c8349639SHoratiu Vultur 		FDMA_INTR_DB_ENA_INTR_DB_ENA,
197c8349639SHoratiu Vultur 		lan966x, FDMA_INTR_DB_ENA);
198c8349639SHoratiu Vultur 
199c8349639SHoratiu Vultur 	/* Activate the channel */
200c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(BIT(rx->channel_id)),
201c8349639SHoratiu Vultur 		FDMA_CH_ACTIVATE_CH_ACTIVATE,
202c8349639SHoratiu Vultur 		lan966x, FDMA_CH_ACTIVATE);
203c8349639SHoratiu Vultur }
204c8349639SHoratiu Vultur 
lan966x_fdma_rx_disable(struct lan966x_rx * rx)205c8349639SHoratiu Vultur static void lan966x_fdma_rx_disable(struct lan966x_rx *rx)
206c8349639SHoratiu Vultur {
207c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
208c8349639SHoratiu Vultur 	u32 val;
209c8349639SHoratiu Vultur 
210c8349639SHoratiu Vultur 	/* Disable the channel */
211c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DISABLE_CH_DISABLE_SET(BIT(rx->channel_id)),
212c8349639SHoratiu Vultur 		FDMA_CH_DISABLE_CH_DISABLE,
213c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DISABLE);
214c8349639SHoratiu Vultur 
215c8349639SHoratiu Vultur 	readx_poll_timeout_atomic(lan966x_fdma_channel_active, lan966x,
216c8349639SHoratiu Vultur 				  val, !(val & BIT(rx->channel_id)),
217c8349639SHoratiu Vultur 				  READL_SLEEP_US, READL_TIMEOUT_US);
218c8349639SHoratiu Vultur 
219c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DB_DISCARD_DB_DISCARD_SET(BIT(rx->channel_id)),
220c8349639SHoratiu Vultur 		FDMA_CH_DB_DISCARD_DB_DISCARD,
221c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DB_DISCARD);
222c8349639SHoratiu Vultur }
223c8349639SHoratiu Vultur 
lan966x_fdma_rx_reload(struct lan966x_rx * rx)224c8349639SHoratiu Vultur static void lan966x_fdma_rx_reload(struct lan966x_rx *rx)
225c8349639SHoratiu Vultur {
226c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
227c8349639SHoratiu Vultur 
228c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_RELOAD_CH_RELOAD_SET(BIT(rx->channel_id)),
229c8349639SHoratiu Vultur 		FDMA_CH_RELOAD_CH_RELOAD,
230c8349639SHoratiu Vultur 		lan966x, FDMA_CH_RELOAD);
231c8349639SHoratiu Vultur }
232c8349639SHoratiu Vultur 
lan966x_fdma_tx_add_dcb(struct lan966x_tx * tx,struct lan966x_tx_dcb * dcb)233c8349639SHoratiu Vultur static void lan966x_fdma_tx_add_dcb(struct lan966x_tx *tx,
234c8349639SHoratiu Vultur 				    struct lan966x_tx_dcb *dcb)
235c8349639SHoratiu Vultur {
236c8349639SHoratiu Vultur 	dcb->nextptr = FDMA_DCB_INVALID_DATA;
237c8349639SHoratiu Vultur 	dcb->info = 0;
238c8349639SHoratiu Vultur }
239c8349639SHoratiu Vultur 
lan966x_fdma_tx_alloc(struct lan966x_tx * tx)240c8349639SHoratiu Vultur static int lan966x_fdma_tx_alloc(struct lan966x_tx *tx)
241c8349639SHoratiu Vultur {
242c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
243c8349639SHoratiu Vultur 	struct lan966x_tx_dcb *dcb;
244c8349639SHoratiu Vultur 	struct lan966x_db *db;
245c8349639SHoratiu Vultur 	int size;
246c8349639SHoratiu Vultur 	int i, j;
247c8349639SHoratiu Vultur 
248c8349639SHoratiu Vultur 	tx->dcbs_buf = kcalloc(FDMA_DCB_MAX, sizeof(struct lan966x_tx_dcb_buf),
249c8349639SHoratiu Vultur 			       GFP_KERNEL);
250c8349639SHoratiu Vultur 	if (!tx->dcbs_buf)
251c8349639SHoratiu Vultur 		return -ENOMEM;
252c8349639SHoratiu Vultur 
253c8349639SHoratiu Vultur 	/* calculate how many pages are needed to allocate the dcbs */
254c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX;
255c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
256c8349639SHoratiu Vultur 	tx->dcbs = dma_alloc_coherent(lan966x->dev, size, &tx->dma, GFP_KERNEL);
257c8349639SHoratiu Vultur 	if (!tx->dcbs)
258c8349639SHoratiu Vultur 		goto out;
259c8349639SHoratiu Vultur 
260c8349639SHoratiu Vultur 	/* Now for each dcb allocate the db */
261c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
262c8349639SHoratiu Vultur 		dcb = &tx->dcbs[i];
263c8349639SHoratiu Vultur 
264c8349639SHoratiu Vultur 		for (j = 0; j < FDMA_TX_DCB_MAX_DBS; ++j) {
265c8349639SHoratiu Vultur 			db = &dcb->db[j];
266c8349639SHoratiu Vultur 			db->dataptr = 0;
267c8349639SHoratiu Vultur 			db->status = 0;
268c8349639SHoratiu Vultur 		}
269c8349639SHoratiu Vultur 
270c8349639SHoratiu Vultur 		lan966x_fdma_tx_add_dcb(tx, dcb);
271c8349639SHoratiu Vultur 	}
272c8349639SHoratiu Vultur 
273c8349639SHoratiu Vultur 	return 0;
274c8349639SHoratiu Vultur 
275c8349639SHoratiu Vultur out:
276c8349639SHoratiu Vultur 	kfree(tx->dcbs_buf);
277c8349639SHoratiu Vultur 	return -ENOMEM;
278c8349639SHoratiu Vultur }
279c8349639SHoratiu Vultur 
lan966x_fdma_tx_free(struct lan966x_tx * tx)280c8349639SHoratiu Vultur static void lan966x_fdma_tx_free(struct lan966x_tx *tx)
281c8349639SHoratiu Vultur {
282c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
283c8349639SHoratiu Vultur 	int size;
284c8349639SHoratiu Vultur 
285c8349639SHoratiu Vultur 	kfree(tx->dcbs_buf);
286c8349639SHoratiu Vultur 
287c8349639SHoratiu Vultur 	size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX;
288c8349639SHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
289c8349639SHoratiu Vultur 	dma_free_coherent(lan966x->dev, size, tx->dcbs, tx->dma);
290c8349639SHoratiu Vultur }
291c8349639SHoratiu Vultur 
lan966x_fdma_tx_activate(struct lan966x_tx * tx)292c8349639SHoratiu Vultur static void lan966x_fdma_tx_activate(struct lan966x_tx *tx)
293c8349639SHoratiu Vultur {
294c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
295c8349639SHoratiu Vultur 	u32 mask;
296c8349639SHoratiu Vultur 
297c8349639SHoratiu Vultur 	/* When activating a channel, first is required to write the first DCB
298c8349639SHoratiu Vultur 	 * address and then to activate it
299c8349639SHoratiu Vultur 	 */
300c8349639SHoratiu Vultur 	lan_wr(lower_32_bits((u64)tx->dma), lan966x,
301c8349639SHoratiu Vultur 	       FDMA_DCB_LLP(tx->channel_id));
302c8349639SHoratiu Vultur 	lan_wr(upper_32_bits((u64)tx->dma), lan966x,
303c8349639SHoratiu Vultur 	       FDMA_DCB_LLP1(tx->channel_id));
304c8349639SHoratiu Vultur 
305c8349639SHoratiu Vultur 	lan_wr(FDMA_CH_CFG_CH_DCB_DB_CNT_SET(FDMA_TX_DCB_MAX_DBS) |
306c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(1) |
307c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_INJ_PORT_SET(0) |
308c8349639SHoratiu Vultur 	       FDMA_CH_CFG_CH_MEM_SET(1),
309c8349639SHoratiu Vultur 	       lan966x, FDMA_CH_CFG(tx->channel_id));
310c8349639SHoratiu Vultur 
311c8349639SHoratiu Vultur 	/* Start fdma */
312c8349639SHoratiu Vultur 	lan_rmw(FDMA_PORT_CTRL_INJ_STOP_SET(0),
313c8349639SHoratiu Vultur 		FDMA_PORT_CTRL_INJ_STOP,
314c8349639SHoratiu Vultur 		lan966x, FDMA_PORT_CTRL(0));
315c8349639SHoratiu Vultur 
316c8349639SHoratiu Vultur 	/* Enable interrupts */
317c8349639SHoratiu Vultur 	mask = lan_rd(lan966x, FDMA_INTR_DB_ENA);
318c8349639SHoratiu Vultur 	mask = FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(mask);
319c8349639SHoratiu Vultur 	mask |= BIT(tx->channel_id);
320c8349639SHoratiu Vultur 	lan_rmw(FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(mask),
321c8349639SHoratiu Vultur 		FDMA_INTR_DB_ENA_INTR_DB_ENA,
322c8349639SHoratiu Vultur 		lan966x, FDMA_INTR_DB_ENA);
323c8349639SHoratiu Vultur 
324c8349639SHoratiu Vultur 	/* Activate the channel */
325c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(BIT(tx->channel_id)),
326c8349639SHoratiu Vultur 		FDMA_CH_ACTIVATE_CH_ACTIVATE,
327c8349639SHoratiu Vultur 		lan966x, FDMA_CH_ACTIVATE);
328c8349639SHoratiu Vultur }
329c8349639SHoratiu Vultur 
lan966x_fdma_tx_disable(struct lan966x_tx * tx)330c8349639SHoratiu Vultur static void lan966x_fdma_tx_disable(struct lan966x_tx *tx)
331c8349639SHoratiu Vultur {
332c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
333c8349639SHoratiu Vultur 	u32 val;
334c8349639SHoratiu Vultur 
335c8349639SHoratiu Vultur 	/* Disable the channel */
336c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DISABLE_CH_DISABLE_SET(BIT(tx->channel_id)),
337c8349639SHoratiu Vultur 		FDMA_CH_DISABLE_CH_DISABLE,
338c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DISABLE);
339c8349639SHoratiu Vultur 
340c8349639SHoratiu Vultur 	readx_poll_timeout_atomic(lan966x_fdma_channel_active, lan966x,
341c8349639SHoratiu Vultur 				  val, !(val & BIT(tx->channel_id)),
342c8349639SHoratiu Vultur 				  READL_SLEEP_US, READL_TIMEOUT_US);
343c8349639SHoratiu Vultur 
344c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_DB_DISCARD_DB_DISCARD_SET(BIT(tx->channel_id)),
345c8349639SHoratiu Vultur 		FDMA_CH_DB_DISCARD_DB_DISCARD,
346c8349639SHoratiu Vultur 		lan966x, FDMA_CH_DB_DISCARD);
347c8349639SHoratiu Vultur 
348c8349639SHoratiu Vultur 	tx->activated = false;
3494a4b6848SHoratiu Vultur 	tx->last_in_use = -1;
350c8349639SHoratiu Vultur }
351c8349639SHoratiu Vultur 
lan966x_fdma_tx_reload(struct lan966x_tx * tx)352c8349639SHoratiu Vultur static void lan966x_fdma_tx_reload(struct lan966x_tx *tx)
353c8349639SHoratiu Vultur {
354c8349639SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
355c8349639SHoratiu Vultur 
356c8349639SHoratiu Vultur 	/* Write the registers to reload the channel */
357c8349639SHoratiu Vultur 	lan_rmw(FDMA_CH_RELOAD_CH_RELOAD_SET(BIT(tx->channel_id)),
358c8349639SHoratiu Vultur 		FDMA_CH_RELOAD_CH_RELOAD,
359c8349639SHoratiu Vultur 		lan966x, FDMA_CH_RELOAD);
360c8349639SHoratiu Vultur }
361c8349639SHoratiu Vultur 
lan966x_fdma_wakeup_netdev(struct lan966x * lan966x)362c8349639SHoratiu Vultur static void lan966x_fdma_wakeup_netdev(struct lan966x *lan966x)
363c8349639SHoratiu Vultur {
364c8349639SHoratiu Vultur 	struct lan966x_port *port;
365c8349639SHoratiu Vultur 	int i;
366c8349639SHoratiu Vultur 
367c8349639SHoratiu Vultur 	for (i = 0; i < lan966x->num_phys_ports; ++i) {
368c8349639SHoratiu Vultur 		port = lan966x->ports[i];
369c8349639SHoratiu Vultur 		if (!port)
370c8349639SHoratiu Vultur 			continue;
371c8349639SHoratiu Vultur 
372c8349639SHoratiu Vultur 		if (netif_queue_stopped(port->dev))
373c8349639SHoratiu Vultur 			netif_wake_queue(port->dev);
374c8349639SHoratiu Vultur 	}
375c8349639SHoratiu Vultur }
376c8349639SHoratiu Vultur 
lan966x_fdma_stop_netdev(struct lan966x * lan966x)3772ea1cbacSHoratiu Vultur static void lan966x_fdma_stop_netdev(struct lan966x *lan966x)
3782ea1cbacSHoratiu Vultur {
3792ea1cbacSHoratiu Vultur 	struct lan966x_port *port;
3802ea1cbacSHoratiu Vultur 	int i;
3812ea1cbacSHoratiu Vultur 
3822ea1cbacSHoratiu Vultur 	for (i = 0; i < lan966x->num_phys_ports; ++i) {
3832ea1cbacSHoratiu Vultur 		port = lan966x->ports[i];
3842ea1cbacSHoratiu Vultur 		if (!port)
3852ea1cbacSHoratiu Vultur 			continue;
3862ea1cbacSHoratiu Vultur 
3872ea1cbacSHoratiu Vultur 		netif_stop_queue(port->dev);
3882ea1cbacSHoratiu Vultur 	}
3892ea1cbacSHoratiu Vultur }
3902ea1cbacSHoratiu Vultur 
lan966x_fdma_tx_clear_buf(struct lan966x * lan966x,int weight)391c8349639SHoratiu Vultur static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
392c8349639SHoratiu Vultur {
393c8349639SHoratiu Vultur 	struct lan966x_tx *tx = &lan966x->tx;
394700f11ebSHoratiu Vultur 	struct lan966x_rx *rx = &lan966x->rx;
395c8349639SHoratiu Vultur 	struct lan966x_tx_dcb_buf *dcb_buf;
396a825b611SHoratiu Vultur 	struct xdp_frame_bulk bq;
397c8349639SHoratiu Vultur 	struct lan966x_db *db;
398c8349639SHoratiu Vultur 	unsigned long flags;
399c8349639SHoratiu Vultur 	bool clear = false;
400c8349639SHoratiu Vultur 	int i;
401c8349639SHoratiu Vultur 
402a825b611SHoratiu Vultur 	xdp_frame_bulk_init(&bq);
403a825b611SHoratiu Vultur 
404c8349639SHoratiu Vultur 	spin_lock_irqsave(&lan966x->tx_lock, flags);
405c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
406c8349639SHoratiu Vultur 		dcb_buf = &tx->dcbs_buf[i];
407c8349639SHoratiu Vultur 
408c8349639SHoratiu Vultur 		if (!dcb_buf->used)
409c8349639SHoratiu Vultur 			continue;
410c8349639SHoratiu Vultur 
411c8349639SHoratiu Vultur 		db = &tx->dcbs[i].db[0];
412c8349639SHoratiu Vultur 		if (!(db->status & FDMA_DCB_STATUS_DONE))
413c8349639SHoratiu Vultur 			continue;
414c8349639SHoratiu Vultur 
415c8349639SHoratiu Vultur 		dcb_buf->dev->stats.tx_packets++;
41649f5eea8SHoratiu Vultur 		dcb_buf->dev->stats.tx_bytes += dcb_buf->len;
417c8349639SHoratiu Vultur 
418c8349639SHoratiu Vultur 		dcb_buf->used = false;
41919c6f534SHoratiu Vultur 		if (dcb_buf->use_skb) {
420c8349639SHoratiu Vultur 			dma_unmap_single(lan966x->dev,
421c8349639SHoratiu Vultur 					 dcb_buf->dma_addr,
42249f5eea8SHoratiu Vultur 					 dcb_buf->len,
423c8349639SHoratiu Vultur 					 DMA_TO_DEVICE);
42419c6f534SHoratiu Vultur 
425c8349639SHoratiu Vultur 			if (!dcb_buf->ptp)
42619c6f534SHoratiu Vultur 				napi_consume_skb(dcb_buf->data.skb, weight);
42719c6f534SHoratiu Vultur 		} else {
428a825b611SHoratiu Vultur 			if (dcb_buf->xdp_ndo)
429a825b611SHoratiu Vultur 				dma_unmap_single(lan966x->dev,
430a825b611SHoratiu Vultur 						 dcb_buf->dma_addr,
431a825b611SHoratiu Vultur 						 dcb_buf->len,
432a825b611SHoratiu Vultur 						 DMA_TO_DEVICE);
433a825b611SHoratiu Vultur 
434a825b611SHoratiu Vultur 			if (dcb_buf->xdp_ndo)
435a825b611SHoratiu Vultur 				xdp_return_frame_bulk(dcb_buf->data.xdpf, &bq);
436a825b611SHoratiu Vultur 			else
437700f11ebSHoratiu Vultur 				page_pool_recycle_direct(rx->page_pool,
438700f11ebSHoratiu Vultur 							 dcb_buf->data.page);
43919c6f534SHoratiu Vultur 		}
440c8349639SHoratiu Vultur 
441c8349639SHoratiu Vultur 		clear = true;
442c8349639SHoratiu Vultur 	}
443c8349639SHoratiu Vultur 
444a825b611SHoratiu Vultur 	xdp_flush_frame_bulk(&bq);
445a825b611SHoratiu Vultur 
446c8349639SHoratiu Vultur 	if (clear)
447c8349639SHoratiu Vultur 		lan966x_fdma_wakeup_netdev(lan966x);
448c8349639SHoratiu Vultur 
449c8349639SHoratiu Vultur 	spin_unlock_irqrestore(&lan966x->tx_lock, flags);
450c8349639SHoratiu Vultur }
451c8349639SHoratiu Vultur 
lan966x_fdma_rx_more_frames(struct lan966x_rx * rx)452c8349639SHoratiu Vultur static bool lan966x_fdma_rx_more_frames(struct lan966x_rx *rx)
453c8349639SHoratiu Vultur {
454c8349639SHoratiu Vultur 	struct lan966x_db *db;
455c8349639SHoratiu Vultur 
456c8349639SHoratiu Vultur 	/* Check if there is any data */
457c8349639SHoratiu Vultur 	db = &rx->dcbs[rx->dcb_index].db[rx->db_index];
458c8349639SHoratiu Vultur 	if (unlikely(!(db->status & FDMA_DCB_STATUS_DONE)))
459c8349639SHoratiu Vultur 		return false;
460c8349639SHoratiu Vultur 
461c8349639SHoratiu Vultur 	return true;
462c8349639SHoratiu Vultur }
463c8349639SHoratiu Vultur 
lan966x_fdma_rx_check_frame(struct lan966x_rx * rx,u64 * src_port)4644a00b0c7SHoratiu Vultur static int lan966x_fdma_rx_check_frame(struct lan966x_rx *rx, u64 *src_port)
465c8349639SHoratiu Vultur {
466c8349639SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
4676a2159beSHoratiu Vultur 	struct lan966x_port *port;
468c8349639SHoratiu Vultur 	struct lan966x_db *db;
469c8349639SHoratiu Vultur 	struct page *page;
470c8349639SHoratiu Vultur 
471c8349639SHoratiu Vultur 	db = &rx->dcbs[rx->dcb_index].db[rx->db_index];
472c8349639SHoratiu Vultur 	page = rx->page[rx->dcb_index][rx->db_index];
4734a00b0c7SHoratiu Vultur 	if (unlikely(!page))
4744a00b0c7SHoratiu Vultur 		return FDMA_ERROR;
475fc57062fSHoratiu Vultur 
4767292bb06SHoratiu Vultur 	dma_sync_single_for_cpu(lan966x->dev,
4777292bb06SHoratiu Vultur 				(dma_addr_t)db->dataptr + XDP_PACKET_HEADROOM,
478fc57062fSHoratiu Vultur 				FDMA_DCB_STATUS_BLOCKL(db->status),
479fc57062fSHoratiu Vultur 				DMA_FROM_DEVICE);
480fc57062fSHoratiu Vultur 
4817292bb06SHoratiu Vultur 	lan966x_ifh_get_src_port(page_address(page) + XDP_PACKET_HEADROOM,
4827292bb06SHoratiu Vultur 				 src_port);
4834a00b0c7SHoratiu Vultur 	if (WARN_ON(*src_port >= lan966x->num_phys_ports))
4844a00b0c7SHoratiu Vultur 		return FDMA_ERROR;
4854a00b0c7SHoratiu Vultur 
4866a2159beSHoratiu Vultur 	port = lan966x->ports[*src_port];
4876a2159beSHoratiu Vultur 	if (!lan966x_xdp_port_present(port))
4884a00b0c7SHoratiu Vultur 		return FDMA_PASS;
4896a2159beSHoratiu Vultur 
4906a2159beSHoratiu Vultur 	return lan966x_xdp_run(port, page, FDMA_DCB_STATUS_BLOCKL(db->status));
4914a00b0c7SHoratiu Vultur }
4924a00b0c7SHoratiu Vultur 
lan966x_fdma_rx_get_frame(struct lan966x_rx * rx,u64 src_port)4934a00b0c7SHoratiu Vultur static struct sk_buff *lan966x_fdma_rx_get_frame(struct lan966x_rx *rx,
4944a00b0c7SHoratiu Vultur 						 u64 src_port)
4954a00b0c7SHoratiu Vultur {
4964a00b0c7SHoratiu Vultur 	struct lan966x *lan966x = rx->lan966x;
4974a00b0c7SHoratiu Vultur 	struct lan966x_db *db;
4984a00b0c7SHoratiu Vultur 	struct sk_buff *skb;
4994a00b0c7SHoratiu Vultur 	struct page *page;
5004a00b0c7SHoratiu Vultur 	u64 timestamp;
5014a00b0c7SHoratiu Vultur 
5024a00b0c7SHoratiu Vultur 	/* Get the received frame and unmap it */
5034a00b0c7SHoratiu Vultur 	db = &rx->dcbs[rx->dcb_index].db[rx->db_index];
5044a00b0c7SHoratiu Vultur 	page = rx->page[rx->dcb_index][rx->db_index];
5054a00b0c7SHoratiu Vultur 
5064a00b0c7SHoratiu Vultur 	skb = build_skb(page_address(page), PAGE_SIZE << rx->page_order);
5074a00b0c7SHoratiu Vultur 	if (unlikely(!skb))
5084a00b0c7SHoratiu Vultur 		goto free_page;
5094a00b0c7SHoratiu Vultur 
51011871abaSHoratiu Vultur 	skb_mark_for_recycle(skb);
51111871abaSHoratiu Vultur 
5127292bb06SHoratiu Vultur 	skb_reserve(skb, XDP_PACKET_HEADROOM);
5134a00b0c7SHoratiu Vultur 	skb_put(skb, FDMA_DCB_STATUS_BLOCKL(db->status));
5144a00b0c7SHoratiu Vultur 
5154a00b0c7SHoratiu Vultur 	lan966x_ifh_get_timestamp(skb->data, &timestamp);
5164a00b0c7SHoratiu Vultur 
517c8349639SHoratiu Vultur 	skb->dev = lan966x->ports[src_port]->dev;
518e83163b6SHoratiu Vultur 	skb_pull(skb, IFH_LEN_BYTES);
519c8349639SHoratiu Vultur 
520c8349639SHoratiu Vultur 	if (likely(!(skb->dev->features & NETIF_F_RXFCS)))
521c8349639SHoratiu Vultur 		skb_trim(skb, skb->len - ETH_FCS_LEN);
522c8349639SHoratiu Vultur 
523ff89ac70SHoratiu Vultur 	lan966x_ptp_rxtstamp(lan966x, skb, src_port, timestamp);
524c8349639SHoratiu Vultur 	skb->protocol = eth_type_trans(skb, skb->dev);
525c8349639SHoratiu Vultur 
526c8349639SHoratiu Vultur 	if (lan966x->bridge_mask & BIT(src_port)) {
527c8349639SHoratiu Vultur 		skb->offload_fwd_mark = 1;
528c8349639SHoratiu Vultur 
529c8349639SHoratiu Vultur 		skb_reset_network_header(skb);
530c8349639SHoratiu Vultur 		if (!lan966x_hw_offload(lan966x, src_port, skb))
531c8349639SHoratiu Vultur 			skb->offload_fwd_mark = 0;
532c8349639SHoratiu Vultur 	}
533c8349639SHoratiu Vultur 
534c8349639SHoratiu Vultur 	skb->dev->stats.rx_bytes += skb->len;
535c8349639SHoratiu Vultur 	skb->dev->stats.rx_packets++;
536c8349639SHoratiu Vultur 
537c8349639SHoratiu Vultur 	return skb;
538c8349639SHoratiu Vultur 
5394a00b0c7SHoratiu Vultur free_page:
54011871abaSHoratiu Vultur 	page_pool_recycle_direct(rx->page_pool, page);
541c8349639SHoratiu Vultur 
542c8349639SHoratiu Vultur 	return NULL;
543c8349639SHoratiu Vultur }
544c8349639SHoratiu Vultur 
lan966x_fdma_napi_poll(struct napi_struct * napi,int weight)545c8349639SHoratiu Vultur static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight)
546c8349639SHoratiu Vultur {
547c8349639SHoratiu Vultur 	struct lan966x *lan966x = container_of(napi, struct lan966x, napi);
548c8349639SHoratiu Vultur 	struct lan966x_rx *rx = &lan966x->rx;
549c8349639SHoratiu Vultur 	int dcb_reload = rx->dcb_index;
550c8349639SHoratiu Vultur 	struct lan966x_rx_dcb *old_dcb;
551c8349639SHoratiu Vultur 	struct lan966x_db *db;
552a825b611SHoratiu Vultur 	bool redirect = false;
553c8349639SHoratiu Vultur 	struct sk_buff *skb;
554c8349639SHoratiu Vultur 	struct page *page;
555c8349639SHoratiu Vultur 	int counter = 0;
5564a00b0c7SHoratiu Vultur 	u64 src_port;
557c8349639SHoratiu Vultur 	u64 nextptr;
558c8349639SHoratiu Vultur 
559c8349639SHoratiu Vultur 	lan966x_fdma_tx_clear_buf(lan966x, weight);
560c8349639SHoratiu Vultur 
561c8349639SHoratiu Vultur 	/* Get all received skb */
562c8349639SHoratiu Vultur 	while (counter < weight) {
563c8349639SHoratiu Vultur 		if (!lan966x_fdma_rx_more_frames(rx))
564c8349639SHoratiu Vultur 			break;
565c8349639SHoratiu Vultur 
566c8349639SHoratiu Vultur 		counter++;
5674a00b0c7SHoratiu Vultur 
5684a00b0c7SHoratiu Vultur 		switch (lan966x_fdma_rx_check_frame(rx, &src_port)) {
5694a00b0c7SHoratiu Vultur 		case FDMA_PASS:
5704a00b0c7SHoratiu Vultur 			break;
5714a00b0c7SHoratiu Vultur 		case FDMA_ERROR:
5724a00b0c7SHoratiu Vultur 			lan966x_fdma_rx_free_page(rx);
5734a00b0c7SHoratiu Vultur 			lan966x_fdma_rx_advance_dcb(rx);
5744a00b0c7SHoratiu Vultur 			goto allocate_new;
575a825b611SHoratiu Vultur 		case FDMA_REDIRECT:
576a825b611SHoratiu Vultur 			redirect = true;
577a825b611SHoratiu Vultur 			fallthrough;
57819c6f534SHoratiu Vultur 		case FDMA_TX:
57919c6f534SHoratiu Vultur 			lan966x_fdma_rx_advance_dcb(rx);
58019c6f534SHoratiu Vultur 			continue;
5816a2159beSHoratiu Vultur 		case FDMA_DROP:
5826a2159beSHoratiu Vultur 			lan966x_fdma_rx_free_page(rx);
5836a2159beSHoratiu Vultur 			lan966x_fdma_rx_advance_dcb(rx);
5846a2159beSHoratiu Vultur 			continue;
585c8349639SHoratiu Vultur 		}
586c8349639SHoratiu Vultur 
5874a00b0c7SHoratiu Vultur 		skb = lan966x_fdma_rx_get_frame(rx, src_port);
5884a00b0c7SHoratiu Vultur 		lan966x_fdma_rx_advance_dcb(rx);
5894a00b0c7SHoratiu Vultur 		if (!skb)
5904a00b0c7SHoratiu Vultur 			goto allocate_new;
5914a00b0c7SHoratiu Vultur 
5924a00b0c7SHoratiu Vultur 		napi_gro_receive(&lan966x->napi, skb);
5934a00b0c7SHoratiu Vultur 	}
5944a00b0c7SHoratiu Vultur 
5954a00b0c7SHoratiu Vultur allocate_new:
596c8349639SHoratiu Vultur 	/* Allocate new pages and map them */
597c8349639SHoratiu Vultur 	while (dcb_reload != rx->dcb_index) {
598c8349639SHoratiu Vultur 		db = &rx->dcbs[dcb_reload].db[rx->db_index];
599c8349639SHoratiu Vultur 		page = lan966x_fdma_rx_alloc_page(rx, db);
600c8349639SHoratiu Vultur 		if (unlikely(!page))
601c8349639SHoratiu Vultur 			break;
602c8349639SHoratiu Vultur 		rx->page[dcb_reload][rx->db_index] = page;
603c8349639SHoratiu Vultur 
604c8349639SHoratiu Vultur 		old_dcb = &rx->dcbs[dcb_reload];
605c8349639SHoratiu Vultur 		dcb_reload++;
606c8349639SHoratiu Vultur 		dcb_reload &= FDMA_DCB_MAX - 1;
607c8349639SHoratiu Vultur 
608c8349639SHoratiu Vultur 		nextptr = rx->dma + ((unsigned long)old_dcb -
609c8349639SHoratiu Vultur 				     (unsigned long)rx->dcbs);
610c8349639SHoratiu Vultur 		lan966x_fdma_rx_add_dcb(rx, old_dcb, nextptr);
611c8349639SHoratiu Vultur 		lan966x_fdma_rx_reload(rx);
612c8349639SHoratiu Vultur 	}
613c8349639SHoratiu Vultur 
614a825b611SHoratiu Vultur 	if (redirect)
615a825b611SHoratiu Vultur 		xdp_do_flush();
616a825b611SHoratiu Vultur 
61712b57179SMagnus Karlsson 	if (counter < weight && napi_complete_done(napi, counter))
61812b57179SMagnus Karlsson 		lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA);
61912b57179SMagnus Karlsson 
620c8349639SHoratiu Vultur 	return counter;
621c8349639SHoratiu Vultur }
622c8349639SHoratiu Vultur 
lan966x_fdma_irq_handler(int irq,void * args)623c8349639SHoratiu Vultur irqreturn_t lan966x_fdma_irq_handler(int irq, void *args)
624c8349639SHoratiu Vultur {
625c8349639SHoratiu Vultur 	struct lan966x *lan966x = args;
626c8349639SHoratiu Vultur 	u32 db, err, err_type;
627c8349639SHoratiu Vultur 
628c8349639SHoratiu Vultur 	db = lan_rd(lan966x, FDMA_INTR_DB);
629c8349639SHoratiu Vultur 	err = lan_rd(lan966x, FDMA_INTR_ERR);
630c8349639SHoratiu Vultur 
631c8349639SHoratiu Vultur 	if (db) {
632c8349639SHoratiu Vultur 		lan_wr(0, lan966x, FDMA_INTR_DB_ENA);
633c8349639SHoratiu Vultur 		lan_wr(db, lan966x, FDMA_INTR_DB);
634c8349639SHoratiu Vultur 
635c8349639SHoratiu Vultur 		napi_schedule(&lan966x->napi);
636c8349639SHoratiu Vultur 	}
637c8349639SHoratiu Vultur 
638c8349639SHoratiu Vultur 	if (err) {
639c8349639SHoratiu Vultur 		err_type = lan_rd(lan966x, FDMA_ERRORS);
640c8349639SHoratiu Vultur 
641c8349639SHoratiu Vultur 		WARN(1, "Unexpected error: %d, error_type: %d\n", err, err_type);
642c8349639SHoratiu Vultur 
643c8349639SHoratiu Vultur 		lan_wr(err, lan966x, FDMA_INTR_ERR);
644c8349639SHoratiu Vultur 		lan_wr(err_type, lan966x, FDMA_ERRORS);
645c8349639SHoratiu Vultur 	}
646c8349639SHoratiu Vultur 
647c8349639SHoratiu Vultur 	return IRQ_HANDLED;
648c8349639SHoratiu Vultur }
649c8349639SHoratiu Vultur 
lan966x_fdma_get_next_dcb(struct lan966x_tx * tx)650c8349639SHoratiu Vultur static int lan966x_fdma_get_next_dcb(struct lan966x_tx *tx)
651c8349639SHoratiu Vultur {
652c8349639SHoratiu Vultur 	struct lan966x_tx_dcb_buf *dcb_buf;
653c8349639SHoratiu Vultur 	int i;
654c8349639SHoratiu Vultur 
655c8349639SHoratiu Vultur 	for (i = 0; i < FDMA_DCB_MAX; ++i) {
656c8349639SHoratiu Vultur 		dcb_buf = &tx->dcbs_buf[i];
657c8349639SHoratiu Vultur 		if (!dcb_buf->used && i != tx->last_in_use)
658c8349639SHoratiu Vultur 			return i;
659c8349639SHoratiu Vultur 	}
660c8349639SHoratiu Vultur 
661c8349639SHoratiu Vultur 	return -1;
662c8349639SHoratiu Vultur }
663c8349639SHoratiu Vultur 
lan966x_fdma_tx_setup_dcb(struct lan966x_tx * tx,int next_to_use,int len,dma_addr_t dma_addr)6643d66bc57SHoratiu Vultur static void lan966x_fdma_tx_setup_dcb(struct lan966x_tx *tx,
6653d66bc57SHoratiu Vultur 				      int next_to_use, int len,
6663d66bc57SHoratiu Vultur 				      dma_addr_t dma_addr)
6673d66bc57SHoratiu Vultur {
6683d66bc57SHoratiu Vultur 	struct lan966x_tx_dcb *next_dcb;
6693d66bc57SHoratiu Vultur 	struct lan966x_db *next_db;
6703d66bc57SHoratiu Vultur 
6713d66bc57SHoratiu Vultur 	next_dcb = &tx->dcbs[next_to_use];
6723d66bc57SHoratiu Vultur 	next_dcb->nextptr = FDMA_DCB_INVALID_DATA;
6733d66bc57SHoratiu Vultur 
6743d66bc57SHoratiu Vultur 	next_db = &next_dcb->db[0];
6753d66bc57SHoratiu Vultur 	next_db->dataptr = dma_addr;
6763d66bc57SHoratiu Vultur 	next_db->status = FDMA_DCB_STATUS_SOF |
6773d66bc57SHoratiu Vultur 			  FDMA_DCB_STATUS_EOF |
6783d66bc57SHoratiu Vultur 			  FDMA_DCB_STATUS_INTR |
6793d66bc57SHoratiu Vultur 			  FDMA_DCB_STATUS_BLOCKO(0) |
6803d66bc57SHoratiu Vultur 			  FDMA_DCB_STATUS_BLOCKL(len);
6813d66bc57SHoratiu Vultur }
6823d66bc57SHoratiu Vultur 
lan966x_fdma_tx_start(struct lan966x_tx * tx,int next_to_use)6833d66bc57SHoratiu Vultur static void lan966x_fdma_tx_start(struct lan966x_tx *tx, int next_to_use)
6843d66bc57SHoratiu Vultur {
6853d66bc57SHoratiu Vultur 	struct lan966x *lan966x = tx->lan966x;
6863d66bc57SHoratiu Vultur 	struct lan966x_tx_dcb *dcb;
6873d66bc57SHoratiu Vultur 
6883d66bc57SHoratiu Vultur 	if (likely(lan966x->tx.activated)) {
6893d66bc57SHoratiu Vultur 		/* Connect current dcb to the next db */
6903d66bc57SHoratiu Vultur 		dcb = &tx->dcbs[tx->last_in_use];
6913d66bc57SHoratiu Vultur 		dcb->nextptr = tx->dma + (next_to_use *
6923d66bc57SHoratiu Vultur 					  sizeof(struct lan966x_tx_dcb));
6933d66bc57SHoratiu Vultur 
6943d66bc57SHoratiu Vultur 		lan966x_fdma_tx_reload(tx);
6953d66bc57SHoratiu Vultur 	} else {
6963d66bc57SHoratiu Vultur 		/* Because it is first time, then just activate */
6973d66bc57SHoratiu Vultur 		lan966x->tx.activated = true;
6983d66bc57SHoratiu Vultur 		lan966x_fdma_tx_activate(tx);
6993d66bc57SHoratiu Vultur 	}
7003d66bc57SHoratiu Vultur 
7013d66bc57SHoratiu Vultur 	/* Move to next dcb because this last in use */
7023d66bc57SHoratiu Vultur 	tx->last_in_use = next_to_use;
7033d66bc57SHoratiu Vultur }
7043d66bc57SHoratiu Vultur 
lan966x_fdma_xmit_xdpf(struct lan966x_port * port,void * ptr,u32 len)705700f11ebSHoratiu Vultur int lan966x_fdma_xmit_xdpf(struct lan966x_port *port, void *ptr, u32 len)
70619c6f534SHoratiu Vultur {
70719c6f534SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
70819c6f534SHoratiu Vultur 	struct lan966x_tx_dcb_buf *next_dcb_buf;
70919c6f534SHoratiu Vultur 	struct lan966x_tx *tx = &lan966x->tx;
710700f11ebSHoratiu Vultur 	struct xdp_frame *xdpf;
71119c6f534SHoratiu Vultur 	dma_addr_t dma_addr;
712700f11ebSHoratiu Vultur 	struct page *page;
71319c6f534SHoratiu Vultur 	int next_to_use;
71419c6f534SHoratiu Vultur 	__be32 *ifh;
71519c6f534SHoratiu Vultur 	int ret = 0;
71619c6f534SHoratiu Vultur 
71719c6f534SHoratiu Vultur 	spin_lock(&lan966x->tx_lock);
71819c6f534SHoratiu Vultur 
71919c6f534SHoratiu Vultur 	/* Get next index */
72019c6f534SHoratiu Vultur 	next_to_use = lan966x_fdma_get_next_dcb(tx);
72119c6f534SHoratiu Vultur 	if (next_to_use < 0) {
72219c6f534SHoratiu Vultur 		netif_stop_queue(port->dev);
72319c6f534SHoratiu Vultur 		ret = NETDEV_TX_BUSY;
72419c6f534SHoratiu Vultur 		goto out;
72519c6f534SHoratiu Vultur 	}
72619c6f534SHoratiu Vultur 
727700f11ebSHoratiu Vultur 	/* Get the next buffer */
728700f11ebSHoratiu Vultur 	next_dcb_buf = &tx->dcbs_buf[next_to_use];
729700f11ebSHoratiu Vultur 
73019c6f534SHoratiu Vultur 	/* Generate new IFH */
731700f11ebSHoratiu Vultur 	if (!len) {
732700f11ebSHoratiu Vultur 		xdpf = ptr;
733700f11ebSHoratiu Vultur 
734a825b611SHoratiu Vultur 		if (xdpf->headroom < IFH_LEN_BYTES) {
735a825b611SHoratiu Vultur 			ret = NETDEV_TX_OK;
736a825b611SHoratiu Vultur 			goto out;
737a825b611SHoratiu Vultur 		}
738a825b611SHoratiu Vultur 
739a825b611SHoratiu Vultur 		ifh = xdpf->data - IFH_LEN_BYTES;
740a825b611SHoratiu Vultur 		memset(ifh, 0x0, sizeof(__be32) * IFH_LEN);
741a825b611SHoratiu Vultur 		lan966x_ifh_set_bypass(ifh, 1);
742a825b611SHoratiu Vultur 		lan966x_ifh_set_port(ifh, BIT_ULL(port->chip_port));
743a825b611SHoratiu Vultur 
744a825b611SHoratiu Vultur 		dma_addr = dma_map_single(lan966x->dev,
745a825b611SHoratiu Vultur 					  xdpf->data - IFH_LEN_BYTES,
746a825b611SHoratiu Vultur 					  xdpf->len + IFH_LEN_BYTES,
747a825b611SHoratiu Vultur 					  DMA_TO_DEVICE);
748a825b611SHoratiu Vultur 		if (dma_mapping_error(lan966x->dev, dma_addr)) {
749a825b611SHoratiu Vultur 			ret = NETDEV_TX_OK;
750a825b611SHoratiu Vultur 			goto out;
751a825b611SHoratiu Vultur 		}
752a825b611SHoratiu Vultur 
753700f11ebSHoratiu Vultur 		next_dcb_buf->data.xdpf = xdpf;
754700f11ebSHoratiu Vultur 		next_dcb_buf->len = xdpf->len + IFH_LEN_BYTES;
755700f11ebSHoratiu Vultur 
756a825b611SHoratiu Vultur 		/* Setup next dcb */
757a825b611SHoratiu Vultur 		lan966x_fdma_tx_setup_dcb(tx, next_to_use,
758a825b611SHoratiu Vultur 					  xdpf->len + IFH_LEN_BYTES,
759a825b611SHoratiu Vultur 					  dma_addr);
760a825b611SHoratiu Vultur 	} else {
761700f11ebSHoratiu Vultur 		page = ptr;
762700f11ebSHoratiu Vultur 
76319c6f534SHoratiu Vultur 		ifh = page_address(page) + XDP_PACKET_HEADROOM;
76419c6f534SHoratiu Vultur 		memset(ifh, 0x0, sizeof(__be32) * IFH_LEN);
76519c6f534SHoratiu Vultur 		lan966x_ifh_set_bypass(ifh, 1);
76619c6f534SHoratiu Vultur 		lan966x_ifh_set_port(ifh, BIT_ULL(port->chip_port));
76719c6f534SHoratiu Vultur 
76819c6f534SHoratiu Vultur 		dma_addr = page_pool_get_dma_addr(page);
769a825b611SHoratiu Vultur 		dma_sync_single_for_device(lan966x->dev,
770a825b611SHoratiu Vultur 					   dma_addr + XDP_PACKET_HEADROOM,
771700f11ebSHoratiu Vultur 					   len + IFH_LEN_BYTES,
77219c6f534SHoratiu Vultur 					   DMA_TO_DEVICE);
77319c6f534SHoratiu Vultur 
774700f11ebSHoratiu Vultur 		next_dcb_buf->data.page = page;
775700f11ebSHoratiu Vultur 		next_dcb_buf->len = len + IFH_LEN_BYTES;
776700f11ebSHoratiu Vultur 
77719c6f534SHoratiu Vultur 		/* Setup next dcb */
778a825b611SHoratiu Vultur 		lan966x_fdma_tx_setup_dcb(tx, next_to_use,
779700f11ebSHoratiu Vultur 					  len + IFH_LEN_BYTES,
78019c6f534SHoratiu Vultur 					  dma_addr + XDP_PACKET_HEADROOM);
781a825b611SHoratiu Vultur 	}
78219c6f534SHoratiu Vultur 
78319c6f534SHoratiu Vultur 	/* Fill up the buffer */
78419c6f534SHoratiu Vultur 	next_dcb_buf->use_skb = false;
785700f11ebSHoratiu Vultur 	next_dcb_buf->xdp_ndo = !len;
78619c6f534SHoratiu Vultur 	next_dcb_buf->dma_addr = dma_addr;
78719c6f534SHoratiu Vultur 	next_dcb_buf->used = true;
78819c6f534SHoratiu Vultur 	next_dcb_buf->ptp = false;
78919c6f534SHoratiu Vultur 	next_dcb_buf->dev = port->dev;
79019c6f534SHoratiu Vultur 
79119c6f534SHoratiu Vultur 	/* Start the transmission */
79219c6f534SHoratiu Vultur 	lan966x_fdma_tx_start(tx, next_to_use);
79319c6f534SHoratiu Vultur 
79419c6f534SHoratiu Vultur out:
79519c6f534SHoratiu Vultur 	spin_unlock(&lan966x->tx_lock);
79619c6f534SHoratiu Vultur 
79719c6f534SHoratiu Vultur 	return ret;
79819c6f534SHoratiu Vultur }
79919c6f534SHoratiu Vultur 
lan966x_fdma_xmit(struct sk_buff * skb,__be32 * ifh,struct net_device * dev)800c8349639SHoratiu Vultur int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev)
801c8349639SHoratiu Vultur {
802c8349639SHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
803c8349639SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
804c8349639SHoratiu Vultur 	struct lan966x_tx_dcb_buf *next_dcb_buf;
805c8349639SHoratiu Vultur 	struct lan966x_tx *tx = &lan966x->tx;
806c8349639SHoratiu Vultur 	int needed_headroom;
807c8349639SHoratiu Vultur 	int needed_tailroom;
808c8349639SHoratiu Vultur 	dma_addr_t dma_addr;
809c8349639SHoratiu Vultur 	int next_to_use;
810c8349639SHoratiu Vultur 	int err;
811c8349639SHoratiu Vultur 
812c8349639SHoratiu Vultur 	/* Get next index */
813c8349639SHoratiu Vultur 	next_to_use = lan966x_fdma_get_next_dcb(tx);
814c8349639SHoratiu Vultur 	if (next_to_use < 0) {
815c8349639SHoratiu Vultur 		netif_stop_queue(dev);
816c8349639SHoratiu Vultur 		return NETDEV_TX_BUSY;
817c8349639SHoratiu Vultur 	}
818c8349639SHoratiu Vultur 
819c8349639SHoratiu Vultur 	if (skb_put_padto(skb, ETH_ZLEN)) {
820c8349639SHoratiu Vultur 		dev->stats.tx_dropped++;
821c8349639SHoratiu Vultur 		return NETDEV_TX_OK;
822c8349639SHoratiu Vultur 	}
823c8349639SHoratiu Vultur 
824c8349639SHoratiu Vultur 	/* skb processing */
825e83163b6SHoratiu Vultur 	needed_headroom = max_t(int, IFH_LEN_BYTES - skb_headroom(skb), 0);
826c8349639SHoratiu Vultur 	needed_tailroom = max_t(int, ETH_FCS_LEN - skb_tailroom(skb), 0);
827c8349639SHoratiu Vultur 	if (needed_headroom || needed_tailroom || skb_header_cloned(skb)) {
828c8349639SHoratiu Vultur 		err = pskb_expand_head(skb, needed_headroom, needed_tailroom,
829c8349639SHoratiu Vultur 				       GFP_ATOMIC);
830c8349639SHoratiu Vultur 		if (unlikely(err)) {
831c8349639SHoratiu Vultur 			dev->stats.tx_dropped++;
832c8349639SHoratiu Vultur 			err = NETDEV_TX_OK;
833c8349639SHoratiu Vultur 			goto release;
834c8349639SHoratiu Vultur 		}
835c8349639SHoratiu Vultur 	}
836c8349639SHoratiu Vultur 
837c8349639SHoratiu Vultur 	skb_tx_timestamp(skb);
838e83163b6SHoratiu Vultur 	skb_push(skb, IFH_LEN_BYTES);
839e83163b6SHoratiu Vultur 	memcpy(skb->data, ifh, IFH_LEN_BYTES);
840c8349639SHoratiu Vultur 	skb_put(skb, 4);
841c8349639SHoratiu Vultur 
842c8349639SHoratiu Vultur 	dma_addr = dma_map_single(lan966x->dev, skb->data, skb->len,
843c8349639SHoratiu Vultur 				  DMA_TO_DEVICE);
844c8349639SHoratiu Vultur 	if (dma_mapping_error(lan966x->dev, dma_addr)) {
845c8349639SHoratiu Vultur 		dev->stats.tx_dropped++;
846c8349639SHoratiu Vultur 		err = NETDEV_TX_OK;
847c8349639SHoratiu Vultur 		goto release;
848c8349639SHoratiu Vultur 	}
849c8349639SHoratiu Vultur 
850c8349639SHoratiu Vultur 	/* Setup next dcb */
8513d66bc57SHoratiu Vultur 	lan966x_fdma_tx_setup_dcb(tx, next_to_use, skb->len, dma_addr);
852c8349639SHoratiu Vultur 
853c8349639SHoratiu Vultur 	/* Fill up the buffer */
854c8349639SHoratiu Vultur 	next_dcb_buf = &tx->dcbs_buf[next_to_use];
85519c6f534SHoratiu Vultur 	next_dcb_buf->use_skb = true;
85619c6f534SHoratiu Vultur 	next_dcb_buf->data.skb = skb;
857a825b611SHoratiu Vultur 	next_dcb_buf->xdp_ndo = false;
85849f5eea8SHoratiu Vultur 	next_dcb_buf->len = skb->len;
859c8349639SHoratiu Vultur 	next_dcb_buf->dma_addr = dma_addr;
860c8349639SHoratiu Vultur 	next_dcb_buf->used = true;
861c8349639SHoratiu Vultur 	next_dcb_buf->ptp = false;
862c8349639SHoratiu Vultur 	next_dcb_buf->dev = dev;
863c8349639SHoratiu Vultur 
864c8349639SHoratiu Vultur 	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
865c8349639SHoratiu Vultur 	    LAN966X_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
866c8349639SHoratiu Vultur 		next_dcb_buf->ptp = true;
867c8349639SHoratiu Vultur 
8683d66bc57SHoratiu Vultur 	/* Start the transmission */
8693d66bc57SHoratiu Vultur 	lan966x_fdma_tx_start(tx, next_to_use);
870c8349639SHoratiu Vultur 
871c8349639SHoratiu Vultur 	return NETDEV_TX_OK;
872c8349639SHoratiu Vultur 
873c8349639SHoratiu Vultur release:
874c8349639SHoratiu Vultur 	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
875c8349639SHoratiu Vultur 	    LAN966X_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
876c8349639SHoratiu Vultur 		lan966x_ptp_txtstamp_release(port, skb);
877c8349639SHoratiu Vultur 
878c8349639SHoratiu Vultur 	dev_kfree_skb_any(skb);
879c8349639SHoratiu Vultur 	return err;
880c8349639SHoratiu Vultur }
881c8349639SHoratiu Vultur 
lan966x_fdma_get_max_mtu(struct lan966x * lan966x)8822ea1cbacSHoratiu Vultur static int lan966x_fdma_get_max_mtu(struct lan966x *lan966x)
8832ea1cbacSHoratiu Vultur {
8842ea1cbacSHoratiu Vultur 	int max_mtu = 0;
8852ea1cbacSHoratiu Vultur 	int i;
8862ea1cbacSHoratiu Vultur 
8872ea1cbacSHoratiu Vultur 	for (i = 0; i < lan966x->num_phys_ports; ++i) {
888872ad758SHoratiu Vultur 		struct lan966x_port *port;
8892ea1cbacSHoratiu Vultur 		int mtu;
8902ea1cbacSHoratiu Vultur 
891872ad758SHoratiu Vultur 		port = lan966x->ports[i];
892872ad758SHoratiu Vultur 		if (!port)
8932ea1cbacSHoratiu Vultur 			continue;
8942ea1cbacSHoratiu Vultur 
895872ad758SHoratiu Vultur 		mtu = lan_rd(lan966x, DEV_MAC_MAXLEN_CFG(port->chip_port));
8962ea1cbacSHoratiu Vultur 		if (mtu > max_mtu)
8972ea1cbacSHoratiu Vultur 			max_mtu = mtu;
8982ea1cbacSHoratiu Vultur 	}
8992ea1cbacSHoratiu Vultur 
9002ea1cbacSHoratiu Vultur 	return max_mtu;
9012ea1cbacSHoratiu Vultur }
9022ea1cbacSHoratiu Vultur 
lan966x_qsys_sw_status(struct lan966x * lan966x)9032ea1cbacSHoratiu Vultur static int lan966x_qsys_sw_status(struct lan966x *lan966x)
9042ea1cbacSHoratiu Vultur {
9052ea1cbacSHoratiu Vultur 	return lan_rd(lan966x, QSYS_SW_STATUS(CPU_PORT));
9062ea1cbacSHoratiu Vultur }
9072ea1cbacSHoratiu Vultur 
lan966x_fdma_reload(struct lan966x * lan966x,int new_mtu)9082ea1cbacSHoratiu Vultur static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
9092ea1cbacSHoratiu Vultur {
91011871abaSHoratiu Vultur 	struct page_pool *page_pool;
9114a4b6848SHoratiu Vultur 	dma_addr_t rx_dma;
9124a4b6848SHoratiu Vultur 	void *rx_dcbs;
9132ea1cbacSHoratiu Vultur 	u32 size;
9142ea1cbacSHoratiu Vultur 	int err;
9152ea1cbacSHoratiu Vultur 
9162ea1cbacSHoratiu Vultur 	/* Store these for later to free them */
9172ea1cbacSHoratiu Vultur 	rx_dma = lan966x->rx.dma;
9182ea1cbacSHoratiu Vultur 	rx_dcbs = lan966x->rx.dcbs;
91911871abaSHoratiu Vultur 	page_pool = lan966x->rx.page_pool;
9202ea1cbacSHoratiu Vultur 
9212ea1cbacSHoratiu Vultur 	napi_synchronize(&lan966x->napi);
9222ea1cbacSHoratiu Vultur 	napi_disable(&lan966x->napi);
9232ea1cbacSHoratiu Vultur 	lan966x_fdma_stop_netdev(lan966x);
9242ea1cbacSHoratiu Vultur 
9252ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_disable(&lan966x->rx);
9262ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_free_pages(&lan966x->rx);
9272ea1cbacSHoratiu Vultur 	lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
92811871abaSHoratiu Vultur 	lan966x->rx.max_mtu = new_mtu;
9292ea1cbacSHoratiu Vultur 	err = lan966x_fdma_rx_alloc(&lan966x->rx);
9302ea1cbacSHoratiu Vultur 	if (err)
9312ea1cbacSHoratiu Vultur 		goto restore;
9322ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_start(&lan966x->rx);
9332ea1cbacSHoratiu Vultur 
9342ea1cbacSHoratiu Vultur 	size = sizeof(struct lan966x_rx_dcb) * FDMA_DCB_MAX;
9352ea1cbacSHoratiu Vultur 	size = ALIGN(size, PAGE_SIZE);
9362ea1cbacSHoratiu Vultur 	dma_free_coherent(lan966x->dev, size, rx_dcbs, rx_dma);
9372ea1cbacSHoratiu Vultur 
93811871abaSHoratiu Vultur 	page_pool_destroy(page_pool);
93911871abaSHoratiu Vultur 
9402ea1cbacSHoratiu Vultur 	lan966x_fdma_wakeup_netdev(lan966x);
9412ea1cbacSHoratiu Vultur 	napi_enable(&lan966x->napi);
9422ea1cbacSHoratiu Vultur 
9432ea1cbacSHoratiu Vultur 	return err;
9442ea1cbacSHoratiu Vultur restore:
94511871abaSHoratiu Vultur 	lan966x->rx.page_pool = page_pool;
9462ea1cbacSHoratiu Vultur 	lan966x->rx.dma = rx_dma;
947f0a65f81SHoratiu Vultur 	lan966x->rx.dcbs = rx_dcbs;
9482ea1cbacSHoratiu Vultur 	lan966x_fdma_rx_start(&lan966x->rx);
9492ea1cbacSHoratiu Vultur 
9502ea1cbacSHoratiu Vultur 	return err;
9512ea1cbacSHoratiu Vultur }
9522ea1cbacSHoratiu Vultur 
lan966x_fdma_get_max_frame(struct lan966x * lan966x)95311871abaSHoratiu Vultur static int lan966x_fdma_get_max_frame(struct lan966x *lan966x)
95411871abaSHoratiu Vultur {
95511871abaSHoratiu Vultur 	return lan966x_fdma_get_max_mtu(lan966x) +
95611871abaSHoratiu Vultur 	       IFH_LEN_BYTES +
95711871abaSHoratiu Vultur 	       SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
9587292bb06SHoratiu Vultur 	       VLAN_HLEN * 2 +
9597292bb06SHoratiu Vultur 	       XDP_PACKET_HEADROOM;
96011871abaSHoratiu Vultur }
96111871abaSHoratiu Vultur 
__lan966x_fdma_reload(struct lan966x * lan966x,int max_mtu)962560c7223SHoratiu Vultur static int __lan966x_fdma_reload(struct lan966x *lan966x, int max_mtu)
9632ea1cbacSHoratiu Vultur {
9642ea1cbacSHoratiu Vultur 	int err;
9652ea1cbacSHoratiu Vultur 	u32 val;
9662ea1cbacSHoratiu Vultur 
9672ea1cbacSHoratiu Vultur 	/* Disable the CPU port */
9682ea1cbacSHoratiu Vultur 	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(0),
9692ea1cbacSHoratiu Vultur 		QSYS_SW_PORT_MODE_PORT_ENA,
9702ea1cbacSHoratiu Vultur 		lan966x, QSYS_SW_PORT_MODE(CPU_PORT));
9712ea1cbacSHoratiu Vultur 
9722ea1cbacSHoratiu Vultur 	/* Flush the CPU queues */
9732ea1cbacSHoratiu Vultur 	readx_poll_timeout(lan966x_qsys_sw_status, lan966x,
9742ea1cbacSHoratiu Vultur 			   val, !(QSYS_SW_STATUS_EQ_AVAIL_GET(val)),
9752ea1cbacSHoratiu Vultur 			   READL_SLEEP_US, READL_TIMEOUT_US);
9762ea1cbacSHoratiu Vultur 
9772ea1cbacSHoratiu Vultur 	/* Add a sleep in case there are frames between the queues and the CPU
9782ea1cbacSHoratiu Vultur 	 * port
9792ea1cbacSHoratiu Vultur 	 */
9802ea1cbacSHoratiu Vultur 	usleep_range(1000, 2000);
9812ea1cbacSHoratiu Vultur 
9822ea1cbacSHoratiu Vultur 	err = lan966x_fdma_reload(lan966x, max_mtu);
9832ea1cbacSHoratiu Vultur 
9842ea1cbacSHoratiu Vultur 	/* Enable back the CPU port */
9852ea1cbacSHoratiu Vultur 	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(1),
9862ea1cbacSHoratiu Vultur 		QSYS_SW_PORT_MODE_PORT_ENA,
9872ea1cbacSHoratiu Vultur 		lan966x,  QSYS_SW_PORT_MODE(CPU_PORT));
9882ea1cbacSHoratiu Vultur 
9892ea1cbacSHoratiu Vultur 	return err;
9902ea1cbacSHoratiu Vultur }
9912ea1cbacSHoratiu Vultur 
lan966x_fdma_change_mtu(struct lan966x * lan966x)992560c7223SHoratiu Vultur int lan966x_fdma_change_mtu(struct lan966x *lan966x)
993560c7223SHoratiu Vultur {
994560c7223SHoratiu Vultur 	int max_mtu;
995560c7223SHoratiu Vultur 
996560c7223SHoratiu Vultur 	max_mtu = lan966x_fdma_get_max_frame(lan966x);
997560c7223SHoratiu Vultur 	if (max_mtu == lan966x->rx.max_mtu)
998560c7223SHoratiu Vultur 		return 0;
999560c7223SHoratiu Vultur 
1000560c7223SHoratiu Vultur 	return __lan966x_fdma_reload(lan966x, max_mtu);
1001560c7223SHoratiu Vultur }
1002560c7223SHoratiu Vultur 
lan966x_fdma_reload_page_pool(struct lan966x * lan966x)1003560c7223SHoratiu Vultur int lan966x_fdma_reload_page_pool(struct lan966x *lan966x)
1004560c7223SHoratiu Vultur {
1005560c7223SHoratiu Vultur 	int max_mtu;
1006560c7223SHoratiu Vultur 
1007560c7223SHoratiu Vultur 	max_mtu = lan966x_fdma_get_max_frame(lan966x);
1008560c7223SHoratiu Vultur 	return __lan966x_fdma_reload(lan966x, max_mtu);
1009560c7223SHoratiu Vultur }
1010560c7223SHoratiu Vultur 
lan966x_fdma_netdev_init(struct lan966x * lan966x,struct net_device * dev)1011c8349639SHoratiu Vultur void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev)
1012c8349639SHoratiu Vultur {
1013c8349639SHoratiu Vultur 	if (lan966x->fdma_ndev)
1014c8349639SHoratiu Vultur 		return;
1015c8349639SHoratiu Vultur 
1016c8349639SHoratiu Vultur 	lan966x->fdma_ndev = dev;
1017b48b89f9SJakub Kicinski 	netif_napi_add(dev, &lan966x->napi, lan966x_fdma_napi_poll);
1018c8349639SHoratiu Vultur 	napi_enable(&lan966x->napi);
1019c8349639SHoratiu Vultur }
1020c8349639SHoratiu Vultur 
lan966x_fdma_netdev_deinit(struct lan966x * lan966x,struct net_device * dev)1021c8349639SHoratiu Vultur void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev)
1022c8349639SHoratiu Vultur {
1023c8349639SHoratiu Vultur 	if (lan966x->fdma_ndev == dev) {
1024c8349639SHoratiu Vultur 		netif_napi_del(&lan966x->napi);
1025c8349639SHoratiu Vultur 		lan966x->fdma_ndev = NULL;
1026c8349639SHoratiu Vultur 	}
1027c8349639SHoratiu Vultur }
1028c8349639SHoratiu Vultur 
lan966x_fdma_init(struct lan966x * lan966x)1029c8349639SHoratiu Vultur int lan966x_fdma_init(struct lan966x *lan966x)
1030c8349639SHoratiu Vultur {
1031c8349639SHoratiu Vultur 	int err;
1032c8349639SHoratiu Vultur 
1033c8349639SHoratiu Vultur 	if (!lan966x->fdma)
1034c8349639SHoratiu Vultur 		return 0;
1035c8349639SHoratiu Vultur 
1036c8349639SHoratiu Vultur 	lan966x->rx.lan966x = lan966x;
1037c8349639SHoratiu Vultur 	lan966x->rx.channel_id = FDMA_XTR_CHANNEL;
103811871abaSHoratiu Vultur 	lan966x->rx.max_mtu = lan966x_fdma_get_max_frame(lan966x);
1039c8349639SHoratiu Vultur 	lan966x->tx.lan966x = lan966x;
1040c8349639SHoratiu Vultur 	lan966x->tx.channel_id = FDMA_INJ_CHANNEL;
1041c8349639SHoratiu Vultur 	lan966x->tx.last_in_use = -1;
1042c8349639SHoratiu Vultur 
1043c8349639SHoratiu Vultur 	err = lan966x_fdma_rx_alloc(&lan966x->rx);
1044c8349639SHoratiu Vultur 	if (err)
1045c8349639SHoratiu Vultur 		return err;
1046c8349639SHoratiu Vultur 
1047c8349639SHoratiu Vultur 	err = lan966x_fdma_tx_alloc(&lan966x->tx);
1048c8349639SHoratiu Vultur 	if (err) {
1049c8349639SHoratiu Vultur 		lan966x_fdma_rx_free(&lan966x->rx);
1050c8349639SHoratiu Vultur 		return err;
1051c8349639SHoratiu Vultur 	}
1052c8349639SHoratiu Vultur 
1053c8349639SHoratiu Vultur 	lan966x_fdma_rx_start(&lan966x->rx);
1054c8349639SHoratiu Vultur 
1055c8349639SHoratiu Vultur 	return 0;
1056c8349639SHoratiu Vultur }
1057c8349639SHoratiu Vultur 
lan966x_fdma_deinit(struct lan966x * lan966x)1058c8349639SHoratiu Vultur void lan966x_fdma_deinit(struct lan966x *lan966x)
1059c8349639SHoratiu Vultur {
1060c8349639SHoratiu Vultur 	if (!lan966x->fdma)
1061c8349639SHoratiu Vultur 		return;
1062c8349639SHoratiu Vultur 
1063c8349639SHoratiu Vultur 	lan966x_fdma_rx_disable(&lan966x->rx);
1064c8349639SHoratiu Vultur 	lan966x_fdma_tx_disable(&lan966x->tx);
1065c8349639SHoratiu Vultur 
1066c8349639SHoratiu Vultur 	napi_synchronize(&lan966x->napi);
1067c8349639SHoratiu Vultur 	napi_disable(&lan966x->napi);
1068c8349639SHoratiu Vultur 
1069c8349639SHoratiu Vultur 	lan966x_fdma_rx_free_pages(&lan966x->rx);
1070c8349639SHoratiu Vultur 	lan966x_fdma_rx_free(&lan966x->rx);
107111871abaSHoratiu Vultur 	page_pool_destroy(lan966x->rx.page_pool);
1072c8349639SHoratiu Vultur 	lan966x_fdma_tx_free(&lan966x->tx);
1073c8349639SHoratiu Vultur }
1074