xref: /openbmc/linux/include/net/busy_poll.h (revision f3c3091b98d5d52df40aaf27f11530701d02ac56)
1a61127c2SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2076bb0c8SEliezer Tamir /*
38b80cda5SEliezer Tamir  * net busy poll support
4076bb0c8SEliezer Tamir  * Copyright(c) 2013 Intel Corporation.
5076bb0c8SEliezer Tamir  *
6076bb0c8SEliezer Tamir  * Author: Eliezer Tamir
7076bb0c8SEliezer Tamir  *
8076bb0c8SEliezer Tamir  * Contact Information:
9076bb0c8SEliezer Tamir  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
10076bb0c8SEliezer Tamir  */
11076bb0c8SEliezer Tamir 
128b80cda5SEliezer Tamir #ifndef _LINUX_NET_BUSY_POLL_H
138b80cda5SEliezer Tamir #define _LINUX_NET_BUSY_POLL_H
14076bb0c8SEliezer Tamir 
15076bb0c8SEliezer Tamir #include <linux/netdevice.h>
16e6017571SIngo Molnar #include <linux/sched/clock.h>
17174cd4b1SIngo Molnar #include <linux/sched/signal.h>
18076bb0c8SEliezer Tamir #include <net/ip.h>
19680ee045SJakub Kicinski #include <net/xdp.h>
20076bb0c8SEliezer Tamir 
21545cd5e5SAlexander Duyck /*		0 - Reserved to indicate value not set
22545cd5e5SAlexander Duyck  *     1..NR_CPUS - Reserved for sender_cpu
23545cd5e5SAlexander Duyck  *  NR_CPUS+1..~0 - Region available for NAPI IDs
24545cd5e5SAlexander Duyck  */
25545cd5e5SAlexander Duyck #define MIN_NAPI_ID ((unsigned int)(NR_CPUS + 1))
26545cd5e5SAlexander Duyck 
277c951cafSBjörn Töpel #define BUSY_POLL_BUDGET 8
287c951cafSBjörn Töpel 
29e4dde412SDaniel Borkmann #ifdef CONFIG_NET_RX_BUSY_POLL
30e4dde412SDaniel Borkmann 
31e4dde412SDaniel Borkmann struct napi_struct;
32e4dde412SDaniel Borkmann extern unsigned int sysctl_net_busy_read __read_mostly;
33e4dde412SDaniel Borkmann extern unsigned int sysctl_net_busy_poll __read_mostly;
34e4dde412SDaniel Borkmann 
net_busy_loop_on(void)35076bb0c8SEliezer Tamir static inline bool net_busy_loop_on(void)
36076bb0c8SEliezer Tamir {
37c42b7cddSKuniyuki Iwashima 	return READ_ONCE(sysctl_net_busy_poll);
38076bb0c8SEliezer Tamir }
39076bb0c8SEliezer Tamir 
sk_can_busy_loop(const struct sock * sk)4021cb84c4SEric Dumazet static inline bool sk_can_busy_loop(const struct sock *sk)
41076bb0c8SEliezer Tamir {
420dbffbb5SEric Dumazet 	return READ_ONCE(sk->sk_ll_usec) && !signal_pending(current);
43076bb0c8SEliezer Tamir }
44076bb0c8SEliezer Tamir 
457db6b048SSridhar Samudrala bool sk_busy_loop_end(void *p, unsigned long start_time);
467db6b048SSridhar Samudrala 
477db6b048SSridhar Samudrala void napi_busy_loop(unsigned int napi_id,
487db6b048SSridhar Samudrala 		    bool (*loop_end)(void *, unsigned long),
497c951cafSBjörn Töpel 		    void *loop_end_arg, bool prefer_busy_poll, u16 budget);
50076bb0c8SEliezer Tamir 
51e0d1095aSCong Wang #else /* CONFIG_NET_RX_BUSY_POLL */
net_busy_loop_on(void)52076bb0c8SEliezer Tamir static inline unsigned long net_busy_loop_on(void)
53076bb0c8SEliezer Tamir {
54076bb0c8SEliezer Tamir 	return 0;
55076bb0c8SEliezer Tamir }
56076bb0c8SEliezer Tamir 
sk_can_busy_loop(struct sock * sk)57076bb0c8SEliezer Tamir static inline bool sk_can_busy_loop(struct sock *sk)
58076bb0c8SEliezer Tamir {
59076bb0c8SEliezer Tamir 	return false;
60076bb0c8SEliezer Tamir }
61076bb0c8SEliezer Tamir 
62e0d1095aSCong Wang #endif /* CONFIG_NET_RX_BUSY_POLL */
63e68b6e50SEric Dumazet 
busy_loop_current_time(void)6437056719SAlexander Duyck static inline unsigned long busy_loop_current_time(void)
6537056719SAlexander Duyck {
6637056719SAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
67*55526afdSEric Dumazet 	return (unsigned long)(ktime_get_ns() >> 10);
6837056719SAlexander Duyck #else
6937056719SAlexander Duyck 	return 0;
7037056719SAlexander Duyck #endif
7137056719SAlexander Duyck }
7237056719SAlexander Duyck 
7337056719SAlexander Duyck /* in poll/select we use the global sysctl_net_ll_poll value */
busy_loop_timeout(unsigned long start_time)7437056719SAlexander Duyck static inline bool busy_loop_timeout(unsigned long start_time)
7537056719SAlexander Duyck {
7637056719SAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
7737056719SAlexander Duyck 	unsigned long bp_usec = READ_ONCE(sysctl_net_busy_poll);
7837056719SAlexander Duyck 
7937056719SAlexander Duyck 	if (bp_usec) {
8037056719SAlexander Duyck 		unsigned long end_time = start_time + bp_usec;
8137056719SAlexander Duyck 		unsigned long now = busy_loop_current_time();
8237056719SAlexander Duyck 
8337056719SAlexander Duyck 		return time_after(now, end_time);
8437056719SAlexander Duyck 	}
8537056719SAlexander Duyck #endif
8637056719SAlexander Duyck 	return true;
8737056719SAlexander Duyck }
8837056719SAlexander Duyck 
sk_busy_loop_timeout(struct sock * sk,unsigned long start_time)8937056719SAlexander Duyck static inline bool sk_busy_loop_timeout(struct sock *sk,
9037056719SAlexander Duyck 					unsigned long start_time)
9137056719SAlexander Duyck {
9237056719SAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
9337056719SAlexander Duyck 	unsigned long bp_usec = READ_ONCE(sk->sk_ll_usec);
9437056719SAlexander Duyck 
9537056719SAlexander Duyck 	if (bp_usec) {
9637056719SAlexander Duyck 		unsigned long end_time = start_time + bp_usec;
9737056719SAlexander Duyck 		unsigned long now = busy_loop_current_time();
9837056719SAlexander Duyck 
9937056719SAlexander Duyck 		return time_after(now, end_time);
10037056719SAlexander Duyck 	}
10137056719SAlexander Duyck #endif
10237056719SAlexander Duyck 	return true;
10337056719SAlexander Duyck }
10437056719SAlexander Duyck 
sk_busy_loop(struct sock * sk,int nonblock)1057db6b048SSridhar Samudrala static inline void sk_busy_loop(struct sock *sk, int nonblock)
1067db6b048SSridhar Samudrala {
1077db6b048SSridhar Samudrala #ifdef CONFIG_NET_RX_BUSY_POLL
1087db6b048SSridhar Samudrala 	unsigned int napi_id = READ_ONCE(sk->sk_napi_id);
1097db6b048SSridhar Samudrala 
1107db6b048SSridhar Samudrala 	if (napi_id >= MIN_NAPI_ID)
1117fd3253aSBjörn Töpel 		napi_busy_loop(napi_id, nonblock ? NULL : sk_busy_loop_end, sk,
1127c951cafSBjörn Töpel 			       READ_ONCE(sk->sk_prefer_busy_poll),
1137c951cafSBjörn Töpel 			       READ_ONCE(sk->sk_busy_poll_budget) ?: BUSY_POLL_BUDGET);
1147db6b048SSridhar Samudrala #endif
1157db6b048SSridhar Samudrala }
1167db6b048SSridhar Samudrala 
117d2e64dbbSAlexander Duyck /* used in the NIC receive handler to mark the skb */
skb_mark_napi_id(struct sk_buff * skb,struct napi_struct * napi)118d2e64dbbSAlexander Duyck static inline void skb_mark_napi_id(struct sk_buff *skb,
119d2e64dbbSAlexander Duyck 				    struct napi_struct *napi)
120d2e64dbbSAlexander Duyck {
121d2e64dbbSAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
12278e57f15SAmritha Nambiar 	/* If the skb was already marked with a valid NAPI ID, avoid overwriting
12378e57f15SAmritha Nambiar 	 * it.
12478e57f15SAmritha Nambiar 	 */
12578e57f15SAmritha Nambiar 	if (skb->napi_id < MIN_NAPI_ID)
126d2e64dbbSAlexander Duyck 		skb->napi_id = napi->napi_id;
127d2e64dbbSAlexander Duyck #endif
128d2e64dbbSAlexander Duyck }
129d2e64dbbSAlexander Duyck 
130e68b6e50SEric Dumazet /* used in the protocol hanlder to propagate the napi_id to the socket */
sk_mark_napi_id(struct sock * sk,const struct sk_buff * skb)131e68b6e50SEric Dumazet static inline void sk_mark_napi_id(struct sock *sk, const struct sk_buff *skb)
132e68b6e50SEric Dumazet {
133e68b6e50SEric Dumazet #ifdef CONFIG_NET_RX_BUSY_POLL
1342b13af8aSEric Dumazet 	if (unlikely(READ_ONCE(sk->sk_napi_id) != skb->napi_id))
135ee8d153dSEric Dumazet 		WRITE_ONCE(sk->sk_napi_id, skb->napi_id);
136e68b6e50SEric Dumazet #endif
137a37a0ee4SEric Dumazet 	sk_rx_queue_update(sk, skb);
138e68b6e50SEric Dumazet }
139e68b6e50SEric Dumazet 
14003cfda4fSEric Dumazet /* Variant of sk_mark_napi_id() for passive flow setup,
14103cfda4fSEric Dumazet  * as sk->sk_napi_id and sk->sk_rx_queue_mapping content
14203cfda4fSEric Dumazet  * needs to be set.
14303cfda4fSEric Dumazet  */
sk_mark_napi_id_set(struct sock * sk,const struct sk_buff * skb)14403cfda4fSEric Dumazet static inline void sk_mark_napi_id_set(struct sock *sk,
14503cfda4fSEric Dumazet 				       const struct sk_buff *skb)
14603cfda4fSEric Dumazet {
14703cfda4fSEric Dumazet #ifdef CONFIG_NET_RX_BUSY_POLL
14803cfda4fSEric Dumazet 	WRITE_ONCE(sk->sk_napi_id, skb->napi_id);
14903cfda4fSEric Dumazet #endif
15003cfda4fSEric Dumazet 	sk_rx_queue_set(sk, skb);
15103cfda4fSEric Dumazet }
15203cfda4fSEric Dumazet 
__sk_mark_napi_id_once(struct sock * sk,unsigned int napi_id)153ba058174SDaniel Borkmann static inline void __sk_mark_napi_id_once(struct sock *sk, unsigned int napi_id)
154b02e5a0eSBjörn Töpel {
155b02e5a0eSBjörn Töpel #ifdef CONFIG_NET_RX_BUSY_POLL
156b02e5a0eSBjörn Töpel 	if (!READ_ONCE(sk->sk_napi_id))
157b02e5a0eSBjörn Töpel 		WRITE_ONCE(sk->sk_napi_id, napi_id);
158b02e5a0eSBjörn Töpel #endif
159b02e5a0eSBjörn Töpel }
160b02e5a0eSBjörn Töpel 
161e68b6e50SEric Dumazet /* variant used for unconnected sockets */
sk_mark_napi_id_once(struct sock * sk,const struct sk_buff * skb)162e68b6e50SEric Dumazet static inline void sk_mark_napi_id_once(struct sock *sk,
163e68b6e50SEric Dumazet 					const struct sk_buff *skb)
164e68b6e50SEric Dumazet {
165ba058174SDaniel Borkmann #ifdef CONFIG_NET_RX_BUSY_POLL
166ba058174SDaniel Borkmann 	__sk_mark_napi_id_once(sk, skb->napi_id);
167ba058174SDaniel Borkmann #endif
168b02e5a0eSBjörn Töpel }
169b02e5a0eSBjörn Töpel 
sk_mark_napi_id_once_xdp(struct sock * sk,const struct xdp_buff * xdp)170b02e5a0eSBjörn Töpel static inline void sk_mark_napi_id_once_xdp(struct sock *sk,
171b02e5a0eSBjörn Töpel 					    const struct xdp_buff *xdp)
172b02e5a0eSBjörn Töpel {
173ba058174SDaniel Borkmann #ifdef CONFIG_NET_RX_BUSY_POLL
174ba058174SDaniel Borkmann 	__sk_mark_napi_id_once(sk, xdp->rxq->napi_id);
175ba058174SDaniel Borkmann #endif
176e68b6e50SEric Dumazet }
177e68b6e50SEric Dumazet 
1788b80cda5SEliezer Tamir #endif /* _LINUX_NET_BUSY_POLL_H */
179