xref: /linux-6.15/include/net/libeth/rx.h (revision ce5cf4af)
1306ec721SAlexander Lobakin /* SPDX-License-Identifier: GPL-2.0-only */
2306ec721SAlexander Lobakin /* Copyright (C) 2024 Intel Corporation */
3306ec721SAlexander Lobakin 
4306ec721SAlexander Lobakin #ifndef __LIBETH_RX_H
5306ec721SAlexander Lobakin #define __LIBETH_RX_H
6306ec721SAlexander Lobakin 
7e6c91556SAlexander Lobakin #include <linux/if_vlan.h>
8e6c91556SAlexander Lobakin 
9e6c91556SAlexander Lobakin #include <net/page_pool/helpers.h>
10306ec721SAlexander Lobakin #include <net/xdp.h>
11306ec721SAlexander Lobakin 
12e6c91556SAlexander Lobakin /* Rx buffer management */
13e6c91556SAlexander Lobakin 
14e6c91556SAlexander Lobakin /* Space reserved in front of each frame */
15e6c91556SAlexander Lobakin #define LIBETH_SKB_HEADROOM	(NET_SKB_PAD + NET_IP_ALIGN)
16e6c91556SAlexander Lobakin /* Maximum headroom for worst-case calculations */
17e6c91556SAlexander Lobakin #define LIBETH_MAX_HEADROOM	LIBETH_SKB_HEADROOM
18e6c91556SAlexander Lobakin /* Link layer / L2 overhead: Ethernet, 2 VLAN tags (C + S), FCS */
19e6c91556SAlexander Lobakin #define LIBETH_RX_LL_LEN	(ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN)
205aaac1aeSAlexander Lobakin /* Maximum supported L2-L4 header length */
215aaac1aeSAlexander Lobakin #define LIBETH_MAX_HEAD		roundup_pow_of_two(max(MAX_HEADER, 256))
22e6c91556SAlexander Lobakin 
23e6c91556SAlexander Lobakin /* Always use order-0 pages */
24e6c91556SAlexander Lobakin #define LIBETH_RX_PAGE_ORDER	0
25e6c91556SAlexander Lobakin /* Pick a sane buffer stride and align to a cacheline boundary */
26e6c91556SAlexander Lobakin #define LIBETH_RX_BUF_STRIDE	SKB_DATA_ALIGN(128)
27e6c91556SAlexander Lobakin /* HW-writeable space in one buffer: truesize - headroom/tailroom, aligned */
28e6c91556SAlexander Lobakin #define LIBETH_RX_PAGE_LEN(hr)						  \
29e6c91556SAlexander Lobakin 	ALIGN_DOWN(SKB_MAX_ORDER(hr, LIBETH_RX_PAGE_ORDER),		  \
30e6c91556SAlexander Lobakin 		   LIBETH_RX_BUF_STRIDE)
31e6c91556SAlexander Lobakin 
32e6c91556SAlexander Lobakin /**
33e6c91556SAlexander Lobakin  * struct libeth_fqe - structure representing an Rx buffer (fill queue element)
34e6c91556SAlexander Lobakin  * @page: page holding the buffer
35e6c91556SAlexander Lobakin  * @offset: offset from the page start (to the headroom)
36e6c91556SAlexander Lobakin  * @truesize: total space occupied by the buffer (w/ headroom and tailroom)
37e6c91556SAlexander Lobakin  *
38e6c91556SAlexander Lobakin  * Depending on the MTU, API switches between one-page-per-frame and shared
39e6c91556SAlexander Lobakin  * page model (to conserve memory on bigger-page platforms). In case of the
40e6c91556SAlexander Lobakin  * former, @offset is always 0 and @truesize is always ```PAGE_SIZE```.
41e6c91556SAlexander Lobakin  */
42e6c91556SAlexander Lobakin struct libeth_fqe {
43e6c91556SAlexander Lobakin 	struct page		*page;
44e6c91556SAlexander Lobakin 	u32			offset;
45e6c91556SAlexander Lobakin 	u32			truesize;
46e6c91556SAlexander Lobakin } __aligned_largest;
47e6c91556SAlexander Lobakin 
48e6c91556SAlexander Lobakin /**
495aaac1aeSAlexander Lobakin  * enum libeth_fqe_type - enum representing types of Rx buffers
505aaac1aeSAlexander Lobakin  * @LIBETH_FQE_MTU: buffer size is determined by MTU
515aaac1aeSAlexander Lobakin  * @LIBETH_FQE_SHORT: buffer size is smaller than MTU, for short frames
525aaac1aeSAlexander Lobakin  * @LIBETH_FQE_HDR: buffer size is ```LIBETH_MAX_HEAD```-sized, for headers
535aaac1aeSAlexander Lobakin  */
545aaac1aeSAlexander Lobakin enum libeth_fqe_type {
555aaac1aeSAlexander Lobakin 	LIBETH_FQE_MTU		= 0U,
565aaac1aeSAlexander Lobakin 	LIBETH_FQE_SHORT,
575aaac1aeSAlexander Lobakin 	LIBETH_FQE_HDR,
585aaac1aeSAlexander Lobakin };
595aaac1aeSAlexander Lobakin 
605aaac1aeSAlexander Lobakin /**
61e6c91556SAlexander Lobakin  * struct libeth_fq - structure representing a buffer (fill) queue
62e6c91556SAlexander Lobakin  * @fp: hotpath part of the structure
63e6c91556SAlexander Lobakin  * @pp: &page_pool for buffer management
64e6c91556SAlexander Lobakin  * @fqes: array of Rx buffers
65e6c91556SAlexander Lobakin  * @truesize: size to allocate per buffer, w/overhead
66e6c91556SAlexander Lobakin  * @count: number of descriptors/buffers the queue has
675aaac1aeSAlexander Lobakin  * @type: type of the buffers this queue has
685aaac1aeSAlexander Lobakin  * @hsplit: flag whether header split is enabled
69e6c91556SAlexander Lobakin  * @buf_len: HW-writeable length per each buffer
70e6c91556SAlexander Lobakin  * @nid: ID of the closest NUMA node with memory
71e6c91556SAlexander Lobakin  */
72e6c91556SAlexander Lobakin struct libeth_fq {
73e6c91556SAlexander Lobakin 	struct_group_tagged(libeth_fq_fp, fp,
74e6c91556SAlexander Lobakin 		struct page_pool	*pp;
75e6c91556SAlexander Lobakin 		struct libeth_fqe	*fqes;
76e6c91556SAlexander Lobakin 
77e6c91556SAlexander Lobakin 		u32			truesize;
78e6c91556SAlexander Lobakin 		u32			count;
79e6c91556SAlexander Lobakin 	);
80e6c91556SAlexander Lobakin 
81e6c91556SAlexander Lobakin 	/* Cold fields */
825aaac1aeSAlexander Lobakin 	enum libeth_fqe_type	type:2;
835aaac1aeSAlexander Lobakin 	bool			hsplit:1;
845aaac1aeSAlexander Lobakin 
85e6c91556SAlexander Lobakin 	u32			buf_len;
86e6c91556SAlexander Lobakin 	int			nid;
87e6c91556SAlexander Lobakin };
88e6c91556SAlexander Lobakin 
89e6c91556SAlexander Lobakin int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi);
90e6c91556SAlexander Lobakin void libeth_rx_fq_destroy(struct libeth_fq *fq);
91e6c91556SAlexander Lobakin 
92e6c91556SAlexander Lobakin /**
93e6c91556SAlexander Lobakin  * libeth_rx_alloc - allocate a new Rx buffer
94e6c91556SAlexander Lobakin  * @fq: fill queue to allocate for
95e6c91556SAlexander Lobakin  * @i: index of the buffer within the queue
96e6c91556SAlexander Lobakin  *
97e6c91556SAlexander Lobakin  * Return: DMA address to be passed to HW for Rx on successful allocation,
98e6c91556SAlexander Lobakin  * ```DMA_MAPPING_ERROR``` otherwise.
99e6c91556SAlexander Lobakin  */
libeth_rx_alloc(const struct libeth_fq_fp * fq,u32 i)100e6c91556SAlexander Lobakin static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq, u32 i)
101e6c91556SAlexander Lobakin {
102e6c91556SAlexander Lobakin 	struct libeth_fqe *buf = &fq->fqes[i];
103e6c91556SAlexander Lobakin 
104e6c91556SAlexander Lobakin 	buf->truesize = fq->truesize;
105e6c91556SAlexander Lobakin 	buf->page = page_pool_dev_alloc(fq->pp, &buf->offset, &buf->truesize);
106e6c91556SAlexander Lobakin 	if (unlikely(!buf->page))
107e6c91556SAlexander Lobakin 		return DMA_MAPPING_ERROR;
108e6c91556SAlexander Lobakin 
109e6c91556SAlexander Lobakin 	return page_pool_get_dma_addr(buf->page) + buf->offset +
110e6c91556SAlexander Lobakin 	       fq->pp->p.offset;
111e6c91556SAlexander Lobakin }
112e6c91556SAlexander Lobakin 
113e6c91556SAlexander Lobakin void libeth_rx_recycle_slow(struct page *page);
114e6c91556SAlexander Lobakin 
115e6c91556SAlexander Lobakin /**
116e6c91556SAlexander Lobakin  * libeth_rx_sync_for_cpu - synchronize or recycle buffer post DMA
117e6c91556SAlexander Lobakin  * @fqe: buffer to process
118e6c91556SAlexander Lobakin  * @len: frame length from the descriptor
119e6c91556SAlexander Lobakin  *
120e6c91556SAlexander Lobakin  * Process the buffer after it's written by HW. The regular path is to
121e6c91556SAlexander Lobakin  * synchronize DMA for CPU, but in case of no data it will be immediately
122e6c91556SAlexander Lobakin  * recycled back to its PP.
123e6c91556SAlexander Lobakin  *
124e6c91556SAlexander Lobakin  * Return: true when there's data to process, false otherwise.
125e6c91556SAlexander Lobakin  */
libeth_rx_sync_for_cpu(const struct libeth_fqe * fqe,u32 len)126e6c91556SAlexander Lobakin static inline bool libeth_rx_sync_for_cpu(const struct libeth_fqe *fqe,
127e6c91556SAlexander Lobakin 					  u32 len)
128e6c91556SAlexander Lobakin {
129e6c91556SAlexander Lobakin 	struct page *page = fqe->page;
130e6c91556SAlexander Lobakin 
131e6c91556SAlexander Lobakin 	/* Very rare, but possible case. The most common reason:
132e6c91556SAlexander Lobakin 	 * the last fragment contained FCS only, which was then
133e6c91556SAlexander Lobakin 	 * stripped by the HW.
134e6c91556SAlexander Lobakin 	 */
135e6c91556SAlexander Lobakin 	if (unlikely(!len)) {
136e6c91556SAlexander Lobakin 		libeth_rx_recycle_slow(page);
137e6c91556SAlexander Lobakin 		return false;
138e6c91556SAlexander Lobakin 	}
139e6c91556SAlexander Lobakin 
140e6c91556SAlexander Lobakin 	page_pool_dma_sync_for_cpu(page->pp, page, fqe->offset, len);
141e6c91556SAlexander Lobakin 
142e6c91556SAlexander Lobakin 	return true;
143e6c91556SAlexander Lobakin }
144e6c91556SAlexander Lobakin 
145306ec721SAlexander Lobakin /* Converting abstract packet type numbers into a software structure with
146306ec721SAlexander Lobakin  * the packet parameters to do O(1) lookup on Rx.
147306ec721SAlexander Lobakin  */
148306ec721SAlexander Lobakin 
149306ec721SAlexander Lobakin enum {
150306ec721SAlexander Lobakin 	LIBETH_RX_PT_OUTER_L2			= 0U,
151306ec721SAlexander Lobakin 	LIBETH_RX_PT_OUTER_IPV4,
152306ec721SAlexander Lobakin 	LIBETH_RX_PT_OUTER_IPV6,
153306ec721SAlexander Lobakin };
154306ec721SAlexander Lobakin 
155306ec721SAlexander Lobakin enum {
156306ec721SAlexander Lobakin 	LIBETH_RX_PT_NOT_FRAG			= 0U,
157306ec721SAlexander Lobakin 	LIBETH_RX_PT_FRAG,
158306ec721SAlexander Lobakin };
159306ec721SAlexander Lobakin 
160306ec721SAlexander Lobakin enum {
161306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_IP_NONE		= 0U,
162306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_IP_IP,
163306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_IP_GRENAT,
164306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_IP_GRENAT_MAC,
165306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_IP_GRENAT_MAC_VLAN,
166306ec721SAlexander Lobakin };
167306ec721SAlexander Lobakin 
168306ec721SAlexander Lobakin enum {
169306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_END_NONE		= 0U,
170306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_END_IPV4,
171306ec721SAlexander Lobakin 	LIBETH_RX_PT_TUNNEL_END_IPV6,
172306ec721SAlexander Lobakin };
173306ec721SAlexander Lobakin 
174306ec721SAlexander Lobakin enum {
175306ec721SAlexander Lobakin 	LIBETH_RX_PT_INNER_NONE			= 0U,
176306ec721SAlexander Lobakin 	LIBETH_RX_PT_INNER_UDP,
177306ec721SAlexander Lobakin 	LIBETH_RX_PT_INNER_TCP,
178306ec721SAlexander Lobakin 	LIBETH_RX_PT_INNER_SCTP,
179306ec721SAlexander Lobakin 	LIBETH_RX_PT_INNER_ICMP,
180306ec721SAlexander Lobakin 	LIBETH_RX_PT_INNER_TIMESYNC,
181306ec721SAlexander Lobakin };
182306ec721SAlexander Lobakin 
183306ec721SAlexander Lobakin #define LIBETH_RX_PT_PAYLOAD_NONE		PKT_HASH_TYPE_NONE
184306ec721SAlexander Lobakin #define LIBETH_RX_PT_PAYLOAD_L2			PKT_HASH_TYPE_L2
185306ec721SAlexander Lobakin #define LIBETH_RX_PT_PAYLOAD_L3			PKT_HASH_TYPE_L3
186306ec721SAlexander Lobakin #define LIBETH_RX_PT_PAYLOAD_L4			PKT_HASH_TYPE_L4
187306ec721SAlexander Lobakin 
188306ec721SAlexander Lobakin struct libeth_rx_pt {
189306ec721SAlexander Lobakin 	u32					outer_ip:2;
190306ec721SAlexander Lobakin 	u32					outer_frag:1;
191306ec721SAlexander Lobakin 	u32					tunnel_type:3;
192306ec721SAlexander Lobakin 	u32					tunnel_end_prot:2;
193306ec721SAlexander Lobakin 	u32					tunnel_end_frag:1;
194306ec721SAlexander Lobakin 	u32					inner_prot:3;
195306ec721SAlexander Lobakin 	enum pkt_hash_types			payload_layer:2;
196306ec721SAlexander Lobakin 
197306ec721SAlexander Lobakin 	u32					pad:2;
198306ec721SAlexander Lobakin 	enum xdp_rss_hash_type			hash_type:16;
199306ec721SAlexander Lobakin };
200306ec721SAlexander Lobakin 
201*ce5cf4afSMateusz Polchlopek /**
202*ce5cf4afSMateusz Polchlopek  * struct libeth_rx_csum - checksum offload bits decoded from the Rx descriptor
203*ce5cf4afSMateusz Polchlopek  * @l3l4p: detectable L3 and L4 integrity check is processed by the hardware
204*ce5cf4afSMateusz Polchlopek  * @ipe: IP checksum error
205*ce5cf4afSMateusz Polchlopek  * @eipe: external (outermost) IP header (only for tunels)
206*ce5cf4afSMateusz Polchlopek  * @eudpe: external (outermost) UDP checksum error (only for tunels)
207*ce5cf4afSMateusz Polchlopek  * @ipv6exadd: IPv6 header with extension headers
208*ce5cf4afSMateusz Polchlopek  * @l4e: L4 integrity error
209*ce5cf4afSMateusz Polchlopek  * @pprs: set for packets that skip checksum calculation in the HW pre parser
210*ce5cf4afSMateusz Polchlopek  * @nat: the packet is a UDP tunneled packet
211*ce5cf4afSMateusz Polchlopek  * @raw_csum_valid: set if raw checksum is valid
212*ce5cf4afSMateusz Polchlopek  * @pad: padding to naturally align raw_csum field
213*ce5cf4afSMateusz Polchlopek  * @raw_csum: raw checksum
214*ce5cf4afSMateusz Polchlopek  */
215*ce5cf4afSMateusz Polchlopek struct libeth_rx_csum {
216*ce5cf4afSMateusz Polchlopek 	u32					l3l4p:1;
217*ce5cf4afSMateusz Polchlopek 	u32					ipe:1;
218*ce5cf4afSMateusz Polchlopek 	u32					eipe:1;
219*ce5cf4afSMateusz Polchlopek 	u32					eudpe:1;
220*ce5cf4afSMateusz Polchlopek 	u32					ipv6exadd:1;
221*ce5cf4afSMateusz Polchlopek 	u32					l4e:1;
222*ce5cf4afSMateusz Polchlopek 	u32					pprs:1;
223*ce5cf4afSMateusz Polchlopek 	u32					nat:1;
224*ce5cf4afSMateusz Polchlopek 
225*ce5cf4afSMateusz Polchlopek 	u32					raw_csum_valid:1;
226*ce5cf4afSMateusz Polchlopek 	u32					pad:7;
227*ce5cf4afSMateusz Polchlopek 	u32					raw_csum:16;
228*ce5cf4afSMateusz Polchlopek };
229*ce5cf4afSMateusz Polchlopek 
230*ce5cf4afSMateusz Polchlopek /**
231*ce5cf4afSMateusz Polchlopek  * struct libeth_rqe_info - receive queue element info
232*ce5cf4afSMateusz Polchlopek  * @len: packet length
233*ce5cf4afSMateusz Polchlopek  * @ptype: packet type based on types programmed into the device
234*ce5cf4afSMateusz Polchlopek  * @eop: whether it's the last fragment of the packet
235*ce5cf4afSMateusz Polchlopek  * @rxe: MAC errors: CRC, Alignment, Oversize, Undersizes, Length error
236*ce5cf4afSMateusz Polchlopek  * @vlan: C-VLAN or S-VLAN tag depending on the VLAN offload configuration
237*ce5cf4afSMateusz Polchlopek  */
238*ce5cf4afSMateusz Polchlopek struct libeth_rqe_info {
239*ce5cf4afSMateusz Polchlopek 	u32					len;
240*ce5cf4afSMateusz Polchlopek 
241*ce5cf4afSMateusz Polchlopek 	u32					ptype:14;
242*ce5cf4afSMateusz Polchlopek 	u32					eop:1;
243*ce5cf4afSMateusz Polchlopek 	u32					rxe:1;
244*ce5cf4afSMateusz Polchlopek 
245*ce5cf4afSMateusz Polchlopek 	u32					vlan:16;
246*ce5cf4afSMateusz Polchlopek };
247*ce5cf4afSMateusz Polchlopek 
248306ec721SAlexander Lobakin void libeth_rx_pt_gen_hash_type(struct libeth_rx_pt *pt);
249306ec721SAlexander Lobakin 
250306ec721SAlexander Lobakin /**
251306ec721SAlexander Lobakin  * libeth_rx_pt_get_ip_ver - get IP version from a packet type structure
252306ec721SAlexander Lobakin  * @pt: packet type params
253306ec721SAlexander Lobakin  *
254306ec721SAlexander Lobakin  * Wrapper to compile out the IPv6 code from the drivers when not supported
255306ec721SAlexander Lobakin  * by the kernel.
256306ec721SAlexander Lobakin  *
257306ec721SAlexander Lobakin  * Return: @pt.outer_ip or stub for IPv6 when not compiled-in.
258306ec721SAlexander Lobakin  */
libeth_rx_pt_get_ip_ver(struct libeth_rx_pt pt)259306ec721SAlexander Lobakin static inline u32 libeth_rx_pt_get_ip_ver(struct libeth_rx_pt pt)
260306ec721SAlexander Lobakin {
261306ec721SAlexander Lobakin #if !IS_ENABLED(CONFIG_IPV6)
262306ec721SAlexander Lobakin 	switch (pt.outer_ip) {
263306ec721SAlexander Lobakin 	case LIBETH_RX_PT_OUTER_IPV4:
264306ec721SAlexander Lobakin 		return LIBETH_RX_PT_OUTER_IPV4;
265306ec721SAlexander Lobakin 	default:
266306ec721SAlexander Lobakin 		return LIBETH_RX_PT_OUTER_L2;
267306ec721SAlexander Lobakin 	}
268306ec721SAlexander Lobakin #else
269306ec721SAlexander Lobakin 	return pt.outer_ip;
270306ec721SAlexander Lobakin #endif
271306ec721SAlexander Lobakin }
272306ec721SAlexander Lobakin 
273306ec721SAlexander Lobakin /* libeth_has_*() can be used to quickly check whether the HW metadata is
274306ec721SAlexander Lobakin  * available to avoid further expensive processing such as descriptor reads.
275306ec721SAlexander Lobakin  * They already check for the corresponding netdev feature to be enabled,
276306ec721SAlexander Lobakin  * thus can be used as drop-in replacements.
277306ec721SAlexander Lobakin  */
278306ec721SAlexander Lobakin 
libeth_rx_pt_has_checksum(const struct net_device * dev,struct libeth_rx_pt pt)279306ec721SAlexander Lobakin static inline bool libeth_rx_pt_has_checksum(const struct net_device *dev,
280306ec721SAlexander Lobakin 					     struct libeth_rx_pt pt)
281306ec721SAlexander Lobakin {
282306ec721SAlexander Lobakin 	/* Non-zero _INNER* is only possible when _OUTER_IPV* is set,
283306ec721SAlexander Lobakin 	 * it is enough to check only for the L4 type.
284306ec721SAlexander Lobakin 	 */
285306ec721SAlexander Lobakin 	return likely(pt.inner_prot > LIBETH_RX_PT_INNER_NONE &&
286306ec721SAlexander Lobakin 		      (dev->features & NETIF_F_RXCSUM));
287306ec721SAlexander Lobakin }
288306ec721SAlexander Lobakin 
libeth_rx_pt_has_hash(const struct net_device * dev,struct libeth_rx_pt pt)289306ec721SAlexander Lobakin static inline bool libeth_rx_pt_has_hash(const struct net_device *dev,
290306ec721SAlexander Lobakin 					 struct libeth_rx_pt pt)
291306ec721SAlexander Lobakin {
292306ec721SAlexander Lobakin 	return likely(pt.payload_layer > LIBETH_RX_PT_PAYLOAD_NONE &&
293306ec721SAlexander Lobakin 		      (dev->features & NETIF_F_RXHASH));
294306ec721SAlexander Lobakin }
295306ec721SAlexander Lobakin 
296306ec721SAlexander Lobakin /**
297306ec721SAlexander Lobakin  * libeth_rx_pt_set_hash - fill in skb hash value basing on the PT
298306ec721SAlexander Lobakin  * @skb: skb to fill the hash in
299306ec721SAlexander Lobakin  * @hash: 32-bit hash value from the descriptor
300306ec721SAlexander Lobakin  * @pt: packet type
301306ec721SAlexander Lobakin  */
libeth_rx_pt_set_hash(struct sk_buff * skb,u32 hash,struct libeth_rx_pt pt)302306ec721SAlexander Lobakin static inline void libeth_rx_pt_set_hash(struct sk_buff *skb, u32 hash,
303306ec721SAlexander Lobakin 					 struct libeth_rx_pt pt)
304306ec721SAlexander Lobakin {
305306ec721SAlexander Lobakin 	skb_set_hash(skb, hash, pt.payload_layer);
306306ec721SAlexander Lobakin }
307306ec721SAlexander Lobakin 
308306ec721SAlexander Lobakin #endif /* __LIBETH_RX_H */
309