diff options
| author | Jerome Glisse <jglisse@redhat.com> | 2012-05-09 09:34:47 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2012-05-09 12:22:19 -0400 |
| commit | 3b7a2b24ea2b703b3af595d0d4ee233ab0b36377 (patch) | |
| tree | 0f8ccea66571d7ffa556dd55cf8717e429ed59cf | |
| parent | bb635567291482a87e4cc46e6683419c1f365ddf (diff) | |
drm/radeon: rework fence handling, drop fence list v7
Using 64bits fence sequence we can directly compare sequence
number to know if a fence is signaled or not. Thus the fence
list became useless, so does the fence lock that mainly
protected the fence list.
Things like ring.ready are no longer behind a lock, this should
be ok as ring.ready is initialized once and will only change
when facing lockup. Worst case is that we return an -EBUSY just
after a successfull GPU reset, or we go into wait state instead
of returning -EBUSY (thus delaying reporting -EBUSY to fence
wait caller).
v2: Remove left over comment, force using writeback on cayman and
newer, thus not having to suffer from possibly scratch reg
exhaustion
v3: Rebase on top of change to uint64 fence patch
v4: Change DCE5 test to force write back on cayman and newer but
also any APU such as PALM or SUMO family
v5: Rebase on top of new uint64 fence patch
v6: Just break if seq doesn't change any more. Use radeon_fence
prefix for all function names. Even if it's now highly optimized,
try avoiding polling to often.
v7: We should never poll the last_seq from the hardware without
waking the sleeping threads, otherwise we might lose events.
Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Christian König <deathsimple@vodafone.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_fence.c | 299 |
3 files changed, 119 insertions, 194 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index cdf46bc6dcc4..7c8711793421 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
| @@ -263,15 +263,12 @@ struct radeon_fence_driver { | |||
| 263 | atomic64_t last_seq; | 263 | atomic64_t last_seq; |
| 264 | unsigned long last_activity; | 264 | unsigned long last_activity; |
| 265 | wait_queue_head_t queue; | 265 | wait_queue_head_t queue; |
| 266 | struct list_head emitted; | ||
| 267 | struct list_head signaled; | ||
| 268 | bool initialized; | 266 | bool initialized; |
| 269 | }; | 267 | }; |
| 270 | 268 | ||
| 271 | struct radeon_fence { | 269 | struct radeon_fence { |
| 272 | struct radeon_device *rdev; | 270 | struct radeon_device *rdev; |
| 273 | struct kref kref; | 271 | struct kref kref; |
| 274 | struct list_head list; | ||
| 275 | /* protected by radeon_fence.lock */ | 272 | /* protected by radeon_fence.lock */ |
| 276 | uint64_t seq; | 273 | uint64_t seq; |
| 277 | /* RB, DMA, etc. */ | 274 | /* RB, DMA, etc. */ |
| @@ -291,7 +288,7 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring); | |||
| 291 | int radeon_fence_wait_empty(struct radeon_device *rdev, int ring); | 288 | int radeon_fence_wait_empty(struct radeon_device *rdev, int ring); |
| 292 | struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence); | 289 | struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence); |
| 293 | void radeon_fence_unref(struct radeon_fence **fence); | 290 | void radeon_fence_unref(struct radeon_fence **fence); |
| 294 | int radeon_fence_count_emitted(struct radeon_device *rdev, int ring); | 291 | unsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring); |
| 295 | 292 | ||
| 296 | /* | 293 | /* |
| 297 | * Tiling registers | 294 | * Tiling registers |
| @@ -1534,7 +1531,6 @@ struct radeon_device { | |||
| 1534 | struct radeon_mode_info mode_info; | 1531 | struct radeon_mode_info mode_info; |
| 1535 | struct radeon_scratch scratch; | 1532 | struct radeon_scratch scratch; |
| 1536 | struct radeon_mman mman; | 1533 | struct radeon_mman mman; |
| 1537 | rwlock_t fence_lock; | ||
| 1538 | struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; | 1534 | struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; |
| 1539 | struct radeon_semaphore_driver semaphore_drv; | 1535 | struct radeon_semaphore_driver semaphore_drv; |
| 1540 | struct mutex ring_lock; | 1536 | struct mutex ring_lock; |
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 3f6ff2a0bce2..0e7b72a0ed35 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
| @@ -225,9 +225,9 @@ int radeon_wb_init(struct radeon_device *rdev) | |||
| 225 | /* disable event_write fences */ | 225 | /* disable event_write fences */ |
| 226 | rdev->wb.use_event = false; | 226 | rdev->wb.use_event = false; |
| 227 | /* disabled via module param */ | 227 | /* disabled via module param */ |
| 228 | if (radeon_no_wb == 1) | 228 | if (radeon_no_wb == 1) { |
| 229 | rdev->wb.enabled = false; | 229 | rdev->wb.enabled = false; |
| 230 | else { | 230 | } else { |
| 231 | if (rdev->flags & RADEON_IS_AGP) { | 231 | if (rdev->flags & RADEON_IS_AGP) { |
| 232 | /* often unreliable on AGP */ | 232 | /* often unreliable on AGP */ |
| 233 | rdev->wb.enabled = false; | 233 | rdev->wb.enabled = false; |
| @@ -237,8 +237,9 @@ int radeon_wb_init(struct radeon_device *rdev) | |||
| 237 | } else { | 237 | } else { |
| 238 | rdev->wb.enabled = true; | 238 | rdev->wb.enabled = true; |
| 239 | /* event_write fences are only available on r600+ */ | 239 | /* event_write fences are only available on r600+ */ |
| 240 | if (rdev->family >= CHIP_R600) | 240 | if (rdev->family >= CHIP_R600) { |
| 241 | rdev->wb.use_event = true; | 241 | rdev->wb.use_event = true; |
| 242 | } | ||
| 242 | } | 243 | } |
| 243 | } | 244 | } |
| 244 | /* always use writeback/events on NI, APUs */ | 245 | /* always use writeback/events on NI, APUs */ |
| @@ -731,7 +732,6 @@ int radeon_device_init(struct radeon_device *rdev, | |||
| 731 | mutex_init(&rdev->gem.mutex); | 732 | mutex_init(&rdev->gem.mutex); |
| 732 | mutex_init(&rdev->pm.mutex); | 733 | mutex_init(&rdev->pm.mutex); |
| 733 | mutex_init(&rdev->vram_mutex); | 734 | mutex_init(&rdev->vram_mutex); |
| 734 | rwlock_init(&rdev->fence_lock); | ||
| 735 | rwlock_init(&rdev->semaphore_drv.lock); | 735 | rwlock_init(&rdev->semaphore_drv.lock); |
| 736 | INIT_LIST_HEAD(&rdev->gem.objects); | 736 | INIT_LIST_HEAD(&rdev->gem.objects); |
| 737 | init_waitqueue_head(&rdev->irq.vblank_queue); | 737 | init_waitqueue_head(&rdev->irq.vblank_queue); |
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index feb2bbc6ef6d..ed202255ac76 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c | |||
| @@ -63,30 +63,18 @@ static u32 radeon_fence_read(struct radeon_device *rdev, int ring) | |||
| 63 | 63 | ||
| 64 | int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) | 64 | int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) |
| 65 | { | 65 | { |
| 66 | unsigned long irq_flags; | 66 | /* we are protected by the ring emission mutex */ |
| 67 | |||
| 68 | write_lock_irqsave(&rdev->fence_lock, irq_flags); | ||
| 69 | if (fence->seq && fence->seq < RADEON_FENCE_NOTEMITED_SEQ) { | 67 | if (fence->seq && fence->seq < RADEON_FENCE_NOTEMITED_SEQ) { |
| 70 | write_unlock_irqrestore(&rdev->fence_lock, irq_flags); | ||
| 71 | return 0; | 68 | return 0; |
| 72 | } | 69 | } |
| 73 | /* we are protected by the ring emission mutex */ | ||
| 74 | fence->seq = ++rdev->fence_drv[fence->ring].seq; | 70 | fence->seq = ++rdev->fence_drv[fence->ring].seq; |
| 75 | radeon_fence_ring_emit(rdev, fence->ring, fence); | 71 | radeon_fence_ring_emit(rdev, fence->ring, fence); |
| 76 | trace_radeon_fence_emit(rdev->ddev, fence->seq); | 72 | trace_radeon_fence_emit(rdev->ddev, fence->seq); |
| 77 | /* are we the first fence on a previusly idle ring? */ | ||
| 78 | if (list_empty(&rdev->fence_drv[fence->ring].emitted)) { | ||
| 79 | rdev->fence_drv[fence->ring].last_activity = jiffies; | ||
| 80 | } | ||
| 81 | list_move_tail(&fence->list, &rdev->fence_drv[fence->ring].emitted); | ||
| 82 | write_unlock_irqrestore(&rdev->fence_lock, irq_flags); | ||
| 83 | return 0; | 73 | return 0; |
| 84 | } | 74 | } |
| 85 | 75 | ||
| 86 | static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring) | 76 | void radeon_fence_process(struct radeon_device *rdev, int ring) |
| 87 | { | 77 | { |
| 88 | struct radeon_fence *fence; | ||
| 89 | struct list_head *i, *n; | ||
| 90 | uint64_t seq, last_seq; | 78 | uint64_t seq, last_seq; |
| 91 | unsigned count_loop = 0; | 79 | unsigned count_loop = 0; |
| 92 | bool wake = false; | 80 | bool wake = false; |
| @@ -120,14 +108,15 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring) | |||
| 120 | seq += 0x100000000LL; | 108 | seq += 0x100000000LL; |
| 121 | } | 109 | } |
| 122 | 110 | ||
| 123 | if (!wake && seq == last_seq) { | 111 | if (seq == last_seq) { |
| 124 | return false; | 112 | break; |
| 125 | } | 113 | } |
| 126 | /* If we loop over we don't want to return without | 114 | /* If we loop over we don't want to return without |
| 127 | * checking if a fence is signaled as it means that the | 115 | * checking if a fence is signaled as it means that the |
| 128 | * seq we just read is different from the previous on. | 116 | * seq we just read is different from the previous on. |
| 129 | */ | 117 | */ |
| 130 | wake = true; | 118 | wake = true; |
| 119 | last_seq = seq; | ||
| 131 | if ((count_loop++) > 10) { | 120 | if ((count_loop++) > 10) { |
| 132 | /* We looped over too many time leave with the | 121 | /* We looped over too many time leave with the |
| 133 | * fact that we might have set an older fence | 122 | * fact that we might have set an older fence |
| @@ -136,46 +125,20 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring) | |||
| 136 | */ | 125 | */ |
| 137 | break; | 126 | break; |
| 138 | } | 127 | } |
| 139 | last_seq = seq; | ||
| 140 | } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); | 128 | } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); |
| 141 | 129 | ||
| 142 | /* reset wake to false */ | 130 | if (wake) { |
| 143 | wake = false; | 131 | rdev->fence_drv[ring].last_activity = jiffies; |
| 144 | rdev->fence_drv[ring].last_activity = jiffies; | 132 | wake_up_all(&rdev->fence_drv[ring].queue); |
| 145 | |||
| 146 | n = NULL; | ||
| 147 | list_for_each(i, &rdev->fence_drv[ring].emitted) { | ||
| 148 | fence = list_entry(i, struct radeon_fence, list); | ||
| 149 | if (fence->seq == seq) { | ||
| 150 | n = i; | ||
