2013-06-10 12:39:50 +04:00
/*
* Low Latency Sockets
* Copyright ( c ) 2013 Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Author : Eliezer Tamir
*
* Contact Information :
* e1000 - devel Mailing List < e1000 - devel @ lists . sourceforge . net >
*/
# ifndef _LINUX_NET_LL_POLL_H
# define _LINUX_NET_LL_POLL_H
# include <linux/netdevice.h>
# include <net/ip.h>
# ifdef CONFIG_NET_LL_RX_POLL
struct napi_struct ;
2013-06-24 11:28:03 +04:00
extern unsigned int sysctl_net_ll_read __read_mostly ;
2013-06-14 17:33:25 +04:00
extern unsigned int sysctl_net_ll_poll __read_mostly ;
2013-06-10 12:39:50 +04:00
/* return values from ndo_ll_poll */
# define LL_FLUSH_FAILED -1
# define LL_FLUSH_BUSY -2
2013-07-08 17:20:34 +04:00
static inline bool net_busy_loop_on ( void )
2013-06-28 16:59:35 +04:00
{
2013-07-08 17:20:34 +04:00
return sysctl_net_ll_poll ;
2013-06-28 16:59:35 +04:00
}
2013-06-28 16:59:26 +04:00
/* a wrapper to make debug_smp_processor_id() happy
* we can use sched_clock ( ) because we don ' t care much about precision
2013-06-14 17:33:35 +04:00
* we only care that the average is bounded
2013-06-28 16:59:26 +04:00
*/
# ifdef CONFIG_DEBUG_PREEMPT
2013-07-08 17:20:34 +04:00
static inline u64 busy_loop_sched_clock ( void )
2013-06-28 16:59:26 +04:00
{
u64 rc ;
preempt_disable_notrace ( ) ;
rc = sched_clock ( ) ;
preempt_enable_no_resched_notrace ( ) ;
return rc ;
}
# else /* CONFIG_DEBUG_PREEMPT */
2013-07-08 17:20:34 +04:00
static inline u64 busy_loop_sched_clock ( void )
2013-06-28 16:59:26 +04:00
{
return sched_clock ( ) ;
}
# endif /* CONFIG_DEBUG_PREEMPT */
/* we don't mind a ~2.5% imprecision so <<10 instead of *1000
2013-06-24 11:28:03 +04:00
* sk - > sk_ll_usec is a u_int so this can ' t overflow
2013-06-14 17:33:35 +04:00
*/
2013-07-08 17:20:34 +04:00
static inline u64 sk_busy_loop_end_time ( struct sock * sk )
2013-06-10 12:39:50 +04:00
{
2013-07-03 00:22:47 +04:00
return ( u64 ) ACCESS_ONCE ( sk - > sk_ll_usec ) < < 10 ;
2013-06-24 11:28:03 +04:00
}
2013-06-14 17:33:35 +04:00
2013-06-28 16:59:35 +04:00
/* in poll/select we use the global sysctl_net_ll_poll value
* only call sched_clock ( ) if enabled
*/
2013-07-08 17:20:34 +04:00
static inline u64 busy_loop_end_time ( void )
2013-06-24 11:28:03 +04:00
{
2013-07-03 00:22:47 +04:00
return ( u64 ) ACCESS_ONCE ( sysctl_net_ll_poll ) < < 10 ;
}
2013-06-28 16:59:35 +04:00
2013-07-08 17:20:34 +04:00
/* if flag is not set we don't need to know the time
* so we want to avoid a potentially expensive sched_clock ( )
*/
static inline u64 busy_loop_start_time ( unsigned int flag )
2013-07-03 00:22:47 +04:00
{
2013-07-08 17:20:34 +04:00
return flag ? busy_loop_sched_clock ( ) : 0 ;
2013-06-10 12:39:50 +04:00
}
2013-07-08 17:20:34 +04:00
static inline bool sk_can_busy_loop ( struct sock * sk )
2013-06-10 12:39:50 +04:00
{
2013-06-14 17:33:57 +04:00
return sk - > sk_ll_usec & & sk - > sk_napi_id & &
2013-06-10 12:39:50 +04:00
! need_resched ( ) & & ! signal_pending ( current ) ;
}
2013-07-03 00:22:47 +04:00
/* careful! time_in_range64 will evaluate now twice */
2013-07-08 17:20:34 +04:00
static inline bool busy_loop_range ( u64 start_time , u64 run_time )
2013-06-10 12:39:50 +04:00
{
2013-07-08 17:20:34 +04:00
u64 now = busy_loop_sched_clock ( ) ;
2013-07-03 00:22:47 +04:00
return time_in_range64 ( now , start_time , start_time + run_time ) ;
2013-06-10 12:39:50 +04:00
}
2013-06-24 11:28:03 +04:00
/* when used in sock_poll() nonblock is known at compile time to be true
* so the loop and end_time will be optimized out
*/
2013-07-08 17:20:34 +04:00
static inline bool sk_busy_loop ( struct sock * sk , int nonblock )
2013-06-10 12:39:50 +04:00
{
2013-07-08 17:20:34 +04:00
u64 start_time = busy_loop_start_time ( ! nonblock ) ;
u64 end_time = sk_busy_loop_end_time ( sk ) ;
2013-06-10 12:39:50 +04:00
const struct net_device_ops * ops ;
struct napi_struct * napi ;
int rc = false ;
/*
* rcu read lock for napi hash
* bh so we don ' t race with net_rx_action
*/
rcu_read_lock_bh ( ) ;
napi = napi_by_id ( sk - > sk_napi_id ) ;
if ( ! napi )
goto out ;
ops = napi - > dev - > netdev_ops ;
if ( ! ops - > ndo_ll_poll )
goto out ;
do {
rc = ops - > ndo_ll_poll ( napi ) ;
if ( rc = = LL_FLUSH_FAILED )
break ; /* permanent failure */
if ( rc > 0 )
/* local bh are disabled so it is ok to use _BH */
NET_ADD_STATS_BH ( sock_net ( sk ) ,
LINUX_MIB_LOWLATENCYRXPACKETS , rc ) ;
2013-06-24 11:28:03 +04:00
} while ( ! nonblock & & skb_queue_empty ( & sk - > sk_receive_queue ) & &
2013-07-08 17:20:34 +04:00
busy_loop_range ( start_time , end_time ) ) ;
2013-06-10 12:39:50 +04:00
rc = ! skb_queue_empty ( & sk - > sk_receive_queue ) ;
out :
rcu_read_unlock_bh ( ) ;
return rc ;
}
/* used in the NIC receive handler to mark the skb */
static inline void skb_mark_ll ( struct sk_buff * skb , struct napi_struct * napi )
{
skb - > napi_id = napi - > napi_id ;
}
/* used in the protocol hanlder to propagate the napi_id to the socket */
static inline void sk_mark_ll ( struct sock * sk , struct sk_buff * skb )
{
sk - > sk_napi_id = skb - > napi_id ;
}
# else /* CONFIG_NET_LL_RX_POLL */
2013-07-08 17:20:34 +04:00
static inline unsigned long net_busy_loop_on ( void )
2013-06-28 16:59:35 +04:00
{
return 0 ;
}
2013-06-10 12:39:50 +04:00
2013-07-08 17:20:34 +04:00
static inline u64 busy_loop_start_time ( unsigned int flag )
2013-06-24 11:28:03 +04:00
{
return 0 ;
}
2013-07-08 17:20:34 +04:00
static inline u64 busy_loop_end_time ( void )
2013-06-10 12:39:50 +04:00
{
return 0 ;
}
2013-07-08 17:20:34 +04:00
static inline bool sk_can_busy_loop ( struct sock * sk )
2013-06-10 12:39:50 +04:00
{
return false ;
}
2013-07-08 17:20:34 +04:00
static inline bool sk_busy_poll ( struct sock * sk , int nonblock )
2013-06-10 12:39:50 +04:00
{
return false ;
}
static inline void skb_mark_ll ( struct sk_buff * skb , struct napi_struct * napi )
{
}
static inline void sk_mark_ll ( struct sock * sk , struct sk_buff * skb )
{
}
2013-07-08 17:20:34 +04:00
static inline bool busy_loop_range ( u64 start_time , u64 run_time )
2013-06-10 12:39:50 +04:00
{
return false ;
}
# endif /* CONFIG_NET_LL_RX_POLL */
# endif /* _LINUX_NET_LL_POLL_H */