175758255SAlex Deucher /* 275758255SAlex Deucher * Copyright 2008 Advanced Micro Devices, Inc. 375758255SAlex Deucher * Copyright 2008 Red Hat Inc. 475758255SAlex Deucher * Copyright 2009 Jerome Glisse. 575758255SAlex Deucher * 675758255SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 775758255SAlex Deucher * copy of this software and associated documentation files (the "Software"), 875758255SAlex Deucher * to deal in the Software without restriction, including without limitation 975758255SAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1075758255SAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the 1175758255SAlex Deucher * Software is furnished to do so, subject to the following conditions: 1275758255SAlex Deucher * 1375758255SAlex Deucher * The above copyright notice and this permission notice shall be included in 1475758255SAlex Deucher * all copies or substantial portions of the Software. 1575758255SAlex Deucher * 1675758255SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1775758255SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1875758255SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1975758255SAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2075758255SAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2175758255SAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2275758255SAlex Deucher * OTHER DEALINGS IN THE SOFTWARE. 2375758255SAlex Deucher * 2475758255SAlex Deucher */ 2575758255SAlex Deucher 2675758255SAlex Deucher #include <linux/kthread.h> 27fdf2f6c5SSam Ravnborg #include <linux/pci.h> 28fdf2f6c5SSam Ravnborg #include <linux/uaccess.h> 29a9ffe2a9SAlex Deucher #include <linux/pm_runtime.h> 30fdf2f6c5SSam Ravnborg 3175758255SAlex Deucher #include "amdgpu.h" 32a4c5b1bbSAlex Deucher #include "amdgpu_pm.h" 33d090e7dbSAlex Deucher #include "amdgpu_dm_debugfs.h" 3417cb04f2SStanley.Yang #include "amdgpu_ras.h" 35a4322e18SWenhui Sheng #include "amdgpu_rap.h" 36ecaafb7bSJinzhou Su #include "amdgpu_securedisplay.h" 3719ae3330SJohn Clements #include "amdgpu_fw_attestation.h" 3837df9560STom St Denis #include "amdgpu_umr.h" 3975758255SAlex Deucher 40d0fb18b5SAndrey Grodzovsky #include "amdgpu_reset.h" 41e50d9ba0SCandice Li #include "amdgpu_psp_ta.h" 42d0fb18b5SAndrey Grodzovsky 4375758255SAlex Deucher #if defined(CONFIG_DEBUG_FS) 4475758255SAlex Deucher 457e4237dbSTom St Denis /** 467e4237dbSTom St Denis * amdgpu_debugfs_process_reg_op - Handle MMIO register reads/writes 477e4237dbSTom St Denis * 487e4237dbSTom St Denis * @read: True if reading 497e4237dbSTom St Denis * @f: open file handle 507e4237dbSTom St Denis * @buf: User buffer to write/read to 517e4237dbSTom St Denis * @size: Number of bytes to write/read 527e4237dbSTom St Denis * @pos: Offset to seek to 537e4237dbSTom St Denis * 547e4237dbSTom St Denis * This debugfs entry has special meaning on the offset being sought. 557e4237dbSTom St Denis * Various bits have different meanings: 567e4237dbSTom St Denis * 577e4237dbSTom St Denis * Bit 62: Indicates a GRBM bank switch is needed 587e4237dbSTom St Denis * Bit 61: Indicates a SRBM bank switch is needed (implies bit 62 is 597e4237dbSTom St Denis * zero) 607e4237dbSTom St Denis * Bits 24..33: The SE or ME selector if needed 617e4237dbSTom St Denis * Bits 34..43: The SH (or SA) or PIPE selector if needed 627e4237dbSTom St Denis * Bits 44..53: The INSTANCE (or CU/WGP) or QUEUE selector if needed 637e4237dbSTom St Denis * 647e4237dbSTom St Denis * Bit 23: Indicates that the PM power gating lock should be held 657e4237dbSTom St Denis * This is necessary to read registers that might be 667e4237dbSTom St Denis * unreliable during a power gating transistion. 677e4237dbSTom St Denis * 687e4237dbSTom St Denis * The lower bits are the BYTE offset of the register to read. This 697e4237dbSTom St Denis * allows reading multiple registers in a single call and having 707e4237dbSTom St Denis * the returned size reflect that. 717e4237dbSTom St Denis */ 72f7a9ee81SAndrey Grodzovsky static int amdgpu_debugfs_process_reg_op(bool read, struct file *f, 73f7a9ee81SAndrey Grodzovsky char __user *buf, size_t size, loff_t *pos) 7475758255SAlex Deucher { 7575758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 7675758255SAlex Deucher ssize_t result = 0; 7775758255SAlex Deucher int r; 78f7a9ee81SAndrey Grodzovsky bool pm_pg_lock, use_bank, use_ring; 790fa4246eSTom St Denis unsigned instance_bank, sh_bank, se_bank, me, pipe, queue, vmid; 8075758255SAlex Deucher 81f7a9ee81SAndrey Grodzovsky pm_pg_lock = use_bank = use_ring = false; 820fa4246eSTom St Denis instance_bank = sh_bank = se_bank = me = pipe = queue = vmid = 0; 83f7a9ee81SAndrey Grodzovsky 84f7a9ee81SAndrey Grodzovsky if (size & 0x3 || *pos & 0x3 || 85f7a9ee81SAndrey Grodzovsky ((*pos & (1ULL << 62)) && (*pos & (1ULL << 61)))) 8675758255SAlex Deucher return -EINVAL; 8775758255SAlex Deucher 8875758255SAlex Deucher /* are we reading registers for which a PG lock is necessary? */ 8975758255SAlex Deucher pm_pg_lock = (*pos >> 23) & 1; 9075758255SAlex Deucher 9175758255SAlex Deucher if (*pos & (1ULL << 62)) { 9275758255SAlex Deucher se_bank = (*pos & GENMASK_ULL(33, 24)) >> 24; 9375758255SAlex Deucher sh_bank = (*pos & GENMASK_ULL(43, 34)) >> 34; 9475758255SAlex Deucher instance_bank = (*pos & GENMASK_ULL(53, 44)) >> 44; 9575758255SAlex Deucher 9675758255SAlex Deucher if (se_bank == 0x3FF) 9775758255SAlex Deucher se_bank = 0xFFFFFFFF; 9875758255SAlex Deucher if (sh_bank == 0x3FF) 9975758255SAlex Deucher sh_bank = 0xFFFFFFFF; 10075758255SAlex Deucher if (instance_bank == 0x3FF) 10175758255SAlex Deucher instance_bank = 0xFFFFFFFF; 102c5b2bd5dSzhengbin use_bank = true; 103f7a9ee81SAndrey Grodzovsky } else if (*pos & (1ULL << 61)) { 104f7a9ee81SAndrey Grodzovsky 105f7a9ee81SAndrey Grodzovsky me = (*pos & GENMASK_ULL(33, 24)) >> 24; 106f7a9ee81SAndrey Grodzovsky pipe = (*pos & GENMASK_ULL(43, 34)) >> 34; 107f7a9ee81SAndrey Grodzovsky queue = (*pos & GENMASK_ULL(53, 44)) >> 44; 10888891430STom St Denis vmid = (*pos & GENMASK_ULL(58, 54)) >> 54; 109f7a9ee81SAndrey Grodzovsky 110c5b2bd5dSzhengbin use_ring = true; 11175758255SAlex Deucher } else { 112c5b2bd5dSzhengbin use_bank = use_ring = false; 11375758255SAlex Deucher } 11475758255SAlex Deucher 11575758255SAlex Deucher *pos &= (1UL << 22) - 1; 11675758255SAlex Deucher 1174a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 1189eee152aSAlex Deucher if (r < 0) { 1194a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 120a9ffe2a9SAlex Deucher return r; 1219eee152aSAlex Deucher } 122a9ffe2a9SAlex Deucher 12395a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 1249eee152aSAlex Deucher if (r < 0) { 1254a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 12695a2f917SYintian Tao return r; 1279eee152aSAlex Deucher } 12895a2f917SYintian Tao 12975758255SAlex Deucher if (use_bank) { 13075758255SAlex Deucher if ((sh_bank != 0xFFFFFFFF && sh_bank >= adev->gfx.config.max_sh_per_se) || 131a9ffe2a9SAlex Deucher (se_bank != 0xFFFFFFFF && se_bank >= adev->gfx.config.max_shader_engines)) { 1324a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 1334a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 13495a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 13575758255SAlex Deucher return -EINVAL; 136a9ffe2a9SAlex Deucher } 13775758255SAlex Deucher mutex_lock(&adev->grbm_idx_mutex); 13875758255SAlex Deucher amdgpu_gfx_select_se_sh(adev, se_bank, 13975758255SAlex Deucher sh_bank, instance_bank); 140f7a9ee81SAndrey Grodzovsky } else if (use_ring) { 141f7a9ee81SAndrey Grodzovsky mutex_lock(&adev->srbm_mutex); 1420fa4246eSTom St Denis amdgpu_gfx_select_me_pipe_q(adev, me, pipe, queue, vmid); 14375758255SAlex Deucher } 14475758255SAlex Deucher 14575758255SAlex Deucher if (pm_pg_lock) 14675758255SAlex Deucher mutex_lock(&adev->pm.mutex); 14775758255SAlex Deucher 14875758255SAlex Deucher while (size) { 14975758255SAlex Deucher uint32_t value; 15075758255SAlex Deucher 151f7a9ee81SAndrey Grodzovsky if (read) { 15275758255SAlex Deucher value = RREG32(*pos >> 2); 15375758255SAlex Deucher r = put_user(value, (uint32_t *)buf); 154f7a9ee81SAndrey Grodzovsky } else { 155f7a9ee81SAndrey Grodzovsky r = get_user(value, (uint32_t *)buf); 156f7a9ee81SAndrey Grodzovsky if (!r) 157f7ee1874SHawking Zhang amdgpu_mm_wreg_mmio_rlc(adev, *pos >> 2, value); 158f7a9ee81SAndrey Grodzovsky } 15975758255SAlex Deucher if (r) { 16075758255SAlex Deucher result = r; 16175758255SAlex Deucher goto end; 16275758255SAlex Deucher } 16375758255SAlex Deucher 16475758255SAlex Deucher result += 4; 16575758255SAlex Deucher buf += 4; 16675758255SAlex Deucher *pos += 4; 16775758255SAlex Deucher size -= 4; 16875758255SAlex Deucher } 16975758255SAlex Deucher 17075758255SAlex Deucher end: 17175758255SAlex Deucher if (use_bank) { 17275758255SAlex Deucher amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); 17375758255SAlex Deucher mutex_unlock(&adev->grbm_idx_mutex); 174f7a9ee81SAndrey Grodzovsky } else if (use_ring) { 1750fa4246eSTom St Denis amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0); 176f7a9ee81SAndrey Grodzovsky mutex_unlock(&adev->srbm_mutex); 17775758255SAlex Deucher } 17875758255SAlex Deucher 17975758255SAlex Deucher if (pm_pg_lock) 18075758255SAlex Deucher mutex_unlock(&adev->pm.mutex); 18175758255SAlex Deucher 1824a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 1834a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 184a9ffe2a9SAlex Deucher 18595a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 18675758255SAlex Deucher return result; 18775758255SAlex Deucher } 18875758255SAlex Deucher 18920ed491bSLee Jones /* 1907e4237dbSTom St Denis * amdgpu_debugfs_regs_read - Callback for reading MMIO registers 1917e4237dbSTom St Denis */ 192f7a9ee81SAndrey Grodzovsky static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf, 193f7a9ee81SAndrey Grodzovsky size_t size, loff_t *pos) 194f7a9ee81SAndrey Grodzovsky { 195f7a9ee81SAndrey Grodzovsky return amdgpu_debugfs_process_reg_op(true, f, buf, size, pos); 196f7a9ee81SAndrey Grodzovsky } 197f7a9ee81SAndrey Grodzovsky 19820ed491bSLee Jones /* 1997e4237dbSTom St Denis * amdgpu_debugfs_regs_write - Callback for writing MMIO registers 2007e4237dbSTom St Denis */ 20175758255SAlex Deucher static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf, 20275758255SAlex Deucher size_t size, loff_t *pos) 20375758255SAlex Deucher { 204f7a9ee81SAndrey Grodzovsky return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos); 20575758255SAlex Deucher } 20675758255SAlex Deucher 20737df9560STom St Denis static int amdgpu_debugfs_regs2_open(struct inode *inode, struct file *file) 20837df9560STom St Denis { 20937df9560STom St Denis struct amdgpu_debugfs_regs2_data *rd; 21037df9560STom St Denis 21137df9560STom St Denis rd = kzalloc(sizeof *rd, GFP_KERNEL); 21237df9560STom St Denis if (!rd) 21337df9560STom St Denis return -ENOMEM; 21437df9560STom St Denis rd->adev = file_inode(file)->i_private; 21537df9560STom St Denis file->private_data = rd; 21637df9560STom St Denis mutex_init(&rd->lock); 21737df9560STom St Denis 21837df9560STom St Denis return 0; 21937df9560STom St Denis } 22037df9560STom St Denis 22137df9560STom St Denis static int amdgpu_debugfs_regs2_release(struct inode *inode, struct file *file) 22237df9560STom St Denis { 22337df9560STom St Denis struct amdgpu_debugfs_regs2_data *rd = file->private_data; 22437df9560STom St Denis mutex_destroy(&rd->lock); 22537df9560STom St Denis kfree(file->private_data); 22637df9560STom St Denis return 0; 22737df9560STom St Denis } 22837df9560STom St Denis 22937df9560STom St Denis static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 offset, size_t size, int write_en) 23037df9560STom St Denis { 23137df9560STom St Denis struct amdgpu_debugfs_regs2_data *rd = f->private_data; 23237df9560STom St Denis struct amdgpu_device *adev = rd->adev; 23337df9560STom St Denis ssize_t result = 0; 23437df9560STom St Denis int r; 23537df9560STom St Denis uint32_t value; 23637df9560STom St Denis 23737df9560STom St Denis if (size & 0x3 || offset & 0x3) 23837df9560STom St Denis return -EINVAL; 23937df9560STom St Denis 24037df9560STom St Denis r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 24137df9560STom St Denis if (r < 0) { 24237df9560STom St Denis pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 24337df9560STom St Denis return r; 24437df9560STom St Denis } 24537df9560STom St Denis 24637df9560STom St Denis r = amdgpu_virt_enable_access_debugfs(adev); 24737df9560STom St Denis if (r < 0) { 24837df9560STom St Denis pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 24937df9560STom St Denis return r; 25037df9560STom St Denis } 25137df9560STom St Denis 25237df9560STom St Denis mutex_lock(&rd->lock); 25337df9560STom St Denis 25437df9560STom St Denis if (rd->id.use_grbm) { 25537df9560STom St Denis if ((rd->id.grbm.sh != 0xFFFFFFFF && rd->id.grbm.sh >= adev->gfx.config.max_sh_per_se) || 25637df9560STom St Denis (rd->id.grbm.se != 0xFFFFFFFF && rd->id.grbm.se >= adev->gfx.config.max_shader_engines)) { 25737df9560STom St Denis pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 25837df9560STom St Denis pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 25937df9560STom St Denis amdgpu_virt_disable_access_debugfs(adev); 26037df9560STom St Denis mutex_unlock(&rd->lock); 26137df9560STom St Denis return -EINVAL; 26237df9560STom St Denis } 26337df9560STom St Denis mutex_lock(&adev->grbm_idx_mutex); 26437df9560STom St Denis amdgpu_gfx_select_se_sh(adev, rd->id.grbm.se, 26537df9560STom St Denis rd->id.grbm.sh, 26637df9560STom St Denis rd->id.grbm.instance); 26737df9560STom St Denis } 26837df9560STom St Denis 26937df9560STom St Denis if (rd->id.use_srbm) { 27037df9560STom St Denis mutex_lock(&adev->srbm_mutex); 27137df9560STom St Denis amdgpu_gfx_select_me_pipe_q(adev, rd->id.srbm.me, rd->id.srbm.pipe, 27237df9560STom St Denis rd->id.srbm.queue, rd->id.srbm.vmid); 27337df9560STom St Denis } 27437df9560STom St Denis 27537df9560STom St Denis if (rd->id.pg_lock) 27637df9560STom St Denis mutex_lock(&adev->pm.mutex); 27737df9560STom St Denis 27837df9560STom St Denis while (size) { 27937df9560STom St Denis if (!write_en) { 28037df9560STom St Denis value = RREG32(offset >> 2); 28137df9560STom St Denis r = put_user(value, (uint32_t *)buf); 28237df9560STom St Denis } else { 28337df9560STom St Denis r = get_user(value, (uint32_t *)buf); 28437df9560STom St Denis if (!r) 28537df9560STom St Denis amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value); 28637df9560STom St Denis } 28737df9560STom St Denis if (r) { 28837df9560STom St Denis result = r; 28937df9560STom St Denis goto end; 29037df9560STom St Denis } 29137df9560STom St Denis offset += 4; 29237df9560STom St Denis size -= 4; 29337df9560STom St Denis result += 4; 29437df9560STom St Denis buf += 4; 29537df9560STom St Denis } 29637df9560STom St Denis end: 29737df9560STom St Denis if (rd->id.use_grbm) { 29837df9560STom St Denis amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); 29937df9560STom St Denis mutex_unlock(&adev->grbm_idx_mutex); 30037df9560STom St Denis } 30137df9560STom St Denis 30237df9560STom St Denis if (rd->id.use_srbm) { 30337df9560STom St Denis amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0); 30437df9560STom St Denis mutex_unlock(&adev->srbm_mutex); 30537df9560STom St Denis } 30637df9560STom St Denis 30737df9560STom St Denis if (rd->id.pg_lock) 30837df9560STom St Denis mutex_unlock(&adev->pm.mutex); 30937df9560STom St Denis 31037df9560STom St Denis mutex_unlock(&rd->lock); 31137df9560STom St Denis 31237df9560STom St Denis pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 31337df9560STom St Denis pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 31437df9560STom St Denis 31537df9560STom St Denis amdgpu_virt_disable_access_debugfs(adev); 31637df9560STom St Denis return result; 31737df9560STom St Denis } 31837df9560STom St Denis 31937df9560STom St Denis static long amdgpu_debugfs_regs2_ioctl(struct file *f, unsigned int cmd, unsigned long data) 32037df9560STom St Denis { 32137df9560STom St Denis struct amdgpu_debugfs_regs2_data *rd = f->private_data; 32237df9560STom St Denis int r; 32337df9560STom St Denis 32437df9560STom St Denis switch (cmd) { 32537df9560STom St Denis case AMDGPU_DEBUGFS_REGS2_IOC_SET_STATE: 32637df9560STom St Denis mutex_lock(&rd->lock); 32737df9560STom St Denis r = copy_from_user(&rd->id, (struct amdgpu_debugfs_regs2_iocdata *)data, sizeof rd->id); 32837df9560STom St Denis mutex_unlock(&rd->lock); 32937df9560STom St Denis return r ? -EINVAL : 0; 33037df9560STom St Denis default: 33137df9560STom St Denis return -EINVAL; 33237df9560STom St Denis } 33337df9560STom St Denis return 0; 33437df9560STom St Denis } 33537df9560STom St Denis 33637df9560STom St Denis static ssize_t amdgpu_debugfs_regs2_read(struct file *f, char __user *buf, size_t size, loff_t *pos) 33737df9560STom St Denis { 33837df9560STom St Denis return amdgpu_debugfs_regs2_op(f, buf, *pos, size, 0); 33937df9560STom St Denis } 34037df9560STom St Denis 34137df9560STom St Denis static ssize_t amdgpu_debugfs_regs2_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) 34237df9560STom St Denis { 34337df9560STom St Denis return amdgpu_debugfs_regs2_op(f, (char __user *)buf, *pos, size, 1); 34437df9560STom St Denis } 34537df9560STom St Denis 3467e4237dbSTom St Denis 3477e4237dbSTom St Denis /** 3487e4237dbSTom St Denis * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register 3497e4237dbSTom St Denis * 3507e4237dbSTom St Denis * @f: open file handle 3517e4237dbSTom St Denis * @buf: User buffer to store read data in 3527e4237dbSTom St Denis * @size: Number of bytes to read 3537e4237dbSTom St Denis * @pos: Offset to seek to 3547e4237dbSTom St Denis * 3557e4237dbSTom St Denis * The lower bits are the BYTE offset of the register to read. This 3567e4237dbSTom St Denis * allows reading multiple registers in a single call and having 3577e4237dbSTom St Denis * the returned size reflect that. 3587e4237dbSTom St Denis */ 35975758255SAlex Deucher static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, 36075758255SAlex Deucher size_t size, loff_t *pos) 36175758255SAlex Deucher { 36275758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 36375758255SAlex Deucher ssize_t result = 0; 36475758255SAlex Deucher int r; 36575758255SAlex Deucher 36675758255SAlex Deucher if (size & 0x3 || *pos & 0x3) 36775758255SAlex Deucher return -EINVAL; 36875758255SAlex Deucher 3694a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 3709eee152aSAlex Deucher if (r < 0) { 3714a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 372a9ffe2a9SAlex Deucher return r; 3739eee152aSAlex Deucher } 374a9ffe2a9SAlex Deucher 37595a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 3769eee152aSAlex Deucher if (r < 0) { 3774a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 37895a2f917SYintian Tao return r; 3799eee152aSAlex Deucher } 38095a2f917SYintian Tao 38175758255SAlex Deucher while (size) { 38275758255SAlex Deucher uint32_t value; 38375758255SAlex Deucher 38443fb6c19SKevin Wang value = RREG32_PCIE(*pos); 38575758255SAlex Deucher r = put_user(value, (uint32_t *)buf); 386edadd6fcSAndré Almeida if (r) 387edadd6fcSAndré Almeida goto out; 38875758255SAlex Deucher 38975758255SAlex Deucher result += 4; 39075758255SAlex Deucher buf += 4; 39175758255SAlex Deucher *pos += 4; 39275758255SAlex Deucher size -= 4; 39375758255SAlex Deucher } 39475758255SAlex Deucher 395edadd6fcSAndré Almeida r = result; 396edadd6fcSAndré Almeida out: 3974a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 3984a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 39995a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 400edadd6fcSAndré Almeida return r; 40175758255SAlex Deucher } 40275758255SAlex Deucher 4037e4237dbSTom St Denis /** 4047e4237dbSTom St Denis * amdgpu_debugfs_regs_pcie_write - Write to a PCIE register 4057e4237dbSTom St Denis * 4067e4237dbSTom St Denis * @f: open file handle 4077e4237dbSTom St Denis * @buf: User buffer to write data from 4087e4237dbSTom St Denis * @size: Number of bytes to write 4097e4237dbSTom St Denis * @pos: Offset to seek to 4107e4237dbSTom St Denis * 4117e4237dbSTom St Denis * The lower bits are the BYTE offset of the register to write. This 4127e4237dbSTom St Denis * allows writing multiple registers in a single call and having 4137e4237dbSTom St Denis * the returned size reflect that. 4147e4237dbSTom St Denis */ 41575758255SAlex Deucher static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user *buf, 41675758255SAlex Deucher size_t size, loff_t *pos) 41775758255SAlex Deucher { 41875758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 41975758255SAlex Deucher ssize_t result = 0; 42075758255SAlex Deucher int r; 42175758255SAlex Deucher 42275758255SAlex Deucher if (size & 0x3 || *pos & 0x3) 42375758255SAlex Deucher return -EINVAL; 42475758255SAlex Deucher 4254a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 4269eee152aSAlex Deucher if (r < 0) { 4274a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 428a9ffe2a9SAlex Deucher return r; 4299eee152aSAlex Deucher } 430a9ffe2a9SAlex Deucher 43195a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 4329eee152aSAlex Deucher if (r < 0) { 4334a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 43495a2f917SYintian Tao return r; 4359eee152aSAlex Deucher } 43695a2f917SYintian Tao 43775758255SAlex Deucher while (size) { 43875758255SAlex Deucher uint32_t value; 43975758255SAlex Deucher 44075758255SAlex Deucher r = get_user(value, (uint32_t *)buf); 441edadd6fcSAndré Almeida if (r) 442edadd6fcSAndré Almeida goto out; 44375758255SAlex Deucher 44443fb6c19SKevin Wang WREG32_PCIE(*pos, value); 44575758255SAlex Deucher 44675758255SAlex Deucher result += 4; 44775758255SAlex Deucher buf += 4; 44875758255SAlex Deucher *pos += 4; 44975758255SAlex Deucher size -= 4; 45075758255SAlex Deucher } 45175758255SAlex Deucher 452edadd6fcSAndré Almeida r = result; 453edadd6fcSAndré Almeida out: 4544a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 4554a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 45695a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 457edadd6fcSAndré Almeida return r; 45875758255SAlex Deucher } 45975758255SAlex Deucher 4607e4237dbSTom St Denis /** 4617e4237dbSTom St Denis * amdgpu_debugfs_regs_didt_read - Read from a DIDT register 4627e4237dbSTom St Denis * 4637e4237dbSTom St Denis * @f: open file handle 4647e4237dbSTom St Denis * @buf: User buffer to store read data in 4657e4237dbSTom St Denis * @size: Number of bytes to read 4667e4237dbSTom St Denis * @pos: Offset to seek to 4677e4237dbSTom St Denis * 4687e4237dbSTom St Denis * The lower bits are the BYTE offset of the register to read. This 4697e4237dbSTom St Denis * allows reading multiple registers in a single call and having 4707e4237dbSTom St Denis * the returned size reflect that. 4717e4237dbSTom St Denis */ 47275758255SAlex Deucher static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, 47375758255SAlex Deucher size_t size, loff_t *pos) 47475758255SAlex Deucher { 47575758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 47675758255SAlex Deucher ssize_t result = 0; 47775758255SAlex Deucher int r; 47875758255SAlex Deucher 47975758255SAlex Deucher if (size & 0x3 || *pos & 0x3) 48075758255SAlex Deucher return -EINVAL; 48175758255SAlex Deucher 4824a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 4839eee152aSAlex Deucher if (r < 0) { 4844a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 485a9ffe2a9SAlex Deucher return r; 4869eee152aSAlex Deucher } 487a9ffe2a9SAlex Deucher 48895a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 4899eee152aSAlex Deucher if (r < 0) { 4904a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 49195a2f917SYintian Tao return r; 4929eee152aSAlex Deucher } 49395a2f917SYintian Tao 49475758255SAlex Deucher while (size) { 49575758255SAlex Deucher uint32_t value; 49675758255SAlex Deucher 49775758255SAlex Deucher value = RREG32_DIDT(*pos >> 2); 49875758255SAlex Deucher r = put_user(value, (uint32_t *)buf); 499edadd6fcSAndré Almeida if (r) 500edadd6fcSAndré Almeida goto out; 50175758255SAlex Deucher 50275758255SAlex Deucher result += 4; 50375758255SAlex Deucher buf += 4; 50475758255SAlex Deucher *pos += 4; 50575758255SAlex Deucher size -= 4; 50675758255SAlex Deucher } 50775758255SAlex Deucher 508edadd6fcSAndré Almeida r = result; 509edadd6fcSAndré Almeida out: 5104a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 5114a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 51295a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 513edadd6fcSAndré Almeida return r; 51475758255SAlex Deucher } 51575758255SAlex Deucher 5167e4237dbSTom St Denis /** 5177e4237dbSTom St Denis * amdgpu_debugfs_regs_didt_write - Write to a DIDT register 5187e4237dbSTom St Denis * 5197e4237dbSTom St Denis * @f: open file handle 5207e4237dbSTom St Denis * @buf: User buffer to write data from 5217e4237dbSTom St Denis * @size: Number of bytes to write 5227e4237dbSTom St Denis * @pos: Offset to seek to 5237e4237dbSTom St Denis * 5247e4237dbSTom St Denis * The lower bits are the BYTE offset of the register to write. This 5257e4237dbSTom St Denis * allows writing multiple registers in a single call and having 5267e4237dbSTom St Denis * the returned size reflect that. 5277e4237dbSTom St Denis */ 52875758255SAlex Deucher static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user *buf, 52975758255SAlex Deucher size_t size, loff_t *pos) 53075758255SAlex Deucher { 53175758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 53275758255SAlex Deucher ssize_t result = 0; 53375758255SAlex Deucher int r; 53475758255SAlex Deucher 53575758255SAlex Deucher if (size & 0x3 || *pos & 0x3) 53675758255SAlex Deucher return -EINVAL; 53775758255SAlex Deucher 5384a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 5399eee152aSAlex Deucher if (r < 0) { 5404a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 541a9ffe2a9SAlex Deucher return r; 5429eee152aSAlex Deucher } 543a9ffe2a9SAlex Deucher 54495a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 5459eee152aSAlex Deucher if (r < 0) { 5464a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 54795a2f917SYintian Tao return r; 5489eee152aSAlex Deucher } 54995a2f917SYintian Tao 55075758255SAlex Deucher while (size) { 55175758255SAlex Deucher uint32_t value; 55275758255SAlex Deucher 55375758255SAlex Deucher r = get_user(value, (uint32_t *)buf); 554edadd6fcSAndré Almeida if (r) 555edadd6fcSAndré Almeida goto out; 55675758255SAlex Deucher 55775758255SAlex Deucher WREG32_DIDT(*pos >> 2, value); 55875758255SAlex Deucher 55975758255SAlex Deucher result += 4; 56075758255SAlex Deucher buf += 4; 56175758255SAlex Deucher *pos += 4; 56275758255SAlex Deucher size -= 4; 56375758255SAlex Deucher } 56475758255SAlex Deucher 565edadd6fcSAndré Almeida r = result; 566edadd6fcSAndré Almeida out: 5674a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 5684a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 56995a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 570edadd6fcSAndré Almeida return r; 57175758255SAlex Deucher } 57275758255SAlex Deucher 5737e4237dbSTom St Denis /** 5747e4237dbSTom St Denis * amdgpu_debugfs_regs_smc_read - Read from a SMC register 5757e4237dbSTom St Denis * 5767e4237dbSTom St Denis * @f: open file handle 5777e4237dbSTom St Denis * @buf: User buffer to store read data in 5787e4237dbSTom St Denis * @size: Number of bytes to read 5797e4237dbSTom St Denis * @pos: Offset to seek to 5807e4237dbSTom St Denis * 5817e4237dbSTom St Denis * The lower bits are the BYTE offset of the register to read. This 5827e4237dbSTom St Denis * allows reading multiple registers in a single call and having 5837e4237dbSTom St Denis * the returned size reflect that. 5847e4237dbSTom St Denis */ 58575758255SAlex Deucher static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, 58675758255SAlex Deucher size_t size, loff_t *pos) 58775758255SAlex Deucher { 58875758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 58975758255SAlex Deucher ssize_t result = 0; 59075758255SAlex Deucher int r; 59175758255SAlex Deucher 59275758255SAlex Deucher if (size & 0x3 || *pos & 0x3) 59375758255SAlex Deucher return -EINVAL; 59475758255SAlex Deucher 5954a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 5969eee152aSAlex Deucher if (r < 0) { 5974a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 598a9ffe2a9SAlex Deucher return r; 5999eee152aSAlex Deucher } 600a9ffe2a9SAlex Deucher 60195a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 6029eee152aSAlex Deucher if (r < 0) { 6034a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 60495a2f917SYintian Tao return r; 6059eee152aSAlex Deucher } 60695a2f917SYintian Tao 60775758255SAlex Deucher while (size) { 60875758255SAlex Deucher uint32_t value; 60975758255SAlex Deucher 61075758255SAlex Deucher value = RREG32_SMC(*pos); 61175758255SAlex Deucher r = put_user(value, (uint32_t *)buf); 612edadd6fcSAndré Almeida if (r) 613edadd6fcSAndré Almeida goto out; 61475758255SAlex Deucher 61575758255SAlex Deucher result += 4; 61675758255SAlex Deucher buf += 4; 61775758255SAlex Deucher *pos += 4; 61875758255SAlex Deucher size -= 4; 61975758255SAlex Deucher } 62075758255SAlex Deucher 621edadd6fcSAndré Almeida r = result; 622edadd6fcSAndré Almeida out: 6234a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 6244a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 62595a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 626edadd6fcSAndré Almeida return r; 62775758255SAlex Deucher } 62875758255SAlex Deucher 6297e4237dbSTom St Denis /** 6307e4237dbSTom St Denis * amdgpu_debugfs_regs_smc_write - Write to a SMC register 6317e4237dbSTom St Denis * 6327e4237dbSTom St Denis * @f: open file handle 6337e4237dbSTom St Denis * @buf: User buffer to write data from 6347e4237dbSTom St Denis * @size: Number of bytes to write 6357e4237dbSTom St Denis * @pos: Offset to seek to 6367e4237dbSTom St Denis * 6377e4237dbSTom St Denis * The lower bits are the BYTE offset of the register to write. This 6387e4237dbSTom St Denis * allows writing multiple registers in a single call and having 6397e4237dbSTom St Denis * the returned size reflect that. 6407e4237dbSTom St Denis */ 64175758255SAlex Deucher static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *buf, 64275758255SAlex Deucher size_t size, loff_t *pos) 64375758255SAlex Deucher { 64475758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 64575758255SAlex Deucher ssize_t result = 0; 64675758255SAlex Deucher int r; 64775758255SAlex Deucher 64875758255SAlex Deucher if (size & 0x3 || *pos & 0x3) 64975758255SAlex Deucher return -EINVAL; 65075758255SAlex Deucher 6514a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 6529eee152aSAlex Deucher if (r < 0) { 6534a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 654a9ffe2a9SAlex Deucher return r; 6559eee152aSAlex Deucher } 656a9ffe2a9SAlex Deucher 65795a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 6589eee152aSAlex Deucher if (r < 0) { 6594a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 66095a2f917SYintian Tao return r; 6619eee152aSAlex Deucher } 66295a2f917SYintian Tao 66375758255SAlex Deucher while (size) { 66475758255SAlex Deucher uint32_t value; 66575758255SAlex Deucher 66675758255SAlex Deucher r = get_user(value, (uint32_t *)buf); 667edadd6fcSAndré Almeida if (r) 668edadd6fcSAndré Almeida goto out; 66975758255SAlex Deucher 67075758255SAlex Deucher WREG32_SMC(*pos, value); 67175758255SAlex Deucher 67275758255SAlex Deucher result += 4; 67375758255SAlex Deucher buf += 4; 67475758255SAlex Deucher *pos += 4; 67575758255SAlex Deucher size -= 4; 67675758255SAlex Deucher } 67775758255SAlex Deucher 678edadd6fcSAndré Almeida r = result; 679edadd6fcSAndré Almeida out: 6804a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 6814a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 68295a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 683edadd6fcSAndré Almeida return r; 68475758255SAlex Deucher } 68575758255SAlex Deucher 6867e4237dbSTom St Denis /** 6877e4237dbSTom St Denis * amdgpu_debugfs_gca_config_read - Read from gfx config data 6887e4237dbSTom St Denis * 6897e4237dbSTom St Denis * @f: open file handle 6907e4237dbSTom St Denis * @buf: User buffer to store read data in 6917e4237dbSTom St Denis * @size: Number of bytes to read 6927e4237dbSTom St Denis * @pos: Offset to seek to 6937e4237dbSTom St Denis * 6947e4237dbSTom St Denis * This file is used to access configuration data in a somewhat 6957e4237dbSTom St Denis * stable fashion. The format is a series of DWORDs with the first 6967e4237dbSTom St Denis * indicating which revision it is. New content is appended to the 6977e4237dbSTom St Denis * end so that older software can still read the data. 6987e4237dbSTom St Denis */ 6997e4237dbSTom St Denis 70075758255SAlex Deucher static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf, 70175758255SAlex Deucher size_t size, loff_t *pos) 70275758255SAlex Deucher { 70375758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 70475758255SAlex Deucher ssize_t result = 0; 70575758255SAlex Deucher int r; 70675758255SAlex Deucher uint32_t *config, no_regs = 0; 70775758255SAlex Deucher 70875758255SAlex Deucher if (size & 0x3 || *pos & 0x3) 70975758255SAlex Deucher return -EINVAL; 71075758255SAlex Deucher 71175758255SAlex Deucher config = kmalloc_array(256, sizeof(*config), GFP_KERNEL); 71275758255SAlex Deucher if (!config) 71375758255SAlex Deucher return -ENOMEM; 71475758255SAlex Deucher 71575758255SAlex Deucher /* version, increment each time something is added */ 716dc2947b3STom St Denis config[no_regs++] = 5; 71775758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_shader_engines; 71875758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_tile_pipes; 71975758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_cu_per_sh; 72075758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_sh_per_se; 72175758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_backends_per_se; 72275758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_texture_channel_caches; 72375758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_gprs; 72475758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_gs_threads; 72575758255SAlex Deucher config[no_regs++] = adev->gfx.config.max_hw_contexts; 72675758255SAlex Deucher config[no_regs++] = adev->gfx.config.sc_prim_fifo_size_frontend; 72775758255SAlex Deucher config[no_regs++] = adev->gfx.config.sc_prim_fifo_size_backend; 72875758255SAlex Deucher config[no_regs++] = adev->gfx.config.sc_hiz_tile_fifo_size; 72975758255SAlex Deucher config[no_regs++] = adev->gfx.config.sc_earlyz_tile_fifo_size; 73075758255SAlex Deucher config[no_regs++] = adev->gfx.config.num_tile_pipes; 73175758255SAlex Deucher config[no_regs++] = adev->gfx.config.backend_enable_mask; 73275758255SAlex Deucher config[no_regs++] = adev->gfx.config.mem_max_burst_length_bytes; 73375758255SAlex Deucher config[no_regs++] = adev->gfx.config.mem_row_size_in_kb; 73475758255SAlex Deucher config[no_regs++] = adev->gfx.config.shader_engine_tile_size; 73575758255SAlex Deucher config[no_regs++] = adev->gfx.config.num_gpus; 73675758255SAlex Deucher config[no_regs++] = adev->gfx.config.multi_gpu_tile_size; 73775758255SAlex Deucher config[no_regs++] = adev->gfx.config.mc_arb_ramcfg; 73875758255SAlex Deucher config[no_regs++] = adev->gfx.config.gb_addr_config; 73975758255SAlex Deucher config[no_regs++] = adev->gfx.config.num_rbs; 74075758255SAlex Deucher 74175758255SAlex Deucher /* rev==1 */ 74275758255SAlex Deucher config[no_regs++] = adev->rev_id; 743dc2947b3STom St Denis config[no_regs++] = lower_32_bits(adev->pg_flags); 74425faeddcSEvan Quan config[no_regs++] = lower_32_bits(adev->cg_flags); 74575758255SAlex Deucher 74675758255SAlex Deucher /* rev==2 */ 74775758255SAlex Deucher config[no_regs++] = adev->family; 74875758255SAlex Deucher config[no_regs++] = adev->external_rev_id; 74975758255SAlex Deucher 75075758255SAlex Deucher /* rev==3 */ 75175758255SAlex Deucher config[no_regs++] = adev->pdev->device; 75275758255SAlex Deucher config[no_regs++] = adev->pdev->revision; 75375758255SAlex Deucher config[no_regs++] = adev->pdev->subsystem_device; 75475758255SAlex Deucher config[no_regs++] = adev->pdev->subsystem_vendor; 75575758255SAlex Deucher 7568f74f68dSTom St Denis /* rev==4 APU flag */ 7578f74f68dSTom St Denis config[no_regs++] = adev->flags & AMD_IS_APU ? 1 : 0; 7588f74f68dSTom St Denis 759dc2947b3STom St Denis /* rev==5 PG/CG flag upper 32bit */ 760dc2947b3STom St Denis config[no_regs++] = upper_32_bits(adev->pg_flags); 76125faeddcSEvan Quan config[no_regs++] = upper_32_bits(adev->cg_flags); 76225faeddcSEvan Quan 76375758255SAlex Deucher while (size && (*pos < no_regs * 4)) { 76475758255SAlex Deucher uint32_t value; 76575758255SAlex Deucher 76675758255SAlex Deucher value = config[*pos >> 2]; 76775758255SAlex Deucher r = put_user(value, (uint32_t *)buf); 76875758255SAlex Deucher if (r) { 76975758255SAlex Deucher kfree(config); 77075758255SAlex Deucher return r; 77175758255SAlex Deucher } 77275758255SAlex Deucher 77375758255SAlex Deucher result += 4; 77475758255SAlex Deucher buf += 4; 77575758255SAlex Deucher *pos += 4; 77675758255SAlex Deucher size -= 4; 77775758255SAlex Deucher } 77875758255SAlex Deucher 77975758255SAlex Deucher kfree(config); 78075758255SAlex Deucher return result; 78175758255SAlex Deucher } 78275758255SAlex Deucher 7837e4237dbSTom St Denis /** 7847e4237dbSTom St Denis * amdgpu_debugfs_sensor_read - Read from the powerplay sensors 7857e4237dbSTom St Denis * 7867e4237dbSTom St Denis * @f: open file handle 7877e4237dbSTom St Denis * @buf: User buffer to store read data in 7887e4237dbSTom St Denis * @size: Number of bytes to read 7897e4237dbSTom St Denis * @pos: Offset to seek to 7907e4237dbSTom St Denis * 7917e4237dbSTom St Denis * The offset is treated as the BYTE address of one of the sensors 7927e4237dbSTom St Denis * enumerated in amd/include/kgd_pp_interface.h under the 7937e4237dbSTom St Denis * 'amd_pp_sensors' enumeration. For instance to read the UVD VCLK 7947e4237dbSTom St Denis * you would use the offset 3 * 4 = 12. 7957e4237dbSTom St Denis */ 79675758255SAlex Deucher static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf, 79775758255SAlex Deucher size_t size, loff_t *pos) 79875758255SAlex Deucher { 79975758255SAlex Deucher struct amdgpu_device *adev = file_inode(f)->i_private; 80075758255SAlex Deucher int idx, x, outsize, r, valuesize; 80175758255SAlex Deucher uint32_t values[16]; 80275758255SAlex Deucher 80375758255SAlex Deucher if (size & 3 || *pos & 0x3) 80475758255SAlex Deucher return -EINVAL; 80575758255SAlex Deucher 806b13aa109SRex Zhu if (!adev->pm.dpm_enabled) 80775758255SAlex Deucher return -EINVAL; 80875758255SAlex Deucher 80975758255SAlex Deucher /* convert offset to sensor number */ 81075758255SAlex Deucher idx = *pos >> 2; 81175758255SAlex Deucher 81275758255SAlex Deucher valuesize = sizeof(values); 813a9ffe2a9SAlex Deucher 8144a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 8159eee152aSAlex Deucher if (r < 0) { 8164a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 817a9ffe2a9SAlex Deucher return r; 8189eee152aSAlex Deucher } 819a9ffe2a9SAlex Deucher 82095a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 8219eee152aSAlex Deucher if (r < 0) { 8224a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 82395a2f917SYintian Tao return r; 8249eee152aSAlex Deucher } 82595a2f917SYintian Tao 82675758255SAlex Deucher r = amdgpu_dpm_read_sensor(adev, idx, &values[0], &valuesize); 827a9ffe2a9SAlex Deucher 8284a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 8294a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 830a9ffe2a9SAlex Deucher 83195a2f917SYintian Tao if (r) { 83295a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 8334a5a2de6SKevin Wang return r; 83495a2f917SYintian Tao } 83575758255SAlex Deucher 83695a2f917SYintian Tao if (size > valuesize) { 83795a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 83875758255SAlex Deucher return -EINVAL; 83995a2f917SYintian Tao } 84075758255SAlex Deucher 84175758255SAlex Deucher outsize = 0; 84275758255SAlex Deucher x = 0; 84375758255SAlex Deucher if (!r) { 84475758255SAlex Deucher while (size) { 84575758255SAlex Deucher r = put_user(values[x++], (int32_t *)buf); 84675758255SAlex Deucher buf += 4; 84775758255SAlex Deucher size -= 4; 84875758255SAlex Deucher outsize += 4; 84975758255SAlex Deucher } 85075758255SAlex Deucher } 85175758255SAlex Deucher 85295a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 85375758255SAlex Deucher return !r ? outsize : r; 85475758255SAlex Deucher } 85575758255SAlex Deucher 8567e4237dbSTom St Denis /** amdgpu_debugfs_wave_read - Read WAVE STATUS data 8577e4237dbSTom St Denis * 8587e4237dbSTom St Denis * @f: open file handle 8597e4237dbSTom St Denis * @buf: User buffer to store read data in 8607e4237dbSTom St Denis * @size: Number of bytes to read 8617e4237dbSTom St Denis * @pos: Offset to seek to 8627e4237dbSTom St Denis * 8637e4237dbSTom St Denis * The offset being sought changes which wave that the status data 8647e4237dbSTom St Denis * will be returned for. The bits are used as follows: 8657e4237dbSTom St Denis * 8667e4237dbSTom St Denis * Bits 0..6: Byte offset into data 8677e4237dbSTom St Denis * Bits 7..14: SE selector 8687e4237dbSTom St Denis * Bits 15..22: SH/SA selector 8697e4237dbSTom St Denis * Bits 23..30: CU/{WGP+SIMD} selector 8707e4237dbSTom St Denis * Bits 31..36: WAVE ID selector 8717e4237dbSTom St Denis * Bits 37..44: SIMD ID selector 8727e4237dbSTom St Denis * 8737e4237dbSTom St Denis * The returned data begins with one DWORD of version information 8747e4237dbSTom St Denis * Followed by WAVE STATUS registers relevant to the GFX IP version 8757e4237dbSTom St Denis * being used. See gfx_v8_0_read_wave_data() for an example output. 8767e4237dbSTom St Denis */ 87775758255SAlex Deucher static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf, 87875758255SAlex Deucher size_t size, loff_t *pos) 87975758255SAlex Deucher { 88075758255SAlex Deucher struct amdgpu_device *adev = f->f_inode->i_private; 88175758255SAlex Deucher int r, x; 88275758255SAlex Deucher ssize_t result = 0; 88375758255SAlex Deucher uint32_t offset, se, sh, cu, wave, simd, data[32]; 88475758255SAlex Deucher 88575758255SAlex Deucher if (size & 3 || *pos & 3) 88675758255SAlex Deucher return -EINVAL; 88775758255SAlex Deucher 88875758255SAlex Deucher /* decode offset */ 88975758255SAlex Deucher offset = (*pos & GENMASK_ULL(6, 0)); 89075758255SAlex Deucher se = (*pos & GENMASK_ULL(14, 7)) >> 7; 89175758255SAlex Deucher sh = (*pos & GENMASK_ULL(22, 15)) >> 15; 89275758255SAlex Deucher cu = (*pos & GENMASK_ULL(30, 23)) >> 23; 89375758255SAlex Deucher wave = (*pos & GENMASK_ULL(36, 31)) >> 31; 89475758255SAlex Deucher simd = (*pos & GENMASK_ULL(44, 37)) >> 37; 89575758255SAlex Deucher 8964a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 8979eee152aSAlex Deucher if (r < 0) { 8984a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 899a9ffe2a9SAlex Deucher return r; 9009eee152aSAlex Deucher } 901a9ffe2a9SAlex Deucher 90295a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 9039eee152aSAlex Deucher if (r < 0) { 9044a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 90595a2f917SYintian Tao return r; 9069eee152aSAlex Deucher } 90795a2f917SYintian Tao 90875758255SAlex Deucher /* switch to the specific se/sh/cu */ 90975758255SAlex Deucher mutex_lock(&adev->grbm_idx_mutex); 91075758255SAlex Deucher amdgpu_gfx_select_se_sh(adev, se, sh, cu); 91175758255SAlex Deucher 91275758255SAlex Deucher x = 0; 91375758255SAlex Deucher if (adev->gfx.funcs->read_wave_data) 91475758255SAlex Deucher adev->gfx.funcs->read_wave_data(adev, simd, wave, data, &x); 91575758255SAlex Deucher 91675758255SAlex Deucher amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); 91775758255SAlex Deucher mutex_unlock(&adev->grbm_idx_mutex); 91875758255SAlex Deucher 9194a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 9204a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 921a9ffe2a9SAlex Deucher 92295a2f917SYintian Tao if (!x) { 92395a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 92475758255SAlex Deucher return -EINVAL; 92595a2f917SYintian Tao } 92675758255SAlex Deucher 92775758255SAlex Deucher while (size && (offset < x * 4)) { 92875758255SAlex Deucher uint32_t value; 92975758255SAlex Deucher 93075758255SAlex Deucher value = data[offset >> 2]; 93175758255SAlex Deucher r = put_user(value, (uint32_t *)buf); 93295a2f917SYintian Tao if (r) { 93395a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 93475758255SAlex Deucher return r; 93595a2f917SYintian Tao } 93675758255SAlex Deucher 93775758255SAlex Deucher result += 4; 93875758255SAlex Deucher buf += 4; 93975758255SAlex Deucher offset += 4; 94075758255SAlex Deucher size -= 4; 94175758255SAlex Deucher } 94275758255SAlex Deucher 94395a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 94475758255SAlex Deucher return result; 94575758255SAlex Deucher } 94675758255SAlex Deucher 9477e4237dbSTom St Denis /** amdgpu_debugfs_gpr_read - Read wave gprs 9487e4237dbSTom St Denis * 9497e4237dbSTom St Denis * @f: open file handle 9507e4237dbSTom St Denis * @buf: User buffer to store read data in 9517e4237dbSTom St Denis * @size: Number of bytes to read 9527e4237dbSTom St Denis * @pos: Offset to seek to 9537e4237dbSTom St Denis * 9547e4237dbSTom St Denis * The offset being sought changes which wave that the status data 9557e4237dbSTom St Denis * will be returned for. The bits are used as follows: 9567e4237dbSTom St Denis * 9577e4237dbSTom St Denis * Bits 0..11: Byte offset into data 9587e4237dbSTom St Denis * Bits 12..19: SE selector 9597e4237dbSTom St Denis * Bits 20..27: SH/SA selector 9607e4237dbSTom St Denis * Bits 28..35: CU/{WGP+SIMD} selector 9617e4237dbSTom St Denis * Bits 36..43: WAVE ID selector 9627e4237dbSTom St Denis * Bits 37..44: SIMD ID selector 9637e4237dbSTom St Denis * Bits 52..59: Thread selector 9647e4237dbSTom St Denis * Bits 60..61: Bank selector (VGPR=0,SGPR=1) 9657e4237dbSTom St Denis * 9667e4237dbSTom St Denis * The return data comes from the SGPR or VGPR register bank for 9677e4237dbSTom St Denis * the selected operational unit. 9687e4237dbSTom St Denis */ 96975758255SAlex Deucher static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf, 97075758255SAlex Deucher size_t size, loff_t *pos) 97175758255SAlex Deucher { 97275758255SAlex Deucher struct amdgpu_device *adev = f->f_inode->i_private; 97375758255SAlex Deucher int r; 97475758255SAlex Deucher ssize_t result = 0; 97575758255SAlex Deucher uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data; 97675758255SAlex Deucher 9776397ec58STom St Denis if (size > 4096 || size & 3 || *pos & 3) 97875758255SAlex Deucher return -EINVAL; 97975758255SAlex Deucher 98075758255SAlex Deucher /* decode offset */ 9816397ec58STom St Denis offset = (*pos & GENMASK_ULL(11, 0)) >> 2; 98275758255SAlex Deucher se = (*pos & GENMASK_ULL(19, 12)) >> 12; 98375758255SAlex Deucher sh = (*pos & GENMASK_ULL(27, 20)) >> 20; 98475758255SAlex Deucher cu = (*pos & GENMASK_ULL(35, 28)) >> 28; 98575758255SAlex Deucher wave = (*pos & GENMASK_ULL(43, 36)) >> 36; 98675758255SAlex Deucher simd = (*pos & GENMASK_ULL(51, 44)) >> 44; 98775758255SAlex Deucher thread = (*pos & GENMASK_ULL(59, 52)) >> 52; 98875758255SAlex Deucher bank = (*pos & GENMASK_ULL(61, 60)) >> 60; 98975758255SAlex Deucher 990929e571cSWang Xiayang data = kcalloc(1024, sizeof(*data), GFP_KERNEL); 99175758255SAlex Deucher if (!data) 99275758255SAlex Deucher return -ENOMEM; 99375758255SAlex Deucher 9944a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 995a9ffe2a9SAlex Deucher if (r < 0) 9963e4aeff3SChen Tao goto err; 997a9ffe2a9SAlex Deucher 99895a2f917SYintian Tao r = amdgpu_virt_enable_access_debugfs(adev); 99995a2f917SYintian Tao if (r < 0) 1000888e32d7SChen Tao goto err; 100195a2f917SYintian Tao 100275758255SAlex Deucher /* switch to the specific se/sh/cu */ 100375758255SAlex Deucher mutex_lock(&adev->grbm_idx_mutex); 100475758255SAlex Deucher amdgpu_gfx_select_se_sh(adev, se, sh, cu); 100575758255SAlex Deucher 100675758255SAlex Deucher if (bank == 0) { 100775758255SAlex Deucher if (adev->gfx.funcs->read_wave_vgprs) 100875758255SAlex Deucher adev->gfx.funcs->read_wave_vgprs(adev, simd, wave, thread, offset, size>>2, data); 100975758255SAlex Deucher } else { 101075758255SAlex Deucher if (adev->gfx.funcs->read_wave_sgprs) 101175758255SAlex Deucher adev->gfx.funcs->read_wave_sgprs(adev, simd, wave, offset, size>>2, data); 101275758255SAlex Deucher } 101375758255SAlex Deucher 101475758255SAlex Deucher amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); 101575758255SAlex Deucher mutex_unlock(&adev->grbm_idx_mutex); 101675758255SAlex Deucher 10174a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 10184a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 1019a9ffe2a9SAlex Deucher 102075758255SAlex Deucher while (size) { 102175758255SAlex Deucher uint32_t value; 102275758255SAlex Deucher 10236397ec58STom St Denis value = data[result >> 2]; 102475758255SAlex Deucher r = put_user(value, (uint32_t *)buf); 102575758255SAlex Deucher if (r) { 10263e4aeff3SChen Tao amdgpu_virt_disable_access_debugfs(adev); 102775758255SAlex Deucher goto err; 102875758255SAlex Deucher } 102975758255SAlex Deucher 103075758255SAlex Deucher result += 4; 103175758255SAlex Deucher buf += 4; 103275758255SAlex Deucher size -= 4; 103375758255SAlex Deucher } 103475758255SAlex Deucher 103575758255SAlex Deucher kfree(data); 103695a2f917SYintian Tao amdgpu_virt_disable_access_debugfs(adev); 103775758255SAlex Deucher return result; 10383e4aeff3SChen Tao 10393e4aeff3SChen Tao err: 10404a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 10413e4aeff3SChen Tao kfree(data); 10423e4aeff3SChen Tao return r; 104375758255SAlex Deucher } 104475758255SAlex Deucher 1045669e2f91STom St Denis /** 1046e72d4a8bSLee Jones * amdgpu_debugfs_gfxoff_write - Enable/disable GFXOFF 1047669e2f91STom St Denis * 1048669e2f91STom St Denis * @f: open file handle 1049669e2f91STom St Denis * @buf: User buffer to write data from 1050669e2f91STom St Denis * @size: Number of bytes to write 1051669e2f91STom St Denis * @pos: Offset to seek to 1052669e2f91STom St Denis * 1053669e2f91STom St Denis * Write a 32-bit zero to disable or a 32-bit non-zero to enable 1054669e2f91STom St Denis */ 1055669e2f91STom St Denis static ssize_t amdgpu_debugfs_gfxoff_write(struct file *f, const char __user *buf, 1056669e2f91STom St Denis size_t size, loff_t *pos) 1057669e2f91STom St Denis { 1058669e2f91STom St Denis struct amdgpu_device *adev = file_inode(f)->i_private; 1059669e2f91STom St Denis ssize_t result = 0; 1060669e2f91STom St Denis int r; 1061669e2f91STom St Denis 1062669e2f91STom St Denis if (size & 0x3 || *pos & 0x3) 1063669e2f91STom St Denis return -EINVAL; 1064669e2f91STom St Denis 10654a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 10669eee152aSAlex Deucher if (r < 0) { 10674a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 1068669e2f91STom St Denis return r; 10699eee152aSAlex Deucher } 1070669e2f91STom St Denis 1071669e2f91STom St Denis while (size) { 1072669e2f91STom St Denis uint32_t value; 1073669e2f91STom St Denis 1074669e2f91STom St Denis r = get_user(value, (uint32_t *)buf); 1075edadd6fcSAndré Almeida if (r) 1076edadd6fcSAndré Almeida goto out; 1077669e2f91STom St Denis 1078669e2f91STom St Denis amdgpu_gfx_off_ctrl(adev, value ? true : false); 1079669e2f91STom St Denis 1080669e2f91STom St Denis result += 4; 1081669e2f91STom St Denis buf += 4; 1082669e2f91STom St Denis *pos += 4; 1083669e2f91STom St Denis size -= 4; 1084669e2f91STom St Denis } 1085669e2f91STom St Denis 1086edadd6fcSAndré Almeida r = result; 1087edadd6fcSAndré Almeida out: 10884a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 10894a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 1090669e2f91STom St Denis 1091edadd6fcSAndré Almeida return r; 1092669e2f91STom St Denis } 1093669e2f91STom St Denis 1094669e2f91STom St Denis 1095443c7f3cSJinzhou.Su /** 1096e72d4a8bSLee Jones * amdgpu_debugfs_gfxoff_read - read gfxoff status 1097443c7f3cSJinzhou.Su * 1098443c7f3cSJinzhou.Su * @f: open file handle 1099443c7f3cSJinzhou.Su * @buf: User buffer to store read data in 1100443c7f3cSJinzhou.Su * @size: Number of bytes to read 1101443c7f3cSJinzhou.Su * @pos: Offset to seek to 1102443c7f3cSJinzhou.Su */ 1103443c7f3cSJinzhou.Su static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf, 1104443c7f3cSJinzhou.Su size_t size, loff_t *pos) 1105443c7f3cSJinzhou.Su { 1106443c7f3cSJinzhou.Su struct amdgpu_device *adev = file_inode(f)->i_private; 1107443c7f3cSJinzhou.Su ssize_t result = 0; 1108443c7f3cSJinzhou.Su int r; 1109443c7f3cSJinzhou.Su 1110443c7f3cSJinzhou.Su if (size & 0x3 || *pos & 0x3) 1111443c7f3cSJinzhou.Su return -EINVAL; 1112443c7f3cSJinzhou.Su 11134a580877SLuben Tuikov r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 11144bd8dd0dSYongzhi Liu if (r < 0) { 11154bd8dd0dSYongzhi Liu pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 1116443c7f3cSJinzhou.Su return r; 11174bd8dd0dSYongzhi Liu } 1118443c7f3cSJinzhou.Su 1119443c7f3cSJinzhou.Su while (size) { 11204686177fSAndré Almeida u32 value = adev->gfx.gfx_off_state; 11214686177fSAndré Almeida 11224686177fSAndré Almeida r = put_user(value, (u32 *)buf); 11234686177fSAndré Almeida if (r) 11244686177fSAndré Almeida goto out; 11254686177fSAndré Almeida 11264686177fSAndré Almeida result += 4; 11274686177fSAndré Almeida buf += 4; 11284686177fSAndré Almeida *pos += 4; 11294686177fSAndré Almeida size -= 4; 11304686177fSAndré Almeida } 11314686177fSAndré Almeida 11324686177fSAndré Almeida r = result; 11334686177fSAndré Almeida out: 11344686177fSAndré Almeida pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 11354686177fSAndré Almeida pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 11364686177fSAndré Almeida 11374686177fSAndré Almeida return r; 11384686177fSAndré Almeida } 11394686177fSAndré Almeida 11404686177fSAndré Almeida static ssize_t amdgpu_debugfs_gfxoff_status_read(struct file *f, char __user *buf, 11414686177fSAndré Almeida size_t size, loff_t *pos) 11424686177fSAndré Almeida { 11434686177fSAndré Almeida struct amdgpu_device *adev = file_inode(f)->i_private; 11444686177fSAndré Almeida ssize_t result = 0; 11454686177fSAndré Almeida int r; 11464686177fSAndré Almeida 11474686177fSAndré Almeida if (size & 0x3 || *pos & 0x3) 11484686177fSAndré Almeida return -EINVAL; 11494686177fSAndré Almeida 11504686177fSAndré Almeida r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 11514686177fSAndré Almeida if (r < 0) { 11524686177fSAndré Almeida pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 11534686177fSAndré Almeida return r; 11544686177fSAndré Almeida } 11554686177fSAndré Almeida 11564686177fSAndré Almeida while (size) { 11574686177fSAndré Almeida u32 value; 1158443c7f3cSJinzhou.Su 1159443c7f3cSJinzhou.Su r = amdgpu_get_gfx_off_status(adev, &value); 1160edadd6fcSAndré Almeida if (r) 1161edadd6fcSAndré Almeida goto out; 1162443c7f3cSJinzhou.Su 11634686177fSAndré Almeida r = put_user(value, (u32 *)buf); 1164edadd6fcSAndré Almeida if (r) 1165edadd6fcSAndré Almeida goto out; 1166443c7f3cSJinzhou.Su 1167443c7f3cSJinzhou.Su result += 4; 1168443c7f3cSJinzhou.Su buf += 4; 1169443c7f3cSJinzhou.Su *pos += 4; 1170443c7f3cSJinzhou.Su size -= 4; 1171443c7f3cSJinzhou.Su } 1172443c7f3cSJinzhou.Su 1173edadd6fcSAndré Almeida r = result; 1174edadd6fcSAndré Almeida out: 11754a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 11764a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 1177443c7f3cSJinzhou.Su 1178edadd6fcSAndré Almeida return r; 1179443c7f3cSJinzhou.Su } 1180443c7f3cSJinzhou.Su 118137df9560STom St Denis static const struct file_operations amdgpu_debugfs_regs2_fops = { 118237df9560STom St Denis .owner = THIS_MODULE, 118337df9560STom St Denis .unlocked_ioctl = amdgpu_debugfs_regs2_ioctl, 118437df9560STom St Denis .read = amdgpu_debugfs_regs2_read, 118537df9560STom St Denis .write = amdgpu_debugfs_regs2_write, 118637df9560STom St Denis .open = amdgpu_debugfs_regs2_open, 118737df9560STom St Denis .release = amdgpu_debugfs_regs2_release, 118837df9560STom St Denis .llseek = default_llseek 118937df9560STom St Denis }; 119037df9560STom St Denis 119175758255SAlex Deucher static const struct file_operations amdgpu_debugfs_regs_fops = { 119275758255SAlex Deucher .owner = THIS_MODULE, 119375758255SAlex Deucher .read = amdgpu_debugfs_regs_read, 119475758255SAlex Deucher .write = amdgpu_debugfs_regs_write, 119575758255SAlex Deucher .llseek = default_llseek 119675758255SAlex Deucher }; 119775758255SAlex Deucher static const struct file_operations amdgpu_debugfs_regs_didt_fops = { 119875758255SAlex Deucher .owner = THIS_MODULE, 119975758255SAlex Deucher .read = amdgpu_debugfs_regs_didt_read, 120075758255SAlex Deucher .write = amdgpu_debugfs_regs_didt_write, 120175758255SAlex Deucher .llseek = default_llseek 120275758255SAlex Deucher }; 120375758255SAlex Deucher static const struct file_operations amdgpu_debugfs_regs_pcie_fops = { 120475758255SAlex Deucher .owner = THIS_MODULE, 120575758255SAlex Deucher .read = amdgpu_debugfs_regs_pcie_read, 120675758255SAlex Deucher .write = amdgpu_debugfs_regs_pcie_write, 120775758255SAlex Deucher .llseek = default_llseek 120875758255SAlex Deucher }; 120975758255SAlex Deucher static const struct file_operations amdgpu_debugfs_regs_smc_fops = { 121075758255SAlex Deucher .owner = THIS_MODULE, 121175758255SAlex Deucher .read = amdgpu_debugfs_regs_smc_read, 121275758255SAlex Deucher .write = amdgpu_debugfs_regs_smc_write, 121375758255SAlex Deucher .llseek = default_llseek 121475758255SAlex Deucher }; 121575758255SAlex Deucher 121675758255SAlex Deucher static const struct file_operations amdgpu_debugfs_gca_config_fops = { 121775758255SAlex Deucher .owner = THIS_MODULE, 121875758255SAlex Deucher .read = amdgpu_debugfs_gca_config_read, 121975758255SAlex Deucher .llseek = default_llseek 122075758255SAlex Deucher }; 122175758255SAlex Deucher 122275758255SAlex Deucher static const struct file_operations amdgpu_debugfs_sensors_fops = { 122375758255SAlex Deucher .owner = THIS_MODULE, 122475758255SAlex Deucher .read = amdgpu_debugfs_sensor_read, 122575758255SAlex Deucher .llseek = default_llseek 122675758255SAlex Deucher }; 122775758255SAlex Deucher 122875758255SAlex Deucher static const struct file_operations amdgpu_debugfs_wave_fops = { 122975758255SAlex Deucher .owner = THIS_MODULE, 123075758255SAlex Deucher .read = amdgpu_debugfs_wave_read, 123175758255SAlex Deucher .llseek = default_llseek 123275758255SAlex Deucher }; 123375758255SAlex Deucher static const struct file_operations amdgpu_debugfs_gpr_fops = { 123475758255SAlex Deucher .owner = THIS_MODULE, 123575758255SAlex Deucher .read = amdgpu_debugfs_gpr_read, 123675758255SAlex Deucher .llseek = default_llseek 123775758255SAlex Deucher }; 123875758255SAlex Deucher 1239669e2f91STom St Denis static const struct file_operations amdgpu_debugfs_gfxoff_fops = { 1240669e2f91STom St Denis .owner = THIS_MODULE, 1241443c7f3cSJinzhou.Su .read = amdgpu_debugfs_gfxoff_read, 1242669e2f91STom St Denis .write = amdgpu_debugfs_gfxoff_write, 1243443c7f3cSJinzhou.Su .llseek = default_llseek 1244669e2f91STom St Denis }; 1245669e2f91STom St Denis 12464686177fSAndré Almeida static const struct file_operations amdgpu_debugfs_gfxoff_status_fops = { 12474686177fSAndré Almeida .owner = THIS_MODULE, 12484686177fSAndré Almeida .read = amdgpu_debugfs_gfxoff_status_read, 12494686177fSAndré Almeida .llseek = default_llseek 12504686177fSAndré Almeida }; 12514686177fSAndré Almeida 125275758255SAlex Deucher static const struct file_operations *debugfs_regs[] = { 125375758255SAlex Deucher &amdgpu_debugfs_regs_fops, 125437df9560STom St Denis &amdgpu_debugfs_regs2_fops, 125575758255SAlex Deucher &amdgpu_debugfs_regs_didt_fops, 125675758255SAlex Deucher &amdgpu_debugfs_regs_pcie_fops, 125775758255SAlex Deucher &amdgpu_debugfs_regs_smc_fops, 125875758255SAlex Deucher &amdgpu_debugfs_gca_config_fops, 125975758255SAlex Deucher &amdgpu_debugfs_sensors_fops, 126075758255SAlex Deucher &amdgpu_debugfs_wave_fops, 126175758255SAlex Deucher &amdgpu_debugfs_gpr_fops, 1262669e2f91STom St Denis &amdgpu_debugfs_gfxoff_fops, 12634686177fSAndré Almeida &amdgpu_debugfs_gfxoff_status_fops, 126475758255SAlex Deucher }; 126575758255SAlex Deucher 126675758255SAlex Deucher static const char *debugfs_regs_names[] = { 126775758255SAlex Deucher "amdgpu_regs", 126837df9560STom St Denis "amdgpu_regs2", 126975758255SAlex Deucher "amdgpu_regs_didt", 127075758255SAlex Deucher "amdgpu_regs_pcie", 127175758255SAlex Deucher "amdgpu_regs_smc", 127275758255SAlex Deucher "amdgpu_gca_config", 127375758255SAlex Deucher "amdgpu_sensors", 127475758255SAlex Deucher "amdgpu_wave", 127575758255SAlex Deucher "amdgpu_gpr", 1276669e2f91STom St Denis "amdgpu_gfxoff", 12774686177fSAndré Almeida "amdgpu_gfxoff_status", 127875758255SAlex Deucher }; 127975758255SAlex Deucher 12807e4237dbSTom St Denis /** 12817e4237dbSTom St Denis * amdgpu_debugfs_regs_init - Initialize debugfs entries that provide 12827e4237dbSTom St Denis * register access. 12837e4237dbSTom St Denis * 12847e4237dbSTom St Denis * @adev: The device to attach the debugfs entries to 12857e4237dbSTom St Denis */ 128675758255SAlex Deucher int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) 128775758255SAlex Deucher { 12884a580877SLuben Tuikov struct drm_minor *minor = adev_to_drm(adev)->primary; 128975758255SAlex Deucher struct dentry *ent, *root = minor->debugfs_root; 1290d344b21bSDan Carpenter unsigned int i; 129175758255SAlex Deucher 129275758255SAlex Deucher for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { 129375758255SAlex Deucher ent = debugfs_create_file(debugfs_regs_names[i], 129475758255SAlex Deucher S_IFREG | S_IRUGO, root, 129575758255SAlex Deucher adev, debugfs_regs[i]); 1296d344b21bSDan Carpenter if (!i && !IS_ERR_OR_NULL(ent)) 129775758255SAlex Deucher i_size_write(ent->d_inode, adev->rmmio_size); 129875758255SAlex Deucher } 129975758255SAlex Deucher 130075758255SAlex Deucher return 0; 130175758255SAlex Deucher } 130275758255SAlex Deucher 130398d28ac2SNirmoy Das static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) 130475758255SAlex Deucher { 130598d28ac2SNirmoy Das struct amdgpu_device *adev = (struct amdgpu_device *)m->private; 130698d28ac2SNirmoy Das struct drm_device *dev = adev_to_drm(adev); 130775758255SAlex Deucher int r = 0, i; 130875758255SAlex Deucher 1309a9ffe2a9SAlex Deucher r = pm_runtime_get_sync(dev->dev); 13109eee152aSAlex Deucher if (r < 0) { 131198d28ac2SNirmoy Das pm_runtime_put_autosuspend(dev->dev); 1312a9ffe2a9SAlex Deucher return r; 13139eee152aSAlex Deucher } 1314a9ffe2a9SAlex Deucher 1315a28fda31SAndrey Grodzovsky /* Avoid accidently unparking the sched thread during GPU reset */ 1316d0fb18b5SAndrey Grodzovsky r = down_write_killable(&adev->reset_domain->sem); 13176049db43SDennis Li if (r) 13186049db43SDennis Li return r; 1319a28fda31SAndrey Grodzovsky 132075758255SAlex Deucher /* hold on the scheduler */ 132175758255SAlex Deucher for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 132275758255SAlex Deucher struct amdgpu_ring *ring = adev->rings[i]; 132375758255SAlex Deucher 132475758255SAlex Deucher if (!ring || !ring->sched.thread) 132575758255SAlex Deucher continue; 132675758255SAlex Deucher kthread_park(ring->sched.thread); 132775758255SAlex Deucher } 132875758255SAlex Deucher 132975758255SAlex Deucher seq_printf(m, "run ib test:\n"); 133075758255SAlex Deucher r = amdgpu_ib_ring_tests(adev); 133175758255SAlex Deucher if (r) 133275758255SAlex Deucher seq_printf(m, "ib ring tests failed (%d).\n", r); 133375758255SAlex Deucher else 133475758255SAlex Deucher seq_printf(m, "ib ring tests passed.\n"); 133575758255SAlex Deucher 133675758255SAlex Deucher /* go on the scheduler */ 133775758255SAlex Deucher for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 133875758255SAlex Deucher struct amdgpu_ring *ring = adev->rings[i]; 133975758255SAlex Deucher 134075758255SAlex Deucher if (!ring || !ring->sched.thread) 134175758255SAlex Deucher continue; 134275758255SAlex Deucher kthread_unpark(ring->sched.thread); 134375758255SAlex Deucher } 134475758255SAlex Deucher 1345d0fb18b5SAndrey Grodzovsky up_write(&adev->reset_domain->sem); 1346a28fda31SAndrey Grodzovsky 1347a9ffe2a9SAlex Deucher pm_runtime_mark_last_busy(dev->dev); 1348a9ffe2a9SAlex Deucher pm_runtime_put_autosuspend(dev->dev); 1349a9ffe2a9SAlex Deucher 135075758255SAlex Deucher return 0; 135175758255SAlex Deucher } 135275758255SAlex Deucher 135398d28ac2SNirmoy Das static int amdgpu_debugfs_evict_vram(void *data, u64 *val) 135475758255SAlex Deucher { 135598d28ac2SNirmoy Das struct amdgpu_device *adev = (struct amdgpu_device *)data; 135698d28ac2SNirmoy Das struct drm_device *dev = adev_to_drm(adev); 1357a9ffe2a9SAlex Deucher int r; 1358a9ffe2a9SAlex Deucher 1359a9ffe2a9SAlex Deucher r = pm_runtime_get_sync(dev->dev); 13609eee152aSAlex Deucher if (r < 0) { 136198d28ac2SNirmoy Das pm_runtime_put_autosuspend(dev->dev); 1362a9ffe2a9SAlex Deucher return r; 13639eee152aSAlex Deucher } 136475758255SAlex Deucher 136558144d28SNirmoy Das *val = amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM); 1366a9ffe2a9SAlex Deucher 1367a9ffe2a9SAlex Deucher pm_runtime_mark_last_busy(dev->dev); 1368a9ffe2a9SAlex Deucher pm_runtime_put_autosuspend(dev->dev); 1369a9ffe2a9SAlex Deucher 137075758255SAlex Deucher return 0; 137175758255SAlex Deucher } 137275758255SAlex Deucher 137398d28ac2SNirmoy Das 137498d28ac2SNirmoy Das static int amdgpu_debugfs_evict_gtt(void *data, u64 *val) 137587e90c76SChristian König { 137698d28ac2SNirmoy Das struct amdgpu_device *adev = (struct amdgpu_device *)data; 137798d28ac2SNirmoy Das struct drm_device *dev = adev_to_drm(adev); 1378a9ffe2a9SAlex Deucher int r; 1379a9ffe2a9SAlex Deucher 1380a9ffe2a9SAlex Deucher r = pm_runtime_get_sync(dev->dev); 13819eee152aSAlex Deucher if (r < 0) { 138258144d28SNirmoy Das pm_runtime_put_autosuspend(dev->dev); 1383a9ffe2a9SAlex Deucher return r; 13849eee152aSAlex Deucher } 138587e90c76SChristian König 138658144d28SNirmoy Das *val = amdgpu_ttm_evict_resources(adev, TTM_PL_TT); 1387a9ffe2a9SAlex Deucher 1388a9ffe2a9SAlex Deucher pm_runtime_mark_last_busy(dev->dev); 1389a9ffe2a9SAlex Deucher pm_runtime_put_autosuspend(dev->dev); 1390a9ffe2a9SAlex Deucher 139187e90c76SChristian König return 0; 139287e90c76SChristian König } 139387e90c76SChristian König 1394e7c47231SAlex Deucher static int amdgpu_debugfs_benchmark(void *data, u64 val) 1395e7c47231SAlex Deucher { 1396e7c47231SAlex Deucher struct amdgpu_device *adev = (struct amdgpu_device *)data; 1397e7c47231SAlex Deucher struct drm_device *dev = adev_to_drm(adev); 1398e7c47231SAlex Deucher int r; 1399e7c47231SAlex Deucher 1400e7c47231SAlex Deucher r = pm_runtime_get_sync(dev->dev); 1401e7c47231SAlex Deucher if (r < 0) { 1402e7c47231SAlex Deucher pm_runtime_put_autosuspend(dev->dev); 1403e7c47231SAlex Deucher return r; 1404e7c47231SAlex Deucher } 1405e7c47231SAlex Deucher 1406e7c47231SAlex Deucher r = amdgpu_benchmark(adev, val); 1407e7c47231SAlex Deucher 1408e7c47231SAlex Deucher pm_runtime_mark_last_busy(dev->dev); 1409e7c47231SAlex Deucher pm_runtime_put_autosuspend(dev->dev); 1410e7c47231SAlex Deucher 1411e7c47231SAlex Deucher return r; 1412e7c47231SAlex Deucher } 141398d28ac2SNirmoy Das 141498d28ac2SNirmoy Das static int amdgpu_debugfs_vm_info_show(struct seq_file *m, void *unused) 1415ff72bc40SMihir Bhogilal Patel { 141698d28ac2SNirmoy Das struct amdgpu_device *adev = (struct amdgpu_device *)m->private; 141798d28ac2SNirmoy Das struct drm_device *dev = adev_to_drm(adev); 1418ff72bc40SMihir Bhogilal Patel struct drm_file *file; 1419ff72bc40SMihir Bhogilal Patel int r; 1420ff72bc40SMihir Bhogilal Patel 1421ff72bc40SMihir Bhogilal Patel r = mutex_lock_interruptible(&dev->filelist_mutex); 1422ff72bc40SMihir Bhogilal Patel if (r) 1423ff72bc40SMihir Bhogilal Patel return r; 1424ff72bc40SMihir Bhogilal Patel 1425ff72bc40SMihir Bhogilal Patel list_for_each_entry(file, &dev->filelist, lhead) { 1426ff72bc40SMihir Bhogilal Patel struct amdgpu_fpriv *fpriv = file->driver_priv; 1427ff72bc40SMihir Bhogilal Patel struct amdgpu_vm *vm = &fpriv->vm; 1428ff72bc40SMihir Bhogilal Patel 1429ff72bc40SMihir Bhogilal Patel seq_printf(m, "pid:%d\tProcess:%s ----------\n", 1430ff72bc40SMihir Bhogilal Patel vm->task_info.pid, vm->task_info.process_name); 1431391629bdSNirmoy Das r = amdgpu_bo_reserve(vm->root.bo, true); 1432ff72bc40SMihir Bhogilal Patel if (r) 1433ff72bc40SMihir Bhogilal Patel break; 1434ff72bc40SMihir Bhogilal Patel amdgpu_debugfs_vm_bo_info(vm, m); 1435391629bdSNirmoy Das amdgpu_bo_unreserve(vm->root.bo); 1436ff72bc40SMihir Bhogilal Patel } 1437ff72bc40SMihir Bhogilal Patel 1438ff72bc40SMihir Bhogilal Patel mutex_unlock(&dev->filelist_mutex); 1439ff72bc40SMihir Bhogilal Patel 1440ff72bc40SMihir Bhogilal Patel return r; 1441ff72bc40SMihir Bhogilal Patel } 1442ff72bc40SMihir Bhogilal Patel 144398d28ac2SNirmoy Das DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_test_ib); 144498d28ac2SNirmoy Das DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_vm_info); 144598d28ac2SNirmoy Das DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_evict_vram_fops, amdgpu_debugfs_evict_vram, 144698d28ac2SNirmoy Das NULL, "%lld\n"); 144798d28ac2SNirmoy Das DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_evict_gtt_fops, amdgpu_debugfs_evict_gtt, 144898d28ac2SNirmoy Das NULL, "%lld\n"); 1449e7c47231SAlex Deucher DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_benchmark_fops, NULL, amdgpu_debugfs_benchmark, 1450e7c47231SAlex Deucher "%lld\n"); 145175758255SAlex Deucher 14526698a3d0SJack Xiao static void amdgpu_ib_preempt_fences_swap(struct amdgpu_ring *ring, 14536698a3d0SJack Xiao struct dma_fence **fences) 14546698a3d0SJack Xiao { 14556698a3d0SJack Xiao struct amdgpu_fence_driver *drv = &ring->fence_drv; 14566698a3d0SJack Xiao uint32_t sync_seq, last_seq; 14576698a3d0SJack Xiao 14586698a3d0SJack Xiao last_seq = atomic_read(&ring->fence_drv.last_seq); 14596698a3d0SJack Xiao sync_seq = ring->fence_drv.sync_seq; 14606698a3d0SJack Xiao 14616698a3d0SJack Xiao last_seq &= drv->num_fences_mask; 14626698a3d0SJack Xiao sync_seq &= drv->num_fences_mask; 14636698a3d0SJack Xiao 14646698a3d0SJack Xiao do { 14656698a3d0SJack Xiao struct dma_fence *fence, **ptr; 14666698a3d0SJack Xiao 14676698a3d0SJack Xiao ++last_seq; 14686698a3d0SJack Xiao last_seq &= drv->num_fences_mask; 14696698a3d0SJack Xiao ptr = &drv->fences[last_seq]; 14706698a3d0SJack Xiao 14716698a3d0SJack Xiao fence = rcu_dereference_protected(*ptr, 1); 14726698a3d0SJack Xiao RCU_INIT_POINTER(*ptr, NULL); 14736698a3d0SJack Xiao 14746698a3d0SJack Xiao if (!fence) 14756698a3d0SJack Xiao continue; 14766698a3d0SJack Xiao 14776698a3d0SJack Xiao fences[last_seq] = fence; 14786698a3d0SJack Xiao 14796698a3d0SJack Xiao } while (last_seq != sync_seq); 14806698a3d0SJack Xiao } 14816698a3d0SJack Xiao 14826698a3d0SJack Xiao static void amdgpu_ib_preempt_signal_fences(struct dma_fence **fences, 14836698a3d0SJack Xiao int length) 14846698a3d0SJack Xiao { 14856698a3d0SJack Xiao int i; 14866698a3d0SJack Xiao struct dma_fence *fence; 14876698a3d0SJack Xiao 14886698a3d0SJack Xiao for (i = 0; i < length; i++) { 14896698a3d0SJack Xiao fence = fences[i]; 14906698a3d0SJack Xiao if (!fence) 14916698a3d0SJack Xiao continue; 14926698a3d0SJack Xiao dma_fence_signal(fence); 14936698a3d0SJack Xiao dma_fence_put(fence); 14946698a3d0SJack Xiao } 14956698a3d0SJack Xiao } 14966698a3d0SJack Xiao 14976698a3d0SJack Xiao static void amdgpu_ib_preempt_job_recovery(struct drm_gpu_scheduler *sched) 14986698a3d0SJack Xiao { 14996698a3d0SJack Xiao struct drm_sched_job *s_job; 15006698a3d0SJack Xiao struct dma_fence *fence; 15016698a3d0SJack Xiao 15026698a3d0SJack Xiao spin_lock(&sched->job_list_lock); 15036efa4b46SLuben Tuikov list_for_each_entry(s_job, &sched->pending_list, list) { 15046698a3d0SJack Xiao fence = sched->ops->run_job(s_job); 15056698a3d0SJack Xiao dma_fence_put(fence); 15066698a3d0SJack Xiao } 15076698a3d0SJack Xiao spin_unlock(&sched->job_list_lock); 15086698a3d0SJack Xiao } 15096698a3d0SJack Xiao 151080f8fb91SJack Xiao static void amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring *ring) 151180f8fb91SJack Xiao { 151280f8fb91SJack Xiao struct amdgpu_job *job; 15137bdb0899SJack Xiao struct drm_sched_job *s_job, *tmp; 151480f8fb91SJack Xiao uint32_t preempt_seq; 151580f8fb91SJack Xiao struct dma_fence *fence, **ptr; 151680f8fb91SJack Xiao struct amdgpu_fence_driver *drv = &ring->fence_drv; 151780f8fb91SJack Xiao struct drm_gpu_scheduler *sched = &ring->sched; 15187bdb0899SJack Xiao bool preempted = true; 151980f8fb91SJack Xiao 152080f8fb91SJack Xiao if (ring->funcs->type != AMDGPU_RING_TYPE_GFX) 152180f8fb91SJack Xiao return; 152280f8fb91SJack Xiao 152380f8fb91SJack Xiao preempt_seq = le32_to_cpu(*(drv->cpu_addr + 2)); 15247bdb0899SJack Xiao if (preempt_seq <= atomic_read(&drv->last_seq)) { 15257bdb0899SJack Xiao preempted = false; 15267bdb0899SJack Xiao goto no_preempt; 15277bdb0899SJack Xiao } 152880f8fb91SJack Xiao 152980f8fb91SJack Xiao preempt_seq &= drv->num_fences_mask; 153080f8fb91SJack Xiao ptr = &drv->fences[preempt_seq]; 153180f8fb91SJack Xiao fence = rcu_dereference_protected(*ptr, 1); 153280f8fb91SJack Xiao 15337bdb0899SJack Xiao no_preempt: 153480f8fb91SJack Xiao spin_lock(&sched->job_list_lock); 15356efa4b46SLuben Tuikov list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) { 15367bdb0899SJack Xiao if (dma_fence_is_signaled(&s_job->s_fence->finished)) { 15377bdb0899SJack Xiao /* remove job from ring_mirror_list */ 15388935ff00SLuben Tuikov list_del_init(&s_job->list); 15397bdb0899SJack Xiao sched->ops->free_job(s_job); 15407bdb0899SJack Xiao continue; 15417bdb0899SJack Xiao } 154280f8fb91SJack Xiao job = to_amdgpu_job(s_job); 1543c530b02fSJack Zhang if (preempted && (&job->hw_fence) == fence) 154480f8fb91SJack Xiao /* mark the job as preempted */ 154580f8fb91SJack Xiao job->preemption_status |= AMDGPU_IB_PREEMPTED; 154680f8fb91SJack Xiao } 154780f8fb91SJack Xiao spin_unlock(&sched->job_list_lock); 154880f8fb91SJack Xiao } 154980f8fb91SJack Xiao 15506698a3d0SJack Xiao static int amdgpu_debugfs_ib_preempt(void *data, u64 val) 15516698a3d0SJack Xiao { 15526698a3d0SJack Xiao int r, resched, length; 15536698a3d0SJack Xiao struct amdgpu_ring *ring; 15546698a3d0SJack Xiao struct dma_fence **fences = NULL; 15556698a3d0SJack Xiao struct amdgpu_device *adev = (struct amdgpu_device *)data; 15566698a3d0SJack Xiao 15576698a3d0SJack Xiao if (val >= AMDGPU_MAX_RINGS) 15586698a3d0SJack Xiao return -EINVAL; 15596698a3d0SJack Xiao 15606698a3d0SJack Xiao ring = adev->rings[val]; 15616698a3d0SJack Xiao 15626698a3d0SJack Xiao if (!ring || !ring->funcs->preempt_ib || !ring->sched.thread) 15636698a3d0SJack Xiao return -EINVAL; 15646698a3d0SJack Xiao 15656698a3d0SJack Xiao /* the last preemption failed */ 15666698a3d0SJack Xiao if (ring->trail_seq != le32_to_cpu(*ring->trail_fence_cpu_addr)) 15676698a3d0SJack Xiao return -EBUSY; 15686698a3d0SJack Xiao 15696698a3d0SJack Xiao length = ring->fence_drv.num_fences_mask + 1; 15706698a3d0SJack Xiao fences = kcalloc(length, sizeof(void *), GFP_KERNEL); 15716698a3d0SJack Xiao if (!fences) 15726698a3d0SJack Xiao return -ENOMEM; 15736698a3d0SJack Xiao 1574a28fda31SAndrey Grodzovsky /* Avoid accidently unparking the sched thread during GPU reset */ 1575d0fb18b5SAndrey Grodzovsky r = down_read_killable(&adev->reset_domain->sem); 15766049db43SDennis Li if (r) 15776049db43SDennis Li goto pro_end; 1578a28fda31SAndrey Grodzovsky 15796698a3d0SJack Xiao /* stop the scheduler */ 15806698a3d0SJack Xiao kthread_park(ring->sched.thread); 15816698a3d0SJack Xiao 15826698a3d0SJack Xiao resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); 15836698a3d0SJack Xiao 15846698a3d0SJack Xiao /* preempt the IB */ 15856698a3d0SJack Xiao r = amdgpu_ring_preempt_ib(ring); 15866698a3d0SJack Xiao if (r) { 15876698a3d0SJack Xiao DRM_WARN("failed to preempt ring %d\n", ring->idx); 15886698a3d0SJack Xiao goto failure; 15896698a3d0SJack Xiao } 15906698a3d0SJack Xiao 15916698a3d0SJack Xiao amdgpu_fence_process(ring); 15926698a3d0SJack Xiao 15936698a3d0SJack Xiao if (atomic_read(&ring->fence_drv.last_seq) != 15946698a3d0SJack Xiao ring->fence_drv.sync_seq) { 15956698a3d0SJack Xiao DRM_INFO("ring %d was preempted\n", ring->idx); 15966698a3d0SJack Xiao 159780f8fb91SJack Xiao amdgpu_ib_preempt_mark_partial_job(ring); 159880f8fb91SJack Xiao 15996698a3d0SJack Xiao /* swap out the old fences */ 16006698a3d0SJack Xiao amdgpu_ib_preempt_fences_swap(ring, fences); 16016698a3d0SJack Xiao 16026698a3d0SJack Xiao amdgpu_fence_driver_force_completion(ring); 16036698a3d0SJack Xiao 16046698a3d0SJack Xiao /* resubmit unfinished jobs */ 16056698a3d0SJack Xiao amdgpu_ib_preempt_job_recovery(&ring->sched); 16066698a3d0SJack Xiao 16076698a3d0SJack Xiao /* wait for jobs finished */ 16086698a3d0SJack Xiao amdgpu_fence_wait_empty(ring); 16096698a3d0SJack Xiao 16106698a3d0SJack Xiao /* signal the old fences */ 16116698a3d0SJack Xiao amdgpu_ib_preempt_signal_fences(fences, length); 16126698a3d0SJack Xiao } 16136698a3d0SJack Xiao 16146698a3d0SJack Xiao failure: 16156698a3d0SJack Xiao /* restart the scheduler */ 16166698a3d0SJack Xiao kthread_unpark(ring->sched.thread); 16176698a3d0SJack Xiao 1618d0fb18b5SAndrey Grodzovsky up_read(&adev->reset_domain->sem); 1619a28fda31SAndrey Grodzovsky 16206698a3d0SJack Xiao ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); 16216698a3d0SJack Xiao 16226049db43SDennis Li pro_end: 16236698a3d0SJack Xiao kfree(fences); 16246698a3d0SJack Xiao 16256049db43SDennis Li return r; 16266698a3d0SJack Xiao } 16276698a3d0SJack Xiao 16280cf64555SChengming Gui static int amdgpu_debugfs_sclk_set(void *data, u64 val) 16290cf64555SChengming Gui { 16300cf64555SChengming Gui int ret = 0; 16310cf64555SChengming Gui uint32_t max_freq, min_freq; 16320cf64555SChengming Gui struct amdgpu_device *adev = (struct amdgpu_device *)data; 16330cf64555SChengming Gui 16340cf64555SChengming Gui if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) 16350cf64555SChengming Gui return -EINVAL; 16360cf64555SChengming Gui 16374a580877SLuben Tuikov ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); 16389eee152aSAlex Deucher if (ret < 0) { 16394a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 16400cf64555SChengming Gui return ret; 16419eee152aSAlex Deucher } 16420cf64555SChengming Gui 1643bc143d8bSEvan Quan ret = amdgpu_dpm_get_dpm_freq_range(adev, PP_SCLK, &min_freq, &max_freq); 1644bc143d8bSEvan Quan if (ret == -EOPNOTSUPP) { 1645bc143d8bSEvan Quan ret = 0; 1646bc143d8bSEvan Quan goto out; 1647bc143d8bSEvan Quan } 1648bc143d8bSEvan Quan if (ret || val > max_freq || val < min_freq) { 1649bc143d8bSEvan Quan ret = -EINVAL; 1650bc143d8bSEvan Quan goto out; 16510cf64555SChengming Gui } 16520cf64555SChengming Gui 1653bc143d8bSEvan Quan ret = amdgpu_dpm_set_soft_freq_range(adev, PP_SCLK, (uint32_t)val, (uint32_t)val); 1654bc143d8bSEvan Quan if (ret) 1655bc143d8bSEvan Quan ret = -EINVAL; 1656bc143d8bSEvan Quan 1657bc143d8bSEvan Quan out: 16584a580877SLuben Tuikov pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 16594a580877SLuben Tuikov pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 16600cf64555SChengming Gui 1661bc143d8bSEvan Quan return ret; 16620cf64555SChengming Gui } 16630cf64555SChengming Gui 16647271a5c2SYang Li DEFINE_DEBUGFS_ATTRIBUTE(fops_ib_preempt, NULL, 16656698a3d0SJack Xiao amdgpu_debugfs_ib_preempt, "%llu\n"); 16666698a3d0SJack Xiao 16677271a5c2SYang Li DEFINE_DEBUGFS_ATTRIBUTE(fops_sclk_set, NULL, 16680cf64555SChengming Gui amdgpu_debugfs_sclk_set, "%llu\n"); 16690cf64555SChengming Gui 16705ce5a584SSomalapuram Amaranath static ssize_t amdgpu_reset_dump_register_list_read(struct file *f, 16715ce5a584SSomalapuram Amaranath char __user *buf, size_t size, loff_t *pos) 16725ce5a584SSomalapuram Amaranath { 16735ce5a584SSomalapuram Amaranath struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; 16745ce5a584SSomalapuram Amaranath char reg_offset[12]; 16755ce5a584SSomalapuram Amaranath int i, ret, len = 0; 16765ce5a584SSomalapuram Amaranath 16775ce5a584SSomalapuram Amaranath if (*pos) 16785ce5a584SSomalapuram Amaranath return 0; 16795ce5a584SSomalapuram Amaranath 16805ce5a584SSomalapuram Amaranath memset(reg_offset, 0, 12); 168138a15ad9SDave Airlie ret = down_read_killable(&adev->reset_domain->sem); 16825ce5a584SSomalapuram Amaranath if (ret) 16835ce5a584SSomalapuram Amaranath return ret; 16845ce5a584SSomalapuram Amaranath 16855ce5a584SSomalapuram Amaranath for (i = 0; i < adev->num_regs; i++) { 16865ce5a584SSomalapuram Amaranath sprintf(reg_offset, "0x%x\n", adev->reset_dump_reg_list[i]); 168738a15ad9SDave Airlie up_read(&adev->reset_domain->sem); 16885ce5a584SSomalapuram Amaranath if (copy_to_user(buf + len, reg_offset, strlen(reg_offset))) 16895ce5a584SSomalapuram Amaranath return -EFAULT; 16905ce5a584SSomalapuram Amaranath 16915ce5a584SSomalapuram Amaranath len += strlen(reg_offset); 169238a15ad9SDave Airlie ret = down_read_killable(&adev->reset_domain->sem); 16935ce5a584SSomalapuram Amaranath if (ret) 16945ce5a584SSomalapuram Amaranath return ret; 16955ce5a584SSomalapuram Amaranath } 16965ce5a584SSomalapuram Amaranath 169738a15ad9SDave Airlie up_read(&adev->reset_domain->sem); 16985ce5a584SSomalapuram Amaranath *pos += len; 16995ce5a584SSomalapuram Amaranath 17005ce5a584SSomalapuram Amaranath return len; 17015ce5a584SSomalapuram Amaranath } 17025ce5a584SSomalapuram Amaranath 17035ce5a584SSomalapuram Amaranath static ssize_t amdgpu_reset_dump_register_list_write(struct file *f, 17045ce5a584SSomalapuram Amaranath const char __user *buf, size_t size, loff_t *pos) 17055ce5a584SSomalapuram Amaranath { 17065ce5a584SSomalapuram Amaranath struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; 17075ce5a584SSomalapuram Amaranath char reg_offset[11]; 1708*ad2feebdSSebin Sebastian uint32_t *new = NULL, *tmp = NULL; 17095ce5a584SSomalapuram Amaranath int ret, i = 0, len = 0; 17105ce5a584SSomalapuram Amaranath 17115ce5a584SSomalapuram Amaranath do { 17125ce5a584SSomalapuram Amaranath memset(reg_offset, 0, 11); 17135ce5a584SSomalapuram Amaranath if (copy_from_user(reg_offset, buf + len, 17145ce5a584SSomalapuram Amaranath min(10, ((int)size-len)))) { 17155ce5a584SSomalapuram Amaranath ret = -EFAULT; 17165ce5a584SSomalapuram Amaranath goto error_free; 17175ce5a584SSomalapuram Amaranath } 17185ce5a584SSomalapuram Amaranath 1719ca6fcfa8STom Rix new = krealloc_array(tmp, i + 1, sizeof(uint32_t), GFP_KERNEL); 1720ca6fcfa8STom Rix if (!new) { 1721ca6fcfa8STom Rix ret = -ENOMEM; 1722ca6fcfa8STom Rix goto error_free; 1723ca6fcfa8STom Rix } 1724ca6fcfa8STom Rix tmp = new; 17255ce5a584SSomalapuram Amaranath if (sscanf(reg_offset, "%X %n", &tmp[i], &ret) != 1) { 17265ce5a584SSomalapuram Amaranath ret = -EINVAL; 17275ce5a584SSomalapuram Amaranath goto error_free; 17285ce5a584SSomalapuram Amaranath } 17295ce5a584SSomalapuram Amaranath 17305ce5a584SSomalapuram Amaranath len += ret; 17315ce5a584SSomalapuram Amaranath i++; 17325ce5a584SSomalapuram Amaranath } while (len < size); 17335ce5a584SSomalapuram Amaranath 1734651d7ee6SSomalapuram Amaranath new = kmalloc_array(i, sizeof(uint32_t), GFP_KERNEL); 1735651d7ee6SSomalapuram Amaranath if (!new) { 1736651d7ee6SSomalapuram Amaranath ret = -ENOMEM; 1737651d7ee6SSomalapuram Amaranath goto error_free; 1738651d7ee6SSomalapuram Amaranath } 173938a15ad9SDave Airlie ret = down_write_killable(&adev->reset_domain->sem); 17405ce5a584SSomalapuram Amaranath if (ret) 17415ce5a584SSomalapuram Amaranath goto error_free; 17425ce5a584SSomalapuram Amaranath 17435ce5a584SSomalapuram Amaranath swap(adev->reset_dump_reg_list, tmp); 1744651d7ee6SSomalapuram Amaranath swap(adev->reset_dump_reg_value, new); 17455ce5a584SSomalapuram Amaranath adev->num_regs = i; 174638a15ad9SDave Airlie up_write(&adev->reset_domain->sem); 17475ce5a584SSomalapuram Amaranath ret = size; 17485ce5a584SSomalapuram Amaranath 17495ce5a584SSomalapuram Amaranath error_free: 1750*ad2feebdSSebin Sebastian if (tmp != new) 17515ce5a584SSomalapuram Amaranath kfree(tmp); 1752651d7ee6SSomalapuram Amaranath kfree(new); 17535ce5a584SSomalapuram Amaranath return ret; 17545ce5a584SSomalapuram Amaranath } 17555ce5a584SSomalapuram Amaranath 17565ce5a584SSomalapuram Amaranath static const struct file_operations amdgpu_reset_dump_register_list = { 17575ce5a584SSomalapuram Amaranath .owner = THIS_MODULE, 17585ce5a584SSomalapuram Amaranath .read = amdgpu_reset_dump_register_list_read, 17595ce5a584SSomalapuram Amaranath .write = amdgpu_reset_dump_register_list_write, 17605ce5a584SSomalapuram Amaranath .llseek = default_llseek 17615ce5a584SSomalapuram Amaranath }; 17625ce5a584SSomalapuram Amaranath 176375758255SAlex Deucher int amdgpu_debugfs_init(struct amdgpu_device *adev) 176475758255SAlex Deucher { 176598d28ac2SNirmoy Das struct dentry *root = adev_to_drm(adev)->primary->debugfs_root; 176688293c03SNirmoy Das struct dentry *ent; 1767fd23cfccSAlex Deucher int r, i; 1768c5820361SAlex Deucher 17695b9581dfSNirmoy Das if (!debugfs_initialized()) 17705b9581dfSNirmoy Das return 0; 17715b9581dfSNirmoy Das 17726ff7fddbSLang Yu debugfs_create_x32("amdgpu_smu_debug", 0600, root, 17737e31a858SEvan Quan &adev->pm.smu_debug_mask); 17746ff7fddbSLang Yu 177598d28ac2SNirmoy Das ent = debugfs_create_file("amdgpu_preempt_ib", 0600, root, adev, 177644b582b3SGeert Uytterhoeven &fops_ib_preempt); 177759715cffSNirmoy Das if (IS_ERR(ent)) { 17786698a3d0SJack Xiao DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n"); 177959715cffSNirmoy Das return PTR_ERR(ent); 17806698a3d0SJack Xiao } 17816698a3d0SJack Xiao 178298d28ac2SNirmoy Das ent = debugfs_create_file("amdgpu_force_sclk", 0200, root, adev, 17830cf64555SChengming Gui &fops_sclk_set); 178459715cffSNirmoy Das if (IS_ERR(ent)) { 17850cf64555SChengming Gui DRM_ERROR("unable to create amdgpu_set_sclk debugsfs file\n"); 178659715cffSNirmoy Das return PTR_ERR(ent); 17870cf64555SChengming Gui } 17880cf64555SChengming Gui 1789c5820361SAlex Deucher /* Register debugfs entries for amdgpu_ttm */ 179098d28ac2SNirmoy Das amdgpu_ttm_debugfs_init(adev); 1791373720f7SNirmoy Das amdgpu_debugfs_pm_init(adev); 179298d28ac2SNirmoy Das amdgpu_debugfs_sa_init(adev); 179398d28ac2SNirmoy Das amdgpu_debugfs_fence_init(adev); 179498d28ac2SNirmoy Das amdgpu_debugfs_gem_init(adev); 17953f5cea67SAlex Deucher 1796f9d64e6cSAlex Deucher r = amdgpu_debugfs_regs_init(adev); 1797f9d64e6cSAlex Deucher if (r) 1798f9d64e6cSAlex Deucher DRM_ERROR("registering register debugfs failed (%d).\n", r); 1799f9d64e6cSAlex Deucher 180098d28ac2SNirmoy Das amdgpu_debugfs_firmware_init(adev); 1801e50d9ba0SCandice Li amdgpu_ta_if_debugfs_init(adev); 1802cd9e29e7SAlex Deucher 1803d090e7dbSAlex Deucher #if defined(CONFIG_DRM_AMD_DC) 1804afd3a359SNirmoy Das if (amdgpu_device_has_dc_support(adev)) 1805afd3a359SNirmoy Das dtn_debugfs_init(adev); 1806d090e7dbSAlex Deucher #endif 1807d090e7dbSAlex Deucher 1808fd23cfccSAlex Deucher for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 1809fd23cfccSAlex Deucher struct amdgpu_ring *ring = adev->rings[i]; 1810fd23cfccSAlex Deucher 1811fd23cfccSAlex Deucher if (!ring) 1812fd23cfccSAlex Deucher continue; 1813fd23cfccSAlex Deucher 181462d266b2SNirmoy Das amdgpu_debugfs_ring_init(adev, ring); 1815fd23cfccSAlex Deucher } 1816fd23cfccSAlex Deucher 181711eb648dSRuijing Dong for ( i = 0; i < adev->vcn.num_vcn_inst; i++) { 181811eb648dSRuijing Dong if (!amdgpu_vcnfw_log) 181911eb648dSRuijing Dong break; 182011eb648dSRuijing Dong 182111eb648dSRuijing Dong if (adev->vcn.harvest_config & (1 << i)) 182211eb648dSRuijing Dong continue; 182311eb648dSRuijing Dong 182411eb648dSRuijing Dong amdgpu_debugfs_vcn_fwlog_init(adev, i, &adev->vcn.inst[i]); 182511eb648dSRuijing Dong } 182611eb648dSRuijing Dong 1827204eaac6STao Zhou amdgpu_ras_debugfs_create_all(adev); 1828a4322e18SWenhui Sheng amdgpu_rap_debugfs_init(adev); 1829ecaafb7bSJinzhou Su amdgpu_securedisplay_debugfs_init(adev); 183019ae3330SJohn Clements amdgpu_fw_attestation_debugfs_init(adev); 183119ae3330SJohn Clements 183298d28ac2SNirmoy Das debugfs_create_file("amdgpu_evict_vram", 0444, root, adev, 183398d28ac2SNirmoy Das &amdgpu_evict_vram_fops); 183498d28ac2SNirmoy Das debugfs_create_file("amdgpu_evict_gtt", 0444, root, adev, 183598d28ac2SNirmoy Das &amdgpu_evict_gtt_fops); 183698d28ac2SNirmoy Das debugfs_create_file("amdgpu_test_ib", 0444, root, adev, 183798d28ac2SNirmoy Das &amdgpu_debugfs_test_ib_fops); 183898d28ac2SNirmoy Das debugfs_create_file("amdgpu_vm_info", 0444, root, adev, 183998d28ac2SNirmoy Das &amdgpu_debugfs_vm_info_fops); 1840e7c47231SAlex Deucher debugfs_create_file("amdgpu_benchmark", 0200, root, adev, 1841e7c47231SAlex Deucher &amdgpu_benchmark_fops); 18425ce5a584SSomalapuram Amaranath debugfs_create_file("amdgpu_reset_dump_register_list", 0644, root, adev, 18435ce5a584SSomalapuram Amaranath &amdgpu_reset_dump_register_list); 184498d28ac2SNirmoy Das 184598d28ac2SNirmoy Das adev->debugfs_vbios_blob.data = adev->bios; 184698d28ac2SNirmoy Das adev->debugfs_vbios_blob.size = adev->bios_size; 184798d28ac2SNirmoy Das debugfs_create_blob("amdgpu_vbios", 0444, root, 184898d28ac2SNirmoy Das &adev->debugfs_vbios_blob); 184998d28ac2SNirmoy Das 185081d1bf01SAlex Deucher adev->debugfs_discovery_blob.data = adev->mman.discovery_bin; 185181d1bf01SAlex Deucher adev->debugfs_discovery_blob.size = adev->mman.discovery_tmr_size; 185281d1bf01SAlex Deucher debugfs_create_blob("amdgpu_discovery", 0444, root, 185381d1bf01SAlex Deucher &adev->debugfs_discovery_blob); 185481d1bf01SAlex Deucher 185598d28ac2SNirmoy Das return 0; 185675758255SAlex Deucher } 185775758255SAlex Deucher 185875758255SAlex Deucher #else 185975758255SAlex Deucher int amdgpu_debugfs_init(struct amdgpu_device *adev) 186075758255SAlex Deucher { 186175758255SAlex Deucher return 0; 186275758255SAlex Deucher } 186375758255SAlex Deucher int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) 186475758255SAlex Deucher { 186575758255SAlex Deucher return 0; 186675758255SAlex Deucher } 186775758255SAlex Deucher #endif 1868