18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2003 Patrick McHardy, <kaber@trash.net> 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 58c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License 68c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version 2 78c2ecf20Sopenharmony_ci * of the License, or (at your option) any later version. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * 2003-10-17 - Ported from altq 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and distribute this software and 158c2ecf20Sopenharmony_ci * its documentation is hereby granted (including for commercial or 168c2ecf20Sopenharmony_ci * for-profit use), provided that both the copyright notice and this 178c2ecf20Sopenharmony_ci * permission notice appear in all copies of the software, derivative 188c2ecf20Sopenharmony_ci * works, or modified versions, and any portions thereof. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF 218c2ecf20Sopenharmony_ci * WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS 228c2ecf20Sopenharmony_ci * SOFTWARE IN ITS ``AS IS'' CONDITION, AND ANY EXPRESS OR IMPLIED 238c2ecf20Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 248c2ecf20Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 258c2ecf20Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 268c2ecf20Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 278c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 288c2ecf20Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 298c2ecf20Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 308c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 318c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 328c2ecf20Sopenharmony_ci * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 338c2ecf20Sopenharmony_ci * DAMAGE. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Carnegie Mellon encourages (but does not require) users of this 368c2ecf20Sopenharmony_ci * software to return any improvements or extensions that they make, 378c2ecf20Sopenharmony_ci * and to grant Carnegie Mellon the rights to redistribute these 388c2ecf20Sopenharmony_ci * changes without encumbrance. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * H-FSC is described in Proceedings of SIGCOMM'97, 428c2ecf20Sopenharmony_ci * "A Hierarchical Fair Service Curve Algorithm for Link-Sharing, 438c2ecf20Sopenharmony_ci * Real-Time and Priority Service" 448c2ecf20Sopenharmony_ci * by Ion Stoica, Hui Zhang, and T. S. Eugene Ng. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Oleg Cherevko <olwi@aq.ml.com.ua> added the upperlimit for link-sharing. 478c2ecf20Sopenharmony_ci * when a class has an upperlimit, the fit-time is computed from the 488c2ecf20Sopenharmony_ci * upperlimit service curve. the link-sharing scheduler does not schedule 498c2ecf20Sopenharmony_ci * a class whose fit-time exceeds the current time. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include <linux/kernel.h> 538c2ecf20Sopenharmony_ci#include <linux/module.h> 548c2ecf20Sopenharmony_ci#include <linux/types.h> 558c2ecf20Sopenharmony_ci#include <linux/errno.h> 568c2ecf20Sopenharmony_ci#include <linux/compiler.h> 578c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 588c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 598c2ecf20Sopenharmony_ci#include <linux/string.h> 608c2ecf20Sopenharmony_ci#include <linux/slab.h> 618c2ecf20Sopenharmony_ci#include <linux/list.h> 628c2ecf20Sopenharmony_ci#include <linux/rbtree.h> 638c2ecf20Sopenharmony_ci#include <linux/init.h> 648c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 658c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h> 668c2ecf20Sopenharmony_ci#include <net/netlink.h> 678c2ecf20Sopenharmony_ci#include <net/pkt_sched.h> 688c2ecf20Sopenharmony_ci#include <net/pkt_cls.h> 698c2ecf20Sopenharmony_ci#include <asm/div64.h> 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * kernel internal service curve representation: 738c2ecf20Sopenharmony_ci * coordinates are given by 64 bit unsigned integers. 748c2ecf20Sopenharmony_ci * x-axis: unit is clock count. 758c2ecf20Sopenharmony_ci * y-axis: unit is byte. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * The service curve parameters are converted to the internal 788c2ecf20Sopenharmony_ci * representation. The slope values are scaled to avoid overflow. 798c2ecf20Sopenharmony_ci * the inverse slope values as well as the y-projection of the 1st 808c2ecf20Sopenharmony_ci * segment are kept in order to avoid 64-bit divide operations 818c2ecf20Sopenharmony_ci * that are expensive on 32-bit architectures. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct internal_sc { 858c2ecf20Sopenharmony_ci u64 sm1; /* scaled slope of the 1st segment */ 868c2ecf20Sopenharmony_ci u64 ism1; /* scaled inverse-slope of the 1st segment */ 878c2ecf20Sopenharmony_ci u64 dx; /* the x-projection of the 1st segment */ 888c2ecf20Sopenharmony_ci u64 dy; /* the y-projection of the 1st segment */ 898c2ecf20Sopenharmony_ci u64 sm2; /* scaled slope of the 2nd segment */ 908c2ecf20Sopenharmony_ci u64 ism2; /* scaled inverse-slope of the 2nd segment */ 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* runtime service curve */ 948c2ecf20Sopenharmony_cistruct runtime_sc { 958c2ecf20Sopenharmony_ci u64 x; /* current starting position on x-axis */ 968c2ecf20Sopenharmony_ci u64 y; /* current starting position on y-axis */ 978c2ecf20Sopenharmony_ci u64 sm1; /* scaled slope of the 1st segment */ 988c2ecf20Sopenharmony_ci u64 ism1; /* scaled inverse-slope of the 1st segment */ 998c2ecf20Sopenharmony_ci u64 dx; /* the x-projection of the 1st segment */ 1008c2ecf20Sopenharmony_ci u64 dy; /* the y-projection of the 1st segment */ 1018c2ecf20Sopenharmony_ci u64 sm2; /* scaled slope of the 2nd segment */ 1028c2ecf20Sopenharmony_ci u64 ism2; /* scaled inverse-slope of the 2nd segment */ 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cienum hfsc_class_flags { 1068c2ecf20Sopenharmony_ci HFSC_RSC = 0x1, 1078c2ecf20Sopenharmony_ci HFSC_FSC = 0x2, 1088c2ecf20Sopenharmony_ci HFSC_USC = 0x4 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistruct hfsc_class { 1128c2ecf20Sopenharmony_ci struct Qdisc_class_common cl_common; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci struct gnet_stats_basic_packed bstats; 1158c2ecf20Sopenharmony_ci struct gnet_stats_queue qstats; 1168c2ecf20Sopenharmony_ci struct net_rate_estimator __rcu *rate_est; 1178c2ecf20Sopenharmony_ci struct tcf_proto __rcu *filter_list; /* filter list */ 1188c2ecf20Sopenharmony_ci struct tcf_block *block; 1198c2ecf20Sopenharmony_ci unsigned int filter_cnt; /* filter count */ 1208c2ecf20Sopenharmony_ci unsigned int level; /* class level in hierarchy */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci struct hfsc_sched *sched; /* scheduler data */ 1238c2ecf20Sopenharmony_ci struct hfsc_class *cl_parent; /* parent class */ 1248c2ecf20Sopenharmony_ci struct list_head siblings; /* sibling classes */ 1258c2ecf20Sopenharmony_ci struct list_head children; /* child classes */ 1268c2ecf20Sopenharmony_ci struct Qdisc *qdisc; /* leaf qdisc */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci struct rb_node el_node; /* qdisc's eligible tree member */ 1298c2ecf20Sopenharmony_ci struct rb_root vt_tree; /* active children sorted by cl_vt */ 1308c2ecf20Sopenharmony_ci struct rb_node vt_node; /* parent's vt_tree member */ 1318c2ecf20Sopenharmony_ci struct rb_root cf_tree; /* active children sorted by cl_f */ 1328c2ecf20Sopenharmony_ci struct rb_node cf_node; /* parent's cf_heap member */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci u64 cl_total; /* total work in bytes */ 1358c2ecf20Sopenharmony_ci u64 cl_cumul; /* cumulative work in bytes done by 1368c2ecf20Sopenharmony_ci real-time criteria */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci u64 cl_d; /* deadline*/ 1398c2ecf20Sopenharmony_ci u64 cl_e; /* eligible time */ 1408c2ecf20Sopenharmony_ci u64 cl_vt; /* virtual time */ 1418c2ecf20Sopenharmony_ci u64 cl_f; /* time when this class will fit for 1428c2ecf20Sopenharmony_ci link-sharing, max(myf, cfmin) */ 1438c2ecf20Sopenharmony_ci u64 cl_myf; /* my fit-time (calculated from this 1448c2ecf20Sopenharmony_ci class's own upperlimit curve) */ 1458c2ecf20Sopenharmony_ci u64 cl_cfmin; /* earliest children's fit-time (used 1468c2ecf20Sopenharmony_ci with cl_myf to obtain cl_f) */ 1478c2ecf20Sopenharmony_ci u64 cl_cvtmin; /* minimal virtual time among the 1488c2ecf20Sopenharmony_ci children fit for link-sharing 1498c2ecf20Sopenharmony_ci (monotonic within a period) */ 1508c2ecf20Sopenharmony_ci u64 cl_vtadj; /* intra-period cumulative vt 1518c2ecf20Sopenharmony_ci adjustment */ 1528c2ecf20Sopenharmony_ci u64 cl_cvtoff; /* largest virtual time seen among 1538c2ecf20Sopenharmony_ci the children */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci struct internal_sc cl_rsc; /* internal real-time service curve */ 1568c2ecf20Sopenharmony_ci struct internal_sc cl_fsc; /* internal fair service curve */ 1578c2ecf20Sopenharmony_ci struct internal_sc cl_usc; /* internal upperlimit service curve */ 1588c2ecf20Sopenharmony_ci struct runtime_sc cl_deadline; /* deadline curve */ 1598c2ecf20Sopenharmony_ci struct runtime_sc cl_eligible; /* eligible curve */ 1608c2ecf20Sopenharmony_ci struct runtime_sc cl_virtual; /* virtual curve */ 1618c2ecf20Sopenharmony_ci struct runtime_sc cl_ulimit; /* upperlimit curve */ 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci u8 cl_flags; /* which curves are valid */ 1648c2ecf20Sopenharmony_ci u32 cl_vtperiod; /* vt period sequence number */ 1658c2ecf20Sopenharmony_ci u32 cl_parentperiod;/* parent's vt period sequence number*/ 1668c2ecf20Sopenharmony_ci u32 cl_nactive; /* number of active children */ 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistruct hfsc_sched { 1708c2ecf20Sopenharmony_ci u16 defcls; /* default class id */ 1718c2ecf20Sopenharmony_ci struct hfsc_class root; /* root class */ 1728c2ecf20Sopenharmony_ci struct Qdisc_class_hash clhash; /* class hash */ 1738c2ecf20Sopenharmony_ci struct rb_root eligible; /* eligible tree */ 1748c2ecf20Sopenharmony_ci struct qdisc_watchdog watchdog; /* watchdog timer */ 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* 1818c2ecf20Sopenharmony_ci * eligible tree holds backlogged classes being sorted by their eligible times. 1828c2ecf20Sopenharmony_ci * there is one eligible tree per hfsc instance. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic void 1868c2ecf20Sopenharmony_cieltree_insert(struct hfsc_class *cl) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct rb_node **p = &cl->sched->eligible.rb_node; 1898c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 1908c2ecf20Sopenharmony_ci struct hfsc_class *cl1; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci while (*p != NULL) { 1938c2ecf20Sopenharmony_ci parent = *p; 1948c2ecf20Sopenharmony_ci cl1 = rb_entry(parent, struct hfsc_class, el_node); 1958c2ecf20Sopenharmony_ci if (cl->cl_e >= cl1->cl_e) 1968c2ecf20Sopenharmony_ci p = &parent->rb_right; 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci p = &parent->rb_left; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci rb_link_node(&cl->el_node, parent, p); 2018c2ecf20Sopenharmony_ci rb_insert_color(&cl->el_node, &cl->sched->eligible); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic inline void 2058c2ecf20Sopenharmony_cieltree_remove(struct hfsc_class *cl) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci rb_erase(&cl->el_node, &cl->sched->eligible); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic inline void 2118c2ecf20Sopenharmony_cieltree_update(struct hfsc_class *cl) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci eltree_remove(cl); 2148c2ecf20Sopenharmony_ci eltree_insert(cl); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* find the class with the minimum deadline among the eligible classes */ 2188c2ecf20Sopenharmony_cistatic inline struct hfsc_class * 2198c2ecf20Sopenharmony_cieltree_get_mindl(struct hfsc_sched *q, u64 cur_time) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct hfsc_class *p, *cl = NULL; 2228c2ecf20Sopenharmony_ci struct rb_node *n; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (n = rb_first(&q->eligible); n != NULL; n = rb_next(n)) { 2258c2ecf20Sopenharmony_ci p = rb_entry(n, struct hfsc_class, el_node); 2268c2ecf20Sopenharmony_ci if (p->cl_e > cur_time) 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci if (cl == NULL || p->cl_d < cl->cl_d) 2298c2ecf20Sopenharmony_ci cl = p; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci return cl; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* find the class with minimum eligible time among the eligible classes */ 2358c2ecf20Sopenharmony_cistatic inline struct hfsc_class * 2368c2ecf20Sopenharmony_cieltree_get_minel(struct hfsc_sched *q) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct rb_node *n; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci n = rb_first(&q->eligible); 2418c2ecf20Sopenharmony_ci if (n == NULL) 2428c2ecf20Sopenharmony_ci return NULL; 2438c2ecf20Sopenharmony_ci return rb_entry(n, struct hfsc_class, el_node); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* 2478c2ecf20Sopenharmony_ci * vttree holds holds backlogged child classes being sorted by their virtual 2488c2ecf20Sopenharmony_ci * time. each intermediate class has one vttree. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_cistatic void 2518c2ecf20Sopenharmony_civttree_insert(struct hfsc_class *cl) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct rb_node **p = &cl->cl_parent->vt_tree.rb_node; 2548c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 2558c2ecf20Sopenharmony_ci struct hfsc_class *cl1; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci while (*p != NULL) { 2588c2ecf20Sopenharmony_ci parent = *p; 2598c2ecf20Sopenharmony_ci cl1 = rb_entry(parent, struct hfsc_class, vt_node); 2608c2ecf20Sopenharmony_ci if (cl->cl_vt >= cl1->cl_vt) 2618c2ecf20Sopenharmony_ci p = &parent->rb_right; 2628c2ecf20Sopenharmony_ci else 2638c2ecf20Sopenharmony_ci p = &parent->rb_left; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci rb_link_node(&cl->vt_node, parent, p); 2668c2ecf20Sopenharmony_ci rb_insert_color(&cl->vt_node, &cl->cl_parent->vt_tree); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic inline void 2708c2ecf20Sopenharmony_civttree_remove(struct hfsc_class *cl) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci rb_erase(&cl->vt_node, &cl->cl_parent->vt_tree); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic inline void 2768c2ecf20Sopenharmony_civttree_update(struct hfsc_class *cl) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci vttree_remove(cl); 2798c2ecf20Sopenharmony_ci vttree_insert(cl); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic inline struct hfsc_class * 2838c2ecf20Sopenharmony_civttree_firstfit(struct hfsc_class *cl, u64 cur_time) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct hfsc_class *p; 2868c2ecf20Sopenharmony_ci struct rb_node *n; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci for (n = rb_first(&cl->vt_tree); n != NULL; n = rb_next(n)) { 2898c2ecf20Sopenharmony_ci p = rb_entry(n, struct hfsc_class, vt_node); 2908c2ecf20Sopenharmony_ci if (p->cl_f <= cur_time) 2918c2ecf20Sopenharmony_ci return p; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci return NULL; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/* 2978c2ecf20Sopenharmony_ci * get the leaf class with the minimum vt in the hierarchy 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistatic struct hfsc_class * 3008c2ecf20Sopenharmony_civttree_get_minvt(struct hfsc_class *cl, u64 cur_time) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci /* if root-class's cfmin is bigger than cur_time nothing to do */ 3038c2ecf20Sopenharmony_ci if (cl->cl_cfmin > cur_time) 3048c2ecf20Sopenharmony_ci return NULL; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci while (cl->level > 0) { 3078c2ecf20Sopenharmony_ci cl = vttree_firstfit(cl, cur_time); 3088c2ecf20Sopenharmony_ci if (cl == NULL) 3098c2ecf20Sopenharmony_ci return NULL; 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * update parent's cl_cvtmin. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ci if (cl->cl_parent->cl_cvtmin < cl->cl_vt) 3148c2ecf20Sopenharmony_ci cl->cl_parent->cl_cvtmin = cl->cl_vt; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci return cl; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void 3208c2ecf20Sopenharmony_cicftree_insert(struct hfsc_class *cl) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct rb_node **p = &cl->cl_parent->cf_tree.rb_node; 3238c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 3248c2ecf20Sopenharmony_ci struct hfsc_class *cl1; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci while (*p != NULL) { 3278c2ecf20Sopenharmony_ci parent = *p; 3288c2ecf20Sopenharmony_ci cl1 = rb_entry(parent, struct hfsc_class, cf_node); 3298c2ecf20Sopenharmony_ci if (cl->cl_f >= cl1->cl_f) 3308c2ecf20Sopenharmony_ci p = &parent->rb_right; 3318c2ecf20Sopenharmony_ci else 3328c2ecf20Sopenharmony_ci p = &parent->rb_left; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci rb_link_node(&cl->cf_node, parent, p); 3358c2ecf20Sopenharmony_ci rb_insert_color(&cl->cf_node, &cl->cl_parent->cf_tree); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic inline void 3398c2ecf20Sopenharmony_cicftree_remove(struct hfsc_class *cl) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci rb_erase(&cl->cf_node, &cl->cl_parent->cf_tree); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic inline void 3458c2ecf20Sopenharmony_cicftree_update(struct hfsc_class *cl) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci cftree_remove(cl); 3488c2ecf20Sopenharmony_ci cftree_insert(cl); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/* 3528c2ecf20Sopenharmony_ci * service curve support functions 3538c2ecf20Sopenharmony_ci * 3548c2ecf20Sopenharmony_ci * external service curve parameters 3558c2ecf20Sopenharmony_ci * m: bps 3568c2ecf20Sopenharmony_ci * d: us 3578c2ecf20Sopenharmony_ci * internal service curve parameters 3588c2ecf20Sopenharmony_ci * sm: (bytes/psched_us) << SM_SHIFT 3598c2ecf20Sopenharmony_ci * ism: (psched_us/byte) << ISM_SHIFT 3608c2ecf20Sopenharmony_ci * dx: psched_us 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * The clock source resolution with ktime and PSCHED_SHIFT 10 is 1.024us. 3638c2ecf20Sopenharmony_ci * 3648c2ecf20Sopenharmony_ci * sm and ism are scaled in order to keep effective digits. 3658c2ecf20Sopenharmony_ci * SM_SHIFT and ISM_SHIFT are selected to keep at least 4 effective 3668c2ecf20Sopenharmony_ci * digits in decimal using the following table. 3678c2ecf20Sopenharmony_ci * 3688c2ecf20Sopenharmony_ci * bits/sec 100Kbps 1Mbps 10Mbps 100Mbps 1Gbps 3698c2ecf20Sopenharmony_ci * ------------+------------------------------------------------------- 3708c2ecf20Sopenharmony_ci * bytes/1.024us 12.8e-3 128e-3 1280e-3 12800e-3 128000e-3 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci * 1.024us/byte 78.125 7.8125 0.78125 0.078125 0.0078125 3738c2ecf20Sopenharmony_ci * 3748c2ecf20Sopenharmony_ci * So, for PSCHED_SHIFT 10 we need: SM_SHIFT 20, ISM_SHIFT 18. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci#define SM_SHIFT (30 - PSCHED_SHIFT) 3778c2ecf20Sopenharmony_ci#define ISM_SHIFT (8 + PSCHED_SHIFT) 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci#define SM_MASK ((1ULL << SM_SHIFT) - 1) 3808c2ecf20Sopenharmony_ci#define ISM_MASK ((1ULL << ISM_SHIFT) - 1) 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic inline u64 3838c2ecf20Sopenharmony_ciseg_x2y(u64 x, u64 sm) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci u64 y; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* 3888c2ecf20Sopenharmony_ci * compute 3898c2ecf20Sopenharmony_ci * y = x * sm >> SM_SHIFT 3908c2ecf20Sopenharmony_ci * but divide it for the upper and lower bits to avoid overflow 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci y = (x >> SM_SHIFT) * sm + (((x & SM_MASK) * sm) >> SM_SHIFT); 3938c2ecf20Sopenharmony_ci return y; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic inline u64 3978c2ecf20Sopenharmony_ciseg_y2x(u64 y, u64 ism) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci u64 x; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (y == 0) 4028c2ecf20Sopenharmony_ci x = 0; 4038c2ecf20Sopenharmony_ci else if (ism == HT_INFINITY) 4048c2ecf20Sopenharmony_ci x = HT_INFINITY; 4058c2ecf20Sopenharmony_ci else { 4068c2ecf20Sopenharmony_ci x = (y >> ISM_SHIFT) * ism 4078c2ecf20Sopenharmony_ci + (((y & ISM_MASK) * ism) >> ISM_SHIFT); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci return x; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci/* Convert m (bps) into sm (bytes/psched us) */ 4138c2ecf20Sopenharmony_cistatic u64 4148c2ecf20Sopenharmony_cim2sm(u32 m) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci u64 sm; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci sm = ((u64)m << SM_SHIFT); 4198c2ecf20Sopenharmony_ci sm += PSCHED_TICKS_PER_SEC - 1; 4208c2ecf20Sopenharmony_ci do_div(sm, PSCHED_TICKS_PER_SEC); 4218c2ecf20Sopenharmony_ci return sm; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci/* convert m (bps) into ism (psched us/byte) */ 4258c2ecf20Sopenharmony_cistatic u64 4268c2ecf20Sopenharmony_cim2ism(u32 m) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci u64 ism; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (m == 0) 4318c2ecf20Sopenharmony_ci ism = HT_INFINITY; 4328c2ecf20Sopenharmony_ci else { 4338c2ecf20Sopenharmony_ci ism = ((u64)PSCHED_TICKS_PER_SEC << ISM_SHIFT); 4348c2ecf20Sopenharmony_ci ism += m - 1; 4358c2ecf20Sopenharmony_ci do_div(ism, m); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci return ism; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/* convert d (us) into dx (psched us) */ 4418c2ecf20Sopenharmony_cistatic u64 4428c2ecf20Sopenharmony_cid2dx(u32 d) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci u64 dx; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci dx = ((u64)d * PSCHED_TICKS_PER_SEC); 4478c2ecf20Sopenharmony_ci dx += USEC_PER_SEC - 1; 4488c2ecf20Sopenharmony_ci do_div(dx, USEC_PER_SEC); 4498c2ecf20Sopenharmony_ci return dx; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/* convert sm (bytes/psched us) into m (bps) */ 4538c2ecf20Sopenharmony_cistatic u32 4548c2ecf20Sopenharmony_cism2m(u64 sm) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci u64 m; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci m = (sm * PSCHED_TICKS_PER_SEC) >> SM_SHIFT; 4598c2ecf20Sopenharmony_ci return (u32)m; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/* convert dx (psched us) into d (us) */ 4638c2ecf20Sopenharmony_cistatic u32 4648c2ecf20Sopenharmony_cidx2d(u64 dx) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci u64 d; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci d = dx * USEC_PER_SEC; 4698c2ecf20Sopenharmony_ci do_div(d, PSCHED_TICKS_PER_SEC); 4708c2ecf20Sopenharmony_ci return (u32)d; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic void 4748c2ecf20Sopenharmony_cisc2isc(struct tc_service_curve *sc, struct internal_sc *isc) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci isc->sm1 = m2sm(sc->m1); 4778c2ecf20Sopenharmony_ci isc->ism1 = m2ism(sc->m1); 4788c2ecf20Sopenharmony_ci isc->dx = d2dx(sc->d); 4798c2ecf20Sopenharmony_ci isc->dy = seg_x2y(isc->dx, isc->sm1); 4808c2ecf20Sopenharmony_ci isc->sm2 = m2sm(sc->m2); 4818c2ecf20Sopenharmony_ci isc->ism2 = m2ism(sc->m2); 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* 4858c2ecf20Sopenharmony_ci * initialize the runtime service curve with the given internal 4868c2ecf20Sopenharmony_ci * service curve starting at (x, y). 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_cistatic void 4898c2ecf20Sopenharmony_cirtsc_init(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci rtsc->x = x; 4928c2ecf20Sopenharmony_ci rtsc->y = y; 4938c2ecf20Sopenharmony_ci rtsc->sm1 = isc->sm1; 4948c2ecf20Sopenharmony_ci rtsc->ism1 = isc->ism1; 4958c2ecf20Sopenharmony_ci rtsc->dx = isc->dx; 4968c2ecf20Sopenharmony_ci rtsc->dy = isc->dy; 4978c2ecf20Sopenharmony_ci rtsc->sm2 = isc->sm2; 4988c2ecf20Sopenharmony_ci rtsc->ism2 = isc->ism2; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci/* 5028c2ecf20Sopenharmony_ci * calculate the y-projection of the runtime service curve by the 5038c2ecf20Sopenharmony_ci * given x-projection value 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_cistatic u64 5068c2ecf20Sopenharmony_cirtsc_y2x(struct runtime_sc *rtsc, u64 y) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci u64 x; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (y < rtsc->y) 5118c2ecf20Sopenharmony_ci x = rtsc->x; 5128c2ecf20Sopenharmony_ci else if (y <= rtsc->y + rtsc->dy) { 5138c2ecf20Sopenharmony_ci /* x belongs to the 1st segment */ 5148c2ecf20Sopenharmony_ci if (rtsc->dy == 0) 5158c2ecf20Sopenharmony_ci x = rtsc->x + rtsc->dx; 5168c2ecf20Sopenharmony_ci else 5178c2ecf20Sopenharmony_ci x = rtsc->x + seg_y2x(y - rtsc->y, rtsc->ism1); 5188c2ecf20Sopenharmony_ci } else { 5198c2ecf20Sopenharmony_ci /* x belongs to the 2nd segment */ 5208c2ecf20Sopenharmony_ci x = rtsc->x + rtsc->dx 5218c2ecf20Sopenharmony_ci + seg_y2x(y - rtsc->y - rtsc->dy, rtsc->ism2); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci return x; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic u64 5278c2ecf20Sopenharmony_cirtsc_x2y(struct runtime_sc *rtsc, u64 x) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci u64 y; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (x <= rtsc->x) 5328c2ecf20Sopenharmony_ci y = rtsc->y; 5338c2ecf20Sopenharmony_ci else if (x <= rtsc->x + rtsc->dx) 5348c2ecf20Sopenharmony_ci /* y belongs to the 1st segment */ 5358c2ecf20Sopenharmony_ci y = rtsc->y + seg_x2y(x - rtsc->x, rtsc->sm1); 5368c2ecf20Sopenharmony_ci else 5378c2ecf20Sopenharmony_ci /* y belongs to the 2nd segment */ 5388c2ecf20Sopenharmony_ci y = rtsc->y + rtsc->dy 5398c2ecf20Sopenharmony_ci + seg_x2y(x - rtsc->x - rtsc->dx, rtsc->sm2); 5408c2ecf20Sopenharmony_ci return y; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/* 5448c2ecf20Sopenharmony_ci * update the runtime service curve by taking the minimum of the current 5458c2ecf20Sopenharmony_ci * runtime service curve and the service curve starting at (x, y). 5468c2ecf20Sopenharmony_ci */ 5478c2ecf20Sopenharmony_cistatic void 5488c2ecf20Sopenharmony_cirtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci u64 y1, y2, dx, dy; 5518c2ecf20Sopenharmony_ci u32 dsm; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (isc->sm1 <= isc->sm2) { 5548c2ecf20Sopenharmony_ci /* service curve is convex */ 5558c2ecf20Sopenharmony_ci y1 = rtsc_x2y(rtsc, x); 5568c2ecf20Sopenharmony_ci if (y1 < y) 5578c2ecf20Sopenharmony_ci /* the current rtsc is smaller */ 5588c2ecf20Sopenharmony_ci return; 5598c2ecf20Sopenharmony_ci rtsc->x = x; 5608c2ecf20Sopenharmony_ci rtsc->y = y; 5618c2ecf20Sopenharmony_ci return; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* 5658c2ecf20Sopenharmony_ci * service curve is concave 5668c2ecf20Sopenharmony_ci * compute the two y values of the current rtsc 5678c2ecf20Sopenharmony_ci * y1: at x 5688c2ecf20Sopenharmony_ci * y2: at (x + dx) 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_ci y1 = rtsc_x2y(rtsc, x); 5718c2ecf20Sopenharmony_ci if (y1 <= y) { 5728c2ecf20Sopenharmony_ci /* rtsc is below isc, no change to rtsc */ 5738c2ecf20Sopenharmony_ci return; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci y2 = rtsc_x2y(rtsc, x + isc->dx); 5778c2ecf20Sopenharmony_ci if (y2 >= y + isc->dy) { 5788c2ecf20Sopenharmony_ci /* rtsc is above isc, replace rtsc by isc */ 5798c2ecf20Sopenharmony_ci rtsc->x = x; 5808c2ecf20Sopenharmony_ci rtsc->y = y; 5818c2ecf20Sopenharmony_ci rtsc->dx = isc->dx; 5828c2ecf20Sopenharmony_ci rtsc->dy = isc->dy; 5838c2ecf20Sopenharmony_ci return; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* 5878c2ecf20Sopenharmony_ci * the two curves intersect 5888c2ecf20Sopenharmony_ci * compute the offsets (dx, dy) using the reverse 5898c2ecf20Sopenharmony_ci * function of seg_x2y() 5908c2ecf20Sopenharmony_ci * seg_x2y(dx, sm1) == seg_x2y(dx, sm2) + (y1 - y) 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci dx = (y1 - y) << SM_SHIFT; 5938c2ecf20Sopenharmony_ci dsm = isc->sm1 - isc->sm2; 5948c2ecf20Sopenharmony_ci do_div(dx, dsm); 5958c2ecf20Sopenharmony_ci /* 5968c2ecf20Sopenharmony_ci * check if (x, y1) belongs to the 1st segment of rtsc. 5978c2ecf20Sopenharmony_ci * if so, add the offset. 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci if (rtsc->x + rtsc->dx > x) 6008c2ecf20Sopenharmony_ci dx += rtsc->x + rtsc->dx - x; 6018c2ecf20Sopenharmony_ci dy = seg_x2y(dx, isc->sm1); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci rtsc->x = x; 6048c2ecf20Sopenharmony_ci rtsc->y = y; 6058c2ecf20Sopenharmony_ci rtsc->dx = dx; 6068c2ecf20Sopenharmony_ci rtsc->dy = dy; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic void 6108c2ecf20Sopenharmony_ciinit_ed(struct hfsc_class *cl, unsigned int next_len) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci u64 cur_time = psched_get_time(); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* update the deadline curve */ 6158c2ecf20Sopenharmony_ci rtsc_min(&cl->cl_deadline, &cl->cl_rsc, cur_time, cl->cl_cumul); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* 6188c2ecf20Sopenharmony_ci * update the eligible curve. 6198c2ecf20Sopenharmony_ci * for concave, it is equal to the deadline curve. 6208c2ecf20Sopenharmony_ci * for convex, it is a linear curve with slope m2. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci cl->cl_eligible = cl->cl_deadline; 6238c2ecf20Sopenharmony_ci if (cl->cl_rsc.sm1 <= cl->cl_rsc.sm2) { 6248c2ecf20Sopenharmony_ci cl->cl_eligible.dx = 0; 6258c2ecf20Sopenharmony_ci cl->cl_eligible.dy = 0; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* compute e and d */ 6298c2ecf20Sopenharmony_ci cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); 6308c2ecf20Sopenharmony_ci cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci eltree_insert(cl); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic void 6368c2ecf20Sopenharmony_ciupdate_ed(struct hfsc_class *cl, unsigned int next_len) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); 6398c2ecf20Sopenharmony_ci cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci eltree_update(cl); 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic inline void 6458c2ecf20Sopenharmony_ciupdate_d(struct hfsc_class *cl, unsigned int next_len) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic inline void 6518c2ecf20Sopenharmony_ciupdate_cfmin(struct hfsc_class *cl) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct rb_node *n = rb_first(&cl->cf_tree); 6548c2ecf20Sopenharmony_ci struct hfsc_class *p; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (n == NULL) { 6578c2ecf20Sopenharmony_ci cl->cl_cfmin = 0; 6588c2ecf20Sopenharmony_ci return; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci p = rb_entry(n, struct hfsc_class, cf_node); 6618c2ecf20Sopenharmony_ci cl->cl_cfmin = p->cl_f; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void 6658c2ecf20Sopenharmony_ciinit_vf(struct hfsc_class *cl, unsigned int len) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci struct hfsc_class *max_cl; 6688c2ecf20Sopenharmony_ci struct rb_node *n; 6698c2ecf20Sopenharmony_ci u64 vt, f, cur_time; 6708c2ecf20Sopenharmony_ci int go_active; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci cur_time = 0; 6738c2ecf20Sopenharmony_ci go_active = 1; 6748c2ecf20Sopenharmony_ci for (; cl->cl_parent != NULL; cl = cl->cl_parent) { 6758c2ecf20Sopenharmony_ci if (go_active && cl->cl_nactive++ == 0) 6768c2ecf20Sopenharmony_ci go_active = 1; 6778c2ecf20Sopenharmony_ci else 6788c2ecf20Sopenharmony_ci go_active = 0; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (go_active) { 6818c2ecf20Sopenharmony_ci n = rb_last(&cl->cl_parent->vt_tree); 6828c2ecf20Sopenharmony_ci if (n != NULL) { 6838c2ecf20Sopenharmony_ci max_cl = rb_entry(n, struct hfsc_class, vt_node); 6848c2ecf20Sopenharmony_ci /* 6858c2ecf20Sopenharmony_ci * set vt to the average of the min and max 6868c2ecf20Sopenharmony_ci * classes. if the parent's period didn't 6878c2ecf20Sopenharmony_ci * change, don't decrease vt of the class. 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci vt = max_cl->cl_vt; 6908c2ecf20Sopenharmony_ci if (cl->cl_parent->cl_cvtmin != 0) 6918c2ecf20Sopenharmony_ci vt = (cl->cl_parent->cl_cvtmin + vt)/2; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (cl->cl_parent->cl_vtperiod != 6948c2ecf20Sopenharmony_ci cl->cl_parentperiod || vt > cl->cl_vt) 6958c2ecf20Sopenharmony_ci cl->cl_vt = vt; 6968c2ecf20Sopenharmony_ci } else { 6978c2ecf20Sopenharmony_ci /* 6988c2ecf20Sopenharmony_ci * first child for a new parent backlog period. 6998c2ecf20Sopenharmony_ci * initialize cl_vt to the highest value seen 7008c2ecf20Sopenharmony_ci * among the siblings. this is analogous to 7018c2ecf20Sopenharmony_ci * what cur_time would provide in realtime case. 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci cl->cl_vt = cl->cl_parent->cl_cvtoff; 7048c2ecf20Sopenharmony_ci cl->cl_parent->cl_cvtmin = 0; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* update the virtual curve */ 7088c2ecf20Sopenharmony_ci rtsc_min(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total); 7098c2ecf20Sopenharmony_ci cl->cl_vtadj = 0; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci cl->cl_vtperiod++; /* increment vt period */ 7128c2ecf20Sopenharmony_ci cl->cl_parentperiod = cl->cl_parent->cl_vtperiod; 7138c2ecf20Sopenharmony_ci if (cl->cl_parent->cl_nactive == 0) 7148c2ecf20Sopenharmony_ci cl->cl_parentperiod++; 7158c2ecf20Sopenharmony_ci cl->cl_f = 0; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci vttree_insert(cl); 7188c2ecf20Sopenharmony_ci cftree_insert(cl); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_USC) { 7218c2ecf20Sopenharmony_ci /* class has upper limit curve */ 7228c2ecf20Sopenharmony_ci if (cur_time == 0) 7238c2ecf20Sopenharmony_ci cur_time = psched_get_time(); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* update the ulimit curve */ 7268c2ecf20Sopenharmony_ci rtsc_min(&cl->cl_ulimit, &cl->cl_usc, cur_time, 7278c2ecf20Sopenharmony_ci cl->cl_total); 7288c2ecf20Sopenharmony_ci /* compute myf */ 7298c2ecf20Sopenharmony_ci cl->cl_myf = rtsc_y2x(&cl->cl_ulimit, 7308c2ecf20Sopenharmony_ci cl->cl_total); 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci f = max(cl->cl_myf, cl->cl_cfmin); 7358c2ecf20Sopenharmony_ci if (f != cl->cl_f) { 7368c2ecf20Sopenharmony_ci cl->cl_f = f; 7378c2ecf20Sopenharmony_ci cftree_update(cl); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci update_cfmin(cl->cl_parent); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic void 7448c2ecf20Sopenharmony_ciupdate_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci u64 f; /* , myf_bound, delta; */ 7478c2ecf20Sopenharmony_ci int go_passive = 0; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC) 7508c2ecf20Sopenharmony_ci go_passive = 1; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci for (; cl->cl_parent != NULL; cl = cl->cl_parent) { 7538c2ecf20Sopenharmony_ci cl->cl_total += len; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (!(cl->cl_flags & HFSC_FSC) || cl->cl_nactive == 0) 7568c2ecf20Sopenharmony_ci continue; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (go_passive && --cl->cl_nactive == 0) 7598c2ecf20Sopenharmony_ci go_passive = 1; 7608c2ecf20Sopenharmony_ci else 7618c2ecf20Sopenharmony_ci go_passive = 0; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* update vt */ 7648c2ecf20Sopenharmony_ci cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total) + cl->cl_vtadj; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci /* 7678c2ecf20Sopenharmony_ci * if vt of the class is smaller than cvtmin, 7688c2ecf20Sopenharmony_ci * the class was skipped in the past due to non-fit. 7698c2ecf20Sopenharmony_ci * if so, we need to adjust vtadj. 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ci if (cl->cl_vt < cl->cl_parent->cl_cvtmin) { 7728c2ecf20Sopenharmony_ci cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt; 7738c2ecf20Sopenharmony_ci cl->cl_vt = cl->cl_parent->cl_cvtmin; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (go_passive) { 7778c2ecf20Sopenharmony_ci /* no more active child, going passive */ 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* update cvtoff of the parent class */ 7808c2ecf20Sopenharmony_ci if (cl->cl_vt > cl->cl_parent->cl_cvtoff) 7818c2ecf20Sopenharmony_ci cl->cl_parent->cl_cvtoff = cl->cl_vt; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* remove this class from the vt tree */ 7848c2ecf20Sopenharmony_ci vttree_remove(cl); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci cftree_remove(cl); 7878c2ecf20Sopenharmony_ci update_cfmin(cl->cl_parent); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci continue; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* update the vt tree */ 7938c2ecf20Sopenharmony_ci vttree_update(cl); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* update f */ 7968c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_USC) { 7978c2ecf20Sopenharmony_ci cl->cl_myf = rtsc_y2x(&cl->cl_ulimit, cl->cl_total); 7988c2ecf20Sopenharmony_ci#if 0 7998c2ecf20Sopenharmony_ci cl->cl_myf = cl->cl_myfadj + rtsc_y2x(&cl->cl_ulimit, 8008c2ecf20Sopenharmony_ci cl->cl_total); 8018c2ecf20Sopenharmony_ci /* 8028c2ecf20Sopenharmony_ci * This code causes classes to stay way under their 8038c2ecf20Sopenharmony_ci * limit when multiple classes are used at gigabit 8048c2ecf20Sopenharmony_ci * speed. needs investigation. -kaber 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_ci /* 8078c2ecf20Sopenharmony_ci * if myf lags behind by more than one clock tick 8088c2ecf20Sopenharmony_ci * from the current time, adjust myfadj to prevent 8098c2ecf20Sopenharmony_ci * a rate-limited class from going greedy. 8108c2ecf20Sopenharmony_ci * in a steady state under rate-limiting, myf 8118c2ecf20Sopenharmony_ci * fluctuates within one clock tick. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ci myf_bound = cur_time - PSCHED_JIFFIE2US(1); 8148c2ecf20Sopenharmony_ci if (cl->cl_myf < myf_bound) { 8158c2ecf20Sopenharmony_ci delta = cur_time - cl->cl_myf; 8168c2ecf20Sopenharmony_ci cl->cl_myfadj += delta; 8178c2ecf20Sopenharmony_ci cl->cl_myf += delta; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci#endif 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci f = max(cl->cl_myf, cl->cl_cfmin); 8238c2ecf20Sopenharmony_ci if (f != cl->cl_f) { 8248c2ecf20Sopenharmony_ci cl->cl_f = f; 8258c2ecf20Sopenharmony_ci cftree_update(cl); 8268c2ecf20Sopenharmony_ci update_cfmin(cl->cl_parent); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic unsigned int 8328c2ecf20Sopenharmony_ciqdisc_peek_len(struct Qdisc *sch) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct sk_buff *skb; 8358c2ecf20Sopenharmony_ci unsigned int len; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci skb = sch->ops->peek(sch); 8388c2ecf20Sopenharmony_ci if (unlikely(skb == NULL)) { 8398c2ecf20Sopenharmony_ci qdisc_warn_nonwc("qdisc_peek_len", sch); 8408c2ecf20Sopenharmony_ci return 0; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci len = qdisc_pkt_len(skb); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return len; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void 8488c2ecf20Sopenharmony_cihfsc_adjust_levels(struct hfsc_class *cl) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct hfsc_class *p; 8518c2ecf20Sopenharmony_ci unsigned int level; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci do { 8548c2ecf20Sopenharmony_ci level = 0; 8558c2ecf20Sopenharmony_ci list_for_each_entry(p, &cl->children, siblings) { 8568c2ecf20Sopenharmony_ci if (p->level >= level) 8578c2ecf20Sopenharmony_ci level = p->level + 1; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci cl->level = level; 8608c2ecf20Sopenharmony_ci } while ((cl = cl->cl_parent) != NULL); 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_cistatic inline struct hfsc_class * 8648c2ecf20Sopenharmony_cihfsc_find_class(u32 classid, struct Qdisc *sch) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 8678c2ecf20Sopenharmony_ci struct Qdisc_class_common *clc; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci clc = qdisc_class_find(&q->clhash, classid); 8708c2ecf20Sopenharmony_ci if (clc == NULL) 8718c2ecf20Sopenharmony_ci return NULL; 8728c2ecf20Sopenharmony_ci return container_of(clc, struct hfsc_class, cl_common); 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic void 8768c2ecf20Sopenharmony_cihfsc_change_rsc(struct hfsc_class *cl, struct tc_service_curve *rsc, 8778c2ecf20Sopenharmony_ci u64 cur_time) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci sc2isc(rsc, &cl->cl_rsc); 8808c2ecf20Sopenharmony_ci rtsc_init(&cl->cl_deadline, &cl->cl_rsc, cur_time, cl->cl_cumul); 8818c2ecf20Sopenharmony_ci cl->cl_eligible = cl->cl_deadline; 8828c2ecf20Sopenharmony_ci if (cl->cl_rsc.sm1 <= cl->cl_rsc.sm2) { 8838c2ecf20Sopenharmony_ci cl->cl_eligible.dx = 0; 8848c2ecf20Sopenharmony_ci cl->cl_eligible.dy = 0; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci cl->cl_flags |= HFSC_RSC; 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic void 8908c2ecf20Sopenharmony_cihfsc_change_fsc(struct hfsc_class *cl, struct tc_service_curve *fsc) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci sc2isc(fsc, &cl->cl_fsc); 8938c2ecf20Sopenharmony_ci rtsc_init(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total); 8948c2ecf20Sopenharmony_ci cl->cl_flags |= HFSC_FSC; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic void 8988c2ecf20Sopenharmony_cihfsc_change_usc(struct hfsc_class *cl, struct tc_service_curve *usc, 8998c2ecf20Sopenharmony_ci u64 cur_time) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci sc2isc(usc, &cl->cl_usc); 9028c2ecf20Sopenharmony_ci rtsc_init(&cl->cl_ulimit, &cl->cl_usc, cur_time, cl->cl_total); 9038c2ecf20Sopenharmony_ci cl->cl_flags |= HFSC_USC; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic void 9078c2ecf20Sopenharmony_cihfsc_upgrade_rt(struct hfsc_class *cl) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci cl->cl_fsc = cl->cl_rsc; 9108c2ecf20Sopenharmony_ci rtsc_init(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total); 9118c2ecf20Sopenharmony_ci cl->cl_flags |= HFSC_FSC; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic const struct nla_policy hfsc_policy[TCA_HFSC_MAX + 1] = { 9158c2ecf20Sopenharmony_ci [TCA_HFSC_RSC] = { .len = sizeof(struct tc_service_curve) }, 9168c2ecf20Sopenharmony_ci [TCA_HFSC_FSC] = { .len = sizeof(struct tc_service_curve) }, 9178c2ecf20Sopenharmony_ci [TCA_HFSC_USC] = { .len = sizeof(struct tc_service_curve) }, 9188c2ecf20Sopenharmony_ci}; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic int 9218c2ecf20Sopenharmony_cihfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, 9228c2ecf20Sopenharmony_ci struct nlattr **tca, unsigned long *arg, 9238c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 9268c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)*arg; 9278c2ecf20Sopenharmony_ci struct hfsc_class *parent = NULL; 9288c2ecf20Sopenharmony_ci struct nlattr *opt = tca[TCA_OPTIONS]; 9298c2ecf20Sopenharmony_ci struct nlattr *tb[TCA_HFSC_MAX + 1]; 9308c2ecf20Sopenharmony_ci struct tc_service_curve *rsc = NULL, *fsc = NULL, *usc = NULL; 9318c2ecf20Sopenharmony_ci u64 cur_time; 9328c2ecf20Sopenharmony_ci int err; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (opt == NULL) 9358c2ecf20Sopenharmony_ci return -EINVAL; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(tb, TCA_HFSC_MAX, opt, hfsc_policy, 9388c2ecf20Sopenharmony_ci NULL); 9398c2ecf20Sopenharmony_ci if (err < 0) 9408c2ecf20Sopenharmony_ci return err; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (tb[TCA_HFSC_RSC]) { 9438c2ecf20Sopenharmony_ci rsc = nla_data(tb[TCA_HFSC_RSC]); 9448c2ecf20Sopenharmony_ci if (rsc->m1 == 0 && rsc->m2 == 0) 9458c2ecf20Sopenharmony_ci rsc = NULL; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (tb[TCA_HFSC_FSC]) { 9498c2ecf20Sopenharmony_ci fsc = nla_data(tb[TCA_HFSC_FSC]); 9508c2ecf20Sopenharmony_ci if (fsc->m1 == 0 && fsc->m2 == 0) 9518c2ecf20Sopenharmony_ci fsc = NULL; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (tb[TCA_HFSC_USC]) { 9558c2ecf20Sopenharmony_ci usc = nla_data(tb[TCA_HFSC_USC]); 9568c2ecf20Sopenharmony_ci if (usc->m1 == 0 && usc->m2 == 0) 9578c2ecf20Sopenharmony_ci usc = NULL; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (cl != NULL) { 9618c2ecf20Sopenharmony_ci int old_flags; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (parentid) { 9648c2ecf20Sopenharmony_ci if (cl->cl_parent && 9658c2ecf20Sopenharmony_ci cl->cl_parent->cl_common.classid != parentid) 9668c2ecf20Sopenharmony_ci return -EINVAL; 9678c2ecf20Sopenharmony_ci if (cl->cl_parent == NULL && parentid != TC_H_ROOT) 9688c2ecf20Sopenharmony_ci return -EINVAL; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci cur_time = psched_get_time(); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (tca[TCA_RATE]) { 9738c2ecf20Sopenharmony_ci err = gen_replace_estimator(&cl->bstats, NULL, 9748c2ecf20Sopenharmony_ci &cl->rate_est, 9758c2ecf20Sopenharmony_ci NULL, 9768c2ecf20Sopenharmony_ci qdisc_root_sleeping_running(sch), 9778c2ecf20Sopenharmony_ci tca[TCA_RATE]); 9788c2ecf20Sopenharmony_ci if (err) 9798c2ecf20Sopenharmony_ci return err; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci sch_tree_lock(sch); 9838c2ecf20Sopenharmony_ci old_flags = cl->cl_flags; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (rsc != NULL) 9868c2ecf20Sopenharmony_ci hfsc_change_rsc(cl, rsc, cur_time); 9878c2ecf20Sopenharmony_ci if (fsc != NULL) 9888c2ecf20Sopenharmony_ci hfsc_change_fsc(cl, fsc); 9898c2ecf20Sopenharmony_ci if (usc != NULL) 9908c2ecf20Sopenharmony_ci hfsc_change_usc(cl, usc, cur_time); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (cl->qdisc->q.qlen != 0) { 9938c2ecf20Sopenharmony_ci int len = qdisc_peek_len(cl->qdisc); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_RSC) { 9968c2ecf20Sopenharmony_ci if (old_flags & HFSC_RSC) 9978c2ecf20Sopenharmony_ci update_ed(cl, len); 9988c2ecf20Sopenharmony_ci else 9998c2ecf20Sopenharmony_ci init_ed(cl, len); 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_FSC) { 10038c2ecf20Sopenharmony_ci if (old_flags & HFSC_FSC) 10048c2ecf20Sopenharmony_ci update_vf(cl, 0, cur_time); 10058c2ecf20Sopenharmony_ci else 10068c2ecf20Sopenharmony_ci init_vf(cl, len); 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci sch_tree_unlock(sch); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci return 0; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (parentid == TC_H_ROOT) 10158c2ecf20Sopenharmony_ci return -EEXIST; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci parent = &q->root; 10188c2ecf20Sopenharmony_ci if (parentid) { 10198c2ecf20Sopenharmony_ci parent = hfsc_find_class(parentid, sch); 10208c2ecf20Sopenharmony_ci if (parent == NULL) 10218c2ecf20Sopenharmony_ci return -ENOENT; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (classid == 0 || TC_H_MAJ(classid ^ sch->handle) != 0) 10258c2ecf20Sopenharmony_ci return -EINVAL; 10268c2ecf20Sopenharmony_ci if (hfsc_find_class(classid, sch)) 10278c2ecf20Sopenharmony_ci return -EEXIST; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (rsc == NULL && fsc == NULL) 10308c2ecf20Sopenharmony_ci return -EINVAL; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci cl = kzalloc(sizeof(struct hfsc_class), GFP_KERNEL); 10338c2ecf20Sopenharmony_ci if (cl == NULL) 10348c2ecf20Sopenharmony_ci return -ENOBUFS; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); 10378c2ecf20Sopenharmony_ci if (err) { 10388c2ecf20Sopenharmony_ci kfree(cl); 10398c2ecf20Sopenharmony_ci return err; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (tca[TCA_RATE]) { 10438c2ecf20Sopenharmony_ci err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est, 10448c2ecf20Sopenharmony_ci NULL, 10458c2ecf20Sopenharmony_ci qdisc_root_sleeping_running(sch), 10468c2ecf20Sopenharmony_ci tca[TCA_RATE]); 10478c2ecf20Sopenharmony_ci if (err) { 10488c2ecf20Sopenharmony_ci tcf_block_put(cl->block); 10498c2ecf20Sopenharmony_ci kfree(cl); 10508c2ecf20Sopenharmony_ci return err; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (rsc != NULL) 10558c2ecf20Sopenharmony_ci hfsc_change_rsc(cl, rsc, 0); 10568c2ecf20Sopenharmony_ci if (fsc != NULL) 10578c2ecf20Sopenharmony_ci hfsc_change_fsc(cl, fsc); 10588c2ecf20Sopenharmony_ci if (usc != NULL) 10598c2ecf20Sopenharmony_ci hfsc_change_usc(cl, usc, 0); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci cl->cl_common.classid = classid; 10628c2ecf20Sopenharmony_ci cl->sched = q; 10638c2ecf20Sopenharmony_ci cl->cl_parent = parent; 10648c2ecf20Sopenharmony_ci cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, 10658c2ecf20Sopenharmony_ci classid, NULL); 10668c2ecf20Sopenharmony_ci if (cl->qdisc == NULL) 10678c2ecf20Sopenharmony_ci cl->qdisc = &noop_qdisc; 10688c2ecf20Sopenharmony_ci else 10698c2ecf20Sopenharmony_ci qdisc_hash_add(cl->qdisc, true); 10708c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cl->children); 10718c2ecf20Sopenharmony_ci cl->vt_tree = RB_ROOT; 10728c2ecf20Sopenharmony_ci cl->cf_tree = RB_ROOT; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci sch_tree_lock(sch); 10758c2ecf20Sopenharmony_ci /* Check if the inner class is a misconfigured 'rt' */ 10768c2ecf20Sopenharmony_ci if (!(parent->cl_flags & HFSC_FSC) && parent != &q->root) { 10778c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 10788c2ecf20Sopenharmony_ci "Forced curve change on parent 'rt' to 'sc'"); 10798c2ecf20Sopenharmony_ci hfsc_upgrade_rt(parent); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci qdisc_class_hash_insert(&q->clhash, &cl->cl_common); 10828c2ecf20Sopenharmony_ci list_add_tail(&cl->siblings, &parent->children); 10838c2ecf20Sopenharmony_ci if (parent->level == 0) 10848c2ecf20Sopenharmony_ci qdisc_purge_queue(parent->qdisc); 10858c2ecf20Sopenharmony_ci hfsc_adjust_levels(parent); 10868c2ecf20Sopenharmony_ci sch_tree_unlock(sch); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci qdisc_class_hash_grow(sch, &q->clhash); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci *arg = (unsigned long)cl; 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic void 10958c2ecf20Sopenharmony_cihfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci tcf_block_put(cl->block); 11008c2ecf20Sopenharmony_ci qdisc_put(cl->qdisc); 11018c2ecf20Sopenharmony_ci gen_kill_estimator(&cl->rate_est); 11028c2ecf20Sopenharmony_ci if (cl != &q->root) 11038c2ecf20Sopenharmony_ci kfree(cl); 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic int 11078c2ecf20Sopenharmony_cihfsc_delete_class(struct Qdisc *sch, unsigned long arg) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 11108c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (cl->level > 0 || cl->filter_cnt > 0 || cl == &q->root) 11138c2ecf20Sopenharmony_ci return -EBUSY; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci sch_tree_lock(sch); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci list_del(&cl->siblings); 11188c2ecf20Sopenharmony_ci hfsc_adjust_levels(cl->cl_parent); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci qdisc_purge_queue(cl->qdisc); 11218c2ecf20Sopenharmony_ci qdisc_class_hash_remove(&q->clhash, &cl->cl_common); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci sch_tree_unlock(sch); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci hfsc_destroy_class(sch, cl); 11268c2ecf20Sopenharmony_ci return 0; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic struct hfsc_class * 11308c2ecf20Sopenharmony_cihfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 11338c2ecf20Sopenharmony_ci struct hfsc_class *head, *cl; 11348c2ecf20Sopenharmony_ci struct tcf_result res; 11358c2ecf20Sopenharmony_ci struct tcf_proto *tcf; 11368c2ecf20Sopenharmony_ci int result; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (TC_H_MAJ(skb->priority ^ sch->handle) == 0 && 11398c2ecf20Sopenharmony_ci (cl = hfsc_find_class(skb->priority, sch)) != NULL) 11408c2ecf20Sopenharmony_ci if (cl->level == 0) 11418c2ecf20Sopenharmony_ci return cl; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; 11448c2ecf20Sopenharmony_ci head = &q->root; 11458c2ecf20Sopenharmony_ci tcf = rcu_dereference_bh(q->root.filter_list); 11468c2ecf20Sopenharmony_ci while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) { 11478c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT 11488c2ecf20Sopenharmony_ci switch (result) { 11498c2ecf20Sopenharmony_ci case TC_ACT_QUEUED: 11508c2ecf20Sopenharmony_ci case TC_ACT_STOLEN: 11518c2ecf20Sopenharmony_ci case TC_ACT_TRAP: 11528c2ecf20Sopenharmony_ci *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; 11538c2ecf20Sopenharmony_ci fallthrough; 11548c2ecf20Sopenharmony_ci case TC_ACT_SHOT: 11558c2ecf20Sopenharmony_ci return NULL; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci#endif 11588c2ecf20Sopenharmony_ci cl = (struct hfsc_class *)res.class; 11598c2ecf20Sopenharmony_ci if (!cl) { 11608c2ecf20Sopenharmony_ci cl = hfsc_find_class(res.classid, sch); 11618c2ecf20Sopenharmony_ci if (!cl) 11628c2ecf20Sopenharmony_ci break; /* filter selected invalid classid */ 11638c2ecf20Sopenharmony_ci if (cl->level >= head->level) 11648c2ecf20Sopenharmony_ci break; /* filter may only point downwards */ 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (cl->level == 0) 11688c2ecf20Sopenharmony_ci return cl; /* hit leaf class */ 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* apply inner filter chain */ 11718c2ecf20Sopenharmony_ci tcf = rcu_dereference_bh(cl->filter_list); 11728c2ecf20Sopenharmony_ci head = cl; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* classification failed, try default class */ 11768c2ecf20Sopenharmony_ci cl = hfsc_find_class(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch); 11778c2ecf20Sopenharmony_ci if (cl == NULL || cl->level > 0) 11788c2ecf20Sopenharmony_ci return NULL; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return cl; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic int 11848c2ecf20Sopenharmony_cihfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, 11858c2ecf20Sopenharmony_ci struct Qdisc **old, struct netlink_ext_ack *extack) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (cl->level > 0) 11908c2ecf20Sopenharmony_ci return -EINVAL; 11918c2ecf20Sopenharmony_ci if (new == NULL) { 11928c2ecf20Sopenharmony_ci new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, 11938c2ecf20Sopenharmony_ci cl->cl_common.classid, NULL); 11948c2ecf20Sopenharmony_ci if (new == NULL) 11958c2ecf20Sopenharmony_ci new = &noop_qdisc; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci *old = qdisc_replace(sch, new, &cl->qdisc); 11998c2ecf20Sopenharmony_ci return 0; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic struct Qdisc * 12038c2ecf20Sopenharmony_cihfsc_class_leaf(struct Qdisc *sch, unsigned long arg) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (cl->level == 0) 12088c2ecf20Sopenharmony_ci return cl->qdisc; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci return NULL; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic void 12148c2ecf20Sopenharmony_cihfsc_qlen_notify(struct Qdisc *sch, unsigned long arg) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* vttree is now handled in update_vf() so that update_vf(cl, 0, 0) 12198c2ecf20Sopenharmony_ci * needs to be called explicitly to remove a class from vttree. 12208c2ecf20Sopenharmony_ci */ 12218c2ecf20Sopenharmony_ci update_vf(cl, 0, 0); 12228c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_RSC) 12238c2ecf20Sopenharmony_ci eltree_remove(cl); 12248c2ecf20Sopenharmony_ci} 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_cistatic unsigned long 12278c2ecf20Sopenharmony_cihfsc_search_class(struct Qdisc *sch, u32 classid) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci return (unsigned long)hfsc_find_class(classid, sch); 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cistatic unsigned long 12338c2ecf20Sopenharmony_cihfsc_bind_tcf(struct Qdisc *sch, unsigned long parent, u32 classid) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct hfsc_class *p = (struct hfsc_class *)parent; 12368c2ecf20Sopenharmony_ci struct hfsc_class *cl = hfsc_find_class(classid, sch); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (cl != NULL) { 12398c2ecf20Sopenharmony_ci if (p != NULL && p->level <= cl->level) 12408c2ecf20Sopenharmony_ci return 0; 12418c2ecf20Sopenharmony_ci cl->filter_cnt++; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return (unsigned long)cl; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic void 12488c2ecf20Sopenharmony_cihfsc_unbind_tcf(struct Qdisc *sch, unsigned long arg) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci cl->filter_cnt--; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic struct tcf_block *hfsc_tcf_block(struct Qdisc *sch, unsigned long arg, 12568c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 12598c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (cl == NULL) 12628c2ecf20Sopenharmony_ci cl = &q->root; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci return cl->block; 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cistatic int 12688c2ecf20Sopenharmony_cihfsc_dump_sc(struct sk_buff *skb, int attr, struct internal_sc *sc) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci struct tc_service_curve tsc; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci tsc.m1 = sm2m(sc->sm1); 12738c2ecf20Sopenharmony_ci tsc.d = dx2d(sc->dx); 12748c2ecf20Sopenharmony_ci tsc.m2 = sm2m(sc->sm2); 12758c2ecf20Sopenharmony_ci if (nla_put(skb, attr, sizeof(tsc), &tsc)) 12768c2ecf20Sopenharmony_ci goto nla_put_failure; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci return skb->len; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci nla_put_failure: 12818c2ecf20Sopenharmony_ci return -1; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic int 12858c2ecf20Sopenharmony_cihfsc_dump_curves(struct sk_buff *skb, struct hfsc_class *cl) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci if ((cl->cl_flags & HFSC_RSC) && 12888c2ecf20Sopenharmony_ci (hfsc_dump_sc(skb, TCA_HFSC_RSC, &cl->cl_rsc) < 0)) 12898c2ecf20Sopenharmony_ci goto nla_put_failure; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if ((cl->cl_flags & HFSC_FSC) && 12928c2ecf20Sopenharmony_ci (hfsc_dump_sc(skb, TCA_HFSC_FSC, &cl->cl_fsc) < 0)) 12938c2ecf20Sopenharmony_ci goto nla_put_failure; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if ((cl->cl_flags & HFSC_USC) && 12968c2ecf20Sopenharmony_ci (hfsc_dump_sc(skb, TCA_HFSC_USC, &cl->cl_usc) < 0)) 12978c2ecf20Sopenharmony_ci goto nla_put_failure; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci return skb->len; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci nla_put_failure: 13028c2ecf20Sopenharmony_ci return -1; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic int 13068c2ecf20Sopenharmony_cihfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, 13078c2ecf20Sopenharmony_ci struct tcmsg *tcm) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 13108c2ecf20Sopenharmony_ci struct nlattr *nest; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->cl_common.classid : 13138c2ecf20Sopenharmony_ci TC_H_ROOT; 13148c2ecf20Sopenharmony_ci tcm->tcm_handle = cl->cl_common.classid; 13158c2ecf20Sopenharmony_ci if (cl->level == 0) 13168c2ecf20Sopenharmony_ci tcm->tcm_info = cl->qdisc->handle; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 13198c2ecf20Sopenharmony_ci if (nest == NULL) 13208c2ecf20Sopenharmony_ci goto nla_put_failure; 13218c2ecf20Sopenharmony_ci if (hfsc_dump_curves(skb, cl) < 0) 13228c2ecf20Sopenharmony_ci goto nla_put_failure; 13238c2ecf20Sopenharmony_ci return nla_nest_end(skb, nest); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci nla_put_failure: 13268c2ecf20Sopenharmony_ci nla_nest_cancel(skb, nest); 13278c2ecf20Sopenharmony_ci return -EMSGSIZE; 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic int 13318c2ecf20Sopenharmony_cihfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg, 13328c2ecf20Sopenharmony_ci struct gnet_dump *d) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct hfsc_class *cl = (struct hfsc_class *)arg; 13358c2ecf20Sopenharmony_ci struct tc_hfsc_stats xstats; 13368c2ecf20Sopenharmony_ci __u32 qlen; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci qdisc_qstats_qlen_backlog(cl->qdisc, &qlen, &cl->qstats.backlog); 13398c2ecf20Sopenharmony_ci xstats.level = cl->level; 13408c2ecf20Sopenharmony_ci xstats.period = cl->cl_vtperiod; 13418c2ecf20Sopenharmony_ci xstats.work = cl->cl_total; 13428c2ecf20Sopenharmony_ci xstats.rtwork = cl->cl_cumul; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d, NULL, &cl->bstats) < 0 || 13458c2ecf20Sopenharmony_ci gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || 13468c2ecf20Sopenharmony_ci gnet_stats_copy_queue(d, NULL, &cl->qstats, qlen) < 0) 13478c2ecf20Sopenharmony_ci return -1; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_cistatic void 13558c2ecf20Sopenharmony_cihfsc_walk(struct Qdisc *sch, struct qdisc_walker *arg) 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 13588c2ecf20Sopenharmony_ci struct hfsc_class *cl; 13598c2ecf20Sopenharmony_ci unsigned int i; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (arg->stop) 13628c2ecf20Sopenharmony_ci return; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci for (i = 0; i < q->clhash.hashsize; i++) { 13658c2ecf20Sopenharmony_ci hlist_for_each_entry(cl, &q->clhash.hash[i], 13668c2ecf20Sopenharmony_ci cl_common.hnode) { 13678c2ecf20Sopenharmony_ci if (arg->count < arg->skip) { 13688c2ecf20Sopenharmony_ci arg->count++; 13698c2ecf20Sopenharmony_ci continue; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci if (arg->fn(sch, (unsigned long)cl, arg) < 0) { 13728c2ecf20Sopenharmony_ci arg->stop = 1; 13738c2ecf20Sopenharmony_ci return; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci arg->count++; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic void 13818c2ecf20Sopenharmony_cihfsc_schedule_watchdog(struct Qdisc *sch) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 13848c2ecf20Sopenharmony_ci struct hfsc_class *cl; 13858c2ecf20Sopenharmony_ci u64 next_time = 0; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci cl = eltree_get_minel(q); 13888c2ecf20Sopenharmony_ci if (cl) 13898c2ecf20Sopenharmony_ci next_time = cl->cl_e; 13908c2ecf20Sopenharmony_ci if (q->root.cl_cfmin != 0) { 13918c2ecf20Sopenharmony_ci if (next_time == 0 || next_time > q->root.cl_cfmin) 13928c2ecf20Sopenharmony_ci next_time = q->root.cl_cfmin; 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci if (next_time) 13958c2ecf20Sopenharmony_ci qdisc_watchdog_schedule(&q->watchdog, next_time); 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic int 13998c2ecf20Sopenharmony_cihfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt, 14008c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 14038c2ecf20Sopenharmony_ci struct tc_hfsc_qopt *qopt; 14048c2ecf20Sopenharmony_ci int err; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci qdisc_watchdog_init(&q->watchdog, sch); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (!opt || nla_len(opt) < sizeof(*qopt)) 14098c2ecf20Sopenharmony_ci return -EINVAL; 14108c2ecf20Sopenharmony_ci qopt = nla_data(opt); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci q->defcls = qopt->defcls; 14138c2ecf20Sopenharmony_ci err = qdisc_class_hash_init(&q->clhash); 14148c2ecf20Sopenharmony_ci if (err < 0) 14158c2ecf20Sopenharmony_ci return err; 14168c2ecf20Sopenharmony_ci q->eligible = RB_ROOT; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci err = tcf_block_get(&q->root.block, &q->root.filter_list, sch, extack); 14198c2ecf20Sopenharmony_ci if (err) 14208c2ecf20Sopenharmony_ci return err; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci q->root.cl_common.classid = sch->handle; 14238c2ecf20Sopenharmony_ci q->root.sched = q; 14248c2ecf20Sopenharmony_ci q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, 14258c2ecf20Sopenharmony_ci sch->handle, NULL); 14268c2ecf20Sopenharmony_ci if (q->root.qdisc == NULL) 14278c2ecf20Sopenharmony_ci q->root.qdisc = &noop_qdisc; 14288c2ecf20Sopenharmony_ci else 14298c2ecf20Sopenharmony_ci qdisc_hash_add(q->root.qdisc, true); 14308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&q->root.children); 14318c2ecf20Sopenharmony_ci q->root.vt_tree = RB_ROOT; 14328c2ecf20Sopenharmony_ci q->root.cf_tree = RB_ROOT; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci qdisc_class_hash_insert(&q->clhash, &q->root.cl_common); 14358c2ecf20Sopenharmony_ci qdisc_class_hash_grow(sch, &q->clhash); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci return 0; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistatic int 14418c2ecf20Sopenharmony_cihfsc_change_qdisc(struct Qdisc *sch, struct nlattr *opt, 14428c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 14458c2ecf20Sopenharmony_ci struct tc_hfsc_qopt *qopt; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (opt == NULL || nla_len(opt) < sizeof(*qopt)) 14488c2ecf20Sopenharmony_ci return -EINVAL; 14498c2ecf20Sopenharmony_ci qopt = nla_data(opt); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci sch_tree_lock(sch); 14528c2ecf20Sopenharmony_ci q->defcls = qopt->defcls; 14538c2ecf20Sopenharmony_ci sch_tree_unlock(sch); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci return 0; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic void 14598c2ecf20Sopenharmony_cihfsc_reset_class(struct hfsc_class *cl) 14608c2ecf20Sopenharmony_ci{ 14618c2ecf20Sopenharmony_ci cl->cl_total = 0; 14628c2ecf20Sopenharmony_ci cl->cl_cumul = 0; 14638c2ecf20Sopenharmony_ci cl->cl_d = 0; 14648c2ecf20Sopenharmony_ci cl->cl_e = 0; 14658c2ecf20Sopenharmony_ci cl->cl_vt = 0; 14668c2ecf20Sopenharmony_ci cl->cl_vtadj = 0; 14678c2ecf20Sopenharmony_ci cl->cl_cvtmin = 0; 14688c2ecf20Sopenharmony_ci cl->cl_cvtoff = 0; 14698c2ecf20Sopenharmony_ci cl->cl_vtperiod = 0; 14708c2ecf20Sopenharmony_ci cl->cl_parentperiod = 0; 14718c2ecf20Sopenharmony_ci cl->cl_f = 0; 14728c2ecf20Sopenharmony_ci cl->cl_myf = 0; 14738c2ecf20Sopenharmony_ci cl->cl_cfmin = 0; 14748c2ecf20Sopenharmony_ci cl->cl_nactive = 0; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci cl->vt_tree = RB_ROOT; 14778c2ecf20Sopenharmony_ci cl->cf_tree = RB_ROOT; 14788c2ecf20Sopenharmony_ci qdisc_reset(cl->qdisc); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_RSC) 14818c2ecf20Sopenharmony_ci rtsc_init(&cl->cl_deadline, &cl->cl_rsc, 0, 0); 14828c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_FSC) 14838c2ecf20Sopenharmony_ci rtsc_init(&cl->cl_virtual, &cl->cl_fsc, 0, 0); 14848c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_USC) 14858c2ecf20Sopenharmony_ci rtsc_init(&cl->cl_ulimit, &cl->cl_usc, 0, 0); 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_cistatic void 14898c2ecf20Sopenharmony_cihfsc_reset_qdisc(struct Qdisc *sch) 14908c2ecf20Sopenharmony_ci{ 14918c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 14928c2ecf20Sopenharmony_ci struct hfsc_class *cl; 14938c2ecf20Sopenharmony_ci unsigned int i; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci for (i = 0; i < q->clhash.hashsize; i++) { 14968c2ecf20Sopenharmony_ci hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode) 14978c2ecf20Sopenharmony_ci hfsc_reset_class(cl); 14988c2ecf20Sopenharmony_ci } 14998c2ecf20Sopenharmony_ci q->eligible = RB_ROOT; 15008c2ecf20Sopenharmony_ci qdisc_watchdog_cancel(&q->watchdog); 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_cistatic void 15048c2ecf20Sopenharmony_cihfsc_destroy_qdisc(struct Qdisc *sch) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 15078c2ecf20Sopenharmony_ci struct hlist_node *next; 15088c2ecf20Sopenharmony_ci struct hfsc_class *cl; 15098c2ecf20Sopenharmony_ci unsigned int i; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci for (i = 0; i < q->clhash.hashsize; i++) { 15128c2ecf20Sopenharmony_ci hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode) { 15138c2ecf20Sopenharmony_ci tcf_block_put(cl->block); 15148c2ecf20Sopenharmony_ci cl->block = NULL; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci for (i = 0; i < q->clhash.hashsize; i++) { 15188c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i], 15198c2ecf20Sopenharmony_ci cl_common.hnode) 15208c2ecf20Sopenharmony_ci hfsc_destroy_class(sch, cl); 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci qdisc_class_hash_destroy(&q->clhash); 15238c2ecf20Sopenharmony_ci qdisc_watchdog_cancel(&q->watchdog); 15248c2ecf20Sopenharmony_ci} 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_cistatic int 15278c2ecf20Sopenharmony_cihfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 15308c2ecf20Sopenharmony_ci unsigned char *b = skb_tail_pointer(skb); 15318c2ecf20Sopenharmony_ci struct tc_hfsc_qopt qopt; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci qopt.defcls = q->defcls; 15348c2ecf20Sopenharmony_ci if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt)) 15358c2ecf20Sopenharmony_ci goto nla_put_failure; 15368c2ecf20Sopenharmony_ci return skb->len; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci nla_put_failure: 15398c2ecf20Sopenharmony_ci nlmsg_trim(skb, b); 15408c2ecf20Sopenharmony_ci return -1; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int 15448c2ecf20Sopenharmony_cihfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci unsigned int len = qdisc_pkt_len(skb); 15478c2ecf20Sopenharmony_ci struct hfsc_class *cl; 15488c2ecf20Sopenharmony_ci int err; 15498c2ecf20Sopenharmony_ci bool first; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci cl = hfsc_classify(skb, sch, &err); 15528c2ecf20Sopenharmony_ci if (cl == NULL) { 15538c2ecf20Sopenharmony_ci if (err & __NET_XMIT_BYPASS) 15548c2ecf20Sopenharmony_ci qdisc_qstats_drop(sch); 15558c2ecf20Sopenharmony_ci __qdisc_drop(skb, to_free); 15568c2ecf20Sopenharmony_ci return err; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci first = !cl->qdisc->q.qlen; 15608c2ecf20Sopenharmony_ci err = qdisc_enqueue(skb, cl->qdisc, to_free); 15618c2ecf20Sopenharmony_ci if (unlikely(err != NET_XMIT_SUCCESS)) { 15628c2ecf20Sopenharmony_ci if (net_xmit_drop_count(err)) { 15638c2ecf20Sopenharmony_ci cl->qstats.drops++; 15648c2ecf20Sopenharmony_ci qdisc_qstats_drop(sch); 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci return err; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (first) { 15708c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_RSC) 15718c2ecf20Sopenharmony_ci init_ed(cl, len); 15728c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_FSC) 15738c2ecf20Sopenharmony_ci init_vf(cl, len); 15748c2ecf20Sopenharmony_ci /* 15758c2ecf20Sopenharmony_ci * If this is the first packet, isolate the head so an eventual 15768c2ecf20Sopenharmony_ci * head drop before the first dequeue operation has no chance 15778c2ecf20Sopenharmony_ci * to invalidate the deadline. 15788c2ecf20Sopenharmony_ci */ 15798c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_RSC) 15808c2ecf20Sopenharmony_ci cl->qdisc->ops->peek(cl->qdisc); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci sch->qstats.backlog += len; 15858c2ecf20Sopenharmony_ci sch->q.qlen++; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci return NET_XMIT_SUCCESS; 15888c2ecf20Sopenharmony_ci} 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic struct sk_buff * 15918c2ecf20Sopenharmony_cihfsc_dequeue(struct Qdisc *sch) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci struct hfsc_sched *q = qdisc_priv(sch); 15948c2ecf20Sopenharmony_ci struct hfsc_class *cl; 15958c2ecf20Sopenharmony_ci struct sk_buff *skb; 15968c2ecf20Sopenharmony_ci u64 cur_time; 15978c2ecf20Sopenharmony_ci unsigned int next_len; 15988c2ecf20Sopenharmony_ci int realtime = 0; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (sch->q.qlen == 0) 16018c2ecf20Sopenharmony_ci return NULL; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci cur_time = psched_get_time(); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci /* 16068c2ecf20Sopenharmony_ci * if there are eligible classes, use real-time criteria. 16078c2ecf20Sopenharmony_ci * find the class with the minimum deadline among 16088c2ecf20Sopenharmony_ci * the eligible classes. 16098c2ecf20Sopenharmony_ci */ 16108c2ecf20Sopenharmony_ci cl = eltree_get_mindl(q, cur_time); 16118c2ecf20Sopenharmony_ci if (cl) { 16128c2ecf20Sopenharmony_ci realtime = 1; 16138c2ecf20Sopenharmony_ci } else { 16148c2ecf20Sopenharmony_ci /* 16158c2ecf20Sopenharmony_ci * use link-sharing criteria 16168c2ecf20Sopenharmony_ci * get the class with the minimum vt in the hierarchy 16178c2ecf20Sopenharmony_ci */ 16188c2ecf20Sopenharmony_ci cl = vttree_get_minvt(&q->root, cur_time); 16198c2ecf20Sopenharmony_ci if (cl == NULL) { 16208c2ecf20Sopenharmony_ci qdisc_qstats_overlimit(sch); 16218c2ecf20Sopenharmony_ci hfsc_schedule_watchdog(sch); 16228c2ecf20Sopenharmony_ci return NULL; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci skb = qdisc_dequeue_peeked(cl->qdisc); 16278c2ecf20Sopenharmony_ci if (skb == NULL) { 16288c2ecf20Sopenharmony_ci qdisc_warn_nonwc("HFSC", cl->qdisc); 16298c2ecf20Sopenharmony_ci return NULL; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci bstats_update(&cl->bstats, skb); 16338c2ecf20Sopenharmony_ci update_vf(cl, qdisc_pkt_len(skb), cur_time); 16348c2ecf20Sopenharmony_ci if (realtime) 16358c2ecf20Sopenharmony_ci cl->cl_cumul += qdisc_pkt_len(skb); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci if (cl->cl_flags & HFSC_RSC) { 16388c2ecf20Sopenharmony_ci if (cl->qdisc->q.qlen != 0) { 16398c2ecf20Sopenharmony_ci /* update ed */ 16408c2ecf20Sopenharmony_ci next_len = qdisc_peek_len(cl->qdisc); 16418c2ecf20Sopenharmony_ci if (realtime) 16428c2ecf20Sopenharmony_ci update_ed(cl, next_len); 16438c2ecf20Sopenharmony_ci else 16448c2ecf20Sopenharmony_ci update_d(cl, next_len); 16458c2ecf20Sopenharmony_ci } else { 16468c2ecf20Sopenharmony_ci /* the class becomes passive */ 16478c2ecf20Sopenharmony_ci eltree_remove(cl); 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci qdisc_bstats_update(sch, skb); 16528c2ecf20Sopenharmony_ci qdisc_qstats_backlog_dec(sch, skb); 16538c2ecf20Sopenharmony_ci sch->q.qlen--; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci return skb; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic const struct Qdisc_class_ops hfsc_class_ops = { 16598c2ecf20Sopenharmony_ci .change = hfsc_change_class, 16608c2ecf20Sopenharmony_ci .delete = hfsc_delete_class, 16618c2ecf20Sopenharmony_ci .graft = hfsc_graft_class, 16628c2ecf20Sopenharmony_ci .leaf = hfsc_class_leaf, 16638c2ecf20Sopenharmony_ci .qlen_notify = hfsc_qlen_notify, 16648c2ecf20Sopenharmony_ci .find = hfsc_search_class, 16658c2ecf20Sopenharmony_ci .bind_tcf = hfsc_bind_tcf, 16668c2ecf20Sopenharmony_ci .unbind_tcf = hfsc_unbind_tcf, 16678c2ecf20Sopenharmony_ci .tcf_block = hfsc_tcf_block, 16688c2ecf20Sopenharmony_ci .dump = hfsc_dump_class, 16698c2ecf20Sopenharmony_ci .dump_stats = hfsc_dump_class_stats, 16708c2ecf20Sopenharmony_ci .walk = hfsc_walk 16718c2ecf20Sopenharmony_ci}; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_cistatic struct Qdisc_ops hfsc_qdisc_ops __read_mostly = { 16748c2ecf20Sopenharmony_ci .id = "hfsc", 16758c2ecf20Sopenharmony_ci .init = hfsc_init_qdisc, 16768c2ecf20Sopenharmony_ci .change = hfsc_change_qdisc, 16778c2ecf20Sopenharmony_ci .reset = hfsc_reset_qdisc, 16788c2ecf20Sopenharmony_ci .destroy = hfsc_destroy_qdisc, 16798c2ecf20Sopenharmony_ci .dump = hfsc_dump_qdisc, 16808c2ecf20Sopenharmony_ci .enqueue = hfsc_enqueue, 16818c2ecf20Sopenharmony_ci .dequeue = hfsc_dequeue, 16828c2ecf20Sopenharmony_ci .peek = qdisc_peek_dequeued, 16838c2ecf20Sopenharmony_ci .cl_ops = &hfsc_class_ops, 16848c2ecf20Sopenharmony_ci .priv_size = sizeof(struct hfsc_sched), 16858c2ecf20Sopenharmony_ci .owner = THIS_MODULE 16868c2ecf20Sopenharmony_ci}; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cistatic int __init 16898c2ecf20Sopenharmony_cihfsc_init(void) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci return register_qdisc(&hfsc_qdisc_ops); 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_cistatic void __exit 16958c2ecf20Sopenharmony_cihfsc_cleanup(void) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci unregister_qdisc(&hfsc_qdisc_ops); 16988c2ecf20Sopenharmony_ci} 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 17018c2ecf20Sopenharmony_cimodule_init(hfsc_init); 17028c2ecf20Sopenharmony_cimodule_exit(hfsc_cleanup); 1703