xref: /linux/drivers/net/ethernet/alibaba/eea/eea_rx.c (revision 5f4f7bc0ed1180a1bff423c39e05256172805b5d)
1aa8bca4cSXuan Zhuo // SPDX-License-Identifier: GPL-2.0-or-later
2aa8bca4cSXuan Zhuo /*
3aa8bca4cSXuan Zhuo  * Driver for Alibaba Elastic Ethernet Adapter.
4aa8bca4cSXuan Zhuo  *
5aa8bca4cSXuan Zhuo  * Copyright (C) 2025 Alibaba Inc.
6aa8bca4cSXuan Zhuo  */
7aa8bca4cSXuan Zhuo 
8aa8bca4cSXuan Zhuo #include <net/netdev_rx_queue.h>
9aa8bca4cSXuan Zhuo #include <net/page_pool/helpers.h>
10aa8bca4cSXuan Zhuo 
11aa8bca4cSXuan Zhuo #include "eea_adminq.h"
12aa8bca4cSXuan Zhuo #include "eea_net.h"
13aa8bca4cSXuan Zhuo #include "eea_pci.h"
14aa8bca4cSXuan Zhuo #include "eea_ring.h"
15aa8bca4cSXuan Zhuo 
16aa8bca4cSXuan Zhuo #define EEA_ENABLE_F_NAPI        BIT(0)
17aa8bca4cSXuan Zhuo 
18aa8bca4cSXuan Zhuo #define EEA_PAGE_FRAGS_NUM 1024
19aa8bca4cSXuan Zhuo 
20df9cad6bSXuan Zhuo #define EEA_RX_BUF_ALIGN 128
21df9cad6bSXuan Zhuo 
22df9cad6bSXuan Zhuo #define EEA_RX_BUF_MAX_LEN (10 * 1024)
23df9cad6bSXuan Zhuo 
24df9cad6bSXuan Zhuo struct eea_rx_ctx {
25df9cad6bSXuan Zhuo 	u32 len;
26df9cad6bSXuan Zhuo 	u32 hdr_len;
27df9cad6bSXuan Zhuo 
28df9cad6bSXuan Zhuo 	u16 flags;
29df9cad6bSXuan Zhuo 	bool more;
30df9cad6bSXuan Zhuo 
31df9cad6bSXuan Zhuo 	struct eea_rx_meta *meta;
32*5f4f7bc0SXuan Zhuo 
33*5f4f7bc0SXuan Zhuo 	struct eea_rx_ctx_stats stats;
34df9cad6bSXuan Zhuo };
35df9cad6bSXuan Zhuo 
36df9cad6bSXuan Zhuo static struct eea_rx_meta *eea_rx_meta_get(struct eea_net_rx *rx)
37df9cad6bSXuan Zhuo {
38df9cad6bSXuan Zhuo 	struct eea_rx_meta *meta;
39df9cad6bSXuan Zhuo 
40df9cad6bSXuan Zhuo 	if (!rx->free)
41df9cad6bSXuan Zhuo 		return NULL;
42df9cad6bSXuan Zhuo 
43df9cad6bSXuan Zhuo 	meta = rx->free;
44df9cad6bSXuan Zhuo 	rx->free = meta->next;
45df9cad6bSXuan Zhuo 
46df9cad6bSXuan Zhuo 	return meta;
47df9cad6bSXuan Zhuo }
48df9cad6bSXuan Zhuo 
49df9cad6bSXuan Zhuo static void eea_rx_meta_put(struct eea_net_rx *rx, struct eea_rx_meta *meta)
50df9cad6bSXuan Zhuo {
51df9cad6bSXuan Zhuo 	meta->next = rx->free;
52df9cad6bSXuan Zhuo 	rx->free = meta;
53df9cad6bSXuan Zhuo }
54df9cad6bSXuan Zhuo 
55aa8bca4cSXuan Zhuo static void eea_free_rx_buffer(struct eea_net_rx *rx, struct eea_rx_meta *meta,
56aa8bca4cSXuan Zhuo 			       bool allow_direct)
57aa8bca4cSXuan Zhuo {
58aa8bca4cSXuan Zhuo 	u32 drain_count;
59aa8bca4cSXuan Zhuo 
60aa8bca4cSXuan Zhuo 	drain_count = EEA_PAGE_FRAGS_NUM - meta->frags;
61aa8bca4cSXuan Zhuo 
62aa8bca4cSXuan Zhuo 	if (page_pool_unref_page(meta->page, drain_count) == 0)
63aa8bca4cSXuan Zhuo 		page_pool_put_unrefed_page(rx->pp, meta->page, -1,
64aa8bca4cSXuan Zhuo 					   allow_direct);
65aa8bca4cSXuan Zhuo 
66aa8bca4cSXuan Zhuo 	meta->page = NULL;
67aa8bca4cSXuan Zhuo }
68aa8bca4cSXuan Zhuo 
69df9cad6bSXuan Zhuo static void eea_rx_meta_dma_sync_for_device(struct eea_net_rx *rx,
70df9cad6bSXuan Zhuo 					    struct eea_rx_meta *meta)
71df9cad6bSXuan Zhuo {
72df9cad6bSXuan Zhuo 	u32 len;
73df9cad6bSXuan Zhuo 
74df9cad6bSXuan Zhuo 	if (meta->sync_for_cpu <= meta->offset + rx->headroom)
75df9cad6bSXuan Zhuo 		return;
76df9cad6bSXuan Zhuo 
77df9cad6bSXuan Zhuo 	len = meta->sync_for_cpu - meta->offset - rx->headroom;
78df9cad6bSXuan Zhuo 
79df9cad6bSXuan Zhuo 	dma_sync_single_for_device(rx->enet->edev->dma_dev,
80df9cad6bSXuan Zhuo 				   meta->dma + meta->offset + rx->headroom,
81df9cad6bSXuan Zhuo 				   len, DMA_FROM_DEVICE);
82df9cad6bSXuan Zhuo 	meta->sync_for_cpu = 0;
83df9cad6bSXuan Zhuo }
84df9cad6bSXuan Zhuo 
85df9cad6bSXuan Zhuo static void meta_align_offset(struct eea_net_rx *rx, struct eea_rx_meta *meta)
86df9cad6bSXuan Zhuo {
87df9cad6bSXuan Zhuo 	int h, b;
88df9cad6bSXuan Zhuo 
89df9cad6bSXuan Zhuo 	h = rx->headroom;
90df9cad6bSXuan Zhuo 	b = meta->offset + h;
91df9cad6bSXuan Zhuo 
92df9cad6bSXuan Zhuo 	/* For better performance, we align the buffer address to
93df9cad6bSXuan Zhuo 	 * EEA_RX_BUF_ALIGN, as required by the device design.
94df9cad6bSXuan Zhuo 	 */
95df9cad6bSXuan Zhuo 	b = ALIGN(b, EEA_RX_BUF_ALIGN);
96df9cad6bSXuan Zhuo 
97df9cad6bSXuan Zhuo 	meta->offset = b - h;
98df9cad6bSXuan Zhuo }
99df9cad6bSXuan Zhuo 
100df9cad6bSXuan Zhuo static int eea_alloc_rx_buffer(struct eea_net_rx *rx, struct eea_rx_meta *meta)
101df9cad6bSXuan Zhuo {
102df9cad6bSXuan Zhuo 	struct page *page;
103df9cad6bSXuan Zhuo 
104df9cad6bSXuan Zhuo 	if (meta->page) {
105df9cad6bSXuan Zhuo 		eea_rx_meta_dma_sync_for_device(rx, meta);
106df9cad6bSXuan Zhuo 		return 0;
107df9cad6bSXuan Zhuo 	}
108df9cad6bSXuan Zhuo 
109df9cad6bSXuan Zhuo 	page = page_pool_dev_alloc_pages(rx->pp);
110df9cad6bSXuan Zhuo 	if (!page)
111df9cad6bSXuan Zhuo 		return -ENOMEM;
112df9cad6bSXuan Zhuo 
113df9cad6bSXuan Zhuo 	page_pool_fragment_page(page, EEA_PAGE_FRAGS_NUM);
114df9cad6bSXuan Zhuo 
115df9cad6bSXuan Zhuo 	meta->page = page;
116df9cad6bSXuan Zhuo 	meta->dma = page_pool_get_dma_addr(page);
117df9cad6bSXuan Zhuo 	meta->offset = 0;
118df9cad6bSXuan Zhuo 	meta->frags = 0;
119df9cad6bSXuan Zhuo 	meta->sync_for_cpu = 0;
120df9cad6bSXuan Zhuo 
121df9cad6bSXuan Zhuo 	meta_align_offset(rx, meta);
122df9cad6bSXuan Zhuo 
123df9cad6bSXuan Zhuo 	return 0;
124df9cad6bSXuan Zhuo }
125df9cad6bSXuan Zhuo 
126df9cad6bSXuan Zhuo static u32 eea_consume_rx_buffer(struct eea_net_rx *rx,
127df9cad6bSXuan Zhuo 				 struct eea_rx_meta *meta,
128df9cad6bSXuan Zhuo 				 u32 consumed)
129df9cad6bSXuan Zhuo {
130df9cad6bSXuan Zhuo 	u32 offset;
131df9cad6bSXuan Zhuo 	int min;
132df9cad6bSXuan Zhuo 
133df9cad6bSXuan Zhuo 	offset = meta->offset;
134df9cad6bSXuan Zhuo 
135df9cad6bSXuan Zhuo 	meta->offset += consumed;
136df9cad6bSXuan Zhuo 	++meta->frags;
137df9cad6bSXuan Zhuo 
138df9cad6bSXuan Zhuo 	min = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
139df9cad6bSXuan Zhuo 	min += rx->headroom;
140df9cad6bSXuan Zhuo 	min += SKB_DATA_ALIGN(ETH_DATA_LEN);
141df9cad6bSXuan Zhuo 
142df9cad6bSXuan Zhuo 	meta_align_offset(rx, meta);
143df9cad6bSXuan Zhuo 
144df9cad6bSXuan Zhuo 	if (min + meta->offset > PAGE_SIZE) {
145df9cad6bSXuan Zhuo 		eea_free_rx_buffer(rx, meta, true);
146df9cad6bSXuan Zhuo 		return PAGE_SIZE - offset;
147df9cad6bSXuan Zhuo 	}
148df9cad6bSXuan Zhuo 
149df9cad6bSXuan Zhuo 	return meta->offset - offset;
150df9cad6bSXuan Zhuo }
151df9cad6bSXuan Zhuo 
152aa8bca4cSXuan Zhuo static void eea_free_rx_hdr(struct eea_net_rx *rx, struct eea_net_cfg *cfg)
153aa8bca4cSXuan Zhuo {
154aa8bca4cSXuan Zhuo 	struct eea_rx_meta *meta;
155aa8bca4cSXuan Zhuo 	int i;
156aa8bca4cSXuan Zhuo 
157aa8bca4cSXuan Zhuo 	for (i = 0; i < cfg->rx_ring_depth; ++i) {
158aa8bca4cSXuan Zhuo 		meta = &rx->meta[i];
159aa8bca4cSXuan Zhuo 		meta->hdr_addr = NULL;
160aa8bca4cSXuan Zhuo 
161aa8bca4cSXuan Zhuo 		if (!meta->hdr_page)
162aa8bca4cSXuan Zhuo 			continue;
163aa8bca4cSXuan Zhuo 
164aa8bca4cSXuan Zhuo 		dma_unmap_page(rx->dma_dev, meta->hdr_dma, PAGE_SIZE,
165aa8bca4cSXuan Zhuo 			       DMA_FROM_DEVICE);
166aa8bca4cSXuan Zhuo 		put_page(meta->hdr_page);
167aa8bca4cSXuan Zhuo 
168aa8bca4cSXuan Zhuo 		meta->hdr_page = NULL;
169aa8bca4cSXuan Zhuo 	}
170aa8bca4cSXuan Zhuo }
171aa8bca4cSXuan Zhuo 
172aa8bca4cSXuan Zhuo static int eea_alloc_rx_hdr(struct eea_net_init_ctx *ctx, struct eea_net_rx *rx)
173aa8bca4cSXuan Zhuo {
174aa8bca4cSXuan Zhuo 	struct page *hdr_page = NULL;
175aa8bca4cSXuan Zhuo 	struct eea_rx_meta *meta;
176aa8bca4cSXuan Zhuo 	u32 offset = 0, hdrsize;
177aa8bca4cSXuan Zhuo 	struct device *dmadev;
178aa8bca4cSXuan Zhuo 	dma_addr_t dma;
179aa8bca4cSXuan Zhuo 	int i;
180aa8bca4cSXuan Zhuo 
181aa8bca4cSXuan Zhuo 	dmadev = ctx->edev->dma_dev;
182aa8bca4cSXuan Zhuo 	hdrsize = ctx->cfg.split_hdr;
183aa8bca4cSXuan Zhuo 
184aa8bca4cSXuan Zhuo 	for (i = 0; i < ctx->cfg.rx_ring_depth; ++i) {
185aa8bca4cSXuan Zhuo 		meta = &rx->meta[i];
186aa8bca4cSXuan Zhuo 		meta->hdr_page = NULL;
187aa8bca4cSXuan Zhuo 
188aa8bca4cSXuan Zhuo 		if (!hdr_page || offset + hdrsize > PAGE_SIZE) {
189aa8bca4cSXuan Zhuo 			hdr_page = alloc_page(GFP_KERNEL);
190aa8bca4cSXuan Zhuo 			if (!hdr_page)
191aa8bca4cSXuan Zhuo 				goto err;
192aa8bca4cSXuan Zhuo 
193aa8bca4cSXuan Zhuo 			dma = dma_map_page(dmadev, hdr_page, 0, PAGE_SIZE,
194aa8bca4cSXuan Zhuo 					   DMA_FROM_DEVICE);
195aa8bca4cSXuan Zhuo 
196aa8bca4cSXuan Zhuo 			if (unlikely(dma_mapping_error(dmadev, dma))) {
197aa8bca4cSXuan Zhuo 				put_page(hdr_page);
198aa8bca4cSXuan Zhuo 				goto err;
199aa8bca4cSXuan Zhuo 			}
200aa8bca4cSXuan Zhuo 
201aa8bca4cSXuan Zhuo 			offset = 0;
202aa8bca4cSXuan Zhuo 			meta->hdr_page = hdr_page;
203aa8bca4cSXuan Zhuo 		}
204aa8bca4cSXuan Zhuo 
205aa8bca4cSXuan Zhuo 		meta->hdr_dma = dma + offset;
206aa8bca4cSXuan Zhuo 		meta->hdr_addr = page_address(hdr_page) + offset;
207aa8bca4cSXuan Zhuo 		offset += hdrsize;
208aa8bca4cSXuan Zhuo 	}
209aa8bca4cSXuan Zhuo 
210aa8bca4cSXuan Zhuo 	return 0;
211aa8bca4cSXuan Zhuo 
212aa8bca4cSXuan Zhuo err:
213aa8bca4cSXuan Zhuo 	eea_free_rx_hdr(rx, &ctx->cfg);
214aa8bca4cSXuan Zhuo 	return -ENOMEM;
215aa8bca4cSXuan Zhuo }
216aa8bca4cSXuan Zhuo 
217df9cad6bSXuan Zhuo static void eea_rx_meta_dma_sync_for_cpu(struct eea_net_rx *rx,
218df9cad6bSXuan Zhuo 					 struct eea_rx_meta *meta, u32 len)
219df9cad6bSXuan Zhuo {
220df9cad6bSXuan Zhuo 	dma_sync_single_for_cpu(rx->enet->edev->dma_dev,
221df9cad6bSXuan Zhuo 				meta->dma + meta->offset + meta->headroom,
222df9cad6bSXuan Zhuo 				len, DMA_FROM_DEVICE);
223df9cad6bSXuan Zhuo 	meta->sync_for_cpu = meta->offset + meta->headroom + len;
224df9cad6bSXuan Zhuo }
225df9cad6bSXuan Zhuo 
226df9cad6bSXuan Zhuo static int eea_harden_check_overflow(struct eea_rx_ctx *ctx,
227df9cad6bSXuan Zhuo 				     struct eea_net *enet)
228df9cad6bSXuan Zhuo {
229df9cad6bSXuan Zhuo 	u32 max_len;
230df9cad6bSXuan Zhuo 
231df9cad6bSXuan Zhuo 	max_len = ctx->meta->truesize - ctx->meta->headroom -
232df9cad6bSXuan Zhuo 		ctx->meta->tailroom;
233df9cad6bSXuan Zhuo 
234df9cad6bSXuan Zhuo 	if (unlikely(ctx->len > max_len)) {
235df9cad6bSXuan Zhuo 		pr_debug("%s: rx error: len %u exceeds truesize %u\n",
236df9cad6bSXuan Zhuo 			 enet->netdev->name, ctx->len, max_len);
237*5f4f7bc0SXuan Zhuo 		++ctx->stats.length_errors;
238df9cad6bSXuan Zhuo 		return -EINVAL;
239df9cad6bSXuan Zhuo 	}
240df9cad6bSXuan Zhuo 
241df9cad6bSXuan Zhuo 	return 0;
242df9cad6bSXuan Zhuo }
243df9cad6bSXuan Zhuo 
244df9cad6bSXuan Zhuo static int eea_harden_check_size(struct eea_rx_ctx *ctx, struct eea_net *enet)
245df9cad6bSXuan Zhuo {
246df9cad6bSXuan Zhuo 	int err;
247df9cad6bSXuan Zhuo 
248df9cad6bSXuan Zhuo 	err = eea_harden_check_overflow(ctx, enet);
249df9cad6bSXuan Zhuo 	if (err)
250df9cad6bSXuan Zhuo 		return err;
251df9cad6bSXuan Zhuo 
252df9cad6bSXuan Zhuo 	if (ctx->hdr_len) {
253df9cad6bSXuan Zhuo 		if (unlikely(ctx->hdr_len < ETH_HLEN)) {
254df9cad6bSXuan Zhuo 			pr_debug("%s: short hdr %u\n", enet->netdev->name,
255df9cad6bSXuan Zhuo 				 ctx->hdr_len);
256*5f4f7bc0SXuan Zhuo 			++ctx->stats.length_errors;
257df9cad6bSXuan Zhuo 			return -EINVAL;
258df9cad6bSXuan Zhuo 		}
259df9cad6bSXuan Zhuo 
260df9cad6bSXuan Zhuo 		if (unlikely(ctx->hdr_len > enet->cfg.split_hdr)) {
261df9cad6bSXuan Zhuo 			pr_debug("%s: rx error: hdr len %u exceeds hdr buffer size %u\n",
262df9cad6bSXuan Zhuo 				 enet->netdev->name, ctx->hdr_len,
263df9cad6bSXuan Zhuo 				 enet->cfg.split_hdr);
264*5f4f7bc0SXuan Zhuo 			++ctx->stats.length_errors;
265df9cad6bSXuan Zhuo 			return -EINVAL;
266df9cad6bSXuan Zhuo 		}
267df9cad6bSXuan Zhuo 
268df9cad6bSXuan Zhuo 		return 0;
269df9cad6bSXuan Zhuo 	}
270df9cad6bSXuan Zhuo 
271df9cad6bSXuan Zhuo 	if (unlikely(ctx->len < ETH_HLEN)) {
272df9cad6bSXuan Zhuo 		pr_debug("%s: short packet %u\n", enet->netdev->name, ctx->len);
273*5f4f7bc0SXuan Zhuo 		++ctx->stats.length_errors;
274df9cad6bSXuan Zhuo 		return -EINVAL;
275df9cad6bSXuan Zhuo 	}
276df9cad6bSXuan Zhuo 
277df9cad6bSXuan Zhuo 	return 0;
278df9cad6bSXuan Zhuo }
279df9cad6bSXuan Zhuo 
280df9cad6bSXuan Zhuo static struct sk_buff *eea_build_skb(void *buf, u32 buflen, u32 headroom,
281df9cad6bSXuan Zhuo 				     u32 len)
282df9cad6bSXuan Zhuo {
283df9cad6bSXuan Zhuo 	struct sk_buff *skb;
284df9cad6bSXuan Zhuo 
285df9cad6bSXuan Zhuo 	skb = build_skb(buf, buflen);
286df9cad6bSXuan Zhuo 	if (unlikely(!skb))
287df9cad6bSXuan Zhuo 		return NULL;
288df9cad6bSXuan Zhuo 
289df9cad6bSXuan Zhuo 	skb_reserve(skb, headroom);
290df9cad6bSXuan Zhuo 	skb_put(skb, len);
291df9cad6bSXuan Zhuo 
292df9cad6bSXuan Zhuo 	return skb;
293df9cad6bSXuan Zhuo }
294df9cad6bSXuan Zhuo 
295df9cad6bSXuan Zhuo static struct sk_buff *eea_rx_build_split_hdr_skb(struct eea_net_rx *rx,
296df9cad6bSXuan Zhuo 						  struct eea_rx_ctx *ctx)
297df9cad6bSXuan Zhuo {
298df9cad6bSXuan Zhuo 	struct eea_rx_meta *meta = ctx->meta;
299df9cad6bSXuan Zhuo 	u32 truesize, offset;
300df9cad6bSXuan Zhuo 	struct sk_buff *skb;
301df9cad6bSXuan Zhuo 	struct page *page;
302df9cad6bSXuan Zhuo 
303df9cad6bSXuan Zhuo 	dma_sync_single_for_cpu(rx->enet->edev->dma_dev, meta->hdr_dma,
304df9cad6bSXuan Zhuo 				ctx->hdr_len, DMA_FROM_DEVICE);
305df9cad6bSXuan Zhuo 
306df9cad6bSXuan Zhuo 	skb = napi_alloc_skb(rx->napi, ctx->hdr_len);
307df9cad6bSXuan Zhuo 	if (unlikely(!skb))
308df9cad6bSXuan Zhuo 		return NULL;
309df9cad6bSXuan Zhuo 
310df9cad6bSXuan Zhuo 	skb_put_data(skb, ctx->meta->hdr_addr, ctx->hdr_len);
311df9cad6bSXuan Zhuo 
312df9cad6bSXuan Zhuo 	if (ctx->len) {
313df9cad6bSXuan Zhuo 		page = meta->page;
314df9cad6bSXuan Zhuo 		offset = meta->offset + meta->headroom;
315df9cad6bSXuan Zhuo 
316df9cad6bSXuan Zhuo 		truesize = eea_consume_rx_buffer(rx, meta,
317df9cad6bSXuan Zhuo 						 meta->headroom + ctx->len);
318df9cad6bSXuan Zhuo 
319df9cad6bSXuan Zhuo 		skb_add_rx_frag(skb, 0, page, offset, ctx->len, truesize);
320df9cad6bSXuan Zhuo 	}
321df9cad6bSXuan Zhuo 
322df9cad6bSXuan Zhuo 	skb_mark_for_recycle(skb);
323df9cad6bSXuan Zhuo 
324df9cad6bSXuan Zhuo 	return skb;
325df9cad6bSXuan Zhuo }
326df9cad6bSXuan Zhuo 
327df9cad6bSXuan Zhuo static struct sk_buff *eea_rx_build_skb(struct eea_net_rx *rx,
328df9cad6bSXuan Zhuo 					struct eea_rx_ctx *ctx)
329df9cad6bSXuan Zhuo {
330df9cad6bSXuan Zhuo 	struct eea_rx_meta *meta = ctx->meta;
331df9cad6bSXuan Zhuo 	u32 shinfo_size, bufsize, truesize;
332df9cad6bSXuan Zhuo 	struct sk_buff *skb;
333df9cad6bSXuan Zhuo 	struct page *page;
334df9cad6bSXuan Zhuo 	void *buf;
335df9cad6bSXuan Zhuo 
336df9cad6bSXuan Zhuo 	page = meta->page;
337df9cad6bSXuan Zhuo 
338df9cad6bSXuan Zhuo 	shinfo_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
339df9cad6bSXuan Zhuo 
340df9cad6bSXuan Zhuo 	buf = page_address(page) + meta->offset;
341df9cad6bSXuan Zhuo 	bufsize = meta->headroom + SKB_DATA_ALIGN(ctx->len) + shinfo_size;
342df9cad6bSXuan Zhuo 
343df9cad6bSXuan Zhuo 	skb = eea_build_skb(buf, bufsize, meta->headroom, ctx->len);
344df9cad6bSXuan Zhuo 	if (unlikely(!skb))
345df9cad6bSXuan Zhuo 		return NULL;
346df9cad6bSXuan Zhuo 
347df9cad6bSXuan Zhuo 	truesize = eea_consume_rx_buffer(rx, meta, bufsize);
348df9cad6bSXuan Zhuo 	skb_mark_for_recycle(skb);
349df9cad6bSXuan Zhuo 
350df9cad6bSXuan Zhuo 	skb->truesize += truesize - bufsize;
351df9cad6bSXuan Zhuo 
352df9cad6bSXuan Zhuo 	return skb;
353df9cad6bSXuan Zhuo }
354df9cad6bSXuan Zhuo 
355df9cad6bSXuan Zhuo static void process_remain_buf(struct eea_net_rx *rx, struct eea_rx_ctx *ctx)
356df9cad6bSXuan Zhuo {
357df9cad6bSXuan Zhuo 	struct eea_net *enet = rx->enet;
358df9cad6bSXuan Zhuo 	struct sk_buff *head_skb;
359df9cad6bSXuan Zhuo 	u32 offset, truesize, nr_frags;
360df9cad6bSXuan Zhuo 	struct page *page;
361df9cad6bSXuan Zhuo 
362df9cad6bSXuan Zhuo 	if (eea_harden_check_overflow(ctx, enet))
363df9cad6bSXuan Zhuo 		goto err;
364df9cad6bSXuan Zhuo 
365df9cad6bSXuan Zhuo 	head_skb = rx->pkt.head_skb;
366df9cad6bSXuan Zhuo 
367df9cad6bSXuan Zhuo 	nr_frags = skb_shinfo(head_skb)->nr_frags;
368df9cad6bSXuan Zhuo 	if (unlikely(nr_frags >= MAX_SKB_FRAGS))
369df9cad6bSXuan Zhuo 		goto err;
370df9cad6bSXuan Zhuo 
371df9cad6bSXuan Zhuo 	offset = ctx->meta->offset + ctx->meta->headroom;
372df9cad6bSXuan Zhuo 	page = ctx->meta->page;
373df9cad6bSXuan Zhuo 	truesize = eea_consume_rx_buffer(rx, ctx->meta,
374df9cad6bSXuan Zhuo 					 ctx->meta->headroom + ctx->len);
375df9cad6bSXuan Zhuo 
376df9cad6bSXuan Zhuo 	skb_add_rx_frag(head_skb, nr_frags, page, offset, ctx->len, truesize);
377df9cad6bSXuan Zhuo 
378df9cad6bSXuan Zhuo 	return;
379df9cad6bSXuan Zhuo 
380df9cad6bSXuan Zhuo err:
381df9cad6bSXuan Zhuo 	dev_kfree_skb(rx->pkt.head_skb);
382*5f4f7bc0SXuan Zhuo 	++ctx->stats.drops;
383df9cad6bSXuan Zhuo 	rx->pkt.do_drop = true;
384df9cad6bSXuan Zhuo 	rx->pkt.head_skb = NULL;
385df9cad6bSXuan Zhuo }
386df9cad6bSXuan Zhuo 
387df9cad6bSXuan Zhuo static void process_first_buf(struct eea_net_rx *rx, struct eea_rx_ctx *ctx)
388df9cad6bSXuan Zhuo {
389df9cad6bSXuan Zhuo 	struct eea_net *enet = rx->enet;
390df9cad6bSXuan Zhuo 	struct sk_buff *skb = NULL;
391df9cad6bSXuan Zhuo 
392df9cad6bSXuan Zhuo 	if (eea_harden_check_size(ctx, enet))
393df9cad6bSXuan Zhuo 		goto err;
394df9cad6bSXuan Zhuo 
395df9cad6bSXuan Zhuo 	rx->pkt.data_valid = ctx->flags & EEA_DESC_F_DATA_VALID;
396df9cad6bSXuan Zhuo 
397df9cad6bSXuan Zhuo 	if (ctx->hdr_len)
398df9cad6bSXuan Zhuo 		skb = eea_rx_build_split_hdr_skb(rx, ctx);
399df9cad6bSXuan Zhuo 	else
400df9cad6bSXuan Zhuo 		skb = eea_rx_build_skb(rx, ctx);
401df9cad6bSXuan Zhuo 
402df9cad6bSXuan Zhuo 	if (unlikely(!skb))
403df9cad6bSXuan Zhuo 		goto err;
404df9cad6bSXuan Zhuo 
405df9cad6bSXuan Zhuo 	rx->pkt.head_skb = skb;
406df9cad6bSXuan Zhuo 
407df9cad6bSXuan Zhuo 	return;
408df9cad6bSXuan Zhuo 
409df9cad6bSXuan Zhuo err:
410*5f4f7bc0SXuan Zhuo 	++ctx->stats.drops;
411df9cad6bSXuan Zhuo 	rx->pkt.do_drop = true;
412df9cad6bSXuan Zhuo }
413df9cad6bSXuan Zhuo 
414df9cad6bSXuan Zhuo static void eea_submit_skb(struct eea_net_rx *rx, struct sk_buff *skb,
415df9cad6bSXuan Zhuo 			   struct eea_rx_cdesc *desc)
416df9cad6bSXuan Zhuo {
417df9cad6bSXuan Zhuo 	struct eea_net *enet = rx->enet;
418df9cad6bSXuan Zhuo 
419df9cad6bSXuan Zhuo 	if (rx->pkt.data_valid)
420df9cad6bSXuan Zhuo 		skb->ip_summed = CHECKSUM_UNNECESSARY;
421df9cad6bSXuan Zhuo 
422df9cad6bSXuan Zhuo 	if (enet->cfg.ts_cfg.rx_filter == HWTSTAMP_FILTER_ALL)
423df9cad6bSXuan Zhuo 		skb_hwtstamps(skb)->hwtstamp = EEA_DESC_TS(desc) +
424df9cad6bSXuan Zhuo 			enet->hw_ts_offset;
425df9cad6bSXuan Zhuo 
426df9cad6bSXuan Zhuo 	skb_record_rx_queue(skb, rx->index);
427df9cad6bSXuan Zhuo 	skb->protocol = eth_type_trans(skb, enet->netdev);
428df9cad6bSXuan Zhuo 
429df9cad6bSXuan Zhuo 	napi_gro_receive(rx->napi, skb);
430df9cad6bSXuan Zhuo }
431df9cad6bSXuan Zhuo 
432df9cad6bSXuan Zhuo static int eea_rx_desc_to_ctx(struct eea_net_rx *rx,
433df9cad6bSXuan Zhuo 			      struct eea_rx_ctx *ctx,
434df9cad6bSXuan Zhuo 			      struct eea_rx_cdesc *desc)
435df9cad6bSXuan Zhuo {
436df9cad6bSXuan Zhuo 	u16 id;
437df9cad6bSXuan Zhuo 
438df9cad6bSXuan Zhuo 	ctx->meta = NULL;
439df9cad6bSXuan Zhuo 
440df9cad6bSXuan Zhuo 	id = le16_to_cpu(desc->id);
441df9cad6bSXuan Zhuo 	if (unlikely(id >= rx->ering->num)) {
442df9cad6bSXuan Zhuo 		if (net_ratelimit())
443df9cad6bSXuan Zhuo 			netdev_err(rx->enet->netdev, "rx invalid id %d\n", id);
444df9cad6bSXuan Zhuo 		return -EINVAL;
445df9cad6bSXuan Zhuo 	}
446df9cad6bSXuan Zhuo 
447df9cad6bSXuan Zhuo 	ctx->meta = &rx->meta[id];
448df9cad6bSXuan Zhuo 	if (!ctx->meta->in_use) {
449df9cad6bSXuan Zhuo 		if (net_ratelimit())
450df9cad6bSXuan Zhuo 			netdev_err(rx->enet->netdev, "rx invalid id %d\n", id);
451df9cad6bSXuan Zhuo 		ctx->meta = NULL;
452df9cad6bSXuan Zhuo 		return -EINVAL;
453df9cad6bSXuan Zhuo 	}
454df9cad6bSXuan Zhuo 
455df9cad6bSXuan Zhuo 	ctx->meta->in_use = false;
456df9cad6bSXuan Zhuo 
457df9cad6bSXuan Zhuo 	ctx->len = le16_to_cpu(desc->len);
458df9cad6bSXuan Zhuo 	if (unlikely(ctx->len > ctx->meta->len)) {
459df9cad6bSXuan Zhuo 		if (net_ratelimit())
460df9cad6bSXuan Zhuo 			netdev_err(rx->enet->netdev, "rx invalid len(%d) id:%d\n",
461df9cad6bSXuan Zhuo 				   ctx->len, id);
462df9cad6bSXuan Zhuo 		return -EINVAL;
463df9cad6bSXuan Zhuo 	}
464df9cad6bSXuan Zhuo 
465df9cad6bSXuan Zhuo 	ctx->flags = le16_to_cpu(desc->flags);
466df9cad6bSXuan Zhuo 
467df9cad6bSXuan Zhuo 	ctx->hdr_len = 0;
468df9cad6bSXuan Zhuo 	if (ctx->flags & EEA_DESC_F_SPLIT_HDR) {
469df9cad6bSXuan Zhuo 		ctx->hdr_len = le16_to_cpu(desc->len_ex) &
470df9cad6bSXuan Zhuo 			EEA_RX_CDESC_HDR_LEN_MASK;
471*5f4f7bc0SXuan Zhuo 		ctx->stats.split_hdr_bytes += ctx->hdr_len;
472*5f4f7bc0SXuan Zhuo 		++ctx->stats.split_hdr_packets;
473df9cad6bSXuan Zhuo 	}
474df9cad6bSXuan Zhuo 
475df9cad6bSXuan Zhuo 	ctx->more = ctx->flags & EEA_RING_DESC_F_MORE;
476df9cad6bSXuan Zhuo 
477df9cad6bSXuan Zhuo 	return 0;
478df9cad6bSXuan Zhuo }
479df9cad6bSXuan Zhuo 
480df9cad6bSXuan Zhuo static int eea_cleanrx(struct eea_net_rx *rx, int budget,
481df9cad6bSXuan Zhuo 		       struct eea_rx_ctx *ctx)
482df9cad6bSXuan Zhuo {
483df9cad6bSXuan Zhuo 	struct eea_rx_cdesc *desc;
484df9cad6bSXuan Zhuo 	struct eea_rx_meta *meta;
485df9cad6bSXuan Zhuo 	int recv, err;
486df9cad6bSXuan Zhuo 
487df9cad6bSXuan Zhuo 	for (recv = 0; recv < budget; ) {
488df9cad6bSXuan Zhuo 		desc = eea_ering_cq_get_desc(rx->ering);
489df9cad6bSXuan Zhuo 		if (!desc)
490df9cad6bSXuan Zhuo 			break;
491df9cad6bSXuan Zhuo 
492df9cad6bSXuan Zhuo 		err = eea_rx_desc_to_ctx(rx, ctx, desc);
493df9cad6bSXuan Zhuo 		if (unlikely(err)) {
494df9cad6bSXuan Zhuo 			if (ctx->meta)
495df9cad6bSXuan Zhuo 				eea_rx_meta_put(rx, ctx->meta);
496df9cad6bSXuan Zhuo 
497*5f4f7bc0SXuan Zhuo 			if (rx->pkt.head_skb) {
498df9cad6bSXuan Zhuo 				dev_kfree_skb(rx->pkt.head_skb);
499*5f4f7bc0SXuan Zhuo 				++ctx->stats.drops;
500*5f4f7bc0SXuan Zhuo 			}
501df9cad6bSXuan Zhuo 
502df9cad6bSXuan Zhuo 			/* A hardware error occurred; we are attempting to
503df9cad6bSXuan Zhuo 			 * mitigate the impact. Subsequent packets may be
504df9cad6bSXuan Zhuo 			 * corrupted.
505df9cad6bSXuan Zhuo 			 */
506df9cad6bSXuan Zhuo 			ctx->more = false;
507df9cad6bSXuan Zhuo 			goto ack;
508df9cad6bSXuan Zhuo 		}
509df9cad6bSXuan Zhuo 
510df9cad6bSXuan Zhuo 		meta = ctx->meta;
511df9cad6bSXuan Zhuo 
512df9cad6bSXuan Zhuo 		if (unlikely(rx->pkt.do_drop))
513df9cad6bSXuan Zhuo 			goto skip;
514df9cad6bSXuan Zhuo 
515df9cad6bSXuan Zhuo 		eea_rx_meta_dma_sync_for_cpu(rx, meta, ctx->len);
516df9cad6bSXuan Zhuo 
517df9cad6bSXuan Zhuo 		rx->pkt.recv_len += ctx->len;
518df9cad6bSXuan Zhuo 		rx->pkt.recv_len += ctx->hdr_len;
519df9cad6bSXuan Zhuo 
520df9cad6bSXuan Zhuo 		if (!rx->pkt.idx)
521df9cad6bSXuan Zhuo 			process_first_buf(rx, ctx);
522df9cad6bSXuan Zhuo 		else
523df9cad6bSXuan Zhuo 			process_remain_buf(rx, ctx);
524df9cad6bSXuan Zhuo 
525df9cad6bSXuan Zhuo 		++rx->pkt.idx;
526df9cad6bSXuan Zhuo 
527*5f4f7bc0SXuan Zhuo 		if (!ctx->more && rx->pkt.head_skb) {
528df9cad6bSXuan Zhuo 			eea_submit_skb(rx, rx->pkt.head_skb, desc);
529*5f4f7bc0SXuan Zhuo 			ctx->stats.bytes += rx->pkt.recv_len;
530*5f4f7bc0SXuan Zhuo 			++ctx->stats.packets;
531*5f4f7bc0SXuan Zhuo 		}
532df9cad6bSXuan Zhuo 
533df9cad6bSXuan Zhuo skip:
534df9cad6bSXuan Zhuo 		eea_rx_meta_put(rx, meta);
535df9cad6bSXuan Zhuo ack:
536df9cad6bSXuan Zhuo 		eea_ering_cq_ack_desc(rx->ering, 1);
537*5f4f7bc0SXuan Zhuo 		++ctx->stats.descs;
538df9cad6bSXuan Zhuo 
539df9cad6bSXuan Zhuo 		if (!ctx->more) {
540df9cad6bSXuan Zhuo 			memset(&rx->pkt, 0, sizeof(rx->pkt));
541df9cad6bSXuan Zhuo 			++recv;
542df9cad6bSXuan Zhuo 		}
543df9cad6bSXuan Zhuo 	}
544df9cad6bSXuan Zhuo 
545df9cad6bSXuan Zhuo 	return recv;
546df9cad6bSXuan Zhuo }
547df9cad6bSXuan Zhuo 
548df9cad6bSXuan Zhuo static void eea_rx_dma_sync_hdr(struct eea_net_rx *rx, dma_addr_t addr)
549df9cad6bSXuan Zhuo {
550df9cad6bSXuan Zhuo 	dma_sync_single_for_device(rx->dma_dev, addr,
551df9cad6bSXuan Zhuo 				   rx->enet->cfg.split_hdr,
552df9cad6bSXuan Zhuo 				   DMA_FROM_DEVICE);
553df9cad6bSXuan Zhuo }
554df9cad6bSXuan Zhuo 
555df9cad6bSXuan Zhuo /* Only be called from napi. */
556*5f4f7bc0SXuan Zhuo static void eea_rx_post(struct eea_net_rx *rx, struct eea_rx_ctx *ctx)
557df9cad6bSXuan Zhuo {
558df9cad6bSXuan Zhuo 	u32 tailroom, headroom, room, len;
559df9cad6bSXuan Zhuo 	struct eea_rx_meta *meta;
560df9cad6bSXuan Zhuo 	struct eea_rx_desc *desc;
561df9cad6bSXuan Zhuo 	int err = 0, num = 0;
562df9cad6bSXuan Zhuo 	dma_addr_t addr;
563df9cad6bSXuan Zhuo 
564df9cad6bSXuan Zhuo 	tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
565df9cad6bSXuan Zhuo 	headroom = rx->headroom;
566df9cad6bSXuan Zhuo 	room = headroom + tailroom;
567df9cad6bSXuan Zhuo 
568df9cad6bSXuan Zhuo 	while (true) {
569df9cad6bSXuan Zhuo 		meta = eea_rx_meta_get(rx);
570df9cad6bSXuan Zhuo 		if (!meta)
571df9cad6bSXuan Zhuo 			break;
572df9cad6bSXuan Zhuo 
573df9cad6bSXuan Zhuo 		err = eea_alloc_rx_buffer(rx, meta);
574df9cad6bSXuan Zhuo 		if (err) {
575df9cad6bSXuan Zhuo 			eea_rx_meta_put(rx, meta);
576df9cad6bSXuan Zhuo 			break;
577df9cad6bSXuan Zhuo 		}
578df9cad6bSXuan Zhuo 
579df9cad6bSXuan Zhuo 		len = min_t(u32, PAGE_SIZE - meta->offset - room,
580df9cad6bSXuan Zhuo 			    EEA_RX_BUF_MAX_LEN);
581df9cad6bSXuan Zhuo 
582df9cad6bSXuan Zhuo 		len = ALIGN_DOWN(len, SMP_CACHE_BYTES);
583df9cad6bSXuan Zhuo 
584df9cad6bSXuan Zhuo 		addr = meta->dma + meta->offset + headroom;
585df9cad6bSXuan Zhuo 
586df9cad6bSXuan Zhuo 		desc = eea_ering_sq_alloc_desc(rx->ering, meta->id, true, 0);
587df9cad6bSXuan Zhuo 		desc->addr = cpu_to_le64(addr);
588df9cad6bSXuan Zhuo 		desc->len = cpu_to_le16(len);
589df9cad6bSXuan Zhuo 
590df9cad6bSXuan Zhuo 		if (meta->hdr_addr) {
591df9cad6bSXuan Zhuo 			eea_rx_dma_sync_hdr(rx, meta->hdr_dma);
592df9cad6bSXuan Zhuo 			desc->hdr_addr = cpu_to_le64(meta->hdr_dma);
593df9cad6bSXuan Zhuo 		}
594df9cad6bSXuan Zhuo 
595df9cad6bSXuan Zhuo 		eea_ering_sq_commit_desc(rx->ering);
596df9cad6bSXuan Zhuo 
597df9cad6bSXuan Zhuo 		meta->truesize = len + room;
598df9cad6bSXuan Zhuo 		meta->headroom = headroom;
599df9cad6bSXuan Zhuo 		meta->tailroom = tailroom;
600df9cad6bSXuan Zhuo 		meta->len = len;
601df9cad6bSXuan Zhuo 		meta->in_use = true;
602df9cad6bSXuan Zhuo 		++num;
603df9cad6bSXuan Zhuo 	}
604df9cad6bSXuan Zhuo 
605*5f4f7bc0SXuan Zhuo 	if (num) {
606df9cad6bSXuan Zhuo 		eea_ering_kick(rx->ering);
607*5f4f7bc0SXuan Zhuo 		++ctx->stats.kicks;
608*5f4f7bc0SXuan Zhuo 	}
609df9cad6bSXuan Zhuo }
610df9cad6bSXuan Zhuo 
611aa8bca4cSXuan Zhuo static int eea_poll(struct napi_struct *napi, int budget)
612aa8bca4cSXuan Zhuo {
613df9cad6bSXuan Zhuo 	struct eea_irq_blk *blk = container_of(napi, struct eea_irq_blk, napi);
614df9cad6bSXuan Zhuo 	struct eea_net_rx *rx = blk->rx;
615df9cad6bSXuan Zhuo 	struct eea_net_tx *tx = &rx->enet->tx[rx->index];
616df9cad6bSXuan Zhuo 	struct eea_rx_ctx ctx = {};
617df9cad6bSXuan Zhuo 	bool busy = false;
618df9cad6bSXuan Zhuo 	u32 received;
619df9cad6bSXuan Zhuo 
620df9cad6bSXuan Zhuo 	busy |= eea_poll_tx(tx, budget) >= budget;
621df9cad6bSXuan Zhuo 
622df9cad6bSXuan Zhuo 	received = eea_cleanrx(rx, budget, &ctx);
623df9cad6bSXuan Zhuo 
624df9cad6bSXuan Zhuo 	if (rx->ering->num_free > budget) {
625df9cad6bSXuan Zhuo 		/* Due to the hardware design, there is no notification when
626df9cad6bSXuan Zhuo 		 * buffers are exhausted. Therefore, we should proactively
627df9cad6bSXuan Zhuo 		 * pre-fill the buffers to avoid starvation.
628df9cad6bSXuan Zhuo 		 */
629*5f4f7bc0SXuan Zhuo 		eea_rx_post(rx, &ctx);
630df9cad6bSXuan Zhuo 
631df9cad6bSXuan Zhuo 		if (rx->ering->num - rx->ering->num_free < budget)
632df9cad6bSXuan Zhuo 			busy = true;
633df9cad6bSXuan Zhuo 	}
634df9cad6bSXuan Zhuo 
635*5f4f7bc0SXuan Zhuo 	eea_update_rx_stats(&rx->stats, &ctx.stats);
636*5f4f7bc0SXuan Zhuo 
637df9cad6bSXuan Zhuo 	busy |= received >= budget;
638df9cad6bSXuan Zhuo 
639df9cad6bSXuan Zhuo 	if (busy)
640df9cad6bSXuan Zhuo 		return budget;
641df9cad6bSXuan Zhuo 
642df9cad6bSXuan Zhuo 	if (napi_complete_done(napi, received))
643df9cad6bSXuan Zhuo 		eea_ering_irq_active(rx->ering, tx->ering);
644df9cad6bSXuan Zhuo 
645df9cad6bSXuan Zhuo 	return received;
646aa8bca4cSXuan Zhuo }
647aa8bca4cSXuan Zhuo 
648aa8bca4cSXuan Zhuo static void eea_free_rx_buffers(struct eea_net_rx *rx, struct eea_net_cfg *cfg)
649aa8bca4cSXuan Zhuo {
650aa8bca4cSXuan Zhuo 	struct eea_rx_meta *meta;
651aa8bca4cSXuan Zhuo 	u32 i;
652aa8bca4cSXuan Zhuo 
653df9cad6bSXuan Zhuo 	if (rx->pkt.head_skb) {
654df9cad6bSXuan Zhuo 		dev_kfree_skb(rx->pkt.head_skb);
655df9cad6bSXuan Zhuo 		rx->pkt.head_skb = NULL;
656df9cad6bSXuan Zhuo 	}
657df9cad6bSXuan Zhuo 
658aa8bca4cSXuan Zhuo 	for (i = 0; i < cfg->rx_ring_depth; ++i) {
659aa8bca4cSXuan Zhuo 		meta = &rx->meta[i];
660aa8bca4cSXuan Zhuo 		if (!meta->page)
661aa8bca4cSXuan Zhuo 			continue;
662aa8bca4cSXuan Zhuo 
663aa8bca4cSXuan Zhuo 		eea_free_rx_buffer(rx, meta, false);
664aa8bca4cSXuan Zhuo 	}
665aa8bca4cSXuan Zhuo }
666aa8bca4cSXuan Zhuo 
667aa8bca4cSXuan Zhuo static struct page_pool *eea_create_pp(struct eea_net_init_ctx *ctx, u32 idx)
668aa8bca4cSXuan Zhuo {
669aa8bca4cSXuan Zhuo 	struct page_pool_params pp_params = {0};
670aa8bca4cSXuan Zhuo 
671aa8bca4cSXuan Zhuo 	pp_params.order     = 0;
672aa8bca4cSXuan Zhuo 	pp_params.flags     = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
673aa8bca4cSXuan Zhuo 	pp_params.pool_size = ctx->cfg.rx_ring_depth;
674aa8bca4cSXuan Zhuo 	pp_params.nid       = dev_to_node(ctx->edev->dma_dev);
675aa8bca4cSXuan Zhuo 	pp_params.dev       = ctx->edev->dma_dev;
676aa8bca4cSXuan Zhuo 	pp_params.netdev    = ctx->netdev;
677aa8bca4cSXuan Zhuo 	pp_params.dma_dir   = DMA_FROM_DEVICE;
678aa8bca4cSXuan Zhuo 	pp_params.max_len   = PAGE_SIZE;
679aa8bca4cSXuan Zhuo 	pp_params.queue_idx = idx;
680aa8bca4cSXuan Zhuo 
681aa8bca4cSXuan Zhuo 	return page_pool_create(&pp_params);
682aa8bca4cSXuan Zhuo }
683aa8bca4cSXuan Zhuo 
684aa8bca4cSXuan Zhuo static void eea_destroy_page_pool(struct eea_net_rx *rx)
685aa8bca4cSXuan Zhuo {
686aa8bca4cSXuan Zhuo 	if (rx->pp)
687aa8bca4cSXuan Zhuo 		page_pool_destroy(rx->pp);
688aa8bca4cSXuan Zhuo }
689aa8bca4cSXuan Zhuo 
690aa8bca4cSXuan Zhuo void enet_rx_stop(struct eea_net_rx *rx)
691aa8bca4cSXuan Zhuo {
692aa8bca4cSXuan Zhuo 	if (rx->flags & EEA_ENABLE_F_NAPI) {
693aa8bca4cSXuan Zhuo 		rx->flags &= ~EEA_ENABLE_F_NAPI;
694aa8bca4cSXuan Zhuo 
695aa8bca4cSXuan Zhuo 		disable_irq(rx->enet->irq_blks[rx->index].irq);
696aa8bca4cSXuan Zhuo 		napi_disable(rx->napi);
697aa8bca4cSXuan Zhuo 
698aa8bca4cSXuan Zhuo 		page_pool_disable_direct_recycling(rx->pp);
699aa8bca4cSXuan Zhuo 		netif_napi_del(rx->napi);
700aa8bca4cSXuan Zhuo 	}
701aa8bca4cSXuan Zhuo }
702aa8bca4cSXuan Zhuo 
703aa8bca4cSXuan Zhuo void enet_rx_start(struct eea_net_rx *rx)
704aa8bca4cSXuan Zhuo {
705aa8bca4cSXuan Zhuo 	netif_napi_add(rx->enet->netdev, rx->napi, eea_poll);
706aa8bca4cSXuan Zhuo 
707aa8bca4cSXuan Zhuo 	page_pool_enable_direct_recycling(rx->pp, rx->napi);
708aa8bca4cSXuan Zhuo 
709aa8bca4cSXuan Zhuo 	napi_enable(rx->napi);
710aa8bca4cSXuan Zhuo 
711aa8bca4cSXuan Zhuo 	rx->flags |= EEA_ENABLE_F_NAPI;
712aa8bca4cSXuan Zhuo 
713aa8bca4cSXuan Zhuo 	local_bh_disable();
714aa8bca4cSXuan Zhuo 	napi_schedule(rx->napi);
715aa8bca4cSXuan Zhuo 	local_bh_enable();
716aa8bca4cSXuan Zhuo 
717aa8bca4cSXuan Zhuo 	enable_irq(rx->enet->irq_blks[rx->index].irq);
718aa8bca4cSXuan Zhuo }
719aa8bca4cSXuan Zhuo 
720aa8bca4cSXuan Zhuo /* Maybe called before eea_bind_q_and_cfg. So the cfg must be passed. */
721aa8bca4cSXuan Zhuo void eea_free_rx(struct eea_net_rx *rx, struct eea_net_cfg *cfg)
722aa8bca4cSXuan Zhuo {
723aa8bca4cSXuan Zhuo 	if (!rx)
724aa8bca4cSXuan Zhuo 		return;
725aa8bca4cSXuan Zhuo 
726aa8bca4cSXuan Zhuo 	if (rx->ering) {
727aa8bca4cSXuan Zhuo 		eea_ering_free(rx->ering);
728aa8bca4cSXuan Zhuo 		rx->ering = NULL;
729aa8bca4cSXuan Zhuo 	}
730aa8bca4cSXuan Zhuo 
731aa8bca4cSXuan Zhuo 	if (rx->meta) {
732aa8bca4cSXuan Zhuo 		eea_free_rx_buffers(rx, cfg);
733aa8bca4cSXuan Zhuo 		eea_free_rx_hdr(rx, cfg);
734aa8bca4cSXuan Zhuo 		kvfree(rx->meta);
735aa8bca4cSXuan Zhuo 		rx->meta = NULL;
736aa8bca4cSXuan Zhuo 	}
737aa8bca4cSXuan Zhuo 
738aa8bca4cSXuan Zhuo 	if (rx->pp) {
739aa8bca4cSXuan Zhuo 		eea_destroy_page_pool(rx);
740aa8bca4cSXuan Zhuo 		rx->pp = NULL;
741aa8bca4cSXuan Zhuo 	}
742aa8bca4cSXuan Zhuo 
743aa8bca4cSXuan Zhuo 	kfree(rx);
744aa8bca4cSXuan Zhuo }
745aa8bca4cSXuan Zhuo 
746aa8bca4cSXuan Zhuo static void eea_rx_meta_init(struct eea_net_rx *rx, u32 num)
747aa8bca4cSXuan Zhuo {
748aa8bca4cSXuan Zhuo 	struct eea_rx_meta *meta;
749aa8bca4cSXuan Zhuo 	int i;
750aa8bca4cSXuan Zhuo 
751aa8bca4cSXuan Zhuo 	rx->free = NULL;
752aa8bca4cSXuan Zhuo 
753aa8bca4cSXuan Zhuo 	for (i = 0; i < num; ++i) {
754aa8bca4cSXuan Zhuo 		meta = &rx->meta[i];
755aa8bca4cSXuan Zhuo 		meta->id = i;
756aa8bca4cSXuan Zhuo 		meta->next = rx->free;
757aa8bca4cSXuan Zhuo 		rx->free = meta;
758aa8bca4cSXuan Zhuo 	}
759aa8bca4cSXuan Zhuo }
760aa8bca4cSXuan Zhuo 
761aa8bca4cSXuan Zhuo struct eea_net_rx *eea_alloc_rx(struct eea_net_init_ctx *ctx, u32 idx)
762aa8bca4cSXuan Zhuo {
763aa8bca4cSXuan Zhuo 	struct eea_ring *ering;
764aa8bca4cSXuan Zhuo 	struct eea_net_rx *rx;
765aa8bca4cSXuan Zhuo 	int err;
766aa8bca4cSXuan Zhuo 
767aa8bca4cSXuan Zhuo 	rx = kzalloc(sizeof(*rx), GFP_KERNEL);
768aa8bca4cSXuan Zhuo 	if (!rx)
769aa8bca4cSXuan Zhuo 		return rx;
770aa8bca4cSXuan Zhuo 
771aa8bca4cSXuan Zhuo 	rx->index = idx;
772aa8bca4cSXuan Zhuo 	snprintf(rx->name, sizeof(rx->name), "rx.%u", idx);
773aa8bca4cSXuan Zhuo 
774*5f4f7bc0SXuan Zhuo 	u64_stats_init(&rx->stats.syncp);
775*5f4f7bc0SXuan Zhuo 
776aa8bca4cSXuan Zhuo 	/* ering */
777aa8bca4cSXuan Zhuo 	ering = eea_ering_alloc(idx * 2, ctx->cfg.rx_ring_depth, ctx->edev,
778aa8bca4cSXuan Zhuo 				ctx->cfg.rx_sq_desc_size,
779aa8bca4cSXuan Zhuo 				ctx->cfg.rx_cq_desc_size,
780aa8bca4cSXuan Zhuo 				rx->name);
781aa8bca4cSXuan Zhuo 	if (!ering)
782aa8bca4cSXuan Zhuo 		goto err_free_rx;
783aa8bca4cSXuan Zhuo 
784aa8bca4cSXuan Zhuo 	rx->ering = ering;
785aa8bca4cSXuan Zhuo 
786aa8bca4cSXuan Zhuo 	rx->dma_dev = ctx->edev->dma_dev;
787aa8bca4cSXuan Zhuo 
788aa8bca4cSXuan Zhuo 	/* meta */
789aa8bca4cSXuan Zhuo 	rx->meta = kvcalloc(ctx->cfg.rx_ring_depth,
790aa8bca4cSXuan Zhuo 			    sizeof(*rx->meta), GFP_KERNEL);
791aa8bca4cSXuan Zhuo 	if (!rx->meta)
792aa8bca4cSXuan Zhuo 		goto err_free_rx;
793aa8bca4cSXuan Zhuo 
794aa8bca4cSXuan Zhuo 	eea_rx_meta_init(rx, ctx->cfg.rx_ring_depth);
795aa8bca4cSXuan Zhuo 
796aa8bca4cSXuan Zhuo 	if (ctx->cfg.split_hdr) {
797aa8bca4cSXuan Zhuo 		err = eea_alloc_rx_hdr(ctx, rx);
798aa8bca4cSXuan Zhuo 		if (err)
799aa8bca4cSXuan Zhuo 			goto err_free_rx;
800aa8bca4cSXuan Zhuo 	}
801aa8bca4cSXuan Zhuo 
802aa8bca4cSXuan Zhuo 	rx->pp = eea_create_pp(ctx, idx);
803aa8bca4cSXuan Zhuo 	if (IS_ERR(rx->pp)) {
804aa8bca4cSXuan Zhuo 		err = PTR_ERR(rx->pp);
805aa8bca4cSXuan Zhuo 		rx->pp = NULL;
806aa8bca4cSXuan Zhuo 		goto err_free_rx;
807aa8bca4cSXuan Zhuo 	}
808aa8bca4cSXuan Zhuo 
809aa8bca4cSXuan Zhuo 	return rx;
810aa8bca4cSXuan Zhuo 
811aa8bca4cSXuan Zhuo err_free_rx:
812aa8bca4cSXuan Zhuo 	eea_free_rx(rx, &ctx->cfg);
813aa8bca4cSXuan Zhuo 	return NULL;
814aa8bca4cSXuan Zhuo }
815