@ -137,7 +137,9 @@ struct red_parms {
u8 Wlog ; /* log(W) */
u8 Plog ; /* random number bits */
u8 Stab [ RED_STAB_SIZE ] ;
} ;
struct red_vars {
/* Variables */
int qcount ; /* Number of packets since last random
number generation */
@ -152,6 +154,16 @@ static inline u32 red_maxp(u8 Plog)
return Plog < 32 ? ( ~ 0U > > Plog ) : ~ 0U ;
}
static inline void red_set_vars ( struct red_vars * v )
{
/* Reset average queue length, the value is strictly bound
* to the parameters below , reseting hurts a bit but leaving
* it might result in an unreasonable qavg for a while . - - TGR
*/
v - > qavg = 0 ;
v - > qcount = - 1 ;
}
static inline void red_set_parms ( struct red_parms * p ,
u32 qth_min , u32 qth_max , u8 Wlog , u8 Plog ,
@ -160,13 +172,6 @@ static inline void red_set_parms(struct red_parms *p,
int delta = qth_max - qth_min ;
u32 max_p_delta ;
/* Reset average queue length, the value is strictly bound
* to the parameters below , reseting hurts a bit but leaving
* it might result in an unreasonable qavg for a while . - - TGR
*/
p - > qavg = 0 ;
p - > qcount = - 1 ;
p - > qth_min = qth_min < < Wlog ;
p - > qth_max = qth_max < < Wlog ;
p - > Wlog = Wlog ;
@ -197,31 +202,32 @@ static inline void red_set_parms(struct red_parms *p,
memcpy ( p - > Stab , stab , sizeof ( p - > Stab ) ) ;
}
static inline int red_is_idling ( const struct red_parms * p )
static inline int red_is_idling ( const struct red_vars * v )
{
return p - > qidlestart . tv64 ! = 0 ;
return v - > qidlestart . tv64 ! = 0 ;
}
static inline void red_start_of_idle_period ( struct red_parms * p )
static inline void red_start_of_idle_period ( struct red_vars * v )
{
p - > qidlestart = ktime_get ( ) ;
v - > qidlestart = ktime_get ( ) ;
}
static inline void red_end_of_idle_period ( struct red_parms * p )
static inline void red_end_of_idle_period ( struct red_vars * v )
{
p - > qidlestart . tv64 = 0 ;
v - > qidlestart . tv64 = 0 ;
}
static inline void red_restart ( struct red_parms * p )
static inline void red_restart ( struct red_vars * v )
{
red_end_of_idle_period ( p ) ;
p - > qavg = 0 ;
p - > qcount = - 1 ;
red_end_of_idle_period ( v ) ;
v - > qavg = 0 ;
v - > qcount = - 1 ;
}
static inline unsigned long red_calc_qavg_from_idle_time ( const struct red_parms * p )
static inline unsigned long red_calc_qavg_from_idle_time ( const struct red_parms * p ,
const struct red_vars * v )
{
s64 delta = ktime_us_delta ( ktime_get ( ) , p - > qidlestart ) ;
s64 delta = ktime_us_delta ( ktime_get ( ) , v - > qidlestart ) ;
long us_idle = min_t ( s64 , delta , p - > Scell_max ) ;
int shift ;
@ -248,7 +254,7 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms
shift = p - > Stab [ ( us_idle > > p - > Scell_log ) & RED_STAB_MASK ] ;
if ( shift )
return p - > qavg > > shift ;
return v - > qavg > > shift ;
else {
/* Approximate initial part of exponent with linear function:
*
@ -257,16 +263,17 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms
* Seems , it is the best solution to
* problem of too coarse exponent tabulation .
*/
us_idle = ( p - > qavg * ( u64 ) us_idle ) > > p - > Scell_log ;
us_idle = ( v - > qavg * ( u64 ) us_idle ) > > p - > Scell_log ;
if ( us_idle < ( p - > qavg > > 1 ) )
return p - > qavg - us_idle ;
if ( us_idle < ( v - > qavg > > 1 ) )
return v - > qavg - us_idle ;
else
return p - > qavg > > 1 ;
return v - > qavg > > 1 ;
}
}
static inline unsigned long red_calc_qavg_no_idle_time ( const struct red_parms * p ,
const struct red_vars * v ,
unsigned int backlog )
{
/*
@ -278,16 +285,17 @@ static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p
*
* - - ANK ( 980924 )
*/
return p - > qavg + ( backlog - ( p - > qavg > > p - > Wlog ) ) ;
return v - > qavg + ( backlog - ( v - > qavg > > p - > Wlog ) ) ;
}
static inline unsigned long red_calc_qavg ( const struct red_parms * p ,
const struct red_vars * v ,
unsigned int backlog )
{
if ( ! red_is_idling ( p ) )
return red_calc_qavg_no_idle_time ( p , backlog ) ;
if ( ! red_is_idling ( v ) )
return red_calc_qavg_no_idle_time ( p , v , backlog ) ;
else
return red_calc_qavg_from_idle_time ( p ) ;
return red_calc_qavg_from_idle_time ( p , v ) ;
}
@ -296,7 +304,9 @@ static inline u32 red_random(const struct red_parms *p)
return reciprocal_divide ( net_random ( ) , p - > max_P_reciprocal ) ;
}
static inline int red_mark_probability ( const struct red_parms * p , unsigned long qavg )
static inline int red_mark_probability ( const struct red_parms * p ,
const struct red_vars * v ,
unsigned long qavg )
{
/* The formula used below causes questions.
@ -314,7 +324,7 @@ static inline int red_mark_probability(const struct red_parms *p, unsigned long
Any questions ? - - ANK ( 980924 )
*/
return ! ( ( ( qavg - p - > qth_min ) > > p - > Wlog ) * p - > qcount < p - > qR ) ;
return ! ( ( ( qavg - p - > qth_min ) > > p - > Wlog ) * v - > qcount < v - > qR ) ;
}
enum {
@ -323,7 +333,7 @@ enum {
RED_ABOVE_MAX_TRESH ,
} ;
static inline int red_cmp_thresh ( struct red_parms * p , unsigned long qavg )
static inline int red_cmp_thresh ( const struct red_parms * p , unsigned long qavg )
{
if ( qavg < p - > qth_min )
return RED_BELOW_MIN_THRESH ;
@ -339,27 +349,29 @@ enum {
RED_HARD_MARK ,
} ;
static inline int red_action ( struct red_parms * p , unsigned long qavg )
static inline int red_action ( const struct red_parms * p ,
struct red_vars * v ,
unsigned long qavg )
{
switch ( red_cmp_thresh ( p , qavg ) ) {
case RED_BELOW_MIN_THRESH :
p - > qcount = - 1 ;
v - > qcount = - 1 ;
return RED_DONT_MARK ;
case RED_BETWEEN_TRESH :
if ( + + p - > qcount ) {
if ( red_mark_probability ( p , qavg ) ) {
p - > qcount = 0 ;
p - > qR = red_random ( p ) ;
if ( + + v - > qcount ) {
if ( red_mark_probability ( p , v , qavg ) ) {
v - > qcount = 0 ;
v - > qR = red_random ( p ) ;
return RED_PROB_MARK ;
}
} else
p - > qR = red_random ( p ) ;
v - > qR = red_random ( p ) ;
return RED_DONT_MARK ;
case RED_ABOVE_MAX_TRESH :
p - > qcount = - 1 ;
v - > qcount = - 1 ;
return RED_HARD_MARK ;
}
@ -367,14 +379,14 @@ static inline int red_action(struct red_parms *p, unsigned long qavg)
return RED_DONT_MARK ;
}
static inline void red_adaptative_algo ( struct red_parms * p )
static inline void red_adaptative_algo ( struct red_parms * p , struct red_vars * v )
{
unsigned long qavg ;
u32 max_p_delta ;
qavg = p - > qavg ;
if ( red_is_idling ( p ) )
qavg = red_calc_qavg_from_idle_time ( p ) ;
qavg = v - > qavg ;
if ( red_is_idling ( v ) )
qavg = red_calc_qavg_from_idle_time ( p , v ) ;
/* p->qavg is fixed point number with point at Wlog */
qavg > > = p - > Wlog ;