From mboxrd@z Thu Jan 1 00:00:00 1970 From: =?UTF-8?B?Q2hyaXN0aWFuIEvDtm5pZw==?= Subject: Re: [PATCH] drm/radeon: signal all fences after lockup to avoid endless waiting in GEM_WAIT Date: Sun, 13 Oct 2013 14:47:22 +0200 Message-ID: <525A965A.1040504@vodafone.de> References: <5252961D.8010502@vodafone.de> <52543111.9000405@vodafone.de> <52553950.3020804@vodafone.de> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------020700070301060906000709" Return-path: Received: from smtp-05.vodafone.de (mxout.vodafone.de [80.84.1.40]) by gabe.freedesktop.org (Postfix) with ESMTP id 9D394E5F91 for ; Sun, 13 Oct 2013 05:47:24 -0700 (PDT) In-Reply-To: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dri-devel-bounces+sf-dri-devel=m.gmane.org@lists.freedesktop.org Errors-To: dri-devel-bounces+sf-dri-devel=m.gmane.org@lists.freedesktop.org To: =?UTF-8?B?TWFyZWsgT2zFocOhaw==?= Cc: dri-devel@lists.freedesktop.org List-Id: dri-devel@lists.freedesktop.org This is a multi-part message in MIME format. --------------020700070301060906000709 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable I've figured out what was wrong with the patch. We need to reset the=20 "needs_reset" flag earlier, otherwise the IB test might think we are in=20 a lockup and aborts the reset after waiting for the minimum timeout perio= d. Please try the attached patch instead. Thanks, Christian. Am 09.10.2013 14:04, schrieb Marek Ol=C5=A1=C3=A1k: > The ring test of the first compute ring always fails and it shouldn't > affect the GPU reset in any way. > > I can't tell if the deadlock issue is fixed, because the GPU reset > usually fails with your patch. It always succeeded without your patch. > > Marek > > On Wed, Oct 9, 2013 at 1:09 PM, Christian K=C3=B6nig wrote: >> Mhm, that doesn't looks like anything related but more like the reset = of the >> compute ring didn't worked. >> >> How often does that happen? And do you still get the problem where X w= aits >> for a fence that never comes back? >> >> Christian. >> >> Am 09.10.2013 12:36, schrieb Marek Ol=C5=A1=C3=A1k: >> >>> I'm afraid your patch sometimes causes the GPU reset to fail, which >>> had never happened before IIRC. >>> >>> The dmesg log from the failure is attached. >>> >>> Marek >>> >>> On Tue, Oct 8, 2013 at 6:21 PM, Christian K=C3=B6nig >>> wrote: >>>> Hi Marek, >>>> >>>> please try the attached patch as a replacement for your signaling al= l >>>> fences >>>> patch. I'm not 100% sure if it fixes all issues, but it's at least a >>>> start. >>>> >>>> Thanks, >>>> Christian. >>>> >>>> Am 07.10.2013 13:08, schrieb Christian K=C3=B6nig: >>>> >>>>>> First of all, I can't complain about the reliability of the hardwa= re >>>>>> GPU reset. It's mostly the kernel driver that happens to run into = a >>>>>> deadlock at the same time. >>>>> >>>>> Alex and I spend quite some time on making this reliable again afte= r >>>>> activating more rings and adding VM support. The main problem is th= at I >>>>> couldn't figure out where the CPU deadlock comes from, cause I coul= dn't >>>>> reliable reproduce the issue. >>>>> >>>>> What is the content of /proc//task/*/stack and >>>>> sys/kernel/debug/dri/0/radeon_fence_info when the X server is stuck= in >>>>> the >>>>> deadlock situation? >>>>> >>>>> I'm pretty sure that we nearly always have a problem when two threa= ds >>>>> are >>>>> waiting for fences on one of them detects that we have a lockup whi= le >>>>> the >>>>> other one keeps holding the exclusive lock. Signaling all fences mi= ght >>>>> work >>>>> around that problem, but it probably would be better to fix the >>>>> underlying >>>>> issue. >>>>> >>>>> Going to take a deeper look into it. >>>>> >>>>> Christian. >>>>> >>>>> Am 03.10.2013 02:45, schrieb Marek Ol=C5=A1=C3=A1k: >>>>>> First of all, I can't complain about the reliability of the hardwa= re >>>>>> GPU reset. It's mostly the kernel driver that happens to run into = a >>>>>> deadlock at the same time. >>>>>> >>>>>> Regarding the issue with fences, the problem is that the GPU reset >>>>>> completes successfully according to dmesg, but X doesn't respond. = I >>>>>> can move the cursor on the screen, but I can't do anything else an= d >>>>>> the UI is frozen. gdb says that X is stuck in GEM_WAIT_IDLE. I can >>>>>> easily reproduce this, because it's the most common reason why a G= PU >>>>>> lockup leads to frozen X. The GPU actually recovers, but X is hung= . I >>>>>> can't tell whether the fences are just not signalled or whether th= ere >>>>>> is actually a real CPU deadlock I can't see. >>>>>> >>>>>> This patch makes the problem go away and GPU resets are successful >>>>>> (except for extreme cases, see below). With a small enough lockup >>>>>> timeout, the lockups are just a minor annoyance and I thought I co= uld >>>>>> get through a piglit run just with a few tens or hundreds of GPU >>>>>> resets... >>>>>> >>>>>> A different type of deadlock showed up, though it needs a lot of >>>>>> concurrently-running apps like piglit. What happened is that the >>>>>> kernel driver was stuck/deadlocked in radeon_cs_ioctl presumably d= ue >>>>>> to a GPU hang while holding onto the exclusive lock, and another >>>>>> thread wanting to do the GPU reset was unable to acquire the lock. >>>>>> >>>>>> That said, I will use the patch locally, because it helps a lot. I= got >>>>>> a few lockups while writing this email and I'm glad I didn't have = to >>>>>> reboot. >>>>>> >>>>>> Marek >>>>>> >>>>>> On Wed, Oct 2, 2013 at 4:50 PM, Christian K=C3=B6nig >>>>>> >>>>>> wrote: >>>>>>> Possible, but I would rather guess that this doesn't work because= the >>>>>>> IB >>>>>>> test runs into a deadlock situation and so the GPU reset never fu= lly >>>>>>> completes. >>>>>>> >>>>>>> Can you reproduce the problem? >>>>>>> >>>>>>> If you want to make GPU resets more reliable I would rather sugge= st to >>>>>>> remove the ring lock dependency. >>>>>>> Then we should try to give all the fence wait functions a (reliab= le) >>>>>>> timeout and move reset handling a layer up into the ioctl functio= ns. >>>>>>> But for >>>>>>> this you need to rip out the old PM code first. >>>>>>> >>>>>>> Christian. >>>>>>> >>>>>>> Marek Ol=C5=A1=C3=A1k schrieb: >>>>>>> >>>>>>>> I'm afraid signalling the fences with an IB test is not reliable= . >>>>>>>> >>>>>>>> Marek >>>>>>>> >>>>>>>> On Wed, Oct 2, 2013 at 3:52 PM, Christian K=C3=B6nig >>>>>>>> wrote: >>>>>>>>> NAK, after recovering from a lockup the first thing we do is >>>>>>>>> signalling all remaining fences with an IB test. >>>>>>>>> >>>>>>>>> If we don't recover we indeed signal all fences manually. >>>>>>>>> >>>>>>>>> Signalling all fences regardless of the outcome of the reset cr= eates >>>>>>>>> problems with both types of partial resets. >>>>>>>>> >>>>>>>>> Christian. >>>>>>>>> >>>>>>>>> Marek Ol=C5=A1=C3=A1k schrieb: >>>>>>>>> >>>>>>>>>> From: Marek Ol=C5=A1=C3=A1k >>>>>>>>>> >>>>>>>>>> After a lockup, fences are not signalled sometimes, causing >>>>>>>>>> the GEM_WAIT_IDLE ioctl to never return, which sometimes resul= ts >>>>>>>>>> in an X server freeze. >>>>>>>>>> >>>>>>>>>> This fixes only one of many deadlocks which can occur during a >>>>>>>>>> lockup. >>>>>>>>>> >>>>>>>>>> Signed-off-by: Marek Ol=C5=A1=C3=A1k >>>>>>>>>> --- >>>>>>>>>> drivers/gpu/drm/radeon/radeon_device.c | 5 +++++ >>>>>>>>>> 1 file changed, 5 insertions(+) >>>>>>>>>> >>>>>>>>>> diff --git a/drivers/gpu/drm/radeon/radeon_device.c >>>>>>>>>> b/drivers/gpu/drm/radeon/radeon_device.c >>>>>>>>>> index 841d0e0..7b97baa 100644 >>>>>>>>>> --- a/drivers/gpu/drm/radeon/radeon_device.c >>>>>>>>>> +++ b/drivers/gpu/drm/radeon/radeon_device.c >>>>>>>>>> @@ -1552,6 +1552,11 @@ int radeon_gpu_reset(struct radeon_devi= ce >>>>>>>>>> *rdev) >>>>>>>>>> radeon_save_bios_scratch_regs(rdev); >>>>>>>>>> /* block TTM */ >>>>>>>>>> resched =3D ttm_bo_lock_delayed_workqueue(&rdev->mman= .bdev); >>>>>>>>>> + >>>>>>>>>> + mutex_lock(&rdev->ring_lock); >>>>>>>>>> + radeon_fence_driver_force_completion(rdev); >>>>>>>>>> + mutex_unlock(&rdev->ring_lock); >>>>>>>>>> + >>>>>>>>>> radeon_pm_suspend(rdev); >>>>>>>>>> radeon_suspend(rdev); >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> 1.8.1.2 >>>>>>>>>> >>>>>>>>>> _______________________________________________ >>>>>>>>>> dri-devel mailing list >>>>>>>>>> dri-devel@lists.freedesktop.org >>>>>>>>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel >>>>> >>>>> _______________________________________________ >>>>> dri-devel mailing list >>>>> dri-devel@lists.freedesktop.org >>>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel >>>> --------------020700070301060906000709 Content-Type: text/x-diff; name="0001-drm-radeon-rework-and-fix-reset-detection-v2.patch" Content-Disposition: attachment; filename="0001-drm-radeon-rework-and-fix-reset-detection-v2.patch" Content-Transfer-Encoding: quoted-printable >>From bdcb7536f8a1b0607c37760cf441888a6fc170c4 Mon Sep 17 00:00:00 2001 From: =3D?UTF-8?q?Christian=3D20K=3DC3=3DB6nig?=3D Date: Tue, 8 Oct 2013 18:02:38 +0200 Subject: [PATCH] drm/radeon: rework and fix reset detection v2 MIME-Version: 1.0 Content-Type: text/plain; charset=3DUTF-8 Content-Transfer-Encoding: 8bit Stop fiddling with jiffies, always wait for RADEON_FENCE_JIFFIES_TIMEOUT. Consolidate the two wait sequence implementations into just one function. Activate all waiters and remember if the reset was already done instead o= f trying to reset from only one thread. v2: clear reset flag earlier to avoid timeout in IB test Signed-off-by: Christian K=C3=B6nig --- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 8 + drivers/gpu/drm/radeon/radeon_fence.c | 347 +++++++++++----------------= ------ 3 files changed, 127 insertions(+), 230 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/rad= eon.h index a400ac1..0201c6e 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -327,7 +327,6 @@ struct radeon_fence_driver { /* sync_seq is protected by ring emission lock */ uint64_t sync_seq[RADEON_NUM_RINGS]; atomic64_t last_seq; - unsigned long last_activity; bool initialized; }; =20 @@ -2170,6 +2169,7 @@ struct radeon_device { bool need_dma32; bool accel_working; bool fastfb_working; /* IGP feature*/ + bool needs_reset; struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES]; const struct firmware *me_fw; /* all family ME firmware */ const struct firmware *pfp_fw; /* r6/700 PFP firmware */ diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/rad= eon/radeon_device.c index 841d0e0..3f35f21 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1549,6 +1549,14 @@ int radeon_gpu_reset(struct radeon_device *rdev) int resched; =20 down_write(&rdev->exclusive_lock); + + if (!rdev->needs_reset) { + up_write(&rdev->exclusive_lock); + return 0; + } + + rdev->needs_reset =3D false; + radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched =3D ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/rade= on/radeon_fence.c index ddb8f8e..b8f68b2 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -190,10 +190,8 @@ void radeon_fence_process(struct radeon_device *rdev= , int ring) } } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); =20 - if (wake) { - rdev->fence_drv[ring].last_activity =3D jiffies; + if (wake) wake_up_all(&rdev->fence_queue); - } } =20 /** @@ -212,13 +210,13 @@ static void radeon_fence_destroy(struct kref *kref) } =20 /** - * radeon_fence_seq_signaled - check if a fence sequeuce number has sign= aled + * radeon_fence_seq_signaled - check if a fence sequence number has sign= aled * * @rdev: radeon device pointer * @seq: sequence number * @ring: ring index the fence is associated with * - * Check if the last singled fence sequnce number is >=3D the requested + * Check if the last signaled fence sequnce number is >=3D the requested * sequence number (all asics). * Returns true if the fence has signaled (current fence value * is >=3D requested value) or false if it has not (current fence @@ -263,113 +261,131 @@ bool radeon_fence_signaled(struct radeon_fence *f= ence) } =20 /** - * radeon_fence_wait_seq - wait for a specific sequence number + * radeon_fence_any_seq_signaled - check if any sequence number is signa= led * * @rdev: radeon device pointer - * @target_seq: sequence number we want to wait for - * @ring: ring index the fence is associated with + * @seq: sequence numbers + * + * Check if the last signaled fence sequnce number is >=3D the requested + * sequence number (all asics). + * Returns true if any has signaled (current value is >=3D requested val= ue) + * or false if it has not. Helper function for radeon_fence_wait_seq. + */ +static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u6= 4 *seq) +{ + unsigned i; + + for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { + if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i)) + return true; + } + return false; +} + +/** + * radeon_fence_wait_seq - wait for a specific sequence numbers + * + * @rdev: radeon device pointer + * @target_seq: sequence number(s) we want to wait for * @intr: use interruptable sleep * @lock_ring: whether the ring should be locked or not * - * Wait for the requested sequence number to be written (all asics). + * Wait for the requested sequence number(s) to be written by any ring + * (all asics). Sequnce number array is indexed by ring id. * @intr selects whether to use interruptable (true) or non-interruptabl= e * (false) sleep when waiting for the sequence number. Helper function - * for radeon_fence_wait(), et al. + * for radeon_fence_wait_*(). * Returns 0 if the sequence number has passed, error for all other case= s. - * -EDEADLK is returned when a GPU lockup has been detected and the ring= is - * marked as not ready so no further jobs get scheduled until a successf= ul - * reset. + * -EDEADLK is returned when a GPU lockup has been detected. */ -static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_= seq, - unsigned ring, bool intr, bool lock_ring) +static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target= _seq, + bool intr, bool lock_ring) { - unsigned long timeout, last_activity; - uint64_t seq; - unsigned i; + uint64_t last_seq[RADEON_NUM_RINGS]; bool signaled; - int r; + int i, r; + + while (!radeon_fence_any_seq_signaled(rdev, target_seq)) { + + /* Save current sequence values, used to check for GPU lockups */ + for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; =20 - while (target_seq > atomic64_read(&rdev->fence_drv[ring].last_seq)) { - if (!rdev->ring[ring].ready) { - return -EBUSY; + last_seq[i] =3D atomic64_read(&rdev->fence_drv[i].last_seq); + trace_radeon_fence_wait_begin(rdev->ddev, target_seq[i]); + radeon_irq_kms_sw_irq_get(rdev, i); } =20 - timeout =3D jiffies - RADEON_FENCE_JIFFIES_TIMEOUT; - if (time_after(rdev->fence_drv[ring].last_activity, timeout)) { - /* the normal case, timeout is somewhere before last_activity */ - timeout =3D rdev->fence_drv[ring].last_activity - timeout; + if (intr) { + r =3D wait_event_interruptible_timeout(rdev->fence_queue, ( + (signaled =3D radeon_fence_any_seq_signaled(rdev, target_seq)) + || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT); } else { - /* either jiffies wrapped around, or no fence was signaled in the las= t 500ms - * anyway we will just wait for the minimum amount and then check for= a lockup - */ - timeout =3D 1; + r =3D wait_event_timeout(rdev->fence_queue, ( + (signaled =3D radeon_fence_any_seq_signaled(rdev, target_seq)) + || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT); } - seq =3D atomic64_read(&rdev->fence_drv[ring].last_seq); - /* Save current last activity valuee, used to check for GPU lockups */ - last_activity =3D rdev->fence_drv[ring].last_activity; =20 - trace_radeon_fence_wait_begin(rdev->ddev, seq); - radeon_irq_kms_sw_irq_get(rdev, ring); - if (intr) { - r =3D wait_event_interruptible_timeout(rdev->fence_queue, - (signaled =3D radeon_fence_seq_signaled(rdev, target_seq, ring)), - timeout); - } else { - r =3D wait_event_timeout(rdev->fence_queue, - (signaled =3D radeon_fence_seq_signaled(rdev, target_seq, ring)), - timeout); + for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; + + radeon_irq_kms_sw_irq_put(rdev, i); + trace_radeon_fence_wait_end(rdev->ddev, target_seq[i]); } - radeon_irq_kms_sw_irq_put(rdev, ring); - if (unlikely(r < 0)) { + + if (unlikely(r < 0)) return r; - } - trace_radeon_fence_wait_end(rdev->ddev, seq); =20 if (unlikely(!signaled)) { + if (rdev->needs_reset) + return -EDEADLK; + /* we were interrupted for some reason and fence * isn't signaled yet, resume waiting */ - if (r) { + if (r) continue; + + for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; + + if (last_seq[i] !=3D atomic64_read(&rdev->fence_drv[i].last_seq)) + break; } =20 - /* check if sequence value has changed since last_activity */ - if (seq !=3D atomic64_read(&rdev->fence_drv[ring].last_seq)) { + if (i !=3D RADEON_NUM_RINGS) continue; - } =20 - if (lock_ring) { + if (lock_ring) mutex_lock(&rdev->ring_lock); - } =20 - /* test if somebody else has already decided that this is a lockup */ - if (last_activity !=3D rdev->fence_drv[ring].last_activity) { - if (lock_ring) { - mutex_unlock(&rdev->ring_lock); - } - continue; + for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; + + if (radeon_ring_is_lockup(rdev, i, &rdev->ring[i])) + break; } =20 - if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) { + if (i < RADEON_NUM_RINGS) { /* good news we believe it's a lockup */ - dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx last fence id= 0x%016llx)\n", - target_seq, seq); - - /* change last activity so nobody else think there is a lockup */ - for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { - rdev->fence_drv[i].last_activity =3D jiffies; - } - - /* mark the ring as not ready any more */ - rdev->ring[ring].ready =3D false; - if (lock_ring) { + dev_warn(rdev->dev, "GPU lockup (waiting for " + "0x%016llx last fence id 0x%016llx on" + " ring %d)\n", + target_seq[i], last_seq[i], i); + + /* remember that we need an reset */ + rdev->needs_reset =3D true; + if (lock_ring) mutex_unlock(&rdev->ring_lock); - } + wake_up_all(&rdev->fence_queue); return -EDEADLK; } =20 - if (lock_ring) { + if (lock_ring) mutex_unlock(&rdev->ring_lock); - } } } return 0; @@ -388,6 +404,7 @@ static int radeon_fence_wait_seq(struct radeon_device= *rdev, u64 target_seq, */ int radeon_fence_wait(struct radeon_fence *fence, bool intr) { + uint64_t seq[RADEON_NUM_RINGS] =3D {}; int r; =20 if (fence =3D=3D NULL) { @@ -395,147 +412,15 @@ int radeon_fence_wait(struct radeon_fence *fence, = bool intr) return -EINVAL; } =20 - r =3D radeon_fence_wait_seq(fence->rdev, fence->seq, - fence->ring, intr, true); - if (r) { - return r; - } - fence->seq =3D RADEON_FENCE_SIGNALED_SEQ; - return 0; -} - -static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u6= 4 *seq) -{ - unsigned i; - - for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { - if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i)) { - return true; - } - } - return false; -} - -/** - * radeon_fence_wait_any_seq - wait for a sequence number on any ring - * - * @rdev: radeon device pointer - * @target_seq: sequence number(s) we want to wait for - * @intr: use interruptable sleep - * - * Wait for the requested sequence number(s) to be written by any ring - * (all asics). Sequnce number array is indexed by ring id. - * @intr selects whether to use interruptable (true) or non-interruptabl= e - * (false) sleep when waiting for the sequence number. Helper function - * for radeon_fence_wait_any(), et al. - * Returns 0 if the sequence number has passed, error for all other case= s. - */ -static int radeon_fence_wait_any_seq(struct radeon_device *rdev, - u64 *target_seq, bool intr) -{ - unsigned long timeout, last_activity, tmp; - unsigned i, ring =3D RADEON_NUM_RINGS; - bool signaled; - int r; - - for (i =3D 0, last_activity =3D 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) { - continue; - } - - /* use the most recent one as indicator */ - if (time_after(rdev->fence_drv[i].last_activity, last_activity)) { - last_activity =3D rdev->fence_drv[i].last_activity; - } - - /* For lockup detection just pick the lowest ring we are - * actively waiting for - */ - if (i < ring) { - ring =3D i; - } - } - - /* nothing to wait for ? */ - if (ring =3D=3D RADEON_NUM_RINGS) { - return -ENOENT; - } - - while (!radeon_fence_any_seq_signaled(rdev, target_seq)) { - timeout =3D jiffies - RADEON_FENCE_JIFFIES_TIMEOUT; - if (time_after(last_activity, timeout)) { - /* the normal case, timeout is somewhere before last_activity */ - timeout =3D last_activity - timeout; - } else { - /* either jiffies wrapped around, or no fence was signaled in the las= t 500ms - * anyway we will just wait for the minimum amount and then check for= a lockup - */ - timeout =3D 1; - } + seq[fence->ring] =3D fence->seq; + if (seq[fence->ring] =3D=3D RADEON_FENCE_SIGNALED_SEQ) + return 0; =20 - trace_radeon_fence_wait_begin(rdev->ddev, target_seq[ring]); - for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { - if (target_seq[i]) { - radeon_irq_kms_sw_irq_get(rdev, i); - } - } - if (intr) { - r =3D wait_event_interruptible_timeout(rdev->fence_queue, - (signaled =3D radeon_fence_any_seq_signaled(rdev, target_seq)), - timeout); - } else { - r =3D wait_event_timeout(rdev->fence_queue, - (signaled =3D radeon_fence_any_seq_signaled(rdev, target_seq)), - timeout); - } - for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { - if (target_seq[i]) { - radeon_irq_kms_sw_irq_put(rdev, i); - } - } - if (unlikely(r < 0)) { - return r; - } - trace_radeon_fence_wait_end(rdev->ddev, target_seq[ring]); - - if (unlikely(!signaled)) { - /* we were interrupted for some reason and fence - * isn't signaled yet, resume waiting */ - if (r) { - continue; - } - - mutex_lock(&rdev->ring_lock); - for (i =3D 0, tmp =3D 0; i < RADEON_NUM_RINGS; ++i) { - if (time_after(rdev->fence_drv[i].last_activity, tmp)) { - tmp =3D rdev->fence_drv[i].last_activity; - } - } - /* test if somebody else has already decided that this is a lockup */ - if (last_activity !=3D tmp) { - last_activity =3D tmp; - mutex_unlock(&rdev->ring_lock); - continue; - } - - if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) { - /* good news we believe it's a lockup */ - dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx)\n", - target_seq[ring]); - - /* change last activity so nobody else think there is a lockup */ - for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { - rdev->fence_drv[i].last_activity =3D jiffies; - } + r =3D radeon_fence_wait_seq(fence->rdev, seq, intr, true); + if (r) + return r; =20 - /* mark the ring as not ready any more */ - rdev->ring[ring].ready =3D false; - mutex_unlock(&rdev->ring_lock); - return -EDEADLK; - } - mutex_unlock(&rdev->ring_lock); - } - } + fence->seq =3D RADEON_FENCE_SIGNALED_SEQ; return 0; } =20 @@ -557,7 +442,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev, bool intr) { uint64_t seq[RADEON_NUM_RINGS]; - unsigned i; + unsigned i, num_rings =3D 0; int r; =20 for (i =3D 0; i < RADEON_NUM_RINGS; ++i) { @@ -567,15 +452,19 @@ int radeon_fence_wait_any(struct radeon_device *rde= v, continue; } =20 - if (fences[i]->seq =3D=3D RADEON_FENCE_SIGNALED_SEQ) { - /* something was allready signaled */ - return 0; - } - seq[i] =3D fences[i]->seq; + ++num_rings; + + /* test if something was allready signaled */ + if (seq[i] =3D=3D RADEON_FENCE_SIGNALED_SEQ) + return 0; } =20 - r =3D radeon_fence_wait_any_seq(rdev, seq, intr); + /* nothing to wait for ? */ + if (num_rings =3D=3D 0) + return -ENOENT; + + r =3D radeon_fence_wait_seq(rdev, seq, intr, true); if (r) { return r; } @@ -594,15 +483,15 @@ int radeon_fence_wait_any(struct radeon_device *rde= v, */ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring) { - uint64_t seq; + uint64_t seq[RADEON_NUM_RINGS] =3D {}; =20 - seq =3D atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; - if (seq >=3D rdev->fence_drv[ring].sync_seq[ring]) { + seq[ring] =3D atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; + if (seq[ring] >=3D rdev->fence_drv[ring].sync_seq[ring]) { /* nothing to wait for, last_seq is already the last emited fence */ return -ENOENT; } - return radeon_fence_wait_seq(rdev, seq, ring, false, false); + return radeon_fence_wait_seq(rdev, seq, false, false); } =20 /** @@ -617,14 +506,15 @@ int radeon_fence_wait_next_locked(struct radeon_dev= ice *rdev, int ring) */ int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) { - uint64_t seq =3D rdev->fence_drv[ring].sync_seq[ring]; + uint64_t seq[RADEON_NUM_RINGS] =3D {}; int r; =20 - r =3D radeon_fence_wait_seq(rdev, seq, ring, false, false); + seq[ring] =3D rdev->fence_drv[ring].sync_seq[ring]; + r =3D radeon_fence_wait_seq(rdev, seq, false, false); if (r) { - if (r =3D=3D -EDEADLK) { + if (r =3D=3D -EDEADLK) return -EDEADLK; - } + dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n", ring, r); } @@ -826,7 +716,6 @@ static void radeon_fence_driver_init_ring(struct rade= on_device *rdev, int ring) for (i =3D 0; i < RADEON_NUM_RINGS; ++i) rdev->fence_drv[ring].sync_seq[i] =3D 0; atomic64_set(&rdev->fence_drv[ring].last_seq, 0); - rdev->fence_drv[ring].last_activity =3D jiffies; rdev->fence_drv[ring].initialized =3D false; } =20 --=20 1.8.1.2 --------------020700070301060906000709 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel --------------020700070301060906000709--