diff options
author | Christian König <deathsimple@vodafone.de> | 2012-05-09 09:34:48 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-05-09 12:22:20 -0400 |
commit | 8a47cc9ec1249eefd600adb273148c62879a560d (patch) | |
tree | 70cda5e8f7830a508431b1a87c472978c927150b /drivers/gpu/drm | |
parent | 3b7a2b24ea2b703b3af595d0d4ee233ab0b36377 (diff) |
drm/radeon: rework locking ring emission mutex in fence deadlock detection v2
Some callers illegal called fence_wait_next/empty
while holding the ring emission mutex. So don't
relock the mutex in that cases, and move the actual
locking into the fence code.
v2: Don't try to unlock the mutex if it isn't locked.
Signed-off-by: Christian König <deathsimple@vodafone.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_fence.c | 43 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_ring.c | 6 |
5 files changed, 37 insertions, 29 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 7c8711793421..701094b05f47 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -284,8 +284,8 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence); | |||
284 | void radeon_fence_process(struct radeon_device *rdev, int ring); | 284 | void radeon_fence_process(struct radeon_device *rdev, int ring); |
285 | bool radeon_fence_signaled(struct radeon_fence *fence); | 285 | bool radeon_fence_signaled(struct radeon_fence *fence); |
286 | int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); | 286 | int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); |
287 | int radeon_fence_wait_next(struct radeon_device *rdev, int ring); | 287 | int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring); |
288 | int radeon_fence_wait_empty(struct radeon_device *rdev, int ring); | 288 | int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); |
289 | struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence); | 289 | struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence); |
290 | void radeon_fence_unref(struct radeon_fence **fence); | 290 | void radeon_fence_unref(struct radeon_fence **fence); |
291 | unsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring); | 291 | unsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring); |
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 0e7b72a0ed35..b827b2e578f3 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
@@ -912,9 +912,12 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) | |||
912 | } | 912 | } |
913 | /* evict vram memory */ | 913 | /* evict vram memory */ |
914 | radeon_bo_evict_vram(rdev); | 914 | radeon_bo_evict_vram(rdev); |
915 | |||
916 | mutex_lock(&rdev->ring_lock); | ||
915 | /* wait for gpu to finish processing current batch */ | 917 | /* wait for gpu to finish processing current batch */ |
916 | for (i = 0; i < RADEON_NUM_RINGS; i++) | 918 | for (i = 0; i < RADEON_NUM_RINGS; i++) |
917 | radeon_fence_wait_empty(rdev, i); | 919 | radeon_fence_wait_empty_locked(rdev, i); |
920 | mutex_unlock(&rdev->ring_lock); | ||
918 | 921 | ||
919 | radeon_save_bios_scratch_regs(rdev); | 922 | radeon_save_bios_scratch_regs(rdev); |
920 | 923 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index ed202255ac76..098d1faed1a6 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c | |||
@@ -194,7 +194,7 @@ bool radeon_fence_signaled(struct radeon_fence *fence) | |||
194 | } | 194 | } |
195 | 195 | ||
196 | static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, | 196 | static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, |
197 | unsigned ring, bool intr) | 197 | unsigned ring, bool intr, bool lock_ring) |
198 | { | 198 | { |
199 | unsigned long timeout, last_activity; | 199 | unsigned long timeout, last_activity; |
200 | uint64_t seq; | 200 | uint64_t seq; |
@@ -249,8 +249,16 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, | |||
249 | if (seq != atomic64_read(&rdev->fence_drv[ring].last_seq)) { | 249 | if (seq != atomic64_read(&rdev->fence_drv[ring].last_seq)) { |
250 | continue; | 250 | continue; |
251 | } | 251 | } |
252 | |||
253 | if (lock_ring) { | ||
254 | mutex_lock(&rdev->ring_lock); | ||
255 | } | ||
256 | |||
252 | /* test if somebody else has already decided that this is a lockup */ | 257 | /* test if somebody else has already decided that this is a lockup */ |
253 | if (last_activity != rdev->fence_drv[ring].last_activity) { | 258 | if (last_activity != rdev->fence_drv[ring].last_activity) { |
259 | if (lock_ring) { | ||
260 | mutex_unlock(&rdev->ring_lock); | ||
261 | } | ||
254 | continue; | 262 | continue; |
255 | } | 263 | } |
256 | 264 | ||
@@ -264,15 +272,17 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, | |||
264 | rdev->fence_drv[i].last_activity = jiffies; | 272 | rdev->fence_drv[i].last_activity = jiffies; |
265 | } | 273 | } |
266 | 274 | ||
267 | /* change last activity so nobody else think there is a lockup */ | ||
268 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { | ||
269 | rdev->fence_drv[i].last_activity = jiffies; | ||
270 | } | ||
271 | |||
272 | /* mark the ring as not ready any more */ | 275 | /* mark the ring as not ready any more */ |
273 | rdev->ring[ring].ready = false; | 276 | rdev->ring[ring].ready = false; |
277 | if (lock_ring) { | ||
278 | mutex_unlock(&rdev->ring_lock); | ||
279 | } | ||
274 | return -EDEADLK; | 280 | return -EDEADLK; |
275 | } | 281 | } |
282 | |||
283 | if (lock_ring) { | ||
284 | mutex_unlock(&rdev->ring_lock); | ||
285 | } | ||
276 | } | 286 | } |
277 | } | 287 | } |
278 | return 0; | 288 | return 0; |
@@ -287,7 +297,8 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) | |||
287 | return -EINVAL; | 297 | return -EINVAL; |
288 | } | 298 | } |
289 | 299 | ||
290 | r = radeon_fence_wait_seq(fence->rdev, fence->seq, fence->ring, intr); | 300 | r = radeon_fence_wait_seq(fence->rdev, fence->seq, |
301 | fence->ring, intr, true); | ||
291 | if (r) { | 302 | if (r) { |
292 | return r; | 303 | return r; |
293 | } | 304 | } |
@@ -295,7 +306,7 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) | |||
295 | return 0; | 306 | return 0; |
296 | } | 307 | } |
297 | 308 | ||
298 | int radeon_fence_wait_next(struct radeon_device *rdev, int ring) | 309 | int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring) |
299 | { | 310 | { |
300 | uint64_t seq; | 311 | uint64_t seq; |
301 | 312 | ||
@@ -305,20 +316,22 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) | |||
305 | */ | 316 | */ |
306 | seq = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; | 317 | seq = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; |
307 | if (seq >= rdev->fence_drv[ring].seq) { | 318 | if (seq >= rdev->fence_drv[ring].seq) { |
308 | /* nothing to wait for, last_seq is already the last emited fence */ | 319 | /* nothing to wait for, last_seq is |
309 | return 0; | 320 | already the last emited fence */ |
321 | return -ENOENT; | ||
310 | } | 322 | } |
311 | return radeon_fence_wait_seq(rdev, seq, ring, false); | 323 | return radeon_fence_wait_seq(rdev, seq, ring, false, false); |
312 | } | 324 | } |
313 | 325 | ||
314 | int radeon_fence_wait_empty(struct radeon_device *rdev, int ring) | 326 | int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) |
315 | { | 327 | { |
316 | /* We are not protected by ring lock when reading current seq | 328 | /* We are not protected by ring lock when reading current seq |
317 | * but it's ok as wait empty is call from place where no more | 329 | * but it's ok as wait empty is call from place where no more |
318 | * activity can be scheduled so there won't be concurrent access | 330 | * activity can be scheduled so there won't be concurrent access |
319 | * to seq value. | 331 | * to seq value. |
320 | */ | 332 | */ |
321 | return radeon_fence_wait_seq(rdev, rdev->fence_drv[ring].seq, ring, false); | 333 | return radeon_fence_wait_seq(rdev, rdev->fence_drv[ring].seq, |
334 | ring, false, false); | ||
322 | } | 335 | } |
323 | 336 | ||
324 | struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence) | 337 | struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence) |
@@ -410,14 +423,16 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) | |||
410 | { | 423 | { |
411 | int ring; | 424 | int ring; |
412 | 425 | ||
426 | mutex_lock(&rdev->ring_lock); | ||
413 | for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { | 427 | for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { |
414 | if (!rdev->fence_drv[ring].initialized) | 428 | if (!rdev->fence_drv[ring].initialized) |
415 | continue; | 429 | continue; |
416 | radeon_fence_wait_empty(rdev, ring); | 430 | radeon_fence_wait_empty_locked(rdev, ring); |
417 | wake_up_all(&rdev->fence_drv[ring].queue); | 431 | wake_up_all(&rdev->fence_drv[ring].queue); |
418 | radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); | 432 | radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); |
419 | rdev->fence_drv[ring].initialized = false; | 433 | rdev->fence_drv[ring].initialized = false; |
420 | } | 434 | } |
435 | mutex_unlock(&rdev->ring_lock); | ||
421 | } | 436 | } |
422 | 437 | ||
423 | 438 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 7c3874589e3b..08825548ee69 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -270,13 +270,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) | |||
270 | } else { | 270 | } else { |
271 | struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; | 271 | struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
272 | if (ring->ready) { | 272 | if (ring->ready) { |
273 | struct radeon_fence *fence; | 273 | radeon_fence_wait_empty_locked(rdev, RADEON_RING_TYPE_GFX_INDEX); |
274 | radeon_ring_alloc(rdev, ring, 64); | ||
275 | radeon_fence_create(rdev, &fence, radeon_ring_index(rdev, ring)); | ||
276 | radeon_fence_emit(rdev, fence); | ||
277 | radeon_ring_commit(rdev, ring); | ||
278 | radeon_fence_wait(fence, false); | ||
279 | radeon_fence_unref(&fence); | ||
280 | } | 274 | } |
281 | } | 275 | } |
282 | radeon_unmap_vram_bos(rdev); | 276 | radeon_unmap_vram_bos(rdev); |
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 4ae222bb3ec5..2fdc8c35f87c 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c | |||
@@ -347,9 +347,7 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi | |||
347 | if (ndw < ring->ring_free_dw) { | 347 | if (ndw < ring->ring_free_dw) { |
348 | break; | 348 | break; |
349 | } | 349 | } |
350 | mutex_unlock(&rdev->ring_lock); | 350 | r = radeon_fence_wait_next_locked(rdev, radeon_ring_index(rdev, ring)); |
351 | r = radeon_fence_wait_next(rdev, radeon_ring_index(rdev, ring)); | ||
352 | mutex_lock(&rdev->ring_lock); | ||
353 | if (r) | 351 | if (r) |
354 | return r; | 352 | return r; |
355 | } | 353 | } |
@@ -408,7 +406,6 @@ void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring * | |||
408 | { | 406 | { |
409 | int r; | 407 | int r; |
410 | 408 | ||
411 | mutex_lock(&rdev->ring_lock); | ||
412 | radeon_ring_free_size(rdev, ring); | 409 | radeon_ring_free_size(rdev, ring); |
413 | if (ring->rptr == ring->wptr) { | 410 | if (ring->rptr == ring->wptr) { |
414 | r = radeon_ring_alloc(rdev, ring, 1); | 411 | r = radeon_ring_alloc(rdev, ring, 1); |
@@ -417,7 +414,6 @@ void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring * | |||
417 | radeon_ring_commit(rdev, ring); | 414 | radeon_ring_commit(rdev, ring); |
418 | } | 415 | } |
419 | } | 416 | } |
420 | mutex_unlock(&rdev->ring_lock); | ||
421 | } | 417 | } |
422 | 418 | ||
423 | void radeon_ring_lockup_update(struct radeon_ring *ring) | 419 | void radeon_ring_lockup_update(struct radeon_ring *ring) |