xref: /openbmc/linux/include/net/busy_poll.h (revision c6345ce7d361dce1b5d02a2181ccb598c27fd7ae)
1076bb0c8SEliezer Tamir /*
28b80cda5SEliezer Tamir  * net busy poll support
3076bb0c8SEliezer Tamir  * Copyright(c) 2013 Intel Corporation.
4076bb0c8SEliezer Tamir  *
5076bb0c8SEliezer Tamir  * This program is free software; you can redistribute it and/or modify it
6076bb0c8SEliezer Tamir  * under the terms and conditions of the GNU General Public License,
7076bb0c8SEliezer Tamir  * version 2, as published by the Free Software Foundation.
8076bb0c8SEliezer Tamir  *
9076bb0c8SEliezer Tamir  * This program is distributed in the hope it will be useful, but WITHOUT
10076bb0c8SEliezer Tamir  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11076bb0c8SEliezer Tamir  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12076bb0c8SEliezer Tamir  * more details.
13076bb0c8SEliezer Tamir  *
14076bb0c8SEliezer Tamir  * You should have received a copy of the GNU General Public License along with
15076bb0c8SEliezer Tamir  * this program; if not, write to the Free Software Foundation, Inc.,
16076bb0c8SEliezer Tamir  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17076bb0c8SEliezer Tamir  *
18076bb0c8SEliezer Tamir  * Author: Eliezer Tamir
19076bb0c8SEliezer Tamir  *
20076bb0c8SEliezer Tamir  * Contact Information:
21076bb0c8SEliezer Tamir  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
22076bb0c8SEliezer Tamir  */
23076bb0c8SEliezer Tamir 
248b80cda5SEliezer Tamir #ifndef _LINUX_NET_BUSY_POLL_H
258b80cda5SEliezer Tamir #define _LINUX_NET_BUSY_POLL_H
26076bb0c8SEliezer Tamir 
27076bb0c8SEliezer Tamir #include <linux/netdevice.h>
28e6017571SIngo Molnar #include <linux/sched/clock.h>
29174cd4b1SIngo Molnar #include <linux/sched/signal.h>
30076bb0c8SEliezer Tamir #include <net/ip.h>
31076bb0c8SEliezer Tamir 
32545cd5e5SAlexander Duyck /*		0 - Reserved to indicate value not set
33545cd5e5SAlexander Duyck  *     1..NR_CPUS - Reserved for sender_cpu
34545cd5e5SAlexander Duyck  *  NR_CPUS+1..~0 - Region available for NAPI IDs
35545cd5e5SAlexander Duyck  */
36545cd5e5SAlexander Duyck #define MIN_NAPI_ID ((unsigned int)(NR_CPUS + 1))
37545cd5e5SAlexander Duyck 
38e4dde412SDaniel Borkmann #ifdef CONFIG_NET_RX_BUSY_POLL
39e4dde412SDaniel Borkmann 
40e4dde412SDaniel Borkmann struct napi_struct;
41e4dde412SDaniel Borkmann extern unsigned int sysctl_net_busy_read __read_mostly;
42e4dde412SDaniel Borkmann extern unsigned int sysctl_net_busy_poll __read_mostly;
43e4dde412SDaniel Borkmann 
44076bb0c8SEliezer Tamir static inline bool net_busy_loop_on(void)
45076bb0c8SEliezer Tamir {
4664b0dc51SEliezer Tamir 	return sysctl_net_busy_poll;
47076bb0c8SEliezer Tamir }
48076bb0c8SEliezer Tamir 
4921cb84c4SEric Dumazet static inline bool sk_can_busy_loop(const struct sock *sk)
50076bb0c8SEliezer Tamir {
51545cd5e5SAlexander Duyck 	return sk->sk_ll_usec && !signal_pending(current);
52076bb0c8SEliezer Tamir }
53076bb0c8SEliezer Tamir 
547db6b048SSridhar Samudrala bool sk_busy_loop_end(void *p, unsigned long start_time);
557db6b048SSridhar Samudrala 
567db6b048SSridhar Samudrala void napi_busy_loop(unsigned int napi_id,
577db6b048SSridhar Samudrala 		    bool (*loop_end)(void *, unsigned long),
587db6b048SSridhar Samudrala 		    void *loop_end_arg);
59076bb0c8SEliezer Tamir 
60e0d1095aSCong Wang #else /* CONFIG_NET_RX_BUSY_POLL */
61076bb0c8SEliezer Tamir static inline unsigned long net_busy_loop_on(void)
62076bb0c8SEliezer Tamir {
63076bb0c8SEliezer Tamir 	return 0;
64076bb0c8SEliezer Tamir }
65076bb0c8SEliezer Tamir 
66076bb0c8SEliezer Tamir static inline bool sk_can_busy_loop(struct sock *sk)
67076bb0c8SEliezer Tamir {
68076bb0c8SEliezer Tamir 	return false;
69076bb0c8SEliezer Tamir }
70076bb0c8SEliezer Tamir 
71e0d1095aSCong Wang #endif /* CONFIG_NET_RX_BUSY_POLL */
72e68b6e50SEric Dumazet 
7337056719SAlexander Duyck static inline unsigned long busy_loop_current_time(void)
7437056719SAlexander Duyck {
7537056719SAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
7637056719SAlexander Duyck 	return (unsigned long)(local_clock() >> 10);
7737056719SAlexander Duyck #else
7837056719SAlexander Duyck 	return 0;
7937056719SAlexander Duyck #endif
8037056719SAlexander Duyck }
8137056719SAlexander Duyck 
8237056719SAlexander Duyck /* in poll/select we use the global sysctl_net_ll_poll value */
8337056719SAlexander Duyck static inline bool busy_loop_timeout(unsigned long start_time)
8437056719SAlexander Duyck {
8537056719SAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
8637056719SAlexander Duyck 	unsigned long bp_usec = READ_ONCE(sysctl_net_busy_poll);
8737056719SAlexander Duyck 
8837056719SAlexander Duyck 	if (bp_usec) {
8937056719SAlexander Duyck 		unsigned long end_time = start_time + bp_usec;
9037056719SAlexander Duyck 		unsigned long now = busy_loop_current_time();
9137056719SAlexander Duyck 
9237056719SAlexander Duyck 		return time_after(now, end_time);
9337056719SAlexander Duyck 	}
9437056719SAlexander Duyck #endif
9537056719SAlexander Duyck 	return true;
9637056719SAlexander Duyck }
9737056719SAlexander Duyck 
9837056719SAlexander Duyck static inline bool sk_busy_loop_timeout(struct sock *sk,
9937056719SAlexander Duyck 					unsigned long start_time)
10037056719SAlexander Duyck {
10137056719SAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
10237056719SAlexander Duyck 	unsigned long bp_usec = READ_ONCE(sk->sk_ll_usec);
10337056719SAlexander Duyck 
10437056719SAlexander Duyck 	if (bp_usec) {
10537056719SAlexander Duyck 		unsigned long end_time = start_time + bp_usec;
10637056719SAlexander Duyck 		unsigned long now = busy_loop_current_time();
10737056719SAlexander Duyck 
10837056719SAlexander Duyck 		return time_after(now, end_time);
10937056719SAlexander Duyck 	}
11037056719SAlexander Duyck #endif
11137056719SAlexander Duyck 	return true;
11237056719SAlexander Duyck }
11337056719SAlexander Duyck 
1147db6b048SSridhar Samudrala static inline void sk_busy_loop(struct sock *sk, int nonblock)
1157db6b048SSridhar Samudrala {
1167db6b048SSridhar Samudrala #ifdef CONFIG_NET_RX_BUSY_POLL
1177db6b048SSridhar Samudrala 	unsigned int napi_id = READ_ONCE(sk->sk_napi_id);
1187db6b048SSridhar Samudrala 
1197db6b048SSridhar Samudrala 	if (napi_id >= MIN_NAPI_ID)
1207db6b048SSridhar Samudrala 		napi_busy_loop(napi_id, nonblock ? NULL : sk_busy_loop_end, sk);
1217db6b048SSridhar Samudrala #endif
1227db6b048SSridhar Samudrala }
1237db6b048SSridhar Samudrala 
1243cafb376SChristoph Hellwig static inline void sock_poll_busy_loop(struct socket *sock, __poll_t events)
1253cafb376SChristoph Hellwig {
1263cafb376SChristoph Hellwig 	if (sk_can_busy_loop(sock->sk) &&
1273cafb376SChristoph Hellwig 	    events && (events & POLL_BUSY_LOOP)) {
1283cafb376SChristoph Hellwig 		/* once, only if requested by syscall */
1293cafb376SChristoph Hellwig 		sk_busy_loop(sock->sk, 1);
1303cafb376SChristoph Hellwig 	}
1313cafb376SChristoph Hellwig }
1323cafb376SChristoph Hellwig 
1333cafb376SChristoph Hellwig /* if this socket can poll_ll, tell the system call */
1343cafb376SChristoph Hellwig static inline __poll_t sock_poll_busy_flag(struct socket *sock)
1353cafb376SChristoph Hellwig {
1363cafb376SChristoph Hellwig 	return sk_can_busy_loop(sock->sk) ? POLL_BUSY_LOOP : 0;
1373cafb376SChristoph Hellwig }
1383cafb376SChristoph Hellwig 
139d2e64dbbSAlexander Duyck /* used in the NIC receive handler to mark the skb */
140d2e64dbbSAlexander Duyck static inline void skb_mark_napi_id(struct sk_buff *skb,
141d2e64dbbSAlexander Duyck 				    struct napi_struct *napi)
142d2e64dbbSAlexander Duyck {
143d2e64dbbSAlexander Duyck #ifdef CONFIG_NET_RX_BUSY_POLL
144d2e64dbbSAlexander Duyck 	skb->napi_id = napi->napi_id;
145d2e64dbbSAlexander Duyck #endif
146d2e64dbbSAlexander Duyck }
147d2e64dbbSAlexander Duyck 
148e68b6e50SEric Dumazet /* used in the protocol hanlder to propagate the napi_id to the socket */
149e68b6e50SEric Dumazet static inline void sk_mark_napi_id(struct sock *sk, const struct sk_buff *skb)
150e68b6e50SEric Dumazet {
151e68b6e50SEric Dumazet #ifdef CONFIG_NET_RX_BUSY_POLL
152e68b6e50SEric Dumazet 	sk->sk_napi_id = skb->napi_id;
153e68b6e50SEric Dumazet #endif
154*c6345ce7SAmritha Nambiar 	sk_rx_queue_set(sk, skb);
155e68b6e50SEric Dumazet }
156e68b6e50SEric Dumazet 
157e68b6e50SEric Dumazet /* variant used for unconnected sockets */
158e68b6e50SEric Dumazet static inline void sk_mark_napi_id_once(struct sock *sk,
159e68b6e50SEric Dumazet 					const struct sk_buff *skb)
160e68b6e50SEric Dumazet {
161e68b6e50SEric Dumazet #ifdef CONFIG_NET_RX_BUSY_POLL
162e68b6e50SEric Dumazet 	if (!sk->sk_napi_id)
163e68b6e50SEric Dumazet 		sk->sk_napi_id = skb->napi_id;
164e68b6e50SEric Dumazet #endif
165e68b6e50SEric Dumazet }
166e68b6e50SEric Dumazet 
1678b80cda5SEliezer Tamir #endif /* _LINUX_NET_BUSY_POLL_H */
168