xref: /linux/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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