From 504f0098ebd074ac8c0ce3471795d79f68e3d265 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 2 Apr 2026 22:44:29 -0400 Subject: drm/amd/pm: fix incorrect FeatureCtrlMask setting on smu v14.0.x OverDriveTable.FanMinimumPwm and FeatureCtrlMask.PP_OD_FEATURE_FAN_LEGACY_BIT have a hard dependency. Invalid handling of this dependency leads to disabled thermal monitoring and temperature boundary validation. v2: squash in typo fix (Yang) Fixes: 9710b84e2a6a ("drm/amd/pm: add overdrive support on smu v14.0.2/3") Cc: stable@vger.kernel.org Signed-off-by: Yang Wang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 62514e3ac600..983bb31bb53e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -2374,6 +2374,7 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp } od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: od_table->OverDriveTable.FanZeroRpmEnable = @@ -2402,7 +2403,8 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp od_table->OverDriveTable.FanMinimumPwm = boot_overdrive_table->OverDriveTable.FanMinimumPwm; od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; default: dev_info(adev->dev, "Invalid table index: %ld\n", input); @@ -2572,6 +2574,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FanLinearPwmPoints[input[0]] = input[2]; od_table->OverDriveTable.FanMode = FAN_MODE_MANUAL_LINEAR; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); break; case PP_OD_EDIT_ACOUSTIC_LIMIT: @@ -2641,7 +2644,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, break; case PP_OD_EDIT_FAN_MINIMUM_PWM: - if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) { + if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_LEGACY_BIT)) { dev_warn(adev->dev, "Fan curve setting not supported!\n"); return -ENOTSUPP; } @@ -2659,7 +2662,8 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FanMinimumPwm = input[0]; od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: -- cgit v1.2.3 From a094bcf204cd86485624ac1a1fd3913337a89446 Mon Sep 17 00:00:00 2001 From: Xiaogang Chen Date: Tue, 7 Apr 2026 16:16:23 -0500 Subject: drm/amdgpu: Remove sys file compute_partition_mem_alloc_mode at module unload Module reload would fail when create sys file that was not removed during module unload. Fixes: e0e9792ea2d4 ("drm/amdgpu: add an option to allow gpu partition allocate all available memory") Signed-off-by: Xiaogang Chen Reviewed-by: Philip Yang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 2956e45c9254..b8ca876694ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -2013,6 +2013,8 @@ static void amdgpu_gfx_sysfs_xcp_fini(struct amdgpu_device *adev) (xcp_mgr->funcs && xcp_mgr->funcs->switch_partition_mode); device_remove_file(adev->dev, &dev_attr_current_compute_partition); + device_remove_file(adev->dev, &dev_attr_compute_partition_mem_alloc_mode); + if (xcp_switch_supported) device_remove_file(adev->dev, &dev_attr_available_compute_partition); -- cgit v1.2.3 From 574b3b14f7d1b329fc6e67b79328f0e6f4d4b3d4 Mon Sep 17 00:00:00 2001 From: "Ramalingeswara Reddy, Kanala" Date: Tue, 31 Mar 2026 17:23:22 +0530 Subject: drm/amdgpu: Use SMUIO 15.0.0 offsets for TSC upper and lower count. Define and use regGOLDEN_TSC_COUNT_UPPER_smu_15_0_0 and regGOLDEN_TSC_COUNT_LOWER_smu_15_0_0 for TSC upper and lower count. Acked-by: Alex Deucher Reviewed-by: Pratik Vishwakarma Signed-off-by: Ramalingeswara Reddy, Kanala Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 5097de940a19..8c82e90f871b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -64,6 +64,11 @@ #define regPC_CONFIG_CNTL_1 0x194d #define regPC_CONFIG_CNTL_1_BASE_IDX 1 +#define regGOLDEN_TSC_COUNT_UPPER_smu_15_0_0 0x0030 +#define regGOLDEN_TSC_COUNT_UPPER_smu_15_0_0_BASE_IDX 1 +#define regGOLDEN_TSC_COUNT_LOWER_smu_15_0_0 0x0031 +#define regGOLDEN_TSC_COUNT_LOWER_smu_15_0_0_BASE_IDX 1 + #define regCP_GFX_MQD_CONTROL_DEFAULT 0x00000100 #define regCP_GFX_HQD_VMID_DEFAULT 0x00000000 #define regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT 0x00000000 @@ -5234,11 +5239,27 @@ static uint64_t gfx_v11_0_get_gpu_clock_counter(struct amdgpu_device *adev) amdgpu_gfx_off_ctrl(adev, true); } else { preempt_disable(); - clock_counter_hi_pre = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_UPPER); - clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_LOWER); - clock_counter_hi_after = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_UPPER); - if (clock_counter_hi_pre != clock_counter_hi_after) - clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_LOWER); + if (amdgpu_ip_version(adev, SMUIO_HWIP, 0) < IP_VERSION(15, 0, 0)) { + clock_counter_hi_pre = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_UPPER); + clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_LOWER); + clock_counter_hi_after = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_UPPER); + if (clock_counter_hi_pre != clock_counter_hi_after) + clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_LOWER); + } else { + clock_counter_hi_pre = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_UPPER_smu_15_0_0); + clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_LOWER_smu_15_0_0); + clock_counter_hi_after = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_UPPER_smu_15_0_0); + if (clock_counter_hi_pre != clock_counter_hi_after) + clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, + regGOLDEN_TSC_COUNT_LOWER_smu_15_0_0); + } preempt_enable(); } clock = clock_counter_lo | (clock_counter_hi_after << 32ULL); -- cgit v1.2.3 From ddda81c4d7e71e41b1be91d921fd85747eddbd12 Mon Sep 17 00:00:00 2001 From: Chenglei Xie Date: Tue, 7 Apr 2026 10:51:24 -0400 Subject: drm/amdgpu: gate VM CPU HDP flush on reset lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During GPU reset, the application could still run CPU page table updates. Each commit called amdgpu_device_flush_hdp(), which on SR-IOV sends work through the KIQ ring. That can advance sync_seq while the GPU is being reset, leaving fence writeback out of sync and causing amdgpu_fence_emit_polling() to time out on later KIQ use. Fix: amdgpu_vm_cpu_commit(): Reset will flush HDP anyway, the HDP flush in amdgpu_vm_cpu_commit() can be skipped when a reset is ongoging. Take reset_domain->sem with down_read_trylock() before amdgpu_device_flush_hdp(). If the reset path holds the write lock, skip the HDP flush so no HDP-related HW access (including KIQ) runs during reset; state is re-established after reset. Signed-off-by: Chenglei Xie Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm_cpu.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_cpu.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_cpu.c index 22e2e5b47341..f078db3fef79 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_cpu.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_cpu.c @@ -21,6 +21,8 @@ */ #include "amdgpu_vm.h" +#include "amdgpu.h" +#include "amdgpu_reset.h" #include "amdgpu_object.h" #include "amdgpu_trace.h" @@ -108,11 +110,19 @@ static int amdgpu_vm_cpu_update(struct amdgpu_vm_update_params *p, static int amdgpu_vm_cpu_commit(struct amdgpu_vm_update_params *p, struct dma_fence **fence) { + struct amdgpu_device *adev = p->adev; + if (p->needs_flush) atomic64_inc(&p->vm->tlb_seq); mb(); - amdgpu_device_flush_hdp(p->adev, NULL); + /* A reset flushed the HDP anyway, so that here can be skipped when a reset is ongoing */ + if (!down_read_trylock(&adev->reset_domain->sem)) + return 0; + + amdgpu_device_flush_hdp(adev, NULL); + up_read(&adev->reset_domain->sem); + return 0; } -- cgit v1.2.3 From e90dc3b2d73986610476b02c29d0074aa4d92fb0 Mon Sep 17 00:00:00 2001 From: "David (Ming Qiang) Wu" Date: Mon, 9 Mar 2026 18:48:37 -0400 Subject: amdgpu/jpeg: fix deepsleep register for jpeg 5_0_0 and 5_0_2 PCTL0__MMHUB_DEEPSLEEP_IB is 0x69004 on MMHUB 4,1,0 and and 0x60804 on MMHUB 4,2,0. 0x62a04 is on MMHUB 1,8,0/1. The DS bits are adjusted to cover more JPEG engines and MMHUB version. Signed-off-by: David (Ming Qiang) Wu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 52 ++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c index 4b4aa9553624..82abe181c730 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c @@ -736,15 +736,35 @@ static void jpeg_v4_0_3_dec_ring_set_wptr(struct amdgpu_ring *ring) */ void jpeg_v4_0_3_dec_ring_insert_start(struct amdgpu_ring *ring) { - if (!amdgpu_sriov_vf(ring->adev)) { + struct amdgpu_device *adev = ring->adev; + + if (!amdgpu_sriov_vf(adev)) { + int jpeg_inst = GET_INST(JPEG, ring->me); + uint32_t value = 0x80004000; /* default DS14 */ + amdgpu_ring_write(ring, PACKETJ(regUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x62a04); /* PCTL0_MMHUB_DEEPSLEEP_IB */ + + /* PCTL0__MMHUB_DEEPSLEEP_IB could be different on different mmhub version */ + switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { + case IP_VERSION(4, 1, 0): + amdgpu_ring_write(ring, 0x69004); + value = 0x80010000; + break; + case IP_VERSION(4, 2, 0): + amdgpu_ring_write(ring, 0x60804); + if (jpeg_inst & 1) + value = 0x80010000; + break; + default: + amdgpu_ring_write(ring, 0x62a04); + break; + } amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x80004000); + amdgpu_ring_write(ring, value); } } @@ -757,15 +777,35 @@ void jpeg_v4_0_3_dec_ring_insert_start(struct amdgpu_ring *ring) */ void jpeg_v4_0_3_dec_ring_insert_end(struct amdgpu_ring *ring) { - if (!amdgpu_sriov_vf(ring->adev)) { + struct amdgpu_device *adev = ring->adev; + + if (!amdgpu_sriov_vf(adev)) { + int jpeg_inst = GET_INST(JPEG, ring->me); + uint32_t value = 0x00004000; /* default DS14 */ + amdgpu_ring_write(ring, PACKETJ(regUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x62a04); + + /* PCTL0__MMHUB_DEEPSLEEP_IB could be different on different mmhub version */ + switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { + case IP_VERSION(4, 1, 0): + amdgpu_ring_write(ring, 0x69004); + value = 0x00010000; + break; + case IP_VERSION(4, 2, 0): + amdgpu_ring_write(ring, 0x60804); + if (jpeg_inst & 1) + value = 0x00010000; + break; + default: + amdgpu_ring_write(ring, 0x62a04); + break; + } amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x00004000); + amdgpu_ring_write(ring, value); } } -- cgit v1.2.3 From 2744103f58e8e03ce675c670bbfe3f46034e5f24 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 8 Apr 2026 22:36:49 -0500 Subject: drm/amd: Add missing firmware declaration for PSP v15.0.0 PSP v15.0.0 needs both TOC and TA firmware. Without the declaration it won't get included in initramfs and leads to following failure: ``` Direct firmware load for amdgpu/psp_15_0_0_ta.bin failed with error -2 early_init of IP block failed -19 Fatal error during GPU init ``` Fixes: 9b24f63d825e7 ("drm/amdgpu: Enable support for PSP 15_0_0") Reviewed-by: Pratik Vishwakarma Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/psp_v15_0.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c index 73a709773e85..2a8582e87f2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c @@ -32,6 +32,7 @@ #include "mp/mp_15_0_0_sh_mask.h" MODULE_FIRMWARE("amdgpu/psp_15_0_0_toc.bin"); +MODULE_FIRMWARE("amdgpu/psp_15_0_0_ta.bin"); static int psp_v15_0_0_init_microcode(struct psp_context *psp) { -- cgit v1.2.3 From 08cdf07b55bff236aeaea3d52a8d1ffe11d801ec Mon Sep 17 00:00:00 2001 From: "Ramalingeswara Reddy, Kanala" Date: Fri, 10 Apr 2026 11:20:20 +0530 Subject: drm/amdgpu: Use NBIF offset for register RCC_STRAP0_RCC_DEV0_EPF0_STRAP0 . Define and use regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10, to get correct rev_id in nbif_v6_3_1_get_rev_id(). Reviewed-by: Pratik Vishwakarma Signed-off-by: Ramalingeswara Reddy, Kanala Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c index db14a1a326d2..b6f832c53860 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c @@ -54,6 +54,8 @@ #define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL_nbif_4_10_BASE_IDX 3 #define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL1_nbif_4_10 0x4f0af6 #define regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL1_nbif_4_10_BASE_IDX 3 +#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10 0x0021 +#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10_BASE_IDX 2 static void nbif_v6_3_1_remap_hdp_registers(struct amdgpu_device *adev) { @@ -65,7 +67,12 @@ static void nbif_v6_3_1_remap_hdp_registers(struct amdgpu_device *adev) static u32 nbif_v6_3_1_get_rev_id(struct amdgpu_device *adev) { - u32 tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0); + u32 tmp; + + if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4)) + tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10); + else + tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0); tmp &= RCC_STRAP0_RCC_DEV0_EPF0_STRAP0__STRAP_ATI_REV_ID_DEV0_F0_MASK; tmp >>= RCC_STRAP0_RCC_DEV0_EPF0_STRAP0__STRAP_ATI_REV_ID_DEV0_F0__SHIFT; -- cgit v1.2.3 From ad52d61d82181dbdb7f05826de38352d5e550cc2 Mon Sep 17 00:00:00 2001 From: Amir Shetaia Date: Fri, 10 Apr 2026 10:38:13 -0400 Subject: drm/amdkfd: Clear VRAM on allocation to prevent stale data exposure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KFD VRAM allocations set AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE but not AMDGPU_GEM_CREATE_VRAM_CLEARED, leaving freshly allocated VRAM with stale data from prior use observable by compute kernels. The GEM ioctl path already sets VRAM_CLEARED for all userspace allocations via amdgpu_gem_create_ioctl() and amdgpu_mode_dumb_create(). The KFD path was missing this flag, allowing stale page table remnants to leak into user buffers. This causes crashes in RCCL P2P transport where non-zero data in ptrExchange/head/tail fields corrupts the protocol handshake. Signed-off-by: Amir Shetaia Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 29b400cdd6d5..72a5a29e63f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1735,7 +1735,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( alloc_domain = AMDGPU_GEM_DOMAIN_GTT; alloc_flags = 0; } else { - alloc_flags = AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE; + alloc_flags = AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE | + AMDGPU_GEM_CREATE_VRAM_CLEARED; alloc_flags |= (flags & KFD_IOC_ALLOC_MEM_FLAGS_PUBLIC) ? AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED : 0; -- cgit v1.2.3 From 97284621c5bf513fa013f9a1c67b42f267732ce4 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Fri, 10 Apr 2026 16:26:00 +0530 Subject: drm/amdgpu: add job->pasid in check as amdgpu_job could be NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In below stack job->pasid is accessed while job is NULL. Access it within the check when job is non NULL. Failure call stack. [ 222.653622] BUG: kernel NULL pointer dereference, address: 000000000000014c [ 222.653625] #PF: supervisor read access in kernel mode [ 222.653628] #PF: error_code(0x0000) - not-present page [ 222.653630] PGD 0 P4D 0 [ 222.653635] Oops: Oops: 0000 [#1] SMP NOPTI [ 222.653639] CPU: 1 UID: 0 PID: 12 Comm: kworker/u96:0 Not tainted 6.19.0-amd-staging-drm-next #271 PREEMPT(voluntary) [ 222.653644] Hardware name: Gigabyte Technology Co., Ltd. X570 AORUS ELITE/X570 AORUS ELITE, BIOS F37c 05/12/2022 [ 222.653646] Workqueue: amdgpu-reset-dev amdgpu_userq_reset_work [amdgpu] [ 222.653961] RIP: 0010:amdgpu_coredump+0x8b/0x470 [amdgpu] [ 222.654158] Code: 48 83 c4 20 5b 41 5c 41 5d 41 5e 41 5f 5d 31 c0 31 c9 31 ff 31 d2 31 f6 45 31 c0 45 31 db e9 8c a9 1a e2 88 58 48 44 88 68 49 <41> 8b b7 4c 01 00 00 89 b0 80 00 00 00 4d 85 ff 48 89 45 d0 0f 84 [ 222.654161] RSP: 0018:ffffce68c0147c00 EFLAGS: 00010282 [ 222.654165] RAX: ffff8bc337407740 RBX: 0000000000000000 RCX: 0000000000000000 [ 222.654167] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 222.654170] RBP: ffffce68c0147c48 R08: 0000000000000000 R09: 0000000000000000 [ 222.654172] R10: ffff8bc337407740 R11: ffffffffc10dda10 R12: ffff8bc2d2e00000 [ 222.654174] R13: 0000000000000001 R14: ffff8bc2d2e5b368 R15: 0000000000000000 [ 222.654176] FS: 0000000000000000(0000) GS:ffff8bc64a5fe000(0000) knlGS:0000000000000000 [ 222.654179] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 222.654182] CR2: 000000000000014c CR3: 0000000135eca000 CR4: 0000000000350ef0 [ 222.654184] Call Trace: [ 222.654187] [ 222.654190] ? amdgpu_ip_block_resume+0x28/0x70 [amdgpu] [ 222.654376] ? srso_return_thunk+0x5/0x5f [ 222.654382] amdgpu_device_reinit_after_reset+0x184/0x320 [amdgpu] [ 222.654552] amdgpu_do_asic_reset+0x129/0x160 [amdgpu] [ 222.654720] amdgpu_device_asic_reset+0x92/0x710 [amdgpu] [ 222.654890] amdgpu_device_gpu_recover+0x2ae/0x3d0 [amdgpu] [ 222.655060] amdgpu_userq_reset_work+0x76/0xa0 [amdgpu] [ 222.655229] process_scheduled_works+0x1f0/0x450 [ 222.655235] worker_thread+0x27f/0x370 Fixes: 32ab301b89b3 ("drm/amdgpu: store ib info for devcoredump") Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index 3f1cc2265645..3d7aa6b09815 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -511,7 +511,6 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, coredump->skip_vram_check = skip_vram_check; coredump->reset_vram_lost = vram_lost; - coredump->pasid = job->pasid; if (job && job->pasid) { struct amdgpu_task_info *ti; @@ -521,6 +520,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, coredump->reset_task_info = *ti; amdgpu_vm_put_task_info(ti); } + coredump->pasid = job->pasid; coredump->num_ibs = job->num_ibs; for (i = 0; i < job->num_ibs; ++i) { coredump->ibs[i].gpu_addr = job->ibs[i].gpu_addr; -- cgit v1.2.3 From d91db49e97382efe38b51f5943c1a7073c0f06cd Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Mon, 13 Apr 2026 23:07:55 -0400 Subject: drm/amdgpu: fix NULL pointer dereference in amdgpu_devcoredump_format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A race condition in the devcoredump code causes a NULL pointer dereference in amdgpu_devcoredump_format() when multiple GPU resets occur in quick succession. The sequence of events: 1. First reset calls amdgpu_coredump(), creates coredump1, sets adev->coredump = coredump1, and queues the deferred work. 2. The deferred work begins executing (work_pending() returns false since the work is now running, not just queued). 3. A second reset calls amdgpu_coredump(). work_pending() returns false because the work is running, so amdgpu_coredump() proceeds: creates coredump2, overwrites adev->coredump = coredump2, and re-queues the deferred work with queue_work(). 4. The first deferred work finishes and unconditionally sets adev->coredump = NULL, destroying the reference to coredump2. 5. The re-queued deferred work starts and reads adev->coredump = NULL. It then passes this NULL into amdgpu_devcoredump_format() which dereferences coredump->adev (offset 0 in the struct), triggering: KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:amdgpu_devcoredump_format+0xa6/0x36b0 [amdgpu] This was observed during the amd_deadlock IGT test where multiple subtests trigger rapid ring resets. The dmesg log shows four coredumps created within 120ms (at 102.377s, 104.424s, 104.492s, and 104.497s), with the crash occurring 13ms after the last one. Fix this with two changes: - Replace work_pending() with work_busy() in amdgpu_coredump() to also reject new coredumps while the deferred work is executing, not just when it is queued. This closes the main race window. - Add a defensive NULL check for adev->coredump at the start of amdgpu_devcoredump_deferred_work() to prevent the crash if the race still occurs (work_busy() is advisory, not a full barrier). v2: Drop the job->pasid NULL guard -- that fix was independently submitted and merged as commit 4c1f0a162da5 ("drm/amdgpu: add job->pasid in check as amdgpu_job could be NULL") by Sunil Khatri, reviewed by Christian König. Integrate with that patch as suggested by Christian. Fixes: 4bbba79a7f1d ("drm/amdgpu: move devcoredump generation to a worker") Cc: Pierre-Eric Pelloux-Prayer Cc: Christian König Cc: Alex Deucher Signed-off-by: Vitaly Prosyak Reviewed-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index 3d7aa6b09815..5e353a83ec0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -464,6 +464,9 @@ static void amdgpu_devcoredump_deferred_work(struct work_struct *work) struct amdgpu_device *adev = container_of(work, typeof(*adev), coredump_work); struct amdgpu_coredump_info *coredump = adev->coredump; + if (!coredump) + goto end; + /* Do a one-time preparation of the coredump output because * repeatingly calling drm_coredump_printer is very slow. */ @@ -499,7 +502,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, int i, off, idx; /* No need to generate a new coredump if there's one in progress already. */ - if (work_pending(&adev->coredump_work)) + if (work_busy(&adev->coredump_work)) return; if (job && job->pasid) -- cgit v1.2.3 From 169a0556d9317e23dc393f085466b9c4a51bf729 Mon Sep 17 00:00:00 2001 From: Ce Sun Date: Fri, 10 Apr 2026 15:26:59 +0800 Subject: drm/amdgpu: correct single device PCIe reset flow for DPC For triggering the dpc event with a single device, we still need to set the in_link_reset flag and the dpc status. Signed-off-by: Ce Sun Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 11 +++++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 584c9ec28bf1..413145a958fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5518,8 +5518,6 @@ static void amdgpu_device_recovery_prepare(struct amdgpu_device *adev, list_add_tail(&tmp_adev->reset_list, device_list); if (adev->shutdown) tmp_adev->shutdown = true; - if (amdgpu_reset_in_dpc(adev)) - tmp_adev->pcie_reset_ctx.in_link_reset = true; } if (!list_is_first(&adev->reset_list, device_list)) list_rotate_to_front(&adev->reset_list, device_list); @@ -6291,6 +6289,9 @@ pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_sta amdgpu_reset_set_dpc_status(adev, true); mutex_lock(&hive->hive_lock); + } else { + if (amdgpu_device_bus_status_check(adev)) + amdgpu_reset_set_dpc_status(adev, true); } memset(&reset_context, 0, sizeof(reset_context)); INIT_LIST_HEAD(&device_list); @@ -6411,6 +6412,7 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev) list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) tmp_adev->pcie_reset_ctx.in_link_reset = true; } else { + adev->pcie_reset_ctx.in_link_reset = true; set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags); } @@ -6467,9 +6469,10 @@ void amdgpu_pci_resume(struct pci_dev *pdev) tmp_adev->pcie_reset_ctx.in_link_reset = false; list_add_tail(&tmp_adev->reset_list, &device_list); } - } else + } else { + adev->pcie_reset_ctx.in_link_reset = false; list_add_tail(&adev->reset_list, &device_list); - + } amdgpu_device_sched_resume(&device_list, NULL, NULL); amdgpu_device_gpu_resume(adev, &device_list, false); amdgpu_device_recovery_put_reset_lock(adev, &device_list); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 03d95dca93d7..debb82a2e031 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -34,6 +34,7 @@ #include "amdgpu.h" #include "amdgpu_pm.h" #include "amdgpu_vcn.h" +#include "amdgpu_reset.h" #include "soc15d.h" /* Firmware Names */ @@ -361,7 +362,7 @@ int amdgpu_vcn_suspend(struct amdgpu_device *adev, int i) /* err_event_athub and dpc recovery will corrupt VCPU buffer, so we need to * restore fw data and clear buffer in amdgpu_vcn_resume() */ - if (in_ras_intr || adev->pcie_reset_ctx.in_link_reset) + if (in_ras_intr || amdgpu_reset_in_dpc(adev)) return 0; return amdgpu_vcn_save_vcpu_bo_inst(adev, i); -- cgit v1.2.3 From d42d3012b278151b65bb8e328bbc6fdc678822a4 Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Thu, 9 Apr 2026 20:05:50 -0400 Subject: drm/amdgpu: fix heap buffer overflow in amdgpu_coredump ring dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The off variable in the ring content dump loop tracks a byte offset accumulated from ring->ring_size (which is in bytes), but it is used as an index into u32 *rings_dw. C pointer arithmetic on a u32 pointer automatically multiplies the index by sizeof(u32) = 4, so the actual byte address accessed is: &rings_dw[off] == (char *)rings_dw + off * 4 This means off is effectively quadrupled, causing a 4x overshoot. Concrete example -- two rings, each ring_size = 8 192 bytes (8 KB): total_ring_size = 16 384 bytes rings_dw = kzalloc(16 384) /* 16 KB buffer */ Ring 0: off = 0 memcpy(&rings_dw[0], ring0->ring, 8192) -> writes bytes 0 .. 8 191 OK off += ring->ring_size -> off = 8 192 (BUG) Ring 1: off = 8 192 memcpy(&rings_dw[8192], ring1->ring, 8192) -> actual byte offset = 8 192 * 4 = 32 768 -> writes bytes 32 768 .. 40 959 -> but buffer is only 16 384 bytes! OVERFLOW With the fix (off += ring->ring_size / 4): Ring 0: off = 0 memcpy(&rings_dw[0], ring0->ring, 8192) OK off += 8 192 / 4 -> off = 2 048 Ring 1: off = 2 048 memcpy(&rings_dw[2048], ring1->ring, 8192) -> byte offset = 2 048 * 4 = 8 192 -> writes bytes 8 192 .. 16 383 OK KASAN catches the overflow as a slab-use-after-free when the write lands on a quarantined slab object: BUG: KASAN: slab-use-after-free in amdgpu_coredump+0x775/0x13c0 [amdgpu] Write of size 8192 at addr ffff8890b2400000 by task kworker/u128:1/329 Workqueue: amdgpu-reset-dev drm_sched_job_timedout [gpu_sched] Call Trace: __asan_memcpy+0x3c/0x60 amdgpu_coredump+0x775/0x13c0 [amdgpu] amdgpu_job_timedout+0xdb5/0x1420 [amdgpu] The corrupted object was a 4 KB drm_exec buffer from a completed amdgpu_cs_ioctl -- the ring dump memcpy overshot into this freed slab region. Fix by accumulating off in dword units (ring->ring_size / 4) so the u32* indexing produces the correct byte address. The reader in amdgpu_devcoredump_format() already consumes the stored offset as a dword index (rings_dw[off + j / 4]), so no change is needed there. Fixes: eea85914d15b ("drm/amdgpu: save ring content before resetting the device") Cc: Pierre-Eric Pelloux-Prayer Cc: Christian König Cc: Alex Deucher Cc: Jesse Zhang Signed-off-by: Vitaly Prosyak Acked-by: Christian König Reviewed-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index 5e353a83ec0d..d386bc775d03 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -566,7 +566,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, coredump->rings[idx].offset = off; memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size); - off += ring->ring_size; + off += ring->ring_size / 4; idx++; } coredump->num_rings = idx; -- cgit v1.2.3 From b8939bd764c9c8bf6488dc0d71d9c718c25d8cfc Mon Sep 17 00:00:00 2001 From: Xiang Liu Date: Thu, 9 Apr 2026 17:10:21 +0800 Subject: drm/amdgpu: fix CPER ring header parsing amdgpu_cper_ring_get_ent_sz() parses CPER headers directly from the circular ring buffer to determine the current entry size. When the ring is full and the write pointer lands near the end of the buffer, the header can wrap across the ring boundary. The existing code treats the 4-byte CPER signature as a C string and uses strcmp() on in-ring binary data, then reads record_length through a direct struct pointer cast. Both assumptions are unsafe for wrapped entries and can read past the end of the ring mapping. Fix the parser by comparing the signature as raw bytes and by copying the header into a local buffer before reading record_length, handling wraparound explicitly in both cases. This avoids out-of-bounds reads in amdgpu_cper_ring_get_ent_sz() when the CPER ring is full or the current entry starts at the tail of the ring. Signed-off-by: Xiang Liu Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c | 36 ++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c index c72c345334d0..4e6e390854e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c @@ -32,6 +32,8 @@ static const guid_t BOOT = BOOT_TYPE; static const guid_t CRASHDUMP = AMD_CRASHDUMP; static const guid_t RUNTIME = AMD_GPU_NONSTANDARD_ERROR; +#define CPER_SIGNATURE_SZ (sizeof(((struct cper_hdr *)0)->signature)) + static void __inc_entry_length(struct cper_hdr *hdr, uint32_t size) { hdr->record_length += size; @@ -425,23 +427,40 @@ int amdgpu_cper_generate_ce_records(struct amdgpu_device *adev, static bool amdgpu_cper_is_hdr(struct amdgpu_ring *ring, u64 pos) { - struct cper_hdr *chdr; + char signature[CPER_SIGNATURE_SZ]; + + if ((pos << 2) >= ring->ring_size) + return false; - chdr = (struct cper_hdr *)&(ring->ring[pos]); - return strcmp(chdr->signature, "CPER") ? false : true; + if ((pos << 2) + CPER_SIGNATURE_SZ <= ring->ring_size) { + memcpy(signature, &ring->ring[pos], CPER_SIGNATURE_SZ); + } else { + u32 chunk = ring->ring_size - (pos << 2); + + memcpy(signature, &ring->ring[pos], chunk); + memcpy(signature + chunk, ring->ring, CPER_SIGNATURE_SZ - chunk); + } + + return !memcmp(signature, "CPER", CPER_SIGNATURE_SZ); } static u32 amdgpu_cper_ring_get_ent_sz(struct amdgpu_ring *ring, u64 pos) { - struct cper_hdr *chdr; + struct cper_hdr chdr; u64 p; u32 chunk, rec_len = 0; - chdr = (struct cper_hdr *)&(ring->ring[pos]); chunk = ring->ring_size - (pos << 2); - if (!strcmp(chdr->signature, "CPER")) { - rec_len = chdr->record_length; + if (amdgpu_cper_is_hdr(ring, pos)) { + if (chunk >= sizeof(chdr)) { + memcpy(&chdr, &ring->ring[pos], sizeof(chdr)); + } else { + memcpy(&chdr, &ring->ring[pos], chunk); + memcpy((u8 *)&chdr + chunk, ring->ring, sizeof(chdr) - chunk); + } + + rec_len = chdr.record_length; goto calc; } @@ -450,8 +469,7 @@ static u32 amdgpu_cper_ring_get_ent_sz(struct amdgpu_ring *ring, u64 pos) goto calc; for (p = pos + 1; p <= ring->buf_mask; p++) { - chdr = (struct cper_hdr *)&(ring->ring[p]); - if (!strcmp(chdr->signature, "CPER")) { + if (amdgpu_cper_is_hdr(ring, p)) { rec_len = (p - pos) << 2; goto calc; } -- cgit v1.2.3 From 505dcb8eeaf2196853c30136b0cbea24af0f7aaa Mon Sep 17 00:00:00 2001 From: Ce Sun Date: Mon, 13 Apr 2026 19:49:24 +0800 Subject: drm/amd/ras: Avoid ECC status update in hw_fini for VF unload VF sends IDH_REQ_GPU_FINI_ACCESS before hw_fini during unload. PF no longer accepts requests, so skip ECC status update to prevent mailbox timeout. Signed-off-by: Ce Sun Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c index eb552d0cce4a..fb4d375e87b2 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c @@ -517,14 +517,9 @@ int amdgpu_virt_ras_hw_fini(struct amdgpu_device *adev) (struct amdgpu_virt_ras_cmd *)ras_mgr->virt_ras_cmd; struct vram_blocks_ecc *blks_ecc = &virt_ras->blocks_ecc; - if (blks_ecc->shared_mem.cpu_addr) { - __set_cmd_auto_update(adev, - RAS_CMD__GET_ALL_BLOCK_ECC_STATUS, - blks_ecc->shared_mem.gpa, - blks_ecc->shared_mem.size, false); - + if (blks_ecc->shared_mem.cpu_addr) memset(blks_ecc->shared_mem.cpu_addr, 0, blks_ecc->shared_mem.size); - } + memset(blks_ecc, 0, sizeof(*blks_ecc)); return 0; -- cgit v1.2.3 From e81a492d1259827f78a06c483a64ea07c81378fe Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Fri, 10 Apr 2026 18:08:56 +0530 Subject: drm/amd/pm: smu7: Remove stale error check in smu7_hwmgr_backend_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit smu7_hwmgr_backend_init() is responsible for initializing the SMU7 power management backend. It allocates and sets up the backend structure, initializes voltage tables, configures dependency tables, and prepares platform-specific power and clock parameters. The function follows a typical pattern where each initialization step returns a status in "result", and failures are handled via a common "goto fail" path that performs cleanup. Commit 2c21648bb814 ("drm/amd/pm/smu7: Remove non-functional SMU7 voltage dependency on DAL") removed a function call in this initialization sequence, but left behind the corresponding error check. As a result, "result" is checked twice without being updated in between: result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); if (result) goto fail; ... if (result) goto fail; The second check is redundant and unreachable for any new failure, since no operation modifies "result" between the two checks. This triggers a Smatch warning about a duplicate zero check and reduces code clarity. Remove the stale error check to keep the control flow correct and readable. Fixes: 9f49e3d4cb86 ("drm/amd/pm/smu7: Remove non-functional SMU7 voltage dependency on DAL") Reported-by: Dan Carpenter Cc: Timur Kristóf Cc: Christian König Cc: Alex Deucher Signed-off-by: Srinivasan Shanmugam Reviewed-by: Timur Kristóf Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index 8c37aa452569..55e2375e1dad 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -3062,9 +3062,6 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) smu7_set_private_data_based_on_pptable_v0(hwmgr); } - if (result) - goto fail; - data->is_tlu_enabled = false; hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = -- cgit v1.2.3 From a6d561a88c72e1dbd34816dee46d8d7d77fffdc4 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Tue, 14 Apr 2026 14:10:21 +0530 Subject: drm/amd/pm: Fix mode2 reset ACK handling on aldebaran v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aldebaran_mode2_reset() sends a mode2 reset message and waits for an acknowledgment from the SMU. The current ACK handling is incorrect. The wait loop runs only when ret is -ETIME. But after a successful async send, ret is 0. Because of this, the loop is skipped and the code does not wait for the reset acknowledgment. Also, the code checks for ret != 1 after calling smu_msg_wait_response(). However, smu_msg_wait_response() returns 0 on success and negative error codes on failure. So checking against 1 is wrong. Return -EOPNOTSUPP when the firmware does not support this reset message. Fix this by setting ret to -ETIME before entering the wait loop, checking for ret != 0 after getting the SMU response, and returning -EOPNOTSUPP when the firmware does not support the message. v2: - Update ACK check to use ret != 0 instead of ret != 1, since smu_msg_wait_response() returns 0 on success (Feifei) - Remove unnecessary handling for ret == 0 Fixes: e42569d02acb ("drm/amd/pm: Modify mode2 msg sequence on aldebaran") Reported-by: Dan Carpenter Cc: Feifei Xu Cc: Lijo Lazar Cc: Hawking Zhang Cc: Alex Deucher Cc: Christian König Signed-off-by: Srinivasan Shanmugam Reviewed-by: Feifei Xu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index dc056f1e4b64..7f386ff0c872 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1846,6 +1846,7 @@ static int aldebaran_mode2_reset(struct smu_context *smu) amdgpu_device_load_pci_state(adev->pdev); dev_dbg(adev->dev, "wait for reset ack\n"); + ret = -ETIME; while (ret == -ETIME && timeout) { ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ @@ -1855,7 +1856,7 @@ static int aldebaran_mode2_reset(struct smu_context *smu) continue; } - if (ret != 1) { + if (ret != 0) { dev_err(adev->dev, "failed to send mode2 message \tparam: 0x%08x response %#x\n", SMU_RESET_MODE_2, ret); goto out; @@ -1865,10 +1866,9 @@ static int aldebaran_mode2_reset(struct smu_context *smu) } else { dev_err(adev->dev, "smu fw 0x%x does not support MSG_GfxDeviceDriverReset MSG\n", smu->smc_fw_version); + ret = -EOPNOTSUPP; } - if (ret == 1) - ret = 0; out: mutex_unlock(&ctl->lock); -- cgit v1.2.3 From 831cb9ba54d2da3eb416845042add6882c0a8527 Mon Sep 17 00:00:00 2001 From: filippor Date: Thu, 16 Apr 2026 16:34:57 +0200 Subject: drm/amdgpu: fix IP discovery v0 handling Cyan skillfish uses IP discovery v0. This was broken when the IP discovery was refactored for newer versions. Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5189 Fixes: d0c647a6aae2 ("drm/amdgpu/discovery: support new discovery binary header") Signed-off-by: filippor Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 8ec5465c3349..fcad7daaa41b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -535,10 +535,11 @@ static int amdgpu_discovery_get_table_info(struct amdgpu_device *adev, *info = &bhdrv2->table_list[table_id]; break; case 1: + case 0: *info = &bhdr->table_list[table_id]; break; default: - dev_err(adev->dev, "Invalid ip discovery table version\n"); + dev_err(adev->dev, "Invalid ip discovery table version %d\n",bhdr->version_major); return -EINVAL; } -- cgit v1.2.3 From 80d4d3a45b86816e9a99de4e3d6640ff82707dac Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 26 Mar 2026 13:50:03 -0400 Subject: drm/amdgpu/sdma7.1: add support for disable_kq Plumb in support for disabling kernel queues and make it the default. For testing, kernel queues can be re-enabled by setting amdgpu.user_queue=0. Kernel queues are still created for use by the kernel driver for memory management, etc., just not user submissions. Reviewed-by: Prike Liang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c index f20e0fc3fc74..061934a2e93a 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c @@ -1268,6 +1268,18 @@ static int sdma_v7_1_early_init(struct amdgpu_ip_block *ip_block) struct amdgpu_device *adev = ip_block->adev; int r; + switch (amdgpu_user_queue) { + case -1: + default: + adev->sdma.no_user_submission = true; + adev->sdma.disable_uq = true; + break; + case 0: + adev->sdma.no_user_submission = false; + adev->sdma.disable_uq = true; + break; + } + r = amdgpu_sdma_init_microcode(adev, 0, true); if (r) { DRM_ERROR("Failed to init sdma firmware!\n"); -- cgit v1.2.3 From 25fd8095a868cfbeb9ef3118131d2ba1f7057846 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 16 Apr 2026 18:17:30 +0800 Subject: drm/amd/pm: fix runtime PM imbalance issue in amdgpu_pm.c Fix runtime PM counter imbalance to prevent device from failing to enter low power state Fixes: a50d32c41fb2 ("drm/amd/pm: Deprecate print_clock_levels interface") Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 62b0b1ef0d10..736304e73ca4 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -995,12 +995,15 @@ static ssize_t amdgpu_get_pp_dpm_clock(struct device *dev, return ret; ret = amdgpu_dpm_emit_clock_levels(adev, type, buf, &size); - if (ret) - return ret; + if (ret) { + size = ret; + goto out_pm_put; + } if (size == 0) size = sysfs_emit(buf, "\n"); +out_pm_put: amdgpu_pm_put_access(adev); return size; @@ -3902,11 +3905,14 @@ static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev, return ret; ret = amdgpu_dpm_emit_clock_levels(adev, od_type, buf, &size); - if (ret) - return ret; + if (ret) { + size = ret; + goto out_pm_put; + } if (size == 0) size = sysfs_emit(buf, "\n"); +out_pm_put: amdgpu_pm_put_access(adev); return size; -- cgit v1.2.3 From 79d47bc4c73080aeac971bfc0e687b0cdefbabde Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 2 Apr 2026 23:30:22 -0400 Subject: drm/amd/pm: add read arg support to smu_cmn_update_table Extend the smu_cmn_update_table function to support reading a 32-bit return argument from the SMU firmware during table transfer operations. - Rename the original function to smu_cmn_update_table_read_arg - Add a uint32_t *read_arg output parameter to capture firmware response - Pass the read_arg pointer to the SMU message command - Keep full backward compatibility using a macro wrapper for the old API This allows the driver to retrieve status codes, results, or configuration feedback from the SMU firmware after table data transfer. No functional changes for existing users of the original smu_cmn_update_table() API. Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 1 + drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 37 ++++++++++++++++++--------- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 14 ++++++---- 3 files changed, 35 insertions(+), 17 deletions(-) (limited to 'drivers/gpu') 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 126fc54cb511..d76e0b005308 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -584,6 +584,7 @@ struct cmn2asic_mapping { /* Message flags for smu_msg_args */ #define SMU_MSG_FLAG_ASYNC BIT(0) /* Async send - skip post-poll */ #define SMU_MSG_FLAG_LOCK_HELD BIT(1) /* Caller holds ctl->lock */ +#define SMU_MSG_FLAG_FORCE_READ_ARG BIT(2) /* force read smu arg from pmfw */ /* smu_msg_ctl flags */ #define SMU_MSG_CTL_DEBUG_MAILBOX BIT(0) /* Debug mailbox supported */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 006ef585a377..3d49e58794d2 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -496,7 +496,8 @@ static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, } /* Read output args */ - if (ret == 0 && args->num_out_args > 0) { + if ((ret == 0 || (args->flags & SMU_MSG_FLAG_FORCE_READ_ARG)) && + args->num_out_args > 0) { __smu_msg_v1_read_out_args(ctl, args); dev_dbg(adev->dev, "smu send message: %s(%d) resp : 0x%08x", smu_get_message_name(smu, args->msg), index, reg); @@ -1060,20 +1061,24 @@ int smu_cmn_check_fw_version(struct smu_context *smu) return 0; } -int smu_cmn_update_table(struct smu_context *smu, - enum smu_table_id table_index, - int argument, - void *table_data, - bool drv2smu) +int smu_cmn_update_table_read_arg(struct smu_context *smu, + enum smu_table_id table_index, + int argument, + void *table_data, + uint32_t *read_arg, + bool drv2smu) { - struct smu_table_context *smu_table = &smu->smu_table; struct amdgpu_device *adev = smu->adev; + struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *table = &smu_table->driver_table; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct smu_msg_args args; int table_id = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_TABLE, table_index); uint32_t table_size; int ret = 0; + if (!table_data || table_index >= SMU_TABLE_COUNT || table_id < 0) return -EINVAL; @@ -1088,11 +1093,19 @@ int smu_cmn_update_table(struct smu_context *smu, amdgpu_hdp_flush(adev, NULL); } - ret = smu_cmn_send_smc_msg_with_param(smu, drv2smu ? - SMU_MSG_TransferTableDram2Smu : - SMU_MSG_TransferTableSmu2Dram, - table_id | ((argument & 0xFFFF) << 16), - NULL); + args.msg = drv2smu ? SMU_MSG_TransferTableDram2Smu : SMU_MSG_TransferTableSmu2Dram; + args.args[0] = ((argument & 0xFFFF) << 16) | (table_id & 0xffff); + args.num_args = 1; + args.out_args[0] = 0; + args.num_out_args = read_arg ? 1 : 0; + args.flags = read_arg ? SMU_MSG_FLAG_FORCE_READ_ARG : 0; + args.timeout = 0; + + ret = ctl->ops->send_msg(ctl, &args); + + if (read_arg) + *read_arg = args.out_args[0]; + if (ret) return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index d129907535bd..c6ac0e876aea 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -102,6 +102,9 @@ int smu_msg_send_async_locked(struct smu_msg_ctl *ctl, #define SMU_DPM_PCIE_GEN_IDX(gen) smu_cmn_dpm_pcie_gen_idx((gen)) #define SMU_DPM_PCIE_WIDTH_IDX(width) smu_cmn_dpm_pcie_width_idx((width)) +#define smu_cmn_update_table(smu, table_index, argument, table_data, drv2smu) \ + smu_cmn_update_table_read_arg((smu), (table_index), (argument), (table_data), NULL, (drv2smu)) + extern const int link_speed[]; /* Helper to Convert from PCIE Gen 1/2/3/4/5/6 to 0.1 GT/s speed units */ @@ -168,11 +171,12 @@ int smu_cmn_get_smc_version(struct smu_context *smu, uint32_t *if_version, uint32_t *smu_version); -int smu_cmn_update_table(struct smu_context *smu, - enum smu_table_id table_index, - int argument, - void *table_data, - bool drv2smu); +int smu_cmn_update_table_read_arg(struct smu_context *smu, + enum smu_table_id table_index, + int argument, + void *table_data, + uint32_t *read_arg, + bool drv2smu); int smu_cmn_vram_cpy(struct smu_context *smu, void *dst, const void *src, size_t len); -- cgit v1.2.3 From 4f2c86c62a0043be59447c1507c81ecdac7bfa55 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 2 Apr 2026 23:52:46 -0400 Subject: drm/amd/pm: add od table upload error message parsing for smu v14.0.x parse and print detailed reasons for od table upload failures to help users understand error causes. example: $ echo "0 30 40" | sudo tee fan_curve $ echo "1 40 30" | sudo tee fan_curve $ echo "c" | sudo tee fan_curve kernel log: [ 75.040174] amdgpu 0000:0a:00.0: Failed to upload overdrive table, ret:-5 [ 75.040178] amdgpu 0000:0a:00.0: Invalid overdrive table content: OD_FAN_CURVE_PWM_ERROR (13) [ 75.040181] amdgpu 0000:0a:00.0: Failed to upload overdrive table! Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 60 +++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 983bb31bb53e..5ce4e982ca33 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -2214,17 +2214,61 @@ static void smu_v14_0_2_dump_od_table(struct smu_context *smu, od_table->OverDriveTable.UclkFmax); } +#define OD_ERROR_MSG_MAP(msg) \ + [msg] = #msg + +static const char *od_error_message[] = { + OD_ERROR_MSG_MAP(OD_REQUEST_ADVANCED_NOT_SUPPORTED), + OD_ERROR_MSG_MAP(OD_UNSUPPORTED_FEATURE), + OD_ERROR_MSG_MAP(OD_INVALID_FEATURE_COMBO_ERROR), + OD_ERROR_MSG_MAP(OD_GFXCLK_VF_CURVE_OFFSET_ERROR), + OD_ERROR_MSG_MAP(OD_VDD_GFX_VMAX_ERROR), + OD_ERROR_MSG_MAP(OD_VDD_SOC_VMAX_ERROR), + OD_ERROR_MSG_MAP(OD_PPT_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_MIN_PWM_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_ACOUSTIC_TARGET_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_ACOUSTIC_LIMIT_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_TARGET_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_ZERO_RPM_STOP_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_CURVE_PWM_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_CURVE_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_GFXCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_UCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_FCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_VDD_GFX_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_VDD_SOC_ERROR), + OD_ERROR_MSG_MAP(OD_TDC_ERROR), + OD_ERROR_MSG_MAP(OD_GFXCLK_ERROR), + OD_ERROR_MSG_MAP(OD_UCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FCLK_ERROR), + OD_ERROR_MSG_MAP(OD_OP_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_OP_GFX_EDC_ERROR), + OD_ERROR_MSG_MAP(OD_OP_GFX_PCC_ERROR), + OD_ERROR_MSG_MAP(OD_POWER_FEATURE_CTRL_ERROR), +}; + static int smu_v14_0_2_upload_overdrive_table(struct smu_context *smu, OverDriveTableExternal_t *od_table) { - int ret; - ret = smu_cmn_update_table(smu, - SMU_TABLE_OVERDRIVE, - 0, - (void *)od_table, - true); - if (ret) - dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + uint32_t read_arg = 0; + int ret, od_error_type; + + ret = smu_cmn_update_table_read_arg(smu, + SMU_TABLE_OVERDRIVE, + 0, + (void *)od_table, + &read_arg, + true); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table, ret:%d\n", ret); + if ((read_arg & 0xff) == TABLE_TRANSFER_FAILED) { + od_error_type = read_arg >> 16; + dev_err(smu->adev->dev, "Invalid overdrive table content: %s (%d)\n", + od_error_type < ARRAY_SIZE(od_error_message) ? + od_error_message[od_error_type] : "unknown", + od_error_type); + } + } return ret; } -- cgit v1.2.3 From e1fb16cef03ec1c12301ae1b26b77118851a14d7 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Fri, 10 Apr 2026 17:57:56 +0530 Subject: drm/amdgpu/mes_v12_1: Fix iterator reuse in mes_v12_1_test_ring() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code waits for the MES self-test to complete by repeatedly checking a register or memory value until it becomes valid or a timeout occurs. The fix ensures the timeout counter works correctly by not reusing the same variable inside another loop. mes_v12_1_test_ring() uses 'i' as the outer timeout loop counter, but reuses the same variable for the inner XCC scan in cooperative mode. This makes the timeout counter ambiguous and can lead to incorrect timeout handling. It also triggers a Smatch warning about reusing the outer loop iterator. Fix this by introducing a separate iterator for the inner XCC loop so that 'i' continues to represent only the timeout wait duration. drivers/gpu/drm/amd/amdgpu/mes_v12_1.c:2080 mes_v12_1_test_ring() warn: reusing outside iterator: 'i' drivers/gpu/drm/amd/amdgpu/mes_v12_1.c 2069 atomic64_set((atomic64_t *)wptr_cpu_addr, wptr); 2070 WDOORBELL64(doorbell_idx, wptr); 2071 2072 for (i = 0; i < adev->usec_timeout; i++) { i is counting usec 2073 if (queue_type == AMDGPU_RING_TYPE_SDMA) { 2074 tmp = le32_to_cpu(*cpu_ptr); 2075 } else { 2076 if (!adev->mes.enable_coop_mode) { 2077 tmp = RREG32_SOC15(GC, GET_INST(GC, xcc_id), 2078 regSCRATCH_REG0); 2079 } else { --> 2080 for (i = 0; i < num_xcc; i++) { and then re-used to count something else Fixes: 44e5195fa3d4 ("drm/amdgpu/mes_v12_1: add mes self test") Reported-by: Dan Carpenter Cc: Jack Xiao Cc: Hawking Zhang Cc: Christian König Cc: Alex Deucher Signed-off-by: Srinivasan Shanmugam Reviewed-by: Jack Xiao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v12_1.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c index 0e9089544769..cec801278126 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c @@ -2028,7 +2028,7 @@ static int mes_v12_1_test_ring(struct amdgpu_device *adev, int xcc_id, int num_xcc = NUM_XCC(adev->gfx.xcc_mask); int sdma_ring_align = 0x10, compute_ring_align = 0x100; uint32_t tmp, xcc_offset; - int r = 0, i, wptr = 0; + int r = 0, i, j, wptr = 0; if (queue_type == AMDGPU_RING_TYPE_COMPUTE) { if (!adev->mes.enable_coop_mode) { @@ -2077,11 +2077,11 @@ static int mes_v12_1_test_ring(struct amdgpu_device *adev, int xcc_id, tmp = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regSCRATCH_REG0); } else { - for (i = 0; i < num_xcc; i++) { - if (xcc_id != adev->mes.master_xcc_ids[i]) + for (j = 0; j < num_xcc; j++) { + if (xcc_id != adev->mes.master_xcc_ids[j]) continue; - tmp = RREG32_SOC15(GC, GET_INST(GC, i), + tmp = RREG32_SOC15(GC, GET_INST(GC, j), regSCRATCH_REG0); if (tmp != 0xDEADBEEF) break; -- cgit v1.2.3 From b35601c5432a52c5a889a8bf505bbe2540e13254 Mon Sep 17 00:00:00 2001 From: Gaghik Khachatrian Date: Sat, 7 Mar 2026 15:10:13 -0500 Subject: drm/amd/display: Fix unused parameters warnings in dml2_0 [Why] Resolve warnings by marking unused parameters explicitly. [How] Keep parameter names in signatures and add a line with '(void)param;' inside the function body Preserved function signatures and avoids breaking code paths that may reference the parameter under conditional compilation. Reviewed-by: Dillon Varone Reviewed-by: Clayton King Signed-off-by: Gaghik Khachatrian Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml2_0/display_mode_core.c | 17 ++++++++++++++++ .../drm/amd/display/dc/dml2_0/display_mode_util.c | 14 +++++++++++++ .../dc/dml2_0/dml21/dml21_translation_helper.c | 3 +++ .../drm/amd/display/dc/dml2_0/dml21/dml21_utils.c | 2 ++ .../display/dc/dml2_0/dml21/dml21_wrapper_fpu.c | 2 ++ .../dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c | 1 + .../dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 23 ++++++++++++++++++++++ .../dml2_0/dml21/src/dml2_core/dml2_core_utils.c | 1 + .../dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c | 1 + .../dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.c | 2 ++ .../dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.c | 1 + .../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c | 5 +++++ .../dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c | 3 +++ .../dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c | 2 ++ .../amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c | 9 +++++++++ .../display/dc/dml2_0/dml2_translation_helper.c | 6 ++++++ drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c | 1 + .../display/dc/dml2_0/dml_display_rq_dlg_calc.c | 1 + 18 files changed, 94 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c index 8e8935995fca..698d62fb9cf7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c @@ -1812,6 +1812,8 @@ static dml_float_t CalculateWriteBackDISPCLK( dml_uint_t WritebackLineBufferSize, dml_float_t DISPCLKDPPCLKVCOSpeed) { + (void)WritebackPixelFormat; + (void)WritebackVRatio; dml_float_t DISPCLK_H, DISPCLK_V, DISPCLK_HB; DISPCLK_H = PixelClock * dml_ceil(WritebackHTaps / 8.0, 1) / WritebackHRatio; @@ -1830,6 +1832,8 @@ static dml_float_t CalculateWriteBackDelay( dml_uint_t WritebackSourceHeight, dml_uint_t HTotal) { + (void)WritebackPixelFormat; + (void)WritebackHRatio; dml_float_t CalculateWriteBackDelay; dml_float_t Line_length; dml_float_t Output_lines_last_notclamped; @@ -1977,6 +1981,7 @@ static void CalculateFlipSchedule( dml_float_t *final_flip_bw, dml_bool_t *ImmediateFlipSupportedForPipe) { + (void)HostVMMinPageSize; dml_float_t min_row_time = 0.0; dml_uint_t HostVMDynamicLevelsTrips = 0; dml_float_t TimeForFetchingMetaPTEImmediateFlip = 0; @@ -2118,6 +2123,11 @@ static void CalculateDCCConfiguration( dml_uint_t *IndependentBlockLuma, dml_uint_t *IndependentBlockChroma) { + (void)SurfaceWidthChroma; + (void)SurfaceHeightChroma; + (void)TilingFormat; + (void)BytePerPixelDETY; + (void)BytePerPixelDETC; dml_uint_t DETBufferSizeForDCC = nomDETInKByte * 1024; dml_uint_t yuv420; @@ -2489,6 +2499,7 @@ static dml_uint_t CalculateVMAndRowBytes( dml_uint_t *DPDE0BytesFrame, dml_uint_t *MetaPTEBytesFrame) { + (void)SourcePixelFormat; dml_uint_t MPDEBytesFrame; dml_uint_t DCCMetaSurfaceBytes; dml_uint_t ExtraDPDEBytesFrame; @@ -3662,6 +3673,8 @@ static void CalculateVMGroupAndRequestTimes( dml_float_t TimePerVMRequestVBlank[], dml_float_t TimePerVMRequestFlip[]) { + (void)dpte_row_width_luma_ub; + (void)dpte_row_width_chroma_ub; dml_uint_t num_group_per_lower_vm_stage; dml_uint_t num_req_per_lower_vm_stage; @@ -3762,6 +3775,7 @@ static void CalculateVMGroupAndRequestTimes( static void CalculateStutterEfficiency(struct display_mode_lib_scratch_st *scratch, struct CalculateStutterEfficiency_params_st *p) { + (void)scratch; dml_float_t DETBufferingTimeY = 0; dml_float_t SwathWidthYCriticalSurface = 0; dml_float_t SwathHeightYCriticalSurface = 0; @@ -4085,6 +4099,7 @@ static void CalculateStutterEfficiency(struct display_mode_lib_scratch_st *scrat static void CalculateSwathAndDETConfiguration(struct display_mode_lib_scratch_st *scratch, struct CalculateSwathAndDETConfiguration_params_st *p) { + (void)scratch; dml_uint_t MaximumSwathHeightY[__DML_NUM_PLANES__]; dml_uint_t MaximumSwathHeightC[__DML_NUM_PLANES__]; dml_uint_t RoundedUpMaxSwathSizeBytesY[__DML_NUM_PLANES__]; @@ -4331,6 +4346,7 @@ static void CalculateSwathWidth( dml_uint_t swath_width_luma_ub[], // per-pipe dml_uint_t swath_width_chroma_ub[]) // per-pipe { + (void)BytePerPixY; enum dml_odm_mode MainSurfaceODMMode; dml_uint_t surface_width_ub_l; dml_uint_t surface_height_ub_l; @@ -5029,6 +5045,7 @@ static void CalculateMaxDETAndMinCompressedBufferSize( dml_uint_t *nomDETInKByte, dml_uint_t *MinCompressedBufferSizeInKByte) { + (void)ROBBufferSizeInKByte; *MaxTotalDETInKByte = ConfigReturnBufferSizeInKByte - ConfigReturnBufferSegmentSizeInKByte; *nomDETInKByte = (dml_uint_t)(dml_floor((dml_float_t) *MaxTotalDETInKByte / (dml_float_t) MaxNumDPP, ConfigReturnBufferSegmentSizeInKByte)); *MinCompressedBufferSizeInKByte = ConfigReturnBufferSizeInKByte - *MaxTotalDETInKByte; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_util.c b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_util.c index 4022f91193ed..b2fada6c44c3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_util.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_util.c @@ -178,6 +178,7 @@ dml_float_t dml_log2(dml_float_t x) dml_float_t dml_round(dml_float_t val, dml_bool_t bankers_rounding) { + (void)bankers_rounding; // if (bankers_rounding) // return (dml_float_t) lrint(val); // else { @@ -217,6 +218,7 @@ dml_uint_t dml_round_to_multiple(dml_uint_t num, dml_uint_t multiple, dml_bool_t void dml_print_data_rq_regs_st(const dml_display_plane_rq_regs_st *rq_regs) { + (void)rq_regs; dml_print("DML: ===================================== \n"); dml_print("DML: DISPLAY_PLANE_RQ_REGS_ST\n"); dml_print("DML: chunk_size = 0x%x\n", rq_regs->chunk_size); @@ -248,6 +250,7 @@ void dml_print_rq_regs_st(const dml_display_rq_regs_st *rq_regs) void dml_print_dlg_regs_st(const dml_display_dlg_regs_st *dlg_regs) { + (void)dlg_regs; dml_print("DML: ===================================== \n"); dml_print("DML: DISPLAY_DLG_REGS_ST \n"); dml_print("DML: refcyc_h_blank_end = 0x%x\n", dlg_regs->refcyc_h_blank_end); @@ -299,6 +302,7 @@ void dml_print_dlg_regs_st(const dml_display_dlg_regs_st *dlg_regs) void dml_print_ttu_regs_st(const dml_display_ttu_regs_st *ttu_regs) { + (void)ttu_regs; dml_print("DML: ===================================== \n"); dml_print("DML: DISPLAY_TTU_REGS_ST \n"); dml_print("DML: qos_level_low_wm = 0x%x\n", ttu_regs->qos_level_low_wm); @@ -326,6 +330,7 @@ void dml_print_ttu_regs_st(const dml_display_ttu_regs_st *ttu_regs) void dml_print_dml_policy(const struct dml_mode_eval_policy_st *policy) { + (void)policy; dml_print("DML: ===================================== \n"); dml_print("DML: DML_MODE_EVAL_POLICY_ST\n"); dml_print("DML: Policy: UseUnboundedRequesting = 0x%x\n", policy->UseUnboundedRequesting); @@ -353,6 +358,8 @@ void dml_print_dml_policy(const struct dml_mode_eval_policy_st *policy) void dml_print_mode_support(struct display_mode_lib_st *mode_lib, dml_uint_t j) { + (void)j; + (void)mode_lib; dml_print("DML: MODE SUPPORT: ===============================================\n"); dml_print("DML: MODE SUPPORT: Voltage State %d\n", j); dml_print("DML: MODE SUPPORT: Mode Supported : %s\n", mode_lib->ms.support.ModeSupport[j] == true ? "Supported" : "NOT Supported"); @@ -526,6 +533,7 @@ void dml_print_dml_mode_support_info(const struct dml_mode_support_info_st *supp void dml_print_dml_display_cfg_timing(const struct dml_timing_cfg_st *timing, dml_uint_t num_plane) { + (void)timing; for (dml_uint_t i = 0; i < num_plane; i++) { dml_print("DML: timing_cfg: plane=%d, HTotal = %d\n", i, timing->HTotal[i]); dml_print("DML: timing_cfg: plane=%d, VTotal = %d\n", i, timing->VTotal[i]); @@ -542,6 +550,7 @@ void dml_print_dml_display_cfg_timing(const struct dml_timing_cfg_st *timing, dm void dml_print_dml_display_cfg_plane(const struct dml_plane_cfg_st *plane, dml_uint_t num_plane) { + (void)plane; dml_print("DML: plane_cfg: num_plane = %d\n", num_plane); dml_print("DML: plane_cfg: GPUVMEnable = %d\n", plane->GPUVMEnable); dml_print("DML: plane_cfg: HostVMEnable = %d\n", plane->HostVMEnable); @@ -590,6 +599,7 @@ void dml_print_dml_display_cfg_plane(const struct dml_plane_cfg_st *plane, dml_u void dml_print_dml_display_cfg_surface(const struct dml_surface_cfg_st *surface, dml_uint_t num_plane) { + (void)surface; for (dml_uint_t i = 0; i < num_plane; i++) { dml_print("DML: surface_cfg: plane=%d, PitchY = %d\n", i, surface->PitchY[i]); dml_print("DML: surface_cfg: plane=%d, SurfaceWidthY = %d\n", i, surface->SurfaceWidthY[i]); @@ -609,6 +619,7 @@ void dml_print_dml_display_cfg_surface(const struct dml_surface_cfg_st *surface, void dml_print_dml_display_cfg_hw_resource(const struct dml_hw_resource_st *hw, dml_uint_t num_plane) { + (void)hw; for (dml_uint_t i = 0; i < num_plane; i++) { dml_print("DML: hw_resource: plane=%d, ODMMode = %d\n", i, hw->ODMMode[i]); dml_print("DML: hw_resource: plane=%d, DPPPerSurface = %d\n", i, hw->DPPPerSurface[i]); @@ -620,6 +631,7 @@ void dml_print_dml_display_cfg_hw_resource(const struct dml_hw_resource_st *hw, __DML_DLL_EXPORT__ void dml_print_soc_state_bounding_box(const struct soc_state_bounding_box_st *state) { + (void)state; dml_print("DML: state_bbox: socclk_mhz = %f\n", state->socclk_mhz); dml_print("DML: state_bbox: dscclk_mhz = %f\n", state->dscclk_mhz); dml_print("DML: state_bbox: phyclk_mhz = %f\n", state->phyclk_mhz); @@ -649,6 +661,7 @@ __DML_DLL_EXPORT__ void dml_print_soc_state_bounding_box(const struct soc_state_ __DML_DLL_EXPORT__ void dml_print_soc_bounding_box(const struct soc_bounding_box_st *soc) { + (void)soc; dml_print("DML: soc_bbox: dprefclk_mhz = %f\n", soc->dprefclk_mhz); dml_print("DML: soc_bbox: xtalclk_mhz = %f\n", soc->xtalclk_mhz); dml_print("DML: soc_bbox: pcierefclk_mhz = %f\n", soc->pcierefclk_mhz); @@ -686,6 +699,7 @@ __DML_DLL_EXPORT__ void dml_print_soc_bounding_box(const struct soc_bounding_box __DML_DLL_EXPORT__ void dml_print_clk_cfg(const struct dml_clk_cfg_st *clk_cfg) { + (void)clk_cfg; dml_print("DML: clk_cfg: 0-use_required, 1-use pipe.clks_cfg, 2-use state bbox\n"); dml_print("DML: clk_cfg: dcfclk_option = %d\n", clk_cfg->dcfclk_option); dml_print("DML: clk_cfg: dispclk_option = %d\n", clk_cfg->dispclk_option); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c index 2f0e0048bea8..5d7b6c399470 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c @@ -441,6 +441,7 @@ static void populate_dml21_surface_config_from_plane_state( struct dml2_surface_cfg *surface, const struct dc_plane_state *plane_state) { + (void)in_dc; surface->plane0.pitch = plane_state->plane_size.surface_pitch; surface->plane1.pitch = plane_state->plane_size.chroma_pitch; surface->plane0.height = plane_state->plane_size.surface_size.height; @@ -873,6 +874,7 @@ static struct dml2_dchub_watermark_regs *wm_set_index_to_dc_wm_set(union dcn_wat void dml21_extract_watermark_sets(const struct dc *in_dc, union dcn_watermark_set *watermarks, struct dml2_context *in_ctx) { + (void)in_dc; const struct dml2_display_cfg_programming *programming = in_ctx->v21.mode_programming.programming; unsigned int wm_index; @@ -907,6 +909,7 @@ void dml21_get_pipe_mcache_config( struct dml2_per_plane_programming *pln_prog, struct dml2_pipe_configuration_descriptor *mcache_pipe_config) { + (void)context; mcache_pipe_config->plane0.viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x; mcache_pipe_config->plane0.viewport_width = pipe_ctx->plane_res.scl_data.viewport.width; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c index 4724b08c77e1..732de97335fa 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c @@ -88,6 +88,7 @@ int dml21_find_dc_pipes_for_plane(const struct dc *in_dc, struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__], int dml_plane_idx) { + (void)in_dc; unsigned int dml_stream_index; unsigned int main_stream_id; unsigned int dc_plane_index; @@ -282,6 +283,7 @@ static struct dc_plane_state *dml21_add_phantom_plane(struct dml2_context *dml_c struct dc_plane_state *main_plane, struct dml2_per_plane_programming *plane_programming) { + (void)plane_programming; struct dc_plane_state *phantom_plane; phantom_plane = dml_ctx->config.svp_pstate.callbacks.create_phantom_plane(dc, context, main_plane); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c index cc992af6ac9c..de40d7bae252 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c @@ -51,6 +51,8 @@ void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const st static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state, struct dml2_context *in_ctx, unsigned int pipe_cnt) { + (void)out_new_hw_state; + (void)pipe_cnt; unsigned int dml_prog_idx = 0, dc_pipe_index = 0, num_dpps_required = 0; struct dml2_per_plane_programming *pln_prog = NULL; struct dml2_per_stream_programming *stream_prog = NULL; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c index 99fc2f0666e2..fda01b0800d6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c @@ -281,6 +281,7 @@ static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters static void create_phantom_plane_from_main_plane(struct dml2_plane_parameters *phantom, const struct dml2_plane_parameters *main, const struct dml2_stream_parameters *phantom_stream, int phantom_stream_index, const struct dml2_stream_parameters *main_stream) { + (void)main_stream; memcpy(phantom, main, sizeof(struct dml2_plane_parameters)); phantom->stream_index = phantom_stream_index; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index f6402e199354..80813159bffd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -840,6 +840,7 @@ static void CalculateSwathWidth( unsigned int swath_width_luma_ub[], // per-pipe unsigned int swath_width_chroma_ub[]) // per-pipe { + (void)BytePerPixY; enum dml2_odm_mode MainSurfaceODMMode; double odm_hactive_factor = 1.0; unsigned int req_width_horz_y; @@ -1283,6 +1284,8 @@ static double TruncToValidBPP( // Output unsigned int *RequiredSlots) { + (void)DSCInputBitPerComponent; + (void)RequiredSlots; double MaxLinkBPP; unsigned int MinDSCBPP; double MaxDSCBPP; @@ -1922,6 +1925,7 @@ static void CalculateRowBandwidth( double *dpte_row_bw, double *meta_row_bw) { + (void)use_one_row_for_frame; if (!DCCEnable || !mrq_present) { *meta_row_bw = 0; } else if (dml_is_420(SourcePixelFormat) || SourcePixelFormat == dml2_rgbe_alpha) { @@ -2020,6 +2024,11 @@ static void CalculateDCCConfiguration( unsigned int *IndependentBlockLuma, unsigned int *IndependentBlockChroma) { + (void)SurfaceWidthChroma; + (void)SurfaceHeightChroma; + (void)TilingFormat; + (void)BytePerPixelDETY; + (void)BytePerPixelDETC; unsigned int DETBufferSizeForDCC = nomDETInKByte * 1024; unsigned int segment_order_horz_contiguous_luma; @@ -2270,6 +2279,7 @@ static void calculate_mcache_row_bytes( struct dml2_core_internal_scratch *scratch, struct dml2_core_calcs_calculate_mcache_row_bytes_params *p) { + (void)scratch; unsigned int vmpg_bytes = 0; unsigned int blk_bytes = 0; float meta_per_mvmpg_per_channel = 0; @@ -3642,6 +3652,8 @@ static double CalculateWriteBackDelay( unsigned int WritebackSourceHeight, unsigned int HTotal) { + (void)WritebackPixelFormat; + (void)WritebackHRatio; double CalculateWriteBackDelay; double Line_length; double Output_lines_last_notclamped; @@ -3959,6 +3971,7 @@ static enum dml2_odm_mode DecideODMMode(unsigned int HActive, double SurfaceRequiredDISPCLKWithODMCombineThreeToOne, double SurfaceRequiredDISPCLKWithODMCombineFourToOne) { + (void)SurfaceRequiredDISPCLKWithODMCombineFourToOne; enum dml2_odm_mode MinimumRequiredODMModeForMaxDispClock; enum dml2_odm_mode MinimumRequiredODMModeForMaxDSCHActive; enum dml2_odm_mode MinimumRequiredODMModeForMax420HActive; @@ -4460,6 +4473,8 @@ static double CalculateWriteBackDISPCLK( unsigned int HTotal, unsigned int WritebackLineBufferSize) { + (void)WritebackPixelFormat; + (void)WritebackVRatio; double DISPCLK_H, DISPCLK_V, DISPCLK_HB; DISPCLK_H = PixelClock * math_ceil2((double)WritebackHTaps / 8.0, 1) / WritebackHRatio; @@ -4561,6 +4576,10 @@ static void CalculateSurfaceSizeInMall( unsigned int SurfaceSizeInMALL[], bool *ExceededMALLSize) { + (void)Read256BytesBlockWidthY; + (void)Read256BytesBlockWidthC; + (void)Read256BytesBlockHeightY; + (void)Read256BytesBlockHeightC; unsigned int TotalSurfaceSizeInMALLForSS = 0; unsigned int TotalSurfaceSizeInMALLForSubVP = 0; unsigned int MALLAllocatedForDCNInBytes = MALLAllocatedForDCN * 1024 * 1024; @@ -4620,6 +4639,7 @@ static void calculate_tdlut_setting( struct dml2_core_internal_scratch *scratch, struct dml2_core_calcs_calculate_tdlut_setting_params *p) { + (void)scratch; // locals unsigned int tdlut_bpe = 8; unsigned int tdlut_width; @@ -6503,6 +6523,7 @@ static void CalculateFlipSchedule( double *final_flip_bw, bool *ImmediateFlipSupportedForPipe) { + (void)use_one_row_for_frame_flip; struct dml2_core_shared_CalculateFlipSchedule_locals *l = &s->CalculateFlipSchedule_locals; l->dual_plane = dml_is_420(SourcePixelFormat) || SourcePixelFormat == dml2_rgbe_alpha; @@ -9968,6 +9989,8 @@ static void CalculateVMGroupAndRequestTimes( double TimePerVMRequestVBlank[], double TimePerVMRequestFlip[]) { + (void)dpte_row_width_luma_ub; + (void)dpte_row_width_chroma_ub; unsigned int num_group_per_lower_vm_stage = 0; unsigned int num_req_per_lower_vm_stage = 0; unsigned int num_group_per_lower_vm_stage_flip; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c index 6930ba7ce5b7..cd9bf190cb1a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c @@ -648,6 +648,7 @@ static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters static void create_phantom_plane_from_main_plane(struct dml2_plane_parameters *phantom, const struct dml2_plane_parameters *main, const struct dml2_stream_parameters *phantom_stream, int phantom_stream_index, const struct dml2_stream_parameters *main_stream) { + (void)main_stream; memcpy(phantom, main, sizeof(struct dml2_plane_parameters)); phantom->stream_index = phantom_stream_index; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c index ab0b4a4b5d65..5ffe211a6643 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c @@ -552,6 +552,7 @@ static int get_displays_without_vactive_margin_mask(struct dml2_dpmm_map_mode_to static int get_displays_with_fams_mask(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out, int latency_hiding_requirement_us) { + (void)latency_hiding_requirement_us; unsigned int i; int displays_with_fams_mask = 0x0; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.c index 1f2d9e97f5fd..39965ff2e111 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.c @@ -8,11 +8,13 @@ static bool dummy_map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out) { + (void)in_out; return true; } static bool dummy_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out) { + (void)in_out; return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.c index 3dcd2c250633..fb0b0ac547c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.c @@ -9,6 +9,7 @@ static bool dummy_build_min_clock_table(struct dml2_mcg_build_min_clock_table_params_in_out *in_out) { + (void)in_out; return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c index e8691983c0eb..f7c10dbfc154 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c @@ -428,6 +428,7 @@ static void insert_strategy_into_expanded_list( struct dml2_pmo_pstate_strategy *expanded_strategy_list, unsigned int *num_expanded_strategies) { + (void)stream_count; if (expanded_strategy_list && num_expanded_strategies) { memcpy(&expanded_strategy_list[*num_expanded_strategies], per_stream_pstate_strategy, sizeof(struct dml2_pmo_pstate_strategy)); @@ -520,6 +521,7 @@ static bool is_variant_method_valid(const struct dml2_pmo_pstate_strategy *base_ const unsigned int num_streams_per_variant_method[PMO_DCN4_MAX_DISPLAYS], const unsigned int stream_count) { + (void)variant_strategy; bool valid = true; unsigned int i; @@ -1180,6 +1182,7 @@ static bool all_timings_support_svp(const struct dml2_pmo_instance *pmo, static void insert_into_candidate_list(const struct dml2_pmo_pstate_strategy *pstate_strategy, int stream_count, struct dml2_pmo_scratch *scratch) { + (void)stream_count; scratch->pmo_dcn4.pstate_strategy_candidates[scratch->pmo_dcn4.num_pstate_candidates] = *pstate_strategy; scratch->pmo_dcn4.num_pstate_candidates++; } @@ -1847,6 +1850,7 @@ static void build_subvp_meta_per_stream(struct dml2_pmo_instance *pmo, struct display_configuation_with_meta *display_config, int stream_index) { + (void)display_config; struct dml2_implicit_svp_meta *stream_svp_meta = &pmo->scratch.pmo_dcn4.stream_svp_meta[stream_index]; struct dml2_pstate_meta *stream_pstate_meta = &pmo->scratch.pmo_dcn4.stream_pstate_meta[stream_index]; @@ -1990,6 +1994,7 @@ static void setup_planes_for_drr_by_mask(struct display_configuation_with_meta * struct dml2_pmo_instance *pmo, int plane_mask) { + (void)pmo; unsigned int plane_index; struct dml2_plane_parameters *plane; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c index 4d687fa86caa..83802aac11cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.c @@ -9,16 +9,19 @@ static bool dummy_init_for_stutter(struct dml2_pmo_init_for_stutter_in_out *in_out) { + (void)in_out; return false; } static bool dummy_test_for_stutter(struct dml2_pmo_test_for_stutter_in_out *in_out) { + (void)in_out; return true; } static bool dummy_optimize_for_stutter(struct dml2_pmo_optimize_for_stutter_in_out *in_out) { + (void)in_out; return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c index 4a7c4c62111e..fa20a91c6e16 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.c @@ -17,6 +17,7 @@ static void setup_unoptimized_display_config_with_meta(const struct dml2_instanc static void setup_speculative_display_config_with_meta(const struct dml2_instance *dml, struct display_configuation_with_meta *out, const struct dml2_display_cfg *display_config) { + (void)dml; memcpy(&out->display_config, display_config, sizeof(struct dml2_display_cfg)); out->stage1.min_clk_index_for_latency = 0; } @@ -472,6 +473,7 @@ static unsigned int count_elements_in_span(int *array, unsigned int array_size, static bool calculate_h_split_for_scaling_transform(int full_vp_width, int h_active, int num_pipes, enum dml2_scaling_transform scaling_transform, int *pipe_vp_x_start, int *pipe_vp_x_end) { + (void)h_active; int i, slice_width; const char MAX_SCL_VP_OVERLAP = 3; bool success = false; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c index 6ef93c6fc1cd..6b78334c2554 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c @@ -178,6 +178,10 @@ static unsigned int find_pipes_assigned_to_plane(struct dml2_context *ctx, static bool validate_pipe_assignment(const struct dml2_context *ctx, const struct dc_state *state, const struct dml_display_cfg_st *disp_cfg, const struct dml2_dml_to_dc_pipe_mapping *mapping) { + (void)ctx; + (void)disp_cfg; + (void)mapping; + (void)state; // int i, j, k; // // unsigned int plane_id; @@ -292,6 +296,7 @@ static unsigned int find_last_resort_pipe_candidates(const struct dc_state *exis const unsigned int stream_id, unsigned int *last_resort_pipe_candidates) { + (void)stream_id; unsigned int num_last_resort_candidates = 0; int i; @@ -541,6 +546,7 @@ static void add_odm_slice_to_odm_tree(struct dml2_context *ctx, struct dc_pipe_mapping_scratch *scratch, unsigned int odm_slice_index) { + (void)ctx; struct pipe_ctx *pipe = NULL; int i; @@ -567,6 +573,8 @@ static struct pipe_ctx *add_plane_to_blend_tree(struct dml2_context *ctx, unsigned int odm_slice, struct pipe_ctx *top_pipe) { + (void)ctx; + (void)plane; int i; for (i = 0; i < pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine; i++) { @@ -722,6 +730,7 @@ static void free_unused_pipes_for_plane(struct dml2_context *ctx, struct dc_stat static void remove_pipes_from_blend_trees(struct dml2_context *ctx, struct dc_state *state, struct dc_plane_pipe_pool *pipe_pool, unsigned int odm_slice) { + (void)ctx; struct pipe_ctx *pipe; int i; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c index cf3a69aba638..8e0997441ee0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c @@ -33,6 +33,7 @@ void dml2_init_ip_params(struct dml2_context *dml2, const struct dc *in_dc, struct ip_params_st *out) { + (void)in_dc; switch (dml2->v20.dml_core_ctx.project) { case dml_project_dcn32: case dml_project_dcn321: @@ -244,6 +245,7 @@ void dml2_init_ip_params(struct dml2_context *dml2, const struct dc *in_dc, stru void dml2_init_socbb_params(struct dml2_context *dml2, const struct dc *in_dc, struct soc_bounding_box_st *out) { + (void)in_dc; out->dprefclk_mhz = dml2->config.bbox_overrides.dprefclk_mhz; out->xtalclk_mhz = dml2->config.bbox_overrides.xtalclk_mhz; out->pcierefclk_mhz = 100; @@ -328,6 +330,7 @@ void dml2_init_socbb_params(struct dml2_context *dml2, const struct dc *in_dc, s void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, const struct soc_bounding_box_st *in_bbox, struct soc_states_st *out) { + (void)in_dc; struct dml2_policy_build_synthetic_soc_states_scratch *s = &dml2->v20.scratch.create_scratch.build_synthetic_socbb_scratch; struct dml2_policy_build_synthetic_soc_states_params *p = &dml2->v20.scratch.build_synthetic_socbb_params; int dcfclk_stas_mhz[NUM_DCFCLK_STAS] = {0}; @@ -782,6 +785,7 @@ static void populate_dml_timing_cfg_from_stream_state(struct dml_timing_cfg_st * static void populate_dml_output_cfg_from_stream_state(struct dml_output_cfg_st *out, unsigned int location, const struct dc_stream_state *in, const struct pipe_ctx *pipe, struct dml2_context *dml2) { + (void)pipe; unsigned int output_bpc; out->DSCEnable[location] = (enum dml_dsc_enable)in->timing.flags.DSC; @@ -1133,6 +1137,7 @@ static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out static unsigned int map_stream_to_dml_display_cfg(const struct dml2_context *dml2, const struct dc_stream_state *stream, const struct dml_display_cfg_st *dml_dispcfg) { + (void)dml_dispcfg; int i = 0; int location = -1; @@ -1173,6 +1178,7 @@ static bool get_plane_id(struct dml2_context *dml2, const struct dc_state *conte static unsigned int map_plane_to_dml_display_cfg(const struct dml2_context *dml2, const struct dc_plane_state *plane, const struct dc_state *context, const struct dml_display_cfg_st *dml_dispcfg, unsigned int stream_id, int plane_index) { + (void)dml_dispcfg; unsigned int plane_id; unsigned int i = 0; unsigned int location = UINT_MAX; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c index 6c7cdf102906..86567e232415 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c @@ -465,6 +465,7 @@ void dml2_initialize_det_scratch(struct dml2_context *in_ctx) static unsigned int find_planes_per_stream_and_stream_count(struct dml2_context *in_ctx, struct dml_display_cfg_st *dml_dispcfg, int *num_of_planes_per_stream) { + (void)in_ctx; unsigned int plane_index, stream_index = 0, num_of_streams; for (plane_index = 0; plane_index < dml_dispcfg->num_surfaces; plane_index++) { diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml_display_rq_dlg_calc.c index 00d22e542469..18962bbf455b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml_display_rq_dlg_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml_display_rq_dlg_calc.c @@ -563,6 +563,7 @@ void dml_rq_dlg_get_dlg_reg(dml_display_dlg_regs_st *disp_dlg_regs, void dml_rq_dlg_get_arb_params(struct display_mode_lib_st *mode_lib, dml_display_arb_params_st *arb_param) { + (void)mode_lib; memset(arb_param, 0, sizeof(*arb_param)); arb_param->max_req_outstanding = 256; arb_param->min_req_outstanding = 256; // turn off the sat level feature if this set to max -- cgit v1.2.3 From 73cea8c0b60ea5ec6afc26da6ea1118e81d618a8 Mon Sep 17 00:00:00 2001 From: Roman Li Date: Wed, 1 Apr 2026 17:38:26 -0400 Subject: drm/amd/display: Drop unused tiling formats from dml2 Remove unused legacy tiling format support from dml2. Legacy asics don't use dml2. Fixes: e56e3cff2a1b ("drm/amd/display: Sync dcn42 with DC 3.2.373") Reviewed-by: Leo Li Signed-off-by: Roman Li Signed-off-by: Alex Deucher --- .../dml2_0/dml21/inc/dml_top_display_cfg_types.h | 14 ----- .../dml2_0/dml21/src/dml2_core/dml2_core_utils.c | 64 +--------------------- .../dml2_0/dml21/src/dml2_core/dml2_core_utils.h | 2 - 3 files changed, 2 insertions(+), 78 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_display_cfg_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_display_cfg_types.h index 4e9abe1a568d..79dfba54344c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_display_cfg_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_display_cfg_types.h @@ -26,20 +26,6 @@ enum dml2_swizzle_mode { dml2_gfx11_sw_64kb_r_x, dml2_gfx11_sw_256kb_d_x, dml2_gfx11_sw_256kb_r_x, - - dml2_sw_linear_256b, // GFX10 SW_LINEAR only accepts 256 byte aligned pitch - dml2_gfx10_sw_64kb_r_x, - dml2_gfx102_sw_64kb_s, - dml2_gfx102_sw_64kb_s_t, - dml2_gfx102_sw_64kb_s_x, - dml2_gfx102_sw_64kb_r_x, - - dml2_linear_64elements, // GFX7 LINEAR_ALIGNED accepts pitch alignment of the maximum of 64 elements or 256 bytes - dml2_gfx7_1d_thin, - dml2_gfx7_2d_thin_gen_zero, - dml2_gfx7_2d_thin_gen_one, - dml2_gfx7_2d_thin_arlene, - dml2_gfx7_2d_thin_anubis }; enum dml2_source_format_class { diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c index cd9bf190cb1a..5dc846802c53 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c @@ -428,10 +428,6 @@ bool dml2_core_utils_is_phantom_pipe(const struct dml2_plane_parameters *plane_c unsigned int dml2_core_utils_get_tile_block_size_bytes(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel) { - if (dml2_core_utils_get_gfx_version(sw_mode) == 10 || dml2_core_utils_get_gfx_version(sw_mode) == 7) { - return dml2_core_utils_get_tile_block_size_bytes_backcompat(sw_mode, byte_per_pixel); - } - if (sw_mode == dml2_sw_linear) return 256; else if (sw_mode == dml2_sw_256b_2d) @@ -462,56 +458,14 @@ unsigned int dml2_core_utils_get_tile_block_size_bytes(enum dml2_swizzle_mode sw }; } -unsigned int dml2_core_utils_get_tile_block_size_bytes_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel) -{ - if (sw_mode == dml2_sw_linear_256b) - return 256; - else if (sw_mode == dml2_gfx10_sw_64kb_r_x) - return 65536; - else if (sw_mode == dml2_gfx102_sw_64kb_s) - return 65536; - else if (sw_mode == dml2_gfx102_sw_64kb_s_t) - return 65536; - else if (sw_mode == dml2_gfx102_sw_64kb_s_x) - return 65536; - else if (sw_mode == dml2_gfx102_sw_64kb_r_x) - return 65536; - else if (sw_mode == dml2_linear_64elements) - return 256; - else if (sw_mode == dml2_gfx7_1d_thin) - return 256; - else if (sw_mode == dml2_gfx7_2d_thin_gen_zero) - return (128 * 64 * byte_per_pixel); - else if (sw_mode == dml2_gfx7_2d_thin_gen_one) - return (128 * 128 * byte_per_pixel); - else if (sw_mode == dml2_gfx7_2d_thin_arlene) - return (64 * 32 * byte_per_pixel); - else if (sw_mode == dml2_gfx7_2d_thin_anubis) - return (128 * 128 * byte_per_pixel); - else { - DML_ASSERT(0); - return 256; - }; -} - bool dml2_core_utils_get_segment_horizontal_contiguous(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel) { - if (dml2_core_utils_get_gfx_version(sw_mode) == 10 || dml2_core_utils_get_gfx_version(sw_mode) == 7) { - return dml2_core_utils_get_segment_horizontal_contiguous_backcompat(sw_mode, byte_per_pixel); - } else { - return (byte_per_pixel != 2); - } -} - -bool dml2_core_utils_get_segment_horizontal_contiguous_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel) -{ - return !((byte_per_pixel == 4) && - ((sw_mode == dml2_gfx10_sw_64kb_r_x) || (sw_mode == dml2_gfx102_sw_64kb_s) || (sw_mode == dml2_gfx102_sw_64kb_s_t) || (sw_mode == dml2_gfx102_sw_64kb_s_x))); + return (byte_per_pixel != 2); } bool dml2_core_utils_is_linear(enum dml2_swizzle_mode sw_mode) { - return (sw_mode == dml2_sw_linear || sw_mode == dml2_sw_linear_256b || sw_mode == dml2_linear_64elements); + return sw_mode == dml2_sw_linear; }; @@ -544,20 +498,6 @@ int unsigned dml2_core_utils_get_gfx_version(enum dml2_swizzle_mode sw_mode) sw_mode == dml2_gfx11_sw_256kb_d_x || sw_mode == dml2_gfx11_sw_256kb_r_x) version = 11; - else if (sw_mode == dml2_sw_linear_256b || - sw_mode == dml2_gfx10_sw_64kb_r_x || - sw_mode == dml2_gfx102_sw_64kb_s || - sw_mode == dml2_gfx102_sw_64kb_s_t || - sw_mode == dml2_gfx102_sw_64kb_s_x || - sw_mode == dml2_gfx102_sw_64kb_r_x) - version = 10; - else if (sw_mode == dml2_linear_64elements || - sw_mode == dml2_gfx7_1d_thin || - sw_mode == dml2_gfx7_2d_thin_gen_zero || - sw_mode == dml2_gfx7_2d_thin_gen_one || - sw_mode == dml2_gfx7_2d_thin_arlene || - sw_mode == dml2_gfx7_2d_thin_anubis) - version = 7; else { DML_LOG_VERBOSE("ERROR: Invalid sw_mode setting! val=%u\n", sw_mode); DML_ASSERT(0); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h index 471e73ed671c..95f0d017add4 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h @@ -22,8 +22,6 @@ void dml2_core_utils_pipe_plane_mapping(const struct core_display_cfg_support_in bool dml2_core_utils_is_phantom_pipe(const struct dml2_plane_parameters *plane_cfg); unsigned int dml2_core_utils_get_tile_block_size_bytes(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel); bool dml2_core_utils_get_segment_horizontal_contiguous(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel); -unsigned int dml2_core_utils_get_tile_block_size_bytes_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel); -bool dml2_core_utils_get_segment_horizontal_contiguous_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel); bool dml2_core_utils_is_vertical_rotation(enum dml2_rotation_angle Scan); bool dml2_core_utils_is_linear(enum dml2_swizzle_mode sw_mode); int unsigned dml2_core_utils_get_gfx_version(enum dml2_swizzle_mode sw_mode); -- cgit v1.2.3 From 06ea8754956dfbed15657c7df6f95ae8689f4a7b Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Fri, 27 Feb 2026 21:17:37 -0500 Subject: drm/amd/display: update dcn42 bounding box [why] update according hw spec. Reviewed-by: Dillon Varone Signed-off-by: Charlene Liu Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h | 2 +- .../drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h index c75778ea7a2c..deea5608c08e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h @@ -234,7 +234,7 @@ static const struct dml2_ip_capabilities dml2_dcn42_max_ip_caps = { .config_return_buffer_segment_size_in_kbytes = 64, .meta_fifo_size_in_kentries = 32, .compressed_buffer_segment_size_in_kbytes = 64, - .cursor_buffer_size = 24, + .cursor_buffer_size = 42, .max_flip_time_us = 110, .max_flip_time_lines = 50, .hostvm_mode = 0, diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c index fda01b0800d6..858e7bbc511f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c @@ -135,7 +135,7 @@ struct dml2_core_ip_params core_dcn42_ip_caps_base = { .cursor_64bpp_support = true, .dynamic_metadata_vm_enabled = false, - .max_num_hdmi_frl_outputs = 0, + .max_num_hdmi_frl_outputs = 1, .max_num_dp2p0_outputs = 2, .max_num_dp2p0_streams = 4, .imall_supported = 1, @@ -155,7 +155,7 @@ struct dml2_core_ip_params core_dcn42_ip_caps_base = { .min_meta_chunk_size_bytes = 256, .dchub_arb_to_ret_delay = 102, - .hostvm_mode = 1, + .hostvm_mode = 0, }; static void patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities *ip_caps, const struct dml2_core_ip_params *ip_params) -- cgit v1.2.3 From ba86f9b5c09aee64923b90b7d7add993fcb34a89 Mon Sep 17 00:00:00 2001 From: Relja Vojvodic Date: Fri, 20 Mar 2026 15:40:25 -0400 Subject: drm/amd/display: Rework YCbCr422 DSC policy - Reworked YCbCr4:2:2 Native/Simple policy decision making with DSC enabled based on DSC caps and stream signal type Reviewed-by: Wenjing Liu Signed-off-by: Relja Vojvodic Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- drivers/gpu/drm/amd/display/dc/dc_dsc.h | 1 + drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c | 13 ++++++------- drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c | 2 +- drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c | 2 +- drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c | 2 +- drivers/gpu/drm/amd/display/dc/link/link_detection.c | 11 +++++------ drivers/gpu/drm/amd/display/dc/link/link_dpms.c | 3 ++- .../gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c | 2 ++ .../drm/amd/display/dc/resource/dcn315/dcn315_resource.c | 2 ++ 10 files changed, 22 insertions(+), 18 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 55ec281db3b7..5ceadcdca524 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -562,6 +562,7 @@ struct dc_config { bool frame_update_cmd_version2; struct spl_sharpness_range dcn_sharpness_range; struct spl_sharpness_range dcn_override_sharpness_range; + bool no_native422_support; }; enum visual_confirm { @@ -986,7 +987,6 @@ struct link_service; * causing an issue or not. */ struct dc_debug_options { - bool native422_support; bool disable_dsc; enum visual_confirm visual_confirm; int visual_confirm_rect_height; diff --git a/drivers/gpu/drm/amd/display/dc/dc_dsc.h b/drivers/gpu/drm/amd/display/dc/dc_dsc.h index 9d18f1c08079..101bce6b8de6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dsc.h @@ -52,6 +52,7 @@ struct dc_dsc_policy { uint32_t max_target_bpp; uint32_t min_target_bpp; bool enable_dsc_when_not_needed; + bool ycbcr422_simple; }; struct dc_dsc_config_options { diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index 5b3584ad5b6b..8dfb6dd14eb2 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -680,9 +680,6 @@ static void get_dsc_enc_caps( } else { build_dsc_enc_caps(dsc, dsc_enc_caps); } - - if (dsc->ctx->dc->debug.native422_support) - dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1; } /* Returns 'false' if no intersection was found for at least one capability. @@ -1100,13 +1097,14 @@ static bool setup_dsc_config( branch_max_throughput_mps = dsc_sink_caps->branch_overall_throughput_0_mps; break; case PIXEL_ENCODING_YCBCR422: - is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_NATIVE_422; - sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_1_mps; - branch_max_throughput_mps = dsc_sink_caps->branch_overall_throughput_1_mps; - if (!is_dsc_possible) { + if (policy.ycbcr422_simple) { is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_SIMPLE_422; dsc_cfg->ycbcr422_simple = is_dsc_possible; sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_0_mps; + } else { + is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_NATIVE_422; + sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_1_mps; + branch_max_throughput_mps = dsc_sink_caps->branch_overall_throughput_1_mps; } break; case PIXEL_ENCODING_YCBCR420: @@ -1406,6 +1404,7 @@ void dc_dsc_get_policy_for_timing(const struct dc_crtc_timing *timing, policy->min_target_bpp = 8; /* DP specs limits to 3 x bpc */ policy->max_target_bpp = 3 * bpc; + policy->ycbcr422_simple = true; break; case PIXEL_ENCODING_YCBCR420: /* DP specs limits to 6 */ diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c index 242f1e6f0d8f..6e1e759462bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c @@ -100,7 +100,7 @@ void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz) dsc_enc_caps->color_formats.bits.RGB = 1; dsc_enc_caps->color_formats.bits.YCBCR_444 = 1; dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1; - dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 0; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1; dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c index e712985f7abd..17acb64a9d80 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c @@ -128,7 +128,7 @@ void dsc35_get_single_enc_caps(struct dsc_enc_caps *dsc_enc_caps, unsigned int m dsc_enc_caps->color_formats.bits.RGB = 1; dsc_enc_caps->color_formats.bits.YCBCR_444 = 1; dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1; - dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 0; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1; dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c index 3bf737195bac..41c3b814b6bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c @@ -78,7 +78,7 @@ static void dsc401_get_single_enc_caps(struct dsc_enc_caps *dsc_enc_caps, unsign dsc_enc_caps->color_formats.bits.RGB = 1; dsc_enc_caps->color_formats.bits.YCBCR_444 = 1; dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1; - dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 0; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1; dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index 59851924bfcd..714370e773c1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -781,10 +781,8 @@ static void restore_phy_clocks_for_destructive_link_verification(const struct dc } static void verify_link_capability_destructive(struct dc_link *link, - struct dc_sink *sink, enum dc_detect_reason reason) { - (void)sink; bool should_prepare_phy_clocks = should_prepare_phy_clocks_for_link_verification(link->dc, reason); @@ -857,11 +855,11 @@ static bool should_verify_link_capability_destructively(struct dc_link *link, return destrictive; } -static void verify_link_capability(struct dc_link *link, struct dc_sink *sink, +static void verify_link_capability(struct dc_link *link, enum dc_detect_reason reason) { if (should_verify_link_capability_destructively(link, reason)) - verify_link_capability_destructive(link, sink, reason); + verify_link_capability_destructive(link, reason); else verify_link_capability_non_destructive(link); } @@ -1455,8 +1453,9 @@ bool link_detect(struct dc_link *link, enum dc_detect_reason reason) is_local_sink_detect_success = detect_link_and_local_sink(link, reason); - if (is_local_sink_detect_success && link->local_sink) - verify_link_capability(link, link->local_sink, reason); + if (is_local_sink_detect_success && link->local_sink) { + verify_link_capability(link, reason); + } DC_LOG_DC("%s: link_index=%d is_local_sink_detect_success=%d pre_link_type=%d link_type=%d\n", __func__, link->link_index, is_local_sink_detect_success, pre_link_type, link->type); diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index b4f46408a000..e12c25896364 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -181,7 +181,8 @@ void link_set_all_streams_dpms_off_for_link(struct dc_link *link) /* link can be also enabled by vbios. In this case it is not recorded * in pipe_ctx. Disable link phy here to make sure it is completely off */ - dp_disable_link_phy(link, &link_res, link->connector_signal); + if (dc_is_dp_signal(link->connector_signal)) + dp_disable_link_phy(link, &link_res, link->connector_signal); } void link_resume(struct dc_link *link) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index ee4bc2c2e73a..07dfb65d6eb9 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -1996,6 +1996,8 @@ static bool dcn31_resource_construct( dc->config.use_pipe_ctx_sync_logic = true; dc->config.disable_hbr_audio_dp2 = true; + dc->config.no_native422_support = true; + /* read VBIOS LTTPR caps */ { if (ctx->dc_bios->funcs->get_lttpr_caps) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index 2ca673114841..9a1bbec1d815 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -1959,6 +1959,8 @@ static bool dcn315_resource_construct( dc->caps.color.mpc.ogam_rom_caps.hlg = 0; dc->caps.color.mpc.ocsc = 1; + dc->config.no_native422_support = true; + /* read VBIOS LTTPR caps */ { if (ctx->dc_bios->funcs->get_lttpr_caps) { -- cgit v1.2.3 From d79e023f2fb96c0e3c5683d1097a8d0f334dc18f Mon Sep 17 00:00:00 2001 From: George Shen Date: Mon, 23 Mar 2026 17:15:16 -0400 Subject: drm/amd/display: Remove unnecessary Freesync w/a from DCN32 [Why/How] A workaround was previously used for certain Freesync cases that would override the vstartup_start value from DML to position the SDP correctly. This is no longer needed in DCN32 and above, so remove the workaround. Reviewed-by: Dillon Varone Signed-off-by: George Shen Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 37 ---------------------- 1 file changed, 37 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index e29497204df7..eb199215d298 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1610,38 +1610,6 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context) return false; } -static void dcn20_adjust_freesync_v_startup(const struct dc_crtc_timing *dc_crtc_timing, int *vstartup_start) -{ - struct dc_crtc_timing patched_crtc_timing; - uint32_t asic_blank_end = 0; - uint32_t asic_blank_start = 0; - uint32_t newVstartup = 0; - - patched_crtc_timing = *dc_crtc_timing; - - if (patched_crtc_timing.flags.INTERLACE == 1) { - if (patched_crtc_timing.v_front_porch < 2) - patched_crtc_timing.v_front_porch = 2; - } else { - if (patched_crtc_timing.v_front_porch < 1) - patched_crtc_timing.v_front_porch = 1; - } - - /* blank_start = frame end - front porch */ - asic_blank_start = patched_crtc_timing.v_total - - patched_crtc_timing.v_front_porch; - - /* blank_end = blank_start - active */ - asic_blank_end = asic_blank_start - - patched_crtc_timing.v_border_bottom - - patched_crtc_timing.v_addressable - - patched_crtc_timing.v_border_top; - - newVstartup = asic_blank_end + (patched_crtc_timing.v_total - asic_blank_start); - - *vstartup_start = ((newVstartup > *vstartup_start) ? newVstartup : *vstartup_start); -} - static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes, int pipe_cnt, int vlevel) @@ -1756,11 +1724,6 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, } } - if (context->res_ctx.pipe_ctx[i].stream->adaptive_sync_infopacket.valid) - dcn20_adjust_freesync_v_startup( - &context->res_ctx.pipe_ctx[i].stream->timing, - &context->res_ctx.pipe_ctx[i].pipe_dlg_param.vstartup_start); - pipe_idx++; } /* If DCN isn't making memory requests we can allow pstate change and lower clocks */ -- cgit v1.2.3 From d49086491bcb7bde67f0cc760c72ea12444ecb79 Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Thu, 5 Mar 2026 17:07:16 +0800 Subject: drm/amd/display: Adjust freesync pcon whitelist Add more freesync supported pcon ID into the whitelist. Reviewed-by: Harry Wentland Signed-off-by: Wayne Lin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 2 ++ drivers/gpu/drm/amd/display/include/ddc_service_types.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index f3fa8eb4bcce..d5ea4fe84b73 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -1400,6 +1400,8 @@ static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id) case DP_BRANCH_DEVICE_ID_0060AD: case DP_BRANCH_DEVICE_ID_00E04C: case DP_BRANCH_DEVICE_ID_90CC24: + case DP_BRANCH_DEVICE_ID_001CF8: + case DP_BRANCH_DEVICE_ID_001FF2: ret_val = true; break; default: diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h index 1c603b12957f..53210e3aa0e0 100644 --- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h +++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h @@ -36,6 +36,7 @@ #define DP_BRANCH_DEVICE_ID_006037 0x006037 #define DP_BRANCH_DEVICE_ID_001CF8 0x001CF8 #define DP_BRANCH_DEVICE_ID_0060AD 0x0060AD +#define DP_BRANCH_DEVICE_ID_001FF2 0x001FF2 #define DP_BRANCH_HW_REV_10 0x10 #define DP_BRANCH_HW_REV_20 0x20 -- cgit v1.2.3 From 72022bad019e038c647a8ea50193ed30459fdb19 Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Tue, 3 Mar 2026 16:00:24 +0800 Subject: drm/amd/display: Parse freesync mccs vcp code [Why & How] DMUB supports to parse freesynce mccs vcp code now. Store it for later freesync mccs manipulation. Reviewed-by: Harry Wentland Signed-off-by: Wayne Lin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 45 ++++++++++++++--------- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 5 +++ drivers/gpu/drm/amd/display/dc/dc_types.h | 2 + 3 files changed, 35 insertions(+), 17 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 1d9ceb432ec3..1e5953d8a90d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -13088,6 +13088,7 @@ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm, vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version; vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate; vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate; + vsdb->freesync_mccs_vcp_code = output->amd_vsdb.freesync_mccs_vcp_code; } else { drm_warn(adev_to_drm(dm->adev), "Unknown EDID CEA parser results\n"); return false; @@ -13122,6 +13123,8 @@ static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm, vsdb_info->amd_vsdb_version = version; vsdb_info->min_refresh_rate_hz = min_rate; vsdb_info->max_refresh_rate_hz = max_rate; + /* Not enabled on DMCU*/ + vsdb_info->freesync_mccs_vcp_code = 0; return true; } /* not amd vsdb */ @@ -13333,14 +13336,19 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) { i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); - if (i >= 0 && vsdb_info.freesync_supported) { - amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; - amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; - if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) - freesync_capable = true; + if (i >= 0) { + amdgpu_dm_connector->vsdb_info = vsdb_info; + sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code; - connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; - connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; + if (vsdb_info.freesync_supported) { + amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; + amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) + freesync_capable = true; + + connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; + connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; + } } } @@ -13349,19 +13357,22 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) { i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); - if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) { - - amdgpu_dm_connector->pack_sdp_v1_3 = true; - amdgpu_dm_connector->as_type = as_type; + if (i >= 0) { amdgpu_dm_connector->vsdb_info = vsdb_info; + sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code; - amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; - amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; - if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) - freesync_capable = true; + if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) { + amdgpu_dm_connector->pack_sdp_v1_3 = true; + amdgpu_dm_connector->as_type = as_type; - connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; - connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; + amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; + amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) + freesync_capable = true; + + connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; + connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; + } } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 63ce1f52b697..8aada3e1c5b8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -758,6 +758,11 @@ struct amdgpu_hdmi_vsdb_info { */ unsigned int max_refresh_rate_hz; + /** + * @freesync_mccs_vcp_code: MCCS VCP code for freesync state + */ + unsigned int freesync_mccs_vcp_code; + /** * @replay_mode: Replay supported */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index fd8ec1660312..5b7490a7dc7a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -205,6 +205,8 @@ struct dc_edid_caps { uint32_t audio_latency; uint32_t video_latency; + unsigned int freesync_vcp_code; + uint8_t qs_bit; uint8_t qy_bit; -- cgit v1.2.3 From 6f71d5dd320663f2003fff252a5da93f4f753bef Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Tue, 3 Mar 2026 13:55:42 +0800 Subject: drm/amd/display: Read sink freesync support via mccs If EDID AMD VSDB declares that sink supports MCCS method for freesync usage, send mccs request to understand sink freesync current supporting state. If sink supports freesync but user toggles OSD to turn off it, disable freesync. If HDMI sink doesn't support MCCS method for freesync usage, disable freesync as well. Reviewed-by: Harry Wentland Signed-off-by: Wayne Lin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 + .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 165 +++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dc_types.h | 4 + drivers/gpu/drm/amd/display/dc/dm_helpers.h | 5 + .../gpu/drm/amd/display/dc/link/link_detection.c | 14 ++ 6 files changed, 197 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 1e5953d8a90d..c7dd75c5d921 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -13376,6 +13376,14 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, } } + /* Handle MCCS */ + dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || + as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) && + (!sink->edid_caps.freesync_vcp_code || + (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported))) + freesync_capable = false; + update: if (dm_con_state) dm_con_state->freesync_capable = freesync_capable; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index d5ea4fe84b73..1332969c7491 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -49,6 +49,45 @@ #include "ddc_service_types.h" #include "clk_mgr.h" +#define MCCS_DEST_ADDR (0x6E >> 1) +#define MCCS_SRC_ADDR 0x51 +#define MCCS_LENGTH_OFFSET 0x80 +#define MCCS_MAX_DATA_SIZE 0x20 + +enum mccs_op_code { + MCCS_OP_CODE_VCP_REQUEST = 0x01, + MCCS_OP_CODE_VCP_REPLY = 0x02, + MCCS_OP_CODE_VCP_SET = 0x03, + MCCS_OP_CODE_VCP_RESET = 0x09, + MCCS_OP_CODE_CAP_REQUEST = 0xF3, + MCCS_OP_CODE_CAP_REPLY = 0xE3 +}; + +enum mccs_op_buff_size { + MCCS_OP_BUFF_SIZE__WR_VCP_REQUEST = 5, + MCCS_OP_BUFF_SIZE_RD_VCP_REQUEST = 11, + MCCS_OP_BUFF_SIZE_WR_VCP_SET = 7, +}; + +enum vcp_reply_mask { + FREESYNC_SUPPORTED = 0x1 +}; + +union vcp_reply { + struct { + unsigned char src_addr; + unsigned char length; /* Length is offset by MccsLengthOffs = 0x80 */ + unsigned char reply_op_code; /* Should return MCCS_OP_CODE_VCP_REPLY = 0x02 */ + unsigned char result_code; /* 00h No Error, 01h Unsupported VCP Code */ + unsigned char request_code; /* Should return mccs vcp code sent in the vcp request */ + unsigned char type_code; /* VCP type code: 00h Set parameter, 01h Momentary */ + unsigned char max_value[2]; /* 2 bytes returning max value current value */ + unsigned char present_value[2]; /* NOTE: Byte0 is MSB, Byte1 is LSB */ + unsigned char check_sum; + } bytes; + unsigned char raw[11]; +}; + static u32 edid_extract_panel_id(struct edid *edid) { return (u32)edid->mfg_id[0] << 24 | @@ -1441,3 +1480,129 @@ bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream // TODO return false; } + +static int mccs_operation_vcp_request(unsigned int vcp_code, struct dc_link *link, + union vcp_reply *reply) +{ + const unsigned char retry_interval_ms = 40; + unsigned char retry = 5; + struct amdgpu_dm_connector *aconnector = link->priv; + struct i2c_adapter *ddc; + struct i2c_msg msg = {0}; + int ret = 0; + int idx; + + unsigned char wr_data[MCCS_OP_BUFF_SIZE__WR_VCP_REQUEST] = { + MCCS_SRC_ADDR, /* Byte0 - Src Addr */ + MCCS_LENGTH_OFFSET + 2, /* Byte1 - Length */ + MCCS_OP_CODE_VCP_REQUEST, /* Byte2 - MCCS Command */ + (unsigned char) vcp_code, /* Byte3 - VCP Code */ + MCCS_DEST_ADDR << 1 /* Byte4 - CheckSum */ + }; + + /* calculate checksum */ + for (idx = 0; idx < (MCCS_OP_BUFF_SIZE__WR_VCP_REQUEST - 1); idx++) + wr_data[(MCCS_OP_BUFF_SIZE__WR_VCP_REQUEST-1)] ^= wr_data[idx]; + + if (link->aux_mode) + ddc = &aconnector->dm_dp_aux.aux.ddc; + else + ddc = &aconnector->i2c->base; + + do { + msg.addr = MCCS_DEST_ADDR; + msg.flags = 0; + msg.len = MCCS_OP_BUFF_SIZE__WR_VCP_REQUEST; + msg.buf = wr_data; + + ret = i2c_transfer(ddc, &msg, 1); + if (ret != 1) + goto mccs_retry; + + msleep(retry_interval_ms); + + msg.addr = MCCS_DEST_ADDR; + msg.flags = I2C_M_RD; + msg.len = MCCS_OP_BUFF_SIZE_RD_VCP_REQUEST; + msg.buf = reply->raw; + + ret = i2c_transfer(ddc, &msg, 1); + + /* sink might reply with null msg if it can't reply in time */ + if (ret == 1 && reply->bytes.length > MCCS_LENGTH_OFFSET) + break; +mccs_retry: + retry--; + msleep(retry_interval_ms); + } while (retry); + + if (!retry) { + drm_dbg_driver(aconnector->base.dev, + "%s: MCCS VCP request failed after retries", __func__); + return -EIO; + } + + return 0; +} + +void dm_helpers_read_mccs_caps(struct dc_context *ctx, struct dc_link *link, + struct dc_sink *sink) +{ + bool mccs_op = false; + struct dpcd_caps *dpcd_caps; + struct drm_device *dev; + uint16_t freesync_vcp_value = 0; + union vcp_reply vcp_reply_value = {0}; + + if (!ctx) + return; + dev = adev_to_drm(ctx->driver_context); + + if (!link || !sink) { + drm_dbg_driver(dev, "%s: link or sink is NULL", __func__); + return; + } + + sink->mccs_caps.freesync_supported = false; + dpcd_caps = &link->dpcd_caps; + + if (sink->edid_caps.freesync_vcp_code != 0) { + if (dc_is_dp_signal(link->connector_signal)) { + if ((dpcd_caps->dpcd_rev.raw >= DPCD_REV_14) && + (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) && + dm_is_freesync_pcon_whitelist(dpcd_caps->branch_dev_id) && + (dpcd_caps->adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT == true)) + mccs_op = true; + + if ((dpcd_caps->dongle_type != DISPLAY_DONGLE_NONE && + dpcd_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER)) { + if (mccs_op == false) + drm_dbg_driver(dev, "%s: Legacy Pcon support", __func__); + mccs_op = true; + } + + if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + // Todo: Freesync over MST + mccs_op = false; + } + } + + if (dc_is_hdmi_signal(link->connector_signal)) { + drm_dbg_driver(dev, "%s: Local HDMI sink", __func__); + mccs_op = true; + } + + if (mccs_op == true) { + // MCCS VCP request to get VCP value + if (!mccs_operation_vcp_request(sink->edid_caps.freesync_vcp_code, link, + &vcp_reply_value)) { + freesync_vcp_value = vcp_reply_value.bytes.present_value[1]; + freesync_vcp_value |= (uint16_t) vcp_reply_value.bytes.present_value[0] << 8; + } + // If VCP Value bit 0 is 1, freesyncSupport = true + sink->mccs_caps.freesync_supported = + (freesync_vcp_value & FREESYNC_SUPPORTED) ? true : false; + } + } +} + diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 5ceadcdca524..7d170eaeb163 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -2725,6 +2725,7 @@ struct dc_sink { struct stereo_3d_features features_3d[TIMING_3D_FORMAT_MAX]; bool converter_disable_audio; + struct mccs_caps mccs_caps; struct scdc_caps scdc_caps; struct dc_sink_dsc_caps dsc_caps; struct dc_sink_fec_caps fec_caps; diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 5b7490a7dc7a..7672ee88be82 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1315,6 +1315,10 @@ struct dc_panel_config { } rio; }; +struct mccs_caps { + bool freesync_supported; +}; + #define MAX_SINKS_PER_LINK 4 /* diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 2818df555e62..3aa2b11f559b 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -181,6 +181,11 @@ enum dc_edid_status dm_helpers_read_local_edid( struct dc_link *link, struct dc_sink *sink); +void dm_helpers_read_mccs_caps( + struct dc_context *ctx, + struct dc_link *link, + struct dc_sink *sink); + bool dm_helpers_dp_handle_test_pattern_request( struct dc_context *ctx, const struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index 714370e773c1..794dd6a95918 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -1234,6 +1234,20 @@ static bool detect_link_and_local_sink(struct dc_link *link, if (dc_is_hdmi_signal(link->connector_signal)) read_scdc_caps(link->ddc, link->local_sink); + /* When FreeSync is toggled through OSD, + * we see same EDID no matter what. Check MCCS caps + * to see if we should update FreeSync caps now. + */ + dm_helpers_read_mccs_caps( + link->ctx, + link, + sink); + + if (prev_sink != NULL) { + if (memcmp(&sink->mccs_caps, &prev_sink->mccs_caps, sizeof(struct mccs_caps))) + same_edid = false; + } + if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && sink_caps.transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { -- cgit v1.2.3 From 602b8ef9d2a607c6028c6b9d8e174b2e859dd769 Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Fri, 6 Mar 2026 16:32:36 +0800 Subject: drm/amd/display: Enable sink freesync via MCCS If sink like HDMI indicates supporting freesync via MCCS, explicitly to send vcp set command on sink to enable freesync. Reviewed-by: Harry Wentland Signed-off-by: Wayne Lin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 + .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 74 ++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 5 ++ 3 files changed, 81 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c7dd75c5d921..5f9bbe178265 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -13383,6 +13383,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, (!sink->edid_caps.freesync_vcp_code || (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported))) freesync_capable = false; + if (sink->mccs_caps.freesync_supported && freesync_capable) + dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); update: if (dm_con_state) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 1332969c7491..3b8ae7798a93 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -1606,3 +1606,77 @@ void dm_helpers_read_mccs_caps(struct dc_context *ctx, struct dc_link *link, } } +static int mccs_operation_vcp_set(unsigned int vcp_code, struct dc_link *link, uint16_t value) +{ + const unsigned char retry_interval_ms = 40; + unsigned char retry = 5; + struct amdgpu_dm_connector *aconnector = link->priv; + struct i2c_adapter *ddc; + struct i2c_msg msg = {0}; + int ret = 0; + int idx; + + unsigned char wr_data[MCCS_OP_BUFF_SIZE_WR_VCP_SET] = { + MCCS_SRC_ADDR, /* Byte0 - Src Addr */ + MCCS_LENGTH_OFFSET + 4, /* Byte1 - Length */ + MCCS_OP_CODE_VCP_SET, /* Byte2 - MCCS Command */ + (unsigned char)vcp_code, /* Byte3 - VCP Code */ + (unsigned char)(value >> 8), /* Byte4 - Value High Byte */ + (unsigned char)(value & 0xFF), /* Byte5 - Value Low Byte */ + MCCS_DEST_ADDR << 1 /* Byte6 - CheckSum */ + }; + + /* calculate checksum */ + for (idx = 0; idx < (MCCS_OP_BUFF_SIZE_WR_VCP_SET - 1); idx++) + wr_data[MCCS_OP_BUFF_SIZE_WR_VCP_SET - 1] ^= wr_data[idx]; + + if (link->aux_mode) + ddc = &aconnector->dm_dp_aux.aux.ddc; + else + ddc = &aconnector->i2c->base; + + do { + msg.addr = MCCS_DEST_ADDR; + msg.flags = 0; + msg.len = MCCS_OP_BUFF_SIZE_WR_VCP_SET; + msg.buf = wr_data; + + ret = i2c_transfer(ddc, &msg, 1); + if (ret == 1) + break; + + retry--; + msleep(retry_interval_ms); + } while (retry); + + if (!retry) + return -EIO; + + return 0; +} + +void dm_helpers_mccs_vcp_set(struct dc_context *ctx, struct dc_link *link, + struct dc_sink *sink) +{ + struct drm_device *dev; + const uint16_t enable = 0x0101; + + if (!ctx) + return; + dev = adev_to_drm(ctx->driver_context); + + if (!link || !sink) { + drm_dbg_driver(dev, "%s: link or sink is NULL", __func__); + return; + } + + if (!sink->mccs_caps.freesync_supported) { + drm_dbg_driver(dev, "%s: MCCS freesync not supported on this sink", __func__); + return; + } + + if (mccs_operation_vcp_set(sink->edid_caps.freesync_vcp_code, link, enable)) + drm_dbg_driver(dev, "%s: Failed to set VCP code %d", __func__, + sink->edid_caps.freesync_vcp_code); +} + diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 3aa2b11f559b..107aec6a1265 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -186,6 +186,11 @@ void dm_helpers_read_mccs_caps( struct dc_link *link, struct dc_sink *sink); +void dm_helpers_mccs_vcp_set( + struct dc_context *ctx, + struct dc_link *link, + struct dc_sink *sink); + bool dm_helpers_dp_handle_test_pattern_request( struct dc_context *ctx, const struct dc_link *link, -- cgit v1.2.3 From 8dc88c6a5948c9565f4901f2a62c74306a8eda8d Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Wed, 11 Mar 2026 16:11:57 +0800 Subject: drm/amd/display: Avoid to do MCCS transaction if unnecessary We don't have to do MCCS/DDCCI transactions with sink side every time by calling get_modes(). Limit it to be operated when hotplug occurs. Reviewed-by: Harry Wentland Signed-off-by: Wayne Lin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 ++++++++++++---------- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 +- .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5f9bbe178265..70ee26c68d4e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3994,7 +3994,7 @@ void amdgpu_dm_update_connector_after_detect( if (sink) { if (aconnector->dc_sink) { - amdgpu_dm_update_freesync_caps(connector, NULL); + amdgpu_dm_update_freesync_caps(connector, NULL, true); /* * retain and release below are used to * bump up refcount for sink because the link doesn't point @@ -4006,9 +4006,9 @@ void amdgpu_dm_update_connector_after_detect( aconnector->dc_sink = sink; dc_sink_retain(aconnector->dc_sink); amdgpu_dm_update_freesync_caps(connector, - aconnector->drm_edid); + aconnector->drm_edid, true); } else { - amdgpu_dm_update_freesync_caps(connector, NULL); + amdgpu_dm_update_freesync_caps(connector, NULL, true); if (!aconnector->dc_sink) { aconnector->dc_sink = aconnector->dc_em_sink; dc_sink_retain(aconnector->dc_sink); @@ -4052,7 +4052,7 @@ void amdgpu_dm_update_connector_after_detect( * If yes, put it here. */ if (aconnector->dc_sink) { - amdgpu_dm_update_freesync_caps(connector, NULL); + amdgpu_dm_update_freesync_caps(connector, NULL, true); dc_sink_release(aconnector->dc_sink); } @@ -4085,13 +4085,13 @@ void amdgpu_dm_update_connector_after_detect( "failed to create aconnector->requested_timing\n"); } - amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid); + amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid, true); update_connector_ext_caps(aconnector); dm_set_panel_type(aconnector); } else { hdmi_cec_unset_edid(aconnector); drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); - amdgpu_dm_update_freesync_caps(connector, NULL); + amdgpu_dm_update_freesync_caps(connector, NULL, true); aconnector->num_modes = 0; dc_sink_release(aconnector->dc_sink); aconnector->dc_sink = NULL; @@ -8855,7 +8855,7 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector, * drm_edid_connector_add_modes() and need to be * restored here. */ - amdgpu_dm_update_freesync_caps(connector, drm_edid); + amdgpu_dm_update_freesync_caps(connector, drm_edid, false); } else { amdgpu_dm_connector->num_modes = 0; } @@ -13270,7 +13270,7 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, * FreeSync parameters. */ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - const struct drm_edid *drm_edid) + const struct drm_edid *drm_edid, bool do_mccs) { int i = 0; struct amdgpu_dm_connector *amdgpu_dm_connector = @@ -13377,13 +13377,16 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, } /* Handle MCCS */ - dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + if (do_mccs) + dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) && (!sink->edid_caps.freesync_vcp_code || (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported))) freesync_capable = false; - if (sink->mccs_caps.freesync_supported && freesync_capable) + + if (do_mccs && sink->mccs_caps.freesync_supported && freesync_capable) dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); update: diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 8aada3e1c5b8..74a8fe1a1999 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -1071,7 +1071,7 @@ void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector); void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - const struct drm_edid *drm_edid); + const struct drm_edid *drm_edid, bool do_mccs); void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 5d8c4c7020b1..be038d9014bb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -474,7 +474,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) if (aconnector->dc_sink) { amdgpu_dm_update_freesync_caps( - connector, aconnector->drm_edid); + connector, aconnector->drm_edid, true); #if defined(CONFIG_DRM_AMD_DC_FP) if (!validate_dsc_caps_on_connector(aconnector)) -- cgit v1.2.3 From 5721b5b9c9c792233d7817239bd81925fb3ad9d1 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 24 Mar 2026 14:28:12 -0400 Subject: drm/amd/display: Fix HostVMMinPageSize unit mismatch in DML2.1 [Why] This was found back on DML2 but was missed when creating DML2.1. The bottom layer calculation (CalculateHostVMDynamicLevels) expects a value in bytes, not KB, but we pass in the value in KB (eg. 4). This causes an extra page table level to be required in the prefetch bytes which can be significant overhead - preventing some modes from being supported that should otherwise be. [How] Correct the units by multiplying the input and override values by 1024. Reviewed-by: Austin Zheng Signed-off-by: Nicholas Kazlauskas Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index 80813159bffd..c4628801f729 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -7402,7 +7402,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter s->tdlut_bytes_per_group, s->HostVMInefficiencyFactor, s->HostVMInefficiencyFactorPrefetch, - mode_lib->soc.hostvm_min_page_size_kbytes, + mode_lib->soc.hostvm_min_page_size_kbytes * 1024, mode_lib->soc.qos_parameters.qos_type, !(display_cfg->overrides.max_outstanding_when_urgent_expected_disable), mode_lib->soc.max_outstanding_reqs, @@ -7498,7 +7498,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter CalculatePrefetchSchedule_params->OutputFormat = display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].output.output_format; CalculatePrefetchSchedule_params->MaxInterDCNTileRepeaters = mode_lib->ip.max_inter_dcn_tile_repeaters; CalculatePrefetchSchedule_params->VStartup = s->MaximumVStartup[k]; - CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; + CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; CalculatePrefetchSchedule_params->DynamicMetadataEnable = display_cfg->plane_descriptors[k].dynamic_meta_data.enable; CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; @@ -8986,7 +8986,7 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->soc.mall_allocated_for_dcn_mbytes; CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthY; CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthC; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ip.dcc_meta_buffer_size_bytes; CalculateVMRowAndSwath_params->mrq_present = mode_lib->ip.dcn_mrq_present; @@ -10778,7 +10778,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->soc.mall_allocated_for_dcn_mbytes; CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->mp.SwathWidthY; CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->mp.SwathWidthC; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ip.dcc_meta_buffer_size_bytes; CalculateVMRowAndSwath_params->mrq_present = mode_lib->ip.dcn_mrq_present; @@ -10994,7 +10994,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex s->tdlut_bytes_per_group, s->HostVMInefficiencyFactor, s->HostVMInefficiencyFactorPrefetch, - mode_lib->soc.hostvm_min_page_size_kbytes, + mode_lib->soc.hostvm_min_page_size_kbytes * 1024, mode_lib->soc.qos_parameters.qos_type, !(display_cfg->overrides.max_outstanding_when_urgent_expected_disable), mode_lib->soc.max_outstanding_reqs, @@ -11287,7 +11287,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex CalculatePrefetchSchedule_params->OutputFormat = display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].output.output_format; CalculatePrefetchSchedule_params->MaxInterDCNTileRepeaters = mode_lib->ip.max_inter_dcn_tile_repeaters; CalculatePrefetchSchedule_params->VStartup = s->MaxVStartupLines[k]; - CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; + CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; CalculatePrefetchSchedule_params->DynamicMetadataEnable = display_cfg->plane_descriptors[k].dynamic_meta_data.enable; CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; -- cgit v1.2.3 From 5a89553231833ee2ac5dc228855791c219e7d784 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 24 Mar 2026 11:50:18 -0400 Subject: drm/amd/display: Correct MALL parameters for DCN42 soc bb [Why & How] The MALL and DCC parameters were copied and pasted from a previous ASIC but the correct value per HW specification should all be 0. If not correct this can impact urgent bandwidth calculation and PMO. Reviewed-by: Dillon Varone Signed-off-by: Nicholas Kazlauskas Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h index deea5608c08e..ccdd9fd1e1bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h @@ -203,7 +203,7 @@ static const struct dml2_soc_bb dml2_socbb_dcn42 = { .xtalclk_mhz = 24, .pcie_refclk_mhz = 100, .dchub_refclk_mhz = 50, - .mall_allocated_for_dcn_mbytes = 64, + .mall_allocated_for_dcn_mbytes = 0, .max_outstanding_reqs = 256, .fabric_datapath_to_dcn_data_return_bytes = 32, .return_bus_width_bytes = 64, -- cgit v1.2.3 From 07ac59230d5fd603d56af2363dae80d3e973e4bc Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 19 Mar 2026 14:34:56 -0400 Subject: drm/amd/display: Pass min page size from SOC BB to dml2_1 plane config [Why] Like dml2_0 this isn't guaranteed to be constant for every ASIC. This can cause corruption or underflow for linear surfaces due to a wrong PTE_ROW_HEIGHT_LINEAR value if not correctly specified. [How] Like dml2_0 pass in the SOC bb into the plane configuration population functions. Set both GPUVM and HostVM page sizes in the overrides. Reviewed-by: Dillon Varone Signed-off-by: Nicholas Kazlauskas Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dc/dml2_0/dml21/dml21_translation_helper.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c index 5d7b6c399470..476030193f14 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c @@ -389,7 +389,9 @@ static void populate_dml21_dummy_surface_cfg(struct dml2_surface_cfg *surface, c surface->tiling = dml2_sw_64kb_2d; } -static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, const struct dc_stream_state *stream) +static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, + const struct dc_stream_state *stream, + const struct dml2_soc_bb *soc_bb) { unsigned int width, height; @@ -433,7 +435,8 @@ static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, plane->pixel_format = dml2_444_32; plane->dynamic_meta_data.enable = false; - plane->overrides.gpuvm_min_page_size_kbytes = 256; + plane->overrides.gpuvm_min_page_size_kbytes = soc_bb->gpuvm_min_page_size_kbytes; + plane->overrides.hostvm_min_page_size_kbytes = soc_bb->hostvm_min_page_size_kbytes; } static void populate_dml21_surface_config_from_plane_state( @@ -504,7 +507,7 @@ static const struct scaler_data *get_scaler_data_for_plane( static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dml_ctx, struct dml2_plane_parameters *plane, const struct dc_plane_state *plane_state, - const struct dc_state *context, unsigned int stream_index) + const struct dc_state *context, unsigned int stream_index, const struct dml2_soc_bb *soc_bb) { const struct scaler_data *scaler_data = get_scaler_data_for_plane(dml_ctx, plane_state, context); struct dc_stream_state *stream = context->streams[stream_index]; @@ -648,7 +651,8 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm plane->composition.rotation_angle = (enum dml2_rotation_angle) plane_state->rotation; plane->stream_index = stream_index; - plane->overrides.gpuvm_min_page_size_kbytes = 256; + plane->overrides.gpuvm_min_page_size_kbytes = soc_bb->gpuvm_min_page_size_kbytes; + plane->overrides.hostvm_min_page_size_kbytes = soc_bb->hostvm_min_page_size_kbytes; plane->immediate_flip = plane_state->flip_immediate; @@ -786,7 +790,9 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s if (context->stream_status[stream_index].plane_count == 0) { disp_cfg_plane_location = dml_dispcfg->num_planes++; populate_dml21_dummy_surface_cfg(&dml_dispcfg->plane_descriptors[disp_cfg_plane_location].surface, context->streams[stream_index]); - populate_dml21_dummy_plane_cfg(&dml_dispcfg->plane_descriptors[disp_cfg_plane_location], context->streams[stream_index]); + populate_dml21_dummy_plane_cfg( + &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], + context->streams[stream_index], &dml_ctx->v21.dml_init.soc_bb); dml_dispcfg->plane_descriptors[disp_cfg_plane_location].stream_index = disp_cfg_stream_location; } else { for (plane_index = 0; plane_index < context->stream_status[stream_index].plane_count; plane_index++) { @@ -798,7 +804,10 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s ASSERT(disp_cfg_plane_location >= 0 && disp_cfg_plane_location < __DML2_WRAPPER_MAX_STREAMS_PLANES__); populate_dml21_surface_config_from_plane_state(in_dc, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location].surface, context->stream_status[stream_index].plane_states[plane_index]); - populate_dml21_plane_config_from_plane_state(dml_ctx, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], context->stream_status[stream_index].plane_states[plane_index], context, stream_index); + populate_dml21_plane_config_from_plane_state( + dml_ctx, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], + context->stream_status[stream_index].plane_states[plane_index], + context, stream_index, &dml_ctx->v21.dml_init.soc_bb); dml_dispcfg->plane_descriptors[disp_cfg_plane_location].stream_index = disp_cfg_stream_location; if (dml21_wrapper_get_plane_id(context, context->streams[stream_index]->stream_id, context->stream_status[stream_index].plane_states[plane_index], &dml_ctx->v21.dml_to_dc_pipe_mapping.disp_cfg_to_plane_id[disp_cfg_plane_location])) -- cgit v1.2.3 From a0ce0de0ce9c7d60a6f22417c2237ad36687ef86 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 19 Mar 2026 14:39:14 -0400 Subject: drm/amd/display: Fix DCN42 gpuvm_min_page_size_kbytes in SOC BB [Why & How] To match the HW specification this should be 4, not 256. Reviewed-by: Dillon Varone Signed-off-by: Nicholas Kazlauskas Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h index ccdd9fd1e1bd..9ee092556233 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h @@ -208,7 +208,7 @@ static const struct dml2_soc_bb dml2_socbb_dcn42 = { .fabric_datapath_to_dcn_data_return_bytes = 32, .return_bus_width_bytes = 64, .hostvm_min_page_size_kbytes = 4, - .gpuvm_min_page_size_kbytes = 256, + .gpuvm_min_page_size_kbytes = 4, .gpuvm_max_page_table_levels = 1, .hostvm_max_non_cached_page_table_levels = 2, .phy_downspread_percent = 0.38, -- cgit v1.2.3 From 463a84daf2875582f5fd6d0a27bf80bcc7e73192 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Wed, 25 Mar 2026 17:03:25 -0400 Subject: drm/amd/display: update dcn42 memory latencies Add latency update based on memory type to dml2.1 Reviewed-by: Dillon Varone Signed-off-by: Dmytro Laktyushkin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h index 9ee092556233..040d89f6de35 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h @@ -68,6 +68,7 @@ static const struct dml2_soc_qos_parameters dml_dcn42_variant_a_soc_qos_params = .qos_type = dml2_qos_param_type_dcn3, }; +/* Default SOC bounding box for DCN42 based on LPDDR5/LPCAMM2 latencies*/ static const struct dml2_soc_bb dml2_socbb_dcn42 = { .clk_table = { .wck_ratio = { @@ -185,12 +186,13 @@ static const struct dml2_soc_bb dml2_socbb_dcn42 = { .qos_type = dml2_qos_param_type_dcn3, }, + /* DCN42 params for LPDDR5/LPCAMM2 */ .power_management_parameters = { - .dram_clk_change_blackout_us = 29, + .dram_clk_change_blackout_us = 36, .fclk_change_blackout_us = 0, .g7_ppt_blackout_us = 0, - .stutter_enter_plus_exit_latency_us = 11, - .stutter_exit_latency_us = 9, + .stutter_enter_plus_exit_latency_us = 14, + .stutter_exit_latency_us = 12, .z8_stutter_enter_plus_exit_latency_us = 300, .z8_stutter_exit_latency_us = 200, }, @@ -222,6 +224,17 @@ static const struct dml2_soc_bb dml2_socbb_dcn42 = { .max_fclk_for_uclk_dpm_khz = 2200 * 1000, }; +/* DCN42 params for DDR5 */ +struct dml2_soc_power_management_parameters dcn42_ddr5_power_management_parameters = { + .dram_clk_change_blackout_us = 36, + .fclk_change_blackout_us = 0, + .g7_ppt_blackout_us = 0, + .stutter_enter_plus_exit_latency_us = 23.5, + .stutter_exit_latency_us = 21.5, + .z8_stutter_enter_plus_exit_latency_us = 300, + .z8_stutter_exit_latency_us = 200, +}; + static const struct dml2_ip_capabilities dml2_dcn42_max_ip_caps = { .pipe_count = 4, .otg_count = 4, -- cgit v1.2.3 From 355408042a4ddbd56548d7e7f6ab49731a7efa4b Mon Sep 17 00:00:00 2001 From: Gaghik Khachatrian Date: Mon, 23 Mar 2026 15:26:53 -0400 Subject: drm/amd/display: Fix implicit narrowing conversions in modules [Why]: Implicit narrowing of wider integer types (unsigned int, uint64_t) into narrower fields (uint8_t, uint16_t, unsigned short) has potential truncation issues. [How]: For each warning site, added ASSERT( <= 0xFFFF/0xFF) for debug-mode bounds verification followed by an explicit cast. Typed intermediate variables introduced where needed for clarity. No functional change intended. Reviewed-by: Dillon Varone Signed-off-by: Gaghik Khachatrian Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/modules/freesync/freesync.c | 32 +++++++++----- .../drm/amd/display/modules/power/power_helpers.c | 49 +++++++++++++++------- drivers/gpu/drm/amd/display/modules/vmid/vmid.c | 8 +++- 3 files changed, 61 insertions(+), 28 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index c9150019aab0..f3b41087678b 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -153,7 +153,7 @@ unsigned int mod_freesync_calc_v_total_from_refresh( * round down the vtotal value to avoid stretching vblank over * panel's vtotal boundary. */ - v_total = div64_u64(div64_u64(((unsigned long long)( + v_total = (unsigned int)div64_u64(div64_u64(((unsigned long long)( frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total), 1000000); } else if (refresh_in_uhz >= stream->timing.max_refresh_in_uhz) { @@ -161,11 +161,11 @@ unsigned int mod_freesync_calc_v_total_from_refresh( * round up the vtotal value to prevent off-by-one error causing * v_total_min to be below the panel's lower bound */ - v_total = div64_u64(div64_u64(((unsigned long long)( + v_total = (unsigned int)div64_u64(div64_u64(((unsigned long long)( frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total) + (1000000 - 1), 1000000); } else { - v_total = div64_u64(div64_u64(((unsigned long long)( + v_total = (unsigned int)div64_u64(div64_u64(((unsigned long long)( frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total) + 500000, 1000000); } @@ -196,11 +196,11 @@ static unsigned int calc_v_total_from_duration( uint32_t h_total_up_scaled; h_total_up_scaled = stream->timing.h_total * 10000; - v_total = div_u64((unsigned long long)duration_in_us + v_total = (unsigned int)div_u64((unsigned long long)duration_in_us * stream->timing.pix_clk_100hz + (h_total_up_scaled - 1), h_total_up_scaled); //ceiling for MMax and MMin for MVRR } else { - v_total = div64_u64(div64_u64(((unsigned long long)( + v_total = (unsigned int)div64_u64(div64_u64(((unsigned long long)( duration_in_us) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total), 1000); } @@ -232,22 +232,28 @@ static void update_v_total_for_static_ramp( target_duration_in_us; /* Calculate ratio between new and current frame duration with 3 digit */ - unsigned int frame_duration_ratio = div64_u64(1000000, + uint64_t frame_duration_ratio_u64 = div64_u64(1000000, (1000 + div64_u64(((unsigned long long)( STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) * current_duration_in_us), 1000000))); + ASSERT(frame_duration_ratio_u64 <= 0xFFFFFFFF); + unsigned int frame_duration_ratio = (unsigned int)frame_duration_ratio_u64; /* Calculate delta between new and current frame duration in us */ - unsigned int frame_duration_delta = div64_u64(((unsigned long long)( + uint64_t frame_duration_delta_u64 = div64_u64(((unsigned long long)( current_duration_in_us) * (1000 - frame_duration_ratio)), 1000); + ASSERT(frame_duration_delta_u64 <= 0xFFFFFFFF); + unsigned int frame_duration_delta = (unsigned int)frame_duration_delta_u64; /* Adjust frame duration delta based on ratio between current and * standard frame duration (frame duration at 60 Hz refresh rate). */ - unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)( + uint64_t ramp_rate_interpolated_u64 = div64_u64(((unsigned long long)( frame_duration_delta) * current_duration_in_us), 16666); + ASSERT(ramp_rate_interpolated_u64 <= 0xFFFFFFFF); + unsigned int ramp_rate_interpolated = (unsigned int)ramp_rate_interpolated_u64; /* Going to a higher refresh rate (lower frame duration) */ if (ramp_direction_is_up) { @@ -277,7 +283,7 @@ static void update_v_total_for_static_ramp( } } - v_total = div64_u64(div64_u64(((unsigned long long)( + v_total = (unsigned int)div64_u64(div64_u64(((unsigned long long)( current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total), 1000); @@ -1058,8 +1064,12 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, else in_out_vrr->fixed_refresh_in_uhz = 0; - refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) - - div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000); + { + uint64_t rr_tmp = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) - + div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000); + ASSERT(rr_tmp <= 0xFFFFFFFF); + refresh_range = (unsigned int)rr_tmp; + } in_out_vrr->supported = true; } diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index df3b8383b06d..5d444e9eb38f 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -250,10 +250,12 @@ static void fill_backlight_transform_table(struct dmcu_iram_parameters params, unsigned int lut_index; table->backlight_thresholds[0] = 0; - table->backlight_offsets[0] = params.backlight_lut_array[0]; + ASSERT(params.backlight_lut_array[0] <= 0xFFFF); + table->backlight_offsets[0] = (uint16_t)params.backlight_lut_array[0]; table->backlight_thresholds[num_entries-1] = 0xFFFF; + ASSERT(params.backlight_lut_array[params.backlight_lut_array_size - 1] <= 0xFFFF); table->backlight_offsets[num_entries-1] = - params.backlight_lut_array[params.backlight_lut_array_size - 1]; + (uint16_t)params.backlight_lut_array[params.backlight_lut_array_size - 1]; /* Setup all brightness levels between 0% and 100% exclusive * Fills brightness-to-backlight transform table. Backlight custom curve @@ -265,12 +267,17 @@ static void fill_backlight_transform_table(struct dmcu_iram_parameters params, */ for (i = 1; i+1 < num_entries; i++) { lut_index = (params.backlight_lut_array_size - 1) * i / (num_entries - 1); + ASSERT(lut_index < params.backlight_lut_array_size); - table->backlight_thresholds[i] = - cpu_to_be16(DIV_ROUNDUP((i * 65536), num_entries)); - table->backlight_offsets[i] = - cpu_to_be16(params.backlight_lut_array[lut_index]); + unsigned int threshold_val = DIV_ROUNDUP((i * 65536), num_entries); + unsigned int offset_val = params.backlight_lut_array[lut_index]; + + ASSERT(threshold_val <= 0xFFFF); + ASSERT(offset_val <= 0xFFFF); + + table->backlight_thresholds[i] = cpu_to_be16((uint16_t)threshold_val); + table->backlight_offsets[i] = cpu_to_be16((uint16_t)offset_val); } } @@ -282,10 +289,12 @@ static void fill_backlight_transform_table_v_2_2(struct dmcu_iram_parameters par unsigned int lut_index; table->backlight_thresholds[0] = 0; - table->backlight_offsets[0] = params.backlight_lut_array[0]; + ASSERT(params.backlight_lut_array[0] <= 0xFFFF); + table->backlight_offsets[0] = (uint16_t)params.backlight_lut_array[0]; table->backlight_thresholds[num_entries-1] = 0xFFFF; + ASSERT(params.backlight_lut_array[params.backlight_lut_array_size - 1] <= 0xFFFF); table->backlight_offsets[num_entries-1] = - params.backlight_lut_array[params.backlight_lut_array_size - 1]; + (uint16_t)params.backlight_lut_array[params.backlight_lut_array_size - 1]; /* Setup all brightness levels between 0% and 100% exclusive * Fills brightness-to-backlight transform table. Backlight custom curve @@ -299,12 +308,16 @@ static void fill_backlight_transform_table_v_2_2(struct dmcu_iram_parameters par lut_index = DIV_ROUNDUP((i * params.backlight_lut_array_size), num_entries); ASSERT(lut_index < params.backlight_lut_array_size); + unsigned int threshold_val = DIV_ROUNDUP((i * 65536), num_entries); + unsigned int offset_val = params.backlight_lut_array[lut_index]; + + ASSERT(threshold_val <= 0xFFFF); + ASSERT(offset_val <= 0xFFFF); + table->backlight_thresholds[i] = (big_endian) ? - cpu_to_be16(DIV_ROUNDUP((i * 65536), num_entries)) : - cpu_to_le16(DIV_ROUNDUP((i * 65536), num_entries)); + cpu_to_be16((uint16_t)threshold_val) : cpu_to_le16((uint16_t)threshold_val); table->backlight_offsets[i] = (big_endian) ? - cpu_to_be16(params.backlight_lut_array[lut_index]) : - cpu_to_le16(params.backlight_lut_array[lut_index]); + cpu_to_be16((uint16_t)offset_val) : cpu_to_le16((uint16_t)offset_val); } } @@ -740,9 +753,12 @@ bool dmub_init_abm_config(struct resource_pool *res_pool, } if (params.backlight_ramping_override) { + + ASSERT(params.backlight_ramping_reduction <= 0xFFFF); + ASSERT(params.backlight_ramping_start <= 0xFFFF); for (i = 0; i < NUM_AGGR_LEVEL; i++) { - config.blRampReduction[i] = params.backlight_ramping_reduction; - config.blRampStart[i] = params.backlight_ramping_start; + config.blRampReduction[i] = (uint16_t)params.backlight_ramping_reduction; + config.blRampStart[i] = (uint16_t)params.backlight_ramping_start; } } else { for (i = 0; i < NUM_AGGR_LEVEL; i++) { @@ -1060,6 +1076,7 @@ void calculate_replay_link_off_frame_count(struct dc_link *link, bool fill_custom_backlight_caps(unsigned int config_no, struct dm_acpi_atif_backlight_caps *caps) { unsigned int data_points_size; + uint64_t caps_size; if (config_no >= ARRAY_SIZE(custom_backlight_profiles)) return false; @@ -1067,7 +1084,9 @@ bool fill_custom_backlight_caps(unsigned int config_no, struct dm_acpi_atif_back data_points_size = custom_backlight_profiles[config_no].num_data_points * sizeof(custom_backlight_profiles[config_no].data_points[0]); - caps->size = sizeof(struct dm_acpi_atif_backlight_caps) - sizeof(caps->data_points) + data_points_size; + caps_size = sizeof(struct dm_acpi_atif_backlight_caps) - sizeof(caps->data_points) + data_points_size; + ASSERT(caps_size <= 0xFFFF); + caps->size = (uint16_t)caps_size; caps->flags = 0; caps->error_code = 0; caps->ac_level_percentage = custom_backlight_profiles[config_no].ac_level_percentage; diff --git a/drivers/gpu/drm/amd/display/modules/vmid/vmid.c b/drivers/gpu/drm/amd/display/modules/vmid/vmid.c index 9f408cb11ac9..179b505f7777 100644 --- a/drivers/gpu/drm/amd/display/modules/vmid/vmid.c +++ b/drivers/gpu/drm/amd/display/modules/vmid/vmid.c @@ -57,7 +57,10 @@ static void clear_entry_from_vmid_table(struct core_vmid *core_vmid, unsigned in static void evict_vmids(struct core_vmid *core_vmid) { int i; - uint16_t ord = dc_get_vmid_use_vector(core_vmid->dc); + int ord_int = dc_get_vmid_use_vector(core_vmid->dc); + + ASSERT(ord_int >= 0 && ord_int <= 0xFFFF); + uint16_t ord = (uint16_t)ord_int; // At this point any positions with value 0 are unused vmids, evict them for (i = 1; i < core_vmid->num_vmid; i++) { @@ -120,7 +123,8 @@ uint8_t mod_vmid_get_for_ptb(struct mod_vmid *mod_vmid, uint64_t ptb) ASSERT(0); } - return vmid; + ASSERT(vmid >= 0 && vmid <= 0xFF); + return (uint8_t)vmid; } void mod_vmid_reset(struct mod_vmid *mod_vmid) -- cgit v1.2.3 From 136d15b077e3ec3ab7df5848cba0bb3a5eff222c Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Wed, 25 Mar 2026 17:07:03 -0400 Subject: drm/amd/display: move memory latency update to dml for dcn42 Memory latencies are soc specific and should be part of dml soc bounding box. This change removes them from clk_mgr and has latency update happen based on memory type when dml socbb is being updated. Reviewed-by: Nicholas Kazlauskas Reviewed-by: Charlene Liu Signed-off-by: Dmytro Laktyushkin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c | 78 ---------------------- .../dcn42/dcn42_soc_and_ip_translator.c | 4 ++ 2 files changed, 4 insertions(+), 78 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c index ec888aed207d..6a97ce69a562 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c @@ -611,80 +611,6 @@ static struct clk_bw_params dcn42_bw_params = { }; -static struct wm_table ddr5_wm_table = { - .entries = { - { - .wm_inst = WM_A, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.72, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - { - .wm_inst = WM_B, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.72, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - { - .wm_inst = WM_C, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.72, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - { - .wm_inst = WM_D, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.72, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - } -}; - -static struct wm_table lpddr5_wm_table = { - .entries = { - { - .wm_inst = WM_A, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - { - .wm_inst = WM_B, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - { - .wm_inst = WM_C, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - { - .wm_inst = WM_D, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 11.65333, - .sr_exit_time_us = 28.0, - .sr_enter_plus_exit_time_us = 30.0, - .valid = true, - }, - } -}; - struct dcn42_ss_info_table dcn42_ss_info_table = { .ss_divider = 1000, .ss_percentage = {0, 0, 375, 375, 375} @@ -1141,10 +1067,6 @@ void dcn42_clk_mgr_construct( if (ctx->dc_bios->integrated_info) { clk_mgr->base.base.dentist_vco_freq_khz = ctx->dc_bios->integrated_info->dentist_vco_freq; - if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) - dcn42_bw_params.wm_table = lpddr5_wm_table; - else - dcn42_bw_params.wm_table = ddr5_wm_table; dcn42_bw_params.vram_type = ctx->dc_bios->integrated_info->memory_type; dcn42_bw_params.dram_channel_width_bytes = ctx->dc_bios->integrated_info->memory_type == 0x22 ? 8 : 4; dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 1; diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c index 146a6e47934b..e723b4d0aff3 100644 --- a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c @@ -155,6 +155,10 @@ static void dcn42_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc dcn42_convert_dc_clock_table_to_soc_bb_clock_table(&soc_bb->clk_table, &soc_bb->vmin_limit, dc->clk_mgr->bw_params); } + + if (dc->clk_mgr->bw_params->vram_type == Ddr5MemType) { + soc_bb->power_management_parameters = dcn42_ddr5_power_management_parameters; + } } static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) -- cgit v1.2.3 From bcfeed174882248d079a7ce02d0b4f7ca2467436 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 25 Mar 2026 14:37:04 -0400 Subject: drm/amd/display: Add DCN42 PMO policy for DML2.1 [Why] The MinTTU policy in DML2.1 does not guarantee that we support p-state in blank. This is a delta vs dml2 and earlier revisions as the prefetch mode override has been removed in favor of a more configurable pstate optimizer. [How] Split off DCN42 with its own PMO helpers so that we can use a simpler strategy of only allowing the mode if we support p-state in vblank and if vactive has enough latency hiding. The actual hookup to use these helpers in the PMO factory will be done in a later patch to satisfy build system requirements. Reviewed-by: Dillon Varone Signed-off-by: Nicholas Kazlauskas Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml2_0/Makefile | 1 + .../dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c | 192 +++++++++++++++++++++ .../dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h | 17 ++ .../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c | 16 +- .../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h | 10 ++ 5 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile index 2625943d7f7e..8a451c36fdb3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile @@ -100,6 +100,7 @@ DML21 += src/dml2_mcg/dml2_mcg_factory.o DML21 += src/dml2_pmo/dml2_pmo_dcn3.o DML21 += src/dml2_pmo/dml2_pmo_factory.o DML21 += src/dml2_pmo/dml2_pmo_dcn4_fams2.o +DML21 += src/dml2_pmo/dml2_pmo_dcn42.o DML21 += src/dml2_standalone_libraries/lib_float_math.o DML21 += dml21_translation_helper.o DML21 += dml21_wrapper.o diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c new file mode 100644 index 000000000000..30fd5efe4b87 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2026 Advanced Micro Devices, Inc. + +#include "dml2_pmo_dcn42.h" +#include "lib_float_math.h" +#include "dml2_debug.h" +#include "dml2_pmo_dcn4_fams2.h" + +/* + * DCN42 PMO Policy Implementation + * This implementation provides VBlank-only strategies for 1, 2, 3, and 4 display + * configurations, ensuring p-state watermark support in the blank period only. + */ + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_1_display[] = { + // VBlank only + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_1_display_size = sizeof(dcn42_strategy_list_1_display) / sizeof(struct dml2_pmo_pstate_strategy); + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_2_display[] = { + // VBlank only for both displays + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_2_display_size = sizeof(dcn42_strategy_list_2_display) / sizeof(struct dml2_pmo_pstate_strategy); + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_3_display[] = { + // VBlank only for all three displays + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_3_display_size = sizeof(dcn42_strategy_list_3_display) / sizeof(struct dml2_pmo_pstate_strategy); + +static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_4_display[] = { + // VBlank only for all four displays + { + .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank }, + .allow_state_increase = true, + }, +}; + +static const int dcn42_strategy_list_4_display_size = sizeof(dcn42_strategy_list_4_display) / sizeof(struct dml2_pmo_pstate_strategy); + +bool pmo_dcn42_test_for_pstate_support(struct dml2_pmo_test_for_pstate_support_in_out *in_out) +{ + const struct dml2_pmo_scratch *s = &in_out->instance->scratch; + const int REQUIRED_RESERVED_TIME = + (int)in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us; + bool p_state_supported = true; + unsigned int stream_index; + + if (in_out->base_display_config->display_config.overrides.all_streams_blanked) + return true; + + if (s->pmo_dcn4.cur_pstate_candidate < 0) + return false; + + for (stream_index = 0; stream_index < in_out->base_display_config->display_config.num_streams; stream_index++) { + if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vblank) { + if (dcn4_get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < REQUIRED_RESERVED_TIME || + dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) > 0) { + p_state_supported = false; + break; + } + } else { + p_state_supported = false; + break; + } + } + + return p_state_supported; +} + +bool pmo_dcn42_initialize(struct dml2_pmo_initialize_in_out *in_out) +{ + int i = 0; + struct dml2_pmo_instance *pmo = in_out->instance; + + unsigned int base_list_size = 0; + const struct dml2_pmo_pstate_strategy *base_list = NULL; + unsigned int *expanded_list_size = NULL; + struct dml2_pmo_pstate_strategy *expanded_list = NULL; + + DML_LOG_COMP_IF_ENTER(); + + pmo->soc_bb = in_out->soc_bb; + pmo->ip_caps = in_out->ip_caps; + pmo->mpc_combine_limit = 2; + pmo->odm_combine_limit = 4; + pmo->mcg_clock_table_size = in_out->mcg_clock_table_size; + + /* + * DCN42 does not support FAMS features like SubVP and DRR. + * These parameters are initialized to safe values but won't be used + * since our strategies only use VBlank. + */ + pmo->fams_params.v2.subvp.refresh_rate_limit_max = 0; + pmo->fams_params.v2.subvp.refresh_rate_limit_min = 0; + pmo->fams_params.v2.drr.refresh_rate_limit_max = 0; + pmo->fams_params.v2.drr.refresh_rate_limit_min = 0; + + pmo->options = in_out->options; + + /* Generate permutations of p-state configs from base strategy list */ + for (i = 0; i < PMO_DCN4_MAX_DISPLAYS; i++) { + switch (i+1) { + case 1: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_1_display; + base_list_size = dcn42_strategy_list_1_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_1_display; + + break; + case 2: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_2_display; + base_list_size = dcn42_strategy_list_2_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_2_display; + + break; + case 3: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_3_display; + base_list_size = dcn42_strategy_list_3_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_3_display; + + break; + case 4: + if (pmo->options->override_strategy_lists[i] && pmo->options->num_override_strategies_per_list[i]) { + base_list = pmo->options->override_strategy_lists[i]; + base_list_size = pmo->options->num_override_strategies_per_list[i]; + } else { + base_list = dcn42_strategy_list_4_display; + base_list_size = dcn42_strategy_list_4_display_size; + } + + expanded_list_size = &pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i]; + expanded_list = pmo->init_data.pmo_dcn4.expanded_strategy_list_4_display; + + break; + } + + DML_ASSERT(base_list_size <= PMO_DCN4_MAX_BASE_STRATEGIES); + + /* + * Populate list using DCN4 FAMS2 expansion function. + * Since our strategies only contain VBlank methods, the expansion + * will not introduce any FAMS-specific logic. + */ + pmo_dcn4_fams2_expand_base_pstate_strategies( + base_list, + base_list_size, + i + 1, + expanded_list, + expanded_list_size); + } + + DML_LOG_DEBUG("%s exit with true\n", __func__); + DML_LOG_COMP_IF_EXIT(); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h new file mode 100644 index 000000000000..31ba8575351d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn42.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#ifndef __DML2_PMO_DCN42_H__ +#define __DML2_PMO_DCN42_H__ + +#include "dml2_internal_shared_types.h" + +struct dml2_pmo_initialize_in_out; +struct dml2_pmo_test_for_pstate_support_in_out; + +bool pmo_dcn42_initialize(struct dml2_pmo_initialize_in_out *in_out); +bool pmo_dcn42_test_for_pstate_support(struct dml2_pmo_test_for_pstate_support_in_out *in_out); + +#endif /* __DML2_PMO_DCN42_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c index f7c10dbfc154..b348c65a0f75 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c @@ -1662,7 +1662,7 @@ static bool validate_pstate_support_strategy_cofunctionality(struct dml2_pmo_ins return is_config_schedulable(pmo, display_cfg, pstate_strategy); } -static int get_vactive_pstate_margin(const struct display_configuation_with_meta *display_cfg, int plane_mask) +int dcn4_get_vactive_pstate_margin(const struct display_configuation_with_meta *display_cfg, int plane_mask) { unsigned int i; int min_vactive_margin_us = 0xFFFFFFF; @@ -1907,7 +1907,7 @@ bool pmo_dcn4_fams2_init_for_pstate_support(struct dml2_pmo_init_for_pstate_supp // Figure out which streams can do vactive, and also build up implicit SVP and FAMS2 meta for (stream_index = 0; stream_index < display_config->display_config.num_streams; stream_index++) { - if (get_vactive_pstate_margin(display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) >= (int)(MIN_VACTIVE_MARGIN_PCT * pmo->soc_bb->power_management_parameters.dram_clk_change_blackout_us)) + if (dcn4_get_vactive_pstate_margin(display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) >= (int)(MIN_VACTIVE_MARGIN_PCT * pmo->soc_bb->power_management_parameters.dram_clk_change_blackout_us)) set_bit_in_bitfield(&s->pmo_dcn4.stream_vactive_capability_mask, stream_index); /* FAMS2 meta */ @@ -2182,7 +2182,9 @@ static bool setup_display_config(struct display_configuation_with_meta *display_ return success; } -static int get_minimum_reserved_time_us_for_planes(struct display_configuation_with_meta *display_config, int plane_mask) +int dcn4_get_minimum_reserved_time_us_for_planes( + const struct display_configuation_with_meta *display_config, + int plane_mask) { int min_time_us = 0xFFFFFF; unsigned int plane_index = 0; @@ -2222,16 +2224,16 @@ bool pmo_dcn4_fams2_test_for_pstate_support(struct dml2_pmo_test_for_pstate_supp if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive || s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vactive_drr) { - if (get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (MIN_VACTIVE_MARGIN_PCT * in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us) || + if (dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (MIN_VACTIVE_MARGIN_PCT * in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us) || get_vactive_det_fill_latency_delay_us(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) > stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_us) { p_state_supported = false; break; } } else if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vblank || s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vblank_drr) { - if (get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < + if (dcn4_get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < REQUIRED_RESERVED_TIME || - get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_VBLANK) { + dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_VBLANK) { p_state_supported = false; break; } @@ -2243,7 +2245,7 @@ bool pmo_dcn4_fams2_test_for_pstate_support(struct dml2_pmo_test_for_pstate_supp } } else if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_drr) { if (!all_planes_match_method(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index], dml2_pstate_method_fw_drr) || - get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_DRR) { + dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < MIN_VACTIVE_MARGIN_DRR) { p_state_supported = false; break; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h index 6baab7ad6ecc..f0afa8002a2f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.h @@ -7,6 +7,16 @@ #include "dml2_internal_shared_types.h" +struct display_configuation_with_meta; + +int dcn4_get_vactive_pstate_margin( + const struct display_configuation_with_meta *display_cfg, + int plane_mask); + +int dcn4_get_minimum_reserved_time_us_for_planes( + const struct display_configuation_with_meta *display_config, + int plane_mask); + bool pmo_dcn4_fams2_initialize(struct dml2_pmo_initialize_in_out *in_out); bool pmo_dcn4_fams2_optimize_dcc_mcache(struct dml2_pmo_optimize_dcc_mcache_in_out *in_out); -- cgit v1.2.3 From 0bb8605a8bef8731e0d7ab77707943f9447ba3c4 Mon Sep 17 00:00:00 2001 From: "Zheng, Austin" Date: Thu, 26 Mar 2026 13:29:32 -0400 Subject: drm/amd/display: Remove Duplicate Prefetch Parameter [Why/How] UrgLatency value is passed in twice to the prefetch calculations. Once through the UrgentLatency term and once through the Turg term. Only Turg is used in the prefetch calculation so remove the unused UrgentLatency parameter Reviewed-by: Dillon Varone Signed-off-by: Zheng, Austin Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 2 -- .../amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index c4628801f729..827bd9143c87 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -7503,7 +7503,6 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; CalculatePrefetchSchedule_params->DynamicMetadataTransmittedBytes = display_cfg->plane_descriptors[k].dynamic_meta_data.transmitted_bytes; - CalculatePrefetchSchedule_params->UrgentLatency = mode_lib->ms.UrgLatency; CalculatePrefetchSchedule_params->ExtraLatencyPrefetch = mode_lib->ms.ExtraLatencyPrefetch; CalculatePrefetchSchedule_params->TCalc = mode_lib->ms.TimeCalc; CalculatePrefetchSchedule_params->vm_bytes = mode_lib->ms.vm_bytes[k]; @@ -11292,7 +11291,6 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; CalculatePrefetchSchedule_params->DynamicMetadataTransmittedBytes = display_cfg->plane_descriptors[k].dynamic_meta_data.transmitted_bytes; - CalculatePrefetchSchedule_params->UrgentLatency = mode_lib->mp.UrgentLatency; CalculatePrefetchSchedule_params->ExtraLatencyPrefetch = mode_lib->mp.ExtraLatencyPrefetch; CalculatePrefetchSchedule_params->TCalc = mode_lib->mp.TCalc; CalculatePrefetchSchedule_params->vm_bytes = mode_lib->mp.vm_bytes[k]; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h index 953f40fde1e1..41d0c99d0864 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h @@ -1931,7 +1931,6 @@ struct dml2_core_calcs_CalculatePrefetchSchedule_params { bool DynamicMetadataVMEnabled; unsigned int DynamicMetadataLinesBeforeActiveRequired; unsigned int DynamicMetadataTransmittedBytes; - double UrgentLatency; double ExtraLatencyPrefetch; double TCalc; unsigned int vm_bytes; -- cgit v1.2.3 From a62346043a89d2cc1693e52f55783aa3cf91471e Mon Sep 17 00:00:00 2001 From: Chuanyu Tseng Date: Sat, 28 Mar 2026 08:13:49 +0800 Subject: drm/amd/display: Fix coding style issue [Why & How] Function logic should put after variable declare section, so let's move it. Reviewed-by: Aurabindo Pillai Signed-off-by: Chuanyu Tseng Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index e12bf3dd3e46..782a45caa13d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -743,8 +743,6 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting { struct dc_link_settings initial_link_setting = { LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0}; - if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) - initial_link_setting.link_rate = link->preferred_link_setting.link_rate; struct dc_link_settings current_link_setting = initial_link_setting; uint32_t link_bw; @@ -752,6 +750,9 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting if (req_bw > dp_link_bandwidth_kbps(link, &link->verified_link_cap)) return false; + if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) + initial_link_setting.link_rate = link->preferred_link_setting.link_rate; + /* search for the minimum link setting that: * 1. is supported according to the link training result * 2. could support the b/w requested by the timing -- cgit v1.2.3 From 1e65171a1daccaf2b37c8b1b2f9df71e550e75c8 Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 27 Mar 2026 18:54:22 -0500 Subject: drm/amd/display: Promote DC to 3.2.377 This version brings along the following updates: - Enable sink freesync via MCCS with pcon whitelist adjustments - Rework YCbCr422 DSC policy - Update DML2.1 parameters - Fix coding style issues and compiler warnings Reviewed-by: Leo Li Signed-off-by: Taimur Hassan Signed-off-by: Roman Li Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7d170eaeb163..5267f1a9473b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -63,7 +63,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.376" +#define DC_VER "3.2.377" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC -- cgit v1.2.3 From 1fd0c5c91e1c735edd6714e2269a7c734ab895b7 Mon Sep 17 00:00:00 2001 From: Roman Li Date: Thu, 9 Apr 2026 13:37:36 -0400 Subject: drm/amd/display: Remove redundant includes from DC [Why] The explicit include of linux/array_size.h in Display Core (DC) is redundant. The ARRAY_SIZE macro is already provided by dm_services.h (via os_types.h) which DC includes. [How] Remove the unnecessary #include from dc_hw_sequencer.c and dce_clock_source.c. Fixes: 2d2366176445 ("drm/amd/display: Replace inline NUM_ELEMENTS macro with ARRAY_SIZE") CC: Linus Probert Signed-off-by: Roman Li Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 2 -- drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 952968ecd46e..7333f5905330 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -23,8 +23,6 @@ * */ -#include - #include "dm_services.h" #include "core_types.h" #include "timing_generator.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 71a876e3dfd4..25c13822fede 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -23,8 +23,6 @@ * */ -#include - #include "dm_services.h" -- cgit v1.2.3 From 7949927ad03c70582c21436442eef30269869732 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Thu, 9 Apr 2026 07:11:48 +0530 Subject: drm/amd/display: Add missing do_mccs parameter description Add missing description for do_mccs parameter in amdgpu_dm_update_freesync_caps. Fixes the below with gcc W=1: ../display/amdgpu_dm/amdgpu_dm.c:13269 function parameter 'do_mccs' not described in 'amdgpu_dm_update_freesync_caps' Fixes: 8dc88c6a5948 ("drm/amd/display: Avoid to do MCCS transaction if unnecessary") Cc: Harry Wentland Cc: Wayne Lin Cc: Roman Li Cc: Alex Hung Cc: Tom Chung Cc: Aurabindo Pillai Signed-off-by: Srinivasan Shanmugam Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 70ee26c68d4e..f69a7e88546a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -13263,6 +13263,10 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, * * @connector: Connector to query. * @drm_edid: DRM EDID from monitor + * @do_mccs: Controls whether MCCS (Monitor Control Command Set) over + * DDC (Display Data Channel) transactions are performed. When true, + * the driver queries the monitor to get or update additional FreeSync + * capability information. When false, these transactions are skipped. * * Amdgpu supports Freesync in DP and HDMI displays, and it is required to keep * track of some of the display information in the internal data struct used by -- cgit v1.2.3 From 17edfa32f1496df914b355cf7c0711a481765446 Mon Sep 17 00:00:00 2001 From: Ray Wu Date: Tue, 7 Apr 2026 16:24:39 +0800 Subject: drm/amd/display: fix NULL ptr deref in ISM delayed work dc_destroy() sets dm->dc to NULL before amdgpu_dm_ism_fini() is called, leaving a window where in-flight ISM delayed work dereferences the stale pointer. Call amdgpu_dm_ism_fini() in amdgpu_dm_fini() before dc_destroy(). Fixes: 754003486c3c ("drm/amd/display: Add Idle state manager(ISM)") Reviewed-by: Leo Li Signed-off-by: Ray Wu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 +++++++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f69a7e88546a..f4be2724471d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2239,6 +2239,8 @@ static int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block) static void amdgpu_dm_fini(struct amdgpu_device *adev) { int i; + struct drm_crtc *crtc; + struct amdgpu_crtc *acrtc; if (adev->dm.vblank_control_workqueue) { destroy_workqueue(adev->dm.vblank_control_workqueue); @@ -2255,6 +2257,13 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) adev->dm.idle_workqueue = NULL; } + /* Finalize ISM for each CRTC before dc_destroy() sets dm->dc to NULL */ + drm_for_each_crtc(crtc, adev_to_drm(adev)) { + acrtc = to_amdgpu_crtc(crtc); + amdgpu_dm_ism_fini(&acrtc->ism); + + } + amdgpu_dm_destroy_drm_device(&adev->dm); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 5d2715f78314..d69f5a75b685 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -457,9 +457,12 @@ static struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *cr static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc) { - struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + /* + * amdgpu_dm_ism_fini() is intentionally called in amdgpu_dm_fini(). + * It must be called before dc_destroy() in amdgpu_dm_fini() + * to avoid ISM accessing an invalid dc handle once dc is released. + */ - amdgpu_dm_ism_fini(&acrtc->ism); drm_crtc_cleanup(crtc); kfree(crtc); } -- cgit v1.2.3 From 82f510ae5ac8b8ff7cfd757aab1ff0fc4f22aed0 Mon Sep 17 00:00:00 2001 From: Gaghik Khachatrian Date: Fri, 20 Mar 2026 16:57:35 -0400 Subject: drm/amd/display: Fix compiler warnings [Why] Implicit conversions from wider integer types to byte-sized fields were generating compiler warnings. These warnings hide intentional protocol /storage boundaries and reduce signal quality during builds. Making conversion intent explicit improves readability and warning hygiene without changing behavior. [How] Added explicit, type-safe casts at intentional narrow-storage boundaries. Kept data models & runtime logic unchanged, only clarifying conversion intent. Functionality and behavior is unchanged; only type intent is explicit. Aligned warning cleanup with existing coding standards for explicit boundary conversions. Reviewed-by: Aric Cyr Signed-off-by: Gaghik Khachatrian Signed-off-by: Aurabindo Pillai Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 8 +++++--- drivers/gpu/drm/amd/display/dc/dc_stream.h | 4 ++-- drivers/gpu/drm/amd/display/dc/dc_types.h | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 5267f1a9473b..c94e532ac4a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1061,9 +1061,11 @@ struct dc_debug_options { bool hdmi20_disable; bool skip_detection_link_training; uint32_t edid_read_retry_times; - unsigned int force_odm_combine; //bit vector based on otg inst - unsigned int seamless_boot_odm_combine; - unsigned int force_odm_combine_4to1; //bit vector based on otg inst + + uint8_t force_odm_combine; //bit vector based on otg inst + uint8_t seamless_boot_odm_combine; + uint8_t force_odm_combine_4to1; //bit vector based on otg inst + int minimum_z8_residency_time; int minimum_z10_residency_time; bool disable_z9_mpc; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 86394203cee7..7c38fa6f8cb1 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -162,13 +162,13 @@ struct test_pattern { #define SUBVP_DRR_MARGIN_US 100 // 100us for DRR margin (SubVP + DRR) struct dc_stream_debug_options { - char force_odm_combine_segments; + uint8_t force_odm_combine_segments; /* * When force_odm_combine_segments is non zero, allow dc to * temporarily transition to ODM bypass when minimal transition state * is required to prevent visual glitches showing on the screen */ - char allow_transition_for_forced_odm; + uint8_t allow_transition_for_forced_odm; }; #define LUMINANCE_DATA_TABLE_SIZE 10 diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 7672ee88be82..c08d5c005df6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -205,7 +205,7 @@ struct dc_edid_caps { uint32_t audio_latency; uint32_t video_latency; - unsigned int freesync_vcp_code; + unsigned char freesync_vcp_code; uint8_t qs_bit; uint8_t qy_bit; -- cgit v1.2.3 From d3a549f4df7864bca8612c8bcfce1ec72b2874fb Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Tue, 24 Mar 2026 20:03:25 -0600 Subject: drm/amd/display: Use overlay cursor when color pipeline is active Force overlay cursor mode when an underlying plane has a non-bypassed color pipeline to avoid incorrect cursor transformation. Reviewed-by: Sun peng (Leo) Li Signed-off-by: Alex Hung Signed-off-by: Aurabindo Pillai Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 53 +++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f4be2724471d..1ecac2174119 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -95,6 +95,7 @@ #include #include #include +#include #include #include @@ -12338,6 +12339,38 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm * available. */ +/** + * dm_plane_color_pipeline_active() - Check if a plane's color pipeline active. + * @state: DRM atomic state + * @plane: DRM plane to check + * @use_old: if true, inspect the old colorop states; otherwise the new ones + * + * A color pipeline may be selected (color_pipeline != NULL) but still is + * inactive if every colorop in the chain is bypassed. Only return + * true when at least one colorop has bypass == false, meaning the cursor + * would be subjected to the transformation in native mode. + * + * Return: true if the pipeline modifies pixels, false otherwise. + */ +static bool dm_plane_color_pipeline_active(struct drm_atomic_state *state, + struct drm_plane *plane, + bool use_old) +{ + struct drm_colorop *colorop; + struct drm_colorop_state *old_colorop_state, *new_colorop_state; + int i; + + for_each_oldnew_colorop_in_state(state, colorop, old_colorop_state, new_colorop_state, i) { + struct drm_colorop_state *cstate = use_old ? old_colorop_state : new_colorop_state; + + if (cstate->colorop->plane != plane) + continue; + if (!cstate->bypass) + return true; + } + return false; +} + /** * dm_crtc_get_cursor_mode() - Determine the required cursor mode on crtc * @adev: amdgpu device @@ -12349,8 +12382,8 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm * the dm_crtc_state. * * The cursor should be enabled in overlay mode if there exists an underlying - * plane - on which the cursor may be blended - that is either YUV formatted, or - * scaled differently from the cursor. + * plane - on which the cursor may be blended - that is either YUV formatted, + * scaled differently from the cursor, or has a color pipeline active. * * Since zpos info is required, drm_atomic_normalize_zpos must be called before * calling this function. @@ -12388,7 +12421,7 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev, /* * Cursor mode can change if a plane's format changes, scale changes, is - * enabled/disabled, or z-order changes. + * enabled/disabled, z-order changes, or color management properties change. */ for_each_oldnew_plane_in_state(state, plane, old_plane_state, plane_state, i) { int new_scale_w, new_scale_h, old_scale_w, old_scale_h; @@ -12413,6 +12446,12 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev, consider_mode_change = true; break; } + + if (dm_plane_color_pipeline_active(state, plane, true) != + dm_plane_color_pipeline_active(state, plane, false)) { + consider_mode_change = true; + break; + } } if (!consider_mode_change && !crtc_state->zpos_changed) @@ -12453,6 +12492,12 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev, return 0; } + /* Underlying plane has an active color pipeline - cursor would be transformed */ + if (dm_plane_color_pipeline_active(state, plane, false)) { + *cursor_mode = DM_CURSOR_OVERLAY_MODE; + return 0; + } + dm_get_plane_scale(plane_state, &underlying_scale_w, &underlying_scale_h); dm_get_plane_scale(cursor_state, @@ -12832,7 +12877,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; } else if (required_cursor_mode == DM_CURSOR_OVERLAY_MODE) { drm_dbg_driver(crtc->dev, - "[CRTC:%d:%s] Cannot enable native cursor due to scaling or YUV restrictions\n", + "[CRTC:%d:%s] Cannot enable native cursor due to scaling, YUV, or color pipeline restrictions\n", crtc->base.id, crtc->name); ret = -EINVAL; goto fail; -- cgit v1.2.3 From 2b104fc31be0607c04188fadbd4a9fa5b50f3b99 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 26 Mar 2026 12:00:34 -0400 Subject: drm/amd/display: fix math_mod() using arg1 instead of arg2 [Why] math_mod() multiplied by arg1 instead of arg2, returning a wrong result for any non-trivial modulo operation. [How] Replace arg1 with arg2 in the subtraction term to correctly implement fmod(arg1, arg2). Cc: Mario Limonciello Cc: Alex Deucher Cc: stable@vger.kernel.org Reviewed-by: Dillon Varone Signed-off-by: Wenjing Liu Signed-off-by: Aurabindo Pillai Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.c index e17b5ceba447..dc5bc649f3ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.c @@ -23,7 +23,7 @@ double math_mod(const double arg1, const double arg2) return arg2; if (isNaN(arg2)) return arg1; - return arg1 - arg1 * ((int)(arg1 / arg2)); + return arg1 - arg2 * ((int)(arg1 / arg2)); } double math_min2(const double arg1, const double arg2) -- cgit v1.2.3 From dd2308c1d007d7a3416c02e542abdc6acc23966d Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 26 Mar 2026 17:13:27 -0400 Subject: drm/amd/display: add const qualifiers to watermark params struct [why] There are few non const input pointer fields. Setting them to const to prevent future modification of read-only data. Reviewed-by: Dillon Varone Signed-off-by: Wenjing Liu Signed-off-by: Aurabindo Pillai Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dml21/src/dml2_core/dml2_core_shared_types.h | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h index 41d0c99d0864..987b29808ca4 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h @@ -1721,30 +1721,30 @@ struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_param double ReturnBW; bool SynchronizeTimings; bool SynchronizeDRRDisplaysForUCLKPStateChange; - unsigned int *dpte_group_bytes; + const unsigned int *dpte_group_bytes; struct dml2_core_internal_SOCParametersList mmSOCParameters; unsigned int WritebackChunkSize; double SOCCLK; double DCFClkDeepSleep; - unsigned int *DETBufferSizeY; - unsigned int *DETBufferSizeC; - unsigned int *SwathHeightY; - unsigned int *SwathHeightC; - unsigned int *SwathWidthY; - unsigned int *SwathWidthC; - unsigned int *DPPPerSurface; - double *BytePerPixelDETY; - double *BytePerPixelDETC; - unsigned int *DSTXAfterScaler; - unsigned int *DSTYAfterScaler; + const unsigned int *DETBufferSizeY; + const unsigned int *DETBufferSizeC; + const unsigned int *SwathHeightY; + const unsigned int *SwathHeightC; + const unsigned int *SwathWidthY; + const unsigned int *SwathWidthC; + const unsigned int *DPPPerSurface; + const double *BytePerPixelDETY; + const double *BytePerPixelDETC; + const unsigned int *DSTXAfterScaler; + const unsigned int *DSTYAfterScaler; bool UnboundedRequestEnabled; unsigned int CompressedBufferSizeInkByte; bool max_outstanding_when_urgent_expected; - unsigned int max_outstanding_requests; - unsigned int max_request_size_bytes; - unsigned int *meta_row_height_l; - unsigned int *meta_row_height_c; - enum dml2_pstate_method *uclk_pstate_switch_modes; + const unsigned int max_outstanding_requests; + const unsigned int max_request_size_bytes; + const unsigned int *meta_row_height_l; + const unsigned int *meta_row_height_c; + const enum dml2_pstate_method *uclk_pstate_switch_modes; // Output struct dml2_core_internal_watermarks *Watermark; -- cgit v1.2.3 From 8d7d0fd7db2c4435dcb3b5f21100c29286ee8b4c Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 26 Mar 2026 17:39:28 -0400 Subject: drm/amd/display: add pstate schedule admissibility flags and frame-time utility [Why] Core needs to track pstate schedule admissibility for different global change scenarios (fclk, temp read, PPT) and requires a reusable way to compute per-stream frame time from timing parameters. [How] Extend dml2_core_internal_mode_support_info with: fclk_pstate_schedule_admissible temp_read_pstate_schedule_admissible ppt_pstate_schedule_admissible Add dummy_double_array[3][DML2_MAX_PLANES] to dml2_core_calcs_mode_support_locals. Introduce dml2_core_utils_get_frame_time_us() in dml2_core_utils.c and export it in dml2_core_utils.h to compute frame time in microseconds from stream timing (vline time * (vactive + vblank)). Reviewed-by: Dillon Varone Signed-off-by: Wenjing Liu Signed-off-by: Aurabindo Pillai Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h | 5 +++++ .../amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c | 8 ++++++++ .../amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h | 1 + 3 files changed, 14 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h index 987b29808ca4..080bc3c3d244 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h @@ -269,6 +269,9 @@ struct dml2_core_internal_mode_support_info { bool global_dram_clock_change_supported; bool global_fclk_change_supported; bool global_temp_read_or_ppt_supported; + bool fclk_pstate_schedule_admissible; + bool temp_read_pstate_schedule_admissible; + bool ppt_pstate_schedule_admissible; bool USRRetrainingSupport; bool AvgBandwidthSupport; bool UrgVactiveBandwidthSupport; @@ -1063,6 +1066,8 @@ struct dml2_core_calcs_mode_support_locals { bool dummy_boolean_array[2][DML2_MAX_PLANES]; double dummy_single[3]; double dummy_single_array[DML2_MAX_PLANES]; + double dummy_double_array[3][DML2_MAX_PLANES]; + enum dml2_pstate_method dummy_pstate_method_array[DML2_MAX_PLANES]; struct dml2_core_internal_watermarks dummy_watermark; double dummy_bw[dml2_core_internal_soc_state_max][dml2_core_internal_bw_max]; double surface_dummy_bw[dml2_core_internal_soc_state_max][dml2_core_internal_bw_max][DML2_MAX_PLANES]; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c index 5dc846802c53..4f5533dc0430 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.c @@ -786,3 +786,11 @@ bool dml2_core_utils_is_odm_split(enum dml2_odm_mode odm_mode) return false; } } + +double dml2_core_utils_get_frame_time_us(const struct dml2_stream_parameters *stream) +{ + double otg_vline_time_us = (double)stream->timing.h_total / (double)stream->timing.pixel_clock_khz * 1000.0; + double non_vtotal = stream->timing.vblank_nom + stream->timing.v_active; + double frame_time_us = non_vtotal * otg_vline_time_us; + return frame_time_us; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h index 95f0d017add4..60fa2abfef85 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.h @@ -39,5 +39,6 @@ bool dml2_core_utils_is_hpo_dp_encoder(const struct dml2_stream_parameters *stre bool dml2_core_utils_is_dp_8b_10b_link_rate(enum dml2_output_link_dp_rate rate); bool dml2_core_utils_is_dp_128b_132b_link_rate(enum dml2_output_link_dp_rate rate); bool dml2_core_utils_is_odm_split(enum dml2_odm_mode odm_mode); +double dml2_core_utils_get_frame_time_us(const struct dml2_stream_parameters *stream); #endif /* __DML2_CORE_UTILS_H__ */ -- cgit v1.2.3 From b5245cbe44115d2eb14c2c273771211e1b170c41 Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 3 Apr 2026 04:34:51 -0500 Subject: drm/amd/display: Promote DC to 3.2.378 DC v3.2.378 summary: New: - Add p-state schedule admissibility flags and frame-time utility Fixes: - Fixed incorrect math_mod() result due to wrong variable in fmod implementation (Cc: stable) - Use overlay cursor when a color pipeline is active to avoid incorrect rendering Cleanups: - Add const qualifiers to watermark params struct - Fix narrowing-conversion compiler warnings Signed-off-by: Taimur Hassan Signed-off-by: Aurabindo Pillai Reviewed-by: Alex Hung Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index c94e532ac4a4..7f55ba09b191 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -63,7 +63,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.377" +#define DC_VER "3.2.378" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC -- cgit v1.2.3 From 0f6d7ec4f1b4febd3f9c6ab39efc25a7cb922cab Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Sat, 11 Apr 2026 21:35:39 +0530 Subject: drm/amdgpu: Clear cached EDID pointer after drm_edid_free() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver stores EDID in amdgpu_connector->edid and uses it as a cache. amdgpu_connector_get_edid() checks this pointer. If it is not NULL, it assumes EDID is already present and does not read it again. In some detect paths, the driver frees the EDID using drm_edid_free(), but does not set the pointer to NULL. Because of this, the pointer still looks valid even though the memory is already freed. Later, when amdgpu_connector_get_edid() is called, it returns early and does not read a new EDID. This can lead to using a freed pointer. Fix this by setting amdgpu_connector->edid = NULL after drm_edid_free(). This makes sure the driver reads a fresh EDID and does not use invalid memory. Fixes: 71036457ad85 ("drm/amdgpu/amdgpu_connectors: remove amdgpu_connector_free_edid") Reported-by: Dan Carpenter Cc: Joshua Peisach Cc: Alex Deucher Cc: Christian König Signed-off-by: Srinivasan Shanmugam Reviewed-by: Joshua Peisach Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index b04fa9fd90b7..92c98e999efe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -866,6 +866,7 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) if (dret) { amdgpu_connector->detected_by_load = false; drm_edid_free(amdgpu_connector->edid); + amdgpu_connector->edid = NULL; amdgpu_connector_get_edid(connector); if (!amdgpu_connector->edid) { @@ -882,6 +883,7 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) */ if (amdgpu_connector->use_digital && amdgpu_connector->shared_ddc) { drm_edid_free(amdgpu_connector->edid); + amdgpu_connector->edid = NULL; ret = connector_status_disconnected; } else { ret = connector_status_connected; @@ -977,6 +979,7 @@ static void amdgpu_connector_shared_ddc(enum drm_connector_status *status, if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { drm_edid_free(amdgpu_connector->edid); + amdgpu_connector->edid = NULL; *status = connector_status_disconnected; } } @@ -1046,6 +1049,7 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) if (dret) { amdgpu_connector->detected_by_load = false; drm_edid_free(amdgpu_connector->edid); + amdgpu_connector->edid = NULL; amdgpu_connector_get_edid(connector); if (!amdgpu_connector->edid) { @@ -1062,6 +1066,7 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) */ if ((!amdgpu_connector->use_digital) && amdgpu_connector->shared_ddc) { drm_edid_free(amdgpu_connector->edid); + amdgpu_connector->edid = NULL; ret = connector_status_disconnected; } else { ret = connector_status_connected; @@ -1412,6 +1417,7 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) } drm_edid_free(amdgpu_connector->edid); + amdgpu_connector->edid = NULL; if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { -- cgit v1.2.3 From 07598c76964a2c73702fa652bcd07ec21088c5ef Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Wed, 8 Apr 2026 15:01:27 +0800 Subject: drm/amd/display: Fix fpu guard warning [Why] Due to improper fpu guarding, we encounter this warning during boot up: [ 10.027021] WARNING: drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/dc_fpu.c:58 at dc_assert_fp_enabled+0x12/0x20 [amdgpu], CPU#8: (udev-worker)/469 [ 10.027644] Modules linked in: binfmt_misc snd_ctl_led nls_iso8859_1 intel_rapl_msr amd_atl intel_rapl_common amdgpu(+) snd_acp_legacy_mach snd_acp_mach snd_soc_nau8821 snd_acp3x_pdm_dma snd_acp3x_rn snd_soc_dmic snd_sof_amd_acp63 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_hda_codec_alc269 snd_sof_xtensa_dsp snd_hda_scodec_component snd_hda_codec_realtek_lib snd_sof snd_hda_codec_generic snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi soundwire_amd snd_hda_codec_atihdmi soundwire_generic_allocation snd_hda_codec_hdmi soundwire_bus snd_soc_sdca edac_mce_amd snd_hda_intel snd_soc_core snd_hda_codec kvm_amd snd_compress snd_hda_core ac97_bus ee1004 amdxcp snd_pcm_dmaengine snd_intel_dspcfg snd_intel_sdw_acpi kvm drm_panel_backlight_quirks snd_rpl_pci_acp6x gpu_sched snd_hwdep snd_acp_pci irqbypass snd_amd_acpi_mach drm_buddy snd_acp_legacy_common snd_seq_midi ghash_clmulni_intel drm_ttm_helper aesni_intel snd_seq_midi_event snd_pci_acp6x joydev rapl [ 10.027750] snd_pcm snd_rawmidi ttm snd_seq snd_pci_acp5x drm_exec drm_suballoc_helper snd_seq_device wmi_bmof snd_rn_pci_acp3x drm_display_helper snd_timer snd_acp_config cec snd_soc_acpi snd rc_core i2c_piix4 ccp snd_pci_acp3x i2c_smbus soundcore k10temp i2c_algo_bit spi_amd cdc_mbim input_leds cdc_wdm mac_hid sch_fq_codel msr parport_pc ppdev lp parport efi_pstore nfnetlink dmi_sysfs autofs4 cdc_ncm cdc_ether usbnet mii hid_logitech_hidpp hid_logitech_dj hid_generic nvme nvme_core ahci serio_raw nvme_keyring usbhid ucsi_acpi amd_xgbe nvme_auth libahci hkdf typec_ucsi video typec wmi i2c_hid_acpi i2c_hid hid [ 10.027853] CPU: 8 UID: 0 PID: 469 Comm: (udev-worker) Not tainted 6.19.0asdn-260408-asdn #1 PREEMPT(voluntary) [ 10.027858] Hardware name: AMD Crater-RN/Crater-RN, BIOS TCR1004A 03/12/2024 [ 10.027861] RIP: 0010:dc_assert_fp_enabled+0x12/0x20 [amdgpu] [ 10.028416] Code: 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 65 8b 05 39 79 cc c4 85 c0 7e 07 31 c0 e9 9e 75 2a c3 <0f> 0b 31 c0 e9 95 75 2a c3 0f 1f 44 00 00 90 90 90 90 90 90 90 90 [ 10.028420] RSP: 0018:ffffcca10188b348 EFLAGS: 00010246 [ 10.028425] RAX: 0000000000000000 RBX: ffff88c6077f8000 RCX: 0000000000000000 [ 10.028428] RDX: ffff88c607d0e400 RSI: ffffffffc204d860 RDI: ffff88c624c00000 [ 10.028430] RBP: ffffcca10188b3e8 R08: ffff88c624c35c88 R09: 0000000000000000 [ 10.028433] R10: 0000000000000000 R11: 0000000000000000 R12: ffffcca10188b548 [ 10.028435] R13: ffff88c60be5bd00 R14: ffffffffc204d860 R15: ffff88c624c00000 [ 10.028438] FS: 00007c80c2432980(0000) GS:ffff88cdc7464000(0000) knlGS:0000000000000000 [ 10.028441] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 10.028443] CR2: 00007866ae013da8 CR3: 000000010a511000 CR4: 0000000000350ef0 [ 10.028446] Call Trace: [ 10.028449] [ 10.028452] ? dcn21_update_bw_bounding_box+0x38/0xb30 [amdgpu] [ 10.028991] ? srso_return_thunk+0x5/0x5f [ 10.029001] dc_create+0x37c/0x730 [amdgpu] [ 10.029505] ? srso_return_thunk+0x5/0x5f [ 10.029512] amdgpu_dm_init+0x374/0x2ff0 [amdgpu] [ 10.030053] ? srso_return_thunk+0x5/0x5f [ 10.030057] ? __irq_work_queue_local+0x61/0xe0 [ 10.030063] ? srso_return_thunk+0x5/0x5f [ 10.030067] ? irq_work_queue+0x2f/0x70 [ 10.030071] ? srso_return_thunk+0x5/0x5f [ 10.030075] ? __wake_up_klogd+0x75/0xa0 [ 10.030081] ? srso_return_thunk+0x5/0x5f [ 10.030085] ? vprintk_emit+0x35b/0x3f0 [ 10.030102] dm_hw_init+0x1c/0x110 [amdgpu] [ 10.030625] amdgpu_device_init+0x23e8/0x3210 [amdgpu] [ 10.031041] ? pci_read+0x55/0x90 [ 10.031047] ? srso_return_thunk+0x5/0x5f [ 10.031051] ? pci_read_config_word+0x27/0x50 [ 10.031057] ? srso_return_thunk+0x5/0x5f [ 10.031061] ? do_pci_enable_device+0x155/0x180 [ 10.031068] amdgpu_driver_load_kms+0x1a/0xd0 [amdgpu] [ 10.031486] amdgpu_pci_probe+0x28c/0x6f0 [amdgpu] [ 10.031902] local_pci_probe+0x47/0xb0 [ 10.031908] pci_device_probe+0xf3/0x270 [ 10.031914] really_probe+0xf1/0x410 [ 10.031920] __driver_probe_device+0x8c/0x190 [ 10.031924] driver_probe_device+0x24/0xd0 [ 10.031928] __driver_attach+0x10b/0x240 [ 10.031932] ? __pfx___driver_attach+0x10/0x10 [ 10.031936] bus_for_each_dev+0x8c/0xf0 [ 10.031942] driver_attach+0x1e/0x30 [ 10.031947] bus_add_driver+0x160/0x2a0 [ 10.031952] driver_register+0x5e/0x130 [ 10.031957] ? __pfx_amdgpu_init+0x10/0x10 [amdgpu] [ 10.032361] __pci_register_driver+0x5e/0x70 [ 10.032366] amdgpu_init+0x5d/0xff0 [amdgpu] [ 10.032768] ? srso_return_thunk+0x5/0x5f [ 10.032773] do_one_initcall+0x5d/0x340 [ 10.032783] do_init_module+0x97/0x2c0 [ 10.032788] load_module+0x2b49/0x2c30 [ 10.032800] init_module_from_file+0xf4/0x120 [ 10.032804] ? init_module_from_file+0xf4/0x120 [ 10.032813] idempotent_init_module+0x10f/0x300 [ 10.032820] __x64_sys_finit_module+0x73/0xf0 [ 10.032824] ? srso_return_thunk+0x5/0x5f [ 10.032829] x64_sys_call+0x1d68/0x26b0 [ 10.032834] do_syscall_64+0x81/0x500 [ 10.032839] ? srso_return_thunk+0x5/0x5f [ 10.032843] ? do_syscall_64+0x2e5/0x500 [ 10.032848] ? srso_return_thunk+0x5/0x5f [ 10.032852] ? native_flush_tlb_global+0x95/0xb0 [ 10.032860] ? srso_return_thunk+0x5/0x5f [ 10.032864] ? __flush_tlb_all+0x13/0x60 [ 10.032870] ? srso_return_thunk+0x5/0x5f [ 10.032874] ? do_flush_tlb_all+0xe/0x20 [ 10.032879] ? srso_return_thunk+0x5/0x5f [ 10.032882] ? __flush_smp_call_function_queue+0x9c/0x430 [ 10.032888] ? srso_return_thunk+0x5/0x5f [ 10.032897] ? irqentry_exit+0xb2/0x740 [ 10.032901] ? srso_return_thunk+0x5/0x5f [ 10.032906] ? srso_return_thunk+0x5/0x5f [ 10.032911] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 10.032915] RIP: 0033:0x7c80c1d3490d [ 10.032920] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d3 f4 0f 00 f7 d8 64 89 01 48 [ 10.032923] RSP: 002b:00007fff3a12fe28 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 10.032928] RAX: ffffffffffffffda RBX: 00005c44096804f0 RCX: 00007c80c1d3490d [ 10.032930] RDX: 0000000000000000 RSI: 00005c4409681690 RDI: 000000000000002b [ 10.032933] RBP: 00007fff3a12fec0 R08: 0000000000000000 R09: 00005c4409681790 [ 10.032935] R10: 0000000000000000 R11: 0000000000000246 R12: 00005c4409681690 [ 10.032937] R13: 0000000000020000 R14: 00005c44094ff7f0 R15: 00005c4409681690 [ 10.032945] [ 10.032948] ---[ end trace 0000000000000000 ]--- [How] Add wrapper function to guard fpu properly for dcn21/dcn31/dcn315/dcn316. Fixes: 3539437f354b ("drm/amd/display: Move FPU Guards From DML To DC - Part 1") Reviewed-by: Dillon Varone Reviewed-by: Rafal Ostrowski Signed-off-by: Wayne Lin Signed-off-by: Chenyu Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 2 +- drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h | 2 +- drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c | 6 +++--- drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h | 6 +++--- drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c | 7 +++++++ drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c | 7 +++++++ drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c | 7 +++++++ drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c | 7 +++++++ 8 files changed, 36 insertions(+), 8 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 887744d56d6a..e82f2d531211 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -2399,7 +2399,7 @@ static struct _vcs_dpi_voltage_scaling_st construct_low_pstate_lvl(struct clk_li return low_pstate_lvl; } -void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +void dcn21_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params) { struct _vcs_dpi_voltage_scaling_st *s = dc->scratch.update_bw_bounding_box.clock_limits; struct dcn21_resource_pool *pool = TO_DCN21_RES_POOL(dc->res_pool); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h index aed00039ca62..8b2226c5bbbf 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h @@ -78,7 +78,7 @@ int dcn21_populate_dml_pipes_from_context(struct dc *dc, enum dc_validate_mode validate_mode); bool dcn21_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, enum dc_validate_mode, display_e2e_pipe_params_st *pipes); -void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); +void dcn21_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params); void dcn21_clk_mgr_set_bw_params_wm_table(struct clk_bw_params *bw_params); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c index 1a28061bb9ff..ad23215da9f8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c @@ -587,7 +587,7 @@ void dcn31_calculate_wm_and_dlg_fp( context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - total_det; } -void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +void dcn31_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params) { struct _vcs_dpi_voltage_scaling_st *s = dc->scratch.update_bw_bounding_box.clock_limits; struct clk_limit_table *clk_table = &bw_params->clk_table; @@ -665,7 +665,7 @@ void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31); } -void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +void dcn315_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params) { struct clk_limit_table *clk_table = &bw_params->clk_table; int i, max_dispclk_mhz = 0, max_dppclk_mhz = 0; @@ -726,7 +726,7 @@ void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param dml_init_instance(&dc->dml, &dcn3_15_soc, &dcn3_15_ip, DML_PROJECT_DCN315); } -void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +void dcn316_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params) { struct _vcs_dpi_voltage_scaling_st *s = dc->scratch.update_bw_bounding_box.clock_limits; struct clk_limit_table *clk_table = &bw_params->clk_table; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h index dfcc5d50071e..0b7fcbbfd17b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h @@ -44,9 +44,9 @@ void dcn31_calculate_wm_and_dlg_fp( int pipe_cnt, int vlevel); -void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); -void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); -void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); +void dcn31_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params); +void dcn315_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params); +void dcn316_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params); int dcn_get_max_non_odm_pix_rate_100hz(struct _vcs_dpi_soc_bounding_box_st *soc); int dcn_get_approx_det_segs_required_for_pstate( struct _vcs_dpi_soc_bounding_box_st *soc, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c index 54ebf8cf607f..84f6d9dc443f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -1394,6 +1394,13 @@ static enum dc_status dcn21_patch_unknown_plane_state(struct dc_plane_state *pla return dcn20_patch_unknown_plane_state(plane_state); } +static void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn21_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} + static const struct resource_funcs dcn21_res_pool_funcs = { .destroy = dcn21_destroy_resource_pool, .link_enc_create = dcn21_link_encoder_create, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 07dfb65d6eb9..39944d90ea98 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -1854,6 +1854,13 @@ static struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn20_get_dcc_compression_cap }; +static void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn31_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} + static struct resource_funcs dcn31_res_pool_funcs = { .destroy = dcn31_destroy_resource_pool, .link_enc_create = dcn31_link_encoder_create, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index 9a1bbec1d815..975e14f3f5fa 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -1849,6 +1849,13 @@ static struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn20_get_dcc_compression_cap }; +static void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn315_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} + static struct resource_funcs dcn315_res_pool_funcs = { .destroy = dcn315_destroy_resource_pool, .link_enc_create = dcn31_link_encoder_create, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c index 2242df112a3f..914d91df174c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c @@ -1725,6 +1725,13 @@ static struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn20_get_dcc_compression_cap }; +static void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn316_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} + static struct resource_funcs dcn316_res_pool_funcs = { .destroy = dcn316_destroy_resource_pool, .link_enc_create = dcn31_link_encoder_create, -- cgit v1.2.3 From 8bf0cb97edb697dba2515e6452c17c5245111448 Mon Sep 17 00:00:00 2001 From: Rafal Ostrowski Date: Fri, 10 Apr 2026 09:09:57 +0200 Subject: drm/amd/display: Move dml2_destroy to non-FPU compilation unit On PREEMPT_RT kernels, vfree() can sleep because spin_lock is converted to rt_mutex. dml2_destroy() calls vfree() while inside an FPU-guarded region (preempt_count=2), which is illegal. dml2_wrapper_fpu.c is compiled with CC_FLAGS_FPU which defines _LINUX_FPU_COMPILATION_UNIT, making DC_RUN_WITH_PREEMPTION_ENABLED() resolve to a no-op. This prevents the macro from cycling FPU context off/on around vfree(). Move dml2_destroy() to dml2_wrapper.c (non-FPU compilation unit) where DC_RUN_WITH_PREEMPTION_ENABLED() properly cycles DC_FP_END/ DC_FP_START around vfree(). This pairs it with dml2_allocate_memory() which already lives there. Reviewed-by: Dillon Varone Signed-off-by: Rafal Ostrowski Signed-off-by: Chenyu Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c | 11 +++++++++++ drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c | 10 ---------- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c index 7398f8b69adb..8bed59e976d1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c @@ -58,8 +58,8 @@ bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const s void dml21_destroy(struct dml2_context *dml2) { - vfree(dml2->v21.dml_init.dml2_instance); - vfree(dml2->v21.mode_programming.programming); + DC_RUN_WITH_PREEMPTION_ENABLED(vfree(dml2->v21.dml_init.dml2_instance)); + DC_RUN_WITH_PREEMPTION_ENABLED(vfree(dml2->v21.mode_programming.programming)); } void dml21_copy(struct dml2_context *dst_dml_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c index 93b7613fc4f2..1772e74349c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c @@ -108,6 +108,17 @@ bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options return true; } +void dml2_destroy(struct dml2_context *dml2) +{ + if (!dml2) + return; + + if (dml2->architecture == dml2_architecture_21) + dml21_destroy(dml2); + + DC_RUN_WITH_PREEMPTION_ENABLED(vfree(dml2)); +} + void dml2_reinit(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c index 66624cfc27b1..a14e3004a7b7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c @@ -548,16 +548,6 @@ void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2) } } -void dml2_destroy(struct dml2_context *dml2) -{ - if (!dml2) - return; - - if (dml2->architecture == dml2_architecture_21) - dml21_destroy(dml2); - vfree(dml2); -} - void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2, unsigned int *fclk_change_support, unsigned int *dram_clk_change_support) { -- cgit v1.2.3 From 732a8adde033fb084f16409206b7d9ee9c3849c9 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Wed, 15 Apr 2026 06:33:33 +0530 Subject: drm/amd/display: Fix ISM teardown crash from NULL dc dereference The Idle State Manager (ISM) uses delayed work to apply display idle optimizations later, instead of immediately. This helps avoid rapid idle transitions that can hurt power or performance. A crash was seen during driver teardown. The system boots normally and the driver loads successfully. Later, when the GPU is being stopped, the log shows: amdgpu 0000:0e:00.0: finishing device. Workqueue: events_unbound dm_ism_sso_delayed_work_func [amdgpu] After this, delayed ISM work still runs and reaches: dm_ism_sso_delayed_work_func() -> amdgpu_dm_ism_commit_event() -> dm_ism_commit_idle_optimization_state() -> dc_allow_idle_optimizations_internal() The crash report showed: KASAN: null-ptr-deref in range [0x690-0x697] Signature: [22601.113316] KASAN: null-ptr-deref in range [0x0000000000000690-0x0000000000000697] ... [22601.113368] Workqueue: events_unbound dm_ism_sso_delayed_work_func [amdgpu] [22601.113930] RIP: 0010:dc_allow_idle_optimizations_internal+0xa6/0xc40 [amdgpu] ... [22601.114491] RDX: dffffc0000000000 RSI: 0000000000000000 RDI: 0000000000000690 ... [22601.114561] Call Trace: [22601.114566] [22601.114572] ? srso_alias_return_thunk+0x5/0xfbef5 [22601.114582] ? update_load_avg+0x1b6/0x20b0 [22601.114593] ? __pfx_dc_allow_idle_optimizations_internal+0x10/0x10 [amdgpu] [22601.114932] ? psi_group_change+0x4ed/0x8d0 [22601.114942] dm_ism_commit_idle_optimization_state+0x214/0x570 [amdgpu] [22601.115268] amdgpu_dm_ism_commit_event+0xe1d/0x15a0 [amdgpu] [22601.115588] ? srso_alias_return_thunk+0x5/0xfbef5 [22601.115595] ? __kasan_check_write+0x18/0x20 [22601.115603] ? srso_alias_return_thunk+0x5/0xfbef5 [22601.115610] ? mutex_lock+0x83/0xc0 [22601.115620] dm_ism_sso_delayed_work_func+0x64/0x90 [amdgpu] GDB resolved dc_allow_idle_optimizations_internal+0xa6 to: struct dc_state *context = dc->current_state; The matching disassembly showed: mov %rdi, %r12 mov 0x690(%r12), %r13 where r12 holds the dc pointer. A GDB layout dump of struct dc showed: /* 1680 | 8 */ struct dc_state *current_state; Since 1680 decimal is 0x690, this confirms that current_state is at offset 0x690. The faulting access was effectively: dc + 0x690 which indicates that dc was NULL at the time of dereference. This shows that ISM work can still run during teardown after dc has been cleared. ISM is not expected to run after dc is destroyed. Fix this by disabling ISM under dc_lock in amdgpu_dm_fini() before dc_destroy(), ensuring no further ISM work runs after dc teardown. Also add ASSERT(dm->dc) in amdgpu_dm_ism_commit_event() to enforce this invariant, and ASSERT(mutex_is_locked(&dm->dc_lock)) in amdgpu_dm_ism_disable() to clarify the locking requirement. Fixes: 754003486c3c ("drm/amd/display: Add Idle state manager(ISM)") Suggested-by: Leo Li Cc: Ray Wu Cc: Roman Li Cc: Alex Hung Cc: Tom Chung Cc: Harry Wentland Cc: Aurabindo Pillai Cc: Mario Limonciello (AMD) Signed-off-by: Srinivasan Shanmugam Reviewed-by: Leo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 11 +++-------- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c | 5 +++++ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 1ecac2174119..e96a12ff2d31 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2240,8 +2240,6 @@ static int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block) static void amdgpu_dm_fini(struct amdgpu_device *adev) { int i; - struct drm_crtc *crtc; - struct amdgpu_crtc *acrtc; if (adev->dm.vblank_control_workqueue) { destroy_workqueue(adev->dm.vblank_control_workqueue); @@ -2258,12 +2256,9 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) adev->dm.idle_workqueue = NULL; } - /* Finalize ISM for each CRTC before dc_destroy() sets dm->dc to NULL */ - drm_for_each_crtc(crtc, adev_to_drm(adev)) { - acrtc = to_amdgpu_crtc(crtc); - amdgpu_dm_ism_fini(&acrtc->ism); - - } + /* Disable ISM before dc_destroy() invalidates dm->dc */ + scoped_guard(mutex, &adev->dm.dc_lock) + amdgpu_dm_ism_disable(&adev->dm); amdgpu_dm_destroy_drm_device(&adev->dm); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c index a3ccb6fdc372..773943f65d6e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c @@ -472,6 +472,9 @@ void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism, /* ISM transitions must be called with mutex acquired */ ASSERT(mutex_is_locked(&dm->dc_lock)); + /* ISM should not run after dc is destroyed */ + ASSERT(dm->dc); + if (!acrtc_state) { trace_amdgpu_dm_ism_event(acrtc->crtc_id, "NO_STATE", "NO_STATE", "N/A"); @@ -545,6 +548,8 @@ void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm) struct amdgpu_crtc *acrtc; struct amdgpu_dm_ism *ism; + ASSERT(mutex_is_locked(&dm->dc_lock)); + drm_for_each_crtc(crtc, dm->ddev) { acrtc = to_amdgpu_crtc(crtc); ism = &acrtc->ism; -- cgit v1.2.3 From a7fe8c1b6cf0cd217a8d22609cf9e0c1fe26e873 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Wed, 8 Apr 2026 10:21:53 +0530 Subject: drm/amdgpu/userq: avoid uneccessary locking in amdgpu_userq_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorganise code to avoid holding mutex userq_mutex while also trying to grab exec lock ww_mutex where its not needed for function amdgpu_userq_input_va_validate Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index bfca5b040a32..b29484ecce9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -737,28 +737,17 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) return r; } - /* - * There could be a situation that we are creating a new queue while - * the other queues under this UQ_mgr are suspended. So if there is any - * resume work pending, wait for it to get done. - * - * This will also make sure we have a valid eviction fence ready to be used. - */ - amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); - uq_funcs = adev->userq_funcs[args->in.ip_type]; if (!uq_funcs) { drm_file_err(uq_mgr->file, "Usermode queue is not supported for this IP (%u)\n", args->in.ip_type); - r = -EINVAL; - goto unlock; + return -EINVAL; } queue = kzalloc_obj(struct amdgpu_usermode_queue); if (!queue) { drm_file_err(uq_mgr->file, "Failed to allocate memory for queue\n"); - r = -ENOMEM; - goto unlock; + return -ENOMEM; } INIT_LIST_HEAD(&queue->userq_va_list); @@ -797,6 +786,15 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) goto free_queue; } + /* + * There could be a situation that we are creating a new queue while + * the other queues under this UQ_mgr are suspended. So if there is any + * resume work pending, wait for it to get done. + * + * This will also make sure we have a valid eviction fence ready to be used. + */ + amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); + r = uq_funcs->mqd_create(queue, &args->in); if (r) { drm_file_err(uq_mgr->file, "Failed to create Queue\n"); @@ -858,11 +856,9 @@ clean_mqd: up_read(&adev->reset_domain->sem); clean_fence_driver: amdgpu_userq_fence_driver_free(queue); + mutex_unlock(&uq_mgr->userq_mutex); free_queue: kfree(queue); -unlock: - mutex_unlock(&uq_mgr->userq_mutex); - return r; } -- cgit v1.2.3 From dc87834e9a50fcad2de8c4be5a8912f40e9b9e9e Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Wed, 8 Apr 2026 10:35:05 +0530 Subject: drm/amdgpu/userq: clean the VA mapping list for failed queue creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the queue creation failed during mapping of the important VA's like queue_va, rptr_va and wptr_va. These needs to be cleaned as queue destroy will not be called for such queues as user never get call to creation failure. Signed-off-by: Sunil Khatri Acked-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index b29484ecce9b..bf152b636536 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -767,7 +767,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va, AMDGPU_GPU_PAGE_SIZE) || amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va, AMDGPU_GPU_PAGE_SIZE)) { r = -EINVAL; - goto free_queue; + goto clean_mapping; } /* Convert relative doorbell offset into absolute doorbell index */ @@ -775,7 +775,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) if (index == (uint64_t)-EINVAL) { drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n"); r = -EINVAL; - goto free_queue; + goto clean_mapping; } queue->doorbell_index = index; @@ -783,7 +783,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv); if (r) { drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n"); - goto free_queue; + goto clean_mapping; } /* @@ -857,7 +857,8 @@ clean_mqd: clean_fence_driver: amdgpu_userq_fence_driver_free(queue); mutex_unlock(&uq_mgr->userq_mutex); -free_queue: +clean_mapping: + amdgpu_userq_buffer_vas_list_cleanup(adev, queue); kfree(queue); return r; } -- cgit v1.2.3 From 1eb90c7403c4afae1d791a2671f4873fd8d44c34 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Wed, 8 Apr 2026 15:11:05 +0530 Subject: drm/amdgpu/userq: fix kerneldoc for amdgpu_userq_ensure_ev_fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the comment for the caller to the definition for amdgpu_userq_ensure_ev_fence in kerneldoc format. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index bf152b636536..33ffbf894801 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -460,6 +460,15 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue) up_read(&adev->reset_domain->sem); } +/** + * amdgpu_userq_ensure_ev_fence - ensure a valid, unsignaled eviction fence exists + * @uq_mgr: the usermode queue manager for this process + * @evf_mgr: the eviction fence manager to check and rearm + * + * Ensures that a valid and not yet signaled eviction fence is attached to the + * usermode queue before any queue operations proceed. If it is signalled, then + * rearm a new eviction fence. + */ void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_eviction_fence_mgr *evf_mgr) @@ -786,13 +795,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) goto clean_mapping; } - /* - * There could be a situation that we are creating a new queue while - * the other queues under this UQ_mgr are suspended. So if there is any - * resume work pending, wait for it to get done. - * - * This will also make sure we have a valid eviction fence ready to be used. - */ amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); r = uq_funcs->mqd_create(queue, &args->in); -- cgit v1.2.3 From 51358444d18d8b9905d7eb1a30686aa5610b2b5f Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Wed, 8 Apr 2026 17:16:24 +0530 Subject: drm/amdgpu/userq: dont lock root bo with userq_mutex held MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not hold reservation lock for root bo if userq_mutex is already held in the call flow this cause a lock issue with ttm_bo_delayed_delete. Its better to lock the vm->root.bo first and then go ahead with userq_mutex so userq_mutex threads dont get stuck until the reservation lock is held. In this case it helps in the function amdgpu_userq_buffer_vas_mapped for each queue during restore_all. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 33ffbf894801..a0a45c5e6335 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -270,15 +270,13 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr) struct amdgpu_bo_va_mapping *mapping; bool r; - if (amdgpu_bo_reserve(vm->root.bo, false)) - return false; + dma_resv_assert_held(vm->root.bo->tbo.base.resv); mapping = amdgpu_vm_bo_lookup_mapping(vm, addr); if (!IS_ERR_OR_NULL(mapping) && atomic_read(&mapping->bo_va->userq_va_mapped)) r = true; else r = false; - amdgpu_bo_unreserve(vm->root.bo); return r; } @@ -991,10 +989,16 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, static int amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) { + struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); + struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_usermode_queue *queue; unsigned long queue_id; int ret = 0, r; + + if (amdgpu_bo_reserve(vm->root.bo, false)) + return false; + mutex_lock(&uq_mgr->userq_mutex); /* Resume all the queues for this process */ xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { @@ -1012,6 +1016,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) } mutex_unlock(&uq_mgr->userq_mutex); + amdgpu_bo_unreserve(vm->root.bo); if (ret) drm_file_err(uq_mgr->file, -- cgit v1.2.3 From 469e6fea0949216d150c7b999d95ad0e0203ce27 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 9 Apr 2026 12:59:33 +0530 Subject: drm/amdgpu/userq: create_mqd does not need userq_mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reshuffle the code to run create_mqd outside the mutex. code here is mostly setting up software structure init before actually registering the userqueue in the xa and to the driver. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index a0a45c5e6335..6c76cf4ff380 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -793,14 +793,14 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) goto clean_mapping; } - amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); - r = uq_funcs->mqd_create(queue, &args->in); if (r) { drm_file_err(uq_mgr->file, "Failed to create Queue\n"); goto clean_fence_driver; } + amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); + /* don't map the queue if scheduling is halted */ if (adev->userq_halt_for_enforce_isolation && ((queue->queue_type == AMDGPU_HW_IP_GFX) || @@ -812,7 +812,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) r = amdgpu_userq_map_helper(queue); if (r) { drm_file_err(uq_mgr->file, "Failed to map Queue\n"); - down_read(&adev->reset_domain->sem); goto clean_mqd; } } @@ -828,9 +827,8 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) if (r) { if (!skip_map_queue) amdgpu_userq_unmap_helper(queue); - r = -ENOMEM; - goto clean_mqd; + goto clean_reset_domain; } r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL)); @@ -838,8 +836,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) xa_erase(&uq_mgr->userq_xa, qid); if (!skip_map_queue) amdgpu_userq_unmap_helper(queue); - - goto clean_mqd; + goto clean_reset_domain; } up_read(&adev->reset_domain->sem); @@ -851,12 +848,13 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) mutex_unlock(&uq_mgr->userq_mutex); return 0; +clean_reset_domain: + up_read(&adev->reset_domain->sem); clean_mqd: + mutex_unlock(&uq_mgr->userq_mutex); uq_funcs->mqd_destroy(queue); - up_read(&adev->reset_domain->sem); clean_fence_driver: amdgpu_userq_fence_driver_free(queue); - mutex_unlock(&uq_mgr->userq_mutex); clean_mapping: amdgpu_userq_buffer_vas_list_cleanup(adev, queue); kfree(queue); -- cgit v1.2.3 From 168178b0cbac72f7adecdcbd68c04e1fd644abf5 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Wed, 8 Apr 2026 17:56:23 +0530 Subject: drm/amdgpu/userq: caller to take reserv lock for vas_list_cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function amdgpu_userq_buffer_vas_list_cleanup, remove the reservation lock for vm and caller should make sure it's taken before locking userq_mutex. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 6c76cf4ff380..d460cb485920 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -312,25 +312,21 @@ static int amdgpu_userq_buffer_vas_list_cleanup(struct amdgpu_device *adev, { struct amdgpu_userq_va_cursor *va_cursor, *tmp; struct amdgpu_bo_va_mapping *mapping; - int r; - r = amdgpu_bo_reserve(queue->vm->root.bo, false); - if (r) - return r; + /* Caller must hold vm->root.bo reservation */ + dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv); list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) { mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, va_cursor->gpu_addr); if (!mapping) { - r = -EINVAL; - goto err; + return -EINVAL; } dev_dbg(adev->dev, "delete the userq:%p va:%llx\n", queue, va_cursor->gpu_addr); amdgpu_userq_buffer_va_list_del(mapping, va_cursor); } -err: - amdgpu_bo_unreserve(queue->vm->root.bo); - return r; + + return 0; } static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue) @@ -444,8 +440,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue) /* Wait for mode-1 reset to complete */ down_read(&adev->reset_domain->sem); - /* Drop the userq reference. */ - amdgpu_userq_buffer_vas_list_cleanup(adev, queue); uq_funcs->mqd_destroy(queue); /* Use interrupt-safe locking since IRQ handlers may access these XArrays */ xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index); @@ -626,6 +620,9 @@ static int amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue) { struct amdgpu_device *adev = uq_mgr->adev; + struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); + struct amdgpu_vm *vm = &fpriv->vm; + int r = 0; cancel_delayed_work_sync(&uq_mgr->resume_work); @@ -633,6 +630,14 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que /* Cancel any pending hang detection work and cleanup */ cancel_delayed_work_sync(&queue->hang_detect_work); + r = amdgpu_bo_reserve(vm->root.bo, false); + if (r) { + drm_file_err(uq_mgr->file, "Failed to reserve root bo during userqueue destroy\n"); + return r; + } + amdgpu_userq_buffer_vas_list_cleanup(adev, queue); + amdgpu_bo_unreserve(vm->root.bo); + mutex_lock(&uq_mgr->userq_mutex); queue->hang_detect_fence = NULL; amdgpu_userq_wait_for_last_fence(queue); @@ -664,7 +669,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que } amdgpu_userq_cleanup(queue); mutex_unlock(&uq_mgr->userq_mutex); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; @@ -856,7 +860,9 @@ clean_mqd: clean_fence_driver: amdgpu_userq_fence_driver_free(queue); clean_mapping: + amdgpu_bo_reserve(fpriv->vm.root.bo, true); amdgpu_userq_buffer_vas_list_cleanup(adev, queue); + amdgpu_bo_unreserve(fpriv->vm.root.bo); kfree(queue); return r; } -- cgit v1.2.3 From 85653fe2e52e19034db5914d65a4579dd7c4b275 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Wed, 8 Apr 2026 21:34:27 +0530 Subject: drm/amdgpu/userq: hold root bo lock in caller of input_va_validate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Caller should hold the reservation lock for root.bo in func amdgpu_userq_input_va_validate. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 17 +++++++++++------ drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index d460cb485920..31510d7fc0e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -239,13 +239,12 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, u64 size; int r = 0; + /* Caller must hold vm->root.bo reservation */ + dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv); + user_addr = (addr & AMDGPU_GMC_HOLE_MASK) >> AMDGPU_GPU_PAGE_SHIFT; size = expected_size >> AMDGPU_GPU_PAGE_SHIFT; - r = amdgpu_bo_reserve(vm->root.bo, false); - if (r) - return r; - va_map = amdgpu_vm_bo_lookup_mapping(vm, user_addr); if (!va_map) { r = -EINVAL; @@ -255,13 +254,11 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, if (user_addr >= va_map->start && va_map->last - user_addr + 1 >= size) { amdgpu_userq_buffer_va_list_add(queue, va_map, user_addr); - amdgpu_bo_unreserve(vm->root.bo); return 0; } r = -EINVAL; out_err: - amdgpu_bo_unreserve(vm->root.bo); return r; } @@ -773,13 +770,20 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) db_info.doorbell_offset = args->in.doorbell_offset; queue->userq_mgr = uq_mgr; + /* Validate the userq virtual address.*/ + r = amdgpu_bo_reserve(fpriv->vm.root.bo, false); + if (r) + goto free_queue; + if (amdgpu_userq_input_va_validate(adev, queue, args->in.queue_va, args->in.queue_size) || amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va, AMDGPU_GPU_PAGE_SIZE) || amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va, AMDGPU_GPU_PAGE_SIZE)) { r = -EINVAL; + amdgpu_bo_unreserve(fpriv->vm.root.bo); goto clean_mapping; } + amdgpu_bo_unreserve(fpriv->vm.root.bo); /* Convert relative doorbell offset into absolute doorbell index */ index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp); @@ -863,6 +867,7 @@ clean_mapping: amdgpu_bo_reserve(fpriv->vm.root.bo, true); amdgpu_userq_buffer_vas_list_cleanup(adev, queue); amdgpu_bo_unreserve(fpriv->vm.root.bo); +free_queue: kfree(queue); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index faac21ee5739..2fc39a6938f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c @@ -322,8 +322,14 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue, goto free_mqd; } + r = amdgpu_bo_reserve(queue->vm->root.bo, false); + if (r) { + kfree(compute_mqd); + goto free_mqd; + } r = amdgpu_userq_input_va_validate(adev, queue, compute_mqd->eop_va, 2048); + amdgpu_bo_unreserve(queue->vm->root.bo); if (r) { kfree(compute_mqd); goto free_mqd; @@ -365,14 +371,22 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue, userq_props->tmz_queue = mqd_user->flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_SECURE; + r = amdgpu_bo_reserve(queue->vm->root.bo, false); + if (r) { + kfree(mqd_gfx_v11); + goto free_mqd; + } r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->shadow_va, shadow_info.shadow_size); if (r) { + amdgpu_bo_unreserve(queue->vm->root.bo); kfree(mqd_gfx_v11); goto free_mqd; } + r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->csa_va, shadow_info.csa_size); + amdgpu_bo_unreserve(queue->vm->root.bo); if (r) { kfree(mqd_gfx_v11); goto free_mqd; @@ -394,8 +408,15 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue, r = -ENOMEM; goto free_mqd; } + + r = amdgpu_bo_reserve(queue->vm->root.bo, false); + if (r) { + kfree(mqd_sdma_v11); + goto free_mqd; + } r = amdgpu_userq_input_va_validate(adev, queue, mqd_sdma_v11->csa_va, 32); + amdgpu_bo_unreserve(queue->vm->root.bo); if (r) { kfree(mqd_sdma_v11); goto free_mqd; -- cgit v1.2.3 From 810df8de2f1f4602c4279455db0a88307ece5c00 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 13 Apr 2026 11:38:46 +0530 Subject: drm/amdgpu/userq: unmap is to be called before freeing doorbell/wptr bo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unmap the queue after freeing doorbell and wptr memory is completely wrong. Any operation on the queue needs the doorbell and wptr to be valid and hence fixing the ordering. Also since we are using amdgpu_bo_reserve in non interruptrable mode so there is no need to check for its return values. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 31510d7fc0e9..ea63273b8be6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -639,21 +639,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que queue->hang_detect_fence = NULL; amdgpu_userq_wait_for_last_fence(queue); - r = amdgpu_bo_reserve(queue->db_obj.obj, true); - if (!r) { - amdgpu_bo_unpin(queue->db_obj.obj); - amdgpu_bo_unreserve(queue->db_obj.obj); - } - amdgpu_bo_unref(&queue->db_obj.obj); - - r = amdgpu_bo_reserve(queue->wptr_obj.obj, true); - if (!r) { - amdgpu_bo_unpin(queue->wptr_obj.obj); - amdgpu_bo_unreserve(queue->wptr_obj.obj); - } - amdgpu_bo_unref(&queue->wptr_obj.obj); - - atomic_dec(&uq_mgr->userq_count[queue->queue_type]); #if defined(CONFIG_DEBUG_FS) debugfs_remove_recursive(queue->debugfs_queue); #endif @@ -664,6 +649,19 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que drm_warn(adev_to_drm(uq_mgr->adev), "trying to destroy a HW mapping userq\n"); queue->state = AMDGPU_USERQ_STATE_HUNG; } + + amdgpu_bo_reserve(queue->db_obj.obj, true); + amdgpu_bo_unpin(queue->db_obj.obj); + amdgpu_bo_unreserve(queue->db_obj.obj); + amdgpu_bo_unref(&queue->db_obj.obj); + + amdgpu_bo_reserve(queue->wptr_obj.obj, true); + amdgpu_bo_unpin(queue->wptr_obj.obj); + amdgpu_bo_unreserve(queue->wptr_obj.obj); + amdgpu_bo_unref(&queue->wptr_obj.obj); + + atomic_dec(&uq_mgr->userq_count[queue->queue_type]); + amdgpu_userq_cleanup(queue); mutex_unlock(&uq_mgr->userq_mutex); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); -- cgit v1.2.3 From 1e8b7062d2a8f7cecdbf7ae3fd07efc49a300d0f Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 13 Apr 2026 11:46:47 +0530 Subject: drm/amdgpu/userq: unmap_helper dont return the queue state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We check for return value of amdgpu_userq_unmap_helper and compare it against the queue->state which is logically wrong and we should just check for failure and do the needfull. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index ea63273b8be6..87b0d291859a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -645,7 +645,7 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que amdgpu_userq_detect_and_reset_queues(uq_mgr); r = amdgpu_userq_unmap_helper(queue); /*TODO: It requires a reset for userq hw unmap error*/ - if (unlikely(r != AMDGPU_USERQ_STATE_UNMAPPED)) { + if (r) { drm_warn(adev_to_drm(uq_mgr->adev), "trying to destroy a HW mapping userq\n"); queue->state = AMDGPU_USERQ_STATE_HUNG; } -- cgit v1.2.3 From d3a9fe4584ffb4717e5362d8259794c6220fc465 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Sat, 11 Apr 2026 13:41:06 +0530 Subject: drm/amdgpu/userq: use pm_runtime_resume_and_get and fix err handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use pm_runtime_resume_and_get instead of pm_runtime_get_sync as it return error but put the reference in the function itself. In goto statements we need to drop the pm reference too. Signed-off-by: Sunil Khatri Reviewed-by: Alex Deucher Acked-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 87b0d291859a..6f328742ef68 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -736,10 +736,9 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) if (r) return r; - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + r = pm_runtime_resume_and_get(adev_to_drm(adev)->dev); if (r < 0) { - drm_file_err(uq_mgr->file, "pm_runtime_get_sync() failed for userqueue create\n"); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + drm_file_err(uq_mgr->file, "pm_runtime_resume_and_get() failed for userqueue create\n"); return r; } @@ -747,13 +746,15 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) if (!uq_funcs) { drm_file_err(uq_mgr->file, "Usermode queue is not supported for this IP (%u)\n", args->in.ip_type); - return -EINVAL; + r = -EINVAL; + goto err_pm_runtime; } queue = kzalloc_obj(struct amdgpu_usermode_queue); if (!queue) { drm_file_err(uq_mgr->file, "Failed to allocate memory for queue\n"); - return -ENOMEM; + r = -ENOMEM; + goto err_pm_runtime; } INIT_LIST_HEAD(&queue->userq_va_list); @@ -867,6 +868,8 @@ clean_mapping: amdgpu_bo_unreserve(fpriv->vm.root.bo); free_queue: kfree(queue); +err_pm_runtime: + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } -- cgit v1.2.3 From b250a43bf57e544071a834a7f4223dcc58270a6b Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 13 Apr 2026 18:23:06 +0530 Subject: drm/amdgpu/userq: unpin and unref doorbell and wptr outside mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In amdgpu_userq_destroy once unmap_helpder is called within mutex there is no need to hold mutex. This helps in avoiding a deadlock between doorbell and wptr ww mutex and we could unpin and unref these bos outside mutex safely. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 6f328742ef68..d5abf785ca17 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -444,7 +444,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue) queue->fence_drv = NULL; queue->userq_mgr = NULL; list_del(&queue->userq_va_list); - kfree(queue); up_read(&adev->reset_domain->sem); } @@ -650,6 +649,10 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que queue->state = AMDGPU_USERQ_STATE_HUNG; } + atomic_dec(&uq_mgr->userq_count[queue->queue_type]); + amdgpu_userq_cleanup(queue); + mutex_unlock(&uq_mgr->userq_mutex); + amdgpu_bo_reserve(queue->db_obj.obj, true); amdgpu_bo_unpin(queue->db_obj.obj); amdgpu_bo_unreserve(queue->db_obj.obj); @@ -659,11 +662,8 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que amdgpu_bo_unpin(queue->wptr_obj.obj); amdgpu_bo_unreserve(queue->wptr_obj.obj); amdgpu_bo_unref(&queue->wptr_obj.obj); + kfree(queue); - atomic_dec(&uq_mgr->userq_count[queue->queue_type]); - - amdgpu_userq_cleanup(queue); - mutex_unlock(&uq_mgr->userq_mutex); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; -- cgit v1.2.3 From dd88d42d9ca0dd7a4ed327dd33f6ead76cedf726 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Wed, 8 Apr 2026 14:00:04 +0800 Subject: drm/amdgpu: drop userq fence driver refs out of fence process() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amdgpu_userq_wait_ioctl() takes extra references on waited-on fence drivers and stores them in waitq->fence_drv_xa. When a new userq fence is created, those references are transferred into userq_fence->fence_drv_array so they can be released when the fence completes. However, those inherited references are currently only dropped from amdgpu_userq_fence_driver_process(). If a fence never reaches that path, such as it is already signaled when created, so we need to explicitly release those fences in that case. v2: use a list(list_cut_before) for managing the signal userq driver fences.(Christian) Link: https://patchwork.freedesktop.org/patch/718078/?series=164763&rev=2 v3: Doesn't cache the userq first unsignaled fence and use the cut before list head directly.(Christian) Cc: Alex Deucher Signed-off-by: Prike Liang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 47 +++++++++++++++++-------- 1 file changed, 33 insertions(+), 14 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 5784f2b3ecae..da39ac862f37 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -145,13 +145,22 @@ amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) amdgpu_userq_fence_driver_put(userq->fence_drv); } +static void +amdgpu_userq_fence_put_fence_drv_array(struct amdgpu_userq_fence *userq_fence) +{ + unsigned long i; + for (i = 0; i < userq_fence->fence_drv_array_count; i++) + amdgpu_userq_fence_driver_put(userq_fence->fence_drv_array[i]); + userq_fence->fence_drv_array_count = 0; +} + void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv) { struct amdgpu_userq_fence *userq_fence, *tmp; + LIST_HEAD(to_be_signaled); struct dma_fence *fence; unsigned long flags; u64 rptr; - int i; if (!fence_drv) return; @@ -159,21 +168,26 @@ void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_d spin_lock_irqsave(&fence_drv->fence_list_lock, flags); rptr = amdgpu_userq_fence_read(fence_drv); - list_for_each_entry_safe(userq_fence, tmp, &fence_drv->fences, link) { - fence = &userq_fence->base; - - if (rptr < fence->seqno) + list_for_each_entry(userq_fence, &fence_drv->fences, link) { + if (rptr < userq_fence->base.seqno) break; + } - dma_fence_signal(fence); - - for (i = 0; i < userq_fence->fence_drv_array_count; i++) - amdgpu_userq_fence_driver_put(userq_fence->fence_drv_array[i]); + list_cut_before(&to_be_signaled, &fence_drv->fences, + &userq_fence->link); + spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); - list_del(&userq_fence->link); + list_for_each_entry_safe(userq_fence, tmp, &to_be_signaled, link) { + fence = &userq_fence->base; + list_del_init(&userq_fence->link); + dma_fence_signal(fence); + /* Drop fence_drv_array outside fence_list_lock + * to avoid the recursion lock. + */ + amdgpu_userq_fence_put_fence_drv_array(userq_fence); dma_fence_put(fence); } - spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); + } void amdgpu_userq_fence_driver_destroy(struct kref *ref) @@ -228,6 +242,7 @@ static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq, struct amdgpu_userq_fence_driver *fence_drv; struct dma_fence *fence; unsigned long flags; + bool signaled = false; fence_drv = userq->fence_drv; if (!fence_drv) @@ -274,13 +289,17 @@ static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq, /* Check if hardware has already processed the job */ spin_lock_irqsave(&fence_drv->fence_list_lock, flags); - if (!dma_fence_is_signaled(fence)) + if (!dma_fence_is_signaled(fence)) { list_add_tail(&userq_fence->link, &fence_drv->fences); - else + } else { + signaled = true; dma_fence_put(fence); - + } spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); + if (signaled) + amdgpu_userq_fence_put_fence_drv_array(userq_fence); + *f = fence; return 0; -- cgit v1.2.3 From 314f6179e370988ac00dadf373a4f6166eb3db15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Mon, 13 Apr 2026 14:23:45 +0300 Subject: drm/i915/psr: Init variable to avoid early exit from et alignment loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uninitialized boolean variable may cause unwanted exit from et alignment loop. Fix this by initializing it as false. Fixes: 1be2fca84f52 ("drm/i915/psr: Repeat Selective Update area alignment") Cc: # v6.9+ Signed-off-by: Jouni Högander Reviewed-by: Nemesa Garg Reported-by: Dan Carpenter Reviewed-by: Andi Shyti Link: https://patch.msgid.link/20260413112345.88853-1-jouni.hogander@intel.com (cherry picked from commit 289678a90b8cf81e3514c9d6c667235cd39c7acf) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 2f1b48cd8efd..31eb366ec999 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2974,7 +2974,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, return ret; do { - bool cursor_in_su_area; + bool cursor_in_su_area = false; /* * Adjust su area to cover cursor fully as necessary -- cgit v1.2.3 From 49ed6f45402ddefc630ebe5d553cf32fe93e1d4c Mon Sep 17 00:00:00 2001 From: Leo Li Date: Fri, 17 Apr 2026 13:54:30 -0400 Subject: drm/amd/display: Undo accidental fix revert in amdgpu_dm_ism.c [Why] Pausing DPM power profiles during static screen caused a bunch of audio/performance/clock issues that were addressed in this fix: 'commit 1412482b7143 ("Revert "drm/amd/display: pause the workload setting in dm"")' This logic in function amdgpu_dm_crtc_vblank_control_worker() was moved to amdgpu_dm_ism.c, but the fix was lost in the process. [How] Reapply the fix to amdgpu_dm_ism.c Fixes: 754003486c3c ("drm/amd/display: Add Idle state manager(ISM)") Reviewed-by: Alex Deucher Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Leo Li Signed-off-by: Alex Deucher (cherry picked from commit bc621e91d6fc004cfae9148c5a91acad19ada3e4) --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c index 773943f65d6e..a64e95860e99 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c @@ -270,7 +270,6 @@ static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism, struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism); struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev); struct amdgpu_display_manager *dm = &adev->dm; - int r; trace_amdgpu_dm_ism_commit(dm->active_vblank_irq_count, vblank_enabled, @@ -323,16 +322,7 @@ static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism, */ if (!vblank_enabled && dm->active_vblank_irq_count == 0) { dc_post_update_surfaces_to_stream(dm->dc); - - r = amdgpu_dpm_pause_power_profile(adev, true); - if (r) - dev_warn(adev->dev, "failed to set default power profile mode\n"); - dc_allow_idle_optimizations(dm->dc, true); - - r = amdgpu_dpm_pause_power_profile(adev, false); - if (r) - dev_warn(adev->dev, "failed to restore the power profile mode\n"); } } -- cgit v1.2.3 From 0e48f27d139ecb5a3ea9123243558abb3f022765 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Sat, 18 Apr 2026 23:16:52 -0500 Subject: drm/amd: Adjust ASPM support quirk to cover more Intel hosts Some of the same issues identified in commit c770ef19673fb ("drm/amd/amdgpu: disable ASPM in some situations") also affect Tiger Lake systems with GFX11 connected over USB4. Widen the net to also match these hosts. Fixes: d9b3a066dfcd ("drm/amd: Exclude dGPUs in eGPU enclosures from DPM quirks") Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5145 Reviewed-by: Yang Wang Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher (cherry picked from commit 0a214d888485b9f35fe03882a92962e6d5697849) --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 413145a958fc..737ef1ef96a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1334,18 +1334,15 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev) #if IS_ENABLED(CONFIG_X86) struct cpuinfo_x86 *c = &cpu_data(0); - if (!(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 0, 0) || - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 0, 1))) - return false; - - if (c->x86 == 6 && - adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN5) { + if (c->x86_vendor == X86_VENDOR_INTEL) { switch (c->x86_model) { case VFM_MODEL(INTEL_ALDERLAKE): case VFM_MODEL(INTEL_ALDERLAKE_L): case VFM_MODEL(INTEL_RAPTORLAKE): case VFM_MODEL(INTEL_RAPTORLAKE_P): case VFM_MODEL(INTEL_RAPTORLAKE_S): + case VFM_MODEL(INTEL_TIGERLAKE): + case VFM_MODEL(INTEL_TIGERLAKE_L): return true; default: return false; -- cgit v1.2.3 From 778bf584f2fb0a2b09594f568faf400bf6858091 Mon Sep 17 00:00:00 2001 From: Siwei He Date: Tue, 14 Apr 2026 14:46:54 -0400 Subject: drm/amdgpu: OR init_pte_flags into invalid leaf PTE updates Invalid leaf clears that only set AMDGPU_PTE_EXECUTABLE match the old GMC9 fault-priority workaround but omit adev->gmc.init_pte_flags. On GFX12 that includes AMDGPU_PTE_IS_PTE; without it, some cleared PTEs can fault as no-retry and bypass the SVM/XNACK handler when a VA is reused after a BO unmap. Apply init_pte_flags in amdgpu_vm_pte_update_flags() alongside EXECUTABLE so range-driven clears (e.g. amdgpu_vm_clear_freed) match amdgpu_vm_pt_clear() for leaf templates. Signed-off-by: Siwei He Reviewed-by: Philip Yang Signed-off-by: Alex Deucher (cherry picked from commit 9d47b2c36b9a6c6b844c33cab407a5d7ad102234) --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c index 31a437ce9570..a930f1522f96 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c @@ -693,8 +693,11 @@ static void amdgpu_vm_pte_update_flags(struct amdgpu_vm_update_params *params, !(flags & AMDGPU_PTE_VALID) && !(flags & AMDGPU_PTE_PRT_FLAG(params->adev))) { - /* Workaround for fault priority problem on GMC9 */ - flags |= AMDGPU_PTE_EXECUTABLE; + /* Workaround for fault priority problem on GMC9 and GFX12, + * EXECUTABLE for GMC9 fault priority and init_pte_flags + * (e.g. AMDGPU_PTE_IS_PTE on GFX12) + */ + flags |= AMDGPU_PTE_EXECUTABLE | adev->gmc.init_pte_flags; } /* -- cgit v1.2.3 From 11b31549b6d6ccf9861787de5606d1b9384a8a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Tue, 21 Apr 2026 01:55:04 +0200 Subject: drm/amd/display: Disable 10-bit truncation and dithering on DCE 6.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DCE 6.x doesn't support 10-bit truncation and 10-bit dithering because the following fields are 1-bit only: FMT_TEMPORAL_DITHER_DEPTH FMT_SPATIAL_DITHER_DEPTH FMT_TRUNCATE_DEPTH Programming these fields to "2" will program them as if the dithering option was 6-bit, resulting in sub-par picture quality and an ugly "color banding" effect. Note that a recent commit changed the default 10-bit dithering option to DITHER_OPTION_SPATIAL10 which improves the picture quality because it happens to look better, but is still not actually supported by DCE 6.x versions. When the color depth is 10-bit or more, just disable any kind of dithering options on DCE 6.x. Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5151 Fixes: 529cad0f945c ("drm/amd/display: Add function to set dither option") Signed-off-by: Timur Kristóf Signed-off-by: Alex Deucher (cherry picked from commit 6be8ced880dfe29ce38c2d5e74489822da5c250e) --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 00b894602423..05991a10f8bf 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -5069,6 +5069,12 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, } } + if (stream->ctx->dce_version < DCE_VERSION_8_0 && + stream->timing.display_color_depth >= COLOR_DEPTH_101010) { + /* DCE 6.x doesn't support 10-bit truncation or dither options. */ + option = DITHER_OPTION_DISABLE; + } + if (option == DITHER_OPTION_DISABLE) return; -- cgit v1.2.3 From f6c73e7156b54d8b9ddf1a27f4e93d3a1e49a73e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 8 Apr 2026 15:42:05 +0300 Subject: drm: rcar-du: Fix crash when no CMM is available Commit 3bce3fdd1ff2 ("drm: rcar-du: Don't leak device_link to CMM") refactored CMM handling, and introduced an incorrect test for CMM availability. When no CMM is present, the rcrtc->cmm field is NULL, testing rcrtc->cmm->dev causes a NULL pointer dereference. This slipped through testing as all tests were run with the CMM present. Fix this issue by correctly testing for rcrtc->cmm. Fixes: 3bce3fdd1ff2 ("drm: rcar-du: Don't leak device_link to CMM") Reported-by: Geert Uytterhoeven Closes: https://lore.kernel.org/dri-devel/CAMuHMdXomz9GFDqkBjGX9Sda_GLccPcrihvFbOz0GAitDVNTbw@mail.gmail.com Signed-off-by: Laurent Pinchart Tested-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260408124205.1962448-1-laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Tomi Valkeinen (cherry picked from commit 3e9a1da270ddff449b1ad9eadc958f43bc204bd2) Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c index 7c36c30a75b6..1a246ebbfc61 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c @@ -513,7 +513,7 @@ static void rcar_du_cmm_setup(struct drm_crtc *crtc) struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); struct rcar_cmm_config cmm_config = {}; - if (!rcrtc->cmm->dev) + if (!rcrtc->cmm) return; if (drm_lut) @@ -667,7 +667,7 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) rcar_du_vsp_disable(rcrtc); - if (rcrtc->cmm->dev) + if (rcrtc->cmm) rcar_cmm_disable(rcrtc->cmm->dev); /* @@ -726,7 +726,7 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc->state); struct rcar_du_device *rcdu = rcrtc->dev; - if (rcrtc->cmm->dev) + if (rcrtc->cmm) rcar_cmm_enable(rcrtc->cmm->dev); rcar_du_crtc_get(rcrtc); -- cgit v1.2.3 From 74b73fa56a395d46745e4f245225963e9f8be7f1 Mon Sep 17 00:00:00 2001 From: Alysa Liu Date: Mon, 30 Mar 2026 10:50:07 -0400 Subject: drm/amdkfd: Add upper bound check for num_of_nodes drm/amdkfd: Add upper bound check for num_of_nodes in kfd_ioctl_get_process_apertures_new. Reviewed-by: Harish Kasiviswanathan Signed-off-by: Alysa Liu Signed-off-by: Alex Deucher (cherry picked from commit 98ff46a5ea090c14d2cdb4f5b993b05d74f3949f) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 3 +++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 1 + drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 11 +++++++++++ 3 files changed, 15 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 462a32abf720..55ea5145a28a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -776,6 +776,9 @@ static int kfd_ioctl_get_process_apertures_new(struct file *filp, goto out_unlock; } + if (args->num_of_nodes > kfd_topology_get_num_devices()) + return -EINVAL; + /* Fill in process-aperture information for all available * nodes, but not more than args->num_of_nodes as that is * the amount of memory allocated by user diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index fa025bea9b4f..6e333bfa17d6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -1191,6 +1191,7 @@ static inline struct kfd_node *kfd_node_by_irq_ids(struct amdgpu_device *adev, return NULL; } int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_node **kdev); +uint32_t kfd_topology_get_num_devices(void); int kfd_numa_node_to_apic_id(int numa_node_id); uint32_t kfd_gpu_node_num(void); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 995f2c2528a9..29dee26261ab 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -2297,6 +2297,17 @@ int kfd_topology_remove_device(struct kfd_node *gpu) return res; } +uint32_t kfd_topology_get_num_devices(void) +{ + uint32_t num_devices; + + down_read(&topology_lock); + num_devices = sys_props.num_devices; + up_read(&topology_lock); + + return num_devices; +} + /* kfd_topology_enum_kfd_devices - Enumerate through all devices in KFD * topology. If GPU device is found @idx, then valid kfd_dev pointer is * returned through @kdev -- cgit v1.2.3