18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net busy poll support 48c2ecf20Sopenharmony_ci * Copyright(c) 2013 Intel Corporation. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Eliezer Tamir 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Contact Information: 98c2ecf20Sopenharmony_ci * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#ifndef _LINUX_NET_BUSY_POLL_H 138c2ecf20Sopenharmony_ci#define _LINUX_NET_BUSY_POLL_H 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 168c2ecf20Sopenharmony_ci#include <linux/sched/clock.h> 178c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 188c2ecf20Sopenharmony_ci#include <net/ip.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 0 - Reserved to indicate value not set 218c2ecf20Sopenharmony_ci * 1..NR_CPUS - Reserved for sender_cpu 228c2ecf20Sopenharmony_ci * NR_CPUS+1..~0 - Region available for NAPI IDs 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci#define MIN_NAPI_ID ((unsigned int)(NR_CPUS + 1)) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct napi_struct; 298c2ecf20Sopenharmony_ciextern unsigned int sysctl_net_busy_read __read_mostly; 308c2ecf20Sopenharmony_ciextern unsigned int sysctl_net_busy_poll __read_mostly; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline bool net_busy_loop_on(void) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return READ_ONCE(sysctl_net_busy_poll); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic inline bool sk_can_busy_loop(const struct sock *sk) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return READ_ONCE(sk->sk_ll_usec) && !signal_pending(current); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cibool sk_busy_loop_end(void *p, unsigned long start_time); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_civoid napi_busy_loop(unsigned int napi_id, 458c2ecf20Sopenharmony_ci bool (*loop_end)(void *, unsigned long), 468c2ecf20Sopenharmony_ci void *loop_end_arg); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#else /* CONFIG_NET_RX_BUSY_POLL */ 498c2ecf20Sopenharmony_cistatic inline unsigned long net_busy_loop_on(void) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic inline bool sk_can_busy_loop(struct sock *sk) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci return false; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#endif /* CONFIG_NET_RX_BUSY_POLL */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic inline unsigned long busy_loop_current_time(void) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 648c2ecf20Sopenharmony_ci return (unsigned long)(local_clock() >> 10); 658c2ecf20Sopenharmony_ci#else 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci#endif 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* in poll/select we use the global sysctl_net_ll_poll value */ 718c2ecf20Sopenharmony_cistatic inline bool busy_loop_timeout(unsigned long start_time) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 748c2ecf20Sopenharmony_ci unsigned long bp_usec = READ_ONCE(sysctl_net_busy_poll); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (bp_usec) { 778c2ecf20Sopenharmony_ci unsigned long end_time = start_time + bp_usec; 788c2ecf20Sopenharmony_ci unsigned long now = busy_loop_current_time(); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return time_after(now, end_time); 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci#endif 838c2ecf20Sopenharmony_ci return true; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline bool sk_busy_loop_timeout(struct sock *sk, 878c2ecf20Sopenharmony_ci unsigned long start_time) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 908c2ecf20Sopenharmony_ci unsigned long bp_usec = READ_ONCE(sk->sk_ll_usec); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (bp_usec) { 938c2ecf20Sopenharmony_ci unsigned long end_time = start_time + bp_usec; 948c2ecf20Sopenharmony_ci unsigned long now = busy_loop_current_time(); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return time_after(now, end_time); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci return true; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline void sk_busy_loop(struct sock *sk, int nonblock) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 1058c2ecf20Sopenharmony_ci unsigned int napi_id = READ_ONCE(sk->sk_napi_id); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (napi_id >= MIN_NAPI_ID) 1088c2ecf20Sopenharmony_ci napi_busy_loop(napi_id, nonblock ? NULL : sk_busy_loop_end, sk); 1098c2ecf20Sopenharmony_ci#endif 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* used in the NIC receive handler to mark the skb */ 1138c2ecf20Sopenharmony_cistatic inline void skb_mark_napi_id(struct sk_buff *skb, 1148c2ecf20Sopenharmony_ci struct napi_struct *napi) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 1178c2ecf20Sopenharmony_ci /* If the skb was already marked with a valid NAPI ID, avoid overwriting 1188c2ecf20Sopenharmony_ci * it. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci if (skb->napi_id < MIN_NAPI_ID) 1218c2ecf20Sopenharmony_ci skb->napi_id = napi->napi_id; 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* used in the protocol hanlder to propagate the napi_id to the socket */ 1268c2ecf20Sopenharmony_cistatic inline void sk_mark_napi_id(struct sock *sk, const struct sk_buff *skb) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 1298c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_napi_id, skb->napi_id); 1308c2ecf20Sopenharmony_ci#endif 1318c2ecf20Sopenharmony_ci sk_rx_queue_set(sk, skb); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* variant used for unconnected sockets */ 1358c2ecf20Sopenharmony_cistatic inline void sk_mark_napi_id_once(struct sock *sk, 1368c2ecf20Sopenharmony_ci const struct sk_buff *skb) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL 1398c2ecf20Sopenharmony_ci if (!READ_ONCE(sk->sk_napi_id)) 1408c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_napi_id, skb->napi_id); 1418c2ecf20Sopenharmony_ci#endif 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#endif /* _LINUX_NET_BUSY_POLL_H */ 145