Added support to capture unsch fw debug logs in debugfs. To enable set amdgpu_umschfw_log =1 in boot args. v1 - reame varibale to umsch_mm_fwlog (Veera) Signed-off-by: Saleemkhan Jamadar <saleemkhan.jamadar@xxxxxxx> Reviewed-by: Veerabadhran Gopalakrishnan <Veerabadhran.Gopalakrishnan@xxxxxxx> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 + drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 3 + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 8 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c | 119 +++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h | 18 +++ drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c | 6 + 6 files changed, 157 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index f87d53e183c3..a855600b13e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -112,6 +112,7 @@ #include "amdgpu_xcp.h" #include "amdgpu_seq64.h" #include "amdgpu_reg_state.h" +#include "amdgpu_umsch_mm.h" #define MAX_GPU_INSTANCE 64 @@ -253,10 +254,12 @@ extern int amdgpu_cik_support; extern int amdgpu_num_kcq; #define AMDGPU_VCNFW_LOG_SIZE (32 * 1024) +#define AMDGPU_UMSCHFW_LOG_SIZE (32 * 1024) extern int amdgpu_vcnfw_log; extern int amdgpu_sg_display; extern int amdgpu_umsch_mm; extern int amdgpu_seamless; +extern int amdgpu_umsch_mm_fwlog; extern int amdgpu_user_partt_mode; extern int amdgpu_agp; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index f5d0fa207a88..82f6d4ccd537 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -2185,6 +2185,9 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) amdgpu_debugfs_vcn_fwlog_init(adev, i, &adev->vcn.inst[i]); } + if (amdgpu_umsch_mm & amdgpu_umsch_mm_fwlog) + amdgpu_debugfs_umsch_fwlog_init(adev, &adev->umsch_mm); + amdgpu_ras_debugfs_create_all(adev); amdgpu_rap_debugfs_init(adev); amdgpu_securedisplay_debugfs_init(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index ea14f1c8f430..9a32724b989e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -214,6 +214,7 @@ uint amdgpu_debug_mask; int amdgpu_agp = -1; /* auto */ int amdgpu_wbrf = -1; int amdgpu_damage_clips = -1; /* auto */ +int amdgpu_umsch_mm_fwlog; static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); @@ -965,6 +966,13 @@ MODULE_PARM_DESC(umsch_mm, "Enable Multi Media User Mode Scheduler (0 = disabled (default), 1 = enabled)"); module_param_named(umsch_mm, amdgpu_umsch_mm, int, 0444); +/** + * DOC: umsch_mm_fwlog (int) + * Enable umschfw log output for debugging, the default is disabled. + */ +MODULE_PARM_DESC(umsch_mm_fwlog, "Enable umschfw log(0 = disable (default value), 1 = enable)"); +module_param_named(umsch_mm_fwlog, amdgpu_umsch_mm_fwlog, int, 0444); + /** * DOC: smu_pptable_id (int) * Used to override pptable id. id = 0 use VBIOS pptable. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c index 9f9d6a6d5cf3..2d2dddea8770 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c @@ -23,7 +23,10 @@ */ #include <linux/firmware.h> +#include <linux/module.h> +#include <linux/debugfs.h> #include <drm/drm_exec.h> +#include <drm/drm_drv.h> #include "amdgpu.h" #include "amdgpu_umsch_mm.h" @@ -743,6 +746,17 @@ static int umsch_mm_init(struct amdgpu_device *adev) return r; } + r = amdgpu_bo_create_kernel(adev, AMDGPU_UMSCHFW_LOG_SIZE, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->umsch_mm.dbglog_bo, + &adev->umsch_mm.log_gpu_addr, + &adev->umsch_mm.log_cpu_addr); + if (r) { + dev_err(adev->dev, "(%d) failed to allocate umsch debug bo\n", r); + return r; + } + mutex_init(&adev->umsch_mm.mutex_hidden); umsch_mm_agdb_index_init(adev); @@ -789,6 +803,7 @@ static int umsch_mm_sw_init(void *handle) if (r) return r; + amdgpu_umsch_fwlog_init(&adev->umsch_mm); r = umsch_mm_ring_init(&adev->umsch_mm); if (r) return r; @@ -815,6 +830,10 @@ static int umsch_mm_sw_fini(void *handle) &adev->umsch_mm.cmd_buf_gpu_addr, (void **)&adev->umsch_mm.cmd_buf_ptr); + amdgpu_bo_free_kernel(&adev->umsch_mm.dbglog_bo, + &adev->umsch_mm.log_gpu_addr, + (void **)&adev->umsch_mm.log_cpu_addr); + amdgpu_device_wb_free(adev, adev->umsch_mm.wb_index); return 0; @@ -868,6 +887,106 @@ static int umsch_mm_resume(void *handle) return umsch_mm_hw_init(adev); } +void amdgpu_umsch_fwlog_init(struct amdgpu_umsch_mm *umsch_mm) +{ +#if defined(CONFIG_DEBUG_FS) + void *fw_log_cpu_addr = umsch_mm->log_cpu_addr; + volatile struct amdgpu_umsch_fwlog *log_buf = fw_log_cpu_addr; + + log_buf->header_size = sizeof(struct amdgpu_umsch_fwlog); + log_buf->buffer_size = AMDGPU_UMSCHFW_LOG_SIZE; + log_buf->rptr = log_buf->header_size; + log_buf->wptr = log_buf->header_size; + log_buf->wrapped = 0; +#endif +} + +/* + * debugfs for mapping umsch firmware log buffer. + */ +#if defined(CONFIG_DEBUG_FS) +static ssize_t amdgpu_debugfs_umsch_fwlog_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_umsch_mm *umsch_mm; + void *log_buf; + volatile struct amdgpu_umsch_fwlog *plog; + unsigned int read_pos, write_pos, available, i, read_bytes = 0; + unsigned int read_num[2] = {0}; + + umsch_mm = file_inode(f)->i_private; + if (!umsch_mm) + return -ENODEV; + + if (!umsch_mm->log_cpu_addr) + return -EFAULT; + + log_buf = umsch_mm->log_cpu_addr; + + plog = (volatile struct amdgpu_umsch_fwlog *)log_buf; + read_pos = plog->rptr; + write_pos = plog->wptr; + + if (read_pos > AMDGPU_UMSCHFW_LOG_SIZE || write_pos > AMDGPU_UMSCHFW_LOG_SIZE) + return -EFAULT; + + if (!size || (read_pos == write_pos)) + return 0; + + if (write_pos > read_pos) { + available = write_pos - read_pos; + read_num[0] = min_t(size_t, size, available); + } else { + read_num[0] = AMDGPU_UMSCHFW_LOG_SIZE - read_pos; + available = read_num[0] + write_pos - plog->header_size; + if (size > available) + read_num[1] = write_pos - plog->header_size; + else if (size > read_num[0]) + read_num[1] = size - read_num[0]; + else + read_num[0] = size; + } + + for (i = 0; i < 2; i++) { + if (read_num[i]) { + if (read_pos == AMDGPU_UMSCHFW_LOG_SIZE) + read_pos = plog->header_size; + if (read_num[i] == copy_to_user((buf + read_bytes), + (log_buf + read_pos), read_num[i])) + return -EFAULT; + + read_bytes += read_num[i]; + read_pos += read_num[i]; + } + } + + plog->rptr = read_pos; + *pos += read_bytes; + return read_bytes; +} + +static const struct file_operations amdgpu_debugfs_umschfwlog_fops = { + .owner = THIS_MODULE, + .read = amdgpu_debugfs_umsch_fwlog_read, + .llseek = default_llseek +}; +#endif + +void amdgpu_debugfs_umsch_fwlog_init(struct amdgpu_device *adev, + struct amdgpu_umsch_mm *umsch_mm) +{ +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + struct dentry *root = minor->debugfs_root; + char name[32]; + + sprintf(name, "amdgpu_umsch_fwlog"); + debugfs_create_file_size(name, S_IFREG | 0444, root, umsch_mm, + &amdgpu_debugfs_umschfwlog_fops, + AMDGPU_UMSCHFW_LOG_SIZE); +#endif +} + static const struct amd_ip_funcs umsch_mm_v4_0_ip_funcs = { .name = "umsch_mm_v4_0", .early_init = umsch_mm_early_init, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h index 5014b5af95fd..2c771a753778 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h @@ -58,6 +58,14 @@ struct umsch_mm_set_resource_input { }; }; +struct amdgpu_umsch_fwlog { + uint32_t rptr; + uint32_t wptr; + uint32_t buffer_size; + uint32_t header_size; + uint32_t wrapped; +}; + struct umsch_mm_add_queue_input { uint32_t process_id; uint64_t page_table_base_addr; @@ -166,6 +174,11 @@ struct amdgpu_umsch_mm { uint32_t agdb_index[CONTEXT_PRIORITY_NUM_LEVELS]; struct mutex mutex_hidden; + struct amdgpu_bo *dbglog_bo; + void *log_cpu_addr; + uint64_t log_gpu_addr; + uint32_t mem_size; + uint32_t log_offset; }; int amdgpu_umsch_mm_submit_pkt(struct amdgpu_umsch_mm *umsch, void *pkt, int ndws); @@ -179,6 +192,11 @@ int amdgpu_umsch_mm_psp_execute_cmd_buf(struct amdgpu_umsch_mm *umsch); int amdgpu_umsch_mm_ring_init(struct amdgpu_umsch_mm *umsch); +void amdgpu_debugfs_umsch_fwlog_init(struct amdgpu_device *adev, + struct amdgpu_umsch_mm *umsch); + +void amdgpu_umsch_fwlog_init(struct amdgpu_umsch_mm *umsch_mm); + #define WREG32_SOC15_UMSCH(reg, value) \ do { \ uint32_t reg_offset = adev->reg_offset[VCN_HWIP][0][reg##_BASE_IDX] + reg; \ diff --git a/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c b/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c index bd57896ab85d..2c5e7b0a73f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c @@ -24,6 +24,7 @@ #include <linux/firmware.h> #include <linux/module.h> +#include <linux/debugfs.h> #include "amdgpu.h" #include "soc15_common.h" #include "soc21.h" @@ -143,6 +144,11 @@ static int umsch_mm_v4_0_load_microcode(struct amdgpu_umsch_mm *umsch) WREG32_SOC15_UMSCH(regVCN_MES_GP0_LO, 0); WREG32_SOC15_UMSCH(regVCN_MES_GP0_HI, 0); +#if defined(CONFIG_DEBUG_FS) + WREG32_SOC15_UMSCH(regVCN_MES_GP0_LO, lower_32_bits(umsch->log_gpu_addr)); + WREG32_SOC15_UMSCH(regVCN_MES_GP0_HI, upper_32_bits(umsch->log_gpu_addr)); +#endif + WREG32_SOC15_UMSCH(regVCN_MES_GP1_LO, 0); WREG32_SOC15_UMSCH(regVCN_MES_GP1_HI, 0); -- 2.25.1