1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev * Copyright 2008 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev * Copyright 2008 Red Hat Inc.
4b843c749SSergey Zigachev * Copyright 2009 Jerome Glisse.
5b843c749SSergey Zigachev *
6b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a
7b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"),
8b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation
9b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the
11b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions:
12b843c749SSergey Zigachev *
13b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in
14b843c749SSergey Zigachev * all copies or substantial portions of the Software.
15b843c749SSergey Zigachev *
16b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE.
23b843c749SSergey Zigachev *
24b843c749SSergey Zigachev * Authors: Dave Airlie
25b843c749SSergey Zigachev * Alex Deucher
26b843c749SSergey Zigachev * Jerome Glisse
27b843c749SSergey Zigachev * Christian König
28b843c749SSergey Zigachev */
29b843c749SSergey Zigachev #include <linux/seq_file.h>
30b843c749SSergey Zigachev #include <linux/slab.h>
31b843c749SSergey Zigachev #include <linux/debugfs.h>
32b843c749SSergey Zigachev #include <drm/drmP.h>
33b843c749SSergey Zigachev #include <drm/amdgpu_drm.h>
34b843c749SSergey Zigachev #include "amdgpu.h"
35b843c749SSergey Zigachev #include "atom.h"
36b843c749SSergey Zigachev
37b843c749SSergey Zigachev /*
38b843c749SSergey Zigachev * Rings
39b843c749SSergey Zigachev * Most engines on the GPU are fed via ring buffers. Ring
40b843c749SSergey Zigachev * buffers are areas of GPU accessible memory that the host
41b843c749SSergey Zigachev * writes commands into and the GPU reads commands out of.
42b843c749SSergey Zigachev * There is a rptr (read pointer) that determines where the
43b843c749SSergey Zigachev * GPU is currently reading, and a wptr (write pointer)
44b843c749SSergey Zigachev * which determines where the host has written. When the
45b843c749SSergey Zigachev * pointers are equal, the ring is idle. When the host
46b843c749SSergey Zigachev * writes commands to the ring buffer, it increments the
47b843c749SSergey Zigachev * wptr. The GPU then starts fetching commands and executes
48b843c749SSergey Zigachev * them until the pointers are equal again.
49b843c749SSergey Zigachev */
50b843c749SSergey Zigachev static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
51b843c749SSergey Zigachev struct amdgpu_ring *ring);
52b843c749SSergey Zigachev static void amdgpu_debugfs_ring_fini(struct amdgpu_ring *ring);
53b843c749SSergey Zigachev
54b843c749SSergey Zigachev /**
55b843c749SSergey Zigachev * amdgpu_ring_alloc - allocate space on the ring buffer
56b843c749SSergey Zigachev *
57b843c749SSergey Zigachev * @adev: amdgpu_device pointer
58b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding ring information
59b843c749SSergey Zigachev * @ndw: number of dwords to allocate in the ring buffer
60b843c749SSergey Zigachev *
61b843c749SSergey Zigachev * Allocate @ndw dwords in the ring buffer (all asics).
62b843c749SSergey Zigachev * Returns 0 on success, error on failure.
63b843c749SSergey Zigachev */
amdgpu_ring_alloc(struct amdgpu_ring * ring,unsigned ndw)64b843c749SSergey Zigachev int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw)
65b843c749SSergey Zigachev {
66b843c749SSergey Zigachev /* Align requested size with padding so unlock_commit can
67b843c749SSergey Zigachev * pad safely */
68b843c749SSergey Zigachev ndw = (ndw + ring->funcs->align_mask) & ~ring->funcs->align_mask;
69b843c749SSergey Zigachev
70b843c749SSergey Zigachev /* Make sure we aren't trying to allocate more space
71b843c749SSergey Zigachev * than the maximum for one submission
72b843c749SSergey Zigachev */
73b843c749SSergey Zigachev if (WARN_ON_ONCE(ndw > ring->max_dw))
74b843c749SSergey Zigachev return -ENOMEM;
75b843c749SSergey Zigachev
76b843c749SSergey Zigachev ring->count_dw = ndw;
77b843c749SSergey Zigachev ring->wptr_old = ring->wptr;
78b843c749SSergey Zigachev
79b843c749SSergey Zigachev if (ring->funcs->begin_use)
80b843c749SSergey Zigachev ring->funcs->begin_use(ring);
81b843c749SSergey Zigachev
82b843c749SSergey Zigachev return 0;
83b843c749SSergey Zigachev }
84b843c749SSergey Zigachev
85b843c749SSergey Zigachev /** amdgpu_ring_insert_nop - insert NOP packets
86b843c749SSergey Zigachev *
87b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding ring information
88b843c749SSergey Zigachev * @count: the number of NOP packets to insert
89b843c749SSergey Zigachev *
90b843c749SSergey Zigachev * This is the generic insert_nop function for rings except SDMA
91b843c749SSergey Zigachev */
amdgpu_ring_insert_nop(struct amdgpu_ring * ring,uint32_t count)92b843c749SSergey Zigachev void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
93b843c749SSergey Zigachev {
94b843c749SSergey Zigachev int i;
95b843c749SSergey Zigachev
96b843c749SSergey Zigachev for (i = 0; i < count; i++)
97b843c749SSergey Zigachev amdgpu_ring_write(ring, ring->funcs->nop);
98b843c749SSergey Zigachev }
99b843c749SSergey Zigachev
100b843c749SSergey Zigachev /** amdgpu_ring_generic_pad_ib - pad IB with NOP packets
101b843c749SSergey Zigachev *
102b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding ring information
103b843c749SSergey Zigachev * @ib: IB to add NOP packets to
104b843c749SSergey Zigachev *
105b843c749SSergey Zigachev * This is the generic pad_ib function for rings except SDMA
106b843c749SSergey Zigachev */
amdgpu_ring_generic_pad_ib(struct amdgpu_ring * ring,struct amdgpu_ib * ib)107b843c749SSergey Zigachev void amdgpu_ring_generic_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
108b843c749SSergey Zigachev {
109b843c749SSergey Zigachev while (ib->length_dw & ring->funcs->align_mask)
110b843c749SSergey Zigachev ib->ptr[ib->length_dw++] = ring->funcs->nop;
111b843c749SSergey Zigachev }
112b843c749SSergey Zigachev
113b843c749SSergey Zigachev /**
114b843c749SSergey Zigachev * amdgpu_ring_commit - tell the GPU to execute the new
115b843c749SSergey Zigachev * commands on the ring buffer
116b843c749SSergey Zigachev *
117b843c749SSergey Zigachev * @adev: amdgpu_device pointer
118b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding ring information
119b843c749SSergey Zigachev *
120b843c749SSergey Zigachev * Update the wptr (write pointer) to tell the GPU to
121b843c749SSergey Zigachev * execute new commands on the ring buffer (all asics).
122b843c749SSergey Zigachev */
amdgpu_ring_commit(struct amdgpu_ring * ring)123b843c749SSergey Zigachev void amdgpu_ring_commit(struct amdgpu_ring *ring)
124b843c749SSergey Zigachev {
125b843c749SSergey Zigachev uint32_t count;
126b843c749SSergey Zigachev
127b843c749SSergey Zigachev /* We pad to match fetch size */
128b843c749SSergey Zigachev count = ring->funcs->align_mask + 1 -
129b843c749SSergey Zigachev (ring->wptr & ring->funcs->align_mask);
130b843c749SSergey Zigachev count %= ring->funcs->align_mask + 1;
131b843c749SSergey Zigachev ring->funcs->insert_nop(ring, count);
132b843c749SSergey Zigachev
133b843c749SSergey Zigachev mb();
134b843c749SSergey Zigachev amdgpu_ring_set_wptr(ring);
135b843c749SSergey Zigachev
136b843c749SSergey Zigachev if (ring->funcs->end_use)
137b843c749SSergey Zigachev ring->funcs->end_use(ring);
138b843c749SSergey Zigachev
139b843c749SSergey Zigachev if (ring->funcs->type != AMDGPU_RING_TYPE_KIQ)
140b843c749SSergey Zigachev amdgpu_ring_lru_touch(ring->adev, ring);
141b843c749SSergey Zigachev }
142b843c749SSergey Zigachev
143b843c749SSergey Zigachev /**
144b843c749SSergey Zigachev * amdgpu_ring_undo - reset the wptr
145b843c749SSergey Zigachev *
146b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding ring information
147b843c749SSergey Zigachev *
148b843c749SSergey Zigachev * Reset the driver's copy of the wptr (all asics).
149b843c749SSergey Zigachev */
amdgpu_ring_undo(struct amdgpu_ring * ring)150b843c749SSergey Zigachev void amdgpu_ring_undo(struct amdgpu_ring *ring)
151b843c749SSergey Zigachev {
152b843c749SSergey Zigachev ring->wptr = ring->wptr_old;
153b843c749SSergey Zigachev
154b843c749SSergey Zigachev if (ring->funcs->end_use)
155b843c749SSergey Zigachev ring->funcs->end_use(ring);
156b843c749SSergey Zigachev }
157b843c749SSergey Zigachev
158b843c749SSergey Zigachev /**
159b843c749SSergey Zigachev * amdgpu_ring_priority_put - restore a ring's priority
160b843c749SSergey Zigachev *
161b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding the information
162b843c749SSergey Zigachev * @priority: target priority
163b843c749SSergey Zigachev *
164b843c749SSergey Zigachev * Release a request for executing at @priority
165b843c749SSergey Zigachev */
amdgpu_ring_priority_put(struct amdgpu_ring * ring,enum drm_sched_priority priority)166b843c749SSergey Zigachev void amdgpu_ring_priority_put(struct amdgpu_ring *ring,
167b843c749SSergey Zigachev enum drm_sched_priority priority)
168b843c749SSergey Zigachev {
169b843c749SSergey Zigachev int i;
170b843c749SSergey Zigachev
171b843c749SSergey Zigachev if (!ring->funcs->set_priority)
172b843c749SSergey Zigachev return;
173b843c749SSergey Zigachev
174b843c749SSergey Zigachev if (atomic_dec_return(&ring->num_jobs[priority]) > 0)
175b843c749SSergey Zigachev return;
176b843c749SSergey Zigachev
177b843c749SSergey Zigachev /* no need to restore if the job is already at the lowest priority */
178b843c749SSergey Zigachev if (priority == DRM_SCHED_PRIORITY_NORMAL)
179b843c749SSergey Zigachev return;
180b843c749SSergey Zigachev
181b843c749SSergey Zigachev mutex_lock(&ring->priority_mutex);
182b843c749SSergey Zigachev /* something higher prio is executing, no need to decay */
183b843c749SSergey Zigachev if (ring->priority > priority)
184b843c749SSergey Zigachev goto out_unlock;
185b843c749SSergey Zigachev
186b843c749SSergey Zigachev /* decay priority to the next level with a job available */
187b843c749SSergey Zigachev for (i = priority; i >= DRM_SCHED_PRIORITY_MIN; i--) {
188b843c749SSergey Zigachev if (i == DRM_SCHED_PRIORITY_NORMAL
189b843c749SSergey Zigachev || atomic_read(&ring->num_jobs[i])) {
190b843c749SSergey Zigachev ring->priority = i;
191b843c749SSergey Zigachev ring->funcs->set_priority(ring, i);
192b843c749SSergey Zigachev break;
193b843c749SSergey Zigachev }
194b843c749SSergey Zigachev }
195b843c749SSergey Zigachev
196b843c749SSergey Zigachev out_unlock:
197b843c749SSergey Zigachev mutex_unlock(&ring->priority_mutex);
198b843c749SSergey Zigachev }
199b843c749SSergey Zigachev
200b843c749SSergey Zigachev /**
201b843c749SSergey Zigachev * amdgpu_ring_priority_get - change the ring's priority
202b843c749SSergey Zigachev *
203b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding the information
204b843c749SSergey Zigachev * @priority: target priority
205b843c749SSergey Zigachev *
206b843c749SSergey Zigachev * Request a ring's priority to be raised to @priority (refcounted).
207b843c749SSergey Zigachev */
amdgpu_ring_priority_get(struct amdgpu_ring * ring,enum drm_sched_priority priority)208b843c749SSergey Zigachev void amdgpu_ring_priority_get(struct amdgpu_ring *ring,
209b843c749SSergey Zigachev enum drm_sched_priority priority)
210b843c749SSergey Zigachev {
211b843c749SSergey Zigachev if (!ring->funcs->set_priority)
212b843c749SSergey Zigachev return;
213b843c749SSergey Zigachev
214b843c749SSergey Zigachev if (atomic_inc_return(&ring->num_jobs[priority]) <= 0)
215b843c749SSergey Zigachev return;
216b843c749SSergey Zigachev
217b843c749SSergey Zigachev mutex_lock(&ring->priority_mutex);
218b843c749SSergey Zigachev if (priority <= ring->priority)
219b843c749SSergey Zigachev goto out_unlock;
220b843c749SSergey Zigachev
221b843c749SSergey Zigachev ring->priority = priority;
222b843c749SSergey Zigachev ring->funcs->set_priority(ring, priority);
223b843c749SSergey Zigachev
224b843c749SSergey Zigachev out_unlock:
225b843c749SSergey Zigachev mutex_unlock(&ring->priority_mutex);
226b843c749SSergey Zigachev }
227b843c749SSergey Zigachev
228b843c749SSergey Zigachev /**
229b843c749SSergey Zigachev * amdgpu_ring_init - init driver ring struct.
230b843c749SSergey Zigachev *
231b843c749SSergey Zigachev * @adev: amdgpu_device pointer
232b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding ring information
233b843c749SSergey Zigachev * @max_ndw: maximum number of dw for ring alloc
234b843c749SSergey Zigachev * @nop: nop packet for this ring
235b843c749SSergey Zigachev *
236b843c749SSergey Zigachev * Initialize the driver information for the selected ring (all asics).
237b843c749SSergey Zigachev * Returns 0 on success, error on failure.
238b843c749SSergey Zigachev */
amdgpu_ring_init(struct amdgpu_device * adev,struct amdgpu_ring * ring,unsigned max_dw,struct amdgpu_irq_src * irq_src,unsigned irq_type)239b843c749SSergey Zigachev int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
240b843c749SSergey Zigachev unsigned max_dw, struct amdgpu_irq_src *irq_src,
241b843c749SSergey Zigachev unsigned irq_type)
242b843c749SSergey Zigachev {
243b843c749SSergey Zigachev int r, i;
244b843c749SSergey Zigachev int sched_hw_submission = amdgpu_sched_hw_submission;
245b843c749SSergey Zigachev
246b843c749SSergey Zigachev /* Set the hw submission limit higher for KIQ because
247b843c749SSergey Zigachev * it's used for a number of gfx/compute tasks by both
248b843c749SSergey Zigachev * KFD and KGD which may have outstanding fences and
249b843c749SSergey Zigachev * it doesn't really use the gpu scheduler anyway;
250b843c749SSergey Zigachev * KIQ tasks get submitted directly to the ring.
251b843c749SSergey Zigachev */
252b843c749SSergey Zigachev if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
253b843c749SSergey Zigachev sched_hw_submission = max(sched_hw_submission, 256);
254b843c749SSergey Zigachev
255b843c749SSergey Zigachev if (ring->adev == NULL) {
256b843c749SSergey Zigachev if (adev->num_rings >= AMDGPU_MAX_RINGS)
257b843c749SSergey Zigachev return -EINVAL;
258b843c749SSergey Zigachev
259b843c749SSergey Zigachev ring->adev = adev;
260b843c749SSergey Zigachev ring->idx = adev->num_rings++;
261b843c749SSergey Zigachev adev->rings[ring->idx] = ring;
262b843c749SSergey Zigachev r = amdgpu_fence_driver_init_ring(ring, sched_hw_submission);
263b843c749SSergey Zigachev if (r)
264b843c749SSergey Zigachev return r;
265b843c749SSergey Zigachev }
266b843c749SSergey Zigachev
267b843c749SSergey Zigachev r = amdgpu_device_wb_get(adev, &ring->rptr_offs);
268b843c749SSergey Zigachev if (r) {
269b843c749SSergey Zigachev dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
270b843c749SSergey Zigachev return r;
271b843c749SSergey Zigachev }
272b843c749SSergey Zigachev
273b843c749SSergey Zigachev r = amdgpu_device_wb_get(adev, &ring->wptr_offs);
274b843c749SSergey Zigachev if (r) {
275b843c749SSergey Zigachev dev_err(adev->dev, "(%d) ring wptr_offs wb alloc failed\n", r);
276b843c749SSergey Zigachev return r;
277b843c749SSergey Zigachev }
278b843c749SSergey Zigachev
279b843c749SSergey Zigachev r = amdgpu_device_wb_get(adev, &ring->fence_offs);
280b843c749SSergey Zigachev if (r) {
281b843c749SSergey Zigachev dev_err(adev->dev, "(%d) ring fence_offs wb alloc failed\n", r);
282b843c749SSergey Zigachev return r;
283b843c749SSergey Zigachev }
284b843c749SSergey Zigachev
285b843c749SSergey Zigachev r = amdgpu_device_wb_get(adev, &ring->cond_exe_offs);
286b843c749SSergey Zigachev if (r) {
287b843c749SSergey Zigachev dev_err(adev->dev, "(%d) ring cond_exec_polling wb alloc failed\n", r);
288b843c749SSergey Zigachev return r;
289b843c749SSergey Zigachev }
290b843c749SSergey Zigachev ring->cond_exe_gpu_addr = adev->wb.gpu_addr + (ring->cond_exe_offs * 4);
291b843c749SSergey Zigachev ring->cond_exe_cpu_addr = &adev->wb.wb[ring->cond_exe_offs];
292b843c749SSergey Zigachev /* always set cond_exec_polling to CONTINUE */
293b843c749SSergey Zigachev *ring->cond_exe_cpu_addr = 1;
294b843c749SSergey Zigachev
295b843c749SSergey Zigachev r = amdgpu_fence_driver_start_ring(ring, irq_src, irq_type);
296b843c749SSergey Zigachev if (r) {
297b843c749SSergey Zigachev dev_err(adev->dev, "failed initializing fences (%d).\n", r);
298b843c749SSergey Zigachev return r;
299b843c749SSergey Zigachev }
300b843c749SSergey Zigachev
301b843c749SSergey Zigachev ring->ring_size = roundup_pow_of_two(max_dw * 4 * sched_hw_submission);
302b843c749SSergey Zigachev
303b843c749SSergey Zigachev ring->buf_mask = (ring->ring_size / 4) - 1;
304b843c749SSergey Zigachev ring->ptr_mask = ring->funcs->support_64bit_ptrs ?
305b843c749SSergey Zigachev 0xffffffffffffffff : ring->buf_mask;
306b843c749SSergey Zigachev /* Allocate ring buffer */
307b843c749SSergey Zigachev if (ring->ring_obj == NULL) {
308b843c749SSergey Zigachev r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE,
309b843c749SSergey Zigachev AMDGPU_GEM_DOMAIN_GTT,
310b843c749SSergey Zigachev &ring->ring_obj,
311*78973132SSergey Zigachev (u64 *)&ring->gpu_addr,
312b843c749SSergey Zigachev (void **)&ring->ring);
313b843c749SSergey Zigachev if (r) {
314b843c749SSergey Zigachev dev_err(adev->dev, "(%d) ring create failed\n", r);
315b843c749SSergey Zigachev return r;
316b843c749SSergey Zigachev }
317b843c749SSergey Zigachev amdgpu_ring_clear_ring(ring);
318b843c749SSergey Zigachev }
319b843c749SSergey Zigachev
320b843c749SSergey Zigachev ring->max_dw = max_dw;
321b843c749SSergey Zigachev ring->priority = DRM_SCHED_PRIORITY_NORMAL;
322*78973132SSergey Zigachev lockinit(&ring->priority_mutex, "agrpm", 0, LK_CANRECURSE);
323b843c749SSergey Zigachev INIT_LIST_HEAD(&ring->lru_list);
324b843c749SSergey Zigachev amdgpu_ring_lru_touch(adev, ring);
325b843c749SSergey Zigachev
326b843c749SSergey Zigachev for (i = 0; i < DRM_SCHED_PRIORITY_MAX; ++i)
327b843c749SSergey Zigachev atomic_set(&ring->num_jobs[i], 0);
328b843c749SSergey Zigachev
329b843c749SSergey Zigachev if (amdgpu_debugfs_ring_init(adev, ring)) {
330b843c749SSergey Zigachev DRM_ERROR("Failed to register debugfs file for rings !\n");
331b843c749SSergey Zigachev }
332b843c749SSergey Zigachev
333b843c749SSergey Zigachev return 0;
334b843c749SSergey Zigachev }
335b843c749SSergey Zigachev
336b843c749SSergey Zigachev /**
337b843c749SSergey Zigachev * amdgpu_ring_fini - tear down the driver ring struct.
338b843c749SSergey Zigachev *
339b843c749SSergey Zigachev * @adev: amdgpu_device pointer
340b843c749SSergey Zigachev * @ring: amdgpu_ring structure holding ring information
341b843c749SSergey Zigachev *
342b843c749SSergey Zigachev * Tear down the driver information for the selected ring (all asics).
343b843c749SSergey Zigachev */
amdgpu_ring_fini(struct amdgpu_ring * ring)344b843c749SSergey Zigachev void amdgpu_ring_fini(struct amdgpu_ring *ring)
345b843c749SSergey Zigachev {
346b843c749SSergey Zigachev ring->ready = false;
347b843c749SSergey Zigachev
348b843c749SSergey Zigachev /* Not to finish a ring which is not initialized */
349b843c749SSergey Zigachev if (!(ring->adev) || !(ring->adev->rings[ring->idx]))
350b843c749SSergey Zigachev return;
351b843c749SSergey Zigachev
352b843c749SSergey Zigachev amdgpu_device_wb_free(ring->adev, ring->rptr_offs);
353b843c749SSergey Zigachev amdgpu_device_wb_free(ring->adev, ring->wptr_offs);
354b843c749SSergey Zigachev
355b843c749SSergey Zigachev amdgpu_device_wb_free(ring->adev, ring->cond_exe_offs);
356b843c749SSergey Zigachev amdgpu_device_wb_free(ring->adev, ring->fence_offs);
357b843c749SSergey Zigachev
358b843c749SSergey Zigachev amdgpu_bo_free_kernel(&ring->ring_obj,
359*78973132SSergey Zigachev (u64 *)&ring->gpu_addr,
360b843c749SSergey Zigachev (void **)&ring->ring);
361b843c749SSergey Zigachev
362b843c749SSergey Zigachev amdgpu_debugfs_ring_fini(ring);
363b843c749SSergey Zigachev
364b843c749SSergey Zigachev dma_fence_put(ring->vmid_wait);
365b843c749SSergey Zigachev ring->vmid_wait = NULL;
366b843c749SSergey Zigachev ring->me = 0;
367b843c749SSergey Zigachev
368b843c749SSergey Zigachev ring->adev->rings[ring->idx] = NULL;
369b843c749SSergey Zigachev }
370b843c749SSergey Zigachev
amdgpu_ring_lru_touch_locked(struct amdgpu_device * adev,struct amdgpu_ring * ring)371b843c749SSergey Zigachev static void amdgpu_ring_lru_touch_locked(struct amdgpu_device *adev,
372b843c749SSergey Zigachev struct amdgpu_ring *ring)
373b843c749SSergey Zigachev {
374b843c749SSergey Zigachev /* list_move_tail handles the case where ring isn't part of the list */
375b843c749SSergey Zigachev list_move_tail(&ring->lru_list, &adev->ring_lru_list);
376b843c749SSergey Zigachev }
377b843c749SSergey Zigachev
amdgpu_ring_is_blacklisted(struct amdgpu_ring * ring,int * blacklist,int num_blacklist)378b843c749SSergey Zigachev static bool amdgpu_ring_is_blacklisted(struct amdgpu_ring *ring,
379b843c749SSergey Zigachev int *blacklist, int num_blacklist)
380b843c749SSergey Zigachev {
381b843c749SSergey Zigachev int i;
382b843c749SSergey Zigachev
383b843c749SSergey Zigachev for (i = 0; i < num_blacklist; i++) {
384b843c749SSergey Zigachev if (ring->idx == blacklist[i])
385b843c749SSergey Zigachev return true;
386b843c749SSergey Zigachev }
387b843c749SSergey Zigachev
388b843c749SSergey Zigachev return false;
389b843c749SSergey Zigachev }
390b843c749SSergey Zigachev
391b843c749SSergey Zigachev /**
392b843c749SSergey Zigachev * amdgpu_ring_lru_get - get the least recently used ring for a HW IP block
393b843c749SSergey Zigachev *
394b843c749SSergey Zigachev * @adev: amdgpu_device pointer
395b843c749SSergey Zigachev * @type: amdgpu_ring_type enum
396b843c749SSergey Zigachev * @blacklist: blacklisted ring ids array
397b843c749SSergey Zigachev * @num_blacklist: number of entries in @blacklist
398b843c749SSergey Zigachev * @lru_pipe_order: find a ring from the least recently used pipe
399b843c749SSergey Zigachev * @ring: output ring
400b843c749SSergey Zigachev *
401b843c749SSergey Zigachev * Retrieve the amdgpu_ring structure for the least recently used ring of
402b843c749SSergey Zigachev * a specific IP block (all asics).
403b843c749SSergey Zigachev * Returns 0 on success, error on failure.
404b843c749SSergey Zigachev */
amdgpu_ring_lru_get(struct amdgpu_device * adev,int type,int * blacklist,int num_blacklist,bool lru_pipe_order,struct amdgpu_ring ** ring)405b843c749SSergey Zigachev int amdgpu_ring_lru_get(struct amdgpu_device *adev, int type,
406b843c749SSergey Zigachev int *blacklist, int num_blacklist,
407b843c749SSergey Zigachev bool lru_pipe_order, struct amdgpu_ring **ring)
408b843c749SSergey Zigachev {
409b843c749SSergey Zigachev struct amdgpu_ring *entry;
410b843c749SSergey Zigachev
411b843c749SSergey Zigachev /* List is sorted in LRU order, find first entry corresponding
412b843c749SSergey Zigachev * to the desired HW IP */
413b843c749SSergey Zigachev *ring = NULL;
414b843c749SSergey Zigachev spin_lock(&adev->ring_lru_list_lock);
415b843c749SSergey Zigachev list_for_each_entry(entry, &adev->ring_lru_list, lru_list) {
416b843c749SSergey Zigachev if (entry->funcs->type != type)
417b843c749SSergey Zigachev continue;
418b843c749SSergey Zigachev
419b843c749SSergey Zigachev if (amdgpu_ring_is_blacklisted(entry, blacklist, num_blacklist))
420b843c749SSergey Zigachev continue;
421b843c749SSergey Zigachev
422b843c749SSergey Zigachev if (!*ring) {
423b843c749SSergey Zigachev *ring = entry;
424b843c749SSergey Zigachev
425b843c749SSergey Zigachev /* We are done for ring LRU */
426b843c749SSergey Zigachev if (!lru_pipe_order)
427b843c749SSergey Zigachev break;
428b843c749SSergey Zigachev }
429b843c749SSergey Zigachev
430b843c749SSergey Zigachev /* Move all rings on the same pipe to the end of the list */
431b843c749SSergey Zigachev if (entry->pipe == (*ring)->pipe)
432b843c749SSergey Zigachev amdgpu_ring_lru_touch_locked(adev, entry);
433b843c749SSergey Zigachev }
434b843c749SSergey Zigachev
435b843c749SSergey Zigachev /* Move the ring we found to the end of the list */
436b843c749SSergey Zigachev if (*ring)
437b843c749SSergey Zigachev amdgpu_ring_lru_touch_locked(adev, *ring);
438b843c749SSergey Zigachev
439b843c749SSergey Zigachev spin_unlock(&adev->ring_lru_list_lock);
440b843c749SSergey Zigachev
441b843c749SSergey Zigachev if (!*ring) {
442b843c749SSergey Zigachev DRM_ERROR("Ring LRU contains no entries for ring type:%d\n", type);
443b843c749SSergey Zigachev return -EINVAL;
444b843c749SSergey Zigachev }
445b843c749SSergey Zigachev
446b843c749SSergey Zigachev return 0;
447b843c749SSergey Zigachev }
448b843c749SSergey Zigachev
449b843c749SSergey Zigachev /**
450b843c749SSergey Zigachev * amdgpu_ring_lru_touch - mark a ring as recently being used
451b843c749SSergey Zigachev *
452b843c749SSergey Zigachev * @adev: amdgpu_device pointer
453b843c749SSergey Zigachev * @ring: ring to touch
454b843c749SSergey Zigachev *
455b843c749SSergey Zigachev * Move @ring to the tail of the lru list
456b843c749SSergey Zigachev */
amdgpu_ring_lru_touch(struct amdgpu_device * adev,struct amdgpu_ring * ring)457b843c749SSergey Zigachev void amdgpu_ring_lru_touch(struct amdgpu_device *adev, struct amdgpu_ring *ring)
458b843c749SSergey Zigachev {
459b843c749SSergey Zigachev spin_lock(&adev->ring_lru_list_lock);
460b843c749SSergey Zigachev amdgpu_ring_lru_touch_locked(adev, ring);
461b843c749SSergey Zigachev spin_unlock(&adev->ring_lru_list_lock);
462b843c749SSergey Zigachev }
463b843c749SSergey Zigachev
464b843c749SSergey Zigachev /**
465b843c749SSergey Zigachev * amdgpu_ring_emit_reg_write_reg_wait_helper - ring helper
466b843c749SSergey Zigachev *
467b843c749SSergey Zigachev * @adev: amdgpu_device pointer
468b843c749SSergey Zigachev * @reg0: register to write
469b843c749SSergey Zigachev * @reg1: register to wait on
470b843c749SSergey Zigachev * @ref: reference value to write/wait on
471b843c749SSergey Zigachev * @mask: mask to wait on
472b843c749SSergey Zigachev *
473b843c749SSergey Zigachev * Helper for rings that don't support write and wait in a
474b843c749SSergey Zigachev * single oneshot packet.
475b843c749SSergey Zigachev */
amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring * ring,uint32_t reg0,uint32_t reg1,uint32_t ref,uint32_t mask)476b843c749SSergey Zigachev void amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring,
477b843c749SSergey Zigachev uint32_t reg0, uint32_t reg1,
478b843c749SSergey Zigachev uint32_t ref, uint32_t mask)
479b843c749SSergey Zigachev {
480b843c749SSergey Zigachev amdgpu_ring_emit_wreg(ring, reg0, ref);
481b843c749SSergey Zigachev amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask);
482b843c749SSergey Zigachev }
483b843c749SSergey Zigachev
484b843c749SSergey Zigachev /*
485b843c749SSergey Zigachev * Debugfs info
486b843c749SSergey Zigachev */
487b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_FS)
488b843c749SSergey Zigachev
489b843c749SSergey Zigachev /* Layout of file is 12 bytes consisting of
490b843c749SSergey Zigachev * - rptr
491b843c749SSergey Zigachev * - wptr
492b843c749SSergey Zigachev * - driver's copy of wptr
493b843c749SSergey Zigachev *
494b843c749SSergey Zigachev * followed by n-words of ring data
495b843c749SSergey Zigachev */
amdgpu_debugfs_ring_read(struct file * f,char __user * buf,size_t size,loff_t * pos)496b843c749SSergey Zigachev static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
497b843c749SSergey Zigachev size_t size, loff_t *pos)
498b843c749SSergey Zigachev {
499b843c749SSergey Zigachev struct amdgpu_ring *ring = file_inode(f)->i_private;
500b843c749SSergey Zigachev int r, i;
501b843c749SSergey Zigachev uint32_t value, result, early[3];
502b843c749SSergey Zigachev
503b843c749SSergey Zigachev if (*pos & 3 || size & 3)
504b843c749SSergey Zigachev return -EINVAL;
505b843c749SSergey Zigachev
506b843c749SSergey Zigachev result = 0;
507b843c749SSergey Zigachev
508b843c749SSergey Zigachev if (*pos < 12) {
509b843c749SSergey Zigachev early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask;
510b843c749SSergey Zigachev early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask;
511b843c749SSergey Zigachev early[2] = ring->wptr & ring->buf_mask;
512b843c749SSergey Zigachev for (i = *pos / 4; i < 3 && size; i++) {
513b843c749SSergey Zigachev r = put_user(early[i], (uint32_t *)buf);
514b843c749SSergey Zigachev if (r)
515b843c749SSergey Zigachev return r;
516b843c749SSergey Zigachev buf += 4;
517b843c749SSergey Zigachev result += 4;
518b843c749SSergey Zigachev size -= 4;
519b843c749SSergey Zigachev *pos += 4;
520b843c749SSergey Zigachev }
521b843c749SSergey Zigachev }
522b843c749SSergey Zigachev
523b843c749SSergey Zigachev while (size) {
524b843c749SSergey Zigachev if (*pos >= (ring->ring_size + 12))
525b843c749SSergey Zigachev return result;
526b843c749SSergey Zigachev
527b843c749SSergey Zigachev value = ring->ring[(*pos - 12)/4];
528b843c749SSergey Zigachev r = put_user(value, (uint32_t*)buf);
529b843c749SSergey Zigachev if (r)
530b843c749SSergey Zigachev return r;
531b843c749SSergey Zigachev buf += 4;
532b843c749SSergey Zigachev result += 4;
533b843c749SSergey Zigachev size -= 4;
534b843c749SSergey Zigachev *pos += 4;
535b843c749SSergey Zigachev }
536b843c749SSergey Zigachev
537b843c749SSergey Zigachev return result;
538b843c749SSergey Zigachev }
539b843c749SSergey Zigachev
540b843c749SSergey Zigachev static const struct file_operations amdgpu_debugfs_ring_fops = {
541b843c749SSergey Zigachev .owner = THIS_MODULE,
542b843c749SSergey Zigachev .read = amdgpu_debugfs_ring_read,
543b843c749SSergey Zigachev .llseek = default_llseek
544b843c749SSergey Zigachev };
545b843c749SSergey Zigachev
546b843c749SSergey Zigachev #endif
547b843c749SSergey Zigachev
amdgpu_debugfs_ring_init(struct amdgpu_device * adev,struct amdgpu_ring * ring)548b843c749SSergey Zigachev static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
549b843c749SSergey Zigachev struct amdgpu_ring *ring)
550b843c749SSergey Zigachev {
551b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_FS)
552b843c749SSergey Zigachev struct drm_minor *minor = adev->ddev->primary;
553b843c749SSergey Zigachev struct dentry *ent, *root = minor->debugfs_root;
554b843c749SSergey Zigachev char name[32];
555b843c749SSergey Zigachev
556b843c749SSergey Zigachev sprintf(name, "amdgpu_ring_%s", ring->name);
557b843c749SSergey Zigachev
558b843c749SSergey Zigachev ent = debugfs_create_file(name,
559b843c749SSergey Zigachev S_IFREG | S_IRUGO, root,
560b843c749SSergey Zigachev ring, &amdgpu_debugfs_ring_fops);
561b843c749SSergey Zigachev if (!ent)
562b843c749SSergey Zigachev return -ENOMEM;
563b843c749SSergey Zigachev
564b843c749SSergey Zigachev i_size_write(ent->d_inode, ring->ring_size + 12);
565b843c749SSergey Zigachev ring->ent = ent;
566b843c749SSergey Zigachev #endif
567b843c749SSergey Zigachev return 0;
568b843c749SSergey Zigachev }
569b843c749SSergey Zigachev
amdgpu_debugfs_ring_fini(struct amdgpu_ring * ring)570b843c749SSergey Zigachev static void amdgpu_debugfs_ring_fini(struct amdgpu_ring *ring)
571b843c749SSergey Zigachev {
572b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_FS)
573b843c749SSergey Zigachev debugfs_remove(ring->ent);
574b843c749SSergey Zigachev #endif
575b843c749SSergey Zigachev }
576