summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2017-11-27 16:20:43 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2017-11-27 16:20:43 +0000
commitead35ae95d4fd007e092cb9ab70426f068b7a8be (patch)
treebe01a0f74eb3b58dc6d5168220cf844e02a298cb /sys
parent1270ca4e890db8d477d052337fc4fe32065c07a0 (diff)
Revise the linux sleeping compat code to avoid lock ordering problems.
Based on a diff from mpi@. ok guenther@, mpi@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/drm/drm_linux.h154
-rw-r--r--sys/dev/pci/drm/i915/intel_sprite.c12
2 files changed, 89 insertions, 77 deletions
diff --git a/sys/dev/pci/drm/drm_linux.h b/sys/dev/pci/drm/drm_linux.h
index 2971a7d0923..d75086494e9 100644
--- a/sys/dev/pci/drm/drm_linux.h
+++ b/sys/dev/pci/drm/drm_linux.h
@@ -1,6 +1,7 @@
-/* $OpenBSD: drm_linux.h,v 1.63 2017/09/05 03:06:26 jsg Exp $ */
+/* $OpenBSD: drm_linux.h,v 1.64 2017/11/27 16:20:42 kettenis Exp $ */
/*
* Copyright (c) 2013, 2014, 2015 Mark Kettenis
+ * Copyright (c) 2017 Martin Pieuchot
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -552,93 +553,84 @@ typedef struct wait_queue_head wait_queue_head_t;
static inline void
init_waitqueue_head(wait_queue_head_t *wq)
{
- mtx_init(&wq->lock, IPL_NONE);
+ mtx_init(&wq->lock, IPL_TTY);
wq->count = 0;
}
-#define wait_event(wq, condition) \
-do { \
- struct sleep_state sls; \
- \
- KASSERT(!cold); \
- if (condition) \
- break; \
- atomic_inc_int(&(wq).count); \
- sleep_setup(&sls, &wq, 0, "drmwe"); \
- sleep_finish(&sls, !(condition)); \
- atomic_dec_int(&(wq).count); \
-} while (!(condition))
-
-#define __wait_event_timeout(wq, condition, ret) \
+#define __wait_event_intr_timeout(wq, condition, timo, prio) \
+({ \
+ long ret = timo; \
+ mtx_enter(&(wq).lock); \
+ do { \
+ int deadline, __error; \
+ \
+ KASSERT(!cold); \
+ atomic_inc_int(&(wq).count); \
+ deadline = ticks + ret; \
+ __error = msleep(&wq, &(wq).lock, prio, "drmweti", ret); \
+ ret = deadline - ticks; \
+ atomic_dec_int(&(wq).count); \
+ if (__error == ERESTART || __error == EINTR) { \
+ ret = -ERESTARTSYS; \
+ break; \
+ } \
+ if (timo && (ret <= 0 || __error == EWOULDBLOCK)) { \
+ ret = ((condition)) ? 1 : 0; \
+ break; \
+ } \
+ } while (ret > 0 && !(condition)); \
+ mtx_leave(&(wq).lock); \
+ ret; \
+})
+
+/*
+ * Sleep until `condition' gets true.
+ */
+#define wait_event(wq, condition) \
do { \
- struct sleep_state sls; \
- int deadline, __error; \
- \
- KASSERT(!cold); \
- atomic_inc_int(&(wq).count); \
- sleep_setup(&sls, &wq, 0, "drmwet"); \
- sleep_setup_timeout(&sls, ret); \
- deadline = ticks + ret; \
- sleep_finish(&sls, !(condition)); \
- ret = deadline - ticks; \
- __error = sleep_finish_timeout(&sls); \
- atomic_dec_int(&(wq).count); \
- if (ret < 0 || __error == EWOULDBLOCK) \
- ret = 0; \
- if (ret == 0 && (condition)) { \
- ret = 1; \
- break; \
- } \
-} while (ret > 0 && !(condition))
+ if (!(condition)) \
+ __wait_event_intr_timeout(wq, condition, 0, 0); \
+} while (0)
+/*
+ * Sleep until `condition' gets true or `timo' expires.
+ *
+ * Returns 0 if `condition' is still false when `timo' expires or
+ * the remaining (>=1) ticks otherwise.
+ */
#define wait_event_timeout(wq, condition, timo) \
({ \
long __ret = timo; \
if (!(condition)) \
- __wait_event_timeout(wq, condition, __ret); \
+ __ret = __wait_event_intr_timeout(wq, condition, timo, 0); \
__ret; \
})
-#define __wait_event_interruptible_timeout(wq, condition, ret) \
-do { \
- struct sleep_state sls; \
- int deadline, __error, __error1; \
- \
- KASSERT(!cold); \
- atomic_inc_int(&(wq).count); \
- sleep_setup(&sls, &wq, PCATCH, "drmweti"); \
- sleep_setup_timeout(&sls, ret); \
- sleep_setup_signal(&sls, PCATCH); \
- deadline = ticks + ret; \
- sleep_finish(&sls, !(condition)); \
- ret = deadline - ticks; \
- __error1 = sleep_finish_timeout(&sls); \
- __error = sleep_finish_signal(&sls); \
- atomic_dec_int(&(wq).count); \
- if (ret < 0 || __error1 == EWOULDBLOCK) \
- ret = 0; \
- if (__error == ERESTART) \
- ret = -ERESTARTSYS; \
- else if (__error) \
- ret = -__error; \
- if (ret == 0 && (condition)) { \
- ret = 1; \
- break; \
- } \
-} while (ret > 0 && !(condition))
-
+/*
+ * Sleep until `condition' gets true, `timo' expires or the process
+ * receives a signal.
+ *
+ * Returns -ERESTARTSYS if interrupted by a signal.
+ * Returns 0 if `condition' is still false when `timo' expires or
+ * the remaining (>=1) ticks otherwise.
+ */
#define wait_event_interruptible_timeout(wq, condition, timo) \
({ \
long __ret = timo; \
if (!(condition)) \
- __wait_event_interruptible_timeout(wq, condition, __ret); \
+ __ret = __wait_event_intr_timeout(wq, condition, timo, PCATCH);\
__ret; \
})
-#define wake_up(x) wakeup(x)
-#define wake_up_all(x) wakeup(x)
-#define wake_up_all_locked(x) wakeup(x)
-#define wake_up_interruptible(x) wakeup(x)
+#define wake_up(wq) \
+do { \
+ mtx_enter(&(wq)->lock); \
+ wakeup(wq); \
+ mtx_leave(&(wq)->lock); \
+} while (0)
+#define wake_up_all(wq) wake_up(wq)
+#define wake_up_all_locked(wq) wakeup(wq)
+#define wake_up_interruptible(wq) wake_up(wq)
#define waitqueue_active(wq) ((wq)->count > 0)
@@ -1186,6 +1178,30 @@ kobject_del(struct kobject *obj)
{
}
+#define DEFINE_WAIT(wait) wait_queue_head_t *wait = NULL
+
+inline void
+prepare_to_wait(wait_queue_head_t *wq, wait_queue_head_t **wait, int state)
+{
+ if (*wait == NULL) {
+ mtx_enter(&wq->lock);
+ *wait = wq;
+ }
+}
+
+inline void
+finish_wait(wait_queue_head_t *wq, wait_queue_head_t **wait)
+{
+ if (*wait)
+ mtx_leave(&wq->lock);
+}
+
+inline long
+schedule_timeout(long timeout, wait_queue_head_t **wait)
+{
+ return -msleep(*wait, &(*wait)->lock, PZERO, "schto", timeout);
+}
+
struct idr_entry {
SPLAY_ENTRY(idr_entry) entry;
int id;
diff --git a/sys/dev/pci/drm/i915/intel_sprite.c b/sys/dev/pci/drm/i915/intel_sprite.c
index d04f1c4cdfe..9c0394934be 100644
--- a/sys/dev/pci/drm/i915/intel_sprite.c
+++ b/sys/dev/pci/drm/i915/intel_sprite.c
@@ -86,7 +86,7 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
long timeout = msecs_to_jiffies_timeout(1);
int scanline, min, max, vblank_start;
wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
- struct sleep_state sls;
+ DEFINE_WAIT(wait);
vblank_start = adjusted_mode->crtc_vblank_start;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -108,14 +108,13 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
crtc->debug.max_vbl = max;
trace_i915_pipe_update_start(crtc);
- KASSERT(!cold);
for (;;) {
/*
* prepare_to_wait() has a memory barrier, which guarantees
* other CPUs can see the task state update by the time we
* read the scanline.
*/
- sleep_setup(&sls, wq, PZERO, "ipus");
+ prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
scanline = intel_get_crtc_scanline(crtc);
if (scanline < min || scanline > max)
@@ -129,15 +128,12 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
local_irq_enable();
- sleep_setup_timeout(&sls, timeout);
- sleep_finish(&sls, 1);
- if (sleep_finish_timeout(&sls))
- timeout = -EWOULDBLOCK;
+ timeout = schedule_timeout(timeout, &wait);
local_irq_disable();
}
- sleep_finish(&sls, 0);
+ finish_wait(wq, &wait);
drm_crtc_vblank_put(&crtc->base);