correct drm work flush behaviour
authorjsg <jsg@openbsd.org>
Sun, 14 Feb 2021 03:42:55 +0000 (03:42 +0000)
committerjsg <jsg@openbsd.org>
Sun, 14 Feb 2021 03:42:55 +0000 (03:42 +0000)
Don't set taskq to system_wq in INIT_WORK().  Test if taskq pointer is
non-NULL before calling taskq_barrier() in flush functions.

fixes a black screen on boot problem with 5.10.y drm using nano x1
bisected by jcs@ to
'drm/i915: Always flush the active worker before returning from the wait'

sys/dev/pci/drm/drm_linux.c
sys/dev/pci/drm/include/linux/workqueue.h

index d400d72..1fc4db1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: drm_linux.c,v 1.77 2021/02/08 08:18:45 mpi Exp $      */
+/*     $OpenBSD: drm_linux.c,v 1.78 2021/02/14 03:42:55 jsg Exp $      */
 /*
  * Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org>
  * Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org>
@@ -158,7 +158,8 @@ flush_workqueue(struct workqueue_struct *wq)
        if (cold)
                return;
 
-       taskq_barrier((struct taskq *)wq);
+       if (wq)
+               taskq_barrier((struct taskq *)wq);
 }
 
 bool
@@ -167,7 +168,8 @@ flush_work(struct work_struct *work)
        if (cold)
                return false;
 
-       taskq_barrier(work->tq);
+       if (work->tq)
+               taskq_barrier(work->tq);
        return false;
 }
 
@@ -184,7 +186,8 @@ flush_delayed_work(struct delayed_work *dwork)
                ret = true;
        }
 
-       taskq_barrier(dwork->tq ? dwork->tq : (struct taskq *)system_wq);
+       if (dwork->tq)
+               taskq_barrier(dwork->tq);
        return ret;
 }
 
index e2a877d..703d2f0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: workqueue.h,v 1.3 2020/06/08 04:48:15 jsg Exp $       */
+/*     $OpenBSD: workqueue.h,v 1.4 2021/02/14 03:42:55 jsg Exp $       */
 /*
  * Copyright (c) 2015 Mark Kettenis
  *
@@ -79,7 +79,7 @@ typedef void (*work_func_t)(struct work_struct *);
 static inline void
 INIT_WORK(struct work_struct *work, work_func_t func)
 {
-       work->tq = (struct taskq *)system_wq;
+       work->tq = NULL;
        task_set(&work->task, (void (*)(void *))func, work);
 }
 
@@ -139,6 +139,7 @@ INIT_DELAYED_WORK_ONSTACK(struct delayed_work *dwork, work_func_t func)
 static inline bool
 schedule_work(struct work_struct *work)
 {
+       work->tq = (struct taskq *)system_wq;
        return task_add(work->tq, &work->task);
 }