diff options
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r-- | net/sched/sch_generic.c | 44 |
1 files changed, 20 insertions, 24 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 20224086cc28..4626cef4b76e 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -901,37 +901,33 @@ void dev_shutdown(struct net_device *dev) | |||
901 | void psched_ratecfg_precompute(struct psched_ratecfg *r, | 901 | void psched_ratecfg_precompute(struct psched_ratecfg *r, |
902 | const struct tc_ratespec *conf) | 902 | const struct tc_ratespec *conf) |
903 | { | 903 | { |
904 | u64 factor; | ||
905 | u64 mult; | ||
906 | int shift; | ||
907 | |||
908 | memset(r, 0, sizeof(*r)); | 904 | memset(r, 0, sizeof(*r)); |
909 | r->overhead = conf->overhead; | 905 | r->overhead = conf->overhead; |
910 | r->rate_bps = (u64)conf->rate << 3; | 906 | r->rate_bytes_ps = conf->rate; |
911 | r->mult = 1; | 907 | r->mult = 1; |
912 | /* | 908 | /* |
913 | * Calibrate mult, shift so that token counting is accurate | 909 | * The deal here is to replace a divide by a reciprocal one |
914 | * for smallest packet size (64 bytes). Token (time in ns) is | 910 | * in fast path (a reciprocal divide is a multiply and a shift) |
915 | * computed as (bytes * 8) * NSEC_PER_SEC / rate_bps. It will | 911 | * |
916 | * work as long as the smallest packet transfer time can be | 912 | * Normal formula would be : |
917 | * accurately represented in nanosec. | 913 | * time_in_ns = (NSEC_PER_SEC * len) / rate_bps |
914 | * | ||
915 | * We compute mult/shift to use instead : | ||
916 | * time_in_ns = (len * mult) >> shift; | ||
917 | * | ||
918 | * We try to get the highest possible mult value for accuracy, | ||
919 | * but have to make sure no overflows will ever happen. | ||
918 | */ | 920 | */ |
919 | if (r->rate_bps > 0) { | 921 | if (r->rate_bytes_ps > 0) { |
920 | /* | 922 | u64 factor = NSEC_PER_SEC; |
921 | * Higher shift gives better accuracy. Find the largest | 923 | |
922 | * shift such that mult fits in 32 bits. | 924 | for (;;) { |
923 | */ | 925 | r->mult = div64_u64(factor, r->rate_bytes_ps); |
924 | for (shift = 0; shift < 16; shift++) { | 926 | if (r->mult & (1U << 31) || factor & (1ULL << 63)) |
925 | r->shift = shift; | ||
926 | factor = 8LLU * NSEC_PER_SEC * (1 << r->shift); | ||
927 | mult = div64_u64(factor, r->rate_bps); | ||
928 | if (mult > UINT_MAX) | ||
929 | break; | 927 | break; |
928 | factor <<= 1; | ||
929 | r->shift++; | ||
930 | } | 930 | } |
931 | |||
932 | r->shift = shift - 1; | ||
933 | factor = 8LLU * NSEC_PER_SEC * (1 << r->shift); | ||
934 | r->mult = div64_u64(factor, r->rate_bps); | ||
935 | } | 931 | } |
936 | } | 932 | } |
937 | EXPORT_SYMBOL(psched_ratecfg_precompute); | 933 | EXPORT_SYMBOL(psched_ratecfg_precompute); |