On Tue, Mar 3, 2015 at 3:56 AM, Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxx> 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@xxxxxxxxxx> > Reported-by: Jon Arne Jørgensen <jonjon.arnearne@xxxxxxxxx> > Reported-and-tested-by: Gustaw Smolarczyk <wielkiegie@xxxxxxxxx> > Cc: stable@xxxxxxxxxxxxxxx (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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel