diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2013-09-24 21:18:59 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2013-09-24 21:18:59 +0000 |
commit | b51d548da7f162bcd341ee09626d1c37d3774546 (patch) | |
tree | 111280557c872566d97a46a3cf78a95eb6b60f9e /sys/dev | |
parent | bdb0fbce2e5a7105ee016282ae107deb4bb0f2dc (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.h | 58 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_irq.c | 4 |
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); } |