Fix Linux timers, jiffies, and HZ
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 4 Dec 2017 23:16:34 +0000 (18:16 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 5 Dec 2017 15:59:32 +0000 (10:59 -0500)
Since commit 2a991d374670 ("Treat jiffies as msec since boot"), we've been
waiting ten times longer than we should.  For Linux code, jiffies are one
msec, and HZ = 1000.

Similarly, some mlx4 code was using mod_timer() for relative changes.  Once
we started treating jiffies as non-zero, these timers broke.

This fixes some nastiness with mod_timer - there never should have been
'delay', since all callers expect to use absolute time.  We should have
just had jiffies == msec or whatever from the beginning.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/net/mlx4/catas.c
kern/drivers/net/mlx4/sense.c
kern/include/linux/compat_todo.h
kern/src/taskqueue.c

index 757974f..d117706 100644 (file)
@@ -247,12 +247,8 @@ static void poll_catas(unsigned long dev_ptr)
                goto internal_err;
        }
 
-#if 0 // AKAROS_PORT
        mod_timer(&priv->catas_err.timer,
                  round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
-#else
-       mod_timer(&priv->catas_err.timer, MLX4_CATAS_POLL_INTERVAL);
-#endif
        return;
 
 internal_err:
@@ -297,12 +293,8 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev)
 
        priv->catas_err.timer.data     = (unsigned long) dev;
        priv->catas_err.timer.function = poll_catas;
-#if 0 // AKAROS_PORT
        priv->catas_err.timer.expires  =
                round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL);
-#else
-       priv->catas_err.timer.delay    = MLX4_CATAS_POLL_INTERVAL;
-#endif
        add_timer(&priv->catas_err.timer);
 }
 
index 22a26a4..62ff5f4 100644 (file)
@@ -107,11 +107,7 @@ static void mlx4_sense_port(struct work_struct *work)
 sense_again:
        qunlock(&priv->port_mutex);
        queue_delayed_work(mlx4_wq , &sense->sense_poll,
-#if 0 // AKAROS_PORT
                           round_jiffies_relative(MLX4_SENSE_RANGE));
-#else
-                          MLX4_SENSE_RANGE);
-#endif
 }
 
 void mlx4_start_sense(struct mlx4_dev *dev)
@@ -123,11 +119,7 @@ void mlx4_start_sense(struct mlx4_dev *dev)
                return;
 
        queue_delayed_work(mlx4_wq , &sense->sense_poll,
-#if 0 // AKAROS_PORT
                           round_jiffies_relative(MLX4_SENSE_RANGE));
-#else
-                          MLX4_SENSE_RANGE);
-#endif
 }
 
 void mlx4_stop_sense(struct mlx4_dev *dev)
index 2969971..a0e8851 100644 (file)
@@ -297,10 +297,20 @@ static inline unsigned long wait_for_completion_timeout(struct completion *x,
 
 #define jiffies tsc2msec(read_tsc())
 
+static inline unsigned long round_jiffies(unsigned long j)
+{
+       return j / 1000 * 1000;
+}
+
+static inline unsigned long round_jiffies_relative(unsigned long j)
+{
+       return round_jiffies(j);
+}
+
 struct timer_list {
        spinlock_t lock;
        bool scheduled;
-       unsigned long delay;
+       unsigned long expires;
        void (*function)(unsigned long);
        unsigned long data;
 };
@@ -309,7 +319,7 @@ static inline void init_timer(struct timer_list *timer)
 {
        spinlock_init_irqsave(&timer->lock);
        timer->scheduled = false;
-       timer->delay = 0;
+       timer->expires = -1;
        timer->function = 0;
        timer->data = 0;
 }
@@ -325,14 +335,16 @@ static inline void setup_timer(struct timer_list *timer,
 static void __timer_wrapper(uint32_t srcid, long a0, long a1, long a2)
 {
        struct timer_list *timer = (struct timer_list *)a0;
-       unsigned long delay = 0;
+       unsigned long expires, now_j;
 
        spin_lock_irqsave(&timer->lock);
-       delay = timer->delay;
+       expires = timer->expires;
        timer->scheduled = false;
        spin_unlock_irqsave(&timer->lock);
 
-       kthread_usleep(delay * 10000);
+       now_j = jiffies;
+       if (expires > now_j)
+               kthread_usleep((expires - now_j) * 1000);
        timer->function(timer->data);
 }
 
@@ -343,14 +355,10 @@ static inline void add_timer(struct timer_list *timer)
                            KMSG_ROUTINE);
 }
 
-static inline void mod_timer(struct timer_list *timer, unsigned long abs_msec)
+static inline void mod_timer(struct timer_list *timer, unsigned long expires)
 {
        spin_lock_irqsave(&timer->lock);
-       /* Our callers often use jiffies + rel_time.  This jiffies may be slightly
-        * more than the previous jiffies */
-       timer->delay = abs_msec - jiffies;
-       if ((long)timer->delay < 0)
-               timer->delay = 0;
+       timer->expires = expires;
        if (timer->scheduled) {
                spin_unlock_irqsave(&timer->lock);
                return;
index 4e868aa..e988409 100644 (file)
@@ -47,11 +47,14 @@ static void __wq_wrapper(uint32_t srcid, long a0, long a1, long a2)
        work->func(work);
 }
 
+/* Linux callers use jiffies as the unit of delay.  We pretend to be a 1000 HZ
+ * machine with 1 msec jiffies. */
 static void __wq_wrapper_delay(uint32_t srcid, long a0, long a1, long a2)
 {
        struct work_struct *work = (struct work_struct*)a0;
        unsigned long delay = (unsigned long)a1;
-       kthread_usleep(delay * 10000);
+
+       kthread_usleep(delay * 1000);
        work->func(work);
 }