* [PATCH 00/12] drm/msm/a8xx: GPU state capture support
@ 2026-10-20 20:46 Rob Clark
2026-10-20 20:46 ` [PATCH 01/12] drm/msm: Import adreno_snapshot.h Rob Clark
` (10 more replies)
0 siblings, 11 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Abhinav Kumar,
David Airlie, Dmitry Baryshkov, Jessica Zhang, Konrad Dybcio,
open list, Marijn Suijten, Sean Paul, Simona Vetter
This series introduces gen8 devcoredump support. Compared to previous
gens, it:
1. Switches to generated tables. Compared to hand modifying headers from
kgsl (which were originally generated, then adjusted a bit by hand before
adding to kgsl tree. And then copied to drm/msm and lightly modified
some more in the process).
In the process, we also switch to generated nonctx reg tables and
cp_protect tables.
2. Aligns to the "snapshot" format that kgsl/etc use for hw state capture.
The non-generation specific bits (SMMU fault info, capturing relevant
BOs, etc) still works as before. Everything gen8 specific gets encoded
as "snapshot" sections, ascii85 encoded in the resulting devcoredump
file (similar to captured BOs).
3. Try to make it easier to at least compare kgsl snapshot code with
upstream, for porting fixes/etc. State capture is tedious and mind-
numbing, and the last thing you want to do when debugging a GPU hang
is going down the rabbit hole of having to first debug gpu state
capture.
However, I don't love kgsl_snapshot_add_section(). It does avoid
duplicating snapshot header stuff everywhere. But the ergonomics
are not great. So instead I went with "align with what I wish kgsl
looked like..
The mesa/crashdec side of this is at:
https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/45304
I'd appreciate tested-by's on Hawi, Maili, Milos, and Pakala, since I
don't have these devices at-hand to test myself. In particular, do
things look fine after the switch to generated nonctx regs. To test
devcoredump, you can use the msm_recovery test in igt.. or just:
cat /sys/kernel/debug/dri/*/gpu > /dev/null
NOTE: Uses $codename for generated file/table names, rather than continue
to perpetuate the equally meaningless gen8_x_y naming from kgsl into
upstream. At least the codenames are familiar upstream and this
removes an extra level of name translation.
Rob Clark (12):
drm/msm: Import adreno_snapshot.h
drm/msm/a8xx: Export aperture helpers
drm/msm/a8xx: Add a8xx_aperture_acquire_slice()
drm/msm/a8xx: Allow nonctx reglist to include GMU regs
drm/msm/a8xx: Stop getting GMEM_PROTECT from nonctx list
drm/msm/adreno: Fix PROTECT span length
drm/msm/adreno: add temporary __maybe_unused
drm/msm/a8xx: Import generated headers
drm/msm/a8xx: devcoredump state capture support
drm/msm/a8xx: Switch to generated nonctx regs
drm/msm/a8xx: Switch to generated protect regs
drm/msm/adreno: Remove temporary __maybe_unused
drivers/gpu/drm/msm/Makefile | 4 +-
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 7 +
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 15 +-
drivers/gpu/drm/msm/adreno/a8xx_catalog.c | 668 +----
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 42 +-
drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c | 1253 +++++++++
.../gpu/drm/msm/adreno/adreno_gen8_snapshot.h | 582 ++++
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +
drivers/gpu/drm/msm/adreno/adreno_snapshot.h | 526 ++++
.../drm/msm/adreno/catalog/adreno_glymur.h | 2315 ++++++++++++++++
.../gpu/drm/msm/adreno/catalog/adreno_hawi.h | 2410 +++++++++++++++++
.../drm/msm/adreno/catalog/adreno_kaanapali.h | 2339 ++++++++++++++++
.../gpu/drm/msm/adreno/catalog/adreno_maili.h | 1900 +++++++++++++
.../gpu/drm/msm/adreno/catalog/adreno_milos.h | 1994 ++++++++++++++
.../drm/msm/adreno/catalog/adreno_pakala.h | 2178 +++++++++++++++
15 files changed, 15583 insertions(+), 652 deletions(-)
create mode 100644 drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c
create mode 100644 drivers/gpu/drm/msm/adreno/adreno_gen8_snapshot.h
create mode 100644 drivers/gpu/drm/msm/adreno/adreno_snapshot.h
create mode 100644 drivers/gpu/drm/msm/adreno/catalog/adreno_glymur.h
create mode 100644 drivers/gpu/drm/msm/adreno/catalog/adreno_hawi.h
create mode 100644 drivers/gpu/drm/msm/adreno/catalog/adreno_kaanapali.h
create mode 100644 drivers/gpu/drm/msm/adreno/catalog/adreno_maili.h
create mode 100644 drivers/gpu/drm/msm/adreno/catalog/adreno_milos.h
create mode 100644 drivers/gpu/drm/msm/adreno/catalog/adreno_pakala.h
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/12] drm/msm: Import adreno_snapshot.h
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 20:46 ` [PATCH 02/12] drm/msm/a8xx: Export aperture helpers Rob Clark
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
Based on kgsl_snapshot.h from downstream KMD. We'll be re-using some of
this for gen8 devcoredump.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/adreno_snapshot.h | 321 +++++++++++++++++++
1 file changed, 321 insertions(+)
create mode 100644 drivers/gpu/drm/msm/adreno/adreno_snapshot.h
diff --git a/drivers/gpu/drm/msm/adreno/adreno_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
new file mode 100644
index 000000000000..f9956e0bc1d5
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#pragma once
+
+#include <linux/types.h>
+
+/* Snapshot header */
+
+/* High word is static, low word is snapshot version ID */
+#define SNAPSHOT_MAGIC 0x504D0002
+
+#define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
+ + sizeof(struct adreno_snapshot_debug))
+
+/* GPU ID scheme:
+ * [16:31] - core identifer (0x0002 for 2D or 0x0003 for 3D)
+ * [00:16] - GPU specific identifier
+ */
+
+struct adreno_snapshot_header {
+ __u32 magic; /* Magic identifier */
+ __u32 gpuid; /* GPU ID - see above */
+ /* Added in snapshot version 2 */
+ __u32 chipid; /* Chip ID from the GPU */
+} __packed;
+
+/* Section header */
+#define SNAPSHOT_SECTION_MAGIC 0xABCD
+
+struct adreno_snapshot_section_header {
+ __u16 magic; /* Magic identifier */
+ __u16 id; /* Type of section */
+ __u32 size; /* Size of the section including this header */
+} __packed;
+
+/* Section identifiers */
+#define ADRENO_SNAPSHOT_SECTION_OS 0x0101
+#define ADRENO_SNAPSHOT_SECTION_REGS 0x0201
+#define ADRENO_SNAPSHOT_SECTION_REGS_V2 0x0202
+#define ADRENO_SNAPSHOT_SECTION_RB_V2 0x0302
+#define ADRENO_SNAPSHOT_SECTION_IB_V2 0x0402
+#define ADRENO_SNAPSHOT_SECTION_INDEXED_REGS 0x0501
+#define ADRENO_SNAPSHOT_SECTION_INDEXED_REGS_V2 0x0502
+#define ADRENO_SNAPSHOT_SECTION_DEBUG 0x0901
+#define ADRENO_SNAPSHOT_SECTION_DEBUGBUS 0x0A01
+#define ADRENO_SNAPSHOT_SECTION_GPU_OBJECT_V2 0x0B02
+#define ADRENO_SNAPSHOT_SECTION_MEMLIST_V2 0x0E02
+#define ADRENO_SNAPSHOT_SECTION_SHADER 0x1201
+#define ADRENO_SNAPSHOT_SECTION_SHADER_V2 0x1202
+#define ADRENO_SNAPSHOT_SECTION_SHADER_V3 0x1203
+#define ADRENO_SNAPSHOT_SECTION_MVC 0x1501
+#define ADRENO_SNAPSHOT_SECTION_MVC_V2 0x1502
+#define ADRENO_SNAPSHOT_SECTION_MVC_V3 0x1503
+#define ADRENO_SNAPSHOT_SECTION_GMU_MEMORY 0x1701
+#define ADRENO_SNAPSHOT_SECTION_SIDE_DEBUGBUS 0x1801
+#define ADRENO_SNAPSHOT_SECTION_TRACE_BUFFER 0x1901
+#define ADRENO_SNAPSHOT_SECTION_EVENTLOG 0x1A01
+
+#define ADRENO_SNAPSHOT_SECTION_END 0xFFFF
+
+/* OS sub-section header */
+#define ADRENO_SNAPSHOT_OS_LINUX_V4 0x00000203
+
+/* Linux OS specific information */
+struct adreno_snapshot_linux_v4 {
+ int osid; /* subsection OS identifier */
+ __u32 seconds; /* Unix timestamp for the snapshot */
+ __u32 power_flags; /* Current power flags */
+ __u32 power_level; /* Current power level */
+ __u32 power_interval_timeout; /* Power interval timeout */
+ __u32 grpclk; /* Current GP clock value */
+ __u32 busclk; /* Current busclk value */
+ __u64 ptbase; /* Current ptbase */
+ __u64 ptbase_lpac; /* Current LPAC ptbase */
+ __u32 pid; /* PID of the process that owns the PT */
+ __u32 pid_lpac; /* PID of the LPAC process that owns the PT */
+ __u32 current_context; /* ID of the current context */
+ __u32 current_context_lpac; /* ID of the current LPAC context */
+ __u32 ctxtcount; /* Number of contexts appended to section */
+ unsigned char release[32]; /* kernel release */
+ unsigned char version[32]; /* kernel version */
+ unsigned char comm[16]; /* Name of the process that owns the PT */
+ unsigned char comm_lpac[16]; /* Name of the LPAC process that owns the PT */
+} __packed;
+
+/*
+ * This structure contains a record of an active context.
+ * These are appended one after another in the OS section below
+ * the header above
+ */
+struct adreno_snapshot_linux_context_v2 {
+ __u32 id; /* The context ID */
+ __u32 timestamp_queued; /* The last queued timestamp */
+ __u32 timestamp_consumed; /* The last timestamp consumed by HW */
+ __u32 timestamp_retired; /* The last timestamp retired by HW */
+};
+
+/* Ringbuffer sub-section header */
+struct adreno_snapshot_rb_v2 {
+ int start; /* dword at the start of the dump */
+ int end; /* dword at the end of the dump */
+ int rbsize; /* Size (in dwords) of the ringbuffer */
+ int wptr; /* Current index of the CPU write pointer */
+ int rptr; /* Current index of the GPU read pointer */
+ int count; /* Number of dwords in the dump */
+ __u32 timestamp_queued; /* The last queued timestamp */
+ __u32 timestamp_retired; /* The last timestamp retired by HW */
+ __u64 gpuaddr; /* The GPU address of the ringbuffer */
+ __u32 id; /* Ringbuffer identifier */
+} __packed;
+
+/* Replay or Memory list section, both sections have same header */
+struct adreno_snapshot_mem_list_v2 {
+ /*
+ * Number of IBs to replay for replay section or
+ * number of memory list entries for mem list section
+ */
+ int num_entries;
+ /* Pagetable base to which the replay IBs or memory entries belong */
+ __u64 ptbase;
+} __packed;
+
+/* Indirect buffer sub-section header (v2) */
+struct adreno_snapshot_ib_v2 {
+ __u64 gpuaddr; /* GPU address of the IB */
+ __u64 ptbase; /* Base for the pagetable the GPU address is valid in */
+ __u64 size; /* Size of the IB */
+} __packed;
+
+/* GMU memory ID's */
+#define SNAPSHOT_GMU_MEM_UNKNOWN 0x00
+#define SNAPSHOT_GMU_MEM_HFI 0x01
+#define SNAPSHOT_GMU_MEM_LOG 0x02
+#define SNAPSHOT_GMU_MEM_BWTABLE 0x03
+#define SNAPSHOT_GMU_MEM_DEBUG 0x04
+#define SNAPSHOT_GMU_MEM_BIN_BLOCK 0x05
+#define SNAPSHOT_GMU_MEM_CONTEXT_QUEUE 0x06
+#define SNAPSHOT_GMU_MEM_HW_FENCE 0x07
+#define SNAPSHOT_GMU_MEM_WARMBOOT 0x08
+#define SNAPSHOT_GMU_MEM_VRB 0x09
+#define SNAPSHOT_GMU_MEM_TRACE 0x0a
+
+/* GMU memory section data */
+struct adreno_snapshot_gmu_mem {
+ int type;
+ uint64_t hostaddr;
+ uint64_t gmuaddr;
+ uint64_t gpuaddr;
+} __packed;
+
+/* Register sub-section header */
+struct adreno_snapshot_regs {
+ __u32 count; /* Number of register pairs in the section */
+} __packed;
+
+/* Indexed register sub-section header */
+struct adreno_snapshot_indexed_regs {
+ __u32 index_reg; /* Offset of the index register for this section */
+ __u32 data_reg; /* Offset of the data register for this section */
+ int start; /* Starting index */
+ int count; /* Number of dwords in the data */
+} __packed;
+
+struct adreno_snapshot_indexed_regs_v2 {
+ u32 index_reg; /* Offset of the index register for this section */
+ u32 data_reg; /* Offset of the data register for this section */
+ u32 start; /* Starting index */
+ u32 count; /* Number of dwords in the data */
+ u32 pipe_id; /* Id of pipe, BV, Br etc */
+ u32 slice_id; /* Slice ID to be dumped */
+} __packed;
+
+/* MVC register sub-section header */
+struct adreno_snapshot_mvc_regs {
+ int ctxt_id;
+ int cluster_id;
+} __packed;
+
+struct adreno_snapshot_mvc_regs_v2 {
+ int ctxt_id;
+ int cluster_id;
+ int pipe_id;
+ int location_id;
+} __packed;
+
+struct adreno_snapshot_mvc_regs_v3 {
+ u32 ctxt_id;
+ u32 cluster_id;
+ u32 pipe_id;
+ u32 location_id;
+ u32 slice_id;
+ u32 sp_id;
+ u32 usptp_id;
+} __packed;
+
+/* Debug data sub-section header */
+
+/* A5XX debug sections */
+#define SNAPSHOT_DEBUG_CP_MEQ 7
+#define SNAPSHOT_DEBUG_CP_PM4_RAM 8
+#define SNAPSHOT_DEBUG_CP_PFP_RAM 9
+#define SNAPSHOT_DEBUG_CP_ROQ 10
+#define SNAPSHOT_DEBUG_SHADER_MEMORY 11
+#define SNAPSHOT_DEBUG_CP_MERCIU 12
+#define SNAPSHOT_DEBUG_SQE_VERSION 14
+
+/* GMU Version information */
+#define SNAPSHOT_DEBUG_GMU_CORE_VERSION 15
+#define SNAPSHOT_DEBUG_GMU_CORE_DEV_VERSION 16
+#define SNAPSHOT_DEBUG_GMU_PWR_VERSION 17
+#define SNAPSHOT_DEBUG_GMU_PWR_DEV_VERSION 18
+#define SNAPSHOT_DEBUG_GMU_HFI_VERSION 19
+#define SNAPSHOT_DEBUG_AQE_VERSION 20
+
+/* Slice mask info */
+#define SNAPSHOT_DEBUG_SLICE_MASK 32
+
+struct adreno_snapshot_debug {
+ int type; /* Type identifier for the attached tata */
+ int size; /* Size of the section in dwords */
+} __packed;
+
+struct adreno_snapshot_debugbus {
+ int id; /* Debug bus ID */
+ int count; /* Number of dwords in the dump */
+} __packed;
+
+struct adreno_snapshot_side_debugbus {
+ int id; /* Debug bus ID */
+ int size; /* Number of dwords in the dump */
+ int valid_data; /* Mask of valid bits of the side debugbus */
+} __packed;
+
+struct adreno_snapshot_shader {
+ int type; /* SP/TP statetype */
+ int index; /* SP/TP index */
+ int size; /* Number of dwords in the dump */
+} __packed;
+
+struct adreno_snapshot_shader_v2 {
+ int type; /* SP/TP statetype */
+ int index; /* SP/TP index */
+ int usptp; /* USPTP index */
+ int pipe_id; /* Pipe id */
+ int location; /* Location value */
+ u32 size; /* Number of dwords in the dump */
+} __packed;
+
+struct adreno_snapshot_shader_v3 {
+ u32 type; /* SP/TP statetype */
+ u32 slice_id; /* Slice ID */
+ u32 sp_index; /* SP/TP index */
+ u32 usptp; /* USPTP index */
+ u32 pipe_id; /* Pipe id */
+ u32 location; /* Location value */
+ u32 ctxt_id; /* Context ID */
+ u32 size; /* Number of dwords in the dump */
+} __packed;
+
+#define TRACE_BUF_NUM_SIG 4
+
+/**
+ * enum trace_buffer_source - Bits to identify the source block of trace buffer information
+ * GX_DBGC : Signals captured from GX block
+ * CX_DBGC : Signals captured from CX block
+ */
+enum trace_buffer_source {
+ GX_DBGC = 1,
+ CX_DBGC = 2,
+};
+
+/**
+ * adreno_snapshot_trace_buffer: Header Information for the tracebuffer in snapshot.
+ */
+struct adreno_snapshot_trace_buffer {
+ /** @dbgc_ctrl: Identify source for trace */
+ __u16 dbgc_ctrl;
+ /** @dbgc_ctrl: Identify source for trace */
+ __u16 segment;
+ /** @granularity: The total number of segments in each packet */
+ __u16 granularity;
+ /** @ping_blk: Signal block */
+ __u16 ping_blk[TRACE_BUF_NUM_SIG];
+ /** @ping_idx: Signal Index */
+ __u16 ping_idx[TRACE_BUF_NUM_SIG];
+ /** @size: Number of bytes in the dump */
+ __u32 size;
+} __packed;
+
+#define SNAPSHOT_GPU_OBJECT_SHADER 1
+#define SNAPSHOT_GPU_OBJECT_IB 2
+#define SNAPSHOT_GPU_OBJECT_GENERIC 3
+#define SNAPSHOT_GPU_OBJECT_DRAW 4
+#define SNAPSHOT_GPU_OBJECT_GLOBAL 5
+
+struct adreno_snapshot_gpu_object_v2 {
+ int type; /* Type of GPU object */
+ __u64 gpuaddr; /* GPU address of the object */
+ __u64 ptbase; /* Base for the pagetable the GPU address is valid in */
+ __u64 size; /* Size of the object (in dwords) */
+} __packed;
+
+struct adreno_snapshot_eventlog {
+ /** @type: Type of the event log buffer */
+ __u16 type;
+ /** @version: Version of the event log buffer */
+ __u16 version;
+ /** @size: Size of the eventlog buffer in bytes */
+ u32 size;
+} __packed;
+
+struct adreno_snapshot_gmu_version {
+ /** @type: Type of the GMU version buffer */
+ u32 type;
+ /** @value: GMU FW version value */
+ u32 value;
+} __packed;
+
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/12] drm/msm/a8xx: Export aperture helpers
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
2026-10-20 20:46 ` [PATCH 01/12] drm/msm: Import adreno_snapshot.h Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 20:46 ` [PATCH 03/12] drm/msm/a8xx: Add a8xx_aperture_acquire_slice() Rob Clark
` (8 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
We'll need these from gen8 gpu state snapshot code as well.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 3 +++
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 6 +++---
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 81d21acccea1..fb000b79fe2f 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -348,6 +348,9 @@ void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
void a6xx_flush_yield(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
int a6xx_zap_shader_init(struct msm_gpu *gpu);
+void a8xx_aperture_acquire(struct msm_gpu *gpu, enum adreno_pipe pipe, unsigned long *flags);
+void a8xx_aperture_release(struct msm_gpu *gpu, unsigned long flags);
+void a8xx_aperture_clear(struct msm_gpu *gpu);
void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off);
int a8xx_fault_handler(void *arg, unsigned long iova, int flags, void *data);
void a8xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index e7d04c865968..a14379e26fbe 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -32,7 +32,7 @@ static void a8xx_aperture_slice_set(struct msm_gpu *gpu, enum adreno_pipe pipe,
a6xx_gpu->cached_aperture = val;
}
-static void a8xx_aperture_acquire(struct msm_gpu *gpu, enum adreno_pipe pipe, unsigned long *flags)
+void a8xx_aperture_acquire(struct msm_gpu *gpu, enum adreno_pipe pipe, unsigned long *flags)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
@@ -42,7 +42,7 @@ static void a8xx_aperture_acquire(struct msm_gpu *gpu, enum adreno_pipe pipe, un
a8xx_aperture_slice_set(gpu, pipe, 0);
}
-static void a8xx_aperture_release(struct msm_gpu *gpu, unsigned long flags)
+void a8xx_aperture_release(struct msm_gpu *gpu, unsigned long flags)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
@@ -50,7 +50,7 @@ static void a8xx_aperture_release(struct msm_gpu *gpu, unsigned long flags)
spin_unlock_irqrestore(&a6xx_gpu->aperture_lock, flags);
}
-static void a8xx_aperture_clear(struct msm_gpu *gpu)
+void a8xx_aperture_clear(struct msm_gpu *gpu)
{
unsigned long flags;
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/12] drm/msm/a8xx: Add a8xx_aperture_acquire_slice()
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
2026-10-20 20:46 ` [PATCH 01/12] drm/msm: Import adreno_snapshot.h Rob Clark
2026-10-20 20:46 ` [PATCH 02/12] drm/msm/a8xx: Export aperture helpers Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 20:46 ` [PATCH 04/12] drm/msm/a8xx: Allow nonctx reglist to include GMU regs Rob Clark
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
The gen8 snapshot code will need a bit more control.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 3 +++
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 19 +++++++++++++++----
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index fb000b79fe2f..d60cbfaa0d8e 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -348,6 +348,9 @@ void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
void a6xx_flush_yield(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
int a6xx_zap_shader_init(struct msm_gpu *gpu);
+void a8xx_aperture_acquire_slice(struct msm_gpu *gpu, enum adreno_pipe pipe,
+ u32 slice, bool use_slice,
+ unsigned long *flags);
void a8xx_aperture_acquire(struct msm_gpu *gpu, enum adreno_pipe pipe, unsigned long *flags);
void a8xx_aperture_release(struct msm_gpu *gpu, unsigned long flags);
void a8xx_aperture_clear(struct msm_gpu *gpu);
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index a14379e26fbe..72c84f73157a 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -16,7 +16,8 @@
#define GPU_PAS_ID 13
-static void a8xx_aperture_slice_set(struct msm_gpu *gpu, enum adreno_pipe pipe, u32 slice)
+static void a8xx_aperture_slice_set(struct msm_gpu *gpu, enum adreno_pipe pipe,
+ u32 slice, bool use_slice)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
@@ -24,6 +25,9 @@ static void a8xx_aperture_slice_set(struct msm_gpu *gpu, enum adreno_pipe pipe,
val = A8XX_CP_APERTURE_CNTL_HOST_PIPEID(pipe) | A8XX_CP_APERTURE_CNTL_HOST_SLICEID(slice);
+ if (use_slice)
+ val |= A8XX_CP_APERTURE_CNTL_HOST_USESLICEID;
+
if (a6xx_gpu->cached_aperture == val)
return;
@@ -32,14 +36,21 @@ static void a8xx_aperture_slice_set(struct msm_gpu *gpu, enum adreno_pipe pipe,
a6xx_gpu->cached_aperture = val;
}
-void a8xx_aperture_acquire(struct msm_gpu *gpu, enum adreno_pipe pipe, unsigned long *flags)
+void a8xx_aperture_acquire_slice(struct msm_gpu *gpu, enum adreno_pipe pipe,
+ u32 slice, bool use_slice,
+ unsigned long *flags)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
spin_lock_irqsave(&a6xx_gpu->aperture_lock, *flags);
- a8xx_aperture_slice_set(gpu, pipe, 0);
+ a8xx_aperture_slice_set(gpu, pipe, slice, use_slice);
+}
+
+void a8xx_aperture_acquire(struct msm_gpu *gpu, enum adreno_pipe pipe, unsigned long *flags)
+{
+ a8xx_aperture_acquire_slice(gpu, pipe, 0, false, flags);
}
void a8xx_aperture_release(struct msm_gpu *gpu, unsigned long flags)
@@ -75,7 +86,7 @@ static u32 a8xx_read_pipe_slice(struct msm_gpu *gpu, enum adreno_pipe pipe, u32
u32 val;
spin_lock_irqsave(&a6xx_gpu->aperture_lock, flags);
- a8xx_aperture_slice_set(gpu, pipe, slice);
+ a8xx_aperture_slice_set(gpu, pipe, slice, false);
val = gpu_read(gpu, offset);
spin_unlock_irqrestore(&a6xx_gpu->aperture_lock, flags);
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/12] drm/msm/a8xx: Allow nonctx reglist to include GMU regs
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (2 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 03/12] drm/msm/a8xx: Add a8xx_aperture_acquire_slice() Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 20:46 ` [PATCH 05/12] drm/msm/a8xx: Stop getting GMEM_PROTECT from nonctx list Rob Clark
` (6 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
From hw PoV, it's all part of the GPU. But from dt perspective it is
it's own device with a separate io space. So we need to detect this and
direct writes to the correct place.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index 72c84f73157a..3e22ef788f2d 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -376,6 +376,7 @@ static void a8xx_set_ubwc_config(struct msm_gpu *gpu)
static void a8xx_nonctxt_config(struct msm_gpu *gpu, u32 *gmem_protect)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gmu *gmu = &to_a6xx_gpu(adreno_gpu)->gmu;
const struct a6xx_info *info = adreno_gpu->info->a6xx;
const struct adreno_reglist_pipe *regs = info->nonctxt_reglist;
unsigned int pipe_id, i;
@@ -395,7 +396,11 @@ static void a8xx_nonctxt_config(struct msm_gpu *gpu, u32 *gmem_protect)
if (regs[i].offset == REG_A8XX_RB_GC_GMEM_PROTECT)
*gmem_protect = regs[i].value;
- gpu_write(gpu, regs[i].offset, regs[i].value);
+ if ((regs[i].offset << 2) >= gmu->mmio_offset) {
+ gmu_write(gmu, regs[i].offset, regs[i].value);
+ } else {
+ gpu_write(gpu, regs[i].offset, regs[i].value);
+ }
}
a8xx_aperture_release(gpu, flags);
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/12] drm/msm/a8xx: Stop getting GMEM_PROTECT from nonctx list
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (3 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 04/12] drm/msm/a8xx: Allow nonctx reglist to include GMU regs Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 20:46 ` [PATCH 06/12] drm/msm/adreno: Fix PROTECT span length Rob Clark
` (5 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
We can just simplify things and calculate the value, instead of manually
adding it to the nonctx list.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index 3e22ef788f2d..6d7982a117f7 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -373,7 +373,7 @@ static void a8xx_set_ubwc_config(struct msm_gpu *gpu)
hbb_lo << 1 | ubwc_mode);
}
-static void a8xx_nonctxt_config(struct msm_gpu *gpu, u32 *gmem_protect)
+static void a8xx_nonctxt_config(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gmu *gmu = &to_a6xx_gpu(adreno_gpu)->gmu;
@@ -393,9 +393,6 @@ static void a8xx_nonctxt_config(struct msm_gpu *gpu, u32 *gmem_protect)
if (!(BIT(pipe_id) & regs[i].pipe))
continue;
- if (regs[i].offset == REG_A8XX_RB_GC_GMEM_PROTECT)
- *gmem_protect = regs[i].value;
-
if ((regs[i].offset << 2) >= gmu->mmio_offset) {
gmu_write(gmu, regs[i].offset, regs[i].value);
} else {
@@ -641,7 +638,6 @@ static int hw_init(struct msm_gpu *gpu)
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
unsigned int pipe_id, i;
- u32 gmem_protect = 0;
u64 gmem_range_min;
int ret;
@@ -722,7 +718,7 @@ static int hw_init(struct msm_gpu *gpu)
gpu_write(gpu, REG_A8XX_UCHE_CLIENT_PF, BIT(7) | 0x1);
- a8xx_nonctxt_config(gpu, &gmem_protect);
+ a8xx_nonctxt_config(gpu);
/* Enable fault detection */
gpu_write(gpu, REG_A8XX_RBBM_INTERFACE_HANG_INT_CNTL, BIT(30) | 0xcfffff);
@@ -841,8 +837,8 @@ static int hw_init(struct msm_gpu *gpu)
* GMEM_PROTECT register should be programmed after GPU is transitioned to
* non-secure mode
*/
- a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_RB_GC_GMEM_PROTECT, gmem_protect);
- WARN_ON(!gmem_protect);
+ a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_RB_GC_GMEM_PROTECT,
+ (adreno_gpu->info->gmem / SZ_4K) << 16);
a8xx_aperture_clear(gpu);
if (!a6xx_gpu->pwrup_reglist_emitted) {
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/12] drm/msm/adreno: Fix PROTECT span length
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (4 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 05/12] drm/msm/a8xx: Stop getting GMEM_PROTECT from nonctx list Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 20:46 ` [PATCH 07/12] drm/msm/adreno: add temporary __maybe_unused Rob Clark
` (4 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
Don't let the length bleed into b31.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index d60cbfaa0d8e..5e1f35c83d63 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -244,7 +244,7 @@ struct a7xx_cp_smmu_info {
*/
#define A6XX_PROTECT_NORDWR(_reg, _len) \
((1 << 31) | \
- (((_len) & 0x3FFF) << 18) | ((_reg) & 0x3FFFF))
+ (((_len) & 0x1FFF) << 18) | ((_reg) & 0x3FFFF))
/*
* Same as above, but allow reads over the range. For areas of mixed use (such
@@ -252,7 +252,7 @@ struct a7xx_cp_smmu_info {
* single register
*/
#define A6XX_PROTECT_RDONLY(_reg, _len) \
- ((((_len) & 0x3FFF) << 18) | ((_reg) & 0x3FFFF))
+ ((((_len) & 0x1FFF) << 18) | ((_reg) & 0x3FFFF))
extern const struct adreno_gpu_funcs a6xx_gpu_funcs;
extern const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs;
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/12] drm/msm/adreno: add temporary __maybe_unused
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (5 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 06/12] drm/msm/adreno: Fix PROTECT span length Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 20:46 ` [PATCH 09/12] drm/msm/a8xx: devcoredump state capture support Rob Clark
` (3 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
To keep this series bisectable. This will be removed once there maybe-
unused protect tables are gone.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 6d6e4c7cf919..c43efb85fde7 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -168,7 +168,7 @@ struct adreno_protect {
};
#define DECLARE_ADRENO_PROTECT(name, __count_max) \
-static const struct adreno_protect name = { \
+static const struct adreno_protect name __maybe_unused = { \
.regs = name ## _regs, \
.count = ARRAY_SIZE(name ## _regs), \
.count_max = __count_max, \
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/12] drm/msm/a8xx: devcoredump state capture support
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (6 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 07/12] drm/msm/adreno: add temporary __maybe_unused Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 23:13 ` sashiko-bot
2026-10-20 20:46 ` [PATCH 10/12] drm/msm/a8xx: Switch to generated nonctx regs Rob Clark
` (2 subsequent siblings)
10 siblings, 1 reply; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Sean Paul,
Marijn Suijten, David Airlie, Simona Vetter, Konrad Dybcio,
open list
This attempts to make it easier to compare to kgsl, the downstream
driver, to make it easier to spot bugs or missing things. Such as
re-using function names, etc.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
Co-developed-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/Makefile | 4 +-
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 7 +
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 5 +
drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c | 1253 ++++++++++++++++++
drivers/gpu/drm/msm/adreno/adreno_snapshot.h | 205 +++
5 files changed, 1473 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 1e246616f83f..b5d64ee7eb74 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -31,7 +31,9 @@ adreno-y := \
adreno-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \
-adreno-$(CONFIG_DRM_MSM_GPU_STATE) += adreno/a6xx_gpu_state.o
+adreno-$(CONFIG_DRM_MSM_GPU_STATE) += \
+ adreno/a6xx_gpu_state.o \
+ adreno/a8xx_gpu_state.o \
msm-display-$(CONFIG_DRM_MSM_HDMI) += \
hdmi/hdmi.o \
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 09d76cdf059f..74064eba98c7 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2946,9 +2946,16 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
.active_ring = a6xx_active_ring,
.irq = a8xx_irq,
.destroy = a6xx_destroy,
+#if defined(CONFIG_DRM_MSM_GPU_STATE)
+ .show = a8xx_show,
+#endif
.gpu_busy = a8xx_gpu_busy,
.gpu_get_freq = a6xx_gmu_get_freq,
.gpu_set_freq = a6xx_gpu_set_freq,
+#if defined(CONFIG_DRM_MSM_GPU_STATE)
+ .gpu_state_get = a8xx_gpu_state_get,
+ .gpu_state_put = a8xx_gpu_state_put,
+#endif
.create_vm = a6xx_create_vm,
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 5e1f35c83d63..07198e8bbff2 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -370,4 +370,9 @@ void a8xx_preempt_irq(struct msm_gpu *gpu);
bool a8xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
void a8xx_perfcntr_flush(struct msm_gpu *gpu);
void a8xx_recover(struct msm_gpu *gpu);
+void a8xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
+ struct drm_printer *p);
+struct msm_gpu_state *a8xx_gpu_state_get(struct msm_gpu *gpu);
+int a8xx_gpu_state_put(struct msm_gpu_state *state);
+
#endif /* __A6XX_GPU_H__ */
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c
new file mode 100644
index 000000000000..e4eb2f335a89
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c
@@ -0,0 +1,1253 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include "msm_gem.h"
+#include "a6xx_gpu.h"
+#include "a6xx_gmu.h"
+#include "adreno_snapshot.h"
+#include "adreno_gen8_snapshot.h"
+
+#define NUM_SLICES(gpu) (hweight32((gpu)->slice_mask))
+
+static inline int next_slice(int slice, u32 slice_mask)
+{
+ for (; slice < fls(slice_mask); slice++)
+ if (BIT(slice) & slice_mask)
+ return slice;
+
+ return slice;
+}
+
+#define NEXT_SLICE(_slice, _region, _slice_mask) \
+ ((_region == UNSLICE) ? fls(_slice_mask) : next_slice(_slice, _slice_mask))
+
+#define FIRST_SLICE(_region, _slice_mask) \
+ ((_region == UNSLICE) ? 0 : NEXT_SLICE(0, _region, _slice_mask))
+
+#define FOR_EACH_SLICE(_slice, _region, _slice_mask) \
+ for (_slice = FIRST_SLICE(_region, _slice_mask); \
+ _slice < fls(_slice_mask); \
+ _slice = NEXT_SLICE(++(_slice), _region, _slice_mask))
+
+/* Use SLICE_ID to access the region (0 for unsliced) */
+#define SLICE_ID(region, j) ((region == SLICE) ? j : 0)
+
+/*
+ * Use HEADER_SLICE_ID to specify the slice in the section header (UINT_MAX for unsliced).
+ * This allows snapshot parsers to differentiate between slice ID 0 and unsliced regions.
+ */
+#define HEADER_SLICE_ID(region, j) ((region == SLICE) ? j : UINT_MAX)
+
+#define GEN8_CP_APERTURE_REG_VAL(_sliceid, _pipe, _cluster, _context) ( \
+ A8XX_CP_APERTURE_CNTL_HOST_USESLICEID | \
+ A8XX_CP_APERTURE_CNTL_HOST_SLICEID(_sliceid) | \
+ A8XX_CP_APERTURE_CNTL_HOST_PIPEID(_pipe) | \
+ A8XX_CP_APERTURE_CNTL_HOST_CLUSTERID(_cluster) | \
+ A8XX_CP_APERTURE_CNTL_HOST_CONTEXTID3D(_context) | \
+ 0)
+
+#define GEN8_SP_READ_SEL_VAL(_contextid, _sliceid, _location, _pipe, _statetype, _usptp, _sptp) ( \
+ A7XX_SP_READ_SEL_CONTEXT(_contextid) | \
+ A7XX_SP_READ_SEL_SLICE(_sliceid) | \
+ A7XX_SP_READ_SEL_LOCATION(_location) | \
+ A7XX_SP_READ_SEL_PIPE(_pipe) | \
+ A7XX_SP_READ_SEL_STATETYPE(_statetype) | \
+ A7XX_SP_READ_SEL_USPTP(_usptp) | \
+ A7XX_SP_READ_SEL_SPTP(_sptp) | \
+ 0)
+
+/*
+ * Allocate 4MB for the crashdumper scratch region - 2MB for the script and
+ * the rest for the data.
+ *
+ * Note gen8_snapshot_indexed_registers() is worst case, needing separate
+ * CD_WRITE + CD_READ per reg, 0xa000 times (so script is ~1.2MB)
+ *
+ * TODO we could perhaps be clever and fill in the out addrs in a 2nd pass
+ * to accomodate invocations that need larger script and smaller data, like
+ * indexed regs.
+ */
+#define A8XX_CD_SIZE SZ_4M
+#define A8XX_CD_DATA_OFFSET (2 * SZ_1M)
+#define A8XX_CD_DATA_SIZE (A8XX_CD_SIZE - A8XX_CD_DATA_OFFSET)
+
+static int a8xx_crashdumper_init(struct msm_gpu *gpu,
+ struct adreno_crashdumper *dumper)
+{
+ dumper->ptr = msm_gem_kernel_new(gpu->dev,
+ A8XX_CD_SIZE, MSM_BO_WC, gpu->vm,
+ &dumper->bo, &dumper->iova);
+
+ if (!IS_ERR(dumper->ptr)) {
+ msm_gem_object_set_name(dumper->bo, "crashdump");
+ dumper->data_offset = A8XX_CD_DATA_OFFSET;
+ }
+
+ return PTR_ERR_OR_ZERO(dumper->ptr);
+}
+
+static inline int __cd_run(struct msm_gpu *gpu, struct adreno_crashdumper *dumper)
+{
+ u32 val;
+ int ret;
+
+ if (IS_ERR_OR_NULL(dumper->ptr))
+ return -EINVAL;
+
+ /* Make sure all pending memory writes are posted */
+ wmb();
+
+ gpu_write64(gpu, REG_A8XX_CP_CRASH_DUMP_SCRIPT_BASE, dumper->iova);
+
+ gpu_write(gpu, REG_A8XX_CP_CRASH_DUMP_CNTL, 1);
+
+ /* NOTE: kgsl uses 500ms timeout */
+ ret = gpu_poll_timeout(gpu, REG_A8XX_CP_CRASH_DUMP_STATUS, val,
+ val & 0x02, 100, 100000);
+
+ gpu_write(gpu, REG_A8XX_CP_CRASH_DUMP_CNTL, 0);
+
+ drm_WARN_ONCE(gpu->dev, ret, "crashdumper timed out: status=%08x (%d)\n", val, ret);
+
+ return ret;
+}
+
+static inline bool __cd_check_overflow(struct cd_script *p)
+{
+ if (WARN_ON_ONCE(p->in > (u64 *)(p->dumper->ptr + A8XX_CD_DATA_OFFSET)))
+ return false;
+ if (WARN_ON_ONCE(p->out > p->dumper->iova + A8XX_CD_SIZE))
+ return false;
+ return true;
+}
+
+static const struct gen8_snapshot_block_list *
+block_list(struct msm_gpu *gpu)
+{
+ return to_adreno_gpu(gpu)->info->snapshot_block_list;
+}
+
+/* The GMU is ioremapped separately, matching how it is described in dt.
+ * However the snapshot tables generated from hw spec do not take into
+ * account dt, and consider it as yet another sub-block of the GPU. This
+ * helper helps to bridge the worlds.
+ */
+static uint32_t reg_read(struct msm_gpu *gpu, uint32_t reg)
+{
+ struct a6xx_gmu *gmu = &to_a6xx_gpu(to_adreno_gpu(gpu))->gmu;
+ if ((reg << 2) >= gmu->mmio_offset)
+ return gmu_read(gmu, reg);
+ return gpu_read(gpu, reg);
+}
+
+static void adreno_snapshot_registers_v2(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state,
+ const u32 *ptr)
+{
+ int k, count;
+
+ /* Figure out how many registers we are going to dump */
+ count = adreno_snapshot_regs_count(ptr);
+
+ snapshot_sect (state, REGS_V2, 4 * count, {}) {
+ for (; ptr[0] != UINT_MAX; ptr += 2) {
+ u32 cnt = REG_COUNT(ptr);
+
+ if (cnt == 1) {
+ snapshot_sect_u32(§, BIT(31) | ptr[0]);
+ } else {
+ snapshot_sect_u32(§, ptr[0]);
+ snapshot_sect_u32(§, cnt);
+ }
+
+ for (k = ptr[0]; k <= ptr[1]; k++) {
+ snapshot_sect_u32(§, reg_read(gpu, k));
+ }
+ }
+ }
+}
+
+static void snapshot_mvc_regs_v3_subheader(struct adreno_snapshot_sect *sect, const u32 *ptr)
+{
+ /*
+ * Note this might look like adreno_snapshot_registers_v2(),
+ * but looks are deceiving. The meaning of b31 is inverted
+ * and the 2nd dword is end-offset instead of count.
+ */
+ if (REG_COUNT(ptr) == 1) {
+ snapshot_sect_u32(sect, ptr[0]);
+ } else {
+ snapshot_sect_u32(sect, BIT(31) | ptr[0]);
+ snapshot_sect_u32(sect, ptr[1]);
+ }
+}
+
+static void gen8_legacy_snapshot_registers(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state,
+ const struct gen8_reg_list *regs,
+ u32 slice_id)
+{
+ int count;
+
+ /* Figure out how many registers we are going to dump */
+ count = adreno_snapshot_regs_count(regs->regs);
+
+ snapshot_sect (state, MVC_V3, 4 * count, {
+ .ctxt_id = 0,
+ .cluster_id = CLUSTER_NONE,
+ .pipe_id = PIPE_NONE,
+ .location_id = UINT_MAX,
+ .sp_id = UINT_MAX,
+ .usptp_id = UINT_MAX,
+ .slice_id = HEADER_SLICE_ID(regs->slice_region, slice_id),
+ }) {
+ unsigned long flags;
+
+ if (regs->sel)
+ gpu_write(gpu, regs->sel->host_reg, regs->sel->val);
+
+ if (regs->slice_region)
+ a8xx_aperture_acquire_slice(gpu, PIPE_NONE, slice_id, false, &flags);
+
+ /* Make sure the previous writes are posted before reading */
+ mb();
+
+ for (const u32 *ptr = regs->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ snapshot_mvc_regs_v3_subheader(§, ptr);
+
+ for (int k = ptr[0]; k <= ptr[1]; k++) {
+ snapshot_sect_u32(§, reg_read(gpu, k));
+ }
+ }
+
+ if (regs->slice_region)
+ a8xx_aperture_release(gpu, flags);
+ }
+}
+
+static bool gen8_reglist_snapshot(struct msm_gpu *gpu, struct adreno_gpu_state *state,
+ struct adreno_crashdumper *dumper)
+{
+ const struct gen8_snapshot_block_list *b = block_list(gpu);
+ u32 slice_mask = to_a6xx_gpu(to_adreno_gpu(gpu))->slice_mask;
+
+ if (!dumper) {
+ for (u32 i = 0; i < b->num_reg_list; i++) {
+ const struct gen8_reg_list *regs = &b->reg_list[i];
+ u32 j;
+
+ FOR_EACH_SLICE (j, regs->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(regs->slice_region, j);
+ gen8_legacy_snapshot_registers(gpu, state, regs, slice_id);
+ }
+
+ /*
+ * The downstream reglist contains registers in other memory regions
+ * (cx_misc/cx_mem and cx_dbgc) and we need to plumb through their
+ * offsets and map them to read them on the CPU. For now only read the
+ * first two regions.
+ */
+ if (i == 1)
+ break;
+ }
+ return true;
+ }
+
+ for (u32 i = 0; i < b->num_reg_list; i++) {
+ const struct gen8_reg_list *regs = &b->reg_list[i];
+ u32 j;
+
+ FOR_EACH_SLICE (j, regs->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(regs->slice_region, j);
+ struct cd_script p = CD_INIT(dumper);
+
+ CD_WRITE(&p, REG_A8XX_CP_APERTURE_CNTL_CD,
+ GEN8_CP_APERTURE_REG_VAL(j, 0, 0, 0));
+
+ /* Program the SEL_CNTL_CD register appropriately */
+ if (regs->sel)
+ CD_WRITE(&p, regs->sel->cd_reg, regs->sel->val);
+
+ for (const u32 *ptr = regs->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ u32 count = REG_COUNT(ptr);
+
+ CD_READ(&p, ptr[0], count);
+ }
+
+ /* Marker for end of script */
+ CD_FINISH(&p);
+
+ /* Try to run the crash dumper and bail if it times out */
+ if (CD_RUN(&p, gpu))
+ return false;
+
+ u32 count = adreno_snapshot_regs_count(regs->regs);
+ snapshot_sect (state, MVC_V3, 4 * count, {
+ .ctxt_id = 0,
+ .cluster_id = CLUSTER_NONE,
+ .pipe_id = PIPE_NONE,
+ .location_id = UINT_MAX,
+ .sp_id = UINT_MAX,
+ .usptp_id = UINT_MAX,
+ .slice_id = HEADER_SLICE_ID(regs->slice_region, slice_id),
+ }) {
+ const u32 *src = dumper->ptr + A8XX_CD_DATA_OFFSET;
+
+ for (const u32 *ptr = regs->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ u32 count = REG_COUNT(ptr);
+
+ snapshot_mvc_regs_v3_subheader(§, ptr);
+ snapshot_sect_data(§, src, count * sizeof(u32));
+
+ src += count;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool gen8_snapshot_indexed_registers(
+ struct msm_gpu *gpu, struct adreno_gpu_state *state, struct adreno_crashdumper *dumper,
+ u32 index, u32 data, u32 start, u32 count, u32 pipe_id, u32 slice_id)
+{
+ struct adreno_snapshot_indexed_regs_v2 hdr = {
+ .index_reg = index,
+ .data_reg = data,
+ .count = count,
+ .start = start,
+ .pipe_id = pipe_id,
+ .slice_id = slice_id,
+ };
+ u32 s = (slice_id == UINT_MAX) ? 0 : slice_id;
+
+ if (!dumper) {
+ snapshot_sect (state, INDEXED_REGS_V2, count * sizeof(u32), hdr) {
+ unsigned long flags;
+
+ a8xx_aperture_acquire_slice(gpu, pipe_id, s, true, &flags);
+
+ for (int i = 0; i < count; i++) {
+ /* Write the address register */
+ gpu_write(gpu, index, start + i);
+
+ /* Make sure the write finishes */
+ wmb();
+
+ snapshot_sect_u32(§, reg_read(gpu, data));
+
+ /* Make sure the read finishes */
+ rmb();
+ }
+
+ a8xx_aperture_release(gpu, flags);
+ }
+
+ return true;
+ }
+
+ struct cd_script p = CD_INIT(dumper);
+
+ CD_WRITE(&p, REG_A8XX_CP_APERTURE_CNTL_CD,
+ GEN8_CP_APERTURE_REG_VAL(s, pipe_id, 0, 0));
+
+ for (int i = 0; i < count; i++) {
+ /* Write the address register */
+ CD_WRITE(&p, index, start + i);
+ CD_READ(&p, data, 1);
+ }
+
+ /* Marker for end of script */
+ CD_FINISH(&p);
+
+ /* Try to run the crash dumper and bail if it times out */
+ if (CD_RUN(&p, gpu))
+ return false;
+
+ snapshot_sect (state, INDEXED_REGS_V2, count * sizeof(u32), hdr) {
+ const u32 *src = dumper->ptr + A8XX_CD_DATA_OFFSET;
+ snapshot_sect_data(§, src, count * sizeof(u32));
+ }
+
+ return true;
+}
+
+static bool gen8_snapshot_cp_indexed_regs(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state,
+ struct adreno_crashdumper *dumper)
+{
+ const struct gen8_snapshot_block_list *b = block_list(gpu);
+
+ for (int i = 0; i < b->index_registers_len; i++) {
+ bool ret = gen8_snapshot_indexed_registers(gpu, state, dumper,
+ b->index_registers[i].addr,
+ b->index_registers[i].data, 0,
+ b->index_registers[i].size,
+ b->index_registers[i].pipe_id, UINT_MAX);
+ if (!ret)
+ return false;
+ }
+
+ return true;
+}
+
+static bool gen8_snapshot_mempool(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state,
+ struct adreno_crashdumper *dumper)
+{
+ const struct gen8_snapshot_block_list *b = block_list(gpu);
+ u32 slice_mask = to_a6xx_gpu(to_adreno_gpu(gpu))->slice_mask;
+ u32 first_slice = ffs(slice_mask);
+
+ for (int i = 0; i < b->mempool_index_registers_len; i++) {
+ const struct gen8_cp_indexed_reg *cp_indexed_reg =
+ &b->mempool_index_registers[i];
+ unsigned long flags;
+ u32 j;
+
+ FOR_EACH_SLICE (j, cp_indexed_reg->slice_region, slice_mask) {
+
+ /* TODO: Remove hardcoded values */
+ /* Set CP_CHICKEN_DBG[StabilizeMVC] to stabilize it while dumping */
+ a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, first_slice, false, &flags);
+ gpu_rmw(gpu, REG_A8XX_CP_CHICKEN_DBG_PIPE, BIT(2), BIT(2));
+ a8xx_aperture_release(gpu, flags);
+
+ a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, j, true, &flags);
+ gpu_rmw(gpu, REG_A8XX_CP_SLICE_CHICKEN_DBG_PIPE, BIT(2), BIT(2));
+ a8xx_aperture_release(gpu, flags);
+
+ gen8_snapshot_indexed_registers(gpu, state, dumper,
+ cp_indexed_reg->addr,
+ cp_indexed_reg->data, 0,
+ cp_indexed_reg->size,
+ cp_indexed_reg->pipe_id,
+ HEADER_SLICE_ID(cp_indexed_reg->slice_region, j));
+
+ /* Reset CP_CHICKEN_DBG[StabilizeMVC] once we are done */
+ a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, first_slice, false, &flags);
+ gpu_rmw(gpu, REG_A8XX_CP_CHICKEN_DBG_PIPE, BIT(2), 0);
+ a8xx_aperture_release(gpu, flags);
+
+ a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, j, true, &flags);
+ gpu_rmw(gpu, REG_A8XX_CP_SLICE_CHICKEN_DBG_PIPE, BIT(2), 0);
+ a8xx_aperture_release(gpu, flags);
+ }
+ }
+
+ /* Clear aperture register */
+ a8xx_aperture_clear(gpu);
+
+ return true;
+}
+
+static void gen8_legacy_snapshot_mvc(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state,
+ const struct gen8_cluster_registers *cluster,
+ u32 slice_id)
+{
+ int count;
+
+ /* Figure out how many registers we are going to dump */
+ count = adreno_snapshot_regs_count(cluster->regs);
+
+ snapshot_sect (state, MVC_V3, 4 * count, {
+ .ctxt_id = (cluster->context_id == STATE_FORCE_CTXT_1) ? 1 : 0,
+ .cluster_id = cluster->cluster_id,
+ .pipe_id = cluster->pipe_id,
+ .location_id = UINT_MAX,
+ .sp_id = UINT_MAX,
+ .usptp_id = UINT_MAX,
+ .slice_id = HEADER_SLICE_ID(cluster->slice_region, slice_id),
+ }) {
+ unsigned long flags;
+
+ /*
+ * Set the AHB control for the Host to read from the
+ * cluster/context for this iteration.
+ */
+ a8xx_aperture_acquire_slice(gpu, cluster->pipe_id, slice_id, true, &flags);
+
+ if (cluster->sel)
+ gpu_write(gpu, cluster->sel->host_reg, cluster->sel->val);
+
+ /* Make sure the previous writes are posted before reading */
+ mb();
+
+ for (const u32 *ptr = cluster->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ snapshot_mvc_regs_v3_subheader(§, ptr);
+
+ for (int k = ptr[0]; k <= ptr[1]; k++) {
+ snapshot_sect_u32(§, reg_read(gpu, k));
+ }
+ }
+
+ a8xx_aperture_release(gpu, flags);
+ }
+}
+
+static bool gen8_snapshot_mvc_regs(
+ struct msm_gpu *gpu, struct adreno_gpu_state *state, struct adreno_crashdumper *dumper,
+ const struct gen8_cluster_registers *clusters, size_t num_cluster)
+{
+ u32 slice_mask = to_a6xx_gpu(to_adreno_gpu(gpu))->slice_mask;
+
+ if (!dumper) {
+ for (int i = 0; i < num_cluster; i++) {
+ const struct gen8_cluster_registers *cluster = &clusters[i];
+ u32 j;
+
+ FOR_EACH_SLICE (j, cluster->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(cluster->slice_region, j);
+ gen8_legacy_snapshot_mvc(gpu, state, cluster, slice_id);
+ }
+ }
+ return true;
+ }
+
+ for (int i = 0; i < num_cluster; i++) {
+ const struct gen8_cluster_registers *cluster = &clusters[i];
+ u32 j;
+
+ FOR_EACH_SLICE (j, cluster->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(cluster->slice_region, j);
+ struct cd_script p = CD_INIT(dumper);
+
+ CD_WRITE(&p, REG_A8XX_CP_APERTURE_CNTL_CD,
+ GEN8_CP_APERTURE_REG_VAL(j, cluster->pipe_id,
+ cluster->cluster_id,
+ cluster->context_id));
+
+ if (cluster->sel)
+ CD_WRITE(&p, cluster->sel->cd_reg, cluster->sel->val);
+
+ for (const u32 *ptr = cluster->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ CD_READ(&p, ptr[0], REG_COUNT(ptr));
+ }
+
+ /* Marker for end of script */
+ CD_FINISH(&p);
+
+ /* Try to run the crash dumper and bail if it times out */
+ if (CD_RUN(&p, gpu))
+ return false;
+
+ u32 count = adreno_snapshot_regs_count(cluster->regs);
+
+ snapshot_sect (state, MVC_V3, 4 * count, {
+ .ctxt_id = (cluster->context_id == STATE_FORCE_CTXT_1) ? 1 : 0,
+ .cluster_id = cluster->cluster_id,
+ .pipe_id = cluster->pipe_id,
+ .location_id = UINT_MAX,
+ .sp_id = UINT_MAX,
+ .usptp_id = UINT_MAX,
+ .slice_id = HEADER_SLICE_ID(cluster->slice_region, slice_id),
+ }) {
+ const u32 *src = dumper->ptr + A8XX_CD_DATA_OFFSET;
+
+ for (const u32 *ptr = cluster->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ u32 count = REG_COUNT(ptr);
+
+ snapshot_mvc_regs_v3_subheader(§, ptr);
+ snapshot_sect_data(§, src, count * sizeof(u32));
+
+ src += count;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+static u32 gen8_read_dbgahb(struct msm_gpu *gpu, u32 regbase, u32 reg)
+{
+ return gpu_read(gpu, REG_A7XX_SP_AHB_READ_APERTURE + reg - regbase);
+}
+
+static void gen8_legacy_snapshot_cluster_dbgahb(
+ struct msm_gpu *gpu, struct adreno_gpu_state *state,
+ const struct gen8_sptp_cluster_registers *cluster,
+ u32 sp, u32 usptp, u32 slice_id)
+{
+ int count;
+
+ /* Figure out how many registers we are going to dump */
+ count = adreno_snapshot_regs_count(cluster->regs);
+
+ snapshot_sect (state, MVC_V3, 4 * count, {
+ .ctxt_id = cluster->context_id,
+ .cluster_id = cluster->cluster_id,
+ .pipe_id = cluster->pipe_id,
+ .location_id = cluster->location_id,
+ .sp_id = sp,
+ .usptp_id = usptp,
+ .slice_id = HEADER_SLICE_ID(cluster->slice_region, slice_id),
+ }) {
+ u32 read_sel = GEN8_SP_READ_SEL_VAL(
+ 0, slice_id, cluster->location_id, cluster->pipe_id,
+ cluster->statetype, usptp, sp);
+
+ gpu_write(gpu, REG_A7XX_SP_READ_SEL, read_sel);
+
+ /*
+ * An explicit barrier is needed so that reads do not happen before
+ * the register write.
+ */
+ mb();
+
+ for (const u32 *ptr = cluster->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ snapshot_mvc_regs_v3_subheader(§, ptr);
+
+ for (int k = ptr[0]; k <= ptr[1]; k++) {
+ u32 val = gen8_read_dbgahb(gpu, cluster->regbase, k);
+ snapshot_sect_u32(§, val);
+ }
+ }
+ }
+}
+
+static bool gen8_snapshot_dbgahb_regs(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state,
+ struct adreno_crashdumper *dumper)
+{
+ const struct gen8_snapshot_block_list *b = block_list(gpu);
+ u32 slice_mask = to_a6xx_gpu(to_adreno_gpu(gpu))->slice_mask;
+
+ if (!dumper) {
+ for (int i = 0; i < b->num_sptp_clusters; i++) {
+ const struct gen8_sptp_cluster_registers *cluster =
+ &b->sptp_clusters[i];
+
+ for (u32 sp = 0; sp < cluster->num_sps; sp++) {
+ for (u32 usptp = 0; usptp < cluster->num_usptps; usptp++) {
+ u32 j;
+
+ FOR_EACH_SLICE (j, cluster->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(cluster->slice_region, j);
+
+ gen8_legacy_snapshot_cluster_dbgahb(
+ gpu, state, cluster,
+ sp, usptp, slice_id);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ for (int i = 0; i < b->num_sptp_clusters; i++) {
+ const struct gen8_sptp_cluster_registers *cluster =
+ &b->sptp_clusters[i];
+
+ for (u32 sp = 0; sp < cluster->num_sps; sp++) {
+ for (u32 usptp = 0; usptp < cluster->num_usptps; usptp++) {
+ u32 j;
+
+ FOR_EACH_SLICE (j, cluster->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(cluster->slice_region, j);
+
+ /* Build the crash script */
+ struct cd_script p = CD_INIT(dumper);
+
+ u32 read_sel = GEN8_SP_READ_SEL_VAL(
+ 0, slice_id, cluster->location_id,
+ cluster->pipe_id, cluster->statetype,
+ usptp, sp);
+
+ /* Program the aperture */
+ CD_WRITE(&p, REG_A7XX_SP_READ_SEL, read_sel);
+
+ for (const u32 *ptr = cluster->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ u32 count = REG_COUNT(ptr);
+ u32 reg = REG_A7XX_SP_AHB_READ_APERTURE + ptr[0] - cluster->regbase;
+
+ CD_READ(&p, reg, count);
+ }
+
+ /* Marker for end of script */
+ CD_FINISH(&p);
+
+ /* Try to run the crash dumper and bail if it times out */
+ if (CD_RUN(&p, gpu))
+ return false;
+
+ u32 count = adreno_snapshot_regs_count(cluster->regs);
+ snapshot_sect (state, MVC_V3, 4 * count, {
+ .ctxt_id = cluster->context_id,
+ .cluster_id = cluster->cluster_id,
+ .pipe_id = cluster->pipe_id,
+ .location_id = cluster->location_id,
+ .sp_id = sp,
+ .usptp_id = usptp,
+ .slice_id = HEADER_SLICE_ID(cluster->slice_region, slice_id),
+ }) {
+ const u32 *src = dumper->ptr + A8XX_CD_DATA_OFFSET;
+
+ for (const u32 *ptr = cluster->regs; ptr[0] != UINT_MAX; ptr += 2) {
+ u32 count = REG_COUNT(ptr);
+
+ snapshot_mvc_regs_v3_subheader(§, ptr);
+ snapshot_sect_data(§, src, count * sizeof(u32));
+
+ src += count;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static void gen8_legacy_snapshot_shader(struct msm_gpu *gpu, struct adreno_gpu_state *state,
+ const struct gen8_shader_block *block,
+ u32 sp, u32 ctxt, u32 slice_id)
+{
+ snapshot_sect (state, SHADER_V3, block->size * sizeof(u32), {
+ .type = block->statetype,
+ .slice_id = HEADER_SLICE_ID(block->slice_region, slice_id),
+ .sp_index = sp,
+ .usptp = block->usptp_id,
+ .pipe_id = block->pipeid,
+ .location = block->location,
+ .ctxt_id = ctxt,
+ .size = block->size,
+ }) {
+ u32 read_sel = GEN8_SP_READ_SEL_VAL(
+ ctxt, slice_id, block->location, block->pipeid,
+ block->statetype, block->usptp_id, sp);
+
+ gpu_write(gpu, REG_A7XX_SP_READ_SEL, read_sel);
+
+ /*
+ * An explicit barrier is needed so that reads do not happen before
+ * the register write.
+ */
+ mb();
+
+ for (int i = 0; i < block->size; i++) {
+ u32 val = gpu_read(gpu, REG_A7XX_SP_AHB_READ_APERTURE + i);
+ snapshot_sect_u32(§, val);
+ }
+ }
+}
+
+static bool gen8_snapshot_shader(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state,
+ struct adreno_crashdumper *dumper)
+{
+ const struct gen8_snapshot_block_list *b = block_list(gpu);
+ u32 slice_mask = to_a6xx_gpu(to_adreno_gpu(gpu))->slice_mask;
+
+ if (!dumper) {
+ for (int i = 0; i < b->num_shader_blocks; i++) {
+ const struct gen8_shader_block *block = &b->shader_blocks[i];
+ u32 j;
+
+ FOR_EACH_SLICE (j, block->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(block->slice_region, j);
+
+ for (u32 sp = 0; sp < block->num_sps; sp++) {
+ for (u32 ctxt = 0; ctxt < block->num_ctx; ctxt++) {
+ gen8_legacy_snapshot_shader(
+ gpu, state, block, sp, ctxt, slice_id);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ for (int i = 0; i < b->num_shader_blocks; i++) {
+ const struct gen8_shader_block *block = &b->shader_blocks[i];
+ u32 j;
+
+ FOR_EACH_SLICE (j, block->slice_region, slice_mask) {
+ u32 slice_id = SLICE_ID(block->slice_region, j);
+
+ for (u32 sp = 0; sp < block->num_sps; sp++) {
+ for (u32 ctxt = 0; ctxt < block->num_ctx; ctxt++) {
+ /* Build the crash script */
+ struct cd_script p = CD_INIT(dumper);
+
+ u32 read_sel = GEN8_SP_READ_SEL_VAL(
+ ctxt, slice_id, block->location, block->pipeid,
+ block->statetype, block->usptp_id, sp);
+
+ /* Program the aperture */
+ CD_WRITE(&p, REG_A7XX_SP_READ_SEL, read_sel);
+
+ /* Read all the data in one chunk */
+ CD_READ(&p, REG_A7XX_SP_AHB_READ_APERTURE, block->size);
+
+ /* Marker for end of script */
+ CD_FINISH(&p);
+
+ /* Try to run the crash dumper and bail if it times out */
+ if (CD_RUN(&p, gpu))
+ return false;
+
+ snapshot_sect (state, SHADER_V3, block->size * sizeof(u32), {
+ .type = block->statetype,
+ .slice_id = HEADER_SLICE_ID(block->slice_region, slice_id),
+ .sp_index = sp,
+ .usptp = block->usptp_id,
+ .pipe_id = block->pipeid,
+ .location = block->location,
+ .ctxt_id = ctxt,
+ .size = block->size,
+ }) {
+ const u32 *src = dumper->ptr + A8XX_CD_DATA_OFFSET;
+ snapshot_sect_data(§, src, block->size * sizeof(u32));
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static void a8xx_snapshot_gmu_bo(struct adreno_gpu_state *state,
+ struct a6xx_gmu_bo *bo,
+ unsigned type)
+{
+ snapshot_sect (state, GMU_MEMORY, bo->size, {
+ .type = type,
+ .gmuaddr = bo->iova,
+ }) {
+ snapshot_sect_data(§, bo->virt, bo->size);
+ }
+}
+
+static void a8xx_snapshot_gpu_bo(struct adreno_gpu_state *state,
+ struct drm_gem_object *bo,
+ uint64_t iova)
+{
+ if (!bo)
+ return;
+
+ snapshot_sect (state, GPU_OBJECT_V2, bo->size, {
+ .type = SNAPSHOT_GPU_OBJECT_GLOBAL,
+ .gpuaddr = iova,
+ .size = bo->size / 4, /* dwords */
+ }) {
+ void *ptr = msm_gem_get_vaddr(bo);
+ snapshot_sect_data(§, ptr, bo->size);
+ msm_gem_put_vaddr(bo);
+ }
+}
+
+static void a8xx_snapshot_gmu_hfi_history(struct msm_gpu *gpu,
+ struct adreno_gpu_state *state)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+ unsigned i, j;
+
+ BUILD_BUG_ON(ARRAY_SIZE(gmu->queues) != ARRAY_SIZE(state->hfi_queue_history));
+
+ for (i = 0; i < ARRAY_SIZE(gmu->queues); i++) {
+ struct a6xx_hfi_queue *queue = &gmu->queues[i];
+ for (j = 0; j < HFI_HISTORY_SZ; j++) {
+ unsigned idx = (j + queue->history_idx) % HFI_HISTORY_SZ;
+ state->hfi_queue_history[i][j] = queue->history[idx];
+ }
+ }
+}
+
+#define GEN8_DEBUGBUS_BLOCK_SIZE 0x100
+
+#define GEN8_DEBUGBUS_BLOCK_IDX_1 128
+#define GEN8_DEBUGBUS_BLOCK_IDX_2 192
+
+static void gen8_cx_dbgc_debugbus_select(struct msm_gpu *gpu, u32 block_id, u32 index)
+{
+ u32 reg;
+
+ reg = A7XX_DBGC_CFG_DBGBUS_SEL_D_PING_INDEX(index) |
+ A7XX_DBGC_CFG_DBGBUS_SEL_D_PING_BLK_SEL(block_id);
+
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_A, reg);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_B, reg);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_C, reg);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_D, reg);
+
+ /* Wait 1 us to make sure the data is flowing */
+ udelay(1);
+}
+
+static void gen8_debugbus_internal_read_setup(struct msm_gpu *gpu)
+{
+ /* Clear the DBGC logic/events */
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM, 0x70000000);
+
+ /* Enable the internal buffer mode and program to tail mode */
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_OPL, 0x28000000);
+
+ /* Program the logic unit 0 to high when the side data is 1 */
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0, 0x0000000c);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0, 0x000000f0);
+
+ /* Enable the DBGC logic/events */
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM, 0x07000000);
+}
+
+static void gen8_cx_gc_us_i_0_debugbus_read(
+ struct msm_gpu *gpu, u32 block_id, u32 index, u32 data[2])
+{
+ gen8_cx_dbgc_debugbus_select(gpu, block_id, index);
+
+ /*
+ * Select lower 32 bits of internal buffer data for internal mux[1:0]
+ * DBGC_CFG_DBGBUS_IDX.internalIndex0 = 24 (0x18)
+ * DBGC_CFG_DBGBUS_IDX.internalIndex1 = 25 (0x19)
+ */
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IDX, 0x00001918);
+ udelay(1);
+
+ data[0] = gpu_read(gpu, REG_A6XX_DBGC_CFG_DBGBUS_TRACE_BUF3);
+
+ /*
+ * Select upper 32 bits of internal buffer data for internal mux[1:0]
+ * DBGC_CFG_DBGBUS_IDX.internalIndex0 = 26 (0x1a)
+ * DBGC_CFG_DBGBUS_IDX.internalIndex1 = 27 (0x1b)
+ */
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IDX, 0x00001a1b);
+ udelay(1);
+
+ data[1] = gpu_read(gpu, REG_A6XX_DBGC_CFG_DBGBUS_TRACE_BUF3);
+}
+
+/* gen8_cx_dbgc_debug_bus_read() - Read data from trace bus */
+static void gen8_cx_debug_bus_read(
+ struct msm_gpu *gpu, u32 block_id, u32 index, u32 data[2])
+{
+ gen8_cx_dbgc_debugbus_select(gpu, block_id, index);
+
+ data[0] = gpu_read(gpu, REG_A6XX_DBGC_CFG_DBGBUS_TRACE_BUF2);
+ data[1] = gpu_read(gpu, REG_A6XX_DBGC_CFG_DBGBUS_TRACE_BUF1);
+}
+
+static void gen8_snapshot_cx_dbgc_debugbus_block(
+ struct msm_gpu *gpu, uint32_t block_id, size_t count,
+ struct adreno_snapshot_sect *sect)
+{
+ /* This block requires an out of order access due to a HW limitation.
+ * (QCTDD12240539)
+ */
+ if (block_id == DEBUGBUS_CX_GC_US_I_0) {
+ static u32 data[GEN8_DEBUGBUS_BLOCK_SIZE * 2];
+ gen8_debugbus_internal_read_setup(gpu);
+ for (int i = 0; i < GEN8_DEBUGBUS_BLOCK_IDX_1; i++)
+ gen8_cx_gc_us_i_0_debugbus_read(gpu, block_id, i, &data[i * 2]);
+ for (int i = GEN8_DEBUGBUS_BLOCK_IDX_2; i < GEN8_DEBUGBUS_BLOCK_SIZE; i++)
+ gen8_cx_gc_us_i_0_debugbus_read(gpu, block_id, i, &data[i * 2]);
+ for (int i = GEN8_DEBUGBUS_BLOCK_IDX_1; i < GEN8_DEBUGBUS_BLOCK_IDX_2; i++)
+ gen8_cx_gc_us_i_0_debugbus_read(gpu, block_id, i, &data[i * 2]);
+ snapshot_sect_arr(sect, data);
+ } else {
+ for (int i = 0; i < count; i++) {
+ u32 data[2];
+ gen8_cx_debug_bus_read(gpu, block_id, i, data);
+ snapshot_sect_arr(sect, data);
+ }
+ }
+}
+
+static void gen8_dbgc_side_debug_bus_read(struct msm_gpu *gpu,
+ u32 block_id, u32 index, struct adreno_snapshot_sect *sect)
+{
+ u32 reg, side_data;
+
+ gen8_cx_dbgc_debugbus_select(gpu, block_id, index);
+
+ reg = gpu_read(gpu, REG_A6XX_DBGC_CFG_DBGBUS_OVER);
+ side_data = FIELD_GET(GENMASK(27, 24), reg);
+
+ snapshot_sect_u32(sect, side_data);
+}
+
+static void gen8_snapshot_dbgc_side_debugbus_block(
+ struct msm_gpu *gpu, uint32_t block_id, size_t count,
+ struct adreno_snapshot_sect *sect)
+{
+ for (int i = 0; i < count; i++)
+ gen8_dbgc_side_debug_bus_read(gpu, block_id, i, sect);
+}
+
+static void gen8_get_debugbus(struct msm_gpu *gpu, struct adreno_gpu_state *state)
+{
+ const struct gen8_snapshot_block_list *b = block_list(gpu);
+
+ /* Set up the GX debug bus */
+
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLT,
+ A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT(0xf));
+
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM,
+ A6XX_DBGC_CFG_DBGBUS_CNTLM_ENABLE(0xf));
+
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_0, 0);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_1, 0);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_2, 0);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_3, 0);
+
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0, 0x76543210);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_1, 0xFEDCBA98);
+
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0, 0);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_1, 0);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_2, 0);
+ gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_3, 0);
+
+ /* Read the blocks: */
+
+ for (int i = 0; i < b->debugbus_blocks_len; i++) {
+ size_t count = GEN8_DEBUGBUS_BLOCK_SIZE;
+ uint32_t block_id = b->debugbus_blocks[i];
+
+ snapshot_sect (state, DEBUGBUS, 4 * 2 * count, {
+ /* debugbus section hdr: */
+ .id = block_id,
+ .count = count * 2,
+ }) {
+ gen8_snapshot_cx_dbgc_debugbus_block(gpu, block_id, count, §);
+ }
+
+ snapshot_sect (state, SIDE_DEBUGBUS, 4 * count, {
+ /* side_debugbus section hdr: */
+ .id = block_id,
+ .size = count,
+ .valid_data = 0x4,
+ }) {
+ gen8_snapshot_dbgc_side_debugbus_block(gpu, block_id, count, §);
+ }
+ }
+
+ for (int i = 0; i < b->gbif_debugbus_blocks_len; i++) {
+ size_t count = GEN8_DEBUGBUS_BLOCK_SIZE;
+ uint32_t block_id = b->gbif_debugbus_blocks[i];
+
+ snapshot_sect (state, DEBUGBUS, 4 * 2 * count, {
+ /* debugbus section hdr: */
+ .id = block_id,
+ .count = count * 2,
+ }) {
+ gen8_snapshot_cx_dbgc_debugbus_block(gpu, block_id, count, §);
+ }
+
+ snapshot_sect (state, SIDE_DEBUGBUS, 4 * count, {
+ /* side_debugbus section hdr: */
+ .id = block_id,
+ .size = count,
+ .valid_data = 0x4,
+ }) {
+ gen8_snapshot_dbgc_side_debugbus_block(gpu, block_id, count, §);
+ }
+ }
+}
+
+struct msm_gpu_state *a8xx_gpu_state_get(struct msm_gpu *gpu)
+{
+ const struct gen8_snapshot_block_list *b = block_list(gpu);
+ struct adreno_crashdumper _dumper = { 0 }, *dumper = NULL;
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct adreno_gpu_state *state;
+ // TODO need to get status from SMMU on some gen8..
+ bool stalled = !!(gpu_read(gpu, REG_A8XX_RBBM_MISC_STATUS) &
+ A8XX_RBBM_MISC_STATUS_SMMU_STALLED_ON_FAULT);
+
+ if (!b)
+ return NULL;
+
+ state = kzalloc_obj(*state);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&state->objs);
+
+ /* Get the generic state from the adreno core */
+ adreno_gpu_state_get(gpu, &state->base);
+
+ adreno_snapshot_registers_v2(gpu, state, b->gmu_cx_unsliced_regs);
+
+ a8xx_snapshot_gmu_bo(state, &a6xx_gpu->gmu.log, SNAPSHOT_GMU_MEM_LOG);
+ a8xx_snapshot_gmu_bo(state, &a6xx_gpu->gmu.hfi, SNAPSHOT_GMU_MEM_HFI);
+ a8xx_snapshot_gmu_bo(state, &a6xx_gpu->gmu.debug, SNAPSHOT_GMU_MEM_DEBUG);
+
+ a8xx_snapshot_gmu_hfi_history(gpu, state);
+
+ /* If GX isn't on the rest of the data isn't going to be accessible */
+ if (!a6xx_gmu_gx_is_on(adreno_gpu))
+ return &state->base;
+
+ snapshot_sect (state, DEBUG, 4, {
+ .type = SNAPSHOT_DEBUG_SLICE_MASK,
+ .size = 1,
+ }) {
+ snapshot_sect_u32(§, a6xx_gpu->slice_mask);
+ }
+
+ gen8_get_debugbus(gpu, state);
+
+ /*
+ * Try to initialize the crashdumper, if we are not dumping state
+ * with the SMMU stalled. The crashdumper needs memory access to
+ * write out GPU state, so we need to skip this when the SMMU is
+ * stalled in response to an iova fault
+ */
+ if (!stalled && !gpu->needs_hw_init &&
+ !a8xx_crashdumper_init(gpu, &_dumper)) {
+ dumper = &_dumper;
+ }
+
+ /* Clear aperture register */
+ a8xx_aperture_clear(gpu);
+
+ /*
+ * Assert the isStatic bit before triggering snapshot.
+ * BIT(0): GPU activity during snapshot dump
+ * BIT(1): GPU UNSLICE activity during snapshot dump
+ * Similarly, BIT(4) for slice-0, BIT(5) for slice-1 and so on.
+ */
+ gpu_write(gpu, REG_A8XX_RBBM_SNAPSHOT_STATUS, BIT(0) | BIT(1) |
+ FIELD_PREP(GENMASK(7, 4), a6xx_gpu->slice_mask));
+
+ /* Dump the registers which get affected by crash dumper trigger */
+ for (int i = 0; i < b->num_pre_crashdumper_regs; i++) {
+ const struct gen8_reg_list *regs = &b->pre_crashdumper_regs[i];
+ u32 j;
+
+ FOR_EACH_SLICE (j, regs->slice_region, a6xx_gpu->slice_mask) {
+ u32 slice_id = SLICE_ID(regs->slice_region, j);
+ gen8_legacy_snapshot_registers(gpu, state, regs, slice_id);
+ }
+ }
+
+ /*
+ * If crashdumper timed out while dumping this section skip everything
+ * since even AHB acceses to the GPU might cause NoC errors.
+ */
+ if (!gen8_reglist_snapshot(gpu, state, dumper))
+ goto out;
+
+ /* CP indexed regs data */
+ if (!gen8_snapshot_cp_indexed_regs(gpu, state, dumper))
+ goto out;
+
+ /* Mempool debug data */
+ if (!gen8_snapshot_mempool(gpu, state, dumper))
+ goto out;
+
+ /*
+ * CP MVC register section
+ * If crashdumper timed out while dumping any section below skip everything
+ * since even AHB acceses to the GPU might cause NoC errors.
+ */
+ if (!gen8_snapshot_mvc_regs(gpu, state, dumper, b->cp_clusters, b->num_cp_clusters))
+ goto out;
+
+ /* MVC register section */
+ if (!gen8_snapshot_mvc_regs(gpu, state, dumper, b->clusters, b->num_clusters))
+ goto out;
+
+ /* registers dumped through DBG AHB */
+ if (!gen8_snapshot_dbgahb_regs(gpu, state, dumper))
+ goto out;
+
+ /* Shader memory */
+ if (!gen8_snapshot_shader(gpu, state, dumper))
+ goto out;
+
+ /*
+ * Capture preempt records after cp_clusters, to make this easier
+ * to decode (ie. so we already know CP_CONTEXT_SWITCH_SMMU_INFO and
+ * CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR) when crashdec sees
+ * the logged GPU objs)
+ */
+ for (unsigned i = 0; i < gpu->nr_rings; i++) {
+ a8xx_snapshot_gpu_bo(state, a6xx_gpu->preempt_bo[i],
+ a6xx_gpu->preempt_iova[i]);
+ a8xx_snapshot_gpu_bo(state, a6xx_gpu->preempt_smmu_bo[i],
+ a6xx_gpu->preempt_smmu_iova[i]);
+ }
+
+out:
+ gpu_write(gpu, REG_A8XX_RBBM_SNAPSHOT_STATUS, 0x0);
+
+ if (dumper)
+ msm_gem_kernel_put(dumper->bo, gpu->vm);
+
+ state->gpu_initialized = !gpu->needs_hw_init;
+
+ return &state->base;
+}
+
+static void a8xx_gpu_state_destroy(struct kref *kref)
+{
+ struct adreno_state_memobj *obj, *tmp;
+ struct msm_gpu_state *state = container_of(kref,
+ struct msm_gpu_state, ref);
+ struct adreno_gpu_state *adreno_state = container_of(state,
+ struct adreno_gpu_state, base);
+
+ list_for_each_entry_safe (obj, tmp, &adreno_state->objs, node) {
+ list_del(&obj->node);
+ kvfree(obj->ptr);
+ kfree(obj);
+ }
+
+ adreno_gpu_state_destroy(state);
+ kfree(adreno_state);
+}
+
+int a8xx_gpu_state_put(struct msm_gpu_state *state)
+{
+ if (IS_ERR_OR_NULL(state))
+ return 1;
+
+ return kref_put(&state->ref, a8xx_gpu_state_destroy);
+}
+
+void a8xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
+ struct drm_printer *p)
+{
+ struct adreno_gpu_state *adreno_state = container_of(state,
+ struct adreno_gpu_state, base);
+ struct adreno_state_memobj *obj;
+
+ if (IS_ERR_OR_NULL(state))
+ return;
+
+ drm_printf(p, "gpu-initialized: %d\n", adreno_state->gpu_initialized);
+
+ adreno_show(gpu, state, p);
+
+ drm_puts(p, "gmu-hfi:\n");
+ for (int i = 0; i < ARRAY_SIZE(adreno_state->hfi_queue_history); i++) {
+ drm_printf(p, " queue-history[%u]:", i);
+ for (int j = 0; j < HFI_HISTORY_SZ; j++) {
+ drm_printf(p, " %d", adreno_state->hfi_queue_history[i][j]);
+ }
+ drm_printf(p, "\n");
+ }
+
+ /*
+ * Parsing note: do not assume each snapshot obj is only a single
+ * section, assume sub-allocation.
+ */
+ drm_puts(p, "snapshot:\n");
+ list_for_each_entry (obj, &adreno_state->objs, node) {
+ drm_printf(p, " size: %zu\n", obj->size);
+ adreno_show_object(p, &obj->ptr, obj->size, &obj->encoded);
+ }
+}
diff --git a/drivers/gpu/drm/msm/adreno/adreno_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
index f9956e0bc1d5..e8ff102a628b 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
@@ -7,6 +7,8 @@
#include <linux/types.h>
+#include "msm_gpu.h"
+
/* Snapshot header */
/* High word is static, low word is snapshot version ID */
@@ -150,6 +152,7 @@ struct adreno_snapshot_gmu_mem {
uint64_t gmuaddr;
uint64_t gpuaddr;
} __packed;
+#define STRUCT_GMU_MEMORY adreno_snapshot_gmu_mem
/* Register sub-section header */
struct adreno_snapshot_regs {
@@ -172,6 +175,7 @@ struct adreno_snapshot_indexed_regs_v2 {
u32 pipe_id; /* Id of pipe, BV, Br etc */
u32 slice_id; /* Slice ID to be dumped */
} __packed;
+#define STRUCT_INDEXED_REGS_V2 adreno_snapshot_indexed_regs_v2
/* MVC register sub-section header */
struct adreno_snapshot_mvc_regs {
@@ -195,6 +199,7 @@ struct adreno_snapshot_mvc_regs_v3 {
u32 sp_id;
u32 usptp_id;
} __packed;
+#define STRUCT_MVC_V3 adreno_snapshot_mvc_regs_v3
/* Debug data sub-section header */
@@ -222,17 +227,20 @@ struct adreno_snapshot_debug {
int type; /* Type identifier for the attached tata */
int size; /* Size of the section in dwords */
} __packed;
+#define STRUCT_DEBUG adreno_snapshot_debug
struct adreno_snapshot_debugbus {
int id; /* Debug bus ID */
int count; /* Number of dwords in the dump */
} __packed;
+#define STRUCT_DEBUGBUS adreno_snapshot_debugbus
struct adreno_snapshot_side_debugbus {
int id; /* Debug bus ID */
int size; /* Number of dwords in the dump */
int valid_data; /* Mask of valid bits of the side debugbus */
} __packed;
+#define STRUCT_SIDE_DEBUGBUS adreno_snapshot_side_debugbus
struct adreno_snapshot_shader {
int type; /* SP/TP statetype */
@@ -259,6 +267,7 @@ struct adreno_snapshot_shader_v3 {
u32 ctxt_id; /* Context ID */
u32 size; /* Number of dwords in the dump */
} __packed;
+#define STRUCT_SHADER_V3 adreno_snapshot_shader_v3
#define TRACE_BUF_NUM_SIG 4
@@ -302,6 +311,7 @@ struct adreno_snapshot_gpu_object_v2 {
__u64 ptbase; /* Base for the pagetable the GPU address is valid in */
__u64 size; /* Size of the object (in dwords) */
} __packed;
+#define STRUCT_GPU_OBJECT_V2 adreno_snapshot_gpu_object_v2
struct adreno_snapshot_eventlog {
/** @type: Type of the event log buffer */
@@ -319,3 +329,198 @@ struct adreno_snapshot_gmu_version {
u32 value;
} __packed;
+struct adreno_snapshot_empty_header { u8 dummy; };
+#define STRUCT_REGS_V2 adreno_snapshot_debugbus
+
+#define REG_COUNT(_ptr) ((_ptr[1] - _ptr[0]) + 1)
+
+static int adreno_snapshot_regs_count(const u32 *ptr)
+{
+ unsigned int count = 0;
+ unsigned int group_count;
+
+ for ( ; ptr[0] != UINT_MAX; ptr += 2) {
+ group_count = REG_COUNT(ptr);
+ if (group_count == 1)
+ count += group_count + 1;
+ else
+ count += group_count + 2;
+ }
+ return count;
+}
+
+struct adreno_gpu_state {
+ struct msm_gpu_state base;
+
+ s32 hfi_queue_history[HFI_MAX_QUEUES][HFI_HISTORY_SZ];
+
+ /* list of struct adreno_state_memobj */
+ struct list_head objs;
+
+ bool gpu_initialized;
+};
+
+struct adreno_state_memobj {
+ struct list_head node;
+ void *ptr; /* replaced by ascii85 encoded string in adreno_show_object() */
+ bool encoded;
+ size_t size;
+};
+
+/**
+ * A on-stack helper to build snapshot sections setting the size field when the
+ * helper goes out of scope, to simplify constructing snapshot sections, but
+ * without resorting to the callback approach that kgsl uses.
+ */
+struct adreno_snapshot_sect {
+ struct adreno_state_memobj *obj;
+ void *cur, *end;
+};
+
+static void __snapshot_sect_fini(struct adreno_snapshot_sect *s)
+{
+ struct adreno_snapshot_section_header *hdr = (void *)s->obj->ptr;
+ hdr->size = s->obj->size = ((u8 *)s->cur - (u8 *)s->obj->ptr);
+}
+
+static struct adreno_snapshot_sect
+__snapshot_sect_init(struct adreno_gpu_state *state, uint16_t id, size_t extra_sz,
+ void *sect_hdr, size_t sect_hdr_sz, const char *func, int line)
+{
+ /* A few section types have no section header: */
+ switch (id) {
+ case ADRENO_SNAPSHOT_SECTION_REGS_V2:
+ sect_hdr_sz = 0;
+ default:
+ break;
+ }
+
+ pr_debug("%s:%d: snapshot_sect(id=%04x, extra_sz=%zu, sect_hdr_sz=%zu)\n",
+ func, line, id, extra_sz, sect_hdr_sz);
+
+ size_t sz = sizeof(struct adreno_snapshot_section_header) + sect_hdr_sz + extra_sz;
+ struct adreno_state_memobj *obj = kzalloc_obj(*obj);
+ void *ptr = kvzalloc(sz, GFP_KERNEL);
+
+ if (!obj || !ptr) {
+ kfree(obj);
+ kvfree(ptr);
+ return (struct adreno_snapshot_sect){};
+ }
+
+ obj->ptr = ptr;
+
+ list_add_tail(&obj->node, &state->objs);
+
+ /* Common snapshot section header: */
+ struct adreno_snapshot_section_header *hdr = ptr;
+ hdr->magic = SNAPSHOT_SECTION_MAGIC;
+ hdr->id = id;
+ /* size filled out in __snapshot_sect_fini() */
+ ptr += sizeof(*hdr);
+
+ /* Section type header: */
+ memcpy(ptr, sect_hdr, sect_hdr_sz);
+ ptr += sect_hdr_sz;
+
+ return (struct adreno_snapshot_sect) {
+ .obj = obj,
+ .cur = ptr,
+ .end = ptr + extra_sz,
+ };
+}
+
+static void
+snapshot_sect_data(struct adreno_snapshot_sect *s, const void *data, size_t sz)
+{
+ /* overflow check: */
+ if (WARN_ON_ONCE(s->cur + sz > s->end))
+ return;
+
+ memcpy(s->cur, data, sz);
+ s->cur += sz;
+}
+
+#define snapshot_sect_arr(_s, _d) snapshot_sect_data(_s, _d, sizeof(_d))
+
+static void
+snapshot_sect_u32(struct adreno_snapshot_sect *s, u32 val)
+{
+ snapshot_sect_data(s, &val, sizeof(val));
+}
+
+#define __snapshot_sect(_label, _state, _id, _extra_sz, ...) \
+ for (struct adreno_snapshot_sect sect = ({ \
+ struct STRUCT_ ## _id sect_hdr = __VA_ARGS__; \
+ __snapshot_sect_init(_state, ADRENO_SNAPSHOT_SECTION_ ## _id, \
+ _extra_sz, §_hdr, \
+ sizeof(sect_hdr), \
+ __func__, __LINE__); }); \
+ sect.obj; ({ goto _label; })) \
+ if (false) { \
+_label: \
+ __snapshot_sect_fini(§); \
+ break; \
+ } else
+
+#define snapshot_sect(_id, _extra_sz, ...) \
+ __snapshot_sect(__UNIQUE_ID(label), _id, _extra_sz, __VA_ARGS__)
+
+struct adreno_crashdumper {
+ void *ptr;
+ size_t data_offset;
+ struct drm_gem_object *bo;
+ u64 iova;
+};
+
+/**
+ * On-stack object to represent a single crashdumper invocation, tracking
+ * in/out ptrs and checking for overflow.
+ */
+struct cd_script {
+ struct adreno_crashdumper *dumper;
+ u64 *in;
+ u64 out;
+};
+
+/* These should be implemented by the gen specific backend: */
+static inline int __cd_run(struct msm_gpu *gpu, struct adreno_crashdumper *dumper);
+static inline bool __cd_check_overflow(struct cd_script *p);
+
+static inline struct cd_script CD_INIT(struct adreno_crashdumper *dumper)
+{
+ return (struct cd_script) {
+ .dumper = dumper,
+ .in = dumper->ptr,
+ .out = dumper->iova + dumper->data_offset,
+ };
+}
+
+static inline void CD_WRITE(struct cd_script *p, u32 reg, u32 val)
+{
+ *(p->in++) = val;
+ *(p->in++) = FIELD_PREP(GENMASK(63, 44), reg) | BIT(21) | BIT(0);
+ __cd_check_overflow(p);
+}
+
+static inline void CD_READ(struct cd_script *p, u32 reg, u32 dwords)
+{
+ *(p->in++) = p->out;
+ *(p->in++) = FIELD_PREP(GENMASK(63, 44), reg) | dwords;
+ p->out += sizeof(u32) * dwords;
+ __cd_check_overflow(p);
+}
+
+static void CD_FINISH(struct cd_script *p)
+{
+ *(p->in++) = 0;
+ *(p->in++) = 0;
+ __cd_check_overflow(p);
+}
+
+static int CD_RUN(struct cd_script *p, struct msm_gpu *gpu)
+{
+ if (!__cd_check_overflow(p))
+ return -ENOSPC;
+ return __cd_run(gpu, p->dumper);
+}
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/12] drm/msm/a8xx: Switch to generated nonctx regs
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (7 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 09/12] drm/msm/a8xx: devcoredump state capture support Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 23:32 ` sashiko-bot
2026-10-20 20:46 ` [PATCH 11/12] drm/msm/a8xx: Switch to generated protect regs Rob Clark
2026-10-20 20:46 ` [PATCH 12/12] drm/msm/adreno: Remove temporary __maybe_unused Rob Clark
10 siblings, 1 reply; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
The generated headers contain the current (at time of generation) hw
recommended values. Using these directly makes it easier to stay up
to date.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a8xx_catalog.c | 354 +---------------------
1 file changed, 7 insertions(+), 347 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
index 15fc10d5db68..bc79013165c1 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
@@ -18,71 +18,6 @@
#include "catalog/adreno_milos.h"
#include "catalog/adreno_pakala.h"
-static const struct adreno_reglist_pipe a830_nonctxt_regs[] = {
- { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
- { REG_A8XX_GRAS_DBG_ECO_CNTL, 0x00000800, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000003, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_PC_CHICKEN_BITS_3, 0x00400000, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BR) | BIT(PIPE_BV) },
- /* Configure GBIF GX registers */
- { REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) },
- /* Enable full concurrent resolve and unresolves */
- { REG_A7XX_RB_CCU_CNTL, 0x00000068, BIT(PIPE_BR) },
- /* Partially enable perf clear, Disable DINT to c/z be data forwarding */
- { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0x00002200, BIT(PIPE_BR) },
- { REG_A8XX_RB_GC_GMEM_PROTECT, 0x0c000000, BIT(PIPE_BR) },
- /* Configure number of outstanding transactions to 32 */
- { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) },
- /* Configure UCHE request time out to 16 cycles for CCU/UCHE arbitration */
- { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) },
- { REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) },
- /* Enable contribution of all shader stages to SP perfcounters */
- { REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) },
- /*
- * BIT(26): Limit the number of wave-slots for Eviction buffer to 1 per ALU GRP
- * BIT(30): Disable LPAC auto-promotion
- */
- { REG_A7XX_SP_CHICKEN_BITS_1, BIT(26) | BIT(30), BIT(PIPE_NONE) },
- /*
- * BIT(22): Disable PS out of order retire
- * BIT(23): Enable half wave mode and MM instruction src&dst is half precision
- */
- { REG_A7XX_SP_CHICKEN_BITS_2, BIT(22) | BIT(23), BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10000000, BIT(PIPE_NONE) },
- /* Enable cubemap small miplevel optimization settings */
- /* BIT(26): Disable final clamp for bicubic filtering */
- { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x04000724, BIT(PIPE_NONE) },
- /* Disable tag bank id hashing */
- { REG_A6XX_UCHE_MODE_CNTL, 0x00080000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) },
- /* Limit gmem number of ways for GMEM requests in each set */
- { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE)},
- /* Disable write slow pointer in data phase queue */
- { REG_A8XX_UCHE_HW_DBG_CNTL, BIT(8), BIT(PIPE_NONE) },
- /* Configure UCHE to CCU switchthreshold timeout cycles */
- { REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) },
- { REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00100020, BIT(PIPE_BR) | BIT(PIPE_BV) },
- { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BR) | BIT(PIPE_BV) },
- /* Disable redundant tile data optimization */
- { REG_A8XX_VSC_KMD_DBG_ECO_CNTL, BIT(11), BIT(PIPE_NONE)},
- { },
-};
-
static const u32 a830_protect_regs[] = {
A6XX_PROTECT_RDONLY(0x00000, 0x03a3),
A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
@@ -306,51 +241,6 @@ static const struct adreno_reglist_pipe a830_dyn_pwrup_reglist_regs[] = {
};
DECLARE_ADRENO_REGLIST_PIPE_LIST(a830_dyn_pwrup_reglist);
-static const struct adreno_reglist_pipe x285_nonctxt_regs[] = {
- { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
- { REG_A8XX_GRAS_DBG_ECO_CNTL, 0x00000800, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0x00200000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000003, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_3, 0x00500000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_RB_GC_GMEM_PROTECT, 0x15000000, BIT(PIPE_BR) },
- { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) },
- { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) },
- { REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_INTERFACE_HANG_INT_CNTL, 0x0fffffff, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_2, 0x00820800, BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) },
- { REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) },
- /* Disable CS dead batch merge */
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_2, BIT(31), BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) },
- { REG_A7XX_SP_READ_SEL, 0x0001ff00, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10000000, BIT(PIPE_NONE) },
- /* BIT(26): Disable final clamp for bicubic filtering */
- { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x04000720, BIT(PIPE_NONE) },
- { REG_A6XX_UCHE_MODE_CNTL, 0x80080000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) },
- { REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00000020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { },
-};
-
static const u32 x285_protect_regs[] = {
A6XX_PROTECT_RDONLY(0x00008, 0x039b),
A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
@@ -446,55 +336,6 @@ static const struct adreno_reglist_pipe x285_dyn_pwrup_reglist_regs[] = {
};
DECLARE_ADRENO_REGLIST_PIPE_LIST(x285_dyn_pwrup_reglist);
-static const struct adreno_reglist_pipe a810_nonctxt_regs[] = {
- { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
- { REG_A8XX_GRAS_DBG_ECO_CNTL, 0x00f80800, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000003, BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000023, BIT(PIPE_BV) }, /* Avoid partial waves at VFD */
- { REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_3, 0x00500000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A7XX_RB_CCU_CNTL, 0x00000068, BIT(PIPE_BR) },
- /* Partially enable perf clear, Disable DINT to c/z be data forwarding */
- { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0x00002200, BIT(PIPE_BR) },
- { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) },
- { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) },
- { REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) },
- /*
- * BIT(22): Disable PS out of order retire
- * BIT(23): Enable half wave mode and MM instruction src&dst is half precision
- */
- { REG_A7XX_SP_CHICKEN_BITS_2, BIT(22) | BIT(23), BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) },
- { REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10100000, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x04000724, BIT(PIPE_NONE) },
- { REG_A6XX_UCHE_MODE_CNTL, 0x00020000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) },
- /* Disable write slow pointer in data phase queue */
- { REG_A8XX_UCHE_HW_DBG_CNTL, BIT(8), BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) },
- { REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00100020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_RB_GC_GMEM_PROTECT, 0x00900000, BIT(PIPE_BR) },
- { },
-};
-
static const u32 a810_protect_regs[] = {
A6XX_PROTECT_RDONLY(0x00000, 0x03a3),
A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
@@ -785,69 +626,6 @@ struct a6xx_hfi_limits_tbl x285_limits_tbl[] = {
};
DECLARE_ADRENO_LIMITS_TABLE(x285_limits);
-static const struct adreno_reglist_pipe a840_nonctxt_regs[] = {
- { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
- { REG_A8XX_GRAS_DBG_ECO_CNTL, 0x00000800, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0x00200000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000003, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_3, 0x00500000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- /* Disable Dead Draw Merge scheme on RB-HLSQ */
- { REG_A6XX_RB_RBP_CNTL, BIT(5), BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A7XX_RB_CCU_CNTL, 0x00000068, BIT(PIPE_BR) },
- /* Partially enable perf clear, Disable DINT to c/z be data forwarding */
- { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0x00002200, BIT(PIPE_BR) },
- { REG_A8XX_RB_GC_GMEM_PROTECT, 0x12000000, BIT(PIPE_BR) },
- { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) },
- { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) },
- { REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_POWER_UP_RESET_SW_OVERRIDE, 0x70809060, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_POWER_UP_RESET_SW_BV_OVERRIDE, 0x30000000, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_INTERFACE_HANG_INT_CNTL, 0x0fffffff, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) },
- /* Disable mode_switch optimization in UMAS */
- { REG_A6XX_SP_CHICKEN_BITS, BIT(24) | BIT(26), BIT(PIPE_NONE) },
- /* Disable LPAC large-LM mode */
- { REG_A8XX_SP_SS_CHICKEN_BITS_0, BIT(3), BIT(PIPE_NONE) },
- /* Disable PS out of order retire */
- { REG_A7XX_SP_CHICKEN_BITS_2, 0x00c21800, BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) },
- /* Disable SP2TP info attribute */
- { REG_A8XX_SP_CHICKEN_BITS_4, 0x00000002, BIT(PIPE_NONE) },
- { REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL, BIT(14), BIT(PIPE_NONE) },
- /* Ignore HLSQ shared constant feedback from SP */
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_1, BIT(17), BIT(PIPE_NONE) },
- /* Disable CS dead batch merge */
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_2, BIT(24), BIT(PIPE_NONE) },
- { REG_A8XX_SP_HLSQ_DBG_ECO_CNTL_3, BIT(7), BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) },
- { REG_A7XX_SP_READ_SEL, 0x0001ff00, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10100000, BIT(PIPE_NONE) },
- /* BIT(26): Disable final clamp for bicubic filtering */
- { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x04000720, BIT(PIPE_NONE) },
- { REG_A6XX_UCHE_MODE_CNTL, 0x80080000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) },
- { REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00000020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { },
-};
-
static const u32 a840_protect_regs[] = {
A6XX_PROTECT_RDONLY(0x00008, 0x039b),
A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
@@ -1178,124 +956,6 @@ struct a6xx_hfi_limits_tbl a840_limits_tbl[] = {
};
DECLARE_ADRENO_LIMITS_TABLE(a840_limits);
-static const struct adreno_reglist_pipe a845_nonctxt_regs[] = {
- { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
- { REG_A8XX_CP_MULTIDRAW_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_GRAS_DBG_ECO_CNTL, 0x01000800, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0x00200000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000803, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_3, 0x00400000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_5, BIT(28) | BIT(30), BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A7XX_RB_CCU_CNTL, 0x00000068, BIT(PIPE_BR) },
- { REG_A7XX_RB_CCU_DBG_ECO_CNTL, BIT(10) | BIT(9), BIT(PIPE_BR) },
- { REG_A6XX_RB_DBG_ECO_CNTL, BIT(17), BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_RB_GC_GMEM_PROTECT, 0x0C000000, BIT(PIPE_BR) },
- { REG_A6XX_RB_RBP_CNTL, BIT(5) | BIT(6), BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) },
- { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) },
- { REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_PERFCTR_CNTL, BIT(0), BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_POWER_UP_RESET_SW_OVERRIDE, 0x70809060, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_POWER_UP_RESET_SW_BV_OVERRIDE, 0x30000000, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) },
- { REG_A6XX_SP_CHICKEN_BITS, BIT(24), BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_2, 0x00820800, BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) },
- { REG_A8XX_SP_CHICKEN_BITS_5, BIT(3), BIT(PIPE_NONE) },
- { REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL, 0x04000000, BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_1, BIT(17), BIT(PIPE_NONE) },
- { REG_A8XX_SP_HLSQ_DBG_ECO_CNTL_3, BIT(1), BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) },
- { REG_A7XX_SP_READ_SEL, 0x0001ff00, BIT(PIPE_NONE) },
- { REG_A8XX_SP_L0_PERF_TUNE, 0x00000024, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10100000, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x00000720, BIT(PIPE_NONE) },
- { REG_A6XX_UCHE_MODE_CNTL, 0x80080000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_DBG_ECO_CNTL_0, BIT(31), BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_HW_DBG_CNTL, 0x01410000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) },
- { REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00080020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VSC_VISIBILITY_FLUSH_CNTL, 0x00080004, BIT(PIPE_NONE) },
- { },
-};
-
-static const struct adreno_reglist_pipe a850_nonctxt_regs[] = {
- { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
- { REG_A8XX_CP_MULTIDRAW_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_GRAS_DBG_ECO_CNTL, 0x01000800, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0x00200000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000003, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_3, 0x00400000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_PC_CHICKEN_BITS_5, BIT(28), BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A7XX_RB_CCU_CNTL, 0x00000068, BIT(PIPE_BR) },
- { REG_A7XX_RB_CCU_DBG_ECO_CNTL, BIT(10) | BIT(9), BIT(PIPE_BR) },
- { REG_A6XX_RB_DBG_ECO_CNTL, BIT(17), BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_RB_GC_GMEM_PROTECT, 0x12000000, BIT(PIPE_BR) },
- { REG_A6XX_RB_RBP_CNTL, BIT(5) | BIT(6), BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) },
- { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) },
- { REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_SLICE_PERFCTR_CNTL, BIT(0), BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_POWER_UP_RESET_SW_OVERRIDE, 0x70809060, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_POWER_UP_RESET_SW_BV_OVERRIDE, 0x30000000, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) },
- { REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) },
- { REG_A6XX_SP_CHICKEN_BITS, BIT(24), BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_2, 0x00820800, BIT(PIPE_NONE) },
- { REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) },
- { REG_A8XX_SP_CHICKEN_BITS_5, BIT(3), BIT(PIPE_NONE) },
- { REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL, 0x04000000, BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_1, BIT(17), BIT(PIPE_NONE) },
- { REG_A8XX_SP_HLSQ_DBG_ECO_CNTL_3, BIT(1), BIT(PIPE_NONE) },
- { REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) },
- { REG_A7XX_SP_READ_SEL, 0x0001ff00, BIT(PIPE_NONE) },
- { REG_A8XX_SP_L0_PERF_TUNE, 0x00000024, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10100000, BIT(PIPE_NONE) },
- { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x00000720, BIT(PIPE_NONE) },
- { REG_A6XX_UCHE_MODE_CNTL, 0x80080000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_DBG_ECO_CNTL_0, BIT(31), BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_HW_DBG_CNTL, 0x01410000, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) },
- { REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) },
- { REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00080020, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) },
- { REG_A8XX_VSC_VISIBILITY_FLUSH_CNTL, 0x00080004, BIT(PIPE_NONE) },
- { },
-};
-
static const u32 a850_protect_regs[] = {
A6XX_PROTECT_RDONLY(0x00008, 0x039b),
A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
@@ -1556,7 +1216,7 @@ static const struct adreno_info a8xx_gpus[] = {
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &a830_protect,
- .nonctxt_reglist = a830_nonctxt_regs,
+ .nonctxt_reglist = pakala_nonctxt_regs,
.pwrup_reglist = &a830_pwrup_reglist,
.dyn_pwrup_reglist = &a830_dyn_pwrup_reglist,
.ifpc_reglist = &a830_ifpc_reglist,
@@ -1601,7 +1261,7 @@ static const struct adreno_info a8xx_gpus[] = {
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &x285_protect,
- .nonctxt_reglist = x285_nonctxt_regs,
+ .nonctxt_reglist = glymur_nonctxt_regs,
.pwrup_reglist = &a840_pwrup_reglist,
.dyn_pwrup_reglist = &x285_dyn_pwrup_reglist,
.ifpc_reglist = &a840_ifpc_reglist,
@@ -1646,7 +1306,7 @@ static const struct adreno_info a8xx_gpus[] = {
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &a840_protect,
- .nonctxt_reglist = a840_nonctxt_regs,
+ .nonctxt_reglist = kaanapali_nonctxt_regs,
.pwrup_reglist = &a840_pwrup_reglist,
.dyn_pwrup_reglist = &a840_dyn_pwrup_reglist,
.ifpc_reglist = &a840_ifpc_reglist,
@@ -1692,7 +1352,7 @@ static const struct adreno_info a8xx_gpus[] = {
.zapfw = "gen80300_zap.mbn",
.a6xx = &(const struct a6xx_info) {
.protect = &a810_protect,
- .nonctxt_reglist = a810_nonctxt_regs,
+ .nonctxt_reglist = milos_nonctxt_regs,
.pwrup_reglist = &a810_pwrup_reglist,
.dyn_pwrup_reglist = &a810_dyn_pwrup_reglist,
.ifpc_reglist = &a810_ifpc_reglist,
@@ -1735,7 +1395,7 @@ static const struct adreno_info a8xx_gpus[] = {
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &x285_protect,
- .nonctxt_reglist = x285_nonctxt_regs,
+ .nonctxt_reglist = glymur_nonctxt_regs,
.pwrup_reglist = &a840_pwrup_reglist,
.dyn_pwrup_reglist = &x285_dyn_pwrup_reglist,
.ifpc_reglist = &a840_ifpc_reglist,
@@ -1778,7 +1438,7 @@ static const struct adreno_info a8xx_gpus[] = {
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &a850_protect,
- .nonctxt_reglist = a845_nonctxt_regs,
+ .nonctxt_reglist = maili_nonctxt_regs,
.pwrup_reglist = &a850_pwrup_reglist,
.dyn_pwrup_reglist = &a850_dyn_pwrup_reglist,
.ifpc_reglist = &a850_ifpc_reglist,
@@ -1822,7 +1482,7 @@ static const struct adreno_info a8xx_gpus[] = {
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &a850_protect,
- .nonctxt_reglist = a850_nonctxt_regs,
+ .nonctxt_reglist = hawi_nonctxt_regs,
.pwrup_reglist = &a850_pwrup_reglist,
.dyn_pwrup_reglist = &a850_dyn_pwrup_reglist,
.ifpc_reglist = &a850_ifpc_reglist,
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 11/12] drm/msm/a8xx: Switch to generated protect regs
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (8 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 10/12] drm/msm/a8xx: Switch to generated nonctx regs Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
2026-10-20 23:41 ` sashiko-bot
2026-10-20 20:46 ` [PATCH 12/12] drm/msm/adreno: Remove temporary __maybe_unused Rob Clark
10 siblings, 1 reply; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
These also fix some perfcntr SEL regs which were mistakenly blocked
since we previously just copied the protect tables from downstream kgsl
(and only sometimes remembered to fix these).
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a8xx_catalog.c | 301 +---------------------
1 file changed, 13 insertions(+), 288 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
index bc79013165c1..5f5f71d86df9 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
@@ -18,58 +18,6 @@
#include "catalog/adreno_milos.h"
#include "catalog/adreno_pakala.h"
-static const u32 a830_protect_regs[] = {
- A6XX_PROTECT_RDONLY(0x00000, 0x03a3),
- A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
- A6XX_PROTECT_NORDWR(0x00440, 0x001f),
- A6XX_PROTECT_RDONLY(0x00580, 0x005f),
- A6XX_PROTECT_NORDWR(0x005e0, 0x011f),
- A6XX_PROTECT_RDONLY(0x0074a, 0x0005),
- A6XX_PROTECT_RDONLY(0x00759, 0x0026),
- A6XX_PROTECT_RDONLY(0x00789, 0x0000),
- A6XX_PROTECT_RDONLY(0x0078c, 0x0013),
- A6XX_PROTECT_NORDWR(0x00800, 0x0029),
- A6XX_PROTECT_NORDWR(0x00837, 0x00af),
- A6XX_PROTECT_RDONLY(0x008e7, 0x00c9),
- A6XX_PROTECT_NORDWR(0x008ec, 0x00c3),
- A6XX_PROTECT_NORDWR(0x009b1, 0x0250),
- A6XX_PROTECT_RDONLY(0x00ce0, 0x0001),
- A6XX_PROTECT_RDONLY(0x00df0, 0x0000),
- A6XX_PROTECT_NORDWR(0x00df1, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e01, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e03, 0x1fff),
- A6XX_PROTECT_NORDWR(0x03c00, 0x00c5),
- A6XX_PROTECT_RDONLY(0x03cc6, 0x1fff),
- A6XX_PROTECT_NORDWR(0x08600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x08e00, 0x00ff),
- A6XX_PROTECT_RDONLY(0x08f00, 0x0000),
- A6XX_PROTECT_NORDWR(0x08f01, 0x01be),
- A6XX_PROTECT_NORDWR(0x09600, 0x01ff),
- A6XX_PROTECT_RDONLY(0x0981a, 0x02e5),
- A6XX_PROTECT_NORDWR(0x09e00, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0ae00, 0x0000),
- A6XX_PROTECT_NORDWR(0x0ae02, 0x0004),
- A6XX_PROTECT_NORDWR(0x0ae08, 0x0006),
- A6XX_PROTECT_NORDWR(0x0ae10, 0x036f),
- A6XX_PROTECT_NORDWR(0x0b600, 0x1fff),
- A6XX_PROTECT_NORDWR(0x0dc00, 0x1fff),
- A6XX_PROTECT_RDONLY(0x0fc00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x18400, 0x003f),
- A6XX_PROTECT_RDONLY(0x18440, 0x013f),
- A6XX_PROTECT_NORDWR(0x18580, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1b400, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1f400, 0x0477),
- A6XX_PROTECT_RDONLY(0x1f878, 0x0787),
- A6XX_PROTECT_NORDWR(0x1f930, 0x0329),
- A6XX_PROTECT_NORDWR(0x20000, 0x1fff),
- A6XX_PROTECT_NORDWR(0x27800, 0x007f),
- A6XX_PROTECT_RDONLY(0x27880, 0x0381),
- A6XX_PROTECT_NORDWR(0x27882, 0x0001),
- A6XX_PROTECT_NORDWR(0x27c02, 0x0000),
-};
-DECLARE_ADRENO_PROTECT(a830_protect, 64);
-
static const u32 a830_pwrup_reglist_regs[] = {
REG_A6XX_UCHE_MODE_CNTL,
REG_A8XX_UCHE_VARB_IDLE_TIMEOUT,
@@ -241,63 +189,6 @@ static const struct adreno_reglist_pipe a830_dyn_pwrup_reglist_regs[] = {
};
DECLARE_ADRENO_REGLIST_PIPE_LIST(a830_dyn_pwrup_reglist);
-static const u32 x285_protect_regs[] = {
- A6XX_PROTECT_RDONLY(0x00008, 0x039b),
- A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
- A6XX_PROTECT_NORDWR(0x00440, 0x001f),
- A6XX_PROTECT_RDONLY(0x00580, 0x005f),
- A6XX_PROTECT_NORDWR(0x005e0, 0x011f),
- A6XX_PROTECT_RDONLY(0x0074a, 0x0005),
- A6XX_PROTECT_RDONLY(0x00759, 0x0026),
- A6XX_PROTECT_RDONLY(0x00789, 0x0000),
- A6XX_PROTECT_RDONLY(0x0078c, 0x0013),
- A6XX_PROTECT_NORDWR(0x00800, 0x0029),
- A6XX_PROTECT_NORDWR(0x0082c, 0x0000),
- A6XX_PROTECT_NORDWR(0x00837, 0x00af),
- A6XX_PROTECT_RDONLY(0x008e7, 0x00c9),
- A6XX_PROTECT_NORDWR(0x008ec, 0x00c3),
- A6XX_PROTECT_NORDWR(0x009b1, 0x0250),
- A6XX_PROTECT_RDONLY(0x00ce0, 0x0001),
- A6XX_PROTECT_RDONLY(0x00df0, 0x0000),
- A6XX_PROTECT_NORDWR(0x00df1, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e01, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e03, 0x1fff),
- A6XX_PROTECT_NORDWR(0x03c00, 0x00c5),
- A6XX_PROTECT_RDONLY(0x03cc6, 0x0039),
- A6XX_PROTECT_NORDWR(0x03d00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x08600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x08e00, 0x00ff),
- A6XX_PROTECT_RDONLY(0x08f00, 0x0000),
- A6XX_PROTECT_NORDWR(0x08f01, 0x01be),
- A6XX_PROTECT_NORDWR(0x09600, 0x01ff),
- A6XX_PROTECT_RDONLY(0x0981a, 0x02e5),
- A6XX_PROTECT_NORDWR(0x09e00, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a82e, 0x0000),
- A6XX_PROTECT_NORDWR(0x0ae00, 0x0006),
- A6XX_PROTECT_NORDWR(0x0ae08, 0x0006),
- A6XX_PROTECT_NORDWR(0x0ae10, 0x00bf),
- A6XX_PROTECT_RDONLY(0x0aed0, 0x002f),
- A6XX_PROTECT_NORDWR(0x0af00, 0x027f),
- A6XX_PROTECT_NORDWR(0x0b600, 0x1fff),
- A6XX_PROTECT_NORDWR(0x0dc00, 0x1fff),
- A6XX_PROTECT_RDONLY(0x0fc00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x18400, 0x003f),
- A6XX_PROTECT_RDONLY(0x18440, 0x013f),
- A6XX_PROTECT_NORDWR(0x18580, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1b400, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1f400, 0x0477),
- A6XX_PROTECT_RDONLY(0x1f878, 0x0507),
- A6XX_PROTECT_NORDWR(0x1f930, 0x0329),
- A6XX_PROTECT_NORDWR(0x1fd80, 0x1fff),
- A6XX_PROTECT_NORDWR(0x27800, 0x007f),
- A6XX_PROTECT_RDONLY(0x27880, 0x0385),
- A6XX_PROTECT_NORDWR(0x27882, 0x000a),
- A6XX_PROTECT_NORDWR(0x27c06, 0x0000),
-};
-
-DECLARE_ADRENO_PROTECT(x285_protect, 15);
-
static const struct adreno_reglist_pipe x285_dyn_pwrup_reglist_regs[] = {
{ REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
{ REG_A8XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
@@ -336,57 +227,6 @@ static const struct adreno_reglist_pipe x285_dyn_pwrup_reglist_regs[] = {
};
DECLARE_ADRENO_REGLIST_PIPE_LIST(x285_dyn_pwrup_reglist);
-static const u32 a810_protect_regs[] = {
- A6XX_PROTECT_RDONLY(0x00000, 0x03a3),
- A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
- A6XX_PROTECT_NORDWR(0x00440, 0x001f),
- A6XX_PROTECT_RDONLY(0x00580, 0x005f),
- A6XX_PROTECT_NORDWR(0x005e0, 0x011f),
- A6XX_PROTECT_RDONLY(0x0074a, 0x0005),
- A6XX_PROTECT_RDONLY(0x00759, 0x0026),
- A6XX_PROTECT_RDONLY(0x00789, 0x0000),
- A6XX_PROTECT_RDONLY(0x0078c, 0x0013),
- A6XX_PROTECT_NORDWR(0x00800, 0x0029),
- A6XX_PROTECT_NORDWR(0x00837, 0x00af),
- A6XX_PROTECT_RDONLY(0x008e7, 0x00c9),
- A6XX_PROTECT_NORDWR(0x008ec, 0x00c3),
- A6XX_PROTECT_NORDWR(0x009b1, 0x0250),
- A6XX_PROTECT_RDONLY(0x00ce0, 0x0001),
- A6XX_PROTECT_RDONLY(0x00df0, 0x0000),
- A6XX_PROTECT_NORDWR(0x00df1, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e01, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e03, 0x1fff),
- A6XX_PROTECT_NORDWR(0x03c00, 0x00c5),
- A6XX_PROTECT_RDONLY(0x03cc6, 0x1fff),
- A6XX_PROTECT_NORDWR(0x08600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x08e00, 0x00ff),
- A6XX_PROTECT_RDONLY(0x08f00, 0x0000),
- A6XX_PROTECT_NORDWR(0x08f01, 0x01be),
- A6XX_PROTECT_NORDWR(0x09600, 0x01ff),
- A6XX_PROTECT_RDONLY(0x0981a, 0x02e5),
- A6XX_PROTECT_NORDWR(0x09e00, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0ae00, 0x0006),
- A6XX_PROTECT_NORDWR(0x0ae08, 0x0006),
- A6XX_PROTECT_NORDWR(0x0ae10, 0x036f),
- A6XX_PROTECT_NORDWR(0x0b600, 0x1fff),
- A6XX_PROTECT_NORDWR(0x0dc00, 0x1fff),
- A6XX_PROTECT_RDONLY(0x0fc00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x18400, 0x003f),
- A6XX_PROTECT_RDONLY(0x18440, 0x013f),
- A6XX_PROTECT_NORDWR(0x18580, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1b400, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1f400, 0x0477),
- A6XX_PROTECT_RDONLY(0x1f878, 0x0787),
- A6XX_PROTECT_NORDWR(0x1f930, 0x0329),
- A6XX_PROTECT_NORDWR(0x20000, 0x1fff),
- A6XX_PROTECT_NORDWR(0x27800, 0x007f),
- A6XX_PROTECT_RDONLY(0x27880, 0x0381),
- A6XX_PROTECT_NORDWR(0x27882, 0x0001),
- A6XX_PROTECT_NORDWR(0x27c02, 0x0000),
-};
-DECLARE_ADRENO_PROTECT(a810_protect, 64);
-
static const uint32_t a810_pwrup_reglist_regs[] = {
REG_A6XX_UCHE_MODE_CNTL,
REG_A8XX_UCHE_VARB_IDLE_TIMEOUT,
@@ -626,64 +466,6 @@ struct a6xx_hfi_limits_tbl x285_limits_tbl[] = {
};
DECLARE_ADRENO_LIMITS_TABLE(x285_limits);
-static const u32 a840_protect_regs[] = {
- A6XX_PROTECT_RDONLY(0x00008, 0x039b),
- A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
- A6XX_PROTECT_NORDWR(0x00440, 0x001f),
- A6XX_PROTECT_RDONLY(0x00580, 0x005f),
- A6XX_PROTECT_NORDWR(0x005e0, 0x011f),
- A6XX_PROTECT_RDONLY(0x0074a, 0x0005),
- A6XX_PROTECT_RDONLY(0x00759, 0x001b),
- A6XX_PROTECT_NORDWR(0x00775, 0x000a),
- A6XX_PROTECT_RDONLY(0x00789, 0x0000),
- A6XX_PROTECT_RDONLY(0x0078c, 0x0013),
- A6XX_PROTECT_NORDWR(0x00800, 0x0029),
- A6XX_PROTECT_NORDWR(0x00837, 0x00af),
- A6XX_PROTECT_RDONLY(0x008e7, 0x00c9),
- A6XX_PROTECT_NORDWR(0x008ec, 0x00c3),
- A6XX_PROTECT_NORDWR(0x009b1, 0x0250),
- A6XX_PROTECT_NORDWR(0x00c07, 0x0008),
- A6XX_PROTECT_RDONLY(0x00ce0, 0x0001),
- A6XX_PROTECT_RDONLY(0x00df0, 0x0000),
- A6XX_PROTECT_NORDWR(0x00df1, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e01, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e03, 0x1fff),
- A6XX_PROTECT_NORDWR(0x03c00, 0x00c5),
- A6XX_PROTECT_RDONLY(0x03cc6, 0x0039),
- A6XX_PROTECT_NORDWR(0x03d00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x08600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x08e00, 0x00ff),
- A6XX_PROTECT_RDONLY(0x08f00, 0x0000),
- A6XX_PROTECT_NORDWR(0x08f01, 0x01be),
- A6XX_PROTECT_NORDWR(0x09600, 0x01ff),
- A6XX_PROTECT_RDONLY(0x0981a, 0x02e5),
- A6XX_PROTECT_NORDWR(0x09e00, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a82e, 0x0000),
- A6XX_PROTECT_NORDWR(0x0ae00, 0x0000),
- A6XX_PROTECT_NORDWR(0x0ae02, 0x0004),
- A6XX_PROTECT_NORDWR(0x0ae08, 0x0006),
- A6XX_PROTECT_NORDWR(0x0ae10, 0x00bf),
- A6XX_PROTECT_RDONLY(0x0aed0, 0x002f),
- A6XX_PROTECT_NORDWR(0x0af00, 0x027f),
- A6XX_PROTECT_NORDWR(0x0b600, 0x1fff),
- A6XX_PROTECT_NORDWR(0x0dc00, 0x1fff),
- A6XX_PROTECT_RDONLY(0x0fc00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x18400, 0x003f),
- A6XX_PROTECT_RDONLY(0x18440, 0x013f),
- A6XX_PROTECT_NORDWR(0x18580, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1b400, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1f400, 0x0477),
- A6XX_PROTECT_RDONLY(0x1f878, 0x0507),
- A6XX_PROTECT_NORDWR(0x1f930, 0x0329),
- A6XX_PROTECT_NORDWR(0x1fd80, 0x1fff),
- A6XX_PROTECT_NORDWR(0x27800, 0x007f),
- A6XX_PROTECT_RDONLY(0x27880, 0x0385),
- A6XX_PROTECT_NORDWR(0x27882, 0x0009),
- A6XX_PROTECT_NORDWR(0x27c06, 0x0000),
-};
-DECLARE_ADRENO_PROTECT(a840_protect, 15);
-
static const struct adreno_reglist a840_gbif[] = {
{ REG_A6XX_GBIF_QSB_SIDE0, 0x00071e20 },
{ REG_A6XX_GBIF_QSB_SIDE1, 0x00071e20 },
@@ -956,67 +738,6 @@ struct a6xx_hfi_limits_tbl a840_limits_tbl[] = {
};
DECLARE_ADRENO_LIMITS_TABLE(a840_limits);
-static const u32 a850_protect_regs[] = {
- A6XX_PROTECT_RDONLY(0x00008, 0x039b),
- A6XX_PROTECT_RDONLY(0x003b4, 0x008b),
- A6XX_PROTECT_NORDWR(0x00440, 0x001f),
- A6XX_PROTECT_RDONLY(0x00580, 0x005f),
- A6XX_PROTECT_NORDWR(0x005e0, 0x011f),
- A6XX_PROTECT_RDONLY(0x0074a, 0x0005),
- A6XX_PROTECT_RDONLY(0x00759, 0x001b),
- A6XX_PROTECT_NORDWR(0x00775, 0x000a),
- A6XX_PROTECT_RDONLY(0x00789, 0x0000),
- A6XX_PROTECT_RDONLY(0x0078c, 0x0013),
- A6XX_PROTECT_NORDWR(0x00800, 0x0029),
- A6XX_PROTECT_NORDWR(0x00837, 0x00af),
- A6XX_PROTECT_RDONLY(0x008e7, 0x00c9),
- A6XX_PROTECT_NORDWR(0x008ec, 0x00c3),
- A6XX_PROTECT_NORDWR(0x009b1, 0x0250),
- A6XX_PROTECT_NORDWR(0x00c07, 0x0008),
- A6XX_PROTECT_RDONLY(0x00ce0, 0x0001),
- A6XX_PROTECT_RDONLY(0x00df0, 0x0000),
- A6XX_PROTECT_NORDWR(0x00df1, 0x0000),
- A6XX_PROTECT_NORDWR(0x00df5, 0x0003),
- A6XX_PROTECT_RDONLY(0x00df9, 0x0007),
- A6XX_PROTECT_NORDWR(0x00e01, 0x0000),
- A6XX_PROTECT_NORDWR(0x00e03, 0x1fff),
- A6XX_PROTECT_NORDWR(0x03c00, 0x00c5),
- A6XX_PROTECT_RDONLY(0x03cc6, 0x0039),
- A6XX_PROTECT_NORDWR(0x03d00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x08600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x08e00, 0x00ff),
- A6XX_PROTECT_RDONLY(0x08f00, 0x0000),
- A6XX_PROTECT_NORDWR(0x08f01, 0x01be),
- A6XX_PROTECT_NORDWR(0x09600, 0x01ff),
- A6XX_PROTECT_RDONLY(0x0981a, 0x02e5),
- A6XX_PROTECT_NORDWR(0x09e00, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a600, 0x01ff),
- A6XX_PROTECT_NORDWR(0x0a82e, 0x0000),
- A6XX_PROTECT_NORDWR(0x0ae00, 0x0000),
- A6XX_PROTECT_NORDWR(0x0ae02, 0x0004),
- A6XX_PROTECT_NORDWR(0x0ae08, 0x0006),
- A6XX_PROTECT_NORDWR(0x0ae10, 0x00bf),
- A6XX_PROTECT_RDONLY(0x0aed0, 0x002f),
- A6XX_PROTECT_NORDWR(0x0af00, 0x027f),
- A6XX_PROTECT_NORDWR(0x0b600, 0x1fff),
- A6XX_PROTECT_NORDWR(0x0dc00, 0x1fff),
- A6XX_PROTECT_RDONLY(0x0fc00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x18400, 0x003f),
- A6XX_PROTECT_RDONLY(0x18440, 0x013f),
- A6XX_PROTECT_NORDWR(0x18580, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1ac00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1cc00, 0x1fff),
- A6XX_PROTECT_NORDWR(0x1f400, 0x0477),
- A6XX_PROTECT_RDONLY(0x1f878, 0x0507),
- A6XX_PROTECT_NORDWR(0x1f930, 0x0329),
- A6XX_PROTECT_NORDWR(0x1fd80, 0x1fff),
- A6XX_PROTECT_NORDWR(0x27800, 0x007f),
- A6XX_PROTECT_RDONLY(0x27880, 0x0385),
- A6XX_PROTECT_NORDWR(0x27882, 0x0035),
- A6XX_PROTECT_NORDWR(0x27c06, 0x0000),
-};
-DECLARE_ADRENO_PROTECT(a850_protect, 15);
-
static const u32 a850_pwrup_reglist_regs[] = {
REG_A8XX_RB_CMP_NC_MODE_CNTL,
REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN,
@@ -1215,7 +936,7 @@ static const struct adreno_info a8xx_gpus[] = {
ADRENO_QUIRK_IFPC,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
- .protect = &a830_protect,
+ .protect = &pakala_protect,
.nonctxt_reglist = pakala_nonctxt_regs,
.pwrup_reglist = &a830_pwrup_reglist,
.dyn_pwrup_reglist = &a830_dyn_pwrup_reglist,
@@ -1260,7 +981,7 @@ static const struct adreno_info a8xx_gpus[] = {
ADRENO_QUIRK_SOFTFUSE,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
- .protect = &x285_protect,
+ .protect = &glymur_protect,
.nonctxt_reglist = glymur_nonctxt_regs,
.pwrup_reglist = &a840_pwrup_reglist,
.dyn_pwrup_reglist = &x285_dyn_pwrup_reglist,
@@ -1305,7 +1026,7 @@ static const struct adreno_info a8xx_gpus[] = {
ADRENO_QUIRK_IFPC,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
- .protect = &a840_protect,
+ .protect = &pakala_protect,
.nonctxt_reglist = kaanapali_nonctxt_regs,
.pwrup_reglist = &a840_pwrup_reglist,
.dyn_pwrup_reglist = &a840_dyn_pwrup_reglist,
@@ -1351,7 +1072,7 @@ static const struct adreno_info a8xx_gpus[] = {
.funcs = &a8xx_gpu_funcs,
.zapfw = "gen80300_zap.mbn",
.a6xx = &(const struct a6xx_info) {
- .protect = &a810_protect,
+ .protect = &milos_protect,
.nonctxt_reglist = milos_nonctxt_regs,
.pwrup_reglist = &a810_pwrup_reglist,
.dyn_pwrup_reglist = &a810_dyn_pwrup_reglist,
@@ -1394,7 +1115,7 @@ static const struct adreno_info a8xx_gpus[] = {
ADRENO_QUIRK_SOFTFUSE,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
- .protect = &x285_protect,
+ .protect = &glymur_protect,
.nonctxt_reglist = glymur_nonctxt_regs,
.pwrup_reglist = &a840_pwrup_reglist,
.dyn_pwrup_reglist = &x285_dyn_pwrup_reglist,
@@ -1437,7 +1158,7 @@ static const struct adreno_info a8xx_gpus[] = {
ADRENO_QUIRK_IFPC,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
- .protect = &a850_protect,
+ .protect = &maili_protect,
.nonctxt_reglist = maili_nonctxt_regs,
.pwrup_reglist = &a850_pwrup_reglist,
.dyn_pwrup_reglist = &a850_dyn_pwrup_reglist,
@@ -1481,7 +1202,7 @@ static const struct adreno_info a8xx_gpus[] = {
ADRENO_QUIRK_IFPC,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
- .protect = &a850_protect,
+ .protect = &hawi_protect,
.nonctxt_reglist = hawi_nonctxt_regs,
.pwrup_reglist = &a850_pwrup_reglist,
.dyn_pwrup_reglist = &a850_dyn_pwrup_reglist,
@@ -1516,6 +1237,10 @@ DECLARE_ADRENO_GPULIST(a8xx);
static inline __always_unused void __build_asserts(void)
{
- BUILD_BUG_ON(a810_protect.count > a810_protect.count_max);
- BUILD_BUG_ON(a830_protect.count > a830_protect.count_max);
+ BUILD_BUG_ON(glymur_protect.count > glymur_protect.count_max);
+ BUILD_BUG_ON(hawi_protect.count > hawi_protect.count_max);
+ BUILD_BUG_ON(kaanapali_protect.count > kaanapali_protect.count_max);
+ BUILD_BUG_ON(maili_protect.count > maili_protect.count_max);
+ BUILD_BUG_ON(milos_protect.count > milos_protect.count_max);
+ BUILD_BUG_ON(pakala_protect.count > pakala_protect.count_max);
}
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 12/12] drm/msm/adreno: Remove temporary __maybe_unused
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
` (9 preceding siblings ...)
2026-10-20 20:46 ` [PATCH 11/12] drm/msm/a8xx: Switch to generated protect regs Rob Clark
@ 2026-10-20 20:46 ` Rob Clark
10 siblings, 0 replies; 15+ messages in thread
From: Rob Clark @ 2026-10-20 20:46 UTC (permalink / raw)
To: dri-devel
Cc: linux-arm-msm, freedreno, Alexander Koskovich, Jie Zhang,
Akhil P Oommen, Bhaskar Reddy Valluru, Rob Clark, Sean Paul,
Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Marijn Suijten, David Airlie, Simona Vetter, open list
Now that is unneeded.
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index ed83dd927b54..3ef3ac2d86f9 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -170,7 +170,7 @@ struct adreno_protect {
};
#define DECLARE_ADRENO_PROTECT(name, __count_max) \
-static const struct adreno_protect name __maybe_unused = { \
+static const struct adreno_protect name = { \
.regs = name ## _regs, \
.count = ARRAY_SIZE(name ## _regs), \
.count_max = __count_max, \
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 09/12] drm/msm/a8xx: devcoredump state capture support
2026-10-20 20:46 ` [PATCH 09/12] drm/msm/a8xx: devcoredump state capture support Rob Clark
@ 2026-10-20 23:13 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-20 23:13 UTC (permalink / raw)
To: Rob Clark, dri-devel
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] drm/msm/a8xx: wrong GX power check and early GX read in a8xx_gpu_state_get()
- [High] drm/msm/a8xx: off-by-one slice ID and ignored error in gen8_snapshot_mempool()
- [Medium] drm/msm/a8xx: unrestored DBGC config after gen8_debugbus_internal_read_setup()
- [Medium] drm/msm/a8xx: hardcoded context 0 in gen8_snapshot_dbgahb_regs() SP_READ_SEL
- [Medium] drm/msm/a8xx: broken host aperture setup in legacy AHB snapshot helpers
- [Low] drm/msm/a8xx: 32-bit GENMASK(63, 44) overflow in CD_WRITE() and CD_READ()
--
commit 2b161a7f68dabf614abb5d253ffd0443bf998e9b
Author: Rob Clark <robin.clark@oss.qualcomm.com>
drm/msm/a8xx: devcoredump state capture support
This commit adds devcoredump GPU state capture and crashdumper support for
Adreno A8xx (Gen8) GPUs, along with snapshot section helpers in
adreno_snapshot.h.
> diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c
> new file mode 100644
> index 0000000000000..e4eb2f335a890
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c
> @@ -0,0 +1,1253 @@
[ ... ]
> +static void gen8_legacy_snapshot_registers(struct msm_gpu *gpu,
> + struct adreno_gpu_state *state,
> + const struct gen8_reg_list *regs,
> + u32 slice_id)
> +{
> + int count;
> +
> + /* Figure out how many registers we are going to dump */
> + count = adreno_snapshot_regs_count(regs->regs);
> +
> + snapshot_sect (state, MVC_V3, 4 * count, {
> + .ctxt_id = 0,
> + .cluster_id = CLUSTER_NONE,
> + .pipe_id = PIPE_NONE,
> + .location_id = UINT_MAX,
> + .sp_id = UINT_MAX,
> + .usptp_id = UINT_MAX,
> + .slice_id = HEADER_SLICE_ID(regs->slice_region, slice_id),
> + }) {
> + unsigned long flags;
> +
> + if (regs->sel)
> + gpu_write(gpu, regs->sel->host_reg, regs->sel->val);
> +
> + if (regs->slice_region)
> + a8xx_aperture_acquire_slice(gpu, PIPE_NONE, slice_id, false, &flags);
> +
> + /* Make sure the previous writes are posted before reading */
> + mb();
> +
> + for (const u32 *ptr = regs->regs; ptr[0] != UINT_MAX; ptr += 2) {
> + snapshot_mvc_regs_v3_subheader(§, ptr);
> +
> + for (int k = ptr[0]; k <= ptr[1]; k++) {
> + snapshot_sect_u32(§, reg_read(gpu, k));
> + }
> + }
> +
> + if (regs->slice_region)
> + a8xx_aperture_release(gpu, flags);
> + }
> +}
[ ... ]
> +static bool gen8_snapshot_mempool(struct msm_gpu *gpu,
> + struct adreno_gpu_state *state,
> + struct adreno_crashdumper *dumper)
> +{
> + const struct gen8_snapshot_block_list *b = block_list(gpu);
> + u32 slice_mask = to_a6xx_gpu(to_adreno_gpu(gpu))->slice_mask;
> + u32 first_slice = ffs(slice_mask);
> +
> + for (int i = 0; i < b->mempool_index_registers_len; i++) {
> + const struct gen8_cp_indexed_reg *cp_indexed_reg =
> + &b->mempool_index_registers[i];
> + unsigned long flags;
> + u32 j;
> +
> + FOR_EACH_SLICE (j, cp_indexed_reg->slice_region, slice_mask) {
> +
> + /* TODO: Remove hardcoded values */
> + /* Set CP_CHICKEN_DBG[StabilizeMVC] to stabilize it while dumping */
> + a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, first_slice, false, &flags);
> + gpu_rmw(gpu, REG_A8XX_CP_CHICKEN_DBG_PIPE, BIT(2), BIT(2));
> + a8xx_aperture_release(gpu, flags);
> +
> + a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, j, true, &flags);
> + gpu_rmw(gpu, REG_A8XX_CP_SLICE_CHICKEN_DBG_PIPE, BIT(2), BIT(2));
> + a8xx_aperture_release(gpu, flags);
> +
> + gen8_snapshot_indexed_registers(gpu, state, dumper,
> + cp_indexed_reg->addr,
> + cp_indexed_reg->data, 0,
> + cp_indexed_reg->size,
> + cp_indexed_reg->pipe_id,
> + HEADER_SLICE_ID(cp_indexed_reg->slice_region, j));
> +
> + /* Reset CP_CHICKEN_DBG[StabilizeMVC] once we are done */
> + a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, first_slice, false, &flags);
> + gpu_rmw(gpu, REG_A8XX_CP_CHICKEN_DBG_PIPE, BIT(2), 0);
> + a8xx_aperture_release(gpu, flags);
> +
> + a8xx_aperture_acquire_slice(gpu, cp_indexed_reg->pipe_id, j, true, &flags);
> + gpu_rmw(gpu, REG_A8XX_CP_SLICE_CHICKEN_DBG_PIPE, BIT(2), 0);
> + a8xx_aperture_release(gpu, flags);
> + }
> + }
> +
> + /* Clear aperture register */
> + a8xx_aperture_clear(gpu);
> +
> + return true;
> +}
[Severity: High]
In drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c, when a8xx_gpu_state_get()
calls gen8_snapshot_mempool(), first_slice is computed as ffs(slice_mask).
Because ffs() returns a 1-based bit index (unlike a8xx_get_first_slice() in
drivers/gpu/drm/msm/adreno/a8xx_gpu.c, which uses ffs(a6xx_gpu->slice_mask) -
1), passing first_slice to a8xx_aperture_acquire_slice() before modifying
REG_A8XX_CP_CHICKEN_DBG_PIPE programs an off-by-one slice ID. On a 1-slice
GPU such as Milos (where slice_mask is 0x1) or when slice ffs(slice_mask) is
fused off in slice_mask, this selects a non-existent or harvested slice.
In addition, for UNSLICE entries in b->mempool_index_registers, FOR_EACH_SLICE
sets j = 0 regardless of slice_mask, and gen8_snapshot_mempool() still
programs the aperture for slice j = 0 with use_slice = true to modify
REG_A8XX_CP_SLICE_CHICKEN_DBG_PIPE even if slice 0 is fused off.
Finally, gen8_snapshot_mempool() ignores the return value of
gen8_snapshot_indexed_registers() and always returns true. If the crashdumper
times out during mempool capture, a8xx_gpu_state_get() will not bail out via
goto out and will continue issuing register accesses.
Should first_slice be ffs(slice_mask) - 1, should
REG_A8XX_CP_SLICE_CHICKEN_DBG_PIPE only be accessed when
cp_indexed_reg->slice_region == SLICE, and should gen8_snapshot_mempool()
propagate failures from gen8_snapshot_indexed_registers()?
> +static void gen8_legacy_snapshot_mvc(struct msm_gpu *gpu,
> + struct adreno_gpu_state *state,
> + const struct gen8_cluster_registers *cluster,
> + u32 slice_id)
> +{
> + int count;
> +
> + /* Figure out how many registers we are going to dump */
> + count = adreno_snapshot_regs_count(cluster->regs);
> +
> + snapshot_sect (state, MVC_V3, 4 * count, {
> + .ctxt_id = (cluster->context_id == STATE_FORCE_CTXT_1) ? 1 : 0,
> + .cluster_id = cluster->cluster_id,
> + .pipe_id = cluster->pipe_id,
> + .location_id = UINT_MAX,
> + .sp_id = UINT_MAX,
> + .usptp_id = UINT_MAX,
> + .slice_id = HEADER_SLICE_ID(cluster->slice_region, slice_id),
> + }) {
> + unsigned long flags;
> +
> + /*
> + * Set the AHB control for the Host to read from the
> + * cluster/context for this iteration.
> + */
> + a8xx_aperture_acquire_slice(gpu, cluster->pipe_id, slice_id, true, &flags);
> +
> + if (cluster->sel)
> + gpu_write(gpu, cluster->sel->host_reg, cluster->sel->val);
> +
> + /* Make sure the previous writes are posted before reading */
> + mb();
> +
> + for (const u32 *ptr = cluster->regs; ptr[0] != UINT_MAX; ptr += 2) {
> + snapshot_mvc_regs_v3_subheader(§, ptr);
> +
> + for (int k = ptr[0]; k <= ptr[1]; k++) {
> + snapshot_sect_u32(§, reg_read(gpu, k));
> + }
> + }
> +
> + a8xx_aperture_release(gpu, flags);
> + }
> +}
[Severity: Medium]
Does the host aperture programming in gen8_legacy_snapshot_mvc() and
gen8_legacy_snapshot_registers() in
drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c match what the hardware expects
when dumping registers over AHB (for b->pre_crashdumper_regs and when dumper
is NULL, such as during an SMMU stall fault)?
1. In gen8_legacy_snapshot_mvc(), calling a8xx_aperture_acquire_slice() only
programs PIPEID, SLICEID, and USESLICEID in REG_A8XX_CP_APERTURE_CNTL_HOST,
leaving CLUSTERID and CONTEXTID3D as 0 (whereas the crashdumper path in
gen8_snapshot_mvc_regs() writes cluster->cluster_id and cluster->context_id
via GEN8_CP_APERTURE_REG_VAL()). All cluster and context-banked MVC registers
read on the CPU fallback path will therefore read cluster 0 and context 0.
2. In gen8_legacy_snapshot_registers():
if (regs->sel)
gpu_write(gpu, regs->sel->host_reg, regs->sel->val);
if (regs->slice_region)
a8xx_aperture_acquire_slice(gpu, PIPE_NONE, slice_id, false, &flags);
regs->sel->host_reg is written before acquiring the aperture lock or setting
the slice, a8xx_aperture_acquire_slice() is called with use_slice = false
instead of true for SLICE regions (omitting
A8XX_CP_APERTURE_CNTL_HOST_USESLICEID), and when a subsequent region has
regs->slice_region == UNSLICE, the aperture is not cleared or updated, leaving
the previous slice selected.
3. Because a8xx_aperture_release() only drops a6xx_gpu->aperture_lock without
clearing REG_A8XX_CP_APERTURE_CNTL_HOST, and the out: path in
a8xx_gpu_state_get() does not call a8xx_aperture_clear(gpu), a CPU-fallback
state capture during a non-reset SMMU stall fault leaves
REG_A8XX_CP_APERTURE_CNTL_HOST and a6xx_gpu->cached_aperture dirty for
subsequent host register accesses.
[ ... ]
> +static void gen8_legacy_snapshot_cluster_dbgahb(
> + struct msm_gpu *gpu, struct adreno_gpu_state *state,
> + const struct gen8_sptp_cluster_registers *cluster,
> + u32 sp, u32 usptp, u32 slice_id)
> +{
> + int count;
> +
> + /* Figure out how many registers we are going to dump */
> + count = adreno_snapshot_regs_count(cluster->regs);
> +
> + snapshot_sect (state, MVC_V3, 4 * count, {
> + .ctxt_id = cluster->context_id,
> + .cluster_id = cluster->cluster_id,
> + .pipe_id = cluster->pipe_id,
> + .location_id = cluster->location_id,
> + .sp_id = sp,
> + .usptp_id = usptp,
> + .slice_id = HEADER_SLICE_ID(cluster->slice_region, slice_id),
> + }) {
> + u32 read_sel = GEN8_SP_READ_SEL_VAL(
> + 0, slice_id, cluster->location_id, cluster->pipe_id,
> + cluster->statetype, usptp, sp);
> +
> + gpu_write(gpu, REG_A7XX_SP_READ_SEL, read_sel);
[ ... ]
> +static bool gen8_snapshot_dbgahb_regs(struct msm_gpu *gpu,
> + struct adreno_gpu_state *state,
> + struct adreno_crashdumper *dumper)
> +{
[ ... ]
> + /* Build the crash script */
> + struct cd_script p = CD_INIT(dumper);
> +
> + u32 read_sel = GEN8_SP_READ_SEL_VAL(
> + 0, slice_id, cluster->location_id,
> + cluster->pipe_id, cluster->statetype,
> + usptp, sp);
> +
> + /* Program the aperture */
> + CD_WRITE(&p, REG_A7XX_SP_READ_SEL, read_sel);
[Severity: Medium]
In drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c, both
gen8_legacy_snapshot_cluster_dbgahb() and gen8_snapshot_dbgahb_regs() record
.ctxt_id = cluster->context_id in the MVC_V3 section header, but pass a
hardcoded 0 instead of cluster->context_id as the first argument (_contextid)
to GEN8_SP_READ_SEL_VAL() when programming REG_A7XX_SP_READ_SEL.
For multi-context SPTP cluster entries in the A8xx snapshot tables (where
cluster->context_id ranges from 0 to 15), won't this repeatedly dump context 0
for every context section?
[ ... ]
> +static void gen8_debugbus_internal_read_setup(struct msm_gpu *gpu)
> +{
> + /* Clear the DBGC logic/events */
> + gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM, 0x70000000);
> +
> + /* Enable the internal buffer mode and program to tail mode */
> + gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_OPL, 0x28000000);
> +
> + /* Program the logic unit 0 to high when the side data is 1 */
> + gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0, 0x0000000c);
> + gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0, 0x000000f0);
> +
> + /* Enable the DBGC logic/events */
> + gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM, 0x07000000);
> +}
[ ... ]
> +static void gen8_snapshot_cx_dbgc_debugbus_block(
> + struct msm_gpu *gpu, uint32_t block_id, size_t count,
> + struct adreno_snapshot_sect *sect)
> +{
> + /* This block requires an out of order access due to a HW limitation.
> + * (QCTDD12240539)
> + */
> + if (block_id == DEBUGBUS_CX_GC_US_I_0) {
> + static u32 data[GEN8_DEBUGBUS_BLOCK_SIZE * 2];
> + gen8_debugbus_internal_read_setup(gpu);
> + for (int i = 0; i < GEN8_DEBUGBUS_BLOCK_IDX_1; i++)
> + gen8_cx_gc_us_i_0_debugbus_read(gpu, block_id, i, &data[i * 2]);
> + for (int i = GEN8_DEBUGBUS_BLOCK_IDX_2; i < GEN8_DEBUGBUS_BLOCK_SIZE; i++)
> + gen8_cx_gc_us_i_0_debugbus_read(gpu, block_id, i, &data[i * 2]);
> + for (int i = GEN8_DEBUGBUS_BLOCK_IDX_1; i < GEN8_DEBUGBUS_BLOCK_IDX_2; i++)
> + gen8_cx_gc_us_i_0_debugbus_read(gpu, block_id, i, &data[i * 2]);
> + snapshot_sect_arr(sect, data);
> + } else {
> + for (int i = 0; i < count; i++) {
> + u32 data[2];
> + gen8_cx_debug_bus_read(gpu, block_id, i, data);
> + snapshot_sect_arr(sect, data);
> + }
> + }
> +}
[Severity: Medium]
In drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c, gen8_get_debugbus() programs
the initial debugbus configuration into REG_A6XX_DBGC_CFG_DBGBUS_CNTLT,
REG_A6XX_DBGC_CFG_DBGBUS_CNTLM, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_0..3,
REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0..1, and REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0..3
before iterating through b->debugbus_blocks[] and b->gbif_debugbus_blocks[].
When gen8_snapshot_cx_dbgc_debugbus_block() encounters DEBUGBUS_CX_GC_US_I_0
(at index 2 of b->debugbus_blocks[] in the A8xx snapshot tables), it calls
gen8_debugbus_internal_read_setup(), which overwrites
REG_A6XX_DBGC_CFG_DBGBUS_CNTLM, REG_A6XX_DBGC_CFG_DBGBUS_OPL,
REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0, and REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0 for
internal buffer mode.
Because those registers are not restored after reading DEBUGBUS_CX_GC_US_I_0,
won't all subsequent blocks in b->debugbus_blocks[] and
b->gbif_debugbus_blocks[] be read with the internal buffer mode configuration
still active?
[ ... ]
> +struct msm_gpu_state *a8xx_gpu_state_get(struct msm_gpu *gpu)
> +{
> + const struct gen8_snapshot_block_list *b = block_list(gpu);
> + struct adreno_crashdumper _dumper = { 0 }, *dumper = NULL;
> + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
> + struct adreno_gpu_state *state;
> + // TODO need to get status from SMMU on some gen8..
> + bool stalled = !!(gpu_read(gpu, REG_A8XX_RBBM_MISC_STATUS) &
> + A8XX_RBBM_MISC_STATUS_SMMU_STALLED_ON_FAULT);
> +
> + if (!b)
> + return NULL;
> +
> + state = kzalloc_obj(*state);
> + if (!state)
> + return ERR_PTR(-ENOMEM);
> +
> + INIT_LIST_HEAD(&state->objs);
> +
> + /* Get the generic state from the adreno core */
> + adreno_gpu_state_get(gpu, &state->base);
> +
> + adreno_snapshot_registers_v2(gpu, state, b->gmu_cx_unsliced_regs);
> +
> + a8xx_snapshot_gmu_bo(state, &a6xx_gpu->gmu.log, SNAPSHOT_GMU_MEM_LOG);
> + a8xx_snapshot_gmu_bo(state, &a6xx_gpu->gmu.hfi, SNAPSHOT_GMU_MEM_HFI);
> + a8xx_snapshot_gmu_bo(state, &a6xx_gpu->gmu.debug, SNAPSHOT_GMU_MEM_DEBUG);
> +
> + a8xx_snapshot_gmu_hfi_history(gpu, state);
> +
> + /* If GX isn't on the rest of the data isn't going to be accessible */
> + if (!a6xx_gmu_gx_is_on(adreno_gpu))
> + return &state->base;
[Severity: High]
Can this cause unclocked or unpowered register accesses in
a8xx_gpu_state_get() in drivers/gpu/drm/msm/adreno/a8xx_gpu_state.c when state
capture is triggered via debugfs or fault/hang recovery while GX (or GMU MX on
A850) is powered off?
First, at the top of a8xx_gpu_state_get(), REG_A8XX_RBBM_MISC_STATUS is read
before checking whether GX is powered on, even though stalled is only used
after the GX power check.
Second, the GX power check calls a6xx_gmu_gx_is_on(adreno_gpu) instead of
adreno_gpu->funcs->gx_is_on(adreno_gpu) (which points to a8xx_gmu_gx_is_on()).
In drivers/gpu/drm/msm/adreno/a6xx_gmu.c:
bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu)
{
...
if (adreno_is_a850_family(adreno_gpu)) {
val = a6xx_cx_misc_read(a6xx_gpu, REG_A8XX_CX_MISC_GFX_PWR_CLK_STATUS);
return !(val &
(A8XX_CX_MISC_GFX_PWR_CLK_STATUS_GX_GDSC_POWER_OFF |
A8XX_CX_MISC_GFX_PWR_CLK_STATUS_GX_CLK_OFF));
}
val = gmu_read(gmu, REG_A8XX_GMU_PWR_CLK_STATUS);
return !(val &
(A8XX_GMU_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF |
A8XX_GMU_PWR_CLK_STATUS_GX_HM_CLK_OFF));
}
Calling a6xx_gmu_gx_is_on() reads REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS (an
A6xx/A7xx register that is not valid on A8xx and accesses GMU MMIO even when
GMU MX is off on A850) and checks the wrong bits, allowing
a8xx_gpu_state_get() to proceed with GX register accesses when GX is powered
off.
[ ... ]
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
> index f9956e0bc1d5f..e8ff102a628b7 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
> +++ b/drivers/gpu/drm/msm/adreno/adreno_snapshot.h
[ ... ]
> +static inline void CD_WRITE(struct cd_script *p, u32 reg, u32 val)
> +{
> + *(p->in++) = val;
> + *(p->in++) = FIELD_PREP(GENMASK(63, 44), reg) | BIT(21) | BIT(0);
> + __cd_check_overflow(p);
> +}
> +
> +static inline void CD_READ(struct cd_script *p, u32 reg, u32 dwords)
> +{
> + *(p->in++) = p->out;
> + *(p->in++) = FIELD_PREP(GENMASK(63, 44), reg) | dwords;
> + p->out += sizeof(u32) * dwords;
> + __cd_check_overflow(p);
> +}
[Severity: Low]
In drivers/gpu/drm/msm/adreno/adreno_snapshot.h, CD_WRITE() and CD_READ() use
GENMASK(63, 44) to build a 64-bit value for u64 *in. On 32-bit architectures
(such as 32-bit ARM builds with CONFIG_DRM_MSM and CONFIG_DRM_MSM_GPU_STATE
enabled), GENMASK() uses unsigned long (32-bit), which overflows the shift
count and triggers a BUILD_BUG_ON_MSG() failure in FIELD_PREP(). Should these
use GENMASK_ULL(63, 44) instead?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020204728.28844-1-robin.clark@oss.qualcomm.com?part=9
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 10/12] drm/msm/a8xx: Switch to generated nonctx regs
2026-10-20 20:46 ` [PATCH 10/12] drm/msm/a8xx: Switch to generated nonctx regs Rob Clark
@ 2026-10-20 23:32 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-20 23:32 UTC (permalink / raw)
To: Rob Clark, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] drm/msm/a8xx: a8xx_nonctxt_config() clobbers LLCC SCID in GBIF_SCACHE_CNTL0
- [Medium] drm/msm/a8xx: nonctxt_reglist clobbers CX GBIF config in a8xx_nonctxt_config()
--
commit 966abf648e13ba76b4165851da9f6e5975e5c769
Author: Rob Clark <robin.clark@oss.qualcomm.com>
drm/msm/a8xx: Switch to generated nonctx regs
This commit removes the hand-maintained non-context register tables in
drivers/gpu/drm/msm/adreno/a8xx_catalog.c and switches the A8xx GPU catalog
entries to use the generated non-context register lists from the catalog
headers.
> diff --git a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
> index 15fc10d5db688..bc79013165c13 100644
> --- a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
> +++ b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
[ ... ]
> @@ -1556,7 +1216,7 @@ static const struct adreno_info a8xx_gpus[] = {
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> .protect = &a830_protect,
> - .nonctxt_reglist = a830_nonctxt_regs,
> + .nonctxt_reglist = pakala_nonctxt_regs,
> .pwrup_reglist = &a830_pwrup_reglist,
> .dyn_pwrup_reglist = &a830_dyn_pwrup_reglist,
> .ifpc_reglist = &a830_ifpc_reglist,
[Severity: Medium]
Will switching .nonctxt_reglist in a8xx_gpus to pakala_nonctxt_regs (and the
other generated *_nonctxt_regs tables) cause a8xx_nonctxt_config() to clobber
the LLCC slice IDs in REG_A6XX_GBIF_SCACHE_CNTL0?
In drivers/gpu/drm/msm/adreno/catalog/adreno_pakala.h (as well as the
glymur_nonctxt_regs, kaanapali_nonctxt_regs, milos_nonctxt_regs,
maili_nonctxt_regs, and hawi_nonctxt_regs tables), the generated list
includes:
{ 0x00003c01 /* GBIF_SCACHE_CNTL0 */, 0x00000100, BIT(PIPE_NONE) },
On initial GPU load (adreno_load_gpu()), job submission after runtime suspend
(msm_gpu_submit()), or recovery (a8xx_recover()), pm_runtime_get_sync() runs
adreno_runtime_resume() -> a6xx_gmu_pm_resume() in
drivers/gpu/drm/msm/adreno/a6xx_gpu.c:
gpu->needs_hw_init = true;
...
if (adreno_is_a8xx(adreno_gpu))
a8xx_llc_activate(a6xx_gpu);
In drivers/gpu/drm/msm/adreno/a8xx_gpu.c, a8xx_llc_activate() programs the
system cache slice ID into REG_A6XX_GBIF_SCACHE_CNTL0 (0x3c01):
gpu_write(gpu, REG_A6XX_GBIF_SCACHE_CNTL0,
FIELD_PREP(GENMASK(27, 22), gpu_scid) |
FIELD_PREP(GENMASK(21, 16), gpu_scid) |
FIELD_PREP(GENMASK(15, 10), gpu_scid) |
BIT(8));
Immediately afterwards, msm_gpu_hw_init() sees gpu->needs_hw_init == true and
calls a8xx_hw_init() -> hw_init() -> a8xx_nonctxt_config(), which executes:
gpu_write(gpu, regs[i].offset, regs[i].value);
Because 0x00003c01 is in info->nonctxt_reglist with value 0x00000100,
wouldn't this overwrite REG_A6XX_GBIF_SCACHE_CNTL0 and zero out the gpu_scid
fields in bits [27:10] on every hardware init?
> @@ -1601,7 +1261,7 @@ static const struct adreno_info a8xx_gpus[] = {
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> .protect = &x285_protect,
> - .nonctxt_reglist = x285_nonctxt_regs,
> + .nonctxt_reglist = glymur_nonctxt_regs,
> .pwrup_reglist = &a840_pwrup_reglist,
> .dyn_pwrup_reglist = &x285_dyn_pwrup_reglist,
> .ifpc_reglist = &a840_ifpc_reglist,
> @@ -1646,7 +1306,7 @@ static const struct adreno_info a8xx_gpus[] = {
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> .protect = &a840_protect,
> - .nonctxt_reglist = a840_nonctxt_regs,
> + .nonctxt_reglist = kaanapali_nonctxt_regs,
> .pwrup_reglist = &a840_pwrup_reglist,
> .dyn_pwrup_reglist = &a840_dyn_pwrup_reglist,
> .ifpc_reglist = &a840_ifpc_reglist,
> @@ -1692,7 +1352,7 @@ static const struct adreno_info a8xx_gpus[] = {
> .zapfw = "gen80300_zap.mbn",
> .a6xx = &(const struct a6xx_info) {
> .protect = &a810_protect,
> - .nonctxt_reglist = a810_nonctxt_regs,
> + .nonctxt_reglist = milos_nonctxt_regs,
> .pwrup_reglist = &a810_pwrup_reglist,
> .dyn_pwrup_reglist = &a810_dyn_pwrup_reglist,
> .ifpc_reglist = &a810_ifpc_reglist,
> @@ -1735,7 +1395,7 @@ static const struct adreno_info a8xx_gpus[] = {
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> .protect = &x285_protect,
> - .nonctxt_reglist = x285_nonctxt_regs,
> + .nonctxt_reglist = glymur_nonctxt_regs,
> .pwrup_reglist = &a840_pwrup_reglist,
> .dyn_pwrup_reglist = &x285_dyn_pwrup_reglist,
> .ifpc_reglist = &a840_ifpc_reglist,
> @@ -1778,7 +1438,7 @@ static const struct adreno_info a8xx_gpus[] = {
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> .protect = &a850_protect,
> - .nonctxt_reglist = a845_nonctxt_regs,
> + .nonctxt_reglist = maili_nonctxt_regs,
> .pwrup_reglist = &a850_pwrup_reglist,
> .dyn_pwrup_reglist = &a850_dyn_pwrup_reglist,
> .ifpc_reglist = &a850_ifpc_reglist,
> @@ -1822,7 +1482,7 @@ static const struct adreno_info a8xx_gpus[] = {
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> .protect = &a850_protect,
> - .nonctxt_reglist = a850_nonctxt_regs,
> + .nonctxt_reglist = hawi_nonctxt_regs,
> .pwrup_reglist = &a850_pwrup_reglist,
> .dyn_pwrup_reglist = &a850_dyn_pwrup_reglist,
> .ifpc_reglist = &a850_ifpc_reglist,
[Severity: Medium]
Should the CX GBIF registers (0x3c00..0x3c45) in the generated *_nonctxt_regs
tables also be excluded or handled separately in a8xx_nonctxt_config()?
Unlike the previous hand-maintained nonctxt_regs arrays in
drivers/gpu/drm/msm/adreno/a8xx_catalog.c, all six generated *_nonctxt_regs
tables include CX GBIF entries:
{ 0x00003c00 /* GBIF_CX_CONFIG */, 0x20023020, BIT(PIPE_NONE) },
{ 0x00003c01 /* GBIF_SCACHE_CNTL0 */, 0x00000100, BIT(PIPE_NONE) },
{ 0x00003c03 /* GBIF_QSB_SIDE0 */, 0x00071e20, BIT(PIPE_NONE) },
{ 0x00003c04 /* GBIF_QSB_SIDE1 */, 0x00071e20, BIT(PIPE_NONE) },
{ 0x00003c05 /* GBIF_QSB_SIDE2 */, 0x00071e20, BIT(PIPE_NONE) },
{ 0x00003c06 /* GBIF_QSB_SIDE3 */, 0x00071e20, BIT(PIPE_NONE) },
{ 0x00003c45 /* GBIF_HALT */, 0x00000008, BIT(PIPE_NONE) },
During resume, a6xx_gmu_pm_resume() -> a6xx_gmu_resume() ->
a6xx_gmu_fw_start() configures gbif_cx and boots the GMU (which enables clock
gating in REG_A6XX_GBIF_CX_CONFIG BIT(0), as noted in a8xx_set_hwcg() in
drivers/gpu/drm/msm/adreno/a8xx_gpu.c):
/*
* GMU enables clk gating in GBIF during boot up. So,
* override that here when hwcg feature is disabled
*/
gpu_rmw(gpu, REG_A6XX_GBIF_CX_CONFIG, BIT(0), 0);
Then in drivers/gpu/drm/msm/adreno/a8xx_gpu.c, hw_init() explicitly clears
REG_A6XX_GBIF_HALT before calling a8xx_nonctxt_config():
/* Clear GBIF halt in case GX domain was not collapsed */
gpu_write(gpu, REG_A6XX_GBIF_HALT, 0);
gpu_read(gpu, REG_A6XX_GBIF_HALT);
...
a8xx_nonctxt_config(gpu);
When a8xx_nonctxt_config() subsequently writes the generated nonctxt_reglist,
could writing 0x20023020 to REG_A6XX_GBIF_CX_CONFIG (0x3c00) clear BIT(0)
that the GMU enabled on boot, and could writing 0x00000008 to
REG_A6XX_GBIF_HALT (0x3c45) undo the earlier clear in hw_init() in addition
to overwriting REG_A6XX_GBIF_SCACHE_CNTL0 (0x3c01)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020204728.28844-1-robin.clark@oss.qualcomm.com?part=10
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 11/12] drm/msm/a8xx: Switch to generated protect regs
2026-10-20 20:46 ` [PATCH 11/12] drm/msm/a8xx: Switch to generated protect regs Rob Clark
@ 2026-10-20 23:41 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-20 23:41 UTC (permalink / raw)
To: Rob Clark, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] drm/msm/a8xx: wrong protect table pakala_protect used for Kaanapali
- [High] drm/msm/a8xx: missing CP_PROTECT_GLOBAL(56..62) in a850_ifpc_reglist_regs
--
commit 552d3a60893e50e06127da749c3d585e911f2b2e
Author: Rob Clark <robin.clark@oss.qualcomm.com>
drm/msm/a8xx: Switch to generated protect regs
This commit replaces the hardcoded protect register tables in
a8xx_catalog.c with the generated protect tables from the per-target
catalog headers.
> diff --git a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
> index bc79013165c13..5f5f71d86df93 100644
> --- a/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
> +++ b/drivers/gpu/drm/msm/adreno/a8xx_catalog.c
[ ... ]
> @@ -1305,7 +1026,7 @@ static const struct adreno_info a8xx_gpus[] = {
> ADRENO_QUIRK_IFPC,
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> - .protect = &a840_protect,
> + .protect = &pakala_protect,
> .nonctxt_reglist = kaanapali_nonctxt_regs,
> .pwrup_reglist = &a840_pwrup_reglist,
> .dyn_pwrup_reglist = &a840_dyn_pwrup_reglist,
[Severity: High]
Should the Kaanapali (Adreno 840, 0x44050a01) entry in a8xx_gpus[] use
&kaanapali_protect instead of &pakala_protect?
__build_asserts() checks kaanapali_protect, which is defined in
drivers/gpu/drm/msm/adreno/catalog/adreno_kaanapali.h, but kaanapali_protect
is left unused in a8xx_gpus[].
When hw_init() -> a8xx_set_cp_protect() programs the protection registers
from pakala_protect_regs on Kaanapali, several Kaanapali-specific spans from
kaanapali_protect_regs (including 0x00775..0x0077f, 0x00c07..0x00c0f,
0x03d00..0x05cff, 0x0a82e, 0x0aed0..0x0b17f, and 0x1fd80..0x1ffff) are left
unprotected against unprivileged userspace command streams, while
0x00000..0x00007 and 0x27c02..0x27c05 are protected instead.
[ ... ]
> @@ -1481,7 +1202,7 @@ static const struct adreno_info a8xx_gpus[] = {
> ADRENO_QUIRK_IFPC,
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> - .protect = &a850_protect,
> + .protect = &hawi_protect,
> .nonctxt_reglist = hawi_nonctxt_regs,
> .pwrup_reglist = &a850_pwrup_reglist,
> .dyn_pwrup_reglist = &a850_dyn_pwrup_reglist,
[Severity: High]
Does switching Hawi (Adreno 850, 0x44051401) to hawi_protect without
updating a850_ifpc_reglist_regs cause REG_A8XX_CP_PROTECT_GLOBAL(56) through
REG_A8XX_CP_PROTECT_GLOBAL(62) to be lost across inter-frame power collapse?
Previously, a850_protect_regs had 57 entries, and a850_ifpc_reglist_regs
omitted REG_A8XX_CP_PROTECT_GLOBAL(56) through
REG_A8XX_CP_PROTECT_GLOBAL(62):
drivers/gpu/drm/msm/adreno/a8xx_catalog.c:
static const u32 a850_ifpc_reglist_regs[] = {
...
REG_A8XX_CP_PROTECT_GLOBAL(54),
REG_A8XX_CP_PROTECT_GLOBAL(55),
REG_A8XX_CP_PROTECT_GLOBAL(63),
};
In drivers/gpu/drm/msm/adreno/catalog/adreno_hawi.h, hawi_protect_regs has
64 entries, so hw_init() -> a8xx_set_cp_protect() populates all 64
REG_A8XX_CP_PROTECT_GLOBAL(0..63) registers:
drivers/gpu/drm/msm/adreno/catalog/adreno_hawi.h:
static const u32 hawi_protect_regs[] __maybe_unused = {
...
A6XX_PROTECT_NORDWR(0x1ac00, 0x1fff),
A6XX_PROTECT_NORDWR(0x1f400, 0x0477),
A6XX_PROTECT_NORDWR(0x1f930, 0x032f),
A6XX_PROTECT_NORDWR(0x1fd80, 0x1fff),
A6XX_PROTECT_NORDWR(0x27800, 0x007f),
A6XX_PROTECT_RDONLY(0x27880, 0x0001),
A6XX_PROTECT_NORDWR(0x27882, 0x037d),
A6XX_PROTECT_NORDWR(0x27c06, 0x0000),
};
DECLARE_ADRENO_PROTECT(hawi_protect, 64);
Because Hawi sets ADRENO_QUIRK_IFPC and uses a850_ifpc_reglist in
a8xx_patch_pwrup_reglist(), those 7 protection registers (covering ranges in
0x1ac00..0x27bff) will not be restored after inter-frame power collapse.
> @@ -1516,6 +1237,10 @@ DECLARE_ADRENO_GPULIST(a8xx);
>
> static inline __always_unused void __build_asserts(void)
> {
> - BUILD_BUG_ON(a810_protect.count > a810_protect.count_max);
> - BUILD_BUG_ON(a830_protect.count > a830_protect.count_max);
> + BUILD_BUG_ON(glymur_protect.count > glymur_protect.count_max);
> + BUILD_BUG_ON(hawi_protect.count > hawi_protect.count_max);
> + BUILD_BUG_ON(kaanapali_protect.count > kaanapali_protect.count_max);
> + BUILD_BUG_ON(maili_protect.count > maili_protect.count_max);
> + BUILD_BUG_ON(milos_protect.count > milos_protect.count_max);
> + BUILD_BUG_ON(pakala_protect.count > pakala_protect.count_max);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020204728.28844-1-robin.clark@oss.qualcomm.com?part=11
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-10-20 23:41 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 20:46 [PATCH 00/12] drm/msm/a8xx: GPU state capture support Rob Clark
2026-10-20 20:46 ` [PATCH 01/12] drm/msm: Import adreno_snapshot.h Rob Clark
2026-10-20 20:46 ` [PATCH 02/12] drm/msm/a8xx: Export aperture helpers Rob Clark
2026-10-20 20:46 ` [PATCH 03/12] drm/msm/a8xx: Add a8xx_aperture_acquire_slice() Rob Clark
2026-10-20 20:46 ` [PATCH 04/12] drm/msm/a8xx: Allow nonctx reglist to include GMU regs Rob Clark
2026-10-20 20:46 ` [PATCH 05/12] drm/msm/a8xx: Stop getting GMEM_PROTECT from nonctx list Rob Clark
2026-10-20 20:46 ` [PATCH 06/12] drm/msm/adreno: Fix PROTECT span length Rob Clark
2026-10-20 20:46 ` [PATCH 07/12] drm/msm/adreno: add temporary __maybe_unused Rob Clark
2026-10-20 20:46 ` [PATCH 09/12] drm/msm/a8xx: devcoredump state capture support Rob Clark
2026-10-20 23:13 ` sashiko-bot
2026-10-20 20:46 ` [PATCH 10/12] drm/msm/a8xx: Switch to generated nonctx regs Rob Clark
2026-10-20 23:32 ` sashiko-bot
2026-10-20 20:46 ` [PATCH 11/12] drm/msm/a8xx: Switch to generated protect regs Rob Clark
2026-10-20 23:41 ` sashiko-bot
2026-10-20 20:46 ` [PATCH 12/12] drm/msm/adreno: Remove temporary __maybe_unused Rob Clark
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.