Module Name: src Committed By: riastradh Date: Sat Feb 28 18:25:39 UTC 2015
Modified Files: src/sys/external/bsd/drm2/dist/drm: drm_irq.c src/sys/external/bsd/drm2/dist/drm/i915: i915_dma.c src/sys/external/bsd/drm2/dist/drm/via: via_dmablit.c via_drv.h via_irq.c via_video.c src/sys/external/bsd/drm2/include/drm: drm_wait_netbsd.h Log Message: New macro DRM_SPIN_WAIT_ON better reflects DRM_WAIT_ON. We still need to adapt all waits from upstream to use an interlock, so we can't implement DRM_WAIT_ON verbatim, but this more closely reflects the API of DRM_WAIT_ON than DRM_*WAIT*_UNTIL do. Major difference is that this polls every tick, like DRM_WAIT_ON, unlike DRM_*WAIT*_UNTIL. So it will mask missing wakeups, but it wouldn't surprise me if there were such things upstream. To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/sys/external/bsd/drm2/dist/drm/drm_irq.c cvs rdiff -u -r1.14 -r1.15 src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c \ src/sys/external/bsd/drm2/dist/drm/via/via_irq.c \ src/sys/external/bsd/drm2/dist/drm/via/via_video.c cvs rdiff -u -r1.2 -r1.3 src/sys/external/bsd/drm2/dist/drm/via/via_drv.h cvs rdiff -u -r1.8 -r1.9 \ src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/drm2/dist/drm/drm_irq.c diff -u src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.7 src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.8 --- src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.7 Sat Feb 28 03:05:09 2015 +++ src/sys/external/bsd/drm2/dist/drm/drm_irq.c Sat Feb 28 18:25:39 2015 @@ -1293,20 +1293,14 @@ int drm_wait_vblank(struct drm_device *d #ifdef __NetBSD__ { unsigned long irqflags; + spin_lock_irqsave(&dev->vbl_lock, irqflags); - DRM_SPIN_TIMED_WAIT_UNTIL(ret, &dev->vblank[crtc].queue, - &dev->vbl_lock, - (3 * HZ), + DRM_SPIN_WAIT_ON(ret, &dev->vblank[crtc].queue, &dev->vbl_lock, + 3 * HZ, (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23)) || !dev->irq_enabled)); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - if (ret < 0) /* Failed: return negative error as is. */ - ; - else if (ret == 0) /* Timed out: return -EBUSY like Linux. */ - ret = -EBUSY; - else /* Succeeded (ret > 0): return 0. */ - ret = 0; } #else DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ, Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.14 src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.15 --- src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.14 Sat Feb 28 03:06:46 2015 +++ src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c Sat Feb 28 18:25:39 2015 @@ -812,16 +812,9 @@ static int i915_wait_irq(struct drm_devi #ifdef __NetBSD__ unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - DRM_SPIN_TIMED_WAIT_UNTIL(ret, &ring->irq_queue, - &dev_priv->irq_lock, + DRM_SPIN_WAIT_ON(ret, &ring->irq_queue, &dev_priv->irq_lock, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - if (ret < 0) /* Failure: return negative error as is. */ - ; - else if (ret == 0) /* Timed out: return -EBUSY like Linux. */ - ret = -EBUSY; - else /* Succeeded (ret > 0): return 0. */ - ret = 0; spin_unlock_irqrestore(&dev_priv->irq_lock, flags); #else DRM_WAIT_ON(ret, ring->irq_queue, 3 * HZ, Index: src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c diff -u src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c:1.3 src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c:1.4 --- src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c:1.3 Sat Feb 28 03:23:32 2015 +++ src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c Sat Feb 28 18:25:39 2015 @@ -597,15 +597,8 @@ via_dmablit_sync(struct drm_device *dev, #ifdef __NetBSD__ spin_lock(&blitq->blit_lock); if (via_dmablit_active(blitq, engine, handle, &queue)) { - DRM_SPIN_TIMED_WAIT_UNTIL(ret, queue, &blitq->blit_lock, - 3*DRM_HZ, + DRM_SPIN_WAIT_ON(ret, queue, &blitq->blit_lock, 3*DRM_HZ, !via_dmablit_active(blitq, engine, handle, NULL)); - if (ret < 0) /* Failure: return negative error as is. */ - ; - else if (ret == 0) /* Timed out: return -EBUSY like Linux. */ - ret = -EBUSY; - else /* Succeeded (ret > 0): return 0. */ - ret = 0; } spin_unlock(&blitq->blit_lock); #else @@ -881,15 +874,9 @@ via_dmablit_grab_slot(drm_via_blitq_t *b spin_lock_irqsave(&blitq->blit_lock, irqsave); while (blitq->num_free == 0) { #ifdef __NetBSD__ - DRM_SPIN_TIMED_WAIT_UNTIL(ret, &blitq->busy_queue, - &blitq->blit_lock, DRM_HZ, + DRM_SPIN_WAIT_ON(ret, &blitq->busy_queue, &blitq->blit_lock, + DRM_HZ, blitq->num_free > 0); - if (ret < 0) /* Failure: return negative error as is. */ - ; - else if (ret == 0) /* Timed out: return -EBUSY like Linux. */ - ret = -EBUSY; - else /* Success (ret > 0): return 0. */ - ret = 0; /* Map -EINTR to -EAGAIN. */ if (ret == -EINTR) ret = -EAGAIN; Index: src/sys/external/bsd/drm2/dist/drm/via/via_irq.c diff -u src/sys/external/bsd/drm2/dist/drm/via/via_irq.c:1.3 src/sys/external/bsd/drm2/dist/drm/via/via_irq.c:1.4 --- src/sys/external/bsd/drm2/dist/drm/via/via_irq.c:1.3 Sat Feb 28 03:23:32 2015 +++ src/sys/external/bsd/drm2/dist/drm/via/via_irq.c Sat Feb 28 18:25:39 2015 @@ -249,23 +249,17 @@ via_driver_irq_wait(struct drm_device *d #ifdef __NetBSD__ spin_lock(&cur_irq->irq_lock); if (masks[real_irq][2] && !force_sequence) { - DRM_SPIN_TIMED_WAIT_UNTIL(ret, &cur_irq->irq_queue, - &cur_irq->irq_lock, 3 * DRM_HZ, + DRM_SPIN_WAIT_ON(ret, &cur_irq->irq_queue, &cur_irq->irq_lock, + 3 * DRM_HZ, ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4])); cur_irq_sequence = cur_irq->irq_received; } else { - DRM_SPIN_TIMED_WAIT_UNTIL(ret, &cur_irq->irq_queue, - &cur_irq->irq_lock, 3 * DRM_HZ, + DRM_SPIN_WAIT_ON(ret, &cur_irq->irq_queue, &cur_irq->irq_lock, + 3 * DRM_HZ, (((cur_irq_sequence = cur_irq->irq_received) - *sequence) <= (1 << 23))); } - if (ret < 0) /* Failure: return negative error as is. */ - ; - else if (ret == 0) /* Timed out: return -EBUSY like Linux. */ - ret = -EBUSY; - else /* Success (ret > 0): return 0. */ - ret = 0; spin_unlock(&cur_irq->irq_lock); #else if (masks[real_irq][2] && !force_sequence) { Index: src/sys/external/bsd/drm2/dist/drm/via/via_video.c diff -u src/sys/external/bsd/drm2/dist/drm/via/via_video.c:1.3 src/sys/external/bsd/drm2/dist/drm/via/via_video.c:1.4 --- src/sys/external/bsd/drm2/dist/drm/via/via_video.c:1.3 Sat Feb 28 03:23:32 2015 +++ src/sys/external/bsd/drm2/dist/drm/via/via_video.c Sat Feb 28 18:25:39 2015 @@ -37,7 +37,7 @@ void via_init_futex(drm_via_private_t *d for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) { #ifdef __NetBSD__ - linux_mutex_init(&dev_priv->decoder_lock[i]); + spin_lock_init(&dev_priv->decoder_lock[i]); DRM_INIT_WAITQUEUE(&dev_priv->decoder_queue[i], "viadec"); #else init_waitqueue_head(&(dev_priv->decoder_queue[i])); @@ -53,7 +53,7 @@ void via_cleanup_futex(drm_via_private_t for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) { DRM_DESTROY_WAITQUEUE(&dev_priv->decoder_queue[i]); - linux_mutex_destroy(&dev_priv->decoder_lock[i]); + spin_lock_destroy(&dev_priv->decoder_lock[i]); } #endif } @@ -72,10 +72,10 @@ void via_release_futex(drm_via_private_t if (_DRM_LOCK_IS_HELD(*lock) && (*lock & _DRM_LOCK_CONT)) { #ifdef __NetBSD__ - mutex_lock(&dev_priv->decoder_lock[i]); - DRM_WAKEUP_ALL(&dev_priv->decoder_queue[i], + spin_lock(&dev_priv->decoder_lock[i]); + DRM_SPIN_WAKEUP_ALL(&dev_priv->decoder_queue[i], &dev_priv->decoder_lock[i]); - mutex_unlock(&dev_priv->decoder_lock[i]); + spin_unlock(&dev_priv->decoder_lock[i]); #else wake_up(&(dev_priv->decoder_queue[i])); #endif @@ -103,18 +103,12 @@ int via_decoder_futex(struct drm_device switch (fx->func) { case VIA_FUTEX_WAIT: #ifdef __NetBSD__ - mutex_lock(&dev_priv->decoder_lock[fx->lock]); - DRM_TIMED_WAIT_UNTIL(ret, &dev_priv->decoder_queue[fx->lock], + spin_lock(&dev_priv->decoder_lock[fx->lock]); + DRM_SPIN_WAIT_ON(ret, &dev_priv->decoder_queue[fx->lock], &dev_priv->decoder_lock[fx->lock], (fx->ms / 10) * (DRM_HZ / 100), *lock != fx->val); - if (ret < 0) /* Failure: return negative error as is. */ - ; - else if (ret == 0) /* Timed out: return -EBUSY like Linux. */ - ret = -EBUSY; - else /* Success (ret > 0): return 0. */ - ret = 0; - mutex_unlock(&dev_priv->decoder_lock[fx->lock]); + spin_unlock(&dev_priv->decoder_lock[fx->lock]); #else DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock], (fx->ms / 10) * (HZ / 100), *lock != fx->val); Index: src/sys/external/bsd/drm2/dist/drm/via/via_drv.h diff -u src/sys/external/bsd/drm2/dist/drm/via/via_drv.h:1.2 src/sys/external/bsd/drm2/dist/drm/via/via_drv.h:1.3 --- src/sys/external/bsd/drm2/dist/drm/via/via_drv.h:1.2 Tue Aug 26 17:28:14 2014 +++ src/sys/external/bsd/drm2/dist/drm/via/via_drv.h Sat Feb 28 18:25:39 2015 @@ -73,7 +73,7 @@ typedef struct drm_via_private { drm_local_map_t *mmio; unsigned long agpAddr; #ifdef __NetBSD__ - struct mutex decoder_lock[VIA_NR_XVMC_LOCKS]; + spinlock_t decoder_lock[VIA_NR_XVMC_LOCKS]; drm_waitqueue_t decoder_queue[VIA_NR_XVMC_LOCKS]; #else wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS]; Index: src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h diff -u src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.8 src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.9 --- src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.8 Sat Feb 28 04:57:12 2015 +++ src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h Sat Feb 28 18:25:39 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: drm_wait_netbsd.h,v 1.8 2015/02/28 04:57:12 riastradh Exp $ */ +/* $NetBSD: drm_wait_netbsd.h,v 1.9 2015/02/28 18:25:39 riastradh Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. @@ -105,31 +105,80 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, } /* - * WARNING: These DRM_*WAIT*_UNTIL macros are designed to replace the - * Linux wait_event* macros. They have a different return value - * convention from the legacy portability DRM_WAIT_ON macro and a + * DRM_SPIN_WAIT_ON is a replacement for the legacy DRM_WAIT_ON + * portability macro. It requires a spin interlock, which may require + * changes to the surrounding code so that the waits actually are + * interlocked by a spin lock. It also polls the condition at every + * tick, which masks missing wakeups. Since DRM_WAIT_ON is going away, + * in favour of Linux's native wait_event* API, waits in new code + * should be written to use the DRM_*WAIT*_UNTIL macros below. + * + * Like the legacy DRM_WAIT_ON, DRM_SPIN_WAIT_ON returns + * + * . -EBUSY if timed out (yes, -EBUSY, not -ETIMEDOUT or -EWOULDBLOCK), + * . -EINTR/-ERESTART if interrupted by a signal, or + * . 0 if the condition was true before or just after the timeout. + * + * Note that cv_timedwait* return -EWOULDBLOCK, not -EBUSY, on timeout. + */ + +#define DRM_SPIN_WAIT_ON(RET, Q, INTERLOCK, TICKS, CONDITION) do \ +{ \ + extern int hardclock_ticks; \ + const int _dswo_start = hardclock_ticks; \ + const int _dswo_end = _dswo_start + (TICKS); \ + \ + KASSERT(spin_is_locked((INTERLOCK))); \ + KASSERT(!cpu_intr_p()); \ + KASSERT(!cpu_softintr_p()); \ + KASSERT(!cold); \ + \ + for (;;) { \ + if (CONDITION) { \ + (RET) = 0; \ + break; \ + } \ + const int _dswo_now = hardclock_ticks; \ + if (_dswo_end < _dswo_now) { \ + (RET) = -EBUSY; /* Match Linux... */ \ + break; \ + } \ + /* XXX errno NetBSD->Linux */ \ + (RET) = -cv_timedwait_sig((Q), &(INTERLOCK)->sl_lock, \ + (_dswo_end - _dswo_now)); \ + if (RET) { \ + if ((RET) == -EWOULDBLOCK) \ + (RET) = (CONDITION) ? 0 : -EBUSY; \ + \ + break; \ + } \ + } \ +} while (0) + +/* + * The DRM_*WAIT*_UNTIL macros are replacements for the Linux + * wait_event* macros. Like DRM_SPIN_WAIT_ON, they add an interlock, + * and so may require some changes to the surrounding code. They have + * a different return value convention from DRM_SPIN_WAIT_ON and a * different return value convention from cv_*wait*. * - * Specifically, the untimed macros + * The untimed DRM_*WAIT*_UNTIL macros return * - * - return negative error code on failure (interruption), and - * - return zero on sucess. + * . -EINTR/-ERESTART if interrupted by a signal, or + * . zero if the condition evaluated * - * The timed macros + * The timed DRM_*TIMED_WAIT*_UNTIL macros return * - * - return negative error code on failure (interruption), - * - return zero on timeout, and - * - return one on success. + * . -EINTR/-ERESTART if interrupted by a signal, + * . 0 if the condition was false after the timeout, + * . 1 if the condition was true just after the timeout, or + * . the number of ticks remaining if the condition was true before the + * timeout. * - * Contrast DRM_WAIT_ON which returns -EINTR/-ERESTART on interruption, + * Contrast DRM_SPIN_WAIT_ON which returns -EINTR/-ERESTART on signal, * -EBUSY on timeout, and zero on success; and cv_*wait*, which return - * -EINTR/-ERESTART on interruption, -EWOULDBLOCK on timeout, and zero - * on success. - * - * We don't simply implement DRM_WAIT_ON because, like Linux - * wait_event*, it lacks an interlock, whereas we require an interlock - * for any waits in order to avoid the standard race conditions - * associated with non-interlocked waits that plague Linux drivers. + * -EINTR/-ERESTART on signal, -EWOULDBLOCK on timeout, and zero on + * success. * * XXX In retrospect, giving the timed and untimed macros a different * return convention from one another to match Linux may have been a @@ -162,19 +211,6 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, #define DRM_WAIT_UNTIL(RET, Q, I, C) \ _DRM_WAIT_UNTIL(RET, cv_wait_sig, Q, I, C) -/* - * Timed wait. Return: - * - * - 0 if condition is false after timeout, - * - 1 if condition is true after timeout or one tick before timeout, - * - number of ticks left if condition evaluated to true before timeout, or - * - negative error if failure (e.g., interrupted). - * - * XXX Comments in Linux say it returns -ERESTARTSYS if interrupted. - * What if by a signal without SA_RESTART? Shouldn't it be -EINTR - * then? I'm going to leave it as what cv_timedwait returned, which is - * ERESTART for signals with SA_RESTART and EINTR otherwise. - */ #define _DRM_TIMED_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, TICKS, CONDITION) do \ { \ extern int hardclock_ticks; \