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.jama...@amd.com>
Reviewed-by: Veerabadhran Gopalakrishnan <veerabadhran.gopalakrish...@amd.com>
---
 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

Reply via email to