diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 101 |
1 files changed, 54 insertions, 47 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 257d72205bb5..3671f9f220bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | |||
@@ -47,6 +47,9 @@ | |||
47 | * that the the relevant GPU caches have been flushed. | 47 | * that the the relevant GPU caches have been flushed. |
48 | */ | 48 | */ |
49 | 49 | ||
50 | static struct kmem_cache *amdgpu_fence_slab; | ||
51 | static atomic_t amdgpu_fence_slab_ref = ATOMIC_INIT(0); | ||
52 | |||
50 | /** | 53 | /** |
51 | * amdgpu_fence_write - write a fence value | 54 | * amdgpu_fence_write - write a fence value |
52 | * | 55 | * |
@@ -85,24 +88,6 @@ static u32 amdgpu_fence_read(struct amdgpu_ring *ring) | |||
85 | } | 88 | } |
86 | 89 | ||
87 | /** | 90 | /** |
88 | * amdgpu_fence_schedule_check - schedule lockup check | ||
89 | * | ||
90 | * @ring: pointer to struct amdgpu_ring | ||
91 | * | ||
92 | * Queues a delayed work item to check for lockups. | ||
93 | */ | ||
94 | static void amdgpu_fence_schedule_check(struct amdgpu_ring *ring) | ||
95 | { | ||
96 | /* | ||
97 | * Do not reset the timer here with mod_delayed_work, | ||
98 | * this can livelock in an interaction with TTM delayed destroy. | ||
99 | */ | ||
100 | queue_delayed_work(system_power_efficient_wq, | ||
101 | &ring->fence_drv.lockup_work, | ||
102 | AMDGPU_FENCE_JIFFIES_TIMEOUT); | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * amdgpu_fence_emit - emit a fence on the requested ring | 91 | * amdgpu_fence_emit - emit a fence on the requested ring |
107 | * | 92 | * |
108 | * @ring: ring the fence is associated with | 93 | * @ring: ring the fence is associated with |
@@ -118,7 +103,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, | |||
118 | struct amdgpu_device *adev = ring->adev; | 103 | struct amdgpu_device *adev = ring->adev; |
119 | 104 | ||
120 | /* we are protected by the ring emission mutex */ | 105 | /* we are protected by the ring emission mutex */ |
121 | *fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL); | 106 | *fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL); |
122 | if ((*fence) == NULL) { | 107 | if ((*fence) == NULL) { |
123 | return -ENOMEM; | 108 | return -ENOMEM; |
124 | } | 109 | } |
@@ -132,11 +117,23 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, | |||
132 | amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, | 117 | amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, |
133 | (*fence)->seq, | 118 | (*fence)->seq, |
134 | AMDGPU_FENCE_FLAG_INT); | 119 | AMDGPU_FENCE_FLAG_INT); |
135 | trace_amdgpu_fence_emit(ring->adev->ddev, ring->idx, (*fence)->seq); | ||
136 | return 0; | 120 | return 0; |
137 | } | 121 | } |
138 | 122 | ||
139 | /** | 123 | /** |
124 | * amdgpu_fence_schedule_fallback - schedule fallback check | ||
125 | * | ||
126 | * @ring: pointer to struct amdgpu_ring | ||
127 | * | ||
128 | * Start a timer as fallback to our interrupts. | ||
129 | */ | ||
130 | static void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring) | ||
131 | { | ||
132 | mod_timer(&ring->fence_drv.fallback_timer, | ||
133 | jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT); | ||
134 | } | ||
135 | |||
136 | /** | ||
140 | * amdgpu_fence_activity - check for fence activity | 137 | * amdgpu_fence_activity - check for fence activity |
141 | * | 138 | * |
142 | * @ring: pointer to struct amdgpu_ring | 139 | * @ring: pointer to struct amdgpu_ring |
@@ -202,45 +199,38 @@ static bool amdgpu_fence_activity(struct amdgpu_ring *ring) | |||
202 | } while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq); | 199 | } while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq); |
203 | 200 | ||
204 | if (seq < last_emitted) | 201 | if (seq < last_emitted) |
205 | amdgpu_fence_schedule_check(ring); | 202 | amdgpu_fence_schedule_fallback(ring); |
206 | 203 | ||
207 | return wake; | 204 | return wake; |
208 | } | 205 | } |
209 | 206 | ||
210 | /** | 207 | /** |
211 | * amdgpu_fence_check_lockup - check for hardware lockup | 208 | * amdgpu_fence_process - process a fence |
212 | * | 209 | * |
213 | * @work: delayed work item | 210 | * @adev: amdgpu_device pointer |
211 | * @ring: ring index the fence is associated with | ||
214 | * | 212 | * |
215 | * Checks for fence activity and if there is none probe | 213 | * Checks the current fence value and wakes the fence queue |
216 | * the hardware if a lockup occured. | 214 | * if the sequence number has increased (all asics). |
217 | */ | 215 | */ |
218 | static void amdgpu_fence_check_lockup(struct work_struct *work) | 216 | void amdgpu_fence_process(struct amdgpu_ring *ring) |
219 | { | 217 | { |
220 | struct amdgpu_fence_driver *fence_drv; | ||
221 | struct amdgpu_ring *ring; | ||
222 | |||
223 | fence_drv = container_of(work, struct amdgpu_fence_driver, | ||
224 | lockup_work.work); | ||
225 | ring = fence_drv->ring; | ||
226 | |||
227 | if (amdgpu_fence_activity(ring)) | 218 | if (amdgpu_fence_activity(ring)) |
228 | wake_up_all(&ring->fence_drv.fence_queue); | 219 | wake_up_all(&ring->fence_drv.fence_queue); |
229 | } | 220 | } |
230 | 221 | ||
231 | /** | 222 | /** |
232 | * amdgpu_fence_process - process a fence | 223 | * amdgpu_fence_fallback - fallback for hardware interrupts |
233 | * | 224 | * |
234 | * @adev: amdgpu_device pointer | 225 | * @work: delayed work item |
235 | * @ring: ring index the fence is associated with | ||
236 | * | 226 | * |
237 | * Checks the current fence value and wakes the fence queue | 227 | * Checks for fence activity. |
238 | * if the sequence number has increased (all asics). | ||
239 | */ | 228 | */ |
240 | void amdgpu_fence_process(struct amdgpu_ring *ring) | 229 | static void amdgpu_fence_fallback(unsigned long arg) |
241 | { | 230 | { |
242 | if (amdgpu_fence_activity(ring)) | 231 | struct amdgpu_ring *ring = (void *)arg; |
243 | wake_up_all(&ring->fence_drv.fence_queue); | 232 | |
233 | amdgpu_fence_process(ring); | ||
244 | } | 234 | } |
245 | 235 | ||
246 | /** | 236 | /** |
@@ -290,7 +280,7 @@ static int amdgpu_fence_ring_wait_seq(struct amdgpu_ring *ring, uint64_t seq) | |||
290 | if (atomic64_read(&ring->fence_drv.last_seq) >= seq) | 280 | if (atomic64_read(&ring->fence_drv.last_seq) >= seq) |
291 | return 0; | 281 | return 0; |
292 | 282 | ||
293 | amdgpu_fence_schedule_check(ring); | 283 | amdgpu_fence_schedule_fallback(ring); |
294 | wait_event(ring->fence_drv.fence_queue, ( | 284 | wait_event(ring->fence_drv.fence_queue, ( |
295 | (signaled = amdgpu_fence_seq_signaled(ring, seq)))); | 285 | (signaled = amdgpu_fence_seq_signaled(ring, seq)))); |
296 | 286 | ||
@@ -491,9 +481,8 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) | |||
491 | atomic64_set(&ring->fence_drv.last_seq, 0); | 481 | atomic64_set(&ring->fence_drv.last_seq, 0); |
492 | ring->fence_drv.initialized = false; | 482 | ring->fence_drv.initialized = false; |
493 | 483 | ||
494 | INIT_DELAYED_WORK(&ring->fence_drv.lockup_work, | 484 | setup_timer(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback, |
495 | amdgpu_fence_check_lockup); | 485 | (unsigned long)ring); |
496 | ring->fence_drv.ring = ring; | ||
497 | 486 | ||
498 | init_waitqueue_head(&ring->fence_drv.fence_queue); | 487 | init_waitqueue_head(&ring->fence_drv.fence_queue); |
499 | 488 | ||
@@ -536,6 +525,13 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) | |||
536 | */ | 525 | */ |
537 | int amdgpu_fence_driver_init(struct amdgpu_device *adev) | 526 | int amdgpu_fence_driver_init(struct amdgpu_device *adev) |
538 | { | 527 | { |
528 | if (atomic_inc_return(&amdgpu_fence_slab_ref) == 1) { | ||
529 | amdgpu_fence_slab = kmem_cache_create( | ||
530 | "amdgpu_fence", sizeof(struct amdgpu_fence), 0, | ||
531 | SLAB_HWCACHE_ALIGN, NULL); | ||
532 | if (!amdgpu_fence_slab) | ||
533 | return -ENOMEM; | ||
534 | } | ||
539 | if (amdgpu_debugfs_fence_init(adev)) | 535 | if (amdgpu_debugfs_fence_init(adev)) |
540 | dev_err(adev->dev, "fence debugfs file creation failed\n"); | 536 | dev_err(adev->dev, "fence debugfs file creation failed\n"); |
541 | 537 | ||
@@ -554,9 +550,12 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev) | |||
554 | { | 550 | { |
555 | int i, r; | 551 | int i, r; |
556 | 552 | ||
553 | if (atomic_dec_and_test(&amdgpu_fence_slab_ref)) | ||
554 | kmem_cache_destroy(amdgpu_fence_slab); | ||
557 | mutex_lock(&adev->ring_lock); | 555 | mutex_lock(&adev->ring_lock); |
558 | for (i = 0; i < AMDGPU_MAX_RINGS; i++) { | 556 | for (i = 0; i < AMDGPU_MAX_RINGS; i++) { |
559 | struct amdgpu_ring *ring = adev->rings[i]; | 557 | struct amdgpu_ring *ring = adev->rings[i]; |
558 | |||
560 | if (!ring || !ring->fence_drv.initialized) | 559 | if (!ring || !ring->fence_drv.initialized) |
561 | continue; | 560 | continue; |
562 | r = amdgpu_fence_wait_empty(ring); | 561 | r = amdgpu_fence_wait_empty(ring); |
@@ -568,6 +567,7 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev) | |||
568 | amdgpu_irq_put(adev, ring->fence_drv.irq_src, | 567 | amdgpu_irq_put(adev, ring->fence_drv.irq_src, |
569 | ring->fence_drv.irq_type); | 568 | ring->fence_drv.irq_type); |
570 | amd_sched_fini(&ring->sched); | 569 | amd_sched_fini(&ring->sched); |
570 | del_timer_sync(&ring->fence_drv.fallback_timer); | ||
571 | ring->fence_drv.initialized = false; | 571 | ring->fence_drv.initialized = false; |
572 | } | 572 | } |
573 | mutex_unlock(&adev->ring_lock); | 573 | mutex_unlock(&adev->ring_lock); |
@@ -751,18 +751,25 @@ static bool amdgpu_fence_enable_signaling(struct fence *f) | |||
751 | fence->fence_wake.func = amdgpu_fence_check_signaled; | 751 | fence->fence_wake.func = amdgpu_fence_check_signaled; |
752 | __add_wait_queue(&ring->fence_drv.fence_queue, &fence->fence_wake); | 752 | __add_wait_queue(&ring->fence_drv.fence_queue, &fence->fence_wake); |
753 | fence_get(f); | 753 | fence_get(f); |
754 | amdgpu_fence_schedule_check(ring); | 754 | if (!timer_pending(&ring->fence_drv.fallback_timer)) |
755 | amdgpu_fence_schedule_fallback(ring); | ||
755 | FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx); | 756 | FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx); |
756 | return true; | 757 | return true; |
757 | } | 758 | } |
758 | 759 | ||
760 | static void amdgpu_fence_release(struct fence *f) | ||
761 | { | ||
762 | struct amdgpu_fence *fence = to_amdgpu_fence(f); | ||
763 | kmem_cache_free(amdgpu_fence_slab, fence); | ||
764 | } | ||
765 | |||
759 | const struct fence_ops amdgpu_fence_ops = { | 766 | const struct fence_ops amdgpu_fence_ops = { |
760 | .get_driver_name = amdgpu_fence_get_driver_name, | 767 | .get_driver_name = amdgpu_fence_get_driver_name, |
761 | .get_timeline_name = amdgpu_fence_get_timeline_name, | 768 | .get_timeline_name = amdgpu_fence_get_timeline_name, |
762 | .enable_signaling = amdgpu_fence_enable_signaling, | 769 | .enable_signaling = amdgpu_fence_enable_signaling, |
763 | .signaled = amdgpu_fence_is_signaled, | 770 | .signaled = amdgpu_fence_is_signaled, |
764 | .wait = fence_default_wait, | 771 | .wait = fence_default_wait, |
765 | .release = NULL, | 772 | .release = amdgpu_fence_release, |
766 | }; | 773 | }; |
767 | 774 | ||
768 | /* | 775 | /* |