[PATCH] drm/radeon: fix wait to actually occur after the signaling callback
Alex Deucher
alexdeucher at gmail.com
Fri Mar 6 06:12:33 PST 2015
On Tue, Mar 3, 2015 at 3:56 AM, Maarten Lankhorst
<maarten.lankhorst at ubuntu.com> wrote:
> A normal wait adds to the front of the tail. By doing something
> similar to fence_default_wait the fence code can run without racing.
>
> This is a complete fix for "panic on suspend from KDE with radeon",
> and a partial fix for "Radeon: System pauses on TAHITI". On tahiti
> si_irq_set needs to be fixed too, to completely flush the writes
> before radeon_fence_activity is called in radeon_fence_enable_signaling.
>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=90741
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=90861
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at ubuntu.com>
> Reported-by: Jon Arne Jørgensen <jonjon.arnearne at gmail.com>
> Reported-and-tested-by: Gustaw Smolarczyk <wielkiegie at gmail.com>
> Cc: stable at vger.kernel.org (v3.18+)
Added to my -fixes queue. Thanks!
Alex
> ---
> drivers/gpu/drm/radeon/radeon_fence.c | 68 +++++++++++++++++++++++------------
> 1 file changed, 45 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
> index d13d1b5a859f..df09ca7c4889 100644
> --- a/drivers/gpu/drm/radeon/radeon_fence.c
> +++ b/drivers/gpu/drm/radeon/radeon_fence.c
> @@ -1030,37 +1030,59 @@ static inline bool radeon_test_signaled(struct radeon_fence *fence)
> return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
> }
>
> +struct radeon_wait_cb {
> + struct fence_cb base;
> + struct task_struct *task;
> +};
> +
> +static void
> +radeon_fence_wait_cb(struct fence *fence, struct fence_cb *cb)
> +{
> + struct radeon_wait_cb *wait =
> + container_of(cb, struct radeon_wait_cb, base);
> +
> + wake_up_process(wait->task);
> +}
> +
> static signed long radeon_fence_default_wait(struct fence *f, bool intr,
> signed long t)
> {
> struct radeon_fence *fence = to_radeon_fence(f);
> struct radeon_device *rdev = fence->rdev;
> - bool signaled;
> + struct radeon_wait_cb cb;
>
> - fence_enable_sw_signaling(&fence->base);
> + cb.task = current;
>
> - /*
> - * This function has to return -EDEADLK, but cannot hold
> - * exclusive_lock during the wait because some callers
> - * may already hold it. This means checking needs_reset without
> - * lock, and not fiddling with any gpu internals.
> - *
> - * The callback installed with fence_enable_sw_signaling will
> - * run before our wait_event_*timeout call, so we will see
> - * both the signaled fence and the changes to needs_reset.
> - */
> + if (fence_add_callback(f, &cb.base, radeon_fence_wait_cb))
> + return t;
> +
> + while (t > 0) {
> + if (intr)
> + set_current_state(TASK_INTERRUPTIBLE);
> + else
> + set_current_state(TASK_UNINTERRUPTIBLE);
> +
> + /*
> + * radeon_test_signaled must be called after
> + * set_current_state to prevent a race with wake_up_process
> + */
> + if (radeon_test_signaled(fence))
> + break;
> +
> + if (rdev->needs_reset) {
> + t = -EDEADLK;
> + break;
> + }
> +
> + t = schedule_timeout(t);
> +
> + if (t > 0 && intr && signal_pending(current))
> + t = -ERESTARTSYS;
> + }
> +
> + __set_current_state(TASK_RUNNING);
> + fence_remove_callback(f, &cb.base);
>
> - if (intr)
> - t = wait_event_interruptible_timeout(rdev->fence_queue,
> - ((signaled = radeon_test_signaled(fence)) ||
> - rdev->needs_reset), t);
> - else
> - t = wait_event_timeout(rdev->fence_queue,
> - ((signaled = radeon_test_signaled(fence)) ||
> - rdev->needs_reset), t);
> -
> - if (t > 0 && !signaled)
> - return -EDEADLK;
> return t;
> }
>
> --
> 2.3.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list