All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Christian König" <christian.koenig@amd.com>
To: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>,
	Alex Deucher <alexander.deucher@amd.com>
Cc: amd-gfx@lists.freedesktop.org, "Lijo Lazar" <lijo.lazar@amd.com>,
	"Felix Kuehling" <felix.kuehling@amd.com>,
	"Lancelot Six" <lancelot.six@amd.com>,
	"James Zhu" <james.zhu@amd.com>,
	"Samuel Pitoiset" <hakzsam@gmail.com>,
	"Natalie Vock" <natalie.vock@gmx.de>,
	"Timur Kristóf" <timur.kristof@gmail.com>,
	"Pierre-Eric Pelloux-Prayer" <pierre-eric.pelloux-prayer@amd.com>
Subject: Re: [PATCH 4/7] drm/amdgpu: Add second-level trap handler infrastructure
Date: Mon, 12 Oct 2026 16:07:46 +0200	[thread overview]
Message-ID: <d6cc0c25-bbee-48b4-9a84-3a79fa82dff5@amd.com> (raw)
In-Reply-To: <20261008070542.1111149-5-srinivasan.shanmugam@amd.com>

On 10/8/26 09:05, Srinivasan Shanmugam wrote:
> From: Lijo Lazar <lijo.lazar@amd.com>
> 
> Expand the CWSR infrastructure to support second-level userspace trap
> handlers and rename it to reflect the broader trap handler scope.
> 
> Rename the CWSR files and common interfaces to amdgpu_trap while keeping
> CWSR-specific naming for the context save/restore functionality.
> 
> Add the basic support needed for a userspace second-level trap handler.
> Store the second-level TBA and TMA addresses in the first-level TMA and
> provide helpers to set and clear them for a GPUVM.
> 
> The first-level TMA buffer can move in memory, so do not keep it
> permanently mapped on the CPU. Map it only while accessing its contents
> and unmap it afterwards.
> 
> Check that the second-level TBA and TMA address ranges are mapped in the
> GPUVM before using them. Wait for GPUVM work to stop before changing the
> addresses and keep the VM locked while checking and updating them.
> 
> Add support for updating the debugger trap flag in the first-level TMA.
> 
> Do not expose a standalone TRAP ioctl. The second-level trap handler is
> controlled through SET_L2_TRAP and CLEAR_L2_TRAP operations on the VM
> ioctl added later in the series.
> 
> Suggested-by: Christian König <christian.koenig@amd.com>
> Suggested-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: Felix Kuehling <felix.kuehling@amd.com>
> Cc: Lancelot Six <lancelot.six@amd.com>
> Cc: James Zhu <james.zhu@amd.com>
> Cc: Lijo Lazar <lijo.lazar@amd.com>
> Cc: Samuel Pitoiset <hakzsam@gmail.com>
> Cc: Natalie Vock <natalie.vock@gmx.de>
> Cc: Timur Kristóf <timur.kristof@gmail.com>
> Cc: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
> Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
> Co-developed-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
> Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>

Reviewed-by: Christian König <christian.koenig@amd.com>

> ---
>  drivers/gpu/drm/amd/amdgpu/Makefile        |   2 +-
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h        |   8 +-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.c   | 534 ---------------
>  drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.h   |  87 ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |   6 +-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c    |   1 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c    |  18 +-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c   | 753 +++++++++++++++++++++
>  drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h   | 143 ++++
>  drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c  |  13 +-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h  |   7 +-
>  drivers/gpu/drm/amd/amdgpu/mes_userqueue.c |  24 +-
>  12 files changed, 935 insertions(+), 661 deletions(-)
>  delete mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.c
>  delete mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.h
>  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
>  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
> index 5086a482daf1..28bd81f0f720 100644
> --- a/drivers/gpu/drm/amd/amdgpu/Makefile
> +++ b/drivers/gpu/drm/amd/amdgpu/Makefile
> @@ -72,7 +72,7 @@ amdgpu-y += amdgpu_device.o amdgpu_reg_access.o amdgpu_doorbell_mgr.o amdgpu_kms
>  	amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o amdgpu_lockdep.o \
>  	amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_dev_coredump.o \
>  	amdgpu_cper.o amdgpu_userq_fence.o amdgpu_eviction_fence.o amdgpu_ip.o \
> -	amdgpu_wb.o amdgpu_cwsr.o
> +	amdgpu_wb.o amdgpu_trap.o
>  
>  amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o
>  
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index bdd55ac5b06e..e55496f5ecdd 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -332,8 +332,8 @@ struct amdgpu_reset_context;
>  struct amdgpu_reset_control;
>  struct amdgpu_coredump_info;
>  struct amdgpu_video_codecs;
> -struct amdgpu_cwsr_isa;
> -struct amdgpu_cwsr_trap_obj;
> +struct amdgpu_trap_isa;
> +struct amdgpu_trap_obj;
>  
>  enum amdgpu_cp_irq {
>  	AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0,
> @@ -422,7 +422,7 @@ struct amdgpu_fpriv {
>  	struct xarray		bo_list_handles;
>  	struct amdgpu_ctx_mgr	ctx_mgr;
>  	struct amdgpu_userq_mgr	userq_mgr;
> -	struct amdgpu_cwsr_trap_obj *cwsr_trap;
> +	struct amdgpu_trap_obj *trap_obj;
>  
>  	/* Eviction fence infra */
>  	struct amdgpu_eviction_fence_mgr evf_mgr;
> @@ -978,7 +978,7 @@ struct amdgpu_device {
>  	 */
>  	struct amdgpu_kfd_dev		kfd;
>  
> -	struct amdgpu_cwsr_info *cwsr_info;
> +	struct amdgpu_trap_info *trap_info;
>  };
>  
>  static inline uint32_t amdgpu_ip_version(const struct amdgpu_device *adev,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.c
> deleted file mode 100644
> index 6b6c11bb5fd7..000000000000
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.c
> +++ /dev/null
> @@ -1,534 +0,0 @@
> -/*
> - * Copyright 2025 Advanced Micro Devices, Inc.
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> - * OTHER DEALINGS IN THE SOFTWARE.
> - */
> -
> -#include <drm/drm_exec.h>
> -
> -#include "amdgpu.h"
> -#include "cwsr_trap_handler.h"
> -#include "amdgpu_cwsr.h"
> -
> -extern int cwsr_enable;
> -
> -#define AMDGPU_CWSR_TBA_MAX_SIZE (2 * AMDGPU_GPU_PAGE_SIZE)
> -#define AMDGPU_CWSR_TMA_MAX_SIZE (AMDGPU_GPU_PAGE_SIZE)
> -#define AMDGPU_CWSR_TMA_OFFSET (AMDGPU_CWSR_TBA_MAX_SIZE)
> -
> -#define SGPR_SIZE_PER_CU 0x4000
> -#define LDS_SIZE_PER_CU 0x10000
> -#define HWREG_SIZE_PER_CU 0x1000
> -#define DEBUGGER_BYTES_ALIGN 64
> -#define DEBUGGER_BYTES_PER_WAVE 32
> -#define SIZEOF_HSA_USER_CONTEXT_SAVE_AREA_HEADER 40
> -
> -enum amdgpu_cwsr_region {
> -	AMDGPU_CWSR_TBA,
> -	AMDGPU_CWSR_TMA,
> -};
> -
> -static inline uint64_t amdgpu_cwsr_tba_vaddr(struct amdgpu_device *adev)
> -{
> -	uint64_t addr = AMDGPU_VA_RESERVED_TRAP_UQ_START(adev);
> -
> -	addr = amdgpu_gmc_sign_extend(addr);
> -
> -	return addr;
> -}
> -
> -static inline bool amdgpu_cwsr_is_supported(struct amdgpu_device *adev)
> -{
> -	uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> -
> -	if (!cwsr_enable || adev->gfx.disable_uq ||
> -	    gc_ver < IP_VERSION(9, 0, 1))
> -		return false;
> -
> -	return true;
> -}
> -
> -uint32_t amdgpu_cwsr_size_needed(struct amdgpu_device *adev, int num_xcc)
> -{
> -	if (!amdgpu_cwsr_is_enabled(adev))
> -		return 0;
> -
> -	return num_xcc *
> -	       (adev->cwsr_info->xcc_cwsr_sz + adev->cwsr_info->xcc_dbg_mem_sz);
> -}
> -
> -static void amdgpu_cwsr_init_isa_details(struct amdgpu_device *adev,
> -					 struct amdgpu_cwsr_info *cwsr_info)
> -{
> -	uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> -
> -	if (gc_ver < IP_VERSION(9, 0, 1)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx8_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx8_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx8_hex);
> -	} else if (gc_ver == IP_VERSION(9, 4, 1)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_arcturus_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_arcturus_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_arcturus_hex);
> -	} else if (gc_ver == IP_VERSION(9, 4, 2)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_aldebaran_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_aldebaran_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_aldebaran_hex);
> -	} else if (gc_ver == IP_VERSION(9, 4, 3) ||
> -		   gc_ver == IP_VERSION(9, 4, 4)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx9_4_3_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx9_4_3_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx9_4_3_hex);
> -	} else if (gc_ver == IP_VERSION(9, 5, 0)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx9_5_0_hex) > PAGE_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx9_5_0_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx9_5_0_hex);
> -	} else if (gc_ver < IP_VERSION(10, 1, 1)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx9_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx9_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx9_hex);
> -	} else if (gc_ver < IP_VERSION(10, 3, 0)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_nv1x_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_nv1x_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_nv1x_hex);
> -	} else if (gc_ver < IP_VERSION(11, 0, 0)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx10_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx10_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx10_hex);
> -	} else if (gc_ver < IP_VERSION(12, 0, 0)) {
> -		/* The gfx11 cwsr trap handler must fit inside a single
> -			   page. */
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx11_hex) > PAGE_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx11_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx11_hex);
> -	} else if (gc_ver < IP_VERSION(12, 1, 0)) {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx12_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx12_hex);
> -	} else {
> -		BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_1_0_hex) >
> -			     AMDGPU_CWSR_TBA_MAX_SIZE);
> -		cwsr_info->isa_buf = cwsr_trap_gfx12_1_0_hex;
> -		cwsr_info->isa_sz = sizeof(cwsr_trap_gfx12_1_0_hex);
> -	}
> -}
> -
> -static uint32_t amdgpu_cwsr_get_vgpr_size_per_cu(struct amdgpu_device *adev)
> -{
> -	uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> -	uint32_t vgpr_size;
> -
> -	switch (gc_ver) {
> -	case IP_VERSION(9, 4, 1): /* GFX_VERSION_ARCTURUS */
> -	case IP_VERSION(9, 4, 2): /* GFX_VERSION_ALDEBARAN */
> -	case IP_VERSION(9, 4, 3): /* GFX_VERSION_AQUA_VANJARAM */
> -	case IP_VERSION(9, 4, 4): /* GFX_VERSION_AQUA_VANJARAM */
> -	case IP_VERSION(9, 5, 0):
> -		vgpr_size = 0x80000;
> -		break;
> -	case IP_VERSION(11, 0, 0):
> -	case IP_VERSION(11, 0, 2):
> -	case IP_VERSION(11, 0, 3):
> -	case IP_VERSION(12, 0, 0):
> -	case IP_VERSION(12, 0, 1):
> -		vgpr_size = 0x60000;
> -		break;
> -	default:
> -		vgpr_size = 0x40000;
> -		break;
> -	}
> -
> -	return vgpr_size;
> -}
> -
> -static uint32_t amdgpu_cwsr_get_wg_ctxt_size_per_cu(struct amdgpu_device *adev)
> -{
> -	uint32_t lds_sz_per_cu;
> -
> -	lds_sz_per_cu =
> -		(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0)) ?
> -			(adev->gfx.cu_info.lds_size << 10) :
> -			LDS_SIZE_PER_CU;
> -
> -	return amdgpu_cwsr_get_vgpr_size_per_cu(adev) + SGPR_SIZE_PER_CU +
> -	       lds_sz_per_cu + HWREG_SIZE_PER_CU;
> -}
> -
> -static uint32_t amdgpu_cwsr_ctl_stack_bytes_per_wave(struct amdgpu_device *adev)
> -{
> -	uint32_t sz;
> -
> -	if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 1, 0))
> -		sz = 12;
> -	else
> -		sz = 8;
> -	return sz;
> -}
> -
> -static void amdgpu_cwsr_init_save_area_info(struct amdgpu_device *adev,
> -					    struct amdgpu_cwsr_info *cwsr_info)
> -{
> -	struct amdgpu_gfx_config *gfx_info = &adev->gfx.config;
> -	uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> -	uint32_t ctl_stack_size, wg_data_size, dbg_mem_size;
> -	uint32_t array_count;
> -	uint32_t wave_num;
> -	uint32_t cu_num;
> -
> -	if (gc_ver < IP_VERSION(9, 0, 1))
> -		return;
> -
> -	array_count = gfx_info->max_shader_engines * gfx_info->max_sh_per_se;
> -
> -	cu_num = adev->gfx.cu_info.number / NUM_XCC(adev->gfx.xcc_mask);
> -	wave_num = (gc_ver < IP_VERSION(10, 1, 0)) ? /* GFX_VERSION_NAVI10 */
> -			   min(cu_num * 40,
> -			       array_count / gfx_info->max_sh_per_se * 512) :
> -			   cu_num * 32;
> -
> -	wg_data_size = ALIGN(cu_num * amdgpu_cwsr_get_wg_ctxt_size_per_cu(adev),
> -			     PAGE_SIZE);
> -	ctl_stack_size =
> -		wave_num * amdgpu_cwsr_ctl_stack_bytes_per_wave(adev) + 8;
> -	ctl_stack_size =
> -		ALIGN(SIZEOF_HSA_USER_CONTEXT_SAVE_AREA_HEADER + ctl_stack_size,
> -		      PAGE_SIZE);
> -	dbg_mem_size =
> -		ALIGN(wave_num * DEBUGGER_BYTES_PER_WAVE, DEBUGGER_BYTES_ALIGN);
> -	/*
> -	* HW design limits control stack size to 0x7000.
> -	* This is insufficient for theoretical PM4 cases
> -	* but sufficient for AQL, limited by SPI events.
> -	*/
> -	if (IP_VERSION_MAJ(gc_ver) == 10)
> -		ctl_stack_size = min(ctl_stack_size, 0x7000);
> -
> -	cwsr_info->xcc_ctl_stack_sz = ctl_stack_size;
> -	cwsr_info->xcc_cwsr_sz = ctl_stack_size + wg_data_size;
> -	cwsr_info->xcc_dbg_mem_sz = dbg_mem_size;
> -}
> -
> -int amdgpu_cwsr_init(struct amdgpu_device *adev)
> -{
> -	struct amdgpu_cwsr_info *cwsr_info __free(kfree) =
> -		kzalloc(sizeof(*cwsr_info), GFP_KERNEL);
> -	void *ptr;
> -	int r;
> -
> -	if (!amdgpu_cwsr_is_supported(adev))
> -		return -EOPNOTSUPP;
> -
> -	if (!cwsr_info)
> -		return -ENOMEM;
> -	amdgpu_cwsr_init_isa_details(adev, cwsr_info);
> -
> -	if (!cwsr_info->isa_sz)
> -		return -EOPNOTSUPP;
> -
> -	r = amdgpu_bo_create_kernel(adev, AMDGPU_CWSR_TBA_MAX_SIZE, PAGE_SIZE,
> -				    AMDGPU_GEM_DOMAIN_GTT, &cwsr_info->isa_bo,
> -				    NULL, &ptr);
> -	if (r)
> -		return r;
> -
> -	memcpy(ptr, cwsr_info->isa_buf, cwsr_info->isa_sz);
> -
> -	amdgpu_cwsr_init_save_area_info(adev, cwsr_info);
> -	adev->cwsr_info = no_free_ptr(cwsr_info);
> -
> -	return 0;
> -}
> -
> -void amdgpu_cwsr_fini(struct amdgpu_device *adev)
> -{
> -	if (!amdgpu_cwsr_is_enabled(adev))
> -		return;
> -
> -	amdgpu_bo_free_kernel(&adev->cwsr_info->isa_bo, NULL, NULL);
> -	kfree(adev->cwsr_info);
> -	adev->cwsr_info = NULL;
> -}
> -
> -/*
> - * amdgpu_map_cwsr_trap_handler should be called during amdgpu_vm_init
> - * it maps virtual address amdgpu_cwsr_trap_handler_vaddr() to this VM, and each
> - * compute queue can use this virtual address for wave save/restore
> - * operations to support compute preemption.
> - */
> -static int amdgpu_cwsr_map_region(struct amdgpu_device *adev,
> -				  struct amdgpu_vm *vm,
> -				  struct amdgpu_cwsr_trap_obj *cwsr,
> -				  enum amdgpu_cwsr_region region)
> -{
> -	uint64_t cwsr_addr, va_flags, va;
> -	struct amdgpu_bo_va **bo_va;
> -	struct amdgpu_bo *bo;
> -	uint32_t size;
> -	int r;
> -
> -	if (!cwsr || !vm)
> -		return -EINVAL;
> -
> -	cwsr_addr = amdgpu_cwsr_tba_vaddr(adev);
> -
> -	if (region == AMDGPU_CWSR_TBA) {
> -		size = AMDGPU_CWSR_TBA_MAX_SIZE;
> -		bo_va = &cwsr->tba_va;
> -		bo = adev->cwsr_info->isa_bo;
> -		va = cwsr_addr;
> -		va_flags = (AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
> -			    AMDGPU_VM_PAGE_EXECUTABLE);
> -	} else {
> -		size = AMDGPU_CWSR_TMA_MAX_SIZE;
> -		bo_va = &cwsr->tma_va;
> -		bo = cwsr->tma_bo;
> -		va = cwsr_addr + AMDGPU_CWSR_TMA_OFFSET;
> -		va_flags = (AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE);
> -	}
> -
> -	*bo_va = amdgpu_vm_bo_add(adev, vm, bo);
> -	if (!*bo_va)
> -		return -ENOMEM;
> -
> -	va &= AMDGPU_GMC_HOLE_MASK;
> -	r = amdgpu_vm_bo_map(adev, *bo_va, va, 0, size, va_flags);
> -	if (r) {
> -		dev_err(adev->dev, "failed to do bo map of %s region, err=%d\n",
> -			(region == AMDGPU_CWSR_TBA ? "tba" : "tma"), r);
> -		amdgpu_vm_bo_del(adev, *bo_va);
> -		*bo_va = NULL;
> -		return r;
> -	}
> -
> -	r = amdgpu_vm_bo_update(adev, *bo_va, false);
> -	if (r) {
> -		dev_err(adev->dev,
> -			"failed to do page table update of %s region, err=%d\n",
> -			(region == AMDGPU_CWSR_TBA ? "tba" : "tma"), r);
> -		amdgpu_vm_bo_del(adev, *bo_va);
> -		*bo_va = NULL;
> -		return r;
> -	}
> -
> -	if (region == AMDGPU_CWSR_TBA)
> -		cwsr->tba_gpu_va_addr = va;
> -	else
> -		cwsr->tma_gpu_va_addr = va;
> -
> -	return 0;
> -}
> -
> -static int amdgpu_cwsr_unmap_region(struct amdgpu_device *adev,
> -				    struct amdgpu_cwsr_trap_obj *cwsr,
> -				    enum amdgpu_cwsr_region region)
> -{
> -	struct amdgpu_bo_va **bo_va;
> -	uint64_t va;
> -	int r;
> -
> -	if (!cwsr)
> -		return -EINVAL;
> -
> -	if (region == AMDGPU_CWSR_TBA) {
> -		bo_va = &cwsr->tba_va;
> -		va = cwsr->tba_gpu_va_addr;
> -	} else {
> -		bo_va = &cwsr->tma_va;
> -		va = cwsr->tma_gpu_va_addr;
> -	}
> -
> -	r = amdgpu_vm_bo_unmap(adev, *bo_va, va);
> -	if (r) {
> -		dev_err(adev->dev,
> -			"failed to do bo_unmap on CWSR trap handler, err=%d\n",
> -			r);
> -		return r;
> -	}
> -
> -	amdgpu_vm_bo_del(adev, *bo_va);
> -	*bo_va = NULL;
> -
> -	return r;
> -}
> -
> -int amdgpu_cwsr_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> -		      struct amdgpu_cwsr_trap_obj **trap_obj)
> -{
> -	struct amdgpu_bo_param bp;
> -	struct amdgpu_cwsr_trap_obj *cwsr;
> -	struct amdgpu_bo *bo;
> -	struct drm_exec exec;
> -	int r;
> -
> -	if (!amdgpu_cwsr_is_enabled(adev))
> -		return -EOPNOTSUPP;
> -	if (!vm || !trap_obj)
> -		return -EINVAL;
> -
> -	cwsr = kzalloc(sizeof(*cwsr), GFP_KERNEL);
> -	if (!cwsr)
> -		return -ENOMEM;
> -
> -	bo = adev->cwsr_info->isa_bo;
> -	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
> -	drm_exec_until_all_locked(&exec) {
> -		r = amdgpu_vm_lock_pd(vm, &exec, 0);
> -		if (likely(!r))
> -			r = drm_exec_lock_obj(&exec, &bo->tbo.base);
> -		drm_exec_retry_on_contention(&exec);
> -		if (unlikely(r)) {
> -			dev_err(adev->dev,
> -				"failed to reserve for CWSR allocs: err=%d\n",
> -				r);
> -			goto err_exec;
> -		}
> -	}
> -
> -	/*
> -	 * Create TMA BO using the VM's already-locked resv so no new
> -	 * reservation_ww_class_mutex acquisition is needed, avoiding the
> -	 * recursive ww_mutex deadlock. Unpinned; eviction is handled via
> -	 * amdgpu_vm_bo_add() inside amdgpu_cwsr_map_region().
> -	 */
> -	memset(&bp, 0, sizeof(bp));
> -	bp.size = AMDGPU_CWSR_TMA_MAX_SIZE;
> -	bp.byte_align = PAGE_SIZE;
> -	bp.domain = AMDGPU_GEM_DOMAIN_GTT;
> -	bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC |
> -		   AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
> -	bp.type = ttm_bo_type_kernel;
> -	bp.bo_ptr_size = sizeof(struct amdgpu_bo);
> -	bp.resv = vm->root.bo->tbo.base.resv;
> -
> -	r = amdgpu_bo_create(adev, &bp, &cwsr->tma_bo);
> -	if (r)
> -		goto err_exec;
> -
> -	/* VM resv already held, kmap directly, no separate reserve needed. */
> -	r = amdgpu_bo_kmap(cwsr->tma_bo, &cwsr->tma_cpu_addr);
> -	if (r)
> -		goto err_tma;
> -
> -	memset(cwsr->tma_cpu_addr, 0, AMDGPU_CWSR_TMA_MAX_SIZE);
> -
> -	r = amdgpu_cwsr_map_region(adev, vm, cwsr, AMDGPU_CWSR_TMA);
> -	if (r)
> -		goto err_kmap;
> -
> -	r = amdgpu_cwsr_map_region(adev, vm, cwsr, AMDGPU_CWSR_TBA);
> -	if (r) {
> -		amdgpu_cwsr_unmap_region(adev, cwsr, AMDGPU_CWSR_TMA);
> -		goto err_kmap;
> -	}
> -
> -	drm_exec_fini(&exec);
> -	*trap_obj = cwsr;
> -	return 0;
> -
> -err_kmap:
> -	amdgpu_bo_kunmap(cwsr->tma_bo);
> -err_tma:
> -	amdgpu_bo_unref(&cwsr->tma_bo);
> -err_exec:
> -	drm_exec_fini(&exec);
> -	kfree(cwsr);
> -	*trap_obj = NULL;
> -	return r;
> -}
> -
> -int amdgpu_cwsr_validate_params(struct amdgpu_device *adev,
> -				struct amdgpu_cwsr_params *cwsr_params,
> -				int num_xcc)
> -{
> -	uint32_t min_size, max_size;
> -
> -	if (!amdgpu_cwsr_is_enabled(adev))
> -		return -EOPNOTSUPP;
> -
> -	if (!cwsr_params)
> -		return -EINVAL;
> -
> -	min_size = amdgpu_cwsr_size_needed(adev, num_xcc);
> -	max_size = 2 * min_size;
> -	/*
> -	 * Only save area size details checked. Address validation needs to be
> -	 * carried out separately. User is expected to pass a cwsr buffer area
> -	 * with size >= ctl stack size + wg data size + debug memory size
> -	 */
> -	if (cwsr_params->cwsr_sz < min_size ||
> -	    cwsr_params->cwsr_sz > max_size) {
> -		dev_dbg(adev->dev,
> -			"queue cwsr size 0x%x should be within min %u : max %u\n",
> -			cwsr_params->cwsr_sz, min_size, max_size);
> -		return -EINVAL;
> -	}
> -
> -	return 0;
> -}
> -
> -void amdgpu_cwsr_free(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> -		      struct amdgpu_cwsr_trap_obj **trap_obj)
> -{
> -	struct amdgpu_bo *tba_bo;
> -	struct amdgpu_bo *tma_bo;
> -	struct drm_exec exec;
> -	int r;
> -
> -	if (!trap_obj || !*trap_obj || !(*trap_obj)->tma_bo)
> -		return;
> -
> -	tba_bo = adev->cwsr_info->isa_bo;
> -	tma_bo = (*trap_obj)->tma_bo;
> -
> -	if (!tba_bo || !tma_bo)
> -		return;
> -
> -	drm_exec_init(&exec, 0, 0);
> -	drm_exec_until_all_locked(&exec) {
> -		r = amdgpu_vm_lock_pd(vm, &exec, 0);
> -		if (likely(!r))
> -			r = drm_exec_lock_obj(&exec, &tba_bo->tbo.base);
> -		drm_exec_retry_on_contention(&exec);
> -		if (unlikely(r)) {
> -			dev_err(adev->dev,
> -				"failed to reserve CWSR BOs: err=%d\n", r);
> -			goto err;
> -		}
> -	}
> -
> -	amdgpu_cwsr_unmap_region(adev, *trap_obj, AMDGPU_CWSR_TBA);
> -	amdgpu_cwsr_unmap_region(adev, *trap_obj, AMDGPU_CWSR_TMA);
> -
> -err:
> -	drm_exec_fini(&exec);
> -
> -	/* TMA BO not pinned, release CPU mapping and free. */
> -	amdgpu_bo_kunmap((*trap_obj)->tma_bo);
> -	amdgpu_bo_unref(&(*trap_obj)->tma_bo);
> -	kfree(*trap_obj);
> -	*trap_obj = NULL;
> -}
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.h
> deleted file mode 100644
> index 5717e1d662fc..000000000000
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cwsr.h
> +++ /dev/null
> @@ -1,87 +0,0 @@
> -/*
> - * Copyright 2025 Advanced Micro Devices, Inc.
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> - * OTHER DEALINGS IN THE SOFTWARE.
> - */
> -
> -#ifndef AMDGPU_CWSR_H
> -#define AMDGPU_CWSR_H
> -
> -#include <linux/types.h>
> -
> -struct amdgpu_bo;
> -struct amdgpu_bo_va;
> -struct amdgpu_device;
> -struct amdgpu_vm;
> -
> -/**
> - * struct amdgpu_cwsr_obj - CWSR (Compute Wave Save Restore) buffer tracking
> - * @bo: Buffer object for CWSR area
> - * @bo_va: Buffer object virtual address mapping
> - */
> -struct amdgpu_cwsr_trap_obj {
> -	uint64_t tma_gpu_va_addr;
> -	uint64_t tba_gpu_va_addr;
> -
> -	struct amdgpu_bo *tma_bo;
> -	struct amdgpu_bo_va *tba_va;
> -	struct amdgpu_bo_va *tma_va;
> -	void *tma_cpu_addr;
> -};
> -
> -struct amdgpu_cwsr_info {
> -	/* cwsr isa */
> -	struct amdgpu_bo *isa_bo;
> -	const void *isa_buf;
> -	uint32_t isa_sz;
> -	/* cwsr size info per XCC*/
> -	uint32_t xcc_ctl_stack_sz;
> -	uint32_t xcc_dbg_mem_sz;
> -	uint32_t xcc_cwsr_sz;
> -};
> -
> -struct amdgpu_cwsr_params {
> -	uint64_t ctx_save_area_address;
> -	/* cwsr size info */
> -	uint32_t cwsr_sz;
> -};
> -
> -int amdgpu_cwsr_init(struct amdgpu_device *adev);
> -void amdgpu_cwsr_fini(struct amdgpu_device *adev);
> -
> -int amdgpu_cwsr_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> -		      struct amdgpu_cwsr_trap_obj **cwsr_obj);
> -void amdgpu_cwsr_free(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> -		      struct amdgpu_cwsr_trap_obj **cwsr_obj);
> -static inline bool amdgpu_cwsr_is_enabled(struct amdgpu_device *adev)
> -{
> -	return adev->cwsr_info != NULL;
> -}
> -
> -uint32_t amdgpu_cwsr_size_needed(struct amdgpu_device *adev, int num_xcc);
> -int amdgpu_cwsr_validate_params(struct amdgpu_device *adev,
> -				struct amdgpu_cwsr_params *cwsr_params,
> -				int num_xcc);
> -static inline bool amdgpu_cwsr_has_dbg_wa(struct amdgpu_device *adev)
> -{
> -	uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> -
> -	return gc_ver >= IP_VERSION(11, 0, 0) && gc_ver <= IP_VERSION(11, 0, 3);
> -}
> -#endif
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 5a7f111763bf..6bac724fc73f 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -81,7 +81,7 @@
>  #include "amdgpu_reset.h"
>  #include "amdgpu_virt.h"
>  #include "amdgpu_dev_coredump.h"
> -#include "amdgpu_cwsr.h"
> +#include "amdgpu_trap.h"
>  
>  #include <linux/suspend.h>
>  #include <drm/task_barrier.h>
> @@ -2551,7 +2551,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
>  	r = amdgpu_cper_init(adev);
>  
>  	if (!r) {
> -		r = amdgpu_cwsr_init(adev);
> +		r = amdgpu_trap_init(adev);
>  		if (r == -EOPNOTSUPP)
>  			r = 0;
>  	}
> @@ -2953,7 +2953,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
>  {
>  	int i, r;
>  
> -	amdgpu_cwsr_fini(adev);
> +	amdgpu_trap_fini(adev);
>  	amdgpu_cper_fini(adev);
>  
>  	if (amdgpu_sriov_vf(adev) && adev->virt.ras_init_done)
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index b2a8a8b37006..77675c895585 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -52,6 +52,7 @@
>  #include "amdgpu_sched.h"
>  #include "amdgpu_xgmi.h"
>  #include "amdgpu_userq.h"
> +#include "amdgpu_trap.h"
>  #include "amdgpu_userq_fence.h"
>  #include "../amdxcp/amdgpu_xcp_drv.h"
>  #include "amdgpu_ualink.h"
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
> index 147c0bd02731..6839d92b9730 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
> @@ -50,7 +50,7 @@
>  #include "amdgpu_video_codecs.h"
>  #include "amdgpu_ras_mgr.h"
>  #include "amdgpu_vm.h"
> -#include "amdgpu_cwsr.h"
> +#include "amdgpu_trap.h"
>  
>  void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev)
>  {
> @@ -1434,15 +1434,15 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
>  		int num_xcc, r;
>  
>  		fpriv = (struct amdgpu_fpriv *)filp->driver_priv;
> -		if (!amdgpu_cwsr_is_enabled(adev) || !fpriv->cwsr_trap)
> +		if (!amdgpu_trap_is_enabled(adev) || !fpriv->trap_obj)
>  			return -EOPNOTSUPP;
>  		num_xcc = amdgpu_xcp_get_num_xcc(adev->xcp_mgr, fpriv->xcp_id);
>  		cwsr_info.ctl_stack_size =
> -			adev->cwsr_info->xcc_ctl_stack_sz * num_xcc;
> +			adev->trap_info->cwsr.xcc_ctl_stack_sz * num_xcc;
>  		cwsr_info.dbg_mem_size =
> -			adev->cwsr_info->xcc_dbg_mem_sz * num_xcc;
> +			adev->trap_info->cwsr.xcc_dbg_mem_sz * num_xcc;
>  		cwsr_info.min_save_area_size =
> -			amdgpu_cwsr_size_needed(adev, num_xcc);
> +			amdgpu_trap_size_needed(adev, num_xcc);
>  		r = copy_to_user(out, &cwsr_info,
>  				 min((size_t)size, sizeof(cwsr_info))) ?
>  			    -EFAULT :
> @@ -1576,10 +1576,10 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
>  
>  	amdgpu_evf_mgr_init(&fpriv->evf_mgr);
>  
> -	if (amdgpu_cwsr_is_enabled(adev)) {
> -		r = amdgpu_cwsr_alloc(adev, &fpriv->vm, &fpriv->cwsr_trap);
> +	if (amdgpu_trap_is_enabled(adev)) {
> +		r = amdgpu_trap_alloc(adev, &fpriv->vm, &fpriv->trap_obj);
>  		if (r)
> -			dev_dbg(adev->dev, "cwsr trap not enabled");
> +			dev_dbg(adev->dev, "trap handler not enabled");
>  	}
>  
>  	amdgpu_ctx_mgr_init(&fpriv->ctx_mgr, adev);
> @@ -1651,7 +1651,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
>  	}
>  
>  	amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr);
> -	amdgpu_cwsr_free(adev, &fpriv->vm, &fpriv->cwsr_trap);
> +	amdgpu_trap_free(adev, &fpriv->vm, &fpriv->trap_obj);
>  
>  	if (pasid)
>  		amdgpu_pasid_free_delayed(pd->tbo.base.resv, pasid);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
> new file mode 100644
> index 000000000000..12e37d0467f9
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
> @@ -0,0 +1,753 @@
> +/*
> + * Copyright 2025 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +#include <linux/iosys-map.h>
> +
> +#include <drm/ttm/ttm_bo.h>
> +#include <drm/drm_exec.h>
> +
> +#include "amdgpu.h"
> +#include "cwsr_trap_handler.h"
> +#include "amdgpu_trap.h"
> +
> +/*
> + * First-level TMA layout used by the second-level trap-handler ABI.
> + * The trap-handler ISA reads L2 TBA at offset 0 and L2 TMA at offset 8.
> + */
> +#define AMDGPU_TRAP_L2_TBA_INDEX	0
> +#define AMDGPU_TRAP_L2_TMA_INDEX	1
> +#define AMDGPU_TRAP_DEBUG_FLAG_INDEX	2
> +
> +extern int cwsr_enable;
> +
> +#define AMDGPU_TRAP_TBA_MAX_SIZE (2 * AMDGPU_GPU_PAGE_SIZE)
> +#define AMDGPU_TRAP_TMA_MAX_SIZE (AMDGPU_GPU_PAGE_SIZE)
> +#define AMDGPU_TRAP_TMA_OFFSET (AMDGPU_TRAP_TBA_MAX_SIZE)
> +
> +#define SGPR_SIZE_PER_CU 0x4000
> +#define LDS_SIZE_PER_CU 0x10000
> +#define HWREG_SIZE_PER_CU 0x1000
> +#define DEBUGGER_BYTES_ALIGN 64
> +#define DEBUGGER_BYTES_PER_WAVE 32
> +#define SIZEOF_HSA_USER_CONTEXT_SAVE_AREA_HEADER 40
> +
> +enum amdgpu_trap_region {
> +	AMDGPU_TRAP_TBA,
> +	AMDGPU_TRAP_TMA,
> +};
> +
> +static inline uint64_t amdgpu_trap_tba_vaddr(struct amdgpu_device *adev)
> +{
> +	u64 addr = AMDGPU_VA_RESERVED_TRAP_UQ_START(adev);
> +
> +	addr = amdgpu_gmc_sign_extend(addr);
> +
> +	return addr;
> +}
> +
> +static inline bool amdgpu_trap_is_supported(struct amdgpu_device *adev)
> +{
> +	u32 gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> +
> +	if (!cwsr_enable || gc_ver < IP_VERSION(9, 0, 1))
> +		return false;
> +
> +	return true;
> +}
> +
> +uint32_t amdgpu_trap_size_needed(struct amdgpu_device *adev, int num_xcc)
> +{
> +	if (!amdgpu_trap_is_enabled(adev))
> +		return 0;
> +
> +	return num_xcc *
> +	       (adev->trap_info->cwsr.xcc_cwsr_sz + adev->trap_info->cwsr.xcc_dbg_mem_sz);
> +}
> +
> +static void amdgpu_trap_cwsr_init_isa_details(struct amdgpu_device *adev,
> +					      struct amdgpu_trap_info *trap_info)
> +{
> +	u32 gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> +
> +	if (gc_ver < IP_VERSION(9, 0, 1)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx8_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx8_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx8_hex);
> +	} else if (gc_ver == IP_VERSION(9, 4, 1)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_arcturus_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_arcturus_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_arcturus_hex);
> +	} else if (gc_ver == IP_VERSION(9, 4, 2)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_aldebaran_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_aldebaran_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_aldebaran_hex);
> +	} else if (gc_ver == IP_VERSION(9, 4, 3) ||
> +		   gc_ver == IP_VERSION(9, 4, 4)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx9_4_3_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx9_4_3_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx9_4_3_hex);
> +	} else if (gc_ver == IP_VERSION(9, 5, 0)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx9_5_0_hex) > PAGE_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx9_5_0_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx9_5_0_hex);
> +	} else if (gc_ver < IP_VERSION(10, 1, 1)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx9_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx9_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx9_hex);
> +	} else if (gc_ver < IP_VERSION(10, 3, 0)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_nv1x_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_nv1x_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_nv1x_hex);
> +	} else if (gc_ver < IP_VERSION(11, 0, 0)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx10_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx10_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx10_hex);
> +	} else if (gc_ver < IP_VERSION(12, 0, 0)) {
> +		/* The gfx11 cwsr trap handler must fit inside a single
> +			   page. */
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx11_hex) > PAGE_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx11_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx11_hex);
> +	} else if (gc_ver < IP_VERSION(12, 1, 0)) {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx12_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx12_hex);
> +	} else {
> +		BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_1_0_hex) >
> +			     AMDGPU_TRAP_TBA_MAX_SIZE);
> +		trap_info->isa_buf = cwsr_trap_gfx12_1_0_hex;
> +		trap_info->isa_sz = sizeof(cwsr_trap_gfx12_1_0_hex);
> +	}
> +}
> +
> +static uint32_t amdgpu_trap_cwsr_get_vgpr_size_per_cu(struct amdgpu_device *adev)
> +{
> +	u32 gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> +	u32 vgpr_size;
> +
> +	switch (gc_ver) {
> +	case IP_VERSION(9, 4, 1): /* GFX_VERSION_ARCTURUS */
> +	case IP_VERSION(9, 4, 2): /* GFX_VERSION_ALDEBARAN */
> +	case IP_VERSION(9, 4, 3): /* GFX_VERSION_AQUA_VANJARAM */
> +	case IP_VERSION(9, 4, 4): /* GFX_VERSION_AQUA_VANJARAM */
> +	case IP_VERSION(9, 5, 0):
> +		vgpr_size = 0x80000;
> +		break;
> +	case IP_VERSION(11, 0, 0):
> +	case IP_VERSION(11, 0, 2):
> +	case IP_VERSION(11, 0, 3):
> +	case IP_VERSION(12, 0, 0):
> +	case IP_VERSION(12, 0, 1):
> +		vgpr_size = 0x60000;
> +		break;
> +	default:
> +		vgpr_size = 0x40000;
> +		break;
> +	}
> +
> +	return vgpr_size;
> +}
> +
> +static uint32_t amdgpu_trap_cwsr_get_wg_ctxt_size_per_cu(struct amdgpu_device *adev)
> +{
> +	u32 lds_sz_per_cu;
> +
> +	lds_sz_per_cu =
> +		(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0)) ?
> +			(adev->gfx.cu_info.lds_size << 10) :
> +			LDS_SIZE_PER_CU;
> +
> +	return amdgpu_trap_cwsr_get_vgpr_size_per_cu(adev) + SGPR_SIZE_PER_CU +
> +	       lds_sz_per_cu + HWREG_SIZE_PER_CU;
> +}
> +
> +static uint32_t amdgpu_trap_cwsr_ctl_stack_bytes_per_wave(struct amdgpu_device *adev)
> +{
> +	u32 sz;
> +
> +	if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 1, 0))
> +		sz = 12;
> +	else
> +		sz = 8;
> +	return sz;
> +}
> +
> +static void amdgpu_trap_cwsr_init_save_area_info(struct amdgpu_device *adev,
> +						 struct amdgpu_trap_info *trap_info)
> +{
> +	struct amdgpu_gfx_config *gfx_info = &adev->gfx.config;
> +	u32 gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> +	u32 ctl_stack_size, wg_data_size, dbg_mem_size;
> +	u32 array_count;
> +	u32 wave_num;
> +	u32 cu_num;
> +
> +	if (gc_ver < IP_VERSION(9, 0, 1))
> +		return;
> +
> +	array_count = gfx_info->max_shader_engines * gfx_info->max_sh_per_se;
> +
> +	cu_num = adev->gfx.cu_info.number / NUM_XCC(adev->gfx.xcc_mask);
> +	wave_num = (gc_ver < IP_VERSION(10, 1, 0)) ? /* GFX_VERSION_NAVI10 */
> +			   min(cu_num * 40,
> +			       array_count / gfx_info->max_sh_per_se * 512) :
> +			   cu_num * 32;
> +
> +	wg_data_size = ALIGN(cu_num * amdgpu_trap_cwsr_get_wg_ctxt_size_per_cu(adev),
> +			     PAGE_SIZE);
> +	ctl_stack_size =
> +		wave_num * amdgpu_trap_cwsr_ctl_stack_bytes_per_wave(adev) + 8;
> +	ctl_stack_size =
> +		ALIGN(SIZEOF_HSA_USER_CONTEXT_SAVE_AREA_HEADER + ctl_stack_size,
> +		      PAGE_SIZE);
> +	dbg_mem_size =
> +		ALIGN(wave_num * DEBUGGER_BYTES_PER_WAVE, DEBUGGER_BYTES_ALIGN);
> +	/*
> +	* HW design limits control stack size to 0x7000.
> +	* This is insufficient for theoretical PM4 cases
> +	* but sufficient for AQL, limited by SPI events.
> +	*/
> +	if (IP_VERSION_MAJ(gc_ver) == 10)
> +		ctl_stack_size = min(ctl_stack_size, 0x7000);
> +
> +	trap_info->cwsr.xcc_ctl_stack_sz = ctl_stack_size;
> +	trap_info->cwsr.xcc_cwsr_sz = ctl_stack_size + wg_data_size;
> +	trap_info->cwsr.xcc_dbg_mem_sz = dbg_mem_size;
> +}
> +
> +int amdgpu_trap_init(struct amdgpu_device *adev)
> +{
> +	struct amdgpu_trap_info *trap_info __free(kfree) =
> +		kzalloc(sizeof(*trap_info), GFP_KERNEL);
> +	void *ptr;
> +	int r;
> +
> +	if (!amdgpu_trap_is_supported(adev))
> +		return -EOPNOTSUPP;
> +
> +	if (!trap_info)
> +		return -ENOMEM;
> +	amdgpu_trap_cwsr_init_isa_details(adev, trap_info);
> +
> +	if (!trap_info->isa_sz)
> +		return -EOPNOTSUPP;
> +
> +	r = amdgpu_bo_create_kernel(adev, AMDGPU_TRAP_TBA_MAX_SIZE, PAGE_SIZE,
> +				    AMDGPU_GEM_DOMAIN_GTT, &trap_info->isa_bo,
> +				    NULL, &ptr);
> +	if (r)
> +		return r;
> +
> +	memcpy(ptr, trap_info->isa_buf, trap_info->isa_sz);
> +
> +	amdgpu_trap_cwsr_init_save_area_info(adev, trap_info);
> +	adev->trap_info = no_free_ptr(trap_info);
> +
> +	return 0;
> +}
> +
> +void amdgpu_trap_fini(struct amdgpu_device *adev)
> +{
> +	if (!amdgpu_trap_is_enabled(adev))
> +		return;
> +
> +	amdgpu_bo_free_kernel(&adev->trap_info->isa_bo, NULL, NULL);
> +	kfree(adev->trap_info);
> +	adev->trap_info = NULL;
> +}
> +
> +/*
> + * amdgpu_map_cwsr_trap_handler should be called during amdgpu_vm_init
> + * it maps virtual address amdgpu_trap_tba_vaddr() to this VM, and each
> + * compute queue can use this virtual address for wave save/restore
> + * operations to support compute preemption.
> + */
> +static int amdgpu_trap_map_region(struct amdgpu_device *adev,
> +				  struct amdgpu_vm *vm,
> +				  struct amdgpu_trap_obj *cwsr,
> +				  enum amdgpu_trap_region region)
> +{
> +	u64 cwsr_addr, va_flags, va;
> +	struct amdgpu_bo_va **bo_va;
> +	struct amdgpu_bo *bo;
> +	u32 size;
> +	int r;
> +
> +	if (!cwsr || !vm)
> +		return -EINVAL;
> +
> +	cwsr_addr = amdgpu_trap_tba_vaddr(adev);
> +
> +	if (region == AMDGPU_TRAP_TBA) {
> +		size = AMDGPU_TRAP_TBA_MAX_SIZE;
> +		bo_va = &cwsr->tba_va;
> +		bo = adev->trap_info->isa_bo;
> +		va = cwsr_addr;
> +		va_flags = (AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
> +			    AMDGPU_VM_PAGE_EXECUTABLE);
> +	} else {
> +		size = AMDGPU_TRAP_TMA_MAX_SIZE;
> +		bo_va = &cwsr->tma_va;
> +		bo = cwsr->tma_bo;
> +		va = cwsr_addr + AMDGPU_TRAP_TMA_OFFSET;
> +		va_flags = (AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE);
> +	}
> +
> +	*bo_va = amdgpu_vm_bo_add(adev, vm, bo);
> +	if (!*bo_va)
> +		return -ENOMEM;
> +
> +	va &= AMDGPU_GMC_HOLE_MASK;
> +	r = amdgpu_vm_bo_map(adev, *bo_va, va, 0, size, va_flags);
> +	if (r) {
> +		dev_err(adev->dev, "failed to do bo map of %s region, err=%d\n",
> +			(region == AMDGPU_TRAP_TBA ? "tba" : "tma"), r);
> +		amdgpu_vm_bo_del(adev, *bo_va);
> +		*bo_va = NULL;
> +		return r;
> +	}
> +
> +	r = amdgpu_vm_bo_update(adev, *bo_va, false);
> +	if (r) {
> +		dev_err(adev->dev,
> +			"failed to do page table update of %s region, err=%d\n",
> +			(region == AMDGPU_TRAP_TBA ? "tba" : "tma"), r);
> +		amdgpu_vm_bo_del(adev, *bo_va);
> +		*bo_va = NULL;
> +		return r;
> +	}
> +
> +	if (region == AMDGPU_TRAP_TBA)
> +		cwsr->tba_gpu_va_addr = va;
> +	else
> +		cwsr->tma_gpu_va_addr = va;
> +
> +	return 0;
> +}
> +
> +static int amdgpu_trap_unmap_region(struct amdgpu_device *adev,
> +				    struct amdgpu_trap_obj *cwsr,
> +				    enum amdgpu_trap_region region)
> +{
> +	struct amdgpu_bo_va **bo_va;
> +	u64 va;
> +	int r;
> +
> +	if (!cwsr)
> +		return -EINVAL;
> +
> +	if (region == AMDGPU_TRAP_TBA) {
> +		bo_va = &cwsr->tba_va;
> +		va = cwsr->tba_gpu_va_addr;
> +	} else {
> +		bo_va = &cwsr->tma_va;
> +		va = cwsr->tma_gpu_va_addr;
> +	}
> +
> +	r = amdgpu_vm_bo_unmap(adev, *bo_va, va);
> +	if (r) {
> +		dev_err(adev->dev,
> +			"failed to do bo_unmap on CWSR trap handler, err=%d\n",
> +			r);
> +		return r;
> +	}
> +
> +	amdgpu_vm_bo_del(adev, *bo_va);
> +	*bo_va = NULL;
> +
> +	return r;
> +}
> +
> +int amdgpu_trap_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> +		      struct amdgpu_trap_obj **trap_obj)
> +{
> +	struct amdgpu_bo_param bp;
> +	struct iosys_map map;
> +	struct amdgpu_trap_obj *cwsr;
> +	struct amdgpu_bo *bo;
> +	struct drm_exec exec;
> +	int r;
> +
> +	if (!amdgpu_trap_is_enabled(adev))
> +		return -EOPNOTSUPP;
> +
> +	if (!vm || !trap_obj)
> +		return -EINVAL;
> +
> +	cwsr = kzalloc_obj(*cwsr, GFP_KERNEL);
> +	if (!cwsr)
> +		return -ENOMEM;
> +
> +	bo = adev->trap_info->isa_bo;
> +
> +	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
> +	drm_exec_until_all_locked(&exec) {
> +		r = amdgpu_vm_lock_pd(vm, &exec, 0);
> +		drm_exec_retry_on_contention(&exec);
> +		if (unlikely(r))
> +			goto err_exec;
> +
> +		r = drm_exec_lock_obj(&exec, &bo->tbo.base);
> +		drm_exec_retry_on_contention(&exec);
> +		if (unlikely(r))
> +			goto err_exec;
> +	}
> +
> +	/*
> +	 * Create the TMA BO with the VM root reservation. The reservation is
> +	 * already held by drm_exec, so creating the BO doesn't recursively
> +	 * acquire another reservation_ww_class_mutex. The TMA remains
> +	 * unpinned and is covered by the VM root reservation.
> +	 */
> +	memset(&bp, 0, sizeof(bp));
> +	bp.size = AMDGPU_TRAP_TMA_MAX_SIZE;
> +	bp.byte_align = PAGE_SIZE;
> +	bp.domain = AMDGPU_GEM_DOMAIN_GTT;
> +	bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC |
> +		   AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
> +	bp.type = ttm_bo_type_kernel;
> +	bp.bo_ptr_size = sizeof(struct amdgpu_bo);
> +	bp.resv = vm->root.bo->tbo.base.resv;
> +
> +	r = amdgpu_bo_create(adev, &bp, &cwsr->tma_bo);
> +	if (r)
> +		goto err_exec;
> +
> +	/*
> +	 * The TMA BO is unpinned and movable. Map it only while accessing
> +	 * its contents so that no CPU mapping can become stale across BO
> +	 * migration. ttm_bo_vmap() and ttm_bo_vunmap() require the BO
> +	 * reservation, which is the already held VM root reservation.
> +	 */
> +	r = ttm_bo_vmap(&cwsr->tma_bo->tbo, &map);
> +	if (r)
> +		goto err_tma;
> +
> +	/*
> +	 * Finish initialization with a DMA write barrier before allowing
> +	 * the GPU to observe the contents.
> +	 */
> +	iosys_map_memset(&map, 0, 0, AMDGPU_TRAP_TMA_MAX_SIZE);
> +	dma_wmb();
> +
> +	ttm_bo_vunmap(&cwsr->tma_bo->tbo, &map);
> +
> +	r = amdgpu_trap_map_region(adev, vm, cwsr, AMDGPU_TRAP_TMA);
> +	if (r)
> +		goto err_tma;
> +
> +	r = amdgpu_trap_map_region(adev, vm, cwsr, AMDGPU_TRAP_TBA);
> +	if (r) {
> +		amdgpu_trap_unmap_region(adev, cwsr, AMDGPU_TRAP_TMA);
> +		goto err_tma;
> +	}
> +
> +	drm_exec_fini(&exec);
> +
> +	*trap_obj = cwsr;
> +
> +	return 0;
> +
> +err_tma:
> +	amdgpu_bo_unref(&cwsr->tma_bo);
> +
> +err_exec:
> +	drm_exec_fini(&exec);
> +	kfree(cwsr);
> +	*trap_obj = NULL;
> +
> +	return r;
> +}
> +
> +static int amdgpu_trap_update_l2_handler(struct amdgpu_trap_obj *trap_obj,
> +					 u64 tba, u64 tma)
> +{
> +	struct iosys_map map;
> +	int r;
> +
> +	if (!trap_obj || !trap_obj->tma_bo)
> +		return -EINVAL;
> +
> +	dma_resv_assert_held(trap_obj->tma_bo->tbo.base.resv);
> +
> +	r = ttm_bo_vmap(&trap_obj->tma_bo->tbo, &map);
> +	if (r)
> +		return r;
> +
> +	/*
> +	 * Publish both descriptor fields before allowing the GPU to observe
> +	 * the updated second-level trap handler.
> +	 */
> +	iosys_map_wr(&map, AMDGPU_TRAP_L2_TBA_INDEX * sizeof(u64),
> +		     u64, tba);
> +	iosys_map_wr(&map, AMDGPU_TRAP_L2_TMA_INDEX * sizeof(u64),
> +		     u64, tma);
> +	dma_wmb();
> +
> +	ttm_bo_vunmap(&trap_obj->tma_bo->tbo, &map);
> +
> +	return 0;
> +}
> +
> +static int amdgpu_trap_clear_l2_handler(struct amdgpu_vm *vm,
> +					struct amdgpu_trap_obj *trap_obj)
> +{
> +	if (!trap_obj || !trap_obj->tma_bo)
> +		return -EINVAL;
> +
> +	dma_resv_assert_held(vm->root.bo->tbo.base.resv);
> +
> +	return amdgpu_trap_update_l2_handler(trap_obj, 0, 0);
> +}
> +
> +int amdgpu_trap_validate_params(struct amdgpu_device *adev,
> +				struct amdgpu_trap_params *trap_params,
> +				int num_xcc)
> +{
> +	u32 min_size, max_size;
> +
> +	if (!amdgpu_trap_is_enabled(adev))
> +		return -EOPNOTSUPP;
> +
> +	if (!trap_params)
> +		return -EINVAL;
> +
> +	min_size = amdgpu_trap_size_needed(adev, num_xcc);
> +	max_size = 2 * min_size;
> +	/*
> +	 * Only save area size details checked. Address validation needs to be
> +	 * carried out separately. User is expected to pass a cwsr buffer area
> +	 * with size >= ctl stack size + wg data size + debug memory size
> +	 */
> +	if (trap_params->cwsr_sz < min_size ||
> +	    trap_params->cwsr_sz > max_size) {
> +		dev_dbg(adev->dev,
> +			"queue cwsr size 0x%x should be within min %u : max %u\n",
> +			trap_params->cwsr_sz, min_size, max_size);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +void amdgpu_trap_free(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> +		      struct amdgpu_trap_obj **trap_obj)
> +{
> +	struct amdgpu_bo *tba_bo;
> +	struct drm_exec exec;
> +	int r;
> +
> +	if (!trap_obj || !*trap_obj)
> +		return;
> +
> +	tba_bo = adev->trap_info->isa_bo;
> +
> +	drm_exec_init(&exec, 0, 0);
> +	drm_exec_until_all_locked(&exec) {
> +		r = amdgpu_vm_lock_pd(vm, &exec, 0);
> +		drm_exec_retry_on_contention(&exec);
> +		if (unlikely(r))
> +			goto out_exec;
> +
> +		if (tba_bo) {
> +			r = drm_exec_lock_obj(&exec, &tba_bo->tbo.base);
> +			drm_exec_retry_on_contention(&exec);
> +			if (unlikely(r))
> +				goto out_exec;
> +		}
> +	}
> +
> +	if ((*trap_obj)->tba_va) {
> +		amdgpu_vm_bo_del(adev, (*trap_obj)->tba_va);
> +		(*trap_obj)->tba_va = NULL;
> +	}
> +
> +	if ((*trap_obj)->tma_va) {
> +		amdgpu_vm_bo_del(adev, (*trap_obj)->tma_va);
> +		(*trap_obj)->tma_va = NULL;
> +	}
> +
> +	drm_exec_fini(&exec);
> +	amdgpu_bo_unref(&(*trap_obj)->tma_bo);
> +	kfree(*trap_obj);
> +	*trap_obj = NULL;
> +
> +	return;
> +
> +out_exec:
> +	drm_exec_fini(&exec);
> +}
> +
> +static int amdgpu_trap_validate_user_addr(struct amdgpu_device *adev,
> +					  struct amdgpu_vm *vm,
> +					 struct amdgpu_trap_usr_addr *usr_addr)
> +{
> +	struct amdgpu_bo_va_mapping *va_map;
> +	u64 start, end, addr, last;
> +
> +	if (!usr_addr || !usr_addr->size)
> +		return -EINVAL;
> +
> +	dma_resv_assert_held(vm->root.bo->tbo.base.resv);
> +
> +	start = usr_addr->addr & AMDGPU_GMC_HOLE_MASK;
> +
> +	if (check_add_overflow(start, (u64)usr_addr->size - 1, &end))
> +		return -EINVAL;
> +
> +	addr = start >> AMDGPU_GPU_PAGE_SHIFT;
> +	last = end >> AMDGPU_GPU_PAGE_SHIFT;
> +
> +	va_map = amdgpu_vm_bo_lookup_mapping(vm, addr);
> +	if (!va_map)
> +		return -EINVAL;
> +
> +	if (addr < va_map->start || last > va_map->last)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +int amdgpu_trap_vm_set_l2_trap(struct amdgpu_device *adev,
> +			       struct amdgpu_vm *vm,
> +			       struct amdgpu_trap_obj *trap_obj,
> +			       u64 tba_va, uint32_t tba_sz,
> +			       u64 tma_va, uint32_t tma_sz)
> +{
> +	struct amdgpu_trap_usr_addr tba = {
> +		.addr = tba_va,
> +		.size = tba_sz,
> +	};
> +	struct amdgpu_trap_usr_addr tma = {
> +		.addr = tma_va,
> +		.size = tma_sz,
> +	};
> +	long timeout;
> +	int r;
> +
> +	if (!amdgpu_trap_is_enabled(adev))
> +		return -EOPNOTSUPP;
> +
> +	if (!vm || !trap_obj || !trap_obj->tma_bo)
> +		return -EINVAL;
> +
> +	r = amdgpu_bo_reserve(vm->root.bo, false);
> +	if (r)
> +		return r;
> +
> +	timeout = dma_resv_wait_timeout(vm->root.bo->tbo.base.resv,
> +					DMA_RESV_USAGE_BOOKKEEP,
> +					true, MAX_SCHEDULE_TIMEOUT);
> +	if (timeout <= 0) {
> +		r = timeout < 0 ? timeout : -ETIMEDOUT;
> +		goto out_unreserve;
> +	}
> +
> +	r = amdgpu_trap_validate_user_addr(adev, vm, &tba);
> +	if (r)
> +		goto out_unreserve;
> +
> +	r = amdgpu_trap_validate_user_addr(adev, vm, &tma);
> +	if (r)
> +		goto out_unreserve;
> +
> +	r = amdgpu_trap_update_l2_handler(trap_obj, tba_va, tma_va);
> +
> +out_unreserve:
> +	amdgpu_bo_unreserve(vm->root.bo);
> +
> +	return r;
> +}
> +
> +int amdgpu_trap_vm_clear_l2_trap(struct amdgpu_device *adev,
> +				 struct amdgpu_vm *vm,
> +				 struct amdgpu_trap_obj *trap_obj)
> +{
> +	long timeout;
> +	int r;
> +
> +	if (!amdgpu_trap_is_enabled(adev))
> +		return -EOPNOTSUPP;
> +
> +	if (!vm || !trap_obj || !trap_obj->tma_bo)
> +		return -EINVAL;
> +
> +	r = amdgpu_bo_reserve(vm->root.bo, false);
> +	if (r)
> +		return r;
> +
> +	timeout = dma_resv_wait_timeout(vm->root.bo->tbo.base.resv,
> +					DMA_RESV_USAGE_BOOKKEEP,
> +					true, MAX_SCHEDULE_TIMEOUT);
> +	if (timeout <= 0) {
> +		r = timeout < 0 ? timeout : -ETIMEDOUT;
> +		goto out_unreserve;
> +	}
> +
> +	r = amdgpu_trap_clear_l2_handler(vm, trap_obj);
> +
> +out_unreserve:
> +	amdgpu_bo_unreserve(vm->root.bo);
> +
> +	return r;
> +}
> +
> +int amdgpu_trap_set_trap_debug_flag(struct amdgpu_device *adev,
> +				    struct amdgpu_vm *vm,
> +				    struct amdgpu_trap_obj *trap_obj,
> +				    bool enabled)
> +{
> +	struct iosys_map map;
> +	int r;
> +
> +	if (!amdgpu_trap_is_enabled(adev))
> +		return -EOPNOTSUPP;
> +
> +	if (!vm || !trap_obj || !trap_obj->tma_bo)
> +		return -EINVAL;
> +
> +	r = amdgpu_bo_reserve(vm->root.bo, false);
> +	if (r)
> +		return r;
> +
> +	r = ttm_bo_vmap(&trap_obj->tma_bo->tbo, &map);
> +	if (r)
> +		goto out_unreserve;
> +
> +	iosys_map_wr(&map, AMDGPU_TRAP_DEBUG_FLAG_INDEX * sizeof(u64),
> +		     u64, (u64)enabled);
> +	dma_wmb();
> +
> +	ttm_bo_vunmap(&trap_obj->tma_bo->tbo, &map);
> +
> +out_unreserve:
> +	amdgpu_bo_unreserve(vm->root.bo);
> +
> +	return r;
> +}
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h
> new file mode 100644
> index 000000000000..c78c60e3d18d
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h
> @@ -0,0 +1,143 @@
> +/*
> + * Copyright 2025 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef AMDGPU_TRAP_H
> +#define AMDGPU_TRAP_H
> +
> +#include <linux/types.h>
> +
> +struct amdgpu_bo;
> +struct amdgpu_bo_va;
> +struct amdgpu_device;
> +struct amdgpu_vm;
> +
> +/**
> + * struct amdgpu_trap_obj - per-GPUVM CWSR trap-handler state
> + * @tma_gpu_va_addr: GPU virtual address of the first-level TMA
> + * @tba_gpu_va_addr: GPU virtual address of the first-level TBA
> + * @tma_bo: buffer object backing the first-level TMA
> + * @tba_va: VM mapping of the first-level TBA
> + * @tma_va: VM mapping of the first-level TMA
> + */
> +struct amdgpu_trap_obj {
> +	u64 tma_gpu_va_addr;
> +	u64 tba_gpu_va_addr;
> +
> +	struct amdgpu_bo *tma_bo;
> +	struct amdgpu_bo_va *tba_va;
> +	struct amdgpu_bo_va *tma_va;
> +};
> +
> +struct amdgpu_trap_info {
> +	/* cwsr isa */
> +	struct amdgpu_bo *isa_bo;
> +	const void *isa_buf;
> +	u32 isa_sz;
> +
> +	/* cwsr size info per XCC */
> +	struct {
> +		u32 xcc_ctl_stack_sz;
> +		u32 xcc_dbg_mem_sz;
> +		u32 xcc_cwsr_sz;
> +	} cwsr;
> +};
> +
> +struct amdgpu_trap_params {
> +	u64 ctx_save_area_address;
> +
> +	/* cwsr size info */
> +	u32 cwsr_sz;
> +};
> +
> +struct amdgpu_trap_usr_addr {
> +	u64 addr;
> +	u32 size;
> +};
> +
> +int amdgpu_trap_init(struct amdgpu_device *adev);
> +void amdgpu_trap_fini(struct amdgpu_device *adev);
> +
> +int amdgpu_trap_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> +		      struct amdgpu_trap_obj **trap_obj);
> +
> +void amdgpu_trap_free(struct amdgpu_device *adev,
> +		      struct amdgpu_vm *vm,
> +		      struct amdgpu_trap_obj **trap_obj);
> +
> +static inline bool amdgpu_trap_is_enabled(struct amdgpu_device *adev)
> +{
> +	return adev->trap_info;
> +}
> +
> +uint32_t amdgpu_trap_size_needed(struct amdgpu_device *adev, int num_xcc);
> +
> +int amdgpu_trap_validate_params(struct amdgpu_device *adev,
> +				struct amdgpu_trap_params *trap_params,
> +				int num_xcc);
> +
> +static inline bool amdgpu_trap_has_dbg_wa(struct amdgpu_device *adev)
> +{
> +	u32 gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
> +
> +	return gc_ver >= IP_VERSION(11, 0, 0) &&
> +	       gc_ver <= IP_VERSION(11, 0, 3);
> +}
> +
> +/**
> + * amdgpu_trap_vm_set_l2_trap - install the second-level trap handler
> + * @adev: AMDGPU device
> + * @vm: GPUVM owning the first-level trap state
> + * @trap_obj: first-level trap object
> + * @tba_va: GPU virtual address of the second-level TBA
> + * @tba_sz: size of the second-level TBA
> + * @tma_va: GPU virtual address of the second-level TMA
> + * @tma_sz: size of the second-level TMA
> + *
> + * The second-level trap handler is configured per GPUVM. The descriptor is
> + * stored in the per-GPUVM first-level TMA.
> + *
> + * Return: 0 on success or a negative error code on failure.
> + */
> +int amdgpu_trap_vm_set_l2_trap(struct amdgpu_device *adev,
> +			       struct amdgpu_vm *vm,
> +			       struct amdgpu_trap_obj *trap_obj,
> +			       u64 tba_va, uint32_t tba_sz,
> +			       u64 tma_va, uint32_t tma_sz);
> +
> +/**
> + * amdgpu_trap_vm_clear_l2_trap - clear the second-level trap handler
> + * @adev: AMDGPU device
> + * @vm: GPUVM owning the first-level trap state
> + * @trap_obj: first-level trap object
> + *
> + * Return: 0 on success or a negative error code on failure.
> + */
> +int amdgpu_trap_vm_clear_l2_trap(struct amdgpu_device *adev,
> +				 struct amdgpu_vm *vm,
> +				 struct amdgpu_trap_obj *trap_obj);
> +
> +int amdgpu_trap_set_trap_debug_flag(struct amdgpu_device *adev,
> +				    struct amdgpu_vm *vm,
> +				    struct amdgpu_trap_obj *trap_obj,
> +				    bool enabled);
> +
> +#endif
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> index 6eea0ca40556..b4c91e8cd37e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> @@ -35,7 +35,7 @@
>  #include "amdgpu_hmm.h"
>  #include "amdgpu_userq_fence.h"
>  #include "amdgpu_trace.h"
> -#include "amdgpu_cwsr.h"
> +#include "amdgpu_trap.h"
>  
>  u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev)
>  {
> @@ -267,9 +267,8 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
>  	return -EINVAL;
>  }
>  
> -int amdgpu_userq_input_cwsr_params_validate(
> -	struct amdgpu_usermode_queue *queue,
> -	struct amdgpu_cwsr_params *cwsr_params)
> +int amdgpu_userq_input_trap_params_validate(struct amdgpu_usermode_queue *queue,
> +					    struct amdgpu_trap_params *trap_params)
>  {
>  	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(queue->userq_mgr);
>  	struct amdgpu_device *adev = queue->userq_mgr->adev;
> @@ -278,16 +277,16 @@ int amdgpu_userq_input_cwsr_params_validate(
>  	int r;
>  
>  	num_xcc = amdgpu_xcp_get_num_xcc(adev->xcp_mgr, fpriv->xcp_id);
> -	r = amdgpu_cwsr_validate_params(queue->userq_mgr->adev, cwsr_params,
> +	r = amdgpu_trap_validate_params(queue->userq_mgr->adev, trap_params,
>  					num_xcc);
>  	if (r)
>  		return r;
> -	cwsr_size = amdgpu_cwsr_size_needed(queue->userq_mgr->adev, num_xcc);
> +	cwsr_size = amdgpu_trap_size_needed(queue->userq_mgr->adev, num_xcc);
>  	if (!cwsr_size)
>  		return -EOPNOTSUPP;
>  
>  	return amdgpu_userq_input_va_validate(
> -		adev, queue, cwsr_params->ctx_save_area_address, cwsr_size,
> +		adev, queue, trap_params->ctx_save_area_address, cwsr_size,
>  		&queue->userq_vas.va.cwsr);
>  }
>  
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
> index 727f60c40bbf..5eb0f3ee9b4e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
> @@ -41,7 +41,7 @@ enum amdgpu_userq_state {
>  };
>  
>  struct amdgpu_mqd_prop;
> -struct amdgpu_cwsr_params;
> +struct amdgpu_trap_params;
>  
>  struct amdgpu_userq_obj {
>  	void		 *cpu_ptr;
> @@ -202,8 +202,7 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
>  
>  void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
>  					struct amdgpu_bo_va_mapping *mapping);
> -int amdgpu_userq_input_cwsr_params_validate(
> -	struct amdgpu_usermode_queue *queue,
> -	struct amdgpu_cwsr_params *cwsr_params);
> +int amdgpu_userq_input_trap_params_validate(struct amdgpu_usermode_queue *queue,
> +					    struct amdgpu_trap_params *trap_params);
>  
>  #endif
> diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
> index 5311e1ad0201..07b653909943 100644
> --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
> +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
> @@ -27,7 +27,7 @@
>  #include "mes_userqueue.h"
>  #include "amdgpu_userq_fence.h"
>  #include "amdgpu_trace.h"
> -#include "amdgpu_cwsr.h"
> +#include "amdgpu_trap.h"
>  
>  #define AMDGPU_USERQ_PROC_CTX_SZ PAGE_SIZE
>  #define AMDGPU_USERQ_GANG_CTX_SZ PAGE_SIZE
> @@ -148,10 +148,10 @@ static int mes_userq_map(struct amdgpu_usermode_queue *queue)
>  	queue_input.page_table_base_addr = amdgpu_gmc_pd_addr(queue->vm->root.bo);
>  	queue_input.wptr_mc_addr = queue->wptr_obj.gpu_addr;
>  
> -	if (fpriv->cwsr_trap) {
> -		queue_input.tba_addr = fpriv->cwsr_trap->tba_gpu_va_addr;
> -		queue_input.tma_addr = fpriv->cwsr_trap->tma_gpu_va_addr;
> -		queue_input.trap_en = !amdgpu_cwsr_has_dbg_wa(adev);
> +	if (fpriv->trap_obj) {
> +		queue_input.tba_addr = fpriv->trap_obj->tba_gpu_va_addr;
> +		queue_input.tma_addr = fpriv->trap_obj->tma_gpu_va_addr;
> +		queue_input.trap_en = !amdgpu_trap_has_dbg_wa(adev);
>  	}
>  
>  	if (mes->use_rs64mem) {
> @@ -415,7 +415,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
>  
>  	if (queue->queue_type == AMDGPU_HW_IP_COMPUTE) {
>  		struct drm_amdgpu_userq_mqd_compute_gfx11 *compute_mqd;
> -		struct amdgpu_cwsr_params cwsr_params;
> +		struct amdgpu_trap_params trap_params;
>  
>  		if (mqd_user->mqd_size != sizeof(*compute_mqd)) {
>  			DRM_ERROR("Invalid compute IP MQD size\n");
> @@ -453,16 +453,16 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
>  		userq_props->tmz_queue =
>  			mqd_user->flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_SECURE;
>  
> -		if (amdgpu_cwsr_is_enabled(adev)) {
> +		if (amdgpu_trap_is_enabled(adev)) {
>  			struct amdgpu_fpriv *fpriv =
>  				uq_mgr_to_fpriv(queue->userq_mgr);
>  			int num_xcc;
>  
>  			num_xcc = amdgpu_xcp_get_num_xcc(adev->xcp_mgr,
>  							 fpriv->xcp_id);
> -			cwsr_params.ctx_save_area_address =
> +			trap_params.ctx_save_area_address =
>  				compute_mqd->ctx_save_area_va;
> -			cwsr_params.cwsr_sz =
> +			trap_params.cwsr_sz =
>  				compute_mqd->ctx_save_area_size;
>  
>  			r = amdgpu_bo_reserve(queue->vm->root.bo, false);
> @@ -471,8 +471,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
>  				goto free_mqd;
>  			}
>  
> -			r = amdgpu_userq_input_cwsr_params_validate(
> -				queue, &cwsr_params);
> +			r = amdgpu_userq_input_trap_params_validate(
> +				queue, &trap_params);
>  			amdgpu_bo_unreserve(queue->vm->root.bo);
>  			if (r) {
>  				kfree(compute_mqd);
> @@ -484,7 +484,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
>  			userq_props->ctx_save_area_size =
>  				compute_mqd->ctx_save_area_size;
>  			userq_props->ctl_stack_size =
> -				adev->cwsr_info->xcc_ctl_stack_sz * num_xcc;
> +				adev->trap_info->cwsr.xcc_ctl_stack_sz * num_xcc;
>  		}
>  
>  		kfree(compute_mqd);


  reply	other threads:[~2026-10-12 14:08 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-08  7:05 [PATCH 0/7] drm/amdgpu: Add CWSR and second-level trap handler support Srinivasan Shanmugam
2026-10-08  7:05 ` [PATCH 1/7] drm/amdgpu: Add CWSR infrastructure for user queues Srinivasan Shanmugam
2026-10-12 11:47   ` Christian König
2026-10-08  7:05 ` [PATCH 2/7] drm/amdgpu: Integrate CWSR with " Srinivasan Shanmugam
2026-10-12 13:12   ` Christian König
2026-10-08  7:05 ` [PATCH 3/7] drm/amdgpu: Add CWSR userspace interfaces Srinivasan Shanmugam
2026-10-12 13:14   ` Christian König
2026-10-08  7:05 ` [PATCH 4/7] drm/amdgpu: Add second-level trap handler infrastructure Srinivasan Shanmugam
2026-10-12 14:07   ` Christian König [this message]
2026-10-08  7:05 ` [PATCH 5/7] drm/amdgpu: Make first-level trap state GPUVM-owned Srinivasan Shanmugam
2026-10-12 14:32   ` Christian König
2026-10-14  9:01     ` SRINIVASAN SHANMUGAM
2026-10-08  7:05 ` [PATCH 6/7] drm/amdgpu: Program trap TBA/TMA for kernel-managed VMIDs Srinivasan Shanmugam
2026-10-12 15:05   ` Christian König
2026-10-08  7:05 ` [PATCH 7/7] drm/amdgpu/uapi: Add SET/CLEAR L2 TRAP to VM ioctl Srinivasan Shanmugam
2026-10-12 15:10   ` Christian König

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d6cc0c25-bbee-48b4-9a84-3a79fa82dff5@amd.com \
    --to=christian.koenig@amd.com \
    --cc=alexander.deucher@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=felix.kuehling@amd.com \
    --cc=hakzsam@gmail.com \
    --cc=james.zhu@amd.com \
    --cc=lancelot.six@amd.com \
    --cc=lijo.lazar@amd.com \
    --cc=natalie.vock@gmx.de \
    --cc=pierre-eric.pelloux-prayer@amd.com \
    --cc=srinivasan.shanmugam@amd.com \
    --cc=timur.kristof@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.