diff options
author | Dave Airlie <airlied@redhat.com> | 2021-06-24 07:15:17 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2021-06-24 07:21:16 +1000 |
commit | 334200bf52f0637a5ab8331c557dfcecbb9c30fa (patch) | |
tree | 506009c182f6204a0998e2b892716bfa8cbac6e0 /drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c | |
parent | 61c0cb8ae7943b4fad5d62213c1748f1a07fe594 (diff) | |
parent | e88bbc91849b2bf57683119c339e52916d34433f (diff) |
Merge tag 'drm-msm-next-2021-06-23b' of https://gitlab.freedesktop.org/drm/msm into drm-next
* devcoredump support for display errors
* dpu: irq cleanup/refactor
* dpu: dt bindings conversion to yaml
* dsi: dt bindings conversion to yaml
* mdp5: alpha/blend_mode/zpos support
* a6xx: cached coherent buffer support
* a660 support
* gpu iova fault improvements:
- info about which block triggered the fault, etc
- generation of gpu devcoredump on fault
* assortment of other cleanups and fixes
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Rob Clark <robdclark@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CAF6AEGs4=qsGBBbyn-4JWqW4-YUSTKh67X3DsPQ=T2D9aXKqNA@mail.gmail.com
Diffstat (limited to 'drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c')
-rw-r--r-- | drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c new file mode 100644 index 000000000000..cabe15190ec1 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include "msm_disp_snapshot.h" + +static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr) +{ + u32 len_padded; + u32 num_rows; + u32 x0, x4, x8, xc; + void __iomem *addr; + u32 *dump_addr = NULL; + void __iomem *end_addr; + int i; + + len_padded = aligned_len * REG_DUMP_ALIGN; + num_rows = aligned_len / REG_DUMP_ALIGN; + + addr = base_addr; + end_addr = base_addr + aligned_len; + + if (!(*reg)) + *reg = kzalloc(len_padded, GFP_KERNEL); + + if (*reg) + dump_addr = *reg; + + for (i = 0; i < num_rows; i++) { + x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0; + x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0; + x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0; + xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0; + + if (dump_addr) { + dump_addr[i * 4] = x0; + dump_addr[i * 4 + 1] = x4; + dump_addr[i * 4 + 2] = x8; + dump_addr[i * 4 + 3] = xc; + } + + addr += REG_DUMP_ALIGN; + } +} + +static void msm_disp_state_print_regs(u32 **reg, u32 len, void __iomem *base_addr, + struct drm_printer *p) +{ + int i; + u32 *dump_addr = NULL; + void __iomem *addr; + u32 num_rows; + + addr = base_addr; + num_rows = len / REG_DUMP_ALIGN; + + if (*reg) + dump_addr = *reg; + + for (i = 0; i < num_rows; i++) { + drm_printf(p, "0x%lx : %08x %08x %08x %08x\n", + (unsigned long)(addr - base_addr), + dump_addr[i * 4], dump_addr[i * 4 + 1], + dump_addr[i * 4 + 2], dump_addr[i * 4 + 3]); + addr += REG_DUMP_ALIGN; + } +} + +void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p) +{ + struct msm_disp_state_block *block, *tmp; + + if (!p) { + DRM_ERROR("invalid drm printer\n"); + return; + } + + drm_printf(p, "---\n"); + + drm_printf(p, "module: " KBUILD_MODNAME "\n"); + drm_printf(p, "dpu devcoredump\n"); + drm_printf(p, "timestamp %lld\n", ktime_to_ns(state->timestamp)); + + list_for_each_entry_safe(block, tmp, &state->blocks, node) { + drm_printf(p, "====================%s================\n", block->name); + msm_disp_state_print_regs(&block->state, block->size, block->base_addr, p); + } + + drm_printf(p, "===================dpu drm state================\n"); + + if (state->atomic_state) + drm_atomic_print_new_state(state->atomic_state, p); +} + +static void msm_disp_capture_atomic_state(struct msm_disp_state *disp_state) +{ + struct drm_device *ddev; + struct drm_modeset_acquire_ctx ctx; + + disp_state->timestamp = ktime_get(); + + ddev = disp_state->drm_dev; + + drm_modeset_acquire_init(&ctx, 0); + + while (drm_modeset_lock_all_ctx(ddev, &ctx) != 0) + drm_modeset_backoff(&ctx); + + disp_state->atomic_state = drm_atomic_helper_duplicate_state(ddev, + &ctx); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state) +{ + struct msm_drm_private *priv; + struct drm_device *drm_dev; + struct msm_kms *kms; + int i; + + drm_dev = disp_state->drm_dev; + priv = drm_dev->dev_private; + kms = priv->kms; + + if (priv->dp) + msm_dp_snapshot(disp_state, priv->dp); + + for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { + if (!priv->dsi[i]) + continue; + + msm_dsi_snapshot(disp_state, priv->dsi[i]); + } + + if (kms->funcs->snapshot) + kms->funcs->snapshot(disp_state, kms); + + msm_disp_capture_atomic_state(disp_state); +} + +void msm_disp_state_free(void *data) +{ + struct msm_disp_state *disp_state = data; + struct msm_disp_state_block *block, *tmp; + + if (disp_state->atomic_state) { + drm_atomic_state_put(disp_state->atomic_state); + disp_state->atomic_state = NULL; + } + + list_for_each_entry_safe(block, tmp, &disp_state->blocks, node) { + list_del(&block->node); + kfree(block->state); + kfree(block); + } + + kfree(disp_state); +} + +void msm_disp_snapshot_add_block(struct msm_disp_state *disp_state, u32 len, + void __iomem *base_addr, const char *fmt, ...) +{ + struct msm_disp_state_block *new_blk; + struct va_format vaf; + va_list va; + + new_blk = kzalloc(sizeof(struct msm_disp_state_block), GFP_KERNEL); + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + snprintf(new_blk->name, sizeof(new_blk->name), "%pV", &vaf); + + va_end(va); + + INIT_LIST_HEAD(&new_blk->node); + new_blk->size = ALIGN(len, REG_DUMP_ALIGN); + new_blk->base_addr = base_addr; + + msm_disp_state_dump_regs(&new_blk->state, new_blk->size, base_addr); + list_add(&new_blk->node, &disp_state->blocks); +} |