18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * net/sched/sch_cbq.c	Class-Based Queueing discipline.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/string.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
158c2ecf20Sopenharmony_ci#include <net/netlink.h>
168c2ecf20Sopenharmony_ci#include <net/pkt_sched.h>
178c2ecf20Sopenharmony_ci#include <net/pkt_cls.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*	Class-Based Queueing (CBQ) algorithm.
218c2ecf20Sopenharmony_ci	=======================================
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	Sources: [1] Sally Floyd and Van Jacobson, "Link-sharing and Resource
248c2ecf20Sopenharmony_ci		 Management Models for Packet Networks",
258c2ecf20Sopenharmony_ci		 IEEE/ACM Transactions on Networking, Vol.3, No.4, 1995
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci		 [2] Sally Floyd, "Notes on CBQ and Guaranteed Service", 1995
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci		 [3] Sally Floyd, "Notes on Class-Based Queueing: Setting
308c2ecf20Sopenharmony_ci		 Parameters", 1996
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci		 [4] Sally Floyd and Michael Speer, "Experimental Results
338c2ecf20Sopenharmony_ci		 for Class-Based Queueing", 1998, not published.
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	-----------------------------------------------------------------------
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	Algorithm skeleton was taken from NS simulator cbq.cc.
388c2ecf20Sopenharmony_ci	If someone wants to check this code against the LBL version,
398c2ecf20Sopenharmony_ci	he should take into account that ONLY the skeleton was borrowed,
408c2ecf20Sopenharmony_ci	the implementation is different. Particularly:
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	--- The WRR algorithm is different. Our version looks more
438c2ecf20Sopenharmony_ci	reasonable (I hope) and works when quanta are allowed to be
448c2ecf20Sopenharmony_ci	less than MTU, which is always the case when real time classes
458c2ecf20Sopenharmony_ci	have small rates. Note, that the statement of [3] is
468c2ecf20Sopenharmony_ci	incomplete, delay may actually be estimated even if class
478c2ecf20Sopenharmony_ci	per-round allotment is less than MTU. Namely, if per-round
488c2ecf20Sopenharmony_ci	allotment is W*r_i, and r_1+...+r_k = r < 1
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	delay_i <= ([MTU/(W*r_i)]*W*r + W*r + k*MTU)/B
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	In the worst case we have IntServ estimate with D = W*r+k*MTU
538c2ecf20Sopenharmony_ci	and C = MTU*r. The proof (if correct at all) is trivial.
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	--- It seems that cbq-2.0 is not very accurate. At least, I cannot
578c2ecf20Sopenharmony_ci	interpret some places, which look like wrong translations
588c2ecf20Sopenharmony_ci	from NS. Anyone is advised to find these differences
598c2ecf20Sopenharmony_ci	and explain to me, why I am wrong 8).
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	--- Linux has no EOI event, so that we cannot estimate true class
628c2ecf20Sopenharmony_ci	idle time. Workaround is to consider the next dequeue event
638c2ecf20Sopenharmony_ci	as sign that previous packet is finished. This is wrong because of
648c2ecf20Sopenharmony_ci	internal device queueing, but on a permanently loaded link it is true.
658c2ecf20Sopenharmony_ci	Moreover, combined with clock integrator, this scheme looks
668c2ecf20Sopenharmony_ci	very close to an ideal solution.  */
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistruct cbq_sched_data;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistruct cbq_class {
728c2ecf20Sopenharmony_ci	struct Qdisc_class_common common;
738c2ecf20Sopenharmony_ci	struct cbq_class	*next_alive;	/* next class with backlog in this priority band */
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* Parameters */
768c2ecf20Sopenharmony_ci	unsigned char		priority;	/* class priority */
778c2ecf20Sopenharmony_ci	unsigned char		priority2;	/* priority to be used after overlimit */
788c2ecf20Sopenharmony_ci	unsigned char		ewma_log;	/* time constant for idle time calculation */
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	u32			defmap;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* Link-sharing scheduler parameters */
838c2ecf20Sopenharmony_ci	long			maxidle;	/* Class parameters: see below. */
848c2ecf20Sopenharmony_ci	long			offtime;
858c2ecf20Sopenharmony_ci	long			minidle;
868c2ecf20Sopenharmony_ci	u32			avpkt;
878c2ecf20Sopenharmony_ci	struct qdisc_rate_table	*R_tab;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* General scheduler (WRR) parameters */
908c2ecf20Sopenharmony_ci	long			allot;
918c2ecf20Sopenharmony_ci	long			quantum;	/* Allotment per WRR round */
928c2ecf20Sopenharmony_ci	long			weight;		/* Relative allotment: see below */
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	struct Qdisc		*qdisc;		/* Ptr to CBQ discipline */
958c2ecf20Sopenharmony_ci	struct cbq_class	*split;		/* Ptr to split node */
968c2ecf20Sopenharmony_ci	struct cbq_class	*share;		/* Ptr to LS parent in the class tree */
978c2ecf20Sopenharmony_ci	struct cbq_class	*tparent;	/* Ptr to tree parent in the class tree */
988c2ecf20Sopenharmony_ci	struct cbq_class	*borrow;	/* NULL if class is bandwidth limited;
998c2ecf20Sopenharmony_ci						   parent otherwise */
1008c2ecf20Sopenharmony_ci	struct cbq_class	*sibling;	/* Sibling chain */
1018c2ecf20Sopenharmony_ci	struct cbq_class	*children;	/* Pointer to children chain */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	struct Qdisc		*q;		/* Elementary queueing discipline */
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* Variables */
1078c2ecf20Sopenharmony_ci	unsigned char		cpriority;	/* Effective priority */
1088c2ecf20Sopenharmony_ci	unsigned char		delayed;
1098c2ecf20Sopenharmony_ci	unsigned char		level;		/* level of the class in hierarchy:
1108c2ecf20Sopenharmony_ci						   0 for leaf classes, and maximal
1118c2ecf20Sopenharmony_ci						   level of children + 1 for nodes.
1128c2ecf20Sopenharmony_ci						 */
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	psched_time_t		last;		/* Last end of service */
1158c2ecf20Sopenharmony_ci	psched_time_t		undertime;
1168c2ecf20Sopenharmony_ci	long			avgidle;
1178c2ecf20Sopenharmony_ci	long			deficit;	/* Saved deficit for WRR */
1188c2ecf20Sopenharmony_ci	psched_time_t		penalized;
1198c2ecf20Sopenharmony_ci	struct gnet_stats_basic_packed bstats;
1208c2ecf20Sopenharmony_ci	struct gnet_stats_queue qstats;
1218c2ecf20Sopenharmony_ci	struct net_rate_estimator __rcu *rate_est;
1228c2ecf20Sopenharmony_ci	struct tc_cbq_xstats	xstats;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	struct tcf_proto __rcu	*filter_list;
1258c2ecf20Sopenharmony_ci	struct tcf_block	*block;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	int			filters;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	struct cbq_class	*defaults[TC_PRIO_MAX + 1];
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistruct cbq_sched_data {
1338c2ecf20Sopenharmony_ci	struct Qdisc_class_hash	clhash;			/* Hash table of all classes */
1348c2ecf20Sopenharmony_ci	int			nclasses[TC_CBQ_MAXPRIO + 1];
1358c2ecf20Sopenharmony_ci	unsigned int		quanta[TC_CBQ_MAXPRIO + 1];
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	struct cbq_class	link;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	unsigned int		activemask;
1408c2ecf20Sopenharmony_ci	struct cbq_class	*active[TC_CBQ_MAXPRIO + 1];	/* List of all classes
1418c2ecf20Sopenharmony_ci								   with backlog */
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
1448c2ecf20Sopenharmony_ci	struct cbq_class	*rx_class;
1458c2ecf20Sopenharmony_ci#endif
1468c2ecf20Sopenharmony_ci	struct cbq_class	*tx_class;
1478c2ecf20Sopenharmony_ci	struct cbq_class	*tx_borrowed;
1488c2ecf20Sopenharmony_ci	int			tx_len;
1498c2ecf20Sopenharmony_ci	psched_time_t		now;		/* Cached timestamp */
1508c2ecf20Sopenharmony_ci	unsigned int		pmask;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	struct hrtimer		delay_timer;
1538c2ecf20Sopenharmony_ci	struct qdisc_watchdog	watchdog;	/* Watchdog timer,
1548c2ecf20Sopenharmony_ci						   started when CBQ has
1558c2ecf20Sopenharmony_ci						   backlog, but cannot
1568c2ecf20Sopenharmony_ci						   transmit just now */
1578c2ecf20Sopenharmony_ci	psched_tdiff_t		wd_expires;
1588c2ecf20Sopenharmony_ci	int			toplevel;
1598c2ecf20Sopenharmony_ci	u32			hgenerator;
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci#define L2T(cl, len)	qdisc_l2t((cl)->R_tab, len)
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic inline struct cbq_class *
1668c2ecf20Sopenharmony_cicbq_class_lookup(struct cbq_sched_data *q, u32 classid)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct Qdisc_class_common *clc;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	clc = qdisc_class_find(&q->clhash, classid);
1718c2ecf20Sopenharmony_ci	if (clc == NULL)
1728c2ecf20Sopenharmony_ci		return NULL;
1738c2ecf20Sopenharmony_ci	return container_of(clc, struct cbq_class, common);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic struct cbq_class *
1798c2ecf20Sopenharmony_cicbq_reclassify(struct sk_buff *skb, struct cbq_class *this)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct cbq_class *cl;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	for (cl = this->tparent; cl; cl = cl->tparent) {
1848c2ecf20Sopenharmony_ci		struct cbq_class *new = cl->defaults[TC_PRIO_BESTEFFORT];
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if (new != NULL && new != this)
1878c2ecf20Sopenharmony_ci			return new;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	return NULL;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci#endif
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/* Classify packet. The procedure is pretty complicated, but
1958c2ecf20Sopenharmony_ci * it allows us to combine link sharing and priority scheduling
1968c2ecf20Sopenharmony_ci * transparently.
1978c2ecf20Sopenharmony_ci *
1988c2ecf20Sopenharmony_ci * Namely, you can put link sharing rules (f.e. route based) at root of CBQ,
1998c2ecf20Sopenharmony_ci * so that it resolves to split nodes. Then packets are classified
2008c2ecf20Sopenharmony_ci * by logical priority, or a more specific classifier may be attached
2018c2ecf20Sopenharmony_ci * to the split node.
2028c2ecf20Sopenharmony_ci */
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic struct cbq_class *
2058c2ecf20Sopenharmony_cicbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
2088c2ecf20Sopenharmony_ci	struct cbq_class *head = &q->link;
2098c2ecf20Sopenharmony_ci	struct cbq_class **defmap;
2108c2ecf20Sopenharmony_ci	struct cbq_class *cl = NULL;
2118c2ecf20Sopenharmony_ci	u32 prio = skb->priority;
2128c2ecf20Sopenharmony_ci	struct tcf_proto *fl;
2138c2ecf20Sopenharmony_ci	struct tcf_result res;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/*
2168c2ecf20Sopenharmony_ci	 *  Step 1. If skb->priority points to one of our classes, use it.
2178c2ecf20Sopenharmony_ci	 */
2188c2ecf20Sopenharmony_ci	if (TC_H_MAJ(prio ^ sch->handle) == 0 &&
2198c2ecf20Sopenharmony_ci	    (cl = cbq_class_lookup(q, prio)) != NULL)
2208c2ecf20Sopenharmony_ci		return cl;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
2238c2ecf20Sopenharmony_ci	for (;;) {
2248c2ecf20Sopenharmony_ci		int result = 0;
2258c2ecf20Sopenharmony_ci		defmap = head->defaults;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		fl = rcu_dereference_bh(head->filter_list);
2288c2ecf20Sopenharmony_ci		/*
2298c2ecf20Sopenharmony_ci		 * Step 2+n. Apply classifier.
2308c2ecf20Sopenharmony_ci		 */
2318c2ecf20Sopenharmony_ci		result = tcf_classify(skb, fl, &res, true);
2328c2ecf20Sopenharmony_ci		if (!fl || result < 0)
2338c2ecf20Sopenharmony_ci			goto fallback;
2348c2ecf20Sopenharmony_ci		if (result == TC_ACT_SHOT)
2358c2ecf20Sopenharmony_ci			return NULL;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		cl = (void *)res.class;
2388c2ecf20Sopenharmony_ci		if (!cl) {
2398c2ecf20Sopenharmony_ci			if (TC_H_MAJ(res.classid))
2408c2ecf20Sopenharmony_ci				cl = cbq_class_lookup(q, res.classid);
2418c2ecf20Sopenharmony_ci			else if ((cl = defmap[res.classid & TC_PRIO_MAX]) == NULL)
2428c2ecf20Sopenharmony_ci				cl = defmap[TC_PRIO_BESTEFFORT];
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci			if (cl == NULL)
2458c2ecf20Sopenharmony_ci				goto fallback;
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci		if (cl->level >= head->level)
2488c2ecf20Sopenharmony_ci			goto fallback;
2498c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
2508c2ecf20Sopenharmony_ci		switch (result) {
2518c2ecf20Sopenharmony_ci		case TC_ACT_QUEUED:
2528c2ecf20Sopenharmony_ci		case TC_ACT_STOLEN:
2538c2ecf20Sopenharmony_ci		case TC_ACT_TRAP:
2548c2ecf20Sopenharmony_ci			*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
2558c2ecf20Sopenharmony_ci			fallthrough;
2568c2ecf20Sopenharmony_ci		case TC_ACT_RECLASSIFY:
2578c2ecf20Sopenharmony_ci			return cbq_reclassify(skb, cl);
2588c2ecf20Sopenharmony_ci		}
2598c2ecf20Sopenharmony_ci#endif
2608c2ecf20Sopenharmony_ci		if (cl->level == 0)
2618c2ecf20Sopenharmony_ci			return cl;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		/*
2648c2ecf20Sopenharmony_ci		 * Step 3+n. If classifier selected a link sharing class,
2658c2ecf20Sopenharmony_ci		 *	   apply agency specific classifier.
2668c2ecf20Sopenharmony_ci		 *	   Repeat this procdure until we hit a leaf node.
2678c2ecf20Sopenharmony_ci		 */
2688c2ecf20Sopenharmony_ci		head = cl;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cifallback:
2728c2ecf20Sopenharmony_ci	cl = head;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/*
2758c2ecf20Sopenharmony_ci	 * Step 4. No success...
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	if (TC_H_MAJ(prio) == 0 &&
2788c2ecf20Sopenharmony_ci	    !(cl = head->defaults[prio & TC_PRIO_MAX]) &&
2798c2ecf20Sopenharmony_ci	    !(cl = head->defaults[TC_PRIO_BESTEFFORT]))
2808c2ecf20Sopenharmony_ci		return head;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return cl;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/*
2868c2ecf20Sopenharmony_ci * A packet has just been enqueued on the empty class.
2878c2ecf20Sopenharmony_ci * cbq_activate_class adds it to the tail of active class list
2888c2ecf20Sopenharmony_ci * of its priority band.
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic inline void cbq_activate_class(struct cbq_class *cl)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
2948c2ecf20Sopenharmony_ci	int prio = cl->cpriority;
2958c2ecf20Sopenharmony_ci	struct cbq_class *cl_tail;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	cl_tail = q->active[prio];
2988c2ecf20Sopenharmony_ci	q->active[prio] = cl;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (cl_tail != NULL) {
3018c2ecf20Sopenharmony_ci		cl->next_alive = cl_tail->next_alive;
3028c2ecf20Sopenharmony_ci		cl_tail->next_alive = cl;
3038c2ecf20Sopenharmony_ci	} else {
3048c2ecf20Sopenharmony_ci		cl->next_alive = cl;
3058c2ecf20Sopenharmony_ci		q->activemask |= (1<<prio);
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci/*
3108c2ecf20Sopenharmony_ci * Unlink class from active chain.
3118c2ecf20Sopenharmony_ci * Note that this same procedure is done directly in cbq_dequeue*
3128c2ecf20Sopenharmony_ci * during round-robin procedure.
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic void cbq_deactivate_class(struct cbq_class *this)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(this->qdisc);
3188c2ecf20Sopenharmony_ci	int prio = this->cpriority;
3198c2ecf20Sopenharmony_ci	struct cbq_class *cl;
3208c2ecf20Sopenharmony_ci	struct cbq_class *cl_prev = q->active[prio];
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	do {
3238c2ecf20Sopenharmony_ci		cl = cl_prev->next_alive;
3248c2ecf20Sopenharmony_ci		if (cl == this) {
3258c2ecf20Sopenharmony_ci			cl_prev->next_alive = cl->next_alive;
3268c2ecf20Sopenharmony_ci			cl->next_alive = NULL;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci			if (cl == q->active[prio]) {
3298c2ecf20Sopenharmony_ci				q->active[prio] = cl_prev;
3308c2ecf20Sopenharmony_ci				if (cl == q->active[prio]) {
3318c2ecf20Sopenharmony_ci					q->active[prio] = NULL;
3328c2ecf20Sopenharmony_ci					q->activemask &= ~(1<<prio);
3338c2ecf20Sopenharmony_ci					return;
3348c2ecf20Sopenharmony_ci				}
3358c2ecf20Sopenharmony_ci			}
3368c2ecf20Sopenharmony_ci			return;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci	} while ((cl_prev = cl) != q->active[prio]);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic void
3428c2ecf20Sopenharmony_cicbq_mark_toplevel(struct cbq_sched_data *q, struct cbq_class *cl)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	int toplevel = q->toplevel;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (toplevel > cl->level) {
3478c2ecf20Sopenharmony_ci		psched_time_t now = psched_get_time();
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci		do {
3508c2ecf20Sopenharmony_ci			if (cl->undertime < now) {
3518c2ecf20Sopenharmony_ci				q->toplevel = cl->level;
3528c2ecf20Sopenharmony_ci				return;
3538c2ecf20Sopenharmony_ci			}
3548c2ecf20Sopenharmony_ci		} while ((cl = cl->borrow) != NULL && toplevel > cl->level);
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int
3598c2ecf20Sopenharmony_cicbq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
3608c2ecf20Sopenharmony_ci	    struct sk_buff **to_free)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
3638c2ecf20Sopenharmony_ci	int ret;
3648c2ecf20Sopenharmony_ci	struct cbq_class *cl = cbq_classify(skb, sch, &ret);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
3678c2ecf20Sopenharmony_ci	q->rx_class = cl;
3688c2ecf20Sopenharmony_ci#endif
3698c2ecf20Sopenharmony_ci	if (cl == NULL) {
3708c2ecf20Sopenharmony_ci		if (ret & __NET_XMIT_BYPASS)
3718c2ecf20Sopenharmony_ci			qdisc_qstats_drop(sch);
3728c2ecf20Sopenharmony_ci		__qdisc_drop(skb, to_free);
3738c2ecf20Sopenharmony_ci		return ret;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	ret = qdisc_enqueue(skb, cl->q, to_free);
3778c2ecf20Sopenharmony_ci	if (ret == NET_XMIT_SUCCESS) {
3788c2ecf20Sopenharmony_ci		sch->q.qlen++;
3798c2ecf20Sopenharmony_ci		cbq_mark_toplevel(q, cl);
3808c2ecf20Sopenharmony_ci		if (!cl->next_alive)
3818c2ecf20Sopenharmony_ci			cbq_activate_class(cl);
3828c2ecf20Sopenharmony_ci		return ret;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (net_xmit_drop_count(ret)) {
3868c2ecf20Sopenharmony_ci		qdisc_qstats_drop(sch);
3878c2ecf20Sopenharmony_ci		cbq_mark_toplevel(q, cl);
3888c2ecf20Sopenharmony_ci		cl->qstats.drops++;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci	return ret;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci/* Overlimit action: penalize leaf class by adding offtime */
3948c2ecf20Sopenharmony_cistatic void cbq_overlimit(struct cbq_class *cl)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
3978c2ecf20Sopenharmony_ci	psched_tdiff_t delay = cl->undertime - q->now;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (!cl->delayed) {
4008c2ecf20Sopenharmony_ci		delay += cl->offtime;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		/*
4038c2ecf20Sopenharmony_ci		 * Class goes to sleep, so that it will have no
4048c2ecf20Sopenharmony_ci		 * chance to work avgidle. Let's forgive it 8)
4058c2ecf20Sopenharmony_ci		 *
4068c2ecf20Sopenharmony_ci		 * BTW cbq-2.0 has a crap in this
4078c2ecf20Sopenharmony_ci		 * place, apparently they forgot to shift it by cl->ewma_log.
4088c2ecf20Sopenharmony_ci		 */
4098c2ecf20Sopenharmony_ci		if (cl->avgidle < 0)
4108c2ecf20Sopenharmony_ci			delay -= (-cl->avgidle) - ((-cl->avgidle) >> cl->ewma_log);
4118c2ecf20Sopenharmony_ci		if (cl->avgidle < cl->minidle)
4128c2ecf20Sopenharmony_ci			cl->avgidle = cl->minidle;
4138c2ecf20Sopenharmony_ci		if (delay <= 0)
4148c2ecf20Sopenharmony_ci			delay = 1;
4158c2ecf20Sopenharmony_ci		cl->undertime = q->now + delay;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		cl->xstats.overactions++;
4188c2ecf20Sopenharmony_ci		cl->delayed = 1;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci	if (q->wd_expires == 0 || q->wd_expires > delay)
4218c2ecf20Sopenharmony_ci		q->wd_expires = delay;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/* Dirty work! We must schedule wakeups based on
4248c2ecf20Sopenharmony_ci	 * real available rate, rather than leaf rate,
4258c2ecf20Sopenharmony_ci	 * which may be tiny (even zero).
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	if (q->toplevel == TC_CBQ_MAXLEVEL) {
4288c2ecf20Sopenharmony_ci		struct cbq_class *b;
4298c2ecf20Sopenharmony_ci		psched_tdiff_t base_delay = q->wd_expires;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		for (b = cl->borrow; b; b = b->borrow) {
4328c2ecf20Sopenharmony_ci			delay = b->undertime - q->now;
4338c2ecf20Sopenharmony_ci			if (delay < base_delay) {
4348c2ecf20Sopenharmony_ci				if (delay <= 0)
4358c2ecf20Sopenharmony_ci					delay = 1;
4368c2ecf20Sopenharmony_ci				base_delay = delay;
4378c2ecf20Sopenharmony_ci			}
4388c2ecf20Sopenharmony_ci		}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		q->wd_expires = base_delay;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic psched_tdiff_t cbq_undelay_prio(struct cbq_sched_data *q, int prio,
4458c2ecf20Sopenharmony_ci				       psched_time_t now)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct cbq_class *cl;
4488c2ecf20Sopenharmony_ci	struct cbq_class *cl_prev = q->active[prio];
4498c2ecf20Sopenharmony_ci	psched_time_t sched = now;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (cl_prev == NULL)
4528c2ecf20Sopenharmony_ci		return 0;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	do {
4558c2ecf20Sopenharmony_ci		cl = cl_prev->next_alive;
4568c2ecf20Sopenharmony_ci		if (now - cl->penalized > 0) {
4578c2ecf20Sopenharmony_ci			cl_prev->next_alive = cl->next_alive;
4588c2ecf20Sopenharmony_ci			cl->next_alive = NULL;
4598c2ecf20Sopenharmony_ci			cl->cpriority = cl->priority;
4608c2ecf20Sopenharmony_ci			cl->delayed = 0;
4618c2ecf20Sopenharmony_ci			cbq_activate_class(cl);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci			if (cl == q->active[prio]) {
4648c2ecf20Sopenharmony_ci				q->active[prio] = cl_prev;
4658c2ecf20Sopenharmony_ci				if (cl == q->active[prio]) {
4668c2ecf20Sopenharmony_ci					q->active[prio] = NULL;
4678c2ecf20Sopenharmony_ci					return 0;
4688c2ecf20Sopenharmony_ci				}
4698c2ecf20Sopenharmony_ci			}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci			cl = cl_prev->next_alive;
4728c2ecf20Sopenharmony_ci		} else if (sched - cl->penalized > 0)
4738c2ecf20Sopenharmony_ci			sched = cl->penalized;
4748c2ecf20Sopenharmony_ci	} while ((cl_prev = cl) != q->active[prio]);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	return sched - now;
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = container_of(timer, struct cbq_sched_data,
4828c2ecf20Sopenharmony_ci						delay_timer);
4838c2ecf20Sopenharmony_ci	struct Qdisc *sch = q->watchdog.qdisc;
4848c2ecf20Sopenharmony_ci	psched_time_t now;
4858c2ecf20Sopenharmony_ci	psched_tdiff_t delay = 0;
4868c2ecf20Sopenharmony_ci	unsigned int pmask;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	now = psched_get_time();
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	pmask = q->pmask;
4918c2ecf20Sopenharmony_ci	q->pmask = 0;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	while (pmask) {
4948c2ecf20Sopenharmony_ci		int prio = ffz(~pmask);
4958c2ecf20Sopenharmony_ci		psched_tdiff_t tmp;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		pmask &= ~(1<<prio);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		tmp = cbq_undelay_prio(q, prio, now);
5008c2ecf20Sopenharmony_ci		if (tmp > 0) {
5018c2ecf20Sopenharmony_ci			q->pmask |= 1<<prio;
5028c2ecf20Sopenharmony_ci			if (tmp < delay || delay == 0)
5038c2ecf20Sopenharmony_ci				delay = tmp;
5048c2ecf20Sopenharmony_ci		}
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (delay) {
5088c2ecf20Sopenharmony_ci		ktime_t time;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci		time = 0;
5118c2ecf20Sopenharmony_ci		time = ktime_add_ns(time, PSCHED_TICKS2NS(now + delay));
5128c2ecf20Sopenharmony_ci		hrtimer_start(&q->delay_timer, time, HRTIMER_MODE_ABS_PINNED);
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	__netif_schedule(qdisc_root(sch));
5168c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/*
5208c2ecf20Sopenharmony_ci * It is mission critical procedure.
5218c2ecf20Sopenharmony_ci *
5228c2ecf20Sopenharmony_ci * We "regenerate" toplevel cutoff, if transmitting class
5238c2ecf20Sopenharmony_ci * has backlog and it is not regulated. It is not part of
5248c2ecf20Sopenharmony_ci * original CBQ description, but looks more reasonable.
5258c2ecf20Sopenharmony_ci * Probably, it is wrong. This question needs further investigation.
5268c2ecf20Sopenharmony_ci */
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic inline void
5298c2ecf20Sopenharmony_cicbq_update_toplevel(struct cbq_sched_data *q, struct cbq_class *cl,
5308c2ecf20Sopenharmony_ci		    struct cbq_class *borrowed)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	if (cl && q->toplevel >= borrowed->level) {
5338c2ecf20Sopenharmony_ci		if (cl->q->q.qlen > 1) {
5348c2ecf20Sopenharmony_ci			do {
5358c2ecf20Sopenharmony_ci				if (borrowed->undertime == PSCHED_PASTPERFECT) {
5368c2ecf20Sopenharmony_ci					q->toplevel = borrowed->level;
5378c2ecf20Sopenharmony_ci					return;
5388c2ecf20Sopenharmony_ci				}
5398c2ecf20Sopenharmony_ci			} while ((borrowed = borrowed->borrow) != NULL);
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci#if 0
5428c2ecf20Sopenharmony_ci	/* It is not necessary now. Uncommenting it
5438c2ecf20Sopenharmony_ci	   will save CPU cycles, but decrease fairness.
5448c2ecf20Sopenharmony_ci	 */
5458c2ecf20Sopenharmony_ci		q->toplevel = TC_CBQ_MAXLEVEL;
5468c2ecf20Sopenharmony_ci#endif
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic void
5518c2ecf20Sopenharmony_cicbq_update(struct cbq_sched_data *q)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct cbq_class *this = q->tx_class;
5548c2ecf20Sopenharmony_ci	struct cbq_class *cl = this;
5558c2ecf20Sopenharmony_ci	int len = q->tx_len;
5568c2ecf20Sopenharmony_ci	psched_time_t now;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	q->tx_class = NULL;
5598c2ecf20Sopenharmony_ci	/* Time integrator. We calculate EOS time
5608c2ecf20Sopenharmony_ci	 * by adding expected packet transmission time.
5618c2ecf20Sopenharmony_ci	 */
5628c2ecf20Sopenharmony_ci	now = q->now + L2T(&q->link, len);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	for ( ; cl; cl = cl->share) {
5658c2ecf20Sopenharmony_ci		long avgidle = cl->avgidle;
5668c2ecf20Sopenharmony_ci		long idle;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		cl->bstats.packets++;
5698c2ecf20Sopenharmony_ci		cl->bstats.bytes += len;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		/*
5728c2ecf20Sopenharmony_ci		 * (now - last) is total time between packet right edges.
5738c2ecf20Sopenharmony_ci		 * (last_pktlen/rate) is "virtual" busy time, so that
5748c2ecf20Sopenharmony_ci		 *
5758c2ecf20Sopenharmony_ci		 *	idle = (now - last) - last_pktlen/rate
5768c2ecf20Sopenharmony_ci		 */
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci		idle = now - cl->last;
5798c2ecf20Sopenharmony_ci		if ((unsigned long)idle > 128*1024*1024) {
5808c2ecf20Sopenharmony_ci			avgidle = cl->maxidle;
5818c2ecf20Sopenharmony_ci		} else {
5828c2ecf20Sopenharmony_ci			idle -= L2T(cl, len);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		/* true_avgidle := (1-W)*true_avgidle + W*idle,
5858c2ecf20Sopenharmony_ci		 * where W=2^{-ewma_log}. But cl->avgidle is scaled:
5868c2ecf20Sopenharmony_ci		 * cl->avgidle == true_avgidle/W,
5878c2ecf20Sopenharmony_ci		 * hence:
5888c2ecf20Sopenharmony_ci		 */
5898c2ecf20Sopenharmony_ci			avgidle += idle - (avgidle>>cl->ewma_log);
5908c2ecf20Sopenharmony_ci		}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		if (avgidle <= 0) {
5938c2ecf20Sopenharmony_ci			/* Overlimit or at-limit */
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci			if (avgidle < cl->minidle)
5968c2ecf20Sopenharmony_ci				avgidle = cl->minidle;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci			cl->avgidle = avgidle;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci			/* Calculate expected time, when this class
6018c2ecf20Sopenharmony_ci			 * will be allowed to send.
6028c2ecf20Sopenharmony_ci			 * It will occur, when:
6038c2ecf20Sopenharmony_ci			 * (1-W)*true_avgidle + W*delay = 0, i.e.
6048c2ecf20Sopenharmony_ci			 * idle = (1/W - 1)*(-true_avgidle)
6058c2ecf20Sopenharmony_ci			 * or
6068c2ecf20Sopenharmony_ci			 * idle = (1 - W)*(-cl->avgidle);
6078c2ecf20Sopenharmony_ci			 */
6088c2ecf20Sopenharmony_ci			idle = (-avgidle) - ((-avgidle) >> cl->ewma_log);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci			/*
6118c2ecf20Sopenharmony_ci			 * That is not all.
6128c2ecf20Sopenharmony_ci			 * To maintain the rate allocated to the class,
6138c2ecf20Sopenharmony_ci			 * we add to undertime virtual clock,
6148c2ecf20Sopenharmony_ci			 * necessary to complete transmitted packet.
6158c2ecf20Sopenharmony_ci			 * (len/phys_bandwidth has been already passed
6168c2ecf20Sopenharmony_ci			 * to the moment of cbq_update)
6178c2ecf20Sopenharmony_ci			 */
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci			idle -= L2T(&q->link, len);
6208c2ecf20Sopenharmony_ci			idle += L2T(cl, len);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci			cl->undertime = now + idle;
6238c2ecf20Sopenharmony_ci		} else {
6248c2ecf20Sopenharmony_ci			/* Underlimit */
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci			cl->undertime = PSCHED_PASTPERFECT;
6278c2ecf20Sopenharmony_ci			if (avgidle > cl->maxidle)
6288c2ecf20Sopenharmony_ci				cl->avgidle = cl->maxidle;
6298c2ecf20Sopenharmony_ci			else
6308c2ecf20Sopenharmony_ci				cl->avgidle = avgidle;
6318c2ecf20Sopenharmony_ci		}
6328c2ecf20Sopenharmony_ci		if ((s64)(now - cl->last) > 0)
6338c2ecf20Sopenharmony_ci			cl->last = now;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	cbq_update_toplevel(q, this, q->tx_borrowed);
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic inline struct cbq_class *
6408c2ecf20Sopenharmony_cicbq_under_limit(struct cbq_class *cl)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
6438c2ecf20Sopenharmony_ci	struct cbq_class *this_cl = cl;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (cl->tparent == NULL)
6468c2ecf20Sopenharmony_ci		return cl;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (cl->undertime == PSCHED_PASTPERFECT || q->now >= cl->undertime) {
6498c2ecf20Sopenharmony_ci		cl->delayed = 0;
6508c2ecf20Sopenharmony_ci		return cl;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	do {
6548c2ecf20Sopenharmony_ci		/* It is very suspicious place. Now overlimit
6558c2ecf20Sopenharmony_ci		 * action is generated for not bounded classes
6568c2ecf20Sopenharmony_ci		 * only if link is completely congested.
6578c2ecf20Sopenharmony_ci		 * Though it is in agree with ancestor-only paradigm,
6588c2ecf20Sopenharmony_ci		 * it looks very stupid. Particularly,
6598c2ecf20Sopenharmony_ci		 * it means that this chunk of code will either
6608c2ecf20Sopenharmony_ci		 * never be called or result in strong amplification
6618c2ecf20Sopenharmony_ci		 * of burstiness. Dangerous, silly, and, however,
6628c2ecf20Sopenharmony_ci		 * no another solution exists.
6638c2ecf20Sopenharmony_ci		 */
6648c2ecf20Sopenharmony_ci		cl = cl->borrow;
6658c2ecf20Sopenharmony_ci		if (!cl) {
6668c2ecf20Sopenharmony_ci			this_cl->qstats.overlimits++;
6678c2ecf20Sopenharmony_ci			cbq_overlimit(this_cl);
6688c2ecf20Sopenharmony_ci			return NULL;
6698c2ecf20Sopenharmony_ci		}
6708c2ecf20Sopenharmony_ci		if (cl->level > q->toplevel)
6718c2ecf20Sopenharmony_ci			return NULL;
6728c2ecf20Sopenharmony_ci	} while (cl->undertime != PSCHED_PASTPERFECT && q->now < cl->undertime);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	cl->delayed = 0;
6758c2ecf20Sopenharmony_ci	return cl;
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic inline struct sk_buff *
6798c2ecf20Sopenharmony_cicbq_dequeue_prio(struct Qdisc *sch, int prio)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
6828c2ecf20Sopenharmony_ci	struct cbq_class *cl_tail, *cl_prev, *cl;
6838c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6848c2ecf20Sopenharmony_ci	int deficit;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	cl_tail = cl_prev = q->active[prio];
6878c2ecf20Sopenharmony_ci	cl = cl_prev->next_alive;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	do {
6908c2ecf20Sopenharmony_ci		deficit = 0;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci		/* Start round */
6938c2ecf20Sopenharmony_ci		do {
6948c2ecf20Sopenharmony_ci			struct cbq_class *borrow = cl;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci			if (cl->q->q.qlen &&
6978c2ecf20Sopenharmony_ci			    (borrow = cbq_under_limit(cl)) == NULL)
6988c2ecf20Sopenharmony_ci				goto skip_class;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci			if (cl->deficit <= 0) {
7018c2ecf20Sopenharmony_ci				/* Class exhausted its allotment per
7028c2ecf20Sopenharmony_ci				 * this round. Switch to the next one.
7038c2ecf20Sopenharmony_ci				 */
7048c2ecf20Sopenharmony_ci				deficit = 1;
7058c2ecf20Sopenharmony_ci				cl->deficit += cl->quantum;
7068c2ecf20Sopenharmony_ci				goto next_class;
7078c2ecf20Sopenharmony_ci			}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci			skb = cl->q->dequeue(cl->q);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci			/* Class did not give us any skb :-(
7128c2ecf20Sopenharmony_ci			 * It could occur even if cl->q->q.qlen != 0
7138c2ecf20Sopenharmony_ci			 * f.e. if cl->q == "tbf"
7148c2ecf20Sopenharmony_ci			 */
7158c2ecf20Sopenharmony_ci			if (skb == NULL)
7168c2ecf20Sopenharmony_ci				goto skip_class;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci			cl->deficit -= qdisc_pkt_len(skb);
7198c2ecf20Sopenharmony_ci			q->tx_class = cl;
7208c2ecf20Sopenharmony_ci			q->tx_borrowed = borrow;
7218c2ecf20Sopenharmony_ci			if (borrow != cl) {
7228c2ecf20Sopenharmony_ci#ifndef CBQ_XSTATS_BORROWS_BYTES
7238c2ecf20Sopenharmony_ci				borrow->xstats.borrows++;
7248c2ecf20Sopenharmony_ci				cl->xstats.borrows++;
7258c2ecf20Sopenharmony_ci#else
7268c2ecf20Sopenharmony_ci				borrow->xstats.borrows += qdisc_pkt_len(skb);
7278c2ecf20Sopenharmony_ci				cl->xstats.borrows += qdisc_pkt_len(skb);
7288c2ecf20Sopenharmony_ci#endif
7298c2ecf20Sopenharmony_ci			}
7308c2ecf20Sopenharmony_ci			q->tx_len = qdisc_pkt_len(skb);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci			if (cl->deficit <= 0) {
7338c2ecf20Sopenharmony_ci				q->active[prio] = cl;
7348c2ecf20Sopenharmony_ci				cl = cl->next_alive;
7358c2ecf20Sopenharmony_ci				cl->deficit += cl->quantum;
7368c2ecf20Sopenharmony_ci			}
7378c2ecf20Sopenharmony_ci			return skb;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ciskip_class:
7408c2ecf20Sopenharmony_ci			if (cl->q->q.qlen == 0 || prio != cl->cpriority) {
7418c2ecf20Sopenharmony_ci				/* Class is empty or penalized.
7428c2ecf20Sopenharmony_ci				 * Unlink it from active chain.
7438c2ecf20Sopenharmony_ci				 */
7448c2ecf20Sopenharmony_ci				cl_prev->next_alive = cl->next_alive;
7458c2ecf20Sopenharmony_ci				cl->next_alive = NULL;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci				/* Did cl_tail point to it? */
7488c2ecf20Sopenharmony_ci				if (cl == cl_tail) {
7498c2ecf20Sopenharmony_ci					/* Repair it! */
7508c2ecf20Sopenharmony_ci					cl_tail = cl_prev;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci					/* Was it the last class in this band? */
7538c2ecf20Sopenharmony_ci					if (cl == cl_tail) {
7548c2ecf20Sopenharmony_ci						/* Kill the band! */
7558c2ecf20Sopenharmony_ci						q->active[prio] = NULL;
7568c2ecf20Sopenharmony_ci						q->activemask &= ~(1<<prio);
7578c2ecf20Sopenharmony_ci						if (cl->q->q.qlen)
7588c2ecf20Sopenharmony_ci							cbq_activate_class(cl);
7598c2ecf20Sopenharmony_ci						return NULL;
7608c2ecf20Sopenharmony_ci					}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci					q->active[prio] = cl_tail;
7638c2ecf20Sopenharmony_ci				}
7648c2ecf20Sopenharmony_ci				if (cl->q->q.qlen)
7658c2ecf20Sopenharmony_ci					cbq_activate_class(cl);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci				cl = cl_prev;
7688c2ecf20Sopenharmony_ci			}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cinext_class:
7718c2ecf20Sopenharmony_ci			cl_prev = cl;
7728c2ecf20Sopenharmony_ci			cl = cl->next_alive;
7738c2ecf20Sopenharmony_ci		} while (cl_prev != cl_tail);
7748c2ecf20Sopenharmony_ci	} while (deficit);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	q->active[prio] = cl_prev;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	return NULL;
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic inline struct sk_buff *
7828c2ecf20Sopenharmony_cicbq_dequeue_1(struct Qdisc *sch)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
7858c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7868c2ecf20Sopenharmony_ci	unsigned int activemask;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	activemask = q->activemask & 0xFF;
7898c2ecf20Sopenharmony_ci	while (activemask) {
7908c2ecf20Sopenharmony_ci		int prio = ffz(~activemask);
7918c2ecf20Sopenharmony_ci		activemask &= ~(1<<prio);
7928c2ecf20Sopenharmony_ci		skb = cbq_dequeue_prio(sch, prio);
7938c2ecf20Sopenharmony_ci		if (skb)
7948c2ecf20Sopenharmony_ci			return skb;
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci	return NULL;
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic struct sk_buff *
8008c2ecf20Sopenharmony_cicbq_dequeue(struct Qdisc *sch)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8038c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
8048c2ecf20Sopenharmony_ci	psched_time_t now;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	now = psched_get_time();
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	if (q->tx_class)
8098c2ecf20Sopenharmony_ci		cbq_update(q);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	q->now = now;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	for (;;) {
8148c2ecf20Sopenharmony_ci		q->wd_expires = 0;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci		skb = cbq_dequeue_1(sch);
8178c2ecf20Sopenharmony_ci		if (skb) {
8188c2ecf20Sopenharmony_ci			qdisc_bstats_update(sch, skb);
8198c2ecf20Sopenharmony_ci			sch->q.qlen--;
8208c2ecf20Sopenharmony_ci			return skb;
8218c2ecf20Sopenharmony_ci		}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci		/* All the classes are overlimit.
8248c2ecf20Sopenharmony_ci		 *
8258c2ecf20Sopenharmony_ci		 * It is possible, if:
8268c2ecf20Sopenharmony_ci		 *
8278c2ecf20Sopenharmony_ci		 * 1. Scheduler is empty.
8288c2ecf20Sopenharmony_ci		 * 2. Toplevel cutoff inhibited borrowing.
8298c2ecf20Sopenharmony_ci		 * 3. Root class is overlimit.
8308c2ecf20Sopenharmony_ci		 *
8318c2ecf20Sopenharmony_ci		 * Reset 2d and 3d conditions and retry.
8328c2ecf20Sopenharmony_ci		 *
8338c2ecf20Sopenharmony_ci		 * Note, that NS and cbq-2.0 are buggy, peeking
8348c2ecf20Sopenharmony_ci		 * an arbitrary class is appropriate for ancestor-only
8358c2ecf20Sopenharmony_ci		 * sharing, but not for toplevel algorithm.
8368c2ecf20Sopenharmony_ci		 *
8378c2ecf20Sopenharmony_ci		 * Our version is better, but slower, because it requires
8388c2ecf20Sopenharmony_ci		 * two passes, but it is unavoidable with top-level sharing.
8398c2ecf20Sopenharmony_ci		 */
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		if (q->toplevel == TC_CBQ_MAXLEVEL &&
8428c2ecf20Sopenharmony_ci		    q->link.undertime == PSCHED_PASTPERFECT)
8438c2ecf20Sopenharmony_ci			break;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		q->toplevel = TC_CBQ_MAXLEVEL;
8468c2ecf20Sopenharmony_ci		q->link.undertime = PSCHED_PASTPERFECT;
8478c2ecf20Sopenharmony_ci	}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/* No packets in scheduler or nobody wants to give them to us :-(
8508c2ecf20Sopenharmony_ci	 * Sigh... start watchdog timer in the last case.
8518c2ecf20Sopenharmony_ci	 */
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	if (sch->q.qlen) {
8548c2ecf20Sopenharmony_ci		qdisc_qstats_overlimit(sch);
8558c2ecf20Sopenharmony_ci		if (q->wd_expires)
8568c2ecf20Sopenharmony_ci			qdisc_watchdog_schedule(&q->watchdog,
8578c2ecf20Sopenharmony_ci						now + q->wd_expires);
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci	return NULL;
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci/* CBQ class maintanance routines */
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic void cbq_adjust_levels(struct cbq_class *this)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	if (this == NULL)
8678c2ecf20Sopenharmony_ci		return;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	do {
8708c2ecf20Sopenharmony_ci		int level = 0;
8718c2ecf20Sopenharmony_ci		struct cbq_class *cl;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci		cl = this->children;
8748c2ecf20Sopenharmony_ci		if (cl) {
8758c2ecf20Sopenharmony_ci			do {
8768c2ecf20Sopenharmony_ci				if (cl->level > level)
8778c2ecf20Sopenharmony_ci					level = cl->level;
8788c2ecf20Sopenharmony_ci			} while ((cl = cl->sibling) != this->children);
8798c2ecf20Sopenharmony_ci		}
8808c2ecf20Sopenharmony_ci		this->level = level + 1;
8818c2ecf20Sopenharmony_ci	} while ((this = this->tparent) != NULL);
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic void cbq_normalize_quanta(struct cbq_sched_data *q, int prio)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct cbq_class *cl;
8878c2ecf20Sopenharmony_ci	unsigned int h;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (q->quanta[prio] == 0)
8908c2ecf20Sopenharmony_ci		return;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	for (h = 0; h < q->clhash.hashsize; h++) {
8938c2ecf20Sopenharmony_ci		hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
8948c2ecf20Sopenharmony_ci			/* BUGGGG... Beware! This expression suffer of
8958c2ecf20Sopenharmony_ci			 * arithmetic overflows!
8968c2ecf20Sopenharmony_ci			 */
8978c2ecf20Sopenharmony_ci			if (cl->priority == prio) {
8988c2ecf20Sopenharmony_ci				cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/
8998c2ecf20Sopenharmony_ci					q->quanta[prio];
9008c2ecf20Sopenharmony_ci			}
9018c2ecf20Sopenharmony_ci			if (cl->quantum <= 0 ||
9028c2ecf20Sopenharmony_ci			    cl->quantum > 32*qdisc_dev(cl->qdisc)->mtu) {
9038c2ecf20Sopenharmony_ci				pr_warn("CBQ: class %08x has bad quantum==%ld, repaired.\n",
9048c2ecf20Sopenharmony_ci					cl->common.classid, cl->quantum);
9058c2ecf20Sopenharmony_ci				cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1;
9068c2ecf20Sopenharmony_ci			}
9078c2ecf20Sopenharmony_ci		}
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_cistatic void cbq_sync_defmap(struct cbq_class *cl)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
9148c2ecf20Sopenharmony_ci	struct cbq_class *split = cl->split;
9158c2ecf20Sopenharmony_ci	unsigned int h;
9168c2ecf20Sopenharmony_ci	int i;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (split == NULL)
9198c2ecf20Sopenharmony_ci		return;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	for (i = 0; i <= TC_PRIO_MAX; i++) {
9228c2ecf20Sopenharmony_ci		if (split->defaults[i] == cl && !(cl->defmap & (1<<i)))
9238c2ecf20Sopenharmony_ci			split->defaults[i] = NULL;
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	for (i = 0; i <= TC_PRIO_MAX; i++) {
9278c2ecf20Sopenharmony_ci		int level = split->level;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci		if (split->defaults[i])
9308c2ecf20Sopenharmony_ci			continue;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci		for (h = 0; h < q->clhash.hashsize; h++) {
9338c2ecf20Sopenharmony_ci			struct cbq_class *c;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci			hlist_for_each_entry(c, &q->clhash.hash[h],
9368c2ecf20Sopenharmony_ci					     common.hnode) {
9378c2ecf20Sopenharmony_ci				if (c->split == split && c->level < level &&
9388c2ecf20Sopenharmony_ci				    c->defmap & (1<<i)) {
9398c2ecf20Sopenharmony_ci					split->defaults[i] = c;
9408c2ecf20Sopenharmony_ci					level = c->level;
9418c2ecf20Sopenharmony_ci				}
9428c2ecf20Sopenharmony_ci			}
9438c2ecf20Sopenharmony_ci		}
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_cistatic void cbq_change_defmap(struct cbq_class *cl, u32 splitid, u32 def, u32 mask)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci	struct cbq_class *split = NULL;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	if (splitid == 0) {
9528c2ecf20Sopenharmony_ci		split = cl->split;
9538c2ecf20Sopenharmony_ci		if (!split)
9548c2ecf20Sopenharmony_ci			return;
9558c2ecf20Sopenharmony_ci		splitid = split->common.classid;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	if (split == NULL || split->common.classid != splitid) {
9598c2ecf20Sopenharmony_ci		for (split = cl->tparent; split; split = split->tparent)
9608c2ecf20Sopenharmony_ci			if (split->common.classid == splitid)
9618c2ecf20Sopenharmony_ci				break;
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (split == NULL)
9658c2ecf20Sopenharmony_ci		return;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if (cl->split != split) {
9688c2ecf20Sopenharmony_ci		cl->defmap = 0;
9698c2ecf20Sopenharmony_ci		cbq_sync_defmap(cl);
9708c2ecf20Sopenharmony_ci		cl->split = split;
9718c2ecf20Sopenharmony_ci		cl->defmap = def & mask;
9728c2ecf20Sopenharmony_ci	} else
9738c2ecf20Sopenharmony_ci		cl->defmap = (cl->defmap & ~mask) | (def & mask);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	cbq_sync_defmap(cl);
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_cistatic void cbq_unlink_class(struct cbq_class *this)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct cbq_class *cl, **clp;
9818c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(this->qdisc);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	qdisc_class_hash_remove(&q->clhash, &this->common);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (this->tparent) {
9868c2ecf20Sopenharmony_ci		clp = &this->sibling;
9878c2ecf20Sopenharmony_ci		cl = *clp;
9888c2ecf20Sopenharmony_ci		do {
9898c2ecf20Sopenharmony_ci			if (cl == this) {
9908c2ecf20Sopenharmony_ci				*clp = cl->sibling;
9918c2ecf20Sopenharmony_ci				break;
9928c2ecf20Sopenharmony_ci			}
9938c2ecf20Sopenharmony_ci			clp = &cl->sibling;
9948c2ecf20Sopenharmony_ci		} while ((cl = *clp) != this->sibling);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci		if (this->tparent->children == this) {
9978c2ecf20Sopenharmony_ci			this->tparent->children = this->sibling;
9988c2ecf20Sopenharmony_ci			if (this->sibling == this)
9998c2ecf20Sopenharmony_ci				this->tparent->children = NULL;
10008c2ecf20Sopenharmony_ci		}
10018c2ecf20Sopenharmony_ci	} else {
10028c2ecf20Sopenharmony_ci		WARN_ON(this->sibling != this);
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_cistatic void cbq_link_class(struct cbq_class *this)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(this->qdisc);
10098c2ecf20Sopenharmony_ci	struct cbq_class *parent = this->tparent;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	this->sibling = this;
10128c2ecf20Sopenharmony_ci	qdisc_class_hash_insert(&q->clhash, &this->common);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (parent == NULL)
10158c2ecf20Sopenharmony_ci		return;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	if (parent->children == NULL) {
10188c2ecf20Sopenharmony_ci		parent->children = this;
10198c2ecf20Sopenharmony_ci	} else {
10208c2ecf20Sopenharmony_ci		this->sibling = parent->children->sibling;
10218c2ecf20Sopenharmony_ci		parent->children->sibling = this;
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic void
10268c2ecf20Sopenharmony_cicbq_reset(struct Qdisc *sch)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
10298c2ecf20Sopenharmony_ci	struct cbq_class *cl;
10308c2ecf20Sopenharmony_ci	int prio;
10318c2ecf20Sopenharmony_ci	unsigned int h;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	q->activemask = 0;
10348c2ecf20Sopenharmony_ci	q->pmask = 0;
10358c2ecf20Sopenharmony_ci	q->tx_class = NULL;
10368c2ecf20Sopenharmony_ci	q->tx_borrowed = NULL;
10378c2ecf20Sopenharmony_ci	qdisc_watchdog_cancel(&q->watchdog);
10388c2ecf20Sopenharmony_ci	hrtimer_cancel(&q->delay_timer);
10398c2ecf20Sopenharmony_ci	q->toplevel = TC_CBQ_MAXLEVEL;
10408c2ecf20Sopenharmony_ci	q->now = psched_get_time();
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++)
10438c2ecf20Sopenharmony_ci		q->active[prio] = NULL;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	for (h = 0; h < q->clhash.hashsize; h++) {
10468c2ecf20Sopenharmony_ci		hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
10478c2ecf20Sopenharmony_ci			qdisc_reset(cl->q);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci			cl->next_alive = NULL;
10508c2ecf20Sopenharmony_ci			cl->undertime = PSCHED_PASTPERFECT;
10518c2ecf20Sopenharmony_ci			cl->avgidle = cl->maxidle;
10528c2ecf20Sopenharmony_ci			cl->deficit = cl->quantum;
10538c2ecf20Sopenharmony_ci			cl->cpriority = cl->priority;
10548c2ecf20Sopenharmony_ci		}
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic int cbq_set_lss(struct cbq_class *cl, struct tc_cbq_lssopt *lss)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	if (lss->change & TCF_CBQ_LSS_FLAGS) {
10628c2ecf20Sopenharmony_ci		cl->share = (lss->flags & TCF_CBQ_LSS_ISOLATED) ? NULL : cl->tparent;
10638c2ecf20Sopenharmony_ci		cl->borrow = (lss->flags & TCF_CBQ_LSS_BOUNDED) ? NULL : cl->tparent;
10648c2ecf20Sopenharmony_ci	}
10658c2ecf20Sopenharmony_ci	if (lss->change & TCF_CBQ_LSS_EWMA)
10668c2ecf20Sopenharmony_ci		cl->ewma_log = lss->ewma_log;
10678c2ecf20Sopenharmony_ci	if (lss->change & TCF_CBQ_LSS_AVPKT)
10688c2ecf20Sopenharmony_ci		cl->avpkt = lss->avpkt;
10698c2ecf20Sopenharmony_ci	if (lss->change & TCF_CBQ_LSS_MINIDLE)
10708c2ecf20Sopenharmony_ci		cl->minidle = -(long)lss->minidle;
10718c2ecf20Sopenharmony_ci	if (lss->change & TCF_CBQ_LSS_MAXIDLE) {
10728c2ecf20Sopenharmony_ci		cl->maxidle = lss->maxidle;
10738c2ecf20Sopenharmony_ci		cl->avgidle = lss->maxidle;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci	if (lss->change & TCF_CBQ_LSS_OFFTIME)
10768c2ecf20Sopenharmony_ci		cl->offtime = lss->offtime;
10778c2ecf20Sopenharmony_ci	return 0;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic void cbq_rmprio(struct cbq_sched_data *q, struct cbq_class *cl)
10818c2ecf20Sopenharmony_ci{
10828c2ecf20Sopenharmony_ci	q->nclasses[cl->priority]--;
10838c2ecf20Sopenharmony_ci	q->quanta[cl->priority] -= cl->weight;
10848c2ecf20Sopenharmony_ci	cbq_normalize_quanta(q, cl->priority);
10858c2ecf20Sopenharmony_ci}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic void cbq_addprio(struct cbq_sched_data *q, struct cbq_class *cl)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	q->nclasses[cl->priority]++;
10908c2ecf20Sopenharmony_ci	q->quanta[cl->priority] += cl->weight;
10918c2ecf20Sopenharmony_ci	cbq_normalize_quanta(q, cl->priority);
10928c2ecf20Sopenharmony_ci}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_cistatic int cbq_set_wrr(struct cbq_class *cl, struct tc_cbq_wrropt *wrr)
10958c2ecf20Sopenharmony_ci{
10968c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (wrr->allot)
10998c2ecf20Sopenharmony_ci		cl->allot = wrr->allot;
11008c2ecf20Sopenharmony_ci	if (wrr->weight)
11018c2ecf20Sopenharmony_ci		cl->weight = wrr->weight;
11028c2ecf20Sopenharmony_ci	if (wrr->priority) {
11038c2ecf20Sopenharmony_ci		cl->priority = wrr->priority - 1;
11048c2ecf20Sopenharmony_ci		cl->cpriority = cl->priority;
11058c2ecf20Sopenharmony_ci		if (cl->priority >= cl->priority2)
11068c2ecf20Sopenharmony_ci			cl->priority2 = TC_CBQ_MAXPRIO - 1;
11078c2ecf20Sopenharmony_ci	}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	cbq_addprio(q, cl);
11108c2ecf20Sopenharmony_ci	return 0;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic int cbq_set_fopt(struct cbq_class *cl, struct tc_cbq_fopt *fopt)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	cbq_change_defmap(cl, fopt->split, fopt->defmap, fopt->defchange);
11168c2ecf20Sopenharmony_ci	return 0;
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_cistatic const struct nla_policy cbq_policy[TCA_CBQ_MAX + 1] = {
11208c2ecf20Sopenharmony_ci	[TCA_CBQ_LSSOPT]	= { .len = sizeof(struct tc_cbq_lssopt) },
11218c2ecf20Sopenharmony_ci	[TCA_CBQ_WRROPT]	= { .len = sizeof(struct tc_cbq_wrropt) },
11228c2ecf20Sopenharmony_ci	[TCA_CBQ_FOPT]		= { .len = sizeof(struct tc_cbq_fopt) },
11238c2ecf20Sopenharmony_ci	[TCA_CBQ_OVL_STRATEGY]	= { .len = sizeof(struct tc_cbq_ovl) },
11248c2ecf20Sopenharmony_ci	[TCA_CBQ_RATE]		= { .len = sizeof(struct tc_ratespec) },
11258c2ecf20Sopenharmony_ci	[TCA_CBQ_RTAB]		= { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
11268c2ecf20Sopenharmony_ci	[TCA_CBQ_POLICE]	= { .len = sizeof(struct tc_cbq_police) },
11278c2ecf20Sopenharmony_ci};
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic int cbq_opt_parse(struct nlattr *tb[TCA_CBQ_MAX + 1],
11308c2ecf20Sopenharmony_ci			 struct nlattr *opt,
11318c2ecf20Sopenharmony_ci			 struct netlink_ext_ack *extack)
11328c2ecf20Sopenharmony_ci{
11338c2ecf20Sopenharmony_ci	int err;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (!opt) {
11368c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "CBQ options are required for this operation");
11378c2ecf20Sopenharmony_ci		return -EINVAL;
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	err = nla_parse_nested_deprecated(tb, TCA_CBQ_MAX, opt,
11418c2ecf20Sopenharmony_ci					  cbq_policy, extack);
11428c2ecf20Sopenharmony_ci	if (err < 0)
11438c2ecf20Sopenharmony_ci		return err;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	if (tb[TCA_CBQ_WRROPT]) {
11468c2ecf20Sopenharmony_ci		const struct tc_cbq_wrropt *wrr = nla_data(tb[TCA_CBQ_WRROPT]);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci		if (wrr->priority > TC_CBQ_MAXPRIO) {
11498c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack, "priority is bigger than TC_CBQ_MAXPRIO");
11508c2ecf20Sopenharmony_ci			err = -EINVAL;
11518c2ecf20Sopenharmony_ci		}
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci	return err;
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic int cbq_init(struct Qdisc *sch, struct nlattr *opt,
11578c2ecf20Sopenharmony_ci		    struct netlink_ext_ack *extack)
11588c2ecf20Sopenharmony_ci{
11598c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
11608c2ecf20Sopenharmony_ci	struct nlattr *tb[TCA_CBQ_MAX + 1];
11618c2ecf20Sopenharmony_ci	struct tc_ratespec *r;
11628c2ecf20Sopenharmony_ci	int err;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	qdisc_watchdog_init(&q->watchdog, sch);
11658c2ecf20Sopenharmony_ci	hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
11668c2ecf20Sopenharmony_ci	q->delay_timer.function = cbq_undelay;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	err = cbq_opt_parse(tb, opt, extack);
11698c2ecf20Sopenharmony_ci	if (err < 0)
11708c2ecf20Sopenharmony_ci		return err;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	if (!tb[TCA_CBQ_RTAB] || !tb[TCA_CBQ_RATE]) {
11738c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Rate specification missing or incomplete");
11748c2ecf20Sopenharmony_ci		return -EINVAL;
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	r = nla_data(tb[TCA_CBQ_RATE]);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB], extack);
11808c2ecf20Sopenharmony_ci	if (!q->link.R_tab)
11818c2ecf20Sopenharmony_ci		return -EINVAL;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	err = tcf_block_get(&q->link.block, &q->link.filter_list, sch, extack);
11848c2ecf20Sopenharmony_ci	if (err)
11858c2ecf20Sopenharmony_ci		goto put_rtab;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	err = qdisc_class_hash_init(&q->clhash);
11888c2ecf20Sopenharmony_ci	if (err < 0)
11898c2ecf20Sopenharmony_ci		goto put_block;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	q->link.sibling = &q->link;
11928c2ecf20Sopenharmony_ci	q->link.common.classid = sch->handle;
11938c2ecf20Sopenharmony_ci	q->link.qdisc = sch;
11948c2ecf20Sopenharmony_ci	q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
11958c2ecf20Sopenharmony_ci				      sch->handle, NULL);
11968c2ecf20Sopenharmony_ci	if (!q->link.q)
11978c2ecf20Sopenharmony_ci		q->link.q = &noop_qdisc;
11988c2ecf20Sopenharmony_ci	else
11998c2ecf20Sopenharmony_ci		qdisc_hash_add(q->link.q, true);
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	q->link.priority = TC_CBQ_MAXPRIO - 1;
12028c2ecf20Sopenharmony_ci	q->link.priority2 = TC_CBQ_MAXPRIO - 1;
12038c2ecf20Sopenharmony_ci	q->link.cpriority = TC_CBQ_MAXPRIO - 1;
12048c2ecf20Sopenharmony_ci	q->link.allot = psched_mtu(qdisc_dev(sch));
12058c2ecf20Sopenharmony_ci	q->link.quantum = q->link.allot;
12068c2ecf20Sopenharmony_ci	q->link.weight = q->link.R_tab->rate.rate;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	q->link.ewma_log = TC_CBQ_DEF_EWMA;
12098c2ecf20Sopenharmony_ci	q->link.avpkt = q->link.allot/2;
12108c2ecf20Sopenharmony_ci	q->link.minidle = -0x7FFFFFFF;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	q->toplevel = TC_CBQ_MAXLEVEL;
12138c2ecf20Sopenharmony_ci	q->now = psched_get_time();
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	cbq_link_class(&q->link);
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	if (tb[TCA_CBQ_LSSOPT])
12188c2ecf20Sopenharmony_ci		cbq_set_lss(&q->link, nla_data(tb[TCA_CBQ_LSSOPT]));
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	cbq_addprio(q, &q->link);
12218c2ecf20Sopenharmony_ci	return 0;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ciput_block:
12248c2ecf20Sopenharmony_ci	tcf_block_put(q->link.block);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ciput_rtab:
12278c2ecf20Sopenharmony_ci	qdisc_put_rtab(q->link.R_tab);
12288c2ecf20Sopenharmony_ci	return err;
12298c2ecf20Sopenharmony_ci}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_cistatic int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
12328c2ecf20Sopenharmony_ci{
12338c2ecf20Sopenharmony_ci	unsigned char *b = skb_tail_pointer(skb);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate))
12368c2ecf20Sopenharmony_ci		goto nla_put_failure;
12378c2ecf20Sopenharmony_ci	return skb->len;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_cinla_put_failure:
12408c2ecf20Sopenharmony_ci	nlmsg_trim(skb, b);
12418c2ecf20Sopenharmony_ci	return -1;
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cistatic int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl)
12458c2ecf20Sopenharmony_ci{
12468c2ecf20Sopenharmony_ci	unsigned char *b = skb_tail_pointer(skb);
12478c2ecf20Sopenharmony_ci	struct tc_cbq_lssopt opt;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	opt.flags = 0;
12508c2ecf20Sopenharmony_ci	if (cl->borrow == NULL)
12518c2ecf20Sopenharmony_ci		opt.flags |= TCF_CBQ_LSS_BOUNDED;
12528c2ecf20Sopenharmony_ci	if (cl->share == NULL)
12538c2ecf20Sopenharmony_ci		opt.flags |= TCF_CBQ_LSS_ISOLATED;
12548c2ecf20Sopenharmony_ci	opt.ewma_log = cl->ewma_log;
12558c2ecf20Sopenharmony_ci	opt.level = cl->level;
12568c2ecf20Sopenharmony_ci	opt.avpkt = cl->avpkt;
12578c2ecf20Sopenharmony_ci	opt.maxidle = cl->maxidle;
12588c2ecf20Sopenharmony_ci	opt.minidle = (u32)(-cl->minidle);
12598c2ecf20Sopenharmony_ci	opt.offtime = cl->offtime;
12608c2ecf20Sopenharmony_ci	opt.change = ~0;
12618c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_CBQ_LSSOPT, sizeof(opt), &opt))
12628c2ecf20Sopenharmony_ci		goto nla_put_failure;
12638c2ecf20Sopenharmony_ci	return skb->len;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_cinla_put_failure:
12668c2ecf20Sopenharmony_ci	nlmsg_trim(skb, b);
12678c2ecf20Sopenharmony_ci	return -1;
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_cistatic int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	unsigned char *b = skb_tail_pointer(skb);
12738c2ecf20Sopenharmony_ci	struct tc_cbq_wrropt opt;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	memset(&opt, 0, sizeof(opt));
12768c2ecf20Sopenharmony_ci	opt.flags = 0;
12778c2ecf20Sopenharmony_ci	opt.allot = cl->allot;
12788c2ecf20Sopenharmony_ci	opt.priority = cl->priority + 1;
12798c2ecf20Sopenharmony_ci	opt.cpriority = cl->cpriority + 1;
12808c2ecf20Sopenharmony_ci	opt.weight = cl->weight;
12818c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_CBQ_WRROPT, sizeof(opt), &opt))
12828c2ecf20Sopenharmony_ci		goto nla_put_failure;
12838c2ecf20Sopenharmony_ci	return skb->len;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_cinla_put_failure:
12868c2ecf20Sopenharmony_ci	nlmsg_trim(skb, b);
12878c2ecf20Sopenharmony_ci	return -1;
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_cistatic int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	unsigned char *b = skb_tail_pointer(skb);
12938c2ecf20Sopenharmony_ci	struct tc_cbq_fopt opt;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	if (cl->split || cl->defmap) {
12968c2ecf20Sopenharmony_ci		opt.split = cl->split ? cl->split->common.classid : 0;
12978c2ecf20Sopenharmony_ci		opt.defmap = cl->defmap;
12988c2ecf20Sopenharmony_ci		opt.defchange = ~0;
12998c2ecf20Sopenharmony_ci		if (nla_put(skb, TCA_CBQ_FOPT, sizeof(opt), &opt))
13008c2ecf20Sopenharmony_ci			goto nla_put_failure;
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci	return skb->len;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cinla_put_failure:
13058c2ecf20Sopenharmony_ci	nlmsg_trim(skb, b);
13068c2ecf20Sopenharmony_ci	return -1;
13078c2ecf20Sopenharmony_ci}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_cistatic int cbq_dump_attr(struct sk_buff *skb, struct cbq_class *cl)
13108c2ecf20Sopenharmony_ci{
13118c2ecf20Sopenharmony_ci	if (cbq_dump_lss(skb, cl) < 0 ||
13128c2ecf20Sopenharmony_ci	    cbq_dump_rate(skb, cl) < 0 ||
13138c2ecf20Sopenharmony_ci	    cbq_dump_wrr(skb, cl) < 0 ||
13148c2ecf20Sopenharmony_ci	    cbq_dump_fopt(skb, cl) < 0)
13158c2ecf20Sopenharmony_ci		return -1;
13168c2ecf20Sopenharmony_ci	return 0;
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_cistatic int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
13208c2ecf20Sopenharmony_ci{
13218c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
13228c2ecf20Sopenharmony_ci	struct nlattr *nest;
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
13258c2ecf20Sopenharmony_ci	if (nest == NULL)
13268c2ecf20Sopenharmony_ci		goto nla_put_failure;
13278c2ecf20Sopenharmony_ci	if (cbq_dump_attr(skb, &q->link) < 0)
13288c2ecf20Sopenharmony_ci		goto nla_put_failure;
13298c2ecf20Sopenharmony_ci	return nla_nest_end(skb, nest);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cinla_put_failure:
13328c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, nest);
13338c2ecf20Sopenharmony_ci	return -1;
13348c2ecf20Sopenharmony_ci}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_cistatic int
13378c2ecf20Sopenharmony_cicbq_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	q->link.xstats.avgidle = q->link.avgidle;
13428c2ecf20Sopenharmony_ci	return gnet_stats_copy_app(d, &q->link.xstats, sizeof(q->link.xstats));
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_cistatic int
13468c2ecf20Sopenharmony_cicbq_dump_class(struct Qdisc *sch, unsigned long arg,
13478c2ecf20Sopenharmony_ci	       struct sk_buff *skb, struct tcmsg *tcm)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
13508c2ecf20Sopenharmony_ci	struct nlattr *nest;
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	if (cl->tparent)
13538c2ecf20Sopenharmony_ci		tcm->tcm_parent = cl->tparent->common.classid;
13548c2ecf20Sopenharmony_ci	else
13558c2ecf20Sopenharmony_ci		tcm->tcm_parent = TC_H_ROOT;
13568c2ecf20Sopenharmony_ci	tcm->tcm_handle = cl->common.classid;
13578c2ecf20Sopenharmony_ci	tcm->tcm_info = cl->q->handle;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
13608c2ecf20Sopenharmony_ci	if (nest == NULL)
13618c2ecf20Sopenharmony_ci		goto nla_put_failure;
13628c2ecf20Sopenharmony_ci	if (cbq_dump_attr(skb, cl) < 0)
13638c2ecf20Sopenharmony_ci		goto nla_put_failure;
13648c2ecf20Sopenharmony_ci	return nla_nest_end(skb, nest);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cinla_put_failure:
13678c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, nest);
13688c2ecf20Sopenharmony_ci	return -1;
13698c2ecf20Sopenharmony_ci}
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_cistatic int
13728c2ecf20Sopenharmony_cicbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
13738c2ecf20Sopenharmony_ci	struct gnet_dump *d)
13748c2ecf20Sopenharmony_ci{
13758c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
13768c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
13778c2ecf20Sopenharmony_ci	__u32 qlen;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	cl->xstats.avgidle = cl->avgidle;
13808c2ecf20Sopenharmony_ci	cl->xstats.undertime = 0;
13818c2ecf20Sopenharmony_ci	qdisc_qstats_qlen_backlog(cl->q, &qlen, &cl->qstats.backlog);
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	if (cl->undertime != PSCHED_PASTPERFECT)
13848c2ecf20Sopenharmony_ci		cl->xstats.undertime = cl->undertime - q->now;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
13878c2ecf20Sopenharmony_ci				  d, NULL, &cl->bstats) < 0 ||
13888c2ecf20Sopenharmony_ci	    gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
13898c2ecf20Sopenharmony_ci	    gnet_stats_copy_queue(d, NULL, &cl->qstats, qlen) < 0)
13908c2ecf20Sopenharmony_ci		return -1;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	return gnet_stats_copy_app(d, &cl->xstats, sizeof(cl->xstats));
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_cistatic int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
13968c2ecf20Sopenharmony_ci		     struct Qdisc **old, struct netlink_ext_ack *extack)
13978c2ecf20Sopenharmony_ci{
13988c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	if (new == NULL) {
14018c2ecf20Sopenharmony_ci		new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
14028c2ecf20Sopenharmony_ci					cl->common.classid, extack);
14038c2ecf20Sopenharmony_ci		if (new == NULL)
14048c2ecf20Sopenharmony_ci			return -ENOBUFS;
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	*old = qdisc_replace(sch, new, &cl->q);
14088c2ecf20Sopenharmony_ci	return 0;
14098c2ecf20Sopenharmony_ci}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_cistatic struct Qdisc *cbq_leaf(struct Qdisc *sch, unsigned long arg)
14128c2ecf20Sopenharmony_ci{
14138c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	return cl->q;
14168c2ecf20Sopenharmony_ci}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_cistatic void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	cbq_deactivate_class(cl);
14238c2ecf20Sopenharmony_ci}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_cistatic unsigned long cbq_find(struct Qdisc *sch, u32 classid)
14268c2ecf20Sopenharmony_ci{
14278c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	return (unsigned long)cbq_class_lookup(q, classid);
14308c2ecf20Sopenharmony_ci}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_cistatic void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
14338c2ecf20Sopenharmony_ci{
14348c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	WARN_ON(cl->filters);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	tcf_block_put(cl->block);
14398c2ecf20Sopenharmony_ci	qdisc_put(cl->q);
14408c2ecf20Sopenharmony_ci	qdisc_put_rtab(cl->R_tab);
14418c2ecf20Sopenharmony_ci	gen_kill_estimator(&cl->rate_est);
14428c2ecf20Sopenharmony_ci	if (cl != &q->link)
14438c2ecf20Sopenharmony_ci		kfree(cl);
14448c2ecf20Sopenharmony_ci}
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_cistatic void cbq_destroy(struct Qdisc *sch)
14478c2ecf20Sopenharmony_ci{
14488c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
14498c2ecf20Sopenharmony_ci	struct hlist_node *next;
14508c2ecf20Sopenharmony_ci	struct cbq_class *cl;
14518c2ecf20Sopenharmony_ci	unsigned int h;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
14548c2ecf20Sopenharmony_ci	q->rx_class = NULL;
14558c2ecf20Sopenharmony_ci#endif
14568c2ecf20Sopenharmony_ci	/*
14578c2ecf20Sopenharmony_ci	 * Filters must be destroyed first because we don't destroy the
14588c2ecf20Sopenharmony_ci	 * classes from root to leafs which means that filters can still
14598c2ecf20Sopenharmony_ci	 * be bound to classes which have been destroyed already. --TGR '04
14608c2ecf20Sopenharmony_ci	 */
14618c2ecf20Sopenharmony_ci	for (h = 0; h < q->clhash.hashsize; h++) {
14628c2ecf20Sopenharmony_ci		hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
14638c2ecf20Sopenharmony_ci			tcf_block_put(cl->block);
14648c2ecf20Sopenharmony_ci			cl->block = NULL;
14658c2ecf20Sopenharmony_ci		}
14668c2ecf20Sopenharmony_ci	}
14678c2ecf20Sopenharmony_ci	for (h = 0; h < q->clhash.hashsize; h++) {
14688c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
14698c2ecf20Sopenharmony_ci					  common.hnode)
14708c2ecf20Sopenharmony_ci			cbq_destroy_class(sch, cl);
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci	qdisc_class_hash_destroy(&q->clhash);
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_cistatic int
14768c2ecf20Sopenharmony_cicbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **tca,
14778c2ecf20Sopenharmony_ci		 unsigned long *arg, struct netlink_ext_ack *extack)
14788c2ecf20Sopenharmony_ci{
14798c2ecf20Sopenharmony_ci	int err;
14808c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
14818c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)*arg;
14828c2ecf20Sopenharmony_ci	struct nlattr *opt = tca[TCA_OPTIONS];
14838c2ecf20Sopenharmony_ci	struct nlattr *tb[TCA_CBQ_MAX + 1];
14848c2ecf20Sopenharmony_ci	struct cbq_class *parent;
14858c2ecf20Sopenharmony_ci	struct qdisc_rate_table *rtab = NULL;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	err = cbq_opt_parse(tb, opt, extack);
14888c2ecf20Sopenharmony_ci	if (err < 0)
14898c2ecf20Sopenharmony_ci		return err;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	if (tb[TCA_CBQ_OVL_STRATEGY] || tb[TCA_CBQ_POLICE]) {
14928c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Neither overlimit strategy nor policing attributes can be used for changing class params");
14938c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	if (cl) {
14978c2ecf20Sopenharmony_ci		/* Check parent */
14988c2ecf20Sopenharmony_ci		if (parentid) {
14998c2ecf20Sopenharmony_ci			if (cl->tparent &&
15008c2ecf20Sopenharmony_ci			    cl->tparent->common.classid != parentid) {
15018c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG(extack, "Invalid parent id");
15028c2ecf20Sopenharmony_ci				return -EINVAL;
15038c2ecf20Sopenharmony_ci			}
15048c2ecf20Sopenharmony_ci			if (!cl->tparent && parentid != TC_H_ROOT) {
15058c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG(extack, "Parent must be root");
15068c2ecf20Sopenharmony_ci				return -EINVAL;
15078c2ecf20Sopenharmony_ci			}
15088c2ecf20Sopenharmony_ci		}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci		if (tb[TCA_CBQ_RATE]) {
15118c2ecf20Sopenharmony_ci			rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]),
15128c2ecf20Sopenharmony_ci					      tb[TCA_CBQ_RTAB], extack);
15138c2ecf20Sopenharmony_ci			if (rtab == NULL)
15148c2ecf20Sopenharmony_ci				return -EINVAL;
15158c2ecf20Sopenharmony_ci		}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci		if (tca[TCA_RATE]) {
15188c2ecf20Sopenharmony_ci			err = gen_replace_estimator(&cl->bstats, NULL,
15198c2ecf20Sopenharmony_ci						    &cl->rate_est,
15208c2ecf20Sopenharmony_ci						    NULL,
15218c2ecf20Sopenharmony_ci						    qdisc_root_sleeping_running(sch),
15228c2ecf20Sopenharmony_ci						    tca[TCA_RATE]);
15238c2ecf20Sopenharmony_ci			if (err) {
15248c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG(extack, "Failed to replace specified rate estimator");
15258c2ecf20Sopenharmony_ci				qdisc_put_rtab(rtab);
15268c2ecf20Sopenharmony_ci				return err;
15278c2ecf20Sopenharmony_ci			}
15288c2ecf20Sopenharmony_ci		}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci		/* Change class parameters */
15318c2ecf20Sopenharmony_ci		sch_tree_lock(sch);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci		if (cl->next_alive != NULL)
15348c2ecf20Sopenharmony_ci			cbq_deactivate_class(cl);
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci		if (rtab) {
15378c2ecf20Sopenharmony_ci			qdisc_put_rtab(cl->R_tab);
15388c2ecf20Sopenharmony_ci			cl->R_tab = rtab;
15398c2ecf20Sopenharmony_ci		}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci		if (tb[TCA_CBQ_LSSOPT])
15428c2ecf20Sopenharmony_ci			cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT]));
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci		if (tb[TCA_CBQ_WRROPT]) {
15458c2ecf20Sopenharmony_ci			cbq_rmprio(q, cl);
15468c2ecf20Sopenharmony_ci			cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT]));
15478c2ecf20Sopenharmony_ci		}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci		if (tb[TCA_CBQ_FOPT])
15508c2ecf20Sopenharmony_ci			cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT]));
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci		if (cl->q->q.qlen)
15538c2ecf20Sopenharmony_ci			cbq_activate_class(cl);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci		sch_tree_unlock(sch);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci		return 0;
15588c2ecf20Sopenharmony_ci	}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	if (parentid == TC_H_ROOT)
15618c2ecf20Sopenharmony_ci		return -EINVAL;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT]) {
15648c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "One of the following attributes MUST be specified: WRR, rate or link sharing");
15658c2ecf20Sopenharmony_ci		return -EINVAL;
15668c2ecf20Sopenharmony_ci	}
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB],
15698c2ecf20Sopenharmony_ci			      extack);
15708c2ecf20Sopenharmony_ci	if (rtab == NULL)
15718c2ecf20Sopenharmony_ci		return -EINVAL;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (classid) {
15748c2ecf20Sopenharmony_ci		err = -EINVAL;
15758c2ecf20Sopenharmony_ci		if (TC_H_MAJ(classid ^ sch->handle) ||
15768c2ecf20Sopenharmony_ci		    cbq_class_lookup(q, classid)) {
15778c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack, "Specified class not found");
15788c2ecf20Sopenharmony_ci			goto failure;
15798c2ecf20Sopenharmony_ci		}
15808c2ecf20Sopenharmony_ci	} else {
15818c2ecf20Sopenharmony_ci		int i;
15828c2ecf20Sopenharmony_ci		classid = TC_H_MAKE(sch->handle, 0x8000);
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci		for (i = 0; i < 0x8000; i++) {
15858c2ecf20Sopenharmony_ci			if (++q->hgenerator >= 0x8000)
15868c2ecf20Sopenharmony_ci				q->hgenerator = 1;
15878c2ecf20Sopenharmony_ci			if (cbq_class_lookup(q, classid|q->hgenerator) == NULL)
15888c2ecf20Sopenharmony_ci				break;
15898c2ecf20Sopenharmony_ci		}
15908c2ecf20Sopenharmony_ci		err = -ENOSR;
15918c2ecf20Sopenharmony_ci		if (i >= 0x8000) {
15928c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack, "Unable to generate classid");
15938c2ecf20Sopenharmony_ci			goto failure;
15948c2ecf20Sopenharmony_ci		}
15958c2ecf20Sopenharmony_ci		classid = classid|q->hgenerator;
15968c2ecf20Sopenharmony_ci	}
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	parent = &q->link;
15998c2ecf20Sopenharmony_ci	if (parentid) {
16008c2ecf20Sopenharmony_ci		parent = cbq_class_lookup(q, parentid);
16018c2ecf20Sopenharmony_ci		err = -EINVAL;
16028c2ecf20Sopenharmony_ci		if (!parent) {
16038c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack, "Failed to find parentid");
16048c2ecf20Sopenharmony_ci			goto failure;
16058c2ecf20Sopenharmony_ci		}
16068c2ecf20Sopenharmony_ci	}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	err = -ENOBUFS;
16098c2ecf20Sopenharmony_ci	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
16108c2ecf20Sopenharmony_ci	if (cl == NULL)
16118c2ecf20Sopenharmony_ci		goto failure;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
16148c2ecf20Sopenharmony_ci	if (err) {
16158c2ecf20Sopenharmony_ci		kfree(cl);
16168c2ecf20Sopenharmony_ci		goto failure;
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	if (tca[TCA_RATE]) {
16208c2ecf20Sopenharmony_ci		err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
16218c2ecf20Sopenharmony_ci					NULL,
16228c2ecf20Sopenharmony_ci					qdisc_root_sleeping_running(sch),
16238c2ecf20Sopenharmony_ci					tca[TCA_RATE]);
16248c2ecf20Sopenharmony_ci		if (err) {
16258c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack, "Couldn't create new estimator");
16268c2ecf20Sopenharmony_ci			tcf_block_put(cl->block);
16278c2ecf20Sopenharmony_ci			kfree(cl);
16288c2ecf20Sopenharmony_ci			goto failure;
16298c2ecf20Sopenharmony_ci		}
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	cl->R_tab = rtab;
16338c2ecf20Sopenharmony_ci	rtab = NULL;
16348c2ecf20Sopenharmony_ci	cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid,
16358c2ecf20Sopenharmony_ci				  NULL);
16368c2ecf20Sopenharmony_ci	if (!cl->q)
16378c2ecf20Sopenharmony_ci		cl->q = &noop_qdisc;
16388c2ecf20Sopenharmony_ci	else
16398c2ecf20Sopenharmony_ci		qdisc_hash_add(cl->q, true);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	cl->common.classid = classid;
16428c2ecf20Sopenharmony_ci	cl->tparent = parent;
16438c2ecf20Sopenharmony_ci	cl->qdisc = sch;
16448c2ecf20Sopenharmony_ci	cl->allot = parent->allot;
16458c2ecf20Sopenharmony_ci	cl->quantum = cl->allot;
16468c2ecf20Sopenharmony_ci	cl->weight = cl->R_tab->rate.rate;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	sch_tree_lock(sch);
16498c2ecf20Sopenharmony_ci	cbq_link_class(cl);
16508c2ecf20Sopenharmony_ci	cl->borrow = cl->tparent;
16518c2ecf20Sopenharmony_ci	if (cl->tparent != &q->link)
16528c2ecf20Sopenharmony_ci		cl->share = cl->tparent;
16538c2ecf20Sopenharmony_ci	cbq_adjust_levels(parent);
16548c2ecf20Sopenharmony_ci	cl->minidle = -0x7FFFFFFF;
16558c2ecf20Sopenharmony_ci	cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT]));
16568c2ecf20Sopenharmony_ci	cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT]));
16578c2ecf20Sopenharmony_ci	if (cl->ewma_log == 0)
16588c2ecf20Sopenharmony_ci		cl->ewma_log = q->link.ewma_log;
16598c2ecf20Sopenharmony_ci	if (cl->maxidle == 0)
16608c2ecf20Sopenharmony_ci		cl->maxidle = q->link.maxidle;
16618c2ecf20Sopenharmony_ci	if (cl->avpkt == 0)
16628c2ecf20Sopenharmony_ci		cl->avpkt = q->link.avpkt;
16638c2ecf20Sopenharmony_ci	if (tb[TCA_CBQ_FOPT])
16648c2ecf20Sopenharmony_ci		cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT]));
16658c2ecf20Sopenharmony_ci	sch_tree_unlock(sch);
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	qdisc_class_hash_grow(sch, &q->clhash);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	*arg = (unsigned long)cl;
16708c2ecf20Sopenharmony_ci	return 0;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_cifailure:
16738c2ecf20Sopenharmony_ci	qdisc_put_rtab(rtab);
16748c2ecf20Sopenharmony_ci	return err;
16758c2ecf20Sopenharmony_ci}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_cistatic int cbq_delete(struct Qdisc *sch, unsigned long arg)
16788c2ecf20Sopenharmony_ci{
16798c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
16808c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	if (cl->filters || cl->children || cl == &q->link)
16838c2ecf20Sopenharmony_ci		return -EBUSY;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	sch_tree_lock(sch);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	qdisc_purge_queue(cl->q);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	if (cl->next_alive)
16908c2ecf20Sopenharmony_ci		cbq_deactivate_class(cl);
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	if (q->tx_borrowed == cl)
16938c2ecf20Sopenharmony_ci		q->tx_borrowed = q->tx_class;
16948c2ecf20Sopenharmony_ci	if (q->tx_class == cl) {
16958c2ecf20Sopenharmony_ci		q->tx_class = NULL;
16968c2ecf20Sopenharmony_ci		q->tx_borrowed = NULL;
16978c2ecf20Sopenharmony_ci	}
16988c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
16998c2ecf20Sopenharmony_ci	if (q->rx_class == cl)
17008c2ecf20Sopenharmony_ci		q->rx_class = NULL;
17018c2ecf20Sopenharmony_ci#endif
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	cbq_unlink_class(cl);
17048c2ecf20Sopenharmony_ci	cbq_adjust_levels(cl->tparent);
17058c2ecf20Sopenharmony_ci	cl->defmap = 0;
17068c2ecf20Sopenharmony_ci	cbq_sync_defmap(cl);
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	cbq_rmprio(q, cl);
17098c2ecf20Sopenharmony_ci	sch_tree_unlock(sch);
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	cbq_destroy_class(sch, cl);
17128c2ecf20Sopenharmony_ci	return 0;
17138c2ecf20Sopenharmony_ci}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_cistatic struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg,
17168c2ecf20Sopenharmony_ci				       struct netlink_ext_ack *extack)
17178c2ecf20Sopenharmony_ci{
17188c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
17198c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	if (cl == NULL)
17228c2ecf20Sopenharmony_ci		cl = &q->link;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	return cl->block;
17258c2ecf20Sopenharmony_ci}
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_cistatic unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,
17288c2ecf20Sopenharmony_ci				     u32 classid)
17298c2ecf20Sopenharmony_ci{
17308c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
17318c2ecf20Sopenharmony_ci	struct cbq_class *p = (struct cbq_class *)parent;
17328c2ecf20Sopenharmony_ci	struct cbq_class *cl = cbq_class_lookup(q, classid);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	if (cl) {
17358c2ecf20Sopenharmony_ci		if (p && p->level <= cl->level)
17368c2ecf20Sopenharmony_ci			return 0;
17378c2ecf20Sopenharmony_ci		cl->filters++;
17388c2ecf20Sopenharmony_ci		return (unsigned long)cl;
17398c2ecf20Sopenharmony_ci	}
17408c2ecf20Sopenharmony_ci	return 0;
17418c2ecf20Sopenharmony_ci}
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_cistatic void cbq_unbind_filter(struct Qdisc *sch, unsigned long arg)
17448c2ecf20Sopenharmony_ci{
17458c2ecf20Sopenharmony_ci	struct cbq_class *cl = (struct cbq_class *)arg;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	cl->filters--;
17488c2ecf20Sopenharmony_ci}
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_cistatic void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
17518c2ecf20Sopenharmony_ci{
17528c2ecf20Sopenharmony_ci	struct cbq_sched_data *q = qdisc_priv(sch);
17538c2ecf20Sopenharmony_ci	struct cbq_class *cl;
17548c2ecf20Sopenharmony_ci	unsigned int h;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	if (arg->stop)
17578c2ecf20Sopenharmony_ci		return;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	for (h = 0; h < q->clhash.hashsize; h++) {
17608c2ecf20Sopenharmony_ci		hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
17618c2ecf20Sopenharmony_ci			if (arg->count < arg->skip) {
17628c2ecf20Sopenharmony_ci				arg->count++;
17638c2ecf20Sopenharmony_ci				continue;
17648c2ecf20Sopenharmony_ci			}
17658c2ecf20Sopenharmony_ci			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
17668c2ecf20Sopenharmony_ci				arg->stop = 1;
17678c2ecf20Sopenharmony_ci				return;
17688c2ecf20Sopenharmony_ci			}
17698c2ecf20Sopenharmony_ci			arg->count++;
17708c2ecf20Sopenharmony_ci		}
17718c2ecf20Sopenharmony_ci	}
17728c2ecf20Sopenharmony_ci}
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_cistatic const struct Qdisc_class_ops cbq_class_ops = {
17758c2ecf20Sopenharmony_ci	.graft		=	cbq_graft,
17768c2ecf20Sopenharmony_ci	.leaf		=	cbq_leaf,
17778c2ecf20Sopenharmony_ci	.qlen_notify	=	cbq_qlen_notify,
17788c2ecf20Sopenharmony_ci	.find		=	cbq_find,
17798c2ecf20Sopenharmony_ci	.change		=	cbq_change_class,
17808c2ecf20Sopenharmony_ci	.delete		=	cbq_delete,
17818c2ecf20Sopenharmony_ci	.walk		=	cbq_walk,
17828c2ecf20Sopenharmony_ci	.tcf_block	=	cbq_tcf_block,
17838c2ecf20Sopenharmony_ci	.bind_tcf	=	cbq_bind_filter,
17848c2ecf20Sopenharmony_ci	.unbind_tcf	=	cbq_unbind_filter,
17858c2ecf20Sopenharmony_ci	.dump		=	cbq_dump_class,
17868c2ecf20Sopenharmony_ci	.dump_stats	=	cbq_dump_class_stats,
17878c2ecf20Sopenharmony_ci};
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_cistatic struct Qdisc_ops cbq_qdisc_ops __read_mostly = {
17908c2ecf20Sopenharmony_ci	.next		=	NULL,
17918c2ecf20Sopenharmony_ci	.cl_ops		=	&cbq_class_ops,
17928c2ecf20Sopenharmony_ci	.id		=	"cbq",
17938c2ecf20Sopenharmony_ci	.priv_size	=	sizeof(struct cbq_sched_data),
17948c2ecf20Sopenharmony_ci	.enqueue	=	cbq_enqueue,
17958c2ecf20Sopenharmony_ci	.dequeue	=	cbq_dequeue,
17968c2ecf20Sopenharmony_ci	.peek		=	qdisc_peek_dequeued,
17978c2ecf20Sopenharmony_ci	.init		=	cbq_init,
17988c2ecf20Sopenharmony_ci	.reset		=	cbq_reset,
17998c2ecf20Sopenharmony_ci	.destroy	=	cbq_destroy,
18008c2ecf20Sopenharmony_ci	.change		=	NULL,
18018c2ecf20Sopenharmony_ci	.dump		=	cbq_dump,
18028c2ecf20Sopenharmony_ci	.dump_stats	=	cbq_dump_stats,
18038c2ecf20Sopenharmony_ci	.owner		=	THIS_MODULE,
18048c2ecf20Sopenharmony_ci};
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_cistatic int __init cbq_module_init(void)
18078c2ecf20Sopenharmony_ci{
18088c2ecf20Sopenharmony_ci	return register_qdisc(&cbq_qdisc_ops);
18098c2ecf20Sopenharmony_ci}
18108c2ecf20Sopenharmony_cistatic void __exit cbq_module_exit(void)
18118c2ecf20Sopenharmony_ci{
18128c2ecf20Sopenharmony_ci	unregister_qdisc(&cbq_qdisc_ops);
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_cimodule_init(cbq_module_init)
18158c2ecf20Sopenharmony_cimodule_exit(cbq_module_exit)
18168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1817