[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