and changed files
[powerpc.git] / net / sched / sch_cbq.c
index 48830ca..a294542 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/socket.h>
@@ -30,6 +29,7 @@
 #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <net/ip.h>
+#include <net/netlink.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -113,7 +113,7 @@ struct cbq_class
 
        /* Overlimit strategy parameters */
        void                    (*overlimit)(struct cbq_class *cl);
-       long                    penalty;
+       psched_tdiff_t          penalty;
 
        /* General scheduler (WRR) parameters */
        long                    allot;
@@ -144,7 +144,7 @@ struct cbq_class
        psched_time_t           undertime;
        long                    avgidle;
        long                    deficit;        /* Saved deficit for WRR */
-       unsigned long           penalized;
+       psched_time_t           penalized;
        struct gnet_stats_basic bstats;
        struct gnet_stats_queue qstats;
        struct gnet_stats_rate_est rate_est;
@@ -181,12 +181,12 @@ struct cbq_sched_data
        psched_time_t           now_rt;         /* Cached real time */
        unsigned                pmask;
 
-       struct timer_list       delay_timer;
-       struct timer_list       wd_timer;       /* Watchdog timer,
+       struct hrtimer          delay_timer;
+       struct qdisc_watchdog   watchdog;       /* Watchdog timer,
                                                   started when CBQ has
                                                   backlog, but cannot
                                                   transmit just now */
-       long                    wd_expires;
+       psched_tdiff_t          wd_expires;
        int                     toplevel;
        u32                     hgenerator;
 };
@@ -385,12 +385,12 @@ cbq_mark_toplevel(struct cbq_sched_data *q, struct cbq_class *cl)
                psched_time_t now;
                psched_tdiff_t incr;
 
-               PSCHED_GET_TIME(now);
-               incr = PSCHED_TDIFF(now, q->now_rt);
-               PSCHED_TADD2(q->now, incr, now);
+               now = psched_get_time();
+               incr = now - q->now_rt;
+               now = q->now + incr;
 
                do {
-                       if (PSCHED_TLESS(cl->undertime, now)) {
+                       if (cl->undertime < now) {
                                q->toplevel = cl->level;
                                return;
                        }
@@ -474,7 +474,7 @@ cbq_requeue(struct sk_buff *skb, struct Qdisc *sch)
 static void cbq_ovl_classic(struct cbq_class *cl)
 {
        struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
-       psched_tdiff_t delay = PSCHED_TDIFF(cl->undertime, q->now);
+       psched_tdiff_t delay = cl->undertime - q->now;
 
        if (!cl->delayed) {
                delay += cl->offtime;
@@ -492,7 +492,7 @@ static void cbq_ovl_classic(struct cbq_class *cl)
                        cl->avgidle = cl->minidle;
                if (delay <= 0)
                        delay = 1;
-               PSCHED_TADD2(q->now, delay, cl->undertime);
+               cl->undertime = q->now + delay;
 
                cl->xstats.overactions++;
                cl->delayed = 1;
@@ -509,7 +509,7 @@ static void cbq_ovl_classic(struct cbq_class *cl)
                psched_tdiff_t base_delay = q->wd_expires;
 
                for (b = cl->borrow; b; b = b->borrow) {
-                       delay = PSCHED_TDIFF(b->undertime, q->now);
+                       delay = b->undertime - q->now;
                        if (delay < base_delay) {
                                if (delay <= 0)
                                        delay = 1;
@@ -547,27 +547,32 @@ static void cbq_ovl_rclassic(struct cbq_class *cl)
 static void cbq_ovl_delay(struct cbq_class *cl)
 {
        struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
-       psched_tdiff_t delay = PSCHED_TDIFF(cl->undertime, q->now);
+       psched_tdiff_t delay = cl->undertime - q->now;
 
        if (!cl->delayed) {
-               unsigned long sched = jiffies;
+               psched_time_t sched = q->now;
+               ktime_t expires;
 
                delay += cl->offtime;
                if (cl->avgidle < 0)
                        delay -= (-cl->avgidle) - ((-cl->avgidle) >> cl->ewma_log);
                if (cl->avgidle < cl->minidle)
                        cl->avgidle = cl->minidle;
-               PSCHED_TADD2(q->now, delay, cl->undertime);
+               cl->undertime = q->now + delay;
 
                if (delay > 0) {
-                       sched += PSCHED_US2JIFFIE(delay) + cl->penalty;
+                       sched += delay + cl->penalty;
                        cl->penalized = sched;
                        cl->cpriority = TC_CBQ_MAXPRIO;
                        q->pmask |= (1<<TC_CBQ_MAXPRIO);
-                       if (del_timer(&q->delay_timer) &&
-                           (long)(q->delay_timer.expires - sched) > 0)
-                               q->delay_timer.expires = sched;
-                       add_timer(&q->delay_timer);
+
+                       expires = ktime_set(0, 0);
+                       expires = ktime_add_ns(expires, PSCHED_US2NS(sched));
+                       if (hrtimer_try_to_cancel(&q->delay_timer) &&
+                           ktime_to_ns(ktime_sub(q->delay_timer.expires,
+                                                 expires)) > 0)
+                               q->delay_timer.expires = expires;
+                       hrtimer_restart(&q->delay_timer);
                        cl->delayed = 1;
                        cl->xstats.overactions++;
                        return;
@@ -584,7 +589,7 @@ static void cbq_ovl_lowprio(struct cbq_class *cl)
 {
        struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
 
-       cl->penalized = jiffies + cl->penalty;
+       cl->penalized = q->now + cl->penalty;
 
        if (cl->cpriority != cl->priority2) {
                cl->cpriority = cl->priority2;
@@ -605,27 +610,19 @@ static void cbq_ovl_drop(struct cbq_class *cl)
        cbq_ovl_classic(cl);
 }
 
-static void cbq_watchdog(unsigned long arg)
-{
-       struct Qdisc *sch = (struct Qdisc*)arg;
-
-       sch->flags &= ~TCQ_F_THROTTLED;
-       netif_schedule(sch->dev);
-}
-
-static unsigned long cbq_undelay_prio(struct cbq_sched_data *q, int prio)
+static psched_tdiff_t cbq_undelay_prio(struct cbq_sched_data *q, int prio,
+                                      psched_time_t now)
 {
        struct cbq_class *cl;
        struct cbq_class *cl_prev = q->active[prio];
-       unsigned long now = jiffies;
-       unsigned long sched = now;
+       psched_time_t sched = now;
 
        if (cl_prev == NULL)
-               return now;
+               return 0;
 
        do {
                cl = cl_prev->next_alive;
-               if ((long)(now - cl->penalized) > 0) {
+               if (now - cl->penalized > 0) {
                        cl_prev->next_alive = cl->next_alive;
                        cl->next_alive = NULL;
                        cl->cpriority = cl->priority;
@@ -641,30 +638,34 @@ static unsigned long cbq_undelay_prio(struct cbq_sched_data *q, int prio)
                        }
 
                        cl = cl_prev->next_alive;
-               } else if ((long)(sched - cl->penalized) > 0)
+               } else if (sched - cl->penalized > 0)
                        sched = cl->penalized;
        } while ((cl_prev = cl) != q->active[prio]);
 
-       return (long)(sched - now);
+       return sched - now;
 }
 
-static void cbq_undelay(unsigned long arg)
+static enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
 {
-       struct Qdisc *sch = (struct Qdisc*)arg;
-       struct cbq_sched_data *q = qdisc_priv(sch);
-       long delay = 0;
+       struct cbq_sched_data *q = container_of(timer, struct cbq_sched_data,
+                                               delay_timer);
+       struct Qdisc *sch = q->watchdog.qdisc;
+       psched_time_t now;
+       psched_tdiff_t delay = 0;
        unsigned pmask;
 
+       now = psched_get_time();
+
        pmask = q->pmask;
        q->pmask = 0;
 
        while (pmask) {
                int prio = ffz(~pmask);
-               long tmp;
+               psched_tdiff_t tmp;
 
                pmask &= ~(1<<prio);
 
-               tmp = cbq_undelay_prio(q, prio);
+               tmp = cbq_undelay_prio(q, prio, now);
                if (tmp > 0) {
                        q->pmask |= 1<<prio;
                        if (tmp < delay || delay == 0)
@@ -673,12 +674,16 @@ static void cbq_undelay(unsigned long arg)
        }
 
        if (delay) {
-               q->delay_timer.expires = jiffies + delay;
-               add_timer(&q->delay_timer);
+               ktime_t time;
+
+               time = ktime_set(0, 0);
+               time = ktime_add_ns(time, PSCHED_US2NS(now + delay));
+               hrtimer_start(&q->delay_timer, time, HRTIMER_MODE_ABS);
        }
 
        sch->flags &= ~TCQ_F_THROTTLED;
        netif_schedule(sch->dev);
+       return HRTIMER_NORESTART;
 }
 
 
@@ -733,7 +738,7 @@ cbq_update_toplevel(struct cbq_sched_data *q, struct cbq_class *cl,
        if (cl && q->toplevel >= borrowed->level) {
                if (cl->q->q.qlen > 1) {
                        do {
-                               if (PSCHED_IS_PASTPERFECT(borrowed->undertime)) {
+                               if (borrowed->undertime == PSCHED_PASTPERFECT) {
                                        q->toplevel = borrowed->level;
                                        return;
                                }
@@ -771,7 +776,7 @@ cbq_update(struct cbq_sched_data *q)
                         idle = (now - last) - last_pktlen/rate
                 */
 
-               idle = PSCHED_TDIFF(q->now, cl->last);
+               idle = q->now - cl->last;
                if ((unsigned long)idle > 128*1024*1024) {
                        avgidle = cl->maxidle;
                } else {
@@ -815,13 +820,11 @@ cbq_update(struct cbq_sched_data *q)
                        idle -= L2T(&q->link, len);
                        idle += L2T(cl, len);
 
-                       PSCHED_AUDIT_TDIFF(idle);
-
-                       PSCHED_TADD2(q->now, idle, cl->undertime);
+                       cl->undertime = q->now + idle;
                } else {
                        /* Underlimit */
 
-                       PSCHED_SET_PASTPERFECT(cl->undertime);
+                       cl->undertime = PSCHED_PASTPERFECT;
                        if (avgidle > cl->maxidle)
                                cl->avgidle = cl->maxidle;
                        else
@@ -842,8 +845,7 @@ cbq_under_limit(struct cbq_class *cl)
        if (cl->tparent == NULL)
                return cl;
 
-       if (PSCHED_IS_PASTPERFECT(cl->undertime) ||
-           !PSCHED_TLESS(q->now, cl->undertime)) {
+       if (cl->undertime == PSCHED_PASTPERFECT || q->now >= cl->undertime) {
                cl->delayed = 0;
                return cl;
        }
@@ -866,8 +868,7 @@ cbq_under_limit(struct cbq_class *cl)
                }
                if (cl->level > q->toplevel)
                        return NULL;
-       } while (!PSCHED_IS_PASTPERFECT(cl->undertime) &&
-                PSCHED_TLESS(q->now, cl->undertime));
+       } while (cl->undertime != PSCHED_PASTPERFECT && q->now < cl->undertime);
 
        cl->delayed = 0;
        return cl;
@@ -1002,8 +1003,8 @@ cbq_dequeue(struct Qdisc *sch)
        psched_time_t now;
        psched_tdiff_t incr;
 
-       PSCHED_GET_TIME(now);
-       incr = PSCHED_TDIFF(now, q->now_rt);
+       now = psched_get_time();
+       incr = now - q->now_rt;
 
        if (q->tx_class) {
                psched_tdiff_t incr2;
@@ -1015,12 +1016,12 @@ cbq_dequeue(struct Qdisc *sch)
                   cbq_time = max(real_time, work);
                 */
                incr2 = L2T(&q->link, q->tx_len);
-               PSCHED_TADD(q->now, incr2);
+               q->now += incr2;
                cbq_update(q);
                if ((incr -= incr2) < 0)
                        incr = 0;
        }
-       PSCHED_TADD(q->now, incr);
+       q->now += incr;
        q->now_rt = now;
 
        for (;;) {
@@ -1052,11 +1053,11 @@ cbq_dequeue(struct Qdisc *sch)
                */
 
                if (q->toplevel == TC_CBQ_MAXLEVEL &&
-                   PSCHED_IS_PASTPERFECT(q->link.undertime))
+                   q->link.undertime == PSCHED_PASTPERFECT)
                        break;
 
                q->toplevel = TC_CBQ_MAXLEVEL;
-               PSCHED_SET_PASTPERFECT(q->link.undertime);
+               q->link.undertime = PSCHED_PASTPERFECT;
        }
 
        /* No packets in scheduler or nobody wants to give them to us :-(
@@ -1064,13 +1065,9 @@ cbq_dequeue(struct Qdisc *sch)
 
        if (sch->q.qlen) {
                sch->qstats.overlimits++;
-               if (q->wd_expires) {
-                       long delay = PSCHED_US2JIFFIE(q->wd_expires);
-                       if (delay <= 0)
-                               delay = 1;
-                       mod_timer(&q->wd_timer, jiffies + delay);
-                       sch->flags |= TCQ_F_THROTTLED;
-               }
+               if (q->wd_expires)
+                       qdisc_watchdog_schedule(&q->watchdog,
+                                               now + q->wd_expires);
        }
        return NULL;
 }
@@ -1277,10 +1274,10 @@ cbq_reset(struct Qdisc* sch)
        q->pmask = 0;
        q->tx_class = NULL;
        q->tx_borrowed = NULL;
-       del_timer(&q->wd_timer);
-       del_timer(&q->delay_timer);
+       qdisc_watchdog_cancel(&q->watchdog);
+       hrtimer_cancel(&q->delay_timer);
        q->toplevel = TC_CBQ_MAXLEVEL;
-       PSCHED_GET_TIME(q->now);
+       q->now = psched_get_time();
        q->now_rt = q->now;
 
        for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++)
@@ -1291,7 +1288,7 @@ cbq_reset(struct Qdisc* sch)
                        qdisc_reset(cl->q);
 
                        cl->next_alive = NULL;
-                       PSCHED_SET_PASTPERFECT(cl->undertime);
+                       cl->undertime = PSCHED_PASTPERFECT;
                        cl->avgidle = cl->maxidle;
                        cl->deficit = cl->quantum;
                        cl->cpriority = cl->priority;
@@ -1380,7 +1377,7 @@ static int cbq_set_overlimit(struct cbq_class *cl, struct tc_cbq_ovl *ovl)
        default:
                return -EINVAL;
        }
-       cl->penalty = (ovl->penalty*HZ)/1000;
+       cl->penalty = ovl->penalty;
        return 0;
 }
 
@@ -1447,14 +1444,11 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt)
        q->link.minidle = -0x7FFFFFFF;
        q->link.stats_lock = &sch->dev->queue_lock;
 
-       init_timer(&q->wd_timer);
-       q->wd_timer.data = (unsigned long)sch;
-       q->wd_timer.function = cbq_watchdog;
-       init_timer(&q->delay_timer);
-       q->delay_timer.data = (unsigned long)sch;
+       qdisc_watchdog_init(&q->watchdog, sch);
+       hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
        q->delay_timer.function = cbq_undelay;
        q->toplevel = TC_CBQ_MAXLEVEL;
-       PSCHED_GET_TIME(q->now);
+       q->now = psched_get_time();
        q->now_rt = q->now;
 
        cbq_link_class(&q->link);
@@ -1468,19 +1462,19 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt)
 
 static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
 {
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
 
        RTA_PUT(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate);
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 
 static __inline__ int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl)
 {
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_lssopt opt;
 
        opt.flags = 0;
@@ -1499,13 +1493,13 @@ static __inline__ int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl)
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 
 static __inline__ int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
 {
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_wrropt opt;
 
        opt.flags = 0;
@@ -1517,30 +1511,30 @@ static __inline__ int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 
 static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl)
 {
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_ovl opt;
 
        opt.strategy = cl->ovl_strategy;
        opt.priority2 = cl->priority2+1;
        opt.pad = 0;
-       opt.penalty = (cl->penalty*1000)/HZ;
+       opt.penalty = cl->penalty;
        RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 
 static __inline__ int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl)
 {
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_fopt opt;
 
        if (cl->split || cl->defmap) {
@@ -1552,14 +1546,14 @@ static __inline__ int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl)
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 
 #ifdef CONFIG_NET_CLS_POLICE
 static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
 {
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_police opt;
 
        if (cl->police) {
@@ -1571,7 +1565,7 @@ static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 #endif
@@ -1593,18 +1587,18 @@ static int cbq_dump_attr(struct sk_buff *skb, struct cbq_class *cl)
 static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
        struct cbq_sched_data *q = qdisc_priv(sch);
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
        struct rtattr *rta;
 
        rta = (struct rtattr*)b;
        RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
        if (cbq_dump_attr(skb, &q->link) < 0)
                goto rtattr_failure;
-       rta->rta_len = skb->tail - b;
+       rta->rta_len = skb_tail_pointer(skb) - b;
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 
@@ -1622,7 +1616,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg,
               struct sk_buff *skb, struct tcmsg *tcm)
 {
        struct cbq_class *cl = (struct cbq_class*)arg;
-       unsigned char    *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
        struct rtattr *rta;
 
        if (cl->tparent)
@@ -1636,11 +1630,11 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg,
        RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
        if (cbq_dump_attr(skb, cl) < 0)
                goto rtattr_failure;
-       rta->rta_len = skb->tail - b;
+       rta->rta_len = skb_tail_pointer(skb) - b;
        return skb->len;
 
 rtattr_failure:
-       skb_trim(skb, b - skb->data);
+       nlmsg_trim(skb, b);
        return -1;
 }
 
@@ -1655,8 +1649,8 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
        cl->xstats.avgidle = cl->avgidle;
        cl->xstats.undertime = 0;
 
-       if (!PSCHED_IS_PASTPERFECT(cl->undertime))
-               cl->xstats.undertime = PSCHED_TDIFF(cl->undertime, q->now);
+       if (cl->undertime != PSCHED_PASTPERFECT)
+               cl->xstats.undertime = cl->undertime - q->now;
 
        if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
 #ifdef CONFIG_NET_ESTIMATOR
@@ -1723,23 +1717,13 @@ static unsigned long cbq_get(struct Qdisc *sch, u32 classid)
        return 0;
 }
 
-static void cbq_destroy_filters(struct cbq_class *cl)
-{
-       struct tcf_proto *tp;
-
-       while ((tp = cl->filter_list) != NULL) {
-               cl->filter_list = tp->next;
-               tcf_destroy(tp);
-       }
-}
-
 static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
 {
        struct cbq_sched_data *q = qdisc_priv(sch);
 
        BUG_TRAP(!cl->filters);
 
-       cbq_destroy_filters(cl);
+       tcf_destroy_chain(cl->filter_list);
        qdisc_destroy(cl->q);
        qdisc_put_rtab(cl->R_tab);
 #ifdef CONFIG_NET_ESTIMATOR
@@ -1766,7 +1750,7 @@ cbq_destroy(struct Qdisc* sch)
         */
        for (h = 0; h < 16; h++)
                for (cl = q->classes[h]; cl; cl = cl->next)
-                       cbq_destroy_filters(cl);
+                       tcf_destroy_chain(cl->filter_list);
 
        for (h = 0; h < 16; h++) {
                struct cbq_class *next;