[NET_SCHED]: sch_cbq: use hrtimer for delay_timer
[linux-3.10.git] / net / sched / sch_cbq.c
index 32f6a30..0491fad 100644 (file)
@@ -112,7 +112,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;
@@ -143,7 +143,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;
@@ -180,7 +180,7 @@ struct cbq_sched_data
        psched_time_t           now_rt;         /* Cached real time */
        unsigned                pmask;
 
-       struct timer_list       delay_timer;
+       struct hrtimer          delay_timer;
        struct qdisc_watchdog   watchdog;       /* Watchdog timer,
                                                   started when CBQ has
                                                   backlog, but cannot
@@ -549,7 +549,8 @@ static void cbq_ovl_delay(struct cbq_class *cl)
        psched_tdiff_t delay = PSCHED_TDIFF(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)
@@ -559,14 +560,18 @@ static void cbq_ovl_delay(struct cbq_class *cl)
                PSCHED_TADD2(q->now, delay, cl->undertime);
 
                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;
@@ -583,7 +588,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;
@@ -604,19 +609,19 @@ static void cbq_ovl_drop(struct cbq_class *cl)
        cbq_ovl_classic(cl);
 }
 
-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 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;
@@ -632,30 +637,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;
 
+       PSCHED_GET_TIME(now);
+
        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)
@@ -664,12 +673,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;
 }
 
 
@@ -1265,7 +1278,7 @@ cbq_reset(struct Qdisc* sch)
        q->tx_class = NULL;
        q->tx_borrowed = NULL;
        qdisc_watchdog_cancel(&q->watchdog);
-       del_timer(&q->delay_timer);
+       hrtimer_cancel(&q->delay_timer);
        q->toplevel = TC_CBQ_MAXLEVEL;
        PSCHED_GET_TIME(q->now);
        q->now_rt = q->now;
@@ -1367,7 +1380,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;
 }
 
@@ -1435,8 +1448,7 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt)
        q->link.stats_lock = &sch->dev->queue_lock;
 
        qdisc_watchdog_init(&q->watchdog, sch);
-       init_timer(&q->delay_timer);
-       q->delay_timer.data = (unsigned long)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);
@@ -1514,7 +1526,7 @@ static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl)
        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;