File Index
Files and directories
Sign in
FILE

msm_disp_snapshot_util.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  4 */
  5
  6#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
  7
  8#include <generated/utsrelease.h>
  9
 10#include "msm_disp_snapshot.h"
 11
 12static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr)
 13{
 14	u32 len_padded;
 15	u32 num_rows;
 16	u32 x0, x4, x8, xc;
 17	void __iomem *addr;
 18	u32 *dump_addr = NULL;
 19	void __iomem *end_addr;
 20	int i;
 21
 22	len_padded = aligned_len * REG_DUMP_ALIGN;
 23	num_rows = aligned_len / REG_DUMP_ALIGN;
 24
 25	addr = base_addr;
 26	end_addr = base_addr + aligned_len;
 27
 28	*reg = kvzalloc(len_padded, GFP_KERNEL);
 29	if (!*reg)
 30		return;
 31
 32	dump_addr = *reg;
 33	for (i = 0; i < num_rows; i++) {
 34		x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0;
 35		x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0;
 36		x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0;
 37		xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0;
 38
 39		dump_addr[i * 4] = x0;
 40		dump_addr[i * 4 + 1] = x4;
 41		dump_addr[i * 4 + 2] = x8;
 42		dump_addr[i * 4 + 3] = xc;
 43
 44		addr += REG_DUMP_ALIGN;
 45	}
 46}
 47
 48static void msm_disp_state_print_regs(const u32 *dump_addr, u32 len,
 49		void __iomem *base_addr, struct drm_printer *p)
 50{
 51	int i;
 52	void __iomem *addr;
 53	u32 num_rows;
 54
 55	if (!dump_addr) {
 56		drm_printf(p, "Registers not stored\n");
 57		return;
 58	}
 59
 60	addr = base_addr;
 61	num_rows = len / REG_DUMP_ALIGN;
 62
 63	for (i = 0; i < num_rows; i++) {
 64		drm_printf(p, "0x%lx : %08x %08x %08x %08x\n",
 65				(unsigned long)(addr - base_addr),
 66				dump_addr[i * 4], dump_addr[i * 4 + 1],
 67				dump_addr[i * 4 + 2], dump_addr[i * 4 + 3]);
 68		addr += REG_DUMP_ALIGN;
 69	}
 70}
 71
 72void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p)
 73{
 74	struct msm_disp_state_block *block, *tmp;
 75
 76	if (!p) {
 77		DRM_ERROR("invalid drm printer\n");
 78		return;
 79	}
 80
 81	drm_printf(p, "---\n");
 82	drm_printf(p, "kernel: " UTS_RELEASE "\n");
 83	drm_printf(p, "module: " KBUILD_MODNAME "\n");
 84	drm_printf(p, "dpu devcoredump\n");
 85	drm_printf(p, "time: %ptSp\n", &state->time);
 86
 87	list_for_each_entry_safe(block, tmp, &state->blocks, node) {
 88		drm_printf(p, "====================%s================\n", block->name);
 89		msm_disp_state_print_regs(block->state, block->size, block->base_addr, p);
 90	}
 91
 92	drm_printf(p, "===================dpu drm state================\n");
 93
 94	if (state->atomic_state)
 95		drm_atomic_print_new_state(state->atomic_state, p);
 96}
 97
 98static void msm_disp_capture_atomic_state(struct msm_disp_state *disp_state)
 99{
100	struct drm_device *ddev;
101	struct drm_modeset_acquire_ctx ctx;
102
103	ktime_get_real_ts64(&disp_state->time);
104
105	ddev = disp_state->drm_dev;
106
107	drm_modeset_acquire_init(&ctx, 0);
108
109	while (drm_modeset_lock_all_ctx(ddev, &ctx) != 0)
110		drm_modeset_backoff(&ctx);
111
112	disp_state->atomic_state = drm_atomic_helper_duplicate_state(ddev,
113			&ctx);
114	drm_modeset_drop_locks(&ctx);
115	drm_modeset_acquire_fini(&ctx);
116}
117
118void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state)
119{
120	struct msm_drm_private *priv;
121	struct drm_device *drm_dev;
122	struct msm_kms *kms;
123	int i;
124
125	drm_dev = disp_state->drm_dev;
126	priv = drm_dev->dev_private;
127	kms = priv->kms;
128
129	for (i = 0; i < ARRAY_SIZE(kms->dp); i++) {
130		if (!kms->dp[i])
131			continue;
132
133		msm_dp_snapshot(disp_state, kms->dp[i]);
134	}
135
136	for (i = 0; i < ARRAY_SIZE(kms->dsi); i++) {
137		if (!kms->dsi[i])
138			continue;
139
140		msm_dsi_snapshot(disp_state, kms->dsi[i]);
141	}
142
143	if (kms->funcs->snapshot)
144		kms->funcs->snapshot(disp_state, kms);
145
146	msm_disp_capture_atomic_state(disp_state);
147}
148
149void msm_disp_state_free(void *data)
150{
151	struct msm_disp_state *disp_state = data;
152	struct msm_disp_state_block *block, *tmp;
153
154	if (disp_state->atomic_state) {
155		drm_atomic_state_put(disp_state->atomic_state);
156		disp_state->atomic_state = NULL;
157	}
158
159	list_for_each_entry_safe(block, tmp, &disp_state->blocks, node) {
160		list_del(&block->node);
161		kvfree(block->state);
162		kfree(block);
163	}
164
165	kfree(disp_state);
166}
167
168void msm_disp_snapshot_add_block(struct msm_disp_state *disp_state, u32 len,
169		void __iomem *base_addr, const char *fmt, ...)
170{
171	struct msm_disp_state_block *new_blk;
172	struct va_format vaf;
173	va_list va;
174
175	new_blk = kzalloc(sizeof(struct msm_disp_state_block), GFP_KERNEL);
176	if (!new_blk)
177		return;
178
179	va_start(va, fmt);
180
181	vaf.fmt = fmt;
182	vaf.va = &va;
183	snprintf(new_blk->name, sizeof(new_blk->name), "%pV", &vaf);
184
185	va_end(va);
186
187	INIT_LIST_HEAD(&new_blk->node);
188	new_blk->size = ALIGN(len, REG_DUMP_ALIGN);
189	new_blk->base_addr = base_addr;
190
191	msm_disp_state_dump_regs(&new_blk->state, new_blk->size, base_addr);
192	list_add_tail(&new_blk->node, &disp_state->blocks);
193}
~/ Read-only file preview.