1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2008 Advanced Micro Devices, Inc.
3*4882a593Smuzhiyun * Copyright 2008 Red Hat Inc.
4*4882a593Smuzhiyun * Copyright 2009 Jerome Glisse.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
7*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
8*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
9*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
11*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * The above copyright notice and this permission notice shall be included in
14*4882a593Smuzhiyun * all copies or substantial portions of the Software.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19*4882a593Smuzhiyun * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20*4882a593Smuzhiyun * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21*4882a593Smuzhiyun * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22*4882a593Smuzhiyun * OTHER DEALINGS IN THE SOFTWARE.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * Authors: Dave Airlie
25*4882a593Smuzhiyun * Alex Deucher
26*4882a593Smuzhiyun * Jerome Glisse
27*4882a593Smuzhiyun * Christian König
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun #include <linux/seq_file.h>
30*4882a593Smuzhiyun #include <linux/slab.h>
31*4882a593Smuzhiyun #include <linux/uaccess.h>
32*4882a593Smuzhiyun #include <linux/debugfs.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include <drm/amdgpu_drm.h>
35*4882a593Smuzhiyun #include "amdgpu.h"
36*4882a593Smuzhiyun #include "atom.h"
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /*
39*4882a593Smuzhiyun * Rings
40*4882a593Smuzhiyun * Most engines on the GPU are fed via ring buffers. Ring
41*4882a593Smuzhiyun * buffers are areas of GPU accessible memory that the host
42*4882a593Smuzhiyun * writes commands into and the GPU reads commands out of.
43*4882a593Smuzhiyun * There is a rptr (read pointer) that determines where the
44*4882a593Smuzhiyun * GPU is currently reading, and a wptr (write pointer)
45*4882a593Smuzhiyun * which determines where the host has written. When the
46*4882a593Smuzhiyun * pointers are equal, the ring is idle. When the host
47*4882a593Smuzhiyun * writes commands to the ring buffer, it increments the
48*4882a593Smuzhiyun * wptr. The GPU then starts fetching commands and executes
49*4882a593Smuzhiyun * them until the pointers are equal again.
50*4882a593Smuzhiyun */
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /**
53*4882a593Smuzhiyun * amdgpu_ring_alloc - allocate space on the ring buffer
54*4882a593Smuzhiyun *
55*4882a593Smuzhiyun * @adev: amdgpu_device pointer
56*4882a593Smuzhiyun * @ring: amdgpu_ring structure holding ring information
57*4882a593Smuzhiyun * @ndw: number of dwords to allocate in the ring buffer
58*4882a593Smuzhiyun *
59*4882a593Smuzhiyun * Allocate @ndw dwords in the ring buffer (all asics).
60*4882a593Smuzhiyun * Returns 0 on success, error on failure.
61*4882a593Smuzhiyun */
amdgpu_ring_alloc(struct amdgpu_ring * ring,unsigned ndw)62*4882a593Smuzhiyun int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun /* Align requested size with padding so unlock_commit can
65*4882a593Smuzhiyun * pad safely */
66*4882a593Smuzhiyun ndw = (ndw + ring->funcs->align_mask) & ~ring->funcs->align_mask;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* Make sure we aren't trying to allocate more space
69*4882a593Smuzhiyun * than the maximum for one submission
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun if (WARN_ON_ONCE(ndw > ring->max_dw))
72*4882a593Smuzhiyun return -ENOMEM;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun ring->count_dw = ndw;
75*4882a593Smuzhiyun ring->wptr_old = ring->wptr;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (ring->funcs->begin_use)
78*4882a593Smuzhiyun ring->funcs->begin_use(ring);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun return 0;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /** amdgpu_ring_insert_nop - insert NOP packets
84*4882a593Smuzhiyun *
85*4882a593Smuzhiyun * @ring: amdgpu_ring structure holding ring information
86*4882a593Smuzhiyun * @count: the number of NOP packets to insert
87*4882a593Smuzhiyun *
88*4882a593Smuzhiyun * This is the generic insert_nop function for rings except SDMA
89*4882a593Smuzhiyun */
amdgpu_ring_insert_nop(struct amdgpu_ring * ring,uint32_t count)90*4882a593Smuzhiyun void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun int i;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun for (i = 0; i < count; i++)
95*4882a593Smuzhiyun amdgpu_ring_write(ring, ring->funcs->nop);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /** amdgpu_ring_generic_pad_ib - pad IB with NOP packets
99*4882a593Smuzhiyun *
100*4882a593Smuzhiyun * @ring: amdgpu_ring structure holding ring information
101*4882a593Smuzhiyun * @ib: IB to add NOP packets to
102*4882a593Smuzhiyun *
103*4882a593Smuzhiyun * This is the generic pad_ib function for rings except SDMA
104*4882a593Smuzhiyun */
amdgpu_ring_generic_pad_ib(struct amdgpu_ring * ring,struct amdgpu_ib * ib)105*4882a593Smuzhiyun void amdgpu_ring_generic_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun while (ib->length_dw & ring->funcs->align_mask)
108*4882a593Smuzhiyun ib->ptr[ib->length_dw++] = ring->funcs->nop;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /**
112*4882a593Smuzhiyun * amdgpu_ring_commit - tell the GPU to execute the new
113*4882a593Smuzhiyun * commands on the ring buffer
114*4882a593Smuzhiyun *
115*4882a593Smuzhiyun * @adev: amdgpu_device pointer
116*4882a593Smuzhiyun * @ring: amdgpu_ring structure holding ring information
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun * Update the wptr (write pointer) to tell the GPU to
119*4882a593Smuzhiyun * execute new commands on the ring buffer (all asics).
120*4882a593Smuzhiyun */
amdgpu_ring_commit(struct amdgpu_ring * ring)121*4882a593Smuzhiyun void amdgpu_ring_commit(struct amdgpu_ring *ring)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun uint32_t count;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* We pad to match fetch size */
126*4882a593Smuzhiyun count = ring->funcs->align_mask + 1 -
127*4882a593Smuzhiyun (ring->wptr & ring->funcs->align_mask);
128*4882a593Smuzhiyun count %= ring->funcs->align_mask + 1;
129*4882a593Smuzhiyun ring->funcs->insert_nop(ring, count);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun mb();
132*4882a593Smuzhiyun amdgpu_ring_set_wptr(ring);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (ring->funcs->end_use)
135*4882a593Smuzhiyun ring->funcs->end_use(ring);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /**
139*4882a593Smuzhiyun * amdgpu_ring_undo - reset the wptr
140*4882a593Smuzhiyun *
141*4882a593Smuzhiyun * @ring: amdgpu_ring structure holding ring information
142*4882a593Smuzhiyun *
143*4882a593Smuzhiyun * Reset the driver's copy of the wptr (all asics).
144*4882a593Smuzhiyun */
amdgpu_ring_undo(struct amdgpu_ring * ring)145*4882a593Smuzhiyun void amdgpu_ring_undo(struct amdgpu_ring *ring)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun ring->wptr = ring->wptr_old;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (ring->funcs->end_use)
150*4882a593Smuzhiyun ring->funcs->end_use(ring);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /**
154*4882a593Smuzhiyun * amdgpu_ring_init - init driver ring struct.
155*4882a593Smuzhiyun *
156*4882a593Smuzhiyun * @adev: amdgpu_device pointer
157*4882a593Smuzhiyun * @ring: amdgpu_ring structure holding ring information
158*4882a593Smuzhiyun * @max_ndw: maximum number of dw for ring alloc
159*4882a593Smuzhiyun * @nop: nop packet for this ring
160*4882a593Smuzhiyun *
161*4882a593Smuzhiyun * Initialize the driver information for the selected ring (all asics).
162*4882a593Smuzhiyun * Returns 0 on success, error on failure.
163*4882a593Smuzhiyun */
amdgpu_ring_init(struct amdgpu_device * adev,struct amdgpu_ring * ring,unsigned int max_dw,struct amdgpu_irq_src * irq_src,unsigned int irq_type,unsigned int hw_prio)164*4882a593Smuzhiyun int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
165*4882a593Smuzhiyun unsigned int max_dw, struct amdgpu_irq_src *irq_src,
166*4882a593Smuzhiyun unsigned int irq_type, unsigned int hw_prio)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun int r, i;
169*4882a593Smuzhiyun int sched_hw_submission = amdgpu_sched_hw_submission;
170*4882a593Smuzhiyun u32 *num_sched;
171*4882a593Smuzhiyun u32 hw_ip;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /* Set the hw submission limit higher for KIQ because
174*4882a593Smuzhiyun * it's used for a number of gfx/compute tasks by both
175*4882a593Smuzhiyun * KFD and KGD which may have outstanding fences and
176*4882a593Smuzhiyun * it doesn't really use the gpu scheduler anyway;
177*4882a593Smuzhiyun * KIQ tasks get submitted directly to the ring.
178*4882a593Smuzhiyun */
179*4882a593Smuzhiyun if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
180*4882a593Smuzhiyun sched_hw_submission = max(sched_hw_submission, 256);
181*4882a593Smuzhiyun else if (ring == &adev->sdma.instance[0].page)
182*4882a593Smuzhiyun sched_hw_submission = 256;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (ring->adev == NULL) {
185*4882a593Smuzhiyun if (adev->num_rings >= AMDGPU_MAX_RINGS)
186*4882a593Smuzhiyun return -EINVAL;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun ring->adev = adev;
189*4882a593Smuzhiyun ring->idx = adev->num_rings++;
190*4882a593Smuzhiyun adev->rings[ring->idx] = ring;
191*4882a593Smuzhiyun r = amdgpu_fence_driver_init_ring(ring, sched_hw_submission);
192*4882a593Smuzhiyun if (r)
193*4882a593Smuzhiyun return r;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun r = amdgpu_device_wb_get(adev, &ring->rptr_offs);
197*4882a593Smuzhiyun if (r) {
198*4882a593Smuzhiyun dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
199*4882a593Smuzhiyun return r;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun r = amdgpu_device_wb_get(adev, &ring->wptr_offs);
203*4882a593Smuzhiyun if (r) {
204*4882a593Smuzhiyun dev_err(adev->dev, "(%d) ring wptr_offs wb alloc failed\n", r);
205*4882a593Smuzhiyun return r;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun r = amdgpu_device_wb_get(adev, &ring->fence_offs);
209*4882a593Smuzhiyun if (r) {
210*4882a593Smuzhiyun dev_err(adev->dev, "(%d) ring fence_offs wb alloc failed\n", r);
211*4882a593Smuzhiyun return r;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun r = amdgpu_device_wb_get(adev, &ring->trail_fence_offs);
215*4882a593Smuzhiyun if (r) {
216*4882a593Smuzhiyun dev_err(adev->dev,
217*4882a593Smuzhiyun "(%d) ring trail_fence_offs wb alloc failed\n", r);
218*4882a593Smuzhiyun return r;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun ring->trail_fence_gpu_addr =
221*4882a593Smuzhiyun adev->wb.gpu_addr + (ring->trail_fence_offs * 4);
222*4882a593Smuzhiyun ring->trail_fence_cpu_addr = &adev->wb.wb[ring->trail_fence_offs];
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun r = amdgpu_device_wb_get(adev, &ring->cond_exe_offs);
225*4882a593Smuzhiyun if (r) {
226*4882a593Smuzhiyun dev_err(adev->dev, "(%d) ring cond_exec_polling wb alloc failed\n", r);
227*4882a593Smuzhiyun return r;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun ring->cond_exe_gpu_addr = adev->wb.gpu_addr + (ring->cond_exe_offs * 4);
230*4882a593Smuzhiyun ring->cond_exe_cpu_addr = &adev->wb.wb[ring->cond_exe_offs];
231*4882a593Smuzhiyun /* always set cond_exec_polling to CONTINUE */
232*4882a593Smuzhiyun *ring->cond_exe_cpu_addr = 1;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun r = amdgpu_fence_driver_start_ring(ring, irq_src, irq_type);
235*4882a593Smuzhiyun if (r) {
236*4882a593Smuzhiyun dev_err(adev->dev, "failed initializing fences (%d).\n", r);
237*4882a593Smuzhiyun return r;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun ring->ring_size = roundup_pow_of_two(max_dw * 4 * sched_hw_submission);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun ring->buf_mask = (ring->ring_size / 4) - 1;
243*4882a593Smuzhiyun ring->ptr_mask = ring->funcs->support_64bit_ptrs ?
244*4882a593Smuzhiyun 0xffffffffffffffff : ring->buf_mask;
245*4882a593Smuzhiyun /* Allocate ring buffer */
246*4882a593Smuzhiyun if (ring->ring_obj == NULL) {
247*4882a593Smuzhiyun r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE,
248*4882a593Smuzhiyun AMDGPU_GEM_DOMAIN_GTT,
249*4882a593Smuzhiyun &ring->ring_obj,
250*4882a593Smuzhiyun &ring->gpu_addr,
251*4882a593Smuzhiyun (void **)&ring->ring);
252*4882a593Smuzhiyun if (r) {
253*4882a593Smuzhiyun dev_err(adev->dev, "(%d) ring create failed\n", r);
254*4882a593Smuzhiyun return r;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun amdgpu_ring_clear_ring(ring);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ring->max_dw = max_dw;
260*4882a593Smuzhiyun ring->priority = DRM_SCHED_PRIORITY_NORMAL;
261*4882a593Smuzhiyun mutex_init(&ring->priority_mutex);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (!ring->no_scheduler) {
264*4882a593Smuzhiyun hw_ip = ring->funcs->type;
265*4882a593Smuzhiyun num_sched = &adev->gpu_sched[hw_ip][hw_prio].num_scheds;
266*4882a593Smuzhiyun adev->gpu_sched[hw_ip][hw_prio].sched[(*num_sched)++] =
267*4882a593Smuzhiyun &ring->sched;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; ++i)
271*4882a593Smuzhiyun atomic_set(&ring->num_jobs[i], 0);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /**
277*4882a593Smuzhiyun * amdgpu_ring_fini - tear down the driver ring struct.
278*4882a593Smuzhiyun *
279*4882a593Smuzhiyun * @adev: amdgpu_device pointer
280*4882a593Smuzhiyun * @ring: amdgpu_ring structure holding ring information
281*4882a593Smuzhiyun *
282*4882a593Smuzhiyun * Tear down the driver information for the selected ring (all asics).
283*4882a593Smuzhiyun */
amdgpu_ring_fini(struct amdgpu_ring * ring)284*4882a593Smuzhiyun void amdgpu_ring_fini(struct amdgpu_ring *ring)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun /* Not to finish a ring which is not initialized */
288*4882a593Smuzhiyun if (!(ring->adev) || !(ring->adev->rings[ring->idx]))
289*4882a593Smuzhiyun return;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun ring->sched.ready = false;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun amdgpu_device_wb_free(ring->adev, ring->rptr_offs);
294*4882a593Smuzhiyun amdgpu_device_wb_free(ring->adev, ring->wptr_offs);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun amdgpu_device_wb_free(ring->adev, ring->cond_exe_offs);
297*4882a593Smuzhiyun amdgpu_device_wb_free(ring->adev, ring->fence_offs);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun amdgpu_bo_free_kernel(&ring->ring_obj,
300*4882a593Smuzhiyun &ring->gpu_addr,
301*4882a593Smuzhiyun (void **)&ring->ring);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun dma_fence_put(ring->vmid_wait);
304*4882a593Smuzhiyun ring->vmid_wait = NULL;
305*4882a593Smuzhiyun ring->me = 0;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun ring->adev->rings[ring->idx] = NULL;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /**
311*4882a593Smuzhiyun * amdgpu_ring_emit_reg_write_reg_wait_helper - ring helper
312*4882a593Smuzhiyun *
313*4882a593Smuzhiyun * @adev: amdgpu_device pointer
314*4882a593Smuzhiyun * @reg0: register to write
315*4882a593Smuzhiyun * @reg1: register to wait on
316*4882a593Smuzhiyun * @ref: reference value to write/wait on
317*4882a593Smuzhiyun * @mask: mask to wait on
318*4882a593Smuzhiyun *
319*4882a593Smuzhiyun * Helper for rings that don't support write and wait in a
320*4882a593Smuzhiyun * single oneshot packet.
321*4882a593Smuzhiyun */
amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring * ring,uint32_t reg0,uint32_t reg1,uint32_t ref,uint32_t mask)322*4882a593Smuzhiyun void amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring,
323*4882a593Smuzhiyun uint32_t reg0, uint32_t reg1,
324*4882a593Smuzhiyun uint32_t ref, uint32_t mask)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun amdgpu_ring_emit_wreg(ring, reg0, ref);
327*4882a593Smuzhiyun amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun /**
331*4882a593Smuzhiyun * amdgpu_ring_soft_recovery - try to soft recover a ring lockup
332*4882a593Smuzhiyun *
333*4882a593Smuzhiyun * @ring: ring to try the recovery on
334*4882a593Smuzhiyun * @vmid: VMID we try to get going again
335*4882a593Smuzhiyun * @fence: timedout fence
336*4882a593Smuzhiyun *
337*4882a593Smuzhiyun * Tries to get a ring proceeding again when it is stuck.
338*4882a593Smuzhiyun */
amdgpu_ring_soft_recovery(struct amdgpu_ring * ring,unsigned int vmid,struct dma_fence * fence)339*4882a593Smuzhiyun bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid,
340*4882a593Smuzhiyun struct dma_fence *fence)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun ktime_t deadline = ktime_add_us(ktime_get(), 10000);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (amdgpu_sriov_vf(ring->adev) || !ring->funcs->soft_recovery || !fence)
345*4882a593Smuzhiyun return false;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun atomic_inc(&ring->adev->gpu_reset_counter);
348*4882a593Smuzhiyun while (!dma_fence_is_signaled(fence) &&
349*4882a593Smuzhiyun ktime_to_ns(ktime_sub(deadline, ktime_get())) > 0)
350*4882a593Smuzhiyun ring->funcs->soft_recovery(ring, vmid);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun return dma_fence_is_signaled(fence);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /*
356*4882a593Smuzhiyun * Debugfs info
357*4882a593Smuzhiyun */
358*4882a593Smuzhiyun #if defined(CONFIG_DEBUG_FS)
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* Layout of file is 12 bytes consisting of
361*4882a593Smuzhiyun * - rptr
362*4882a593Smuzhiyun * - wptr
363*4882a593Smuzhiyun * - driver's copy of wptr
364*4882a593Smuzhiyun *
365*4882a593Smuzhiyun * followed by n-words of ring data
366*4882a593Smuzhiyun */
amdgpu_debugfs_ring_read(struct file * f,char __user * buf,size_t size,loff_t * pos)367*4882a593Smuzhiyun static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
368*4882a593Smuzhiyun size_t size, loff_t *pos)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun struct amdgpu_ring *ring = file_inode(f)->i_private;
371*4882a593Smuzhiyun int r, i;
372*4882a593Smuzhiyun uint32_t value, result, early[3];
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (*pos & 3 || size & 3)
375*4882a593Smuzhiyun return -EINVAL;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun result = 0;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun if (*pos < 12) {
380*4882a593Smuzhiyun early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask;
381*4882a593Smuzhiyun early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask;
382*4882a593Smuzhiyun early[2] = ring->wptr & ring->buf_mask;
383*4882a593Smuzhiyun for (i = *pos / 4; i < 3 && size; i++) {
384*4882a593Smuzhiyun r = put_user(early[i], (uint32_t *)buf);
385*4882a593Smuzhiyun if (r)
386*4882a593Smuzhiyun return r;
387*4882a593Smuzhiyun buf += 4;
388*4882a593Smuzhiyun result += 4;
389*4882a593Smuzhiyun size -= 4;
390*4882a593Smuzhiyun *pos += 4;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun while (size) {
395*4882a593Smuzhiyun if (*pos >= (ring->ring_size + 12))
396*4882a593Smuzhiyun return result;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun value = ring->ring[(*pos - 12)/4];
399*4882a593Smuzhiyun r = put_user(value, (uint32_t*)buf);
400*4882a593Smuzhiyun if (r)
401*4882a593Smuzhiyun return r;
402*4882a593Smuzhiyun buf += 4;
403*4882a593Smuzhiyun result += 4;
404*4882a593Smuzhiyun size -= 4;
405*4882a593Smuzhiyun *pos += 4;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun return result;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun static const struct file_operations amdgpu_debugfs_ring_fops = {
412*4882a593Smuzhiyun .owner = THIS_MODULE,
413*4882a593Smuzhiyun .read = amdgpu_debugfs_ring_read,
414*4882a593Smuzhiyun .llseek = default_llseek
415*4882a593Smuzhiyun };
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun #endif
418*4882a593Smuzhiyun
amdgpu_debugfs_ring_init(struct amdgpu_device * adev,struct amdgpu_ring * ring)419*4882a593Smuzhiyun int amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
420*4882a593Smuzhiyun struct amdgpu_ring *ring)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun #if defined(CONFIG_DEBUG_FS)
423*4882a593Smuzhiyun struct drm_minor *minor = adev_to_drm(adev)->primary;
424*4882a593Smuzhiyun struct dentry *ent, *root = minor->debugfs_root;
425*4882a593Smuzhiyun char name[32];
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun sprintf(name, "amdgpu_ring_%s", ring->name);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun ent = debugfs_create_file(name,
430*4882a593Smuzhiyun S_IFREG | S_IRUGO, root,
431*4882a593Smuzhiyun ring, &amdgpu_debugfs_ring_fops);
432*4882a593Smuzhiyun if (!ent)
433*4882a593Smuzhiyun return -ENOMEM;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun i_size_write(ent->d_inode, ring->ring_size + 12);
436*4882a593Smuzhiyun ring->ent = ent;
437*4882a593Smuzhiyun #endif
438*4882a593Smuzhiyun return 0;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /**
442*4882a593Smuzhiyun * amdgpu_ring_test_helper - tests ring and set sched readiness status
443*4882a593Smuzhiyun *
444*4882a593Smuzhiyun * @ring: ring to try the recovery on
445*4882a593Smuzhiyun *
446*4882a593Smuzhiyun * Tests ring and set sched readiness status
447*4882a593Smuzhiyun *
448*4882a593Smuzhiyun * Returns 0 on success, error on failure.
449*4882a593Smuzhiyun */
amdgpu_ring_test_helper(struct amdgpu_ring * ring)450*4882a593Smuzhiyun int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun struct amdgpu_device *adev = ring->adev;
453*4882a593Smuzhiyun int r;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun r = amdgpu_ring_test_ring(ring);
456*4882a593Smuzhiyun if (r)
457*4882a593Smuzhiyun DRM_DEV_ERROR(adev->dev, "ring %s test failed (%d)\n",
458*4882a593Smuzhiyun ring->name, r);
459*4882a593Smuzhiyun else
460*4882a593Smuzhiyun DRM_DEV_DEBUG(adev->dev, "ring test on %s succeeded\n",
461*4882a593Smuzhiyun ring->name);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun ring->sched.ready = !r;
464*4882a593Smuzhiyun return r;
465*4882a593Smuzhiyun }
466