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 
39d38ceaf9SAlex Deucher #include "amdgpu.h"
40d38ceaf9SAlex Deucher #include "amdgpu_trace.h"
41d38ceaf9SAlex Deucher 
42d38ceaf9SAlex Deucher /*
43d38ceaf9SAlex Deucher  * Fences
44d38ceaf9SAlex Deucher  * Fences mark an event in the GPUs pipeline and are used
45d38ceaf9SAlex Deucher  * for GPU/CPU synchronization.  When the fence is written,
46d38ceaf9SAlex Deucher  * it is expected that all buffers associated with that fence
47d38ceaf9SAlex Deucher  * are no longer in use by the associated ring on the GPU and
48d38ceaf9SAlex Deucher  * that the the relevant GPU caches have been flushed.
49d38ceaf9SAlex Deucher  */
50d38ceaf9SAlex Deucher 
5122e5a2f4SChristian König struct amdgpu_fence {
52f54d1867SChris Wilson 	struct dma_fence base;
5322e5a2f4SChristian König 
5422e5a2f4SChristian König 	/* RB, DMA, etc. */
5522e5a2f4SChristian König 	struct amdgpu_ring		*ring;
5622e5a2f4SChristian König };
5722e5a2f4SChristian König 
58b49c84a5SChunming Zhou static struct kmem_cache *amdgpu_fence_slab;
59b49c84a5SChunming Zhou 
60d573de2dSRex Zhu int amdgpu_fence_slab_init(void)
61d573de2dSRex Zhu {
62d573de2dSRex Zhu 	amdgpu_fence_slab = kmem_cache_create(
63d573de2dSRex Zhu 		"amdgpu_fence", sizeof(struct amdgpu_fence), 0,
64d573de2dSRex Zhu 		SLAB_HWCACHE_ALIGN, NULL);
65d573de2dSRex Zhu 	if (!amdgpu_fence_slab)
66d573de2dSRex Zhu 		return -ENOMEM;
67d573de2dSRex Zhu 	return 0;
68d573de2dSRex Zhu }
69d573de2dSRex Zhu 
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;
79f54d1867SChris Wilson static inline struct amdgpu_fence *to_amdgpu_fence(struct dma_fence *f)
8022e5a2f4SChristian König {
8122e5a2f4SChristian König 	struct amdgpu_fence *__f = container_of(f, struct amdgpu_fence, base);
8222e5a2f4SChristian König 
8322e5a2f4SChristian König 	if (__f->base.ops == &amdgpu_fence_ops)
8422e5a2f4SChristian König 		return __f;
8522e5a2f4SChristian König 
8622e5a2f4SChristian König 	return NULL;
8722e5a2f4SChristian König }
8822e5a2f4SChristian König 
89d38ceaf9SAlex Deucher /**
90d38ceaf9SAlex Deucher  * amdgpu_fence_write - write a fence value
91d38ceaf9SAlex Deucher  *
92d38ceaf9SAlex Deucher  * @ring: ring the fence is associated with
93d38ceaf9SAlex Deucher  * @seq: sequence number to write
94d38ceaf9SAlex Deucher  *
95d38ceaf9SAlex Deucher  * Writes a fence value to memory (all asics).
96d38ceaf9SAlex Deucher  */
97d38ceaf9SAlex Deucher static void amdgpu_fence_write(struct amdgpu_ring *ring, u32 seq)
98d38ceaf9SAlex Deucher {
99d38ceaf9SAlex Deucher 	struct amdgpu_fence_driver *drv = &ring->fence_drv;
100d38ceaf9SAlex Deucher 
101d38ceaf9SAlex Deucher 	if (drv->cpu_addr)
102d38ceaf9SAlex Deucher 		*drv->cpu_addr = cpu_to_le32(seq);
103d38ceaf9SAlex Deucher }
104d38ceaf9SAlex Deucher 
105d38ceaf9SAlex Deucher /**
106d38ceaf9SAlex Deucher  * amdgpu_fence_read - read a fence value
107d38ceaf9SAlex Deucher  *
108d38ceaf9SAlex Deucher  * @ring: ring the fence is associated with
109d38ceaf9SAlex Deucher  *
110d38ceaf9SAlex Deucher  * Reads a fence value from memory (all asics).
111d38ceaf9SAlex Deucher  * Returns the value of the fence read from memory.
112d38ceaf9SAlex Deucher  */
113d38ceaf9SAlex Deucher static u32 amdgpu_fence_read(struct amdgpu_ring *ring)
114d38ceaf9SAlex Deucher {
115d38ceaf9SAlex Deucher 	struct amdgpu_fence_driver *drv = &ring->fence_drv;
116d38ceaf9SAlex Deucher 	u32 seq = 0;
117d38ceaf9SAlex Deucher 
118d38ceaf9SAlex Deucher 	if (drv->cpu_addr)
119d38ceaf9SAlex Deucher 		seq = le32_to_cpu(*drv->cpu_addr);
120d38ceaf9SAlex Deucher 	else
121742c085fSChristian König 		seq = atomic_read(&drv->last_seq);
122d38ceaf9SAlex Deucher 
123d38ceaf9SAlex Deucher 	return seq;
124d38ceaf9SAlex Deucher }
125d38ceaf9SAlex Deucher 
126d38ceaf9SAlex Deucher /**
127d38ceaf9SAlex Deucher  * amdgpu_fence_emit - emit a fence on the requested ring
128d38ceaf9SAlex Deucher  *
129d38ceaf9SAlex Deucher  * @ring: ring the fence is associated with
130364beb2cSChristian König  * @f: resulting fence object
131f02f8c32SLee Jones  * @flags: flags to pass into the subordinate .emit_fence() call
132d38ceaf9SAlex Deucher  *
133d38ceaf9SAlex Deucher  * Emits a fence command on the requested ring (all asics).
134d38ceaf9SAlex Deucher  * Returns 0 on success, -ENOMEM on failure.
135d38ceaf9SAlex Deucher  */
136d240cd9eSMarek Olšák int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f,
137d240cd9eSMarek Olšák 		      unsigned flags)
138d38ceaf9SAlex Deucher {
139d38ceaf9SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
140364beb2cSChristian König 	struct amdgpu_fence *fence;
1413d2aca8cSChristian König 	struct dma_fence __rcu **ptr;
142742c085fSChristian König 	uint32_t seq;
1433d2aca8cSChristian König 	int r;
144d38ceaf9SAlex Deucher 
145364beb2cSChristian König 	fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL);
146364beb2cSChristian König 	if (fence == NULL)
147d38ceaf9SAlex Deucher 		return -ENOMEM;
148364beb2cSChristian König 
149742c085fSChristian König 	seq = ++ring->fence_drv.sync_seq;
150364beb2cSChristian König 	fence->ring = ring;
151f54d1867SChris Wilson 	dma_fence_init(&fence->base, &amdgpu_fence_ops,
1524a7d74f1SChristian König 		       &ring->fence_drv.lock,
1537f06c236Smonk.liu 		       adev->fence_context + ring->idx,
154742c085fSChristian König 		       seq);
155890ee23fSChunming Zhou 	amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
156d240cd9eSMarek Olšák 			       seq, flags | AMDGPU_FENCE_FLAG_INT);
1574a580877SLuben Tuikov 	pm_runtime_get_noresume(adev_to_drm(adev)->dev);
158742c085fSChristian König 	ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
1593d2aca8cSChristian König 	if (unlikely(rcu_dereference_protected(*ptr, 1))) {
1603d2aca8cSChristian König 		struct dma_fence *old;
1613d2aca8cSChristian König 
1623d2aca8cSChristian König 		rcu_read_lock();
1633d2aca8cSChristian König 		old = dma_fence_get_rcu_safe(ptr);
1643d2aca8cSChristian König 		rcu_read_unlock();
1653d2aca8cSChristian König 
1663d2aca8cSChristian König 		if (old) {
1673d2aca8cSChristian König 			r = dma_fence_wait(old, false);
1683d2aca8cSChristian König 			dma_fence_put(old);
1693d2aca8cSChristian König 			if (r)
1703d2aca8cSChristian König 				return r;
1713d2aca8cSChristian König 		}
1723d2aca8cSChristian König 	}
1733d2aca8cSChristian König 
174c89377d1SChristian König 	/* This function can't be called concurrently anyway, otherwise
175c89377d1SChristian König 	 * emitting the fence would mess up the hardware ring buffer.
176c89377d1SChristian König 	 */
177f54d1867SChris Wilson 	rcu_assign_pointer(*ptr, dma_fence_get(&fence->base));
178c89377d1SChristian König 
179364beb2cSChristian König 	*f = &fence->base;
180c89377d1SChristian König 
181d38ceaf9SAlex Deucher 	return 0;
182d38ceaf9SAlex Deucher }
183d38ceaf9SAlex Deucher 
184d38ceaf9SAlex Deucher /**
18543ca8efaSpding  * amdgpu_fence_emit_polling - emit a fence on the requeste ring
18643ca8efaSpding  *
18743ca8efaSpding  * @ring: ring the fence is associated with
18843ca8efaSpding  * @s: resulting sequence number
189f02f8c32SLee Jones  * @timeout: the timeout for waiting in usecs
19043ca8efaSpding  *
19143ca8efaSpding  * Emits a fence command on the requested ring (all asics).
19243ca8efaSpding  * Used For polling fence.
19343ca8efaSpding  * Returns 0 on success, -ENOMEM on failure.
19443ca8efaSpding  */
19504e4e2e9SYintian Tao int amdgpu_fence_emit_polling(struct amdgpu_ring *ring, uint32_t *s,
19604e4e2e9SYintian Tao 			      uint32_t timeout)
19743ca8efaSpding {
19843ca8efaSpding 	uint32_t seq;
19904e4e2e9SYintian Tao 	signed long r;
20043ca8efaSpding 
20143ca8efaSpding 	if (!s)
20243ca8efaSpding 		return -EINVAL;
20343ca8efaSpding 
20443ca8efaSpding 	seq = ++ring->fence_drv.sync_seq;
20504e4e2e9SYintian Tao 	r = amdgpu_fence_wait_polling(ring,
20604e4e2e9SYintian Tao 				      seq - ring->fence_drv.num_fences_mask,
20704e4e2e9SYintian Tao 				      timeout);
20804e4e2e9SYintian Tao 	if (r < 1)
20904e4e2e9SYintian Tao 		return -ETIMEDOUT;
21004e4e2e9SYintian Tao 
21143ca8efaSpding 	amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
212d118a621SMonk Liu 			       seq, 0);
21343ca8efaSpding 
21443ca8efaSpding 	*s = seq;
21543ca8efaSpding 
21643ca8efaSpding 	return 0;
21743ca8efaSpding }
21843ca8efaSpding 
21943ca8efaSpding /**
2208c5e13ecSAndrey Grodzovsky  * amdgpu_fence_schedule_fallback - schedule fallback check
2218c5e13ecSAndrey Grodzovsky  *
2228c5e13ecSAndrey Grodzovsky  * @ring: pointer to struct amdgpu_ring
2238c5e13ecSAndrey Grodzovsky  *
2248c5e13ecSAndrey Grodzovsky  * Start a timer as fallback to our interrupts.
2258c5e13ecSAndrey Grodzovsky  */
2268c5e13ecSAndrey Grodzovsky static void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring)
2278c5e13ecSAndrey Grodzovsky {
2288c5e13ecSAndrey Grodzovsky 	mod_timer(&ring->fence_drv.fallback_timer,
2298c5e13ecSAndrey Grodzovsky 		  jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT);
2308c5e13ecSAndrey Grodzovsky }
2318c5e13ecSAndrey Grodzovsky 
2328c5e13ecSAndrey Grodzovsky /**
233ca08e04dSChristian König  * amdgpu_fence_process - check for fence activity
234d38ceaf9SAlex Deucher  *
235d38ceaf9SAlex Deucher  * @ring: pointer to struct amdgpu_ring
236d38ceaf9SAlex Deucher  *
237d38ceaf9SAlex Deucher  * Checks the current fence value and calculates the last
238ca08e04dSChristian König  * signalled fence value. Wakes the fence queue if the
239ca08e04dSChristian König  * sequence number has increased.
24095d7fc4aSAndrey Grodzovsky  *
24195d7fc4aSAndrey Grodzovsky  * Returns true if fence was processed
242d38ceaf9SAlex Deucher  */
24395d7fc4aSAndrey Grodzovsky bool amdgpu_fence_process(struct amdgpu_ring *ring)
244d38ceaf9SAlex Deucher {
2454a7d74f1SChristian König 	struct amdgpu_fence_driver *drv = &ring->fence_drv;
24645a80abeSAlex Deucher 	struct amdgpu_device *adev = ring->adev;
247742c085fSChristian König 	uint32_t seq, last_seq;
2484a7d74f1SChristian König 	int r;
249d38ceaf9SAlex Deucher 
250d38ceaf9SAlex Deucher 	do {
251742c085fSChristian König 		last_seq = atomic_read(&ring->fence_drv.last_seq);
252d38ceaf9SAlex Deucher 		seq = amdgpu_fence_read(ring);
253d38ceaf9SAlex Deucher 
254742c085fSChristian König 	} while (atomic_cmpxchg(&drv->last_seq, last_seq, seq) != last_seq);
255d38ceaf9SAlex Deucher 
2563547e3cfSAndrey Grodzovsky 	if (del_timer(&ring->fence_drv.fallback_timer) &&
2573547e3cfSAndrey Grodzovsky 	    seq != ring->fence_drv.sync_seq)
2588c5e13ecSAndrey Grodzovsky 		amdgpu_fence_schedule_fallback(ring);
2598c5e13ecSAndrey Grodzovsky 
2602ef004d9SChristian König 	if (unlikely(seq == last_seq))
26195d7fc4aSAndrey Grodzovsky 		return false;
2622ef004d9SChristian König 
2634f399a08SChristian König 	last_seq &= drv->num_fences_mask;
2644f399a08SChristian König 	seq &= drv->num_fences_mask;
2654f399a08SChristian König 
2662ef004d9SChristian König 	do {
267f54d1867SChris Wilson 		struct dma_fence *fence, **ptr;
2684a7d74f1SChristian König 
2694f399a08SChristian König 		++last_seq;
2704f399a08SChristian König 		last_seq &= drv->num_fences_mask;
2714f399a08SChristian König 		ptr = &drv->fences[last_seq];
2724a7d74f1SChristian König 
2734a7d74f1SChristian König 		/* There is always exactly one thread signaling this fence slot */
2744a7d74f1SChristian König 		fence = rcu_dereference_protected(*ptr, 1);
27584fae133SMuhammad Falak R Wani 		RCU_INIT_POINTER(*ptr, NULL);
2764a7d74f1SChristian König 
2774f399a08SChristian König 		if (!fence)
2784f399a08SChristian König 			continue;
2794a7d74f1SChristian König 
280f54d1867SChris Wilson 		r = dma_fence_signal(fence);
2814a7d74f1SChristian König 		if (!r)
282f54d1867SChris Wilson 			DMA_FENCE_TRACE(fence, "signaled from irq context\n");
2834a7d74f1SChristian König 		else
2844a7d74f1SChristian König 			BUG();
2854a7d74f1SChristian König 
286f54d1867SChris Wilson 		dma_fence_put(fence);
2874a580877SLuben Tuikov 		pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
2884a580877SLuben Tuikov 		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
2892ef004d9SChristian König 	} while (last_seq != seq);
29095d7fc4aSAndrey Grodzovsky 
29195d7fc4aSAndrey Grodzovsky 	return true;
292e0d8f3c3SChunming Zhou }
293d38ceaf9SAlex Deucher 
294d38ceaf9SAlex Deucher /**
2958c5e13ecSAndrey Grodzovsky  * amdgpu_fence_fallback - fallback for hardware interrupts
2968c5e13ecSAndrey Grodzovsky  *
297f02f8c32SLee Jones  * @t: timer context used to obtain the pointer to ring structure
2988c5e13ecSAndrey Grodzovsky  *
2998c5e13ecSAndrey Grodzovsky  * Checks for fence activity.
3008c5e13ecSAndrey Grodzovsky  */
3018c5e13ecSAndrey Grodzovsky static void amdgpu_fence_fallback(struct timer_list *t)
3028c5e13ecSAndrey Grodzovsky {
3038c5e13ecSAndrey Grodzovsky 	struct amdgpu_ring *ring = from_timer(ring, t,
3048c5e13ecSAndrey Grodzovsky 					      fence_drv.fallback_timer);
3058c5e13ecSAndrey Grodzovsky 
30695d7fc4aSAndrey Grodzovsky 	if (amdgpu_fence_process(ring))
3073547e3cfSAndrey Grodzovsky 		DRM_WARN("Fence fallback timer expired on ring %s\n", ring->name);
3088c5e13ecSAndrey Grodzovsky }
3098c5e13ecSAndrey Grodzovsky 
3108c5e13ecSAndrey Grodzovsky /**
311d38ceaf9SAlex Deucher  * amdgpu_fence_wait_empty - wait for all fences to signal
312d38ceaf9SAlex Deucher  *
313d38ceaf9SAlex Deucher  * @ring: ring index the fence is associated with
314d38ceaf9SAlex Deucher  *
315d38ceaf9SAlex Deucher  * Wait for all fences on the requested ring to signal (all asics).
316d38ceaf9SAlex Deucher  * Returns 0 if the fences have passed, error for all other cases.
317d38ceaf9SAlex Deucher  */
318d38ceaf9SAlex Deucher int amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
319d38ceaf9SAlex Deucher {
3206aa7de05SMark Rutland 	uint64_t seq = READ_ONCE(ring->fence_drv.sync_seq);
321f54d1867SChris Wilson 	struct dma_fence *fence, **ptr;
322f09c2be4SChristian König 	int r;
32300d2a2b2SChristian König 
3247f06c236Smonk.liu 	if (!seq)
325d38ceaf9SAlex Deucher 		return 0;
326d38ceaf9SAlex Deucher 
327f09c2be4SChristian König 	ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
328f09c2be4SChristian König 	rcu_read_lock();
329f09c2be4SChristian König 	fence = rcu_dereference(*ptr);
330f54d1867SChris Wilson 	if (!fence || !dma_fence_get_rcu(fence)) {
331f09c2be4SChristian König 		rcu_read_unlock();
332f09c2be4SChristian König 		return 0;
333f09c2be4SChristian König 	}
334f09c2be4SChristian König 	rcu_read_unlock();
335f09c2be4SChristian König 
336f54d1867SChris Wilson 	r = dma_fence_wait(fence, false);
337f54d1867SChris Wilson 	dma_fence_put(fence);
338f09c2be4SChristian König 	return r;
339d38ceaf9SAlex Deucher }
340d38ceaf9SAlex Deucher 
341d38ceaf9SAlex Deucher /**
34243ca8efaSpding  * amdgpu_fence_wait_polling - busy wait for givn sequence number
34343ca8efaSpding  *
34443ca8efaSpding  * @ring: ring index the fence is associated with
34543ca8efaSpding  * @wait_seq: sequence number to wait
34643ca8efaSpding  * @timeout: the timeout for waiting in usecs
34743ca8efaSpding  *
34843ca8efaSpding  * Wait for all fences on the requested ring to signal (all asics).
34943ca8efaSpding  * Returns left time if no timeout, 0 or minus if timeout.
35043ca8efaSpding  */
35143ca8efaSpding signed long amdgpu_fence_wait_polling(struct amdgpu_ring *ring,
35243ca8efaSpding 				      uint32_t wait_seq,
35343ca8efaSpding 				      signed long timeout)
35443ca8efaSpding {
35543ca8efaSpding 	uint32_t seq;
35643ca8efaSpding 
35743ca8efaSpding 	do {
35843ca8efaSpding 		seq = amdgpu_fence_read(ring);
35943ca8efaSpding 		udelay(5);
36043ca8efaSpding 		timeout -= 5;
36143ca8efaSpding 	} while ((int32_t)(wait_seq - seq) > 0 && timeout > 0);
36243ca8efaSpding 
36343ca8efaSpding 	return timeout > 0 ? timeout : 0;
36443ca8efaSpding }
36543ca8efaSpding /**
366d38ceaf9SAlex Deucher  * amdgpu_fence_count_emitted - get the count of emitted fences
367d38ceaf9SAlex Deucher  *
368d38ceaf9SAlex Deucher  * @ring: ring the fence is associated with
369d38ceaf9SAlex Deucher  *
370d38ceaf9SAlex Deucher  * Get the number of fences emitted on the requested ring (all asics).
371d38ceaf9SAlex Deucher  * Returns the number of emitted fences on the ring.  Used by the
372d38ceaf9SAlex Deucher  * dynpm code to ring track activity.
373d38ceaf9SAlex Deucher  */
374d38ceaf9SAlex Deucher unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring)
375d38ceaf9SAlex Deucher {
376d38ceaf9SAlex Deucher 	uint64_t emitted;
377d38ceaf9SAlex Deucher 
378d38ceaf9SAlex Deucher 	/* We are not protected by ring lock when reading the last sequence
379d38ceaf9SAlex Deucher 	 * but it's ok to report slightly wrong fence count here.
380d38ceaf9SAlex Deucher 	 */
381d38ceaf9SAlex Deucher 	amdgpu_fence_process(ring);
382742c085fSChristian König 	emitted = 0x100000000ull;
383742c085fSChristian König 	emitted -= atomic_read(&ring->fence_drv.last_seq);
3846aa7de05SMark Rutland 	emitted += READ_ONCE(ring->fence_drv.sync_seq);
385742c085fSChristian König 	return lower_32_bits(emitted);
386d38ceaf9SAlex Deucher }
387d38ceaf9SAlex Deucher 
388d38ceaf9SAlex Deucher /**
389d38ceaf9SAlex Deucher  * amdgpu_fence_driver_start_ring - make the fence driver
390d38ceaf9SAlex Deucher  * ready for use on the requested ring.
391d38ceaf9SAlex Deucher  *
392d38ceaf9SAlex Deucher  * @ring: ring to start the fence driver on
393d38ceaf9SAlex Deucher  * @irq_src: interrupt source to use for this ring
394d38ceaf9SAlex Deucher  * @irq_type: interrupt type to use for this ring
395d38ceaf9SAlex Deucher  *
396d38ceaf9SAlex Deucher  * Make the fence driver ready for processing (all asics).
397d38ceaf9SAlex Deucher  * Not all asics have all rings, so each asic will only
398d38ceaf9SAlex Deucher  * start the fence driver on the rings it has.
399d38ceaf9SAlex Deucher  * Returns 0 for success, errors for failure.
400d38ceaf9SAlex Deucher  */
401d38ceaf9SAlex Deucher int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
402d38ceaf9SAlex Deucher 				   struct amdgpu_irq_src *irq_src,
403d38ceaf9SAlex Deucher 				   unsigned irq_type)
404d38ceaf9SAlex Deucher {
405d38ceaf9SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
406d38ceaf9SAlex Deucher 	uint64_t index;
407d38ceaf9SAlex Deucher 
408d9e98ee2SLeo Liu 	if (ring->funcs->type != AMDGPU_RING_TYPE_UVD) {
409d38ceaf9SAlex Deucher 		ring->fence_drv.cpu_addr = &adev->wb.wb[ring->fence_offs];
410d38ceaf9SAlex Deucher 		ring->fence_drv.gpu_addr = adev->wb.gpu_addr + (ring->fence_offs * 4);
411d38ceaf9SAlex Deucher 	} else {
412d38ceaf9SAlex Deucher 		/* put fence directly behind firmware */
413d38ceaf9SAlex Deucher 		index = ALIGN(adev->uvd.fw->size, 8);
41410dd74eaSJames Zhu 		ring->fence_drv.cpu_addr = adev->uvd.inst[ring->me].cpu_addr + index;
41510dd74eaSJames Zhu 		ring->fence_drv.gpu_addr = adev->uvd.inst[ring->me].gpu_addr + index;
416d38ceaf9SAlex Deucher 	}
417742c085fSChristian König 	amdgpu_fence_write(ring, atomic_read(&ring->fence_drv.last_seq));
41855611b50SJack Xiao 
41955611b50SJack Xiao 	if (irq_src)
420c6a4079bSChunming Zhou 		amdgpu_irq_get(adev, irq_src, irq_type);
421c6a4079bSChunming Zhou 
422d38ceaf9SAlex Deucher 	ring->fence_drv.irq_src = irq_src;
423d38ceaf9SAlex Deucher 	ring->fence_drv.irq_type = irq_type;
424c6a4079bSChunming Zhou 	ring->fence_drv.initialized = true;
425c6a4079bSChunming Zhou 
426e241df69STiezhu Yang 	DRM_DEV_DEBUG(adev->dev, "fence driver on ring %s use gpu addr 0x%016llx\n",
427e241df69STiezhu Yang 		      ring->name, ring->fence_drv.gpu_addr);
428d38ceaf9SAlex Deucher 	return 0;
429d38ceaf9SAlex Deucher }
430d38ceaf9SAlex Deucher 
431d38ceaf9SAlex Deucher /**
432d38ceaf9SAlex Deucher  * amdgpu_fence_driver_init_ring - init the fence driver
433d38ceaf9SAlex Deucher  * for the requested ring.
434d38ceaf9SAlex Deucher  *
435d38ceaf9SAlex Deucher  * @ring: ring to init the fence driver on
436e6151a08SChristian König  * @num_hw_submission: number of entries on the hardware queue
437d38ceaf9SAlex Deucher  *
438d38ceaf9SAlex Deucher  * Init the fence driver for the requested ring (all asics).
439d38ceaf9SAlex Deucher  * Helper function for amdgpu_fence_driver_init().
440d38ceaf9SAlex Deucher  */
441e6151a08SChristian König int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring,
442e6151a08SChristian König 				  unsigned num_hw_submission)
443d38ceaf9SAlex Deucher {
444912dfc84SEvan Quan 	struct amdgpu_device *adev = ring->adev;
445687c1c2eSEvan Quan 	long timeout;
4465907a0d8SChristian König 	int r;
447d38ceaf9SAlex Deucher 
448912dfc84SEvan Quan 	if (!adev)
449912dfc84SEvan Quan 		return -EINVAL;
450912dfc84SEvan Quan 
4515d5bd5e3SKevin Wang 	if (!is_power_of_2(num_hw_submission))
452e6151a08SChristian König 		return -EINVAL;
453e6151a08SChristian König 
454d38ceaf9SAlex Deucher 	ring->fence_drv.cpu_addr = NULL;
455d38ceaf9SAlex Deucher 	ring->fence_drv.gpu_addr = 0;
4565907a0d8SChristian König 	ring->fence_drv.sync_seq = 0;
457742c085fSChristian König 	atomic_set(&ring->fence_drv.last_seq, 0);
458d38ceaf9SAlex Deucher 	ring->fence_drv.initialized = false;
459d38ceaf9SAlex Deucher 
4608c5e13ecSAndrey Grodzovsky 	timer_setup(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback, 0);
4618c5e13ecSAndrey Grodzovsky 
46266067ad7SChunming Zhou 	ring->fence_drv.num_fences_mask = num_hw_submission * 2 - 1;
4634a7d74f1SChristian König 	spin_lock_init(&ring->fence_drv.lock);
46466067ad7SChunming Zhou 	ring->fence_drv.fences = kcalloc(num_hw_submission * 2, sizeof(void *),
465c89377d1SChristian König 					 GFP_KERNEL);
466c89377d1SChristian König 	if (!ring->fence_drv.fences)
467c89377d1SChristian König 		return -ENOMEM;
4685ec92a76SChristian König 
469730c2eb9SAlex Deucher 	/* No need to setup the GPU scheduler for rings that don't need it */
470730c2eb9SAlex Deucher 	if (!ring->no_scheduler) {
471912dfc84SEvan Quan 		switch (ring->funcs->type) {
472912dfc84SEvan Quan 		case AMDGPU_RING_TYPE_GFX:
473912dfc84SEvan Quan 			timeout = adev->gfx_timeout;
474912dfc84SEvan Quan 			break;
475912dfc84SEvan Quan 		case AMDGPU_RING_TYPE_COMPUTE:
476912dfc84SEvan Quan 			timeout = adev->compute_timeout;
477912dfc84SEvan Quan 			break;
478912dfc84SEvan Quan 		case AMDGPU_RING_TYPE_SDMA:
479912dfc84SEvan Quan 			timeout = adev->sdma_timeout;
480912dfc84SEvan Quan 			break;
481912dfc84SEvan Quan 		default:
482912dfc84SEvan Quan 			timeout = adev->video_timeout;
483912dfc84SEvan Quan 			break;
484912dfc84SEvan Quan 		}
485687c1c2eSEvan Quan 
4861b1f42d8SLucas Stach 		r = drm_sched_init(&ring->sched, &amdgpu_sched_ops,
48795aa9b1dSMonk Liu 				   num_hw_submission, amdgpu_job_hang_limit,
488687c1c2eSEvan Quan 				   timeout, ring->name);
4894f839a24SChristian König 		if (r) {
4904f839a24SChristian König 			DRM_ERROR("Failed to create scheduler on ring %s.\n",
4914f839a24SChristian König 				  ring->name);
4924f839a24SChristian König 			return r;
493b80d8475SAlex Deucher 		}
494e2250442STrigger Huang 	}
495d38ceaf9SAlex Deucher 
4964f839a24SChristian König 	return 0;
4974f839a24SChristian König }
4984f839a24SChristian König 
499d38ceaf9SAlex Deucher /**
500d38ceaf9SAlex Deucher  * amdgpu_fence_driver_init - init the fence driver
501d38ceaf9SAlex Deucher  * for all possible rings.
502d38ceaf9SAlex Deucher  *
503d38ceaf9SAlex Deucher  * @adev: amdgpu device pointer
504d38ceaf9SAlex Deucher  *
505d38ceaf9SAlex Deucher  * Init the fence driver for all possible rings (all asics).
506d38ceaf9SAlex Deucher  * Not all asics have all rings, so each asic will only
507d38ceaf9SAlex Deucher  * start the fence driver on the rings it has using
508d38ceaf9SAlex Deucher  * amdgpu_fence_driver_start_ring().
509d38ceaf9SAlex Deucher  * Returns 0 for success.
510d38ceaf9SAlex Deucher  */
511d38ceaf9SAlex Deucher int amdgpu_fence_driver_init(struct amdgpu_device *adev)
512d38ceaf9SAlex Deucher {
513d38ceaf9SAlex Deucher 	return 0;
514d38ceaf9SAlex Deucher }
515d38ceaf9SAlex Deucher 
516d38ceaf9SAlex Deucher /**
517d38ceaf9SAlex Deucher  * amdgpu_fence_driver_fini - tear down the fence driver
518d38ceaf9SAlex Deucher  * for all possible rings.
519d38ceaf9SAlex Deucher  *
520d38ceaf9SAlex Deucher  * @adev: amdgpu device pointer
521d38ceaf9SAlex Deucher  *
522d38ceaf9SAlex Deucher  * Tear down the fence driver for all possible rings (all asics).
523d38ceaf9SAlex Deucher  */
524d38ceaf9SAlex Deucher void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
525d38ceaf9SAlex Deucher {
526c89377d1SChristian König 	unsigned i, j;
527c89377d1SChristian König 	int r;
528d38ceaf9SAlex Deucher 
529d38ceaf9SAlex Deucher 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
530d38ceaf9SAlex Deucher 		struct amdgpu_ring *ring = adev->rings[i];
531c2776afeSChristian König 
532d38ceaf9SAlex Deucher 		if (!ring || !ring->fence_drv.initialized)
533d38ceaf9SAlex Deucher 			continue;
534d38ceaf9SAlex Deucher 		r = amdgpu_fence_wait_empty(ring);
535d38ceaf9SAlex Deucher 		if (r) {
536d38ceaf9SAlex Deucher 			/* no need to trigger GPU reset as we are unloading */
5372f9d4084SMonk Liu 			amdgpu_fence_driver_force_completion(ring);
538d38ceaf9SAlex Deucher 		}
53955611b50SJack Xiao 		if (ring->fence_drv.irq_src)
540c6a4079bSChunming Zhou 			amdgpu_irq_put(adev, ring->fence_drv.irq_src,
541c6a4079bSChunming Zhou 				       ring->fence_drv.irq_type);
542730c2eb9SAlex Deucher 		if (!ring->no_scheduler)
5431b1f42d8SLucas Stach 			drm_sched_fini(&ring->sched);
5448c5e13ecSAndrey Grodzovsky 		del_timer_sync(&ring->fence_drv.fallback_timer);
545c89377d1SChristian König 		for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
546f54d1867SChris Wilson 			dma_fence_put(ring->fence_drv.fences[j]);
547c89377d1SChristian König 		kfree(ring->fence_drv.fences);
54854ddf3a6SGrazvydas Ignotas 		ring->fence_drv.fences = NULL;
549d38ceaf9SAlex Deucher 		ring->fence_drv.initialized = false;
550d38ceaf9SAlex Deucher 	}
551d38ceaf9SAlex Deucher }
552d38ceaf9SAlex Deucher 
553d38ceaf9SAlex Deucher /**
5545ceb54c6SAlex Deucher  * amdgpu_fence_driver_suspend - suspend the fence driver
5555ceb54c6SAlex Deucher  * for all possible rings.
5565ceb54c6SAlex Deucher  *
5575ceb54c6SAlex Deucher  * @adev: amdgpu device pointer
5585ceb54c6SAlex Deucher  *
5595ceb54c6SAlex Deucher  * Suspend the fence driver for all possible rings (all asics).
5605ceb54c6SAlex Deucher  */
5615ceb54c6SAlex Deucher void amdgpu_fence_driver_suspend(struct amdgpu_device *adev)
5625ceb54c6SAlex Deucher {
5635ceb54c6SAlex Deucher 	int i, r;
5645ceb54c6SAlex Deucher 
5655ceb54c6SAlex Deucher 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
5665ceb54c6SAlex Deucher 		struct amdgpu_ring *ring = adev->rings[i];
5675ceb54c6SAlex Deucher 		if (!ring || !ring->fence_drv.initialized)
5685ceb54c6SAlex Deucher 			continue;
5695ceb54c6SAlex Deucher 
5705ceb54c6SAlex Deucher 		/* wait for gpu to finish processing current batch */
5715ceb54c6SAlex Deucher 		r = amdgpu_fence_wait_empty(ring);
5725ceb54c6SAlex Deucher 		if (r) {
5735ceb54c6SAlex Deucher 			/* delay GPU reset to resume */
5742f9d4084SMonk Liu 			amdgpu_fence_driver_force_completion(ring);
5755ceb54c6SAlex Deucher 		}
5765ceb54c6SAlex Deucher 
5775ceb54c6SAlex Deucher 		/* disable the interrupt */
57855611b50SJack Xiao 		if (ring->fence_drv.irq_src)
5795ceb54c6SAlex Deucher 			amdgpu_irq_put(adev, ring->fence_drv.irq_src,
5805ceb54c6SAlex Deucher 				       ring->fence_drv.irq_type);
5815ceb54c6SAlex Deucher 	}
5825ceb54c6SAlex Deucher }
5835ceb54c6SAlex Deucher 
5845ceb54c6SAlex Deucher /**
5855ceb54c6SAlex Deucher  * amdgpu_fence_driver_resume - resume the fence driver
5865ceb54c6SAlex Deucher  * for all possible rings.
5875ceb54c6SAlex Deucher  *
5885ceb54c6SAlex Deucher  * @adev: amdgpu device pointer
5895ceb54c6SAlex Deucher  *
5905ceb54c6SAlex Deucher  * Resume the fence driver for all possible rings (all asics).
5915ceb54c6SAlex Deucher  * Not all asics have all rings, so each asic will only
5925ceb54c6SAlex Deucher  * start the fence driver on the rings it has using
5935ceb54c6SAlex Deucher  * amdgpu_fence_driver_start_ring().
5945ceb54c6SAlex Deucher  * Returns 0 for success.
5955ceb54c6SAlex Deucher  */
5965ceb54c6SAlex Deucher void amdgpu_fence_driver_resume(struct amdgpu_device *adev)
5975ceb54c6SAlex Deucher {
5985ceb54c6SAlex Deucher 	int i;
5995ceb54c6SAlex Deucher 
6005ceb54c6SAlex Deucher 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
6015ceb54c6SAlex Deucher 		struct amdgpu_ring *ring = adev->rings[i];
6025ceb54c6SAlex Deucher 		if (!ring || !ring->fence_drv.initialized)
6035ceb54c6SAlex Deucher 			continue;
6045ceb54c6SAlex Deucher 
6055ceb54c6SAlex Deucher 		/* enable the interrupt */
60655611b50SJack Xiao 		if (ring->fence_drv.irq_src)
6075ceb54c6SAlex Deucher 			amdgpu_irq_get(adev, ring->fence_drv.irq_src,
6085ceb54c6SAlex Deucher 				       ring->fence_drv.irq_type);
6095ceb54c6SAlex Deucher 	}
6105ceb54c6SAlex Deucher }
6115ceb54c6SAlex Deucher 
6125ceb54c6SAlex Deucher /**
6132f9d4084SMonk Liu  * amdgpu_fence_driver_force_completion - force signal latest fence of ring
614d38ceaf9SAlex Deucher  *
6152f9d4084SMonk Liu  * @ring: fence of the ring to signal
616d38ceaf9SAlex Deucher  *
617d38ceaf9SAlex Deucher  */
6182f9d4084SMonk Liu void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
619d38ceaf9SAlex Deucher {
6205907a0d8SChristian König 	amdgpu_fence_write(ring, ring->fence_drv.sync_seq);
6212f9d4084SMonk Liu 	amdgpu_fence_process(ring);
62265781c78SMonk Liu }
62365781c78SMonk Liu 
624a95e2642SChristian König /*
625a95e2642SChristian König  * Common fence implementation
626a95e2642SChristian König  */
627a95e2642SChristian König 
628f54d1867SChris Wilson static const char *amdgpu_fence_get_driver_name(struct dma_fence *fence)
629a95e2642SChristian König {
630a95e2642SChristian König 	return "amdgpu";
631a95e2642SChristian König }
632a95e2642SChristian König 
633f54d1867SChris Wilson static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f)
634a95e2642SChristian König {
635a95e2642SChristian König 	struct amdgpu_fence *fence = to_amdgpu_fence(f);
636a95e2642SChristian König 	return (const char *)fence->ring->name;
637a95e2642SChristian König }
638a95e2642SChristian König 
639a95e2642SChristian König /**
6408c5e13ecSAndrey Grodzovsky  * amdgpu_fence_enable_signaling - enable signalling on fence
641f02f8c32SLee Jones  * @f: fence
6428c5e13ecSAndrey Grodzovsky  *
6438c5e13ecSAndrey Grodzovsky  * This function is called with fence_queue lock held, and adds a callback
6448c5e13ecSAndrey Grodzovsky  * to fence_queue that checks if this fence is signaled, and if so it
6458c5e13ecSAndrey Grodzovsky  * signals the fence and removes itself.
6468c5e13ecSAndrey Grodzovsky  */
6478c5e13ecSAndrey Grodzovsky static bool amdgpu_fence_enable_signaling(struct dma_fence *f)
6488c5e13ecSAndrey Grodzovsky {
6498c5e13ecSAndrey Grodzovsky 	struct amdgpu_fence *fence = to_amdgpu_fence(f);
6508c5e13ecSAndrey Grodzovsky 	struct amdgpu_ring *ring = fence->ring;
6518c5e13ecSAndrey Grodzovsky 
6528c5e13ecSAndrey Grodzovsky 	if (!timer_pending(&ring->fence_drv.fallback_timer))
6538c5e13ecSAndrey Grodzovsky 		amdgpu_fence_schedule_fallback(ring);
6548c5e13ecSAndrey Grodzovsky 
6558c5e13ecSAndrey Grodzovsky 	DMA_FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx);
6568c5e13ecSAndrey Grodzovsky 
6578c5e13ecSAndrey Grodzovsky 	return true;
6588c5e13ecSAndrey Grodzovsky }
6598c5e13ecSAndrey Grodzovsky 
6608c5e13ecSAndrey Grodzovsky /**
661b4413535SChristian König  * amdgpu_fence_free - free up the fence memory
662b4413535SChristian König  *
663b4413535SChristian König  * @rcu: RCU callback head
664b4413535SChristian König  *
665b4413535SChristian König  * Free up the fence memory after the RCU grace period.
666b4413535SChristian König  */
667b4413535SChristian König static void amdgpu_fence_free(struct rcu_head *rcu)
668b49c84a5SChunming Zhou {
669f54d1867SChris Wilson 	struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
670b49c84a5SChunming Zhou 	struct amdgpu_fence *fence = to_amdgpu_fence(f);
671b49c84a5SChunming Zhou 	kmem_cache_free(amdgpu_fence_slab, fence);
672b49c84a5SChunming Zhou }
673b49c84a5SChunming Zhou 
674b4413535SChristian König /**
675b4413535SChristian König  * amdgpu_fence_release - callback that fence can be freed
676b4413535SChristian König  *
677f02f8c32SLee Jones  * @f: fence
678b4413535SChristian König  *
679b4413535SChristian König  * This function is called when the reference count becomes zero.
680b4413535SChristian König  * It just RCU schedules freeing up the fence.
681b4413535SChristian König  */
682f54d1867SChris Wilson static void amdgpu_fence_release(struct dma_fence *f)
683b4413535SChristian König {
684b4413535SChristian König 	call_rcu(&f->rcu, amdgpu_fence_free);
685b4413535SChristian König }
686b4413535SChristian König 
687f54d1867SChris Wilson static const struct dma_fence_ops amdgpu_fence_ops = {
688a95e2642SChristian König 	.get_driver_name = amdgpu_fence_get_driver_name,
689a95e2642SChristian König 	.get_timeline_name = amdgpu_fence_get_timeline_name,
6908c5e13ecSAndrey Grodzovsky 	.enable_signaling = amdgpu_fence_enable_signaling,
691b49c84a5SChunming Zhou 	.release = amdgpu_fence_release,
692a95e2642SChristian König };
693d38ceaf9SAlex Deucher 
694d38ceaf9SAlex Deucher /*
695d38ceaf9SAlex Deucher  * Fence debugfs
696d38ceaf9SAlex Deucher  */
697d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
698*98d28ac2SNirmoy Das static int amdgpu_debugfs_fence_info_show(struct seq_file *m, void *unused)
699d38ceaf9SAlex Deucher {
700*98d28ac2SNirmoy Das 	struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
7015907a0d8SChristian König 	int i;
702d38ceaf9SAlex Deucher 
703d38ceaf9SAlex Deucher 	for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
704d38ceaf9SAlex Deucher 		struct amdgpu_ring *ring = adev->rings[i];
705d38ceaf9SAlex Deucher 		if (!ring || !ring->fence_drv.initialized)
706d38ceaf9SAlex Deucher 			continue;
707d38ceaf9SAlex Deucher 
708d38ceaf9SAlex Deucher 		amdgpu_fence_process(ring);
709d38ceaf9SAlex Deucher 
710344c19f9SChristian König 		seq_printf(m, "--- ring %d (%s) ---\n", i, ring->name);
711742c085fSChristian König 		seq_printf(m, "Last signaled fence          0x%08x\n",
712742c085fSChristian König 			   atomic_read(&ring->fence_drv.last_seq));
713742c085fSChristian König 		seq_printf(m, "Last emitted                 0x%08x\n",
7145907a0d8SChristian König 			   ring->fence_drv.sync_seq);
715e71de076Spding 
716ef3e1323SJack Xiao 		if (ring->funcs->type == AMDGPU_RING_TYPE_GFX ||
717ef3e1323SJack Xiao 		    ring->funcs->type == AMDGPU_RING_TYPE_SDMA) {
718ef3e1323SJack Xiao 			seq_printf(m, "Last signaled trailing fence 0x%08x\n",
719ef3e1323SJack Xiao 				   le32_to_cpu(*ring->trail_fence_cpu_addr));
720ef3e1323SJack Xiao 			seq_printf(m, "Last emitted                 0x%08x\n",
721ef3e1323SJack Xiao 				   ring->trail_seq);
722ef3e1323SJack Xiao 		}
723ef3e1323SJack Xiao 
724e71de076Spding 		if (ring->funcs->type != AMDGPU_RING_TYPE_GFX)
725e71de076Spding 			continue;
726e71de076Spding 
727e71de076Spding 		/* set in CP_VMID_PREEMPT and preemption occurred */
728e71de076Spding 		seq_printf(m, "Last preempted               0x%08x\n",
729e71de076Spding 			   le32_to_cpu(*(ring->fence_drv.cpu_addr + 2)));
730e71de076Spding 		/* set in CP_VMID_RESET and reset occurred */
731e71de076Spding 		seq_printf(m, "Last reset                   0x%08x\n",
732e71de076Spding 			   le32_to_cpu(*(ring->fence_drv.cpu_addr + 4)));
733e71de076Spding 		/* Both preemption and reset occurred */
734e71de076Spding 		seq_printf(m, "Last both                    0x%08x\n",
735e71de076Spding 			   le32_to_cpu(*(ring->fence_drv.cpu_addr + 6)));
736d38ceaf9SAlex Deucher 	}
737d38ceaf9SAlex Deucher 	return 0;
738d38ceaf9SAlex Deucher }
739d38ceaf9SAlex Deucher 
740f02f8c32SLee Jones /*
7415740682eSMonk Liu  * amdgpu_debugfs_gpu_recover - manually trigger a gpu reset & recover
74218db89b4SAlex Deucher  *
74318db89b4SAlex Deucher  * Manually trigger a gpu reset at the next fence wait.
74418db89b4SAlex Deucher  */
745*98d28ac2SNirmoy Das static int gpu_recover_get(void *data, u64 *val)
74618db89b4SAlex Deucher {
747*98d28ac2SNirmoy Das 	struct amdgpu_device *adev = (struct amdgpu_device *)data;
748*98d28ac2SNirmoy Das 	struct drm_device *dev = adev_to_drm(adev);
749a9ffe2a9SAlex Deucher 	int r;
750a9ffe2a9SAlex Deucher 
751a9ffe2a9SAlex Deucher 	r = pm_runtime_get_sync(dev->dev);
752e520d3e0SAlex Deucher 	if (r < 0) {
753e520d3e0SAlex Deucher 		pm_runtime_put_autosuspend(dev->dev);
754a9ffe2a9SAlex Deucher 		return 0;
755e520d3e0SAlex Deucher 	}
75618db89b4SAlex Deucher 
757*98d28ac2SNirmoy Das 	*val = amdgpu_device_gpu_recover(adev, NULL);
75818db89b4SAlex Deucher 
759a9ffe2a9SAlex Deucher 	pm_runtime_mark_last_busy(dev->dev);
760a9ffe2a9SAlex Deucher 	pm_runtime_put_autosuspend(dev->dev);
761a9ffe2a9SAlex Deucher 
76218db89b4SAlex Deucher 	return 0;
76318db89b4SAlex Deucher }
76418db89b4SAlex Deucher 
765*98d28ac2SNirmoy Das DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_fence_info);
766*98d28ac2SNirmoy Das DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gpu_recover_fops, gpu_recover_get, NULL,
767*98d28ac2SNirmoy Das 			 "%lld\n");
7684fbf87e2SMonk Liu 
769d38ceaf9SAlex Deucher #endif
770d38ceaf9SAlex Deucher 
771*98d28ac2SNirmoy Das void amdgpu_debugfs_fence_init(struct amdgpu_device *adev)
772d38ceaf9SAlex Deucher {
773d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
774*98d28ac2SNirmoy Das 	struct drm_minor *minor = adev_to_drm(adev)->primary;
775*98d28ac2SNirmoy Das 	struct dentry *root = minor->debugfs_root;
776*98d28ac2SNirmoy Das 
777*98d28ac2SNirmoy Das 	debugfs_create_file("amdgpu_fence_info", 0444, root, adev,
778*98d28ac2SNirmoy Das 			    &amdgpu_debugfs_fence_info_fops);
779*98d28ac2SNirmoy Das 
780*98d28ac2SNirmoy Das 	if (!amdgpu_sriov_vf(adev))
781*98d28ac2SNirmoy Das 		debugfs_create_file("amdgpu_gpu_recover", 0444, root, adev,
782*98d28ac2SNirmoy Das 				    &amdgpu_debugfs_gpu_recover_fops);
783d38ceaf9SAlex Deucher #endif
784d38ceaf9SAlex Deucher }
785d38ceaf9SAlex Deucher 
786