From 858f5b2bcf82254397f8dea448097ef89d56c6cb Mon Sep 17 00:00:00 2001 From: "Jesse.Zhang" Date: Sat, 4 Oct 2025 22:39:24 +0800 Subject: [PATCH 01/62] drm/amd/pm: Disable VCN queue reset on SMU v13.0.6 due to regression Disable VCN reset capability for the program 4 as it's causing regressions. Reviewed-by: Lijo Lazar Signed-off-by: Jesse Zhang --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index c2bb578150fbf..6f70ea756ce1a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -458,8 +458,7 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu) ((pgm == 4) && (fw_ver >= 0x4557000))) smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET)); - if (((pgm == 0) && (fw_ver >= 0x00558200)) || - ((pgm == 4) && (fw_ver >= 0x04557100))) + if ((pgm == 0) && (fw_ver >= 0x00558200)) smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET)); } From 6ff5abe81c63588f518d8b51044d7b67b64ba289 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 8 Oct 2025 10:26:47 +0530 Subject: [PATCH 02/62] drm/amdgpu: Skip SDMA suspend during mode-2 reset For SDMA IP versions >= v4.4.2, firmware will take care of quiescing SDMA before mode-2 reset. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal --- drivers/gpu/drm/amd/amdgpu/aldebaran.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 9569dc16dd3da..daa7b23bc7750 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -88,6 +88,10 @@ static int aldebaran_mode2_suspend_ip(struct amdgpu_device *adev) uint32_t ip_block; int r, i; + /* Skip suspend of SDMA IP versions >= 4.4.2. They are multi-aid */ + if (adev->aid_mask) + ip_block_mask &= ~BIT(AMD_IP_BLOCK_TYPE_SDMA); + amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); From 11d35db5c11e5befb72324da1d7b56b5e9341e11 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Fri, 10 Oct 2025 16:24:01 +0800 Subject: [PATCH 03/62] drm/amdkcl: fix suballoc helper availability for distro kernels Some distribution kernels include drm/drm_suballoc.h header but have CONFIG_DRM_SUBALLOC_HELPER disabled. This causes build failures as the suballoc symbols are unavailable from the main DRM subsystem. Move the #endif directive for HAVE_DRM_DRM_SUBALLOC_H to properly expose KCL suballoc fallback implementations when the main DRM suballoc helper is not available. This ensures amdgpu can use kcl_drm_suballoc functions as fallback and resolves DKMS build failures on such configurations. Signed-off-by: Perry Yuan Reviewed-by: Bob Zhou (cherry picked from commit f72c0179d8407660cdbfb3af96723d1b477d09ed) Change-Id: I67fd4b4ba50674791d1e07dd7fc1a900886af253 --- include/kcl/kcl_drm_suballoc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/kcl/kcl_drm_suballoc.h b/include/kcl/kcl_drm_suballoc.h index 7629274cc4a0a..8a176ebc933ed 100644 --- a/include/kcl/kcl_drm_suballoc.h +++ b/include/kcl/kcl_drm_suballoc.h @@ -51,6 +51,7 @@ struct drm_suballoc { size_t eoffset; struct dma_fence *fence; }; +#endif /*HAVE_DRM_DRM_SUBALLOC_H*/ #ifndef HAVE_DRM_SUBALLOC_MANAGER_INIT void kcl_drm_suballoc_manager_init(struct drm_suballoc_manager *sa_manager, @@ -119,6 +120,5 @@ kcl_drm_suballoc_dump_debug_info(struct drm_suballoc_manager *sa_manager, #define drm_suballoc_dump_debug_info kcl_drm_suballoc_dump_debug_info #endif /* HAVE_DRM_SUBALLOC_MANAGER_INIT */ -#endif /*HAVE_DRM_DRM_SUBALLOC_H*/ #endif /* _KCL_DRM_SUBALLOC_H_ */ From bccf33390982e03523b861239fb68518108500ff Mon Sep 17 00:00:00 2001 From: Sathishkumar S Date: Fri, 10 Oct 2025 23:32:40 +0530 Subject: [PATCH 04/62] drm/amdgpu: fix bit shift logic BIT_ULL(n) sets nth bit, remove explicit shift and set the position Fixes: e30383fce4cb ("drm/amdgpu: fix shift-out-of-bounds in amdgpu_debugfs_jpeg_sched_mask_set") Signed-off-by: Sathishkumar S Reviewed-by: Leo Liu --- drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c index e7b4b768f7d21..91678621f1ff7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c @@ -370,7 +370,7 @@ static int amdgpu_debugfs_jpeg_sched_mask_set(void *data, u64 val) for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { ring = &adev->jpeg.inst[i].ring_dec[j]; - if (val & (BIT_ULL(1) << ((i * adev->jpeg.num_jpeg_rings) + j))) + if (val & (BIT_ULL((i * adev->jpeg.num_jpeg_rings) + j))) ring->sched.ready = true; else ring->sched.ready = false; From e85ca181ff8cc6901b86f8fcb966fd489f9e07d2 Mon Sep 17 00:00:00 2001 From: Victor Zhao Date: Thu, 9 Oct 2025 10:38:28 +0800 Subject: [PATCH 05/62] drm/amdgpu: Add kiq hdp flush callbacks Add kiq hdp flush callbacks for gfx ips to support gpu hdp flush when no ring presents Reviewed-by: Lijo Lazar Signed-off-by: Victor Zhao --- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 5 +++-- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 1 + 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 279be67679994..7e2d47ff7f630 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -10083,6 +10083,7 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_kiq = { .emit_wreg = gfx_v10_0_ring_emit_wreg, .emit_reg_wait = gfx_v10_0_ring_emit_reg_wait, .emit_reg_write_reg_wait = gfx_v10_0_ring_emit_reg_write_reg_wait, + .emit_hdp_flush = gfx_v10_0_ring_emit_hdp_flush, }; static void gfx_v10_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 39e8cbb2b5034..2cedfacdc35ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -2438,7 +2438,7 @@ static int gfx_v11_0_rlc_load_microcode(struct amdgpu_device *adev) if (version_minor == 3) gfx_v11_0_load_rlcp_rlcv_microcode(adev); } - + return 0; } @@ -3886,7 +3886,7 @@ static int gfx_v11_0_cp_compute_load_microcode(struct amdgpu_device *adev) } memcpy(fw, fw_data, fw_size); - + amdgpu_bo_kunmap(adev->gfx.mec.mec_fw_obj); amdgpu_bo_unreserve(adev->gfx.mec.mec_fw_obj); @@ -7331,6 +7331,7 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_kiq = { .emit_wreg = gfx_v11_0_ring_emit_wreg, .emit_reg_wait = gfx_v11_0_ring_emit_reg_wait, .emit_reg_write_reg_wait = gfx_v11_0_ring_emit_reg_write_reg_wait, + .emit_hdp_flush = gfx_v11_0_ring_emit_hdp_flush, }; static void gfx_v11_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index c95d907f1faa1..5db6226f5e672 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -5608,6 +5608,7 @@ static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_kiq = { .emit_wreg = gfx_v12_0_ring_emit_wreg, .emit_reg_wait = gfx_v12_0_ring_emit_reg_wait, .emit_reg_write_reg_wait = gfx_v12_0_ring_emit_reg_write_reg_wait, + .emit_hdp_flush = gfx_v12_0_ring_emit_hdp_flush, }; static void gfx_v12_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 7f740daf7415e..12a740f954d0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -7067,6 +7067,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = { .pad_ib = amdgpu_ring_generic_pad_ib, .emit_rreg = gfx_v8_0_ring_emit_rreg, .emit_wreg = gfx_v8_0_ring_emit_wreg, + .emit_hdp_flush = gfx_v8_0_ring_emit_hdp_flush, }; static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 63ccded25aa46..81cd7bdba23f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -7715,6 +7715,7 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = { .emit_wreg = gfx_v9_0_ring_emit_wreg, .emit_reg_wait = gfx_v9_0_ring_emit_reg_wait, .emit_reg_write_reg_wait = gfx_v9_0_ring_emit_reg_write_reg_wait, + .emit_hdp_flush = gfx_v9_0_ring_emit_hdp_flush, }; static void gfx_v9_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 59cba26049f17..cbf358d28c632 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -4962,6 +4962,7 @@ static const struct amdgpu_ring_funcs gfx_v9_4_3_ring_funcs_kiq = { .emit_wreg = gfx_v9_4_3_ring_emit_wreg, .emit_reg_wait = gfx_v9_4_3_ring_emit_reg_wait, .emit_reg_write_reg_wait = gfx_v9_4_3_ring_emit_reg_write_reg_wait, + .emit_hdp_flush = gfx_v9_4_3_ring_emit_hdp_flush, }; static void gfx_v9_4_3_set_ring_funcs(struct amdgpu_device *adev) From 4972be896a4174cd9719db215e573913ce904a97 Mon Sep 17 00:00:00 2001 From: Victor Zhao Date: Thu, 9 Oct 2025 10:42:48 +0800 Subject: [PATCH 06/62] drm/amdgpu: use GPU_HDP_FLUSH for sriov Currently SRIOV runtime will use kiq to write HDP_MEM_FLUSH_CNTL for hdp flush. This register need to be write from CPU for nbif to aware, otherwise it will not work. Implement amdgpu_kiq_hdp_flush and use kiq to do gpu hdp flush during sriov runtime. v2: - fallback to amdgpu_asic_flush_hdp when amdgpu_kiq_hdp_flush failed - add function amdgpu_mes_hdp_flush v3: - changed returned error Reviewed-by: Lijo Lazar Signed-off-by: Victor Zhao --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 13 +++- drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 71 ++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 12 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 1 + 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 5f075ac74d611..3d0a6809e4e7d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -7329,10 +7329,17 @@ void amdgpu_device_flush_hdp(struct amdgpu_device *adev, if (adev->gmc.xgmi.connected_to_cpu) return; - if (ring && ring->funcs->emit_hdp_flush) + if (ring && ring->funcs->emit_hdp_flush) { amdgpu_ring_emit_hdp_flush(ring); - else - amdgpu_asic_flush_hdp(adev, ring); + return; + } + + if (!ring && amdgpu_sriov_runtime(adev)) { + if (!amdgpu_kiq_hdp_flush(adev)) + return; + } + + amdgpu_asic_flush_hdp(adev, ring); } void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 7f02e36ccc1ea..3d24f9cd750a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -33,6 +33,7 @@ #include "amdgpu_reset.h" #include "amdgpu_xcp.h" #include "amdgpu_xgmi.h" +#include "amdgpu_mes.h" #include "nvd.h" /* delay 0.1 second to enable gfx off feature */ @@ -1194,6 +1195,75 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3 dev_err(adev->dev, "failed to write reg:%x\n", reg); } +int amdgpu_kiq_hdp_flush(struct amdgpu_device *adev) +{ + signed long r, cnt = 0; + unsigned long flags; + uint32_t seq; + struct amdgpu_kiq *kiq = &adev->gfx.kiq[0]; + struct amdgpu_ring *ring = &kiq->ring; + + if (amdgpu_device_skip_hw_access(adev)) + return 0; + + if (adev->enable_mes_kiq && adev->mes.ring[0].sched.ready) + return amdgpu_mes_hdp_flush(adev); + + if (!ring->funcs->emit_hdp_flush) { + return -EOPNOTSUPP; + } + + spin_lock_irqsave(&kiq->ring_lock, flags); + r = amdgpu_ring_alloc(ring, 32); + if (r) + goto failed_unlock; + + amdgpu_ring_emit_hdp_flush(ring); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) + goto failed_undo; + + amdgpu_ring_commit(ring); + spin_unlock_irqrestore(&kiq->ring_lock, flags); + + r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); + + /* don't wait anymore for gpu reset case because this way may + * block gpu_recover() routine forever, e.g. this virt_kiq_rreg + * is triggered in TTM and ttm_bo_lock_delayed_workqueue() will + * never return if we keep waiting in virt_kiq_rreg, which cause + * gpu_recover() hang there. + * + * also don't wait anymore for IRQ context + * */ + if (r < 1 && (amdgpu_in_reset(adev) || in_interrupt())) + goto failed_kiq_hdp_flush; + + might_sleep(); + while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) { + if (amdgpu_in_reset(adev)) + goto failed_kiq_hdp_flush; + + msleep(MAX_KIQ_REG_BAILOUT_INTERVAL); + r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); + } + + if (cnt > MAX_KIQ_REG_TRY) { + dev_err(adev->dev, "failed to flush HDP via KIQ timeout\n"); + return -ETIMEDOUT; + } + + return 0; + +failed_undo: + amdgpu_ring_undo(ring); +failed_unlock: + spin_unlock_irqrestore(&kiq->ring_lock, flags); +failed_kiq_hdp_flush: + dev_err(adev->dev, "failed to flush HDP via KIQ\n"); + return r < 0 ? r : -EIO; +} + int amdgpu_gfx_get_num_kcq(struct amdgpu_device *adev) { if (amdgpu_num_kcq == -1) { @@ -2484,3 +2554,4 @@ void amdgpu_debugfs_compute_sched_mask_init(struct amdgpu_device *adev) &amdgpu_debugfs_compute_sched_mask_fops); #endif } + diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 57e75a8078464..c1523bdee992c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -626,6 +626,7 @@ int amdgpu_gfx_cp_ecc_error_irq(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry); uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t xcc_id); void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t xcc_id); +int amdgpu_kiq_hdp_flush(struct amdgpu_device *adev); int amdgpu_gfx_get_num_kcq(struct amdgpu_device *adev); void amdgpu_gfx_cp_init_microcode(struct amdgpu_device *adev, uint32_t ucode_id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 5bf9be073cddf..d44e586c067ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -523,6 +523,18 @@ int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev, return r; } +int amdgpu_mes_hdp_flush(struct amdgpu_device *adev) +{ + uint32_t hdp_flush_req_offset, hdp_flush_done_offset, ref_and_mask; + + hdp_flush_req_offset = adev->nbio.funcs->get_hdp_flush_req_offset(adev); + hdp_flush_done_offset = adev->nbio.funcs->get_hdp_flush_done_offset(adev); + ref_and_mask = adev->nbio.hdp_flush_reg->ref_and_mask_cp0; + + return amdgpu_mes_reg_write_reg_wait(adev, hdp_flush_req_offset, hdp_flush_done_offset, + ref_and_mask, ref_and_mask); +} + int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, uint64_t process_context_addr, uint32_t spi_gdbg_per_vmid_cntl, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 49942a1cb8f52..a8f4ac564985b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -426,6 +426,7 @@ int amdgpu_mes_wreg(struct amdgpu_device *adev, int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev, uint32_t reg0, uint32_t reg1, uint32_t ref, uint32_t mask); +int amdgpu_mes_hdp_flush(struct amdgpu_device *adev); int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, uint64_t process_context_addr, uint32_t spi_gdbg_per_vmid_cntl, From cb2e207de9f3e0c2880ac769ba31d65096f2bbd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 7 Oct 2025 10:10:52 +0200 Subject: [PATCH 07/62] drm/amdgpu: hide VRAM sysfs attributes on GPUs without VRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise accessing them can cause a crash. Signed-off-by: Christian König Tested-by: Mangesh Gadre Acked-by: Alex Deucher Reviewed-by: Arunpravin Paneer Selvam (cherry picked from commit 02fdc6bd473459034137f04908355b4f6988c282) Change-Id: I1f8d0e98d509f7154ad5e60cef4269777e08dd62 --- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 02cbf9aaa2c60..3487bc738ba46 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -239,6 +239,9 @@ static umode_t amdgpu_vram_attrs_is_visible(struct kobject *kobj, !adev->gmc.vram_vendor) return 0; + if (!ttm_resource_manager_used(&adev->mman.vram_mgr.manager)) + return 0; + return attr->mode; } From d3b227e1cdd5921e0c1061452c8c5a0adde2fd55 Mon Sep 17 00:00:00 2001 From: Kent Russell Date: Fri, 28 Mar 2025 12:10:33 -0400 Subject: [PATCH 08/62] drm/amdkcl: Add Peerdirect checks for KFD Certain kernels may have integrated peer_mem into their base Linux module, while others may have it as a separate module. Link against the ofa_kernel as a last resort in case that's the only option available. Some older NICs can't support dma_buf, so this is required in order to get PeerDirect to work on NICs that don't support dma_buf Signed-off-by: Kent Russell Reviewed-by: Perry Yuan --- drivers/gpu/drm/amd/amdkfd/kfd_peerdirect.c | 13 ++++++--- drivers/gpu/drm/amd/dkms/Kbuild | 9 ++++++ drivers/gpu/drm/amd/dkms/config/config.h | 3 ++ drivers/gpu/drm/amd/dkms/m4/kernel.m4 | 1 + drivers/gpu/drm/amd/dkms/m4/peer_direct.m4 | 31 +++++++++++++++++++++ 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/amd/dkms/m4/peer_direct.m4 diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_peerdirect.c b/drivers/gpu/drm/amd/amdkfd/kfd_peerdirect.c index f7cd9661d5047..cd75d2432a9f8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_peerdirect.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_peerdirect.c @@ -86,7 +86,6 @@ */ #define IB_PEER_MEMORY_NAME_MAX 64 #define IB_PEER_MEMORY_VER_MAX 16 - struct peer_memory_client { char name[IB_PEER_MEMORY_NAME_MAX]; char version[IB_PEER_MEMORY_VER_MAX]; @@ -117,7 +116,6 @@ void *ib_register_peer_memory_client(struct peer_memory_client *peer_client, invalidate_peer_memory *invalidate_callback); void ib_unregister_peer_memory_client(void *reg_handle); - /*------------------- PeerDirect bridge driver ------------------------------*/ #define AMD_PEER_BRIDGE_DRIVER_VERSION "1.0" @@ -465,6 +463,10 @@ void kfd_init_peer_direct(void) pr_debug("Try to initialize PeerDirect support\n"); +#if defined(HAVE_KFD_PEERDIRECT_SUPPORT) + pfn_ib_register_peer_memory_client = ib_register_peer_memory_client; + pfn_ib_unregister_peer_memory_client = ib_unregister_peer_memory_client; +#else pfn_ib_register_peer_memory_client = (void *(*)(struct peer_memory_client *, invalidate_peer_memory *)) @@ -473,6 +475,7 @@ void kfd_init_peer_direct(void) pfn_ib_unregister_peer_memory_client = (void (*)(void *)) symbol_request(ib_unregister_peer_memory_client); +#endif if (!pfn_ib_register_peer_memory_client || !pfn_ib_unregister_peer_memory_client) { pr_debug("PeerDirect interface was not detected\n"); @@ -505,13 +508,15 @@ void kfd_close_peer_direct(void) if (pfn_ib_unregister_peer_memory_client) { if (ib_reg_handle) pfn_ib_unregister_peer_memory_client(ib_reg_handle); - +#if !defined(HAVE_KFD_PEERDIRECT_SUPPORT) symbol_put(ib_unregister_peer_memory_client); +#endif } +#if !defined(HAVE_KFD_PEERDIRECT_SUPPORT) if (pfn_ib_register_peer_memory_client) symbol_put(ib_register_peer_memory_client); - +#endif /* Reset pointers to be safe */ pfn_ib_unregister_peer_memory_client = NULL; diff --git a/drivers/gpu/drm/amd/dkms/Kbuild b/drivers/gpu/drm/amd/dkms/Kbuild index 02fb141c1d995..96a6424ce8378 100644 --- a/drivers/gpu/drm/amd/dkms/Kbuild +++ b/drivers/gpu/drm/amd/dkms/Kbuild @@ -32,6 +32,15 @@ LINUX_SRCTREE_INCLUDE := \ $(filter-out -I%/uapi "-include %/kconfig.h",$(_KCL_LINUXINCLUDE)) USER_INCLUDE := $(filter-out $(LINUX_SRCTREE_INCLUDE), $(_KCL_LINUXINCLUDE)) +# In the peerdirect m4, we determine if the p2p symbols are in the ofa_kernel's Module.symvers +# If so, we need to include the path for the function pointers, as well as the include path for +# rdma/peer_mem.h, since the ofa_kernel isn't integrated into the base kernel in that configuration +_is_kcl_macro_defined=$(shell grep $1 $(src)/amd/dkms/config/config.h | grep -q "define" && echo "y" || echo "n") +ifeq ($(call _is_kcl_macro_defined,HAVE_KFD_PEERDIRECT_SUPPORT_NEED_OFAPATH),y) +KBUILD_EXTRA_SYMBOLS += /usr/src/ofa_kernel/x86_64/$(KERNELRELEASE)/Module.symvers +USER_INCLUDE += -I/usr/src/ofa_kernel/x86_64/$(KERNELRELEASE)/include +endif + LINUXINCLUDE := \ -I$(src)/include \ -I$(src)/include/kcl/header \ diff --git a/drivers/gpu/drm/amd/dkms/config/config.h b/drivers/gpu/drm/amd/dkms/config/config.h index ebdae68c26743..a051966eb7093 100644 --- a/drivers/gpu/drm/amd/dkms/config/config.h +++ b/drivers/gpu/drm/amd/dkms/config/config.h @@ -862,6 +862,9 @@ /* kernel_write() take arg type of position as pointer */ #define HAVE_KERNEL_WRITE_PPOS 1 +/* HAVE_KFD_PEERDIRECT_SUPPORT is available */ +/* #undef HAVE_KFD_PEERDIRECT_SUPPORT */ + /* kfifo_out_linear() available */ #define HAVE_KFIFO_OUT_LINEAR 1 diff --git a/drivers/gpu/drm/amd/dkms/m4/kernel.m4 b/drivers/gpu/drm/amd/dkms/m4/kernel.m4 index 7d8b00ac6905f..3c1e8baa846d2 100644 --- a/drivers/gpu/drm/amd/dkms/m4/kernel.m4 +++ b/drivers/gpu/drm/amd/dkms/m4/kernel.m4 @@ -301,6 +301,7 @@ AC_DEFUN([AC_CONFIG_KERNEL], [ AC_AMDGPU_VFS_IOCB_ITER_READ AC_AMDGPU_LIST_IS_HEAD AC_AMDGPU_DEVM_I2C_ADD_ADAPTER + AC_AMDGPU_KFD_PEERDIRECT_SUPPORT AC_KERNEL_WAIT AS_IF([test "$LINUX_OBJ" != "$LINUX"], [ diff --git a/drivers/gpu/drm/amd/dkms/m4/peer_direct.m4 b/drivers/gpu/drm/amd/dkms/m4/peer_direct.m4 new file mode 100644 index 0000000000000..6447b6c16afac --- /dev/null +++ b/drivers/gpu/drm/amd/dkms/m4/peer_direct.m4 @@ -0,0 +1,31 @@ +dnl # +dnl # +dnl # PEER DIRECT support +dnl # +dnl # Note that some kernels will have rdma/peer_mem.h and general P2P +dnl # support included. We should check for that case first. If so, we +dnl # set p2p support to 1. +dnl # If the system uses the ofa_kernel, which is present outside of the +dnl # base kernel, then check if it exists and has a p2p symbol present. +dnl # If so, we set p2p support to 1, but also require setting the path +dnl # to the ofa_kernel, which is checked in Kbuild. +dnl # This way we can support configs that have p2p integrated into the +dnl # base kernel, or configs using the ofa_kernel +AC_DEFUN([AC_AMDGPU_KFD_PEERDIRECT_SUPPORT], [ + AC_KERNEL_DO_BACKGROUND([ + AC_KERNEL_TRY_COMPILE([ + #include + ], [ + struct peer_memory_client client; + ib_register_peer_memory_client(&client, NULL); + ], [ + AC_DEFINE(HAVE_KFD_PEERDIRECT_SUPPORT, 1, [HAVE_KFD_PEERDIRECT_SUPPORT is available]) + ], [ + AS_IF([ grep -qw ib_register_peer_memory_client /usr/src/ofa_kernel/x86_64/${KERNELVER}/Module.symvers ], [ + AC_DEFINE(HAVE_KFD_PEERDIRECT_SUPPORT, 1, [HAVE_KFD_PEERDIRECT_SUPPORT is available]) + AC_DEFINE(HAVE_KFD_PEERDIRECT_SUPPORT_NEED_OFAPATH, 1, [HAVE_KFD_PEERDIRECT_SUPPORT is available and needs OFA path]) + ]) + ]) + ]) +]) + From 7c33556176393cb274e783f960de2b902257b4f0 Mon Sep 17 00:00:00 2001 From: Ahmad Rehman Date: Wed, 5 Nov 2025 16:07:26 -0500 Subject: [PATCH 09/62] amdkfd: Do nto wait for queue op response during reset This patch adds the condition to not wait for the queue response for unmap, if the gpu is in reset. Signed-off-by: Ahmad Rehman Reviewed-by: Lijo Lazar --- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index b11c1e9c873da..f918ac807ce5a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -2133,7 +2133,8 @@ int amdkfd_fence_wait_timeout(struct device_queue_manager *dqm, while (*fence_addr != fence_value) { /* Fatal err detected, this response won't come */ - if (amdgpu_amdkfd_is_fed(dqm->dev->adev)) + if (amdgpu_amdkfd_is_fed(dqm->dev->adev) || + amdgpu_in_reset(dqm->dev->adev)) return -EIO; if (time_after(jiffies, end_jiffies)) { From ae161fb066e7b3841010ce4a895ee2f2455b68b6 Mon Sep 17 00:00:00 2001 From: Ellen Pan Date: Mon, 6 Oct 2025 15:47:45 -0500 Subject: [PATCH 10/62] drm/amdgpu: Updated naming of SRIOV critical region offsets/sizes with _V1 suffix - This change prepares the later patches to intro _v2 suffix to SRIOV critical regions Signed-off-by: Ellen Pan Reviewed-by: Alex Deucher (cherry picked from commit 2a3fd0a20754e3cb8d68daa7449d378b4482ca25) Change-Id: Ic0c69049913b47e72a019285b442931eb981a44b --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 20 ++++----- drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 50 +++++++++++++++------ 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 3328ab63376bb..e95adf0407a05 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -686,7 +686,7 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) /* got through this logic in early init stage to get necessary flags, e.g. rlcg_acc related*/ adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) - (adev->bios + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10)); + (adev->bios + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); amdgpu_virt_read_pf2vf_data(adev); } @@ -703,21 +703,21 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev) if (adev->mman.fw_vram_usage_va) { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10)); + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10)); + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.ras_telemetry = - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB << 10)); + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); } else if (adev->mman.drv_vram_usage_va) { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) - (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10)); + (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) - (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10)); + (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.ras_telemetry = - (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB << 10)); + (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); } amdgpu_virt_read_pf2vf_data(adev); @@ -1304,7 +1304,7 @@ static int amdgpu_virt_cache_host_error_counts(struct amdgpu_device *adev, checksum = host_telemetry->header.checksum; used_size = host_telemetry->header.used_size; - if (used_size > (AMD_SRIOV_RAS_TELEMETRY_SIZE_KB << 10)) + if (used_size > (AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1 << 10)) return 0; tmp = kmemdup(&host_telemetry->body.error_count, used_size, GFP_KERNEL); @@ -1383,7 +1383,7 @@ amdgpu_virt_write_cpers_to_ring(struct amdgpu_device *adev, checksum = host_telemetry->header.checksum; used_size = host_telemetry->header.used_size; - if (used_size > (AMD_SRIOV_RAS_TELEMETRY_SIZE_KB << 10)) + if (used_size > (AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1 << 10)) return -EINVAL; cper_dump = kmemdup(&host_telemetry->body.cper_dump, used_size, GFP_KERNEL); @@ -1515,7 +1515,7 @@ static int amdgpu_virt_cache_chk_criti_hit(struct amdgpu_device *adev, checksum = host_telemetry->header.checksum; used_size = host_telemetry->header.used_size; - if (used_size > (AMD_SRIOV_RAS_TELEMETRY_SIZE_KB << 10)) + if (used_size > (AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1 << 10)) return 0; tmp = kmemdup(&host_telemetry->body.chk_criti, used_size, GFP_KERNEL); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h index 3a79ed7d8031e..7509756b9ac5a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h @@ -23,26 +23,48 @@ #ifndef AMDGV_SRIOV_MSG__H_ #define AMDGV_SRIOV_MSG__H_ -/* unit in kilobytes */ -#define AMD_SRIOV_MSG_VBIOS_OFFSET 0 -#define AMD_SRIOV_MSG_VBIOS_SIZE_KB 64 -#define AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB AMD_SRIOV_MSG_VBIOS_SIZE_KB -#define AMD_SRIOV_MSG_DATAEXCHANGE_SIZE_KB 4 -#define AMD_SRIOV_MSG_TMR_OFFSET_KB 2048 -#define AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB 2 -#define AMD_SRIOV_RAS_TELEMETRY_SIZE_KB 64 +#define AMD_SRIOV_MSG_SIZE_KB 1 + /* - * layout + * layout v1 * 0 64KB 65KB 66KB 68KB 132KB * | VBIOS | PF2VF | VF2PF | Bad Page | RAS Telemetry Region | ... * | 64KB | 1KB | 1KB | 2KB | 64KB | ... */ -#define AMD_SRIOV_MSG_SIZE_KB 1 -#define AMD_SRIOV_MSG_PF2VF_OFFSET_KB AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB -#define AMD_SRIOV_MSG_VF2PF_OFFSET_KB (AMD_SRIOV_MSG_PF2VF_OFFSET_KB + AMD_SRIOV_MSG_SIZE_KB) -#define AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB (AMD_SRIOV_MSG_VF2PF_OFFSET_KB + AMD_SRIOV_MSG_SIZE_KB) -#define AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB (AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB + AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB) +/* + * layout v2 (offsets are dynamically allocated and the offsets below are examples) + * 0 1KB 64KB 65KB 66KB 68KB 132KB + * | INITD_H | VBIOS | PF2VF | VF2PF | Bad Page | RAS Telemetry Region | ... + * | 1KB | 64KB | 1KB | 1KB | 2KB | 64KB | ... + * + * Note: PF2VF + VF2PF + Bad Page = DataExchange region (allocated contiguously) + */ + +/* v1 layout sizes */ +#define AMD_SRIOV_MSG_VBIOS_SIZE_KB_V1 64 +#define AMD_SRIOV_MSG_PF2VF_SIZE_KB_V1 1 +#define AMD_SRIOV_MSG_VF2PF_SIZE_KB_V1 1 +#define AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB_V1 2 +#define AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1 64 +#define AMD_SRIOV_MSG_DATAEXCHANGE_SIZE_KB_V1 \ + (AMD_SRIOV_MSG_PF2VF_SIZE_KB_V1 + AMD_SRIOV_MSG_VF2PF_SIZE_KB_V1 + \ + AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB_V1) + +/* v1 offsets */ +#define AMD_SRIOV_MSG_VBIOS_OFFSET_V1 0 +#define AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB_V1 AMD_SRIOV_MSG_VBIOS_SIZE_KB_V1 +#define AMD_SRIOV_MSG_TMR_OFFSET_KB 2048 +#define AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB_V1 +#define AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 \ + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 + AMD_SRIOV_MSG_SIZE_KB) +#define AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB_V1 \ + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 + AMD_SRIOV_MSG_SIZE_KB) +#define AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 \ + (AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB_V1 + AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB_V1) +#define AMD_SRIOV_MSG_INIT_DATA_TOT_SIZE_KB_V1 \ + (AMD_SRIOV_MSG_VBIOS_SIZE_KB_V1 + AMD_SRIOV_MSG_DATAEXCHANGE_SIZE_KB_V1 + \ + AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1) /* * PF2VF history log: From e47760187bfa2d93e6c1d3e15c3b93beedf56590 Mon Sep 17 00:00:00 2001 From: Ellen Pan Date: Tue, 7 Oct 2025 09:46:16 -0500 Subject: [PATCH 11/62] drm/amdgpu: Add SRIOV crit_region_version support 1. Added enum amd_sriov_crit_region_version to support multi versions 2. Added logic in SRIOV mailbox to regonize crit_region version during req_gpu_init_data Signed-off-by: Ellen Pan Reviewed-by: Alex Deucher (cherry picked from commit 176de1520d0d050c755a7d89771d0d52403de49c) Change-Id: I736feee621a5c4a0fbc5244181791236dfc7b9d6 --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 5 +++-- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 8 +++++++ drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 5 +++++ drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c | 23 ++++++++++++++------- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index e95adf0407a05..39ab7d00379ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -150,9 +150,10 @@ void amdgpu_virt_request_init_data(struct amdgpu_device *adev) virt->ops->req_init_data(adev); if (adev->virt.req_init_data_ver > 0) - DRM_INFO("host supports REQ_INIT_DATA handshake\n"); + dev_info(adev->dev, "host supports REQ_INIT_DATA handshake of critical_region_version %d\n", + adev->virt.req_init_data_ver); else - DRM_WARN("host doesn't support REQ_INIT_DATA handshake\n"); + dev_warn(adev->dev, "host doesn't support REQ_INIT_DATA handshake\n"); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index d1172c8e58c47..36247a160aa63 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -262,6 +262,11 @@ struct amdgpu_virt_ras { DECLARE_ATTR_CAP_CLASS(amdgpu_virt, AMDGPU_VIRT_CAPS_LIST); +struct amdgpu_virt_region { + uint32_t offset; + uint32_t size_kb; +}; + /* GPU virtualization */ struct amdgpu_virt { uint32_t caps; @@ -289,6 +294,9 @@ struct amdgpu_virt { bool ras_init_done; uint32_t reg_access; + /* dynamic(v2) critical regions */ + struct amdgpu_virt_region init_data_header; + /* vf2pf message */ struct delayed_work vf2pf_work; uint32_t vf2pf_update_interval_ms; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h index 7509756b9ac5a..9228fd2c6dfd9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h @@ -66,6 +66,11 @@ (AMD_SRIOV_MSG_VBIOS_SIZE_KB_V1 + AMD_SRIOV_MSG_DATAEXCHANGE_SIZE_KB_V1 + \ AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1) +enum amd_sriov_crit_region_version { + GPU_CRIT_REGION_V1 = 1, + GPU_CRIT_REGION_V2 = 2, +}; + /* * PF2VF history log: * v1 defined in amdgim diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c index e5282a5d05d95..cd5b2f07edb89 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c @@ -222,12 +222,20 @@ static int xgpu_nv_send_access_requests_with_param(struct amdgpu_device *adev, adev->virt.req_init_data_ver = 0; } else { if (req == IDH_REQ_GPU_INIT_DATA) { - adev->virt.req_init_data_ver = - RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW1); - - /* assume V1 in case host doesn't set version number */ - if (adev->virt.req_init_data_ver < 1) - adev->virt.req_init_data_ver = 1; + switch (RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW1)) { + case GPU_CRIT_REGION_V2: + adev->virt.req_init_data_ver = GPU_CRIT_REGION_V2; + adev->virt.init_data_header.offset = + RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW2); + adev->virt.init_data_header.size_kb = + RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW3); + break; + default: + adev->virt.req_init_data_ver = GPU_CRIT_REGION_V1; + adev->virt.init_data_header.offset = -1; + adev->virt.init_data_header.size_kb = 0; + break; + } } } @@ -285,7 +293,8 @@ static int xgpu_nv_release_full_gpu_access(struct amdgpu_device *adev, static int xgpu_nv_request_init_data(struct amdgpu_device *adev) { - return xgpu_nv_send_access_requests(adev, IDH_REQ_GPU_INIT_DATA); + return xgpu_nv_send_access_requests_with_param(adev, IDH_REQ_GPU_INIT_DATA, + 0, GPU_CRIT_REGION_V2, 0); } static int xgpu_nv_mailbox_ack_irq(struct amdgpu_device *adev, From 509ddf48b7059af73274351c15770f98fdbfa039 Mon Sep 17 00:00:00 2001 From: Ellen Pan Date: Tue, 7 Oct 2025 11:00:16 -0500 Subject: [PATCH 12/62] drm/amdgpu: Introduce SRIOV critical regions v2 during VF init 1. Introduced amdgpu_virt_init_critical_region during VF init. - VFs use init_data_header_offset and init_data_header_size_kb transmitted via PF2VF mailbox to fetch the offset of critical regions' offsets/sizes in VRAM and save to adev->virt.crit_region_offsets and adev->virt.crit_region_sizes_kb. Signed-off-by: Ellen Pan Reviewed-by: Alex Deucher Reviewed-by: Lijo Lazar --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 + drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 174 ++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 11 ++ drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 31 ++++ 4 files changed, 220 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 3d0a6809e4e7d..dd634c3ef08b5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2779,6 +2779,10 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) r = amdgpu_virt_request_full_gpu(adev, true); if (r) return r; + + r = amdgpu_virt_init_critical_region(adev); + if (r) + return r; } switch (adev->asic_type) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 39ab7d00379ba..2a97d137f19c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -44,6 +44,18 @@ vf2pf_info->ucode_info[ucode].version = ver; \ } while (0) +#define mmRCC_CONFIG_MEMSIZE 0xde3 + +const char *amdgpu_virt_dynamic_crit_table_name[] = { + "IP DISCOVERY", + "VBIOS IMG", + "RAS TELEMETRY", + "DATA EXCHANGE", + "BAD PAGE INFO", + "INIT HEADER", + "LAST", +}; + bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev) { /* By now all MMIO pages except mailbox are blocked */ @@ -843,6 +855,168 @@ static void amdgpu_virt_init_ras(struct amdgpu_device *adev) adev->virt.ras.cper_rptr = 0; } +static uint8_t amdgpu_virt_crit_region_calc_checksum(uint8_t *buf_start, uint8_t *buf_end) +{ + uint32_t sum = 0; + + if (buf_start >= buf_end) + return 0; + + for (; buf_start < buf_end; buf_start++) + sum += buf_start[0]; + + return 0xffffffff - sum; +} + +int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) +{ + struct amd_sriov_msg_init_data_header *init_data_hdr = NULL; + uint32_t init_hdr_offset = adev->virt.init_data_header.offset; + uint32_t init_hdr_size = adev->virt.init_data_header.size_kb << 10; + uint64_t vram_size; + int r = 0; + uint8_t checksum = 0; + + /* Skip below init if critical region version != v2 */ + if (adev->virt.req_init_data_ver != GPU_CRIT_REGION_V2) + return 0; + + if (init_hdr_offset < 0) { + dev_err(adev->dev, "Invalid init header offset\n"); + return -EINVAL; + } + + vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); + if (!vram_size || vram_size == U32_MAX) + return -EINVAL; + vram_size <<= 20; + + if ((init_hdr_offset + init_hdr_size) > vram_size) { + dev_err(adev->dev, "init_data_header exceeds VRAM size, exiting\n"); + return -EINVAL; + } + + /* Allocate for init_data_hdr */ + init_data_hdr = kzalloc(sizeof(struct amd_sriov_msg_init_data_header), GFP_KERNEL); + if (!init_data_hdr) + return -ENOMEM; + + amdgpu_device_vram_access(adev, (uint64_t)init_hdr_offset, (uint32_t *)init_data_hdr, + sizeof(struct amd_sriov_msg_init_data_header), false); + + /* Table validation */ + if (strncmp(init_data_hdr->signature, + AMDGPU_SRIOV_CRIT_DATA_SIGNATURE, + AMDGPU_SRIOV_CRIT_DATA_SIG_LEN) != 0) { + dev_err(adev->dev, "Invalid init data signature: %.4s\n", + init_data_hdr->signature); + r = -EINVAL; + goto out; + } + + checksum = amdgpu_virt_crit_region_calc_checksum( + (uint8_t *)&init_data_hdr->initdata_offset, + (uint8_t *)init_data_hdr + + sizeof(struct amd_sriov_msg_init_data_header)); + if (checksum != init_data_hdr->checksum) { + dev_err(adev->dev, "Found unmatching checksum from calculation 0x%x and init_data 0x%x\n", + checksum, init_data_hdr->checksum); + r = -EINVAL; + goto out; + } + + memset(&adev->virt.crit_regn, 0, sizeof(adev->virt.crit_regn)); + memset(adev->virt.crit_regn_tbl, 0, sizeof(adev->virt.crit_regn_tbl)); + + adev->virt.crit_regn.offset = init_data_hdr->initdata_offset; + adev->virt.crit_regn.size_kb = init_data_hdr->initdata_size_in_kb; + + /* Validation and initialization for each table entry */ + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_IPD_TABLE_ID)) { + if (!init_data_hdr->ip_discovery_size_in_kb || + init_data_hdr->ip_discovery_size_in_kb > DISCOVERY_TMR_SIZE) { + dev_err(adev->dev, "Invalid %s size: 0x%x\n", + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_IPD_TABLE_ID], + init_data_hdr->ip_discovery_size_in_kb); + r = -EINVAL; + goto out; + } + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset = + init_data_hdr->ip_discovery_offset; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb = + init_data_hdr->ip_discovery_size_in_kb; + } + + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID)) { + if (!init_data_hdr->vbios_img_size_in_kb) { + dev_err(adev->dev, "Invalid %s size: 0x%x\n", + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID], + init_data_hdr->vbios_img_size_in_kb); + r = -EINVAL; + goto out; + } + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].offset = + init_data_hdr->vbios_img_offset; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].size_kb = + init_data_hdr->vbios_img_size_in_kb; + } + + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID)) { + if (!init_data_hdr->ras_tele_info_size_in_kb) { + dev_err(adev->dev, "Invalid %s size: 0x%x\n", + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID], + init_data_hdr->ras_tele_info_size_in_kb); + r = -EINVAL; + goto out; + } + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].offset = + init_data_hdr->ras_tele_info_offset; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].size_kb = + init_data_hdr->ras_tele_info_size_in_kb; + } + + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID)) { + if (!init_data_hdr->dataexchange_size_in_kb) { + dev_err(adev->dev, "Invalid %s size: 0x%x\n", + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID], + init_data_hdr->dataexchange_size_in_kb); + r = -EINVAL; + goto out; + } + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset = + init_data_hdr->dataexchange_offset; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb = + init_data_hdr->dataexchange_size_in_kb; + } + + if (IS_SRIOV_CRIT_REGN_ENTRY_VALID(init_data_hdr, AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID)) { + if (!init_data_hdr->bad_page_size_in_kb) { + dev_err(adev->dev, "Invalid %s size: 0x%x\n", + amdgpu_virt_dynamic_crit_table_name[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID], + init_data_hdr->bad_page_size_in_kb); + r = -EINVAL; + goto out; + } + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID].offset = + init_data_hdr->bad_page_info_offset; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID].size_kb = + init_data_hdr->bad_page_size_in_kb; + } + + adev->virt.is_dynamic_crit_regn_enabled = true; + +out: + kfree(init_data_hdr); + init_data_hdr = NULL; + + return r; +} + void amdgpu_virt_init(struct amdgpu_device *adev) { bool is_sriov = false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index 36247a160aa63..8d03a8620de9a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -54,6 +54,12 @@ #define AMDGPU_VF2PF_UPDATE_MAX_RETRY_LIMIT 2 +/* Signature used to validate the SR-IOV dynamic critical region init data header ("INDA") */ +#define AMDGPU_SRIOV_CRIT_DATA_SIGNATURE "INDA" +#define AMDGPU_SRIOV_CRIT_DATA_SIG_LEN 4 + +#define IS_SRIOV_CRIT_REGN_ENTRY_VALID(hdr, id) ((hdr)->valid_tables & (1 << (id))) + enum amdgpu_sriov_vf_mode { SRIOV_VF_MODE_BARE_METAL = 0, SRIOV_VF_MODE_ONE_VF, @@ -296,6 +302,9 @@ struct amdgpu_virt { /* dynamic(v2) critical regions */ struct amdgpu_virt_region init_data_header; + struct amdgpu_virt_region crit_regn; + struct amdgpu_virt_region crit_regn_tbl[AMD_SRIOV_MSG_MAX_TABLE_ID]; + bool is_dynamic_crit_regn_enabled; /* vf2pf message */ struct delayed_work vf2pf_work; @@ -432,6 +441,8 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev); void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev); void amdgpu_virt_init(struct amdgpu_device *adev); +int amdgpu_virt_init_critical_region(struct amdgpu_device *adev); + bool amdgpu_virt_can_access_debugfs(struct amdgpu_device *adev); int amdgpu_virt_enable_access_debugfs(struct amdgpu_device *adev); void amdgpu_virt_disable_access_debugfs(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h index 9228fd2c6dfd9..1cee083fb6bd6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h @@ -71,6 +71,37 @@ enum amd_sriov_crit_region_version { GPU_CRIT_REGION_V2 = 2, }; +/* v2 layout offset enum (in order of allocation) */ +enum amd_sriov_msg_table_id_enum { + AMD_SRIOV_MSG_IPD_TABLE_ID = 0, + AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID, + AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID, + AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID, + AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID, + AMD_SRIOV_MSG_INITD_H_TABLE_ID, + AMD_SRIOV_MSG_MAX_TABLE_ID, +}; + +struct amd_sriov_msg_init_data_header { + char signature[4]; /* "INDA" */ + uint32_t version; + uint32_t checksum; + uint32_t initdata_offset; /* 0 */ + uint32_t initdata_size_in_kb; /* 5MB */ + uint32_t valid_tables; + uint32_t vbios_img_offset; + uint32_t vbios_img_size_in_kb; + uint32_t dataexchange_offset; + uint32_t dataexchange_size_in_kb; + uint32_t ras_tele_info_offset; + uint32_t ras_tele_info_size_in_kb; + uint32_t ip_discovery_offset; + uint32_t ip_discovery_size_in_kb; + uint32_t bad_page_info_offset; + uint32_t bad_page_size_in_kb; + uint32_t reserved[8]; +}; + /* * PF2VF history log: * v1 defined in amdgim From 584c6511a0dd8a7b031a11e67d890a6500cbfa8f Mon Sep 17 00:00:00 2001 From: Ellen Pan Date: Wed, 8 Oct 2025 15:01:10 -0500 Subject: [PATCH 13/62] drm/amdgpu: Reuse fw_vram_usage_* for dynamic critical region in SRIOV - During guest driver init, asa VFs receive PF msg to init dynamic critical region(v2), VFs reuse fw_vram_usage_* from ttm to store critical region tables in a 5MB chunk. Signed-off-by: Ellen Pan Reviewed-by: Alex Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c | 29 ++++++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 13 +++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 9 ++++++ 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index c7d32fb216e4e..636385c80f643 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -181,19 +181,22 @@ int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev) u8 frev, crev; int usage_bytes = 0; - if (amdgpu_atom_parse_data_header(ctx, index, NULL, &frev, &crev, &data_offset)) { - if (frev == 2 && crev == 1) { - fw_usage_v2_1 = - (struct vram_usagebyfirmware_v2_1 *)(ctx->bios + data_offset); - amdgpu_atomfirmware_allocate_fb_v2_1(adev, - fw_usage_v2_1, - &usage_bytes); - } else if (frev >= 2 && crev >= 2) { - fw_usage_v2_2 = - (struct vram_usagebyfirmware_v2_2 *)(ctx->bios + data_offset); - amdgpu_atomfirmware_allocate_fb_v2_2(adev, - fw_usage_v2_2, - &usage_bytes); + /* Skip atomfirmware allocation for SRIOV VFs when dynamic crit regn is enabled */ + if (!(amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled)) { + if (amdgpu_atom_parse_data_header(ctx, index, NULL, &frev, &crev, &data_offset)) { + if (frev == 2 && crev == 1) { + fw_usage_v2_1 = + (struct vram_usagebyfirmware_v2_1 *)(ctx->bios + data_offset); + amdgpu_atomfirmware_allocate_fb_v2_1(adev, + fw_usage_v2_1, + &usage_bytes); + } else if (frev >= 2 && crev >= 2) { + fw_usage_v2_2 = + (struct vram_usagebyfirmware_v2_2 *)(ctx->bios + data_offset); + amdgpu_atomfirmware_allocate_fb_v2_2(adev, + fw_usage_v2_2, + &usage_bytes); + } } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index bd7e5059865c0..7778b399669ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2393,19 +2393,20 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; /* - *The reserved vram for driver must be pinned to the specified - *place on the VRAM, so reserve it early. + * The reserved VRAM for the driver must be pinned to a specific + * location in VRAM, so reserve it early. */ r = amdgpu_ttm_drv_reserve_vram_init(adev); if (r) return r; /* - * only NAVI10 and onwards ASIC support for IP discovery. - * If IP discovery enabled, a block of memory should be - * reserved for IP discovey. + * only NAVI10 and later ASICs support IP discovery. + * If IP discovery is enabled, a block of memory should be + * reserved for it. */ - if (adev->mman.discovery_bin) { + if (adev->mman.discovery_bin && + !adev->virt.is_dynamic_crit_regn_enabled) { r = amdgpu_ttm_reserve_tmr(adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 2a97d137f19c5..98ddfff0d8092 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -1008,6 +1008,15 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) init_data_hdr->bad_page_size_in_kb; } + /* reserved memory starts from crit region base offset with the size of 5MB */ + adev->mman.fw_vram_usage_start_offset = adev->virt.crit_regn.offset; + adev->mman.fw_vram_usage_size = adev->virt.crit_regn.size_kb << 10; + dev_info(adev->dev, + "critical region v%d requested to reserve memory start at %08llx with %llu KB.\n", + init_data_hdr->version, + adev->mman.fw_vram_usage_start_offset, + adev->mman.fw_vram_usage_size >> 10); + adev->virt.is_dynamic_crit_regn_enabled = true; out: From d1763d40aa1cca0e6abe9aa54f9ab033d76f61fe Mon Sep 17 00:00:00 2001 From: Ellen Pan Date: Tue, 7 Oct 2025 11:12:39 -0500 Subject: [PATCH 14/62] drm/amdgpu: Add logic for VF ipd and VF bios to init from dynamic crit_region offsets 1. Added VF logic in amdgpu_virt to init IP discovery using the offsets from dynamic(v2) critical regions; 2. Added VF logic in amdgpu_virt to init bios image using the offsets from dynamic(v2) critical regions; Signed-off-by: Ellen Pan Reviewed-by: Lijo Lazar Change-Id: I35cc87edffdecf3715646b268cceccbe2d816607 --- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 34 ++++++++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 24 ++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 37 +++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 2 + 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index 00e96419fcdad..db705bf723f12 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -96,11 +96,12 @@ void amdgpu_bios_release(struct amdgpu_device *adev) * part of the system bios. On boot, the system bios puts a * copy of the igp rom at the start of vram if a discrete card is * present. - * For SR-IOV, the vbios image is also put in VRAM in the VF. + * For SR-IOV, if dynamic critical region is not enabled, + * the vbios image is also put at the start of VRAM in the VF. */ static bool amdgpu_read_bios_from_vram(struct amdgpu_device *adev) { - uint8_t __iomem *bios; + uint8_t __iomem *bios = NULL; resource_size_t vram_base; resource_size_t size = 256 * 1024; /* ??? */ @@ -114,18 +115,33 @@ static bool amdgpu_read_bios_from_vram(struct amdgpu_device *adev) adev->bios = NULL; vram_base = pci_resource_start(adev->pdev, 0); - bios = ioremap_wc(vram_base, size); - if (!bios) - return false; adev->bios = kmalloc(size, GFP_KERNEL); - if (!adev->bios) { - iounmap(bios); + if (!adev->bios) return false; + + /* For SRIOV with dynamic critical region is enabled, + * the vbios image is put at a dynamic offset of VRAM in the VF. + * If dynamic critical region is disabled, follow the existing logic as on baremetal. + */ + if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) { + if (amdgpu_virt_get_dynamic_data_info(adev, + AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID, adev->bios, (uint64_t *)&size)) { + amdgpu_bios_release(adev); + return false; + } + } else { + bios = ioremap_wc(vram_base, size); + if (!bios) { + amdgpu_bios_release(adev); + return false; + } + + memcpy_fromio(adev->bios, bios, size); + iounmap(bios); } + adev->bios_size = size; - memcpy_fromio(adev->bios, bios, size); - iounmap(bios); if (!check_atom_bios(adev, size)) { amdgpu_bios_release(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index bc5327b98e162..fe5f71e38007e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -299,9 +299,25 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, vram_size <<= 20; if (sz_valid) { - uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET; - amdgpu_device_vram_access(adev, pos, (uint32_t *)binary, - adev->mman.discovery_tmr_size, false); + if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) { + /* For SRIOV VFs with dynamic critical region enabled, + * we will get the IPD binary via below call. + * If dynamic critical is disabled, fall through to normal seq. + */ + if (amdgpu_virt_get_dynamic_data_info(adev, + AMD_SRIOV_MSG_IPD_TABLE_ID, binary, + (uint64_t *)&adev->mman.discovery_tmr_size)) { + dev_err(adev->dev, + "failed to read discovery info from dynamic critical region."); + ret = -EINVAL; + goto exit; + } + } else { + uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET; + + amdgpu_device_vram_access(adev, pos, (uint32_t *)binary, + adev->mman.discovery_tmr_size, false); + } } else { ret = amdgpu_discovery_read_binary_from_sysmem(adev, binary); } @@ -310,7 +326,7 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, dev_err(adev->dev, "failed to read discovery info from memory, vram size read: %llx", vram_size); - +exit: return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 98ddfff0d8092..505087a102a3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -1008,6 +1008,14 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) init_data_hdr->bad_page_size_in_kb; } + /* Validation for critical region info */ + if (adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb > DISCOVERY_TMR_SIZE) { + dev_err(adev->dev, "Invalid IP discovery size: 0x%x\n", + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb); + r = -EINVAL; + goto out; + } + /* reserved memory starts from crit region base offset with the size of 5MB */ adev->mman.fw_vram_usage_start_offset = adev->virt.crit_regn.offset; adev->mman.fw_vram_usage_size = adev->virt.crit_regn.size_kb << 10; @@ -1026,6 +1034,35 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) return r; } +int amdgpu_virt_get_dynamic_data_info(struct amdgpu_device *adev, + int data_id, uint8_t *binary, uint64_t *size) +{ + uint32_t data_offset = 0; + uint32_t data_size = 0; + enum amd_sriov_msg_table_id_enum data_table_id = data_id; + + if (data_table_id >= AMD_SRIOV_MSG_MAX_TABLE_ID) + return -EINVAL; + + data_offset = adev->virt.crit_regn_tbl[data_table_id].offset; + data_size = adev->virt.crit_regn_tbl[data_table_id].size_kb << 10; + + /* Validate on input params */ + if (!binary || !size || *size < (uint64_t)data_size) + return -EINVAL; + + /* Proceed to copy the dynamic content */ + amdgpu_device_vram_access(adev, + (uint64_t)data_offset, (uint32_t *)binary, data_size, false); + *size = (uint64_t)data_size; + + dev_dbg(adev->dev, + "Got %s info from dynamic crit_region_table at offset 0x%x with size of 0x%x bytes.\n", + amdgpu_virt_dynamic_crit_table_name[data_id], data_offset, data_size); + + return 0; +} + void amdgpu_virt_init(struct amdgpu_device *adev) { bool is_sriov = false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index 8d03a8620de9a..2a13cc892a139 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -442,6 +442,8 @@ void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev); void amdgpu_virt_init(struct amdgpu_device *adev); int amdgpu_virt_init_critical_region(struct amdgpu_device *adev); +int amdgpu_virt_get_dynamic_data_info(struct amdgpu_device *adev, + int data_id, uint8_t *binary, uint64_t *size); bool amdgpu_virt_can_access_debugfs(struct amdgpu_device *adev); int amdgpu_virt_enable_access_debugfs(struct amdgpu_device *adev); From a46363c9aeb5963aa69e2abc1f17b903bd3bf9a4 Mon Sep 17 00:00:00 2001 From: Ellen Pan Date: Wed, 8 Oct 2025 15:36:50 -0500 Subject: [PATCH 15/62] drm/amdgpu: Add logic for VF data exchange region to init from dynamic crit_region offsets 1. Added VF logic to init data exchange region using the offsets from dynamic(v2) critical regions; Signed-off-by: Ellen Pan Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 104 ++++++++++++++++++----- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 505087a102a3b..8a285b37e6877 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -218,12 +218,12 @@ int amdgpu_virt_alloc_mm_table(struct amdgpu_device *adev) &adev->virt.mm_table.gpu_addr, (void *)&adev->virt.mm_table.cpu_addr); if (r) { - DRM_ERROR("failed to alloc mm table and error = %d.\n", r); + dev_err(adev->dev, "failed to alloc mm table and error = %d.\n", r); return r; } memset((void *)adev->virt.mm_table.cpu_addr, 0, PAGE_SIZE); - DRM_INFO("MM table gpu addr = 0x%llx, cpu addr = %p.\n", + dev_info(adev->dev, "MM table gpu addr = 0x%llx, cpu addr = %p.\n", adev->virt.mm_table.gpu_addr, adev->virt.mm_table.cpu_addr); return 0; @@ -403,7 +403,9 @@ static void amdgpu_virt_ras_reserve_bps(struct amdgpu_device *adev) if (amdgpu_bo_create_kernel_at(adev, bp << AMDGPU_GPU_PAGE_SHIFT, AMDGPU_GPU_PAGE_SIZE, &bo, NULL)) - DRM_DEBUG("RAS WARN: reserve vram for retired page %llx fail\n", bp); + dev_dbg(adev->dev, + "RAS WARN: reserve vram for retired page %llx fail\n", + bp); data->bps_bo[i] = bo; } data->last_reserved = i + 1; @@ -671,10 +673,34 @@ static void amdgpu_virt_update_vf2pf_work_item(struct work_struct *work) schedule_delayed_work(&(adev->virt.vf2pf_work), adev->virt.vf2pf_update_interval_ms); } +static int amdgpu_virt_read_exchange_data_from_mem(struct amdgpu_device *adev, uint32_t *pfvf_data) +{ + uint32_t dataexchange_offset = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset; + uint32_t dataexchange_size = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10; + uint64_t pos = 0; + + dev_info(adev->dev, + "Got data exchange info from dynamic crit_region_table at offset 0x%x with size of 0x%x bytes.\n", + dataexchange_offset, dataexchange_size); + + if (!IS_ALIGNED(dataexchange_offset, 4) || !IS_ALIGNED(dataexchange_size, 4)) { + dev_err(adev->dev, "Data exchange data not aligned to 4 bytes\n"); + return -EINVAL; + } + + pos = (uint64_t)dataexchange_offset; + amdgpu_device_vram_access(adev, pos, pfvf_data, + dataexchange_size, false); + + return 0; +} + void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev) { if (adev->virt.vf2pf_update_interval_ms != 0) { - DRM_INFO("clean up the vf2pf work item\n"); + dev_info(adev->dev, "clean up the vf2pf work item\n"); cancel_delayed_work_sync(&adev->virt.vf2pf_work); adev->virt.vf2pf_update_interval_ms = 0; } @@ -682,13 +708,15 @@ void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev) void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) { + uint32_t *pfvf_data = NULL; + adev->virt.fw_reserve.p_pf2vf = NULL; adev->virt.fw_reserve.p_vf2pf = NULL; adev->virt.vf2pf_update_interval_ms = 0; adev->virt.vf2pf_update_retry_cnt = 0; if (adev->mman.fw_vram_usage_va && adev->mman.drv_vram_usage_va) { - DRM_WARN("Currently fw_vram and drv_vram should not have values at the same time!"); + dev_warn(adev->dev, "Currently fw_vram and drv_vram should not have values at the same time!"); } else if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) { /* go through this logic in ip_init and reset to init workqueue*/ amdgpu_virt_exchange_data(adev); @@ -697,11 +725,34 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) schedule_delayed_work(&(adev->virt.vf2pf_work), msecs_to_jiffies(adev->virt.vf2pf_update_interval_ms)); } else if (adev->bios != NULL) { /* got through this logic in early init stage to get necessary flags, e.g. rlcg_acc related*/ - adev->virt.fw_reserve.p_pf2vf = - (struct amd_sriov_msg_pf2vf_info_header *) - (adev->bios + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); + if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) { + pfvf_data = + kzalloc(adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10, + GFP_KERNEL); + if (!pfvf_data) { + dev_err(adev->dev, "Failed to allocate memory for pfvf_data\n"); + return; + } - amdgpu_virt_read_pf2vf_data(adev); + if (amdgpu_virt_read_exchange_data_from_mem(adev, pfvf_data)) + goto free_pfvf_data; + + adev->virt.fw_reserve.p_pf2vf = + (struct amd_sriov_msg_pf2vf_info_header *)pfvf_data; + + amdgpu_virt_read_pf2vf_data(adev); + +free_pfvf_data: + kfree(pfvf_data); + pfvf_data = NULL; + adev->virt.fw_reserve.p_pf2vf = NULL; + } else { + adev->virt.fw_reserve.p_pf2vf = + (struct amd_sriov_msg_pf2vf_info_header *) + (adev->bios + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); + + amdgpu_virt_read_pf2vf_data(adev); + } } } @@ -714,14 +765,29 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev) if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) { if (adev->mman.fw_vram_usage_va) { - adev->virt.fw_reserve.p_pf2vf = - (struct amd_sriov_msg_pf2vf_info_header *) - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); - adev->virt.fw_reserve.p_vf2pf = - (struct amd_sriov_msg_vf2pf_info_header *) - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); - adev->virt.fw_reserve.ras_telemetry = - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); + if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) { + adev->virt.fw_reserve.p_pf2vf = + (struct amd_sriov_msg_pf2vf_info_header *) + (adev->mman.fw_vram_usage_va + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset); + adev->virt.fw_reserve.p_vf2pf = + (struct amd_sriov_msg_vf2pf_info_header *) + (adev->mman.fw_vram_usage_va + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset + + (AMD_SRIOV_MSG_SIZE_KB << 10)); + adev->virt.fw_reserve.ras_telemetry = + (adev->mman.fw_vram_usage_va + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].offset); + } else { + adev->virt.fw_reserve.p_pf2vf = + (struct amd_sriov_msg_pf2vf_info_header *) + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); + adev->virt.fw_reserve.p_vf2pf = + (struct amd_sriov_msg_vf2pf_info_header *) + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); + adev->virt.fw_reserve.ras_telemetry = + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); + } } else if (adev->mman.drv_vram_usage_va) { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) @@ -829,7 +895,7 @@ static bool amdgpu_virt_init_req_data(struct amdgpu_device *adev, u32 reg) break; default: /* other chip doesn't support SRIOV */ is_sriov = false; - DRM_ERROR("Unknown asic type: %d!\n", adev->asic_type); + dev_err(adev->dev, "Unknown asic type: %d!\n", adev->asic_type); break; } } @@ -1510,7 +1576,7 @@ amdgpu_ras_block_to_sriov(struct amdgpu_device *adev, enum amdgpu_ras_block bloc case AMDGPU_RAS_BLOCK__MPIO: return RAS_TELEMETRY_GPU_BLOCK_MPIO; default: - DRM_WARN_ONCE("Unsupported SRIOV RAS telemetry block 0x%x\n", + dev_warn(adev->dev, "Unsupported SRIOV RAS telemetry block 0x%x\n", block); return RAS_TELEMETRY_GPU_BLOCK_COUNT; } From 8431ebc6553eecca3424ca6702b22b05e99294fe Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 9 Oct 2025 15:59:04 -0500 Subject: [PATCH 16/62] drm/amd: Stop overloading power limit with limit type When passed around internally the upper 8 bits of power limit include the limit type. This is non-obvious without digging into the nuances of each function. Instead pass the limit type as an argument to all applicable layers. Reviewed-by: Lijo Lazar Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 2 +- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 3 ++- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 3 +-- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 2 +- drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 10 ++++------ drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 1 - 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index e23a10157f506..cb436d470c210 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -463,7 +463,7 @@ struct amd_pm_funcs { bool gate, int inst); int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id); - int (*set_power_limit)(void *handle, uint32_t n); + int (*set_power_limit)(void *handle, uint32_t limit_type, uint32_t n); int (*get_power_limit)(void *handle, uint32_t *limit, enum pp_power_limit_level pp_limit_level, enum pp_power_type power_type); diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index f3a5777c67c3c..758f5ea4b68f0 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -1616,6 +1616,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev, } int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev, + uint32_t limit_type, uint32_t limit) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -1626,7 +1627,7 @@ int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev, mutex_lock(&adev->pm.mutex); ret = pp_funcs->set_power_limit(adev->powerplay.pp_handle, - limit); + limit_type, limit); mutex_unlock(&adev->pm.mutex); return ret; diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 0b621a8265cfb..6b1ce52f4acf5 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -3390,13 +3390,12 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, return err; value = value / 1000000; /* convert to Watt */ - value |= limit_type << 24; err = amdgpu_pm_get_access(adev); if (err < 0) return err; - err = amdgpu_dpm_set_power_limit(adev, value); + err = amdgpu_dpm_set_power_limit(adev, limit_type, value); amdgpu_pm_put_access(adev); diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index cda2d7f77c015..f824bc4bba9e7 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -553,7 +553,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev, enum pp_power_limit_level pp_limit_level, enum pp_power_type power_type); int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev, - uint32_t limit); + uint32_t limit_type, uint32_t limit); int amdgpu_dpm_is_cclk_dpm_supported(struct amdgpu_device *adev); int amdgpu_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev, struct seq_file *m); diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 554492dfa3c00..c07df2638438a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -955,7 +955,7 @@ static int pp_dpm_switch_power_profile(void *handle, return 0; } -static int pp_set_power_limit(void *handle, uint32_t limit) +static int pp_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit) { struct pp_hwmgr *hwmgr = handle; uint32_t max_power_limit; diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 91e112491dec2..fc0bc8b5a640c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -68,7 +68,7 @@ static int smu_handle_task(struct smu_context *smu, static int smu_reset(struct smu_context *smu); static int smu_set_fan_speed_pwm(void *handle, u32 speed); static int smu_set_fan_control_mode(void *handle, u32 value); -static int smu_set_power_limit(void *handle, uint32_t limit); +static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit); static int smu_set_fan_speed_rpm(void *handle, uint32_t speed); static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled); static int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state); @@ -510,7 +510,7 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) /* set the user dpm power limit */ if (smu->user_dpm_profile.power_limit) { - ret = smu_set_power_limit(smu, smu->user_dpm_profile.power_limit); + ret = smu_set_power_limit(smu, SMU_DEFAULT_PPT_LIMIT, smu->current_power_limit); if (ret) dev_err(smu->adev->dev, "Failed to set power limit value\n"); } @@ -2258,7 +2258,7 @@ static int smu_resume(struct amdgpu_ip_block *ip_block) adev->pm.dpm_enabled = true; if (smu->current_power_limit) { - ret = smu_set_power_limit(smu, smu->current_power_limit); + ret = smu_set_power_limit(smu, SMU_DEFAULT_PPT_LIMIT, smu->current_power_limit); if (ret && ret != -EOPNOTSUPP) return ret; } @@ -2958,16 +2958,14 @@ int smu_get_power_limit(void *handle, return ret; } -static int smu_set_power_limit(void *handle, uint32_t limit) +static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit) { struct smu_context *smu = handle; - uint32_t limit_type = limit >> 24; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; - limit &= (1<<24)-1; if (limit_type != SMU_DEFAULT_PPT_LIMIT) if (smu->ppt_funcs->set_power_limit) return smu->ppt_funcs->set_power_limit(smu, limit_type, limit); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index a4b4c01b9bd95..0641c4a608f61 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2403,7 +2403,6 @@ static int vangogh_set_power_limit(struct smu_context *smu, smu->current_power_limit = ppt_limit; break; case SMU_FAST_PPT_LIMIT: - ppt_limit &= ~(SMU_FAST_PPT_LIMIT << 24); if (ppt_limit > power_context->max_fast_ppt_limit) { dev_err(smu->adev->dev, "New power limit (%d) is over the max allowed %d\n", From 3d19f4af12bec1ffa0d821bb92eab0a3230fe996 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 9 Oct 2025 15:59:05 -0500 Subject: [PATCH 17/62] drm/amd: Remove second call to set_power_limit() The min/max limits only make sense for default PPT. Restructure smu_set_power_limit() to only use them in that case. Reviewed-by: Lijo Lazar Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index fc0bc8b5a640c..9492b26943e65 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2966,20 +2966,17 @@ static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; - if (limit_type != SMU_DEFAULT_PPT_LIMIT) - if (smu->ppt_funcs->set_power_limit) - return smu->ppt_funcs->set_power_limit(smu, limit_type, limit); - - if ((limit > smu->max_power_limit) || (limit < smu->min_power_limit)) { - dev_err(smu->adev->dev, - "New power limit (%d) is out of range [%d,%d]\n", - limit, smu->min_power_limit, smu->max_power_limit); - return -EINVAL; + if (limit_type == SMU_DEFAULT_PPT_LIMIT) { + if (!limit) + limit = smu->current_power_limit; + if ((limit > smu->max_power_limit) || (limit < smu->min_power_limit)) { + dev_err(smu->adev->dev, + "New power limit (%d) is out of range [%d,%d]\n", + limit, smu->min_power_limit, smu->max_power_limit); + return -EINVAL; + } } - if (!limit) - limit = smu->current_power_limit; - if (smu->ppt_funcs->set_power_limit) { ret = smu->ppt_funcs->set_power_limit(smu, limit_type, limit); if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) From 3dcd53b29f093ff5efb9293cce821a7276f497b4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 9 Oct 2025 15:59:06 -0500 Subject: [PATCH 18/62] drm/amd: Save and restore all limit types Vangogh has separate limits for default PPT and fast PPT. Add infrastructure to save both of these limits and restore both of them. Reviewed-by: Lijo Lazar Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 19 ++++++++++++------- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 9492b26943e65..421b6816444ea 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -508,11 +508,14 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) /* Enable restore flag */ smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE; - /* set the user dpm power limit */ - if (smu->user_dpm_profile.power_limit) { - ret = smu_set_power_limit(smu, SMU_DEFAULT_PPT_LIMIT, smu->current_power_limit); + /* set the user dpm power limits */ + for (int i = SMU_DEFAULT_PPT_LIMIT; i < SMU_LIMIT_TYPE_COUNT; i++) { + if (!smu->user_dpm_profile.power_limits[i]) + continue; + ret = smu_set_power_limit(smu, i, + smu->user_dpm_profile.power_limits[i]); if (ret) - dev_err(smu->adev->dev, "Failed to set power limit value\n"); + dev_err(smu->adev->dev, "Failed to set %d power limit value\n", i); } /* set the user dpm clock configurations */ @@ -2979,11 +2982,13 @@ static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit if (smu->ppt_funcs->set_power_limit) { ret = smu->ppt_funcs->set_power_limit(smu, limit_type, limit); - if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) - smu->user_dpm_profile.power_limit = limit; + if (ret) + return ret; + if (!(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) + smu->user_dpm_profile.power_limits[limit_type] = limit; } - return ret; + return 0; } static int smu_print_smuclk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 148153b3025b7..4c00f6edebaec 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -212,6 +212,7 @@ enum smu_power_src_type { enum smu_ppt_limit_type { SMU_DEFAULT_PPT_LIMIT = 0, SMU_FAST_PPT_LIMIT, + SMU_LIMIT_TYPE_COUNT, }; enum smu_ppt_limit_level { @@ -231,7 +232,7 @@ enum smu_memory_pool_size { struct smu_user_dpm_profile { uint32_t fan_mode; - uint32_t power_limit; + uint32_t power_limits[SMU_LIMIT_TYPE_COUNT]; uint32_t fan_speed_pwm; uint32_t fan_speed_rpm; uint32_t flags; From df4fe3b1f9089636169a5066bd2a08ab282dffd7 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 9 Oct 2025 15:59:07 -0500 Subject: [PATCH 19/62] drm/amd: Drop calls to restore power limit and clock from smu_resume() User requested power limits and clock settings are already restored as part of smu_restore_dpm_user_profile(). It's unnecessary to call the same restore as part of smu_resume(). Revert the following commits to drop that extra restore: commit ed4efe426a49 ("drm/amd: Restore cached power limit during resume") commit 796ff8a7e01b ("drm/amd: Restore cached manual clock settings during resume") commit f9b80514a722 ("drm/amd: Only restore cached manual clock settings in restore if OD enabled") Suggested-by: Lijo Lazar Reviewed-by: Lijo Lazar Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 421b6816444ea..319ad29bd87b3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2228,7 +2228,6 @@ static int smu_resume(struct amdgpu_ip_block *ip_block) int ret; struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); if (amdgpu_sriov_multi_vf_mode(adev)) return 0; @@ -2260,18 +2259,6 @@ static int smu_resume(struct amdgpu_ip_block *ip_block) adev->pm.dpm_enabled = true; - if (smu->current_power_limit) { - ret = smu_set_power_limit(smu, SMU_DEFAULT_PPT_LIMIT, smu->current_power_limit); - if (ret && ret != -EOPNOTSUPP) - return ret; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL && smu->od_enabled) { - ret = smu_od_edit_dpm_table(smu, PP_OD_COMMIT_DPM_TABLE, NULL, 0); - if (ret) - return ret; - } - dev_info(adev->dev, "SMU is resumed successfully!\n"); return 0; From f376e7b3e638b8d7b4ef6f503ac15129e3ed1f06 Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Thu, 6 Nov 2025 10:03:20 -0500 Subject: [PATCH 20/62] drm/amdgpu: disable peer-to-peer access for DCC-enabled GC12 VRAM surfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Certain multi-GPU configurations (especially GFX12) may hit data corruption when a DCC-compressed VRAM surface is shared across GPUs using peer-to-peer (P2P) DMA transfers. Such surfaces rely on device-local metadata and cannot be safely accessed through a remote GPU’s page tables. Attempting to import a DCC-enabled surface through P2P leads to incorrect rendering or GPU faults. This change disables P2P for DCC-enabled VRAM buffers that are contiguous and allocated on GFX12+ hardware. In these cases, the importer falls back to the standard system-memory path, avoiding invalid access to compressed surfaces. Future work could consider optional migration (VRAM→System→VRAM) if a performance regression is observed when `attach->peer2peer = false`. Tested on: - Dual RX 9700 XT (Navi4x) setup - GNOME and Wayland compositor scenarios - Confirmed no corruption after disabling P2P under these conditions Suggested-by: Christian König Signed-off-by: Vitaly Prosyak Reviewed-by: Christian König Change-Id: Idd16caa2a2d8021c4642b065a20a16327ae7312f --- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index 9a0bce3ba24c9..d2d31031f672d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -260,11 +260,24 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); #ifdef HAVE_STRUCT_DMA_BUF_ATTACH_OPS_ALLOW_PEER2PEER + /* + * Disable peer-to-peer access for DCC-enabled VRAM surfaces on GFX12+. + * Such buffers cannot be safely accessed over P2P due to device-local + * compression metadata. Fallback to system-memory path instead. + * Device supports GFX12 (GC 12.x or newer) + * BO was created with the AMDGPU_GEM_CREATE_GFX12_DCC flag + * + */ + if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(12, 0, 0)) && + bo->flags & AMDGPU_GEM_CREATE_GFX12_DCC) { + attach->peer2peer = false; + goto update_vm; + } if (!amdgpu_dmabuf_is_xgmi_accessible(attach_adev, bo) && pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) attach->peer2peer = false; #endif - +update_vm: amdgpu_vm_bo_update_shared(bo); return 0; From 895f8d4f6d2e4c33a4aed94d6185d08cf6e12903 Mon Sep 17 00:00:00 2001 From: Marek Olsak Date: Thu, 6 Nov 2025 15:13:56 -0500 Subject: [PATCH 21/62] Revert "drm/amdgpu: disable peer-to-peer access for DCC-enabled GC12 VRAM surfaces" This reverts commit f376e7b3e638b8d7b4ef6f503ac15129e3ed1f06. Reason for revert: We need to discuss this with the ROCm team to decide whether we want this. Change-Id: If7d309ae6388cf87c4d76e80f404671e9e90a137 --- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index d2d31031f672d..9a0bce3ba24c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -260,24 +260,11 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); #ifdef HAVE_STRUCT_DMA_BUF_ATTACH_OPS_ALLOW_PEER2PEER - /* - * Disable peer-to-peer access for DCC-enabled VRAM surfaces on GFX12+. - * Such buffers cannot be safely accessed over P2P due to device-local - * compression metadata. Fallback to system-memory path instead. - * Device supports GFX12 (GC 12.x or newer) - * BO was created with the AMDGPU_GEM_CREATE_GFX12_DCC flag - * - */ - if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(12, 0, 0)) && - bo->flags & AMDGPU_GEM_CREATE_GFX12_DCC) { - attach->peer2peer = false; - goto update_vm; - } if (!amdgpu_dmabuf_is_xgmi_accessible(attach_adev, bo) && pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) attach->peer2peer = false; #endif -update_vm: + amdgpu_vm_bo_update_shared(bo); return 0; From 234b4a98640bb49df15297aa6904a8363dc93f6b Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Fri, 31 Oct 2025 10:50:02 -0400 Subject: [PATCH 22/62] drm/amdkfd: Don't clear PT after process killed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If process is killed. the vm entity is stopped, submit pt update job will trigger the error message "*ERROR* Trying to push to a killed entity", job will not execute. Suggested-by: Christian König Signed-off-by: Philip Yang Reviewed-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 66c44cc4fffdc..e47a54678d915 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1364,6 +1364,10 @@ static int unmap_bo_from_gpuvm(struct kgd_mem *mem, (void)amdgpu_vm_bo_unmap(adev, bo_va, entry->va); + /* VM entity stopped if process killed, don't clear freed pt bo */ + if (!amdgpu_vm_ready(vm)) + return 0; + (void)amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update); (void)amdgpu_sync_fence(sync, bo_va->last_pt_update, GFP_KERNEL); From b518f60157797e3d6ba8e94f4faf0f8a30f3108d Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Thu, 6 Nov 2025 15:22:06 -0500 Subject: [PATCH 23/62] Revert "drm/amdkfd: Don't clear PT after process killed" This reverts codmmit 234b4a98640bb49df15297aa6904a8363dc93f6b. Reason for revert: test requied Change-Id: I3224e51ab956b880902f5aef86d32f0a9e731d7c --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index e47a54678d915..66c44cc4fffdc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1364,10 +1364,6 @@ static int unmap_bo_from_gpuvm(struct kgd_mem *mem, (void)amdgpu_vm_bo_unmap(adev, bo_va, entry->va); - /* VM entity stopped if process killed, don't clear freed pt bo */ - if (!amdgpu_vm_ready(vm)) - return 0; - (void)amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update); (void)amdgpu_sync_fence(sync, bo_va->last_pt_update, GFP_KERNEL); From 7b4bec6e9dd63d28e37ea353de6ea89aa987f85d Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Mon, 8 Sep 2025 17:08:29 +0800 Subject: [PATCH 24/62] drm/amd/pm: add new message definitions for pmfw eeprom interface Add new message definitions for pmfw eeprom interface Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- .../pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h | 16 ++++++---------- drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 9 ++++++++- .../drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 7 +++++++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h index 4b066c42e0ec9..fe1b3ac50a75b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h @@ -105,19 +105,15 @@ #define PPSMC_MSG_UpdatePccWaitDecMaxStr 0x4C #define PPSMC_MSG_ResetSDMA 0x4D #define PPSMC_MSG_GetRasTableVersion 0x4E -#define PPSMC_MSG_GetRmaStatus 0x4F -#define PPSMC_MSG_GetErrorCount 0x50 -#define PPSMC_MSG_GetBadPageCount 0x51 -#define PPSMC_MSG_GetBadPageInfo 0x52 -#define PPSMC_MSG_GetBadPagePaAddrLoHi 0x53 -#define PPSMC_MSG_SetTimestampLoHi 0x54 -#define PPSMC_MSG_GetTimestampLoHi 0x55 -#define PPSMC_MSG_GetRasPolicy 0x56 -#define PPSMC_MSG_DumpErrorRecord 0x57 +#define PPSMC_MSG_GetBadPageCount 0x50 +#define PPSMC_MSG_GetBadPageMcaAddress 0x51 +#define PPSMC_MSG_SetTimestamp 0x53 +#define PPSMC_MSG_SetTimestampHi 0x54 +#define PPSMC_MSG_GetTimestamp 0x55 +#define PPSMC_MSG_GetBadPageIpIdLoHi 0x57 #define PPSMC_MSG_EraseRasTable 0x58 #define PPSMC_MSG_GetStaticMetricsTable 0x59 #define PPSMC_MSG_ResetVfArbitersByIndex 0x5A -#define PPSMC_MSG_GetBadPageSeverity 0x5B #define PPSMC_MSG_GetSystemMetricsTable 0x5C #define PPSMC_MSG_GetSystemMetricsVersion 0x5D #define PPSMC_MSG_ResetVCN 0x5E diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index 71e8b6f52a042..4a1d964333b03 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -286,7 +286,14 @@ __SMU_DUMMY_MAP(ResetSDMA), \ __SMU_DUMMY_MAP(ResetVCN), \ __SMU_DUMMY_MAP(GetStaticMetricsTable), \ - __SMU_DUMMY_MAP(GetSystemMetricsTable), + __SMU_DUMMY_MAP(GetSystemMetricsTable), \ + __SMU_DUMMY_MAP(GetRASTableVersion), \ + __SMU_DUMMY_MAP(GetBadPageCount), \ + __SMU_DUMMY_MAP(GetBadPageMcaAddr), \ + __SMU_DUMMY_MAP(SetTimestamp), \ + __SMU_DUMMY_MAP(GetTimestamp), \ + __SMU_DUMMY_MAP(GetBadPageIpid), \ + __SMU_DUMMY_MAP(EraseRasTable), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(type) SMU_MSG_##type diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index cb3fea9e8cf31..27b950c126abf 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -139,6 +139,13 @@ const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0), MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1), MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1), + MSG_MAP(GetRASTableVersion, PPSMC_MSG_GetRasTableVersion, 0), + MSG_MAP(GetBadPageCount, PPSMC_MSG_GetBadPageCount, 0), + MSG_MAP(GetBadPageMcaAddr, PPSMC_MSG_GetBadPageMcaAddress, 0), + MSG_MAP(SetTimestamp, PPSMC_MSG_SetTimestamp, 0), + MSG_MAP(GetTimestamp, PPSMC_MSG_GetTimestamp, 0), + MSG_MAP(GetBadPageIpid, PPSMC_MSG_GetBadPageIpIdLoHi, 0), + MSG_MAP(EraseRasTable, PPSMC_MSG_EraseRasTable, 0), }; int smu_v13_0_12_tables_init(struct smu_context *smu) From 6547b5806931ddd6564ff00542241baf1189b0e5 Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Fri, 12 Sep 2025 12:43:35 +0800 Subject: [PATCH 25/62] drm/amd/pm: implement ras_smu_drv interface for smu v13.0.12 implement ras_smu_drv interface for smu v13.0.12 Signed-off-by: Gangliang Xie Signed-off-by: Yang Wang Reviewed-by: Tao Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 26 ++++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 129 ++++++++++++++++++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h | 2 + 3 files changed, 157 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index 6cf0dfd38be8b..d16e0f5da5915 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -503,6 +503,32 @@ struct ras_critical_region { uint64_t size; }; +struct ras_eeprom_table_version { + uint32_t minor : 16; + uint32_t major : 16; +}; + +struct ras_eeprom_smu_funcs { + int (*get_ras_table_version)(struct amdgpu_device *adev, + uint32_t *table_version); + int (*get_badpage_count)(struct amdgpu_device *adev, uint32_t *count, uint32_t timeout); + int (*get_badpage_mca_addr)(struct amdgpu_device *adev, uint16_t index, uint64_t *mca_addr); + int (*set_timestamp)(struct amdgpu_device *adev, uint64_t timestamp); + int (*get_timestamp)(struct amdgpu_device *adev, + uint16_t index, uint64_t *timestamp); + int (*get_badpage_ipid)(struct amdgpu_device *adev, uint16_t index, uint64_t *ipid); + int (*erase_ras_table)(struct amdgpu_device *adev, uint32_t *result); +}; + +enum ras_smu_feature_flags { + RAS_SMU_FEATURE_BIT__RAS_EEPROM = BIT_ULL(0), +}; + +struct ras_smu_drv { + const struct ras_eeprom_smu_funcs *smu_eeprom_funcs; + void (*ras_smu_feature_flags)(struct amdgpu_device *adev, uint64_t *flags); +}; + struct amdgpu_ras { /* ras infrastructure */ /* for ras itself. */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 27b950c126abf..5a54d54fb49f0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -34,6 +34,7 @@ #include "amdgpu_fru_eeprom.h" #include #include "smu_cmn.h" +#include "amdgpu_ras.h" #undef MP1_Public #undef smnMP1_FIRMWARE_FLAGS @@ -941,3 +942,131 @@ const struct smu_temp_funcs smu_v13_0_12_temp_funcs = { .temp_metrics_is_supported = smu_v13_0_12_is_temp_metrics_supported, .get_temp_metrics = smu_v13_0_12_get_temp_metrics, }; + +static int smu_v13_0_12_get_ras_table_version(struct amdgpu_device *adev, + uint32_t *table_version) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetRASTableVersion, 0, table_version); +} + +static int smu_v13_0_12_get_badpage_count(struct amdgpu_device *adev, uint32_t *count, + uint32_t timeout) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint64_t end, now; + int ret = 0; + + now = (uint64_t)ktime_to_ms(ktime_get()); + end = now + timeout; + do { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageCount, 0, count); + /* eeprom is not ready */ + if (ret != -EBUSY) + return ret; + mdelay(10); + now = (uint64_t)ktime_to_ms(ktime_get()); + } while (now < end); + + return ret; +} + +static int smu_v13_0_12_set_timestamp(struct amdgpu_device *adev, uint64_t timestamp) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetTimestamp, (uint32_t)timestamp, 0); +} + +static int smu_v13_0_12_get_timestamp(struct amdgpu_device *adev, + uint16_t index, uint64_t *timestamp) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint32_t temp; + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetTimestamp, index, &temp); + if (!ret) + *timestamp = temp; + + return ret; +} + +static int smu_v13_0_12_get_badpage_ipid(struct amdgpu_device *adev, + uint16_t index, uint64_t *ipid) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint32_t temp_arg, temp_ipid_lo, temp_ipid_high; + int ret; + + temp_arg = index | (1 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_lo); + if (ret) + return ret; + + temp_arg = index | (2 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_high); + if (!ret) + *ipid = (uint64_t)temp_ipid_high << 32 | temp_ipid_lo; + return ret; +} + +static int smu_v13_0_12_erase_ras_table(struct amdgpu_device *adev, + uint32_t *result) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_EraseRasTable, 0, result); +} + +static int smu_v13_0_12_get_badpage_mca_addr(struct amdgpu_device *adev, + uint16_t index, uint64_t *mca_addr) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint32_t temp_arg, temp_addr_lo, temp_addr_high; + int ret; + + temp_arg = index | (1 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_lo); + if (ret) + return ret; + + temp_arg = index | (2 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_high); + if (!ret) + *mca_addr = (uint64_t)temp_addr_high << 32 | temp_addr_lo; + return ret; +} + +static const struct ras_eeprom_smu_funcs smu_v13_0_12_eeprom_smu_funcs = { + .get_ras_table_version = smu_v13_0_12_get_ras_table_version, + .get_badpage_count = smu_v13_0_12_get_badpage_count, + .get_badpage_mca_addr = smu_v13_0_12_get_badpage_mca_addr, + .set_timestamp = smu_v13_0_12_set_timestamp, + .get_timestamp = smu_v13_0_12_get_timestamp, + .get_badpage_ipid = smu_v13_0_12_get_badpage_ipid, + .erase_ras_table = smu_v13_0_12_erase_ras_table, +}; + +static void smu_v13_0_12_ras_smu_feature_flags(struct amdgpu_device *adev, uint64_t *flags) +{ + if (!flags) + return; + + *flags = 0ULL; +} + +const struct ras_smu_drv smu_v13_0_12_ras_smu_drv = { + .smu_eeprom_funcs = &smu_v13_0_12_eeprom_smu_funcs, + .ras_smu_feature_flags = smu_v13_0_12_ras_smu_feature_flags, +}; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h index 7ef5f3e66c273..b75d87f688fc7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h @@ -99,4 +99,6 @@ int smu_v13_0_12_get_npm_data(struct smu_context *smu, extern const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[]; extern const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[]; extern const struct smu_temp_funcs smu_v13_0_12_temp_funcs; +extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv; + #endif From cd4748450ae1f34241bf84e7b8577cc770e82b5f Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Mon, 15 Sep 2025 12:52:35 +0800 Subject: [PATCH 26/62] drm/amd/pm: add smu ras driver framework add functions to get smu ras driver Signed-off-by: Gangliang Xie Signed-off-by: Yang Wang Reviewed-by: Tao Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 2 ++ drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 7 +++++++ drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 1 + drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 11 ++++++++++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 6 ++++++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 21 +++++++++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 1 + 7 files changed, 49 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index d16e0f5da5915..1e07fefe323ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -616,6 +616,8 @@ struct amdgpu_ras { /* Protect poison injection */ struct mutex poison_lock; + + const struct ras_smu_drv *ras_smu_drv; }; struct ras_fs_data { diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 758f5ea4b68f0..e1da77934c118 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -2148,3 +2148,10 @@ void amdgpu_dpm_phase_det_debugfs_init(struct amdgpu_device *adev) amdgpu_smu_phase_det_debugfs_init(adev); } + +const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev) +{ + void *pp_handle = adev->powerplay.pp_handle; + + return smu_get_ras_smu_driver(pp_handle); +} diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index f824bc4bba9e7..041e72934b877 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -615,5 +615,6 @@ int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask); bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev); bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev, enum smu_temp_metric_type type); +const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 319ad29bd87b3..64f8170d71e3e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2786,6 +2786,17 @@ const struct amdgpu_ip_block_version smu_v14_0_ip_block = { .funcs = &smu_ip_funcs, }; +const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle) +{ + struct smu_context *smu = (struct smu_context *)handle; + const struct ras_smu_drv *tmp = NULL; + int ret; + + ret = smu_get_ras_smu_drv(smu, &tmp); + + return ret ? NULL : tmp; +} + static int smu_load_microcode(void *handle) { struct smu_context *smu = handle; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 4c00f6edebaec..429eb27697b9e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1553,6 +1553,11 @@ struct pptable_funcs { */ ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id, void *table); + /** + * @get_ras_smu_drv: Get RAS smu driver interface + * Return: ras_smu_drv * + */ + int (*get_ras_smu_drv)(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv); }; typedef enum { @@ -1817,6 +1822,7 @@ int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type, int level); ssize_t smu_get_pm_policy_info(struct smu_context *smu, enum pp_pm_policy p_type, char *sysbuf); +const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle); int smu_set_phase_det_param(struct smu_context *smu, enum pp_pm_phase_det_param_id id, uint32_t val); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 6f70ea756ce1a..7ec7d25c590e0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -4033,6 +4033,26 @@ static void smu_v13_0_6_set_temp_funcs(struct smu_context *smu) == IP_VERSION(13, 0, 12)) ? &smu_v13_0_12_temp_funcs : NULL; } +static int smu_v13_0_6_get_ras_smu_drv(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv) +{ + if (!ras_smu_drv) + return -EINVAL; + + if (amdgpu_sriov_vf(smu->adev)) + return -EOPNOTSUPP; + + switch (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)) { + case IP_VERSION(13, 0, 12): + *ras_smu_drv = &smu_v13_0_12_ras_smu_drv; + break; + default: + *ras_smu_drv = NULL; + break; + } + + return 0; +} + static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { /* init dpm */ .get_allowed_feature_mask = smu_v13_0_6_get_allowed_feature_mask, @@ -4091,6 +4111,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .reset_sdma = smu_v13_0_6_reset_sdma, .dpm_reset_vcn = smu_v13_0_6_reset_vcn, .post_init = smu_v13_0_6_post_init, + .get_ras_smu_drv = smu_v13_0_6_get_ras_smu_drv, }; void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index c09ecf1a68a0d..34f6b4b1c3ba0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -100,6 +100,7 @@ #define smu_is_asic_wbrf_supported(smu) smu_ppt_funcs(is_asic_wbrf_supported, false, smu) #define smu_enable_uclk_shadow(smu, enable) smu_ppt_funcs(enable_uclk_shadow, 0, smu, enable) #define smu_set_wbrf_exclusion_ranges(smu, freq_band_range) smu_ppt_funcs(set_wbrf_exclusion_ranges, -EOPNOTSUPP, smu, freq_band_range) +#define smu_get_ras_smu_drv(smu, ras_smu_drv) smu_ppt_funcs(get_ras_smu_drv, -EOPNOTSUPP, smu, ras_smu_drv) #endif #endif From 2d9cc3794af98566182747ed9b31c578279d9b4f Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Mon, 15 Sep 2025 12:55:36 +0800 Subject: [PATCH 27/62] drm/amdgpu: add function to check if pmfw eeprom is supported add function to check if pmfw is supported, skip eeprom check and recover when pmfw eeprom is supported Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2 + .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 46 ++++++++++++++++++- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h | 2 + 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index c6f3a327108b8..7c487a171b979 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -3613,6 +3613,8 @@ int amdgpu_ras_init_badpage_info(struct amdgpu_device *adev) return 0; control = &con->eeprom_control; + con->ras_smu_drv = amdgpu_dpm_get_ras_smu_driver(adev); + ret = amdgpu_ras_eeprom_init(control); control->is_eeprom_valid = !ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 3eb3fb55ccb05..1a69e402d8c9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1541,7 +1541,8 @@ void amdgpu_ras_eeprom_check_and_recover(struct amdgpu_device *adev) struct amdgpu_ras_eeprom_control *control; int res; - if (!__is_ras_eeprom_supported(adev) || !ras) + if (!__is_ras_eeprom_supported(adev) || !ras || + amdgpu_ras_smu_eeprom_supported(adev)) return; control = &ras->eeprom_control; if (!control->is_eeprom_valid) @@ -1561,4 +1562,45 @@ void amdgpu_ras_eeprom_check_and_recover(struct amdgpu_device *adev) control->is_eeprom_valid = false; } return; -} \ No newline at end of file +} + +static const struct ras_smu_drv *amdgpu_ras_get_smu_ras_drv(struct amdgpu_device *adev) +{ + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + + if (!ras) + return NULL; + + return ras->ras_smu_drv; +} + +static uint64_t amdgpu_ras_smu_get_feature_flags(struct amdgpu_device *adev) +{ + const struct ras_smu_drv *ras_smu_drv = amdgpu_ras_get_smu_ras_drv(adev); + uint64_t flags = 0ULL; + + if (!ras_smu_drv) + goto out; + + if (ras_smu_drv->ras_smu_feature_flags) + ras_smu_drv->ras_smu_feature_flags(adev, &flags); + +out: + return flags; +} + +bool amdgpu_ras_smu_eeprom_supported(struct amdgpu_device *adev) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + uint64_t flags = 0ULL; + + if (!__is_ras_eeprom_supported(adev) || !smu_ras_drv) + return false; + + if (!smu_ras_drv->smu_eeprom_funcs) + return false; + + flags = amdgpu_ras_smu_get_feature_flags(adev); + + return !!(flags & RAS_SMU_FEATURE_BIT__RAS_EEPROM); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index ebfca4cb5688b..feff46b22b6ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -163,6 +163,8 @@ int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control); void amdgpu_ras_eeprom_check_and_recover(struct amdgpu_device *adev); +bool amdgpu_ras_smu_eeprom_supported(struct amdgpu_device *adev); + extern const struct file_operations amdgpu_ras_debugfs_eeprom_size_ops; extern const struct file_operations amdgpu_ras_debugfs_eeprom_table_ops; From d2a666a69e6bf013358b0abca5d4ab3466b27d17 Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Mon, 15 Sep 2025 17:13:25 +0800 Subject: [PATCH 28/62] drm/amdgpu: add wrapper functions for pmfw eeprom interface add wrapper functions for pmfw eeprom interface, for these interfaces to be easily and safely called Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 98 +++++++++++++++++++ .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h | 21 ++++ 2 files changed, 119 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 1a69e402d8c9b..2987028f45cbe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1604,3 +1604,101 @@ bool amdgpu_ras_smu_eeprom_supported(struct amdgpu_device *adev) return !!(flags & RAS_SMU_FEATURE_BIT__RAS_EEPROM); } + +int amdgpu_ras_smu_get_table_version(struct amdgpu_device *adev, + uint32_t *table_version) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return -EOPNOTSUPP; + + if (smu_ras_drv->smu_eeprom_funcs->get_ras_table_version) + return smu_ras_drv->smu_eeprom_funcs->get_ras_table_version(adev, + table_version); + return -EOPNOTSUPP; +} + +int amdgpu_ras_smu_get_badpage_count(struct amdgpu_device *adev, + uint32_t *count, uint32_t timeout) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return -EOPNOTSUPP; + + if (smu_ras_drv->smu_eeprom_funcs->get_badpage_count) + return smu_ras_drv->smu_eeprom_funcs->get_badpage_count(adev, + count, timeout); + return -EOPNOTSUPP; +} + +int amdgpu_ras_smu_get_badpage_mca_addr(struct amdgpu_device *adev, + uint16_t index, uint64_t *mca_addr) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return -EOPNOTSUPP; + + if (smu_ras_drv->smu_eeprom_funcs->get_badpage_mca_addr) + return smu_ras_drv->smu_eeprom_funcs->get_badpage_mca_addr(adev, + index, mca_addr); + return -EOPNOTSUPP; +} + +int amdgpu_ras_smu_set_timestamp(struct amdgpu_device *adev, + uint64_t timestamp) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return -EOPNOTSUPP; + + if (smu_ras_drv->smu_eeprom_funcs->set_timestamp) + return smu_ras_drv->smu_eeprom_funcs->set_timestamp(adev, + timestamp); + return -EOPNOTSUPP; +} + +int amdgpu_ras_smu_get_timestamp(struct amdgpu_device *adev, + uint16_t index, uint64_t *timestamp) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return -EOPNOTSUPP; + + if (smu_ras_drv->smu_eeprom_funcs->get_timestamp) + return smu_ras_drv->smu_eeprom_funcs->get_timestamp(adev, + index, timestamp); + return -EOPNOTSUPP; +} + +int amdgpu_ras_smu_get_badpage_ipid(struct amdgpu_device *adev, + uint16_t index, uint64_t *ipid) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return -EOPNOTSUPP; + + if (smu_ras_drv->smu_eeprom_funcs->get_badpage_ipid) + return smu_ras_drv->smu_eeprom_funcs->get_badpage_ipid(adev, + index, ipid); + return -EOPNOTSUPP; +} + +int amdgpu_ras_smu_erase_ras_table(struct amdgpu_device *adev, + uint32_t *result) +{ + const struct ras_smu_drv *smu_ras_drv = amdgpu_ras_get_smu_ras_drv(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return -EOPNOTSUPP; + + if (smu_ras_drv->smu_eeprom_funcs->erase_ras_table) + return smu_ras_drv->smu_eeprom_funcs->erase_ras_table(adev, + result); + return -EOPNOTSUPP; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index feff46b22b6ff..cfbd402ddea2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -165,6 +165,27 @@ void amdgpu_ras_eeprom_check_and_recover(struct amdgpu_device *adev); bool amdgpu_ras_smu_eeprom_supported(struct amdgpu_device *adev); +int amdgpu_ras_smu_get_table_version(struct amdgpu_device *adev, + uint32_t *table_version); + +int amdgpu_ras_smu_get_badpage_count(struct amdgpu_device *adev, + uint32_t *count, uint32_t timeout); + +int amdgpu_ras_smu_get_badpage_mca_addr(struct amdgpu_device *adev, + uint16_t index, uint64_t *mca_addr); + +int amdgpu_ras_smu_set_timestamp(struct amdgpu_device *adev, + uint64_t timestamp); + +int amdgpu_ras_smu_get_timestamp(struct amdgpu_device *adev, + uint16_t index, uint64_t *timestamp); + +int amdgpu_ras_smu_get_badpage_ipid(struct amdgpu_device *adev, + uint16_t index, uint64_t *ipid); + +int amdgpu_ras_smu_erase_ras_table(struct amdgpu_device *adev, + uint32_t *result); + extern const struct file_operations amdgpu_ras_debugfs_eeprom_size_ops; extern const struct file_operations amdgpu_ras_debugfs_eeprom_table_ops; From 20dc791a8e6fe7bcde5af743f5af7d80690bcf6c Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Thu, 4 Sep 2025 18:04:33 +0800 Subject: [PATCH 29/62] drm/amdgpu: adapt reset function for pmfw eeprom adapt reset function for pmfw eeprom Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 2987028f45cbe..f0896d51d638c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -443,40 +443,51 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr; struct amdgpu_ras_eeprom_table_ras_info *rai = &control->tbl_rai; struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + u32 erase_res = 0; u8 csum; int res; mutex_lock(&control->ras_tbl_mutex); - hdr->header = RAS_TABLE_HDR_VAL; - amdgpu_ras_set_eeprom_table_version(control); + if (!amdgpu_ras_smu_eeprom_supported(adev)) { + hdr->header = RAS_TABLE_HDR_VAL; + amdgpu_ras_set_eeprom_table_version(control); - if (hdr->version >= RAS_TABLE_VER_V2_1) { - hdr->first_rec_offset = RAS_RECORD_START_V2_1; - hdr->tbl_size = RAS_TABLE_HEADER_SIZE + - RAS_TABLE_V2_1_INFO_SIZE; - rai->rma_status = GPU_HEALTH_USABLE; - /** - * GPU health represented as a percentage. - * 0 means worst health, 100 means fully health. - */ - rai->health_percent = 100; - /* ecc_page_threshold = 0 means disable bad page retirement */ - rai->ecc_page_threshold = con->bad_page_cnt_threshold; + if (hdr->version >= RAS_TABLE_VER_V2_1) { + hdr->first_rec_offset = RAS_RECORD_START_V2_1; + hdr->tbl_size = RAS_TABLE_HEADER_SIZE + + RAS_TABLE_V2_1_INFO_SIZE; + rai->rma_status = GPU_HEALTH_USABLE; + /** + * GPU health represented as a percentage. + * 0 means worst health, 100 means fully health. + */ + rai->health_percent = 100; + /* ecc_page_threshold = 0 means disable bad page retirement */ + rai->ecc_page_threshold = con->bad_page_cnt_threshold; + } else { + hdr->first_rec_offset = RAS_RECORD_START; + hdr->tbl_size = RAS_TABLE_HEADER_SIZE; + } + + csum = __calc_hdr_byte_sum(control); + if (hdr->version >= RAS_TABLE_VER_V2_1) + csum += __calc_ras_info_byte_sum(control); + csum = -csum; + hdr->checksum = csum; + res = __write_table_header(control); + if (!res && hdr->version > RAS_TABLE_VER_V1) + res = __write_table_ras_info(control); } else { - hdr->first_rec_offset = RAS_RECORD_START; - hdr->tbl_size = RAS_TABLE_HEADER_SIZE; + res = amdgpu_ras_smu_erase_ras_table(adev, &erase_res); + if (res || erase_res) { + dev_warn(adev->dev, "RAS EEPROM reset failed, res:%d result:%d", + res, erase_res); + if (!res) + res = -EIO; + } } - csum = __calc_hdr_byte_sum(control); - if (hdr->version >= RAS_TABLE_VER_V2_1) - csum += __calc_ras_info_byte_sum(control); - csum = -csum; - hdr->checksum = csum; - res = __write_table_header(control); - if (!res && hdr->version > RAS_TABLE_VER_V1) - res = __write_table_ras_info(control); - control->ras_num_recs = 0; control->ras_num_bad_pages = 0; control->ras_num_mca_recs = 0; From 17d5be1f56dfef7ce969e3eb9249aadb47249202 Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Thu, 4 Sep 2025 18:07:40 +0800 Subject: [PATCH 30/62] drm/amdgpu: add initialization function for pmfw eeprom add initialization function for pmfw eeprom Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index f0896d51d638c..25808ddd5dae9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1381,6 +1381,42 @@ static int __read_table_ras_info(struct amdgpu_ras_eeprom_control *control) return res == RAS_TABLE_V2_1_INFO_SIZE ? 0 : res; } +static int amdgpu_ras_smu_eeprom_init(struct amdgpu_ras_eeprom_control *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + uint64_t local_time; + int res; + + ras->is_rma = false; + + if (!__is_ras_eeprom_supported(adev)) + return 0; + mutex_init(&control->ras_tbl_mutex); + + res = amdgpu_ras_smu_get_table_version(adev, &(hdr->version)); + if (res) + return res; + + res = amdgpu_ras_smu_get_badpage_count(adev, + &(control->ras_num_recs), 100); + if (res) + return res; + + local_time = (uint64_t)ktime_get_real_seconds(); + res = amdgpu_ras_smu_set_timestamp(adev, local_time); + if (res) + return res; + + control->ras_max_record_count = 4000; + + control->ras_num_mca_recs = 0; + control->ras_num_pa_recs = 0; + + return 0; +} + int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -1389,6 +1425,9 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); int res; + if (amdgpu_ras_smu_eeprom_supported(adev)) + return amdgpu_ras_smu_eeprom_init(control); + ras->is_rma = false; if (!__is_ras_eeprom_supported(adev)) From 0362db36d1e77691828dc1f7ffb18b90b18ede1a Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Thu, 4 Sep 2025 18:09:40 +0800 Subject: [PATCH 31/62] drm/amdgpu: add check function for pmfw eeprom add check function for pmfw eeprom Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 25808ddd5dae9..998fde5db24f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1494,6 +1494,47 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) return 0; } +static int amdgpu_ras_smu_eeprom_check(struct amdgpu_ras_eeprom_control *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + + if (!__is_ras_eeprom_supported(adev)) + return 0; + + control->ras_num_bad_pages = ras->bad_page_num; + + if ((ras->bad_page_cnt_threshold < control->ras_num_bad_pages) && + amdgpu_bad_page_threshold != 0) { + dev_warn(adev->dev, + "RAS records:%d exceed threshold:%d\n", + control->ras_num_bad_pages, ras->bad_page_cnt_threshold); + if ((amdgpu_bad_page_threshold == -1) || + (amdgpu_bad_page_threshold == -2)) { + dev_warn(adev->dev, + "Please consult AMD Service Action Guide (SAG) for appropriate service procedures\n"); + } else { + ras->is_rma = true; + dev_warn(adev->dev, + "User defined threshold is set, runtime service will be halt when threshold is reached\n"); + } + + return 0; + } + + dev_dbg(adev->dev, + "Found existing EEPROM table with %d records", + control->ras_num_bad_pages); + + /* Warn if we are at 90% of the threshold or above + */ + if (10 * control->ras_num_bad_pages >= 9 * ras->bad_page_cnt_threshold) + dev_warn(adev->dev, "RAS records:%u exceeds 90%% of threshold:%d", + control->ras_num_bad_pages, + ras->bad_page_cnt_threshold); + return 0; +} + int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -1501,6 +1542,9 @@ int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control) struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); int res = 0; + if (amdgpu_ras_smu_eeprom_supported(adev)) + return amdgpu_ras_smu_eeprom_check(control); + if (!__is_ras_eeprom_supported(adev)) return 0; From a83aca721ca94cdc08a44bf2970a60a1c4adddd8 Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Wed, 22 Oct 2025 10:36:40 +0800 Subject: [PATCH 32/62] drm/amd/pm: check pmfw eeprom feature bit get and check the pmfw eeprom feature bit to decide if pmfw eeprom is supported Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- .../gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h | 2 +- drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 ++- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 7 +++++++ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 3 +++ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h index bf6aa9620911b..fa43d2e229a09 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h @@ -87,7 +87,7 @@ typedef enum { /*37*/ FEATURE_DVO = 37, /*38*/ FEATURE_XVMINORPSM_CLKSTOP_DS = 38, /*39*/ FEATURE_GLOBAL_DPM = 39, -/*40*/ FEATURE_NODE_POWER_MANAGER = 40, +/*40*/ FEATURE_HROM_EN = 40, /*41*/ NUM_FEATURES = 41 } FEATURE_LIST_e; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index 4a1d964333b03..bd759b0990e42 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -472,7 +472,8 @@ enum smu_clk_type { __SMU_DUMMY_MAP(GFX_EDC_XVMIN), \ __SMU_DUMMY_MAP(GFX_DIDT_XVMIN), \ __SMU_DUMMY_MAP(FAN_ABNORMAL), \ - __SMU_DUMMY_MAP(PIT), + __SMU_DUMMY_MAP(PIT), \ + __SMU_DUMMY_MAP(HROM_EN), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(feature) SMU_FEATURE_##feature##_BIT diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 5a54d54fb49f0..971960ebc379c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -82,6 +82,7 @@ const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[SMU_FEATURE_COUNT] = SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_DS_MPIOCLK), SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_DS_MP0CLK), SMU_13_0_12_FEA_MAP(SMU_FEATURE_PIT_BIT, FEATURE_PIT), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_HROM_EN_BIT, FEATURE_HROM_EN), }; const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[SMU_MSG_MAX_COUNT] = { @@ -1060,10 +1061,16 @@ static const struct ras_eeprom_smu_funcs smu_v13_0_12_eeprom_smu_funcs = { static void smu_v13_0_12_ras_smu_feature_flags(struct amdgpu_device *adev, uint64_t *flags) { + struct smu_context *smu = adev->powerplay.pp_handle; + if (!flags) return; *flags = 0ULL; + + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(RAS_EEPROM))) + *flags |= RAS_SMU_FEATURE_BIT__RAS_EEPROM; + } const struct ras_smu_drv smu_v13_0_12_ras_smu_drv = { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 7ec7d25c590e0..9f2015ee6e6ce 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -4041,6 +4041,9 @@ static int smu_v13_0_6_get_ras_smu_drv(struct smu_context *smu, const struct ras if (amdgpu_sriov_vf(smu->adev)) return -EOPNOTSUPP; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_HROM_EN_BIT)) + smu_v13_0_6_cap_set(smu, SMU_CAP(RAS_EEPROM)); + switch (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)) { case IP_VERSION(13, 0, 12): *ras_smu_drv = &smu_v13_0_12_ras_smu_drv; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h index b75d87f688fc7..1f5bcc497749e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h @@ -72,6 +72,7 @@ enum smu_v13_0_6_caps { SMU_CAP(PLDM_VERSION), SMU_CAP(TEMP_METRICS), SMU_CAP(NPM_METRICS), + SMU_CAP(RAS_EEPROM), SMU_CAP(ALL), }; From fdf50448c557907c935a704bf503b701afee7de5 Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Fri, 31 Oct 2025 13:41:36 +0800 Subject: [PATCH 33/62] drm/amdgpu: initialize max record count after table reset initialize max record count and record offset after table reset Signed-off-by: Gangliang Xie Reviewed-by: Tao Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 998fde5db24f9..f53a59a48756f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -458,6 +458,9 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) hdr->tbl_size = RAS_TABLE_HEADER_SIZE + RAS_TABLE_V2_1_INFO_SIZE; rai->rma_status = GPU_HEALTH_USABLE; + + control->ras_record_offset = RAS_RECORD_START_V2_1; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1; /** * GPU health represented as a percentage. * 0 means worst health, 100 means fully health. @@ -468,6 +471,9 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) } else { hdr->first_rec_offset = RAS_RECORD_START; hdr->tbl_size = RAS_TABLE_HEADER_SIZE; + + control->ras_record_offset = RAS_RECORD_START; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT; } csum = __calc_hdr_byte_sum(control); From 2b39bed2c0b929bcbdece53700d1afa4b22a2816 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Tue, 30 Sep 2025 10:56:00 +0800 Subject: [PATCH 34/62] drm/amdgpu: make MCA IPID parse global So we can call it in other blocks. v2: add a new IPID parse interface for umc and we can implement it for each ASIC. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h | 2 ++ drivers/gpu/drm/amd/amdgpu/umc_v12_0.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index ec203f9e5ffab..28dff750c47e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -113,6 +113,8 @@ struct amdgpu_umc_ras { uint32_t (*get_die_id_from_pa)(struct amdgpu_device *adev, uint64_t mca_addr, uint64_t retired_page); void (*get_retire_flip_bits)(struct amdgpu_device *adev); + void (*mca_ipid_parse)(struct amdgpu_device *adev, uint64_t ipid, + uint32_t *did, uint32_t *ch, uint32_t *umc_inst, uint32_t *sid); }; struct amdgpu_umc_funcs { diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c index 8dc32787d6250..0f5b1719fda56 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c @@ -711,6 +711,19 @@ static uint32_t umc_v12_0_get_die_id(struct amdgpu_device *adev, return die; } +static void umc_v12_0_mca_ipid_parse(struct amdgpu_device *adev, uint64_t ipid, + uint32_t *did, uint32_t *ch, uint32_t *umc_inst, uint32_t *sid) +{ + if (did) + *did = MCA_IPID_2_DIE_ID(ipid); + if (ch) + *ch = MCA_IPID_2_UMC_CH(ipid); + if (umc_inst) + *umc_inst = MCA_IPID_2_UMC_INST(ipid); + if (sid) + *sid = MCA_IPID_2_SOCKET_ID(ipid); +} + struct amdgpu_umc_ras umc_v12_0_ras = { .ras_block = { .hw_ops = &umc_v12_0_ras_hw_ops, @@ -724,5 +737,6 @@ struct amdgpu_umc_ras umc_v12_0_ras = { .convert_ras_err_addr = umc_v12_0_convert_error_address, .get_die_id_from_pa = umc_v12_0_get_die_id, .get_retire_flip_bits = umc_v12_0_get_retire_flip_bits, + .mca_ipid_parse = umc_v12_0_mca_ipid_parse, }; From cffad3d3f0805c766e69de6ae1a245f8680a82fc Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Wed, 23 Jul 2025 19:04:17 +0800 Subject: [PATCH 35/62] drm/amdgpu: add ras_eeprom_read_idx interface PMFW will manage RAS eeprom data by itself, add new interface to read eeprom data via PMFW, we can read part of records by setting index. v2: use IPID parse interface. pa is not used and set it to a fixed value. v3: optimize the null pointer check for IPID parse interface. Signed-off-by: Tao Zhou Reviewed-by: Yang Wang Reviewed-by: Hawking Zhang --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 51 +++++++++++++++++++ .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h | 4 ++ 2 files changed, 55 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index f53a59a48756f..57dffb5823fca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -965,6 +965,50 @@ static int __amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control, return res; } +int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *record, u32 rec_idx, + const u32 num) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + uint64_t ts, end_idx; + int i, ret; + u64 mca, ipid; + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return 0; + + if (!adev->umc.ras || !adev->umc.ras->mca_ipid_parse) + return -EOPNOTSUPP; + + end_idx = rec_idx + num; + for (i = rec_idx; i < end_idx; i++) { + ret = amdgpu_ras_smu_get_badpage_mca_addr(adev, i, &mca); + if (ret) + return ret; + + ret = amdgpu_ras_smu_get_badpage_ipid(adev, i, &ipid); + if (ret) + return ret; + + ret = amdgpu_ras_smu_get_timestamp(adev, i, &ts); + if (ret) + return ret; + + record[i - rec_idx].address = mca; + /* retired_page (pa) is unused now */ + record[i - rec_idx].retired_page = 0x1ULL; + record[i - rec_idx].ts = ts; + record[i - rec_idx].err_type = AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE; + record[i - rec_idx].cu = 0; + + adev->umc.ras->mca_ipid_parse(adev, ipid, NULL, + (uint32_t *)&(record[i - rec_idx].mem_channel), + (uint32_t *)&(record[i - rec_idx].mcumc_id), NULL); + } + + return 0; +} + /** * amdgpu_ras_eeprom_read -- read EEPROM * @control: pointer to control structure @@ -986,6 +1030,9 @@ int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control, u8 *buf, *pp; u32 g0, g1; + if (amdgpu_ras_smu_eeprom_supported(adev)) + return amdgpu_ras_eeprom_read_idx(control, record, 0, num); + if (!__is_ras_eeprom_supported(adev)) return 0; @@ -1157,6 +1204,10 @@ static ssize_t amdgpu_ras_debugfs_table_read(struct file *f, char __user *buf, int res = -EFAULT; size_t data_len; + /* pmfw manages eeprom data by itself */ + if (amdgpu_ras_smu_eeprom_supported(adev)) + return 0; + mutex_lock(&control->ras_tbl_mutex); /* We want *pos - data_len > 0, which means there's diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index cfbd402ddea2f..e881007f715b0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -186,6 +186,10 @@ int amdgpu_ras_smu_get_badpage_ipid(struct amdgpu_device *adev, int amdgpu_ras_smu_erase_ras_table(struct amdgpu_device *adev, uint32_t *result); +int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *record, u32 rec_idx, + const u32 num); + extern const struct file_operations amdgpu_ras_debugfs_eeprom_size_ops; extern const struct file_operations amdgpu_ras_debugfs_eeprom_table_ops; From d8d3facf28ecc2caf005a8d4b6ab4bc1ba63d9a6 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Thu, 24 Jul 2025 15:01:03 +0800 Subject: [PATCH 36/62] drm/amdgpu: support to load RAS bad pages from PMFW PMFW manages eeprom bad page records, update bad page loading accrodingly. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 7c487a171b979..dbb37ad371fd4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2995,8 +2995,12 @@ static int __amdgpu_ras_convert_rec_from_rom(struct amdgpu_device *adev, int i = 0; enum amdgpu_memory_partition save_nps; - save_nps = (bps->retired_page >> UMC_NPS_SHIFT) & UMC_NPS_MASK; - bps->retired_page &= ~(UMC_NPS_MASK << UMC_NPS_SHIFT); + if (!amdgpu_ras_smu_eeprom_supported(adev)) { + save_nps = (bps->retired_page >> UMC_NPS_SHIFT) & UMC_NPS_MASK; + bps->retired_page &= ~(UMC_NPS_MASK << UMC_NPS_SHIFT); + } else { + save_nps = nps; + } if (save_nps == nps) { if (amdgpu_umc_pages_in_a_row(adev, err_data, @@ -3062,7 +3066,8 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, if (from_rom) { /* there is no pa recs in V3, so skip pa recs processing */ - if (control->tbl_hdr.version < RAS_TABLE_VER_V3) { + if ((control->tbl_hdr.version < RAS_TABLE_VER_V3) && + !amdgpu_ras_smu_eeprom_supported(adev)) { for (i = 0; i < pages; i++) { if (control->ras_num_recs - i >= adev->umc.retire_unit) { if ((bps[i].address == bps[i + 1].address) && @@ -3193,7 +3198,8 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) /*In V3, there is no pa recs, and some cases(when address==0) may be parsed as pa recs, so add verion check to avoid it. */ - if (control->tbl_hdr.version < RAS_TABLE_VER_V3) { + if ((control->tbl_hdr.version < RAS_TABLE_VER_V3) && + !amdgpu_ras_smu_eeprom_supported(adev)) { for (i = 0; i < control->ras_num_recs; i++) { if ((control->ras_num_recs - i) >= adev->umc.retire_unit) { if ((bps[i].address == bps[i + 1].address) && From 202da73462462e8487f002981274cbb20111b7d6 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Mon, 8 Sep 2025 20:39:49 +0800 Subject: [PATCH 37/62] drm/amdgpu: skip writing eeprom when PMFW manages RAS data Only update bad page number in legacy eeprom write path. v2: add null pointer check for con. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 20 ++++++++++++++++++- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h | 3 +++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 57dffb5823fca..1fbbc615803fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -866,6 +866,18 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control) return res; } +int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + + if (!amdgpu_ras_smu_eeprom_supported(adev)) + return 0; + + control->ras_num_recs_old = control->ras_num_recs; + return amdgpu_ras_smu_get_badpage_count(adev, + &(control->ras_num_recs), 12); +} + /** * amdgpu_ras_eeprom_append -- append records to the EEPROM RAS table * @control: pointer to control structure @@ -884,12 +896,18 @@ int amdgpu_ras_eeprom_append(struct amdgpu_ras_eeprom_control *control, const u32 num) { struct amdgpu_device *adev = to_amdgpu_device(control); + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); int res, i; uint64_t nps = AMDGPU_NPS1_PARTITION_MODE; - if (!__is_ras_eeprom_supported(adev)) + if (!__is_ras_eeprom_supported(adev) || !con) return 0; + if (amdgpu_ras_smu_eeprom_supported(adev)) { + control->ras_num_bad_pages = con->bad_page_num; + return 0; + } + if (num == 0) { dev_err(adev->dev, "will not append 0 records\n"); return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index e881007f715b0..2e5d63957e714 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -82,6 +82,7 @@ struct amdgpu_ras_eeprom_control { /* Number of records in the table. */ u32 ras_num_recs; + u32 ras_num_recs_old; /* the bad page number is ras_num_recs or * ras_num_recs * umc.retire_unit @@ -190,6 +191,8 @@ int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control, struct eeprom_table_record *record, u32 rec_idx, const u32 num); +int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control); + extern const struct file_operations amdgpu_ras_debugfs_eeprom_size_ops; extern const struct file_operations amdgpu_ras_debugfs_eeprom_table_ops; From 8b72f514e8f93df0d0e8af1bfa2d5c12709e5376 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Fri, 25 Jul 2025 10:47:35 +0800 Subject: [PATCH 38/62] drm/amdgpu: load RAS bad page from PMFW in page retirement In legacy way, bad page is queried from MCA registers, switch to getting it from PMFW when PMFW manages eeprom data. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 8 +- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 137 ++++++++++++++---------- 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index dbb37ad371fd4..279d26b8683db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -3137,7 +3137,13 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev, mutex_lock(&con->recovery_lock); control = &con->eeprom_control; data = con->eh_data; - unit_num = data->count / adev->umc.retire_unit - control->ras_num_recs; + if (amdgpu_ras_smu_eeprom_supported(adev)) + unit_num = control->ras_num_recs - + control->ras_num_recs_old; + else + unit_num = data->count / adev->umc.retire_unit - + control->ras_num_recs; + save_count = con->bad_page_num - control->ras_num_bad_pages; mutex_unlock(&con->recovery_lock); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index 983a428eddd4a..f540ee37a4acc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -96,67 +96,96 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev, { struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + struct amdgpu_ras_eeprom_control *control = &con->eeprom_control; unsigned int error_query_mode; int ret = 0; unsigned long err_count; amdgpu_ras_get_error_query_mode(adev, &error_query_mode); + err_data->err_addr = + kcalloc(adev->umc.max_ras_err_cnt_per_query, + sizeof(struct eeprom_table_record), GFP_KERNEL); + + /* still call query_ras_error_address to clear error status + * even NOMEM error is encountered + */ + if (!err_data->err_addr) + dev_warn(adev->dev, + "Failed to alloc memory for umc error address record!\n"); + else + err_data->err_addr_len = adev->umc.max_ras_err_cnt_per_query; + mutex_lock(&con->page_retirement_lock); - ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc)); - if (ret == -EOPNOTSUPP && - error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { - if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && - adev->umc.ras->ras_block.hw_ops->query_ras_error_count) - adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev, ras_error_status); - - if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && - adev->umc.ras->ras_block.hw_ops->query_ras_error_address && - adev->umc.max_ras_err_cnt_per_query) { - err_data->err_addr = - kcalloc(adev->umc.max_ras_err_cnt_per_query, - sizeof(struct eeprom_table_record), GFP_KERNEL); - - /* still call query_ras_error_address to clear error status - * even NOMEM error is encountered - */ - if(!err_data->err_addr) - dev_warn(adev->dev, "Failed to alloc memory for " - "umc error address record!\n"); - else - err_data->err_addr_len = adev->umc.max_ras_err_cnt_per_query; - - /* umc query_ras_error_address is also responsible for clearing - * error status - */ - adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev, ras_error_status); + if (!amdgpu_ras_smu_eeprom_supported(adev)) { + ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc)); + if (ret == -EOPNOTSUPP && + error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { + if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && + adev->umc.ras->ras_block.hw_ops->query_ras_error_count) + adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev, + ras_error_status); + + if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && + adev->umc.ras->ras_block.hw_ops->query_ras_error_address && + adev->umc.max_ras_err_cnt_per_query) { + err_data->err_addr = + kcalloc(adev->umc.max_ras_err_cnt_per_query, + sizeof(struct eeprom_table_record), GFP_KERNEL); + + /* still call query_ras_error_address to clear error status + * even NOMEM error is encountered + */ + if (!err_data->err_addr) + dev_warn(adev->dev, + "Failed to alloc memory for umc error address record!\n"); + else + err_data->err_addr_len = + adev->umc.max_ras_err_cnt_per_query; + + /* umc query_ras_error_address is also responsible for clearing + * error status + */ + adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev, + ras_error_status); + } + } else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY || + (!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) { + if (adev->umc.ras && + adev->umc.ras->ecc_info_query_ras_error_count) + adev->umc.ras->ecc_info_query_ras_error_count(adev, + ras_error_status); + + if (adev->umc.ras && + adev->umc.ras->ecc_info_query_ras_error_address && + adev->umc.max_ras_err_cnt_per_query) { + err_data->err_addr = + kcalloc(adev->umc.max_ras_err_cnt_per_query, + sizeof(struct eeprom_table_record), GFP_KERNEL); + + /* still call query_ras_error_address to clear error status + * even NOMEM error is encountered + */ + if (!err_data->err_addr) + dev_warn(adev->dev, + "Failed to alloc memory for umc error address record!\n"); + else + err_data->err_addr_len = + adev->umc.max_ras_err_cnt_per_query; + + /* umc query_ras_error_address is also responsible for clearing + * error status + */ + adev->umc.ras->ecc_info_query_ras_error_address(adev, + ras_error_status); + } } - } else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY || - (!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) { - if (adev->umc.ras && - adev->umc.ras->ecc_info_query_ras_error_count) - adev->umc.ras->ecc_info_query_ras_error_count(adev, ras_error_status); - - if (adev->umc.ras && - adev->umc.ras->ecc_info_query_ras_error_address && - adev->umc.max_ras_err_cnt_per_query) { - err_data->err_addr = - kcalloc(adev->umc.max_ras_err_cnt_per_query, - sizeof(struct eeprom_table_record), GFP_KERNEL); - - /* still call query_ras_error_address to clear error status - * even NOMEM error is encountered - */ - if(!err_data->err_addr) - dev_warn(adev->dev, "Failed to alloc memory for " - "umc error address record!\n"); - else - err_data->err_addr_len = adev->umc.max_ras_err_cnt_per_query; - - /* umc query_ras_error_address is also responsible for clearing - * error status - */ - adev->umc.ras->ecc_info_query_ras_error_address(adev, ras_error_status); + } else { + if (!amdgpu_ras_eeprom_update_record_num(control)) { + err_data->err_addr_cnt = err_data->de_count = + control->ras_num_recs - control->ras_num_recs_old; + amdgpu_ras_eeprom_read_idx(control, err_data->err_addr, + control->ras_num_recs_old, err_data->de_count); } } @@ -166,7 +195,7 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev, if ((amdgpu_bad_page_threshold != 0) && err_data->err_addr_cnt) { amdgpu_ras_add_bad_pages(adev, err_data->err_addr, - err_data->err_addr_cnt, false); + err_data->err_addr_cnt, amdgpu_ras_smu_eeprom_supported(adev)); amdgpu_ras_save_bad_pages(adev, &err_count); amdgpu_dpm_send_hbm_bad_pages_num(adev, From be0076881a1a85a7067eefeb82fd35757ca520d5 Mon Sep 17 00:00:00 2001 From: Gangliang Xie Date: Thu, 6 Nov 2025 11:06:21 +0800 Subject: [PATCH 39/62] drm/amd/pm: remove unnecessary prints for smu busy smu busy is a normal case when calling SMU_MSG_GetBadPageCount, so no need to print error status at each time.Instead, only print error status when timeout given by user is reached. Signed-off-by: Gangliang Xie --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 2 ++ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 971960ebc379c..9208e357957ee 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -972,6 +972,8 @@ static int smu_v13_0_12_get_badpage_count(struct amdgpu_device *adev, uint32_t * now = (uint64_t)ktime_to_ms(ktime_get()); } while (now < end); + dev_err(adev->dev, + "smu get bad page count timeout!\n"); return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index f4d32f0c072f0..76918d5ed970a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -164,9 +164,13 @@ static void __smu_cmn_reg_print_error(struct smu_context *smu, msg_index, param, message); break; case SMU_RESP_BUSY_OTHER: - dev_err_ratelimited(adev->dev, - "SMU: I'm very busy for your command: index:%d param:0x%08X message:%s", - msg_index, param, message); + /* It is normal for SMU_MSG_GetBadPageCount to return busy + * so don't print error at this case. + */ + if (msg != SMU_MSG_GetBadPageCount) + dev_err_ratelimited(adev->dev, + "SMU: I'm very busy for your command: index:%d param:0x%08X message:%s", + msg_index, param, message); break; case SMU_RESP_DEBUG_END: dev_err_ratelimited(adev->dev, From 5d38c29bd97a43999054ca87bcec8ef36d09ac4f Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Wed, 27 Aug 2025 15:48:06 +0800 Subject: [PATCH 40/62] drm/amdgpu: get RAS bad page address from MCA address Instead of from physical address. v2: add comment to make the code more readable Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 15 ++++++++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 279d26b8683db..5f1070976a67d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2851,8 +2851,13 @@ static int amdgpu_ras_mca2pa_by_idx(struct amdgpu_device *adev, addr_in.ma.err_addr = bps->address; addr_in.ma.socket_id = socket; addr_in.ma.ch_inst = bps->mem_channel; - /* tell RAS TA the node instance is not used */ - addr_in.ma.node_inst = TA_RAS_INV_NODE; + if (!amdgpu_ras_smu_eeprom_supported(adev)) { + /* tell RAS TA the node instance is not used */ + addr_in.ma.node_inst = TA_RAS_INV_NODE; + } else { + addr_in.ma.umc_inst = bps->mcumc_id; + addr_in.ma.node_inst = bps->cu; + } if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr) ret = adev->umc.ras->convert_ras_err_addr(adev, err_data, @@ -2999,7 +3004,11 @@ static int __amdgpu_ras_convert_rec_from_rom(struct amdgpu_device *adev, save_nps = (bps->retired_page >> UMC_NPS_SHIFT) & UMC_NPS_MASK; bps->retired_page &= ~(UMC_NPS_MASK << UMC_NPS_SHIFT); } else { - save_nps = nps; + /* if pmfw manages eeprom, save_nps is not stored on eeprom, + * we should always convert mca address into physical address, + * make save_nps different from nps + */ + save_nps = nps + 1; } if (save_nps == nps) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 1fbbc615803fe..c92c2de6bc3b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1017,9 +1017,9 @@ int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control, record[i - rec_idx].retired_page = 0x1ULL; record[i - rec_idx].ts = ts; record[i - rec_idx].err_type = AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE; - record[i - rec_idx].cu = 0; - adev->umc.ras->mca_ipid_parse(adev, ipid, NULL, + adev->umc.ras->mca_ipid_parse(adev, ipid, + (uint32_t *)&(record[i - rec_idx].cu), (uint32_t *)&(record[i - rec_idx].mem_channel), (uint32_t *)&(record[i - rec_idx].mcumc_id), NULL); } From c7775b9329d0994b9173925d948a9b3fc4c72705 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Wed, 27 Aug 2025 19:33:02 +0800 Subject: [PATCH 41/62] drm/amdgpu: try for more times if RAS bad page number is not updated RAS info update in PMFW is time cost, wait for it. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index c92c2de6bc3b4..bb80db61b9927 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -869,13 +869,33 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control) int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control) { struct amdgpu_device *adev = to_amdgpu_device(control); + int ret, timeout = 1000; if (!amdgpu_ras_smu_eeprom_supported(adev)) return 0; control->ras_num_recs_old = control->ras_num_recs; - return amdgpu_ras_smu_get_badpage_count(adev, + + do { + ret = amdgpu_ras_smu_get_badpage_count(adev, &(control->ras_num_recs), 12); + if (!ret && + (control->ras_num_recs_old == control->ras_num_recs)) { + /* record number update in PMFW needs some time */ + msleep(50); + timeout -= 50; + } else { + break; + } + } while (timeout); + + /* no update of record number is not a real failure, + * don't print warning here + */ + if (!ret && (control->ras_num_recs_old == control->ras_num_recs)) + ret = -EINVAL; + + return ret; } /** From 78ac9584bd83ffad6b1c10051d20dca537a3bebb Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Wed, 24 Sep 2025 17:52:24 +0800 Subject: [PATCH 42/62] drm/amdgpu: add RAS bad page threshold handling for PMFW manages eeprom Check if bad page threshold is reached and take actions accordingly. v2: remove rma message sent to smu when pmfw manages eeprom. v3: add null pointer check for con. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index bb80db61b9927..9d23c4dcf90f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -898,6 +898,33 @@ int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *contro return ret; } +static int amdgpu_ras_smu_eeprom_append(struct amdgpu_ras_eeprom_control *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + + if (!amdgpu_ras_smu_eeprom_supported(adev) || !con) + return 0; + + control->ras_num_bad_pages = con->bad_page_num; + + if (amdgpu_bad_page_threshold != 0 && + control->ras_num_bad_pages > con->bad_page_cnt_threshold) { + dev_warn(adev->dev, + "Saved bad pages %d reaches threshold value %d\n", + control->ras_num_bad_pages, con->bad_page_cnt_threshold); + + if (adev->cper.enabled && amdgpu_cper_generate_bp_threshold_record(adev)) + dev_warn(adev->dev, "fail to generate bad page threshold cper records\n"); + + if ((amdgpu_bad_page_threshold != -1) && + (amdgpu_bad_page_threshold != -2)) + con->is_rma = true; + } + + return 0; +} + /** * amdgpu_ras_eeprom_append -- append records to the EEPROM RAS table * @control: pointer to control structure @@ -916,17 +943,14 @@ int amdgpu_ras_eeprom_append(struct amdgpu_ras_eeprom_control *control, const u32 num) { struct amdgpu_device *adev = to_amdgpu_device(control); - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); int res, i; uint64_t nps = AMDGPU_NPS1_PARTITION_MODE; - if (!__is_ras_eeprom_supported(adev) || !con) + if (!__is_ras_eeprom_supported(adev)) return 0; - if (amdgpu_ras_smu_eeprom_supported(adev)) { - control->ras_num_bad_pages = con->bad_page_num; - return 0; - } + if (amdgpu_ras_smu_eeprom_supported(adev)) + return amdgpu_ras_smu_eeprom_append(control); if (num == 0) { dev_err(adev->dev, "will not append 0 records\n"); From c2f940350b9e8ca7bbd1b5ed75f82453f0ea3cb7 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Thu, 6 Nov 2025 16:26:56 +0800 Subject: [PATCH 43/62] drm/amdgpu: optimize timeout implemention in ras_eeprom_update_record_num The busy status returned by ras_eeprom_update_record_num may not be an error, increase timeout to exclude false busy status. Also add more comments to make the code readable. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 9d23c4dcf90f3..abe9ebfa6e7d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -869,7 +869,7 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control) int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control) { struct amdgpu_device *adev = to_amdgpu_device(control); - int ret, timeout = 1000; + int ret, retry = 20; if (!amdgpu_ras_smu_eeprom_supported(adev)) return 0; @@ -877,17 +877,23 @@ int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *contro control->ras_num_recs_old = control->ras_num_recs; do { + /* 1000ms timeout is long enough, smu_get_badpage_count won't + * return -EBUSY before timeout. + */ ret = amdgpu_ras_smu_get_badpage_count(adev, - &(control->ras_num_recs), 12); + &(control->ras_num_recs), 1000); if (!ret && (control->ras_num_recs_old == control->ras_num_recs)) { - /* record number update in PMFW needs some time */ + /* record number update in PMFW needs some time, + * smu_get_badpage_count may return immediately without + * count update, sleep for a while and retry again. + */ msleep(50); - timeout -= 50; + retry--; } else { break; } - } while (timeout); + } while (retry); /* no update of record number is not a real failure, * don't print warning here From c53924ce581fbe2a0e3fb1584a8eb9c64707f821 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Tue, 14 Oct 2025 15:05:19 +0800 Subject: [PATCH 44/62] drm/amdgpu: get rev_id from strap register or IP-discovery table Query the sub-revision field in the IP Discovery table for the VFs to obtain their revision ID. Meanwhile, read the revision ID from the strap register for the PF. Signed-off-by: Perry Yuan Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 4 ++++ drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c | 24 +++++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 2041737a5fbe0..72897cf1ac818 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1841,6 +1841,10 @@ static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev) if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0)) adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM3E; + if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) && + adev->rev_id == 0x3) + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM3E; + if (!(adev->flags & AMD_IS_APU) && !amdgpu_sriov_vf(adev)) { vram_info = RREG32(regBIF_BIOS_SCRATCH_4); adev->gmc.vram_vendor = vram_info & 0xF; diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c index 1c22bc11c1f85..bdfd2917e3cab 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c @@ -41,19 +41,21 @@ static void nbio_v7_9_remap_hdp_registers(struct amdgpu_device *adev) static u32 nbio_v7_9_get_rev_id(struct amdgpu_device *adev) { - u32 tmp; - - tmp = IP_VERSION_SUBREV(amdgpu_ip_version_full(adev, NBIO_HWIP, 0)); - /* If it is VF or subrevision holds a non-zero value, that should be used */ - if (tmp || amdgpu_sriov_vf(adev)) - return tmp; + u32 rev_id; - /* If discovery subrev is not updated, use register version */ - tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0); - tmp = REG_GET_FIELD(tmp, RCC_STRAP0_RCC_DEV0_EPF0_STRAP0, - STRAP_ATI_REV_ID_DEV0_F0); + /* + * fetch the sub-revision field from the IP-discovery table + * (returns zero if the table entry is not populated). + */ + if (amdgpu_sriov_vf(adev)) { + rev_id = IP_VERSION_SUBREV(amdgpu_ip_version_full(adev, NBIO_HWIP, 0)); + } else { + rev_id = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0); + rev_id = REG_GET_FIELD(rev_id, RCC_STRAP0_RCC_DEV0_EPF0_STRAP0, + STRAP_ATI_REV_ID_DEV0_F0); + } - return tmp; + return rev_id; } static void nbio_v7_9_mc_access_enable(struct amdgpu_device *adev, bool enable) From b64b87cad27cedf1655df23451ce0e44a1c8bbbc Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Thu, 6 Nov 2025 11:12:37 +0800 Subject: [PATCH 45/62] drm/amdgpu: add new performance monitor PSP interfaces Introduce new psp interfaces and structures for performance monitoring hardware control. Signed-off-by: Perry Yuan Reviewed-by: Lijo Lazar Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 22 ++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 022b70522d763..58862d0fa44c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -357,6 +357,28 @@ struct spirom_bo { }; #endif +enum psp_ptl_cmd { + PSP_PTL_PERF_MON_QUERY = 0xA0000000, + PSP_PTL_PERF_MON_SET = 0xA0000001, +}; + +enum psp_ptl_format_type +{ + GFX_FTYPE_I8 = 0x00000000, + GFX_FTYPE_F16 = 0x00000001, + GFX_FTYPE_BF16 = 0x00000002, + GFX_FTYPE_F32 = 0x00000003, + GFX_FTYPE_F64 = 0x00000004, + GFX_FTYPE_INVALID = 0xFFFFFFFF, +}; + +struct psp_ptl_perf_req { + enum psp_ptl_cmd req; + uint32_t ptl_state; + uint32_t pref_format1; + uint32_t pref_format2; +}; + struct psp_context { struct amdgpu_device *adev; struct psp_ring km_ring; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h index 333d59f3eb119..bcb36951dc4cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h +++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h @@ -107,6 +107,7 @@ enum psp_gfx_cmd_id GFX_CMD_ID_CONFIG_SQ_PERFMON = 0x00000046, /* Config CGTT_SQ_CLK_CTRL */ /* Dynamic memory partitioninig (NPS mode change)*/ GFX_CMD_ID_FB_NPS_MODE = 0x00000048, /* Configure memory partitioning mode */ + GFX_CMD_ID_PERF_HW = 0x0000004C, /* performance monitor */ GFX_CMD_ID_FB_FW_RESERV_ADDR = 0x00000050, /* Query FW reservation addr */ GFX_CMD_ID_FB_FW_RESERV_EXT_ADDR = 0x00000051, /* Query FW reservation extended addr */ }; @@ -371,6 +372,13 @@ struct psp_gfx_cmd_fb_memory_part { uint32_t resvd; }; +struct psp_gfx_cmd_req_perf_hw { + uint32_t req; + uint32_t ptl_state; + uint32_t pref_format1; + uint32_t pref_format2; +}; + /* All GFX ring buffer commands. */ union psp_gfx_commands { @@ -387,6 +395,7 @@ union psp_gfx_commands struct psp_gfx_cmd_sriov_spatial_part cmd_spatial_part; struct psp_gfx_cmd_config_sq_perfmon config_sq_perfmon; struct psp_gfx_cmd_fb_memory_part cmd_memory_part; + struct psp_gfx_cmd_req_perf_hw cmd_req_perf_hw; }; struct psp_gfx_uresp_reserved @@ -413,12 +422,21 @@ struct psp_gfx_uresp_fw_reserve_info { uint32_t reserve_size; }; +struct psp_gfx_uresp_perf_hw +{ + uint32_t resp; + uint32_t ptl_state; + uint32_t pref_format1; + uint32_t pref_format2; +}; + /* Union of command-specific responses for GPCOM ring. */ union psp_gfx_uresp { struct psp_gfx_uresp_reserved reserved; struct psp_gfx_uresp_bootcfg boot_cfg; struct psp_gfx_uresp_fwar_db_info fwar_db_info; struct psp_gfx_uresp_fw_reserve_info fw_reserve_info; + struct psp_gfx_uresp_perf_hw perf_hw_info; }; /* Structure of GFX Response buffer. From d7a5b4cbe8e1568d5188f95286fe03c4d344c5c2 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Tue, 4 Nov 2025 17:45:55 +0800 Subject: [PATCH 46/62] drm/amdgpu: add psp interfaces for peak tops limiter driver Introduce a Peak Tops Limiter (PTL) driver that dynamically caps engine frequency to ensure delivered TOPS never exceeds a defined TOPS_limit. This initial implementation provides core data structures and kernel-space interfaces (set/get, enable/disable) to manage PTL state. PTL performs a firmware handshake to initialize its state and update predefined format types. It supports updating these format types at runtime while user-space tools automatically switch PTL state, and also allows explicitly switching PTL state via newly added commands. Signed-off-by: Perry Yuan Reviewed-by: Lijo Lazar Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 80 +++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 6 ++ include/uapi/linux/kfd_ioctl.h | 9 +++ 3 files changed, 95 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 5e6040d901bd3..d09b1f364717d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -670,6 +670,8 @@ static const char *psp_gfx_cmd_name(enum psp_gfx_cmd_id cmd_id) return "SPATIAL_PARTITION"; case GFX_CMD_ID_FB_NPS_MODE: return "NPS_MODE_CHANGE"; + case GFX_CMD_ID_PERF_HW: + return "PERF MONITORING HW"; default: return "UNKNOWN CMD"; } @@ -1200,6 +1202,84 @@ int psp_memory_partition(struct psp_context *psp, int mode) return ret; } +static int psp_ptl_fmt_verify(struct psp_context *psp, enum amdgpu_ptl_fmt fmt, + uint32_t *ptl_fmt) +{ + struct amdgpu_device *adev = psp->adev; + + if (amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(9, 4, 4)) + return -EINVAL; + + switch (fmt) { + case AMDGPU_PTL_FMT_I8: + *ptl_fmt = GFX_FTYPE_I8; + break; + case AMDGPU_PTL_FMT_F16: + *ptl_fmt = GFX_FTYPE_F16; + break; + case AMDGPU_PTL_FMT_BF16: + *ptl_fmt = GFX_FTYPE_BF16; + break; + case AMDGPU_PTL_FMT_F32: + *ptl_fmt = GFX_FTYPE_F32; + break; + case AMDGPU_PTL_FMT_F64: + *ptl_fmt = GFX_FTYPE_F64; + break; + default: + return -EINVAL; + } + + return 0; +} + +int psp_performance_monitor_hw(struct psp_context *psp, u32 req_code, + uint32_t *ptl_state, uint32_t *fmt1, uint32_t *fmt2) +{ + struct psp_gfx_cmd_resp *cmd; + uint32_t ptl_fmt1, ptl_fmt2; + int ret; + + if (!psp || !ptl_state || !fmt1 || !fmt2) + return -EINVAL; + + if (amdgpu_sriov_vf(psp->adev)) + return 0; + + if (psp_ptl_fmt_verify(psp, *fmt1, &ptl_fmt1) || + psp_ptl_fmt_verify(psp, *fmt2, &ptl_fmt2)) + return -EINVAL; + + cmd = acquire_psp_cmd_buf(psp); + + cmd->cmd_id = GFX_CMD_ID_PERF_HW; + cmd->cmd.cmd_req_perf_hw.req = req_code; + cmd->cmd.cmd_req_perf_hw.ptl_state = *ptl_state; + cmd->cmd.cmd_req_perf_hw.pref_format1 = ptl_fmt1; + cmd->cmd.cmd_req_perf_hw.pref_format2 = ptl_fmt2; + + ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + if (ret) + goto out; + + switch (req_code) { + case PSP_PTL_PERF_MON_QUERY: + *ptl_state = cmd->resp.uresp.perf_hw_info.ptl_state; + *fmt1 = cmd->resp.uresp.perf_hw_info.pref_format1; + *fmt2 = cmd->resp.uresp.perf_hw_info.pref_format2; + break; + case PSP_PTL_PERF_MON_SET: + psp->ptl_enabled = *ptl_state; + psp->ptl_fmt1 = ptl_fmt1; + psp->ptl_fmt2 = ptl_fmt2; + break; + } + +out: + release_psp_cmd_buf(psp); + return ret; +} + int psp_spatial_partition(struct psp_context *psp, int mode) { struct psp_gfx_cmd_resp *cmd; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 58862d0fa44c0..eb979108c74d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -469,6 +469,10 @@ struct psp_context { #if defined(CONFIG_DEBUG_FS) struct spirom_bo *spirom_dump_trip; #endif + enum amdgpu_ptl_fmt ptl_fmt1; + enum amdgpu_ptl_fmt ptl_fmt2; + bool ptl_enabled; + bool ptl_hw_supported; }; struct amdgpu_psp_funcs { @@ -644,5 +648,7 @@ int amdgpu_psp_reg_program_no_ring(struct psp_context *psp, uint32_t val, enum psp_reg_prog_id id); void amdgpu_psp_debugfs_init(struct amdgpu_device *adev); +int psp_performance_monitor_hw(struct psp_context *psp, u32 req_code, + u32 *ptl_state, u32 *fmt1, u32 *fmt2); #endif diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index bdeebc8caebff..a7d68fc391ad4 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -1700,6 +1700,15 @@ enum kfd_ioctl_pc_sample_op { KFD_IOCTL_PCS_OP_STOP, }; +enum amdgpu_ptl_fmt { + AMDGPU_PTL_FMT_I8 = 0, + AMDGPU_PTL_FMT_F16 = 1, + AMDGPU_PTL_FMT_BF16 = 2, + AMDGPU_PTL_FMT_F32 = 3, + AMDGPU_PTL_FMT_F64 = 4, + AMDGPU_PTL_FMT_INVALID = 5, +}; + /* Values have to be a power of 2*/ #define KFD_IOCTL_PCS_FLAG_POWER_OF_2 0x00000001 From 1acae0dcc6d155f5ffcacc118e7189044e32c1d8 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Tue, 4 Nov 2025 17:53:18 +0800 Subject: [PATCH 47/62] drm/amdgpu: add PTL enable/query gfx control support for GC 9.4.4 Introduce hardware detection, runtime state tracking and a kgd->ptl_ctrl() callback to enable/disable/query PTL via the PSP performance-monitor interface (commands 0xA0000000/1). The driver now exposes PTL capability to KFD and keeps the software state in sync with the hardware. Signed-off-by: Perry Yuan Reviewed-by: Lijo Lazar Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index cbf358d28c632..95c30010ebeef 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -2392,11 +2392,45 @@ static int gfx_v9_4_3_hw_init(struct amdgpu_ip_block *ip_block) return r; } +static int gfx_v9_4_3_perf_monitor_ptl_init(struct amdgpu_device *adev, bool state) +{ + uint32_t fmt1, fmt2; + uint32_t ptl_state = state ? 1 : 0; + int r; + + if (amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(9, 4, 4)) + return -ENOTSUPP; + + if (!adev->psp.funcs) + return -EOPNOTSUPP; + + if (!adev->psp.ptl_hw_supported) { + fmt1 = GFX_FTYPE_I8; + fmt2 = GFX_FTYPE_BF16; + } else { + fmt1 = adev->psp.ptl_fmt1; + fmt2 = adev->psp.ptl_fmt2; + } + + /* initialize PTL with default formats: GFX_FTYPE_I8 & GFX_FTYPE_BF16 */ + r = psp_performance_monitor_hw(&adev->psp, PSP_PTL_PERF_MON_SET, &ptl_state, + &fmt1, &fmt2); + if (r) + return r; + + adev->psp.ptl_hw_supported = true; + + return 0; +} + static int gfx_v9_4_3_hw_fini(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; int i, num_xcc; + if (adev->psp.ptl_hw_supported) + gfx_v9_4_3_perf_monitor_ptl_init(adev, 0); + amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.spm_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -2676,6 +2710,8 @@ static int gfx_v9_4_3_late_init(struct amdgpu_ip_block *ip_block) adev->gfx.ras->enable_watchdog_timer) adev->gfx.ras->enable_watchdog_timer(adev); + gfx_v9_4_3_perf_monitor_ptl_init(adev, 1); + return 0; } From c991e9ce9846516ae8becc4edd57c64ce4d3d1f8 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Tue, 4 Nov 2025 17:57:30 +0800 Subject: [PATCH 48/62] drm/amdkfd: add kgd control interface for ptl Add kgd->ptl_ctrl() callback so KFD can query/enable/disable PTL state through the PSP performance monitor interface. Signed-off-by: Perry Yuan Reviewed-by: Lijo Lazar Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c | 11 +++++++++++ drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c index a577e1ff00401..a6058a1c5a3e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c @@ -550,6 +550,16 @@ static uint32_t kgd_v9_4_3_trigger_pc_sample_trap(struct amdgpu_device *adev, target_simd, target_wave_slot, method, inst); } +static uint32_t kgd_v9_4_3_ptl_ctrl(struct amdgpu_device *adev, + uint32_t cmd, + uint32_t *ptl_state, + enum amdgpu_ptl_fmt *fmt1, + enum amdgpu_ptl_fmt *fmt2) +{ + return psp_performance_monitor_hw(&adev->psp, cmd, + ptl_state, fmt1, fmt2); +} + static uint32_t kgd_v9_4_3_setup_stoch_sampling(struct amdgpu_device *adev, uint32_t compute_vmid_bitmap, bool enable, @@ -613,4 +623,5 @@ const struct kfd2kgd_calls gc_9_4_3_kfd2kgd = { .trigger_pc_sample_trap = kgd_v9_4_3_trigger_pc_sample_trap, .override_core_cg = kgd_gfx_v9_4_3_override_core_cg, .setup_stoch_sampling = kgd_v9_4_3_setup_stoch_sampling, + .ptl_ctrl = kgd_v9_4_3_ptl_ctrl, }; diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index df5b578a5e6b1..e1c25444a0fab 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -355,6 +355,11 @@ struct kfd2kgd_calls { enum kfd_ioctl_pc_sample_type type, uint64_t intval, uint32_t inst); + uint32_t (*ptl_ctrl)(struct amdgpu_device *adev, + uint32_t cmd, + uint32_t *ptl_state, + enum amdgpu_ptl_fmt *fmt1, + enum amdgpu_ptl_fmt *fmt2); }; #endif /* KGD_KFD_INTERFACE_H_INCLUDED */ From b9e648a31dfe3d6245b65556315826911e1a98fa Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Tue, 11 Nov 2025 15:41:12 +0800 Subject: [PATCH 49/62] drm/amdgpu: integrate PTL control with PMC device locking Combine PTL hardware control with the existing PMC device locking mechanism to ensure proper synchronization and hardware state management during profiling operations. Signed-off-by: Perry Yuan Reviewed-by: Lijo Lazar Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 2ddb83ae6f578..f062d6df779df 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1888,6 +1888,27 @@ static int kfd_ioctl_pc_sample(struct file *filep, return ret; } +static int kfd_ptl_control(struct kfd_process_device *pdd, bool enable) +{ + struct amdgpu_device *adev = pdd->dev->adev; + enum amdgpu_ptl_fmt pref_format1 = adev->psp.ptl_fmt1; + enum amdgpu_ptl_fmt pref_format2 = adev->psp.ptl_fmt2; + uint32_t ptl_state = enable ? 1 : 0; + int ret; + + if (!adev->psp.ptl_hw_supported) + return -EOPNOTSUPP; + + if (!pdd->dev->kfd2kgd || !pdd->dev->kfd2kgd->ptl_ctrl) + return -EOPNOTSUPP; + + ret = pdd->dev->kfd2kgd->ptl_ctrl(adev, PSP_PTL_PERF_MON_SET, + &ptl_state, + &pref_format1, + &pref_format2); + return ret; +} + static int criu_checkpoint_process(struct kfd_process *p, uint8_t __user *user_priv_data, uint64_t *priv_offset) @@ -3392,6 +3413,7 @@ static inline uint32_t profile_lock_device(struct kfd_process *p, if (!kfd->profiler_process) { kfd->profiler_process = p; status = 0; + kfd_ptl_control(pdd, false); } else if (kfd->profiler_process == p) { status = -EALREADY; } else { @@ -3400,6 +3422,7 @@ static inline uint32_t profile_lock_device(struct kfd_process *p, } else if (op == 0 && kfd->profiler_process == p) { kfd->profiler_process = NULL; status = 0; + kfd_ptl_control(pdd, true); } mutex_unlock(&kfd->profiler_lock); From 1163438be73cfb3e67211e9b98596693677afd96 Mon Sep 17 00:00:00 2001 From: Alexander Deucher Date: Wed, 12 Nov 2025 12:03:06 -0500 Subject: [PATCH 50/62] Revert "drm/amdgpu: integrate PTL control with PMC device locking" Revert submission 1291049 Reason for revert: RM needs merge this Reverted Changes: I63bec83a0:drm/amdgpu: integrate PTL control with PMC device ... I31b7df2a3:drm/amdgpu: add PTL enable/query gfx control suppo... I6682872fe:drm/amdkfd: add kgd control interface for ptl Ide92c0668:drm/amdgpu: add new performance monitor PSP interf... I2d019792a:drm/amdgpu: add psp interfaces for peak tops limit... Change-Id: Ic3d2cd5a72afcd04b3cc0d2c3d9d898cf708552e --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index f062d6df779df..2ddb83ae6f578 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1888,27 +1888,6 @@ static int kfd_ioctl_pc_sample(struct file *filep, return ret; } -static int kfd_ptl_control(struct kfd_process_device *pdd, bool enable) -{ - struct amdgpu_device *adev = pdd->dev->adev; - enum amdgpu_ptl_fmt pref_format1 = adev->psp.ptl_fmt1; - enum amdgpu_ptl_fmt pref_format2 = adev->psp.ptl_fmt2; - uint32_t ptl_state = enable ? 1 : 0; - int ret; - - if (!adev->psp.ptl_hw_supported) - return -EOPNOTSUPP; - - if (!pdd->dev->kfd2kgd || !pdd->dev->kfd2kgd->ptl_ctrl) - return -EOPNOTSUPP; - - ret = pdd->dev->kfd2kgd->ptl_ctrl(adev, PSP_PTL_PERF_MON_SET, - &ptl_state, - &pref_format1, - &pref_format2); - return ret; -} - static int criu_checkpoint_process(struct kfd_process *p, uint8_t __user *user_priv_data, uint64_t *priv_offset) @@ -3413,7 +3392,6 @@ static inline uint32_t profile_lock_device(struct kfd_process *p, if (!kfd->profiler_process) { kfd->profiler_process = p; status = 0; - kfd_ptl_control(pdd, false); } else if (kfd->profiler_process == p) { status = -EALREADY; } else { @@ -3422,7 +3400,6 @@ static inline uint32_t profile_lock_device(struct kfd_process *p, } else if (op == 0 && kfd->profiler_process == p) { kfd->profiler_process = NULL; status = 0; - kfd_ptl_control(pdd, true); } mutex_unlock(&kfd->profiler_lock); From b980c4c4ee29fdaf7557c99f50c931368113c76a Mon Sep 17 00:00:00 2001 From: Alexander Deucher Date: Wed, 12 Nov 2025 12:03:06 -0500 Subject: [PATCH 51/62] Revert "drm/amdkfd: add kgd control interface for ptl" Revert submission 1291049 Reason for revert: RM needs merge this Reverted Changes: I63bec83a0:drm/amdgpu: integrate PTL control with PMC device ... I31b7df2a3:drm/amdgpu: add PTL enable/query gfx control suppo... I6682872fe:drm/amdkfd: add kgd control interface for ptl Ide92c0668:drm/amdgpu: add new performance monitor PSP interf... I2d019792a:drm/amdgpu: add psp interfaces for peak tops limit... Change-Id: I7a96c6b934864773cbe08995280100a76451f104 --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c | 11 ----------- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 5 ----- 2 files changed, 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c index a6058a1c5a3e1..a577e1ff00401 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c @@ -550,16 +550,6 @@ static uint32_t kgd_v9_4_3_trigger_pc_sample_trap(struct amdgpu_device *adev, target_simd, target_wave_slot, method, inst); } -static uint32_t kgd_v9_4_3_ptl_ctrl(struct amdgpu_device *adev, - uint32_t cmd, - uint32_t *ptl_state, - enum amdgpu_ptl_fmt *fmt1, - enum amdgpu_ptl_fmt *fmt2) -{ - return psp_performance_monitor_hw(&adev->psp, cmd, - ptl_state, fmt1, fmt2); -} - static uint32_t kgd_v9_4_3_setup_stoch_sampling(struct amdgpu_device *adev, uint32_t compute_vmid_bitmap, bool enable, @@ -623,5 +613,4 @@ const struct kfd2kgd_calls gc_9_4_3_kfd2kgd = { .trigger_pc_sample_trap = kgd_v9_4_3_trigger_pc_sample_trap, .override_core_cg = kgd_gfx_v9_4_3_override_core_cg, .setup_stoch_sampling = kgd_v9_4_3_setup_stoch_sampling, - .ptl_ctrl = kgd_v9_4_3_ptl_ctrl, }; diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index e1c25444a0fab..df5b578a5e6b1 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -355,11 +355,6 @@ struct kfd2kgd_calls { enum kfd_ioctl_pc_sample_type type, uint64_t intval, uint32_t inst); - uint32_t (*ptl_ctrl)(struct amdgpu_device *adev, - uint32_t cmd, - uint32_t *ptl_state, - enum amdgpu_ptl_fmt *fmt1, - enum amdgpu_ptl_fmt *fmt2); }; #endif /* KGD_KFD_INTERFACE_H_INCLUDED */ From 4d3dfef309bbce729f6959d4f88b5d98c7a64737 Mon Sep 17 00:00:00 2001 From: Alexander Deucher Date: Wed, 12 Nov 2025 12:03:06 -0500 Subject: [PATCH 52/62] Revert "drm/amdgpu: add PTL enable/query gfx control support for..." Revert submission 1291049 Reason for revert: RM needs merge this Reverted Changes: I63bec83a0:drm/amdgpu: integrate PTL control with PMC device ... I31b7df2a3:drm/amdgpu: add PTL enable/query gfx control suppo... I6682872fe:drm/amdkfd: add kgd control interface for ptl Ide92c0668:drm/amdgpu: add new performance monitor PSP interf... I2d019792a:drm/amdgpu: add psp interfaces for peak tops limit... Change-Id: I8189f2da53b916b3fc874ac686742c8737949a05 --- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 36 ------------------------- 1 file changed, 36 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 95c30010ebeef..cbf358d28c632 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -2392,45 +2392,11 @@ static int gfx_v9_4_3_hw_init(struct amdgpu_ip_block *ip_block) return r; } -static int gfx_v9_4_3_perf_monitor_ptl_init(struct amdgpu_device *adev, bool state) -{ - uint32_t fmt1, fmt2; - uint32_t ptl_state = state ? 1 : 0; - int r; - - if (amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(9, 4, 4)) - return -ENOTSUPP; - - if (!adev->psp.funcs) - return -EOPNOTSUPP; - - if (!adev->psp.ptl_hw_supported) { - fmt1 = GFX_FTYPE_I8; - fmt2 = GFX_FTYPE_BF16; - } else { - fmt1 = adev->psp.ptl_fmt1; - fmt2 = adev->psp.ptl_fmt2; - } - - /* initialize PTL with default formats: GFX_FTYPE_I8 & GFX_FTYPE_BF16 */ - r = psp_performance_monitor_hw(&adev->psp, PSP_PTL_PERF_MON_SET, &ptl_state, - &fmt1, &fmt2); - if (r) - return r; - - adev->psp.ptl_hw_supported = true; - - return 0; -} - static int gfx_v9_4_3_hw_fini(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; int i, num_xcc; - if (adev->psp.ptl_hw_supported) - gfx_v9_4_3_perf_monitor_ptl_init(adev, 0); - amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.spm_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -2710,8 +2676,6 @@ static int gfx_v9_4_3_late_init(struct amdgpu_ip_block *ip_block) adev->gfx.ras->enable_watchdog_timer) adev->gfx.ras->enable_watchdog_timer(adev); - gfx_v9_4_3_perf_monitor_ptl_init(adev, 1); - return 0; } From 6b7bcc073156477ca3cf1836a070e70b3d2d4850 Mon Sep 17 00:00:00 2001 From: Alexander Deucher Date: Wed, 12 Nov 2025 12:03:06 -0500 Subject: [PATCH 53/62] Revert "drm/amdgpu: add psp interfaces for peak tops limiter driver" Revert submission 1291049 Reason for revert: RM needs merge this Reverted Changes: I63bec83a0:drm/amdgpu: integrate PTL control with PMC device ... I31b7df2a3:drm/amdgpu: add PTL enable/query gfx control suppo... I6682872fe:drm/amdkfd: add kgd control interface for ptl Ide92c0668:drm/amdgpu: add new performance monitor PSP interf... I2d019792a:drm/amdgpu: add psp interfaces for peak tops limit... Change-Id: Id08776d4d52ff9427791c54bc7cf45d7960661cb --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 80 ------------------------- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 6 -- include/uapi/linux/kfd_ioctl.h | 9 --- 3 files changed, 95 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index d09b1f364717d..5e6040d901bd3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -670,8 +670,6 @@ static const char *psp_gfx_cmd_name(enum psp_gfx_cmd_id cmd_id) return "SPATIAL_PARTITION"; case GFX_CMD_ID_FB_NPS_MODE: return "NPS_MODE_CHANGE"; - case GFX_CMD_ID_PERF_HW: - return "PERF MONITORING HW"; default: return "UNKNOWN CMD"; } @@ -1202,84 +1200,6 @@ int psp_memory_partition(struct psp_context *psp, int mode) return ret; } -static int psp_ptl_fmt_verify(struct psp_context *psp, enum amdgpu_ptl_fmt fmt, - uint32_t *ptl_fmt) -{ - struct amdgpu_device *adev = psp->adev; - - if (amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(9, 4, 4)) - return -EINVAL; - - switch (fmt) { - case AMDGPU_PTL_FMT_I8: - *ptl_fmt = GFX_FTYPE_I8; - break; - case AMDGPU_PTL_FMT_F16: - *ptl_fmt = GFX_FTYPE_F16; - break; - case AMDGPU_PTL_FMT_BF16: - *ptl_fmt = GFX_FTYPE_BF16; - break; - case AMDGPU_PTL_FMT_F32: - *ptl_fmt = GFX_FTYPE_F32; - break; - case AMDGPU_PTL_FMT_F64: - *ptl_fmt = GFX_FTYPE_F64; - break; - default: - return -EINVAL; - } - - return 0; -} - -int psp_performance_monitor_hw(struct psp_context *psp, u32 req_code, - uint32_t *ptl_state, uint32_t *fmt1, uint32_t *fmt2) -{ - struct psp_gfx_cmd_resp *cmd; - uint32_t ptl_fmt1, ptl_fmt2; - int ret; - - if (!psp || !ptl_state || !fmt1 || !fmt2) - return -EINVAL; - - if (amdgpu_sriov_vf(psp->adev)) - return 0; - - if (psp_ptl_fmt_verify(psp, *fmt1, &ptl_fmt1) || - psp_ptl_fmt_verify(psp, *fmt2, &ptl_fmt2)) - return -EINVAL; - - cmd = acquire_psp_cmd_buf(psp); - - cmd->cmd_id = GFX_CMD_ID_PERF_HW; - cmd->cmd.cmd_req_perf_hw.req = req_code; - cmd->cmd.cmd_req_perf_hw.ptl_state = *ptl_state; - cmd->cmd.cmd_req_perf_hw.pref_format1 = ptl_fmt1; - cmd->cmd.cmd_req_perf_hw.pref_format2 = ptl_fmt2; - - ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); - if (ret) - goto out; - - switch (req_code) { - case PSP_PTL_PERF_MON_QUERY: - *ptl_state = cmd->resp.uresp.perf_hw_info.ptl_state; - *fmt1 = cmd->resp.uresp.perf_hw_info.pref_format1; - *fmt2 = cmd->resp.uresp.perf_hw_info.pref_format2; - break; - case PSP_PTL_PERF_MON_SET: - psp->ptl_enabled = *ptl_state; - psp->ptl_fmt1 = ptl_fmt1; - psp->ptl_fmt2 = ptl_fmt2; - break; - } - -out: - release_psp_cmd_buf(psp); - return ret; -} - int psp_spatial_partition(struct psp_context *psp, int mode) { struct psp_gfx_cmd_resp *cmd; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index eb979108c74d0..58862d0fa44c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -469,10 +469,6 @@ struct psp_context { #if defined(CONFIG_DEBUG_FS) struct spirom_bo *spirom_dump_trip; #endif - enum amdgpu_ptl_fmt ptl_fmt1; - enum amdgpu_ptl_fmt ptl_fmt2; - bool ptl_enabled; - bool ptl_hw_supported; }; struct amdgpu_psp_funcs { @@ -648,7 +644,5 @@ int amdgpu_psp_reg_program_no_ring(struct psp_context *psp, uint32_t val, enum psp_reg_prog_id id); void amdgpu_psp_debugfs_init(struct amdgpu_device *adev); -int psp_performance_monitor_hw(struct psp_context *psp, u32 req_code, - u32 *ptl_state, u32 *fmt1, u32 *fmt2); #endif diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index a7d68fc391ad4..bdeebc8caebff 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -1700,15 +1700,6 @@ enum kfd_ioctl_pc_sample_op { KFD_IOCTL_PCS_OP_STOP, }; -enum amdgpu_ptl_fmt { - AMDGPU_PTL_FMT_I8 = 0, - AMDGPU_PTL_FMT_F16 = 1, - AMDGPU_PTL_FMT_BF16 = 2, - AMDGPU_PTL_FMT_F32 = 3, - AMDGPU_PTL_FMT_F64 = 4, - AMDGPU_PTL_FMT_INVALID = 5, -}; - /* Values have to be a power of 2*/ #define KFD_IOCTL_PCS_FLAG_POWER_OF_2 0x00000001 From a79d8cf9e5da1b608ad5897e29c5595c8a06c7fe Mon Sep 17 00:00:00 2001 From: Alexander Deucher Date: Wed, 12 Nov 2025 12:03:06 -0500 Subject: [PATCH 54/62] Revert "drm/amdgpu: add new performance monitor PSP interfaces" Revert submission 1291049 Reason for revert: RM needs merge this Reverted Changes: I63bec83a0:drm/amdgpu: integrate PTL control with PMC device ... I31b7df2a3:drm/amdgpu: add PTL enable/query gfx control suppo... I6682872fe:drm/amdkfd: add kgd control interface for ptl Ide92c0668:drm/amdgpu: add new performance monitor PSP interf... I2d019792a:drm/amdgpu: add psp interfaces for peak tops limit... Change-Id: I4df792d6cf22c16ae0272673894dfc4ca28a859f --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 22 ---------------------- drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h | 18 ------------------ 2 files changed, 40 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 58862d0fa44c0..022b70522d763 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -357,28 +357,6 @@ struct spirom_bo { }; #endif -enum psp_ptl_cmd { - PSP_PTL_PERF_MON_QUERY = 0xA0000000, - PSP_PTL_PERF_MON_SET = 0xA0000001, -}; - -enum psp_ptl_format_type -{ - GFX_FTYPE_I8 = 0x00000000, - GFX_FTYPE_F16 = 0x00000001, - GFX_FTYPE_BF16 = 0x00000002, - GFX_FTYPE_F32 = 0x00000003, - GFX_FTYPE_F64 = 0x00000004, - GFX_FTYPE_INVALID = 0xFFFFFFFF, -}; - -struct psp_ptl_perf_req { - enum psp_ptl_cmd req; - uint32_t ptl_state; - uint32_t pref_format1; - uint32_t pref_format2; -}; - struct psp_context { struct amdgpu_device *adev; struct psp_ring km_ring; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h index bcb36951dc4cb..333d59f3eb119 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h +++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h @@ -107,7 +107,6 @@ enum psp_gfx_cmd_id GFX_CMD_ID_CONFIG_SQ_PERFMON = 0x00000046, /* Config CGTT_SQ_CLK_CTRL */ /* Dynamic memory partitioninig (NPS mode change)*/ GFX_CMD_ID_FB_NPS_MODE = 0x00000048, /* Configure memory partitioning mode */ - GFX_CMD_ID_PERF_HW = 0x0000004C, /* performance monitor */ GFX_CMD_ID_FB_FW_RESERV_ADDR = 0x00000050, /* Query FW reservation addr */ GFX_CMD_ID_FB_FW_RESERV_EXT_ADDR = 0x00000051, /* Query FW reservation extended addr */ }; @@ -372,13 +371,6 @@ struct psp_gfx_cmd_fb_memory_part { uint32_t resvd; }; -struct psp_gfx_cmd_req_perf_hw { - uint32_t req; - uint32_t ptl_state; - uint32_t pref_format1; - uint32_t pref_format2; -}; - /* All GFX ring buffer commands. */ union psp_gfx_commands { @@ -395,7 +387,6 @@ union psp_gfx_commands struct psp_gfx_cmd_sriov_spatial_part cmd_spatial_part; struct psp_gfx_cmd_config_sq_perfmon config_sq_perfmon; struct psp_gfx_cmd_fb_memory_part cmd_memory_part; - struct psp_gfx_cmd_req_perf_hw cmd_req_perf_hw; }; struct psp_gfx_uresp_reserved @@ -422,21 +413,12 @@ struct psp_gfx_uresp_fw_reserve_info { uint32_t reserve_size; }; -struct psp_gfx_uresp_perf_hw -{ - uint32_t resp; - uint32_t ptl_state; - uint32_t pref_format1; - uint32_t pref_format2; -}; - /* Union of command-specific responses for GPCOM ring. */ union psp_gfx_uresp { struct psp_gfx_uresp_reserved reserved; struct psp_gfx_uresp_bootcfg boot_cfg; struct psp_gfx_uresp_fwar_db_info fwar_db_info; struct psp_gfx_uresp_fw_reserve_info fw_reserve_info; - struct psp_gfx_uresp_perf_hw perf_hw_info; }; /* Structure of GFX Response buffer. From 8b0726aee511d2ce6bf6abbd950f60414efe70f4 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Wed, 12 Nov 2025 11:55:42 -0500 Subject: [PATCH 55/62] Revert "drm/amdgpu: integrate PTL control with PMC device locking" Revert submission 1291049 Reason for revert: Reverted Changes: I63bec83a0:drm/amdgpu: integrate PTL control with PMC device ... I6682872fe:drm/amdkfd: add kgd control interface for ptl I31b7df2a3:drm/amdgpu: add PTL enable/query gfx control suppo... I2d019792a:drm/amdgpu: add psp interfaces for peak tops limit... Ide92c0668:drm/amdgpu: add new performance monitor PSP interf... Change-Id: I94ea76ebec3c0b78e78a7605e5032ac449dd96dd From 17f1f16c53c514a4aaad6090ed79668e1f6e28f3 Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Thu, 6 Nov 2025 10:03:20 -0500 Subject: [PATCH 56/62] drm/amdgpu: disable peer-to-peer access for DCC-enabled GC12 VRAM surfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Certain multi-GPU configurations (especially GFX12) may hit data corruption when a DCC-compressed VRAM surface is shared across GPUs using peer-to-peer (P2P) DMA transfers. Such surfaces rely on device-local metadata and cannot be safely accessed through a remote GPU’s page tables. Attempting to import a DCC-enabled surface through P2P leads to incorrect rendering or GPU faults. This change disables P2P for DCC-enabled VRAM buffers that are contiguous and allocated on GFX12+ hardware. In these cases, the importer falls back to the standard system-memory path, avoiding invalid access to compressed surfaces. Future work could consider optional migration (VRAM→System→VRAM) if a performance regression is observed when `attach->peer2peer = false`. Tested on: - Dual RX 9700 XT (Navi4x) setup - GNOME and Wayland compositor scenarios - Confirmed no corruption after disabling P2P under these conditions Suggested-by: Christian König Signed-off-by: Vitaly Prosyak Reviewed-by: Christian König Change-Id: Ia0dd9eb39ab7a8c2226717307f6cc81083ce8773 --- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index 9a0bce3ba24c9..d2d31031f672d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -260,11 +260,24 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); #ifdef HAVE_STRUCT_DMA_BUF_ATTACH_OPS_ALLOW_PEER2PEER + /* + * Disable peer-to-peer access for DCC-enabled VRAM surfaces on GFX12+. + * Such buffers cannot be safely accessed over P2P due to device-local + * compression metadata. Fallback to system-memory path instead. + * Device supports GFX12 (GC 12.x or newer) + * BO was created with the AMDGPU_GEM_CREATE_GFX12_DCC flag + * + */ + if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(12, 0, 0)) && + bo->flags & AMDGPU_GEM_CREATE_GFX12_DCC) { + attach->peer2peer = false; + goto update_vm; + } if (!amdgpu_dmabuf_is_xgmi_accessible(attach_adev, bo) && pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) attach->peer2peer = false; #endif - +update_vm: amdgpu_vm_bo_update_shared(bo); return 0; From 63f896b4d2a03be33250ebf2ca37f9832d13b9c9 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Fri, 31 Oct 2025 10:50:02 -0400 Subject: [PATCH 57/62] drm/amdkfd: Don't clear PT after process killed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If process is killed. the vm entity is stopped, submit pt update job will trigger the error message "*ERROR* Trying to push to a killed entity", job will not execute. Suggested-by: Christian König Signed-off-by: Philip Yang Reviewed-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 66c44cc4fffdc..e47a54678d915 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1364,6 +1364,10 @@ static int unmap_bo_from_gpuvm(struct kgd_mem *mem, (void)amdgpu_vm_bo_unmap(adev, bo_va, entry->va); + /* VM entity stopped if process killed, don't clear freed pt bo */ + if (!amdgpu_vm_ready(vm)) + return 0; + (void)amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update); (void)amdgpu_sync_fence(sync, bo_va->last_pt_update, GFP_KERNEL); From 39c36219bf8a02d22bb588136bb56f79d9e186e5 Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Wed, 12 Nov 2025 12:18:14 -0500 Subject: [PATCH 58/62] drm/amdkfd: Fix AIS deinit warnings Device manager releases device-specific resources when a driver disconnects from a device, devm_memunmap_pages is redundant. It causes below warning trace when module is removed Call Trace: dump_stack_lvl+0x76/0xa0 dump_stack+0x10/0x20 bad_page+0x76/0x120 free_page_is_bad_report+0x86/0xa0 free_unref_page_prepare+0x279/0x3d0 free_unref_page+0x34/0x180 __free_pages+0x112/0x130 free_pages+0x3d/0x60 free_pagetable+0xc4/0xe0 remove_pud_table+0x1c3/0x270 remove_p4d_table+0xf8/0x1b0 remove_pagetable+0xd7/0x160 arch_remove_memory+0x3d/0x50 memunmap_pages+0xbe/0x300 devm_memremap_pages_release+0xe/0x20 devm_action_release+0x15/0x30 release_nodes+0x45/0xd0 devres_release_all+0x97/0xe0 device_unbind_cleanup+0x12/0x80 device_release_driver_internal+0x230/0x270 driver_detach+0x4a/0xa0 bus_remove_driver+0x83/0x110 driver_unregister+0x2f/0x60 pci_unregister_driver+0x40/0x90 amdgpu_exit+0x15/0x3b [amdgpu] __do_sys_delete_module.constprop.0+0x1a3/0x300 __x64_sys_delete_module+0x12/0x20 x64_sys_call+0x14e9/0x24b0 do_syscall_64+0x81/0x170 entry_SYSCALL_64_after_hwframe+0x78/0x80 Fixes: b70e506746de ("drm/amdkfd: Add AMD Infinity Storage (AIS) support") Signed-off-by: Harish Kasiviswanathan Reviewed-by: Lijo Lazar --- drivers/gpu/drm/amd/amdkfd/kfd_ais.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_ais.c b/drivers/gpu/drm/amd/amdkfd/kfd_ais.c index f4dd34909cfd4..4533393b02249 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_ais.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_ais.c @@ -154,24 +154,7 @@ int kfd_ais_init(struct amdgpu_device *adev) void kfd_ais_deinit(struct amdgpu_device *adev) { - if (adev->kfd.dev->ais_initialized) { - unsigned long pci_start_pfn = PHYS_PFN(pci_resource_start(adev->pdev, 0)); - struct page *p2p_page = NULL; - - if (pfn_valid(pci_start_pfn)) { - p2p_page = pfn_to_page(pci_start_pfn); -#ifdef HAVE_PAGE_PGMAP - if (p2p_page && is_pci_p2pdma_page(p2p_page) && - page_pgmap(p2p_page)) - devm_memunmap_pages(&adev->pdev->dev, page_pgmap(p2p_page)); -#else - if (p2p_page && is_pci_p2pdma_page(p2p_page) && - p2p_page->pgmap) - devm_memunmap_pages(&adev->pdev->dev, p2p_page->pgmap); -#endif - } - adev->kfd.dev->ais_initialized = false; - } + adev->kfd.dev->ais_initialized = false; } int kfd_ais_rw_file(struct amdgpu_device *adev, struct amdgpu_bo *bo, From db63a49961f7a36c4285e584bf2cb6cdf17bb672 Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Thu, 13 Nov 2025 16:20:27 -0500 Subject: [PATCH 59/62] drm/amdkfd: Don't remap PCI P2P range Commit 502360c9a391 ("drm/amdkfd: Fix AIS deinit warnings") removed devm_memunmap_pages from kfd_ais_deinit(). kfd_ais_init() gets called again when compute or memory partitions are changed. Don't remap P2P range again if P2P range has already been initialized. Fixes: 502360c9a391 ("drm/amdkfd: Fix AIS deinit warnings") Signed-off-by: Harish Kasiviswanathan Reviewed-by: Lijo Lazar --- drivers/gpu/drm/amd/amdkfd/kfd_ais.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_ais.c b/drivers/gpu/drm/amd/amdkfd/kfd_ais.c index 4533393b02249..6ebd0cd026512 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_ais.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_ais.c @@ -123,6 +123,8 @@ int kfd_ais_init(struct amdgpu_device *adev) { #ifdef CONFIG_PCI_P2PDMA int ret; + struct page *p2p_page = NULL; + unsigned long pci_start_pfn = PHYS_PFN(pci_resource_start(adev->pdev, 0)); unsigned long size = ALIGN(adev->gmc.real_vram_size, 2ULL << 20); bool is_large_bar = adev->gmc.visible_vram_size && adev->gmc.real_vram_size == adev->gmc.visible_vram_size; @@ -133,6 +135,13 @@ int kfd_ais_init(struct amdgpu_device *adev) return 0; } + p2p_page = pfn_valid(pci_start_pfn) ? pfn_to_page(pci_start_pfn) : NULL; + if (p2p_page && is_pci_p2pdma_page(p2p_page)) { + adev->kfd.dev->ais_initialized = true; + dev_dbg(adev->dev, "AIS: PCI P2PDMA resource already exists\n"); + return 0; + } + ret = pci_p2pdma_add_resource(adev->pdev, 0 /*bar*/, 0 /*whole VRAM*/, 0 /*offset*/); if (ret) { From 6fbeb5921cbd1e69e41a8986ff2b324d2798c774 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 19 Nov 2025 20:19:22 +0530 Subject: [PATCH 60/62] drm/amdkfd: Disable AIS on virtualized environment AIS is not supported on virtualization yet. Signed-off-by: Lijo Lazar Reviewed-by: Harish Kasiviswanathan --- drivers/gpu/drm/amd/amdkfd/kfd_ais.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_ais.c b/drivers/gpu/drm/amd/amdkfd/kfd_ais.c index 6ebd0cd026512..9e59c32f9516f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_ais.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_ais.c @@ -129,6 +129,11 @@ int kfd_ais_init(struct amdgpu_device *adev) bool is_large_bar = adev->gmc.visible_vram_size && adev->gmc.real_vram_size == adev->gmc.visible_vram_size; + if (amdgpu_sriov_vf(adev)) { + dev_dbg(adev->dev, "AIS: not supported on SRIOV\n"); + return 0; + } + /* AIS support limited to large BAR dGPUs */ if (adev->flags & AMD_IS_APU || adev->gmc.xgmi.connected_to_cpu || !is_large_bar) { dev_dbg(adev->dev, "AIS: only supported for large BAR dGPU\n"); From 01cee31f91e55dc913933217d10341360f4a6f9e Mon Sep 17 00:00:00 2001 From: Shikang Fan Date: Wed, 19 Nov 2025 18:05:10 +0800 Subject: [PATCH 61/62] drm/amdgpu: Add sriov vf check for VCN per queue reset support. Add SRIOV check when setting VCN ring's supported reset mask. Signed-off-by: Shikang Fan Reviewed-by: Lijo Lazar --- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 2 +- drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c index eacf4e93ba2fe..cb7123ec1a5d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c @@ -141,7 +141,7 @@ static int vcn_v4_0_3_late_init(struct amdgpu_ip_block *ip_block) adev->vcn.supported_reset = amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); - if (amdgpu_dpm_reset_vcn_is_supported(adev)) + if (amdgpu_dpm_reset_vcn_is_supported(adev) && !amdgpu_sriov_vf(adev)) adev->vcn.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c index 714350cabf2fc..8bd457dea4cff 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c @@ -122,7 +122,9 @@ static int vcn_v5_0_1_late_init(struct amdgpu_ip_block *ip_block) switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { case IP_VERSION(13, 0, 12): - if ((adev->psp.sos.fw_version >= 0x00450025) && amdgpu_dpm_reset_vcn_is_supported(adev)) + if ((adev->psp.sos.fw_version >= 0x00450025) && + amdgpu_dpm_reset_vcn_is_supported(adev) && + !amdgpu_sriov_vf(adev)) adev->vcn.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; break; default: From fa6e6b8566d0d3a26810d6ca8d3c87b5098bcafd Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Sat, 17 Jan 2026 16:27:02 -0500 Subject: [PATCH 62/62] drm/amdgpu: fix non-x86 GPU VCRAT parsing On ppc64le, an IO link entry in the GPU VCRAT causes a parsing failure which results in the device not being added to the kfd topology: amdgpu [...]: amdgpu: Error parsing VCRAT kfd kfd: amdgpu: Error adding device to topology kfd kfd: amdgpu: Error initializing KFD node kfd kfd: amdgpu: device [...]:[...] NOT added due to errors In kfd_create_vcrat_image_gpu, skip IO link entry creation on non-x86 platforms, matching kfd_create_vcrat_image_cpu's behaviour. With this change, the device is successfully added to the kfd topology on ppc64le. --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 17ddfe4092020..569a5d7bfa5ec 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -2344,6 +2344,7 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image, * Only direct links are added here which is Link from GPU to * its NUMA node. Indirect links are added by userspace. */ +#ifdef CONFIG_X86_64 sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr + sub_type_hdr->length); ret = kfd_fill_gpu_direct_io_link_to_cpu(&avail_size, kdev, @@ -2354,6 +2355,9 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image, crat_table->length += sub_type_hdr->length; crat_table->total_entries++; +#else + pr_info("IO link not available for non x86 platforms\n"); +#endif /* Fill in Subtype: IO_LINKS