Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 292f1c7f authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

sch: make htb_rate_cfg and functions around that generic



As it is going to be used in tbf as well, push these to generic code.

Signed-off-by: default avatarJiri Pirko <jiri@resnulli.us>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b9a7afde
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -679,4 +679,23 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask,
}
#endif

struct psched_ratecfg {
	u64 rate_bps;
	u32 mult;
	u32 shift;
};

static inline u64 psched_l2t_ns(const struct psched_ratecfg *r,
				unsigned int len)
{
	return ((u64)len * r->mult) >> r->shift;
}

extern void psched_ratecfg_precompute(struct psched_ratecfg *r, u32 rate);

static inline u32 psched_ratecfg_getrate(const struct psched_ratecfg *r)
{
	return r->rate_bps >> 3;
}

#endif
+37 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/rcupdate.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <net/sch_generic.h>
#include <net/pkt_sched.h>
#include <net/dst.h>

@@ -896,3 +897,39 @@ void dev_shutdown(struct net_device *dev)

	WARN_ON(timer_pending(&dev->watchdog_timer));
}

void psched_ratecfg_precompute(struct psched_ratecfg *r, u32 rate)
{
	u64 factor;
	u64 mult;
	int shift;

	r->rate_bps = rate << 3;
	r->shift = 0;
	r->mult = 1;
	/*
	 * Calibrate mult, shift so that token counting is accurate
	 * for smallest packet size (64 bytes).  Token (time in ns) is
	 * computed as (bytes * 8) * NSEC_PER_SEC / rate_bps.  It will
	 * work as long as the smallest packet transfer time can be
	 * accurately represented in nanosec.
	 */
	if (r->rate_bps > 0) {
		/*
		 * Higher shift gives better accuracy.  Find the largest
		 * shift such that mult fits in 32 bits.
		 */
		for (shift = 0; shift < 16; shift++) {
			r->shift = shift;
			factor = 8LLU * NSEC_PER_SEC * (1 << r->shift);
			mult = div64_u64(factor, r->rate_bps);
			if (mult > UINT_MAX)
				break;
		}

		r->shift = shift - 1;
		factor = 8LLU * NSEC_PER_SEC * (1 << r->shift);
		r->mult = div64_u64(factor, r->rate_bps);
	}
}
EXPORT_SYMBOL(psched_ratecfg_precompute);
+9 −56
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <net/netlink.h>
#include <net/sch_generic.h>
#include <net/pkt_sched.h>

/* HTB algorithm.
@@ -71,12 +72,6 @@ enum htb_cmode {
	HTB_CAN_SEND		/* class can send */
};

struct htb_rate_cfg {
	u64 rate_bps;
	u32 mult;
	u32 shift;
};

/* interior & leaf nodes; props specific to leaves are marked L: */
struct htb_class {
	struct Qdisc_class_common common;
@@ -124,8 +119,8 @@ struct htb_class {
	int filter_cnt;

	/* token bucket parameters */
	struct htb_rate_cfg rate;
	struct htb_rate_cfg ceil;
	struct psched_ratecfg rate;
	struct psched_ratecfg ceil;
	s64 buffer, cbuffer;	/* token bucket depth/rate */
	psched_tdiff_t mbuffer;	/* max wait time */
	s64 tokens, ctokens;	/* current number of tokens */
@@ -168,45 +163,6 @@ struct htb_sched {
	struct work_struct work;
};

static u64 l2t_ns(struct htb_rate_cfg *r, unsigned int len)
{
	return ((u64)len * r->mult) >> r->shift;
}

static void htb_precompute_ratedata(struct htb_rate_cfg *r)
{
	u64 factor;
	u64 mult;
	int shift;

	r->shift = 0;
	r->mult = 1;
	/*
	 * Calibrate mult, shift so that token counting is accurate
	 * for smallest packet size (64 bytes).  Token (time in ns) is
	 * computed as (bytes * 8) * NSEC_PER_SEC / rate_bps.  It will
	 * work as long as the smallest packet transfer time can be
	 * accurately represented in nanosec.
	 */
	if (r->rate_bps > 0) {
		/*
		 * Higher shift gives better accuracy.  Find the largest
		 * shift such that mult fits in 32 bits.
		 */
		for (shift = 0; shift < 16; shift++) {
			r->shift = shift;
			factor = 8LLU * NSEC_PER_SEC * (1 << r->shift);
			mult = div64_u64(factor, r->rate_bps);
			if (mult > UINT_MAX)
				break;
		}

		r->shift = shift - 1;
		factor = 8LLU * NSEC_PER_SEC * (1 << r->shift);
		r->mult = div64_u64(factor, r->rate_bps);
	}
}

/* find class in global hash table using given handle */
static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
{
@@ -632,7 +588,7 @@ static inline void htb_accnt_tokens(struct htb_class *cl, int bytes, s64 diff)

	if (toks > cl->buffer)
		toks = cl->buffer;
	toks -= (s64) l2t_ns(&cl->rate, bytes);
	toks -= (s64) psched_l2t_ns(&cl->rate, bytes);
	if (toks <= -cl->mbuffer)
		toks = 1 - cl->mbuffer;

@@ -645,7 +601,7 @@ static inline void htb_accnt_ctokens(struct htb_class *cl, int bytes, s64 diff)

	if (toks > cl->cbuffer)
		toks = cl->cbuffer;
	toks -= (s64) l2t_ns(&cl->ceil, bytes);
	toks -= (s64) psched_l2t_ns(&cl->ceil, bytes);
	if (toks <= -cl->mbuffer)
		toks = 1 - cl->mbuffer;

@@ -1134,9 +1090,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,

	memset(&opt, 0, sizeof(opt));

	opt.rate.rate = cl->rate.rate_bps >> 3;
	opt.rate.rate = psched_ratecfg_getrate(&cl->rate);
	opt.buffer = PSCHED_NS2TICKS(cl->buffer);
	opt.ceil.rate = cl->ceil.rate_bps >> 3;
	opt.ceil.rate = psched_ratecfg_getrate(&cl->ceil);
	opt.cbuffer = PSCHED_NS2TICKS(cl->cbuffer);
	opt.quantum = cl->quantum;
	opt.prio = cl->prio;
@@ -1503,11 +1459,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
			cl->prio = TC_HTB_NUMPRIO - 1;
	}

	cl->rate.rate_bps = (u64)hopt->rate.rate << 3;
	cl->ceil.rate_bps = (u64)hopt->ceil.rate << 3;

	htb_precompute_ratedata(&cl->rate);
	htb_precompute_ratedata(&cl->ceil);
	psched_ratecfg_precompute(&cl->rate, hopt->rate.rate);
	psched_ratecfg_precompute(&cl->ceil, hopt->ceil.rate);

	cl->buffer = PSCHED_TICKS2NS(hopt->buffer);
	cl->cbuffer = PSCHED_TICKS2NS(hopt->buffer);