xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_debugfs.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1*41ec0267Sriastradh /*	$NetBSD: amdgpu_debugfs.c,v 1.2 2021/12/18 23:44:58 riastradh Exp $	*/
24e390cabSriastradh 
34e390cabSriastradh /*
44e390cabSriastradh  * Copyright 2008 Advanced Micro Devices, Inc.
54e390cabSriastradh  * Copyright 2008 Red Hat Inc.
64e390cabSriastradh  * Copyright 2009 Jerome Glisse.
74e390cabSriastradh  *
84e390cabSriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
94e390cabSriastradh  * copy of this software and associated documentation files (the "Software"),
104e390cabSriastradh  * to deal in the Software without restriction, including without limitation
114e390cabSriastradh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
124e390cabSriastradh  * and/or sell copies of the Software, and to permit persons to whom the
134e390cabSriastradh  * Software is furnished to do so, subject to the following conditions:
144e390cabSriastradh  *
154e390cabSriastradh  * The above copyright notice and this permission notice shall be included in
164e390cabSriastradh  * all copies or substantial portions of the Software.
174e390cabSriastradh  *
184e390cabSriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
194e390cabSriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
204e390cabSriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
214e390cabSriastradh  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
224e390cabSriastradh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
234e390cabSriastradh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
244e390cabSriastradh  * OTHER DEALINGS IN THE SOFTWARE.
254e390cabSriastradh  *
264e390cabSriastradh  */
274e390cabSriastradh 
284e390cabSriastradh #include <sys/cdefs.h>
29*41ec0267Sriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_debugfs.c,v 1.2 2021/12/18 23:44:58 riastradh Exp $");
304e390cabSriastradh 
314e390cabSriastradh #include <linux/kthread.h>
324e390cabSriastradh #include <linux/pci.h>
334e390cabSriastradh #include <linux/uaccess.h>
344e390cabSriastradh #include <linux/pm_runtime.h>
354e390cabSriastradh 
364e390cabSriastradh #include <drm/drm_debugfs.h>
374e390cabSriastradh 
384e390cabSriastradh #include "amdgpu.h"
394e390cabSriastradh 
404e390cabSriastradh /**
414e390cabSriastradh  * amdgpu_debugfs_add_files - Add simple debugfs entries
424e390cabSriastradh  *
434e390cabSriastradh  * @adev:  Device to attach debugfs entries to
444e390cabSriastradh  * @files:  Array of function callbacks that respond to reads
454e390cabSriastradh  * @nfiles: Number of callbacks to register
464e390cabSriastradh  *
474e390cabSriastradh  */
amdgpu_debugfs_add_files(struct amdgpu_device * adev,const struct drm_info_list * files,unsigned nfiles)484e390cabSriastradh int amdgpu_debugfs_add_files(struct amdgpu_device *adev,
494e390cabSriastradh 			     const struct drm_info_list *files,
504e390cabSriastradh 			     unsigned nfiles)
514e390cabSriastradh {
524e390cabSriastradh 	unsigned i;
534e390cabSriastradh 
544e390cabSriastradh 	for (i = 0; i < adev->debugfs_count; i++) {
554e390cabSriastradh 		if (adev->debugfs[i].files == files) {
564e390cabSriastradh 			/* Already registered */
574e390cabSriastradh 			return 0;
584e390cabSriastradh 		}
594e390cabSriastradh 	}
604e390cabSriastradh 
614e390cabSriastradh 	i = adev->debugfs_count + 1;
624e390cabSriastradh 	if (i > AMDGPU_DEBUGFS_MAX_COMPONENTS) {
634e390cabSriastradh 		DRM_ERROR("Reached maximum number of debugfs components.\n");
644e390cabSriastradh 		DRM_ERROR("Report so we increase "
654e390cabSriastradh 			  "AMDGPU_DEBUGFS_MAX_COMPONENTS.\n");
664e390cabSriastradh 		return -EINVAL;
674e390cabSriastradh 	}
684e390cabSriastradh 	adev->debugfs[adev->debugfs_count].files = files;
694e390cabSriastradh 	adev->debugfs[adev->debugfs_count].num_files = nfiles;
704e390cabSriastradh 	adev->debugfs_count = i;
714e390cabSriastradh #if defined(CONFIG_DEBUG_FS)
724e390cabSriastradh 	drm_debugfs_create_files(files, nfiles,
734e390cabSriastradh 				 adev->ddev->primary->debugfs_root,
744e390cabSriastradh 				 adev->ddev->primary);
754e390cabSriastradh #endif
764e390cabSriastradh 	return 0;
774e390cabSriastradh }
784e390cabSriastradh 
794e390cabSriastradh #if defined(CONFIG_DEBUG_FS)
804e390cabSriastradh 
814e390cabSriastradh /**
824e390cabSriastradh  * amdgpu_debugfs_process_reg_op - Handle MMIO register reads/writes
834e390cabSriastradh  *
844e390cabSriastradh  * @read: True if reading
854e390cabSriastradh  * @f: open file handle
864e390cabSriastradh  * @buf: User buffer to write/read to
874e390cabSriastradh  * @size: Number of bytes to write/read
884e390cabSriastradh  * @pos:  Offset to seek to
894e390cabSriastradh  *
904e390cabSriastradh  * This debugfs entry has special meaning on the offset being sought.
914e390cabSriastradh  * Various bits have different meanings:
924e390cabSriastradh  *
934e390cabSriastradh  * Bit 62:  Indicates a GRBM bank switch is needed
944e390cabSriastradh  * Bit 61:  Indicates a SRBM bank switch is needed (implies bit 62 is
954e390cabSriastradh  * 			zero)
964e390cabSriastradh  * Bits 24..33: The SE or ME selector if needed
974e390cabSriastradh  * Bits 34..43: The SH (or SA) or PIPE selector if needed
984e390cabSriastradh  * Bits 44..53: The INSTANCE (or CU/WGP) or QUEUE selector if needed
994e390cabSriastradh  *
1004e390cabSriastradh  * Bit 23:  Indicates that the PM power gating lock should be held
1014e390cabSriastradh  * 			This is necessary to read registers that might be
1024e390cabSriastradh  * 			unreliable during a power gating transistion.
1034e390cabSriastradh  *
1044e390cabSriastradh  * The lower bits are the BYTE offset of the register to read.  This
1054e390cabSriastradh  * allows reading multiple registers in a single call and having
1064e390cabSriastradh  * the returned size reflect that.
1074e390cabSriastradh  */
amdgpu_debugfs_process_reg_op(bool read,struct file * f,char __user * buf,size_t size,loff_t * pos)1084e390cabSriastradh static int  amdgpu_debugfs_process_reg_op(bool read, struct file *f,
1094e390cabSriastradh 		char __user *buf, size_t size, loff_t *pos)
1104e390cabSriastradh {
1114e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
1124e390cabSriastradh 	ssize_t result = 0;
1134e390cabSriastradh 	int r;
1144e390cabSriastradh 	bool pm_pg_lock, use_bank, use_ring;
1154e390cabSriastradh 	unsigned instance_bank, sh_bank, se_bank, me, pipe, queue, vmid;
1164e390cabSriastradh 
1174e390cabSriastradh 	pm_pg_lock = use_bank = use_ring = false;
1184e390cabSriastradh 	instance_bank = sh_bank = se_bank = me = pipe = queue = vmid = 0;
1194e390cabSriastradh 
1204e390cabSriastradh 	if (size & 0x3 || *pos & 0x3 ||
1214e390cabSriastradh 			((*pos & (1ULL << 62)) && (*pos & (1ULL << 61))))
1224e390cabSriastradh 		return -EINVAL;
1234e390cabSriastradh 
1244e390cabSriastradh 	/* are we reading registers for which a PG lock is necessary? */
1254e390cabSriastradh 	pm_pg_lock = (*pos >> 23) & 1;
1264e390cabSriastradh 
1274e390cabSriastradh 	if (*pos & (1ULL << 62)) {
1284e390cabSriastradh 		se_bank = (*pos & GENMASK_ULL(33, 24)) >> 24;
1294e390cabSriastradh 		sh_bank = (*pos & GENMASK_ULL(43, 34)) >> 34;
1304e390cabSriastradh 		instance_bank = (*pos & GENMASK_ULL(53, 44)) >> 44;
1314e390cabSriastradh 
1324e390cabSriastradh 		if (se_bank == 0x3FF)
1334e390cabSriastradh 			se_bank = 0xFFFFFFFF;
1344e390cabSriastradh 		if (sh_bank == 0x3FF)
1354e390cabSriastradh 			sh_bank = 0xFFFFFFFF;
1364e390cabSriastradh 		if (instance_bank == 0x3FF)
1374e390cabSriastradh 			instance_bank = 0xFFFFFFFF;
1384e390cabSriastradh 		use_bank = true;
1394e390cabSriastradh 	} else if (*pos & (1ULL << 61)) {
1404e390cabSriastradh 
1414e390cabSriastradh 		me = (*pos & GENMASK_ULL(33, 24)) >> 24;
1424e390cabSriastradh 		pipe = (*pos & GENMASK_ULL(43, 34)) >> 34;
1434e390cabSriastradh 		queue = (*pos & GENMASK_ULL(53, 44)) >> 44;
1444e390cabSriastradh 		vmid = (*pos & GENMASK_ULL(58, 54)) >> 54;
1454e390cabSriastradh 
1464e390cabSriastradh 		use_ring = true;
1474e390cabSriastradh 	} else {
1484e390cabSriastradh 		use_bank = use_ring = false;
1494e390cabSriastradh 	}
1504e390cabSriastradh 
1514e390cabSriastradh 	*pos &= (1UL << 22) - 1;
1524e390cabSriastradh 
1534e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
1544e390cabSriastradh 	if (r < 0)
1554e390cabSriastradh 		return r;
1564e390cabSriastradh 
1574e390cabSriastradh 	if (use_bank) {
1584e390cabSriastradh 		if ((sh_bank != 0xFFFFFFFF && sh_bank >= adev->gfx.config.max_sh_per_se) ||
1594e390cabSriastradh 		    (se_bank != 0xFFFFFFFF && se_bank >= adev->gfx.config.max_shader_engines)) {
1604e390cabSriastradh 			pm_runtime_mark_last_busy(adev->ddev->dev);
1614e390cabSriastradh 			pm_runtime_put_autosuspend(adev->ddev->dev);
1624e390cabSriastradh 			return -EINVAL;
1634e390cabSriastradh 		}
1644e390cabSriastradh 		mutex_lock(&adev->grbm_idx_mutex);
1654e390cabSriastradh 		amdgpu_gfx_select_se_sh(adev, se_bank,
1664e390cabSriastradh 					sh_bank, instance_bank);
1674e390cabSriastradh 	} else if (use_ring) {
1684e390cabSriastradh 		mutex_lock(&adev->srbm_mutex);
1694e390cabSriastradh 		amdgpu_gfx_select_me_pipe_q(adev, me, pipe, queue, vmid);
1704e390cabSriastradh 	}
1714e390cabSriastradh 
1724e390cabSriastradh 	if (pm_pg_lock)
1734e390cabSriastradh 		mutex_lock(&adev->pm.mutex);
1744e390cabSriastradh 
1754e390cabSriastradh 	while (size) {
1764e390cabSriastradh 		uint32_t value;
1774e390cabSriastradh 
1784e390cabSriastradh 		if (read) {
1794e390cabSriastradh 			value = RREG32(*pos >> 2);
1804e390cabSriastradh 			r = put_user(value, (uint32_t *)buf);
1814e390cabSriastradh 		} else {
1824e390cabSriastradh 			r = get_user(value, (uint32_t *)buf);
1834e390cabSriastradh 			if (!r)
1844e390cabSriastradh 				WREG32(*pos >> 2, value);
1854e390cabSriastradh 		}
1864e390cabSriastradh 		if (r) {
1874e390cabSriastradh 			result = r;
1884e390cabSriastradh 			goto end;
1894e390cabSriastradh 		}
1904e390cabSriastradh 
1914e390cabSriastradh 		result += 4;
1924e390cabSriastradh 		buf += 4;
1934e390cabSriastradh 		*pos += 4;
1944e390cabSriastradh 		size -= 4;
1954e390cabSriastradh 	}
1964e390cabSriastradh 
1974e390cabSriastradh end:
1984e390cabSriastradh 	if (use_bank) {
1994e390cabSriastradh 		amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
2004e390cabSriastradh 		mutex_unlock(&adev->grbm_idx_mutex);
2014e390cabSriastradh 	} else if (use_ring) {
2024e390cabSriastradh 		amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
2034e390cabSriastradh 		mutex_unlock(&adev->srbm_mutex);
2044e390cabSriastradh 	}
2054e390cabSriastradh 
2064e390cabSriastradh 	if (pm_pg_lock)
2074e390cabSriastradh 		mutex_unlock(&adev->pm.mutex);
2084e390cabSriastradh 
2094e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
2104e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
2114e390cabSriastradh 
2124e390cabSriastradh 	return result;
2134e390cabSriastradh }
2144e390cabSriastradh 
2154e390cabSriastradh /**
2164e390cabSriastradh  * amdgpu_debugfs_regs_read - Callback for reading MMIO registers
2174e390cabSriastradh  */
amdgpu_debugfs_regs_read(struct file * f,char __user * buf,size_t size,loff_t * pos)2184e390cabSriastradh static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf,
2194e390cabSriastradh 					size_t size, loff_t *pos)
2204e390cabSriastradh {
2214e390cabSriastradh 	return amdgpu_debugfs_process_reg_op(true, f, buf, size, pos);
2224e390cabSriastradh }
2234e390cabSriastradh 
2244e390cabSriastradh /**
2254e390cabSriastradh  * amdgpu_debugfs_regs_write - Callback for writing MMIO registers
2264e390cabSriastradh  */
amdgpu_debugfs_regs_write(struct file * f,const char __user * buf,size_t size,loff_t * pos)2274e390cabSriastradh static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
2284e390cabSriastradh 					 size_t size, loff_t *pos)
2294e390cabSriastradh {
2304e390cabSriastradh 	return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos);
2314e390cabSriastradh }
2324e390cabSriastradh 
2334e390cabSriastradh 
2344e390cabSriastradh /**
2354e390cabSriastradh  * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register
2364e390cabSriastradh  *
2374e390cabSriastradh  * @f: open file handle
2384e390cabSriastradh  * @buf: User buffer to store read data in
2394e390cabSriastradh  * @size: Number of bytes to read
2404e390cabSriastradh  * @pos:  Offset to seek to
2414e390cabSriastradh  *
2424e390cabSriastradh  * The lower bits are the BYTE offset of the register to read.  This
2434e390cabSriastradh  * allows reading multiple registers in a single call and having
2444e390cabSriastradh  * the returned size reflect that.
2454e390cabSriastradh  */
amdgpu_debugfs_regs_pcie_read(struct file * f,char __user * buf,size_t size,loff_t * pos)2464e390cabSriastradh static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf,
2474e390cabSriastradh 					size_t size, loff_t *pos)
2484e390cabSriastradh {
2494e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
2504e390cabSriastradh 	ssize_t result = 0;
2514e390cabSriastradh 	int r;
2524e390cabSriastradh 
2534e390cabSriastradh 	if (size & 0x3 || *pos & 0x3)
2544e390cabSriastradh 		return -EINVAL;
2554e390cabSriastradh 
2564e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
2574e390cabSriastradh 	if (r < 0)
2584e390cabSriastradh 		return r;
2594e390cabSriastradh 
2604e390cabSriastradh 	while (size) {
2614e390cabSriastradh 		uint32_t value;
2624e390cabSriastradh 
2634e390cabSriastradh 		value = RREG32_PCIE(*pos >> 2);
2644e390cabSriastradh 		r = put_user(value, (uint32_t *)buf);
2654e390cabSriastradh 		if (r) {
2664e390cabSriastradh 			pm_runtime_mark_last_busy(adev->ddev->dev);
2674e390cabSriastradh 			pm_runtime_put_autosuspend(adev->ddev->dev);
2684e390cabSriastradh 			return r;
2694e390cabSriastradh 		}
2704e390cabSriastradh 
2714e390cabSriastradh 		result += 4;
2724e390cabSriastradh 		buf += 4;
2734e390cabSriastradh 		*pos += 4;
2744e390cabSriastradh 		size -= 4;
2754e390cabSriastradh 	}
2764e390cabSriastradh 
2774e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
2784e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
2794e390cabSriastradh 
2804e390cabSriastradh 	return result;
2814e390cabSriastradh }
2824e390cabSriastradh 
2834e390cabSriastradh /**
2844e390cabSriastradh  * amdgpu_debugfs_regs_pcie_write - Write to a PCIE register
2854e390cabSriastradh  *
2864e390cabSriastradh  * @f: open file handle
2874e390cabSriastradh  * @buf: User buffer to write data from
2884e390cabSriastradh  * @size: Number of bytes to write
2894e390cabSriastradh  * @pos:  Offset to seek to
2904e390cabSriastradh  *
2914e390cabSriastradh  * The lower bits are the BYTE offset of the register to write.  This
2924e390cabSriastradh  * allows writing multiple registers in a single call and having
2934e390cabSriastradh  * the returned size reflect that.
2944e390cabSriastradh  */
amdgpu_debugfs_regs_pcie_write(struct file * f,const char __user * buf,size_t size,loff_t * pos)2954e390cabSriastradh static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user *buf,
2964e390cabSriastradh 					 size_t size, loff_t *pos)
2974e390cabSriastradh {
2984e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
2994e390cabSriastradh 	ssize_t result = 0;
3004e390cabSriastradh 	int r;
3014e390cabSriastradh 
3024e390cabSriastradh 	if (size & 0x3 || *pos & 0x3)
3034e390cabSriastradh 		return -EINVAL;
3044e390cabSriastradh 
3054e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
3064e390cabSriastradh 	if (r < 0)
3074e390cabSriastradh 		return r;
3084e390cabSriastradh 
3094e390cabSriastradh 	while (size) {
3104e390cabSriastradh 		uint32_t value;
3114e390cabSriastradh 
3124e390cabSriastradh 		r = get_user(value, (uint32_t *)buf);
3134e390cabSriastradh 		if (r) {
3144e390cabSriastradh 			pm_runtime_mark_last_busy(adev->ddev->dev);
3154e390cabSriastradh 			pm_runtime_put_autosuspend(adev->ddev->dev);
3164e390cabSriastradh 			return r;
3174e390cabSriastradh 		}
3184e390cabSriastradh 
3194e390cabSriastradh 		WREG32_PCIE(*pos >> 2, value);
3204e390cabSriastradh 
3214e390cabSriastradh 		result += 4;
3224e390cabSriastradh 		buf += 4;
3234e390cabSriastradh 		*pos += 4;
3244e390cabSriastradh 		size -= 4;
3254e390cabSriastradh 	}
3264e390cabSriastradh 
3274e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
3284e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
3294e390cabSriastradh 
3304e390cabSriastradh 	return result;
3314e390cabSriastradh }
3324e390cabSriastradh 
3334e390cabSriastradh /**
3344e390cabSriastradh  * amdgpu_debugfs_regs_didt_read - Read from a DIDT register
3354e390cabSriastradh  *
3364e390cabSriastradh  * @f: open file handle
3374e390cabSriastradh  * @buf: User buffer to store read data in
3384e390cabSriastradh  * @size: Number of bytes to read
3394e390cabSriastradh  * @pos:  Offset to seek to
3404e390cabSriastradh  *
3414e390cabSriastradh  * The lower bits are the BYTE offset of the register to read.  This
3424e390cabSriastradh  * allows reading multiple registers in a single call and having
3434e390cabSriastradh  * the returned size reflect that.
3444e390cabSriastradh  */
amdgpu_debugfs_regs_didt_read(struct file * f,char __user * buf,size_t size,loff_t * pos)3454e390cabSriastradh static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf,
3464e390cabSriastradh 					size_t size, loff_t *pos)
3474e390cabSriastradh {
3484e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
3494e390cabSriastradh 	ssize_t result = 0;
3504e390cabSriastradh 	int r;
3514e390cabSriastradh 
3524e390cabSriastradh 	if (size & 0x3 || *pos & 0x3)
3534e390cabSriastradh 		return -EINVAL;
3544e390cabSriastradh 
3554e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
3564e390cabSriastradh 	if (r < 0)
3574e390cabSriastradh 		return r;
3584e390cabSriastradh 
3594e390cabSriastradh 	while (size) {
3604e390cabSriastradh 		uint32_t value;
3614e390cabSriastradh 
3624e390cabSriastradh 		value = RREG32_DIDT(*pos >> 2);
3634e390cabSriastradh 		r = put_user(value, (uint32_t *)buf);
3644e390cabSriastradh 		if (r) {
3654e390cabSriastradh 			pm_runtime_mark_last_busy(adev->ddev->dev);
3664e390cabSriastradh 			pm_runtime_put_autosuspend(adev->ddev->dev);
3674e390cabSriastradh 			return r;
3684e390cabSriastradh 		}
3694e390cabSriastradh 
3704e390cabSriastradh 		result += 4;
3714e390cabSriastradh 		buf += 4;
3724e390cabSriastradh 		*pos += 4;
3734e390cabSriastradh 		size -= 4;
3744e390cabSriastradh 	}
3754e390cabSriastradh 
3764e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
3774e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
3784e390cabSriastradh 
3794e390cabSriastradh 	return result;
3804e390cabSriastradh }
3814e390cabSriastradh 
3824e390cabSriastradh /**
3834e390cabSriastradh  * amdgpu_debugfs_regs_didt_write - Write to a DIDT register
3844e390cabSriastradh  *
3854e390cabSriastradh  * @f: open file handle
3864e390cabSriastradh  * @buf: User buffer to write data from
3874e390cabSriastradh  * @size: Number of bytes to write
3884e390cabSriastradh  * @pos:  Offset to seek to
3894e390cabSriastradh  *
3904e390cabSriastradh  * The lower bits are the BYTE offset of the register to write.  This
3914e390cabSriastradh  * allows writing multiple registers in a single call and having
3924e390cabSriastradh  * the returned size reflect that.
3934e390cabSriastradh  */
amdgpu_debugfs_regs_didt_write(struct file * f,const char __user * buf,size_t size,loff_t * pos)3944e390cabSriastradh static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user *buf,
3954e390cabSriastradh 					 size_t size, loff_t *pos)
3964e390cabSriastradh {
3974e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
3984e390cabSriastradh 	ssize_t result = 0;
3994e390cabSriastradh 	int r;
4004e390cabSriastradh 
4014e390cabSriastradh 	if (size & 0x3 || *pos & 0x3)
4024e390cabSriastradh 		return -EINVAL;
4034e390cabSriastradh 
4044e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
4054e390cabSriastradh 	if (r < 0)
4064e390cabSriastradh 		return r;
4074e390cabSriastradh 
4084e390cabSriastradh 	while (size) {
4094e390cabSriastradh 		uint32_t value;
4104e390cabSriastradh 
4114e390cabSriastradh 		r = get_user(value, (uint32_t *)buf);
4124e390cabSriastradh 		if (r) {
4134e390cabSriastradh 			pm_runtime_mark_last_busy(adev->ddev->dev);
4144e390cabSriastradh 			pm_runtime_put_autosuspend(adev->ddev->dev);
4154e390cabSriastradh 			return r;
4164e390cabSriastradh 		}
4174e390cabSriastradh 
4184e390cabSriastradh 		WREG32_DIDT(*pos >> 2, value);
4194e390cabSriastradh 
4204e390cabSriastradh 		result += 4;
4214e390cabSriastradh 		buf += 4;
4224e390cabSriastradh 		*pos += 4;
4234e390cabSriastradh 		size -= 4;
4244e390cabSriastradh 	}
4254e390cabSriastradh 
4264e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
4274e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
4284e390cabSriastradh 
4294e390cabSriastradh 	return result;
4304e390cabSriastradh }
4314e390cabSriastradh 
4324e390cabSriastradh /**
4334e390cabSriastradh  * amdgpu_debugfs_regs_smc_read - Read from a SMC register
4344e390cabSriastradh  *
4354e390cabSriastradh  * @f: open file handle
4364e390cabSriastradh  * @buf: User buffer to store read data in
4374e390cabSriastradh  * @size: Number of bytes to read
4384e390cabSriastradh  * @pos:  Offset to seek to
4394e390cabSriastradh  *
4404e390cabSriastradh  * The lower bits are the BYTE offset of the register to read.  This
4414e390cabSriastradh  * allows reading multiple registers in a single call and having
4424e390cabSriastradh  * the returned size reflect that.
4434e390cabSriastradh  */
amdgpu_debugfs_regs_smc_read(struct file * f,char __user * buf,size_t size,loff_t * pos)4444e390cabSriastradh static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf,
4454e390cabSriastradh 					size_t size, loff_t *pos)
4464e390cabSriastradh {
4474e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
4484e390cabSriastradh 	ssize_t result = 0;
4494e390cabSriastradh 	int r;
4504e390cabSriastradh 
4514e390cabSriastradh 	if (size & 0x3 || *pos & 0x3)
4524e390cabSriastradh 		return -EINVAL;
4534e390cabSriastradh 
4544e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
4554e390cabSriastradh 	if (r < 0)
4564e390cabSriastradh 		return r;
4574e390cabSriastradh 
4584e390cabSriastradh 	while (size) {
4594e390cabSriastradh 		uint32_t value;
4604e390cabSriastradh 
4614e390cabSriastradh 		value = RREG32_SMC(*pos);
4624e390cabSriastradh 		r = put_user(value, (uint32_t *)buf);
4634e390cabSriastradh 		if (r) {
4644e390cabSriastradh 			pm_runtime_mark_last_busy(adev->ddev->dev);
4654e390cabSriastradh 			pm_runtime_put_autosuspend(adev->ddev->dev);
4664e390cabSriastradh 			return r;
4674e390cabSriastradh 		}
4684e390cabSriastradh 
4694e390cabSriastradh 		result += 4;
4704e390cabSriastradh 		buf += 4;
4714e390cabSriastradh 		*pos += 4;
4724e390cabSriastradh 		size -= 4;
4734e390cabSriastradh 	}
4744e390cabSriastradh 
4754e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
4764e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
4774e390cabSriastradh 
4784e390cabSriastradh 	return result;
4794e390cabSriastradh }
4804e390cabSriastradh 
4814e390cabSriastradh /**
4824e390cabSriastradh  * amdgpu_debugfs_regs_smc_write - Write to a SMC register
4834e390cabSriastradh  *
4844e390cabSriastradh  * @f: open file handle
4854e390cabSriastradh  * @buf: User buffer to write data from
4864e390cabSriastradh  * @size: Number of bytes to write
4874e390cabSriastradh  * @pos:  Offset to seek to
4884e390cabSriastradh  *
4894e390cabSriastradh  * The lower bits are the BYTE offset of the register to write.  This
4904e390cabSriastradh  * allows writing multiple registers in a single call and having
4914e390cabSriastradh  * the returned size reflect that.
4924e390cabSriastradh  */
amdgpu_debugfs_regs_smc_write(struct file * f,const char __user * buf,size_t size,loff_t * pos)4934e390cabSriastradh static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *buf,
4944e390cabSriastradh 					 size_t size, loff_t *pos)
4954e390cabSriastradh {
4964e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
4974e390cabSriastradh 	ssize_t result = 0;
4984e390cabSriastradh 	int r;
4994e390cabSriastradh 
5004e390cabSriastradh 	if (size & 0x3 || *pos & 0x3)
5014e390cabSriastradh 		return -EINVAL;
5024e390cabSriastradh 
5034e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
5044e390cabSriastradh 	if (r < 0)
5054e390cabSriastradh 		return r;
5064e390cabSriastradh 
5074e390cabSriastradh 	while (size) {
5084e390cabSriastradh 		uint32_t value;
5094e390cabSriastradh 
5104e390cabSriastradh 		r = get_user(value, (uint32_t *)buf);
5114e390cabSriastradh 		if (r) {
5124e390cabSriastradh 			pm_runtime_mark_last_busy(adev->ddev->dev);
5134e390cabSriastradh 			pm_runtime_put_autosuspend(adev->ddev->dev);
5144e390cabSriastradh 			return r;
5154e390cabSriastradh 		}
5164e390cabSriastradh 
5174e390cabSriastradh 		WREG32_SMC(*pos, value);
5184e390cabSriastradh 
5194e390cabSriastradh 		result += 4;
5204e390cabSriastradh 		buf += 4;
5214e390cabSriastradh 		*pos += 4;
5224e390cabSriastradh 		size -= 4;
5234e390cabSriastradh 	}
5244e390cabSriastradh 
5254e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
5264e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
5274e390cabSriastradh 
5284e390cabSriastradh 	return result;
5294e390cabSriastradh }
5304e390cabSriastradh 
5314e390cabSriastradh /**
5324e390cabSriastradh  * amdgpu_debugfs_gca_config_read - Read from gfx config data
5334e390cabSriastradh  *
5344e390cabSriastradh  * @f: open file handle
5354e390cabSriastradh  * @buf: User buffer to store read data in
5364e390cabSriastradh  * @size: Number of bytes to read
5374e390cabSriastradh  * @pos:  Offset to seek to
5384e390cabSriastradh  *
5394e390cabSriastradh  * This file is used to access configuration data in a somewhat
5404e390cabSriastradh  * stable fashion.  The format is a series of DWORDs with the first
5414e390cabSriastradh  * indicating which revision it is.  New content is appended to the
5424e390cabSriastradh  * end so that older software can still read the data.
5434e390cabSriastradh  */
5444e390cabSriastradh 
amdgpu_debugfs_gca_config_read(struct file * f,char __user * buf,size_t size,loff_t * pos)5454e390cabSriastradh static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
5464e390cabSriastradh 					size_t size, loff_t *pos)
5474e390cabSriastradh {
5484e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
5494e390cabSriastradh 	ssize_t result = 0;
5504e390cabSriastradh 	int r;
5514e390cabSriastradh 	uint32_t *config, no_regs = 0;
5524e390cabSriastradh 
5534e390cabSriastradh 	if (size & 0x3 || *pos & 0x3)
5544e390cabSriastradh 		return -EINVAL;
5554e390cabSriastradh 
5564e390cabSriastradh 	config = kmalloc_array(256, sizeof(*config), GFP_KERNEL);
5574e390cabSriastradh 	if (!config)
5584e390cabSriastradh 		return -ENOMEM;
5594e390cabSriastradh 
5604e390cabSriastradh 	/* version, increment each time something is added */
5614e390cabSriastradh 	config[no_regs++] = 3;
5624e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_shader_engines;
5634e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_tile_pipes;
5644e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_cu_per_sh;
5654e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_sh_per_se;
5664e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_backends_per_se;
5674e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_texture_channel_caches;
5684e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_gprs;
5694e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_gs_threads;
5704e390cabSriastradh 	config[no_regs++] = adev->gfx.config.max_hw_contexts;
5714e390cabSriastradh 	config[no_regs++] = adev->gfx.config.sc_prim_fifo_size_frontend;
5724e390cabSriastradh 	config[no_regs++] = adev->gfx.config.sc_prim_fifo_size_backend;
5734e390cabSriastradh 	config[no_regs++] = adev->gfx.config.sc_hiz_tile_fifo_size;
5744e390cabSriastradh 	config[no_regs++] = adev->gfx.config.sc_earlyz_tile_fifo_size;
5754e390cabSriastradh 	config[no_regs++] = adev->gfx.config.num_tile_pipes;
5764e390cabSriastradh 	config[no_regs++] = adev->gfx.config.backend_enable_mask;
5774e390cabSriastradh 	config[no_regs++] = adev->gfx.config.mem_max_burst_length_bytes;
5784e390cabSriastradh 	config[no_regs++] = adev->gfx.config.mem_row_size_in_kb;
5794e390cabSriastradh 	config[no_regs++] = adev->gfx.config.shader_engine_tile_size;
5804e390cabSriastradh 	config[no_regs++] = adev->gfx.config.num_gpus;
5814e390cabSriastradh 	config[no_regs++] = adev->gfx.config.multi_gpu_tile_size;
5824e390cabSriastradh 	config[no_regs++] = adev->gfx.config.mc_arb_ramcfg;
5834e390cabSriastradh 	config[no_regs++] = adev->gfx.config.gb_addr_config;
5844e390cabSriastradh 	config[no_regs++] = adev->gfx.config.num_rbs;
5854e390cabSriastradh 
5864e390cabSriastradh 	/* rev==1 */
5874e390cabSriastradh 	config[no_regs++] = adev->rev_id;
5884e390cabSriastradh 	config[no_regs++] = adev->pg_flags;
5894e390cabSriastradh 	config[no_regs++] = adev->cg_flags;
5904e390cabSriastradh 
5914e390cabSriastradh 	/* rev==2 */
5924e390cabSriastradh 	config[no_regs++] = adev->family;
5934e390cabSriastradh 	config[no_regs++] = adev->external_rev_id;
5944e390cabSriastradh 
5954e390cabSriastradh 	/* rev==3 */
5964e390cabSriastradh 	config[no_regs++] = adev->pdev->device;
5974e390cabSriastradh 	config[no_regs++] = adev->pdev->revision;
5984e390cabSriastradh 	config[no_regs++] = adev->pdev->subsystem_device;
5994e390cabSriastradh 	config[no_regs++] = adev->pdev->subsystem_vendor;
6004e390cabSriastradh 
6014e390cabSriastradh 	while (size && (*pos < no_regs * 4)) {
6024e390cabSriastradh 		uint32_t value;
6034e390cabSriastradh 
6044e390cabSriastradh 		value = config[*pos >> 2];
6054e390cabSriastradh 		r = put_user(value, (uint32_t *)buf);
6064e390cabSriastradh 		if (r) {
6074e390cabSriastradh 			kfree(config);
6084e390cabSriastradh 			return r;
6094e390cabSriastradh 		}
6104e390cabSriastradh 
6114e390cabSriastradh 		result += 4;
6124e390cabSriastradh 		buf += 4;
6134e390cabSriastradh 		*pos += 4;
6144e390cabSriastradh 		size -= 4;
6154e390cabSriastradh 	}
6164e390cabSriastradh 
6174e390cabSriastradh 	kfree(config);
6184e390cabSriastradh 	return result;
6194e390cabSriastradh }
6204e390cabSriastradh 
6214e390cabSriastradh /**
6224e390cabSriastradh  * amdgpu_debugfs_sensor_read - Read from the powerplay sensors
6234e390cabSriastradh  *
6244e390cabSriastradh  * @f: open file handle
6254e390cabSriastradh  * @buf: User buffer to store read data in
6264e390cabSriastradh  * @size: Number of bytes to read
6274e390cabSriastradh  * @pos:  Offset to seek to
6284e390cabSriastradh  *
6294e390cabSriastradh  * The offset is treated as the BYTE address of one of the sensors
6304e390cabSriastradh  * enumerated in amd/include/kgd_pp_interface.h under the
6314e390cabSriastradh  * 'amd_pp_sensors' enumeration.  For instance to read the UVD VCLK
6324e390cabSriastradh  * you would use the offset 3 * 4 = 12.
6334e390cabSriastradh  */
amdgpu_debugfs_sensor_read(struct file * f,char __user * buf,size_t size,loff_t * pos)6344e390cabSriastradh static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,
6354e390cabSriastradh 					size_t size, loff_t *pos)
6364e390cabSriastradh {
6374e390cabSriastradh 	struct amdgpu_device *adev = file_inode(f)->i_private;
6384e390cabSriastradh 	int idx, x, outsize, r, valuesize;
6394e390cabSriastradh 	uint32_t values[16];
6404e390cabSriastradh 
6414e390cabSriastradh 	if (size & 3 || *pos & 0x3)
6424e390cabSriastradh 		return -EINVAL;
6434e390cabSriastradh 
6444e390cabSriastradh 	if (!adev->pm.dpm_enabled)
6454e390cabSriastradh 		return -EINVAL;
6464e390cabSriastradh 
6474e390cabSriastradh 	/* convert offset to sensor number */
6484e390cabSriastradh 	idx = *pos >> 2;
6494e390cabSriastradh 
6504e390cabSriastradh 	valuesize = sizeof(values);
6514e390cabSriastradh 
6524e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
6534e390cabSriastradh 	if (r < 0)
6544e390cabSriastradh 		return r;
6554e390cabSriastradh 
6564e390cabSriastradh 	r = amdgpu_dpm_read_sensor(adev, idx, &values[0], &valuesize);
6574e390cabSriastradh 
6584e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
6594e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
6604e390cabSriastradh 
6614e390cabSriastradh 	if (r)
6624e390cabSriastradh 		return r;
6634e390cabSriastradh 
6644e390cabSriastradh 	if (size > valuesize)
6654e390cabSriastradh 		return -EINVAL;
6664e390cabSriastradh 
6674e390cabSriastradh 	outsize = 0;
6684e390cabSriastradh 	x = 0;
6694e390cabSriastradh 	if (!r) {
6704e390cabSriastradh 		while (size) {
6714e390cabSriastradh 			r = put_user(values[x++], (int32_t *)buf);
6724e390cabSriastradh 			buf += 4;
6734e390cabSriastradh 			size -= 4;
6744e390cabSriastradh 			outsize += 4;
6754e390cabSriastradh 		}
6764e390cabSriastradh 	}
6774e390cabSriastradh 
6784e390cabSriastradh 	return !r ? outsize : r;
6794e390cabSriastradh }
6804e390cabSriastradh 
6814e390cabSriastradh /** amdgpu_debugfs_wave_read - Read WAVE STATUS data
6824e390cabSriastradh  *
6834e390cabSriastradh  * @f: open file handle
6844e390cabSriastradh  * @buf: User buffer to store read data in
6854e390cabSriastradh  * @size: Number of bytes to read
6864e390cabSriastradh  * @pos:  Offset to seek to
6874e390cabSriastradh  *
6884e390cabSriastradh  * The offset being sought changes which wave that the status data
6894e390cabSriastradh  * will be returned for.  The bits are used as follows:
6904e390cabSriastradh  *
6914e390cabSriastradh  * Bits 0..6: 	Byte offset into data
6924e390cabSriastradh  * Bits 7..14:	SE selector
6934e390cabSriastradh  * Bits 15..22:	SH/SA selector
6944e390cabSriastradh  * Bits 23..30: CU/{WGP+SIMD} selector
6954e390cabSriastradh  * Bits 31..36: WAVE ID selector
6964e390cabSriastradh  * Bits 37..44: SIMD ID selector
6974e390cabSriastradh  *
6984e390cabSriastradh  * The returned data begins with one DWORD of version information
6994e390cabSriastradh  * Followed by WAVE STATUS registers relevant to the GFX IP version
7004e390cabSriastradh  * being used.  See gfx_v8_0_read_wave_data() for an example output.
7014e390cabSriastradh  */
amdgpu_debugfs_wave_read(struct file * f,char __user * buf,size_t size,loff_t * pos)7024e390cabSriastradh static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf,
7034e390cabSriastradh 					size_t size, loff_t *pos)
7044e390cabSriastradh {
7054e390cabSriastradh 	struct amdgpu_device *adev = f->f_inode->i_private;
7064e390cabSriastradh 	int r, x;
7074e390cabSriastradh 	ssize_t result=0;
7084e390cabSriastradh 	uint32_t offset, se, sh, cu, wave, simd, data[32];
7094e390cabSriastradh 
7104e390cabSriastradh 	if (size & 3 || *pos & 3)
7114e390cabSriastradh 		return -EINVAL;
7124e390cabSriastradh 
7134e390cabSriastradh 	/* decode offset */
7144e390cabSriastradh 	offset = (*pos & GENMASK_ULL(6, 0));
7154e390cabSriastradh 	se = (*pos & GENMASK_ULL(14, 7)) >> 7;
7164e390cabSriastradh 	sh = (*pos & GENMASK_ULL(22, 15)) >> 15;
7174e390cabSriastradh 	cu = (*pos & GENMASK_ULL(30, 23)) >> 23;
7184e390cabSriastradh 	wave = (*pos & GENMASK_ULL(36, 31)) >> 31;
7194e390cabSriastradh 	simd = (*pos & GENMASK_ULL(44, 37)) >> 37;
7204e390cabSriastradh 
7214e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
7224e390cabSriastradh 	if (r < 0)
7234e390cabSriastradh 		return r;
7244e390cabSriastradh 
7254e390cabSriastradh 	/* switch to the specific se/sh/cu */
7264e390cabSriastradh 	mutex_lock(&adev->grbm_idx_mutex);
7274e390cabSriastradh 	amdgpu_gfx_select_se_sh(adev, se, sh, cu);
7284e390cabSriastradh 
7294e390cabSriastradh 	x = 0;
7304e390cabSriastradh 	if (adev->gfx.funcs->read_wave_data)
7314e390cabSriastradh 		adev->gfx.funcs->read_wave_data(adev, simd, wave, data, &x);
7324e390cabSriastradh 
7334e390cabSriastradh 	amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
7344e390cabSriastradh 	mutex_unlock(&adev->grbm_idx_mutex);
7354e390cabSriastradh 
7364e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
7374e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
7384e390cabSriastradh 
7394e390cabSriastradh 	if (!x)
7404e390cabSriastradh 		return -EINVAL;
7414e390cabSriastradh 
7424e390cabSriastradh 	while (size && (offset < x * 4)) {
7434e390cabSriastradh 		uint32_t value;
7444e390cabSriastradh 
7454e390cabSriastradh 		value = data[offset >> 2];
7464e390cabSriastradh 		r = put_user(value, (uint32_t *)buf);
7474e390cabSriastradh 		if (r)
7484e390cabSriastradh 			return r;
7494e390cabSriastradh 
7504e390cabSriastradh 		result += 4;
7514e390cabSriastradh 		buf += 4;
7524e390cabSriastradh 		offset += 4;
7534e390cabSriastradh 		size -= 4;
7544e390cabSriastradh 	}
7554e390cabSriastradh 
7564e390cabSriastradh 	return result;
7574e390cabSriastradh }
7584e390cabSriastradh 
7594e390cabSriastradh /** amdgpu_debugfs_gpr_read - Read wave gprs
7604e390cabSriastradh  *
7614e390cabSriastradh  * @f: open file handle
7624e390cabSriastradh  * @buf: User buffer to store read data in
7634e390cabSriastradh  * @size: Number of bytes to read
7644e390cabSriastradh  * @pos:  Offset to seek to
7654e390cabSriastradh  *
7664e390cabSriastradh  * The offset being sought changes which wave that the status data
7674e390cabSriastradh  * will be returned for.  The bits are used as follows:
7684e390cabSriastradh  *
7694e390cabSriastradh  * Bits 0..11:	Byte offset into data
7704e390cabSriastradh  * Bits 12..19:	SE selector
7714e390cabSriastradh  * Bits 20..27:	SH/SA selector
7724e390cabSriastradh  * Bits 28..35: CU/{WGP+SIMD} selector
7734e390cabSriastradh  * Bits 36..43: WAVE ID selector
7744e390cabSriastradh  * Bits 37..44: SIMD ID selector
7754e390cabSriastradh  * Bits 52..59: Thread selector
7764e390cabSriastradh  * Bits 60..61: Bank selector (VGPR=0,SGPR=1)
7774e390cabSriastradh  *
7784e390cabSriastradh  * The return data comes from the SGPR or VGPR register bank for
7794e390cabSriastradh  * the selected operational unit.
7804e390cabSriastradh  */
amdgpu_debugfs_gpr_read(struct file * f,char __user * buf,size_t size,loff_t * pos)7814e390cabSriastradh static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
7824e390cabSriastradh 					size_t size, loff_t *pos)
7834e390cabSriastradh {
7844e390cabSriastradh 	struct amdgpu_device *adev = f->f_inode->i_private;
7854e390cabSriastradh 	int r;
7864e390cabSriastradh 	ssize_t result = 0;
7874e390cabSriastradh 	uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data;
7884e390cabSriastradh 
7894e390cabSriastradh 	if (size & 3 || *pos & 3)
7904e390cabSriastradh 		return -EINVAL;
7914e390cabSriastradh 
7924e390cabSriastradh 	/* decode offset */
7934e390cabSriastradh 	offset = *pos & GENMASK_ULL(11, 0);
7944e390cabSriastradh 	se = (*pos & GENMASK_ULL(19, 12)) >> 12;
7954e390cabSriastradh 	sh = (*pos & GENMASK_ULL(27, 20)) >> 20;
7964e390cabSriastradh 	cu = (*pos & GENMASK_ULL(35, 28)) >> 28;
7974e390cabSriastradh 	wave = (*pos & GENMASK_ULL(43, 36)) >> 36;
7984e390cabSriastradh 	simd = (*pos & GENMASK_ULL(51, 44)) >> 44;
7994e390cabSriastradh 	thread = (*pos & GENMASK_ULL(59, 52)) >> 52;
8004e390cabSriastradh 	bank = (*pos & GENMASK_ULL(61, 60)) >> 60;
8014e390cabSriastradh 
8024e390cabSriastradh 	data = kcalloc(1024, sizeof(*data), GFP_KERNEL);
8034e390cabSriastradh 	if (!data)
8044e390cabSriastradh 		return -ENOMEM;
8054e390cabSriastradh 
8064e390cabSriastradh 	r = pm_runtime_get_sync(adev->ddev->dev);
8074e390cabSriastradh 	if (r < 0)
8084e390cabSriastradh 		return r;
8094e390cabSriastradh 
8104e390cabSriastradh 	/* switch to the specific se/sh/cu */
8114e390cabSriastradh 	mutex_lock(&adev->grbm_idx_mutex);
8124e390cabSriastradh 	amdgpu_gfx_select_se_sh(adev, se, sh, cu);
8134e390cabSriastradh 
8144e390cabSriastradh 	if (bank == 0) {
8154e390cabSriastradh 		if (adev->gfx.funcs->read_wave_vgprs)
8164e390cabSriastradh 			adev->gfx.funcs->read_wave_vgprs(adev, simd, wave, thread, offset, size>>2, data);
8174e390cabSriastradh 	} else {
8184e390cabSriastradh 		if (adev->gfx.funcs->read_wave_sgprs)
8194e390cabSriastradh 			adev->gfx.funcs->read_wave_sgprs(adev, simd, wave, offset, size>>2, data);
8204e390cabSriastradh 	}
8214e390cabSriastradh 
8224e390cabSriastradh 	amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
8234e390cabSriastradh 	mutex_unlock(&adev->grbm_idx_mutex);
8244e390cabSriastradh 
8254e390cabSriastradh 	pm_runtime_mark_last_busy(adev->ddev->dev);
8264e390cabSriastradh 	pm_runtime_put_autosuspend(adev->ddev->dev);
8274e390cabSriastradh 
8284e390cabSriastradh 	while (size) {
8294e390cabSriastradh 		uint32_t value;
8304e390cabSriastradh 
8314e390cabSriastradh 		value = data[offset++];
8324e390cabSriastradh 		r = put_user(value, (uint32_t *)buf);
8334e390cabSriastradh 		if (r) {
8344e390cabSriastradh 			result = r;
8354e390cabSriastradh 			goto err;
8364e390cabSriastradh 		}
8374e390cabSriastradh 
8384e390cabSriastradh 		result += 4;
8394e390cabSriastradh 		buf += 4;
8404e390cabSriastradh 		size -= 4;
8414e390cabSriastradh 	}
8424e390cabSriastradh 
8434e390cabSriastradh err:
8444e390cabSriastradh 	kfree(data);
8454e390cabSriastradh 	return result;
8464e390cabSriastradh }
8474e390cabSriastradh 
8484e390cabSriastradh static const struct file_operations amdgpu_debugfs_regs_fops = {
8494e390cabSriastradh 	.owner = THIS_MODULE,
8504e390cabSriastradh 	.read = amdgpu_debugfs_regs_read,
8514e390cabSriastradh 	.write = amdgpu_debugfs_regs_write,
8524e390cabSriastradh 	.llseek = default_llseek
8534e390cabSriastradh };
8544e390cabSriastradh static const struct file_operations amdgpu_debugfs_regs_didt_fops = {
8554e390cabSriastradh 	.owner = THIS_MODULE,
8564e390cabSriastradh 	.read = amdgpu_debugfs_regs_didt_read,
8574e390cabSriastradh 	.write = amdgpu_debugfs_regs_didt_write,
8584e390cabSriastradh 	.llseek = default_llseek
8594e390cabSriastradh };
8604e390cabSriastradh static const struct file_operations amdgpu_debugfs_regs_pcie_fops = {
8614e390cabSriastradh 	.owner = THIS_MODULE,
8624e390cabSriastradh 	.read = amdgpu_debugfs_regs_pcie_read,
8634e390cabSriastradh 	.write = amdgpu_debugfs_regs_pcie_write,
8644e390cabSriastradh 	.llseek = default_llseek
8654e390cabSriastradh };
8664e390cabSriastradh static const struct file_operations amdgpu_debugfs_regs_smc_fops = {
8674e390cabSriastradh 	.owner = THIS_MODULE,
8684e390cabSriastradh 	.read = amdgpu_debugfs_regs_smc_read,
8694e390cabSriastradh 	.write = amdgpu_debugfs_regs_smc_write,
8704e390cabSriastradh 	.llseek = default_llseek
8714e390cabSriastradh };
8724e390cabSriastradh 
8734e390cabSriastradh static const struct file_operations amdgpu_debugfs_gca_config_fops = {
8744e390cabSriastradh 	.owner = THIS_MODULE,
8754e390cabSriastradh 	.read = amdgpu_debugfs_gca_config_read,
8764e390cabSriastradh 	.llseek = default_llseek
8774e390cabSriastradh };
8784e390cabSriastradh 
8794e390cabSriastradh static const struct file_operations amdgpu_debugfs_sensors_fops = {
8804e390cabSriastradh 	.owner = THIS_MODULE,
8814e390cabSriastradh 	.read = amdgpu_debugfs_sensor_read,
8824e390cabSriastradh 	.llseek = default_llseek
8834e390cabSriastradh };
8844e390cabSriastradh 
8854e390cabSriastradh static const struct file_operations amdgpu_debugfs_wave_fops = {
8864e390cabSriastradh 	.owner = THIS_MODULE,
8874e390cabSriastradh 	.read = amdgpu_debugfs_wave_read,
8884e390cabSriastradh 	.llseek = default_llseek
8894e390cabSriastradh };
8904e390cabSriastradh static const struct file_operations amdgpu_debugfs_gpr_fops = {
8914e390cabSriastradh 	.owner = THIS_MODULE,
8924e390cabSriastradh 	.read = amdgpu_debugfs_gpr_read,
8934e390cabSriastradh 	.llseek = default_llseek
8944e390cabSriastradh };
8954e390cabSriastradh 
8964e390cabSriastradh static const struct file_operations *debugfs_regs[] = {
8974e390cabSriastradh 	&amdgpu_debugfs_regs_fops,
8984e390cabSriastradh 	&amdgpu_debugfs_regs_didt_fops,
8994e390cabSriastradh 	&amdgpu_debugfs_regs_pcie_fops,
9004e390cabSriastradh 	&amdgpu_debugfs_regs_smc_fops,
9014e390cabSriastradh 	&amdgpu_debugfs_gca_config_fops,
9024e390cabSriastradh 	&amdgpu_debugfs_sensors_fops,
9034e390cabSriastradh 	&amdgpu_debugfs_wave_fops,
9044e390cabSriastradh 	&amdgpu_debugfs_gpr_fops,
9054e390cabSriastradh };
9064e390cabSriastradh 
9074e390cabSriastradh static const char *debugfs_regs_names[] = {
9084e390cabSriastradh 	"amdgpu_regs",
9094e390cabSriastradh 	"amdgpu_regs_didt",
9104e390cabSriastradh 	"amdgpu_regs_pcie",
9114e390cabSriastradh 	"amdgpu_regs_smc",
9124e390cabSriastradh 	"amdgpu_gca_config",
9134e390cabSriastradh 	"amdgpu_sensors",
9144e390cabSriastradh 	"amdgpu_wave",
9154e390cabSriastradh 	"amdgpu_gpr",
9164e390cabSriastradh };
9174e390cabSriastradh 
9184e390cabSriastradh /**
9194e390cabSriastradh  * amdgpu_debugfs_regs_init -	Initialize debugfs entries that provide
9204e390cabSriastradh  * 								register access.
9214e390cabSriastradh  *
9224e390cabSriastradh  * @adev: The device to attach the debugfs entries to
9234e390cabSriastradh  */
amdgpu_debugfs_regs_init(struct amdgpu_device * adev)9244e390cabSriastradh int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
9254e390cabSriastradh {
9264e390cabSriastradh 	struct drm_minor *minor = adev->ddev->primary;
9274e390cabSriastradh 	struct dentry *ent, *root = minor->debugfs_root;
9284e390cabSriastradh 	unsigned int i;
9294e390cabSriastradh 
9304e390cabSriastradh 	for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) {
9314e390cabSriastradh 		ent = debugfs_create_file(debugfs_regs_names[i],
9324e390cabSriastradh 					  S_IFREG | S_IRUGO, root,
9334e390cabSriastradh 					  adev, debugfs_regs[i]);
9344e390cabSriastradh 		if (!i && !IS_ERR_OR_NULL(ent))
9354e390cabSriastradh 			i_size_write(ent->d_inode, adev->rmmio_size);
9364e390cabSriastradh 		adev->debugfs_regs[i] = ent;
9374e390cabSriastradh 	}
9384e390cabSriastradh 
9394e390cabSriastradh 	return 0;
9404e390cabSriastradh }
9414e390cabSriastradh 
amdgpu_debugfs_regs_cleanup(struct amdgpu_device * adev)9424e390cabSriastradh void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev)
9434e390cabSriastradh {
9444e390cabSriastradh 	unsigned i;
9454e390cabSriastradh 
9464e390cabSriastradh 	for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) {
9474e390cabSriastradh 		if (adev->debugfs_regs[i]) {
9484e390cabSriastradh 			debugfs_remove(adev->debugfs_regs[i]);
9494e390cabSriastradh 			adev->debugfs_regs[i] = NULL;
9504e390cabSriastradh 		}
9514e390cabSriastradh 	}
9524e390cabSriastradh }
9534e390cabSriastradh 
amdgpu_debugfs_test_ib(struct seq_file * m,void * data)9544e390cabSriastradh static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data)
9554e390cabSriastradh {
9564e390cabSriastradh 	struct drm_info_node *node = (struct drm_info_node *) m->private;
9574e390cabSriastradh 	struct drm_device *dev = node->minor->dev;
9584e390cabSriastradh 	struct amdgpu_device *adev = dev->dev_private;
9594e390cabSriastradh 	int r = 0, i;
9604e390cabSriastradh 
9614e390cabSriastradh 	r = pm_runtime_get_sync(dev->dev);
9624e390cabSriastradh 	if (r < 0)
9634e390cabSriastradh 		return r;
9644e390cabSriastradh 
9654e390cabSriastradh 	/* Avoid accidently unparking the sched thread during GPU reset */
9664e390cabSriastradh 	mutex_lock(&adev->lock_reset);
9674e390cabSriastradh 
9684e390cabSriastradh 	/* hold on the scheduler */
9694e390cabSriastradh 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
9704e390cabSriastradh 		struct amdgpu_ring *ring = adev->rings[i];
9714e390cabSriastradh 
9724e390cabSriastradh 		if (!ring || !ring->sched.thread)
9734e390cabSriastradh 			continue;
9744e390cabSriastradh 		kthread_park(ring->sched.thread);
9754e390cabSriastradh 	}
9764e390cabSriastradh 
9774e390cabSriastradh 	seq_printf(m, "run ib test:\n");
9784e390cabSriastradh 	r = amdgpu_ib_ring_tests(adev);
9794e390cabSriastradh 	if (r)
9804e390cabSriastradh 		seq_printf(m, "ib ring tests failed (%d).\n", r);
9814e390cabSriastradh 	else
9824e390cabSriastradh 		seq_printf(m, "ib ring tests passed.\n");
9834e390cabSriastradh 
9844e390cabSriastradh 	/* go on the scheduler */
9854e390cabSriastradh 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
9864e390cabSriastradh 		struct amdgpu_ring *ring = adev->rings[i];
9874e390cabSriastradh 
9884e390cabSriastradh 		if (!ring || !ring->sched.thread)
9894e390cabSriastradh 			continue;
9904e390cabSriastradh 		kthread_unpark(ring->sched.thread);
9914e390cabSriastradh 	}
9924e390cabSriastradh 
9934e390cabSriastradh 	mutex_unlock(&adev->lock_reset);
9944e390cabSriastradh 
9954e390cabSriastradh 	pm_runtime_mark_last_busy(dev->dev);
9964e390cabSriastradh 	pm_runtime_put_autosuspend(dev->dev);
9974e390cabSriastradh 
9984e390cabSriastradh 	return 0;
9994e390cabSriastradh }
10004e390cabSriastradh 
amdgpu_debugfs_get_vbios_dump(struct seq_file * m,void * data)10014e390cabSriastradh static int amdgpu_debugfs_get_vbios_dump(struct seq_file *m, void *data)
10024e390cabSriastradh {
10034e390cabSriastradh 	struct drm_info_node *node = (struct drm_info_node *) m->private;
10044e390cabSriastradh 	struct drm_device *dev = node->minor->dev;
10054e390cabSriastradh 	struct amdgpu_device *adev = dev->dev_private;
10064e390cabSriastradh 
10074e390cabSriastradh 	seq_write(m, adev->bios, adev->bios_size);
10084e390cabSriastradh 	return 0;
10094e390cabSriastradh }
10104e390cabSriastradh 
amdgpu_debugfs_evict_vram(struct seq_file * m,void * data)10114e390cabSriastradh static int amdgpu_debugfs_evict_vram(struct seq_file *m, void *data)
10124e390cabSriastradh {
10134e390cabSriastradh 	struct drm_info_node *node = (struct drm_info_node *)m->private;
10144e390cabSriastradh 	struct drm_device *dev = node->minor->dev;
10154e390cabSriastradh 	struct amdgpu_device *adev = dev->dev_private;
10164e390cabSriastradh 	int r;
10174e390cabSriastradh 
10184e390cabSriastradh 	r = pm_runtime_get_sync(dev->dev);
10194e390cabSriastradh 	if (r < 0)
10204e390cabSriastradh 		return r;
10214e390cabSriastradh 
10224e390cabSriastradh 	seq_printf(m, "(%d)\n", amdgpu_bo_evict_vram(adev));
10234e390cabSriastradh 
10244e390cabSriastradh 	pm_runtime_mark_last_busy(dev->dev);
10254e390cabSriastradh 	pm_runtime_put_autosuspend(dev->dev);
10264e390cabSriastradh 
10274e390cabSriastradh 	return 0;
10284e390cabSriastradh }
10294e390cabSriastradh 
amdgpu_debugfs_evict_gtt(struct seq_file * m,void * data)10304e390cabSriastradh static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data)
10314e390cabSriastradh {
10324e390cabSriastradh 	struct drm_info_node *node = (struct drm_info_node *)m->private;
10334e390cabSriastradh 	struct drm_device *dev = node->minor->dev;
10344e390cabSriastradh 	struct amdgpu_device *adev = dev->dev_private;
10354e390cabSriastradh 	int r;
10364e390cabSriastradh 
10374e390cabSriastradh 	r = pm_runtime_get_sync(dev->dev);
10384e390cabSriastradh 	if (r < 0)
10394e390cabSriastradh 		return r;
10404e390cabSriastradh 
10414e390cabSriastradh 	seq_printf(m, "(%d)\n", ttm_bo_evict_mm(&adev->mman.bdev, TTM_PL_TT));
10424e390cabSriastradh 
10434e390cabSriastradh 	pm_runtime_mark_last_busy(dev->dev);
10444e390cabSriastradh 	pm_runtime_put_autosuspend(dev->dev);
10454e390cabSriastradh 
10464e390cabSriastradh 	return 0;
10474e390cabSriastradh }
10484e390cabSriastradh 
10494e390cabSriastradh static const struct drm_info_list amdgpu_debugfs_list[] = {
10504e390cabSriastradh 	{"amdgpu_vbios", amdgpu_debugfs_get_vbios_dump},
10514e390cabSriastradh 	{"amdgpu_test_ib", &amdgpu_debugfs_test_ib},
10524e390cabSriastradh 	{"amdgpu_evict_vram", &amdgpu_debugfs_evict_vram},
10534e390cabSriastradh 	{"amdgpu_evict_gtt", &amdgpu_debugfs_evict_gtt},
10544e390cabSriastradh };
10554e390cabSriastradh 
amdgpu_ib_preempt_fences_swap(struct amdgpu_ring * ring,struct dma_fence ** fences)10564e390cabSriastradh static void amdgpu_ib_preempt_fences_swap(struct amdgpu_ring *ring,
10574e390cabSriastradh 					  struct dma_fence **fences)
10584e390cabSriastradh {
10594e390cabSriastradh 	struct amdgpu_fence_driver *drv = &ring->fence_drv;
10604e390cabSriastradh 	uint32_t sync_seq, last_seq;
10614e390cabSriastradh 
10624e390cabSriastradh 	last_seq = atomic_read(&ring->fence_drv.last_seq);
10634e390cabSriastradh 	sync_seq = ring->fence_drv.sync_seq;
10644e390cabSriastradh 
10654e390cabSriastradh 	last_seq &= drv->num_fences_mask;
10664e390cabSriastradh 	sync_seq &= drv->num_fences_mask;
10674e390cabSriastradh 
10684e390cabSriastradh 	do {
10694e390cabSriastradh 		struct dma_fence *fence, **ptr;
10704e390cabSriastradh 
10714e390cabSriastradh 		++last_seq;
10724e390cabSriastradh 		last_seq &= drv->num_fences_mask;
10734e390cabSriastradh 		ptr = &drv->fences[last_seq];
10744e390cabSriastradh 
10754e390cabSriastradh 		fence = rcu_dereference_protected(*ptr, 1);
10764e390cabSriastradh 		RCU_INIT_POINTER(*ptr, NULL);
10774e390cabSriastradh 
10784e390cabSriastradh 		if (!fence)
10794e390cabSriastradh 			continue;
10804e390cabSriastradh 
10814e390cabSriastradh 		fences[last_seq] = fence;
10824e390cabSriastradh 
10834e390cabSriastradh 	} while (last_seq != sync_seq);
10844e390cabSriastradh }
10854e390cabSriastradh 
amdgpu_ib_preempt_signal_fences(struct dma_fence ** fences,int length)10864e390cabSriastradh static void amdgpu_ib_preempt_signal_fences(struct dma_fence **fences,
10874e390cabSriastradh 					    int length)
10884e390cabSriastradh {
10894e390cabSriastradh 	int i;
10904e390cabSriastradh 	struct dma_fence *fence;
10914e390cabSriastradh 
10924e390cabSriastradh 	for (i = 0; i < length; i++) {
10934e390cabSriastradh 		fence = fences[i];
10944e390cabSriastradh 		if (!fence)
10954e390cabSriastradh 			continue;
10964e390cabSriastradh 		dma_fence_signal(fence);
10974e390cabSriastradh 		dma_fence_put(fence);
10984e390cabSriastradh 	}
10994e390cabSriastradh }
11004e390cabSriastradh 
amdgpu_ib_preempt_job_recovery(struct drm_gpu_scheduler * sched)11014e390cabSriastradh static void amdgpu_ib_preempt_job_recovery(struct drm_gpu_scheduler *sched)
11024e390cabSriastradh {
11034e390cabSriastradh 	struct drm_sched_job *s_job;
11044e390cabSriastradh 	struct dma_fence *fence;
11054e390cabSriastradh 
11064e390cabSriastradh 	spin_lock(&sched->job_list_lock);
11074e390cabSriastradh 	list_for_each_entry(s_job, &sched->ring_mirror_list, node) {
11084e390cabSriastradh 		fence = sched->ops->run_job(s_job);
11094e390cabSriastradh 		dma_fence_put(fence);
11104e390cabSriastradh 	}
11114e390cabSriastradh 	spin_unlock(&sched->job_list_lock);
11124e390cabSriastradh }
11134e390cabSriastradh 
amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring * ring)11144e390cabSriastradh static void amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring *ring)
11154e390cabSriastradh {
11164e390cabSriastradh 	struct amdgpu_job *job;
11174e390cabSriastradh 	struct drm_sched_job *s_job;
11184e390cabSriastradh 	uint32_t preempt_seq;
11194e390cabSriastradh 	struct dma_fence *fence, **ptr;
11204e390cabSriastradh 	struct amdgpu_fence_driver *drv = &ring->fence_drv;
11214e390cabSriastradh 	struct drm_gpu_scheduler *sched = &ring->sched;
11224e390cabSriastradh 
11234e390cabSriastradh 	if (ring->funcs->type != AMDGPU_RING_TYPE_GFX)
11244e390cabSriastradh 		return;
11254e390cabSriastradh 
11264e390cabSriastradh 	preempt_seq = le32_to_cpu(*(drv->cpu_addr + 2));
11274e390cabSriastradh 	if (preempt_seq <= atomic_read(&drv->last_seq))
11284e390cabSriastradh 		return;
11294e390cabSriastradh 
11304e390cabSriastradh 	preempt_seq &= drv->num_fences_mask;
11314e390cabSriastradh 	ptr = &drv->fences[preempt_seq];
11324e390cabSriastradh 	fence = rcu_dereference_protected(*ptr, 1);
11334e390cabSriastradh 
11344e390cabSriastradh 	spin_lock(&sched->job_list_lock);
11354e390cabSriastradh 	list_for_each_entry(s_job, &sched->ring_mirror_list, node) {
11364e390cabSriastradh 		job = to_amdgpu_job(s_job);
11374e390cabSriastradh 		if (job->fence == fence)
11384e390cabSriastradh 			/* mark the job as preempted */
11394e390cabSriastradh 			job->preemption_status |= AMDGPU_IB_PREEMPTED;
11404e390cabSriastradh 	}
11414e390cabSriastradh 	spin_unlock(&sched->job_list_lock);
11424e390cabSriastradh }
11434e390cabSriastradh 
amdgpu_debugfs_ib_preempt(void * data,u64 val)11444e390cabSriastradh static int amdgpu_debugfs_ib_preempt(void *data, u64 val)
11454e390cabSriastradh {
11464e390cabSriastradh 	int r, resched, length;
11474e390cabSriastradh 	struct amdgpu_ring *ring;
11484e390cabSriastradh 	struct dma_fence **fences = NULL;
11494e390cabSriastradh 	struct amdgpu_device *adev = (struct amdgpu_device *)data;
11504e390cabSriastradh 
11514e390cabSriastradh 	if (val >= AMDGPU_MAX_RINGS)
11524e390cabSriastradh 		return -EINVAL;
11534e390cabSriastradh 
11544e390cabSriastradh 	ring = adev->rings[val];
11554e390cabSriastradh 
11564e390cabSriastradh 	if (!ring || !ring->funcs->preempt_ib || !ring->sched.thread)
11574e390cabSriastradh 		return -EINVAL;
11584e390cabSriastradh 
11594e390cabSriastradh 	/* the last preemption failed */
11604e390cabSriastradh 	if (ring->trail_seq != le32_to_cpu(*ring->trail_fence_cpu_addr))
11614e390cabSriastradh 		return -EBUSY;
11624e390cabSriastradh 
11634e390cabSriastradh 	length = ring->fence_drv.num_fences_mask + 1;
11644e390cabSriastradh 	fences = kcalloc(length, sizeof(void *), GFP_KERNEL);
11654e390cabSriastradh 	if (!fences)
11664e390cabSriastradh 		return -ENOMEM;
11674e390cabSriastradh 
11684e390cabSriastradh 	/* Avoid accidently unparking the sched thread during GPU reset */
11694e390cabSriastradh 	mutex_lock(&adev->lock_reset);
11704e390cabSriastradh 
11714e390cabSriastradh 	/* stop the scheduler */
11724e390cabSriastradh 	kthread_park(ring->sched.thread);
11734e390cabSriastradh 
11744e390cabSriastradh 	resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
11754e390cabSriastradh 
11764e390cabSriastradh 	/* preempt the IB */
11774e390cabSriastradh 	r = amdgpu_ring_preempt_ib(ring);
11784e390cabSriastradh 	if (r) {
11794e390cabSriastradh 		DRM_WARN("failed to preempt ring %d\n", ring->idx);
11804e390cabSriastradh 		goto failure;
11814e390cabSriastradh 	}
11824e390cabSriastradh 
11834e390cabSriastradh 	amdgpu_fence_process(ring);
11844e390cabSriastradh 
11854e390cabSriastradh 	if (atomic_read(&ring->fence_drv.last_seq) !=
11864e390cabSriastradh 	    ring->fence_drv.sync_seq) {
11874e390cabSriastradh 		DRM_INFO("ring %d was preempted\n", ring->idx);
11884e390cabSriastradh 
11894e390cabSriastradh 		amdgpu_ib_preempt_mark_partial_job(ring);
11904e390cabSriastradh 
11914e390cabSriastradh 		/* swap out the old fences */
11924e390cabSriastradh 		amdgpu_ib_preempt_fences_swap(ring, fences);
11934e390cabSriastradh 
11944e390cabSriastradh 		amdgpu_fence_driver_force_completion(ring);
11954e390cabSriastradh 
11964e390cabSriastradh 		/* resubmit unfinished jobs */
11974e390cabSriastradh 		amdgpu_ib_preempt_job_recovery(&ring->sched);
11984e390cabSriastradh 
11994e390cabSriastradh 		/* wait for jobs finished */
12004e390cabSriastradh 		amdgpu_fence_wait_empty(ring);
12014e390cabSriastradh 
12024e390cabSriastradh 		/* signal the old fences */
12034e390cabSriastradh 		amdgpu_ib_preempt_signal_fences(fences, length);
12044e390cabSriastradh 	}
12054e390cabSriastradh 
12064e390cabSriastradh failure:
12074e390cabSriastradh 	/* restart the scheduler */
12084e390cabSriastradh 	kthread_unpark(ring->sched.thread);
12094e390cabSriastradh 
12104e390cabSriastradh 	mutex_unlock(&adev->lock_reset);
12114e390cabSriastradh 
12124e390cabSriastradh 	ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
12134e390cabSriastradh 
12144e390cabSriastradh 	kfree(fences);
12154e390cabSriastradh 
12164e390cabSriastradh 	return 0;
12174e390cabSriastradh }
12184e390cabSriastradh 
12194e390cabSriastradh DEFINE_SIMPLE_ATTRIBUTE(fops_ib_preempt, NULL,
12204e390cabSriastradh 			amdgpu_debugfs_ib_preempt, "%llu\n");
12214e390cabSriastradh 
amdgpu_debugfs_init(struct amdgpu_device * adev)12224e390cabSriastradh int amdgpu_debugfs_init(struct amdgpu_device *adev)
12234e390cabSriastradh {
12244e390cabSriastradh 	adev->debugfs_preempt =
12254e390cabSriastradh 		debugfs_create_file("amdgpu_preempt_ib", 0600,
12264e390cabSriastradh 				    adev->ddev->primary->debugfs_root, adev,
12274e390cabSriastradh 				    &fops_ib_preempt);
12284e390cabSriastradh 	if (!(adev->debugfs_preempt)) {
12294e390cabSriastradh 		DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n");
12304e390cabSriastradh 		return -EIO;
12314e390cabSriastradh 	}
12324e390cabSriastradh 
12334e390cabSriastradh 	return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list,
12344e390cabSriastradh 					ARRAY_SIZE(amdgpu_debugfs_list));
12354e390cabSriastradh }
12364e390cabSriastradh 
amdgpu_debugfs_preempt_cleanup(struct amdgpu_device * adev)12374e390cabSriastradh void amdgpu_debugfs_preempt_cleanup(struct amdgpu_device *adev)
12384e390cabSriastradh {
12394e390cabSriastradh 	debugfs_remove(adev->debugfs_preempt);
12404e390cabSriastradh }
12414e390cabSriastradh 
12424e390cabSriastradh #else
amdgpu_debugfs_init(struct amdgpu_device * adev)12434e390cabSriastradh int amdgpu_debugfs_init(struct amdgpu_device *adev)
12444e390cabSriastradh {
12454e390cabSriastradh 	return 0;
12464e390cabSriastradh }
amdgpu_debugfs_preempt_cleanup(struct amdgpu_device * adev)12474e390cabSriastradh void amdgpu_debugfs_preempt_cleanup(struct amdgpu_device *adev) { }
amdgpu_debugfs_regs_init(struct amdgpu_device * adev)12484e390cabSriastradh int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
12494e390cabSriastradh {
12504e390cabSriastradh 	return 0;
12514e390cabSriastradh }
amdgpu_debugfs_regs_cleanup(struct amdgpu_device * adev)12524e390cabSriastradh void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev) { }
12534e390cabSriastradh #endif
1254