summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2013-09-24 21:18:59 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2013-09-24 21:18:59 +0000
commitb51d548da7f162bcd341ee09626d1c37d3774546 (patch)
tree111280557c872566d97a46a3cf78a95eb6b60f9e /sys/dev
parentbdb0fbce2e5a7105ee016282ae107deb4bb0f2dc (diff)
Make (almost all) atomic operations really atomic.
Potentially fixes a race/panic reported by claudio@ ok jsg@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/drm/drm_atomic.h58
-rw-r--r--sys/dev/pci/drm/drm_irq.c4
2 files changed, 19 insertions, 43 deletions
diff --git a/sys/dev/pci/drm/drm_atomic.h b/sys/dev/pci/drm/drm_atomic.h
index 43c35bd0ef8..6138144a04f 100644
--- a/sys/dev/pci/drm/drm_atomic.h
+++ b/sys/dev/pci/drm/drm_atomic.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_atomic.h,v 1.8 2013/08/12 04:11:52 jsg Exp $ */
+/* $OpenBSD: drm_atomic.h,v 1.9 2013/09/24 21:18:57 kettenis Exp $ */
/**
* \file drm_atomic.h
* Atomic operations used in the DRM which may or may not be provided by the OS.
@@ -42,40 +42,30 @@ typedef u_int64_t atomic64_t;
#define atomic_read(p) (*(p))
#define atomic_inc(p) __sync_fetch_and_add(p, 1)
#define atomic_dec(p) __sync_fetch_and_sub(p, 1)
-#define atomic_add(n, p) (*(p) += (n))
-#define atomic_fetchadd_int(p, n) __sync_fetch_and_add(p, n)
-#define atomic_fetchsub_int(p, n) __sync_fetch_and_sub(p, n)
+#define atomic_add(n, p) __sync_fetch_and_add(p, n)
+#define atomic_sub(n, p) __sync_fetch_and_sub(p, n)
+#define atomic_add_return(n, p) __sync_add_and_fetch(p, n)
+#define atomic_sub_return(n, p) __sync_sub_and_fetch(p, n)
+#define atomic_inc_return(v) atomic_add_return(1, (v))
+#define atomic_dec_return(v) atomic_sub_return(1, (v))
+#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
+#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
#define atomic64_set(p, v) (*(p) = (v))
#define atomic64_read(p) (*(p))
static __inline int
-atomic_xchg(volatile int *p, int new)
+atomic_xchg(volatile int *v, int n)
{
- int old;
-
- old = *p;
- *p = new;
-
- return (old);
+ __sync_synchronize();
+ return __sync_lock_test_and_set(v, n);
}
static __inline int64_t
-atomic64_xchg(volatile int64_t *p, int64_t new)
-{
- int64_t old;
-
- old = *p;
- *p = new;
-
- return (old);
-}
-
-static inline int
-atomic_add_return(int n, atomic_t *p)
+atomic64_xchg(volatile int64_t *v, int64_t n)
{
- *(p) += (n);
- return (*p);
+ __sync_synchronize();
+ return __sync_lock_test_and_set(v, n);
}
static inline int
@@ -88,25 +78,11 @@ atomic_inc_not_zero(atomic_t *p)
return (*p);
}
-#define atomic_inc_return(v) atomic_add_return(1, (v))
-#define atomic_dec_return(v) atomic_sub_return(1, (v))
-#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
-#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
-
-#define atomic_sub(n, p) (*(p) -= (n))
-
-static __inline int
-atomic_sub_return(int i, atomic_t *p)
-{
- atomic_sub(i, p);
- return (*p);
-}
-
/* FIXME */
-#define atomic_add_int(p, v) *(p) += v
-#define atomic_subtract_int(p, v) *(p) -= v
#define atomic_set_int(p, bits) atomic_setbits_int(p,bits)
#define atomic_clear_int(p, bits) atomic_clearbits_int(p,bits)
+#define atomic_fetchadd_int(p, n) __sync_fetch_and_add(p, n)
+#define atomic_fetchsub_int(p, n) __sync_fetch_and_sub(p, n)
#if defined(__i386__) || defined(__amd64__)
static __inline int
diff --git a/sys/dev/pci/drm/drm_irq.c b/sys/dev/pci/drm/drm_irq.c
index 43fe21ef27a..2d5818958cb 100644
--- a/sys/dev/pci/drm/drm_irq.c
+++ b/sys/dev/pci/drm/drm_irq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_irq.c,v 1.50 2013/09/24 21:16:24 kettenis Exp $ */
+/* $OpenBSD: drm_irq.c,v 1.51 2013/09/24 21:18:58 kettenis Exp $ */
/**
* \file drm_irq.c
* IRQ support
@@ -1017,7 +1017,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);
/* Last user schedules interrupt disable */
- if ((--dev->vblank_refcount[crtc] == 0) &&
+ if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
(drm_vblank_offdelay > 0))
timeout_add_msec(&dev->vblank_disable_timer, drm_vblank_offdelay);
}