xref: /OK3568_Linux_fs/kernel/net/sched/sch_hfsc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2003 Patrick McHardy, <kaber@trash.net>
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
5*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License
6*4882a593Smuzhiyun  * as published by the Free Software Foundation; either version 2
7*4882a593Smuzhiyun  * of the License, or (at your option) any later version.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * 2003-10-17 - Ported from altq
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun /*
12*4882a593Smuzhiyun  * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Permission to use, copy, modify, and distribute this software and
15*4882a593Smuzhiyun  * its documentation is hereby granted (including for commercial or
16*4882a593Smuzhiyun  * for-profit use), provided that both the copyright notice and this
17*4882a593Smuzhiyun  * permission notice appear in all copies of the software, derivative
18*4882a593Smuzhiyun  * works, or modified versions, and any portions thereof.
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF
21*4882a593Smuzhiyun  * WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON PROVIDES THIS
22*4882a593Smuzhiyun  * SOFTWARE IN ITS ``AS IS'' CONDITION, AND ANY EXPRESS OR IMPLIED
23*4882a593Smuzhiyun  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24*4882a593Smuzhiyun  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25*4882a593Smuzhiyun  * DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
26*4882a593Smuzhiyun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27*4882a593Smuzhiyun  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
28*4882a593Smuzhiyun  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29*4882a593Smuzhiyun  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30*4882a593Smuzhiyun  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32*4882a593Smuzhiyun  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33*4882a593Smuzhiyun  * DAMAGE.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * Carnegie Mellon encourages (but does not require) users of this
36*4882a593Smuzhiyun  * software to return any improvements or extensions that they make,
37*4882a593Smuzhiyun  * and to grant Carnegie Mellon the rights to redistribute these
38*4882a593Smuzhiyun  * changes without encumbrance.
39*4882a593Smuzhiyun  */
40*4882a593Smuzhiyun /*
41*4882a593Smuzhiyun  * H-FSC is described in Proceedings of SIGCOMM'97,
42*4882a593Smuzhiyun  * "A Hierarchical Fair Service Curve Algorithm for Link-Sharing,
43*4882a593Smuzhiyun  * Real-Time and Priority Service"
44*4882a593Smuzhiyun  * by Ion Stoica, Hui Zhang, and T. S. Eugene Ng.
45*4882a593Smuzhiyun  *
46*4882a593Smuzhiyun  * Oleg Cherevko <olwi@aq.ml.com.ua> added the upperlimit for link-sharing.
47*4882a593Smuzhiyun  * when a class has an upperlimit, the fit-time is computed from the
48*4882a593Smuzhiyun  * upperlimit service curve.  the link-sharing scheduler does not schedule
49*4882a593Smuzhiyun  * a class whose fit-time exceeds the current time.
50*4882a593Smuzhiyun  */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #include <linux/kernel.h>
53*4882a593Smuzhiyun #include <linux/module.h>
54*4882a593Smuzhiyun #include <linux/types.h>
55*4882a593Smuzhiyun #include <linux/errno.h>
56*4882a593Smuzhiyun #include <linux/compiler.h>
57*4882a593Smuzhiyun #include <linux/spinlock.h>
58*4882a593Smuzhiyun #include <linux/skbuff.h>
59*4882a593Smuzhiyun #include <linux/string.h>
60*4882a593Smuzhiyun #include <linux/slab.h>
61*4882a593Smuzhiyun #include <linux/list.h>
62*4882a593Smuzhiyun #include <linux/rbtree.h>
63*4882a593Smuzhiyun #include <linux/init.h>
64*4882a593Smuzhiyun #include <linux/rtnetlink.h>
65*4882a593Smuzhiyun #include <linux/pkt_sched.h>
66*4882a593Smuzhiyun #include <net/netlink.h>
67*4882a593Smuzhiyun #include <net/pkt_sched.h>
68*4882a593Smuzhiyun #include <net/pkt_cls.h>
69*4882a593Smuzhiyun #include <asm/div64.h>
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /*
72*4882a593Smuzhiyun  * kernel internal service curve representation:
73*4882a593Smuzhiyun  *   coordinates are given by 64 bit unsigned integers.
74*4882a593Smuzhiyun  *   x-axis: unit is clock count.
75*4882a593Smuzhiyun  *   y-axis: unit is byte.
76*4882a593Smuzhiyun  *
77*4882a593Smuzhiyun  *   The service curve parameters are converted to the internal
78*4882a593Smuzhiyun  *   representation. The slope values are scaled to avoid overflow.
79*4882a593Smuzhiyun  *   the inverse slope values as well as the y-projection of the 1st
80*4882a593Smuzhiyun  *   segment are kept in order to avoid 64-bit divide operations
81*4882a593Smuzhiyun  *   that are expensive on 32-bit architectures.
82*4882a593Smuzhiyun  */
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun struct internal_sc {
85*4882a593Smuzhiyun 	u64	sm1;	/* scaled slope of the 1st segment */
86*4882a593Smuzhiyun 	u64	ism1;	/* scaled inverse-slope of the 1st segment */
87*4882a593Smuzhiyun 	u64	dx;	/* the x-projection of the 1st segment */
88*4882a593Smuzhiyun 	u64	dy;	/* the y-projection of the 1st segment */
89*4882a593Smuzhiyun 	u64	sm2;	/* scaled slope of the 2nd segment */
90*4882a593Smuzhiyun 	u64	ism2;	/* scaled inverse-slope of the 2nd segment */
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* runtime service curve */
94*4882a593Smuzhiyun struct runtime_sc {
95*4882a593Smuzhiyun 	u64	x;	/* current starting position on x-axis */
96*4882a593Smuzhiyun 	u64	y;	/* current starting position on y-axis */
97*4882a593Smuzhiyun 	u64	sm1;	/* scaled slope of the 1st segment */
98*4882a593Smuzhiyun 	u64	ism1;	/* scaled inverse-slope of the 1st segment */
99*4882a593Smuzhiyun 	u64	dx;	/* the x-projection of the 1st segment */
100*4882a593Smuzhiyun 	u64	dy;	/* the y-projection of the 1st segment */
101*4882a593Smuzhiyun 	u64	sm2;	/* scaled slope of the 2nd segment */
102*4882a593Smuzhiyun 	u64	ism2;	/* scaled inverse-slope of the 2nd segment */
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun enum hfsc_class_flags {
106*4882a593Smuzhiyun 	HFSC_RSC = 0x1,
107*4882a593Smuzhiyun 	HFSC_FSC = 0x2,
108*4882a593Smuzhiyun 	HFSC_USC = 0x4
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun struct hfsc_class {
112*4882a593Smuzhiyun 	struct Qdisc_class_common cl_common;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	struct gnet_stats_basic_packed bstats;
115*4882a593Smuzhiyun 	struct gnet_stats_queue qstats;
116*4882a593Smuzhiyun 	struct net_rate_estimator __rcu *rate_est;
117*4882a593Smuzhiyun 	struct tcf_proto __rcu *filter_list; /* filter list */
118*4882a593Smuzhiyun 	struct tcf_block *block;
119*4882a593Smuzhiyun 	unsigned int	filter_cnt;	/* filter count */
120*4882a593Smuzhiyun 	unsigned int	level;		/* class level in hierarchy */
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	struct hfsc_sched *sched;	/* scheduler data */
123*4882a593Smuzhiyun 	struct hfsc_class *cl_parent;	/* parent class */
124*4882a593Smuzhiyun 	struct list_head siblings;	/* sibling classes */
125*4882a593Smuzhiyun 	struct list_head children;	/* child classes */
126*4882a593Smuzhiyun 	struct Qdisc	*qdisc;		/* leaf qdisc */
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	struct rb_node el_node;		/* qdisc's eligible tree member */
129*4882a593Smuzhiyun 	struct rb_root vt_tree;		/* active children sorted by cl_vt */
130*4882a593Smuzhiyun 	struct rb_node vt_node;		/* parent's vt_tree member */
131*4882a593Smuzhiyun 	struct rb_root cf_tree;		/* active children sorted by cl_f */
132*4882a593Smuzhiyun 	struct rb_node cf_node;		/* parent's cf_heap member */
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	u64	cl_total;		/* total work in bytes */
135*4882a593Smuzhiyun 	u64	cl_cumul;		/* cumulative work in bytes done by
136*4882a593Smuzhiyun 					   real-time criteria */
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	u64	cl_d;			/* deadline*/
139*4882a593Smuzhiyun 	u64	cl_e;			/* eligible time */
140*4882a593Smuzhiyun 	u64	cl_vt;			/* virtual time */
141*4882a593Smuzhiyun 	u64	cl_f;			/* time when this class will fit for
142*4882a593Smuzhiyun 					   link-sharing, max(myf, cfmin) */
143*4882a593Smuzhiyun 	u64	cl_myf;			/* my fit-time (calculated from this
144*4882a593Smuzhiyun 					   class's own upperlimit curve) */
145*4882a593Smuzhiyun 	u64	cl_cfmin;		/* earliest children's fit-time (used
146*4882a593Smuzhiyun 					   with cl_myf to obtain cl_f) */
147*4882a593Smuzhiyun 	u64	cl_cvtmin;		/* minimal virtual time among the
148*4882a593Smuzhiyun 					   children fit for link-sharing
149*4882a593Smuzhiyun 					   (monotonic within a period) */
150*4882a593Smuzhiyun 	u64	cl_vtadj;		/* intra-period cumulative vt
151*4882a593Smuzhiyun 					   adjustment */
152*4882a593Smuzhiyun 	u64	cl_cvtoff;		/* largest virtual time seen among
153*4882a593Smuzhiyun 					   the children */
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	struct internal_sc cl_rsc;	/* internal real-time service curve */
156*4882a593Smuzhiyun 	struct internal_sc cl_fsc;	/* internal fair service curve */
157*4882a593Smuzhiyun 	struct internal_sc cl_usc;	/* internal upperlimit service curve */
158*4882a593Smuzhiyun 	struct runtime_sc cl_deadline;	/* deadline curve */
159*4882a593Smuzhiyun 	struct runtime_sc cl_eligible;	/* eligible curve */
160*4882a593Smuzhiyun 	struct runtime_sc cl_virtual;	/* virtual curve */
161*4882a593Smuzhiyun 	struct runtime_sc cl_ulimit;	/* upperlimit curve */
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	u8		cl_flags;	/* which curves are valid */
164*4882a593Smuzhiyun 	u32		cl_vtperiod;	/* vt period sequence number */
165*4882a593Smuzhiyun 	u32		cl_parentperiod;/* parent's vt period sequence number*/
166*4882a593Smuzhiyun 	u32		cl_nactive;	/* number of active children */
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun struct hfsc_sched {
170*4882a593Smuzhiyun 	u16	defcls;				/* default class id */
171*4882a593Smuzhiyun 	struct hfsc_class root;			/* root class */
172*4882a593Smuzhiyun 	struct Qdisc_class_hash clhash;		/* class hash */
173*4882a593Smuzhiyun 	struct rb_root eligible;		/* eligible tree */
174*4882a593Smuzhiyun 	struct qdisc_watchdog watchdog;		/* watchdog timer */
175*4882a593Smuzhiyun };
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun #define	HT_INFINITY	0xffffffffffffffffULL	/* infinite time value */
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /*
181*4882a593Smuzhiyun  * eligible tree holds backlogged classes being sorted by their eligible times.
182*4882a593Smuzhiyun  * there is one eligible tree per hfsc instance.
183*4882a593Smuzhiyun  */
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun static void
eltree_insert(struct hfsc_class * cl)186*4882a593Smuzhiyun eltree_insert(struct hfsc_class *cl)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	struct rb_node **p = &cl->sched->eligible.rb_node;
189*4882a593Smuzhiyun 	struct rb_node *parent = NULL;
190*4882a593Smuzhiyun 	struct hfsc_class *cl1;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	while (*p != NULL) {
193*4882a593Smuzhiyun 		parent = *p;
194*4882a593Smuzhiyun 		cl1 = rb_entry(parent, struct hfsc_class, el_node);
195*4882a593Smuzhiyun 		if (cl->cl_e >= cl1->cl_e)
196*4882a593Smuzhiyun 			p = &parent->rb_right;
197*4882a593Smuzhiyun 		else
198*4882a593Smuzhiyun 			p = &parent->rb_left;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 	rb_link_node(&cl->el_node, parent, p);
201*4882a593Smuzhiyun 	rb_insert_color(&cl->el_node, &cl->sched->eligible);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun static inline void
eltree_remove(struct hfsc_class * cl)205*4882a593Smuzhiyun eltree_remove(struct hfsc_class *cl)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	rb_erase(&cl->el_node, &cl->sched->eligible);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun static inline void
eltree_update(struct hfsc_class * cl)211*4882a593Smuzhiyun eltree_update(struct hfsc_class *cl)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	eltree_remove(cl);
214*4882a593Smuzhiyun 	eltree_insert(cl);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun /* find the class with the minimum deadline among the eligible classes */
218*4882a593Smuzhiyun static inline struct hfsc_class *
eltree_get_mindl(struct hfsc_sched * q,u64 cur_time)219*4882a593Smuzhiyun eltree_get_mindl(struct hfsc_sched *q, u64 cur_time)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	struct hfsc_class *p, *cl = NULL;
222*4882a593Smuzhiyun 	struct rb_node *n;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	for (n = rb_first(&q->eligible); n != NULL; n = rb_next(n)) {
225*4882a593Smuzhiyun 		p = rb_entry(n, struct hfsc_class, el_node);
226*4882a593Smuzhiyun 		if (p->cl_e > cur_time)
227*4882a593Smuzhiyun 			break;
228*4882a593Smuzhiyun 		if (cl == NULL || p->cl_d < cl->cl_d)
229*4882a593Smuzhiyun 			cl = p;
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 	return cl;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun /* find the class with minimum eligible time among the eligible classes */
235*4882a593Smuzhiyun static inline struct hfsc_class *
eltree_get_minel(struct hfsc_sched * q)236*4882a593Smuzhiyun eltree_get_minel(struct hfsc_sched *q)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	struct rb_node *n;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	n = rb_first(&q->eligible);
241*4882a593Smuzhiyun 	if (n == NULL)
242*4882a593Smuzhiyun 		return NULL;
243*4882a593Smuzhiyun 	return rb_entry(n, struct hfsc_class, el_node);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun  * vttree holds holds backlogged child classes being sorted by their virtual
248*4882a593Smuzhiyun  * time. each intermediate class has one vttree.
249*4882a593Smuzhiyun  */
250*4882a593Smuzhiyun static void
vttree_insert(struct hfsc_class * cl)251*4882a593Smuzhiyun vttree_insert(struct hfsc_class *cl)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct rb_node **p = &cl->cl_parent->vt_tree.rb_node;
254*4882a593Smuzhiyun 	struct rb_node *parent = NULL;
255*4882a593Smuzhiyun 	struct hfsc_class *cl1;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	while (*p != NULL) {
258*4882a593Smuzhiyun 		parent = *p;
259*4882a593Smuzhiyun 		cl1 = rb_entry(parent, struct hfsc_class, vt_node);
260*4882a593Smuzhiyun 		if (cl->cl_vt >= cl1->cl_vt)
261*4882a593Smuzhiyun 			p = &parent->rb_right;
262*4882a593Smuzhiyun 		else
263*4882a593Smuzhiyun 			p = &parent->rb_left;
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 	rb_link_node(&cl->vt_node, parent, p);
266*4882a593Smuzhiyun 	rb_insert_color(&cl->vt_node, &cl->cl_parent->vt_tree);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun static inline void
vttree_remove(struct hfsc_class * cl)270*4882a593Smuzhiyun vttree_remove(struct hfsc_class *cl)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	rb_erase(&cl->vt_node, &cl->cl_parent->vt_tree);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun static inline void
vttree_update(struct hfsc_class * cl)276*4882a593Smuzhiyun vttree_update(struct hfsc_class *cl)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	vttree_remove(cl);
279*4882a593Smuzhiyun 	vttree_insert(cl);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun static inline struct hfsc_class *
vttree_firstfit(struct hfsc_class * cl,u64 cur_time)283*4882a593Smuzhiyun vttree_firstfit(struct hfsc_class *cl, u64 cur_time)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	struct hfsc_class *p;
286*4882a593Smuzhiyun 	struct rb_node *n;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	for (n = rb_first(&cl->vt_tree); n != NULL; n = rb_next(n)) {
289*4882a593Smuzhiyun 		p = rb_entry(n, struct hfsc_class, vt_node);
290*4882a593Smuzhiyun 		if (p->cl_f <= cur_time)
291*4882a593Smuzhiyun 			return p;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 	return NULL;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun /*
297*4882a593Smuzhiyun  * get the leaf class with the minimum vt in the hierarchy
298*4882a593Smuzhiyun  */
299*4882a593Smuzhiyun static struct hfsc_class *
vttree_get_minvt(struct hfsc_class * cl,u64 cur_time)300*4882a593Smuzhiyun vttree_get_minvt(struct hfsc_class *cl, u64 cur_time)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	/* if root-class's cfmin is bigger than cur_time nothing to do */
303*4882a593Smuzhiyun 	if (cl->cl_cfmin > cur_time)
304*4882a593Smuzhiyun 		return NULL;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	while (cl->level > 0) {
307*4882a593Smuzhiyun 		cl = vttree_firstfit(cl, cur_time);
308*4882a593Smuzhiyun 		if (cl == NULL)
309*4882a593Smuzhiyun 			return NULL;
310*4882a593Smuzhiyun 		/*
311*4882a593Smuzhiyun 		 * update parent's cl_cvtmin.
312*4882a593Smuzhiyun 		 */
313*4882a593Smuzhiyun 		if (cl->cl_parent->cl_cvtmin < cl->cl_vt)
314*4882a593Smuzhiyun 			cl->cl_parent->cl_cvtmin = cl->cl_vt;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 	return cl;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun static void
cftree_insert(struct hfsc_class * cl)320*4882a593Smuzhiyun cftree_insert(struct hfsc_class *cl)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct rb_node **p = &cl->cl_parent->cf_tree.rb_node;
323*4882a593Smuzhiyun 	struct rb_node *parent = NULL;
324*4882a593Smuzhiyun 	struct hfsc_class *cl1;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	while (*p != NULL) {
327*4882a593Smuzhiyun 		parent = *p;
328*4882a593Smuzhiyun 		cl1 = rb_entry(parent, struct hfsc_class, cf_node);
329*4882a593Smuzhiyun 		if (cl->cl_f >= cl1->cl_f)
330*4882a593Smuzhiyun 			p = &parent->rb_right;
331*4882a593Smuzhiyun 		else
332*4882a593Smuzhiyun 			p = &parent->rb_left;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 	rb_link_node(&cl->cf_node, parent, p);
335*4882a593Smuzhiyun 	rb_insert_color(&cl->cf_node, &cl->cl_parent->cf_tree);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun static inline void
cftree_remove(struct hfsc_class * cl)339*4882a593Smuzhiyun cftree_remove(struct hfsc_class *cl)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	rb_erase(&cl->cf_node, &cl->cl_parent->cf_tree);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun static inline void
cftree_update(struct hfsc_class * cl)345*4882a593Smuzhiyun cftree_update(struct hfsc_class *cl)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	cftree_remove(cl);
348*4882a593Smuzhiyun 	cftree_insert(cl);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun /*
352*4882a593Smuzhiyun  * service curve support functions
353*4882a593Smuzhiyun  *
354*4882a593Smuzhiyun  *  external service curve parameters
355*4882a593Smuzhiyun  *	m: bps
356*4882a593Smuzhiyun  *	d: us
357*4882a593Smuzhiyun  *  internal service curve parameters
358*4882a593Smuzhiyun  *	sm: (bytes/psched_us) << SM_SHIFT
359*4882a593Smuzhiyun  *	ism: (psched_us/byte) << ISM_SHIFT
360*4882a593Smuzhiyun  *	dx: psched_us
361*4882a593Smuzhiyun  *
362*4882a593Smuzhiyun  * The clock source resolution with ktime and PSCHED_SHIFT 10 is 1.024us.
363*4882a593Smuzhiyun  *
364*4882a593Smuzhiyun  * sm and ism are scaled in order to keep effective digits.
365*4882a593Smuzhiyun  * SM_SHIFT and ISM_SHIFT are selected to keep at least 4 effective
366*4882a593Smuzhiyun  * digits in decimal using the following table.
367*4882a593Smuzhiyun  *
368*4882a593Smuzhiyun  *  bits/sec      100Kbps     1Mbps     10Mbps     100Mbps    1Gbps
369*4882a593Smuzhiyun  *  ------------+-------------------------------------------------------
370*4882a593Smuzhiyun  *  bytes/1.024us 12.8e-3    128e-3     1280e-3    12800e-3   128000e-3
371*4882a593Smuzhiyun  *
372*4882a593Smuzhiyun  *  1.024us/byte  78.125     7.8125     0.78125    0.078125   0.0078125
373*4882a593Smuzhiyun  *
374*4882a593Smuzhiyun  * So, for PSCHED_SHIFT 10 we need: SM_SHIFT 20, ISM_SHIFT 18.
375*4882a593Smuzhiyun  */
376*4882a593Smuzhiyun #define	SM_SHIFT	(30 - PSCHED_SHIFT)
377*4882a593Smuzhiyun #define	ISM_SHIFT	(8 + PSCHED_SHIFT)
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun #define	SM_MASK		((1ULL << SM_SHIFT) - 1)
380*4882a593Smuzhiyun #define	ISM_MASK	((1ULL << ISM_SHIFT) - 1)
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun static inline u64
seg_x2y(u64 x,u64 sm)383*4882a593Smuzhiyun seg_x2y(u64 x, u64 sm)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	u64 y;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	/*
388*4882a593Smuzhiyun 	 * compute
389*4882a593Smuzhiyun 	 *	y = x * sm >> SM_SHIFT
390*4882a593Smuzhiyun 	 * but divide it for the upper and lower bits to avoid overflow
391*4882a593Smuzhiyun 	 */
392*4882a593Smuzhiyun 	y = (x >> SM_SHIFT) * sm + (((x & SM_MASK) * sm) >> SM_SHIFT);
393*4882a593Smuzhiyun 	return y;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun static inline u64
seg_y2x(u64 y,u64 ism)397*4882a593Smuzhiyun seg_y2x(u64 y, u64 ism)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	u64 x;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (y == 0)
402*4882a593Smuzhiyun 		x = 0;
403*4882a593Smuzhiyun 	else if (ism == HT_INFINITY)
404*4882a593Smuzhiyun 		x = HT_INFINITY;
405*4882a593Smuzhiyun 	else {
406*4882a593Smuzhiyun 		x = (y >> ISM_SHIFT) * ism
407*4882a593Smuzhiyun 		    + (((y & ISM_MASK) * ism) >> ISM_SHIFT);
408*4882a593Smuzhiyun 	}
409*4882a593Smuzhiyun 	return x;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun /* Convert m (bps) into sm (bytes/psched us) */
413*4882a593Smuzhiyun static u64
m2sm(u32 m)414*4882a593Smuzhiyun m2sm(u32 m)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	u64 sm;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	sm = ((u64)m << SM_SHIFT);
419*4882a593Smuzhiyun 	sm += PSCHED_TICKS_PER_SEC - 1;
420*4882a593Smuzhiyun 	do_div(sm, PSCHED_TICKS_PER_SEC);
421*4882a593Smuzhiyun 	return sm;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun /* convert m (bps) into ism (psched us/byte) */
425*4882a593Smuzhiyun static u64
m2ism(u32 m)426*4882a593Smuzhiyun m2ism(u32 m)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	u64 ism;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (m == 0)
431*4882a593Smuzhiyun 		ism = HT_INFINITY;
432*4882a593Smuzhiyun 	else {
433*4882a593Smuzhiyun 		ism = ((u64)PSCHED_TICKS_PER_SEC << ISM_SHIFT);
434*4882a593Smuzhiyun 		ism += m - 1;
435*4882a593Smuzhiyun 		do_div(ism, m);
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun 	return ism;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun /* convert d (us) into dx (psched us) */
441*4882a593Smuzhiyun static u64
d2dx(u32 d)442*4882a593Smuzhiyun d2dx(u32 d)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	u64 dx;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	dx = ((u64)d * PSCHED_TICKS_PER_SEC);
447*4882a593Smuzhiyun 	dx += USEC_PER_SEC - 1;
448*4882a593Smuzhiyun 	do_div(dx, USEC_PER_SEC);
449*4882a593Smuzhiyun 	return dx;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun /* convert sm (bytes/psched us) into m (bps) */
453*4882a593Smuzhiyun static u32
sm2m(u64 sm)454*4882a593Smuzhiyun sm2m(u64 sm)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	u64 m;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	m = (sm * PSCHED_TICKS_PER_SEC) >> SM_SHIFT;
459*4882a593Smuzhiyun 	return (u32)m;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun /* convert dx (psched us) into d (us) */
463*4882a593Smuzhiyun static u32
dx2d(u64 dx)464*4882a593Smuzhiyun dx2d(u64 dx)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun 	u64 d;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	d = dx * USEC_PER_SEC;
469*4882a593Smuzhiyun 	do_div(d, PSCHED_TICKS_PER_SEC);
470*4882a593Smuzhiyun 	return (u32)d;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun static void
sc2isc(struct tc_service_curve * sc,struct internal_sc * isc)474*4882a593Smuzhiyun sc2isc(struct tc_service_curve *sc, struct internal_sc *isc)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	isc->sm1  = m2sm(sc->m1);
477*4882a593Smuzhiyun 	isc->ism1 = m2ism(sc->m1);
478*4882a593Smuzhiyun 	isc->dx   = d2dx(sc->d);
479*4882a593Smuzhiyun 	isc->dy   = seg_x2y(isc->dx, isc->sm1);
480*4882a593Smuzhiyun 	isc->sm2  = m2sm(sc->m2);
481*4882a593Smuzhiyun 	isc->ism2 = m2ism(sc->m2);
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun /*
485*4882a593Smuzhiyun  * initialize the runtime service curve with the given internal
486*4882a593Smuzhiyun  * service curve starting at (x, y).
487*4882a593Smuzhiyun  */
488*4882a593Smuzhiyun static void
rtsc_init(struct runtime_sc * rtsc,struct internal_sc * isc,u64 x,u64 y)489*4882a593Smuzhiyun rtsc_init(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	rtsc->x	   = x;
492*4882a593Smuzhiyun 	rtsc->y    = y;
493*4882a593Smuzhiyun 	rtsc->sm1  = isc->sm1;
494*4882a593Smuzhiyun 	rtsc->ism1 = isc->ism1;
495*4882a593Smuzhiyun 	rtsc->dx   = isc->dx;
496*4882a593Smuzhiyun 	rtsc->dy   = isc->dy;
497*4882a593Smuzhiyun 	rtsc->sm2  = isc->sm2;
498*4882a593Smuzhiyun 	rtsc->ism2 = isc->ism2;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun /*
502*4882a593Smuzhiyun  * calculate the y-projection of the runtime service curve by the
503*4882a593Smuzhiyun  * given x-projection value
504*4882a593Smuzhiyun  */
505*4882a593Smuzhiyun static u64
rtsc_y2x(struct runtime_sc * rtsc,u64 y)506*4882a593Smuzhiyun rtsc_y2x(struct runtime_sc *rtsc, u64 y)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	u64 x;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	if (y < rtsc->y)
511*4882a593Smuzhiyun 		x = rtsc->x;
512*4882a593Smuzhiyun 	else if (y <= rtsc->y + rtsc->dy) {
513*4882a593Smuzhiyun 		/* x belongs to the 1st segment */
514*4882a593Smuzhiyun 		if (rtsc->dy == 0)
515*4882a593Smuzhiyun 			x = rtsc->x + rtsc->dx;
516*4882a593Smuzhiyun 		else
517*4882a593Smuzhiyun 			x = rtsc->x + seg_y2x(y - rtsc->y, rtsc->ism1);
518*4882a593Smuzhiyun 	} else {
519*4882a593Smuzhiyun 		/* x belongs to the 2nd segment */
520*4882a593Smuzhiyun 		x = rtsc->x + rtsc->dx
521*4882a593Smuzhiyun 		    + seg_y2x(y - rtsc->y - rtsc->dy, rtsc->ism2);
522*4882a593Smuzhiyun 	}
523*4882a593Smuzhiyun 	return x;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun static u64
rtsc_x2y(struct runtime_sc * rtsc,u64 x)527*4882a593Smuzhiyun rtsc_x2y(struct runtime_sc *rtsc, u64 x)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	u64 y;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	if (x <= rtsc->x)
532*4882a593Smuzhiyun 		y = rtsc->y;
533*4882a593Smuzhiyun 	else if (x <= rtsc->x + rtsc->dx)
534*4882a593Smuzhiyun 		/* y belongs to the 1st segment */
535*4882a593Smuzhiyun 		y = rtsc->y + seg_x2y(x - rtsc->x, rtsc->sm1);
536*4882a593Smuzhiyun 	else
537*4882a593Smuzhiyun 		/* y belongs to the 2nd segment */
538*4882a593Smuzhiyun 		y = rtsc->y + rtsc->dy
539*4882a593Smuzhiyun 		    + seg_x2y(x - rtsc->x - rtsc->dx, rtsc->sm2);
540*4882a593Smuzhiyun 	return y;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun /*
544*4882a593Smuzhiyun  * update the runtime service curve by taking the minimum of the current
545*4882a593Smuzhiyun  * runtime service curve and the service curve starting at (x, y).
546*4882a593Smuzhiyun  */
547*4882a593Smuzhiyun static void
rtsc_min(struct runtime_sc * rtsc,struct internal_sc * isc,u64 x,u64 y)548*4882a593Smuzhiyun rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun 	u64 y1, y2, dx, dy;
551*4882a593Smuzhiyun 	u32 dsm;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	if (isc->sm1 <= isc->sm2) {
554*4882a593Smuzhiyun 		/* service curve is convex */
555*4882a593Smuzhiyun 		y1 = rtsc_x2y(rtsc, x);
556*4882a593Smuzhiyun 		if (y1 < y)
557*4882a593Smuzhiyun 			/* the current rtsc is smaller */
558*4882a593Smuzhiyun 			return;
559*4882a593Smuzhiyun 		rtsc->x = x;
560*4882a593Smuzhiyun 		rtsc->y = y;
561*4882a593Smuzhiyun 		return;
562*4882a593Smuzhiyun 	}
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	/*
565*4882a593Smuzhiyun 	 * service curve is concave
566*4882a593Smuzhiyun 	 * compute the two y values of the current rtsc
567*4882a593Smuzhiyun 	 *	y1: at x
568*4882a593Smuzhiyun 	 *	y2: at (x + dx)
569*4882a593Smuzhiyun 	 */
570*4882a593Smuzhiyun 	y1 = rtsc_x2y(rtsc, x);
571*4882a593Smuzhiyun 	if (y1 <= y) {
572*4882a593Smuzhiyun 		/* rtsc is below isc, no change to rtsc */
573*4882a593Smuzhiyun 		return;
574*4882a593Smuzhiyun 	}
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	y2 = rtsc_x2y(rtsc, x + isc->dx);
577*4882a593Smuzhiyun 	if (y2 >= y + isc->dy) {
578*4882a593Smuzhiyun 		/* rtsc is above isc, replace rtsc by isc */
579*4882a593Smuzhiyun 		rtsc->x = x;
580*4882a593Smuzhiyun 		rtsc->y = y;
581*4882a593Smuzhiyun 		rtsc->dx = isc->dx;
582*4882a593Smuzhiyun 		rtsc->dy = isc->dy;
583*4882a593Smuzhiyun 		return;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	/*
587*4882a593Smuzhiyun 	 * the two curves intersect
588*4882a593Smuzhiyun 	 * compute the offsets (dx, dy) using the reverse
589*4882a593Smuzhiyun 	 * function of seg_x2y()
590*4882a593Smuzhiyun 	 *	seg_x2y(dx, sm1) == seg_x2y(dx, sm2) + (y1 - y)
591*4882a593Smuzhiyun 	 */
592*4882a593Smuzhiyun 	dx = (y1 - y) << SM_SHIFT;
593*4882a593Smuzhiyun 	dsm = isc->sm1 - isc->sm2;
594*4882a593Smuzhiyun 	do_div(dx, dsm);
595*4882a593Smuzhiyun 	/*
596*4882a593Smuzhiyun 	 * check if (x, y1) belongs to the 1st segment of rtsc.
597*4882a593Smuzhiyun 	 * if so, add the offset.
598*4882a593Smuzhiyun 	 */
599*4882a593Smuzhiyun 	if (rtsc->x + rtsc->dx > x)
600*4882a593Smuzhiyun 		dx += rtsc->x + rtsc->dx - x;
601*4882a593Smuzhiyun 	dy = seg_x2y(dx, isc->sm1);
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	rtsc->x = x;
604*4882a593Smuzhiyun 	rtsc->y = y;
605*4882a593Smuzhiyun 	rtsc->dx = dx;
606*4882a593Smuzhiyun 	rtsc->dy = dy;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun static void
init_ed(struct hfsc_class * cl,unsigned int next_len)610*4882a593Smuzhiyun init_ed(struct hfsc_class *cl, unsigned int next_len)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	u64 cur_time = psched_get_time();
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	/* update the deadline curve */
615*4882a593Smuzhiyun 	rtsc_min(&cl->cl_deadline, &cl->cl_rsc, cur_time, cl->cl_cumul);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	/*
618*4882a593Smuzhiyun 	 * update the eligible curve.
619*4882a593Smuzhiyun 	 * for concave, it is equal to the deadline curve.
620*4882a593Smuzhiyun 	 * for convex, it is a linear curve with slope m2.
621*4882a593Smuzhiyun 	 */
622*4882a593Smuzhiyun 	cl->cl_eligible = cl->cl_deadline;
623*4882a593Smuzhiyun 	if (cl->cl_rsc.sm1 <= cl->cl_rsc.sm2) {
624*4882a593Smuzhiyun 		cl->cl_eligible.dx = 0;
625*4882a593Smuzhiyun 		cl->cl_eligible.dy = 0;
626*4882a593Smuzhiyun 	}
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	/* compute e and d */
629*4882a593Smuzhiyun 	cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul);
630*4882a593Smuzhiyun 	cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	eltree_insert(cl);
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun static void
update_ed(struct hfsc_class * cl,unsigned int next_len)636*4882a593Smuzhiyun update_ed(struct hfsc_class *cl, unsigned int next_len)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun 	cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul);
639*4882a593Smuzhiyun 	cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	eltree_update(cl);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun static inline void
update_d(struct hfsc_class * cl,unsigned int next_len)645*4882a593Smuzhiyun update_d(struct hfsc_class *cl, unsigned int next_len)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun 	cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun static inline void
update_cfmin(struct hfsc_class * cl)651*4882a593Smuzhiyun update_cfmin(struct hfsc_class *cl)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun 	struct rb_node *n = rb_first(&cl->cf_tree);
654*4882a593Smuzhiyun 	struct hfsc_class *p;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	if (n == NULL) {
657*4882a593Smuzhiyun 		cl->cl_cfmin = 0;
658*4882a593Smuzhiyun 		return;
659*4882a593Smuzhiyun 	}
660*4882a593Smuzhiyun 	p = rb_entry(n, struct hfsc_class, cf_node);
661*4882a593Smuzhiyun 	cl->cl_cfmin = p->cl_f;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun static void
init_vf(struct hfsc_class * cl,unsigned int len)665*4882a593Smuzhiyun init_vf(struct hfsc_class *cl, unsigned int len)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun 	struct hfsc_class *max_cl;
668*4882a593Smuzhiyun 	struct rb_node *n;
669*4882a593Smuzhiyun 	u64 vt, f, cur_time;
670*4882a593Smuzhiyun 	int go_active;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	cur_time = 0;
673*4882a593Smuzhiyun 	go_active = 1;
674*4882a593Smuzhiyun 	for (; cl->cl_parent != NULL; cl = cl->cl_parent) {
675*4882a593Smuzhiyun 		if (go_active && cl->cl_nactive++ == 0)
676*4882a593Smuzhiyun 			go_active = 1;
677*4882a593Smuzhiyun 		else
678*4882a593Smuzhiyun 			go_active = 0;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 		if (go_active) {
681*4882a593Smuzhiyun 			n = rb_last(&cl->cl_parent->vt_tree);
682*4882a593Smuzhiyun 			if (n != NULL) {
683*4882a593Smuzhiyun 				max_cl = rb_entry(n, struct hfsc_class, vt_node);
684*4882a593Smuzhiyun 				/*
685*4882a593Smuzhiyun 				 * set vt to the average of the min and max
686*4882a593Smuzhiyun 				 * classes.  if the parent's period didn't
687*4882a593Smuzhiyun 				 * change, don't decrease vt of the class.
688*4882a593Smuzhiyun 				 */
689*4882a593Smuzhiyun 				vt = max_cl->cl_vt;
690*4882a593Smuzhiyun 				if (cl->cl_parent->cl_cvtmin != 0)
691*4882a593Smuzhiyun 					vt = (cl->cl_parent->cl_cvtmin + vt)/2;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 				if (cl->cl_parent->cl_vtperiod !=
694*4882a593Smuzhiyun 				    cl->cl_parentperiod || vt > cl->cl_vt)
695*4882a593Smuzhiyun 					cl->cl_vt = vt;
696*4882a593Smuzhiyun 			} else {
697*4882a593Smuzhiyun 				/*
698*4882a593Smuzhiyun 				 * first child for a new parent backlog period.
699*4882a593Smuzhiyun 				 * initialize cl_vt to the highest value seen
700*4882a593Smuzhiyun 				 * among the siblings. this is analogous to
701*4882a593Smuzhiyun 				 * what cur_time would provide in realtime case.
702*4882a593Smuzhiyun 				 */
703*4882a593Smuzhiyun 				cl->cl_vt = cl->cl_parent->cl_cvtoff;
704*4882a593Smuzhiyun 				cl->cl_parent->cl_cvtmin = 0;
705*4882a593Smuzhiyun 			}
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 			/* update the virtual curve */
708*4882a593Smuzhiyun 			rtsc_min(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total);
709*4882a593Smuzhiyun 			cl->cl_vtadj = 0;
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 			cl->cl_vtperiod++;  /* increment vt period */
712*4882a593Smuzhiyun 			cl->cl_parentperiod = cl->cl_parent->cl_vtperiod;
713*4882a593Smuzhiyun 			if (cl->cl_parent->cl_nactive == 0)
714*4882a593Smuzhiyun 				cl->cl_parentperiod++;
715*4882a593Smuzhiyun 			cl->cl_f = 0;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 			vttree_insert(cl);
718*4882a593Smuzhiyun 			cftree_insert(cl);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 			if (cl->cl_flags & HFSC_USC) {
721*4882a593Smuzhiyun 				/* class has upper limit curve */
722*4882a593Smuzhiyun 				if (cur_time == 0)
723*4882a593Smuzhiyun 					cur_time = psched_get_time();
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 				/* update the ulimit curve */
726*4882a593Smuzhiyun 				rtsc_min(&cl->cl_ulimit, &cl->cl_usc, cur_time,
727*4882a593Smuzhiyun 					 cl->cl_total);
728*4882a593Smuzhiyun 				/* compute myf */
729*4882a593Smuzhiyun 				cl->cl_myf = rtsc_y2x(&cl->cl_ulimit,
730*4882a593Smuzhiyun 						      cl->cl_total);
731*4882a593Smuzhiyun 			}
732*4882a593Smuzhiyun 		}
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 		f = max(cl->cl_myf, cl->cl_cfmin);
735*4882a593Smuzhiyun 		if (f != cl->cl_f) {
736*4882a593Smuzhiyun 			cl->cl_f = f;
737*4882a593Smuzhiyun 			cftree_update(cl);
738*4882a593Smuzhiyun 		}
739*4882a593Smuzhiyun 		update_cfmin(cl->cl_parent);
740*4882a593Smuzhiyun 	}
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun static void
update_vf(struct hfsc_class * cl,unsigned int len,u64 cur_time)744*4882a593Smuzhiyun update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun 	u64 f; /* , myf_bound, delta; */
747*4882a593Smuzhiyun 	int go_passive = 0;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC)
750*4882a593Smuzhiyun 		go_passive = 1;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	for (; cl->cl_parent != NULL; cl = cl->cl_parent) {
753*4882a593Smuzhiyun 		cl->cl_total += len;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 		if (!(cl->cl_flags & HFSC_FSC) || cl->cl_nactive == 0)
756*4882a593Smuzhiyun 			continue;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 		if (go_passive && --cl->cl_nactive == 0)
759*4882a593Smuzhiyun 			go_passive = 1;
760*4882a593Smuzhiyun 		else
761*4882a593Smuzhiyun 			go_passive = 0;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 		/* update vt */
764*4882a593Smuzhiyun 		cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total) + cl->cl_vtadj;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 		/*
767*4882a593Smuzhiyun 		 * if vt of the class is smaller than cvtmin,
768*4882a593Smuzhiyun 		 * the class was skipped in the past due to non-fit.
769*4882a593Smuzhiyun 		 * if so, we need to adjust vtadj.
770*4882a593Smuzhiyun 		 */
771*4882a593Smuzhiyun 		if (cl->cl_vt < cl->cl_parent->cl_cvtmin) {
772*4882a593Smuzhiyun 			cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt;
773*4882a593Smuzhiyun 			cl->cl_vt = cl->cl_parent->cl_cvtmin;
774*4882a593Smuzhiyun 		}
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 		if (go_passive) {
777*4882a593Smuzhiyun 			/* no more active child, going passive */
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 			/* update cvtoff of the parent class */
780*4882a593Smuzhiyun 			if (cl->cl_vt > cl->cl_parent->cl_cvtoff)
781*4882a593Smuzhiyun 				cl->cl_parent->cl_cvtoff = cl->cl_vt;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 			/* remove this class from the vt tree */
784*4882a593Smuzhiyun 			vttree_remove(cl);
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 			cftree_remove(cl);
787*4882a593Smuzhiyun 			update_cfmin(cl->cl_parent);
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 			continue;
790*4882a593Smuzhiyun 		}
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 		/* update the vt tree */
793*4882a593Smuzhiyun 		vttree_update(cl);
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 		/* update f */
796*4882a593Smuzhiyun 		if (cl->cl_flags & HFSC_USC) {
797*4882a593Smuzhiyun 			cl->cl_myf = rtsc_y2x(&cl->cl_ulimit, cl->cl_total);
798*4882a593Smuzhiyun #if 0
799*4882a593Smuzhiyun 			cl->cl_myf = cl->cl_myfadj + rtsc_y2x(&cl->cl_ulimit,
800*4882a593Smuzhiyun 							      cl->cl_total);
801*4882a593Smuzhiyun 			/*
802*4882a593Smuzhiyun 			 * This code causes classes to stay way under their
803*4882a593Smuzhiyun 			 * limit when multiple classes are used at gigabit
804*4882a593Smuzhiyun 			 * speed. needs investigation. -kaber
805*4882a593Smuzhiyun 			 */
806*4882a593Smuzhiyun 			/*
807*4882a593Smuzhiyun 			 * if myf lags behind by more than one clock tick
808*4882a593Smuzhiyun 			 * from the current time, adjust myfadj to prevent
809*4882a593Smuzhiyun 			 * a rate-limited class from going greedy.
810*4882a593Smuzhiyun 			 * in a steady state under rate-limiting, myf
811*4882a593Smuzhiyun 			 * fluctuates within one clock tick.
812*4882a593Smuzhiyun 			 */
813*4882a593Smuzhiyun 			myf_bound = cur_time - PSCHED_JIFFIE2US(1);
814*4882a593Smuzhiyun 			if (cl->cl_myf < myf_bound) {
815*4882a593Smuzhiyun 				delta = cur_time - cl->cl_myf;
816*4882a593Smuzhiyun 				cl->cl_myfadj += delta;
817*4882a593Smuzhiyun 				cl->cl_myf += delta;
818*4882a593Smuzhiyun 			}
819*4882a593Smuzhiyun #endif
820*4882a593Smuzhiyun 		}
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 		f = max(cl->cl_myf, cl->cl_cfmin);
823*4882a593Smuzhiyun 		if (f != cl->cl_f) {
824*4882a593Smuzhiyun 			cl->cl_f = f;
825*4882a593Smuzhiyun 			cftree_update(cl);
826*4882a593Smuzhiyun 			update_cfmin(cl->cl_parent);
827*4882a593Smuzhiyun 		}
828*4882a593Smuzhiyun 	}
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun static unsigned int
qdisc_peek_len(struct Qdisc * sch)832*4882a593Smuzhiyun qdisc_peek_len(struct Qdisc *sch)
833*4882a593Smuzhiyun {
834*4882a593Smuzhiyun 	struct sk_buff *skb;
835*4882a593Smuzhiyun 	unsigned int len;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	skb = sch->ops->peek(sch);
838*4882a593Smuzhiyun 	if (unlikely(skb == NULL)) {
839*4882a593Smuzhiyun 		qdisc_warn_nonwc("qdisc_peek_len", sch);
840*4882a593Smuzhiyun 		return 0;
841*4882a593Smuzhiyun 	}
842*4882a593Smuzhiyun 	len = qdisc_pkt_len(skb);
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	return len;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun static void
hfsc_adjust_levels(struct hfsc_class * cl)848*4882a593Smuzhiyun hfsc_adjust_levels(struct hfsc_class *cl)
849*4882a593Smuzhiyun {
850*4882a593Smuzhiyun 	struct hfsc_class *p;
851*4882a593Smuzhiyun 	unsigned int level;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	do {
854*4882a593Smuzhiyun 		level = 0;
855*4882a593Smuzhiyun 		list_for_each_entry(p, &cl->children, siblings) {
856*4882a593Smuzhiyun 			if (p->level >= level)
857*4882a593Smuzhiyun 				level = p->level + 1;
858*4882a593Smuzhiyun 		}
859*4882a593Smuzhiyun 		cl->level = level;
860*4882a593Smuzhiyun 	} while ((cl = cl->cl_parent) != NULL);
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun static inline struct hfsc_class *
hfsc_find_class(u32 classid,struct Qdisc * sch)864*4882a593Smuzhiyun hfsc_find_class(u32 classid, struct Qdisc *sch)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
867*4882a593Smuzhiyun 	struct Qdisc_class_common *clc;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	clc = qdisc_class_find(&q->clhash, classid);
870*4882a593Smuzhiyun 	if (clc == NULL)
871*4882a593Smuzhiyun 		return NULL;
872*4882a593Smuzhiyun 	return container_of(clc, struct hfsc_class, cl_common);
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun static void
hfsc_change_rsc(struct hfsc_class * cl,struct tc_service_curve * rsc,u64 cur_time)876*4882a593Smuzhiyun hfsc_change_rsc(struct hfsc_class *cl, struct tc_service_curve *rsc,
877*4882a593Smuzhiyun 		u64 cur_time)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun 	sc2isc(rsc, &cl->cl_rsc);
880*4882a593Smuzhiyun 	rtsc_init(&cl->cl_deadline, &cl->cl_rsc, cur_time, cl->cl_cumul);
881*4882a593Smuzhiyun 	cl->cl_eligible = cl->cl_deadline;
882*4882a593Smuzhiyun 	if (cl->cl_rsc.sm1 <= cl->cl_rsc.sm2) {
883*4882a593Smuzhiyun 		cl->cl_eligible.dx = 0;
884*4882a593Smuzhiyun 		cl->cl_eligible.dy = 0;
885*4882a593Smuzhiyun 	}
886*4882a593Smuzhiyun 	cl->cl_flags |= HFSC_RSC;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun static void
hfsc_change_fsc(struct hfsc_class * cl,struct tc_service_curve * fsc)890*4882a593Smuzhiyun hfsc_change_fsc(struct hfsc_class *cl, struct tc_service_curve *fsc)
891*4882a593Smuzhiyun {
892*4882a593Smuzhiyun 	sc2isc(fsc, &cl->cl_fsc);
893*4882a593Smuzhiyun 	rtsc_init(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total);
894*4882a593Smuzhiyun 	cl->cl_flags |= HFSC_FSC;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun static void
hfsc_change_usc(struct hfsc_class * cl,struct tc_service_curve * usc,u64 cur_time)898*4882a593Smuzhiyun hfsc_change_usc(struct hfsc_class *cl, struct tc_service_curve *usc,
899*4882a593Smuzhiyun 		u64 cur_time)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun 	sc2isc(usc, &cl->cl_usc);
902*4882a593Smuzhiyun 	rtsc_init(&cl->cl_ulimit, &cl->cl_usc, cur_time, cl->cl_total);
903*4882a593Smuzhiyun 	cl->cl_flags |= HFSC_USC;
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun static const struct nla_policy hfsc_policy[TCA_HFSC_MAX + 1] = {
907*4882a593Smuzhiyun 	[TCA_HFSC_RSC]	= { .len = sizeof(struct tc_service_curve) },
908*4882a593Smuzhiyun 	[TCA_HFSC_FSC]	= { .len = sizeof(struct tc_service_curve) },
909*4882a593Smuzhiyun 	[TCA_HFSC_USC]	= { .len = sizeof(struct tc_service_curve) },
910*4882a593Smuzhiyun };
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun static int
hfsc_change_class(struct Qdisc * sch,u32 classid,u32 parentid,struct nlattr ** tca,unsigned long * arg,struct netlink_ext_ack * extack)913*4882a593Smuzhiyun hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
914*4882a593Smuzhiyun 		  struct nlattr **tca, unsigned long *arg,
915*4882a593Smuzhiyun 		  struct netlink_ext_ack *extack)
916*4882a593Smuzhiyun {
917*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
918*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)*arg;
919*4882a593Smuzhiyun 	struct hfsc_class *parent = NULL;
920*4882a593Smuzhiyun 	struct nlattr *opt = tca[TCA_OPTIONS];
921*4882a593Smuzhiyun 	struct nlattr *tb[TCA_HFSC_MAX + 1];
922*4882a593Smuzhiyun 	struct tc_service_curve *rsc = NULL, *fsc = NULL, *usc = NULL;
923*4882a593Smuzhiyun 	u64 cur_time;
924*4882a593Smuzhiyun 	int err;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	if (opt == NULL)
927*4882a593Smuzhiyun 		return -EINVAL;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	err = nla_parse_nested_deprecated(tb, TCA_HFSC_MAX, opt, hfsc_policy,
930*4882a593Smuzhiyun 					  NULL);
931*4882a593Smuzhiyun 	if (err < 0)
932*4882a593Smuzhiyun 		return err;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	if (tb[TCA_HFSC_RSC]) {
935*4882a593Smuzhiyun 		rsc = nla_data(tb[TCA_HFSC_RSC]);
936*4882a593Smuzhiyun 		if (rsc->m1 == 0 && rsc->m2 == 0)
937*4882a593Smuzhiyun 			rsc = NULL;
938*4882a593Smuzhiyun 	}
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	if (tb[TCA_HFSC_FSC]) {
941*4882a593Smuzhiyun 		fsc = nla_data(tb[TCA_HFSC_FSC]);
942*4882a593Smuzhiyun 		if (fsc->m1 == 0 && fsc->m2 == 0)
943*4882a593Smuzhiyun 			fsc = NULL;
944*4882a593Smuzhiyun 	}
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	if (tb[TCA_HFSC_USC]) {
947*4882a593Smuzhiyun 		usc = nla_data(tb[TCA_HFSC_USC]);
948*4882a593Smuzhiyun 		if (usc->m1 == 0 && usc->m2 == 0)
949*4882a593Smuzhiyun 			usc = NULL;
950*4882a593Smuzhiyun 	}
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	if (cl != NULL) {
953*4882a593Smuzhiyun 		int old_flags;
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 		if (parentid) {
956*4882a593Smuzhiyun 			if (cl->cl_parent &&
957*4882a593Smuzhiyun 			    cl->cl_parent->cl_common.classid != parentid)
958*4882a593Smuzhiyun 				return -EINVAL;
959*4882a593Smuzhiyun 			if (cl->cl_parent == NULL && parentid != TC_H_ROOT)
960*4882a593Smuzhiyun 				return -EINVAL;
961*4882a593Smuzhiyun 		}
962*4882a593Smuzhiyun 		cur_time = psched_get_time();
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 		if (tca[TCA_RATE]) {
965*4882a593Smuzhiyun 			err = gen_replace_estimator(&cl->bstats, NULL,
966*4882a593Smuzhiyun 						    &cl->rate_est,
967*4882a593Smuzhiyun 						    NULL,
968*4882a593Smuzhiyun 						    qdisc_root_sleeping_running(sch),
969*4882a593Smuzhiyun 						    tca[TCA_RATE]);
970*4882a593Smuzhiyun 			if (err)
971*4882a593Smuzhiyun 				return err;
972*4882a593Smuzhiyun 		}
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 		sch_tree_lock(sch);
975*4882a593Smuzhiyun 		old_flags = cl->cl_flags;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 		if (rsc != NULL)
978*4882a593Smuzhiyun 			hfsc_change_rsc(cl, rsc, cur_time);
979*4882a593Smuzhiyun 		if (fsc != NULL)
980*4882a593Smuzhiyun 			hfsc_change_fsc(cl, fsc);
981*4882a593Smuzhiyun 		if (usc != NULL)
982*4882a593Smuzhiyun 			hfsc_change_usc(cl, usc, cur_time);
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 		if (cl->qdisc->q.qlen != 0) {
985*4882a593Smuzhiyun 			int len = qdisc_peek_len(cl->qdisc);
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 			if (cl->cl_flags & HFSC_RSC) {
988*4882a593Smuzhiyun 				if (old_flags & HFSC_RSC)
989*4882a593Smuzhiyun 					update_ed(cl, len);
990*4882a593Smuzhiyun 				else
991*4882a593Smuzhiyun 					init_ed(cl, len);
992*4882a593Smuzhiyun 			}
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 			if (cl->cl_flags & HFSC_FSC) {
995*4882a593Smuzhiyun 				if (old_flags & HFSC_FSC)
996*4882a593Smuzhiyun 					update_vf(cl, 0, cur_time);
997*4882a593Smuzhiyun 				else
998*4882a593Smuzhiyun 					init_vf(cl, len);
999*4882a593Smuzhiyun 			}
1000*4882a593Smuzhiyun 		}
1001*4882a593Smuzhiyun 		sch_tree_unlock(sch);
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 		return 0;
1004*4882a593Smuzhiyun 	}
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	if (parentid == TC_H_ROOT)
1007*4882a593Smuzhiyun 		return -EEXIST;
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	parent = &q->root;
1010*4882a593Smuzhiyun 	if (parentid) {
1011*4882a593Smuzhiyun 		parent = hfsc_find_class(parentid, sch);
1012*4882a593Smuzhiyun 		if (parent == NULL)
1013*4882a593Smuzhiyun 			return -ENOENT;
1014*4882a593Smuzhiyun 	}
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	if (classid == 0 || TC_H_MAJ(classid ^ sch->handle) != 0)
1017*4882a593Smuzhiyun 		return -EINVAL;
1018*4882a593Smuzhiyun 	if (hfsc_find_class(classid, sch))
1019*4882a593Smuzhiyun 		return -EEXIST;
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	if (rsc == NULL && fsc == NULL)
1022*4882a593Smuzhiyun 		return -EINVAL;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	cl = kzalloc(sizeof(struct hfsc_class), GFP_KERNEL);
1025*4882a593Smuzhiyun 	if (cl == NULL)
1026*4882a593Smuzhiyun 		return -ENOBUFS;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
1029*4882a593Smuzhiyun 	if (err) {
1030*4882a593Smuzhiyun 		kfree(cl);
1031*4882a593Smuzhiyun 		return err;
1032*4882a593Smuzhiyun 	}
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	if (tca[TCA_RATE]) {
1035*4882a593Smuzhiyun 		err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
1036*4882a593Smuzhiyun 					NULL,
1037*4882a593Smuzhiyun 					qdisc_root_sleeping_running(sch),
1038*4882a593Smuzhiyun 					tca[TCA_RATE]);
1039*4882a593Smuzhiyun 		if (err) {
1040*4882a593Smuzhiyun 			tcf_block_put(cl->block);
1041*4882a593Smuzhiyun 			kfree(cl);
1042*4882a593Smuzhiyun 			return err;
1043*4882a593Smuzhiyun 		}
1044*4882a593Smuzhiyun 	}
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 	if (rsc != NULL)
1047*4882a593Smuzhiyun 		hfsc_change_rsc(cl, rsc, 0);
1048*4882a593Smuzhiyun 	if (fsc != NULL)
1049*4882a593Smuzhiyun 		hfsc_change_fsc(cl, fsc);
1050*4882a593Smuzhiyun 	if (usc != NULL)
1051*4882a593Smuzhiyun 		hfsc_change_usc(cl, usc, 0);
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 	cl->cl_common.classid = classid;
1054*4882a593Smuzhiyun 	cl->sched     = q;
1055*4882a593Smuzhiyun 	cl->cl_parent = parent;
1056*4882a593Smuzhiyun 	cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
1057*4882a593Smuzhiyun 				      classid, NULL);
1058*4882a593Smuzhiyun 	if (cl->qdisc == NULL)
1059*4882a593Smuzhiyun 		cl->qdisc = &noop_qdisc;
1060*4882a593Smuzhiyun 	else
1061*4882a593Smuzhiyun 		qdisc_hash_add(cl->qdisc, true);
1062*4882a593Smuzhiyun 	INIT_LIST_HEAD(&cl->children);
1063*4882a593Smuzhiyun 	cl->vt_tree = RB_ROOT;
1064*4882a593Smuzhiyun 	cl->cf_tree = RB_ROOT;
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 	sch_tree_lock(sch);
1067*4882a593Smuzhiyun 	qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
1068*4882a593Smuzhiyun 	list_add_tail(&cl->siblings, &parent->children);
1069*4882a593Smuzhiyun 	if (parent->level == 0)
1070*4882a593Smuzhiyun 		qdisc_purge_queue(parent->qdisc);
1071*4882a593Smuzhiyun 	hfsc_adjust_levels(parent);
1072*4882a593Smuzhiyun 	sch_tree_unlock(sch);
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	qdisc_class_hash_grow(sch, &q->clhash);
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	*arg = (unsigned long)cl;
1077*4882a593Smuzhiyun 	return 0;
1078*4882a593Smuzhiyun }
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun static void
hfsc_destroy_class(struct Qdisc * sch,struct hfsc_class * cl)1081*4882a593Smuzhiyun hfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl)
1082*4882a593Smuzhiyun {
1083*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	tcf_block_put(cl->block);
1086*4882a593Smuzhiyun 	qdisc_put(cl->qdisc);
1087*4882a593Smuzhiyun 	gen_kill_estimator(&cl->rate_est);
1088*4882a593Smuzhiyun 	if (cl != &q->root)
1089*4882a593Smuzhiyun 		kfree(cl);
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun static int
hfsc_delete_class(struct Qdisc * sch,unsigned long arg)1093*4882a593Smuzhiyun hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
1094*4882a593Smuzhiyun {
1095*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1096*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	if (cl->level > 0 || cl->filter_cnt > 0 || cl == &q->root)
1099*4882a593Smuzhiyun 		return -EBUSY;
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	sch_tree_lock(sch);
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 	list_del(&cl->siblings);
1104*4882a593Smuzhiyun 	hfsc_adjust_levels(cl->cl_parent);
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 	qdisc_purge_queue(cl->qdisc);
1107*4882a593Smuzhiyun 	qdisc_class_hash_remove(&q->clhash, &cl->cl_common);
1108*4882a593Smuzhiyun 
1109*4882a593Smuzhiyun 	sch_tree_unlock(sch);
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	hfsc_destroy_class(sch, cl);
1112*4882a593Smuzhiyun 	return 0;
1113*4882a593Smuzhiyun }
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun static struct hfsc_class *
hfsc_classify(struct sk_buff * skb,struct Qdisc * sch,int * qerr)1116*4882a593Smuzhiyun hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1119*4882a593Smuzhiyun 	struct hfsc_class *head, *cl;
1120*4882a593Smuzhiyun 	struct tcf_result res;
1121*4882a593Smuzhiyun 	struct tcf_proto *tcf;
1122*4882a593Smuzhiyun 	int result;
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	if (TC_H_MAJ(skb->priority ^ sch->handle) == 0 &&
1125*4882a593Smuzhiyun 	    (cl = hfsc_find_class(skb->priority, sch)) != NULL)
1126*4882a593Smuzhiyun 		if (cl->level == 0)
1127*4882a593Smuzhiyun 			return cl;
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
1130*4882a593Smuzhiyun 	head = &q->root;
1131*4882a593Smuzhiyun 	tcf = rcu_dereference_bh(q->root.filter_list);
1132*4882a593Smuzhiyun 	while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
1133*4882a593Smuzhiyun #ifdef CONFIG_NET_CLS_ACT
1134*4882a593Smuzhiyun 		switch (result) {
1135*4882a593Smuzhiyun 		case TC_ACT_QUEUED:
1136*4882a593Smuzhiyun 		case TC_ACT_STOLEN:
1137*4882a593Smuzhiyun 		case TC_ACT_TRAP:
1138*4882a593Smuzhiyun 			*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
1139*4882a593Smuzhiyun 			fallthrough;
1140*4882a593Smuzhiyun 		case TC_ACT_SHOT:
1141*4882a593Smuzhiyun 			return NULL;
1142*4882a593Smuzhiyun 		}
1143*4882a593Smuzhiyun #endif
1144*4882a593Smuzhiyun 		cl = (struct hfsc_class *)res.class;
1145*4882a593Smuzhiyun 		if (!cl) {
1146*4882a593Smuzhiyun 			cl = hfsc_find_class(res.classid, sch);
1147*4882a593Smuzhiyun 			if (!cl)
1148*4882a593Smuzhiyun 				break; /* filter selected invalid classid */
1149*4882a593Smuzhiyun 			if (cl->level >= head->level)
1150*4882a593Smuzhiyun 				break; /* filter may only point downwards */
1151*4882a593Smuzhiyun 		}
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 		if (cl->level == 0)
1154*4882a593Smuzhiyun 			return cl; /* hit leaf class */
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 		/* apply inner filter chain */
1157*4882a593Smuzhiyun 		tcf = rcu_dereference_bh(cl->filter_list);
1158*4882a593Smuzhiyun 		head = cl;
1159*4882a593Smuzhiyun 	}
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	/* classification failed, try default class */
1162*4882a593Smuzhiyun 	cl = hfsc_find_class(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch);
1163*4882a593Smuzhiyun 	if (cl == NULL || cl->level > 0)
1164*4882a593Smuzhiyun 		return NULL;
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	return cl;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun static int
hfsc_graft_class(struct Qdisc * sch,unsigned long arg,struct Qdisc * new,struct Qdisc ** old,struct netlink_ext_ack * extack)1170*4882a593Smuzhiyun hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
1171*4882a593Smuzhiyun 		 struct Qdisc **old, struct netlink_ext_ack *extack)
1172*4882a593Smuzhiyun {
1173*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	if (cl->level > 0)
1176*4882a593Smuzhiyun 		return -EINVAL;
1177*4882a593Smuzhiyun 	if (new == NULL) {
1178*4882a593Smuzhiyun 		new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
1179*4882a593Smuzhiyun 					cl->cl_common.classid, NULL);
1180*4882a593Smuzhiyun 		if (new == NULL)
1181*4882a593Smuzhiyun 			new = &noop_qdisc;
1182*4882a593Smuzhiyun 	}
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	*old = qdisc_replace(sch, new, &cl->qdisc);
1185*4882a593Smuzhiyun 	return 0;
1186*4882a593Smuzhiyun }
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun static struct Qdisc *
hfsc_class_leaf(struct Qdisc * sch,unsigned long arg)1189*4882a593Smuzhiyun hfsc_class_leaf(struct Qdisc *sch, unsigned long arg)
1190*4882a593Smuzhiyun {
1191*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	if (cl->level == 0)
1194*4882a593Smuzhiyun 		return cl->qdisc;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	return NULL;
1197*4882a593Smuzhiyun }
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun static void
hfsc_qlen_notify(struct Qdisc * sch,unsigned long arg)1200*4882a593Smuzhiyun hfsc_qlen_notify(struct Qdisc *sch, unsigned long arg)
1201*4882a593Smuzhiyun {
1202*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	/* vttree is now handled in update_vf() so that update_vf(cl, 0, 0)
1205*4882a593Smuzhiyun 	 * needs to be called explicitly to remove a class from vttree.
1206*4882a593Smuzhiyun 	 */
1207*4882a593Smuzhiyun 	update_vf(cl, 0, 0);
1208*4882a593Smuzhiyun 	if (cl->cl_flags & HFSC_RSC)
1209*4882a593Smuzhiyun 		eltree_remove(cl);
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun static unsigned long
hfsc_search_class(struct Qdisc * sch,u32 classid)1213*4882a593Smuzhiyun hfsc_search_class(struct Qdisc *sch, u32 classid)
1214*4882a593Smuzhiyun {
1215*4882a593Smuzhiyun 	return (unsigned long)hfsc_find_class(classid, sch);
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun static unsigned long
hfsc_bind_tcf(struct Qdisc * sch,unsigned long parent,u32 classid)1219*4882a593Smuzhiyun hfsc_bind_tcf(struct Qdisc *sch, unsigned long parent, u32 classid)
1220*4882a593Smuzhiyun {
1221*4882a593Smuzhiyun 	struct hfsc_class *p = (struct hfsc_class *)parent;
1222*4882a593Smuzhiyun 	struct hfsc_class *cl = hfsc_find_class(classid, sch);
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	if (cl != NULL) {
1225*4882a593Smuzhiyun 		if (p != NULL && p->level <= cl->level)
1226*4882a593Smuzhiyun 			return 0;
1227*4882a593Smuzhiyun 		cl->filter_cnt++;
1228*4882a593Smuzhiyun 	}
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	return (unsigned long)cl;
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun static void
hfsc_unbind_tcf(struct Qdisc * sch,unsigned long arg)1234*4882a593Smuzhiyun hfsc_unbind_tcf(struct Qdisc *sch, unsigned long arg)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	cl->filter_cnt--;
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun 
hfsc_tcf_block(struct Qdisc * sch,unsigned long arg,struct netlink_ext_ack * extack)1241*4882a593Smuzhiyun static struct tcf_block *hfsc_tcf_block(struct Qdisc *sch, unsigned long arg,
1242*4882a593Smuzhiyun 					struct netlink_ext_ack *extack)
1243*4882a593Smuzhiyun {
1244*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1245*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	if (cl == NULL)
1248*4882a593Smuzhiyun 		cl = &q->root;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 	return cl->block;
1251*4882a593Smuzhiyun }
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun static int
hfsc_dump_sc(struct sk_buff * skb,int attr,struct internal_sc * sc)1254*4882a593Smuzhiyun hfsc_dump_sc(struct sk_buff *skb, int attr, struct internal_sc *sc)
1255*4882a593Smuzhiyun {
1256*4882a593Smuzhiyun 	struct tc_service_curve tsc;
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	tsc.m1 = sm2m(sc->sm1);
1259*4882a593Smuzhiyun 	tsc.d  = dx2d(sc->dx);
1260*4882a593Smuzhiyun 	tsc.m2 = sm2m(sc->sm2);
1261*4882a593Smuzhiyun 	if (nla_put(skb, attr, sizeof(tsc), &tsc))
1262*4882a593Smuzhiyun 		goto nla_put_failure;
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 	return skb->len;
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun  nla_put_failure:
1267*4882a593Smuzhiyun 	return -1;
1268*4882a593Smuzhiyun }
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun static int
hfsc_dump_curves(struct sk_buff * skb,struct hfsc_class * cl)1271*4882a593Smuzhiyun hfsc_dump_curves(struct sk_buff *skb, struct hfsc_class *cl)
1272*4882a593Smuzhiyun {
1273*4882a593Smuzhiyun 	if ((cl->cl_flags & HFSC_RSC) &&
1274*4882a593Smuzhiyun 	    (hfsc_dump_sc(skb, TCA_HFSC_RSC, &cl->cl_rsc) < 0))
1275*4882a593Smuzhiyun 		goto nla_put_failure;
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	if ((cl->cl_flags & HFSC_FSC) &&
1278*4882a593Smuzhiyun 	    (hfsc_dump_sc(skb, TCA_HFSC_FSC, &cl->cl_fsc) < 0))
1279*4882a593Smuzhiyun 		goto nla_put_failure;
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	if ((cl->cl_flags & HFSC_USC) &&
1282*4882a593Smuzhiyun 	    (hfsc_dump_sc(skb, TCA_HFSC_USC, &cl->cl_usc) < 0))
1283*4882a593Smuzhiyun 		goto nla_put_failure;
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	return skb->len;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun  nla_put_failure:
1288*4882a593Smuzhiyun 	return -1;
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun static int
hfsc_dump_class(struct Qdisc * sch,unsigned long arg,struct sk_buff * skb,struct tcmsg * tcm)1292*4882a593Smuzhiyun hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb,
1293*4882a593Smuzhiyun 		struct tcmsg *tcm)
1294*4882a593Smuzhiyun {
1295*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1296*4882a593Smuzhiyun 	struct nlattr *nest;
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->cl_common.classid :
1299*4882a593Smuzhiyun 					  TC_H_ROOT;
1300*4882a593Smuzhiyun 	tcm->tcm_handle = cl->cl_common.classid;
1301*4882a593Smuzhiyun 	if (cl->level == 0)
1302*4882a593Smuzhiyun 		tcm->tcm_info = cl->qdisc->handle;
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
1305*4882a593Smuzhiyun 	if (nest == NULL)
1306*4882a593Smuzhiyun 		goto nla_put_failure;
1307*4882a593Smuzhiyun 	if (hfsc_dump_curves(skb, cl) < 0)
1308*4882a593Smuzhiyun 		goto nla_put_failure;
1309*4882a593Smuzhiyun 	return nla_nest_end(skb, nest);
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun  nla_put_failure:
1312*4882a593Smuzhiyun 	nla_nest_cancel(skb, nest);
1313*4882a593Smuzhiyun 	return -EMSGSIZE;
1314*4882a593Smuzhiyun }
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun static int
hfsc_dump_class_stats(struct Qdisc * sch,unsigned long arg,struct gnet_dump * d)1317*4882a593Smuzhiyun hfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
1318*4882a593Smuzhiyun 	struct gnet_dump *d)
1319*4882a593Smuzhiyun {
1320*4882a593Smuzhiyun 	struct hfsc_class *cl = (struct hfsc_class *)arg;
1321*4882a593Smuzhiyun 	struct tc_hfsc_stats xstats;
1322*4882a593Smuzhiyun 	__u32 qlen;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	qdisc_qstats_qlen_backlog(cl->qdisc, &qlen, &cl->qstats.backlog);
1325*4882a593Smuzhiyun 	xstats.level   = cl->level;
1326*4882a593Smuzhiyun 	xstats.period  = cl->cl_vtperiod;
1327*4882a593Smuzhiyun 	xstats.work    = cl->cl_total;
1328*4882a593Smuzhiyun 	xstats.rtwork  = cl->cl_cumul;
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d, NULL, &cl->bstats) < 0 ||
1331*4882a593Smuzhiyun 	    gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
1332*4882a593Smuzhiyun 	    gnet_stats_copy_queue(d, NULL, &cl->qstats, qlen) < 0)
1333*4882a593Smuzhiyun 		return -1;
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun static void
hfsc_walk(struct Qdisc * sch,struct qdisc_walker * arg)1341*4882a593Smuzhiyun hfsc_walk(struct Qdisc *sch, struct qdisc_walker *arg)
1342*4882a593Smuzhiyun {
1343*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1344*4882a593Smuzhiyun 	struct hfsc_class *cl;
1345*4882a593Smuzhiyun 	unsigned int i;
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	if (arg->stop)
1348*4882a593Smuzhiyun 		return;
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 	for (i = 0; i < q->clhash.hashsize; i++) {
1351*4882a593Smuzhiyun 		hlist_for_each_entry(cl, &q->clhash.hash[i],
1352*4882a593Smuzhiyun 				     cl_common.hnode) {
1353*4882a593Smuzhiyun 			if (arg->count < arg->skip) {
1354*4882a593Smuzhiyun 				arg->count++;
1355*4882a593Smuzhiyun 				continue;
1356*4882a593Smuzhiyun 			}
1357*4882a593Smuzhiyun 			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
1358*4882a593Smuzhiyun 				arg->stop = 1;
1359*4882a593Smuzhiyun 				return;
1360*4882a593Smuzhiyun 			}
1361*4882a593Smuzhiyun 			arg->count++;
1362*4882a593Smuzhiyun 		}
1363*4882a593Smuzhiyun 	}
1364*4882a593Smuzhiyun }
1365*4882a593Smuzhiyun 
1366*4882a593Smuzhiyun static void
hfsc_schedule_watchdog(struct Qdisc * sch)1367*4882a593Smuzhiyun hfsc_schedule_watchdog(struct Qdisc *sch)
1368*4882a593Smuzhiyun {
1369*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1370*4882a593Smuzhiyun 	struct hfsc_class *cl;
1371*4882a593Smuzhiyun 	u64 next_time = 0;
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	cl = eltree_get_minel(q);
1374*4882a593Smuzhiyun 	if (cl)
1375*4882a593Smuzhiyun 		next_time = cl->cl_e;
1376*4882a593Smuzhiyun 	if (q->root.cl_cfmin != 0) {
1377*4882a593Smuzhiyun 		if (next_time == 0 || next_time > q->root.cl_cfmin)
1378*4882a593Smuzhiyun 			next_time = q->root.cl_cfmin;
1379*4882a593Smuzhiyun 	}
1380*4882a593Smuzhiyun 	if (next_time)
1381*4882a593Smuzhiyun 		qdisc_watchdog_schedule(&q->watchdog, next_time);
1382*4882a593Smuzhiyun }
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun static int
hfsc_init_qdisc(struct Qdisc * sch,struct nlattr * opt,struct netlink_ext_ack * extack)1385*4882a593Smuzhiyun hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt,
1386*4882a593Smuzhiyun 		struct netlink_ext_ack *extack)
1387*4882a593Smuzhiyun {
1388*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1389*4882a593Smuzhiyun 	struct tc_hfsc_qopt *qopt;
1390*4882a593Smuzhiyun 	int err;
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	qdisc_watchdog_init(&q->watchdog, sch);
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun 	if (!opt || nla_len(opt) < sizeof(*qopt))
1395*4882a593Smuzhiyun 		return -EINVAL;
1396*4882a593Smuzhiyun 	qopt = nla_data(opt);
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	q->defcls = qopt->defcls;
1399*4882a593Smuzhiyun 	err = qdisc_class_hash_init(&q->clhash);
1400*4882a593Smuzhiyun 	if (err < 0)
1401*4882a593Smuzhiyun 		return err;
1402*4882a593Smuzhiyun 	q->eligible = RB_ROOT;
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	err = tcf_block_get(&q->root.block, &q->root.filter_list, sch, extack);
1405*4882a593Smuzhiyun 	if (err)
1406*4882a593Smuzhiyun 		return err;
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 	q->root.cl_common.classid = sch->handle;
1409*4882a593Smuzhiyun 	q->root.sched   = q;
1410*4882a593Smuzhiyun 	q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
1411*4882a593Smuzhiyun 					  sch->handle, NULL);
1412*4882a593Smuzhiyun 	if (q->root.qdisc == NULL)
1413*4882a593Smuzhiyun 		q->root.qdisc = &noop_qdisc;
1414*4882a593Smuzhiyun 	else
1415*4882a593Smuzhiyun 		qdisc_hash_add(q->root.qdisc, true);
1416*4882a593Smuzhiyun 	INIT_LIST_HEAD(&q->root.children);
1417*4882a593Smuzhiyun 	q->root.vt_tree = RB_ROOT;
1418*4882a593Smuzhiyun 	q->root.cf_tree = RB_ROOT;
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun 	qdisc_class_hash_insert(&q->clhash, &q->root.cl_common);
1421*4882a593Smuzhiyun 	qdisc_class_hash_grow(sch, &q->clhash);
1422*4882a593Smuzhiyun 
1423*4882a593Smuzhiyun 	return 0;
1424*4882a593Smuzhiyun }
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun static int
hfsc_change_qdisc(struct Qdisc * sch,struct nlattr * opt,struct netlink_ext_ack * extack)1427*4882a593Smuzhiyun hfsc_change_qdisc(struct Qdisc *sch, struct nlattr *opt,
1428*4882a593Smuzhiyun 		  struct netlink_ext_ack *extack)
1429*4882a593Smuzhiyun {
1430*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1431*4882a593Smuzhiyun 	struct tc_hfsc_qopt *qopt;
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 	if (opt == NULL || nla_len(opt) < sizeof(*qopt))
1434*4882a593Smuzhiyun 		return -EINVAL;
1435*4882a593Smuzhiyun 	qopt = nla_data(opt);
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	sch_tree_lock(sch);
1438*4882a593Smuzhiyun 	q->defcls = qopt->defcls;
1439*4882a593Smuzhiyun 	sch_tree_unlock(sch);
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 	return 0;
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun static void
hfsc_reset_class(struct hfsc_class * cl)1445*4882a593Smuzhiyun hfsc_reset_class(struct hfsc_class *cl)
1446*4882a593Smuzhiyun {
1447*4882a593Smuzhiyun 	cl->cl_total        = 0;
1448*4882a593Smuzhiyun 	cl->cl_cumul        = 0;
1449*4882a593Smuzhiyun 	cl->cl_d            = 0;
1450*4882a593Smuzhiyun 	cl->cl_e            = 0;
1451*4882a593Smuzhiyun 	cl->cl_vt           = 0;
1452*4882a593Smuzhiyun 	cl->cl_vtadj        = 0;
1453*4882a593Smuzhiyun 	cl->cl_cvtmin       = 0;
1454*4882a593Smuzhiyun 	cl->cl_cvtoff       = 0;
1455*4882a593Smuzhiyun 	cl->cl_vtperiod     = 0;
1456*4882a593Smuzhiyun 	cl->cl_parentperiod = 0;
1457*4882a593Smuzhiyun 	cl->cl_f            = 0;
1458*4882a593Smuzhiyun 	cl->cl_myf          = 0;
1459*4882a593Smuzhiyun 	cl->cl_cfmin        = 0;
1460*4882a593Smuzhiyun 	cl->cl_nactive      = 0;
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun 	cl->vt_tree = RB_ROOT;
1463*4882a593Smuzhiyun 	cl->cf_tree = RB_ROOT;
1464*4882a593Smuzhiyun 	qdisc_reset(cl->qdisc);
1465*4882a593Smuzhiyun 
1466*4882a593Smuzhiyun 	if (cl->cl_flags & HFSC_RSC)
1467*4882a593Smuzhiyun 		rtsc_init(&cl->cl_deadline, &cl->cl_rsc, 0, 0);
1468*4882a593Smuzhiyun 	if (cl->cl_flags & HFSC_FSC)
1469*4882a593Smuzhiyun 		rtsc_init(&cl->cl_virtual, &cl->cl_fsc, 0, 0);
1470*4882a593Smuzhiyun 	if (cl->cl_flags & HFSC_USC)
1471*4882a593Smuzhiyun 		rtsc_init(&cl->cl_ulimit, &cl->cl_usc, 0, 0);
1472*4882a593Smuzhiyun }
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun static void
hfsc_reset_qdisc(struct Qdisc * sch)1475*4882a593Smuzhiyun hfsc_reset_qdisc(struct Qdisc *sch)
1476*4882a593Smuzhiyun {
1477*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1478*4882a593Smuzhiyun 	struct hfsc_class *cl;
1479*4882a593Smuzhiyun 	unsigned int i;
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	for (i = 0; i < q->clhash.hashsize; i++) {
1482*4882a593Smuzhiyun 		hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode)
1483*4882a593Smuzhiyun 			hfsc_reset_class(cl);
1484*4882a593Smuzhiyun 	}
1485*4882a593Smuzhiyun 	q->eligible = RB_ROOT;
1486*4882a593Smuzhiyun 	qdisc_watchdog_cancel(&q->watchdog);
1487*4882a593Smuzhiyun }
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun static void
hfsc_destroy_qdisc(struct Qdisc * sch)1490*4882a593Smuzhiyun hfsc_destroy_qdisc(struct Qdisc *sch)
1491*4882a593Smuzhiyun {
1492*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1493*4882a593Smuzhiyun 	struct hlist_node *next;
1494*4882a593Smuzhiyun 	struct hfsc_class *cl;
1495*4882a593Smuzhiyun 	unsigned int i;
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	for (i = 0; i < q->clhash.hashsize; i++) {
1498*4882a593Smuzhiyun 		hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode) {
1499*4882a593Smuzhiyun 			tcf_block_put(cl->block);
1500*4882a593Smuzhiyun 			cl->block = NULL;
1501*4882a593Smuzhiyun 		}
1502*4882a593Smuzhiyun 	}
1503*4882a593Smuzhiyun 	for (i = 0; i < q->clhash.hashsize; i++) {
1504*4882a593Smuzhiyun 		hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
1505*4882a593Smuzhiyun 					  cl_common.hnode)
1506*4882a593Smuzhiyun 			hfsc_destroy_class(sch, cl);
1507*4882a593Smuzhiyun 	}
1508*4882a593Smuzhiyun 	qdisc_class_hash_destroy(&q->clhash);
1509*4882a593Smuzhiyun 	qdisc_watchdog_cancel(&q->watchdog);
1510*4882a593Smuzhiyun }
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun static int
hfsc_dump_qdisc(struct Qdisc * sch,struct sk_buff * skb)1513*4882a593Smuzhiyun hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
1514*4882a593Smuzhiyun {
1515*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1516*4882a593Smuzhiyun 	unsigned char *b = skb_tail_pointer(skb);
1517*4882a593Smuzhiyun 	struct tc_hfsc_qopt qopt;
1518*4882a593Smuzhiyun 
1519*4882a593Smuzhiyun 	qopt.defcls = q->defcls;
1520*4882a593Smuzhiyun 	if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt))
1521*4882a593Smuzhiyun 		goto nla_put_failure;
1522*4882a593Smuzhiyun 	return skb->len;
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun  nla_put_failure:
1525*4882a593Smuzhiyun 	nlmsg_trim(skb, b);
1526*4882a593Smuzhiyun 	return -1;
1527*4882a593Smuzhiyun }
1528*4882a593Smuzhiyun 
1529*4882a593Smuzhiyun static int
hfsc_enqueue(struct sk_buff * skb,struct Qdisc * sch,struct sk_buff ** to_free)1530*4882a593Smuzhiyun hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
1531*4882a593Smuzhiyun {
1532*4882a593Smuzhiyun 	unsigned int len = qdisc_pkt_len(skb);
1533*4882a593Smuzhiyun 	struct hfsc_class *cl;
1534*4882a593Smuzhiyun 	int err;
1535*4882a593Smuzhiyun 	bool first;
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun 	cl = hfsc_classify(skb, sch, &err);
1538*4882a593Smuzhiyun 	if (cl == NULL) {
1539*4882a593Smuzhiyun 		if (err & __NET_XMIT_BYPASS)
1540*4882a593Smuzhiyun 			qdisc_qstats_drop(sch);
1541*4882a593Smuzhiyun 		__qdisc_drop(skb, to_free);
1542*4882a593Smuzhiyun 		return err;
1543*4882a593Smuzhiyun 	}
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 	first = !cl->qdisc->q.qlen;
1546*4882a593Smuzhiyun 	err = qdisc_enqueue(skb, cl->qdisc, to_free);
1547*4882a593Smuzhiyun 	if (unlikely(err != NET_XMIT_SUCCESS)) {
1548*4882a593Smuzhiyun 		if (net_xmit_drop_count(err)) {
1549*4882a593Smuzhiyun 			cl->qstats.drops++;
1550*4882a593Smuzhiyun 			qdisc_qstats_drop(sch);
1551*4882a593Smuzhiyun 		}
1552*4882a593Smuzhiyun 		return err;
1553*4882a593Smuzhiyun 	}
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 	if (first) {
1556*4882a593Smuzhiyun 		if (cl->cl_flags & HFSC_RSC)
1557*4882a593Smuzhiyun 			init_ed(cl, len);
1558*4882a593Smuzhiyun 		if (cl->cl_flags & HFSC_FSC)
1559*4882a593Smuzhiyun 			init_vf(cl, len);
1560*4882a593Smuzhiyun 		/*
1561*4882a593Smuzhiyun 		 * If this is the first packet, isolate the head so an eventual
1562*4882a593Smuzhiyun 		 * head drop before the first dequeue operation has no chance
1563*4882a593Smuzhiyun 		 * to invalidate the deadline.
1564*4882a593Smuzhiyun 		 */
1565*4882a593Smuzhiyun 		if (cl->cl_flags & HFSC_RSC)
1566*4882a593Smuzhiyun 			cl->qdisc->ops->peek(cl->qdisc);
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 	}
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun 	sch->qstats.backlog += len;
1571*4882a593Smuzhiyun 	sch->q.qlen++;
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun 	return NET_XMIT_SUCCESS;
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun 
1576*4882a593Smuzhiyun static struct sk_buff *
hfsc_dequeue(struct Qdisc * sch)1577*4882a593Smuzhiyun hfsc_dequeue(struct Qdisc *sch)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun 	struct hfsc_sched *q = qdisc_priv(sch);
1580*4882a593Smuzhiyun 	struct hfsc_class *cl;
1581*4882a593Smuzhiyun 	struct sk_buff *skb;
1582*4882a593Smuzhiyun 	u64 cur_time;
1583*4882a593Smuzhiyun 	unsigned int next_len;
1584*4882a593Smuzhiyun 	int realtime = 0;
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	if (sch->q.qlen == 0)
1587*4882a593Smuzhiyun 		return NULL;
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 	cur_time = psched_get_time();
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun 	/*
1592*4882a593Smuzhiyun 	 * if there are eligible classes, use real-time criteria.
1593*4882a593Smuzhiyun 	 * find the class with the minimum deadline among
1594*4882a593Smuzhiyun 	 * the eligible classes.
1595*4882a593Smuzhiyun 	 */
1596*4882a593Smuzhiyun 	cl = eltree_get_mindl(q, cur_time);
1597*4882a593Smuzhiyun 	if (cl) {
1598*4882a593Smuzhiyun 		realtime = 1;
1599*4882a593Smuzhiyun 	} else {
1600*4882a593Smuzhiyun 		/*
1601*4882a593Smuzhiyun 		 * use link-sharing criteria
1602*4882a593Smuzhiyun 		 * get the class with the minimum vt in the hierarchy
1603*4882a593Smuzhiyun 		 */
1604*4882a593Smuzhiyun 		cl = vttree_get_minvt(&q->root, cur_time);
1605*4882a593Smuzhiyun 		if (cl == NULL) {
1606*4882a593Smuzhiyun 			qdisc_qstats_overlimit(sch);
1607*4882a593Smuzhiyun 			hfsc_schedule_watchdog(sch);
1608*4882a593Smuzhiyun 			return NULL;
1609*4882a593Smuzhiyun 		}
1610*4882a593Smuzhiyun 	}
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 	skb = qdisc_dequeue_peeked(cl->qdisc);
1613*4882a593Smuzhiyun 	if (skb == NULL) {
1614*4882a593Smuzhiyun 		qdisc_warn_nonwc("HFSC", cl->qdisc);
1615*4882a593Smuzhiyun 		return NULL;
1616*4882a593Smuzhiyun 	}
1617*4882a593Smuzhiyun 
1618*4882a593Smuzhiyun 	bstats_update(&cl->bstats, skb);
1619*4882a593Smuzhiyun 	update_vf(cl, qdisc_pkt_len(skb), cur_time);
1620*4882a593Smuzhiyun 	if (realtime)
1621*4882a593Smuzhiyun 		cl->cl_cumul += qdisc_pkt_len(skb);
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	if (cl->cl_flags & HFSC_RSC) {
1624*4882a593Smuzhiyun 		if (cl->qdisc->q.qlen != 0) {
1625*4882a593Smuzhiyun 			/* update ed */
1626*4882a593Smuzhiyun 			next_len = qdisc_peek_len(cl->qdisc);
1627*4882a593Smuzhiyun 			if (realtime)
1628*4882a593Smuzhiyun 				update_ed(cl, next_len);
1629*4882a593Smuzhiyun 			else
1630*4882a593Smuzhiyun 				update_d(cl, next_len);
1631*4882a593Smuzhiyun 		} else {
1632*4882a593Smuzhiyun 			/* the class becomes passive */
1633*4882a593Smuzhiyun 			eltree_remove(cl);
1634*4882a593Smuzhiyun 		}
1635*4882a593Smuzhiyun 	}
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun 	qdisc_bstats_update(sch, skb);
1638*4882a593Smuzhiyun 	qdisc_qstats_backlog_dec(sch, skb);
1639*4882a593Smuzhiyun 	sch->q.qlen--;
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 	return skb;
1642*4882a593Smuzhiyun }
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun static const struct Qdisc_class_ops hfsc_class_ops = {
1645*4882a593Smuzhiyun 	.change		= hfsc_change_class,
1646*4882a593Smuzhiyun 	.delete		= hfsc_delete_class,
1647*4882a593Smuzhiyun 	.graft		= hfsc_graft_class,
1648*4882a593Smuzhiyun 	.leaf		= hfsc_class_leaf,
1649*4882a593Smuzhiyun 	.qlen_notify	= hfsc_qlen_notify,
1650*4882a593Smuzhiyun 	.find		= hfsc_search_class,
1651*4882a593Smuzhiyun 	.bind_tcf	= hfsc_bind_tcf,
1652*4882a593Smuzhiyun 	.unbind_tcf	= hfsc_unbind_tcf,
1653*4882a593Smuzhiyun 	.tcf_block	= hfsc_tcf_block,
1654*4882a593Smuzhiyun 	.dump		= hfsc_dump_class,
1655*4882a593Smuzhiyun 	.dump_stats	= hfsc_dump_class_stats,
1656*4882a593Smuzhiyun 	.walk		= hfsc_walk
1657*4882a593Smuzhiyun };
1658*4882a593Smuzhiyun 
1659*4882a593Smuzhiyun static struct Qdisc_ops hfsc_qdisc_ops __read_mostly = {
1660*4882a593Smuzhiyun 	.id		= "hfsc",
1661*4882a593Smuzhiyun 	.init		= hfsc_init_qdisc,
1662*4882a593Smuzhiyun 	.change		= hfsc_change_qdisc,
1663*4882a593Smuzhiyun 	.reset		= hfsc_reset_qdisc,
1664*4882a593Smuzhiyun 	.destroy	= hfsc_destroy_qdisc,
1665*4882a593Smuzhiyun 	.dump		= hfsc_dump_qdisc,
1666*4882a593Smuzhiyun 	.enqueue	= hfsc_enqueue,
1667*4882a593Smuzhiyun 	.dequeue	= hfsc_dequeue,
1668*4882a593Smuzhiyun 	.peek		= qdisc_peek_dequeued,
1669*4882a593Smuzhiyun 	.cl_ops		= &hfsc_class_ops,
1670*4882a593Smuzhiyun 	.priv_size	= sizeof(struct hfsc_sched),
1671*4882a593Smuzhiyun 	.owner		= THIS_MODULE
1672*4882a593Smuzhiyun };
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun static int __init
hfsc_init(void)1675*4882a593Smuzhiyun hfsc_init(void)
1676*4882a593Smuzhiyun {
1677*4882a593Smuzhiyun 	return register_qdisc(&hfsc_qdisc_ops);
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun static void __exit
hfsc_cleanup(void)1681*4882a593Smuzhiyun hfsc_cleanup(void)
1682*4882a593Smuzhiyun {
1683*4882a593Smuzhiyun 	unregister_qdisc(&hfsc_qdisc_ops);
1684*4882a593Smuzhiyun }
1685*4882a593Smuzhiyun 
1686*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1687*4882a593Smuzhiyun module_init(hfsc_init);
1688*4882a593Smuzhiyun module_exit(hfsc_cleanup);
1689