diff --git a/sys/dev/drm/include/linux/workqueue.h b/sys/dev/drm/include/linux/workqueue.h --- a/sys/dev/drm/include/linux/workqueue.h +++ b/sys/dev/drm/include/linux/workqueue.h @@ -60,6 +60,7 @@ struct workqueue_struct { bool is_draining; int num_workers; + struct lock queue_lock; /* serializes cross-CPU queue_work */ struct workqueue_worker (*workers)[]; }; --- a/sys/dev/drm/linux_workqueue.c +++ b/sys/dev/drm/linux_workqueue.c @@ -122,9 +122,11 @@ struct workqueue_worker *worker; int ret = false; + lockmgr(&wq->queue_lock, LK_EXCLUSIVE); + /* XXX: should we block instead ? */ if (wq->is_draining) - return false; + goto out; if (wq->num_workers > 1) worker = &(*wq->workers)[mycpuid]; @@ -144,6 +146,8 @@ ret = true; } lockmgr(&worker->worker_lock, LK_RELEASE); +out: + lockmgr(&wq->queue_lock, LK_RELEASE); return ret; } @@ -201,6 +205,8 @@ wq = kmalloc(sizeof(*wq), M_DRM, M_WAITOK | M_ZERO); + lockinit(&wq->queue_lock, "wqql", 0, 0); + if (flags & WQ_HIGHPRI) priority = TDPRI_INT_SUPPORT; else