diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /net/sched/sch_cbq.c | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'net/sched/sch_cbq.c')
-rw-r--r-- | net/sched/sch_cbq.c | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 2244b68ed..0308a02f1 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -176,6 +176,7 @@ struct cbq_sched_data struct cbq_class *tx_borrowed; int tx_len; psched_time_t now; /* Cached timestamp */ + psched_time_t now_rt; /* Cached real time */ unsigned pmask; struct timer_list delay_timer; @@ -191,8 +192,6 @@ struct cbq_sched_data #define L2T(cl,len) ((cl)->R_tab->data[(len)>>(cl)->R_tab->rate.cell_log]) -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - static __inline__ unsigned cbq_hash(u32 h) { @@ -375,9 +374,11 @@ cbq_mark_toplevel(struct cbq_sched_data *q, struct cbq_class *cl) if (toplevel > cl->level && !(cl->q->flags&TCQ_F_THROTTLED)) { psched_time_t now; + psched_tdiff_t incr; + PSCHED_GET_TIME(now); - if (PSCHED_TLESS(now, q->now)) - now = q->now; + incr = PSCHED_TDIFF(now, q->now_rt); + PSCHED_TADD2(q->now, incr, now); do { if (PSCHED_TLESS(cl->undertime, now)) { @@ -394,6 +395,7 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch) struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl = cbq_classify(skb, sch); int len = skb->len; + int ret = NET_XMIT_POLICED; #ifdef CONFIG_NET_CLS_POLICE q->rx_class = cl; @@ -402,14 +404,14 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch) #ifdef CONFIG_NET_CLS_POLICE cl->q->__parent = sch; #endif - if (cl->q->enqueue(skb, cl->q) == 1) { + if ((ret = cl->q->enqueue(skb, cl->q)) == 0) { sch->q.qlen++; sch->stats.packets++; sch->stats.bytes+=len; cbq_mark_toplevel(q, cl); if (!cl->next_alive) cbq_activate_class(cl); - return 1; + return 0; } } @@ -420,7 +422,7 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch) cbq_mark_toplevel(q, cl); cl->stats.drops++; } - return 0; + return ret; } static int @@ -428,11 +430,12 @@ cbq_requeue(struct sk_buff *skb, struct Qdisc *sch) { struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl; + int ret; if ((cl = q->tx_class) == NULL) { kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_CN; } q->tx_class = NULL; @@ -442,15 +445,15 @@ cbq_requeue(struct sk_buff *skb, struct Qdisc *sch) q->rx_class = cl; cl->q->__parent = sch; #endif - if (cl->q->ops->requeue(skb, cl->q) == 1) { + if ((ret = cl->q->ops->requeue(skb, cl->q)) == 0) { sch->q.qlen++; if (!cl->next_alive) cbq_activate_class(cl); - return 1; + return 0; } sch->stats.drops++; cl->stats.drops++; - return 0; + return ret; } /* Overlimit actions */ @@ -685,7 +688,7 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child) q->rx_class = cl; cl->q->__parent = sch; - if (cl->q->enqueue(skb, cl->q) == 1) { + if (cl->q->enqueue(skb, cl->q) == 0) { sch->q.qlen++; sch->stats.packets++; sch->stats.bytes+=len; @@ -756,14 +759,19 @@ cbq_update(struct cbq_sched_data *q) idle = (now - last) - last_pktlen/rate */ - idle = PSCHED_TDIFF(q->now, cl->last) - L2T(cl, len); + idle = PSCHED_TDIFF(q->now, cl->last); + if ((unsigned long)idle > 128*1024*1024) { + avgidle = cl->maxidle; + } else { + idle -= L2T(cl, len); /* true_avgidle := (1-W)*true_avgidle + W*idle, where W=2^{-ewma_log}. But cl->avgidle is scaled: cl->avgidle == true_avgidle/W, hence: */ - avgidle += idle - (avgidle>>cl->ewma_log); + avgidle += idle - (avgidle>>cl->ewma_log); + } if (avgidle <= 0) { /* Overlimit or at-limit */ @@ -980,10 +988,13 @@ cbq_dequeue(struct Qdisc *sch) struct sk_buff *skb; struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; psched_time_t now; + psched_tdiff_t incr; PSCHED_GET_TIME(now); + incr = PSCHED_TDIFF(now, q->now_rt); if (q->tx_class) { + psched_tdiff_t incr2; /* Time integrator. We calculate EOS time by adding expected packet transmittion time. If real time is greater, we warp artificial clock, @@ -991,12 +1002,14 @@ cbq_dequeue(struct Qdisc *sch) cbq_time = max(real_time, work); */ - PSCHED_TADD(q->now, L2T(&q->link, q->tx_len)); - if (PSCHED_TLESS(q->now, now)) - q->now = now; + incr2 = L2T(&q->link, q->tx_len); + PSCHED_TADD(q->now, incr2); cbq_update(q); - } else if (PSCHED_TLESS(q->now, now)) - q->now = now; + if ((incr -= incr2) < 0) + incr = 0; + } + PSCHED_TADD(q->now, incr); + q->now_rt = now; for (;;) { q->wd_expires = 0; @@ -1224,7 +1237,7 @@ static int cbq_drop(struct Qdisc* sch) struct cbq_class *cl, *cl_head; int prio; - for (prio = TC_CBQ_MAXPRIO; prio >= 0; prio++) { + for (prio = TC_CBQ_MAXPRIO; prio >= 0; prio--) { if ((cl_head = q->active[prio]) == NULL) continue; @@ -1252,6 +1265,8 @@ cbq_reset(struct Qdisc* sch) del_timer(&q->wd_timer); del_timer(&q->delay_timer); q->toplevel = TC_CBQ_MAXLEVEL; + PSCHED_GET_TIME(q->now); + q->now_rt = q->now; for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++) q->active[prio] = NULL; @@ -1426,6 +1441,8 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt) q->delay_timer.data = (unsigned long)sch; q->delay_timer.function = cbq_undelay; q->toplevel = TC_CBQ_MAXLEVEL; + PSCHED_GET_TIME(q->now); + q->now_rt = q->now; cbq_link_class(&q->link); @@ -1561,7 +1578,7 @@ static int cbq_dump_attr(struct sk_buff *skb, struct cbq_class *cl) int cbq_copy_xstats(struct sk_buff *skb, struct tc_cbq_xstats *st) { - RTA_PUT(skb, TCA_STATS, sizeof(*st), st); + RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st); return 0; rtattr_failure: @@ -1838,7 +1855,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t if (cl->q->q.qlen) cbq_activate_class(cl); - sch_tree_lock(sch); + sch_tree_unlock(sch); #ifdef CONFIG_NET_ESTIMATOR if (tca[TCA_RATE-1]) { |