18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc. 48c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 88c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 98c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 108c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 118c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 148c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 208c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 218c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 228c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Authors: Dave Airlie 258c2ecf20Sopenharmony_ci * Alex Deucher 268c2ecf20Sopenharmony_ci * Jerome Glisse 278c2ecf20Sopenharmony_ci * Christian König 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 328c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <drm/amdgpu_drm.h> 358c2ecf20Sopenharmony_ci#include "amdgpu.h" 368c2ecf20Sopenharmony_ci#include "atom.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Rings 408c2ecf20Sopenharmony_ci * Most engines on the GPU are fed via ring buffers. Ring 418c2ecf20Sopenharmony_ci * buffers are areas of GPU accessible memory that the host 428c2ecf20Sopenharmony_ci * writes commands into and the GPU reads commands out of. 438c2ecf20Sopenharmony_ci * There is a rptr (read pointer) that determines where the 448c2ecf20Sopenharmony_ci * GPU is currently reading, and a wptr (write pointer) 458c2ecf20Sopenharmony_ci * which determines where the host has written. When the 468c2ecf20Sopenharmony_ci * pointers are equal, the ring is idle. When the host 478c2ecf20Sopenharmony_ci * writes commands to the ring buffer, it increments the 488c2ecf20Sopenharmony_ci * wptr. The GPU then starts fetching commands and executes 498c2ecf20Sopenharmony_ci * them until the pointers are equal again. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * amdgpu_ring_alloc - allocate space on the ring buffer 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 568c2ecf20Sopenharmony_ci * @ring: amdgpu_ring structure holding ring information 578c2ecf20Sopenharmony_ci * @ndw: number of dwords to allocate in the ring buffer 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Allocate @ndw dwords in the ring buffer (all asics). 608c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ciint amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci /* Align requested size with padding so unlock_commit can 658c2ecf20Sopenharmony_ci * pad safely */ 668c2ecf20Sopenharmony_ci ndw = (ndw + ring->funcs->align_mask) & ~ring->funcs->align_mask; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Make sure we aren't trying to allocate more space 698c2ecf20Sopenharmony_ci * than the maximum for one submission 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(ndw > ring->max_dw)) 728c2ecf20Sopenharmony_ci return -ENOMEM; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci ring->count_dw = ndw; 758c2ecf20Sopenharmony_ci ring->wptr_old = ring->wptr; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (ring->funcs->begin_use) 788c2ecf20Sopenharmony_ci ring->funcs->begin_use(ring); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** amdgpu_ring_insert_nop - insert NOP packets 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * @ring: amdgpu_ring structure holding ring information 868c2ecf20Sopenharmony_ci * @count: the number of NOP packets to insert 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * This is the generic insert_nop function for rings except SDMA 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_civoid amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci int i; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 958c2ecf20Sopenharmony_ci amdgpu_ring_write(ring, ring->funcs->nop); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** amdgpu_ring_generic_pad_ib - pad IB with NOP packets 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * @ring: amdgpu_ring structure holding ring information 1018c2ecf20Sopenharmony_ci * @ib: IB to add NOP packets to 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * This is the generic pad_ib function for rings except SDMA 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_civoid amdgpu_ring_generic_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci while (ib->length_dw & ring->funcs->align_mask) 1088c2ecf20Sopenharmony_ci ib->ptr[ib->length_dw++] = ring->funcs->nop; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/** 1128c2ecf20Sopenharmony_ci * amdgpu_ring_commit - tell the GPU to execute the new 1138c2ecf20Sopenharmony_ci * commands on the ring buffer 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 1168c2ecf20Sopenharmony_ci * @ring: amdgpu_ring structure holding ring information 1178c2ecf20Sopenharmony_ci * 1188c2ecf20Sopenharmony_ci * Update the wptr (write pointer) to tell the GPU to 1198c2ecf20Sopenharmony_ci * execute new commands on the ring buffer (all asics). 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_civoid amdgpu_ring_commit(struct amdgpu_ring *ring) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci uint32_t count; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* We pad to match fetch size */ 1268c2ecf20Sopenharmony_ci count = ring->funcs->align_mask + 1 - 1278c2ecf20Sopenharmony_ci (ring->wptr & ring->funcs->align_mask); 1288c2ecf20Sopenharmony_ci count %= ring->funcs->align_mask + 1; 1298c2ecf20Sopenharmony_ci ring->funcs->insert_nop(ring, count); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci mb(); 1328c2ecf20Sopenharmony_ci amdgpu_ring_set_wptr(ring); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (ring->funcs->end_use) 1358c2ecf20Sopenharmony_ci ring->funcs->end_use(ring); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/** 1398c2ecf20Sopenharmony_ci * amdgpu_ring_undo - reset the wptr 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * @ring: amdgpu_ring structure holding ring information 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * Reset the driver's copy of the wptr (all asics). 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_civoid amdgpu_ring_undo(struct amdgpu_ring *ring) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci ring->wptr = ring->wptr_old; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (ring->funcs->end_use) 1508c2ecf20Sopenharmony_ci ring->funcs->end_use(ring); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/** 1548c2ecf20Sopenharmony_ci * amdgpu_ring_init - init driver ring struct. 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 1578c2ecf20Sopenharmony_ci * @ring: amdgpu_ring structure holding ring information 1588c2ecf20Sopenharmony_ci * @max_ndw: maximum number of dw for ring alloc 1598c2ecf20Sopenharmony_ci * @nop: nop packet for this ring 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * Initialize the driver information for the selected ring (all asics). 1628c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ciint amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, 1658c2ecf20Sopenharmony_ci unsigned int max_dw, struct amdgpu_irq_src *irq_src, 1668c2ecf20Sopenharmony_ci unsigned int irq_type, unsigned int hw_prio) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int r, i; 1698c2ecf20Sopenharmony_ci int sched_hw_submission = amdgpu_sched_hw_submission; 1708c2ecf20Sopenharmony_ci u32 *num_sched; 1718c2ecf20Sopenharmony_ci u32 hw_ip; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* Set the hw submission limit higher for KIQ because 1748c2ecf20Sopenharmony_ci * it's used for a number of gfx/compute tasks by both 1758c2ecf20Sopenharmony_ci * KFD and KGD which may have outstanding fences and 1768c2ecf20Sopenharmony_ci * it doesn't really use the gpu scheduler anyway; 1778c2ecf20Sopenharmony_ci * KIQ tasks get submitted directly to the ring. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ) 1808c2ecf20Sopenharmony_ci sched_hw_submission = max(sched_hw_submission, 256); 1818c2ecf20Sopenharmony_ci else if (ring == &adev->sdma.instance[0].page) 1828c2ecf20Sopenharmony_ci sched_hw_submission = 256; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (ring->adev == NULL) { 1858c2ecf20Sopenharmony_ci if (adev->num_rings >= AMDGPU_MAX_RINGS) 1868c2ecf20Sopenharmony_ci return -EINVAL; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci ring->adev = adev; 1898c2ecf20Sopenharmony_ci ring->idx = adev->num_rings++; 1908c2ecf20Sopenharmony_ci adev->rings[ring->idx] = ring; 1918c2ecf20Sopenharmony_ci r = amdgpu_fence_driver_init_ring(ring, sched_hw_submission); 1928c2ecf20Sopenharmony_ci if (r) 1938c2ecf20Sopenharmony_ci return r; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci r = amdgpu_device_wb_get(adev, &ring->rptr_offs); 1978c2ecf20Sopenharmony_ci if (r) { 1988c2ecf20Sopenharmony_ci dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r); 1998c2ecf20Sopenharmony_ci return r; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci r = amdgpu_device_wb_get(adev, &ring->wptr_offs); 2038c2ecf20Sopenharmony_ci if (r) { 2048c2ecf20Sopenharmony_ci dev_err(adev->dev, "(%d) ring wptr_offs wb alloc failed\n", r); 2058c2ecf20Sopenharmony_ci return r; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci r = amdgpu_device_wb_get(adev, &ring->fence_offs); 2098c2ecf20Sopenharmony_ci if (r) { 2108c2ecf20Sopenharmony_ci dev_err(adev->dev, "(%d) ring fence_offs wb alloc failed\n", r); 2118c2ecf20Sopenharmony_ci return r; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci r = amdgpu_device_wb_get(adev, &ring->trail_fence_offs); 2158c2ecf20Sopenharmony_ci if (r) { 2168c2ecf20Sopenharmony_ci dev_err(adev->dev, 2178c2ecf20Sopenharmony_ci "(%d) ring trail_fence_offs wb alloc failed\n", r); 2188c2ecf20Sopenharmony_ci return r; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci ring->trail_fence_gpu_addr = 2218c2ecf20Sopenharmony_ci adev->wb.gpu_addr + (ring->trail_fence_offs * 4); 2228c2ecf20Sopenharmony_ci ring->trail_fence_cpu_addr = &adev->wb.wb[ring->trail_fence_offs]; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci r = amdgpu_device_wb_get(adev, &ring->cond_exe_offs); 2258c2ecf20Sopenharmony_ci if (r) { 2268c2ecf20Sopenharmony_ci dev_err(adev->dev, "(%d) ring cond_exec_polling wb alloc failed\n", r); 2278c2ecf20Sopenharmony_ci return r; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci ring->cond_exe_gpu_addr = adev->wb.gpu_addr + (ring->cond_exe_offs * 4); 2308c2ecf20Sopenharmony_ci ring->cond_exe_cpu_addr = &adev->wb.wb[ring->cond_exe_offs]; 2318c2ecf20Sopenharmony_ci /* always set cond_exec_polling to CONTINUE */ 2328c2ecf20Sopenharmony_ci *ring->cond_exe_cpu_addr = 1; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci r = amdgpu_fence_driver_start_ring(ring, irq_src, irq_type); 2358c2ecf20Sopenharmony_ci if (r) { 2368c2ecf20Sopenharmony_ci dev_err(adev->dev, "failed initializing fences (%d).\n", r); 2378c2ecf20Sopenharmony_ci return r; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci ring->ring_size = roundup_pow_of_two(max_dw * 4 * sched_hw_submission); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ring->buf_mask = (ring->ring_size / 4) - 1; 2438c2ecf20Sopenharmony_ci ring->ptr_mask = ring->funcs->support_64bit_ptrs ? 2448c2ecf20Sopenharmony_ci 0xffffffffffffffff : ring->buf_mask; 2458c2ecf20Sopenharmony_ci /* Allocate ring buffer */ 2468c2ecf20Sopenharmony_ci if (ring->ring_obj == NULL) { 2478c2ecf20Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE, 2488c2ecf20Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 2498c2ecf20Sopenharmony_ci &ring->ring_obj, 2508c2ecf20Sopenharmony_ci &ring->gpu_addr, 2518c2ecf20Sopenharmony_ci (void **)&ring->ring); 2528c2ecf20Sopenharmony_ci if (r) { 2538c2ecf20Sopenharmony_ci dev_err(adev->dev, "(%d) ring create failed\n", r); 2548c2ecf20Sopenharmony_ci return r; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci amdgpu_ring_clear_ring(ring); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci ring->max_dw = max_dw; 2608c2ecf20Sopenharmony_ci ring->priority = DRM_SCHED_PRIORITY_NORMAL; 2618c2ecf20Sopenharmony_ci mutex_init(&ring->priority_mutex); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (!ring->no_scheduler) { 2648c2ecf20Sopenharmony_ci hw_ip = ring->funcs->type; 2658c2ecf20Sopenharmony_ci num_sched = &adev->gpu_sched[hw_ip][hw_prio].num_scheds; 2668c2ecf20Sopenharmony_ci adev->gpu_sched[hw_ip][hw_prio].sched[(*num_sched)++] = 2678c2ecf20Sopenharmony_ci &ring->sched; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; ++i) 2718c2ecf20Sopenharmony_ci atomic_set(&ring->num_jobs[i], 0); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/** 2778c2ecf20Sopenharmony_ci * amdgpu_ring_fini - tear down the driver ring struct. 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 2808c2ecf20Sopenharmony_ci * @ring: amdgpu_ring structure holding ring information 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * Tear down the driver information for the selected ring (all asics). 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_civoid amdgpu_ring_fini(struct amdgpu_ring *ring) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Not to finish a ring which is not initialized */ 2888c2ecf20Sopenharmony_ci if (!(ring->adev) || !(ring->adev->rings[ring->idx])) 2898c2ecf20Sopenharmony_ci return; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci ring->sched.ready = false; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci amdgpu_device_wb_free(ring->adev, ring->rptr_offs); 2948c2ecf20Sopenharmony_ci amdgpu_device_wb_free(ring->adev, ring->wptr_offs); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci amdgpu_device_wb_free(ring->adev, ring->cond_exe_offs); 2978c2ecf20Sopenharmony_ci amdgpu_device_wb_free(ring->adev, ring->fence_offs); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci amdgpu_bo_free_kernel(&ring->ring_obj, 3008c2ecf20Sopenharmony_ci &ring->gpu_addr, 3018c2ecf20Sopenharmony_ci (void **)&ring->ring); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dma_fence_put(ring->vmid_wait); 3048c2ecf20Sopenharmony_ci ring->vmid_wait = NULL; 3058c2ecf20Sopenharmony_ci ring->me = 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci ring->adev->rings[ring->idx] = NULL; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/** 3118c2ecf20Sopenharmony_ci * amdgpu_ring_emit_reg_write_reg_wait_helper - ring helper 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 3148c2ecf20Sopenharmony_ci * @reg0: register to write 3158c2ecf20Sopenharmony_ci * @reg1: register to wait on 3168c2ecf20Sopenharmony_ci * @ref: reference value to write/wait on 3178c2ecf20Sopenharmony_ci * @mask: mask to wait on 3188c2ecf20Sopenharmony_ci * 3198c2ecf20Sopenharmony_ci * Helper for rings that don't support write and wait in a 3208c2ecf20Sopenharmony_ci * single oneshot packet. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_civoid amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring, 3238c2ecf20Sopenharmony_ci uint32_t reg0, uint32_t reg1, 3248c2ecf20Sopenharmony_ci uint32_t ref, uint32_t mask) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci amdgpu_ring_emit_wreg(ring, reg0, ref); 3278c2ecf20Sopenharmony_ci amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/** 3318c2ecf20Sopenharmony_ci * amdgpu_ring_soft_recovery - try to soft recover a ring lockup 3328c2ecf20Sopenharmony_ci * 3338c2ecf20Sopenharmony_ci * @ring: ring to try the recovery on 3348c2ecf20Sopenharmony_ci * @vmid: VMID we try to get going again 3358c2ecf20Sopenharmony_ci * @fence: timedout fence 3368c2ecf20Sopenharmony_ci * 3378c2ecf20Sopenharmony_ci * Tries to get a ring proceeding again when it is stuck. 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_cibool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid, 3408c2ecf20Sopenharmony_ci struct dma_fence *fence) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci ktime_t deadline = ktime_add_us(ktime_get(), 10000); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(ring->adev) || !ring->funcs->soft_recovery || !fence) 3458c2ecf20Sopenharmony_ci return false; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci atomic_inc(&ring->adev->gpu_reset_counter); 3488c2ecf20Sopenharmony_ci while (!dma_fence_is_signaled(fence) && 3498c2ecf20Sopenharmony_ci ktime_to_ns(ktime_sub(deadline, ktime_get())) > 0) 3508c2ecf20Sopenharmony_ci ring->funcs->soft_recovery(ring, vmid); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return dma_fence_is_signaled(fence); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/* 3568c2ecf20Sopenharmony_ci * Debugfs info 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* Layout of file is 12 bytes consisting of 3618c2ecf20Sopenharmony_ci * - rptr 3628c2ecf20Sopenharmony_ci * - wptr 3638c2ecf20Sopenharmony_ci * - driver's copy of wptr 3648c2ecf20Sopenharmony_ci * 3658c2ecf20Sopenharmony_ci * followed by n-words of ring data 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_cistatic ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, 3688c2ecf20Sopenharmony_ci size_t size, loff_t *pos) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = file_inode(f)->i_private; 3718c2ecf20Sopenharmony_ci int r, i; 3728c2ecf20Sopenharmony_ci uint32_t value, result, early[3]; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (*pos & 3 || size & 3) 3758c2ecf20Sopenharmony_ci return -EINVAL; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci result = 0; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (*pos < 12) { 3808c2ecf20Sopenharmony_ci early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask; 3818c2ecf20Sopenharmony_ci early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask; 3828c2ecf20Sopenharmony_ci early[2] = ring->wptr & ring->buf_mask; 3838c2ecf20Sopenharmony_ci for (i = *pos / 4; i < 3 && size; i++) { 3848c2ecf20Sopenharmony_ci r = put_user(early[i], (uint32_t *)buf); 3858c2ecf20Sopenharmony_ci if (r) 3868c2ecf20Sopenharmony_ci return r; 3878c2ecf20Sopenharmony_ci buf += 4; 3888c2ecf20Sopenharmony_ci result += 4; 3898c2ecf20Sopenharmony_ci size -= 4; 3908c2ecf20Sopenharmony_ci *pos += 4; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci while (size) { 3958c2ecf20Sopenharmony_ci if (*pos >= (ring->ring_size + 12)) 3968c2ecf20Sopenharmony_ci return result; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci value = ring->ring[(*pos - 12)/4]; 3998c2ecf20Sopenharmony_ci r = put_user(value, (uint32_t*)buf); 4008c2ecf20Sopenharmony_ci if (r) 4018c2ecf20Sopenharmony_ci return r; 4028c2ecf20Sopenharmony_ci buf += 4; 4038c2ecf20Sopenharmony_ci result += 4; 4048c2ecf20Sopenharmony_ci size -= 4; 4058c2ecf20Sopenharmony_ci *pos += 4; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return result; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic const struct file_operations amdgpu_debugfs_ring_fops = { 4128c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4138c2ecf20Sopenharmony_ci .read = amdgpu_debugfs_ring_read, 4148c2ecf20Sopenharmony_ci .llseek = default_llseek 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci#endif 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ciint amdgpu_debugfs_ring_init(struct amdgpu_device *adev, 4208c2ecf20Sopenharmony_ci struct amdgpu_ring *ring) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 4238c2ecf20Sopenharmony_ci struct drm_minor *minor = adev_to_drm(adev)->primary; 4248c2ecf20Sopenharmony_ci struct dentry *ent, *root = minor->debugfs_root; 4258c2ecf20Sopenharmony_ci char name[32]; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci sprintf(name, "amdgpu_ring_%s", ring->name); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ent = debugfs_create_file(name, 4308c2ecf20Sopenharmony_ci S_IFREG | S_IRUGO, root, 4318c2ecf20Sopenharmony_ci ring, &amdgpu_debugfs_ring_fops); 4328c2ecf20Sopenharmony_ci if (!ent) 4338c2ecf20Sopenharmony_ci return -ENOMEM; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci i_size_write(ent->d_inode, ring->ring_size + 12); 4368c2ecf20Sopenharmony_ci ring->ent = ent; 4378c2ecf20Sopenharmony_ci#endif 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/** 4428c2ecf20Sopenharmony_ci * amdgpu_ring_test_helper - tests ring and set sched readiness status 4438c2ecf20Sopenharmony_ci * 4448c2ecf20Sopenharmony_ci * @ring: ring to try the recovery on 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * Tests ring and set sched readiness status 4478c2ecf20Sopenharmony_ci * 4488c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_ciint amdgpu_ring_test_helper(struct amdgpu_ring *ring) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 4538c2ecf20Sopenharmony_ci int r; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci r = amdgpu_ring_test_ring(ring); 4568c2ecf20Sopenharmony_ci if (r) 4578c2ecf20Sopenharmony_ci DRM_DEV_ERROR(adev->dev, "ring %s test failed (%d)\n", 4588c2ecf20Sopenharmony_ci ring->name, r); 4598c2ecf20Sopenharmony_ci else 4608c2ecf20Sopenharmony_ci DRM_DEV_DEBUG(adev->dev, "ring test on %s succeeded\n", 4618c2ecf20Sopenharmony_ci ring->name); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ring->sched.ready = !r; 4648c2ecf20Sopenharmony_ci return r; 4658c2ecf20Sopenharmony_ci} 466