1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher * Copyright 2009 Jerome Glisse.
3d38ceaf9SAlex Deucher * All Rights Reserved.
4d38ceaf9SAlex Deucher *
5d38ceaf9SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a
6d38ceaf9SAlex Deucher * copy of this software and associated documentation files (the
7d38ceaf9SAlex Deucher * "Software"), to deal in the Software without restriction, including
8d38ceaf9SAlex Deucher * without limitation the rights to use, copy, modify, merge, publish,
9d38ceaf9SAlex Deucher * distribute, sub license, and/or sell copies of the Software, and to
10d38ceaf9SAlex Deucher * permit persons to whom the Software is furnished to do so, subject to
11d38ceaf9SAlex Deucher * the following conditions:
12d38ceaf9SAlex Deucher *
13d38ceaf9SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14d38ceaf9SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15d38ceaf9SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16d38ceaf9SAlex Deucher * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17d38ceaf9SAlex Deucher * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18d38ceaf9SAlex Deucher * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19d38ceaf9SAlex Deucher * USE OR OTHER DEALINGS IN THE SOFTWARE.
20d38ceaf9SAlex Deucher *
21d38ceaf9SAlex Deucher * The above copyright notice and this permission notice (including the
22d38ceaf9SAlex Deucher * next paragraph) shall be included in all copies or substantial portions
23d38ceaf9SAlex Deucher * of the Software.
24d38ceaf9SAlex Deucher *
25d38ceaf9SAlex Deucher */
26d38ceaf9SAlex Deucher /*
27d38ceaf9SAlex Deucher * Authors:
28d38ceaf9SAlex Deucher * Jerome Glisse <glisse@freedesktop.org>
29d38ceaf9SAlex Deucher * Dave Airlie
30d38ceaf9SAlex Deucher */
31d38ceaf9SAlex Deucher #include <linux/seq_file.h>
32d38ceaf9SAlex Deucher #include <linux/atomic.h>
33d38ceaf9SAlex Deucher #include <linux/wait.h>
34d38ceaf9SAlex Deucher #include <linux/kref.h>
35d38ceaf9SAlex Deucher #include <linux/slab.h>
36d38ceaf9SAlex Deucher #include <linux/firmware.h>
3745a80abeSAlex Deucher #include <linux/pm_runtime.h>
38fdf2f6c5SSam Ravnborg
3954a85db8SAndrey Grodzovsky #include <drm/drm_drv.h>
40d38ceaf9SAlex Deucher #include "amdgpu.h"
41d38ceaf9SAlex Deucher #include "amdgpu_trace.h"
422f83658fSAndrey Grodzovsky #include "amdgpu_reset.h"
43d38ceaf9SAlex Deucher
44d38ceaf9SAlex Deucher /*
45d38ceaf9SAlex Deucher * Fences mark an event in the GPUs pipeline and are used
46d38ceaf9SAlex Deucher * for GPU/CPU synchronization. When the fence is written,
47d38ceaf9SAlex Deucher * it is expected that all buffers associated with that fence
48d38ceaf9SAlex Deucher * are no longer in use by the associated ring on the GPU and
499dd4545fSSlark Xiao * that the relevant GPU caches have been flushed.
50d38ceaf9SAlex Deucher */
51d38ceaf9SAlex Deucher
5222e5a2f4SChristian König struct amdgpu_fence {
53f54d1867SChris Wilson struct dma_fence base;
5422e5a2f4SChristian König
5522e5a2f4SChristian König /* RB, DMA, etc. */
5622e5a2f4SChristian König struct amdgpu_ring *ring;
573f4c175dSJiadong.Zhu ktime_t start_timestamp;
5822e5a2f4SChristian König };
5922e5a2f4SChristian König
60b49c84a5SChunming Zhou static struct kmem_cache *amdgpu_fence_slab;
61b49c84a5SChunming Zhou
amdgpu_fence_slab_init(void)62d573de2dSRex Zhu int amdgpu_fence_slab_init(void)
63d573de2dSRex Zhu {
643d14cb02SKunwu Chan amdgpu_fence_slab = KMEM_CACHE(amdgpu_fence, SLAB_HWCACHE_ALIGN);
65d573de2dSRex Zhu if (!amdgpu_fence_slab)
66d573de2dSRex Zhu return -ENOMEM;
67d573de2dSRex Zhu return 0;
68d573de2dSRex Zhu }
69d573de2dSRex Zhu
amdgpu_fence_slab_fini(void)70d573de2dSRex Zhu void amdgpu_fence_slab_fini(void)
71d573de2dSRex Zhu {
720f10425eSGrazvydas Ignotas rcu_barrier();
73d573de2dSRex Zhu kmem_cache_destroy(amdgpu_fence_slab);
74d573de2dSRex Zhu }
7522e5a2f4SChristian König /*
7622e5a2f4SChristian König * Cast helper
7722e5a2f4SChristian König */
78f54d1867SChris Wilson static const struct dma_fence_ops amdgpu_fence_ops;
79bf67014dSHuang Rui static const struct dma_fence_ops amdgpu_job_fence_ops;
to_amdgpu_fence(struct dma_fence * f)80f54d1867SChris Wilson static inline struct amdgpu_fence *to_amdgpu_fence(struct dma_fence *f)
8122e5a2f4SChristian König {
8222e5a2f4SChristian König struct amdgpu_fence *__f = container_of(f, struct amdgpu_fence, base);
8322e5a2f4SChristian König
84bf67014dSHuang Rui if (__f->base.ops == &amdgpu_fence_ops ||
85bf67014dSHuang Rui __f->base.ops == &amdgpu_job_fence_ops)
8622e5a2f4SChristian König return __f;
8722e5a2f4SChristian König
8822e5a2f4SChristian König return NULL;
8922e5a2f4SChristian König }
9022e5a2f4SChristian König
91d38ceaf9SAlex Deucher /**
92d38ceaf9SAlex Deucher * amdgpu_fence_write - write a fence value
93d38ceaf9SAlex Deucher *
94d38ceaf9SAlex Deucher * @ring: ring the fence is associated with
95d38ceaf9SAlex Deucher * @seq: sequence number to write
96d38ceaf9SAlex Deucher *
97d38ceaf9SAlex Deucher * Writes a fence value to memory (all asics).
98d38ceaf9SAlex Deucher */
amdgpu_fence_write(struct amdgpu_ring * ring,u32 seq)99d38ceaf9SAlex Deucher static void amdgpu_fence_write(struct amdgpu_ring *ring, u32 seq)
100d38ceaf9SAlex Deucher {
101d38ceaf9SAlex Deucher struct amdgpu_fence_driver *drv = &ring->fence_drv;
102d38ceaf9SAlex Deucher
103d38ceaf9SAlex Deucher if (drv->cpu_addr)
104d38ceaf9SAlex Deucher *drv->cpu_addr = cpu_to_le32(seq);
105d38ceaf9SAlex Deucher }
106d38ceaf9SAlex Deucher
107d38ceaf9SAlex Deucher /**
108d38ceaf9SAlex Deucher * amdgpu_fence_read - read a fence value
109d38ceaf9SAlex Deucher *
110d38ceaf9SAlex Deucher * @ring: ring the fence is associated with
111d38ceaf9SAlex Deucher *
112d38ceaf9SAlex Deucher * Reads a fence value from memory (all asics).
113d38ceaf9SAlex Deucher * Returns the value of the fence read from memory.
114d38ceaf9SAlex Deucher */
amdgpu_fence_read(struct amdgpu_ring * ring)115d38ceaf9SAlex Deucher static u32 amdgpu_fence_read(struct amdgpu_ring *ring)
116d38ceaf9SAlex Deucher {
117d38ceaf9SAlex Deucher struct amdgpu_fence_driver *drv = &ring->fence_drv;
118d38ceaf9SAlex Deucher u32 seq = 0;
119d38ceaf9SAlex Deucher
120d38ceaf9SAlex Deucher if (drv->cpu_addr)
121d38ceaf9SAlex Deucher seq = le32_to_cpu(*drv->cpu_addr);
122d38ceaf9SAlex Deucher else
123742c085fSChristian König seq = atomic_read(&drv->last_seq);
124d38ceaf9SAlex Deucher
125d38ceaf9SAlex Deucher return seq;
126d38ceaf9SAlex Deucher }
127d38ceaf9SAlex Deucher
128d38ceaf9SAlex Deucher /**
129d38ceaf9SAlex Deucher * amdgpu_fence_emit - emit a fence on the requested ring
130d38ceaf9SAlex Deucher *
131d38ceaf9SAlex Deucher * @ring: ring the fence is associated with
132364beb2cSChristian König * @f: resulting fence object
133c530b02fSJack Zhang * @job: job the fence is embedded in
134f02f8c32SLee Jones * @flags: flags to pass into the subordinate .emit_fence() call
135d38ceaf9SAlex Deucher *
136d38ceaf9SAlex Deucher * Emits a fence command on the requested ring (all asics).
137d38ceaf9SAlex Deucher * Returns 0 on success, -ENOMEM on failure.
138d38ceaf9SAlex Deucher */
amdgpu_fence_emit(struct amdgpu_ring * ring,struct dma_fence ** f,struct amdgpu_job * job,unsigned int flags)139c530b02fSJack Zhang int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amdgpu_job *job,
1409e690184SSrinivasan Shanmugam unsigned int flags)
141d38ceaf9SAlex Deucher {
142d38ceaf9SAlex Deucher struct amdgpu_device *adev = ring->adev;
143c530b02fSJack Zhang struct dma_fence *fence;
144c530b02fSJack Zhang struct amdgpu_fence *am_fence;
1453d2aca8cSChristian König struct dma_fence __rcu **ptr;
146742c085fSChristian König uint32_t seq;
1473d2aca8cSChristian König int r;
148d38ceaf9SAlex Deucher
149c530b02fSJack Zhang if (job == NULL) {
150c530b02fSJack Zhang /* create a sperate hw fence */
151c530b02fSJack Zhang am_fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_ATOMIC);
152c530b02fSJack Zhang if (am_fence == NULL)
153d38ceaf9SAlex Deucher return -ENOMEM;
154c530b02fSJack Zhang fence = &am_fence->base;
155c530b02fSJack Zhang am_fence->ring = ring;
156c530b02fSJack Zhang } else {
157c530b02fSJack Zhang /* take use of job-embedded fence */
158c530b02fSJack Zhang fence = &job->hw_fence;
159c530b02fSJack Zhang }
160364beb2cSChristian König
161742c085fSChristian König seq = ++ring->fence_drv.sync_seq;
162bf67014dSHuang Rui if (job && job->job_run_counter) {
163c530b02fSJack Zhang /* reinit seq for resubmitted jobs */
164c530b02fSJack Zhang fence->seqno = seq;
1659ae55f03SAndrey Grodzovsky /* TO be inline with external fence creation and other drivers */
1669ae55f03SAndrey Grodzovsky dma_fence_get(fence);
167c530b02fSJack Zhang } else {
1689ae55f03SAndrey Grodzovsky if (job) {
169bf67014dSHuang Rui dma_fence_init(fence, &amdgpu_job_fence_ops,
170bf67014dSHuang Rui &ring->fence_drv.lock,
171bf67014dSHuang Rui adev->fence_context + ring->idx, seq);
1729ae55f03SAndrey Grodzovsky /* Against remove in amdgpu_job_{free, free_cb} */
1739ae55f03SAndrey Grodzovsky dma_fence_get(fence);
1749e690184SSrinivasan Shanmugam } else {
175c530b02fSJack Zhang dma_fence_init(fence, &amdgpu_fence_ops,
1764a7d74f1SChristian König &ring->fence_drv.lock,
177bf67014dSHuang Rui adev->fence_context + ring->idx, seq);
178c530b02fSJack Zhang }
1799e690184SSrinivasan Shanmugam }
180c530b02fSJack Zhang
181890ee23fSChunming Zhou amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
182d240cd9eSMarek Olšák seq, flags | AMDGPU_FENCE_FLAG_INT);
1834a580877SLuben Tuikov pm_runtime_get_noresume(adev_to_drm(adev)->dev);
184742c085fSChristian König ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
1853d2aca8cSChristian König if (unlikely(rcu_dereference_protected(*ptr, 1))) {
1863d2aca8cSChristian König struct dma_fence *old;
1873d2aca8cSChristian König
1883d2aca8cSChristian König rcu_read_lock();
1893d2aca8cSChristian König old = dma_fence_get_rcu_safe(ptr);
1903d2aca8cSChristian König rcu_read_unlock();
1913d2aca8cSChristian König
1923d2aca8cSChristian König if (old) {
1933d2aca8cSChristian König r = dma_fence_wait(old, false);
1943d2aca8cSChristian König dma_fence_put(old);
1953d2aca8cSChristian König if (r)
1963d2aca8cSChristian König return r;
1973d2aca8cSChristian König }
1983d2aca8cSChristian König }
1993d2aca8cSChristian König
2003f4c175dSJiadong.Zhu to_amdgpu_fence(fence)->start_timestamp = ktime_get();
2013f4c175dSJiadong.Zhu
202c89377d1SChristian König /* This function can't be called concurrently anyway, otherwise
203c89377d1SChristian König * emitting the fence would mess up the hardware ring buffer.
204c89377d1SChristian König */
205c530b02fSJack Zhang rcu_assign_pointer(*ptr, dma_fence_get(fence));
206c89377d1SChristian König
207c530b02fSJack Zhang *f = fence;
208c89377d1SChristian König
209d38ceaf9SAlex Deucher return 0;
210d38ceaf9SAlex Deucher }
211d38ceaf9SAlex Deucher
212d38ceaf9SAlex Deucher /**
21343ca8efaSpding * amdgpu_fence_emit_polling - emit a fence on the requeste ring
21443ca8efaSpding *
21543ca8efaSpding * @ring: ring the fence is associated with
21643ca8efaSpding * @s: resulting sequence number
217f02f8c32SLee Jones * @timeout: the timeout for waiting in usecs
21843ca8efaSpding *
21943ca8efaSpding * Emits a fence command on the requested ring (all asics).
22043ca8efaSpding * Used For polling fence.
22143ca8efaSpding * Returns 0 on success, -ENOMEM on failure.
22243ca8efaSpding */
amdgpu_fence_emit_polling(struct amdgpu_ring * ring,uint32_t * s,uint32_t timeout)22304e4e2e9SYintian Tao int amdgpu_fence_emit_polling(struct amdgpu_ring *ring, uint32_t *s,
22404e4e2e9SYintian Tao uint32_t timeout)
22543ca8efaSpding {
22643ca8efaSpding uint32_t seq;
22704e4e2e9SYintian Tao signed long r;
22843ca8efaSpding
22943ca8efaSpding if (!s)
23043ca8efaSpding return -EINVAL;
23143ca8efaSpding
23243ca8efaSpding seq = ++ring->fence_drv.sync_seq;
23304e4e2e9SYintian Tao r = amdgpu_fence_wait_polling(ring,
23404e4e2e9SYintian Tao seq - ring->fence_drv.num_fences_mask,
23504e4e2e9SYintian Tao timeout);
23604e4e2e9SYintian Tao if (r < 1)
23704e4e2e9SYintian Tao return -ETIMEDOUT;
23804e4e2e9SYintian Tao
23943ca8efaSpding amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
240d118a621SMonk Liu seq, 0);
24143ca8efaSpding
24243ca8efaSpding *s = seq;
24343ca8efaSpding
24443ca8efaSpding return 0;
24543ca8efaSpding }
24643ca8efaSpding
24743ca8efaSpding /**
2488c5e13ecSAndrey Grodzovsky * amdgpu_fence_schedule_fallback - schedule fallback check
2498c5e13ecSAndrey Grodzovsky *
2508c5e13ecSAndrey Grodzovsky * @ring: pointer to struct amdgpu_ring
2518c5e13ecSAndrey Grodzovsky *
2528c5e13ecSAndrey Grodzovsky * Start a timer as fallback to our interrupts.
2538c5e13ecSAndrey Grodzovsky */
amdgpu_fence_schedule_fallback(struct amdgpu_ring * ring)2548c5e13ecSAndrey Grodzovsky static void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring)
2558c5e13ecSAndrey Grodzovsky {
2568c5e13ecSAndrey Grodzovsky mod_timer(&ring->fence_drv.fallback_timer,
2578c5e13ecSAndrey Grodzovsky jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT);
2588c5e13ecSAndrey Grodzovsky }
2598c5e13ecSAndrey Grodzovsky
2608c5e13ecSAndrey Grodzovsky /**
261ca08e04dSChristian König * amdgpu_fence_process - check for fence activity
262d38ceaf9SAlex Deucher *
263d38ceaf9SAlex Deucher * @ring: pointer to struct amdgpu_ring
264d38ceaf9SAlex Deucher *
265d38ceaf9SAlex Deucher * Checks the current fence value and calculates the last
266ca08e04dSChristian König * signalled fence value. Wakes the fence queue if the
267ca08e04dSChristian König * sequence number has increased.
26895d7fc4aSAndrey Grodzovsky *
26995d7fc4aSAndrey Grodzovsky * Returns true if fence was processed
270d38ceaf9SAlex Deucher */
amdgpu_fence_process(struct amdgpu_ring * ring)27195d7fc4aSAndrey Grodzovsky bool amdgpu_fence_process(struct amdgpu_ring *ring)
272d38ceaf9SAlex Deucher {
2734a7d74f1SChristian König struct amdgpu_fence_driver *drv = &ring->fence_drv;
27445a80abeSAlex Deucher struct amdgpu_device *adev = ring->adev;
275742c085fSChristian König uint32_t seq, last_seq;
276d38ceaf9SAlex Deucher
277d38ceaf9SAlex Deucher do {
278742c085fSChristian König last_seq = atomic_read(&ring->fence_drv.last_seq);
279d38ceaf9SAlex Deucher seq = amdgpu_fence_read(ring);
280d38ceaf9SAlex Deucher
281742c085fSChristian König } while (atomic_cmpxchg(&drv->last_seq, last_seq, seq) != last_seq);
282d38ceaf9SAlex Deucher
2833547e3cfSAndrey Grodzovsky if (del_timer(&ring->fence_drv.fallback_timer) &&
2843547e3cfSAndrey Grodzovsky seq != ring->fence_drv.sync_seq)
2858c5e13ecSAndrey Grodzovsky amdgpu_fence_schedule_fallback(ring);
2868c5e13ecSAndrey Grodzovsky
2872ef004d9SChristian König if (unlikely(seq == last_seq))
28895d7fc4aSAndrey Grodzovsky return false;
2892ef004d9SChristian König
2904f399a08SChristian König last_seq &= drv->num_fences_mask;
2914f399a08SChristian König seq &= drv->num_fences_mask;
2924f399a08SChristian König
2932ef004d9SChristian König do {
294f54d1867SChris Wilson struct dma_fence *fence, **ptr;
2954a7d74f1SChristian König
2964f399a08SChristian König ++last_seq;
2974f399a08SChristian König last_seq &= drv->num_fences_mask;
2984f399a08SChristian König ptr = &drv->fences[last_seq];
2994a7d74f1SChristian König
3004a7d74f1SChristian König /* There is always exactly one thread signaling this fence slot */
3014a7d74f1SChristian König fence = rcu_dereference_protected(*ptr, 1);
30284fae133SMuhammad Falak R Wani RCU_INIT_POINTER(*ptr, NULL);
3034a7d74f1SChristian König
3044f399a08SChristian König if (!fence)
3054f399a08SChristian König continue;
3064a7d74f1SChristian König
307d72277b6SChristian König dma_fence_signal(fence);
308f54d1867SChris Wilson dma_fence_put(fence);
3094a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
3104a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
3112ef004d9SChristian König } while (last_seq != seq);
31295d7fc4aSAndrey Grodzovsky
31395d7fc4aSAndrey Grodzovsky return true;
314e0d8f3c3SChunming Zhou }
315d38ceaf9SAlex Deucher
316d38ceaf9SAlex Deucher /**
3178c5e13ecSAndrey Grodzovsky * amdgpu_fence_fallback - fallback for hardware interrupts
3188c5e13ecSAndrey Grodzovsky *
319f02f8c32SLee Jones * @t: timer context used to obtain the pointer to ring structure
3208c5e13ecSAndrey Grodzovsky *
3218c5e13ecSAndrey Grodzovsky * Checks for fence activity.
3228c5e13ecSAndrey Grodzovsky */
amdgpu_fence_fallback(struct timer_list * t)3238c5e13ecSAndrey Grodzovsky static void amdgpu_fence_fallback(struct timer_list *t)
3248c5e13ecSAndrey Grodzovsky {
3258c5e13ecSAndrey Grodzovsky struct amdgpu_ring *ring = from_timer(ring, t,
3268c5e13ecSAndrey Grodzovsky fence_drv.fallback_timer);
3278c5e13ecSAndrey Grodzovsky
32895d7fc4aSAndrey Grodzovsky if (amdgpu_fence_process(ring))
3293547e3cfSAndrey Grodzovsky DRM_WARN("Fence fallback timer expired on ring %s\n", ring->name);
3308c5e13ecSAndrey Grodzovsky }
3318c5e13ecSAndrey Grodzovsky
3328c5e13ecSAndrey Grodzovsky /**
333d38ceaf9SAlex Deucher * amdgpu_fence_wait_empty - wait for all fences to signal
334d38ceaf9SAlex Deucher *
335d38ceaf9SAlex Deucher * @ring: ring index the fence is associated with
336d38ceaf9SAlex Deucher *
337d38ceaf9SAlex Deucher * Wait for all fences on the requested ring to signal (all asics).
338d38ceaf9SAlex Deucher * Returns 0 if the fences have passed, error for all other cases.
339d38ceaf9SAlex Deucher */
amdgpu_fence_wait_empty(struct amdgpu_ring * ring)340d38ceaf9SAlex Deucher int amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
341d38ceaf9SAlex Deucher {
3426aa7de05SMark Rutland uint64_t seq = READ_ONCE(ring->fence_drv.sync_seq);
343f54d1867SChris Wilson struct dma_fence *fence, **ptr;
344f09c2be4SChristian König int r;
34500d2a2b2SChristian König
3467f06c236Smonk.liu if (!seq)
347d38ceaf9SAlex Deucher return 0;
348d38ceaf9SAlex Deucher
349f09c2be4SChristian König ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
350f09c2be4SChristian König rcu_read_lock();
351f09c2be4SChristian König fence = rcu_dereference(*ptr);
352f54d1867SChris Wilson if (!fence || !dma_fence_get_rcu(fence)) {
353f09c2be4SChristian König rcu_read_unlock();
354f09c2be4SChristian König return 0;
355f09c2be4SChristian König }
356f09c2be4SChristian König rcu_read_unlock();
357f09c2be4SChristian König
358f54d1867SChris Wilson r = dma_fence_wait(fence, false);
359f54d1867SChris Wilson dma_fence_put(fence);
360f09c2be4SChristian König return r;
361d38ceaf9SAlex Deucher }
362d38ceaf9SAlex Deucher
363d38ceaf9SAlex Deucher /**
36443ca8efaSpding * amdgpu_fence_wait_polling - busy wait for givn sequence number
36543ca8efaSpding *
36643ca8efaSpding * @ring: ring index the fence is associated with
36743ca8efaSpding * @wait_seq: sequence number to wait
36843ca8efaSpding * @timeout: the timeout for waiting in usecs
36943ca8efaSpding *
37043ca8efaSpding * Wait for all fences on the requested ring to signal (all asics).
37143ca8efaSpding * Returns left time if no timeout, 0 or minus if timeout.
37243ca8efaSpding */
amdgpu_fence_wait_polling(struct amdgpu_ring * ring,uint32_t wait_seq,signed long timeout)37343ca8efaSpding signed long amdgpu_fence_wait_polling(struct amdgpu_ring *ring,
37443ca8efaSpding uint32_t wait_seq,
37543ca8efaSpding signed long timeout)
37643ca8efaSpding {
37743ca8efaSpding
3786e87c422SAlex Sierra while ((int32_t)(wait_seq - amdgpu_fence_read(ring)) > 0 && timeout > 0) {
3796e87c422SAlex Sierra udelay(2);
3806e87c422SAlex Sierra timeout -= 2;
3816e87c422SAlex Sierra }
38243ca8efaSpding return timeout > 0 ? timeout : 0;
38343ca8efaSpding }
38443ca8efaSpding /**
385d38ceaf9SAlex Deucher * amdgpu_fence_count_emitted - get the count of emitted fences
386d38ceaf9SAlex Deucher *
387d38ceaf9SAlex Deucher * @ring: ring the fence is associated with
388d38ceaf9SAlex Deucher *
389d38ceaf9SAlex Deucher * Get the number of fences emitted on the requested ring (all asics).
390d38ceaf9SAlex Deucher * Returns the number of emitted fences on the ring. Used by the
391d38ceaf9SAlex Deucher * dynpm code to ring track activity.
392d38ceaf9SAlex Deucher */
amdgpu_fence_count_emitted(struct amdgpu_ring * ring)3939e690184SSrinivasan Shanmugam unsigned int amdgpu_fence_count_emitted(struct amdgpu_ring *ring)
394d38ceaf9SAlex Deucher {
395d38ceaf9SAlex Deucher uint64_t emitted;
396d38ceaf9SAlex Deucher
397d38ceaf9SAlex Deucher /* We are not protected by ring lock when reading the last sequence
398d38ceaf9SAlex Deucher * but it's ok to report slightly wrong fence count here.
399d38ceaf9SAlex Deucher */
400742c085fSChristian König emitted = 0x100000000ull;
401742c085fSChristian König emitted -= atomic_read(&ring->fence_drv.last_seq);
4026aa7de05SMark Rutland emitted += READ_ONCE(ring->fence_drv.sync_seq);
403742c085fSChristian König return lower_32_bits(emitted);
404d38ceaf9SAlex Deucher }
405d38ceaf9SAlex Deucher
406d38ceaf9SAlex Deucher /**
4073f4c175dSJiadong.Zhu * amdgpu_fence_last_unsignaled_time_us - the time fence emitted until now
4083f4c175dSJiadong.Zhu * @ring: ring the fence is associated with
4093f4c175dSJiadong.Zhu *
4103f4c175dSJiadong.Zhu * Find the earliest fence unsignaled until now, calculate the time delta
4113f4c175dSJiadong.Zhu * between the time fence emitted and now.
4123f4c175dSJiadong.Zhu */
amdgpu_fence_last_unsignaled_time_us(struct amdgpu_ring * ring)4133f4c175dSJiadong.Zhu u64 amdgpu_fence_last_unsignaled_time_us(struct amdgpu_ring *ring)
4143f4c175dSJiadong.Zhu {
4153f4c175dSJiadong.Zhu struct amdgpu_fence_driver *drv = &ring->fence_drv;
4163f4c175dSJiadong.Zhu struct dma_fence *fence;
4173f4c175dSJiadong.Zhu uint32_t last_seq, sync_seq;
4183f4c175dSJiadong.Zhu
4193f4c175dSJiadong.Zhu last_seq = atomic_read(&ring->fence_drv.last_seq);
4203f4c175dSJiadong.Zhu sync_seq = READ_ONCE(ring->fence_drv.sync_seq);
4213f4c175dSJiadong.Zhu if (last_seq == sync_seq)
4223f4c175dSJiadong.Zhu return 0;
4233f4c175dSJiadong.Zhu
4243f4c175dSJiadong.Zhu ++last_seq;
4253f4c175dSJiadong.Zhu last_seq &= drv->num_fences_mask;
4263f4c175dSJiadong.Zhu fence = drv->fences[last_seq];
4273f4c175dSJiadong.Zhu if (!fence)
4283f4c175dSJiadong.Zhu return 0;
4293f4c175dSJiadong.Zhu
4303f4c175dSJiadong.Zhu return ktime_us_delta(ktime_get(),
4313f4c175dSJiadong.Zhu to_amdgpu_fence(fence)->start_timestamp);
4323f4c175dSJiadong.Zhu }
4333f4c175dSJiadong.Zhu
4343f4c175dSJiadong.Zhu /**
4353f4c175dSJiadong.Zhu * amdgpu_fence_update_start_timestamp - update the timestamp of the fence
4363f4c175dSJiadong.Zhu * @ring: ring the fence is associated with
4373f4c175dSJiadong.Zhu * @seq: the fence seq number to update.
4383f4c175dSJiadong.Zhu * @timestamp: the start timestamp to update.
4393f4c175dSJiadong.Zhu *
4403f4c175dSJiadong.Zhu * The function called at the time the fence and related ib is about to
4413f4c175dSJiadong.Zhu * resubmit to gpu in MCBP scenario. Thus we do not consider race condition
4423f4c175dSJiadong.Zhu * with amdgpu_fence_process to modify the same fence.
4433f4c175dSJiadong.Zhu */
amdgpu_fence_update_start_timestamp(struct amdgpu_ring * ring,uint32_t seq,ktime_t timestamp)4443f4c175dSJiadong.Zhu void amdgpu_fence_update_start_timestamp(struct amdgpu_ring *ring, uint32_t seq, ktime_t timestamp)
4453f4c175dSJiadong.Zhu {
4463f4c175dSJiadong.Zhu struct amdgpu_fence_driver *drv = &ring->fence_drv;
4473f4c175dSJiadong.Zhu struct dma_fence *fence;
4483f4c175dSJiadong.Zhu
4493f4c175dSJiadong.Zhu seq &= drv->num_fences_mask;
4503f4c175dSJiadong.Zhu fence = drv->fences[seq];
4513f4c175dSJiadong.Zhu if (!fence)
4523f4c175dSJiadong.Zhu return;
4533f4c175dSJiadong.Zhu
4543f4c175dSJiadong.Zhu to_amdgpu_fence(fence)->start_timestamp = timestamp;
4553f4c175dSJiadong.Zhu }
4563f4c175dSJiadong.Zhu
4573f4c175dSJiadong.Zhu /**
458d38ceaf9SAlex Deucher * amdgpu_fence_driver_start_ring - make the fence driver
459d38ceaf9SAlex Deucher * ready for use on the requested ring.
460d38ceaf9SAlex Deucher *
461d38ceaf9SAlex Deucher * @ring: ring to start the fence driver on
462d38ceaf9SAlex Deucher * @irq_src: interrupt source to use for this ring
463d38ceaf9SAlex Deucher * @irq_type: interrupt type to use for this ring
464d38ceaf9SAlex Deucher *
465d38ceaf9SAlex Deucher * Make the fence driver ready for processing (all asics).
466d38ceaf9SAlex Deucher * Not all asics have all rings, so each asic will only
467d38ceaf9SAlex Deucher * start the fence driver on the rings it has.
468d38ceaf9SAlex Deucher * Returns 0 for success, errors for failure.
469d38ceaf9SAlex Deucher */
amdgpu_fence_driver_start_ring(struct amdgpu_ring * ring,struct amdgpu_irq_src * irq_src,unsigned int irq_type)470d38ceaf9SAlex Deucher int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
471d38ceaf9SAlex Deucher struct amdgpu_irq_src *irq_src,
4729e690184SSrinivasan Shanmugam unsigned int irq_type)
473d38ceaf9SAlex Deucher {
474d38ceaf9SAlex Deucher struct amdgpu_device *adev = ring->adev;
475d38ceaf9SAlex Deucher uint64_t index;
476d38ceaf9SAlex Deucher
477d9e98ee2SLeo Liu if (ring->funcs->type != AMDGPU_RING_TYPE_UVD) {
478ae9fd76fSJack Xiao ring->fence_drv.cpu_addr = ring->fence_cpu_addr;
479ae9fd76fSJack Xiao ring->fence_drv.gpu_addr = ring->fence_gpu_addr;
480d38ceaf9SAlex Deucher } else {
481d38ceaf9SAlex Deucher /* put fence directly behind firmware */
482d38ceaf9SAlex Deucher index = ALIGN(adev->uvd.fw->size, 8);
48310dd74eaSJames Zhu ring->fence_drv.cpu_addr = adev->uvd.inst[ring->me].cpu_addr + index;
48410dd74eaSJames Zhu ring->fence_drv.gpu_addr = adev->uvd.inst[ring->me].gpu_addr + index;
485d38ceaf9SAlex Deucher }
486742c085fSChristian König amdgpu_fence_write(ring, atomic_read(&ring->fence_drv.last_seq));
48755611b50SJack Xiao
488d38ceaf9SAlex Deucher ring->fence_drv.irq_src = irq_src;
489d38ceaf9SAlex Deucher ring->fence_drv.irq_type = irq_type;
490c6a4079bSChunming Zhou ring->fence_drv.initialized = true;
491c6a4079bSChunming Zhou
492e241df69STiezhu Yang DRM_DEV_DEBUG(adev->dev, "fence driver on ring %s use gpu addr 0x%016llx\n",
493e241df69STiezhu Yang ring->name, ring->fence_drv.gpu_addr);
494d38ceaf9SAlex Deucher return 0;
495d38ceaf9SAlex Deucher }
496d38ceaf9SAlex Deucher
497d38ceaf9SAlex Deucher /**
498d38ceaf9SAlex Deucher * amdgpu_fence_driver_init_ring - init the fence driver
499d38ceaf9SAlex Deucher * for the requested ring.
500d38ceaf9SAlex Deucher *
501d38ceaf9SAlex Deucher * @ring: ring to init the fence driver on
502d38ceaf9SAlex Deucher *
503d38ceaf9SAlex Deucher * Init the fence driver for the requested ring (all asics).
504d38ceaf9SAlex Deucher * Helper function for amdgpu_fence_driver_init().
505d38ceaf9SAlex Deucher */
amdgpu_fence_driver_init_ring(struct amdgpu_ring * ring)5065fd8518dSAndrey Grodzovsky int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
507d38ceaf9SAlex Deucher {
508912dfc84SEvan Quan struct amdgpu_device *adev = ring->adev;
509d38ceaf9SAlex Deucher
510912dfc84SEvan Quan if (!adev)
511912dfc84SEvan Quan return -EINVAL;
512912dfc84SEvan Quan
5135fd8518dSAndrey Grodzovsky if (!is_power_of_2(ring->num_hw_submission))
514e6151a08SChristian König return -EINVAL;
515e6151a08SChristian König
516d38ceaf9SAlex Deucher ring->fence_drv.cpu_addr = NULL;
517d38ceaf9SAlex Deucher ring->fence_drv.gpu_addr = 0;
5185907a0d8SChristian König ring->fence_drv.sync_seq = 0;
519742c085fSChristian König atomic_set(&ring->fence_drv.last_seq, 0);
520d38ceaf9SAlex Deucher ring->fence_drv.initialized = false;
521d38ceaf9SAlex Deucher
5228c5e13ecSAndrey Grodzovsky timer_setup(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback, 0);
5238c5e13ecSAndrey Grodzovsky
5245fd8518dSAndrey Grodzovsky ring->fence_drv.num_fences_mask = ring->num_hw_submission * 2 - 1;
5254a7d74f1SChristian König spin_lock_init(&ring->fence_drv.lock);
5265fd8518dSAndrey Grodzovsky ring->fence_drv.fences = kcalloc(ring->num_hw_submission * 2, sizeof(void *),
527c89377d1SChristian König GFP_KERNEL);
5285fd8518dSAndrey Grodzovsky
529c89377d1SChristian König if (!ring->fence_drv.fences)
530c89377d1SChristian König return -ENOMEM;
5315ec92a76SChristian König
5324f839a24SChristian König return 0;
5334f839a24SChristian König }
5344f839a24SChristian König
535d38ceaf9SAlex Deucher /**
536067f44c8SGuchun Chen * amdgpu_fence_driver_sw_init - init the fence driver
537d38ceaf9SAlex Deucher * for all possible rings.
538d38ceaf9SAlex Deucher *
539d38ceaf9SAlex Deucher * @adev: amdgpu device pointer
540d38ceaf9SAlex Deucher *
541d38ceaf9SAlex Deucher * Init the fence driver for all possible rings (all asics).
542d38ceaf9SAlex Deucher * Not all asics have all rings, so each asic will only
543d38ceaf9SAlex Deucher * start the fence driver on the rings it has using
544d38ceaf9SAlex Deucher * amdgpu_fence_driver_start_ring().
545d38ceaf9SAlex Deucher * Returns 0 for success.
546d38ceaf9SAlex Deucher */
amdgpu_fence_driver_sw_init(struct amdgpu_device * adev)547067f44c8SGuchun Chen int amdgpu_fence_driver_sw_init(struct amdgpu_device *adev)
548d38ceaf9SAlex Deucher {
549d38ceaf9SAlex Deucher return 0;
550d38ceaf9SAlex Deucher }
551d38ceaf9SAlex Deucher
552d38ceaf9SAlex Deucher /**
553603b9a57STim Huang * amdgpu_fence_need_ring_interrupt_restore - helper function to check whether
554603b9a57STim Huang * fence driver interrupts need to be restored.
555603b9a57STim Huang *
556603b9a57STim Huang * @ring: ring that to be checked
557603b9a57STim Huang *
558603b9a57STim Huang * Interrupts for rings that belong to GFX IP don't need to be restored
559603b9a57STim Huang * when the target power state is s0ix.
560603b9a57STim Huang *
561603b9a57STim Huang * Return true if need to restore interrupts, false otherwise.
562603b9a57STim Huang */
amdgpu_fence_need_ring_interrupt_restore(struct amdgpu_ring * ring)563603b9a57STim Huang static bool amdgpu_fence_need_ring_interrupt_restore(struct amdgpu_ring *ring)
564603b9a57STim Huang {
565603b9a57STim Huang struct amdgpu_device *adev = ring->adev;
566603b9a57STim Huang bool is_gfx_power_domain = false;
567603b9a57STim Huang
568603b9a57STim Huang switch (ring->funcs->type) {
569603b9a57STim Huang case AMDGPU_RING_TYPE_SDMA:
570603b9a57STim Huang /* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */
5714e8303cfSLijo Lazar if (amdgpu_ip_version(adev, SDMA0_HWIP, 0) >=
5724e8303cfSLijo Lazar IP_VERSION(5, 0, 0))
573603b9a57STim Huang is_gfx_power_domain = true;
574603b9a57STim Huang break;
575603b9a57STim Huang case AMDGPU_RING_TYPE_GFX:
576603b9a57STim Huang case AMDGPU_RING_TYPE_COMPUTE:
577603b9a57STim Huang case AMDGPU_RING_TYPE_KIQ:
578603b9a57STim Huang case AMDGPU_RING_TYPE_MES:
579603b9a57STim Huang is_gfx_power_domain = true;
580603b9a57STim Huang break;
581603b9a57STim Huang default:
582603b9a57STim Huang break;
583603b9a57STim Huang }
584603b9a57STim Huang
585603b9a57STim Huang return !(adev->in_s0ix && is_gfx_power_domain);
586603b9a57STim Huang }
587603b9a57STim Huang
588603b9a57STim Huang /**
589067f44c8SGuchun Chen * amdgpu_fence_driver_hw_fini - tear down the fence driver
590d38ceaf9SAlex Deucher * for all possible rings.
591d38ceaf9SAlex Deucher *
592d38ceaf9SAlex Deucher * @adev: amdgpu device pointer
593d38ceaf9SAlex Deucher *
594d38ceaf9SAlex Deucher * Tear down the fence driver for all possible rings (all asics).
595d38ceaf9SAlex Deucher */
amdgpu_fence_driver_hw_fini(struct amdgpu_device * adev)5968d35a259SLikun Gao void amdgpu_fence_driver_hw_fini(struct amdgpu_device *adev)
597d38ceaf9SAlex Deucher {
59854a85db8SAndrey Grodzovsky int i, r;
599d38ceaf9SAlex Deucher
600d38ceaf9SAlex Deucher for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
601d38ceaf9SAlex Deucher struct amdgpu_ring *ring = adev->rings[i];
602c2776afeSChristian König
603d38ceaf9SAlex Deucher if (!ring || !ring->fence_drv.initialized)
604d38ceaf9SAlex Deucher continue;
605067f44c8SGuchun Chen
60654a85db8SAndrey Grodzovsky /* You can't wait for HW to signal if it's gone */
607c58a863bSGuchun Chen if (!drm_dev_is_unplugged(adev_to_drm(adev)))
608d38ceaf9SAlex Deucher r = amdgpu_fence_wait_empty(ring);
60954a85db8SAndrey Grodzovsky else
61054a85db8SAndrey Grodzovsky r = -ENODEV;
611d38ceaf9SAlex Deucher /* no need to trigger GPU reset as we are unloading */
61254a85db8SAndrey Grodzovsky if (r)
6132f9d4084SMonk Liu amdgpu_fence_driver_force_completion(ring);
61454a85db8SAndrey Grodzovsky
6153083b100SGuchun Chen if (!drm_dev_is_unplugged(adev_to_drm(adev)) &&
616603b9a57STim Huang ring->fence_drv.irq_src &&
617603b9a57STim Huang amdgpu_fence_need_ring_interrupt_restore(ring))
618c6a4079bSChunming Zhou amdgpu_irq_put(adev, ring->fence_drv.irq_src,
619c6a4079bSChunming Zhou ring->fence_drv.irq_type);
620bb0cd09bSEmily Deng
6218c5e13ecSAndrey Grodzovsky del_timer_sync(&ring->fence_drv.fallback_timer);
62272c8c97bSAndrey Grodzovsky }
62372c8c97bSAndrey Grodzovsky }
62472c8c97bSAndrey Grodzovsky
6259e225fb9SAndrey Grodzovsky /* Will either stop and flush handlers for amdgpu interrupt or reanble it */
amdgpu_fence_driver_isr_toggle(struct amdgpu_device * adev,bool stop)6269e225fb9SAndrey Grodzovsky void amdgpu_fence_driver_isr_toggle(struct amdgpu_device *adev, bool stop)
6279e225fb9SAndrey Grodzovsky {
6289e225fb9SAndrey Grodzovsky int i;
6299e225fb9SAndrey Grodzovsky
6309e225fb9SAndrey Grodzovsky for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
6319e225fb9SAndrey Grodzovsky struct amdgpu_ring *ring = adev->rings[i];
6329e225fb9SAndrey Grodzovsky
6339e225fb9SAndrey Grodzovsky if (!ring || !ring->fence_drv.initialized || !ring->fence_drv.irq_src)
6349e225fb9SAndrey Grodzovsky continue;
6359e225fb9SAndrey Grodzovsky
6369e225fb9SAndrey Grodzovsky if (stop)
6379e225fb9SAndrey Grodzovsky disable_irq(adev->irq.irq);
6389e225fb9SAndrey Grodzovsky else
6399e225fb9SAndrey Grodzovsky enable_irq(adev->irq.irq);
6409e225fb9SAndrey Grodzovsky }
6419e225fb9SAndrey Grodzovsky }
6429e225fb9SAndrey Grodzovsky
amdgpu_fence_driver_sw_fini(struct amdgpu_device * adev)6438d35a259SLikun Gao void amdgpu_fence_driver_sw_fini(struct amdgpu_device *adev)
64472c8c97bSAndrey Grodzovsky {
64572c8c97bSAndrey Grodzovsky unsigned int i, j;
64672c8c97bSAndrey Grodzovsky
64772c8c97bSAndrey Grodzovsky for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
64872c8c97bSAndrey Grodzovsky struct amdgpu_ring *ring = adev->rings[i];
64972c8c97bSAndrey Grodzovsky
65072c8c97bSAndrey Grodzovsky if (!ring || !ring->fence_drv.initialized)
65172c8c97bSAndrey Grodzovsky continue;
65272c8c97bSAndrey Grodzovsky
6535ad7bbf3SGuilherme G. Piccoli /*
6545ad7bbf3SGuilherme G. Piccoli * Notice we check for sched.ops since there's some
6555ad7bbf3SGuilherme G. Piccoli * override on the meaning of sched.ready by amdgpu.
6565ad7bbf3SGuilherme G. Piccoli * The natural check would be sched.ready, which is
6575ad7bbf3SGuilherme G. Piccoli * set as drm_sched_init() finishes...
6585ad7bbf3SGuilherme G. Piccoli */
6595ad7bbf3SGuilherme G. Piccoli if (ring->sched.ops)
660067f44c8SGuchun Chen drm_sched_fini(&ring->sched);
661067f44c8SGuchun Chen
662c89377d1SChristian König for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
663f54d1867SChris Wilson dma_fence_put(ring->fence_drv.fences[j]);
664c89377d1SChristian König kfree(ring->fence_drv.fences);
66554ddf3a6SGrazvydas Ignotas ring->fence_drv.fences = NULL;
666d38ceaf9SAlex Deucher ring->fence_drv.initialized = false;
667d38ceaf9SAlex Deucher }
668d38ceaf9SAlex Deucher }
669d38ceaf9SAlex Deucher
670d38ceaf9SAlex Deucher /**
6718d35a259SLikun Gao * amdgpu_fence_driver_hw_init - enable the fence driver
6725ceb54c6SAlex Deucher * for all possible rings.
6735ceb54c6SAlex Deucher *
6745ceb54c6SAlex Deucher * @adev: amdgpu device pointer
6755ceb54c6SAlex Deucher *
6768d35a259SLikun Gao * Enable the fence driver for all possible rings (all asics).
6775ceb54c6SAlex Deucher * Not all asics have all rings, so each asic will only
6785ceb54c6SAlex Deucher * start the fence driver on the rings it has using
6795ceb54c6SAlex Deucher * amdgpu_fence_driver_start_ring().
6805ceb54c6SAlex Deucher * Returns 0 for success.
6815ceb54c6SAlex Deucher */
amdgpu_fence_driver_hw_init(struct amdgpu_device * adev)6828d35a259SLikun Gao void amdgpu_fence_driver_hw_init(struct amdgpu_device *adev)
6835ceb54c6SAlex Deucher {
6845ceb54c6SAlex Deucher int i;
6855ceb54c6SAlex Deucher
6865ceb54c6SAlex Deucher for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
6875ceb54c6SAlex Deucher struct amdgpu_ring *ring = adev->rings[i];
6889e690184SSrinivasan Shanmugam
6895ceb54c6SAlex Deucher if (!ring || !ring->fence_drv.initialized)
6905ceb54c6SAlex Deucher continue;
6915ceb54c6SAlex Deucher
6925ceb54c6SAlex Deucher /* enable the interrupt */
693603b9a57STim Huang if (ring->fence_drv.irq_src &&
694603b9a57STim Huang amdgpu_fence_need_ring_interrupt_restore(ring))
6955ceb54c6SAlex Deucher amdgpu_irq_get(adev, ring->fence_drv.irq_src,
6965ceb54c6SAlex Deucher ring->fence_drv.irq_type);
6975ceb54c6SAlex Deucher }
6985ceb54c6SAlex Deucher }
6995ceb54c6SAlex Deucher
7005ceb54c6SAlex Deucher /**
701bf67014dSHuang Rui * amdgpu_fence_driver_clear_job_fences - clear job embedded fences of ring
702bf67014dSHuang Rui *
703bf67014dSHuang Rui * @ring: fence of the ring to be cleared
704bf67014dSHuang Rui *
705bf67014dSHuang Rui */
amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring * ring)706bf67014dSHuang Rui void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring)
707bf67014dSHuang Rui {
708bf67014dSHuang Rui int i;
709bf67014dSHuang Rui struct dma_fence *old, **ptr;
710bf67014dSHuang Rui
711bf67014dSHuang Rui for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) {
712bf67014dSHuang Rui ptr = &ring->fence_drv.fences[i];
713bf67014dSHuang Rui old = rcu_dereference_protected(*ptr, 1);
714dd70748eSAndrey Grodzovsky if (old && old->ops == &amdgpu_job_fence_ops) {
715033c5647SYuBiao Wang struct amdgpu_job *job;
716033c5647SYuBiao Wang
717033c5647SYuBiao Wang /* For non-scheduler bad job, i.e. failed ib test, we need to signal
718033c5647SYuBiao Wang * it right here or we won't be able to track them in fence_drv
719033c5647SYuBiao Wang * and they will remain unsignaled during sa_bo free.
720033c5647SYuBiao Wang */
721033c5647SYuBiao Wang job = container_of(old, struct amdgpu_job, hw_fence);
722033c5647SYuBiao Wang if (!job->base.s_fence && !dma_fence_is_signaled(old))
723033c5647SYuBiao Wang dma_fence_signal(old);
724bf67014dSHuang Rui RCU_INIT_POINTER(*ptr, NULL);
725dd70748eSAndrey Grodzovsky dma_fence_put(old);
726dd70748eSAndrey Grodzovsky }
727bf67014dSHuang Rui }
728bf67014dSHuang Rui }
729bf67014dSHuang Rui
730bf67014dSHuang Rui /**
731b13eb02bSChristian König * amdgpu_fence_driver_set_error - set error code on fences
732b13eb02bSChristian König * @ring: the ring which contains the fences
733b13eb02bSChristian König * @error: the error code to set
734b13eb02bSChristian König *
735b13eb02bSChristian König * Set an error code to all the fences pending on the ring.
736b13eb02bSChristian König */
amdgpu_fence_driver_set_error(struct amdgpu_ring * ring,int error)737b13eb02bSChristian König void amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error)
738b13eb02bSChristian König {
739b13eb02bSChristian König struct amdgpu_fence_driver *drv = &ring->fence_drv;
740b13eb02bSChristian König unsigned long flags;
741b13eb02bSChristian König
742b13eb02bSChristian König spin_lock_irqsave(&drv->lock, flags);
743b13eb02bSChristian König for (unsigned int i = 0; i <= drv->num_fences_mask; ++i) {
744b13eb02bSChristian König struct dma_fence *fence;
745b13eb02bSChristian König
746b13eb02bSChristian König fence = rcu_dereference_protected(drv->fences[i],
747b13eb02bSChristian König lockdep_is_held(&drv->lock));
748b13eb02bSChristian König if (fence && !dma_fence_is_signaled_locked(fence))
749b13eb02bSChristian König dma_fence_set_error(fence, error);
750b13eb02bSChristian König }
751b13eb02bSChristian König spin_unlock_irqrestore(&drv->lock, flags);
752b13eb02bSChristian König }
753b13eb02bSChristian König
754b13eb02bSChristian König /**
7552f9d4084SMonk Liu * amdgpu_fence_driver_force_completion - force signal latest fence of ring
756d38ceaf9SAlex Deucher *
7572f9d4084SMonk Liu * @ring: fence of the ring to signal
758d38ceaf9SAlex Deucher *
759d38ceaf9SAlex Deucher */
amdgpu_fence_driver_force_completion(struct amdgpu_ring * ring)7602f9d4084SMonk Liu void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
761d38ceaf9SAlex Deucher {
7620a33b11dSChristian König amdgpu_fence_driver_set_error(ring, -ECANCELED);
7635907a0d8SChristian König amdgpu_fence_write(ring, ring->fence_drv.sync_seq);
7642f9d4084SMonk Liu amdgpu_fence_process(ring);
76565781c78SMonk Liu }
76665781c78SMonk Liu
767a95e2642SChristian König /*
768a95e2642SChristian König * Common fence implementation
769a95e2642SChristian König */
770a95e2642SChristian König
amdgpu_fence_get_driver_name(struct dma_fence * fence)771f54d1867SChris Wilson static const char *amdgpu_fence_get_driver_name(struct dma_fence *fence)
772a95e2642SChristian König {
773a95e2642SChristian König return "amdgpu";
774a95e2642SChristian König }
775a95e2642SChristian König
amdgpu_fence_get_timeline_name(struct dma_fence * f)776f54d1867SChris Wilson static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f)
777a95e2642SChristian König {
778bf67014dSHuang Rui return (const char *)to_amdgpu_fence(f)->ring->name;
779bf67014dSHuang Rui }
780c530b02fSJack Zhang
amdgpu_job_fence_get_timeline_name(struct dma_fence * f)781bf67014dSHuang Rui static const char *amdgpu_job_fence_get_timeline_name(struct dma_fence *f)
782bf67014dSHuang Rui {
783c530b02fSJack Zhang struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
784c530b02fSJack Zhang
785bf67014dSHuang Rui return (const char *)to_amdgpu_ring(job->base.sched)->name;
786a95e2642SChristian König }
787a95e2642SChristian König
788a95e2642SChristian König /**
7898c5e13ecSAndrey Grodzovsky * amdgpu_fence_enable_signaling - enable signalling on fence
790f02f8c32SLee Jones * @f: fence
7918c5e13ecSAndrey Grodzovsky *
7928c5e13ecSAndrey Grodzovsky * This function is called with fence_queue lock held, and adds a callback
7938c5e13ecSAndrey Grodzovsky * to fence_queue that checks if this fence is signaled, and if so it
7948c5e13ecSAndrey Grodzovsky * signals the fence and removes itself.
7958c5e13ecSAndrey Grodzovsky */
amdgpu_fence_enable_signaling(struct dma_fence * f)7968c5e13ecSAndrey Grodzovsky static bool amdgpu_fence_enable_signaling(struct dma_fence *f)
7978c5e13ecSAndrey Grodzovsky {
798bf67014dSHuang Rui if (!timer_pending(&to_amdgpu_fence(f)->ring->fence_drv.fallback_timer))
799bf67014dSHuang Rui amdgpu_fence_schedule_fallback(to_amdgpu_fence(f)->ring);
800c530b02fSJack Zhang
801bf67014dSHuang Rui return true;
802c530b02fSJack Zhang }
8038c5e13ecSAndrey Grodzovsky
804bf67014dSHuang Rui /**
805bf67014dSHuang Rui * amdgpu_job_fence_enable_signaling - enable signalling on job fence
806bf67014dSHuang Rui * @f: fence
807bf67014dSHuang Rui *
808bf67014dSHuang Rui * This is the simliar function with amdgpu_fence_enable_signaling above, it
809bf67014dSHuang Rui * only handles the job embedded fence.
810bf67014dSHuang Rui */
amdgpu_job_fence_enable_signaling(struct dma_fence * f)811bf67014dSHuang Rui static bool amdgpu_job_fence_enable_signaling(struct dma_fence *f)
812bf67014dSHuang Rui {
813bf67014dSHuang Rui struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
814bf67014dSHuang Rui
815bf67014dSHuang Rui if (!timer_pending(&to_amdgpu_ring(job->base.sched)->fence_drv.fallback_timer))
816bf67014dSHuang Rui amdgpu_fence_schedule_fallback(to_amdgpu_ring(job->base.sched));
8178c5e13ecSAndrey Grodzovsky
8188c5e13ecSAndrey Grodzovsky return true;
8198c5e13ecSAndrey Grodzovsky }
8208c5e13ecSAndrey Grodzovsky
8218c5e13ecSAndrey Grodzovsky /**
822b4413535SChristian König * amdgpu_fence_free - free up the fence memory
823b4413535SChristian König *
824b4413535SChristian König * @rcu: RCU callback head
825b4413535SChristian König *
826b4413535SChristian König * Free up the fence memory after the RCU grace period.
827b4413535SChristian König */
amdgpu_fence_free(struct rcu_head * rcu)828b4413535SChristian König static void amdgpu_fence_free(struct rcu_head *rcu)
829b49c84a5SChunming Zhou {
830f54d1867SChris Wilson struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
831c530b02fSJack Zhang
832c530b02fSJack Zhang /* free fence_slab if it's separated fence*/
833bf67014dSHuang Rui kmem_cache_free(amdgpu_fence_slab, to_amdgpu_fence(f));
834b49c84a5SChunming Zhou }
835bf67014dSHuang Rui
836bf67014dSHuang Rui /**
837bf67014dSHuang Rui * amdgpu_job_fence_free - free up the job with embedded fence
838bf67014dSHuang Rui *
839bf67014dSHuang Rui * @rcu: RCU callback head
840bf67014dSHuang Rui *
841bf67014dSHuang Rui * Free up the job with embedded fence after the RCU grace period.
842bf67014dSHuang Rui */
amdgpu_job_fence_free(struct rcu_head * rcu)843bf67014dSHuang Rui static void amdgpu_job_fence_free(struct rcu_head *rcu)
844bf67014dSHuang Rui {
845bf67014dSHuang Rui struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
846bf67014dSHuang Rui
847bf67014dSHuang Rui /* free job if fence has a parent job */
848bf67014dSHuang Rui kfree(container_of(f, struct amdgpu_job, hw_fence));
849c530b02fSJack Zhang }
850b49c84a5SChunming Zhou
851b4413535SChristian König /**
852b4413535SChristian König * amdgpu_fence_release - callback that fence can be freed
853b4413535SChristian König *
854f02f8c32SLee Jones * @f: fence
855b4413535SChristian König *
856b4413535SChristian König * This function is called when the reference count becomes zero.
857b4413535SChristian König * It just RCU schedules freeing up the fence.
858b4413535SChristian König */
amdgpu_fence_release(struct dma_fence * f)859f54d1867SChris Wilson static void amdgpu_fence_release(struct dma_fence *f)
860b4413535SChristian König {
861b4413535SChristian König call_rcu(&f->rcu, amdgpu_fence_free);
862b4413535SChristian König }
863b4413535SChristian König
864bf67014dSHuang Rui /**
865bf67014dSHuang Rui * amdgpu_job_fence_release - callback that job embedded fence can be freed
866bf67014dSHuang Rui *
867bf67014dSHuang Rui * @f: fence
868bf67014dSHuang Rui *
869bf67014dSHuang Rui * This is the simliar function with amdgpu_fence_release above, it
870bf67014dSHuang Rui * only handles the job embedded fence.
871bf67014dSHuang Rui */
amdgpu_job_fence_release(struct dma_fence * f)872bf67014dSHuang Rui static void amdgpu_job_fence_release(struct dma_fence *f)
873bf67014dSHuang Rui {
874bf67014dSHuang Rui call_rcu(&f->rcu, amdgpu_job_fence_free);
875bf67014dSHuang Rui }
876bf67014dSHuang Rui
877f54d1867SChris Wilson static const struct dma_fence_ops amdgpu_fence_ops = {
878a95e2642SChristian König .get_driver_name = amdgpu_fence_get_driver_name,
879a95e2642SChristian König .get_timeline_name = amdgpu_fence_get_timeline_name,
8808c5e13ecSAndrey Grodzovsky .enable_signaling = amdgpu_fence_enable_signaling,
881b49c84a5SChunming Zhou .release = amdgpu_fence_release,
882a95e2642SChristian König };
883d38ceaf9SAlex Deucher
884bf67014dSHuang Rui static const struct dma_fence_ops amdgpu_job_fence_ops = {
885bf67014dSHuang Rui .get_driver_name = amdgpu_fence_get_driver_name,
886bf67014dSHuang Rui .get_timeline_name = amdgpu_job_fence_get_timeline_name,
887bf67014dSHuang Rui .enable_signaling = amdgpu_job_fence_enable_signaling,
888bf67014dSHuang Rui .release = amdgpu_job_fence_release,
889bf67014dSHuang Rui };
890c530b02fSJack Zhang
891d38ceaf9SAlex Deucher /*
892d38ceaf9SAlex Deucher * Fence debugfs
893d38ceaf9SAlex Deucher */
894d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
amdgpu_debugfs_fence_info_show(struct seq_file * m,void * unused)89598d28ac2SNirmoy Das static int amdgpu_debugfs_fence_info_show(struct seq_file *m, void *unused)
896d38ceaf9SAlex Deucher {
897109b4d8cSSu Hui struct amdgpu_device *adev = m->private;
8985907a0d8SChristian König int i;
899d38ceaf9SAlex Deucher
900d38ceaf9SAlex Deucher for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
901d38ceaf9SAlex Deucher struct amdgpu_ring *ring = adev->rings[i];
9029e690184SSrinivasan Shanmugam
903d38ceaf9SAlex Deucher if (!ring || !ring->fence_drv.initialized)
904d38ceaf9SAlex Deucher continue;
905d38ceaf9SAlex Deucher
906d38ceaf9SAlex Deucher amdgpu_fence_process(ring);
907d38ceaf9SAlex Deucher
908344c19f9SChristian König seq_printf(m, "--- ring %d (%s) ---\n", i, ring->name);
909742c085fSChristian König seq_printf(m, "Last signaled fence 0x%08x\n",
910742c085fSChristian König atomic_read(&ring->fence_drv.last_seq));
911742c085fSChristian König seq_printf(m, "Last emitted 0x%08x\n",
9125907a0d8SChristian König ring->fence_drv.sync_seq);
913e71de076Spding
914ef3e1323SJack Xiao if (ring->funcs->type == AMDGPU_RING_TYPE_GFX ||
915ef3e1323SJack Xiao ring->funcs->type == AMDGPU_RING_TYPE_SDMA) {
916ef3e1323SJack Xiao seq_printf(m, "Last signaled trailing fence 0x%08x\n",
917ef3e1323SJack Xiao le32_to_cpu(*ring->trail_fence_cpu_addr));
918ef3e1323SJack Xiao seq_printf(m, "Last emitted 0x%08x\n",
919ef3e1323SJack Xiao ring->trail_seq);
920ef3e1323SJack Xiao }
921ef3e1323SJack Xiao
922e71de076Spding if (ring->funcs->type != AMDGPU_RING_TYPE_GFX)
923e71de076Spding continue;
924e71de076Spding
925e71de076Spding /* set in CP_VMID_PREEMPT and preemption occurred */
926e71de076Spding seq_printf(m, "Last preempted 0x%08x\n",
927e71de076Spding le32_to_cpu(*(ring->fence_drv.cpu_addr + 2)));
928e71de076Spding /* set in CP_VMID_RESET and reset occurred */
929e71de076Spding seq_printf(m, "Last reset 0x%08x\n",
930e71de076Spding le32_to_cpu(*(ring->fence_drv.cpu_addr + 4)));
931e71de076Spding /* Both preemption and reset occurred */
932e71de076Spding seq_printf(m, "Last both 0x%08x\n",
933e71de076Spding le32_to_cpu(*(ring->fence_drv.cpu_addr + 6)));
934d38ceaf9SAlex Deucher }
935d38ceaf9SAlex Deucher return 0;
936d38ceaf9SAlex Deucher }
937d38ceaf9SAlex Deucher
938f02f8c32SLee Jones /*
9395740682eSMonk Liu * amdgpu_debugfs_gpu_recover - manually trigger a gpu reset & recover
94018db89b4SAlex Deucher *
94118db89b4SAlex Deucher * Manually trigger a gpu reset at the next fence wait.
94218db89b4SAlex Deucher */
gpu_recover_get(void * data,u64 * val)94398d28ac2SNirmoy Das static int gpu_recover_get(void *data, u64 *val)
94418db89b4SAlex Deucher {
94598d28ac2SNirmoy Das struct amdgpu_device *adev = (struct amdgpu_device *)data;
94698d28ac2SNirmoy Das struct drm_device *dev = adev_to_drm(adev);
947a9ffe2a9SAlex Deucher int r;
948a9ffe2a9SAlex Deucher
949a9ffe2a9SAlex Deucher r = pm_runtime_get_sync(dev->dev);
950e520d3e0SAlex Deucher if (r < 0) {
951e520d3e0SAlex Deucher pm_runtime_put_autosuspend(dev->dev);
952a9ffe2a9SAlex Deucher return 0;
953e520d3e0SAlex Deucher }
95418db89b4SAlex Deucher
9552f83658fSAndrey Grodzovsky if (amdgpu_reset_domain_schedule(adev->reset_domain, &adev->reset_work))
9562f83658fSAndrey Grodzovsky flush_work(&adev->reset_work);
9572f83658fSAndrey Grodzovsky
9582f83658fSAndrey Grodzovsky *val = atomic_read(&adev->reset_domain->reset_res);
95918db89b4SAlex Deucher
960a9ffe2a9SAlex Deucher pm_runtime_mark_last_busy(dev->dev);
961a9ffe2a9SAlex Deucher pm_runtime_put_autosuspend(dev->dev);
962a9ffe2a9SAlex Deucher
96318db89b4SAlex Deucher return 0;
96418db89b4SAlex Deucher }
96518db89b4SAlex Deucher
96698d28ac2SNirmoy Das DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_fence_info);
96798d28ac2SNirmoy Das DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gpu_recover_fops, gpu_recover_get, NULL,
96898d28ac2SNirmoy Das "%lld\n");
9694fbf87e2SMonk Liu
amdgpu_debugfs_reset_work(struct work_struct * work)9702f83658fSAndrey Grodzovsky static void amdgpu_debugfs_reset_work(struct work_struct *work)
9712f83658fSAndrey Grodzovsky {
9722f83658fSAndrey Grodzovsky struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
9732f83658fSAndrey Grodzovsky reset_work);
9742f83658fSAndrey Grodzovsky
975f1549c09SLikun Gao struct amdgpu_reset_context reset_context;
9769e690184SSrinivasan Shanmugam
977f1549c09SLikun Gao memset(&reset_context, 0, sizeof(reset_context));
978f1549c09SLikun Gao
979f1549c09SLikun Gao reset_context.method = AMD_RESET_METHOD_NONE;
980f1549c09SLikun Gao reset_context.reset_req_dev = adev;
981bac640ddSEric Huang reset_context.src = AMDGPU_RESET_SRC_USER;
982f1549c09SLikun Gao set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
983*3a86fdc4SLijo Lazar set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);
984f1549c09SLikun Gao
985f1549c09SLikun Gao amdgpu_device_gpu_recover(adev, NULL, &reset_context);
9862f83658fSAndrey Grodzovsky }
9872f83658fSAndrey Grodzovsky
988d38ceaf9SAlex Deucher #endif
989d38ceaf9SAlex Deucher
amdgpu_debugfs_fence_init(struct amdgpu_device * adev)99098d28ac2SNirmoy Das void amdgpu_debugfs_fence_init(struct amdgpu_device *adev)
991d38ceaf9SAlex Deucher {
992d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
99398d28ac2SNirmoy Das struct drm_minor *minor = adev_to_drm(adev)->primary;
99498d28ac2SNirmoy Das struct dentry *root = minor->debugfs_root;
99598d28ac2SNirmoy Das
99698d28ac2SNirmoy Das debugfs_create_file("amdgpu_fence_info", 0444, root, adev,
99798d28ac2SNirmoy Das &amdgpu_debugfs_fence_info_fops);
99898d28ac2SNirmoy Das
9992f83658fSAndrey Grodzovsky if (!amdgpu_sriov_vf(adev)) {
10002f83658fSAndrey Grodzovsky
10012f83658fSAndrey Grodzovsky INIT_WORK(&adev->reset_work, amdgpu_debugfs_reset_work);
100298d28ac2SNirmoy Das debugfs_create_file("amdgpu_gpu_recover", 0444, root, adev,
100398d28ac2SNirmoy Das &amdgpu_debugfs_gpu_recover_fops);
10042f83658fSAndrey Grodzovsky }
1005d38ceaf9SAlex Deucher #endif
1006d38ceaf9SAlex Deucher }
1007d38ceaf9SAlex Deucher
1008