2005-04-17 02:20:36 +04:00
/* net/atm/atm_misc.c - Various functions for use by ATM drivers */
/* Written 1995-2000 by Werner Almesberger, EPFL ICA */
# include <linux/module.h>
# include <linux/atm.h>
# include <linux/atmdev.h>
# include <linux/skbuff.h>
# include <linux/sonet.h>
# include <linux/bitops.h>
2010-01-26 14:40:02 +03:00
# include <linux/errno.h>
2011-07-27 03:09:06 +04:00
# include <linux/atomic.h>
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:02 +03:00
int atm_charge ( struct atm_vcc * vcc , int truesize )
2005-04-17 02:20:36 +04:00
{
2010-01-26 14:40:02 +03:00
atm_force_charge ( vcc , truesize ) ;
2005-04-17 02:20:36 +04:00
if ( atomic_read ( & sk_atm ( vcc ) - > sk_rmem_alloc ) < = sk_atm ( vcc ) - > sk_rcvbuf )
return 1 ;
2010-01-26 14:40:02 +03:00
atm_return ( vcc , truesize ) ;
2005-04-17 02:20:36 +04:00
atomic_inc ( & vcc - > stats - > rx_drop ) ;
return 0 ;
}
2010-01-26 14:40:02 +03:00
EXPORT_SYMBOL ( atm_charge ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:02 +03:00
struct sk_buff * atm_alloc_charge ( struct atm_vcc * vcc , int pdu_size ,
gfp_t gfp_flags )
2005-04-17 02:20:36 +04:00
{
struct sock * sk = sk_atm ( vcc ) ;
2011-11-22 16:51:56 +04:00
int guess = SKB_TRUESIZE ( pdu_size ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:02 +03:00
atm_force_charge ( vcc , guess ) ;
2005-04-17 02:20:36 +04:00
if ( atomic_read ( & sk - > sk_rmem_alloc ) < = sk - > sk_rcvbuf ) {
2010-01-26 14:40:02 +03:00
struct sk_buff * skb = alloc_skb ( pdu_size , gfp_flags ) ;
2005-04-17 02:20:36 +04:00
if ( skb ) {
atomic_add ( skb - > truesize - guess ,
& sk - > sk_rmem_alloc ) ;
return skb ;
}
}
2010-01-26 14:40:02 +03:00
atm_return ( vcc , guess ) ;
2005-04-17 02:20:36 +04:00
atomic_inc ( & vcc - > stats - > rx_drop ) ;
return NULL ;
}
2010-01-26 14:40:02 +03:00
EXPORT_SYMBOL ( atm_alloc_charge ) ;
2005-04-17 02:20:36 +04:00
/*
* atm_pcr_goal returns the positive PCR if it should be rounded up , the
* negative PCR if it should be rounded down , and zero if the maximum available
* bandwidth should be used .
*
* The rules are as follows ( * = maximum , - = absent ( 0 ) , x = value " x " ,
* ( x + = x or next value above x , x - = x or next value below ) :
*
* min max pcr result min max pcr result
* - - - * ( UBR only ) x - - x +
* - - * * x - * *
* - - z z - x - z z -
* - * - * x * - x +
* - * * * x * * *
* - * z z - x * z z -
* - y - y - x y - x +
* - y * y - x y * y -
* - y z z - x y z z -
*
* All non - error cases can be converted with the following simple set of rules :
*
* if pcr = = z then z -
* else if min = = x & & pcr = = - then x +
* else if max = = y then y -
* else *
*/
2005-11-30 03:13:55 +03:00
int atm_pcr_goal ( const struct atm_trafprm * tp )
2005-04-17 02:20:36 +04:00
{
2005-11-30 03:13:55 +03:00
if ( tp - > pcr & & tp - > pcr ! = ATM_MAX_PCR )
return - tp - > pcr ;
if ( tp - > min_pcr & & ! tp - > pcr )
return tp - > min_pcr ;
if ( tp - > max_pcr ! = ATM_MAX_PCR )
return - tp - > max_pcr ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-01-26 14:40:02 +03:00
EXPORT_SYMBOL ( atm_pcr_goal ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:02 +03:00
void sonet_copy_stats ( struct k_sonet_stats * from , struct sonet_stats * to )
2005-04-17 02:20:36 +04:00
{
# define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
__SONET_ITEMS
# undef __HANDLE_ITEM
}
2010-01-26 14:40:02 +03:00
EXPORT_SYMBOL ( sonet_copy_stats ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:02 +03:00
void sonet_subtract_stats ( struct k_sonet_stats * from , struct sonet_stats * to )
2005-04-17 02:20:36 +04:00
{
2010-01-26 14:40:02 +03:00
# define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
2005-04-17 02:20:36 +04:00
__SONET_ITEMS
# undef __HANDLE_ITEM
}
EXPORT_SYMBOL ( sonet_subtract_stats ) ;