1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher  * Copyright 2008 Advanced Micro Devices, Inc.
3d38ceaf9SAlex Deucher  * Copyright 2008 Red Hat Inc.
4d38ceaf9SAlex Deucher  * Copyright 2009 Jerome Glisse.
5d38ceaf9SAlex Deucher  *
6d38ceaf9SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
7d38ceaf9SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
8d38ceaf9SAlex Deucher  * to deal in the Software without restriction, including without limitation
9d38ceaf9SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10d38ceaf9SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
11d38ceaf9SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
12d38ceaf9SAlex Deucher  *
13d38ceaf9SAlex Deucher  * The above copyright notice and this permission notice shall be included in
14d38ceaf9SAlex Deucher  * all copies or substantial portions of the Software.
15d38ceaf9SAlex Deucher  *
16d38ceaf9SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d38ceaf9SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d38ceaf9SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19d38ceaf9SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20d38ceaf9SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21d38ceaf9SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22d38ceaf9SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
23d38ceaf9SAlex Deucher  *
24d38ceaf9SAlex Deucher  * Authors: Dave Airlie
25d38ceaf9SAlex Deucher  *          Alex Deucher
26d38ceaf9SAlex Deucher  *          Jerome Glisse
27d38ceaf9SAlex Deucher  *          Christian König
28d38ceaf9SAlex Deucher  */
29d38ceaf9SAlex Deucher #include <linux/seq_file.h>
30d38ceaf9SAlex Deucher #include <linux/slab.h>
31fdf2f6c5SSam Ravnborg 
32d38ceaf9SAlex Deucher #include <drm/amdgpu_drm.h>
33fdf2f6c5SSam Ravnborg 
34d38ceaf9SAlex Deucher #include "amdgpu.h"
35d38ceaf9SAlex Deucher #include "atom.h"
3665f7260bSAndrey Grodzovsky #include "amdgpu_trace.h"
37d38ceaf9SAlex Deucher 
38bb7ad55bSChunming Zhou #define AMDGPU_IB_TEST_TIMEOUT	msecs_to_jiffies(1000)
39d4162c61Sshaoyunl #define AMDGPU_IB_TEST_GFX_XGMI_TIMEOUT	msecs_to_jiffies(2000)
40bbec97aaSChristian König 
41d38ceaf9SAlex Deucher /*
42d38ceaf9SAlex Deucher  * IB
43d38ceaf9SAlex Deucher  * IBs (Indirect Buffers) and areas of GPU accessible memory where
44d38ceaf9SAlex Deucher  * commands are stored.  You can put a pointer to the IB in the
45d38ceaf9SAlex Deucher  * command ring and the hw will fetch the commands from the IB
46d38ceaf9SAlex Deucher  * and execute them.  Generally userspace acceleration drivers
47d38ceaf9SAlex Deucher  * produce command buffers which are send to the kernel and
48d38ceaf9SAlex Deucher  * put in IBs for execution by the requested ring.
49d38ceaf9SAlex Deucher  */
50d38ceaf9SAlex Deucher 
51d38ceaf9SAlex Deucher /**
52d38ceaf9SAlex Deucher  * amdgpu_ib_get - request an IB (Indirect Buffer)
53d38ceaf9SAlex Deucher  *
54ad8eb024SLee Jones  * @adev: amdgpu_device pointer
55ad8eb024SLee Jones  * @vm: amdgpu_vm pointer
56d38ceaf9SAlex Deucher  * @size: requested IB size
57ad8eb024SLee Jones  * @pool_type: IB pool type (delayed, immediate, direct)
58d38ceaf9SAlex Deucher  * @ib: IB object returned
59d38ceaf9SAlex Deucher  *
60d38ceaf9SAlex Deucher  * Request an IB (all asics).  IBs are allocated using the
61d38ceaf9SAlex Deucher  * suballocator.
62d38ceaf9SAlex Deucher  * Returns 0 on success, error on failure.
63d38ceaf9SAlex Deucher  */
amdgpu_ib_get(struct amdgpu_device * adev,struct amdgpu_vm * vm,unsigned int size,enum amdgpu_ib_pool_type pool_type,struct amdgpu_ib * ib)64b07c60c0SChristian König int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm,
65fc8e55f3SSrinivasan Shanmugam 		  unsigned int size, enum amdgpu_ib_pool_type pool_type,
66c8e42d57Sxinhui pan 		  struct amdgpu_ib *ib)
67d38ceaf9SAlex Deucher {
68d38ceaf9SAlex Deucher 	int r;
69d38ceaf9SAlex Deucher 
70d38ceaf9SAlex Deucher 	if (size) {
719ecefb19SChristian König 		r = amdgpu_sa_bo_new(&adev->ib_pools[pool_type],
72c103a23fSMaarten Lankhorst 				     &ib->sa_bo, size);
73d38ceaf9SAlex Deucher 		if (r) {
74d38ceaf9SAlex Deucher 			dev_err(adev->dev, "failed to get a new IB (%d)\n", r);
75d38ceaf9SAlex Deucher 			return r;
76d38ceaf9SAlex Deucher 		}
77d38ceaf9SAlex Deucher 
78d38ceaf9SAlex Deucher 		ib->ptr = amdgpu_sa_bo_cpu_addr(ib->sa_bo);
795c88e3b8SJinzhou Su 		/* flush the cache before commit the IB */
805c88e3b8SJinzhou Su 		ib->flags = AMDGPU_IB_FLAG_EMIT_MEM_SYNC;
81d38ceaf9SAlex Deucher 
82d38ceaf9SAlex Deucher 		if (!vm)
83d38ceaf9SAlex Deucher 			ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo);
84d38ceaf9SAlex Deucher 	}
85d38ceaf9SAlex Deucher 
86d38ceaf9SAlex Deucher 	return 0;
87d38ceaf9SAlex Deucher }
88d38ceaf9SAlex Deucher 
89d38ceaf9SAlex Deucher /**
90d38ceaf9SAlex Deucher  * amdgpu_ib_free - free an IB (Indirect Buffer)
91d38ceaf9SAlex Deucher  *
92d38ceaf9SAlex Deucher  * @ib: IB object to free
93cc55c45dSMonk Liu  * @f: the fence SA bo need wait on for the ib alloation
94d38ceaf9SAlex Deucher  *
95d38ceaf9SAlex Deucher  * Free an IB (all asics).
96d38ceaf9SAlex Deucher  */
amdgpu_ib_free(struct amdgpu_ib * ib,struct dma_fence * f)970014952bSPierre-Eric Pelloux-Prayer void amdgpu_ib_free(struct amdgpu_ib *ib, struct dma_fence *f)
98d38ceaf9SAlex Deucher {
990014952bSPierre-Eric Pelloux-Prayer 	amdgpu_sa_bo_free(&ib->sa_bo, f);
100d38ceaf9SAlex Deucher }
101d38ceaf9SAlex Deucher 
102d38ceaf9SAlex Deucher /**
103d38ceaf9SAlex Deucher  * amdgpu_ib_schedule - schedule an IB (Indirect Buffer) on the ring
104d38ceaf9SAlex Deucher  *
105ad8eb024SLee Jones  * @ring: ring index the IB is associated with
106d38ceaf9SAlex Deucher  * @num_ibs: number of IBs to schedule
107d38ceaf9SAlex Deucher  * @ibs: IB objects to schedule
1087ad0c80cSLee Jones  * @job: job to schedule
109ec72b800SChristian König  * @f: fence created during this submission
110d38ceaf9SAlex Deucher  *
111d38ceaf9SAlex Deucher  * Schedule an IB on the associated ring (all asics).
112d38ceaf9SAlex Deucher  * Returns 0 on success, error on failure.
113d38ceaf9SAlex Deucher  *
114d38ceaf9SAlex Deucher  * On SI, there are two parallel engines fed from the primary ring,
115d38ceaf9SAlex Deucher  * the CE (Constant Engine) and the DE (Drawing Engine).  Since
116d38ceaf9SAlex Deucher  * resource descriptors have moved to memory, the CE allows you to
117d38ceaf9SAlex Deucher  * prime the caches while the DE is updating register state so that
118d38ceaf9SAlex Deucher  * the resource descriptors will be already in cache when the draw is
119d38ceaf9SAlex Deucher  * processed.  To accomplish this, the userspace driver submits two
120d38ceaf9SAlex Deucher  * IBs, one for the CE and one for the DE.  If there is a CE IB (called
121d38ceaf9SAlex Deucher  * a CONST_IB), it will be put on the ring prior to the DE IB.  Prior
122d38ceaf9SAlex Deucher  * to SI there was just a DE IB.
123d38ceaf9SAlex Deucher  */
amdgpu_ib_schedule(struct amdgpu_ring * ring,unsigned int num_ibs,struct amdgpu_ib * ibs,struct amdgpu_job * job,struct dma_fence ** f)124fc8e55f3SSrinivasan Shanmugam int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
12550ddc75eSJunwei Zhang 		       struct amdgpu_ib *ibs, struct amdgpu_job *job,
12650ddc75eSJunwei Zhang 		       struct dma_fence **f)
127d38ceaf9SAlex Deucher {
128b07c60c0SChristian König 	struct amdgpu_device *adev = ring->adev;
129d38ceaf9SAlex Deucher 	struct amdgpu_ib *ib = &ibs[0];
130b9bf33d5SChunming Zhou 	struct dma_fence *tmp = NULL;
1317d9c70d2SJiansong Chen 	bool need_ctx_switch;
13292f25098SChristian König 	struct amdgpu_vm *vm;
1333aecd24cSMonk Liu 	uint64_t fence_ctx;
1349a9db6efSAlex Deucher 	uint32_t status = 0, alloc_size;
135fc8e55f3SSrinivasan Shanmugam 	unsigned int fence_flags = 0;
136ac928705SChristian König 	bool secure, init_shadow;
137ac928705SChristian König 	u64 shadow_va, csa_va, gds_va;
138ac928705SChristian König 	int vmid = AMDGPU_JOB_GET_VMID(job);
139c68cbbfdSChristian König 	bool need_pipe_sync = false;
140c68cbbfdSChristian König 	unsigned int cond_exec;
14103ccf481SMonk Liu 
142fc8e55f3SSrinivasan Shanmugam 	unsigned int i;
143d38ceaf9SAlex Deucher 	int r = 0;
144d38ceaf9SAlex Deucher 
145d38ceaf9SAlex Deucher 	if (num_ibs == 0)
146d38ceaf9SAlex Deucher 		return -EINVAL;
147d38ceaf9SAlex Deucher 
14892f25098SChristian König 	/* ring tests don't use a job */
14992f25098SChristian König 	if (job) {
150c5637837SMonk Liu 		vm = job->vm;
151dcafbd50SFelix Kuehling 		fence_ctx = job->base.s_fence ?
152dcafbd50SFelix Kuehling 			job->base.s_fence->scheduled.context : 0;
153ac928705SChristian König 		shadow_va = job->shadow_va;
154ac928705SChristian König 		csa_va = job->csa_va;
155ac928705SChristian König 		gds_va = job->gds_va;
156ac928705SChristian König 		init_shadow = job->init_shadow;
15792f25098SChristian König 	} else {
15892f25098SChristian König 		vm = NULL;
1593aecd24cSMonk Liu 		fence_ctx = 0;
160ac928705SChristian König 		shadow_va = 0;
161ac928705SChristian König 		csa_va = 0;
162ac928705SChristian König 		gds_va = 0;
163ac928705SChristian König 		init_shadow = false;
16492f25098SChristian König 	}
165d919ad49SChristian König 
166f89703f5SJack Xiao 	if (!ring->sched.ready && !ring->is_mes_queue) {
1671b583649STom St Denis 		dev_err(adev->dev, "couldn't schedule ib on ring <%s>\n", ring->name);
168d38ceaf9SAlex Deucher 		return -EINVAL;
169d38ceaf9SAlex Deucher 	}
170be86c606SChunming Zhou 
171f89703f5SJack Xiao 	if (vm && !job->vmid && !ring->is_mes_queue) {
1728d0a7ceaSChristian König 		dev_err(adev->dev, "VM IB without ID\n");
1738d0a7ceaSChristian König 		return -EINVAL;
1748d0a7ceaSChristian König 	}
1758d0a7ceaSChristian König 
176b33f9d70SAlex Deucher 	if ((ib->flags & AMDGPU_IB_FLAGS_SECURE) &&
1778c0f11ffSLang Yu 	    (!ring->funcs->secure_submission_supported)) {
1788c0f11ffSLang Yu 		dev_err(adev->dev, "secure submissions not supported on ring <%s>\n", ring->name);
179b33f9d70SAlex Deucher 		return -EINVAL;
180b33f9d70SAlex Deucher 	}
181b33f9d70SAlex Deucher 
182e12f3d7aSChristian König 	alloc_size = ring->funcs->emit_frame_size + num_ibs *
183e12f3d7aSChristian König 		ring->funcs->emit_ib_size;
1849a9db6efSAlex Deucher 
1859a9db6efSAlex Deucher 	r = amdgpu_ring_alloc(ring, alloc_size);
186d38ceaf9SAlex Deucher 	if (r) {
187d38ceaf9SAlex Deucher 		dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
188d38ceaf9SAlex Deucher 		return r;
189d38ceaf9SAlex Deucher 	}
190df83d1ebSChunming Zhou 
1914f0ecd36SEmily Deng 	need_ctx_switch = ring->current_ctx != fence_ctx;
192df83d1ebSChunming Zhou 	if (ring->funcs->emit_pipeline_sync && job &&
1931b2d5edaSChristian König 	    ((tmp = amdgpu_sync_get_fence(&job->explicit_sync)) ||
194def59436SChristian König 	     need_ctx_switch || amdgpu_vm_need_pipeline_sync(ring, job))) {
195def59436SChristian König 
1968fdf074fSMonk Liu 		need_pipe_sync = true;
19765f7260bSAndrey Grodzovsky 
19865f7260bSAndrey Grodzovsky 		if (tmp)
19965f7260bSAndrey Grodzovsky 			trace_amdgpu_ib_pipe_sync(job, tmp);
20065f7260bSAndrey Grodzovsky 
201df83d1ebSChunming Zhou 		dma_fence_put(tmp);
202df83d1ebSChunming Zhou 	}
203d38ceaf9SAlex Deucher 
20443c8546bSAndrey Grodzovsky 	if ((ib->flags & AMDGPU_IB_FLAG_EMIT_MEM_SYNC) && ring->funcs->emit_mem_sync)
20543c8546bSAndrey Grodzovsky 		ring->funcs->emit_mem_sync(ring);
20643c8546bSAndrey Grodzovsky 
20722e4f315SNirmoy Das 	if (ring->funcs->emit_wave_limit &&
20822e4f315SNirmoy Das 	    ring->hw_prio == AMDGPU_GFX_PIPE_PRIO_HIGH)
20922e4f315SNirmoy Das 		ring->funcs->emit_wave_limit(ring, true);
21022e4f315SNirmoy Das 
211ef44f854SLeo Liu 	if (ring->funcs->insert_start)
212ef44f854SLeo Liu 		ring->funcs->insert_start(ring);
213ef44f854SLeo Liu 
214df264f9eSChristian König 	if (job) {
2158fdf074fSMonk Liu 		r = amdgpu_vm_flush(ring, job, need_pipe_sync);
21641d9eb2cSChristian König 		if (r) {
21741d9eb2cSChristian König 			amdgpu_ring_undo(ring);
21841d9eb2cSChristian König 			return r;
21941d9eb2cSChristian König 		}
220794ff571SMonk Liu 	}
221d38ceaf9SAlex Deucher 
2223f4c175dSJiadong.Zhu 	amdgpu_ring_ib_begin(ring);
223ac928705SChristian König 
22438be7796SAlex Deucher 	if (ring->funcs->emit_gfx_shadow)
225ac928705SChristian König 		amdgpu_ring_emit_gfx_shadow(ring, shadow_va, csa_va, gds_va,
226ac928705SChristian König 					    init_shadow, vmid);
227ac928705SChristian König 
22838be7796SAlex Deucher 	if (ring->funcs->init_cond_exec)
229c68cbbfdSChristian König 		cond_exec = amdgpu_ring_init_cond_exec(ring,
230c68cbbfdSChristian König 						       ring->cond_exe_gpu_addr);
231e9d672b2SMonk Liu 
232810085ddSEric Huang 	amdgpu_device_flush_hdp(adev, ring);
233d2edb07bSChristian König 
234753ad49cSMonk Liu 	if (need_ctx_switch)
235753ad49cSMonk Liu 		status |= AMDGPU_HAVE_CTX_SWITCH;
2367e6bf80fSMonk Liu 
237c4c905ecSJack Xiao 	if (job && ring->funcs->emit_cntxcntl) {
238c4c905ecSJack Xiao 		status |= job->preamble_status;
239d8780dc7SJack Xiao 		status |= job->preemption_status;
2400bb5d5b0SLuben Tuikov 		amdgpu_ring_emit_cntxcntl(ring, status);
241753ad49cSMonk Liu 	}
242753ad49cSMonk Liu 
243f77c9affSHuang Rui 	/* Setup initial TMZiness and send it off.
244f77c9affSHuang Rui 	 */
2450bb5d5b0SLuben Tuikov 	secure = false;
246f77c9affSHuang Rui 	if (job && ring->funcs->emit_frame_cntl) {
247f77c9affSHuang Rui 		secure = ib->flags & AMDGPU_IB_FLAGS_SECURE;
248f77c9affSHuang Rui 		amdgpu_ring_emit_frame_cntl(ring, true, secure);
249f77c9affSHuang Rui 	}
250f77c9affSHuang Rui 
251d38ceaf9SAlex Deucher 	for (i = 0; i < num_ibs; ++i) {
252f153d286SChristian König 		ib = &ibs[i];
2539f8fb5a2SChristian König 
254f77c9affSHuang Rui 		if (job && ring->funcs->emit_frame_cntl) {
255f77c9affSHuang Rui 			if (secure != !!(ib->flags & AMDGPU_IB_FLAGS_SECURE)) {
256f77c9affSHuang Rui 				amdgpu_ring_emit_frame_cntl(ring, false, secure);
257f77c9affSHuang Rui 				secure = !secure;
258f77c9affSHuang Rui 				amdgpu_ring_emit_frame_cntl(ring, true, secure);
2590bb5d5b0SLuben Tuikov 			}
2600bb5d5b0SLuben Tuikov 		}
2610bb5d5b0SLuben Tuikov 
262c4c905ecSJack Xiao 		amdgpu_ring_emit_ib(ring, job, ib, status);
263c4c905ecSJack Xiao 		status &= ~AMDGPU_HAVE_CTX_SWITCH;
264d38ceaf9SAlex Deucher 	}
265d38ceaf9SAlex Deucher 
266f77c9affSHuang Rui 	if (job && ring->funcs->emit_frame_cntl)
267f77c9affSHuang Rui 		amdgpu_ring_emit_frame_cntl(ring, false, secure);
2683b4d68e9SMonk Liu 
269810085ddSEric Huang 	amdgpu_device_invalidate_hdp(adev, ring);
27011afbde8SChunming Zhou 
271d240cd9eSMarek Olšák 	if (ib->flags & AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE)
272d240cd9eSMarek Olšák 		fence_flags |= AMDGPU_FENCE_FLAG_TC_WB_ONLY;
273d240cd9eSMarek Olšák 
2749fc15f5fSNicolai Hähnle 	/* wrap the last IB with fence */
2759fc15f5fSNicolai Hähnle 	if (job && job->uf_addr) {
2769fc15f5fSNicolai Hähnle 		amdgpu_ring_emit_fence(ring, job->uf_addr, job->uf_sequence,
2779fc15f5fSNicolai Hähnle 				       fence_flags | AMDGPU_FENCE_FLAG_64BIT);
2789fc15f5fSNicolai Hähnle 	}
2799fc15f5fSNicolai Hähnle 
280c68cbbfdSChristian König 	if (ring->funcs->emit_gfx_shadow && ring->funcs->init_cond_exec) {
281ac928705SChristian König 		amdgpu_ring_emit_gfx_shadow(ring, 0, 0, 0, false, 0);
282c68cbbfdSChristian König 		amdgpu_ring_init_cond_exec(ring, ring->cond_exe_gpu_addr);
283ac928705SChristian König 	}
284ac928705SChristian König 
285c530b02fSJack Zhang 	r = amdgpu_fence_emit(ring, f, job, fence_flags);
286d38ceaf9SAlex Deucher 	if (r) {
287d38ceaf9SAlex Deucher 		dev_err(adev->dev, "failed to emit fence (%d)\n", r);
288c4f46f22SChristian König 		if (job && job->vmid)
2890530553bSLe Ma 			amdgpu_vmid_reset(adev, ring->vm_hub, job->vmid);
290a27de35cSChristian König 		amdgpu_ring_undo(ring);
291d38ceaf9SAlex Deucher 		return r;
292d38ceaf9SAlex Deucher 	}
293d38ceaf9SAlex Deucher 
294135d4735SLeo Liu 	if (ring->funcs->insert_end)
295135d4735SLeo Liu 		ring->funcs->insert_end(ring);
296135d4735SLeo Liu 
297c68cbbfdSChristian König 	amdgpu_ring_patch_cond_exec(ring, cond_exec);
29803ccf481SMonk Liu 
2993aecd24cSMonk Liu 	ring->current_ctx = fence_ctx;
300*b5290939SLin.Cao 	if (job && ring->funcs->emit_switch_buffer)
301c2167a65SMonk Liu 		amdgpu_ring_emit_switch_buffer(ring);
30222e4f315SNirmoy Das 
30322e4f315SNirmoy Das 	if (ring->funcs->emit_wave_limit &&
30422e4f315SNirmoy Das 	    ring->hw_prio == AMDGPU_GFX_PIPE_PRIO_HIGH)
30522e4f315SNirmoy Das 		ring->funcs->emit_wave_limit(ring, false);
30622e4f315SNirmoy Das 
3073f4c175dSJiadong.Zhu 	amdgpu_ring_ib_end(ring);
308a27de35cSChristian König 	amdgpu_ring_commit(ring);
309d38ceaf9SAlex Deucher 	return 0;
310d38ceaf9SAlex Deucher }
311d38ceaf9SAlex Deucher 
312d38ceaf9SAlex Deucher /**
313d38ceaf9SAlex Deucher  * amdgpu_ib_pool_init - Init the IB (Indirect Buffer) pool
314d38ceaf9SAlex Deucher  *
315d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
316d38ceaf9SAlex Deucher  *
317d38ceaf9SAlex Deucher  * Initialize the suballocator to manage a pool of memory
318d38ceaf9SAlex Deucher  * for use as IBs (all asics).
319d38ceaf9SAlex Deucher  * Returns 0 on success, error on failure.
320d38ceaf9SAlex Deucher  */
amdgpu_ib_pool_init(struct amdgpu_device * adev)321d38ceaf9SAlex Deucher int amdgpu_ib_pool_init(struct amdgpu_device *adev)
322d38ceaf9SAlex Deucher {
3239ecefb19SChristian König 	int r, i;
324d38ceaf9SAlex Deucher 
3259ecefb19SChristian König 	if (adev->ib_pool_ready)
326d38ceaf9SAlex Deucher 		return 0;
3279ecefb19SChristian König 
328c8e42d57Sxinhui pan 	for (i = 0; i < AMDGPU_IB_POOL_MAX; i++) {
3299ecefb19SChristian König 		r = amdgpu_sa_bo_manager_init(adev, &adev->ib_pools[i],
330c103a23fSMaarten Lankhorst 					      AMDGPU_IB_POOL_SIZE, 256,
331d38ceaf9SAlex Deucher 					      AMDGPU_GEM_DOMAIN_GTT);
3329ecefb19SChristian König 		if (r)
3339ecefb19SChristian König 			goto error;
334c8e42d57Sxinhui pan 	}
335d38ceaf9SAlex Deucher 	adev->ib_pool_ready = true;
33615997544SAlex Deucher 
337d38ceaf9SAlex Deucher 	return 0;
3389ecefb19SChristian König 
3399ecefb19SChristian König error:
3409ecefb19SChristian König 	while (i--)
3419ecefb19SChristian König 		amdgpu_sa_bo_manager_fini(adev, &adev->ib_pools[i]);
3429ecefb19SChristian König 	return r;
343d38ceaf9SAlex Deucher }
344d38ceaf9SAlex Deucher 
345d38ceaf9SAlex Deucher /**
346d38ceaf9SAlex Deucher  * amdgpu_ib_pool_fini - Free the IB (Indirect Buffer) pool
347d38ceaf9SAlex Deucher  *
348d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
349d38ceaf9SAlex Deucher  *
350d38ceaf9SAlex Deucher  * Tear down the suballocator managing the pool of memory
351d38ceaf9SAlex Deucher  * for use as IBs (all asics).
352d38ceaf9SAlex Deucher  */
amdgpu_ib_pool_fini(struct amdgpu_device * adev)353d38ceaf9SAlex Deucher void amdgpu_ib_pool_fini(struct amdgpu_device *adev)
354d38ceaf9SAlex Deucher {
355c8e42d57Sxinhui pan 	int i;
356c8e42d57Sxinhui pan 
3579ecefb19SChristian König 	if (!adev->ib_pool_ready)
3589ecefb19SChristian König 		return;
3599ecefb19SChristian König 
360c8e42d57Sxinhui pan 	for (i = 0; i < AMDGPU_IB_POOL_MAX; i++)
3619ecefb19SChristian König 		amdgpu_sa_bo_manager_fini(adev, &adev->ib_pools[i]);
362d38ceaf9SAlex Deucher 	adev->ib_pool_ready = false;
363d38ceaf9SAlex Deucher }
364d38ceaf9SAlex Deucher 
365d38ceaf9SAlex Deucher /**
366d38ceaf9SAlex Deucher  * amdgpu_ib_ring_tests - test IBs on the rings
367d38ceaf9SAlex Deucher  *
368d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
369d38ceaf9SAlex Deucher  *
370d38ceaf9SAlex Deucher  * Test an IB (Indirect Buffer) on each ring.
371d38ceaf9SAlex Deucher  * If the test fails, disable the ring.
372d38ceaf9SAlex Deucher  * Returns 0 on success, error if the primary GFX ring
373d38ceaf9SAlex Deucher  * IB test fails.
374d38ceaf9SAlex Deucher  */
amdgpu_ib_ring_tests(struct amdgpu_device * adev)375d38ceaf9SAlex Deucher int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
376d38ceaf9SAlex Deucher {
377dbf79765SMonk Liu 	long tmo_gfx, tmo_mm;
3789ecefb19SChristian König 	int r, ret = 0;
379fc8e55f3SSrinivasan Shanmugam 	unsigned int i;
380dbf79765SMonk Liu 
381dbf79765SMonk Liu 	tmo_mm = tmo_gfx = AMDGPU_IB_TEST_TIMEOUT;
382dbf79765SMonk Liu 	if (amdgpu_sriov_vf(adev)) {
383dbf79765SMonk Liu 		/* for MM engines in hypervisor side they are not scheduled together
384dbf79765SMonk Liu 		 * with CP and SDMA engines, so even in exclusive mode MM engine could
385dbf79765SMonk Liu 		 * still running on other VF thus the IB TEST TIMEOUT for MM engines
386dbf79765SMonk Liu 		 * under SR-IOV should be set to a long time. 8 sec should be enough
387dbf79765SMonk Liu 		 * for the MM comes back to this VF.
388dbf79765SMonk Liu 		 */
389dbf79765SMonk Liu 		tmo_mm = 8 * AMDGPU_IB_TEST_TIMEOUT;
390dbf79765SMonk Liu 	}
391dbf79765SMonk Liu 
392dbf79765SMonk Liu 	if (amdgpu_sriov_runtime(adev)) {
393dbf79765SMonk Liu 		/* for CP & SDMA engines since they are scheduled together so
394dbf79765SMonk Liu 		 * need to make the timeout width enough to cover the time
395dbf79765SMonk Liu 		 * cost waiting for it coming back under RUNTIME only
396dbf79765SMonk Liu 		 */
397dbf79765SMonk Liu 		tmo_gfx = 8 * AMDGPU_IB_TEST_TIMEOUT;
398d4162c61Sshaoyunl 	} else if (adev->gmc.xgmi.hive_id) {
399d4162c61Sshaoyunl 		tmo_gfx = AMDGPU_IB_TEST_GFX_XGMI_TIMEOUT;
400dbf79765SMonk Liu 	}
401d38ceaf9SAlex Deucher 
402af70a471SChristian König 	for (i = 0; i < adev->num_rings; ++i) {
403d38ceaf9SAlex Deucher 		struct amdgpu_ring *ring = adev->rings[i];
404dbf79765SMonk Liu 		long tmo;
405d38ceaf9SAlex Deucher 
406315fed03SChristian König 		/* KIQ rings don't have an IB test because we never submit IBs
407315fed03SChristian König 		 * to them and they have no interrupt support.
408158b594aSPratik Vishwakarma 		 */
409315fed03SChristian König 		if (!ring->sched.ready || !ring->funcs->test_ib)
410158b594aSPratik Vishwakarma 			continue;
411158b594aSPratik Vishwakarma 
4129d3bccdcSJack Xiao 		if (adev->enable_mes &&
4139d3bccdcSJack Xiao 		    ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
4149d3bccdcSJack Xiao 			continue;
4159d3bccdcSJack Xiao 
416dbf79765SMonk Liu 		/* MM engine need more time */
417dbf79765SMonk Liu 		if (ring->funcs->type == AMDGPU_RING_TYPE_UVD ||
418dbf79765SMonk Liu 			ring->funcs->type == AMDGPU_RING_TYPE_VCE ||
419dbf79765SMonk Liu 			ring->funcs->type == AMDGPU_RING_TYPE_UVD_ENC ||
420dbf79765SMonk Liu 			ring->funcs->type == AMDGPU_RING_TYPE_VCN_DEC ||
4215b2329b6SBoyuan Zhang 			ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC ||
4225b2329b6SBoyuan Zhang 			ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG)
423dbf79765SMonk Liu 			tmo = tmo_mm;
424dbf79765SMonk Liu 		else
425dbf79765SMonk Liu 			tmo = tmo_gfx;
426dbf79765SMonk Liu 
427dbf79765SMonk Liu 		r = amdgpu_ring_test_ib(ring, tmo);
428af70a471SChristian König 		if (!r) {
429af70a471SChristian König 			DRM_DEV_DEBUG(adev->dev, "ib test on %s succeeded\n",
430af70a471SChristian König 				      ring->name);
431af70a471SChristian König 			continue;
432af70a471SChristian König 		}
433af70a471SChristian König 
434c66ed765SAndrey Grodzovsky 		ring->sched.ready = false;
435af70a471SChristian König 		DRM_DEV_ERROR(adev->dev, "IB test failed on %s (%d).\n",
436af70a471SChristian König 			  ring->name, r);
437d38ceaf9SAlex Deucher 
438d38ceaf9SAlex Deucher 		if (ring == &adev->gfx.gfx_ring[0]) {
439d38ceaf9SAlex Deucher 			/* oh, oh, that's really bad */
440d38ceaf9SAlex Deucher 			adev->accel_working = false;
441d38ceaf9SAlex Deucher 			return r;
442d38ceaf9SAlex Deucher 
443d38ceaf9SAlex Deucher 		} else {
4441f703e66SChunming Zhou 			ret = r;
445d38ceaf9SAlex Deucher 		}
446d38ceaf9SAlex Deucher 	}
4471f703e66SChunming Zhou 	return ret;
448d38ceaf9SAlex Deucher }
449d38ceaf9SAlex Deucher 
450d38ceaf9SAlex Deucher /*
451d38ceaf9SAlex Deucher  * Debugfs info
452d38ceaf9SAlex Deucher  */
453d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
454d38ceaf9SAlex Deucher 
amdgpu_debugfs_sa_info_show(struct seq_file * m,void * unused)45598d28ac2SNirmoy Das static int amdgpu_debugfs_sa_info_show(struct seq_file *m, void *unused)
456d38ceaf9SAlex Deucher {
457109b4d8cSSu Hui 	struct amdgpu_device *adev = m->private;
458d38ceaf9SAlex Deucher 
459fc8e55f3SSrinivasan Shanmugam 	seq_puts(m, "--------------------- DELAYED ---------------------\n");
4609ecefb19SChristian König 	amdgpu_sa_bo_dump_debug_info(&adev->ib_pools[AMDGPU_IB_POOL_DELAYED],
4619ecefb19SChristian König 				     m);
462fc8e55f3SSrinivasan Shanmugam 	seq_puts(m, "-------------------- IMMEDIATE --------------------\n");
4639ecefb19SChristian König 	amdgpu_sa_bo_dump_debug_info(&adev->ib_pools[AMDGPU_IB_POOL_IMMEDIATE],
4649ecefb19SChristian König 				     m);
465fc8e55f3SSrinivasan Shanmugam 	seq_puts(m, "--------------------- DIRECT ----------------------\n");
4669ecefb19SChristian König 	amdgpu_sa_bo_dump_debug_info(&adev->ib_pools[AMDGPU_IB_POOL_DIRECT], m);
467d38ceaf9SAlex Deucher 
468d38ceaf9SAlex Deucher 	return 0;
469d38ceaf9SAlex Deucher }
470d38ceaf9SAlex Deucher 
47198d28ac2SNirmoy Das DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_sa_info);
472d38ceaf9SAlex Deucher 
473d38ceaf9SAlex Deucher #endif
474d38ceaf9SAlex Deucher 
amdgpu_debugfs_sa_init(struct amdgpu_device * adev)47598d28ac2SNirmoy Das void amdgpu_debugfs_sa_init(struct amdgpu_device *adev)
476d38ceaf9SAlex Deucher {
477d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
47898d28ac2SNirmoy Das 	struct drm_minor *minor = adev_to_drm(adev)->primary;
47998d28ac2SNirmoy Das 	struct dentry *root = minor->debugfs_root;
48098d28ac2SNirmoy Das 
48198d28ac2SNirmoy Das 	debugfs_create_file("amdgpu_sa_info", 0444, root, adev,
48298d28ac2SNirmoy Das 			    &amdgpu_debugfs_sa_info_fops);
48398d28ac2SNirmoy Das 
484d38ceaf9SAlex Deucher #endif
485d38ceaf9SAlex Deucher }
486