diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
-rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 81 |
2 files changed, 108 insertions, 12 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index e79ac1e2c460..35ca732f7ffe 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -720,16 +720,49 @@ int connector_debugfs_init(struct amdgpu_dm_connector *connector) return 0; } +/* + * Writes DTN log state to the user supplied buffer. + * Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_dtn_log + */ static ssize_t dtn_log_read( struct file *f, char __user *buf, size_t size, loff_t *pos) { - /* TODO: Write log output to the user supplied buffer. */ - return 0; + struct amdgpu_device *adev = file_inode(f)->i_private; + struct dc *dc = adev->dm.dc; + struct dc_log_buffer_ctx log_ctx = { 0 }; + ssize_t result = 0; + + if (!buf || !size) + return -EINVAL; + + if (!dc->hwss.log_hw_state) + return 0; + + dc->hwss.log_hw_state(dc, &log_ctx); + + if (*pos < log_ctx.pos) { + size_t to_copy = log_ctx.pos - *pos; + + to_copy = min(to_copy, size); + + if (!copy_to_user(buf, log_ctx.buf + *pos, to_copy)) { + *pos += to_copy; + result = to_copy; + } + } + + kfree(log_ctx.buf); + + return result; } +/* + * Writes DTN log state to dmesg when triggered via a write. + * Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dtn_log + */ static ssize_t dtn_log_write( struct file *f, const char __user *buf, @@ -744,7 +777,7 @@ static ssize_t dtn_log_write( return 0; if (dc->hwss.log_hw_state) - dc->hwss.log_hw_state(dc); + dc->hwss.log_hw_state(dc, NULL); return size; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 86b63ce1dbf6..39997d977efb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -335,28 +335,91 @@ bool dm_helpers_dp_mst_send_payload_allocation( return true; } -void dm_dtn_log_begin(struct dc_context *ctx) +void dm_dtn_log_begin(struct dc_context *ctx, + struct dc_log_buffer_ctx *log_ctx) { - pr_info("[dtn begin]\n"); + static const char msg[] = "[dtn begin]\n"; + + if (!log_ctx) { + pr_info("%s", msg); + return; + } + + dm_dtn_log_append_v(ctx, log_ctx, "%s", msg); } void dm_dtn_log_append_v(struct dc_context *ctx, - const char *msg, ...) + struct dc_log_buffer_ctx *log_ctx, + const char *msg, ...) { - struct va_format vaf; va_list args; + size_t total; + int n; + + if (!log_ctx) { + /* No context, redirect to dmesg. */ + struct va_format vaf; + + vaf.fmt = msg; + vaf.va = &args; + + va_start(args, msg); + pr_info("%pV", &vaf); + va_end(args); + return; + } + + /* Measure the output. */ va_start(args, msg); - vaf.fmt = msg; - vaf.va = &args; + n = vsnprintf(NULL, 0, msg, args); + va_end(args); + + if (n <= 0) + return; + + /* Reallocate the string buffer as needed. */ + total = log_ctx->pos + n + 1; - pr_info("%pV", &vaf); + if (total > log_ctx->size) { + char *buf = (char *)kvcalloc(total, sizeof(char), GFP_KERNEL); + + if (buf) { + memcpy(buf, log_ctx->buf, log_ctx->pos); + kfree(log_ctx->buf); + + log_ctx->buf = buf; + log_ctx->size = total; + } + } + + if (!log_ctx->buf) + return; + + /* Write the formatted string to the log buffer. */ + va_start(args, msg); + n = vscnprintf( + log_ctx->buf + log_ctx->pos, + log_ctx->size - log_ctx->pos, + msg, + args); va_end(args); + + if (n > 0) + log_ctx->pos += n; } -void dm_dtn_log_end(struct dc_context *ctx) +void dm_dtn_log_end(struct dc_context *ctx, + struct dc_log_buffer_ctx *log_ctx) { - pr_info("[dtn end]\n"); + static const char msg[] = "[dtn end]\n"; + + if (!log_ctx) { + pr_info("%s", msg); + return; + } + + dm_dtn_log_append_v(ctx, log_ctx, "%s", msg); } bool dm_helpers_dp_mst_start_top_mgr( |