From 977b7437170ee6903db83a0c32decd028f98076b Mon Sep 17 00:00:00 2001 From: Mukul Joshi Date: Tue, 15 Sep 2026 14:45:51 -0400 Subject: [PATCH 001/103] drm/amd: set CP_HQD_PQ_CONTROL.SCOPE for PM4 and KCQs on GFX 12.1 The previous change set CP_HQD_PQ_CONTROL.SCOPE=3 (SYSTEM) only for KFD AQL queues, but PM4 queues and the kernel-managed compute (KCQ) queues can also use non-coherently cached ring buffers and hit the same stale-packet problem. Set the scope for both PM4 queues and KCQs as well. Reviewed-by: Harish Kasiviswanathan Signed-off-by: Mukul Joshi Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 1 + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c index d7effa43c0fa..1a09bd41f795 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c @@ -2276,6 +2276,7 @@ static int gfx_v12_1_compute_mqd_init(struct amdgpu_device *adev, void *m, tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE, (order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1)); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, SCOPE, 3); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, 0); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c index ef74d62c9d56..d508ac5a18f8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c @@ -274,6 +274,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; + m->cp_hqd_pq_control |= 3 << CP_HQD_PQ_CONTROL__SCOPE__SHIFT; pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); @@ -335,7 +336,6 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, /* GC 10 removed WPP_CLAMP from PQ Control */ m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__NO_UPDATE_RPTR_MASK | 2 << CP_HQD_PQ_CONTROL__SLOT_BASED_WPTR__SHIFT | - 3 << CP_HQD_PQ_CONTROL__SCOPE__SHIFT | 1 << CP_HQD_PQ_CONTROL__QUEUE_FULL_EN__SHIFT; m->cp_hqd_pq_doorbell_control |= 1 << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_BIF_DROP__SHIFT; From 458e3ce5552219aafa75395cb7f4a906b2110f31 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Wed, 16 Sep 2026 16:11:37 +0800 Subject: [PATCH 002/103] drm/amd/ras: enable UniRAS for psp v15_0_8 Enable UniRAS for psp v15_0_8. Signed-off-by: Candice Li Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c index 982ca34dba8f..eb72d030b66e 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c @@ -328,7 +328,8 @@ int amdgpu_ras_mgr_sw_init(struct amdgpu_device *adev, struct ras_module_param * return 0; else if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 12) || - amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6)) + amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6) || + amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(15, 0, 8)) con->uniras_enabled = true; else return 0; From c99a13b20092c343d5aa3b8941777578c1715e54 Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Thu, 10 Sep 2026 14:46:38 -0400 Subject: [PATCH 003/103] drm/amdgpu: Check for PCIe atomic ops support when reading pf2vf data The critical region v2 patches clear the fw_reserve.p_pf2vf variable after pf2vf data is read the first time. have_atomics_support relies on that variable to check for PCIe atomic ops support. Move have_atomics_support check for SRIOV VFs to be when pf2vf data is read. Signed-off-by: Victor Lu Reviewed-by: Ellen Pan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 33 ++++++++++------------ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 3 ++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 494aa2faef95..8ac8c423f6d9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4006,24 +4006,21 @@ int amdgpu_device_init(struct amdgpu_device *adev, } /* enable PCIE atomic ops */ - if (amdgpu_sriov_vf(adev)) { - if (adev->virt.fw_reserve.p_pf2vf) - adev->have_atomics_support = ((struct amd_sriov_msg_pf2vf_info *) - adev->virt.fw_reserve.p_pf2vf)->pcie_atomic_ops_support_flags == - (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | PCI_EXP_DEVCAP2_ATOMIC_COMP64); - /* APUs w/ gfx9 onwards doesn't reply on PCIe atomics, rather it is a - * internal path natively support atomics, set have_atomics_support to true. - */ - } else if ((adev->flags & AMD_IS_APU && - amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0)) || - (adev->gmc.xgmi.connected_to_cpu && - amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 1, 0))) { - adev->have_atomics_support = true; - } else { - adev->have_atomics_support = - !pci_enable_atomic_ops_to_root(adev->pdev, - PCI_EXP_DEVCAP2_ATOMIC_COMP32 | - PCI_EXP_DEVCAP2_ATOMIC_COMP64); + if (!amdgpu_sriov_vf(adev)) { + /* APUs w/ gfx9 onwards doesn't reply on PCIe atomics, rather it is a + * internal path natively support atomics, set have_atomics_support to true. + */ + if ((adev->flags & AMD_IS_APU && + amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0)) || + (adev->gmc.xgmi.connected_to_cpu && + amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 1, 0))) { + adev->have_atomics_support = true; + } else { + adev->have_atomics_support = + !pci_enable_atomic_ops_to_root(adev->pdev, + PCI_EXP_DEVCAP2_ATOMIC_COMP32 | + PCI_EXP_DEVCAP2_ATOMIC_COMP64); + } } if (!adev->have_atomics_support) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 5fadcefaa528..a58a352b4a35 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -652,6 +652,9 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) adev->virt.ras_en_caps.all = pf2vf->pf2vf_ras_caps.ras_en_caps.all; adev->virt.ras_telemetry_en_caps.all = pf2vf->pf2vf_ras_caps.ras_telemetry_en_caps.all; + + adev->have_atomics_support = pf2vf->pcie_atomic_ops_support_flags == + (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | PCI_EXP_DEVCAP2_ATOMIC_COMP64); break; default: dev_err(adev->dev, "invalid pf2vf version: 0x%x\n", pf2vf_info->version); From 102a47065a62dc8f6bbbb47cf082a2934282eb08 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 16 Sep 2026 09:49:56 +0000 Subject: [PATCH 004/103] drm/amd/display: Fix dc stream excess put in dm_update_crtc_state() In dm_update_crtc_state(), when a modeset is required the newly created stream is stored in dm_new_crtc_state->stream and an extra reference is taken with dc_stream_retain(). The reference returned by create_validate_stream_for_sink() is released as an extra reference at the skip_modeset label, leaving the stream owned by the new CRTC state. If amdgpu_dm_check_crtc_color_mgmt() fails afterwards, the code jumps to the fail label which releases new_stream again. Since the extra reference was already released at skip_modeset, this drops the reference owned by dm_new_crtc_state->stream and the stream is released while the atomic state still points to it, leading to a premature free of the dc stream. Set new_stream to NULL after releasing the extra reference at the skip_modeset label so that a later goto fail cannot release the reference owned by the new CRTC state. Fixes: 7cd4b70091a5 ("drm/amd/display: Rework CRTC color management") Signed-off-by: Wentao Liang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 b5fef1f0b86b..86c7e16ba9c5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5714,8 +5714,10 @@ STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm, skip_modeset: /* Release extra reference */ - if (new_stream) + if (new_stream) { dc_stream_release(new_stream); + new_stream = NULL; + } new_stream = NULL; /* From 388c53d2135ca4c8c733c0b9a87ccc1720924b2b Mon Sep 17 00:00:00 2001 From: Jesse Zhang Date: Tue, 15 Sep 2026 14:45:34 +0800 Subject: [PATCH 005/103] drm/amdgpu/mes12: clear event log on resume to avoid MES page fault The MES event-log/MSCRATCH region is only zeroed once at sw_init. On the resume path (hw_init without sw_init) it retains stale data, so with mes_log_enable=1 the MES firmware walks stale pointers on activation and triggers a recoverable CPC page fault: [gfxhub] page fault (src_id:0 ring:153 vmid:0 pasid:0) in page starting at address 0x000000855c237000 from client 10 GCVM_L2_PROTECTION_FAULT_STATUS:0x00000B33 Faulty UTCL2 client ID: CPC (0x5) MORE_FAULTS: 0x1 WALKER_ERROR: 0x1 PERMISSION_FAULTS: 0x3 MAPPING_ERROR: 0x1 RW: 0x0 Re-clear it before unhalting MES. Reviewed-by: James Zhu Tested-by: James Zhu Signed-off-by: Jesse Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v12_0.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c index ee72afdb0a1d..9e149cf98889 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c @@ -1306,6 +1306,17 @@ static void mes_v12_0_enable(struct amdgpu_device *adev, bool enable) uint32_t pipe, data = 0; if (enable) { + /* + * The event-log/MSCRATCH region is only zeroed once at sw_init. + * On the resume path (hw_init without sw_init) it still holds the + * previous session's data, so the MES firmware walks stale + * pointers on activation and triggers a CPC page fault. Re-clear + * it before unhalting MES. + */ + if (amdgpu_mes_log_enable && adev->mes.event_log_cpu_addr) + memset(adev->mes.event_log_cpu_addr, 0, + adev->mes.event_log_size); + mutex_lock(&adev->srbm_mutex); for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { soc24_grbm_select(adev, 3, pipe, 0, 0); From 6cb55205f42df5bdff27ccce52089ec8850d0552 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Mon, 10 Aug 2026 18:23:33 +0800 Subject: [PATCH 006/103] drm/amd/pm: Add GetRmaStatus message Add GetRmaStatus message for smu_v13_0_12 and smu_v15_0_8. Signed-off-by: YiPeng Chai Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h | 1 + drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 1 + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 1 + drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c | 1 + 5 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h index d09b6ae9827e..ac7e617e64ad 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h @@ -105,6 +105,7 @@ #define PPSMC_MSG_UpdatePccWaitDecMaxStr 0x4C #define PPSMC_MSG_ResetSDMA 0x4D #define PPSMC_MSG_GetRasTableVersion 0x4E +#define PPSMC_MSG_GetRmaStatus 0x4F #define PPSMC_MSG_GetBadPageCount 0x50 #define PPSMC_MSG_GetBadPageMcaAddress 0x51 #define PPSMC_MSG_SetTimestamp 0x53 diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index d6675b4ee9be..2631e12b5e59 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -285,6 +285,7 @@ __SMU_DUMMY_MAP(GetStaticMetricsTable), \ __SMU_DUMMY_MAP(GetSystemMetricsTable), \ __SMU_DUMMY_MAP(GetRASTableVersion), \ + __SMU_DUMMY_MAP(GetRmaStatus), \ __SMU_DUMMY_MAP(GetBadPageCount), \ __SMU_DUMMY_MAP(GetBadPageMcaAddr), \ __SMU_DUMMY_MAP(SetTimestamp), \ diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 1ecf65d402ba..d8ddad531d26 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -153,6 +153,7 @@ const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1), MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1), MSG_MAP(GetRASTableVersion, PPSMC_MSG_GetRasTableVersion, 0), + MSG_MAP(GetRmaStatus, PPSMC_MSG_GetRmaStatus, 0), MSG_MAP(GetBadPageCount, PPSMC_MSG_GetBadPageCount, 0), MSG_MAP(GetBadPageMcaAddr, PPSMC_MSG_GetBadPageMcaAddress, 0), MSG_MAP(SetTimestamp, PPSMC_MSG_SetTimestamp, 0), diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index 62423f486017..d6cc603de7b6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -126,6 +126,7 @@ static const struct cmn2asic_msg_mapping smu_v15_0_8_message_map[SMU_MSG_MAX_COU MSG_MAP(GetTimestamp, PPSMC_MSG_GetTimestamp, 0), MSG_MAP(GetBadPageIpid, PPSMC_MSG_GetBadPageIpIdLoHi, 0), MSG_MAP(EraseRasTable, PPSMC_MSG_EraseRasTable, 0), + MSG_MAP(GetRmaStatus, PPSMC_MSG_GetRmaStatus, 0), MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1), MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1), MSG_MAP(GetSystemMetricsVersion, PPSMC_MSG_GetSystemMetricsVersion, 0), diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c index baf5f156fc6f..166992dd6979 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c @@ -27,6 +27,7 @@ static const enum smu_message_type ras_smu_msg_maps[RAS_MP1_MSG_MAX] = { [RAS_MP1_MSG_GetRasTableVersion] = SMU_MSG_GetRASTableVersion, + [RAS_MP1_MSG_GetRmaStatus] = SMU_MSG_GetRmaStatus, [RAS_MP1_MSG_GetBadPageCount] = SMU_MSG_GetBadPageCount, [RAS_MP1_MSG_GetBadPageMcaAddr] = SMU_MSG_GetBadPageMcaAddr, [RAS_MP1_MSG_SetTimestamp] = SMU_MSG_SetTimestamp, From 3bd4fbc5ed89621340b5cd249869092691a9c81f Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Fri, 31 Jul 2026 11:44:37 +0800 Subject: [PATCH 007/103] drm/amdgpu: move userq fence wait out of signalling section The eviction fence suspend worker waits for every pending userq fence from inside a dma_fence_begin_signalling() critical section. Waiting on another DMA fence while responsible for signalling one violates the cross-driver fence contract and is reported by lockdep as a dma_fence_map dependency. Move the wait before dma_fence_begin_signalling(). Keep userq_mutex held so queue lifetime remains stable while inspecting last_fence. Fixes: fc61df151617 ("drm/amdgpu: annotate eviction fence signaling path") Signed-off-by: Prike Liang Reviewed-by: Vitaly Prosyak Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 4 +--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c index f6b7522c3c82..f8652fd0525d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c @@ -68,6 +68,9 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work) mutex_lock(&uq_mgr->userq_mutex); + /* Fence waits are not allowed in a fence signalling critical section. */ + amdgpu_userq_wait_for_signal(uq_mgr); + /* * This is intentionally after taking the userq_mutex since we do * allocate memory while holding this lock, but only after ensuring that diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 12fbff02e4b5..5d07320a29b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1294,7 +1294,7 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr) return ret; } -static void +void amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) { struct amdgpu_usermode_queue *queue; @@ -1313,8 +1313,6 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr) { - /* Wait for any pending userqueue fence work to finish */ - amdgpu_userq_wait_for_signal(uq_mgr); amdgpu_userq_evict_all(uq_mgr); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index 6412a7f7b6ef..488dc21d7c81 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -162,6 +162,7 @@ void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev); void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr); void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr); +void amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr); void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr); void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr, From ad3f86f7d8575a4efe3656a7bc8c9b3de300f0e3 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Mon, 24 Aug 2026 14:32:50 +0800 Subject: [PATCH 008/103] drm/amd/ras: retrieve ras error info via common interface and message for mp1_v13_0 Retrieve ras error info via common interface and message for mp1_v13_0. Signed-off-by: YiPeng Chai Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/core/ras_mp1.h | 8 +++ drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c | 61 +++++++++++++------ .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c | 4 ++ 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/ras/core/ras_mp1.h b/drivers/gpu/drm/amd/ras/core/ras_mp1.h index d70070645ced..81d5f1eed676 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_mp1.h +++ b/drivers/gpu/drm/amd/ras/core/ras_mp1.h @@ -25,7 +25,15 @@ #define __RAS_MP1_H__ #include "ras.h" +#define MAX_UE_BANKS_PER_QUERY 12 +#define MAX_CE_BANKS_PER_QUERY 12 + enum ras_mp1_msg_id { + RAS_MP1_MSG_QueryValidMcaCount, + RAS_MP1_MSG_McaBankDumpDW, + RAS_MP1_MSG_ClearMcaOnRead, + RAS_MP1_MSG_QueryValidMcaCeCount, + RAS_MP1_MSG_McaBankCeDumpDW, RAS_MP1_MSG_GetRasTableVersion, RAS_MP1_MSG_GetRmaStatus, RAS_MP1_MSG_GetBadPageCount, diff --git a/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c b/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c index 6fd746fe64c4..bdedaadd85b3 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c +++ b/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c @@ -26,30 +26,52 @@ #include "core_status.h" #include "ras_mp1_v13_0.h" -#define RAS_MP1_MSG_QueryValidMcaCount 0x36 -#define RAS_MP1_MSG_McaBankDumpDW 0x37 -#define RAS_MP1_MSG_ClearMcaOnRead 0x39 -#define RAS_MP1_MSG_QueryValidMcaCeCount 0x3A -#define RAS_MP1_MSG_McaBankCeDumpDW 0x3B +static int __send_mp1_msg32(struct ras_core_context *ras_core, + enum ras_mp1_msg_id msg_id, u32 input, u32 *output) +{ + if (!ras_core->ras_mp1.sys_func || + !ras_core->ras_mp1.sys_func->mp1_send_ras_msg) + return -EOPNOTSUPP; -#define MAX_UE_BANKS_PER_QUERY 12 -#define MAX_CE_BANKS_PER_QUERY 12 + return ras_core->ras_mp1.sys_func->mp1_send_ras_msg(ras_core, + msg_id, &input, 1, output, output ? 1 : 0); +} + +static int __dump_mp1_bank_reg64(struct ras_core_context *ras_core, + u32 msg, u32 idx, u32 reg_idx, u64 *val) +{ + u32 data[2] = {0, 0}; + u32 param; + int ret; + u32 i, offset; + + offset = reg_idx * 8; + for (i = 0; i < ARRAY_SIZE(data); i++) { + param = ((idx & 0xffff) << 16) | ((offset + (i << 2)) & 0xfffc); + ret = __send_mp1_msg32(ras_core, msg, param, &data[i]); + if (ret) { + RAS_DEV_ERR(ras_core->dev, + "ACA failed to read register[%u], offset:0x%x\n", + reg_idx, offset); + return ret; + } + } + + *val = ((u64)data[1] << 32) | data[0]; + + return 0; +} static int mp1_v13_0_get_bank_count(struct ras_core_context *ras_core, enum ras_err_type type, u32 *count) { - struct ras_mp1 *mp1 = &ras_core->ras_mp1; - const struct ras_mp1_sys_func *sys_func = mp1->sys_func; - uint32_t bank_count = 0; + u32 bank_count = 0; u32 msg; int ret; if (!count) return -EINVAL; - if (!sys_func || !sys_func->mp1_get_valid_bank_count) - return -RAS_CORE_NOT_SUPPORTED; - switch (type) { case RAS_ERR_TYPE__UE: msg = RAS_MP1_MSG_QueryValidMcaCount; @@ -62,10 +84,11 @@ static int mp1_v13_0_get_bank_count(struct ras_core_context *ras_core, return -EINVAL; } - ret = sys_func->mp1_get_valid_bank_count(ras_core, msg, &bank_count); + ret = __send_mp1_msg32(ras_core, msg, 0, &bank_count); if (!ret) { if (((type == RAS_ERR_TYPE__UE) && (bank_count >= MAX_UE_BANKS_PER_QUERY)) || - ((type == RAS_ERR_TYPE__CE) && (bank_count >= MAX_CE_BANKS_PER_QUERY))) + ((type == RAS_ERR_TYPE__CE || type == RAS_ERR_TYPE__DE) && + (bank_count >= MAX_CE_BANKS_PER_QUERY))) return -EINVAL; *count = bank_count; @@ -77,13 +100,11 @@ static int mp1_v13_0_get_bank_count(struct ras_core_context *ras_core, static int mp1_v13_0_dump_bank(struct ras_core_context *ras_core, enum ras_err_type type, u32 idx, u64 *regs, u32 regs_sz) { - struct ras_mp1 *mp1 = &ras_core->ras_mp1; - const struct ras_mp1_sys_func *sys_func = mp1->sys_func; int i, ret, reg_cnt; u32 msg; - if (!sys_func || !sys_func->mp1_dump_valid_bank) - return -RAS_CORE_NOT_SUPPORTED; + if (!regs || !regs_sz || (idx > 0xffff)) + return -EINVAL; switch (type) { case RAS_ERR_TYPE__UE: @@ -99,7 +120,7 @@ static int mp1_v13_0_dump_bank(struct ras_core_context *ras_core, reg_cnt = min_t(int, 16, regs_sz); for (i = 0; i < reg_cnt; i++) { - ret = sys_func->mp1_dump_valid_bank(ras_core, msg, idx, i, ®s[i]); + ret = __dump_mp1_bank_reg64(ras_core, msg, idx, i, ®s[i]); if (ret) return ret; } diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c index 166992dd6979..37d446798bd0 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c @@ -26,6 +26,10 @@ #include "ras.h" static const enum smu_message_type ras_smu_msg_maps[RAS_MP1_MSG_MAX] = { + [RAS_MP1_MSG_QueryValidMcaCount] = SMU_MSG_QueryValidMcaCount, + [RAS_MP1_MSG_McaBankDumpDW] = SMU_MSG_McaBankDumpDW, + [RAS_MP1_MSG_QueryValidMcaCeCount] = SMU_MSG_QueryValidMcaCeCount, + [RAS_MP1_MSG_McaBankCeDumpDW] = SMU_MSG_McaBankCeDumpDW, [RAS_MP1_MSG_GetRasTableVersion] = SMU_MSG_GetRASTableVersion, [RAS_MP1_MSG_GetRmaStatus] = SMU_MSG_GetRmaStatus, [RAS_MP1_MSG_GetBadPageCount] = SMU_MSG_GetBadPageCount, From 82605e80a3c4c1df27aa975731deec6425bc75d4 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Mon, 24 Aug 2026 14:35:14 +0800 Subject: [PATCH 009/103] drm/amd/ras: add pmfw-managed eeprom support for mp1_v13_0 Add pmfw-managed eeprom support for mp1_v13_0. Signed-off-by: YiPeng Chai Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/core/ras_mp1.h | 26 +++++- drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c | 92 ++++++++++++++++++++ 2 files changed, 115 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/ras/core/ras_mp1.h b/drivers/gpu/drm/amd/ras/core/ras_mp1.h index 81d5f1eed676..410530fb8ada 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_mp1.h +++ b/drivers/gpu/drm/amd/ras/core/ras_mp1.h @@ -48,9 +48,29 @@ enum ras_mp1_msg_id { }; struct eeprom_err_record { - u64 timestamp; - u64 mca_addr; - u64 ipid; + union { + struct { + u32 timestamp_low; + u32 timestamp_high; + }; + u64 timestamp; + }; + + union { + struct { + u32 mca_addr_low; + u32 mca_addr_high; + }; + u64 mca_addr; + }; + + union { + struct { + u32 ipid_low; + u32 ipid_high; + }; + u64 ipid; + }; }; enum ras_err_type; diff --git a/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c b/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c index bdedaadd85b3..5ace16ab4cbd 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c +++ b/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c @@ -26,6 +26,9 @@ #include "core_status.h" #include "ras_mp1_v13_0.h" +#define MSG_DATA_LOW32(idx) (((idx) & 0xFFFFU) | BIT(16)) +#define MSG_DATA_HIGH32(idx) (((idx) & 0xFFFFU) | BIT(17)) + static int __send_mp1_msg32(struct ras_core_context *ras_core, enum ras_mp1_msg_id msg_id, u32 input, u32 *output) { @@ -37,6 +40,89 @@ static int __send_mp1_msg32(struct ras_core_context *ras_core, msg_id, &input, 1, output, output ? 1 : 0); } +static int mp1_v13_0_get_table_version(struct ras_core_context *ras_core, + u32 *table_ver) +{ + if (!table_ver) + return -EINVAL; + + return __send_mp1_msg32(ras_core, RAS_MP1_MSG_GetRasTableVersion, + 0, table_ver); +} + +static bool mp1_v13_0_rma_detected(struct ras_core_context *ras_core) +{ + u32 rma = 0; + + if (__send_mp1_msg32(ras_core, RAS_MP1_MSG_GetRmaStatus, 0, &rma)) + return false; + + return rma; +} + +static int mp1_v13_0_set_timestamp(struct ras_core_context *ras_core, + u64 timestamp) +{ + if (!timestamp) + return -EINVAL; + + return __send_mp1_msg32(ras_core, RAS_MP1_MSG_SetTimestamp, (u32)timestamp, NULL); +} + +static int mp1_v13_0_reset_ras_table(struct ras_core_context *ras_core, + u32 *result) +{ + if (!result) + return -EINVAL; + + return __send_mp1_msg32(ras_core, RAS_MP1_MSG_EraseRasTable, 0, result); +} + +static int mp1_v13_0_get_record_count(struct ras_core_context *ras_core, + u32 *count) +{ + if (!count) + return -EINVAL; + + *count = 0; + + return __send_mp1_msg32(ras_core, RAS_MP1_MSG_GetBadPageCount, 0, count); +} + +static int mp1_v13_0_get_record(struct ras_core_context *ras_core, + u32 idx, struct eeprom_err_record *rec) +{ + int ret; + + if (!rec || (idx > 0xFFFFU)) + return -EINVAL; + + ret = __send_mp1_msg32(ras_core, RAS_MP1_MSG_GetTimestamp, + idx, &rec->timestamp_low); + if (ret) + return ret; + + ret = __send_mp1_msg32(ras_core, RAS_MP1_MSG_GetBadPageMcaAddr, + MSG_DATA_LOW32(idx), &rec->mca_addr_low); + if (ret) + return ret; + + ret = __send_mp1_msg32(ras_core, RAS_MP1_MSG_GetBadPageMcaAddr, + MSG_DATA_HIGH32(idx), &rec->mca_addr_high); + if (ret) + return ret; + + ret = __send_mp1_msg32(ras_core, RAS_MP1_MSG_GetBadPageIpId, + MSG_DATA_LOW32(idx), &rec->ipid_low); + if (ret) + return ret; + + ret = __send_mp1_msg32(ras_core, RAS_MP1_MSG_GetBadPageIpId, + MSG_DATA_HIGH32(idx), &rec->ipid_high); + + return ret; +} + static int __dump_mp1_bank_reg64(struct ras_core_context *ras_core, u32 msg, u32 idx, u32 reg_idx, u64 *val) { @@ -144,4 +230,10 @@ const struct ras_mp1_ip_func mp1_ras_func_v13_0 = { .get_valid_bank_count = mp1_v13_0_get_bank_count, .dump_valid_bank = mp1_v13_0_dump_bank, .set_debug_mode = mp1_v13_0_set_debug_mode, + .get_table_version = mp1_v13_0_get_table_version, + .rma_detected = mp1_v13_0_rma_detected, + .set_timestamp = mp1_v13_0_set_timestamp, + .reset_ras_table = mp1_v13_0_reset_ras_table, + .get_record_count = mp1_v13_0_get_record_count, + .get_record = mp1_v13_0_get_record, }; From 1f2a84c2922848d14e67620f3790d0240f0a876e Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Mon, 24 Aug 2026 16:32:56 +0800 Subject: [PATCH 010/103] drm/amd/ras: support aca debug mode for mp1 v13_0 Use uniras generic mp1 message to enable/disable aca debug mode on mp1 v13_0. Signed-off-by: YiPeng Chai Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c | 12 ++++++------ drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c b/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c index 5ace16ab4cbd..713c30c5e5a1 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c +++ b/drivers/gpu/drm/amd/ras/core/ras_mp1_v13_0.c @@ -29,6 +29,9 @@ #define MSG_DATA_LOW32(idx) (((idx) & 0xFFFFU) | BIT(16)) #define MSG_DATA_HIGH32(idx) (((idx) & 0xFFFFU) | BIT(17)) +#define MP1_V13_ClearMcaOnRead_UE_FLAG_MASK 0x1 +#define MP1_V13_ClearMcaOnRead_CE_POLL_MASK 0x2 + static int __send_mp1_msg32(struct ras_core_context *ras_core, enum ras_mp1_msg_id msg_id, u32 input, u32 *output) { @@ -216,13 +219,10 @@ static int mp1_v13_0_dump_bank(struct ras_core_context *ras_core, static int mp1_v13_0_set_debug_mode(struct ras_core_context *ras_core, bool enable) { - struct ras_mp1 *mp1 = &ras_core->ras_mp1; - const struct ras_mp1_sys_func *sys_func = mp1->sys_func; + u32 param = enable ? 0 : + (MP1_V13_ClearMcaOnRead_UE_FLAG_MASK | MP1_V13_ClearMcaOnRead_CE_POLL_MASK); - if (!sys_func || !sys_func->mp1_set_debug_mode) - return -RAS_CORE_NOT_SUPPORTED; - - return sys_func->mp1_set_debug_mode(ras_core, enable); + return __send_mp1_msg32(ras_core, RAS_MP1_MSG_ClearMcaOnRead, param, NULL); } diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c index 37d446798bd0..1ce5daf5a9bc 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c @@ -28,6 +28,7 @@ static const enum smu_message_type ras_smu_msg_maps[RAS_MP1_MSG_MAX] = { [RAS_MP1_MSG_QueryValidMcaCount] = SMU_MSG_QueryValidMcaCount, [RAS_MP1_MSG_McaBankDumpDW] = SMU_MSG_McaBankDumpDW, + [RAS_MP1_MSG_ClearMcaOnRead] = SMU_MSG_ClearMcaOnRead, [RAS_MP1_MSG_QueryValidMcaCeCount] = SMU_MSG_QueryValidMcaCeCount, [RAS_MP1_MSG_McaBankCeDumpDW] = SMU_MSG_McaBankCeDumpDW, [RAS_MP1_MSG_GetRasTableVersion] = SMU_MSG_GetRASTableVersion, From 5dc3f516cb610dd626178f36f9b25782e7a842dc Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Tue, 15 Sep 2026 12:10:07 +0530 Subject: [PATCH 011/103] drm/amdgpu: Fix NULL dereference in amdgpu_ualink_info_set_accel_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0a6da5dcfe42 ("drm/amdgpu: Improve ualink state transitions") introduced an access to info->accel_state before checking whether info is NULL. Move the access after the NULL check to avoid a potential NULL pointer dereference. Fixes: 0a6da5dcfe42 ("drm/amdgpu: Improve ualink state transitions") Reported-by: Dan Carpenter Cc: Lijo Lazar Cc: Felix Kuehling Cc: Christian König Cc: Alex Deucher Signed-off-by: Srinivasan Shanmugam Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c index b2c2650b0149..35aabc4c4526 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c @@ -162,7 +162,7 @@ amdgpu_ualink_info_set_accel_state(struct amdgpu_device *adev, struct amdgpu_ualink_info *info, enum psp_gfx_ual_config_state cfg_state) { - enum amdgpu_ualink_accel_state cur = info->accel_state; + enum amdgpu_ualink_accel_state cur; enum amdgpu_ualink_accel_state target; bool ppod_validated; bool vpod_validated; @@ -170,6 +170,8 @@ amdgpu_ualink_info_set_accel_state(struct amdgpu_device *adev, if (!info) return; + cur = info->accel_state; + ppod_validated = cur >= AMDGPU_UALINK_ACCEL_STATE_PPOD_CONFIGURED && cur <= AMDGPU_UALINK_ACCEL_STATE_ACTIVE; vpod_validated = cur >= AMDGPU_UALINK_ACCEL_STATE_VPOD_CONFIGURED && From 13d44ca033cb74756c2aef0ade54a75cdf2f6271 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 17 Sep 2026 18:56:45 +0530 Subject: [PATCH 012/103] drm/amdgpu/userq: fix double jiffies conversion in hang detect timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function amdgpu_userq_start_hang_detect_work() calls msecs_to_jiffies() on adev->gfx_timeout/compute_timeout/sdma_timeout before arming hang_detect_work. These timeout values already hold jiffies values from amdgpu_device_get_job_timeout_settings() at device init. This silently shrinks the real hang-detect deadline to (2 * HZ) ms instead of the intended timeout. e.g. 500ms instead of the 2000ms default on a CONFIG_HZ=250 kernel, only coincidentally correct at HZ=1000. The shortened window is easily exceeded by ordinary fence-completion latency, causing hang_detect_work to fire and trigger a per-queue or full GPU reset for queues that are not actually hung. Pass the jiffies value directly to queue_delayed_work() instead of converting it a second time. Fixes: fc3336be9c62 ("drm/amd/amdgpu: Add independent hang detect work for user queue fence") Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 5d07320a29b2..75d5ceaa53c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -184,27 +184,27 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work) void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue) { struct amdgpu_device *adev; - unsigned long timeout_ms; + unsigned long timeout_jiffies; adev = queue->userq_mgr->adev; /* Determine timeout based on queue type */ switch (queue->queue_type) { case AMDGPU_RING_TYPE_GFX: - timeout_ms = adev->gfx_timeout; + timeout_jiffies = adev->gfx_timeout; break; case AMDGPU_RING_TYPE_COMPUTE: - timeout_ms = adev->compute_timeout; + timeout_jiffies = adev->compute_timeout; break; case AMDGPU_RING_TYPE_SDMA: - timeout_ms = adev->sdma_timeout; + timeout_jiffies = adev->sdma_timeout; break; default: - timeout_ms = adev->gfx_timeout; + timeout_jiffies = adev->gfx_timeout; break; } queue_delayed_work(adev->reset_domain->wq, &queue->hang_detect_work, - msecs_to_jiffies(timeout_ms)); + timeout_jiffies); } void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell) From c73391c5898f206abc4ba8ccd2d1f4437c42aec3 Mon Sep 17 00:00:00 2001 From: Karl Mehltretter Date: Mon, 14 Sep 2026 07:46:04 +0200 Subject: [PATCH 013/103] drm/amdgpu: Initialize UALink handle uniqueness state amdgpu_generate_ualink_handle() continues when handle_lo is zero. For accelerator ID 0, the random value can become zero after the low 10 bits are cleared. This path reaches while (!unique) without assigning unique. Clang's -Wconditional-uninitialized reports the read. A reduced MemorySanitizer test reports use-of-uninitialized-value at the loop condition. If the uninitialized value ends the loop, handle 0 is inserted into exp_xa while robj->ualink_handle_lo still says that the BO has no handle. A later export can create another entry for the same BO. Initialize unique to false so the zero-handle path repeats the loop. Fixes: c67cb19811ec ("drm/amdgpu: Implement UALink handle export") Assisted-by: LLM Signed-off-by: Karl Mehltretter Signed-off-by: Felix Kuehling Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c index 35aabc4c4526..0d16047dca67 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c @@ -1822,7 +1822,7 @@ static void amdgpu_ualink_npa_mm_fini(struct amdgpu_device *adev) static void amdgpu_generate_ualink_handle(struct amdgpu_device *adev, struct amdgpu_ualink_handle *handle) { - bool unique; + bool unique = false; do { handle->handle_lo = get_random_u64(); From 61c057105de5f4f47f1142a836facc9237f99606 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Mon, 8 Jun 2026 22:48:21 -0400 Subject: [PATCH 014/103] drm/amdgpu: Resync UALink ring wptr after reboot When one side of UALink nodes reboots, its ring wptr resets to 0 while the peer keeps a stale value. Read the remote wptr and adopt it as the local wptr and rptr to resync, before the first message is sent. Either side can notice first, so do this both when setting up the connection and when receiving the HELLO from the peer. On the sdma path, read the wptr in a fence callback because the IB buffer holding the result is recycled once the fence signals, so reading it after dma_fence_wait_timeout() is too late. The lsdma path copies synchronously, so it reads the wptr directly. Take peer->lock in the callers (amdgpu_ualink_remote_interrupt and amdgpu_ualink_remote_shootdown) instead of in amdgpu_ualink_send_command, so the ring->ready check and the send are atomic against a concurrent ring reset. Move the rptr refresh and ring-full check out of amdgpu_ualink_send_command() into amdgpu_ualink_ring_check_space(), so it runs under the caller's peer->lock before the job is allocated. On a failed NPA-REQ send, reset the connection like the NPA-RSP timeout path already does, so the next attempt resyncs the ring wptr. On connection reset, amdgpu_ualink_reset_peer_rings() only clears ring->ready, so the writeback address is re-registered on the next send. v10: - Fix the resync missed on the receiving side: after a reboot the peer may send HELLO before we set up the connection, so resync the ring wptr in amdgpu_ualink_process_hello_msg() too. v9: - Fix the unnecessary connection reset after an app exits: the peer is idle here but still busy handling NPA revokes on the remote, so the HELLO reset a healthy connection. Only send it if the wptr changed. - Resync both rings together under peer->lock, read both remote wptr before updating either so a failed read changes nothing. v8: - Fix regression with concurrent import ioctls: do the idle check and ring reset in amdgpu_ualink_setup_connection() under conn_state->lock, and return -EAGAIN for IN_PROGRESS/PENDING first. - Reset the peer rings only, the imp/exp xarray cleanup is not needed to resync wptr. v7: - With v6 reboot one node of vPOD test passed on minirack. - Use the per-remote imported and exported handle lists for the idle check instead of walking the xarrays. - Rename amdgpu_ualink_resync_peer_rings() to amdgpu_ualink_reset_peer_rings(), it only clears ring->ready. v6: - Check idleness per remote accelerator instead of globally, and reset the stale connection at the import ioctl so the peer re-runs the HELLO handshake after a reboot. v5: - Resync the ring pointers at the import ioctl when the connection is completely idle (no exported or imported BOs), so the first command from a new application after a remote reboot/reset succeeds. - Put the sdma wptr read fence callback on the stack instead of allocating it; it is cancelled on timeout so it never outlives the call. v4: - Cancel the sdma fence callback on the wait timeout/failure path so it cannot write into the caller's stack after the function returns, and free the callback state in one place. v3: - Resync both rings at connection setup instead of on the send path. - Set the writeback rptr too, the stale value disagrees with the resynced wptr until the remote FW writes it back. v2: - Match the FW change: resync wptr only on the first send or after a timeout, instead of checking the remote periodically. Suggested-by: Felix Kuehling Signed-off-by: Philip Yang Reviewed-by: Felix Kuehling Reviewed-by: Mukul Joshi Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 343 +++++++++++++++++---- 1 file changed, 291 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c index 0d16047dca67..8411ea17172f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c @@ -56,6 +56,10 @@ static int amdgpu_ualink_remote_shootdown(struct amdgpu_device *adev, u32 size_in_pages, u32 flush_type); static void __amdgpu_ualink_activate_vpod_locked(struct amdgpu_device *adev); static bool amdgpu_ualink_vpod_membership_changed(struct amdgpu_device *adev); +static void amdgpu_ualink_reset_peer_rings(struct amdgpu_device *adev, + u32 remote_accel_id); +static int amdgpu_ualink_ring_resync_ptrs(struct amdgpu_device *adev, + u32 remote_accel_id); #define STRIP_NPA(addr) \ (((u64)(addr) & ~AMDGPU_UALINK_NPA_ADDR_GPUID_MASK)) @@ -2284,11 +2288,23 @@ static void amdgpu_ualink_process_hello_msg(struct amdgpu_device *adev, generation_count); } + /* Peer may have rebooted. */ + r = amdgpu_ualink_ring_resync_ptrs(adev, sender_acc_id); + if (r < 0) { + dev_err(adev->dev, + "HELLO: resync sender AccId %u ptrs failed %d\n", + sender_acc_id, r); + goto out_set_state; + } + if (r) + amdgpu_ualink_reset_peer_rings(adev, sender_acc_id); + r = amdgpu_ualink_send_hello_ack_msg(adev, sender_acc_id); if (r) dev_err(adev->dev, "HELLO-ACK: send failed to remote AccId:%u\n", sender_acc_id); +out_set_state: mutex_lock(&conn_state->lock); if (r) { conn_state->state = AMDGPU_UALINK_CONN_NOT_READY; @@ -2305,6 +2321,14 @@ static void amdgpu_ualink_process_hello_msg(struct amdgpu_device *adev, mutex_unlock(&conn_state->lock); } +/* True if nothing is exported to, or imported from, this remote accelerator. */ +static bool amdgpu_ualink_peer_idle(struct amdgpu_device *adev, u32 remote_accel_id) +{ + /* Unlocked: a racing import at worst costs one redundant ring resync. */ + return list_empty(&adev->ualink.imp_handles_list[remote_accel_id]) && + list_empty(&adev->ualink.exp_handles_list[remote_accel_id]); +} + static int amdgpu_ualink_setup_connection(struct amdgpu_device *adev, u32 remote_acc_id) { @@ -2326,16 +2350,31 @@ static int amdgpu_ualink_setup_connection(struct amdgpu_device *adev, * already done by another thread. */ mutex_lock(&conn_state->lock); - if (conn_state->state == AMDGPU_UALINK_CONN_ESTABLISHED) { - r = 0; - goto out; - } else if (conn_state->state == AMDGPU_UALINK_CONN_IN_PROGRESS || - conn_state->state == AMDGPU_UALINK_CONN_PENDING) { + if (conn_state->state == AMDGPU_UALINK_CONN_IN_PROGRESS || + conn_state->state == AMDGPU_UALINK_CONN_PENDING) { r = -EAGAIN; goto out; } + if (conn_state->state == AMDGPU_UALINK_CONN_ESTABLISHED && + !amdgpu_ualink_peer_idle(adev, remote_acc_id)) { + r = 0; + goto out; + } + + /* Peer is idle or not connected, it may have rebooted. Skip the + * handshake if the rings are still in sync, it would reset the remote. + */ + r = amdgpu_ualink_ring_resync_ptrs(adev, remote_acc_id); + if (r < 0) + goto out; + if (!r && conn_state->state == AMDGPU_UALINK_CONN_ESTABLISHED) + goto out; + + amdgpu_ualink_reset_peer_rings(adev, remote_acc_id); + conn_state->state = AMDGPU_UALINK_CONN_IN_PROGRESS; + mutex_unlock(&conn_state->lock); /* Send HELLO message */ @@ -3672,7 +3711,7 @@ static int amdgpu_ualink_do_import_handle(struct amdgpu_device *adev, dev_warn(adev->dev, "IMPORT: NPA-REQ send failed to remote AccId:%u\n", remote_acc_id); - return r; + goto reset_conn; } /* Wait for the NPA_RSP to come back */ @@ -5513,6 +5552,34 @@ static void amdgpu_ualink_emit_update_wb_addr(u32 **cpu_addr_p, u32 wb_data, typedef void (*ualink_emit_packet)(u32 **cpu_addr_p, u32 wb, u32 dw0, u32 dw1, u32 dw2, u32 dw3); +/* + * Refresh rptr from the writeback and check the ring has room for one more + * command. The caller must hold the peer lock. + * + * Return 0 on success or a negative error code. + */ +static int amdgpu_ualink_ring_check_space(struct amdgpu_device *adev, + u32 remote_accel_id, + struct amdgpu_ualink_ring *ring, + struct amdgpu_ualink_wb *wb_cpu) +{ + ring->rptr = READ_ONCE(wb_cpu->rptr); + + if (WARN_ON_ONCE(ring->rptr > ring->wptr)) { + dev_err(adev->dev, "accel_id %u ring overflow wptr 0x%llx rptr 0x%llx\n", + remote_accel_id, ring->wptr, ring->rptr); + return -EFAULT; + } + + if ((ring->wptr + 1 - ring->rptr) >= ring->rb_size) { + dev_err(adev->dev, "accel_id %u command ring full wptr 0x%llx rptr 0x%llx\n", + remote_accel_id, ring->wptr, ring->rptr); + return -ENOSPC; + } + + return 0; +} + static int amdgpu_ualink_send_command(struct amdgpu_device *adev, u32 remote_accel_id, struct amdgpu_ualink_ring *ring, @@ -5538,6 +5605,10 @@ static int amdgpu_ualink_send_command(struct amdgpu_device *adev, peer = &remote->peer[remote_accel_id]; + r = amdgpu_ualink_ring_check_space(adev, remote_accel_id, ring, wb_cpu); + if (r) + goto out; + /* * 3 sdma copy commands: write data to ring buffer, update wptr, ring doorbell * @@ -5554,25 +5625,7 @@ static int amdgpu_ualink_send_command(struct amdgpu_device *adev, ndw * 4, AMDGPU_IB_POOL_IMMEDIATE, AMDGPU_KERNEL_JOB_ID_TTM_COPY_BUFFER, &job); if (r) - return r; - - mutex_lock(&peer->lock); - - ring->rptr = READ_ONCE(wb_cpu->rptr); - - if (WARN_ON_ONCE(ring->rptr > ring->wptr)) { - dev_err(adev->dev, "accel_id %u ring overflow wptr 0x%llx rptr 0x%llx\n", - remote_accel_id, ring->wptr, ring->rptr); - r = -EFAULT; - goto unlock_free; - } - - if ((ring->wptr + 1 - ring->rptr) >= ring->rb_size) { - dev_err(adev->dev, "accel_id %u command ring full wptr 0x%llx rptr 0x%llx\n", - remote_accel_id, ring->wptr, ring->rptr); - r = -ENOSPC; - goto unlock_free; - } + goto out; ib = &job->ibs[0]; src = ib->gpu_addr + ndw_copy_cmd * 4; @@ -5630,12 +5683,11 @@ static int amdgpu_ualink_send_command(struct amdgpu_device *adev, dev_dbg(adev->dev, "remote %u lsdma copy failed (r %d), skip completion wait\n", remote_accel_id, r); - mutex_unlock(&peer->lock); return r; } goto out_wait_complete; - } + } sdma_ring = &adev->sdma.instance[0].ring; @@ -5666,12 +5718,9 @@ static int amdgpu_ualink_send_command(struct amdgpu_device *adev, if (r <= 0) { dev_dbg(adev->dev, "remote %u sdma fence wait return r %d\n", remote_accel_id, r); - if (r == 0) r = -ETIME; - - mutex_unlock(&peer->lock); - return r; + goto out; } out_wait_complete: @@ -5680,21 +5729,15 @@ out_wait_complete: */ r = amdgpu_ualink_remote_wait_timeout(adev, remote_accel_id, wb_cpu, seq); - /* increase local copy ring wptr, only if FW not timeout */ + /* + * Advance wptr unless the remote timed out, even if the FW returned an + * error status. On timeout the caller resets the connection, which + * resyncs wptr from the remote in amdgpu_ualink_setup_connection. + */ if (r != -ETIME) ring->wptr++; - /* - * Release ring lock after the remote FW handle command completes to - * prevent race conditions. - */ - mutex_unlock(&peer->lock); - return r; - - -unlock_free: - mutex_unlock(&peer->lock); - amdgpu_job_free(job); +out: dev_dbg(adev->dev, "ret r = %d\n", r); return r; } @@ -5734,6 +5777,196 @@ static void amdgpu_ualink_get_wb_addr(struct amdgpu_device *adev, remote_accel_id, npa + offset); } +struct amdgpu_ualink_wptr_fence_cb { + struct dma_fence_cb base; + u64 *wptr_cpu; + u64 result; +}; + +static void amdgpu_ualink_read_wptr_fence_cb(struct dma_fence *fence, + struct dma_fence_cb *cb) +{ + struct amdgpu_ualink_wptr_fence_cb *wptr_cb; + + wptr_cb = container_of(cb, typeof(*wptr_cb), base); + wptr_cb->result = *wptr_cb->wptr_cpu; +} + +static int amdgpu_ualink_read_remote_wptr(struct amdgpu_device *adev, + u32 remote_accel_id, + struct amdgpu_ualink_ring *ring, + u64 *wptr) +{ + struct amdgpu_ualink_remote *remote = to_remote(adev); + struct amdgpu_ualink_peer *peer = &remote->peer[remote_accel_id]; + struct amdgpu_ualink_wptr_fence_cb wptr_cb = { }; + struct amdgpu_ring *sdma_ring; + struct dma_fence *fence; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + u32 ndw, ndw_copy_cmd; + u64 wptr_gpu, *wptr_cpu; + int r; + + *wptr = 0; + + /* Refuse remote access unless active */ + if (adev->ualink.info->accel_state != AMDGPU_UALINK_ACCEL_STATE_ACTIVE) + return -ESHUTDOWN; + + /* 1 sdma copy command to read wptr */ + ndw_copy_cmd = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); + + /* wptr 2 dwords */ + ndw = ndw_copy_cmd + 2; + r = amdgpu_job_alloc_with_ib(adev, &peer->entity, AMDGPU_FENCE_OWNER_VM, + ndw * 4, AMDGPU_IB_POOL_IMMEDIATE, + AMDGPU_KERNEL_JOB_ID_TTM_COPY_BUFFER, &job); + if (r) + return r; + + ib = &job->ibs[0]; + wptr_gpu = ib->gpu_addr + ndw_copy_cmd * 4; + wptr_cpu = (u64 *)(ib->ptr + ndw_copy_cmd); + + dev_dbg(adev->dev, "read wptr from remote %u npa gart wptr 0x%llx use %s\n", + remote_accel_id, ring->wptr_npa_gart, + remote->use_lsdma ? "lsdma" : "sdma"); + + if (remote->use_lsdma) { + r = amdgpu_lsdma_copy_mem(adev, ring->wptr_npa_gart, wptr_gpu, 8); + if (!r) + *wptr = *wptr_cpu; + amdgpu_job_free(job); + goto out; + } + + wptr_cb.wptr_cpu = wptr_cpu; + + amdgpu_emit_copy_buffer(adev, ib, ring->wptr_npa_gart, wptr_gpu, 8, 0); + + sdma_ring = &adev->sdma.instance[0].ring; + amdgpu_ring_pad_ib(sdma_ring, ib); + WARN_ON(ib->length_dw > ndw_copy_cmd); + + fence = amdgpu_job_submit(job); + + r = dma_fence_add_callback(fence, &wptr_cb.base, + amdgpu_ualink_read_wptr_fence_cb); + if (r == -ENOENT) { + /* Fence already signaled; the callback won't run, do it inline. */ + amdgpu_ualink_read_wptr_fence_cb(fence, &wptr_cb.base); + r = 0; + goto out_put_fence; + } else if (r) { + /* -EINVAL: NULL fence or func, not expected here. */ + goto out_put_fence; + } + + r = dma_fence_wait_timeout(fence, false, AMDGPU_FENCE_JIFFIES_TIMEOUT); + if (r > 0) { + r = 0; /* read wptr successfully */ + goto out_put_fence; + } + + dev_dbg(adev->dev, "remote %u sdma fence wait return r %d\n", + remote_accel_id, r); + + if (r == 0) + r = -ETIME; + + /* + * Timed out: the callback is still armed and wptr_cb is on our stack. + * Cancel it so it can't fire after we return and write into the freed + * stack frame. + */ + dma_fence_remove_callback(fence, &wptr_cb.base); + +out_put_fence: + if (!r) + *wptr = wptr_cb.result; + dma_fence_put(fence); + +out: + dev_dbg(adev->dev, "remote %u wptr 0x%llx return %d\n", + remote_accel_id, *wptr, r); + return r; +} + +/** + * amdgpu_ualink_ring_resync_ptrs - sync local ring pointers from remote + * @adev: amdgpu device pointer + * @remote_accel_id: remote accelerator ID + * + * After a reboot on either side the two ends disagree on wptr. Read the remote + * wptr of both peer rings and adopt it as the local wptr and rptr. + * + * Return 0 if both rings already match, 1 if they were resynced, or a negative + * error code if a remote read failed, leaving the rings untouched. + */ +static int amdgpu_ualink_ring_resync_ptrs(struct amdgpu_device *adev, + u32 remote_accel_id) +{ + struct amdgpu_ualink_peer *peer = &to_remote(adev)->peer[remote_accel_id]; + struct amdgpu_ualink_wb *int_wb, *tlb_wb; + u64 int_wptr, tlb_wptr; + int r; + + /* ring->wptr and ring->rptr are owned by the send path. */ + guard(mutex)(&peer->lock); + + /* Read both before updating either, so a failure changes nothing. */ + r = amdgpu_ualink_read_remote_wptr(adev, remote_accel_id, + &peer->interrupt, &int_wptr); + if (!r) + r = amdgpu_ualink_read_remote_wptr(adev, remote_accel_id, + &peer->shootdown, &tlb_wptr); + if (r) { + dev_dbg(adev->dev, "accel_id %u read remote %u wptr failed %d\n", + ualink_accel_id(adev), remote_accel_id, r); + return r; + } + + if (peer->interrupt.wptr == int_wptr && peer->shootdown.wptr == tlb_wptr) { + dev_dbg(adev->dev, "accel_id %u wptr 0x%llx 0x%llx is same as remote %u\n", + ualink_accel_id(adev), int_wptr, tlb_wptr, remote_accel_id); + return 0; + } + + dev_dbg(adev->dev, + "accel_id %u wptr 0x%llx 0x%llx sync to remote %u wptr 0x%llx 0x%llx\n", + ualink_accel_id(adev), peer->interrupt.wptr, peer->shootdown.wptr, + remote_accel_id, int_wptr, tlb_wptr); + + amdgpu_ualink_get_wb_addr(adev, remote_accel_id, &int_wb, NULL, + RB_TYPE_REMOTE_INTERRUPT); + amdgpu_ualink_get_wb_addr(adev, remote_accel_id, &tlb_wb, NULL, + RB_TYPE_TLB_INV); + + peer->interrupt.wptr = int_wptr; + peer->interrupt.rptr = int_wptr; + peer->shootdown.wptr = tlb_wptr; + peer->shootdown.rptr = tlb_wptr; + + /* Drop the stale writeback rptr, it disagrees with the resynced wptr. */ + WRITE_ONCE(int_wb->rptr, int_wptr); + WRITE_ONCE(tlb_wb->rptr, tlb_wptr); + return 1; +} + +static void amdgpu_ualink_reset_peer_rings(struct amdgpu_device *adev, + u32 remote_accel_id) +{ + struct amdgpu_ualink_peer *peer = &to_remote(adev)->peer[remote_accel_id]; + + dev_dbg(adev->dev, "remote accel_id %u\n", remote_accel_id); + + guard(mutex)(&peer->lock); + + peer->interrupt.ready = false; + peer->shootdown.ready = false; +} + static int amdgpu_ualink_update_wb_address(struct amdgpu_device *adev, u32 remote_accel_id, u32 ring_type) { @@ -5796,6 +6029,9 @@ static int amdgpu_ualink_remote_shootdown(struct amdgpu_device *adev, peer = &remote->peer[remote_accel_id]; ring = &peer->shootdown; + + guard(mutex)(&peer->lock); + if (!ring->ready) { dev_dbg(adev->dev, "accel_id %u ring not ready\n", remote_accel_id); r = amdgpu_ualink_update_wb_address(adev, remote_accel_id, @@ -5804,11 +6040,11 @@ static int amdgpu_ualink_remote_shootdown(struct amdgpu_device *adev, return r; } - r = amdgpu_ualink_send_command(adev, remote_accel_id, ring, ring->wb_cpu, - amdgpu_ualink_emit_shootdown, - flush_type, upper_32_bits(addr), - lower_32_bits(addr), size_in_pages); - return r; + return amdgpu_ualink_send_command(adev, remote_accel_id, ring, + ring->wb_cpu, + amdgpu_ualink_emit_shootdown, + flush_type, upper_32_bits(addr), + lower_32_bits(addr), size_in_pages); } /** @@ -5837,6 +6073,9 @@ static int amdgpu_ualink_remote_interrupt(struct amdgpu_device *adev, peer = &remote->peer[remote_accel_id]; ring = &peer->interrupt; + + guard(mutex)(&peer->lock); + if (!ring->ready) { dev_dbg(adev->dev, "accel_id %u ring not ready\n", remote_accel_id); r = amdgpu_ualink_update_wb_address(adev, remote_accel_id, @@ -5845,10 +6084,10 @@ static int amdgpu_ualink_remote_interrupt(struct amdgpu_device *adev, return r; } - r = amdgpu_ualink_send_command(adev, remote_accel_id, ring, ring->wb_cpu, - amdgpu_ualink_emit_interrupt, - dw0, dw1, dw2, dw3); - return r; + return amdgpu_ualink_send_command(adev, remote_accel_id, ring, + ring->wb_cpu, + amdgpu_ualink_emit_interrupt, + dw0, dw1, dw2, dw3); } /** From b8334fec8b90ebffcaa01001a23edca9f29a05e9 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 17 Sep 2026 18:56:45 +0530 Subject: [PATCH 015/103] drm/amdgpu/vcn5.0.1: fix video_timeout unit mismatch in jpeg reset wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vcn_v5_0_1_reset_jpeg_pre_helper() passes adev->video_timeout directly to amdgpu_fence_wait_polling(), whose timeout parameter is documented and implemented in usecs (busy-wait loop decrementing by udelay(2)). adev->video_timeout is set in jiffies by amdgpu_device_get_job_timeout_settings(), via msecs_to_jiffies(). Passing it unconverted means the intended ~2s wait for outstanding JPEG fences to complete before the JPEG queue is torn down actually lasts only a couple of microseconds (HZ jiffies interpreted as usecs), so pending jobs are almost never given a real chance to finish before the reset path forces completion in the following helper. Convert the jiffies value to usecs with jiffies_to_usecs() before passing it to amdgpu_fence_wait_polling(). Fixes: fab47d2db5ca ("drm/amdgpu/vcn5.0.1: rework reset handling") Cc: Jesse.Zhang Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c index 09e553b8a657..c9e990ab297d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c @@ -1336,7 +1336,8 @@ static int vcn_v5_0_1_reset_jpeg_pre_helper(struct amdgpu_device *adev, int inst /* if Jobs are still pending after timeout, * We'll handle them in the bottom helper */ - amdgpu_fence_wait_polling(ring, wait_seq, adev->video_timeout); + amdgpu_fence_wait_polling(ring, wait_seq, + jiffies_to_usecs(adev->video_timeout)); } return 0; From 5feabbd673c10ebee22b880e4d812f08974d2ef7 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 17 Sep 2026 18:56:45 +0530 Subject: [PATCH 016/103] drm/amdgpu/vcn4.0.3: fix video_timeout unit mismatch in jpeg reset wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vcn_v4_0_3_reset_jpeg_pre_helper() passes adev->video_timeout directly to amdgpu_fence_wait_polling(), whose timeout parameter is documented and implemented in usecs (busy-wait loop decrementing by udelay(2)). adev->video_timeout is set in jiffies by amdgpu_device_get_job_timeout_settings(), via msecs_to_jiffies(). Passing it unconverted means the intended ~2s wait for outstanding JPEG fences to complete before the JPEG queue is torn down actually lasts only a couple of microseconds (HZ jiffies interpreted as usecs), so pending jobs are almost never given a real chance to finish before the reset path forces completion in the following helper. Convert the jiffies value to usecs with jiffies_to_usecs() before passing it to amdgpu_fence_wait_polling(). Fixes: d25c67fd9d6f ("drm/amdgpu/vcn4.0.3: rework reset handling") Cc: Jesse.Zhang Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c index 2fa8f0d911d0..3f39aa83c319 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c @@ -1690,7 +1690,8 @@ static int vcn_v4_0_3_reset_jpeg_pre_helper(struct amdgpu_device *adev, int inst /* if Jobs are still pending after timeout, * We'll handle them in the bottom helper */ - amdgpu_fence_wait_polling(ring, wait_seq, adev->video_timeout); + amdgpu_fence_wait_polling(ring, wait_seq, + jiffies_to_usecs(adev->video_timeout)); } return 0; From 6ae5eaab20c8442ad4663d4ed0bc613b8965c561 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 17 Sep 2026 18:58:26 +0530 Subject: [PATCH 017/103] drm/amdgpu/mes12: add more debug info on MES packet failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When MES fails to respond to a packet, the existing failure log only prints the op name. Add fence_wait_ret and the packet's status word to the same message, so a fence-wait timeout (MES itself stalled) can be told apart from a fast explicit rejection (fence signaled, but the low status word is 0) directly from the log, along with the MES-reported error code carried in the high status word for the latter case. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v12_0.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c index 9e149cf98889..9d220bff0f6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c @@ -240,14 +240,20 @@ static int mes_v12_0_submit_pkt_and_poll_completion(struct amdgpu_mes *mes, if (r < 1 || !(lower_32_bits(*status_ptr))) { if (misc_op_str) - dev_err(adev->dev, "MES(%d) failed to respond to msg=%s (%s)\n", - pipe, op_str, misc_op_str); + dev_err(adev->dev, + "MES(%d) failed to respond to msg=%s (%s) fence_wait_ret=%ld status=0x%x_%x\n", + pipe, op_str, misc_op_str, r, + upper_32_bits(*status_ptr), lower_32_bits(*status_ptr)); else if (op_str) - dev_err(adev->dev, "MES(%d) failed to respond to msg=%s\n", - pipe, op_str); + dev_err(adev->dev, + "MES(%d) failed to respond to msg=%s fence_wait_ret=%ld status=0x%x_%x\n", + pipe, op_str, r, + upper_32_bits(*status_ptr), lower_32_bits(*status_ptr)); else - dev_err(adev->dev, "MES(%d) failed to respond to msg=%d\n", - pipe, x_pkt->header.opcode); + dev_err(adev->dev, + "MES(%d) failed to respond to msg=%d fence_wait_ret=%ld status=0x%x_%x\n", + pipe, x_pkt->header.opcode, r, + upper_32_bits(*status_ptr), lower_32_bits(*status_ptr)); while (halt_if_hws_hang) schedule(); From dca2c40dc925513c610fba8368a1d6019ad36baa Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 17 Sep 2026 18:58:27 +0530 Subject: [PATCH 018/103] drm/amdgpu/mes11: add more debug info on MES packet failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When MES fails to respond to a packet, the existing failure log only prints the op name. Add fence_wait_ret and the packet's status word to the same message. status_ptr is written directly by MES as part of completing the packet, independently of the ring fence that fence_wait_ret waits on, so a nonzero status despite a timed-out fence_wait_ret narrows the failure to the trailing ring/query-status packet rather than the original request. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index c81e4b8616d0..51bfb672bed7 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -257,14 +257,17 @@ static int mes_v11_0_submit_pkt_and_poll_completion(struct amdgpu_mes *mes, if (r < 1 || !*status_ptr) { if (misc_op_str) - dev_err(adev->dev, "MES failed to respond to msg=%s (%s)\n", - op_str, misc_op_str); + dev_err(adev->dev, + "MES failed to respond to msg=%s (%s) fence_wait_ret=%ld status=0x%llx\n", + op_str, misc_op_str, r, *status_ptr); else if (op_str) - dev_err(adev->dev, "MES failed to respond to msg=%s\n", - op_str); + dev_err(adev->dev, + "MES failed to respond to msg=%s fence_wait_ret=%ld status=0x%llx\n", + op_str, r, *status_ptr); else - dev_err(adev->dev, "MES failed to respond to msg=%d\n", - x_pkt->header.opcode); + dev_err(adev->dev, + "MES failed to respond to msg=%d fence_wait_ret=%ld status=0x%llx\n", + x_pkt->header.opcode, r, *status_ptr); while (halt_if_hws_hang) schedule(); From 0bd9d38e3ea68622e3306db03135e3ca08bbf1f0 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 17 Sep 2026 18:58:27 +0530 Subject: [PATCH 019/103] drm/amdgpu/mes12.1: add more debug info on MES packet failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When MES fails to respond to a packet, the existing failure log only prints the op name. Add fence_wait_ret and the packet's status word to the same message. status_ptr is written directly by MES as part of completing the packet, independently of the ring fence that fence_wait_ret waits on, so a nonzero status despite a timed-out fence_wait_ret narrows the failure to the trailing ring/query-status packet rather than the original request. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v12_1.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c index 7459547b7a69..20159fb9d6ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c @@ -236,16 +236,16 @@ static int mes_v12_1_submit_pkt_and_poll_completion(struct amdgpu_mes *mes, if (r < 1 || !*status_ptr) { if (misc_op_str) dev_err(adev->dev, - "MES(%d, %d) failed to respond to msg=%s (%s)\n", - xcc_id, pipe, op_str, misc_op_str); + "MES(%d, %d) failed to respond to msg=%s (%s) fence_wait_ret=%ld status=0x%x\n", + xcc_id, pipe, op_str, misc_op_str, r, *status_ptr); else if (op_str) dev_err(adev->dev, - "MES(%d, %d) failed to respond to msg=%s\n", - xcc_id, pipe, op_str); + "MES(%d, %d) failed to respond to msg=%s fence_wait_ret=%ld status=0x%x\n", + xcc_id, pipe, op_str, r, *status_ptr); else dev_err(adev->dev, - "MES(%d, %d) failed to respond to msg=%d\n", - xcc_id, pipe, x_pkt->header.opcode); + "MES(%d, %d) failed to respond to msg=%d fence_wait_ret=%ld status=0x%x\n", + xcc_id, pipe, x_pkt->header.opcode, r, *status_ptr); while (halt_if_hws_hang) schedule(); From b922c91b95f2f6d5daf39e8f19dbde11ca3c0747 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Tue, 25 Aug 2026 09:53:32 +0800 Subject: [PATCH 020/103] drm/amd/ras: add MP1 RAS feature status query Add a generic MP1 interface to query the status of RAS-related SMU features, including the PMFW EEPROM feature. Signed-off-by: YiPeng Chai Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/core/ras.h | 2 ++ drivers/gpu/drm/amd/ras/core/ras_mp1.c | 13 +++++++++ drivers/gpu/drm/amd/ras/core/ras_mp1.h | 7 +++++ .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c | 28 +++++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/drivers/gpu/drm/amd/ras/core/ras.h b/drivers/gpu/drm/amd/ras/core/ras.h index fcea457d5cbe..47fa30f94a2a 100644 --- a/drivers/gpu/drm/amd/ras/core/ras.h +++ b/drivers/gpu/drm/amd/ras/core/ras.h @@ -216,6 +216,8 @@ struct ras_mp1_sys_func { int (*mp1_set_debug_mode)(struct ras_core_context *ras_core, bool enable); int (*mp1_send_ras_msg)(struct ras_core_context *ras_core, u32 msg_id, u32 *params, u32 num_params, u32 *read_args, u32 num_read_args); + int (*check_ras_feature_status)(struct ras_core_context *ras_core, + enum ras_mp1_feature_id feature_id, u32 *status); }; struct ras_eeprom_param_config { diff --git a/drivers/gpu/drm/amd/ras/core/ras_mp1.c b/drivers/gpu/drm/amd/ras/core/ras_mp1.c index 0f5140abb6a8..4c180027850f 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_mp1.c +++ b/drivers/gpu/drm/amd/ras/core/ras_mp1.c @@ -183,6 +183,19 @@ int ras_mp1_set_debug_mode(struct ras_core_context *ras_core, bool enable) return mp1->ip_func->set_debug_mode(ras_core, enable); } +int ras_mp1_check_feature_status(struct ras_core_context *ras_core, + enum ras_mp1_feature_id feature_id, u32 *status) +{ + struct ras_mp1 *mp1 = &ras_core->ras_mp1; + + if (!mp1->sys_func || + !mp1->sys_func->check_ras_feature_status) + return -EOPNOTSUPP; + + return mp1->sys_func->check_ras_feature_status(ras_core, + feature_id, status); +} + int ras_mp1_sw_init(struct ras_core_context *ras_core) { struct ras_mp1 *mp1 = &ras_core->ras_mp1; diff --git a/drivers/gpu/drm/amd/ras/core/ras_mp1.h b/drivers/gpu/drm/amd/ras/core/ras_mp1.h index 410530fb8ada..b872fc975866 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_mp1.h +++ b/drivers/gpu/drm/amd/ras/core/ras_mp1.h @@ -28,6 +28,11 @@ #define MAX_UE_BANKS_PER_QUERY 12 #define MAX_CE_BANKS_PER_QUERY 12 +enum ras_mp1_feature_id { + RAS_MP1_FEATURE_PMFW_EEPROM, + RAS_MP1_FEATURE_MAX +}; + enum ras_mp1_msg_id { RAS_MP1_MSG_QueryValidMcaCount, RAS_MP1_MSG_McaBankDumpDW, @@ -122,4 +127,6 @@ int ras_mp1_reset_ras_table(struct ras_core_context *ras_core, int ras_mp1_get_record_count(struct ras_core_context *ras_core, u32 *count); int ras_mp1_get_record(struct ras_core_context *ras_core, u32 idx, struct eeprom_err_record *rec); +int ras_mp1_check_feature_status(struct ras_core_context *ras_core, + enum ras_mp1_feature_id feature_id, u32 *status); #endif diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c index 1ce5daf5a9bc..7ca2f33f2cf0 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1.c @@ -25,6 +25,10 @@ #include "amdgpu_reset.h" #include "ras.h" +static const enum smu_feature_mask ras_smu_feature_masks[RAS_MP1_FEATURE_MAX] = { + [RAS_MP1_FEATURE_PMFW_EEPROM] = SMU_FEATURE_HROM_EN_BIT, +}; + static const enum smu_message_type ras_smu_msg_maps[RAS_MP1_MSG_MAX] = { [RAS_MP1_MSG_QueryValidMcaCount] = SMU_MSG_QueryValidMcaCount, [RAS_MP1_MSG_McaBankDumpDW] = SMU_MSG_McaBankDumpDW, @@ -50,6 +54,29 @@ static enum smu_message_type return ras_smu_msg_maps[msg_id]; } +static int amdgpu_ras_check_ras_feature_status(struct ras_core_context *ras_core, + enum ras_mp1_feature_id feature_id, u32 *status) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; + u32 res = 0; + + if (!status || (feature_id >= RAS_MP1_FEATURE_MAX)) + return -EINVAL; + + if (down_read_trylock(&adev->reset_domain->sem)) { + if (amdgpu_smu_ras_feature_is_enabled(adev, + ras_smu_feature_masks[feature_id])) + res = 1; + up_read(&adev->reset_domain->sem); + } else { + return -RAS_CORE_GPU_IN_MODE1_RESET; + } + + *status = res; + + return 0; +} + static int amdgpu_ras_send_mp1_msg(struct ras_core_context *ras_core, u32 msg_id, u32 *params, u32 num_params, u32 *read_args, u32 num_read_args) { @@ -74,4 +101,5 @@ static int amdgpu_ras_send_mp1_msg(struct ras_core_context *ras_core, u32 msg_id const struct ras_mp1_sys_func amdgpu_ras_mp1_sys_func = { .mp1_send_ras_msg = amdgpu_ras_send_mp1_msg, + .check_ras_feature_status = amdgpu_ras_check_ras_feature_status, }; From 895891da970981ca48b0d67b3ff880520b369823 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Fri, 21 Aug 2026 14:32:37 +0800 Subject: [PATCH 021/103] drm/amd/ras: use common mp1 ras interface for v13 Use the common mp1 ras manager interface for MP1 v13_0. Signed-off-by: YiPeng Chai Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c index eb72d030b66e..bd2c7e464993 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c @@ -158,8 +158,6 @@ static int amdgpu_ras_mgr_init_mp1_config(struct amdgpu_device *adev, case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 14): case IP_VERSION(13, 0, 12): - mp1_cfg->mp1_sys_fn = &amdgpu_ras_mp1_sys_func_v13_0; - break; case IP_VERSION(15, 0, 8): mp1_cfg->mp1_sys_fn = &amdgpu_ras_mp1_sys_func; break; From f8753e547a9c4f583cc8058f6bb9e93e303feb88 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Mon, 24 Aug 2026 17:42:58 +0800 Subject: [PATCH 022/103] drm/amd/ras: remove obsolete ras mp1 v13 manager code Remove obsolete ras mp1 v13 manager code. Signed-off-by: YiPeng Chai Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/core/ras.h | 9 - drivers/gpu/drm/amd/ras/ras_mgr/Makefile | 1 - .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c | 1 - .../amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c | 161 ------------------ .../amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.h | 30 ---- 5 files changed, 202 deletions(-) delete mode 100644 drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c delete mode 100644 drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.h diff --git a/drivers/gpu/drm/amd/ras/core/ras.h b/drivers/gpu/drm/amd/ras/core/ras.h index 47fa30f94a2a..73e3960c7c8e 100644 --- a/drivers/gpu/drm/amd/ras/core/ras.h +++ b/drivers/gpu/drm/amd/ras/core/ras.h @@ -205,15 +205,6 @@ struct ras_psp; struct ras_eeprom_mgr; struct ras_mp1_sys_func { - int (*mp1_get_valid_bank_count)(struct ras_core_context *ras_core, - u32 msg, u32 *count); - int (*mp1_dump_valid_bank)(struct ras_core_context *ras_core, - u32 msg, u32 idx, u32 reg_idx, u64 *val); - int (*mp1_send_eeprom_msg)(struct ras_core_context *ras_core, - u32 msg_id, uint32_t param, uint32_t *read_arg); - int (*mp1_get_ras_enabled_mask)(struct ras_core_context *ras_core, - uint64_t *enabled_mask); - int (*mp1_set_debug_mode)(struct ras_core_context *ras_core, bool enable); int (*mp1_send_ras_msg)(struct ras_core_context *ras_core, u32 msg_id, u32 *params, u32 num_params, u32 *read_args, u32 num_read_args); int (*check_ras_feature_status)(struct ras_core_context *ras_core, diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/Makefile b/drivers/gpu/drm/amd/ras/ras_mgr/Makefile index 4f94c97c15ca..c70760f10ffd 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/Makefile +++ b/drivers/gpu/drm/amd/ras/ras_mgr/Makefile @@ -21,7 +21,6 @@ RAS_MGR_FILES = amdgpu_ras_sys.o \ amdgpu_ras_mgr.o \ amdgpu_ras_eeprom_i2c.o \ - amdgpu_ras_mp1_v13_0.o \ amdgpu_ras_mp1.o \ amdgpu_ras_cmd.o \ amdgpu_virt_ras_cmd.o \ diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c index bd2c7e464993..eb5722a59786 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c @@ -30,7 +30,6 @@ #include "amdgpu_virt_ras_cmd.h" #include "amdgpu_ras_process.h" #include "amdgpu_ras_eeprom_i2c.h" -#include "amdgpu_ras_mp1_v13_0.h" #include "amdgpu_ras_mp1.h" #include "amdgpu_ras_nbio_v7_9.h" #include "amdgpu_ras_bert.h" diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c deleted file mode 100644 index 548594373d0b..000000000000 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright 2025 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu_smu.h" -#include "amdgpu_reset.h" -#include "amdgpu_ras_mp1_v13_0.h" -#include "smu13_driver_if_v13_0_6.h" - -#define RAS_MP1_MSG_QueryValidMcaCeCount 0x3A -#define RAS_MP1_MSG_McaBankCeDumpDW 0x3B - -static const enum smu_message_type pmfw_eeprom_msgs[] = { - [RAS_SMU_GetRASTableVersion] = SMU_MSG_GetRASTableVersion, - [RAS_SMU_GetBadPageCount] = SMU_MSG_GetBadPageCount, - [RAS_SMU_SetTimestamp] = SMU_MSG_SetTimestamp, - [RAS_SMU_GetTimestamp] = SMU_MSG_GetTimestamp, - [RAS_SMU_GetBadPageIpid] = SMU_MSG_GetBadPageIpid, - [RAS_SMU_EraseRasTable] = SMU_MSG_EraseRasTable, - [RAS_SMU_GetBadPageMcaAddr] = SMU_MSG_GetBadPageMcaAddr, -}; - -static int mp1_v13_send_smu_msg(struct amdgpu_device *adev, enum smu_message_type msg, - uint32_t param, uint32_t *read_arg) -{ - return amdgpu_smu_ras_send_msg(adev, msg, ¶m, 1, read_arg, read_arg ? 1 : 0); -} - -static int mp1_v13_0_get_valid_bank_count(struct ras_core_context *ras_core, - u32 msg, u32 *count) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; - u32 smu_msg; - int ret = 0; - - if (!count) - return -EINVAL; - - smu_msg = (msg == RAS_MP1_MSG_QueryValidMcaCeCount) ? - SMU_MSG_QueryValidMcaCeCount : SMU_MSG_QueryValidMcaCount; - - if (down_read_trylock(&adev->reset_domain->sem)) { - ret = mp1_v13_send_smu_msg(adev, smu_msg, 0, count); - up_read(&adev->reset_domain->sem); - } else { - ret = -RAS_CORE_GPU_IN_MODE1_RESET; - } - - if (ret) - *count = 0; - - return ret; -} - -static int mp1_v13_0_dump_valid_bank(struct ras_core_context *ras_core, - u32 msg, u32 idx, u32 reg_idx, u64 *val) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; - uint32_t data[2] = {0, 0}; - uint32_t param; - int ret = 0; - int i, offset; - u32 smu_msg = (msg == RAS_MP1_MSG_McaBankCeDumpDW) ? - SMU_MSG_McaBankCeDumpDW : SMU_MSG_McaBankDumpDW; - - if (down_read_trylock(&adev->reset_domain->sem)) { - offset = reg_idx * 8; - for (i = 0; i < ARRAY_SIZE(data); i++) { - param = ((idx & 0xffff) << 16) | ((offset + (i << 2)) & 0xfffc); - ret = mp1_v13_send_smu_msg(adev, smu_msg, param, &data[i]); - if (ret) { - RAS_DEV_ERR(adev, "ACA failed to read register[%d], offset:0x%x\n", - reg_idx, offset); - break; - } - } - up_read(&adev->reset_domain->sem); - - if (!ret) - *val = (uint64_t)data[1] << 32 | data[0]; - } else { - ret = -RAS_CORE_GPU_IN_MODE1_RESET; - } - - return ret; -} - -static int mp1_v13_0_eeprom_send_msg(struct ras_core_context *ras_core, - u32 msg_id, uint32_t param, uint32_t *read_arg) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; - int ret = 0; - - if (down_read_trylock(&adev->reset_domain->sem)) { - ret = mp1_v13_send_smu_msg(adev, - pmfw_eeprom_msgs[msg_id], param, read_arg); - up_read(&adev->reset_domain->sem); - } else { - ret = -RAS_CORE_GPU_IN_MODE1_RESET; - } - - return ret; -} - -static int mp1_v13_0_get_ras_enabled_mask(struct ras_core_context *ras_core, - uint64_t *enabled_mask) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; - int ret = 0; - - if (down_read_trylock(&adev->reset_domain->sem)) { - if (amdgpu_smu_ras_feature_is_enabled(adev, SMU_FEATURE_HROM_EN_BIT)) - *enabled_mask |= RAS_CORE_FW_FEATURE_BIT__RAS_EEPROM; - up_read(&adev->reset_domain->sem); - } else { - ret = -RAS_CORE_GPU_IN_MODE1_RESET; - } - - return ret; -} - -static int mp1_v13_0_set_debug_mode(struct ras_core_context *ras_core, bool enable) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; - u32 param = enable ? 0 : ClearMcaOnRead_UE_FLAG_MASK | - ClearMcaOnRead_CE_POLL_MASK; - int ret; - u32 smu_msg = SMU_MSG_ClearMcaOnRead; - - ret = amdgpu_smu_ras_send_msg(adev, smu_msg, - ¶m, 1, NULL, 0); - return ret; -} - -const struct ras_mp1_sys_func amdgpu_ras_mp1_sys_func_v13_0 = { - .mp1_get_valid_bank_count = mp1_v13_0_get_valid_bank_count, - .mp1_dump_valid_bank = mp1_v13_0_dump_valid_bank, - .mp1_send_eeprom_msg = mp1_v13_0_eeprom_send_msg, - .mp1_get_ras_enabled_mask = mp1_v13_0_get_ras_enabled_mask, - .mp1_set_debug_mode = mp1_v13_0_set_debug_mode, -}; - diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.h b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.h deleted file mode 100644 index 71c614ae1ae4..000000000000 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright 2025 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __AMDGPU_RAS_MP1_V13_0_H__ -#define __AMDGPU_RAS_MP1_V13_0_H__ -#include "ras.h" - -extern const struct ras_mp1_sys_func amdgpu_ras_mp1_sys_func_v13_0; - -#endif From 52a484f3ef5b36c063d8fca7b8763c1a9676c625 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 3 Sep 2026 11:22:10 +0530 Subject: [PATCH 023/103] drm/amdgpu: Move GC v12.1 spm vmid init to hw init GC reset is not released during sw init and hence it shouldn't be accessed. Move spm vmid programming to hw init phase. This programming may later be overridden with the job's vmid. Fixes: ad5f1ee0a9b0 ("drm/amdgpu: Add initial support for gfx v12_1") Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c index 1a09bd41f795..db541939555b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c @@ -213,6 +213,8 @@ static void gfx_v12_1_xcc_update_perf_clk(struct amdgpu_device *adev, static int gfx_v12_1_init_cp_compute_microcode_bo(struct amdgpu_device *adev); static void gfx_v12_1_xcc_update_medium_grain_clock_gating( struct amdgpu_device *adev, bool enable, int xcc_id, bool force); +static void gfx_v12_1_update_spm_vmid(struct amdgpu_device *adev, int xcc_id, + struct amdgpu_ring *ring, unsigned vmid); static void gfx_v12_1_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, int mem_space, int opt, uint32_t addr0, @@ -544,7 +546,7 @@ static void gfx_v12_1_init_rlcg_reg_access_ctrl(struct amdgpu_device *adev) static int gfx_v12_1_rlc_init(struct amdgpu_device *adev) { const struct cs_section_def *cs_data; - int r, i, num_xcc; + int r; adev->gfx.rlc.cs_data = gfx12_cs_data; @@ -557,13 +559,6 @@ static int gfx_v12_1_rlc_init(struct amdgpu_device *adev) return r; } - /* init spm vmid with 0xf */ - num_xcc = NUM_XCC(adev->gfx.xcc_mask); - for (i = 0; i < num_xcc; i++) { - if (adev->gfx.rlc.funcs->update_spm_vmid) - adev->gfx.rlc.funcs->update_spm_vmid(adev, i, NULL, 0xf); - } - return 0; } @@ -1836,6 +1831,9 @@ static int gfx_v12_1_xcc_rlc_resume(struct amdgpu_device *adev, { int r; + /* init spm vmid with 0xf */ + gfx_v12_1_update_spm_vmid(adev, xcc_id, NULL, 0xf); + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { gfx_v12_1_xcc_init_csb(adev, xcc_id); From 1128b4a52de1572e87431de837fd9850cb99542c Mon Sep 17 00:00:00 2001 From: Asad Kamal Date: Fri, 28 Aug 2026 15:59:21 +0800 Subject: [PATCH 024/103] drm/amdkfd: fix use-after-free and multi-container gap in kfd_dev_mapping kfd_dev_mapping caches the address_space of the first /dev/kfd opener so that the GPU reset path can call unmap_mapping_range() to zap all userspace mappings of doorbell and MMIO ranges. This design has two bugs that both manifest under SRIOV with multiple containers: 1. Use-after-free / rwsem deadlock. The cached pointer refers to an inode owned by the first opener's container. When that container exits and its inode is released, kfd_dev_mapping becomes a dangling pointer. A subsequent GPU reset dereferences it inside unmap_mapping_range(), which takes i_mmap_rwsem on the freed inode, causing a hard hang observable as an uninterruptible rwsem wait. 2. Multi-container gap. Only the first opener's address_space is cached; VMAs created by later openers live in a different address_space and are never reached by unmap_mapping_range(). After a GPU reset those stale mappings keep doorbell and MMIO pages accessible to guest userspace with no GPU behind them, risking PCIe transaction timeouts and NMI panics. Fix both bugs with the same approach used by DRM core (drm_drv.c): create a private pseudo-filesystem at module init time and allocate one anonymous inode from it. In kfd_open() redirect every opener's file->f_mapping to that inode's address_space. The inode is module-owned, lives exactly as long as the amdgpu module, and collects VMAs from all openers in one address_space. A single unmap_mapping_range() call in the reset path then correctly reaches every container's mappings with no dangling pointer risk. The hang manifests as an NMI backtrace on the GPU reset workqueue stuck spinning in rwsem_down_read_slowpath() with a corrupted i_mmap_rwsem: Workqueue: amdgpu-reset-dev xgpu_ai_mailbox_flr_work [amdgpu] Call Trace: kvm_wait+0x1f/0x40 __pv_queued_spin_lock_slowpath+0x31d/0x3a0 _raw_spin_lock_irq+0x51/0x80 rwsem_down_read_slowpath+0xb3/0x550 down_read+0x48/0xd0 unmap_mapping_range+0x71/0x140 kfd_dev_unmap_mapping_range+0x5b/0x140 [amdgpu] amdgpu_amdkfd_clear_kfd_mapping+0xd8/0x190 [amdgpu] amdgpu_device_gpu_recover+0x232/0x450 [amdgpu] xgpu_ai_mailbox_flr_work+0xb5/0xc0 [amdgpu] process_one_work+0x18e/0x3e0 worker_thread+0x2e3/0x420 kthread+0x10a/0x230 Fixes: 70cadefcc616 ("drm/amdgpu: unmap all user mappings of framebuffer and doorbell before mode1 reset") Signed-off-by: Asad Kamal Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 71 +++++++++++++++++++----- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 504a286368eb..344da6c0e96a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -70,18 +71,54 @@ static const struct class kfd_class = { }; /* - * Cache the address space of the chardev on first open so that the reset - * path can drop all userspace mappings of doorbell and MMIO ranges via - * unmap_mapping_range(). + * Private pseudo-filesystem for KFD, Provides a stable, module-owned + * inode whose address_space is the unmap target for all /dev/kfd + * openers during GPU reset. */ -static struct address_space *kfd_dev_mapping; +static struct vfsmount *kfd_fs_mnt; +static int kfd_fs_cnt; + +static int kfd_fs_init_fs_context(struct fs_context *fc) +{ + return init_pseudo(fc, 0x4b464400 /* "KFD" */) ? 0 : -ENOMEM; +} + +static struct file_system_type kfd_fs_type = { + .name = "kfd", + .init_fs_context = kfd_fs_init_fs_context, + .kill_sb = kill_anon_super, +}; + +static struct inode *kfd_fs_inode_new(void) +{ + struct inode *inode; + int r; + + r = simple_pin_fs(&kfd_fs_type, &kfd_fs_mnt, &kfd_fs_cnt); + if (r < 0) + return ERR_PTR(r); + + inode = alloc_anon_inode(kfd_fs_mnt->mnt_sb); + if (IS_ERR(inode)) + simple_release_fs(&kfd_fs_mnt, &kfd_fs_cnt); + + return inode; +} + +static void kfd_fs_inode_free(struct inode *inode) +{ + if (inode) { + iput(inode); + simple_release_fs(&kfd_fs_mnt, &kfd_fs_cnt); + } +} + +static struct inode *kfd_anon_inode; void kfd_dev_unmap_mapping_range(loff_t const holebegin, loff_t const holelen) { - struct address_space *mapping = READ_ONCE(kfd_dev_mapping); - - if (mapping) - unmap_mapping_range(mapping, holebegin, holelen, 1); + if (kfd_anon_inode) + unmap_mapping_range(kfd_anon_inode->i_mapping, holebegin, holelen, 1); } static inline struct kfd_process_device *kfd_lock_pdd_by_id(struct kfd_process *p, __u32 gpu_id) @@ -107,6 +144,13 @@ int kfd_chardev_init(void) { int err = 0; + kfd_anon_inode = kfd_fs_inode_new(); + if (IS_ERR(kfd_anon_inode)) { + err = PTR_ERR(kfd_anon_inode); + kfd_anon_inode = NULL; + return err; + } + kfd_char_dev_major = register_chrdev(0, kfd_dev_name, &kfd_fops); err = kfd_char_dev_major; if (err < 0) @@ -130,6 +174,8 @@ err_device_create: err_class_create: unregister_chrdev(kfd_char_dev_major, kfd_dev_name); err_register_chrdev: + kfd_fs_inode_free(kfd_anon_inode); + kfd_anon_inode = NULL; return err; } @@ -138,6 +184,8 @@ void kfd_chardev_exit(void) device_destroy(&kfd_class, MKDEV(kfd_char_dev_major, 0)); class_unregister(&kfd_class); unregister_chrdev(kfd_char_dev_major, kfd_dev_name); + kfd_fs_inode_free(kfd_anon_inode); + kfd_anon_inode = NULL; kfd_device = NULL; } @@ -150,12 +198,7 @@ static int kfd_open(struct inode *inode, struct file *filep) if (iminor(inode) != 0) return -ENODEV; - /* - * /dev/kfd is a single chardev so all opens share one inode. Cache - * its address_space on the first open for use by the reset path. - */ - if (!READ_ONCE(kfd_dev_mapping)) - cmpxchg(&kfd_dev_mapping, NULL, inode->i_mapping); + filep->f_mapping = kfd_anon_inode->i_mapping; is_32bit_user_mode = in_compat_syscall(); From ae4e74197108bcd634dfe51f9a7ac1b35726e94f Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 16 Sep 2026 10:06:48 +0530 Subject: [PATCH 025/103] drm/amd/pm: Fix SMUv14/15 power context allocation Allocate the right power context objects in smu v14 and smu v15 Signed-off-by: Lijo Lazar Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c | 4 ++-- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index 80dac277d1ae..f2e6105b0d79 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -396,10 +396,10 @@ int smu_v14_0_init_power(struct smu_context *smu) if (smu_power->power_context || smu_power->power_context_size != 0) return -EINVAL; - smu_power->power_context = kzalloc_obj(struct smu_14_0_dpm_context); + smu_power->power_context = kzalloc_obj(struct smu_14_0_power_context); if (!smu_power->power_context) return -ENOMEM; - smu_power->power_context_size = sizeof(struct smu_14_0_dpm_context); + smu_power->power_context_size = sizeof(struct smu_14_0_power_context); return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c index 2269703869f9..dfc1022112d5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -338,10 +338,10 @@ int smu_v15_0_init_power(struct smu_context *smu) if (smu_power->power_context || smu_power->power_context_size != 0) return -EINVAL; - smu_power->power_context = kzalloc_obj(struct smu_15_0_dpm_context); + smu_power->power_context = kzalloc_obj(struct smu_15_0_power_context); if (!smu_power->power_context) return -ENOMEM; - smu_power->power_context_size = sizeof(struct smu_15_0_dpm_context); + smu_power->power_context_size = sizeof(struct smu_15_0_power_context); return 0; } From f0de4582915c67f1a9ee5873466f865d2bcb2318 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 16 Sep 2026 10:18:18 +0530 Subject: [PATCH 026/103] drm/amd/pm: Drop redundant power_context_size The size is stored and cleared in init/fini but never used to for anything else like copy. Drop the size and use pointer for init/fini checks. Signed-off-by: Lijo Lazar Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 1 - drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 6 ++---- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c | 6 ++---- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c | 6 ++---- 5 files changed, 6 insertions(+), 15 deletions(-) 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 d52e5fe1c42a..cad8b1cce794 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -486,7 +486,6 @@ struct smu_power_gate { struct smu_power_context { void *power_context; - uint32_t power_context_size; struct smu_power_gate power_gate; }; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index f0b2e7da67b1..09e20d5ee044 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -345,7 +345,6 @@ int smu_v11_0_init_power(struct smu_context *smu) smu_power->power_context = kzalloc(size, GFP_KERNEL); if (!smu_power->power_context) return -ENOMEM; - smu_power->power_context_size = size; return 0; } @@ -356,7 +355,6 @@ int smu_v11_0_fini_power(struct smu_context *smu) kfree(smu_power->power_context); smu_power->power_context = NULL; - smu_power->power_context_size = 0; return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index c4b2fe60da62..b250c5e41e45 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -427,13 +427,12 @@ int smu_v13_0_init_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; - if (smu_power->power_context || smu_power->power_context_size != 0) + if (smu_power->power_context) return -EINVAL; smu_power->power_context = kzalloc_obj(struct smu_13_0_power_context); if (!smu_power->power_context) return -ENOMEM; - smu_power->power_context_size = sizeof(struct smu_13_0_power_context); return 0; } @@ -442,12 +441,11 @@ int smu_v13_0_fini_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; - if (!smu_power->power_context || smu_power->power_context_size == 0) + if (!smu_power->power_context) return -EINVAL; kfree(smu_power->power_context); smu_power->power_context = NULL; - smu_power->power_context_size = 0; return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index f2e6105b0d79..5e890b56fd37 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -393,13 +393,12 @@ int smu_v14_0_init_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; - if (smu_power->power_context || smu_power->power_context_size != 0) + if (smu_power->power_context) return -EINVAL; smu_power->power_context = kzalloc_obj(struct smu_14_0_power_context); if (!smu_power->power_context) return -ENOMEM; - smu_power->power_context_size = sizeof(struct smu_14_0_power_context); return 0; } @@ -408,12 +407,11 @@ int smu_v14_0_fini_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; - if (!smu_power->power_context || smu_power->power_context_size == 0) + if (!smu_power->power_context) return -EINVAL; kfree(smu_power->power_context); smu_power->power_context = NULL; - smu_power->power_context_size = 0; return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c index dfc1022112d5..4be864e4f0e6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -335,13 +335,12 @@ int smu_v15_0_init_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; - if (smu_power->power_context || smu_power->power_context_size != 0) + if (smu_power->power_context) return -EINVAL; smu_power->power_context = kzalloc_obj(struct smu_15_0_power_context); if (!smu_power->power_context) return -ENOMEM; - smu_power->power_context_size = sizeof(struct smu_15_0_power_context); return 0; } @@ -350,12 +349,11 @@ int smu_v15_0_fini_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; - if (!smu_power->power_context || smu_power->power_context_size == 0) + if (!smu_power->power_context) return -EINVAL; kfree(smu_power->power_context); smu_power->power_context = NULL; - smu_power->power_context_size = 0; return 0; } From f2b96986851203e9c50ca0d13aaa3581ca3e8ebd Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 16 Sep 2026 10:01:39 +0000 Subject: [PATCH 027/103] drm/amdgpu: Fix vmid_wait fence leak in amdgpu_ring_init() amdgpu_ring_init() initializes ring->vmid_wait with a reference to the stub fence taken via dma_fence_get_stub(). When a later step of the initialization fails, e.g. amdgpu_fence_driver_init_ring(), a writeback slot allocation or the ring buffer allocation, the function returns an error without releasing the stub fence reference and the reference is leaked if the ring is torn down without amdgpu_ring_fini(). Move the stub fence assignment to the end of the initialization, right before the ring is registered with the GPU scheduler, where no further failure is possible. The stub fence is only consumed by command submission handling in amdgpu_ids.c once the ring is up and running, so nothing reads it during the error-prone part of the initialization. Fixes: 48e9fbd1a284 ("drm/amdgpu: initialize the vmid_wait with the stub fence") Signed-off-by: Wentao Liang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 3aea81c75fdd..227734541316 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -239,7 +239,6 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, ring->adev = adev; ring->num_hw_submission = sched_hw_submission; ring->sched_score = sched_score; - ring->vmid_wait = dma_fence_get_stub(); ring->idx = adev->num_rings++; adev->rings[ring->idx] = ring; @@ -357,6 +356,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, ring->max_dw = max_dw; ring->hw_prio = hw_prio; + ring->vmid_wait = dma_fence_get_stub(); if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) { hw_ip = ring->funcs->type; From 9211ef48b31ec66999cf55e04d0cbc60cd855fd5 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 16 Sep 2026 09:54:32 +0000 Subject: [PATCH 028/103] drm/amdgpu: Fix acpi device leak in amdgpu_acpi_enumerate_xcc() amdgpu_acpi_enumerate_xcc() looks up each XCC ACPI device with acpi_dev_get_first_match_dev(), which takes a reference to the device. The reference is dropped with acpi_dev_put() after the XCC info is initialized, but if the kzalloc_obj() allocation of the XCC info fails the function returns -ENOMEM without releasing the reference, leaking the last reference to the ACPI device. Drop the ACPI device reference on the allocation failure path before returning. Fixes: 4d5275ab0b18 ("drm/amdgpu: Add parsing of acpi xcc objects") Reviewed-by: Lijo Lazar Signed-off-by: Wentao Liang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 7f5abb03be1b..8b8acf98fdfe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1167,8 +1167,10 @@ int amdgpu_acpi_enumerate_xcc(void) } xcc_info = kzalloc_obj(struct amdgpu_acpi_xcc_info); - if (!xcc_info) + if (!xcc_info) { + acpi_dev_put(acpi_dev); return -ENOMEM; + } INIT_LIST_HEAD(&xcc_info->list); xcc_info->handle = acpi_device_handle(acpi_dev); From e7979c84fc05a176bdf855ee664871b1648404c9 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 16 Sep 2026 09:55:36 +0000 Subject: [PATCH 029/103] drm/amdgpu: Fix last_update fence leak in amdgpu_vm_init() amdgpu_vm_init() initializes vm->last_update, vm->last_unlocked and vm->last_tlb_flush with references to the stub fence taken via dma_fence_get_stub(). The error label at the end of the function releases the last_unlocked and last_tlb_flush references with dma_fence_put(), but the reference stored in vm->last_update is never dropped, so whenever the page table root creation, the reservation of the root BO or the PASID registration fails, the stub fence reference leaks. Drop the vm->last_update reference together with the other stub fence references on the error path. Fixes: 187916e6ed9d ("drm/amdgpu: install stub fence into potential unused fence pointers") Signed-off-by: Wentao Liang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 6b210f7af57b..ed92dc1a29e7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2701,6 +2701,7 @@ error_free_root: amdgpu_bo_unref(&root_bo); error_free_delayed: + dma_fence_put(vm->last_update); dma_fence_put(vm->last_tlb_flush); dma_fence_put(vm->last_unlocked); ttm_lru_bulk_move_fini(&adev->mman.bdev, &vm->lru_bulk_move); From ec30a576c2d4c0364549e6c04218f50704ef56c8 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 16 Sep 2026 09:58:05 +0000 Subject: [PATCH 030/103] drm/amdgpu: Fix runtime PM leak in amdgpu_debugfs_test_ib_show() amdgpu_debugfs_test_ib_show() resumes the device with pm_runtime_get_sync() before taking the reset domain semaphore with down_write_killable(). If the write lock acquisition is interrupted, the function returns without calling pm_runtime_put_autosuspend(), leaking the runtime PM reference acquired for the device and keeping the GPU awake. Drop the runtime PM reference on the interrupted down_write_killable() error path before returning. Fixes: 6049db43d6dd ("drm/amdgpu: change reset lock from mutex to rw_semaphore") Signed-off-by: Wentao Liang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index d8786a93a851..1b7673d239db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -1781,8 +1781,10 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) /* Avoid accidently unparking the sched thread during GPU reset */ r = down_write_killable(&adev->reset_domain->sem); - if (r) + if (r) { + pm_runtime_put_autosuspend(dev->dev); return r; + } /* hold on the scheduler */ for (i = 0; i < AMDGPU_MAX_RINGS; i++) { From 258403174db4e92cd90ea0f04989b9a2ba8fca31 Mon Sep 17 00:00:00 2001 From: "Huang, Leon" Date: Wed, 2 Sep 2026 23:02:50 +0800 Subject: [PATCH 031/103] drm/amd/display: Forward periodic ABM keep-alive scenario to DMU [Why & How] 1. The periodic ABM full-frame update for VESA PR is now owned by the DMU timer. 2. In PR_update_state, compute whether the current scenario allows the periodic keep-alive (not CTS, not front-buffer rendering, not force-full-frame, content actively updating) and forward it via the abm_periodic_ffu_allowed runtime flag only when it changes. Reviewed-by: Robin Chen Reviewed-by: Alex Hung Signed-off-by: Leon Huang Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 01f7c9addc6c..7ff2152ff233 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1309,6 +1309,8 @@ struct replay_settings { uint16_t frame_skip_number; /* Current Panel Replay events */ uint32_t replay_events; + /* Last ABM periodic keep-alive FFU allowed bit sent to DMUB (VESA PR) */ + bool last_abm_periodic_ffu_allowed; }; /* To split out "global" and "per-panel" config settings. From f2395cdd28dd79c1b3a6c1fbf74d0b96aee738c5 Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Tue, 1 Sep 2026 17:58:57 -0400 Subject: [PATCH 032/103] drm/amd/display: Expose 3 overlay planes on DCN6 [Why&How] DCN6 has 4 pipes, so we should be able to use 3 overlay + 1 primary plane. Reviewed-by: Alvin Lee Signed-off-by: Ivan Lipski Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c index 171626298e41..ad841431b70c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c @@ -2036,9 +2036,9 @@ static bool dcn60_resource_construct( dc->caps.cache_line_size = 64; dc->caps.cache_num_ways = 16; - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; + dc->caps.max_slave_planes = 3; + dc->caps.max_slave_yuv_planes = 3; + dc->caps.max_slave_rgb_planes = 3; dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; dc->caps.hdmi_hpo = true; From 6917cf9230277c471146d077cf5731105181c42c Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Wed, 2 Sep 2026 17:42:35 -0400 Subject: [PATCH 033/103] drm/amd/display: add SPDX-License-Identifier Add the AMD Open-Source SPDX line to dc files. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c | 1 + drivers/gpu/drm/amd/display/dc/dcn301/dcn301_panel_cntl.c | 1 + drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c | 1 + drivers/gpu/drm/amd/display/dc/hubp/dcn31/dcn31_hubp.c | 1 + drivers/gpu/drm/amd/display/dc/inc/clock_source.h | 3 ++- 5 files changed, 6 insertions(+), 1 deletion(-) 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 f88404a37dea..54ef1808ca35 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 @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT /* * Copyright 2012-15 Advanced Micro Devices, Inc. * diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_panel_cntl.c index 9e96a3ace207..1e11328050e5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_panel_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_panel_cntl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT /* * Copyright 2020 Advanced Micro Devices, Inc. * diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c index f9961a6446f3..d7c3f26777e3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT /* * Copyright 2021 Advanced Micro Devices, Inc. * diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn31/dcn31_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn31/dcn31_hubp.c index 189045f85039..9cc5766235f0 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn31/dcn31_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn31/dcn31_hubp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT /* * Copyright 2012-20 Advanced Micro Devices, Inc. * diff --git a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h index 6bbbb8ea7dad..9e2dac044495 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h @@ -1,4 +1,5 @@ -/* +/* SPDX-License-Identifier: MIT + * * Copyright 2012-15 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a From e5dae013f44be80e1c28ac5b9d736d2933f81f97 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Thu, 3 Sep 2026 16:05:03 -0400 Subject: [PATCH 034/103] drm/amd/display: Add inst field to struct hubbub Add an inst member and initialize it to 0 in every hubbub*_construct() from DCN10 through DCN60. No functional change. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn201/dcn201_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn21/dcn21_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn30/dcn30_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn301/dcn301_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c | 1 + drivers/gpu/drm/amd/display/dc/hubbub/dcn32/dcn32_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c | 2 ++ drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 1 + 13 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.c index d683d0740c13..4e33648f74bb 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.c @@ -933,6 +933,8 @@ void hubbub1_construct(struct hubbub *hubbub, hubbub1->base.ctx = ctx; + hubbub1->base.inst = 0; + hubbub1->base.funcs = &hubbub1_funcs; hubbub1->regs = hubbub_regs; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c index 9fb2907361c3..e5b55fe502ca 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c @@ -680,6 +680,8 @@ void hubbub2_construct(struct dcn20_hubbub *hubbub, { hubbub->base.ctx = ctx; + hubbub->base.inst = 0; + hubbub->base.funcs = &hubbub2_funcs; hubbub->regs = hubbub_regs; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn201/dcn201_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn201/dcn201_hubbub.c index 63798132ed95..e6b527cd2047 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn201/dcn201_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn201/dcn201_hubbub.c @@ -96,6 +96,8 @@ void hubbub201_construct(struct dcn20_hubbub *hubbub, { hubbub->base.ctx = ctx; + hubbub->base.inst = 0; + hubbub->base.funcs = &hubbub201_funcs; hubbub->regs = hubbub_regs; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn21/dcn21_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn21/dcn21_hubbub.c index d790d6ee359a..881e91e9385d 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn21/dcn21_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn21/dcn21_hubbub.c @@ -712,6 +712,8 @@ void hubbub21_construct(struct dcn20_hubbub *hubbub, { hubbub->base.ctx = ctx; + hubbub->base.inst = 0; + hubbub->base.funcs = &hubbub21_funcs; hubbub->regs = hubbub_regs; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn30/dcn30_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn30/dcn30_hubbub.c index 6a7c1bee5747..582d647da812 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn30/dcn30_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn30/dcn30_hubbub.c @@ -478,6 +478,8 @@ void hubbub3_construct(struct dcn20_hubbub *hubbub3, const struct dcn_hubbub_mask *hubbub_mask) { hubbub3->base.ctx = ctx; + + hubbub3->base.inst = 0; hubbub3->base.funcs = &hubbub30_funcs; hubbub3->regs = hubbub_regs; hubbub3->shifts = hubbub_shift; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn301/dcn301_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn301/dcn301_hubbub.c index c1959672df50..f432874b32dd 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn301/dcn301_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn301/dcn301_hubbub.c @@ -74,6 +74,8 @@ void hubbub301_construct(struct dcn20_hubbub *hubbub3, const struct dcn_hubbub_mask *hubbub_mask) { hubbub3->base.ctx = ctx; + + hubbub3->base.inst = 0; hubbub3->base.funcs = &hubbub301_funcs; hubbub3->regs = hubbub_regs; hubbub3->shifts = hubbub_shift; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c index 35c94ca8335a..8dd4b7b9ba36 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c @@ -1080,6 +1080,7 @@ void hubbub31_construct(struct dcn20_hubbub *hubbub31, int pixel_chunk_size_kb, int config_return_buffer_size_kb) { + hubbub31->base.inst = 0; hubbub3_construct(hubbub31, ctx, hubbub_regs, hubbub_shift, hubbub_mask); hubbub31->base.funcs = &hubbub31_funcs; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn32/dcn32_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn32/dcn32_hubbub.c index 237331b35378..dd9bc1f08b56 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn32/dcn32_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn32/dcn32_hubbub.c @@ -1050,6 +1050,8 @@ void hubbub32_construct(struct dcn20_hubbub *hubbub2, int config_return_buffer_size_kb) { hubbub2->base.ctx = ctx; + + hubbub2->base.inst = 0; hubbub2->base.funcs = &hubbub32_funcs; hubbub2->regs = hubbub_regs; hubbub2->shifts = hubbub_shift; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c index 466bab437e37..ad333cd3241b 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c @@ -655,6 +655,8 @@ void hubbub35_construct(struct dcn20_hubbub *hubbub2, int config_return_buffer_size_kb) { hubbub2->base.ctx = ctx; + + hubbub2->base.inst = 0; hubbub2->base.funcs = &hubbub35_funcs; hubbub2->regs = hubbub_regs; hubbub2->shifts = hubbub_shift; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c index e9ff20c02b1e..d948525bc09e 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c @@ -1264,6 +1264,8 @@ void hubbub401_construct(struct dcn20_hubbub *hubbub2, int config_return_buffer_size_kb) { hubbub2->base.ctx = ctx; + + hubbub2->base.inst = 0; hubbub2->base.funcs = &hubbub4_01_funcs; hubbub2->regs = hubbub_regs; hubbub2->shifts = hubbub_shift; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c index 71bc926c7035..b8657de84d31 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c @@ -555,6 +555,8 @@ void hubbub42_construct(struct dcn20_hubbub *hubbub2, int config_return_buffer_size_kb) { hubbub2->base.ctx = ctx; + + hubbub2->base.inst = 0; hubbub2->base.funcs = &hubbub42_funcs; hubbub2->regs = hubbub_regs; hubbub2->shifts = hubbub_shift; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c index c89c8ff42185..639c71cf1123 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c @@ -1982,6 +1982,8 @@ void hubbub60_construct(struct dcn20_hubbub *hubbub2, int config_return_buffer_size_kb) { hubbub2->base.ctx = ctx; + + hubbub2->base.inst = 0; hubbub2->base.funcs = &hubbub60_funcs; hubbub2->regs = hubbub_regs; hubbub2->shifts = hubbub_shift; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index 22a0e3dcb25c..8d1024a875a7 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -301,6 +301,7 @@ struct hubbub_funcs { struct hubbub { const struct hubbub_funcs *funcs; struct dc_context *ctx; + int inst; bool riommu_active; }; From f670603d372a6205a5ab26a678cf7792a14697b3 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Tue, 8 Sep 2026 12:35:16 -0400 Subject: [PATCH 035/103] drm/amd/display: Enable double buffering for DSCCLK updates [Description] Double buffering needs to be enabled for DSCCLK updates otherwise a frame of underflow could occur when updating the DSC pipe config or DSC clock. Reviewed-by: Ilya Bakoulin Signed-off-by: Alvin Lee Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h | 4 ++++ drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.h | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h index cecfb0a68030..f47733db96f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h @@ -256,6 +256,10 @@ type DSCCLK1_EN;\ type DSCCLK2_EN;\ type DSCCLK3_EN;\ + type DSCCLK0_DTO_DB_EN;\ + type DSCCLK1_DTO_DB_EN;\ + type DSCCLK2_DTO_DB_EN;\ + type DSCCLK3_DTO_DB_EN;\ type DISPCLK_DCCG_GATE_DISABLE;\ type DCCG_GLOBAL_FGCG_REP_DIS; \ type PHYASYMCLK_EN;\ diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c index e08a9679aaf7..9f15e6adc715 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c @@ -76,6 +76,7 @@ static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst, switch (inst) { case 0: + REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_DTO_DB_EN, 1); REG_UPDATE_2(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, 1, DSCCLK0_DTO_MODULO, 1); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1); @@ -92,6 +93,7 @@ static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst, break; case 1: + REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_DTO_DB_EN, 1); REG_UPDATE_2(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, 1, DSCCLK1_DTO_MODULO, 1); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1); @@ -103,6 +105,7 @@ static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst, break; case 2: + REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_DTO_DB_EN, 1); REG_UPDATE_2(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, 1, DSCCLK2_DTO_MODULO, 1); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1); @@ -114,6 +117,7 @@ static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst, break; case 3: + REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_DTO_DB_EN, 1); REG_UPDATE_2(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, 1, DSCCLK3_DTO_MODULO, 1); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1); diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.h index 3f068ccfcdd5..3a6b65dee154 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.h @@ -96,6 +96,10 @@ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_EN, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_EN, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_EN, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_DTO_DB_EN, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_DTO_DB_EN, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_DB_EN, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_DTO_DB_EN, mask_sh),\ DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_MODULO, mask_sh),\ DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, mask_sh),\ From 1d416cf01550938ef0c3e1cca8e484150de13000 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Thu, 3 Sep 2026 20:16:21 -0400 Subject: [PATCH 036/103] drm/amd/display: Add inst field to struct clk_mgr Add an inst member to struct clk_mgr and set it to 0 in the DCN401, DCN42, DCN42B and DCN60 construct paths, since clk_mgr is a singleton on all of them. No functional change; the field has no readers yet. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c | 1 + .../gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c | 7 ++++--- .../gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c | 3 ++- .../gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h | 1 + 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c index 6d791a5d9776..120f9dd691f3 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c @@ -1632,6 +1632,7 @@ struct clk_mgr_internal *dcn401_clk_mgr_construct( clk_mgr = &clk_mgr401->base; clk_mgr->base.ctx = ctx; + clk_mgr->base.inst = 0; clk_mgr->base.funcs = &dcn401_funcs; clk_mgr->regs = &clk_mgr_regs_dcn401; clk_mgr->clk_mgr_shift = &clk_mgr_shift_dcn401; 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 c62be9f25dae..405145889ba2 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 @@ -392,7 +392,7 @@ void dcn42_notify_cstate_disable(struct clk_mgr *clk_mgr_base, bool disable) struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); bool target_allow = !disable; - DC_LOGGER_INIT(clk_mgr_base->ctx->logger); +DC_LOGGER_INIT(clk_mgr_base->ctx->logger); /* Idempotent: only send when the cached vote actually changes. */ if (clk_mgr_base->clks.cstate_allow == target_allow) @@ -619,7 +619,7 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base) struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int); - DC_LOGGER_INIT(clk_mgr_base->ctx->logger); +DC_LOGGER_INIT(clk_mgr_base->ctx->logger); (void)dc_logger; init_clk_states(clk_mgr_base); @@ -814,7 +814,7 @@ void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base) void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base) { - (void)clk_mgr_base; +(void)clk_mgr_base; } @@ -1115,6 +1115,7 @@ void dcn42_clk_mgr_construct( struct dccg *dccg) { clk_mgr->base.base.ctx = ctx; + clk_mgr->base.base.inst = 0; clk_mgr->base.base.funcs = &dcn42_funcs; clk_mgr->base.regs = &clk_mgr_regs_dcn42; clk_mgr->base.clk_mgr_shift = &clk_mgr_shift_dcn42; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c index 003ed4f60f97..d500a3210eed 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c @@ -228,7 +228,7 @@ void dcn42b_init_clocks(struct clk_mgr *clk_mgr_base) struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42B(clk_mgr_int); - DC_LOGGER_INIT(clk_mgr_base->ctx->logger); +DC_LOGGER_INIT(clk_mgr_base->ctx->logger); (void)dc_logger; init_clk_states(clk_mgr_base); @@ -619,6 +619,7 @@ void dcn42b_clk_mgr_construct( struct dccg *dccg) { clk_mgr->base.base.ctx = ctx; + clk_mgr->base.base.inst = 0; clk_mgr->base.base.funcs = &dcn42b_funcs; clk_mgr->base.regs = &clk_mgr_regs_dcn42b; clk_mgr->base.clk_mgr_shift = &clk_mgr_shift_dcn42b; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c index 9f5714a83a0d..b0f7f27fd7a1 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c @@ -1709,6 +1709,7 @@ struct clk_mgr_internal *dcn60_clk_mgr_construct( clk_mgr = &clk_mgr60->base; clk_mgr->base.ctx = ctx; + clk_mgr->base.inst = 0; clk_mgr->base.funcs = &dcn60_funcs; clk_mgr->regs = &clk_mgr_regs_dcn60; clk_mgr->clk_mgr_shift = &clk_mgr_shift_dcn60; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index 614beb5924fd..5b06659423d5 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -433,6 +433,7 @@ struct clk_mgr_funcs { struct clk_mgr { struct dc_context *ctx; struct clk_mgr_funcs *funcs; + int inst; struct dc_clocks clks; bool psr_allow_active_cache; bool force_smu_not_present; From e61a01511c7ab546b22dfb2f5d011de457d1a143 Mon Sep 17 00:00:00 2001 From: Austin Zheng Date: Thu, 3 Sep 2026 16:39:28 -0400 Subject: [PATCH 037/103] drm/amd/display: Add Back Unified CalculateFlipSchedule [Why] CalculateFlipSchedule has slightly different calculations depending on if it was called by mode support or mode programming. Mode support calculates the lower bound of the required bandwidth for immediate flips. This takes into the account of the register limits to ensure it is still programmable. Mode programming uses the required bandwidth for immediate flips on a per-plane basis to calculate the number of dst_y lines needed to achieve this bandwidth. Usually the immediate flip bandwidth per plane determined by mode programming is above the lower bound calculated by mode support. However, mode programming can fail if that isn't the case since a bandwidth lower than the lower bound will end up exceeding the register limit used by hardware. e.g. The proportion of a single plane's flip bandwidth w.r.t to the total bandwidth available for all planes can result in one of the planes having a lower BW than the lower bound calculated in mode support [How] Update function to always use the use_lb_flip_bw path. Add calculations for dst_y_per_vm/row_flip lines. Consolidate calculation of lb_flip_bw by having it consider register limits: Instead of doing two steps of: 1. Taking the max of the bandwidths without considering register limits. 2. Taking the max of itself with the bandwidths with register limits accounted for. Do it in one step as it is easy to miss either step 1 or 2. Also add some local variables for intermediate values and remove no longer referenced inputs to improve readability. Also increase DCN401 max_flip_time_lines by 2 lines to ensure previously supported configs remain supported as worst-case bandwidth can increase compared to before. Fixes: 1e719006b623 ("drm/amd/display: Unify CalculateFlipSchedule Logic") Fixes: 285a363f8c63 ("Revert "drm/amd/display: Unify CalculateFlipSchedule Logic"") Reviewed-by: Dillon Varone Reviewed-by: Alex Hung Signed-off-by: Austin Zheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dml21/inc/bounding_boxes/dcn4_soc_bb.h | 2 +- .../src/dml2_core/dml2_core_dcn4_calcs.c | 146 +++++++----------- .../src/dml2_core/dml2_core_shared_types.h | 3 + 3 files changed, 57 insertions(+), 94 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h index f26366ebeeda..ed82ef55b651 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h @@ -342,7 +342,7 @@ static const struct dml2_ip_capabilities dml2_dcn401_max_ip_caps = { .compressed_buffer_segment_size_in_kbytes = 64, .cursor_buffer_size = 24, .max_flip_time_us = 80, - .max_flip_time_lines = 32, + .max_flip_time_lines = 34, .hostvm_mode = 0, .subvp_drr_scheduling_margin_us = 100, .subvp_prefetch_end_to_mall_start_us = 15, 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 64afb67054d5..2d43a35c4c42 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 @@ -6555,7 +6555,6 @@ static void CalculateFlipSchedule( bool GPUVMEnable, double vm_bytes, // vm_bytes double DPTEBytesPerRow, // dpte_row_bytes - double BandwidthAvailableForImmediateFlip, unsigned int TotImmediateFlipBytes, enum dml2_source_format_class SourcePixelFormat, double LineTime, @@ -6567,7 +6566,6 @@ static void CalculateFlipSchedule( bool use_one_row_for_frame_flip, unsigned int max_flip_time_us, unsigned int max_flip_time_lines, - unsigned int per_pipe_flip_bytes, unsigned int meta_row_bytes, unsigned int meta_row_height, unsigned int meta_row_height_chroma, @@ -6589,7 +6587,6 @@ static void CalculateFlipSchedule( DML_LOG_VERBOSE("DML::%s: GPUVMEnable = %u\n", __func__, GPUVMEnable); DML_LOG_VERBOSE("DML::%s: ip.max_flip_time_us = %d\n", __func__, max_flip_time_us); DML_LOG_VERBOSE("DML::%s: ip.max_flip_time_lines = %d\n", __func__, max_flip_time_lines); - DML_LOG_VERBOSE("DML::%s: BandwidthAvailableForImmediateFlip = %f\n", __func__, BandwidthAvailableForImmediateFlip); DML_LOG_VERBOSE("DML::%s: TotImmediateFlipBytes = %u\n", __func__, TotImmediateFlipBytes); DML_LOG_VERBOSE("DML::%s: use_lb_flip_bw = %u\n", __func__, use_lb_flip_bw); DML_LOG_VERBOSE("DML::%s: iflip_enable = %u\n", __func__, iflip_enable); @@ -6637,104 +6634,71 @@ static void CalculateFlipSchedule( #endif DML_ASSERT(l->min_row_time > 0); - if (use_lb_flip_bw) { - // For mode check, calculation the flip bw requirement with worst case flip time - l->max_flip_time = math_min2(math_min2(l->min_row_time, (double)max_flip_time_lines * LineTime / VRatio), - math_max2(Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded, (double)max_flip_time_us)); + // For mode check, calculation the flip bw requirement with worst case flip time + l->max_flip_time = math_min2(math_min2(l->min_row_time, (double)max_flip_time_lines * LineTime / VRatio), + math_max2(Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded, (double)max_flip_time_us)); - //The lower bound on flip bandwidth - // Note: The get_urgent_bandwidth_required already consider dpte_row_bw and meta_row_bw in bandwidth calculation, so leave final_flip_bw = 0 if iflip not required - l->lb_flip_bw = 0; + //The lower bound on flip bandwidth + // Note: The get_urgent_bandwidth_required already consider dpte_row_bw and meta_row_bw in bandwidth calculation, so leave final_flip_bw = 0 if iflip not required + l->lb_flip_bw = 0; - if (iflip_enable) { - l->hvm_scaled_vm_bytes = vm_bytes * HostVMInefficiencyFactor; - l->num_rows = 2; - l->hvm_scaled_row_bytes = (l->num_rows * l->dpte_row_bytes * HostVMInefficiencyFactor + l->num_rows * meta_row_bytes); - l->hvm_scaled_vm_row_bytes = l->hvm_scaled_vm_bytes + l->hvm_scaled_row_bytes; - l->lb_flip_bw = math_max3( - l->hvm_scaled_vm_row_bytes / (l->max_flip_time - Tno_bw_flip), - l->hvm_scaled_vm_bytes / (l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded), - l->hvm_scaled_row_bytes / (l->max_flip_time - Tvm_trips_flip_rounded)); + l->vm_and_row_time_budget = l->max_flip_time - Tno_bw_flip; + l->vm_time_budget = l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded; + l->row_time_budget = l->max_flip_time - Tvm_trips_flip_rounded; + + if (iflip_enable) { + l->hvm_scaled_vm_bytes = vm_bytes * HostVMInefficiencyFactor; + l->num_rows = 2; + l->hvm_scaled_row_bytes = (l->num_rows * l->dpte_row_bytes * HostVMInefficiencyFactor + l->num_rows * meta_row_bytes); + l->hvm_scaled_vm_row_bytes = l->hvm_scaled_vm_bytes + l->hvm_scaled_row_bytes; + l->lb_flip_bw = math_max3( + l->hvm_scaled_vm_row_bytes / l->vm_and_row_time_budget, + l->hvm_scaled_vm_bytes / math_min2(l->vm_time_budget, 31.75 * LineTime - Tno_bw_flip), + (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / math_min2(l->row_time_budget / 2, 15.75 * LineTime)); //use bandwidth for a single row #ifdef __DML_VBA_DEBUG__ - DML_LOG_VERBOSE("DML::%s: max_flip_time = %f\n", __func__, l->max_flip_time); - DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_bytes); - DML_LOG_VERBOSE("DML::%s: total row bytes (%f row, hvm ineff scaled) = %f\n", __func__, l->num_rows, l->hvm_scaled_row_bytes); - DML_LOG_VERBOSE("DML::%s: total vm+row bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_row_bytes); - DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm and row = %f\n", __func__, l->hvm_scaled_vm_row_bytes / (l->max_flip_time - Tno_bw_flip)); - DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm = %f\n", __func__, l->hvm_scaled_vm_bytes / (l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded)); - DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row = %f\n", __func__, l->hvm_scaled_row_bytes / (l->max_flip_time - Tvm_trips_flip_rounded)); - - if (l->lb_flip_bw > 0) { - DML_LOG_VERBOSE("DML::%s: mode_support est Tvm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw); - DML_LOG_VERBOSE("DML::%s: mode_support est Tr0_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / l->num_rows); - DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_vm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw / LineTime); - DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_row_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / LineTime / l->num_rows); - DML_LOG_VERBOSE("DML::%s: Tvm_trips_flip_rounded + 2*Tr0_trips_flip_rounded = %f\n", __func__, (Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded)); - } + DML_LOG_VERBOSE("DML::%s: max_flip_time = %f\n", __func__, l->max_flip_time); + DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_bytes); + DML_LOG_VERBOSE("DML::%s: total row bytes (%f row, hvm ineff scaled) = %f\n", __func__, l->num_rows, l->hvm_scaled_row_bytes); + DML_LOG_VERBOSE("DML::%s: total vm+row bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_row_bytes); + DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm and row = %f\n", __func__, l->hvm_scaled_vm_row_bytes / l->vm_and_row_time_budget); + DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm = %f\n", __func__, l->hvm_scaled_vm_bytes / l->vm_time_budget); + DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row = %f\n", __func__, l->hvm_scaled_row_bytes / l->row_time_budget); + DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm reg limit = %f\n", __func__, l->hvm_scaled_vm_bytes / (31.75 * LineTime - Tno_bw_flip)); + DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row reg limit = %f\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (15.75 * LineTime)); #endif - l->lb_flip_bw = math_max3(l->lb_flip_bw, - l->hvm_scaled_vm_bytes / (31 * LineTime) - Tno_bw_flip, - (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (15 * LineTime)); + } -#ifdef __DML_VBA_DEBUG__ - DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm reg limit = %f\n", __func__, l->hvm_scaled_vm_bytes / (31 * LineTime) - Tno_bw_flip); - DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row reg limit = %f\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (15 * LineTime)); -#endif - } + *final_flip_bw = l->lb_flip_bw; - *final_flip_bw = l->lb_flip_bw; + if (l->lb_flip_bw > 0) { + DML_LOG_VERBOSE("DML::%s: mode_support est Tvm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw); + DML_LOG_VERBOSE("DML::%s: mode_support est Tr0_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / l->num_rows); + DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_vm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw / LineTime); + DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_row_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / LineTime / l->num_rows); + DML_LOG_VERBOSE("DML::%s: Tvm_trips_flip_rounded + 2*Tr0_trips_flip_rounded = %f\n", __func__, (Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded)); - *dst_y_per_vm_flip = 1; // not used - *dst_y_per_row_flip = 1; // not used - *ImmediateFlipSupportedForPipe = l->min_row_time >= (Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded); - } else { - if (iflip_enable) { - l->ImmediateFlipBW = (double)per_pipe_flip_bytes * BandwidthAvailableForImmediateFlip / (double)TotImmediateFlipBytes; // flip_bw(i) + l->Tvm_flip = math_max3(Tvm_trips_flip, + Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->lb_flip_bw, + LineTime / 4.0); + l->Tr0_flip = math_max3(Tr0_trips_flip, + (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / l->lb_flip_bw, + LineTime / 4.0); -#ifdef __DML_VBA_DEBUG__ - DML_LOG_VERBOSE("DML::%s: per_pipe_flip_bytes = %d\n", __func__, per_pipe_flip_bytes); - DML_LOG_VERBOSE("DML::%s: BandwidthAvailableForImmediateFlip = %f\n", __func__, BandwidthAvailableForImmediateFlip); - DML_LOG_VERBOSE("DML::%s: ImmediateFlipBW = %f\n", __func__, l->ImmediateFlipBW); - DML_LOG_VERBOSE("DML::%s: portion of flip bw = %f\n", __func__, (double)per_pipe_flip_bytes / (double)TotImmediateFlipBytes); -#endif - if (l->ImmediateFlipBW == 0) { - l->Tvm_flip = 0; - l->Tr0_flip = 0; - } else { - l->Tvm_flip = math_max3(Tvm_trips_flip, - Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->ImmediateFlipBW, - LineTime / 4.0); + *dst_y_per_vm_flip = math_ceil2(4.0 * l->Tvm_flip / LineTime, 1.0) / 4.0; + *dst_y_per_row_flip = math_ceil2(4.0 * l->Tr0_flip / LineTime, 1.0) / 4.0; - l->Tr0_flip = math_max3(Tr0_trips_flip, - (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / l->ImmediateFlipBW, - LineTime / 4.0); - } -#ifdef __DML_VBA_DEBUG__ - DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, vm_bytes * HostVMInefficiencyFactor); - DML_LOG_VERBOSE("DML::%s: total row bytes (hvm ineff scaled, one row) = %f\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes)); - - DML_LOG_VERBOSE("DML::%s: Tvm_flip = %f (bw-based), Tvm_trips_flip = %f (latency-based)\n", __func__, Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->ImmediateFlipBW, Tvm_trips_flip); - DML_LOG_VERBOSE("DML::%s: Tr0_flip = %f (bw-based), Tr0_trips_flip = %f (latency-based)\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / l->ImmediateFlipBW, Tr0_trips_flip); -#endif - *dst_y_per_vm_flip = math_ceil2(4.0 * (l->Tvm_flip / LineTime), 1.0) / 4.0; - *dst_y_per_row_flip = math_ceil2(4.0 * (l->Tr0_flip / LineTime), 1.0) / 4.0; - - *final_flip_bw = math_max2(vm_bytes * HostVMInefficiencyFactor / (*dst_y_per_vm_flip * LineTime), - (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (*dst_y_per_row_flip * LineTime)); - - if (*dst_y_per_vm_flip >= 32 || *dst_y_per_row_flip >= 16 || l->Tvm_flip + 2 * l->Tr0_flip > l->min_row_time) { - *ImmediateFlipSupportedForPipe = false; - } else { - *ImmediateFlipSupportedForPipe = iflip_enable; - } + if (*dst_y_per_vm_flip >= 32 || *dst_y_per_row_flip >= 16 || l->Tvm_flip + 2 * l->Tr0_flip > l->min_row_time) { + *ImmediateFlipSupportedForPipe = false; } else { - l->Tvm_flip = 0; - l->Tr0_flip = 0; - *dst_y_per_vm_flip = 0; - *dst_y_per_row_flip = 0; - *final_flip_bw = 0; *ImmediateFlipSupportedForPipe = iflip_enable; } + } else { + l->Tvm_flip = 0; + l->Tr0_flip = 0; + *dst_y_per_vm_flip = 0; + *dst_y_per_row_flip = 0; + *final_flip_bw = 0; + *ImmediateFlipSupportedForPipe = iflip_enable; } } else { l->Tvm_flip = 0; @@ -7891,7 +7855,6 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter display_cfg->gpuvm_enable, mode_lib->ms.vm_bytes[k], mode_lib->ms.DPTEBytesPerRow[k], - mode_lib->ms.BandwidthAvailableForImmediateFlip, mode_lib->ms.TotImmediateFlipBytes, display_cfg->plane_descriptors[k].pixel_format, (display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.h_total / ((double)display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000)), @@ -7903,7 +7866,6 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter mode_lib->ms.use_one_row_for_frame_flip[k], mode_lib->ip.max_flip_time_us, mode_lib->ip.max_flip_time_lines, - s->per_pipe_flip_bytes[k], mode_lib->ms.meta_row_bytes[k], s->meta_row_height_luma[k], s->meta_row_height_chroma[k], @@ -11692,7 +11654,6 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex display_cfg->gpuvm_enable, mode_lib->mp.vm_bytes[k], mode_lib->mp.PixelPTEBytesPerRow[k], - mode_lib->mp.BandwidthAvailableForImmediateFlip, mode_lib->mp.TotImmediateFlipBytes, display_cfg->plane_descriptors[k].pixel_format, display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.h_total / ((double)display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000), @@ -11704,7 +11665,6 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex mode_lib->mp.use_one_row_for_frame_flip[k], mode_lib->ip.max_flip_time_us, mode_lib->ip.max_flip_time_lines, - s->per_pipe_flip_bytes[k], mode_lib->mp.meta_row_bytes[k], mode_lib->mp.meta_row_height[k], mode_lib->mp.meta_row_height_chroma[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 d4e6464640ad..9eabee1fc001 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 @@ -1659,6 +1659,9 @@ struct dml2_core_shared_CalculateFlipSchedule_locals { double num_rows; double hvm_scaled_row_bytes; double hvm_scaled_vm_row_bytes; + double vm_time_budget; + double row_time_budget; + double vm_and_row_time_budget; bool dual_plane; }; From 8fe96f0083a95ccd3d564b3b8e31ad0c4fcc6b4d Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Thu, 3 Sep 2026 08:25:27 -0400 Subject: [PATCH 038/103] drm/amd/display: Add inst field to struct abm Add an inst member to struct abm and set it to 0 in dce_abm_construct() and dmub_abm_construct(), since ABM is a singleton. No functional change; the field has no readers yet. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_abm.c | 2 ++ drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/abm.h | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index 469b4b8f88a3..bd9e0173ff9d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -220,6 +220,7 @@ static bool dce_abm_set_level(struct abm *abm, uint32_t level) static bool dce_abm_immediate_disable(struct abm *abm, uint32_t panel_inst) { + if (abm->dmcu_is_running == false) return true; @@ -272,6 +273,7 @@ static void dce_abm_construct( base->ctx = ctx; base->funcs = &dce_funcs; base->dmcu_is_running = false; + base->inst = 0; abm_dce->regs = regs; abm_dce->abm_shift = abm_shift; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c index 2df6e82b794f..8cca8599b917 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c @@ -280,6 +280,7 @@ static void dmub_abm_construct( base->ctx = ctx; base->funcs = &abm_funcs; base->dmcu_is_running = false; + base->inst = 0; abm_dce->regs = regs; abm_dce->abm_shift = abm_shift; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h index 6ae7cf109565..e3fa987304da 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h @@ -33,6 +33,7 @@ struct abm { struct dc_context *ctx; const struct abm_funcs *funcs; bool dmcu_is_running; + unsigned int inst; }; struct abm_funcs { From 6657d6bbbbf32a46bd3c442931452a7d1d22d326 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Sat, 5 Sep 2026 09:54:51 -0400 Subject: [PATCH 039/103] drm/amd/display: Add inst field to struct dmub_psr Add an inst member to struct dmub_psr and set it to 0 in dmub_psr_construct(), since the PSR object is a pool singleton. No functional change; the field has no readers yet. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c | 1 + drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c index 45630c3effe1..66d8ba73d38b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -481,6 +481,7 @@ static void dmub_psr_construct(struct dmub_psr *psr, struct dc_context *ctx) { psr->ctx = ctx; psr->funcs = &psr_funcs; + psr->inst = 0; } /* diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h index a6e282d950c3..45ba9902ebbb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h @@ -34,6 +34,7 @@ struct dmub_psr_funcs; struct dmub_psr { struct dc_context *ctx; const struct dmub_psr_funcs *funcs; + uint32_t inst; }; struct dmub_psr_funcs { From 7b464181c288dd750270c4da3e4ebbde9b221400 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Sat, 5 Sep 2026 09:55:23 -0400 Subject: [PATCH 040/103] drm/amd/display: Add inst field to struct dmub_replay Add an inst member to struct dmub_replay and set it to 0 in dmub_replay_construct(), since the replay object is a pool singleton. Also move the (void)panel_inst cast in dmub_replay_set_coasting_vtotal() below the local declarations, where it belongs. No functional change; the inst field has no readers yet. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c | 3 ++- drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c index 0785a30eb643..e6adca240ccf 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c @@ -217,13 +217,13 @@ static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub, uint8_t panel_inst, uint16_t frame_skip_number) { - (void)panel_inst; union dmub_rb_cmd cmd; struct dc_context *dc = dmub->ctx; struct dmub_rb_cmd_replay_set_coasting_vtotal *pCmd = NULL; pCmd = &(cmd.replay_set_coasting_vtotal); + (void)panel_inst; memset(&cmd, 0, sizeof(cmd)); pCmd->header.type = DMUB_CMD__REPLAY; pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_COASTING_VTOTAL; @@ -458,6 +458,7 @@ static void dmub_replay_construct(struct dmub_replay *replay, struct dc_context { replay->ctx = ctx; replay->funcs = &replay_funcs; + replay->inst = 0; } /* diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h index 271a42a226e9..fa17cd395e5c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h @@ -13,6 +13,7 @@ struct dmub_replay_funcs; struct dmub_replay { struct dc_context *ctx; const struct dmub_replay_funcs *funcs; + uint32_t inst; }; struct dmub_replay_funcs { From 7c23fe74a152ea0fa0791e134d27c4a13cd8636c Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 20:28:46 -0600 Subject: [PATCH 041/103] drm/amd/display: Select KUnit helpers [WHAT] DRM_KUNIT_TEST_HELPERS has no prompt, so it can only be turned on by a select. DRM_AMD_DC_KUNIT_TEST merely depended on it, which forced the amdgpu_dm KUnit config to enable CONFIG_DRM_KUNIT_TEST as well and drag in the entire core DRM test suite. [HOW] Select DRM_KUNIT_TEST_HELPERS from DRM_AMD_DC_KUNIT_TEST, matching what DRM_KUNIT_TEST and DRM_TTM_KUNIT_TEST already do, and drop CONFIG_DRM_KUNIT_TEST from the amdgpu_dm kunitconfig. The amdgpu_dm tests now build standalone and a run executes only the amdgpu_dm suites. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/Kconfig | 3 ++- drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 617bc1932524..a319680c329b 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -67,7 +67,8 @@ config DRM_AMD_SECURE_DISPLAY config DRM_AMD_DC_KUNIT_TEST tristate "KUnit tests for the AMD DC display driver" if !KUNIT_ALL_TESTS - depends on DRM_AMD_DC && KUNIT && DEBUG_FS && DRM_KUNIT_TEST_HELPERS + depends on DRM_AMD_DC && KUNIT && DEBUG_FS + select DRM_KUNIT_TEST_HELPERS default KUNIT_ALL_TESTS help This option enables KUnit tests for the AMD Display Core driver. diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig index c7c8527dbb10..0c26c510f7a5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig @@ -6,7 +6,6 @@ CONFIG_DRM_AMD_DC=y CONFIG_DEBUG_FS=y CONFIG_DRM_AMD_DC_KUNIT_TEST=y CONFIG_FW_LOADER=y -CONFIG_DRM_KUNIT_TEST=y CONFIG_DRM_KUNIT_TEST_HELPERS=y CONFIG_DRM_KMS_HELPER=y CONFIG_DRM_TTM=y From 7d7b5a0fb7ebf35b622b2942b7cb2997bc4661e1 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:38:26 -0600 Subject: [PATCH 042/103] drm/amd/display: Fold blending tests into two cases [WHAT] Reduce the five KUnit tests for amdgpu_dm_plane_fill_blending_from_plane_state() to two, keeping every covered path. [HOW] Turn the opaque, premultiplied and coverage cases into one table-driven test over the pixel blend mode, and fold the DCN 4.2 case into the global alpha test as a second table row selecting the DCE IP version. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 239 ++++++------------ 1 file changed, 83 insertions(+), 156 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index a18b1d99ae85..6a53f117cab1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -117,142 +117,111 @@ static void dm_test_plane_is_video_format_known_video(struct kunit *test) } /** - * dm_test_fill_blending_defaults() - Verify default blending output values. + * dm_test_fill_blending_pixel_blend_modes() - Verify per-pixel blending modes. * @test: KUnit test context. * - * Verify if default blending output values are used for opaque alpha and no - * per-pixel blending. + * Verify if opaque alpha keeps the default outputs, and if the premultiplied + * and coverage modes enable per-pixel alpha for an alpha-capable format. */ -static void dm_test_fill_blending_defaults(struct kunit *test) +static void dm_test_fill_blending_pixel_blend_modes(struct kunit *test) { - struct drm_plane_state state = { 0 }; - bool per_pixel_alpha; - bool pre_multiplied_alpha; - bool global_alpha; - int global_alpha_value; - - state.pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE; - state.alpha = 0xffff; - - amdgpu_dm_plane_fill_blending_from_plane_state(&state, - &per_pixel_alpha, - &pre_multiplied_alpha, - &global_alpha, - &global_alpha_value); - - KUNIT_EXPECT_FALSE(test, per_pixel_alpha); - KUNIT_EXPECT_TRUE(test, pre_multiplied_alpha); - KUNIT_EXPECT_FALSE(test, global_alpha); - KUNIT_EXPECT_EQ(test, global_alpha_value, 0xff); -} - -/** - * dm_test_fill_blending_premulti_alpha_format() - Verify premultiplied alpha path. - * @test: KUnit test context. - * - * Verify if premultiplied mode enables per-pixel alpha for ARGB8888. - */ -static void dm_test_fill_blending_premulti_alpha_format(struct kunit *test) -{ - struct drm_plane_state state = { 0 }; + static const struct { + const char *name; + unsigned int blend_mode; + bool with_fb; + bool per_pixel_alpha; + bool pre_multiplied_alpha; + } cases[] = { + { "defaults", DRM_MODE_BLEND_PIXEL_NONE, false, false, true }, + { "premultiplied", DRM_MODE_BLEND_PREMULTI, true, true, true }, + { "coverage", DRM_MODE_BLEND_COVERAGE, true, true, false }, + }; struct drm_framebuffer fb = { 0 }; - bool per_pixel_alpha; - bool pre_multiplied_alpha; - bool global_alpha; - int global_alpha_value; + unsigned int i; fb.format = drm_format_info(DRM_FORMAT_ARGB8888); KUNIT_ASSERT_NOT_NULL(test, fb.format); - state.fb = &fb; - state.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; - state.alpha = 0xffff; + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct drm_plane_state state = { 0 }; + bool per_pixel_alpha; + bool pre_multiplied_alpha; + bool global_alpha; + int global_alpha_value; - amdgpu_dm_plane_fill_blending_from_plane_state(&state, - &per_pixel_alpha, - &pre_multiplied_alpha, - &global_alpha, - &global_alpha_value); + if (cases[i].with_fb) + state.fb = &fb; + state.pixel_blend_mode = cases[i].blend_mode; + state.alpha = 0xffff; - KUNIT_EXPECT_TRUE(test, per_pixel_alpha); - KUNIT_EXPECT_TRUE(test, pre_multiplied_alpha); - KUNIT_EXPECT_FALSE(test, global_alpha); - KUNIT_EXPECT_EQ(test, global_alpha_value, 0xff); + amdgpu_dm_plane_fill_blending_from_plane_state(&state, + &per_pixel_alpha, + &pre_multiplied_alpha, + &global_alpha, + &global_alpha_value); + + KUNIT_EXPECT_EQ_MSG(test, per_pixel_alpha, cases[i].per_pixel_alpha, + "%s", cases[i].name); + KUNIT_EXPECT_EQ_MSG(test, pre_multiplied_alpha, cases[i].pre_multiplied_alpha, + "%s", cases[i].name); + KUNIT_EXPECT_FALSE_MSG(test, global_alpha, "%s", cases[i].name); + KUNIT_EXPECT_EQ_MSG(test, global_alpha_value, 0xff, "%s", cases[i].name); + } } /** - * dm_test_fill_blending_coverage_alpha_format() - Verify coverage mode behavior. + * dm_test_fill_blending_global_alpha() - Verify global alpha down-scaling. * @test: KUnit test context. * - * Verify if coverage mode sets per-pixel alpha and disables - * pre_multiplied_alpha for ARGB8888. - */ -static void dm_test_fill_blending_coverage_alpha_format(struct kunit *test) -{ - struct drm_plane_state state = { 0 }; - struct drm_framebuffer fb = { 0 }; - bool per_pixel_alpha; - bool pre_multiplied_alpha; - bool global_alpha; - int global_alpha_value; - - fb.format = drm_format_info(DRM_FORMAT_ARGB8888); - KUNIT_ASSERT_NOT_NULL(test, fb.format); - - state.fb = &fb; - state.pixel_blend_mode = DRM_MODE_BLEND_COVERAGE; - state.alpha = 0xffff; - - amdgpu_dm_plane_fill_blending_from_plane_state(&state, - &per_pixel_alpha, - &pre_multiplied_alpha, - &global_alpha, - &global_alpha_value); - - KUNIT_EXPECT_TRUE(test, per_pixel_alpha); - KUNIT_EXPECT_FALSE(test, pre_multiplied_alpha); - KUNIT_EXPECT_FALSE(test, global_alpha); - KUNIT_EXPECT_EQ(test, global_alpha_value, 0xff); -} - -/** - * dm_test_fill_blending_global_alpha() - Verify global alpha conversion to 8 bits. - * @test: KUnit test context. - * - * Verify if global alpha is enabled and converted from 16-bit to 8-bit. + * Verify if global alpha is enabled and the 16-bit DRM alpha is scaled down to + * the 8-bit hardware field, or to the 12-bit field used by DCN 4.2. */ static void dm_test_fill_blending_global_alpha(struct kunit *test) { - struct amdgpu_device *adev; - struct drm_plane *plane; - struct drm_plane_state *state; - bool per_pixel_alpha; - bool pre_multiplied_alpha; - bool global_alpha; - int global_alpha_value; + static const struct { + const char *name; + u32 dce_version; + int expected; + } cases[] = { + { "8-bit field", IP_VERSION(4, 0, 0), 0x80 }, + { "DCN 4.2 12-bit field", IP_VERSION(4, 2, 0), 0x800 }, + }; + unsigned int i; - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, state); + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct amdgpu_device *adev; + struct drm_plane *plane; + struct drm_plane_state *state; + bool per_pixel_alpha; + bool pre_multiplied_alpha; + bool global_alpha; + int global_alpha_value; - plane->dev = &adev->ddev; - state->plane = plane; - state->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE; - state->alpha = 0x8000; + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, state); - amdgpu_dm_plane_fill_blending_from_plane_state(state, - &per_pixel_alpha, - &pre_multiplied_alpha, - &global_alpha, - &global_alpha_value); + adev->ip_versions[DCE_HWIP][0] = cases[i].dce_version; + plane->dev = &adev->ddev; + state->plane = plane; + state->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE; + state->alpha = 0x8000; - KUNIT_EXPECT_FALSE(test, per_pixel_alpha); - KUNIT_EXPECT_TRUE(test, pre_multiplied_alpha); - KUNIT_EXPECT_TRUE(test, global_alpha); - KUNIT_EXPECT_EQ(test, global_alpha_value, 0x80); + amdgpu_dm_plane_fill_blending_from_plane_state(state, + &per_pixel_alpha, + &pre_multiplied_alpha, + &global_alpha, + &global_alpha_value); + + KUNIT_EXPECT_FALSE_MSG(test, per_pixel_alpha, "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, pre_multiplied_alpha, "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, global_alpha, "%s", cases[i].name); + KUNIT_EXPECT_EQ_MSG(test, global_alpha_value, cases[i].expected, + "%s", cases[i].name); + } } /** @@ -1157,45 +1126,6 @@ static void dm_test_get_format_info(struct kunit *test) KUNIT_EXPECT_NOT_NULL(test, format_info); } -/** - * dm_test_fill_blending_global_alpha_dcn42() - Verify DCN 4.2 alpha scaling. - * @test: KUnit test context. - * - * Verify if DCN 4.2 scales the 16-bit DRM alpha down by 4 bits instead of 8. - */ -static void dm_test_fill_blending_global_alpha_dcn42(struct kunit *test) -{ - struct amdgpu_device *adev; - struct drm_plane *plane; - struct drm_plane_state *state; - bool per_pixel_alpha; - bool pre_multiplied_alpha; - bool global_alpha; - int global_alpha_value; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, state); - - adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 2, 0); - plane->dev = &adev->ddev; - state->plane = plane; - state->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE; - state->alpha = 0x8000; - - amdgpu_dm_plane_fill_blending_from_plane_state(state, - &per_pixel_alpha, - &pre_multiplied_alpha, - &global_alpha, - &global_alpha_value); - - KUNIT_EXPECT_TRUE(test, global_alpha); - KUNIT_EXPECT_EQ(test, global_alpha_value, 0x800); -} - /* Modifier lists are terminated by DRM_FORMAT_MOD_INVALID, which is not counted. */ static int dm_test_mods_count(const u64 *mods) { @@ -4023,11 +3953,8 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { /* amdgpu_dm_plane_get_format_info() */ KUNIT_CASE(dm_test_get_format_info), /* amdgpu_dm_plane_fill_blending_from_plane_state() */ - KUNIT_CASE(dm_test_fill_blending_defaults), - KUNIT_CASE(dm_test_fill_blending_premulti_alpha_format), - KUNIT_CASE(dm_test_fill_blending_coverage_alpha_format), + KUNIT_CASE(dm_test_fill_blending_pixel_blend_modes), KUNIT_CASE(dm_test_fill_blending_global_alpha), - KUNIT_CASE(dm_test_fill_blending_global_alpha_dcn42), /* amdgpu_dm_plane_modifier_* helpers() */ KUNIT_CASE(dm_test_modifier_has_dcc), KUNIT_CASE(dm_test_modifier_gfx9_swizzle_mode), From 323d41b49e3bbcba6aa2d07d025273e47e597060 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:38:55 -0600 Subject: [PATCH 043/103] drm/amd/display: Fold universal overlay format test [WHAT] Reduce the two KUnit tests for amdgpu_dm_plane_get_plane_formats() to one. [HOW] Allocate a second plane cap with the DCN universal type in the existing test and check the overlay format count against it, then drop the standalone test. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 39 ++++++------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index 6a53f117cab1..c2d26e0ca109 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -258,18 +258,23 @@ static void dm_test_modifier_gfx9_swizzle_mode(struct kunit *test) * dm_test_get_plane_formats() - Verify plane format counts for key plane types. * @test: KUnit test context. * - * Verify if returned format counts match primary, overlay, and cursor planes. + * Verify if returned format counts match primary, overlay, and cursor planes, + * and if an overlay with a DCN universal plane cap reports the RGB list + * instead of the overlay-only list. */ static void dm_test_get_plane_formats(struct kunit *test) { struct drm_plane *plane; struct dc_plane_cap *cap; + struct dc_plane_cap *universal_cap; uint32_t formats[32] = {0}; plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); cap = kunit_kzalloc(test, sizeof(*cap), GFP_KERNEL); + universal_cap = kunit_kzalloc(test, sizeof(*universal_cap), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, plane); KUNIT_ASSERT_NOT_NULL(test, cap); + KUNIT_ASSERT_NOT_NULL(test, universal_cap); plane->type = DRM_PLANE_TYPE_PRIMARY; KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_get_plane_formats(plane, NULL, formats, 32), 14); @@ -282,6 +287,11 @@ static void dm_test_get_plane_formats(struct kunit *test) plane->type = DRM_PLANE_TYPE_OVERLAY; KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_get_plane_formats(plane, NULL, formats, 32), 9); + universal_cap->type = DC_PLANE_TYPE_DCN_UNIVERSAL; + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_get_plane_formats(plane, universal_cap, formats, 32), + 14); + plane->type = DRM_PLANE_TYPE_CURSOR; KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_get_plane_formats(plane, NULL, formats, 32), 1); } @@ -1307,32 +1317,6 @@ static u64 dm_test_gfx11_dcc_4k_modifier(u32 pipe_xor_bits, u32 pkrs, u32 tile) AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B); } -/** - * dm_test_get_plane_formats_overlay_universal_cap() - Verify universal overlay. - * @test: KUnit test context. - * - * Verify if an overlay plane with a DCN universal plane cap reports the RGB - * format list instead of the overlay-only list. - */ -static void dm_test_get_plane_formats_overlay_universal_cap(struct kunit *test) -{ - struct drm_plane *plane; - struct dc_plane_cap *cap; - u32 formats[32] = {0}; - - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - cap = kunit_kzalloc(test, sizeof(*cap), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, cap); - - plane->type = DRM_PLANE_TYPE_OVERLAY; - cap->type = DC_PLANE_TYPE_DCN_UNIVERSAL; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_get_plane_formats(plane, cap, formats, 32), - 14); -} - /** * dm_test_get_plane_modifiers_gfx9() - Verify GFX9 modifier list generation. * @test: KUnit test context. @@ -3960,7 +3944,6 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_modifier_gfx9_swizzle_mode), /* amdgpu_dm_plane_get_plane_formats() */ KUNIT_CASE(dm_test_get_plane_formats), - KUNIT_CASE(dm_test_get_plane_formats_overlay_universal_cap), /* amdgpu_dm_plane_get_plane_modifiers() */ KUNIT_CASE(dm_test_get_plane_modifiers), KUNIT_CASE(dm_test_get_plane_modifiers_gfx6), From 5d95a6d2cc7a85ea870993274377dd79d515b1f0 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:39:24 -0600 Subject: [PATCH 044/103] drm/amd/display: Fold plane modifier list tests [WHAT] Reduce the six KUnit tests for amdgpu_dm_plane_get_plane_modifiers() to three, keeping every family dispatch covered. [HOW] Merge the GFX10.1, GFX10.3 and GFX12 cases into one table-driven test over the family and GC IP version, and merge the two RV cases into a table over the external revision id that selects the constant-encode modifier variants. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 233 +++++++----------- 1 file changed, 88 insertions(+), 145 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index c2d26e0ca109..f11ae8e82adc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -1340,45 +1340,66 @@ static void dm_test_get_plane_modifiers_gfx9(struct kunit *test) dm_test_expect_mods_terminated(test, adev); } +/** + * dm_test_get_plane_modifiers_gfx10_and_gfx12() - Verify newer family dispatch. + * @test: KUnit test context. + * + * Verify if the GFX10.1, GFX10.3 and GFX12 configurations each dispatch to + * their modifier builder and produce a terminated list. + */ +static void dm_test_get_plane_modifiers_gfx10_and_gfx12(struct kunit *test) +{ + static const struct { + u32 family; + u32 gc_ip_version; + u32 num_pipes; + u32 num_pkrs; + } cases[] = { + { AMDGPU_FAMILY_NV, IP_VERSION(10, 1, 0), 4, 0 }, + { AMDGPU_FAMILY_NV, IP_VERSION(10, 3, 0), 4, 2 }, + { AMDGPU_FAMILY_GC_12_0_0, 0, 0, 0 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->family = cases[i].family; + adev->ip_versions[GC_HWIP][0] = cases[i].gc_ip_version; + adev->gfx.config.gb_addr_config_fields.num_pipes = cases[i].num_pipes; + adev->gfx.config.gb_addr_config_fields.num_pkrs = cases[i].num_pkrs; + + dm_test_expect_mods_terminated(test, adev); + } +} + /** * dm_test_get_plane_modifiers_rv() - Verify RV modifier list generation. * @test: KUnit test context. * - * Verify if pre-Raven2 RV devices add RV-specific S-swizzle modifiers and - * non-constant-encode DCC modifiers. + * Verify if RV devices add the RV-specific S-swizzle modifiers, and if the + * constant-encode DCC variants only appear from Raven2 onwards. */ static void dm_test_get_plane_modifiers_rv(struct kunit *test) { - struct amdgpu_device *adev; - u64 *mods; - u64 dcc_mod; - u64 s_x_mod; - u64 s_mod; + static const struct { + const char *name; + u32 external_rev_id; + u32 constant_encode; + } cases[] = { + { "raven", 0x80, 0 }, + { "raven2", 0x81, 1 }, + }; int pipes = 2; int pipe_xor_bits = 3; int bank_xor_bits = 2; + u64 s_x_mod; + u64 s_mod; + unsigned int i; - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - - adev->family = AMDGPU_FAMILY_RV; - adev->asic_type = CHIP_RAVEN; - adev->external_rev_id = 0x80; - adev->gfx.config.gb_addr_config_fields.num_pipes = 4; - adev->gfx.config.gb_addr_config_fields.num_banks = 4; - adev->gfx.config.gb_addr_config_fields.num_se = 2; - adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 2; - - mods = dm_test_get_primary_mods(test, adev); - dcc_mod = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | - AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | - AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) | - AMD_FMT_MOD_SET(DCC, 1) | - AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | - AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) | - AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0); s_x_mod = AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | @@ -1388,105 +1409,49 @@ static void dm_test_get_plane_modifiers_rv(struct kunit *test) AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9); - KUNIT_EXPECT_TRUE(test, dm_test_mods_contain(mods, dcc_mod)); - KUNIT_EXPECT_TRUE(test, dm_test_mods_contain(mods, dcc_mod | - AMD_FMT_MOD_SET(DCC_RETILE, 1) | - AMD_FMT_MOD_SET(RB, 2) | - AMD_FMT_MOD_SET(PIPE, pipes))); - KUNIT_EXPECT_TRUE(test, dm_test_mods_contain(mods, s_x_mod)); - KUNIT_EXPECT_TRUE(test, dm_test_mods_contain(mods, s_mod)); + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct amdgpu_device *adev; + u64 *mods; + u64 dcc_mod; + u64 retile_mod; - kfree(mods); -} + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); -/** - * dm_test_get_plane_modifiers_rv_constant_encode() - Verify Raven2+ modifiers. - * @test: KUnit test context. - * - * Verify if Raven2 and later RV devices add the constant-encode modifier - * variants. - */ -static void dm_test_get_plane_modifiers_rv_constant_encode(struct kunit *test) -{ - struct amdgpu_device *adev; - u64 *mods; - u64 dcc_mod; - int pipes = 2; - int pipe_xor_bits = 3; - int bank_xor_bits = 2; + adev->family = AMDGPU_FAMILY_RV; + adev->asic_type = CHIP_RAVEN; + adev->external_rev_id = cases[i].external_rev_id; + adev->gfx.config.gb_addr_config_fields.num_pipes = 4; + adev->gfx.config.gb_addr_config_fields.num_banks = 4; + adev->gfx.config.gb_addr_config_fields.num_se = 2; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 2; - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); + mods = dm_test_get_primary_mods(test, adev); + dcc_mod = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) | + AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, cases[i].constant_encode); + retile_mod = dcc_mod | + AMD_FMT_MOD_SET(DCC_RETILE, 1) | + AMD_FMT_MOD_SET(RB, 2) | + AMD_FMT_MOD_SET(PIPE, pipes); - adev->family = AMDGPU_FAMILY_RV; - adev->asic_type = CHIP_RAVEN; - adev->external_rev_id = 0x81; - adev->gfx.config.gb_addr_config_fields.num_pipes = 4; - adev->gfx.config.gb_addr_config_fields.num_banks = 4; - adev->gfx.config.gb_addr_config_fields.num_se = 2; - adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 2; + KUNIT_EXPECT_TRUE_MSG(test, dm_test_mods_contain(mods, dcc_mod), + "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, dm_test_mods_contain(mods, retile_mod), + "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, dm_test_mods_contain(mods, s_x_mod), + "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, dm_test_mods_contain(mods, s_mod), + "%s", cases[i].name); - mods = dm_test_get_primary_mods(test, adev); - dcc_mod = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | - AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | - AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) | - AMD_FMT_MOD_SET(DCC, 1) | - AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | - AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) | - AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1); - - KUNIT_EXPECT_TRUE(test, dm_test_mods_contain(mods, dcc_mod)); - KUNIT_EXPECT_TRUE(test, dm_test_mods_contain(mods, dcc_mod | - AMD_FMT_MOD_SET(DCC_RETILE, 1) | - AMD_FMT_MOD_SET(RB, 2) | - AMD_FMT_MOD_SET(PIPE, pipes))); - - kfree(mods); -} - -/** - * dm_test_get_plane_modifiers_gfx10_1() - Verify GFX10.1 modifier list generation. - * @test: KUnit test context. - * - * Verify if a pre-10.3 NV family device dispatches to the GFX10.1 modifier - * builder and produces a terminated list. - */ -static void dm_test_get_plane_modifiers_gfx10_1(struct kunit *test) -{ - struct amdgpu_device *adev; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - - adev->family = AMDGPU_FAMILY_NV; - adev->gfx.config.gb_addr_config_fields.num_pipes = 4; - adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 1, 0); - - dm_test_expect_mods_terminated(test, adev); -} - -/** - * dm_test_get_plane_modifiers_gfx10_3() - Verify GFX10.3 modifier list generation. - * @test: KUnit test context. - * - * Verify if a 10.3+ NV family device dispatches to the GFX10.3 modifier - * builder and produces a terminated list. - */ -static void dm_test_get_plane_modifiers_gfx10_3(struct kunit *test) -{ - struct amdgpu_device *adev; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - - adev->family = AMDGPU_FAMILY_NV; - adev->gfx.config.gb_addr_config_fields.num_pipes = 4; - adev->gfx.config.gb_addr_config_fields.num_pkrs = 2; - adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0); - - dm_test_expect_mods_terminated(test, adev); + kfree(mods); + } } /** @@ -1571,25 +1536,6 @@ static void dm_test_get_plane_modifiers_gfx11_256k_first(struct kunit *test) kfree(mods); } -/** - * dm_test_get_plane_modifiers_gfx12() - Verify GFX12 modifier list generation. - * @test: KUnit test context. - * - * Verify if the GFX12 family dispatches to the GFX12 modifier builder and - * produces a terminated list. - */ -static void dm_test_get_plane_modifiers_gfx12(struct kunit *test) -{ - struct amdgpu_device *adev; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - - adev->family = AMDGPU_FAMILY_GC_12_0_0; - - dm_test_expect_mods_terminated(test, adev); -} - /** * dm_test_fill_gfx9_plane_attributes_dcc() - Verify GFX9 DCC modifier path. * @test: KUnit test context. @@ -3949,12 +3895,9 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_get_plane_modifiers_gfx6), KUNIT_CASE(dm_test_get_plane_modifiers_gfx9), KUNIT_CASE(dm_test_get_plane_modifiers_rv), - KUNIT_CASE(dm_test_get_plane_modifiers_rv_constant_encode), - KUNIT_CASE(dm_test_get_plane_modifiers_gfx10_1), - KUNIT_CASE(dm_test_get_plane_modifiers_gfx10_3), + KUNIT_CASE(dm_test_get_plane_modifiers_gfx10_and_gfx12), KUNIT_CASE(dm_test_get_plane_modifiers_gfx11_64k_first), KUNIT_CASE(dm_test_get_plane_modifiers_gfx11_256k_first), - KUNIT_CASE(dm_test_get_plane_modifiers_gfx12), /* amdgpu_dm_plane_fill_dc_scaling_info() */ KUNIT_CASE(dm_test_fill_dc_scaling_info), KUNIT_CASE(dm_test_fill_dc_scaling_info_nv12_dcn1x), From 961c31c1c4aa310120849c81419e52e408aadfd7 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:39:52 -0600 Subject: [PATCH 045/103] drm/amd/display: Fold modifier append tests [WHAT] Reduce the four KUnit tests for amdgpu_dm_plane_add_modifier() to two, and the two tests for amdgpu_dm_plane_add_modifier_dedup() to one. [HOW] Group the append and capacity-growth cases into one test and the NULL-list and allocation-failure cases into another, and run the duplicate-skip and NULL-list dedup cases in sequence within a single test. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 96 +++++++------------ 1 file changed, 33 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index f11ae8e82adc..288eb618342b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -855,12 +855,13 @@ static void dm_test_validate_dcc_independent_64b_mismatch_fails(struct kunit *te } /** - * dm_test_add_modifier_appends_value() - Verify one modifier append. + * dm_test_add_modifier_appends_and_grows() - Verify append and capacity growth. * @test: KUnit test context. * - * Verify if a modifier is appended and size is updated. + * Verify if a modifier is appended within the existing capacity, and if a full + * list is grown while preserving the modifiers already stored. */ -static void dm_test_add_modifier_appends_value(struct kunit *test) +static void dm_test_add_modifier_appends_and_grows(struct kunit *test) { uint64_t size = 0; uint64_t cap = 2; @@ -876,20 +877,10 @@ static void dm_test_add_modifier_appends_value(struct kunit *test) KUNIT_EXPECT_EQ(test, mods[0], 0x1234ULL); kfree(mods); -} - -/** - * dm_test_add_modifier_grows_capacity() - Verify add triggers growth and preserves old data. - * @test: KUnit test context. - * - * Verify if modifier array growth keeps old data and appends new data. - */ -static void dm_test_add_modifier_grows_capacity(struct kunit *test) -{ - uint64_t size = 1; - uint64_t cap = 1; - uint64_t *mods = kmalloc_array(cap, sizeof(*mods), GFP_KERNEL); + size = 1; + cap = 1; + mods = kmalloc_array(cap, sizeof(*mods), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, mods); mods[0] = 0xAAULL; @@ -905,12 +896,14 @@ static void dm_test_add_modifier_grows_capacity(struct kunit *test) } /** - * dm_test_add_modifier_noop_when_mods_null() - Verify helper is a no-op on NULL mods list. + * dm_test_add_modifier_failure_paths() - Verify the two failure paths. * @test: KUnit test context. * - * Verify if add_modifier does nothing when the modifier list is NULL. + * Verify if the append is a no-op once the modifier list is NULL, and if a + * failed capacity growth releases and clears the list so the caller can detect + * the allocation failure. */ -static void dm_test_add_modifier_noop_when_mods_null(struct kunit *test) +static void dm_test_add_modifier_failure_paths(struct kunit *test) { uint64_t size = 3; uint64_t cap = 7; @@ -921,6 +914,17 @@ static void dm_test_add_modifier_noop_when_mods_null(struct kunit *test) KUNIT_EXPECT_PTR_EQ(test, mods, NULL); KUNIT_EXPECT_EQ(test, size, 3ULL); KUNIT_EXPECT_EQ(test, cap, 7ULL); + + /* Doubling this capacity overflows the kmalloc_array() size product. */ + cap = 1ULL << 62; + size = cap; + mods = kmalloc_array(1, sizeof(*mods), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, mods); + + amdgpu_dm_plane_add_modifier(&mods, &size, &cap, 0x1234ULL); + + KUNIT_EXPECT_PTR_EQ(test, mods, NULL); + KUNIT_EXPECT_EQ(test, size, 1ULL << 62); } /** @@ -3020,13 +3024,14 @@ static void dm_test_plane_destroy_state_releases_resources(struct kunit *test) } /** - * dm_test_add_modifier_dedup_skips_duplicate() - Verify duplicates are not appended. + * dm_test_add_modifier_dedup() - Verify the de-duplicating append. * @test: KUnit test context. * * Verify if a modifier already present in the list is not appended a second - * time. + * time, and if the append is a no-op once the list is NULL after an earlier + * allocation failure. */ -static void dm_test_add_modifier_dedup_skips_duplicate(struct kunit *test) +static void dm_test_add_modifier_dedup(struct kunit *test) { u64 size = 2; u64 cap = 4; @@ -3047,20 +3052,10 @@ static void dm_test_add_modifier_dedup_skips_duplicate(struct kunit *test) KUNIT_EXPECT_EQ(test, mods[2], 0xCCULL); kfree(mods); -} -/** - * dm_test_add_modifier_dedup_noop_when_mods_null() - Verify NULL list is a no-op. - * @test: KUnit test context. - * - * Verify if the de-duplicating append does nothing when the modifier list is - * NULL after an earlier allocation failure. - */ -static void dm_test_add_modifier_dedup_noop_when_mods_null(struct kunit *test) -{ - u64 size = 3; - u64 cap = 7; - u64 *mods = NULL; + size = 3; + cap = 7; + mods = NULL; amdgpu_dm_plane_add_modifier_dedup(&mods, &size, &cap, 0x55ULL); @@ -3555,28 +3550,6 @@ static void dm_test_atomic_async_update_copies_state(struct kunit *test) KUNIT_EXPECT_EQ(test, cur_state->crtc_h, 64U); } -/** - * dm_test_add_modifier_alloc_failure() - Verify the growth allocation failure. - * @test: KUnit test context. - * - * Verify if a failed capacity growth releases and clears the modifier list so - * the caller can detect the allocation failure. - */ -static void dm_test_add_modifier_alloc_failure(struct kunit *test) -{ - /* Doubling this capacity overflows the kmalloc_array() size product. */ - u64 cap = 1ULL << 62; - u64 size = cap; - u64 *mods = kmalloc_array(1, sizeof(*mods), GFP_KERNEL); - - KUNIT_ASSERT_NOT_NULL(test, mods); - - amdgpu_dm_plane_add_modifier(&mods, &size, &cap, 0x1234ULL); - - KUNIT_EXPECT_PTR_EQ(test, mods, NULL); - KUNIT_EXPECT_EQ(test, size, 1ULL << 62); -} - /** * dm_test_fill_plane_buffer_attributes_gfx6() - Verify the pre-GFX9 dispatch. * @test: KUnit test context. @@ -3968,13 +3941,10 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_plane_destroy_state_minimal), KUNIT_CASE(dm_test_plane_destroy_state_releases_resources), /* amdgpu_dm_plane_add_modifier() */ - KUNIT_CASE(dm_test_add_modifier_appends_value), - KUNIT_CASE(dm_test_add_modifier_grows_capacity), - KUNIT_CASE(dm_test_add_modifier_noop_when_mods_null), - KUNIT_CASE(dm_test_add_modifier_alloc_failure), + KUNIT_CASE(dm_test_add_modifier_appends_and_grows), + KUNIT_CASE(dm_test_add_modifier_failure_paths), /* amdgpu_dm_plane_add_modifier_dedup() */ - KUNIT_CASE(dm_test_add_modifier_dedup_skips_duplicate), - KUNIT_CASE(dm_test_add_modifier_dedup_noop_when_mods_null), + KUNIT_CASE(dm_test_add_modifier_dedup), /* amdgpu_dm_plane_fill_gfx6_tiling_info_from_modifier() */ KUNIT_CASE(dm_test_fill_gfx6_tiling_info_linear), KUNIT_CASE(dm_test_fill_gfx6_tiling_info_rejects), From 5cdf1619d92087f56119d2aea6133884c5b2ad47 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:40:21 -0600 Subject: [PATCH 046/103] drm/amd/display: Fold GFX9 tiling info tests [WHAT] Reduce the two KUnit tests for amdgpu_dm_plane_fill_gfx9_tiling_info_from_device() to one, and the three for amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier() to one. [HOW] Reprogram the device configuration and re-run the helper in sequence inside a single test per function, so the pre-10.3, 10.3-and-later, linear, pre-NV and NV-and-later cases all stay covered. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 80 ++++--------------- 1 file changed, 17 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index 288eb618342b..fd3eb07e4e42 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -928,12 +928,13 @@ static void dm_test_add_modifier_failure_paths(struct kunit *test) } /** - * dm_test_fill_gfx9_tiling_info_from_device_pre_10_3() - Verify GFX9 field copy before 10.3. + * dm_test_fill_gfx9_tiling_info_from_device() - Verify GFX9 device field copy. * @test: KUnit test context. * - * Verify if pre-10.3 device fields are copied and existing num_pkrs is kept. + * Verify if the device tiling fields are copied, and if num_pkrs is left + * untouched before GFX 10.3 but taken from the device from GFX 10.3 onwards. */ -static void dm_test_fill_gfx9_tiling_info_from_device_pre_10_3(struct kunit *test) +static void dm_test_fill_gfx9_tiling_info_from_device(struct kunit *test) { struct amdgpu_device *adev; struct dc_tiling_info tiling_info = {0}; @@ -962,21 +963,6 @@ static void dm_test_fill_gfx9_tiling_info_from_device_pre_10_3(struct kunit *tes KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_rb_per_se, 2U); KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 0x5aU); -} - -/** - * dm_test_fill_gfx9_tiling_info_from_device_10_3_plus() - Verify num_pkrs update on 10.3+. - * @test: KUnit test context. - * - * Verify if 10.3+ device fields are copied and num_pkrs is updated. - */ -static void dm_test_fill_gfx9_tiling_info_from_device_10_3_plus(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc_tiling_info tiling_info = {0}; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); adev->gfx.config.gb_addr_config_fields.num_pipes = 2; adev->gfx.config.gb_addr_config_fields.num_banks = 4; @@ -987,6 +973,8 @@ static void dm_test_fill_gfx9_tiling_info_from_device_10_3_plus(struct kunit *te adev->gfx.config.gb_addr_config_fields.num_pkrs = 6; adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0); + memset(&tiling_info, 0, sizeof(tiling_info)); + amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(adev, &tiling_info); KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pipes, 2U); @@ -1000,15 +988,18 @@ static void dm_test_fill_gfx9_tiling_info_from_device_10_3_plus(struct kunit *te } /** - * dm_test_fill_gfx9_tiling_info_from_modifier_linear() - Verify non-AMD modifier keeps device values. + * dm_test_fill_gfx9_tiling_info_from_modifier() - Verify GFX9 modifier decoding. * @test: KUnit test context. * - * Verify if linear modifier path keeps values from device configuration. + * Verify if a non-AMD modifier keeps the device values, if an AMD modifier + * updates the bank count on pre-NV families, and if it updates the packer + * count on NV and later. */ -static void dm_test_fill_gfx9_tiling_info_from_modifier_linear(struct kunit *test) +static void dm_test_fill_gfx9_tiling_info_from_modifier(struct kunit *test) { struct amdgpu_device *adev; struct dc_tiling_info tiling_info = {0}; + uint64_t modifier; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, adev); @@ -1034,33 +1025,13 @@ static void dm_test_fill_gfx9_tiling_info_from_modifier_linear(struct kunit *tes KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_rb_per_se, 2U); KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 3U); -} - -/** - * dm_test_fill_gfx9_tiling_info_from_modifier_pre_nv() - Verify AMD modifier updates banks on pre-NV. - * @test: KUnit test context. - * - * Verify if AMD modifier updates pre-NV pipe, engine, and bank fields. - */ -static void dm_test_fill_gfx9_tiling_info_from_modifier_pre_nv(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc_tiling_info tiling_info = {0}; - uint64_t modifier; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); adev->family = AMDGPU_FAMILY_RV; - adev->gfx.config.gb_addr_config_fields.num_pipes = 4; adev->gfx.config.gb_addr_config_fields.num_banks = 16; - adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 256; - adev->gfx.config.gb_addr_config_fields.num_se = 2; - adev->gfx.config.gb_addr_config_fields.max_compress_frags = 1; - adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 2; adev->gfx.config.gb_addr_config_fields.num_pkrs = 7; adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 2, 9); + memset(&tiling_info, 0, sizeof(tiling_info)); tiling_info.gfx9.num_pkrs = 0x5a; modifier = AMD_FMT_MOD | @@ -1076,22 +1047,6 @@ static void dm_test_fill_gfx9_tiling_info_from_modifier_pre_nv(struct kunit *tes KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_banks, 8U); KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 0x5aU); KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); -} - -/** - * dm_test_fill_gfx9_tiling_info_from_modifier_nv() - Verify AMD modifier updates packers on NV+. - * @test: KUnit test context. - * - * Verify if AMD modifier updates NV+ pipe, engine, and packer fields. - */ -static void dm_test_fill_gfx9_tiling_info_from_modifier_nv(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc_tiling_info tiling_info = {0}; - uint64_t modifier; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); adev->family = AMDGPU_FAMILY_NV; adev->gfx.config.gb_addr_config_fields.num_pipes = 2; @@ -1103,6 +1058,8 @@ static void dm_test_fill_gfx9_tiling_info_from_modifier_nv(struct kunit *test) adev->gfx.config.gb_addr_config_fields.num_pkrs = 2; adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0); + memset(&tiling_info, 0, sizeof(tiling_info)); + modifier = AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, 6) | @@ -3963,12 +3920,9 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { /* amdgpu_dm_plane_gfx6_format_mod_supported() */ KUNIT_CASE(dm_test_gfx6_format_mod_supported), /* amdgpu_dm_plane_fill_gfx9_tiling_info_from_device() */ - KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_device_pre_10_3), - KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_device_10_3_plus), + KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_device), /* amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier() */ - KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier_linear), - KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier_pre_nv), - KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier_nv), + KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier), /* amdgpu_dm_plane_validate_dcc() */ KUNIT_CASE(dm_test_validate_dcc_disabled_returns_success), KUNIT_CASE(dm_test_validate_dcc_video_non_gfx12_fails), From b15161b13287cac501e6e4ff108d6ee3e902065a Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:40:50 -0600 Subject: [PATCH 047/103] drm/amd/display: Fold GFX6-8 tiling and modifier tests [WHAT] Reduce the four KUnit tests for amdgpu_dm_plane_fill_gfx6_tiling_info_from_modifier() to one, and the three for amdgpu_dm_plane_calc_gfx6_mod() to one. [HOW] Build the linear, rejected, 1D tiled and 2D tiled modifiers as locals and decode them in sequence, and drive the micro tiled, GFX7-8 and GFX6 modifier calculations from two devices inside a single test. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 152 ++++++------------ 1 file changed, 48 insertions(+), 104 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index fd3eb07e4e42..331abfbd252d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -3027,80 +3027,50 @@ static int dm_test_gfx6_tiling(struct dc_tiling_info *tiling_info, u64 modifier) } /** - * dm_test_fill_gfx6_tiling_info_linear() - Verify linear modifier decoding. + * dm_test_fill_gfx6_tiling_info_from_modifier() - Verify GFX6-8 modifier decoding. * @test: KUnit test context. * - * Verify if a linear modifier maps to the generic linear array mode. + * Verify if a linear modifier maps to the generic linear array mode, if non-AMD + * modifiers and newer tile versions are rejected, if a 1D tiled modifier stops + * before the macro tiling fields, and if a 2D tiled modifier decodes them all. */ -static void dm_test_fill_gfx6_tiling_info_linear(struct kunit *test) -{ - struct dc_tiling_info tiling_info = {0}; - - KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, DRM_FORMAT_MOD_LINEAR), 0); - KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.array_mode, (int)DC_ARRAY_LINEAR_GENERAL); - KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxVersion8); -} - -/** - * dm_test_fill_gfx6_tiling_info_rejects() - Verify unsupported modifiers fail. - * @test: KUnit test context. - * - * Verify if non-AMD modifiers and AMD modifiers from a newer tile version are - * rejected. - */ -static void dm_test_fill_gfx6_tiling_info_rejects(struct kunit *test) +static void dm_test_fill_gfx6_tiling_info_from_modifier(struct kunit *test) { struct dc_tiling_info tiling_info = {0}; u64 not_amd_mod = DRM_FORMAT_MOD_VENDOR_AMD; u64 gfx9_mod = AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9); + u64 mod_1d = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_1D_TILED_THIN1) | + AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY) | + AMD_FMT_MOD_SET(NUM_BANKS, 3); + u64 mod_2d = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_2D_TILED_THIN1) | + AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY) | + AMD_FMT_MOD_SET(PIPE_CONFIG, 5) | + AMD_FMT_MOD_SET(TILE_SPLIT, 4) | + AMD_FMT_MOD_SET(BANK_WIDTH, 1) | + AMD_FMT_MOD_SET(BANK_HEIGHT, 2) | + AMD_FMT_MOD_SET(MACRO_TILE_ASPECT, 3) | + AMD_FMT_MOD_SET(NUM_BANKS, 2); + + KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, DRM_FORMAT_MOD_LINEAR), 0); + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.array_mode, (int)DC_ARRAY_LINEAR_GENERAL); + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxVersion8); KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, not_amd_mod), -EINVAL); KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, gfx9_mod), -EINVAL); -} -/** - * dm_test_fill_gfx6_tiling_info_1d() - Verify micro tiled modifier decoding. - * @test: KUnit test context. - * - * Verify if a 1D tiled modifier stops before decoding the macro tiling fields. - */ -static void dm_test_fill_gfx6_tiling_info_1d(struct kunit *test) -{ - struct dc_tiling_info tiling_info = {0}; - u64 modifier = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_1D_TILED_THIN1) | - AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY) | - AMD_FMT_MOD_SET(NUM_BANKS, 3); - - KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, modifier), 0); + memset(&tiling_info, 0, sizeof(tiling_info)); + KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, mod_1d), 0); KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.array_mode, (int)AMD_FMT_MOD_TILE_GFX6_1D_TILED_THIN1); KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxVersion8); KUNIT_EXPECT_EQ(test, tiling_info.gfx8.num_banks, 0U); -} -/** - * dm_test_fill_gfx6_tiling_info_2d() - Verify macro tiled modifier decoding. - * @test: KUnit test context. - * - * Verify if a 2D tiled modifier decodes the full set of macro tiling fields. - */ -static void dm_test_fill_gfx6_tiling_info_2d(struct kunit *test) -{ - struct dc_tiling_info tiling_info = {0}; - u64 modifier = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_2D_TILED_THIN1) | - AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY) | - AMD_FMT_MOD_SET(PIPE_CONFIG, 5) | - AMD_FMT_MOD_SET(TILE_SPLIT, 4) | - AMD_FMT_MOD_SET(BANK_WIDTH, 1) | - AMD_FMT_MOD_SET(BANK_HEIGHT, 2) | - AMD_FMT_MOD_SET(MACRO_TILE_ASPECT, 3) | - AMD_FMT_MOD_SET(NUM_BANKS, 2); - - KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, modifier), 0); + memset(&tiling_info, 0, sizeof(tiling_info)); + KUNIT_EXPECT_EQ(test, dm_test_gfx6_tiling(&tiling_info, mod_2d), 0); KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.array_mode, (int)AMD_FMT_MOD_TILE_GFX6_2D_TILED_THIN1); KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.tile_mode, @@ -3227,35 +3197,26 @@ static void dm_test_get_gfx7_macro_tile_idx(struct kunit *test) } /** - * dm_test_calc_gfx6_mod_1d() - Verify the micro tiled GFX6-8 modifier. + * dm_test_calc_gfx6_mod() - Verify the GFX6-8 modifier calculation. * @test: KUnit test context. * * Verify if a micro tiled array mode returns early with only the base modifier - * fields set. + * fields set, if GFX7-8 combines the tile mode pipe config and computed tile + * split with the bank fields from the macro tile mode table, and if GFX6 takes + * the tile split and bank fields directly from the tile mode register. */ -static void dm_test_calc_gfx6_mod_1d(struct kunit *test) +static void dm_test_calc_gfx6_mod(struct kunit *test) { struct amdgpu_device *adev = dm_test_alloc_gfx7_device(test); - u64 expected = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_1D_TILED_THIN1) | - AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY); + struct amdgpu_device *si_adev; + u64 expected_1d = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_1D_TILED_THIN1) | + AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY); KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_calc_gfx6_mod(adev, 0, DC_ARRAY_1D_TILED_THIN1), - expected); -} - -/** - * dm_test_calc_gfx6_mod_gfx7() - Verify the macro tiled GFX7-8 modifier. - * @test: KUnit test context. - * - * Verify if the modifier combines the tile mode pipe config and computed tile - * split with the bank fields taken from the macro tile mode table. - */ -static void dm_test_calc_gfx6_mod_gfx7(struct kunit *test) -{ - struct amdgpu_device *adev = dm_test_alloc_gfx7_device(test); + expected_1d); /* 32 bpp: 256 byte tile split (log2 of 4 units), macro tile mode 2. */ KUNIT_EXPECT_EQ(test, @@ -3266,30 +3227,18 @@ static void dm_test_calc_gfx6_mod_gfx7(struct kunit *test) KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_calc_gfx6_mod(adev, 64, DC_ARRAY_2D_TILED_THIN1), dm_test_gfx6_mod(AMD_FMT_MOD_TILE_GFX6_2D_TILED_THIN1, 2, 3, 2, 2, 2, 0)); -} -/** - * dm_test_calc_gfx6_mod_si() - Verify the macro tiled GFX6 modifier. - * @test: KUnit test context. - * - * Verify if GFX6 takes the tile split and bank fields directly from the tile - * mode register instead of the macro tile mode table. - */ -static void dm_test_calc_gfx6_mod_si(struct kunit *test) -{ - struct amdgpu_device *adev; + si_adev = kunit_kzalloc(test, sizeof(*si_adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, si_adev); - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - - adev->family = AMDGPU_FAMILY_SI; + si_adev->family = AMDGPU_FAMILY_SI; /* 2D_TILED_THIN1, pipe config 3, 256 byte tile split, banks 1/2/3/1. */ - adev->gfx.config.tile_mode_array[12] = (4u << 2) | (3u << 6) | (2u << 11) | - (1u << 14) | (2u << 16) | (3u << 18) | - (1u << 20); + si_adev->gfx.config.tile_mode_array[12] = (4u << 2) | (3u << 6) | (2u << 11) | + (1u << 14) | (2u << 16) | (3u << 18) | + (1u << 20); KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_calc_gfx6_mod(adev, 32, DC_ARRAY_2D_TILED_THIN1), + amdgpu_dm_plane_calc_gfx6_mod(si_adev, 32, DC_ARRAY_2D_TILED_THIN1), dm_test_gfx6_mod(AMD_FMT_MOD_TILE_GFX6_2D_TILED_THIN1, 3, 2, 1, 2, 3, 1)); } @@ -3903,10 +3852,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { /* amdgpu_dm_plane_add_modifier_dedup() */ KUNIT_CASE(dm_test_add_modifier_dedup), /* amdgpu_dm_plane_fill_gfx6_tiling_info_from_modifier() */ - KUNIT_CASE(dm_test_fill_gfx6_tiling_info_linear), - KUNIT_CASE(dm_test_fill_gfx6_tiling_info_rejects), - KUNIT_CASE(dm_test_fill_gfx6_tiling_info_1d), - KUNIT_CASE(dm_test_fill_gfx6_tiling_info_2d), + KUNIT_CASE(dm_test_fill_gfx6_tiling_info_from_modifier), /* amdgpu_dm_plane_get_gfx6_tile_idx() */ KUNIT_CASE(dm_test_get_gfx6_tile_idx), /* amdgpu_dm_plane_calc_gfx7_tile_split() */ @@ -3914,9 +3860,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { /* amdgpu_dm_plane_get_gfx7_macro_tile_idx() */ KUNIT_CASE(dm_test_get_gfx7_macro_tile_idx), /* amdgpu_dm_plane_calc_gfx6_mod() */ - KUNIT_CASE(dm_test_calc_gfx6_mod_1d), - KUNIT_CASE(dm_test_calc_gfx6_mod_gfx7), - KUNIT_CASE(dm_test_calc_gfx6_mod_si), + KUNIT_CASE(dm_test_calc_gfx6_mod), /* amdgpu_dm_plane_gfx6_format_mod_supported() */ KUNIT_CASE(dm_test_gfx6_format_mod_supported), /* amdgpu_dm_plane_fill_gfx9_tiling_info_from_device() */ From fd5e57fe736eeca1642356e530aaa978c150916a Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:41:19 -0600 Subject: [PATCH 048/103] drm/amd/display: Fold DCC validation tests [WHAT] Reduce the seven KUnit tests for amdgpu_dm_plane_validate_dcc() to three. [HOW] Split them into a table-driven test for the checks that run before the DC capability query and a table-driven test for the rejections that come out of it, leaving the success and scan-mapping test unchanged. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 240 ++++++------------ 1 file changed, 72 insertions(+), 168 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index 331abfbd252d..ef48f71f22d0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -633,152 +633,95 @@ static void dm_test_helper_check_state_viewport_reject(struct kunit *test) } /** - * dm_test_validate_dcc_disabled_returns_success() - Verify disabled DCC is accepted. + * dm_test_validate_dcc_early_exits() - Verify the checks before the DC query. * @test: KUnit test context. * - * Verify if DCC validation succeeds when DCC is disabled. + * Verify if disabled DCC is accepted without consulting DC, and if a video + * format on a pre-GFX12 device and a missing capability callback are rejected. */ -static void dm_test_validate_dcc_disabled_returns_success(struct kunit *test) +static void dm_test_validate_dcc_early_exits(struct kunit *test) { - struct amdgpu_device *adev; - struct dc *dc; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct plane_size plane_size = {0}; - - dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, - &plane_size, test); - dcc.enable = 0; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, - ROTATION_ANGLE_0, &tiling_info, &dcc, - &address, &plane_size), - 0); -} - -/** - * dm_test_validate_dcc_video_non_gfx12_fails() - Verify video format restriction on pre-GFX12. - * @test: KUnit test context. - * - * Verify if video format DCC validation fails on non-GFX12 devices. - */ -static void dm_test_validate_dcc_video_non_gfx12_fails(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct plane_size plane_size = {0}; - - dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, - &plane_size, test); - adev->family = AMDGPU_FAMILY_NV; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, - ROTATION_ANGLE_0, &tiling_info, &dcc, - &address, &plane_size), - -EINVAL); -} - -/** - * dm_test_validate_dcc_missing_cap_func_fails() - Verify missing capability callback fails. - * @test: KUnit test context. - * - * Verify if validation fails when DCC capability callback is not provided. - */ -static void dm_test_validate_dcc_missing_cap_func_fails(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct plane_size plane_size = {0}; - - dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, - &plane_size, test); - dc->cap_funcs.get_dcc_compression_cap = NULL; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, - ROTATION_ANGLE_0, &tiling_info, &dcc, - &address, &plane_size), - -EINVAL); -} - -/** - * dm_test_validate_dcc_cap_callback_fails() - Verify callback failure path. - * @test: KUnit test context. - * - * Verify if validation fails when the DCC capability callback returns false. - */ -static void dm_test_validate_dcc_cap_callback_fails(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct plane_size plane_size = {0}; - enum surface_pixel_format format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888; - enum dc_rotation_angle rotation = ROTATION_ANGLE_0; - struct dm_test_dcc_cap_ctx ctx = { - .callback_ret = false, - .capable = true, + static const struct { + const char *name; + bool dcc_enable; + enum surface_pixel_format format; + int expected; + } cases[] = { + { "dcc disabled", false, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, 0 }, + { "video before gfx12", true, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, -EINVAL }, + { "no capability callback", true, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, -EINVAL }, }; - int ret; + unsigned int i; - dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, - &plane_size, test); - dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; - dm_test_dcc_ctx = &ctx; + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct amdgpu_device *adev; + struct dc *dc; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct plane_size plane_size = {0}; + int ret; - ret = amdgpu_dm_plane_validate_dcc(adev, format, rotation, &tiling_info, - &dcc, &address, &plane_size); - KUNIT_EXPECT_EQ(test, ret, -EINVAL); - KUNIT_EXPECT_TRUE(test, ctx.called); + dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, + &plane_size, test); + dcc.enable = cases[i].dcc_enable; - dm_test_dcc_ctx = NULL; + ret = amdgpu_dm_plane_validate_dcc(adev, cases[i].format, ROTATION_ANGLE_0, + &tiling_info, &dcc, &address, &plane_size); + KUNIT_EXPECT_EQ_MSG(test, ret, cases[i].expected, "%s", cases[i].name); + } } /** - * dm_test_validate_dcc_not_capable_fails() - Verify not-capable callback output. + * dm_test_validate_dcc_rejects_from_cap() - Verify rejections from the DC query. * @test: KUnit test context. * - * Verify if validation fails when the DCC capability callback reports that the - * surface is not DCC capable. + * Verify if a failing capability callback, a surface reported as not DCC + * capable, and an independent_64b_blks mismatch are all rejected. */ -static void dm_test_validate_dcc_not_capable_fails(struct kunit *test) +static void dm_test_validate_dcc_rejects_from_cap(struct kunit *test) { - struct amdgpu_device *adev; - struct dc *dc; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct plane_size plane_size = {0}; - enum surface_pixel_format format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888; - enum dc_rotation_angle rotation = ROTATION_ANGLE_0; - struct dm_test_dcc_cap_ctx ctx = { - .callback_ret = true, - .capable = false, + static const struct { + const char *name; + bool callback_ret; + bool capable; + bool output_independent_64b_blks; + u32 independent_64b_blks; + } cases[] = { + { "callback fails", false, true, false, 1 }, + { "not capable", true, false, false, 1 }, + { "independent 64B mismatch", true, true, true, 0 }, }; - int ret; + unsigned int i; - dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, - &plane_size, test); - dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; - dm_test_dcc_ctx = &ctx; + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct amdgpu_device *adev; + struct dc *dc; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct plane_size plane_size = {0}; + struct dm_test_dcc_cap_ctx ctx = { + .callback_ret = cases[i].callback_ret, + .capable = cases[i].capable, + .output_independent_64b_blks = cases[i].output_independent_64b_blks, + }; + int ret; - ret = amdgpu_dm_plane_validate_dcc(adev, format, rotation, &tiling_info, - &dcc, &address, &plane_size); - KUNIT_EXPECT_EQ(test, ret, -EINVAL); - KUNIT_EXPECT_TRUE(test, ctx.called); + dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, + &plane_size, test); + dcc.independent_64b_blks = cases[i].independent_64b_blks; + dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; + dm_test_dcc_ctx = &ctx; - dm_test_dcc_ctx = NULL; + ret = amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + ROTATION_ANGLE_0, &tiling_info, &dcc, + &address, &plane_size); + dm_test_dcc_ctx = NULL; + + KUNIT_EXPECT_EQ_MSG(test, ret, -EINVAL, "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, ctx.called, "%s", cases[i].name); + } } /** @@ -819,41 +762,6 @@ static void dm_test_validate_dcc_success_and_scan_mapping(struct kunit *test) dm_test_dcc_ctx = NULL; } -/** - * dm_test_validate_dcc_independent_64b_mismatch_fails() - Verify 64B compatibility check. - * @test: KUnit test context. - * - * Verify if validation fails when independent_64b_blks values do not match. - */ -static void dm_test_validate_dcc_independent_64b_mismatch_fails(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct plane_size plane_size = {0}; - struct dm_test_dcc_cap_ctx ctx = { - .callback_ret = true, - .capable = true, - .output_independent_64b_blks = true, - }; - - dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, - &plane_size, test); - dcc.independent_64b_blks = 0; - dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; - dm_test_dcc_ctx = &ctx; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, - ROTATION_ANGLE_0, &tiling_info, &dcc, - &address, &plane_size), - -EINVAL); - - dm_test_dcc_ctx = NULL; -} - /** * dm_test_add_modifier_appends_and_grows() - Verify append and capacity growth. * @test: KUnit test context. @@ -3868,13 +3776,9 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { /* amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier() */ KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier), /* amdgpu_dm_plane_validate_dcc() */ - KUNIT_CASE(dm_test_validate_dcc_disabled_returns_success), - KUNIT_CASE(dm_test_validate_dcc_video_non_gfx12_fails), - KUNIT_CASE(dm_test_validate_dcc_missing_cap_func_fails), - KUNIT_CASE(dm_test_validate_dcc_cap_callback_fails), - KUNIT_CASE(dm_test_validate_dcc_not_capable_fails), + KUNIT_CASE(dm_test_validate_dcc_early_exits), + KUNIT_CASE(dm_test_validate_dcc_rejects_from_cap), KUNIT_CASE(dm_test_validate_dcc_success_and_scan_mapping), - KUNIT_CASE(dm_test_validate_dcc_independent_64b_mismatch_fails), /* amdgpu_dm_plane_init() */ KUNIT_CASE(dm_test_plane_init_creates_optional_properties), KUNIT_CASE(dm_test_plane_init_creates_color_pipeline), From c1fbc2facc2210a40810ff0f51a594854b9f87da Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:41:47 -0600 Subject: [PATCH 049/103] drm/amd/display: Fold DCC block mode tests [WHAT] Reduce the five KUnit tests for the GFX9 DCC block modes of amdgpu_dm_plane_fill_gfx9_attrs_from_modifiers() to one, and the three for amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers() to one. [HOW] Drive both from a table of modifier bits and the expected HUBP independent block mode, allocating the device, DC and framebuffer once and resetting the tiling, DCC and address outputs per row. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 424 ++++-------------- 1 file changed, 91 insertions(+), 333 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index ef48f71f22d0..688419012ed5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -492,65 +492,6 @@ static void dm_test_format_mod_supported(struct kunit *test) listed_mod)); } -/** - * dm_test_fill_gfx12_plane_attributes_from_modifiers() - Verify GFX12 DCC mapping path. - * @test: KUnit test context. - * - * Verify if GFX12 modifier parsing enables DCC and sets expected DCC block mode. - */ -static void dm_test_fill_gfx12_plane_attributes_from_modifiers(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; - struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct dm_test_dcc_cap_ctx ctx = { - .callback_ret = true, - .capable = true, - .output_independent_64b_blks = false, - }; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, dc); - KUNIT_ASSERT_NOT_NULL(test, afb); - - adev->family = AMDGPU_FAMILY_GC_12_0_0; - adev->dm.dc = dc; - adev->gfx.config.gb_addr_config_fields.num_pipes = 2; - adev->gfx.config.gb_addr_config_fields.num_banks = 4; - adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 256; - adev->gfx.config.gb_addr_config_fields.num_se = 1; - adev->gfx.config.gb_addr_config_fields.max_compress_frags = 2; - adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 1; - dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; - dm_test_dcc_ctx = &ctx; - - afb->base.modifier = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX12_64K_2D) | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX12) | - AMD_FMT_MOD_SET(DCC, 1) | - AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, 1); - plane_size.surface_size.width = 1920; - plane_size.surface_size.height = 1080; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers( - adev, afb, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, - ROTATION_ANGLE_0, &plane_size, &tiling_info, &dcc, &address), - 0); - KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxAddr3); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, (int)hubp_ind_block_128b); - - dm_test_dcc_ctx = NULL; -} - /** * dm_test_fill_gfx9_plane_attributes_from_modifiers() - Verify basic GFX9 linear modifier path. * @test: KUnit test context. @@ -1502,24 +1443,36 @@ static void dm_test_fill_gfx9_plane_attributes_validate_fails(struct kunit *test } /** - * dm_test_fill_gfx9_plane_attributes_dcc_rbplus_64b_no_128bcl() - Verify block mode. + * dm_test_fill_gfx9_plane_attributes_dcc_ind_blk() - Verify DCC block modes. * @test: KUnit test context. * - * Verify if a GFX10-RBPLUS modifier with both 64B and 128B independent block - * bits selects the 64B-no-128BCL block mode. + * Verify if the independent 64B and 128B block bits of a GFX9 or GFX10-RBPLUS + * DCC modifier select the matching HUBP independent block mode. */ -static void dm_test_fill_gfx9_plane_attributes_dcc_rbplus_64b_no_128bcl(struct kunit *test) +static void dm_test_fill_gfx9_plane_attributes_dcc_ind_blk(struct kunit *test) { - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; + static const struct { + const char *name; + u64 tile_version; + bool independent_64b_blks; + bool independent_128b_blks; + int expected_ind_blk; + } cases[] = { + { "rbplus 64B no 128BCL", AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS, true, true, + hubp_ind_block_64b_no_128bcl }, + { "rbplus 128B", AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS, false, true, + hubp_ind_block_128b }, + { "rbplus unconstrained", AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS, false, false, + hubp_ind_block_unconstrained }, + { "gfx9 64B", AMD_FMT_MOD_TILE_VER_GFX9, true, false, hubp_ind_block_64b }, + { "gfx9 unconstrained", AMD_FMT_MOD_TILE_VER_GFX9, false, false, + hubp_ind_block_unconstrained }, + }; struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct dm_test_dcc_cap_ctx ctx = {0}; - u64 tile_version = AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS; - int ret; + struct amdgpu_device *adev; + struct amdgpu_framebuffer *afb; + struct dc *dc; + unsigned int i; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); @@ -1528,209 +1481,62 @@ static void dm_test_fill_gfx9_plane_attributes_dcc_rbplus_64b_no_128bcl(struct k KUNIT_ASSERT_NOT_NULL(test, dc); KUNIT_ASSERT_NOT_NULL(test, afb); - dm_test_setup_gfx9_dcc_device(adev, dc, &ctx, true); - afb->base.modifier = dm_test_gfx9_dcc_modifier(tile_version, true, true); plane_size.surface_size.width = 1920; plane_size.surface_size.height = 1080; - ret = dm_test_gfx9_attrs(adev, afb, &plane_size, &tiling_info, &dcc, - &address); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, - (int)hubp_ind_block_64b_no_128bcl); + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct dm_test_dcc_cap_ctx ctx = {0}; + int ret; - dm_test_dcc_ctx = NULL; + dm_test_setup_gfx9_dcc_device(adev, dc, &ctx, cases[i].independent_64b_blks); + afb->base.modifier = dm_test_gfx9_dcc_modifier(cases[i].tile_version, + cases[i].independent_64b_blks, + cases[i].independent_128b_blks); + + ret = dm_test_gfx9_attrs(adev, afb, &plane_size, &tiling_info, &dcc, + &address); + dm_test_dcc_ctx = NULL; + + KUNIT_EXPECT_EQ_MSG(test, ret, 0, "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, dcc.enable, "%s", cases[i].name); + KUNIT_EXPECT_EQ_MSG(test, (int)dcc.dcc_ind_blk, cases[i].expected_ind_blk, + "%s", cases[i].name); + } } /** - * dm_test_fill_gfx9_plane_attributes_dcc_rbplus_128b() - Verify 128B block mode. + * dm_test_fill_gfx12_plane_attributes_dcc_blocks() - Verify GFX12 DCC blocks. * @test: KUnit test context. * - * Verify if a GFX10-RBPLUS modifier with only the 128B independent block bit - * selects the 128B block mode. + * Verify if the max-compressed-block field of a GFX12 DCC modifier selects the + * matching HUBP independent block mode and independent 64B flag, and if the + * GFX addr3 tiling version is reported. */ -static void dm_test_fill_gfx9_plane_attributes_dcc_rbplus_128b(struct kunit *test) +static void dm_test_fill_gfx12_plane_attributes_dcc_blocks(struct kunit *test) { - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; - struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct dm_test_dcc_cap_ctx ctx = {0}; - u64 tile_version = AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS; - int ret; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, dc); - KUNIT_ASSERT_NOT_NULL(test, afb); - - dm_test_setup_gfx9_dcc_device(adev, dc, &ctx, false); - afb->base.modifier = dm_test_gfx9_dcc_modifier(tile_version, false, true); - plane_size.surface_size.width = 1920; - plane_size.surface_size.height = 1080; - - ret = dm_test_gfx9_attrs(adev, afb, &plane_size, &tiling_info, &dcc, - &address); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, (int)hubp_ind_block_128b); - - dm_test_dcc_ctx = NULL; -} - -/** - * dm_test_fill_gfx9_plane_attributes_dcc_rbplus_unconstrained() - Verify block mode. - * @test: KUnit test context. - * - * Verify if a GFX10-RBPLUS modifier without independent block bits selects the - * unconstrained block mode. - */ -static void dm_test_fill_gfx9_plane_attributes_dcc_rbplus_unconstrained(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; - struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct dm_test_dcc_cap_ctx ctx = {0}; - u64 tile_version = AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS; - int ret; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, dc); - KUNIT_ASSERT_NOT_NULL(test, afb); - - dm_test_setup_gfx9_dcc_device(adev, dc, &ctx, false); - afb->base.modifier = dm_test_gfx9_dcc_modifier(tile_version, false, false); - plane_size.surface_size.width = 1920; - plane_size.surface_size.height = 1080; - - ret = dm_test_gfx9_attrs(adev, afb, &plane_size, &tiling_info, &dcc, - &address); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, - (int)hubp_ind_block_unconstrained); - - dm_test_dcc_ctx = NULL; -} - -/** - * dm_test_fill_gfx9_plane_attributes_dcc_gfx9_64b() - Verify legacy 64B mode. - * @test: KUnit test context. - * - * Verify if a pre-RBPLUS GFX9 modifier with the 64B independent block bit - * selects the 64B block mode. - */ -static void dm_test_fill_gfx9_plane_attributes_dcc_gfx9_64b(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; - struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct dm_test_dcc_cap_ctx ctx = {0}; - int ret; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, dc); - KUNIT_ASSERT_NOT_NULL(test, afb); - - dm_test_setup_gfx9_dcc_device(adev, dc, &ctx, true); - afb->base.modifier = dm_test_gfx9_dcc_modifier(AMD_FMT_MOD_TILE_VER_GFX9, - true, false); - plane_size.surface_size.width = 1920; - plane_size.surface_size.height = 1080; - - ret = dm_test_gfx9_attrs(adev, afb, &plane_size, &tiling_info, &dcc, - &address); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, (int)hubp_ind_block_64b); - - dm_test_dcc_ctx = NULL; -} - -/** - * dm_test_fill_gfx9_plane_attributes_dcc_gfx9_unconstrained() - Verify legacy mode. - * @test: KUnit test context. - * - * Verify if a pre-RBPLUS GFX9 modifier without the 64B independent block bit - * selects the unconstrained block mode. - */ -static void dm_test_fill_gfx9_plane_attributes_dcc_gfx9_unconstrained(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; - struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct dm_test_dcc_cap_ctx ctx = {0}; - int ret; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, dc); - KUNIT_ASSERT_NOT_NULL(test, afb); - - dm_test_setup_gfx9_dcc_device(adev, dc, &ctx, false); - afb->base.modifier = dm_test_gfx9_dcc_modifier(AMD_FMT_MOD_TILE_VER_GFX9, - false, false); - plane_size.surface_size.width = 1920; - plane_size.surface_size.height = 1080; - - ret = dm_test_gfx9_attrs(adev, afb, &plane_size, &tiling_info, &dcc, - &address); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, - (int)hubp_ind_block_unconstrained); - - dm_test_dcc_ctx = NULL; -} - -/** - * dm_test_fill_gfx12_plane_attributes_block0() - Verify GFX12 64B max-compressed-block path. - * @test: KUnit test context. - * - * Verify if a zero max-compressed-block modifier selects the 64B independent - * block mode on GFX12. - */ -static void dm_test_fill_gfx12_plane_attributes_block0(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; - struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; + static const struct { + const char *name; + u64 max_compressed_block; + bool independent_64b_blks; + int expected_ind_blk; + } cases[] = { + { "64B", 0, true, hubp_ind_block_64b }, + { "128B", 1, false, hubp_ind_block_128b }, + { "unconstrained", 2, false, hubp_ind_block_unconstrained }, + }; struct dm_test_dcc_cap_ctx ctx = { .callback_ret = true, .capable = true, .output_independent_64b_blks = false, }; - int ret; + struct plane_size plane_size = {0}; + struct amdgpu_device *adev; + struct amdgpu_framebuffer *afb; + struct dc *dc; + unsigned int i; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); @@ -1742,78 +1548,36 @@ static void dm_test_fill_gfx12_plane_attributes_block0(struct kunit *test) adev->family = AMDGPU_FAMILY_GC_12_0_0; adev->dm.dc = dc; dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; - dm_test_dcc_ctx = &ctx; - - afb->base.modifier = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX12_64K_2D) | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX12) | - AMD_FMT_MOD_SET(DCC, 1) | - AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, 0); plane_size.surface_size.width = 1920; plane_size.surface_size.height = 1080; - ret = dm_test_gfx12_attrs(adev, afb, &plane_size, &tiling_info, &dcc, - &address); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_TRUE(test, dcc.independent_64b_blks); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, (int)hubp_ind_block_64b); + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + int ret; - dm_test_dcc_ctx = NULL; -} + afb->base.modifier = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX12_64K_2D) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX12) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, + cases[i].max_compressed_block); + dm_test_dcc_ctx = &ctx; -/** - * dm_test_fill_gfx12_plane_attributes_block_unconstrained() - Verify block path. - * @test: KUnit test context. - * - * Verify if a max-compressed-block value above one selects the unconstrained - * independent block mode on GFX12. - */ -static void dm_test_fill_gfx12_plane_attributes_block_unconstrained(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct amdgpu_framebuffer *afb; - struct plane_size plane_size = {0}; - struct dc_tiling_info tiling_info = {0}; - struct dc_plane_dcc_param dcc = {0}; - struct dc_plane_address address = {0}; - struct dm_test_dcc_cap_ctx ctx = { - .callback_ret = true, - .capable = true, - .output_independent_64b_blks = false, - }; - int ret; + ret = dm_test_gfx12_attrs(adev, afb, &plane_size, &tiling_info, &dcc, + &address); + dm_test_dcc_ctx = NULL; - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, dc); - KUNIT_ASSERT_NOT_NULL(test, afb); - - adev->family = AMDGPU_FAMILY_GC_12_0_0; - adev->dm.dc = dc; - dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; - dm_test_dcc_ctx = &ctx; - - afb->base.modifier = AMD_FMT_MOD | - AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX12_64K_2D) | - AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX12) | - AMD_FMT_MOD_SET(DCC, 1) | - AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, 2); - plane_size.surface_size.width = 1920; - plane_size.surface_size.height = 1080; - - ret = dm_test_gfx12_attrs(adev, afb, &plane_size, &tiling_info, &dcc, - &address); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_TRUE(test, dcc.enable); - KUNIT_EXPECT_FALSE(test, dcc.independent_64b_blks); - KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, - (int)hubp_ind_block_unconstrained); - - dm_test_dcc_ctx = NULL; + KUNIT_EXPECT_EQ_MSG(test, ret, 0, "%s", cases[i].name); + KUNIT_EXPECT_EQ_MSG(test, (int)tiling_info.gfxversion, (int)DcGfxAddr3, + "%s", cases[i].name); + KUNIT_EXPECT_TRUE_MSG(test, dcc.enable, "%s", cases[i].name); + KUNIT_EXPECT_EQ_MSG(test, (bool)dcc.independent_64b_blks, + cases[i].independent_64b_blks, "%s", cases[i].name); + KUNIT_EXPECT_EQ_MSG(test, (int)dcc.dcc_ind_blk, cases[i].expected_ind_blk, + "%s", cases[i].name); + } } /** @@ -3704,19 +3468,13 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_format_mod_supported_d_swizzle_reject), KUNIT_CASE(dm_test_format_mod_supported_gfx6), /* amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers() */ - KUNIT_CASE(dm_test_fill_gfx12_plane_attributes_from_modifiers), - KUNIT_CASE(dm_test_fill_gfx12_plane_attributes_block0), - KUNIT_CASE(dm_test_fill_gfx12_plane_attributes_block_unconstrained), + KUNIT_CASE(dm_test_fill_gfx12_plane_attributes_dcc_blocks), KUNIT_CASE(dm_test_fill_gfx12_plane_attributes_validate_fails), /* amdgpu_dm_plane_fill_gfx9_attrs_from_modifiers() */ KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_from_modifiers), KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc), KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_validate_fails), - KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc_rbplus_64b_no_128bcl), - KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc_rbplus_128b), - KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc_rbplus_unconstrained), - KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc_gfx9_64b), - KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc_gfx9_unconstrained), + KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc_ind_blk), /* amdgpu_dm_plane_helper_check_state() */ KUNIT_CASE(dm_test_helper_check_state_viewport_reject), KUNIT_CASE(dm_test_helper_check_state_small_viewport_width), From e1581d81441dde429b7e5e2acef82dec178080d1 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:42:16 -0600 Subject: [PATCH 050/103] drm/amd/display: Fold plane scaling and cursor tests [WHAT] Reduce the two KUnit tests for amdgpu_dm_plane_get_min_max_dc_plane_scaling() to one, and the two for amdgpu_dm_plane_get_cursor_position() to one. [HOW] Populate the fp16 scaling caps alongside the NV12 and ARGB8888 ones and query all three formats from one device, and append the oversized cursor rejection to the existing clipping test. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 93 ++++--------------- 1 file changed, 17 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index 688419012ed5..3f78a6735790 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -352,7 +352,8 @@ static void dm_test_fill_dc_scaling_info(struct kunit *test) * dm_test_get_min_max_dc_plane_scaling() - Verify format-specific cap selection and 1->1000 conversion. * @test: KUnit test context. * - * Verify if min/max scaling values are correct for NV12 and XRGB8888 formats. + * Verify if min/max scaling values are correct for the NV12, XRGB8888 and fp16 + * caps. */ static void dm_test_get_min_max_dc_plane_scaling(struct kunit *test) { @@ -374,6 +375,8 @@ static void dm_test_get_min_max_dc_plane_scaling(struct kunit *test) dc->caps.planes[0].max_downscale_factor.nv12 = 1; dc->caps.planes[0].max_upscale_factor.argb8888 = 1600; dc->caps.planes[0].max_downscale_factor.argb8888 = 250; + dc->caps.planes[0].max_upscale_factor.fp16 = 2000; + dc->caps.planes[0].max_downscale_factor.fp16 = 500; fb->format = drm_format_info(DRM_FORMAT_NV12); KUNIT_ASSERT_NOT_NULL(test, fb->format); @@ -386,13 +389,20 @@ static void dm_test_get_min_max_dc_plane_scaling(struct kunit *test) amdgpu_dm_plane_get_min_max_dc_plane_scaling(&adev->ddev, fb, &min_downscale, &max_upscale); KUNIT_EXPECT_EQ(test, min_downscale, 250); KUNIT_EXPECT_EQ(test, max_upscale, 1600); + + fb->format = drm_format_info(DRM_FORMAT_ARGB16161616F); + KUNIT_ASSERT_NOT_NULL(test, fb->format); + amdgpu_dm_plane_get_min_max_dc_plane_scaling(&adev->ddev, fb, &min_downscale, &max_upscale); + KUNIT_EXPECT_EQ(test, min_downscale, 500); + KUNIT_EXPECT_EQ(test, max_upscale, 2000); } /** * dm_test_get_cursor_position() - Verify cursor clipping and off-screen handling. * @test: KUnit test context. * - * Verify if cursor clipping, hotspot adjustment, and off-screen disable behavior work. + * Verify if cursor clipping, hotspot adjustment, off-screen disable behavior + * and the oversized-cursor rejection work. */ static void dm_test_get_cursor_position(struct kunit *test) { @@ -443,6 +453,11 @@ static void dm_test_get_cursor_position(struct kunit *test) amdgpu_dm_plane_get_cursor_position(plane, &amdgpu_crtc->base, &position), 0); KUNIT_EXPECT_FALSE(test, position.enable); + + state->crtc_w = 128; + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_get_cursor_position(plane, &amdgpu_crtc->base, &position), + -EINVAL); } /** @@ -1718,39 +1733,6 @@ static void dm_test_fill_plane_buffer_attributes_gfx12(struct kunit *test) KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxAddr3); } -/** - * dm_test_get_min_max_dc_plane_scaling_fp16() - Verify fp16 cap selection. - * @test: KUnit test context. - * - * Verify if 64bpp fp16 formats use the fp16 scaling caps. - */ -static void dm_test_get_min_max_dc_plane_scaling_fp16(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc *dc; - struct drm_framebuffer *fb; - int min_downscale = 0; - int max_upscale = 0; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, dc); - KUNIT_ASSERT_NOT_NULL(test, fb); - - adev->dm.dc = dc; - dc->caps.planes[0].max_upscale_factor.fp16 = 2000; - dc->caps.planes[0].max_downscale_factor.fp16 = 500; - - fb->format = drm_format_info(DRM_FORMAT_ARGB16161616F); - KUNIT_ASSERT_NOT_NULL(test, fb->format); - amdgpu_dm_plane_get_min_max_dc_plane_scaling(&adev->ddev, fb, - &min_downscale, &max_upscale); - KUNIT_EXPECT_EQ(test, min_downscale, 500); - KUNIT_EXPECT_EQ(test, max_upscale, 2000); -} - /** * dm_test_helper_check_state_small_viewport_width() - Verify width rejection. * @test: KUnit test context. @@ -2024,45 +2006,6 @@ static void dm_test_fill_dc_scaling_info_plane_caps(struct kunit *test) 0); } -/** - * dm_test_get_cursor_position_bad_size() - Verify oversized cursor rejection. - * @test: KUnit test context. - * - * Verify if a cursor larger than the CRTC maximum is rejected. - */ -static void dm_test_get_cursor_position_bad_size(struct kunit *test) -{ - struct amdgpu_device *adev; - struct amdgpu_crtc *amdgpu_crtc; - struct drm_plane *plane; - struct drm_plane_state *state; - struct drm_framebuffer *fb; - struct dc_cursor_position position = {0}; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - amdgpu_crtc = kunit_kzalloc(test, sizeof(*amdgpu_crtc), GFP_KERNEL); - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, adev); - KUNIT_ASSERT_NOT_NULL(test, amdgpu_crtc); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, state); - KUNIT_ASSERT_NOT_NULL(test, fb); - - amdgpu_crtc->max_cursor_width = 64; - amdgpu_crtc->max_cursor_height = 64; - plane->dev = &adev->ddev; - plane->state = state; - state->fb = fb; - state->crtc_w = 128; - state->crtc_h = 32; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_get_cursor_position(plane, &amdgpu_crtc->base, &position), - -EINVAL); -} - /** * dm_test_format_mod_supported_d_swizzle_reject() - Verify D swizzle rejection. * @test: KUnit test context. @@ -3455,14 +3398,12 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_fill_dc_scaling_info_plane_caps), /* amdgpu_dm_plane_get_min_max_dc_plane_scaling() */ KUNIT_CASE(dm_test_get_min_max_dc_plane_scaling), - KUNIT_CASE(dm_test_get_min_max_dc_plane_scaling_fp16), /* amdgpu_dm_plane_fill_plane_buffer_attributes() */ KUNIT_CASE(dm_test_fill_plane_buffer_attributes_video), KUNIT_CASE(dm_test_fill_plane_buffer_attributes_gfx12), KUNIT_CASE(dm_test_fill_plane_buffer_attributes_gfx6), /* amdgpu_dm_plane_get_cursor_position() */ KUNIT_CASE(dm_test_get_cursor_position), - KUNIT_CASE(dm_test_get_cursor_position_bad_size), /* amdgpu_dm_plane_format_mod_supported() */ KUNIT_CASE(dm_test_format_mod_supported), KUNIT_CASE(dm_test_format_mod_supported_d_swizzle_reject), From ae2e917936ebfd3e087c8510c3eef489fd552325 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 01:42:44 -0600 Subject: [PATCH 051/103] drm/amd/display: Fold plane state check tests [WHAT] Reduce the four viewport KUnit tests for amdgpu_dm_plane_helper_check_state() to one, and the three rejection tests for amdgpu_dm_plane_atomic_check() to one. [HOW] Drive the viewport cases from a table of CRTC rectangles and display sizes, and rebuild the atomic state between the helper-check, color pipeline conflict and scaling-info sub-cases of the atomic check test. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 256 ++++-------------- 1 file changed, 59 insertions(+), 197 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index 3f78a6735790..776272cd93ae 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -550,42 +550,63 @@ static void dm_test_fill_gfx9_plane_attributes_from_modifiers(struct kunit *test } /** - * dm_test_helper_check_state_viewport_reject() - Verify viewport outside screen rejects state. + * dm_test_helper_check_state_viewport_rejects() - Verify viewport rejections. * @test: KUnit test context. * - * Verify if plane state is rejected when the viewport is outside display bounds. + * Verify if a viewport outside the display bounds, or one clipped by an edge + * to below the minimum pipe-split width or height, is rejected. */ -static void dm_test_helper_check_state_viewport_reject(struct kunit *test) +static void dm_test_helper_check_state_viewport_rejects(struct kunit *test) { - struct drm_plane *plane; - struct drm_plane_state *state; - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state; - struct drm_framebuffer *fb; + static const struct { + const char *name; + int crtc_x; + int crtc_y; + int crtc_w; + int crtc_h; + int hdisplay; + int vdisplay; + } cases[] = { + { "outside the display", 200, 0, 100, 100, 100, 100 }, + { "width below minimum", 0, 0, 10, 100, 1920, 1080 }, + { "top-clipped height", -2, -95, 100, 100, 1920, 1080 }, + { "bottom-clipped height", 0, 95, 100, 100, 1920, 100 }, + }; + unsigned int i; - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - new_crtc_state = kunit_kzalloc(test, sizeof(*new_crtc_state), GFP_KERNEL); - fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, state); - KUNIT_ASSERT_NOT_NULL(test, crtc); - KUNIT_ASSERT_NOT_NULL(test, new_crtc_state); - KUNIT_ASSERT_NOT_NULL(test, fb); + for (i = 0; i < ARRAY_SIZE(cases); i++) { + struct drm_plane *plane; + struct drm_plane_state *state; + struct drm_crtc *crtc; + struct drm_crtc_state *new_crtc_state; + struct drm_framebuffer *fb; + int ret; - plane->type = DRM_PLANE_TYPE_OVERLAY; - state->plane = plane; - state->fb = fb; - state->crtc = crtc; - state->crtc_x = 200; - state->crtc_y = 0; - state->crtc_w = 100; - state->crtc_h = 100; - new_crtc_state->mode.crtc_hdisplay = 100; - new_crtc_state->mode.crtc_vdisplay = 100; + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); + new_crtc_state = kunit_kzalloc(test, sizeof(*new_crtc_state), GFP_KERNEL); + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, new_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, fb); - KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_helper_check_state(state, new_crtc_state), -EINVAL); + plane->type = DRM_PLANE_TYPE_OVERLAY; + state->plane = plane; + state->fb = fb; + state->crtc = crtc; + state->crtc_x = cases[i].crtc_x; + state->crtc_y = cases[i].crtc_y; + state->crtc_w = cases[i].crtc_w; + state->crtc_h = cases[i].crtc_h; + new_crtc_state->mode.crtc_hdisplay = cases[i].hdisplay; + new_crtc_state->mode.crtc_vdisplay = cases[i].vdisplay; + + ret = amdgpu_dm_plane_helper_check_state(state, new_crtc_state); + KUNIT_EXPECT_EQ_MSG(test, ret, -EINVAL, "%s", cases[i].name); + } } /** @@ -1733,130 +1754,6 @@ static void dm_test_fill_plane_buffer_attributes_gfx12(struct kunit *test) KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxAddr3); } -/** - * dm_test_helper_check_state_small_viewport_width() - Verify width rejection. - * @test: KUnit test context. - * - * Verify if a viewport width below the minimum pipe-split width is rejected. - */ -static void dm_test_helper_check_state_small_viewport_width(struct kunit *test) -{ - struct drm_plane *plane; - struct drm_plane_state *state; - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state; - struct drm_framebuffer *fb; - - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - new_crtc_state = kunit_kzalloc(test, sizeof(*new_crtc_state), GFP_KERNEL); - fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, state); - KUNIT_ASSERT_NOT_NULL(test, crtc); - KUNIT_ASSERT_NOT_NULL(test, new_crtc_state); - KUNIT_ASSERT_NOT_NULL(test, fb); - - plane->type = DRM_PLANE_TYPE_OVERLAY; - state->plane = plane; - state->fb = fb; - state->crtc = crtc; - state->crtc_x = 0; - state->crtc_y = 0; - state->crtc_w = 10; - state->crtc_h = 100; - new_crtc_state->mode.crtc_hdisplay = 1920; - new_crtc_state->mode.crtc_vdisplay = 1080; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_helper_check_state(state, new_crtc_state), - -EINVAL); -} - -/** - * dm_test_helper_check_state_small_viewport_height() - Verify height rejection. - * @test: KUnit test context. - * - * Verify if a negative-offset viewport with a too-small height is rejected. - */ -static void dm_test_helper_check_state_small_viewport_height(struct kunit *test) -{ - struct drm_plane *plane; - struct drm_plane_state *state; - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state; - struct drm_framebuffer *fb; - - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - new_crtc_state = kunit_kzalloc(test, sizeof(*new_crtc_state), GFP_KERNEL); - fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, state); - KUNIT_ASSERT_NOT_NULL(test, crtc); - KUNIT_ASSERT_NOT_NULL(test, new_crtc_state); - KUNIT_ASSERT_NOT_NULL(test, fb); - - plane->type = DRM_PLANE_TYPE_OVERLAY; - state->plane = plane; - state->fb = fb; - state->crtc = crtc; - state->crtc_x = -2; - state->crtc_y = -95; - state->crtc_w = 100; - state->crtc_h = 100; - new_crtc_state->mode.crtc_hdisplay = 1920; - new_crtc_state->mode.crtc_vdisplay = 1080; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_helper_check_state(state, new_crtc_state), - -EINVAL); -} - -/** - * dm_test_helper_check_state_bottom_clipped_height() - Verify bottom clipping. - * @test: KUnit test context. - * - * Verify if a viewport clipped by the bottom edge to below the minimum height - * is rejected. - */ -static void dm_test_helper_check_state_bottom_clipped_height(struct kunit *test) -{ - struct drm_plane *plane; - struct drm_plane_state *state; - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state; - struct drm_framebuffer *fb; - - plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); - state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - new_crtc_state = kunit_kzalloc(test, sizeof(*new_crtc_state), GFP_KERNEL); - fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, plane); - KUNIT_ASSERT_NOT_NULL(test, state); - KUNIT_ASSERT_NOT_NULL(test, crtc); - KUNIT_ASSERT_NOT_NULL(test, new_crtc_state); - KUNIT_ASSERT_NOT_NULL(test, fb); - - plane->type = DRM_PLANE_TYPE_OVERLAY; - state->plane = plane; - state->fb = fb; - state->crtc = crtc; - state->crtc_x = 0; - state->crtc_y = 95; - state->crtc_w = 100; - state->crtc_h = 100; - new_crtc_state->mode.crtc_hdisplay = 1920; - new_crtc_state->mode.crtc_vdisplay = 100; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_plane_helper_check_state(state, new_crtc_state), - -EINVAL); -} - /** * dm_test_helper_check_state_scaling_caps() - Verify DC scaling caps are applied. * @test: KUnit test context. @@ -2274,43 +2171,29 @@ static void dm_test_atomic_check_missing_crtc_state(struct kunit *test) } /** - * dm_test_atomic_check_helper_failure() - Verify helper-check failures return. + * dm_test_atomic_check_rejects() - Verify the checks before DC validation. * @test: KUnit test context. * * Verify if atomic_check returns before DC validation when the DRM helper state - * validation rejects the plane. + * validation rejects the plane, when both the plane COLOR_PIPELINE and the CRTC + * DEGAMMA_LUT are in use, and when filling the scaling info fails. */ -static void dm_test_atomic_check_helper_failure(struct kunit *test) +static void dm_test_atomic_check_rejects(struct kunit *test) { struct drm_atomic_commit *state; struct drm_plane *plane; struct dm_plane_state *dm_plane_state; struct drm_crtc_state *new_crtc_state; struct drm_framebuffer *fb; + struct amdgpu_device *adev; + void *color_pipeline; + void *degamma_lut; dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state, &new_crtc_state, &fb); dm_plane_state->base.crtc_w = 10; KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), -EINVAL); -} - -/** - * dm_test_atomic_check_color_pipeline_conflict() - Verify color conflict rejection. - * @test: KUnit test context. - * - * Verify if atomic_check rejects use of both plane COLOR_PIPELINE and CRTC - * DEGAMMA_LUT before DC validation. - */ -static void dm_test_atomic_check_color_pipeline_conflict(struct kunit *test) -{ - struct drm_atomic_commit *state; - struct drm_plane *plane; - struct dm_plane_state *dm_plane_state; - struct drm_crtc_state *new_crtc_state; - struct drm_framebuffer *fb; - void *color_pipeline; - void *degamma_lut; dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state, &new_crtc_state, &fb); @@ -2323,22 +2206,6 @@ static void dm_test_atomic_check_color_pipeline_conflict(struct kunit *test) new_crtc_state->degamma_lut = degamma_lut; KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), -EINVAL); -} - -/** - * dm_test_atomic_check_scaling_failure() - Verify scaling-info failures return. - * @test: KUnit test context. - * - * Verify if atomic_check returns the scaling-info error before DC validation. - */ -static void dm_test_atomic_check_scaling_failure(struct kunit *test) -{ - struct amdgpu_device *adev; - struct drm_atomic_commit *state; - struct drm_plane *plane; - struct dm_plane_state *dm_plane_state; - struct drm_crtc_state *new_crtc_state; - struct drm_framebuffer *fb; adev = dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state, &new_crtc_state, &fb); @@ -3417,10 +3284,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_validate_fails), KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_dcc_ind_blk), /* amdgpu_dm_plane_helper_check_state() */ - KUNIT_CASE(dm_test_helper_check_state_viewport_reject), - KUNIT_CASE(dm_test_helper_check_state_small_viewport_width), - KUNIT_CASE(dm_test_helper_check_state_small_viewport_height), - KUNIT_CASE(dm_test_helper_check_state_bottom_clipped_height), + KUNIT_CASE(dm_test_helper_check_state_viewport_rejects), KUNIT_CASE(dm_test_helper_check_state_scaling_caps), /* amdgpu_dm_plane_helper_prepare_fb() */ KUNIT_CASE(dm_test_helper_prepare_fb_no_fb), @@ -3438,9 +3302,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { /* amdgpu_dm_plane_atomic_check() */ KUNIT_CASE(dm_test_atomic_check_no_dc_state), KUNIT_CASE(dm_test_atomic_check_missing_crtc_state), - KUNIT_CASE(dm_test_atomic_check_helper_failure), - KUNIT_CASE(dm_test_atomic_check_color_pipeline_conflict), - KUNIT_CASE(dm_test_atomic_check_scaling_failure), + KUNIT_CASE(dm_test_atomic_check_rejects), KUNIT_CASE(dm_test_atomic_check_success), /* amdgpu_dm_plane_panic_flush() */ KUNIT_CASE(dm_test_panic_flush_no_dc_state), From 06421edfe74b5897dfcc37c00c8e0c40310cdc4f Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Wed, 2 Sep 2026 12:15:10 +0200 Subject: [PATCH 052/103] drm/amd/display: Refactor DPP_PROGRAM_UPSP to drop pipe_ctx [Why] Hwss executors shouldn't be coupled to complex dc structs such as pipe_ctx. The DPP_PROGRAM_UPSP executor took a whole pipe_ctx only to reach two fields. [How] Change program_upsp_params to hold the dpp and the dscl_prog_data that dpp_program_upsp() actually needs, and extract them in the generic HWSS layer. Add hwss_add_dpp_program_upsp() so the build site uses a helper with the standard bounds check instead of assigning the step inline. Update the BLS specs. Reviewed-by: Alvin Lee Signed-off-by: Piotr Maziarz Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/core/dc_hw_sequencer.c | 35 ++++++++++--------- .../drm/amd/display/dc/hwss/hw_sequencer.h | 8 ++++- 2 files changed, 26 insertions(+), 17 deletions(-) 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 6ed22b2e9c74..b3270f5bb56e 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 @@ -1023,11 +1023,9 @@ void hwss_build_full_sequence(struct dc *dc, if (current_pipe->plane_res.hubp->funcs->hubp_program_mcache_id_and_split_coordinate) hwss_add_hubp_program_mcache_id(&seq_state, current_pipe->plane_res.hubp, ¤t_pipe->mcache_regs); - if (current_pipe->plane_res.dpp->funcs->dpp_program_upsp) { - block_sequence[*num_steps].params.program_upsp_params.pipe_ctx = current_pipe; - block_sequence[*num_steps].func = DPP_PROGRAM_UPSP; - (*num_steps)++; - } + if (current_pipe->plane_res.dpp->funcs->dpp_program_upsp) + hwss_add_dpp_program_upsp(&seq_state, current_pipe->plane_res.dpp, + ¤t_pipe->plane_res.scl_data.dscl_prog_data); } } current_pipe = current_pipe->bottom_pipe; @@ -3009,18 +3007,11 @@ void hwss_program_bias_and_scale(union block_sequence_params *params) void hwss_program_upsp(union block_sequence_params *params) { - struct pipe_ctx *pipe_ctx = params->program_upsp_params.pipe_ctx; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dscl_prog_data *dscl_prog_data = &pipe_ctx->plane_res.scl_data.dscl_prog_data; + struct dpp *dpp = params->program_upsp_params.dpp; + const struct dscl_prog_data *dscl_prog_data = params->program_upsp_params.dscl_prog_data; - if (!dpp || !dscl_prog_data) - return; - - if (dpp && dpp->funcs->dpp_program_upsp) { - // program upsampler - dpp->funcs->dpp_program_upsp(dpp, - dscl_prog_data); - } + if (dpp && dscl_prog_data && dpp->funcs->dpp_program_upsp) + dpp->funcs->dpp_program_upsp(dpp, dscl_prog_data); } void hwss_power_on_mpc_mem_pwr(union block_sequence_params *params) @@ -5737,6 +5728,18 @@ void hwss_add_dpp_set_scaler(struct block_sequence_state *seq_state, } } +void hwss_add_dpp_program_upsp(struct block_sequence_state *seq_state, + struct dpp *dpp, + const struct dscl_prog_data *dscl_prog_data) +{ + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + seq_state->steps[*seq_state->num_steps].func = DPP_PROGRAM_UPSP; + seq_state->steps[*seq_state->num_steps].params.program_upsp_params.dpp = dpp; + seq_state->steps[*seq_state->num_steps].params.program_upsp_params.dscl_prog_data = dscl_prog_data; + (*seq_state->num_steps)++; + } +} + void hwss_add_hubp_mem_program_viewport(struct block_sequence_state *seq_state, struct hubp *hubp, const struct rect *viewport, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index fc5935b1e8b7..7d4310c0ef3f 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -54,6 +54,7 @@ struct pg_block_update; struct drr_params; struct dc_underflow_debug_data; struct dsc_optc_config; +struct dscl_prog_data; struct vm_system_aperture_param; struct stream_encoder; struct hpo_dp_stream_encoder; @@ -171,7 +172,8 @@ struct set_output_transfer_func_params { const struct dc_stream_state *stream; }; struct program_upsp_params { - struct pipe_ctx *pipe_ctx; + struct dpp *dpp; + const struct dscl_prog_data *dscl_prog_data; }; struct update_visual_confirm_params { @@ -2628,6 +2630,10 @@ void hwss_add_dpp_set_scaler(struct block_sequence_state *seq_state, struct dpp *dpp, const struct scaler_data *scl_data); +void hwss_add_dpp_program_upsp(struct block_sequence_state *seq_state, + struct dpp *dpp, + const struct dscl_prog_data *dscl_prog_data); + void hwss_add_hubp_mem_program_viewport(struct block_sequence_state *seq_state, struct hubp *hubp, const struct rect *viewport, From 23c7a0a0ecd9a23aba3d61f65c8b4eacf5cd5908 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Thu, 3 Sep 2026 13:31:05 +0200 Subject: [PATCH 053/103] drm/amd/display: Remove phantom SW state ops from block sequence [Why] HWS_APPLY_UPDATE_FLAGS_FOR_PHANTOM and HWS_UPDATE_PHANTOM_VP_POSITION program no hardware. They only mutate driver state: pipe update flags, the phantom plane viewport and the phantom scaling params. A block sequence is built first and executed later, so both ops ran only after the builder had already inspected pipe_ctx->update_flags to decide which steps to emit. The phantom pipe was therefore built from stale flags. [How] Call apply_update_flags_for_phantom() and update_phantom_vp_position() directly from hwss_build_post_unlock_full_sequence(), before program_pipe_sequence(), matching the legacy dcn401_post_unlock_program_front_end() ordering. Reviewed-by: Alvin Lee Signed-off-by: Piotr Maziarz Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/core/dc_hw_sequencer.c | 46 ++----------------- .../drm/amd/display/dc/hwss/hw_sequencer.h | 20 -------- 2 files changed, 5 insertions(+), 61 deletions(-) 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 b3270f5bb56e..2c13f76d764b 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 @@ -1102,11 +1102,13 @@ void hwss_build_post_unlock_full_sequence(struct dc *dc, if (pipe->plane_state && !pipe->top_pipe) { while (pipe) { if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { - /* Apply update flags for phantom pipes using existing HWS functions */ + /* Phantom SW state must be updated before the pipe sequence is built, + * since the build reads the update flags and scaling params. + */ if (dc->hwss.apply_update_flags_for_phantom) - hwss_add_hws_apply_update_flags_for_phantom(&seq_state, pipe); + dc->hwss.apply_update_flags_for_phantom(pipe); if (dc->hwss.update_phantom_vp_position) - hwss_add_hws_update_phantom_vp_position(&seq_state, dc, context, pipe); + dc->hwss.update_phantom_vp_position(dc, context, pipe); /* Program the phantom pipe - use program_pipe_sequence if available */ if (dc->hwseq && dc->hwseq->funcs.program_pipe_sequence) @@ -1804,14 +1806,6 @@ void hwss_execute_sequence(struct dc *dc, params->hubp_wait_pipe_read_start_params.hubp->funcs->hubp_wait_pipe_read_start( params->hubp_wait_pipe_read_start_params.hubp); break; - case HWS_APPLY_UPDATE_FLAGS_FOR_PHANTOM: - dc->hwss.apply_update_flags_for_phantom(params->apply_update_flags_for_phantom_params.pipe_ctx); - break; - case HWS_UPDATE_PHANTOM_VP_POSITION: - dc->hwss.update_phantom_vp_position(params->update_phantom_vp_position_params.dc, - params->update_phantom_vp_position_params.context, - params->update_phantom_vp_position_params.pipe_ctx); - break; case OPTC_SET_ODM_COMBINE: hwss_set_odm_combine(params); break; @@ -2590,36 +2584,6 @@ void hwss_add_hubp_wait_pipe_read_start(struct block_sequence_state *seq_state, } } -/* - * Helper function to add HWS apply update flags for phantom to block sequence - */ -void hwss_add_hws_apply_update_flags_for_phantom(struct block_sequence_state *seq_state, - struct pipe_ctx *pipe_ctx) -{ - if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { - seq_state->steps[*seq_state->num_steps].params.apply_update_flags_for_phantom_params.pipe_ctx = pipe_ctx; - seq_state->steps[*seq_state->num_steps].func = HWS_APPLY_UPDATE_FLAGS_FOR_PHANTOM; - (*seq_state->num_steps)++; - } -} - -/* - * Helper function to add HWS update phantom VP position to block sequence - */ -void hwss_add_hws_update_phantom_vp_position(struct block_sequence_state *seq_state, - struct dc *dc, - struct dc_state *context, - struct pipe_ctx *pipe_ctx) -{ - if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { - seq_state->steps[*seq_state->num_steps].params.update_phantom_vp_position_params.dc = dc; - seq_state->steps[*seq_state->num_steps].params.update_phantom_vp_position_params.context = context; - seq_state->steps[*seq_state->num_steps].params.update_phantom_vp_position_params.pipe_ctx = pipe_ctx; - seq_state->steps[*seq_state->num_steps].func = HWS_UPDATE_PHANTOM_VP_POSITION; - (*seq_state->num_steps)++; - } -} - /* * Helper function to add OPTC set ODM combine to block sequence */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index 7d4310c0ef3f..cc1c54c46e25 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -249,16 +249,6 @@ struct hubp_wait_pipe_read_start_params { struct hubp *hubp; }; -struct apply_update_flags_for_phantom_params { - struct pipe_ctx *pipe_ctx; -}; - -struct update_phantom_vp_position_params { - struct dc *dc; - struct pipe_ctx *pipe_ctx; - struct dc_state *context; -}; - struct set_odm_combine_params { struct timing_generator *tg; int opp_inst[MAX_PIPES]; @@ -1098,8 +1088,6 @@ union block_sequence_params { struct control_cm_hist_params control_cm_hist_params; struct program_cursor_update_now_params program_cursor_update_now_params; struct hubp_wait_pipe_read_start_params hubp_wait_pipe_read_start_params; - struct apply_update_flags_for_phantom_params apply_update_flags_for_phantom_params; - struct update_phantom_vp_position_params update_phantom_vp_position_params; struct set_odm_combine_params set_odm_combine_params; struct set_odm_bypass_params set_odm_bypass_params; struct opp_pipe_clock_control_params opp_pipe_clock_control_params; @@ -1278,8 +1266,6 @@ enum block_sequence_func { DPP_PROGRAM_CM_HIST, PROGRAM_CURSOR_UPDATE_NOW, HUBP_WAIT_PIPE_READ_START, - HWS_APPLY_UPDATE_FLAGS_FOR_PHANTOM, - HWS_UPDATE_PHANTOM_VP_POSITION, OPTC_SET_ODM_COMBINE, OPTC_SET_ODM_BYPASS, OPP_PIPE_CLOCK_CONTROL, @@ -2248,12 +2234,6 @@ void hwss_add_lsdma_send_pio_copy(struct block_sequence_state *seq_state, void hwss_add_hubp_wait_pipe_read_start(struct block_sequence_state *seq_state, struct hubp *hubp); -void hwss_add_hws_apply_update_flags_for_phantom(struct block_sequence_state *seq_state, - struct pipe_ctx *pipe_ctx); - -void hwss_add_hws_update_phantom_vp_position(struct block_sequence_state *seq_state, - struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); - void hwss_add_optc_set_odm_combine(struct block_sequence_state *seq_state, struct timing_generator *tg, int opp_inst[MAX_PIPES], int opp_head_count, int odm_slice_width, int last_odm_slice_width); From 81b3e948d623f6a33e233f8f53dd7f6f22aeb474 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Thu, 3 Sep 2026 08:27:32 -0400 Subject: [PATCH 054/103] drm/amd/display: Add inst field to struct pg_cntl Add an inst member to struct pg_cntl and set it to 0 in pg_cntl35_create() and pg_cntl42_create(), since PG cntl is a singleton. No functional change; the field has no readers yet. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h | 1 + drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c | 1 + drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h index 227e3f8d7e5f..3e5140993935 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h @@ -34,6 +34,7 @@ struct pg_cntl { const struct pg_cntl_funcs *funcs; bool pg_pipe_res_enable[PG_HW_PIPE_RESOURCES_NUM_ELEMENT][MAX_PIPES]; bool pg_res_enable[PG_HW_RESOURCES_NUM_ELEMENT]; + unsigned int inst; }; struct pg_cntl_funcs { diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c index 1d0181534a67..6e5ea1bbca02 100644 --- a/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c @@ -553,6 +553,7 @@ struct pg_cntl *pg_cntl35_create( base = &pg_cntl_dcn->base; base->ctx = ctx; base->funcs = &pg_cntl35_funcs; + base->inst = 0; pg_cntl_dcn->regs = regs; pg_cntl_dcn->pg_cntl_shift = pg_cntl_shift; diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c index 79f1b79eacc2..e9125d2467fc 100644 --- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c @@ -630,6 +630,7 @@ struct pg_cntl *pg_cntl42_create( base = &pg_cntl_dcn->base; base->ctx = ctx; base->funcs = &pg_cntl42_funcs; + base->inst = 0; pg_cntl_dcn->regs = regs; pg_cntl_dcn->pg_cntl_shift = pg_cntl_shift; From 87c0087e8822779ee4445ba73f4be22ea889635c Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Tue, 8 Sep 2026 14:07:01 -0600 Subject: [PATCH 055/103] drm/amd/display: Fix amdgpu_dm's kernel-doc warnings [WHAT] Document the amdgpu_dm struct members and function parameters reported by kernel-doc. Convert non-kernel-doc prose comments to regular comments and clarify the HDMI FRL polling fields. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202609051521.dVjPj9Zw-lkp@intel.com/ Assisted-by: Copilot:GPT-5.6-Luna Reviewed-by: Jerry Zuo Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 ++++++- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 9 +++++++++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) 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 1d256dce0e4b..0143b42fa2bd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -593,6 +593,11 @@ struct amdgpu_display_manager { struct amdgpu_dm_backlight_caps backlight_caps[AMDGPU_DM_MAX_NUM_EDP]; struct mod_freesync *freesync_module; + /** + * @power_module: + * + * Power management module. + */ struct mod_power *power_module; struct hdcp_workqueue *hdcp_workqueue; @@ -734,7 +739,7 @@ struct amdgpu_display_manager { /** * @hdmi_frl_status_polling_wq: * - * workqueue for 200ms frl status polling + * Workqueue for HDMI FRL status polling. */ struct workqueue_struct *hdmi_frl_status_polling_wq; /** diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h index bc16ecc67329..6ba567df5f0a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h @@ -44,6 +44,8 @@ enum dmub_notification_type; * * This function should be called exactly once - during DM initialization. * + * @adev: AMDGPU device. + * * Returns: * 0 - success * non-zero - error @@ -55,6 +57,8 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev); * * This function should be called exactly once - during DM destruction. * + * @adev: AMDGPU device. + * */ void amdgpu_dm_irq_fini(struct amdgpu_device *adev); @@ -82,6 +86,7 @@ void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev, * by amdgpu_dm_irq_register_interrupt(). * * @adev: AMD DRM device. + * @irq_source: IRQ source to unregister. * @ih_index: irq handler index which was returned by * amdgpu_dm_irq_register_interrupt */ @@ -126,6 +131,8 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev); /** * amdgpu_dm_irq_suspend - disable ASIC interrupt during suspend. * + * @adev: AMDGPU device. + * */ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev); @@ -133,6 +140,8 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev); * amdgpu_dm_irq_resume_early - enable HPDRX ASIC interrupts during resume. * amdgpu_dm_irq_resume - enable ASIC interrupt during resume. * + * @adev: AMDGPU device. + * */ void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev); void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h index 4436d256a2ae..21fedc5f21bd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h @@ -37,7 +37,7 @@ #define DP_BRANCH_VENDOR_SPECIFIC_START 0x50C -/** +/* * Panamera MST Hub detection * Offset DPCD 050Eh == 0x5A indicates cascaded MST hub case * Check from beginning of branch device vendor specific field (050Ch) From a767ba25a84c7659d40ecb65868091624db8bc57 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Tue, 8 Sep 2026 17:22:23 -0400 Subject: [PATCH 056/103] drm/amd/display: Wait response should be based on fw_based_mclk_switch [Description] When sending the indicate P-Stat message to PMFW, the wait_resp flag should be set based on fw_based_mclk_switching in order to maintain the logic from previous product. Reviewed-by: Wenjing Liu Signed-off-by: Alvin Lee Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c index b0f7f27fd7a1..7f33180f5e75 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c @@ -1297,7 +1297,8 @@ static unsigned int dcn60_build_bandwidth_clocks_block_sequence_with_action( action->fams.enable || clk_mgr_base->clks.fw_based_mclk_switching; block_sequence[num_steps].params.indicate_pstate_status_params.wait_resp = - action->fams.enable; + action->fams.enable + || clk_mgr_base->clks.fw_based_mclk_switching; block_sequence[num_steps].params.indicate_pstate_status_params.alt_ch_enable = action->alt_ch.enable || clk_mgr_base->clks.alt_ch_pstate_switch; From 08d0e9af43a5a132302f91a4141f3b8ec4cc2993 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Wed, 9 Sep 2026 10:14:28 -0400 Subject: [PATCH 057/103] drm/amd/display: Re-enable P-State message to SMU [Description] Re-enable P-State message to SMU now that support has been added on SMU side Reviewed-by: Dillon Varone Signed-off-by: Alvin Lee Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h | 3 +- .../dc/clk_mgr/dcn60/dcn60_clk_mgr_smu_msg.c | 30 +++++++------------ 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h index 9b109959bd7f..234777bdd183 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h @@ -170,7 +170,8 @@ typedef struct { #define DALSMC_MSG_ReturnHardMinStatus 0x19 ///< Return hard min status #define DALSMC_MSG_GetDispclkFreq 0x1A ///< Get display clock frequency. Return in MHZ #define DALSMC_MSG_GetDppclkFreq 0x1B ///< Get DPP clock frequency. Return in MHZ -#define DALSMC_Message_Count 0x1C ///< Total number of VBIS and DAL messages +#define DALSMC_MSG_IndicatePstateStatus 0x1C ///< Set UCLK/FCLK related actions +#define DALSMC_Message_Count 0x1D ///< Total number of VBIS and DAL messages /** @}*/ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr_smu_msg.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr_smu_msg.c index f56a49151c4d..5c1c95160892 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr_smu_msg.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr_smu_msg.c @@ -398,29 +398,19 @@ void dcn60_smu_indicate_pstate_status(struct clk_mgr_internal *clk_mgr, bool allow_fclk, bool allow_uclk, bool wait_resp, bool drr_enable, bool alt_ch_enable) { - //TODO: Re-enable this function once PMFW has support for this message - // Temporary until message is implemented on PMFW side - (void)clk_mgr; - (void)allow_fclk; - (void)allow_uclk; - (void)wait_resp; - (void)drr_enable; - (void)alt_ch_enable; + DALSMC_IndicatePstateStatus_arg_t arg = {}; - //DALSMC_IndicatePstateStatus_arg_t arg = {}; + smu_print("SMU Indicate pstate status: allow_fclk=%d allow_uclk=%d wait_resp=%d drr_enable=%d alt_ch_enable=%d\n", + allow_fclk, allow_uclk, wait_resp, drr_enable, alt_ch_enable); - //smu_print("SMU Indicate pstate status: allow_fclk=%d allow_uclk=%d wait_resp=%d drr_enable=%d alt_ch_enable=%d\n", - // allow_fclk, allow_uclk, wait_resp, drr_enable, alt_ch_enable); + arg.AllowFclk = allow_fclk ? 1 : 0; + arg.AllowUclk = allow_uclk ? 1 : 0; + arg.WaitResp = wait_resp ? 1 : 0; + arg.DrrEnable = drr_enable ? 1 : 0; + arg.AltCh = alt_ch_enable ? 1 : 0; - //arg.AllowFclk = allow_fclk ? 1 : 0; - //arg.AllowUclk = allow_uclk ? 1 : 0; - //arg.WaitResp = wait_resp ? 1 : 0; - //arg.DrrEnable = drr_enable ? 1 : 0; - //arg.AltCh = alt_ch_enable ? 1 : 0; - - // DALSMC_MSG_IndicatePstateStatus not defined in latest dalsmc.h header. Comment out for now. - //dcn60_smu_send_msg_with_args(clk_mgr, - // DALSMC_MSG_IndicatePstateStatus, arg.Args, NULL, NULL); + dcn60_smu_send_msg_with_args(clk_mgr, + DALSMC_MSG_IndicatePstateStatus, arg.Args, NULL, NULL); } static bool dcn60_smu_transfer_table_smu_2_dram(struct clk_mgr_internal *clk_mgr, From 4075810c436421a82ab66411f44f66a8bd163d5b Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 3 Sep 2026 19:38:11 -0600 Subject: [PATCH 058/103] drm/amd/display: Test EDID helper paths [WHAT] Add KUnit tests for three EDID paths in amdgpu_dm_helpers.c the SDC panel PSR PHY power-down quirk in apply_edid_quirks(), the HDMI compliance-auto branch of dm_helpers_parse_edid_caps(), and the VBIOS fallback and corrupt-EDID paths of dm_helpers_read_local_edid(). [HOW] apply_edid_quirks() is driven twice with the SDC panel ids, once on a DisplayPort signal and once on eDP, showing the quirk is embedded-only. dm_helpers_parse_edid_caps() runs against an HDMI connector whose hdmi_comp_auto flag is set, so the FRL and FRL DSC debug options are forced on and the quirk is recorded in the panel patch. dm_helpers_read_local_edid() is given an embedded link with no DDC line, so it falls back to the EDID hardcoded in the VBIOS embedded panel info that the existing fake dc_bios supplies. A second test corrupts the base block checksum served by the fake AUX DDC, so the read fails, the real checksum is written back and EDID_BAD_CHECKSUM is reported. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c index 51c3995de76d..b433634e0390 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c @@ -176,6 +176,34 @@ static void dm_test_apply_edid_quirks_disable_colorimetry(struct kunit *test) KUNIT_EXPECT_TRUE(test, edid_caps.panel_patch.disable_colorimetry); } +/** + * dm_test_apply_edid_quirks_psr_phy_power_down - Test SDC PSR PHY power-down quirk + * @test: The KUnit test context + * + * The quirk is embedded-only, so an external signal leaves the debug option + * alone and an embedded one forces PHY power down/up level 2. + */ +static void dm_test_apply_edid_quirks_psr_phy_power_down(struct kunit *test) +{ + struct dc_edid_caps edid_caps = {0}; + struct dc_link *link = dm_test_quirk_link(test); + struct dc *dc = dm_kunit_alloc_dc_with_ctx(test); + struct edid *external = dm_test_edid_with_panel_id(test, + drm_edid_encode_panel_id('S', 'D', 'C', 0x4197)); + struct edid *embedded = dm_test_edid_with_panel_id(test, + drm_edid_encode_panel_id('S', 'D', 'C', 0x4203)); + + link->ctx = dc->ctx; + + link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; + apply_edid_quirks(link, external, &edid_caps); + KUNIT_EXPECT_FALSE(test, dc->debug.psr_phy_force_phy_power_down_up_level_2); + + link->connector_signal = SIGNAL_TYPE_EDP; + apply_edid_quirks(link, embedded, &edid_caps); + KUNIT_EXPECT_TRUE(test, dc->debug.psr_phy_force_phy_power_down_up_level_2); +} + /** * dm_test_apply_edid_quirks_skip_phy_ssc - Test DEL 0x4147 PHY SSC quirk * @test: The KUnit test context @@ -463,6 +491,40 @@ static void dm_test_parse_edid_caps_hdmi_frl_dsc(struct kunit *test) KUNIT_EXPECT_TRUE(test, edid_caps->frl_dsc_10bpc); } +/** + * dm_test_parse_edid_caps_hdmi_comp_auto - Test the HDMI compliance-auto branch + * @test: The KUnit test context + * + * A connector flagged for automated HDMI compliance forces the FRL and FRL DSC + * debug options on and records the quirk in the panel patch. + */ +static void dm_test_parse_edid_caps_hdmi_comp_auto(struct kunit *test) +{ + struct dc_link *link = dm_test_quirk_link(test); + struct amdgpu_dm_connector *aconnector = link->priv; + struct dc *dc = dm_kunit_alloc_dc_with_ctx(test); + struct dc_edid_caps *edid_caps; + struct dc_edid *dc_edid; + + dc_edid = kunit_kzalloc(test, sizeof(*dc_edid), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dc_edid); + edid_caps = kunit_kzalloc(test, sizeof(*edid_caps), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, edid_caps); + + link->dc = dc; + link->ctx = dc->ctx; + + dm_test_fill_base_edid(dc_edid, true); + + aconnector->base.display_info.is_hdmi = true; + aconnector->hdmi_comp_auto = true; + + KUNIT_EXPECT_EQ(test, dm_helpers_parse_edid_caps(link, dc_edid, edid_caps), EDID_OK); + KUNIT_EXPECT_TRUE(test, edid_caps->panel_patch.hdmi_comp_auto); + KUNIT_EXPECT_TRUE(test, dc->debug.force_frl_max); + KUNIT_EXPECT_TRUE(test, dc->debug.force_frl_dsc); +} + /* * Build a 2-block EDID: a valid base block plus a CTA-861 extension block * carrying one LPCM Short Audio Descriptor and, when @with_speaker is set, a @@ -4570,6 +4632,60 @@ static void dm_test_read_local_edid_i2c_no_response(struct kunit *test) KUNIT_EXPECT_EQ(test, dm_test_prepare_ddc_calls, 1U); } +/** + * dm_test_read_local_edid_vbios_embedded - Test the VBIOS hardcoded EDID path + * @test: The KUnit test context + * + * An embedded panel with no DDC line has no I2C adapter to read from, so the + * helper falls back to the EDID hardcoded in the VBIOS embedded panel info. + */ +static void dm_test_read_local_edid_vbios_embedded(struct kunit *test) +{ + struct dm_test_local_edid fixture = dm_test_setup_local_edid(test); + struct dm_test_vbios_edid *vbios; + + vbios = kunit_kzalloc(test, sizeof(*vbios), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, vbios); + + vbios->bios.funcs = &dm_test_vbios_edid_funcs; + vbios->result = BP_RESULT_OK; + /* the fixture already holds a valid base EDID */ + vbios->fake_edid = fixture.aux->edid; + vbios->fake_edid_size = EDID_LENGTH; + + fixture.ctx->dc_bios = &vbios->bios; + fixture.link->ctx = fixture.ctx; + fixture.link->aux_mode = false; + fixture.link->ddc_hw_inst = GPIO_DDC_LINE_UNKNOWN; + fixture.link->connector_signal = SIGNAL_TYPE_EDP; + + KUNIT_EXPECT_EQ(test, + dm_helpers_read_local_edid(fixture.ctx, fixture.link, fixture.sink), + EDID_OK); + KUNIT_EXPECT_EQ(test, fixture.sink->dc_edid.length, (uint32_t)EDID_LENGTH); + KUNIT_EXPECT_EQ(test, fixture.sink->edid_caps.manufacturer_id, 0xAC10); +} + +/** + * dm_test_read_local_edid_corrupt_checksum - Test the corrupt-EDID compliance path + * @test: The KUnit test context + * + * The sink serves an EDID with a bad checksum, so the DDC read fails and marks + * the connector's EDID corrupt. The helper writes the real checksum back over + * AUX, clears the corrupt flag and reports EDID_BAD_CHECKSUM. + */ +static void dm_test_read_local_edid_corrupt_checksum(struct kunit *test) +{ + struct dm_test_local_edid fixture = dm_test_setup_local_edid(test); + + fixture.aux->edid[EDID_LENGTH - 1] ^= 0xFF; + + KUNIT_EXPECT_EQ(test, + dm_helpers_read_local_edid(fixture.ctx, fixture.link, fixture.sink), + EDID_BAD_CHECKSUM); + KUNIT_EXPECT_FALSE(test, fixture.aconnector->base.edid_corrupt); +} + static struct kunit_case amdgpu_dm_helpers_test_cases[] = { /* edid_extract_panel_id */ KUNIT_CASE(dm_test_edid_extract_panel_id_basic), @@ -4579,6 +4695,7 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = { KUNIT_CASE(dm_test_apply_edid_quirks_disable_fams), KUNIT_CASE(dm_test_apply_edid_quirks_remove_sink_ext_caps), KUNIT_CASE(dm_test_apply_edid_quirks_disable_colorimetry), + KUNIT_CASE(dm_test_apply_edid_quirks_psr_phy_power_down), KUNIT_CASE(dm_test_apply_edid_quirks_skip_phy_ssc), KUNIT_CASE(dm_test_apply_edid_quirks_force_freesync_min), KUNIT_CASE(dm_test_apply_edid_quirks_unknown_noop), @@ -4591,6 +4708,7 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = { KUNIT_CASE(dm_test_parse_edid_caps_bad_checksum), KUNIT_CASE(dm_test_parse_edid_caps_hdmi_frl), KUNIT_CASE(dm_test_parse_edid_caps_hdmi_frl_dsc), + KUNIT_CASE(dm_test_parse_edid_caps_hdmi_comp_auto), KUNIT_CASE(dm_test_parse_edid_caps_cea_audio), KUNIT_CASE(dm_test_parse_edid_caps_cea_no_speaker), /* ACPI / VBIOS / local EDID readers */ @@ -4774,6 +4892,8 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = { KUNIT_CASE(dm_test_read_local_edid_aux_mode), KUNIT_CASE(dm_test_read_local_edid_test_request), KUNIT_CASE(dm_test_read_local_edid_i2c_no_response), + KUNIT_CASE(dm_test_read_local_edid_vbios_embedded), + KUNIT_CASE(dm_test_read_local_edid_corrupt_checksum), {} }; From e149c8a69758d1321f320aff0b2ba16bbc0c2d7b Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 3 Sep 2026 19:38:55 -0600 Subject: [PATCH 059/103] drm/amd/display: Test AUX transfer paths [WHAT] Add KUnit tests for the AUX paths of dm_helper_dmub_aux_transfer_sync(), dm_helpers_read_mccs_caps() and dm_helpers_mccs_vcp_set(). Only their early returns and the plain I2C branch were covered before. [HOW] dm_helper_dmub_aux_transfer_sync() is called with HPD connected so it forwards the payload to the DMUB transfer. dc->link_count is zero, so the async transfer is rejected and the engine-acquire error is reported. Both MCCS helpers pick their DDC adapter from link->aux_mode. Add a fake AUX channel that ACKs every I2C-over-AUX transaction and counts the sized writes, then route the shared MCCS fixture through it. The VCP set completes on the first write. The VCP request gets an empty reply, so every attempt is retried and the request finally fails. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c index b433634e0390..b38601c1da5a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c @@ -2488,6 +2488,39 @@ static void dm_test_dmub_aux_transfer_sync_hpd_discon(struct kunit *test) KUNIT_EXPECT_EQ(test, (int)result, (int)AUX_RET_ERROR_HPD_DISCON); } +/** + * dm_test_dmub_aux_transfer_sync_hpd_connected - Test the transfer is forwarded to DMUB + * @test: The KUnit test context + * + * With HPD connected the helper forwards the payload to + * amdgpu_dm_process_dmub_aux_transfer_sync(). dc->link_count is zero, so the + * async transfer is rejected and the engine-acquire error is reported. + */ +static void dm_test_dmub_aux_transfer_sync_hpd_connected(struct kunit *test) +{ + struct aux_payload payload = {0}; + enum aux_return_code_type result = AUX_RET_SUCCESS; + struct amdgpu_device *adev; + struct dc_context *ctx; + struct dc_link *link; + int ret; + + adev = dm_kunit_alloc_adev(test); + KUNIT_ASSERT_NOT_NULL(test, adev); + ctx = dm_kunit_alloc_dc_with_ctx(test)->ctx; + link = dm_kunit_alloc_link(test); + + ctx->driver_context = adev; + mutex_init(&adev->dm.dpia_aux_lock); + init_completion(&adev->dm.dmub_aux_transfer_done); + link->hpd_status = true; + + ret = dm_helper_dmub_aux_transfer_sync(ctx, link, &payload, &result); + + KUNIT_EXPECT_EQ(test, ret, -1); + KUNIT_EXPECT_EQ(test, (int)result, (int)AUX_RET_ERROR_ENGINE_ACQUIRE); +} + /* Tests for empty stub functions (must not crash) */ /** @@ -3075,6 +3108,56 @@ static void dm_test_read_mccs_caps_i2c_failure(struct kunit *test) KUNIT_EXPECT_EQ(test, fake->reads, 0U); } +/* Counts sized I2C-over-AUX writes; the bracketing bare-address ones have size 0. */ +static unsigned int dm_test_mccs_aux_writes; + +static ssize_t dm_test_mccs_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) +{ + if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE && msg->size) + dm_test_mccs_aux_writes++; + + msg->reply = DP_AUX_I2C_REPLY_ACK; + return msg->size; +} + +/* + * Route the fixture's link through an AUX DDC instead of the fake I2C adapter, + * so the MCCS helpers take their link->aux_mode branch. + */ +static void dm_test_mccs_use_aux(struct dm_test_mccs_fixture *fixture) +{ + struct drm_dp_aux *aux = &fixture->aconnector->dm_dp_aux.aux; + + aux->drm_dev = &fixture->adev->ddev; + aux->transfer = dm_test_mccs_aux_transfer; + drm_dp_aux_init(aux); + + fixture->aconnector->base.dev = &fixture->adev->ddev; + fixture->link->aux_mode = true; + dm_test_mccs_aux_writes = 0; +} + +/** + * dm_test_read_mccs_caps_aux_mode - Test the MCCS VCP request over I2C-over-AUX + * @test: The KUnit test context + * + * The AUX DDC ACKs both transactions but answers with an empty VCP reply, so + * every attempt is retried and the request finally fails. + */ +static void dm_test_read_mccs_caps_aux_mode(struct kunit *test) +{ + struct dm_test_mccs_fixture fixture = dm_test_alloc_mccs_fixture(test); + + dm_test_mccs_use_aux(&fixture); + fixture.link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A; + fixture.sink->edid_caps.freesync_vcp_code = 0xe3; + + dm_helpers_read_mccs_caps(fixture.ctx, fixture.link, fixture.sink); + + KUNIT_EXPECT_FALSE(test, fixture.sink->mccs_caps.freesync_supported); + KUNIT_EXPECT_EQ(test, dm_test_mccs_aux_writes, 5U); +} + /* Tests for dm_helpers_mccs_vcp_set() */ /** @@ -3188,6 +3271,23 @@ static void dm_test_mccs_vcp_set_i2c_failure(struct kunit *test) KUNIT_EXPECT_EQ(test, fake->reads, 0U); } +/** + * dm_test_mccs_vcp_set_aux_mode - Test the MCCS VCP set over I2C-over-AUX + * @test: The KUnit test context + */ +static void dm_test_mccs_vcp_set_aux_mode(struct kunit *test) +{ + struct dm_test_mccs_fixture fixture = dm_test_alloc_mccs_fixture(test); + + dm_test_mccs_use_aux(&fixture); + fixture.sink->mccs_caps.freesync_supported = true; + fixture.sink->edid_caps.freesync_vcp_code = 0xe3; + + dm_helpers_mccs_vcp_set(fixture.ctx, fixture.link, fixture.sink); + + KUNIT_EXPECT_EQ(test, dm_test_mccs_aux_writes, 1U); +} + /* Tests for dm_helpers_construct_old_payload() */ /** @@ -4809,6 +4909,7 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = { KUNIT_CASE(dm_test_submit_i2c_partial_transfer), /* dm_helper_dmub_aux_transfer_sync */ KUNIT_CASE(dm_test_dmub_aux_transfer_sync_hpd_discon), + KUNIT_CASE(dm_test_dmub_aux_transfer_sync_hpd_connected), /* Empty stub functions */ KUNIT_CASE(dm_test_dp_update_branch_info_no_crash), KUNIT_CASE(dm_test_mst_poll_pending_down_reply_no_crash), @@ -4854,12 +4955,14 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = { KUNIT_CASE(dm_test_read_mccs_caps_hdmi_vcp_request), KUNIT_CASE(dm_test_read_mccs_caps_legacy_pcon_vcp_request), KUNIT_CASE(dm_test_read_mccs_caps_i2c_failure), + KUNIT_CASE(dm_test_read_mccs_caps_aux_mode), /* dm_helpers_mccs_vcp_set */ KUNIT_CASE(dm_test_mccs_vcp_set_null_ctx), KUNIT_CASE(dm_test_mccs_vcp_set_not_supported), KUNIT_CASE(dm_test_mccs_vcp_set_null_link), KUNIT_CASE(dm_test_mccs_vcp_set_i2c_packet), KUNIT_CASE(dm_test_mccs_vcp_set_i2c_failure), + KUNIT_CASE(dm_test_mccs_vcp_set_aux_mode), /* dm_helpers_construct_old_payload */ KUNIT_CASE(dm_test_construct_old_payload_empty_list), KUNIT_CASE(dm_test_construct_old_payload_intervening), From 0a2e54900a25a820d88f6a3457c58bad5cb64c6d Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 3 Sep 2026 19:39:39 -0600 Subject: [PATCH 060/103] drm/amd/display: Test MST topology start [WHAT] Add a KUnit test to cover dm_helpers_dp_mst_start_top_mgr() its success path. [HOW] Mark the topology manager as already in MST mode, so drm_dp_mst_topology_mgr_set_mst() returns success without touching the AUX channel or queueing the link probe work, and the helper reports that MST was started. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c index b38601c1da5a..09eba15c2705 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c @@ -3535,6 +3535,30 @@ static void dm_test_mst_start_top_mgr_set_mst_fail(struct kunit *test) KUNIT_EXPECT_FALSE(test, dm_helpers_dp_mst_start_top_mgr(NULL, link, false)); } +/** + * dm_test_mst_start_top_mgr_already_started - Test MST start on an active manager + * @test: The KUnit test context + * + * With the topology manager already in MST mode, + * drm_dp_mst_topology_mgr_set_mst(true) is a no-op that returns success, so the + * helper logs the cached DPCD caps and returns true. + */ +static void dm_test_mst_start_top_mgr_already_started(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct dc_link *link; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + link = dm_kunit_alloc_link(test); + + mutex_init(&aconnector->mst_mgr.lock); + aconnector->mst_mgr.mst_state = true; + link->priv = aconnector; + + KUNIT_EXPECT_TRUE(test, dm_helpers_dp_mst_start_top_mgr(NULL, link, false)); +} + /** * dm_test_mst_stop_top_mgr_active - Test MST stop on an active topology manager * @test: The KUnit test context @@ -4881,6 +4905,7 @@ static struct kunit_case amdgpu_dm_helpers_test_cases[] = { KUNIT_CASE(dm_test_mst_stop_top_mgr_null_priv), KUNIT_CASE(dm_test_mst_start_top_mgr_boot), KUNIT_CASE(dm_test_mst_start_top_mgr_set_mst_fail), + KUNIT_CASE(dm_test_mst_start_top_mgr_already_started), KUNIT_CASE(dm_test_mst_stop_top_mgr_active), /* dm_helpers_dp_write_hblank_reduction */ KUNIT_CASE(dm_test_dp_write_hblank_reduction_false), From a6b2fb633ca51eaf542a6c11317466b5dde0ad79 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 3 Sep 2026 23:59:06 -0600 Subject: [PATCH 061/103] drm/amd/display: Test unassigned OTG CRTC lookup [WHAT] amdgpu_dm_get_crtc_by_otg_inst() had no test for an OTG instance of -1, so its WARN_ON guard and the fallback to the first CRTC were never executed. [HOW] Add dm_test_get_crtc_by_otg_inst_unassigned_otg(), which installs a CRTC as mode_info.crtcs[0] and asserts the lookup returns it rather than walking the CRTC list. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index dc7d94f75ff4..50e6482ebbf9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -1301,6 +1301,28 @@ static void dm_test_get_crtc_by_otg_inst_empty_list(struct kunit *test) KUNIT_EXPECT_NULL(test, amdgpu_dm_get_crtc_by_otg_inst(adev, 0)); } +/** + * dm_test_get_crtc_by_otg_inst_unassigned_otg - Test CRTC lookup for a disabled OTG + * @test: The KUnit test context + * + * An IRQ that names an OTG instance of -1 cannot be matched, so the lookup + * trips its WARN_ON and falls back to the first CRTC rather than walking the + * list. + */ +static void dm_test_get_crtc_by_otg_inst_unassigned_otg(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_crtc *acrtc; + + adev = dm_kunit_alloc_adev(test); + + acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + adev->mode_info.crtcs[0] = acrtc; + + KUNIT_EXPECT_PTR_EQ(test, amdgpu_dm_get_crtc_by_otg_inst(adev, -1), acrtc); +} + /* Tests for amdgpu_dm_set_irq_funcs() */ /** @@ -4865,6 +4887,7 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_get_crtc_by_otg_inst_returns_match), KUNIT_CASE(dm_test_get_crtc_by_otg_inst_returns_null), KUNIT_CASE(dm_test_get_crtc_by_otg_inst_empty_list), + KUNIT_CASE(dm_test_get_crtc_by_otg_inst_unassigned_otg), /* amdgpu_dm_set_irq_funcs */ KUNIT_CASE(dm_test_set_irq_funcs), /* amdgpu_dm_irq_suspend/resume_early/resume_late */ From dd6d670069a04064b7d10477a8d263699d8c3d07 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 3 Sep 2026 23:59:06 -0600 Subject: [PATCH 062/103] drm/amd/display: Test VRR pageflip completion [WHAT] dm_pflip_high_irq() only ever ran with VRR inactive, so the scanout position query and the front-porch path that queues the pageflip event on the vblank event list were never reached. [HOW] Add a fake timing generator reporting a scanout position past the start of the front porch, plus a fixture that puts a submitted flip on an active-VRR stream. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index 50e6482ebbf9..7c75d115c8f0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -14,6 +14,7 @@ #include "dc.h" #include "inc/core_types.h" +#include "inc/hw/timing_generator.h" #include "irq/irq_service.h" #include "amdgpu.h" #include "amdgpu_mode.h" @@ -214,6 +215,23 @@ static bool dm_test_allow_hpd_rx_irq_true(const struct dc_link *link) return true; } +/* Report a scanout position past the start of the front porch. */ +static void dm_test_tg_get_scanoutpos(struct timing_generator *tg, + uint32_t *v_blank_start, + uint32_t *v_blank_end, + uint32_t *h_position, + uint32_t *v_position) +{ + *v_blank_start = 100; + *v_blank_end = 110; + *h_position = 0; + *v_position = 200; +} + +static const struct timing_generator_funcs dm_test_tg_funcs = { + .get_scanoutpos = dm_test_tg_get_scanoutpos, +}; + static uint32_t dm_test_dmub_get_outbox0_wptr(struct dmub_srv *dmub) { @@ -3658,6 +3676,124 @@ static void dm_test_pflip_high_irq_completes_flip(struct kunit *test) KUNIT_EXPECT_EQ(test, acrtc->pflip_status, AMDGPU_FLIP_NONE); } +/* + * Build a CRTC with a submitted flip on an active-VRR stream whose scanout + * position comes from the given fake timing generator (NULL for a stream that + * is not on any pipe, so the position is unavailable). + */ +static struct amdgpu_crtc *dm_test_setup_vrr_pflip_crtc(struct kunit *test, + struct timing_generator *tg) +{ + struct dc_stream_state *stream; + struct amdgpu_device *adev; + struct amdgpu_crtc *acrtc; + struct dc_link *link; + struct dc *dc; + + adev = dm_kunit_alloc_adev(test); + KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0); + + dc = dm_kunit_alloc_dc_with_ctx(test); + dc->current_state = kunit_kzalloc(test, sizeof(*dc->current_state), + GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc->current_state); + adev->dm.dc = dc; + + link = dm_kunit_alloc_link(test); + stream = dm_kunit_alloc_stream(test, link); + stream->ctx = dc->ctx; + + if (tg) { + dc->current_state->res_ctx.pipe_ctx[0].stream = stream; + dc->current_state->res_ctx.pipe_ctx[0].stream_res.tg = tg; + } + + acrtc = dm_test_add_crtc(test, adev); + acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; + acrtc->dm_irq_params.stream = stream; + acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; + + return acrtc; +} + +/** + * dm_test_pflip_high_irq_vrr_no_scanoutpos - Test VRR flip with no scanout data + * @test: The KUnit test context + * + * When the stream is not on any pipe the scanout position is unavailable, so + * the handler cannot tell it is inside the front porch and completes the flip + * immediately. + */ +static void dm_test_pflip_high_irq_vrr_no_scanoutpos(struct kunit *test) +{ + struct drm_pending_vblank_event *event; + struct common_irq_params params = { 0 }; + struct amdgpu_device *adev; + struct amdgpu_crtc *acrtc; + + acrtc = dm_test_setup_vrr_pflip_crtc(test, NULL); + adev = drm_to_adev(acrtc->base.dev); + + /* drm_crtc_send_vblank_event() consumes (kfree()s) the event. */ + event = kzalloc_obj(*event, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + acrtc->event = event; + + /* Balance the handler's drm_crtc_vblank_put(). */ + adev->ddev.vblank[0].enabled = true; + KUNIT_ASSERT_EQ(test, drm_crtc_vblank_get(&acrtc->base), 0); + + params.adev = adev; + params.irq_src = (enum dc_irq_source)IRQ_TYPE_PFLIP; + + dm_pflip_high_irq(¶ms); + + KUNIT_EXPECT_NULL(test, acrtc->event); + KUNIT_EXPECT_EQ(test, acrtc->pflip_status, AMDGPU_FLIP_NONE); +} + +/** + * dm_test_pflip_high_irq_vrr_front_porch - Test VRR flip inside the front porch + * @test: The KUnit test context + * + * A VRR flip that completes while scanout is still in the front porch has no + * valid vblank count yet, so the event is queued on the device's vblank event + * list for the late vblank handler to send out instead. + */ +static void dm_test_pflip_high_irq_vrr_front_porch(struct kunit *test) +{ + struct drm_pending_vblank_event *event; + struct common_irq_params params = { 0 }; + struct timing_generator *tg; + struct amdgpu_device *adev; + struct amdgpu_crtc *acrtc; + + tg = kunit_kzalloc(test, sizeof(*tg), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg); + tg->funcs = &dm_test_tg_funcs; + + acrtc = dm_test_setup_vrr_pflip_crtc(test, tg); + adev = drm_to_adev(acrtc->base.dev); + + event = kzalloc_obj(*event, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + acrtc->event = event; + + params.adev = adev; + params.irq_src = (enum dc_irq_source)IRQ_TYPE_PFLIP; + + dm_pflip_high_irq(¶ms); + + KUNIT_EXPECT_NULL(test, acrtc->event); + KUNIT_EXPECT_EQ(test, acrtc->pflip_status, AMDGPU_FLIP_NONE); + KUNIT_ASSERT_PTR_EQ(test, adev->ddev.vblank_event_list.next, + &event->base.link); + + /* The event was queued rather than sent, so the test owns it. */ + list_del(&event->base.link); + kfree(event); +} + /** * dm_test_vupdate_high_irq_no_crtc - Test vupdate high IRQ with no CRTC * @test: The KUnit test context @@ -4981,6 +5117,8 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_pflip_high_irq_no_crtc), KUNIT_CASE(dm_test_pflip_high_irq_not_submitted), KUNIT_CASE(dm_test_pflip_high_irq_completes_flip), + KUNIT_CASE(dm_test_pflip_high_irq_vrr_no_scanoutpos), + KUNIT_CASE(dm_test_pflip_high_irq_vrr_front_porch), KUNIT_CASE(dm_test_vupdate_high_irq_no_crtc), KUNIT_CASE(dm_test_vupdate_high_irq_dcn_completes_flip), KUNIT_CASE(dm_test_vupdate_high_irq_dcn_no_active_planes), From 92cfd5eb14dc398701217c7223df3c5d4cca6103 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 00:00:59 -0600 Subject: [PATCH 063/103] drm/amd/display: Test HPD RX offload work branches [WHAT] dm_handle_hpd_rx_offload_work() was covered only for its automated-test and link-loss branches. The connection-type failure, the GPU-reset drop, the MST message-ready drain and the forced reconnect were never entered. [HOW] Add a fixture that builds a queued offload work item on a DisplayPort link and four tests: a failing connection-type probe, a device already in reset, a deferred UP_REQ_MSG_RDY drained through an AUX that fails every transfer, and an automated test whose timing changed, which forces the connector off and back on. The last one registers the DRM device so the hotplug uevent helpers find a sysfs minor on the primary node. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index 7c75d115c8f0..2f40022a705f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -6,11 +6,13 @@ */ #include +#include #include #include #include #include #include +#include #include "dc.h" #include "inc/core_types.h" @@ -115,6 +117,18 @@ static enum dc_status dm_test_dp_read_hpd_rx_irq_data_ok(struct dc_link *link, return DC_OK; } +static const struct dc_link_status *dm_test_get_link_status(const struct dc_link *link) +{ + return &link->link_status; +} + +/* Fail every AUX transaction so the MST ESI read loop bails out immediately. */ +static ssize_t dm_test_aux_transfer_fail(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + return -EIO; +} + /* * Allocate a refcounted dc_sink for tests without pulling in the DC-core * dc_sink_create()/dc_sink_release() symbols. Production code under test still @@ -511,6 +525,22 @@ static void dm_test_connector_cleanup(void *data) drm_connector_cleanup(data); } +static void dm_test_drm_dev_unregister(void *data) +{ + drm_dev_unregister(data); +} + +/* + * Registering the DRM device gives its primary minor a sysfs device, which the + * DRM hotplug uevent helpers dereference unconditionally. + */ +static void dm_test_register_drm_dev(struct kunit *test, struct amdgpu_device *adev) +{ + KUNIT_ASSERT_EQ(test, drm_dev_register(&adev->ddev, 0), 0); + KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_drm_dev_unregister, + &adev->ddev), 0); +} + /* Tests for amdgpu_dm_hpd_to_dal_irq_source() */ /** @@ -2412,6 +2442,155 @@ static void dm_test_hpd_rx_offload_work_no_connection(struct kunit *test) dm_handle_hpd_rx_offload_work(&offload_work->work); } +/* + * Build a queued hpd_rx_irq_offload_work for dm_handle_hpd_rx_offload_work(): + * an adev that is not in reset, an offload queue owning a connector with an + * HPD lock, and a DisplayPort dc/link pair that reports a present sink. + * Caller sets the link_srv stubs and the service-IRQ bits its branch needs. + * + * The work item is kzalloc'd because the worker frees it. + */ +static struct hpd_rx_irq_offload_work * +dm_test_setup_hpd_rx_offload_work(struct kunit *test, + struct link_service **link_srv_out) +{ + struct hpd_rx_irq_offload_work_queue *offload_wq; + struct hpd_rx_irq_offload_work *offload_work; + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + struct amdgpu_device *adev; + struct dc_context *ctx; + struct dc_link *link; + struct dc *dc; + + adev = dm_kunit_alloc_adev(test); + mutex_init(&adev->dm.dc_lock); + adev->reset_domain = kunit_kzalloc(test, sizeof(*adev->reset_domain), + GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->reset_domain); + + offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); + spin_lock_init(&offload_wq->offload_lock); + + aconn = dm_kunit_alloc_connector(test, adev, NULL); + mutex_init(&aconn->hpd_lock); + offload_wq->aconnector = aconn; + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link_srv->detect_connection_type = dm_test_detect_connection_single; + dc->link_srv = link_srv; + dc->ctx = ctx; + ctx->dc = dc; + link->dc = dc; + link->ctx = ctx; + link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; + aconn->dc_link = link; + + offload_work = kzalloc_obj(*offload_work, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work); + offload_work->offload_wq = offload_wq; + offload_work->adev = adev; + INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); + + *link_srv_out = link_srv; + + return offload_work; +} + +/** + * dm_test_hpd_rx_offload_work_detect_type_fails - Test detect failure logging + * @test: The KUnit test context + * + * When dc_link_detect_connection_type() fails the worker logs an error and + * carries on with the connection type left as none, so it still skips out + * before any DP IRQ handling. + */ +static void dm_test_hpd_rx_offload_work_detect_type_fails(struct kunit *test) +{ + struct hpd_rx_irq_offload_work *offload_work; + struct link_service *link_srv; + + dm_test_automated_test_count = 0; + + offload_work = dm_test_setup_hpd_rx_offload_work(test, &link_srv); + link_srv->detect_connection_type = dm_test_detect_connection_fail; + link_srv->dp_handle_automated_test = dm_test_dp_handle_automated_test; + offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST = 1; + + dm_handle_hpd_rx_offload_work(&offload_work->work); + + KUNIT_EXPECT_EQ(test, dm_test_automated_test_count, 0); +} + +/** + * dm_test_hpd_rx_offload_work_in_reset - Test the GPU-reset early exit + * @test: The KUnit test context + * + * A GPU reset owns the link, so a deferred HPD RX IRQ must be dropped before + * any DP IRQ handling runs. + */ +static void dm_test_hpd_rx_offload_work_in_reset(struct kunit *test) +{ + struct hpd_rx_irq_offload_work *offload_work; + struct link_service *link_srv; + + dm_test_automated_test_count = 0; + + offload_work = dm_test_setup_hpd_rx_offload_work(test, &link_srv); + link_srv->dp_handle_automated_test = dm_test_dp_handle_automated_test; + offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST = 1; + atomic_set(&offload_work->adev->reset_domain->in_gpu_reset, 1); + + dm_handle_hpd_rx_offload_work(&offload_work->work); + + KUNIT_EXPECT_EQ(test, dm_test_automated_test_count, 0); +} + +/** + * dm_test_hpd_rx_offload_work_msg_rdy - Test the MST message-ready branch + * @test: The KUnit test context + * + * A deferred UP_REQ_MSG_RDY drains the sideband messages and then re-opens the + * queue for the next MST message-ready event. The AUX transfers all fail, so + * the ESI read loop bails out on its first iteration. + */ +static void dm_test_hpd_rx_offload_work_msg_rdy(struct kunit *test) +{ + struct hpd_rx_irq_offload_work *offload_work; + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + struct dc_link *link; + + offload_work = dm_test_setup_hpd_rx_offload_work(test, &link_srv); + aconn = offload_work->offload_wq->aconnector; + link = aconn->dc_link; + + link_srv->get_status = dm_test_get_link_status; + link->link_status.dpcd_caps = &link->dpcd_caps; + + mutex_init(&aconn->handle_mst_msg_ready); + aconn->dm_dp_aux.aux.name = "dm_irq_test_msg_rdy_aux"; + aconn->dm_dp_aux.aux.transfer = dm_test_aux_transfer_fail; + drm_dp_aux_init(&aconn->dm_dp_aux.aux); + drm_dp_dpcd_set_probe(&aconn->dm_dp_aux.aux, false); + + offload_work->offload_wq->is_handling_mst_msg_rdy_event = true; + offload_work->data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY = 1; + + dm_handle_hpd_rx_offload_work(&offload_work->work); + + KUNIT_EXPECT_FALSE(test, offload_work->offload_wq->is_handling_mst_msg_rdy_event); +} + /** * dm_test_hpd_rx_offload_work_automated_test - Test AUTOMATED_TEST branch * @test: The KUnit test context @@ -2482,6 +2661,37 @@ static void dm_test_hpd_rx_offload_work_automated_test(struct kunit *test) KUNIT_EXPECT_EQ(test, dm_test_automated_test_count, 1); } +/** + * dm_test_hpd_rx_offload_work_timing_changed - Test the forced reconnect path + * @test: The KUnit test context + * + * An automated test that changed the timing must force the connector off and + * back on again through force_connector_state(), which sends a hotplug uevent + * and therefore needs a registered DRM device. + */ +static void dm_test_hpd_rx_offload_work_timing_changed(struct kunit *test) +{ + struct hpd_rx_irq_offload_work *offload_work; + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + + offload_work = dm_test_setup_hpd_rx_offload_work(test, &link_srv); + aconn = offload_work->offload_wq->aconnector; + dm_test_register_drm_dev(test, offload_work->adev); + + link_srv->dp_handle_automated_test = dm_test_dp_handle_automated_test; + aconn->timing_changed = true; + aconn->dc_link->aux_access_disabled = true; + offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST = 1; + + /* The forced off/on cycle must leave the connector back at its default. */ + aconn->base.force = DRM_FORCE_ON; + + dm_handle_hpd_rx_offload_work(&offload_work->work); + + KUNIT_EXPECT_EQ(test, aconn->base.force, DRM_FORCE_UNSPECIFIED); +} + /** * dm_test_hpd_rx_offload_work_link_loss - Test link-loss branch * @test: The KUnit test context @@ -5079,7 +5289,11 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { /* dm_handle_hpd_rx_offload_work */ KUNIT_CASE(dm_test_hpd_rx_offload_work_no_connector), KUNIT_CASE(dm_test_hpd_rx_offload_work_no_connection), + KUNIT_CASE(dm_test_hpd_rx_offload_work_detect_type_fails), + KUNIT_CASE(dm_test_hpd_rx_offload_work_in_reset), + KUNIT_CASE(dm_test_hpd_rx_offload_work_msg_rdy), KUNIT_CASE(dm_test_hpd_rx_offload_work_automated_test), + KUNIT_CASE(dm_test_hpd_rx_offload_work_timing_changed), KUNIT_CASE(dm_test_hpd_rx_offload_work_link_loss), /* amdgpu_dm_hdmi_hpd_debounce_work */ KUNIT_CASE(dm_test_hdmi_hpd_debounce_detect_false), From ed32f69ac516f0f1ce0a01e5dd7608dbb1b85da8 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 00:00:59 -0600 Subject: [PATCH 064/103] drm/amd/display: Test HDMI HPD debounce re-detect [WHAT] amdgpu_dm_hdmi_hpd_debounce_work() only ran with detection failing, so neither outcome of the sink comparison that decides whether an HPD toggle was spurious was covered. [HOW] Add a fixture for the debounce work item and two tests: a re-detect finding the same sink, which re-enables internally without notifying userspace, and one finding a different sink, which sends the hotplug event. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index 2f40022a705f..dbbb7ed377b8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -61,6 +61,12 @@ static bool dm_test_detect_link_false(struct dc_link *link, return false; } +static bool dm_test_detect_link_true(struct dc_link *link, + enum dc_detect_reason reason) +{ + return true; +} + /* Spy on dc_link_detect() to prove the debounce early-return skipped it. */ static int dm_test_detect_link_count; @@ -2764,6 +2770,51 @@ static void dm_test_hpd_rx_offload_work_link_loss(struct kunit *test) /* Tests for amdgpu_dm_hdmi_hpd_debounce_work() */ +/* + * Build an aconnector wired for amdgpu_dm_hdmi_hpd_debounce_work(): an HPD + * lock, the debounce work item and a dc/link pair whose re-detect fails. + * Caller sets the link_srv stubs and any sinks the branch under test needs. + */ +static struct amdgpu_dm_connector *dm_test_setup_hdmi_debounce(struct kunit *test, + struct link_service **link_srv_out) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + struct amdgpu_device *adev; + struct dc_context *ctx; + struct dc_link *link; + struct dc *dc; + + adev = dm_kunit_alloc_adev(test); + mutex_init(&adev->dm.dc_lock); + + aconn = dm_kunit_alloc_connector(test, adev, NULL); + mutex_init(&aconn->hpd_lock); + INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work, + amdgpu_dm_hdmi_hpd_debounce_work); + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link_srv->detect_link = dm_test_detect_link_false; + dc->ctx = ctx; + dc->link_srv = link_srv; + ctx->dc = dc; + link->dc = dc; + link->ctx = ctx; + aconn->dc_link = link; + + *link_srv_out = link_srv; + + return aconn; +} + /** * dm_test_hdmi_hpd_debounce_detect_false - Test debounce false detect path * @test: The KUnit test context @@ -2874,6 +2925,67 @@ static void dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit *test) KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink); } +/** + * dm_test_hdmi_hpd_debounce_sink_unchanged - Test the spontaneous-toggle path + * @test: The KUnit test context + * + * A re-detect that finds the same sink as before the HPD toggle is an internal + * re-enable, so the connector state is refreshed but no hotplug event is sent + * to userspace. An MST-state connector keeps + * amdgpu_dm_update_connector_after_detect() to its early return. + */ +static void dm_test_hdmi_hpd_debounce_sink_unchanged(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + struct dc_link *link; + + aconn = dm_test_setup_hdmi_debounce(test, &link_srv); + link_srv->detect_link = dm_test_detect_link_true; + aconn->mst_mgr.mst_state = true; + link = aconn->dc_link; + + /* Two identically zeroed sinks compare equal, i.e. a spurious toggle. */ + link->local_sink = dm_test_sink_create(link); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link->local_sink); + aconn->hdmi_prev_sink = dm_test_sink_create(link); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn->hdmi_prev_sink); + + amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work); + + KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink); + + dm_test_sink_release(link->local_sink); +} + +/** + * dm_test_hdmi_hpd_debounce_sink_changed - Test the real-hotplug path + * @test: The KUnit test context + * + * A re-detect that finds a different sink than the one cached before the HPD + * toggle is a real hotplug, so userspace must be notified. Sending the uevent + * needs a registered DRM device. + */ +static void dm_test_hdmi_hpd_debounce_sink_changed(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + + aconn = dm_test_setup_hdmi_debounce(test, &link_srv); + dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev)); + + link_srv->detect_link = dm_test_detect_link_true; + aconn->mst_mgr.mst_state = true; + + /* The link lost its sink, so it cannot match the cached one. */ + aconn->hdmi_prev_sink = dm_test_sink_create(aconn->dc_link); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn->hdmi_prev_sink); + + amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work); + + KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink); +} + /* Tests for handle_hpd_irq()/handle_hpd_irq_helper() */ /** @@ -5298,6 +5410,8 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { /* amdgpu_dm_hdmi_hpd_debounce_work */ KUNIT_CASE(dm_test_hdmi_hpd_debounce_detect_false), KUNIT_CASE(dm_test_hdmi_hpd_debounce_reallow_idle), + KUNIT_CASE(dm_test_hdmi_hpd_debounce_sink_unchanged), + KUNIT_CASE(dm_test_hdmi_hpd_debounce_sink_changed), /* handle_hpd_irq/handle_hpd_irq_helper */ KUNIT_CASE(dm_test_handle_hpd_irq_disabled), KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_schedule), From eaf681630590c2fb609bb0a06993cdf6af28a758 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 00:00:59 -0600 Subject: [PATCH 065/103] drm/amd/display: Test HPD handler HDCP and detect [WHAT] handle_hpd_irq_helper() never ran its HDCP reset, its forced connector branch or its successful re-detect branch. [HOW] Add a minimal HDCP work queue fixture and three tests: an HPD on a driver that carries an HDCP work queue, which must reset the display and flag the connector state; a connector forced on that reports no connection and is emulated instead of detected; and a successful re-detect that notifies userspace. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index dbbb7ed377b8..ae68aa34818a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -21,6 +21,7 @@ #include "amdgpu.h" #include "amdgpu_mode.h" #include "amdgpu_dm.h" +#include "amdgpu_dm_hdcp.h" #include "amdgpu_dm_irq.h" #include "amdgpu_dm_kunit_test_helpers.h" #include "dc_dmub_srv.h" @@ -547,6 +548,39 @@ static void dm_test_register_drm_dev(struct kunit *test, struct amdgpu_device *a &adev->ddev), 0); } +static void dm_test_hdcp_dummy_work(struct work_struct *work) +{ +} + +/* + * Allocate the minimal hdcp_workqueue that hdcp_reset_display() and + * hdcp_handle_cpirq() touch: the per-link mutex, the delayed works + * process_output() re-arms, and the CP IRQ work item. + */ +static struct hdcp_workqueue *dm_test_alloc_hdcp_workqueue(struct kunit *test) +{ + struct hdcp_workqueue *hdcp_work; + + hdcp_work = kunit_kzalloc(test, sizeof(*hdcp_work), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hdcp_work); + + mutex_init(&hdcp_work->mutex); + INIT_WORK(&hdcp_work->cpirq_work, dm_test_hdcp_dummy_work); + INIT_DELAYED_WORK(&hdcp_work->callback_dwork, dm_test_hdcp_dummy_work); + INIT_DELAYED_WORK(&hdcp_work->watchdog_timer_dwork, dm_test_hdcp_dummy_work); + INIT_DELAYED_WORK(&hdcp_work->property_validate_dwork, dm_test_hdcp_dummy_work); + + return hdcp_work; +} + +static void dm_test_flush_hdcp_workqueue(struct hdcp_workqueue *hdcp_work) +{ + flush_work(&hdcp_work->cpirq_work); + cancel_delayed_work_sync(&hdcp_work->callback_dwork); + cancel_delayed_work_sync(&hdcp_work->watchdog_timer_dwork); + cancel_delayed_work_sync(&hdcp_work->property_validate_dwork); +} + /* Tests for amdgpu_dm_hpd_to_dal_irq_source() */ /** @@ -3206,6 +3240,88 @@ static void dm_test_handle_hpd_irq_helper_detect_type_fails(struct kunit *test) KUNIT_EXPECT_FALSE(test, aconn->fake_enable); } +/** + * dm_test_handle_hpd_irq_helper_hdcp_reset - Test the HDCP reset branch + * @test: The KUnit test context + * + * An HPD invalidates the link's HDCP authentication, so a driver carrying an + * HDCP work queue must reset the display and flag the connector state for a + * property update. + */ +static void dm_test_handle_hpd_irq_helper_hdcp_reset(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct hdcp_workqueue *hdcp_work; + struct link_service *link_srv; + + aconn = dm_test_setup_hpd_irq_helper(test, &link_srv); + link_srv->detect_link = dm_test_detect_link_false; + + hdcp_work = dm_test_alloc_hdcp_workqueue(test); + drm_to_adev(aconn->base.dev)->dm.hdcp_workqueue = hdcp_work; + + handle_hpd_irq_helper(aconn, DETECT_REASON_HPD); + + KUNIT_EXPECT_TRUE(test, to_dm_connector_state(aconn->base.state)->update_hdcp); + + dm_test_flush_hdcp_workqueue(hdcp_work); +} + +/** + * dm_test_handle_hpd_irq_helper_forced_detect - Test the forced-connector branch + * @test: The KUnit test context + * + * A connector forced on but reporting no connection is emulated rather than + * detected, and an HPD RX always notifies userspace. An unset connector signal + * keeps amdgpu_dm_emulated_link_detect() to its unsupported-signal early + * return. + */ +static void dm_test_handle_hpd_irq_helper_forced_detect(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + + dm_test_detect_link_count = 0; + + aconn = dm_test_setup_hpd_irq_helper(test, &link_srv); + dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev)); + + link_srv->detect_link = dm_test_detect_link_false_count; + aconn->base.force = DRM_FORCE_ON; + aconn->dc_link->ctx->driver_context = drm_to_adev(aconn->base.dev); + + handle_hpd_irq_helper(aconn, DETECT_REASON_HPDRX); + + /* The emulated path replaces detection entirely. */ + KUNIT_EXPECT_EQ(test, dm_test_detect_link_count, 0); +} + +/** + * dm_test_handle_hpd_irq_helper_detect_true - Test the connected detect branch + * @test: The KUnit test context + * + * A successful re-detect refreshes the connector state and notifies userspace. + * An MST-state connector keeps amdgpu_dm_update_connector_after_detect() to its + * early return. + */ +static void dm_test_handle_hpd_irq_helper_detect_true(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + + aconn = dm_test_setup_hpd_irq_helper(test, &link_srv); + dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev)); + + link_srv->detect_connection_type = dm_test_detect_connection_single; + link_srv->detect_link = dm_test_detect_link_true; + aconn->mst_mgr.mst_state = true; + aconn->fake_enable = true; + + handle_hpd_irq_helper(aconn, DETECT_REASON_HPD); + + KUNIT_EXPECT_FALSE(test, aconn->fake_enable); +} + /** * dm_test_handle_hpd_irq_helper_debounce_pending - Test pending-debounce exit * @test: The KUnit test context @@ -5419,6 +5535,9 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_handle_hpd_irq_helper_detect_false), KUNIT_CASE(dm_test_handle_hpd_irq_helper_detect_type_fails), KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_pending), + KUNIT_CASE(dm_test_handle_hpd_irq_helper_hdcp_reset), + KUNIT_CASE(dm_test_handle_hpd_irq_helper_forced_detect), + KUNIT_CASE(dm_test_handle_hpd_irq_helper_detect_true), /* handle_hpd_rx_irq/schedule_hpd_rx_offload_work */ KUNIT_CASE(dm_test_handle_hpd_rx_irq_disabled), KUNIT_CASE(dm_test_handle_hpd_rx_irq_no_left_work), From 8cc240ffad03d19527c82a4f85990ce436f32a58 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 00:00:59 -0600 Subject: [PATCH 066/103] drm/amd/display: Test HPD RX downstream handling [WHAT] handle_hpd_rx_irq() left its whole post-detect block untested apart from a failing re-detect, and never dispatched a CP_IRQ. [HOW] Add four tests covering a failing connection-type probe, a connector forced on that is emulated instead of detected, a successful re-detect that notifies userspace, and a CP_IRQ that must be handed to the HDCP work queue for the connector that raised it. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index ae68aa34818a..eab04a44a9eb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -231,6 +231,19 @@ static bool dm_test_handle_hpd_rx_result_true(struct dc_link *link, return true; } +static bool dm_test_handle_hpd_rx_cp_irq(struct dc_link *link, + union hpd_irq_data *hpd_irq_data, + bool *link_loss, + bool defer_handling, + bool *has_left_work) +{ + *link_loss = false; + *has_left_work = false; + hpd_irq_data->bytes.device_service_irq.bits.CP_IRQ = 1; + + return false; +} + static bool dm_test_allow_hpd_rx_irq_true(const struct dc_link *link) { return true; @@ -3594,6 +3607,123 @@ static void dm_test_handle_hpd_rx_irq_downstream_change(struct kunit *test) KUNIT_EXPECT_TRUE(test, aconn->fake_enable); } +/** + * dm_test_handle_hpd_rx_irq_detect_type_fails - Test HPDRX detect failure logging + * @test: The KUnit test context + * + * A handled HPD RX IRQ on a connector that is not an MST root means a + * downstream port status change, so the handler must re-detect the link. The + * connection-type probe is stubbed to fail, so it logs an error and continues + * into the re-detect branch, and a non-MST-branch link also exercises the + * trailing CEC IRQ dispatch. + */ +static void dm_test_handle_hpd_rx_irq_detect_type_fails(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + + dm_test_detect_link_count = 0; + + aconn = dm_test_setup_hpd_rx_irq(test, &link_srv); + link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_result_true; + link_srv->detect_connection_type = dm_test_detect_connection_fail; + link_srv->detect_link = dm_test_detect_link_false_count; + + aconn->mst_mgr.mst_state = false; + aconn->dc_link->type = dc_connection_single; + + handle_hpd_rx_irq(aconn); + + KUNIT_EXPECT_EQ(test, dm_test_detect_link_count, 1); +} + +/** + * dm_test_handle_hpd_rx_irq_forced_detect - Test HPDRX forced-connector branch + * @test: The KUnit test context + * + * A connector forced on but reporting no connection is emulated rather than + * detected, and userspace is always notified. An unset connector signal keeps + * amdgpu_dm_emulated_link_detect() to its unsupported-signal early return, and + * a sink-less link keeps amdgpu_dm_update_connector_after_detect() to its + * unchanged-sink early return. + */ +static void dm_test_handle_hpd_rx_irq_forced_detect(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + + dm_test_detect_link_count = 0; + + aconn = dm_test_setup_hpd_rx_irq(test, &link_srv); + dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev)); + + link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_result_true; + link_srv->detect_connection_type = dm_test_detect_connection_none; + link_srv->detect_link = dm_test_detect_link_false_count; + + aconn->mst_mgr.mst_state = false; + aconn->base.force = DRM_FORCE_ON; + aconn->dc_link->ctx->driver_context = drm_to_adev(aconn->base.dev); + aconn->fake_enable = true; + + handle_hpd_rx_irq(aconn); + + KUNIT_EXPECT_FALSE(test, aconn->fake_enable); + KUNIT_EXPECT_EQ(test, dm_test_detect_link_count, 0); +} + +/** + * dm_test_handle_hpd_rx_irq_detect_true - Test HPDRX connected detect branch + * @test: The KUnit test context + * + * A downstream-port change that re-detects a display refreshes the connector + * and notifies userspace. A sink-less link keeps + * amdgpu_dm_update_connector_after_detect() to its unchanged-sink early return. + */ +static void dm_test_handle_hpd_rx_irq_detect_true(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct link_service *link_srv; + + aconn = dm_test_setup_hpd_rx_irq(test, &link_srv); + dm_test_register_drm_dev(test, drm_to_adev(aconn->base.dev)); + + link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_result_true; + link_srv->detect_connection_type = dm_test_detect_connection_single; + link_srv->detect_link = dm_test_detect_link_true; + + aconn->mst_mgr.mst_state = false; + aconn->fake_enable = true; + + handle_hpd_rx_irq(aconn); + + KUNIT_EXPECT_FALSE(test, aconn->fake_enable); +} + +/** + * dm_test_handle_hpd_rx_irq_cp_irq - Test HPDRX content-protection dispatch + * @test: The KUnit test context + * + * A CP_IRQ in the device service field must be handed to the HDCP work queue + * for the connector that raised it. + */ +static void dm_test_handle_hpd_rx_irq_cp_irq(struct kunit *test) +{ + struct amdgpu_dm_connector *aconn; + struct hdcp_workqueue *hdcp_work; + struct link_service *link_srv; + + aconn = dm_test_setup_hpd_rx_irq(test, &link_srv); + link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_cp_irq; + + hdcp_work = dm_test_alloc_hdcp_workqueue(test); + drm_to_adev(aconn->base.dev)->dm.hdcp_workqueue = hdcp_work; + + handle_hpd_rx_irq(aconn); + + dm_test_flush_hdcp_workqueue(hdcp_work); +} + /* Tests for dmub_hpd_callback()/dmub_hpd_sense_callback() */ /** @@ -5545,6 +5675,10 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_handle_hpd_rx_irq_msg_rdy), KUNIT_CASE(dm_test_handle_hpd_rx_irq_link_loss), KUNIT_CASE(dm_test_handle_hpd_rx_irq_downstream_change), + KUNIT_CASE(dm_test_handle_hpd_rx_irq_detect_type_fails), + KUNIT_CASE(dm_test_handle_hpd_rx_irq_forced_detect), + KUNIT_CASE(dm_test_handle_hpd_rx_irq_detect_true), + KUNIT_CASE(dm_test_handle_hpd_rx_irq_cp_irq), KUNIT_CASE(dm_test_schedule_hpd_rx_offload_work), /* dmub_hpd_callback/dmub_hpd_sense_callback */ KUNIT_CASE(dm_test_dmub_hpd_callback_null_inputs), From c27fabd80ddb3a3a5d3d7bb6fe3f3f6996a312c5 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 4 Sep 2026 00:00:59 -0600 Subject: [PATCH 067/103] drm/amd/display: Drop redundant amdgpu_dm_irq tests [WHAT] Thirteen tests in the amdgpu_dm_irq suite only re-ran a path that another test already covered, and five more repeated setup that the fixtures added by the preceding patches now provide. [HOW] Delete the tests whose executed path is a strict subset of another's, and fold the remaining duplicated setup onto the shared fixtures. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 499 +----------------- 1 file changed, 11 insertions(+), 488 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index eab04a44a9eb..13beaeb34de1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -266,7 +266,6 @@ static const struct timing_generator_funcs dm_test_tg_funcs = { .get_scanoutpos = dm_test_tg_get_scanoutpos, }; - static uint32_t dm_test_dmub_get_outbox0_wptr(struct dmub_srv *dmub) { return 0; @@ -666,27 +665,8 @@ static void dm_test_hpd_to_dal_irq_source_invalid(struct kunit *test) (int)DC_IRQ_SOURCE_INVALID); } -/** - * dm_test_hpd_to_dal_irq_source_out_of_range - Test Hpd to dal irq source out of range - * @test: The KUnit test context - */ -static void dm_test_hpd_to_dal_irq_source_out_of_range(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(99), - (int)DC_IRQ_SOURCE_INVALID); -} - /* Tests for are_sinks_equal() */ -/** - * dm_test_are_sinks_equal_both_null - Test Are sinks equal both null - * @test: The KUnit test context - */ -static void dm_test_are_sinks_equal_both_null(struct kunit *test) -{ - KUNIT_EXPECT_FALSE(test, are_sinks_equal(NULL, NULL)); -} - /** * dm_test_are_sinks_equal_first_null - Test Are sinks equal first null * @test: The KUnit test context @@ -778,29 +758,6 @@ static void dm_test_are_sinks_equal_different_edid_data(struct kunit *test) KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2)); } -/** - * dm_test_are_sinks_equal_identical - Test Are sinks equal identical - * @test: The KUnit test context - */ -static void dm_test_are_sinks_equal_identical(struct kunit *test) -{ - struct dc_sink *sink1, *sink2; - - sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); - sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); - - sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; - sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; - sink1->dc_edid.length = 4; - sink2->dc_edid.length = 4; - memset(sink1->dc_edid.raw_edid, 0xAA, 4); - memset(sink2->dc_edid.raw_edid, 0xAA, 4); - - KUNIT_EXPECT_TRUE(test, are_sinks_equal(sink1, sink2)); -} - /** * dm_test_are_sinks_equal_zero_length - Test Are sinks equal zero length * @test: The KUnit test context @@ -1044,105 +1001,6 @@ static void dm_test_irq_register_rejects_invalid_source(struct kunit *test) dm_test_irq_handler, NULL)); } -/** - * dm_test_irq_register_adds_low_context_handler - Test register adds low handler - * @test: The KUnit test context - */ -static void dm_test_irq_register_adds_low_context_handler(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc_interrupt_params int_params = { 0 }; - void *handler; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); - - int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; - int_params.irq_source = DC_IRQ_SOURCE_HPD1; - - handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_test_irq_handler, adev); - - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); - KUNIT_EXPECT_FALSE(test, - list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); - KUNIT_EXPECT_TRUE(test, - list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD1])); - - amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, - dm_test_irq_handler); - KUNIT_EXPECT_TRUE(test, - list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); -} - -/** - * dm_test_irq_register_adds_high_context_handler - Test register adds high handler - * @test: The KUnit test context - */ -static void dm_test_irq_register_adds_high_context_handler(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc_interrupt_params int_params = { 0 }; - void *handler; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = DC_IRQ_SOURCE_HPD2; - - handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_test_irq_handler, adev); - - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); - KUNIT_EXPECT_FALSE(test, - list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD2])); - KUNIT_EXPECT_TRUE(test, - list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD2])); - - amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD2, - dm_test_irq_handler); - KUNIT_EXPECT_TRUE(test, - list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD2])); -} - -/** - * dm_test_irq_register_multiple_handlers - Test register keeps multiple handlers - * @test: The KUnit test context - */ -static void dm_test_irq_register_multiple_handlers(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc_interrupt_params int_params = { 0 }; - struct list_head *hnd_list; - void *handler1, *handler2; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); - - int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; - int_params.irq_source = DC_IRQ_SOURCE_HPD1; - - handler1 = amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_test_irq_handler, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler1); - handler2 = amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_test_irq_handler_alt, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler2); - - hnd_list = &adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]; - KUNIT_EXPECT_EQ(test, list_count_nodes(hnd_list), 2); - - amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, - dm_test_irq_handler); - amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, - dm_test_irq_handler_alt); - KUNIT_EXPECT_TRUE(test, list_empty(hnd_list)); -} - /** * dm_test_irq_register_separate_contexts - Test register same source in two contexts * @test: The KUnit test context @@ -1870,48 +1728,6 @@ static void dm_test_set_pflip_irq_state_disable(struct kunit *test) amdgpu_dm_set_pflip_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_DISABLE), 0); } -/** - * dm_test_set_vline0_irq_state_enable - Test vline0 irq state reaches DC (enable) - * @test: The KUnit test context - */ -static void dm_test_set_vline0_irq_state_enable(struct kunit *test) -{ - struct amdgpu_device *adev; - struct amdgpu_crtc *acrtc; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); - - acrtc->otg_inst = 0; - adev->mode_info.crtcs[0] = acrtc; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_set_vline0_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0); -} - -/** - * dm_test_set_vupdate_irq_state_enable - Test vupdate irq state reaches DC (enable) - * @test: The KUnit test context - */ -static void dm_test_set_vupdate_irq_state_enable(struct kunit *test) -{ - struct amdgpu_device *adev; - struct amdgpu_crtc *acrtc; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); - - acrtc->otg_inst = 2; - adev->mode_info.crtcs[0] = acrtc; - - KUNIT_EXPECT_EQ(test, - amdgpu_dm_set_vupdate_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0); -} - /** * dm_test_set_crtc_irq_state_allows_idle - Test the idle-optimization branch * @test: The KUnit test context @@ -1971,34 +1787,6 @@ static void dm_test_irq_immediate_work_empty(struct kunit *test) amdgpu_dm_irq_immediate_work(adev, DC_IRQ_SOURCE_HPD1); } -/** - * dm_test_irq_immediate_work_invokes_handler - Test immediate work calls handler - * @test: The KUnit test context - */ -static void dm_test_irq_immediate_work_invokes_handler(struct kunit *test) -{ - struct amdgpu_device *adev; - struct dc_interrupt_params int_params = { 0 }; - int count = 0; - void *handler; - - adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = DC_IRQ_SOURCE_HPD1; - handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_test_irq_handler_count, &count); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); - - /* High-context handlers are invoked synchronously, in-place. */ - amdgpu_dm_irq_immediate_work(adev, DC_IRQ_SOURCE_HPD1); - KUNIT_EXPECT_EQ(test, count, 1); - - amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, dm_test_irq_handler_count); -} - /** * dm_test_irq_immediate_work_invokes_all - Test immediate work calls all handlers * @test: The KUnit test context @@ -2449,52 +2237,6 @@ static void dm_test_hpd_rx_offload_work_no_connector(struct kunit *test) dm_handle_hpd_rx_offload_work(&offload_work->work); } -/** - * dm_test_hpd_rx_offload_work_no_connection - Test no connection early exit - * @test: The KUnit test context - */ -static void dm_test_hpd_rx_offload_work_no_connection(struct kunit *test) -{ - struct hpd_rx_irq_offload_work_queue *offload_wq; - struct hpd_rx_irq_offload_work *offload_work; - struct amdgpu_dm_connector *aconn; - struct link_service *link_srv; - struct amdgpu_device *adev; - struct dc_link *link; - struct dc *dc; - - adev = dm_kunit_alloc_adev(test); - mutex_init(&adev->dm.dc_lock); - - offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); - - aconn = dm_kunit_alloc_connector(test, adev, NULL); - mutex_init(&aconn->hpd_lock); - offload_wq->aconnector = aconn; - - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); - - link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); - link_srv->detect_connection_type = dm_test_detect_connection_none; - dc->link_srv = link_srv; - - link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); - link->dc = dc; - aconn->dc_link = link; - - offload_work = kzalloc_obj(*offload_work); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work); - offload_work->offload_wq = offload_wq; - offload_work->adev = adev; - INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); - - dm_handle_hpd_rx_offload_work(&offload_work->work); -} - /* * Build a queued hpd_rx_irq_offload_work for dm_handle_hpd_rx_offload_work(): * an adev that is not in reset, an offload queue owning a connector with an @@ -2656,58 +2398,15 @@ static void dm_test_hpd_rx_offload_work_msg_rdy(struct kunit *test) */ static void dm_test_hpd_rx_offload_work_automated_test(struct kunit *test) { - struct hpd_rx_irq_offload_work_queue *offload_wq; struct hpd_rx_irq_offload_work *offload_work; - struct amdgpu_dm_connector *aconn; struct link_service *link_srv; - struct amdgpu_device *adev; - struct dc_context *ctx; - struct dc_link *link; - struct dc *dc; dm_test_automated_test_count = 0; - adev = dm_kunit_alloc_adev(test); - mutex_init(&adev->dm.dc_lock); - adev->reset_domain = kunit_kzalloc(test, sizeof(*adev->reset_domain), - GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->reset_domain); - - offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); - spin_lock_init(&offload_wq->offload_lock); - - aconn = dm_kunit_alloc_connector(test, adev, NULL); - mutex_init(&aconn->hpd_lock); - aconn->timing_changed = false; - offload_wq->aconnector = aconn; - - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); - ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); - link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); - - link_srv->detect_connection_type = dm_test_detect_connection_single; + offload_work = dm_test_setup_hpd_rx_offload_work(test, &link_srv); link_srv->dp_handle_automated_test = dm_test_dp_handle_automated_test; - dc->link_srv = link_srv; - dc->ctx = ctx; - ctx->dc = dc; - link->dc = dc; - link->ctx = ctx; - link->aux_access_disabled = true; - link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; - aconn->dc_link = link; - - offload_work = kzalloc_obj(*offload_work); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work); - offload_work->offload_wq = offload_wq; - offload_work->adev = adev; + offload_work->offload_wq->aconnector->dc_link->aux_access_disabled = true; offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST = 1; - INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); dm_handle_hpd_rx_offload_work(&offload_work->work); @@ -2757,58 +2456,16 @@ static void dm_test_hpd_rx_offload_work_timing_changed(struct kunit *test) */ static void dm_test_hpd_rx_offload_work_link_loss(struct kunit *test) { - struct hpd_rx_irq_offload_work_queue *offload_wq; struct hpd_rx_irq_offload_work *offload_work; - struct amdgpu_dm_connector *aconn; struct link_service *link_srv; - struct amdgpu_device *adev; - struct dc_context *ctx; - struct dc_link *link; - struct dc *dc; dm_test_handle_link_loss_count = 0; - adev = dm_kunit_alloc_adev(test); - mutex_init(&adev->dm.dc_lock); - adev->reset_domain = kunit_kzalloc(test, sizeof(*adev->reset_domain), - GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->reset_domain); - - offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); - spin_lock_init(&offload_wq->offload_lock); - - aconn = dm_kunit_alloc_connector(test, adev, NULL); - mutex_init(&aconn->hpd_lock); - offload_wq->aconnector = aconn; - - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); - ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); - link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); - - link_srv->detect_connection_type = dm_test_detect_connection_single; + offload_work = dm_test_setup_hpd_rx_offload_work(test, &link_srv); link_srv->dp_parse_link_loss_status = dm_test_dp_parse_link_loss_true; link_srv->dp_should_allow_hpd_rx_irq = dm_test_dp_should_allow_hpd_rx_irq_true; link_srv->dp_read_hpd_rx_irq_data = dm_test_dp_read_hpd_rx_irq_data_ok; link_srv->dp_handle_link_loss = dm_test_dp_handle_link_loss; - dc->link_srv = link_srv; - dc->ctx = ctx; - ctx->dc = dc; - link->dc = dc; - link->ctx = ctx; - link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; - aconn->dc_link = link; - - offload_work = kzalloc_obj(*offload_work); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work); - offload_work->offload_wq = offload_wq; - offload_work->adev = adev; - INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); dm_handle_hpd_rx_offload_work(&offload_work->work); @@ -2870,35 +2527,8 @@ static void dm_test_hdmi_hpd_debounce_detect_false(struct kunit *test) { struct amdgpu_dm_connector *aconn; struct link_service *link_srv; - struct amdgpu_device *adev; - struct dc_context *ctx; - struct dc_link *link; - struct dc *dc; - adev = dm_kunit_alloc_adev(test); - mutex_init(&adev->dm.dc_lock); - - aconn = dm_kunit_alloc_connector(test, adev, NULL); - mutex_init(&aconn->hpd_lock); - INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work, - amdgpu_dm_hdmi_hpd_debounce_work); - - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); - ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); - link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); - - link_srv->detect_link = dm_test_detect_link_false; - dc->ctx = ctx; - dc->link_srv = link_srv; - ctx->dc = dc; - link->dc = dc; - link->ctx = ctx; - aconn->dc_link = link; + aconn = dm_test_setup_hdmi_debounce(test, &link_srv); amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work); KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink); @@ -2919,43 +2549,19 @@ static void dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit *test) struct amdgpu_dm_connector *aconn; struct link_service *link_srv; struct dc_dmub_srv *dmub_srv; - struct amdgpu_device *adev; struct dal_logger *logger; - struct dc_context *ctx; - struct dc_link *link; struct dc *dc; - adev = dm_kunit_alloc_adev(test); - mutex_init(&adev->dm.dc_lock); + aconn = dm_test_setup_hdmi_debounce(test, &link_srv); + dc = aconn->dc_link->ctx->dc; - aconn = dm_kunit_alloc_connector(test, adev, NULL); - mutex_init(&aconn->hpd_lock); - INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work, - amdgpu_dm_hdmi_hpd_debounce_work); - - dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); - ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); - link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger); dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); - link_srv->detect_link = dm_test_detect_link_false; - dc->ctx = ctx; - dc->link_srv = link_srv; - ctx->dc = dc; - link->dc = dc; - link->ctx = ctx; - aconn->dc_link = link; - /* DC_LOG_* dereferences ctx->logger->dev, so wire a real drm device. */ - logger->dev = &adev->ddev; + logger->dev = aconn->base.dev; dc->ctx->logger = logger; /* Make reallow_idle true and keep dc_allow_idle*() a safe early return. */ @@ -2965,7 +2571,7 @@ static void dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit *test) dc->debug.disable_idle_power_optimizations = true; /* A cached previous sink must be released and cleared. */ - aconn->hdmi_prev_sink = dm_test_sink_create(link); + aconn->hdmi_prev_sink = dm_test_sink_create(aconn->dc_link); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn->hdmi_prev_sink); amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work); @@ -3206,37 +2812,13 @@ static void dm_test_handle_hpd_irq_helper_debounce_release_prev(struct kunit *te dm_test_sink_release(link->local_sink); } -/** - * dm_test_handle_hpd_irq_helper_detect_false - Test immediate detect branch - * @test: The KUnit test context - * - * With no force, no debounce, and detection stubbed to report no connection, - * the helper takes the else branch: dc_exit_ips_for_hw_access() is a safe - * no-op (no IPS support) and dc_link_detect() returns false, so the connected - * if (ret) block is skipped. fake_enable must still be cleared. - */ -static void dm_test_handle_hpd_irq_helper_detect_false(struct kunit *test) -{ - struct amdgpu_dm_connector *aconn; - struct link_service *link_srv; - - aconn = dm_test_setup_hpd_irq_helper(test, &link_srv); - link_srv->detect_link = dm_test_detect_link_false; - aconn->fake_enable = true; - - /* No debounce delay and no force -> immediate-detect else branch. */ - handle_hpd_irq_helper(aconn, DETECT_REASON_HPD); - - KUNIT_EXPECT_FALSE(test, aconn->fake_enable); -} - /** * dm_test_handle_hpd_irq_helper_detect_type_fails - Test detect failure logging * @test: The KUnit test context * - * When dc_link_detect_connection_type() itself fails the helper logs an error - * and carries on with the connection type left as none, so it still falls - * through to the immediate-detect branch. + * When dc_link_detect_connection_type() fails the helper logs an error and + * carries on with the connection type left as none, so with no force and no + * debounce it still takes the immediate-detect branch. */ static void dm_test_handle_hpd_irq_helper_detect_type_fails(struct kunit *test) { @@ -3497,24 +3079,6 @@ static struct amdgpu_dm_connector *dm_test_setup_hpd_rx_irq(struct kunit *test, return aconn; } -/** - * dm_test_handle_hpd_rx_irq_no_left_work - Test HPDRX early out (no left work) - * @test: The KUnit test context - * - * When dc_link_handle_hpd_rx_irq() reports no left-over work, the handler - * jumps to out and returns without scheduling any offload work. - */ -static void dm_test_handle_hpd_rx_irq_no_left_work(struct kunit *test) -{ - struct amdgpu_dm_connector *aconn; - struct link_service *link_srv; - - aconn = dm_test_setup_hpd_rx_irq(test, &link_srv); - link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work; - - handle_hpd_rx_irq(aconn); -} - /** * dm_test_handle_hpd_rx_irq_automated_test - Test HPDRX automated-test path * @test: The KUnit test context @@ -3579,34 +3143,6 @@ static void dm_test_handle_hpd_rx_irq_link_loss(struct kunit *test) ->dm.hpd_rx_offload_wq->is_handling_link_loss); } -/** - * dm_test_handle_hpd_rx_irq_downstream_change - Test HPDRX post-detect block - * @test: The KUnit test context - * - * A handled HPD RX IRQ on a connector that is not an MST root means a - * downstream port status change, so the handler must re-detect the link. - * Detection is stubbed to fail, leaving the connector untouched, and a - * non-MST-branch link also exercises the trailing CEC IRQ dispatch. - */ -static void dm_test_handle_hpd_rx_irq_downstream_change(struct kunit *test) -{ - struct amdgpu_dm_connector *aconn; - struct link_service *link_srv; - - aconn = dm_test_setup_hpd_rx_irq(test, &link_srv); - link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_result_true; - link_srv->detect_connection_type = dm_test_detect_connection_single; - link_srv->detect_link = dm_test_detect_link_false; - - aconn->mst_mgr.mst_state = false; - aconn->dc_link->type = dc_connection_single; - aconn->fake_enable = true; - - handle_hpd_rx_irq(aconn); - - KUNIT_EXPECT_TRUE(test, aconn->fake_enable); -} - /** * dm_test_handle_hpd_rx_irq_detect_type_fails - Test HPDRX detect failure logging * @test: The KUnit test context @@ -5548,15 +5084,12 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd5), KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd6), KUNIT_CASE(dm_test_hpd_to_dal_irq_source_invalid), - KUNIT_CASE(dm_test_hpd_to_dal_irq_source_out_of_range), /* are_sinks_equal */ - KUNIT_CASE(dm_test_are_sinks_equal_both_null), KUNIT_CASE(dm_test_are_sinks_equal_first_null), KUNIT_CASE(dm_test_are_sinks_equal_second_null), KUNIT_CASE(dm_test_are_sinks_equal_different_signal), KUNIT_CASE(dm_test_are_sinks_equal_different_edid_length), KUNIT_CASE(dm_test_are_sinks_equal_different_edid_data), - KUNIT_CASE(dm_test_are_sinks_equal_identical), KUNIT_CASE(dm_test_are_sinks_equal_zero_length), KUNIT_CASE(dm_test_are_sinks_equal_full_edid_identical), KUNIT_CASE(dm_test_are_sinks_equal_full_edid_last_byte_differs), @@ -5576,9 +5109,6 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_irq_register_rejects_null_params), KUNIT_CASE(dm_test_irq_register_rejects_invalid_context), KUNIT_CASE(dm_test_irq_register_rejects_invalid_source), - KUNIT_CASE(dm_test_irq_register_adds_low_context_handler), - KUNIT_CASE(dm_test_irq_register_adds_high_context_handler), - KUNIT_CASE(dm_test_irq_register_multiple_handlers), KUNIT_CASE(dm_test_irq_register_separate_contexts), /* amdgpu_dm_irq_unregister_interrupt */ KUNIT_CASE(dm_test_irq_unregister_rejects_invalid_source), @@ -5617,12 +5147,9 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_set_crtc_irq_state_otg_disabled), KUNIT_CASE(dm_test_set_crtc_irq_state_enable), KUNIT_CASE(dm_test_set_pflip_irq_state_disable), - KUNIT_CASE(dm_test_set_vline0_irq_state_enable), - KUNIT_CASE(dm_test_set_vupdate_irq_state_enable), KUNIT_CASE(dm_test_set_crtc_irq_state_allows_idle), /* amdgpu_dm_irq_immediate_work */ KUNIT_CASE(dm_test_irq_immediate_work_empty), - KUNIT_CASE(dm_test_irq_immediate_work_invokes_handler), KUNIT_CASE(dm_test_irq_immediate_work_invokes_all), /* amdgpu_dm_irq_schedule_work */ KUNIT_CASE(dm_test_irq_schedule_work_empty), @@ -5646,7 +5173,6 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_hpd_init_skips_connector_without_link), /* dm_handle_hpd_rx_offload_work */ KUNIT_CASE(dm_test_hpd_rx_offload_work_no_connector), - KUNIT_CASE(dm_test_hpd_rx_offload_work_no_connection), KUNIT_CASE(dm_test_hpd_rx_offload_work_detect_type_fails), KUNIT_CASE(dm_test_hpd_rx_offload_work_in_reset), KUNIT_CASE(dm_test_hpd_rx_offload_work_msg_rdy), @@ -5662,7 +5188,6 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_handle_hpd_irq_disabled), KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_schedule), KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_release_prev), - KUNIT_CASE(dm_test_handle_hpd_irq_helper_detect_false), KUNIT_CASE(dm_test_handle_hpd_irq_helper_detect_type_fails), KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_pending), KUNIT_CASE(dm_test_handle_hpd_irq_helper_hdcp_reset), @@ -5670,11 +5195,9 @@ static struct kunit_case amdgpu_dm_irq_tests[] = { KUNIT_CASE(dm_test_handle_hpd_irq_helper_detect_true), /* handle_hpd_rx_irq/schedule_hpd_rx_offload_work */ KUNIT_CASE(dm_test_handle_hpd_rx_irq_disabled), - KUNIT_CASE(dm_test_handle_hpd_rx_irq_no_left_work), KUNIT_CASE(dm_test_handle_hpd_rx_irq_automated_test), KUNIT_CASE(dm_test_handle_hpd_rx_irq_msg_rdy), KUNIT_CASE(dm_test_handle_hpd_rx_irq_link_loss), - KUNIT_CASE(dm_test_handle_hpd_rx_irq_downstream_change), KUNIT_CASE(dm_test_handle_hpd_rx_irq_detect_type_fails), KUNIT_CASE(dm_test_handle_hpd_rx_irq_forced_detect), KUNIT_CASE(dm_test_handle_hpd_rx_irq_detect_true), From af5b78daa5ae2ab5e57a614891b3a6cb7b588f43 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Tue, 8 Sep 2026 19:22:49 -0400 Subject: [PATCH 068/103] drm/amd/display: Add inst field to encoder structs Add an inst member to struct link_encoder, struct stream_encoder and struct hpo_frl_stream_encoder, and populate it in the DCN10 through DCN60 construct paths. No functional change; the field has no readers yet. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c | 2 ++ drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/dcn20/dcn20_stream_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn30/dcn30_dio_stream_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c | 1 + .../gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn42/dcn42_dio_stream_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_link_encoder.c | 2 ++ .../drm/amd/display/dc/dio/dcn60/dcn60_dio_stream_encoder.c | 2 ++ .../gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c | 3 +++ .../drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c | 1 + .../amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c | 2 ++ .../amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c | 2 ++ .../amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c | 2 ++ .../amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c | 2 ++ drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h | 2 ++ 28 files changed, 54 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c index aee9a363e336..32e12d894e31 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c @@ -781,6 +781,8 @@ void dcn10_link_encoder_construct( if (enc10->base.ctx->dc->debug.hdmi20_disable) { enc10->base.features.flags.bits.HDMI_6GB_EN = 0; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } bool dcn10_link_encoder_validate_output_with_stream( diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c index d913f065ecca..c937788d0763 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c @@ -1625,5 +1625,7 @@ void dcn10_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = eng_id - ENGINE_ID_DIGA; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.c index 3bd35f3392dc..dbd4c534c5c3 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.c @@ -502,4 +502,6 @@ void dcn20_link_encoder_construct( if (enc10->base.ctx->dc->debug.hdmi20_disable) { enc10->base.features.flags.bits.HDMI_6GB_EN = 0; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_stream_encoder.c index bec0b4aaeb2b..ac6ca7771d2f 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_stream_encoder.c @@ -657,5 +657,7 @@ void dcn20_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = eng_id - ENGINE_ID_DIGA; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c index 8c4010c5b2e7..5fd5158482ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c @@ -456,6 +456,8 @@ void dcn30_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } #define AUX_REG(reg)\ diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_stream_encoder.c index c14fb51c2611..9757d3bcdf32 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_stream_encoder.c @@ -899,5 +899,7 @@ void dcn30_dio_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = vpg->inst; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c index 02fb844670f9..7106669eab5b 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c @@ -209,4 +209,6 @@ void dcn301_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c index f57f3ba68a02..1b9ba0e9f068 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c @@ -509,6 +509,8 @@ void dcn31_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } void dcn31_link_encoder_construct_minimal( diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c index d1fd5462dca5..482c52c1d7d6 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c @@ -504,5 +504,7 @@ void dcn314_dio_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = vpg->inst; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c index 68e0dc93ae7d..63990c47ac14 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c @@ -551,4 +551,6 @@ void dcn32_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c index edafa3808455..3dd8fe423232 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c @@ -491,5 +491,7 @@ void dcn32_dio_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = vpg->inst; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c index 4108fd0f4380..67d6050d5163 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c @@ -210,4 +210,6 @@ void dcn321_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c index 8fa9b8c500f2..9375c9b939be 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c @@ -290,6 +290,8 @@ void dcn35_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } /* DPIA equivalent of link_transmitter_control. */ diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c index de24dcd27e6c..dabcb45840a7 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c @@ -517,5 +517,7 @@ void dcn35_dio_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = vpg->inst; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c index dad4ef565168..6594fbb3fa43 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c @@ -557,4 +557,6 @@ void dcn401_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c index 79d0c2896d29..4616b6f76aeb 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c @@ -793,6 +793,7 @@ void dcn401_dio_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = vpg->inst; + enc1->base.inst = enc1->base.stream_enc_inst; } void enc401_set_dynamic_metadata(struct stream_encoder *enc, diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c index 50174aded6aa..3b11be9991c3 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c @@ -223,4 +223,6 @@ void dcn42_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_stream_encoder.c index 35845e6dd5aa..b7671d41ea24 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_stream_encoder.c @@ -581,4 +581,6 @@ void dcn42_dio_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = vpg->inst; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_link_encoder.c index 6fe15324ea50..f65326a0f6d2 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_link_encoder.c @@ -370,4 +370,6 @@ void dcn60_link_encoder_construct( enc10->base.features.flags.bits.IS_FRL_20G_CAPABLE = 1; enc10->base.features.flags.bits.IS_FRL_24G_CAPABLE = 0; } + + enc10->base.inst = (unsigned int)enc10->base.preferred_engine; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_stream_encoder.c index b76cc891857d..b645914c1c71 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn60/dcn60_dio_stream_encoder.c @@ -535,4 +535,6 @@ void dcn60_dio_stream_encoder_construct( enc1->se_shift = se_shift; enc1->se_mask = se_mask; enc1->base.stream_enc_inst = vpg->inst; + enc1->base.inst = enc1->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c index 5b2bba0eff0e..f847fef069c9 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c @@ -27,6 +27,7 @@ #include "dm_services_types.h" #include "virtual_link_encoder.h" +#include "stream_encoder.h" static bool virtual_link_encoder_validate_output_with_stream( struct link_encoder *enc, @@ -167,5 +168,7 @@ bool virtual_link_encoder_construct( enc->preferred_engine = ENGINE_ID_VIRTUAL; + enc->inst = 0; + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c index 27448f2b2467..f6b1e2a42baa 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c @@ -190,6 +190,7 @@ bool virtual_stream_encoder_construct( struct dc_context *ctx, struct dc_bios *bp) { + enc->inst = 0; if (!enc) return false; if (!bp) diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c index f4c21998d845..f0128c5bf993 100644 --- a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c @@ -1040,4 +1040,6 @@ void dcn30_hpo_frl_stream_encoder_construct( enc3->hpo_se_shift = hpo_se_shift; enc3->hpo_se_mask = hpo_se_mask; enc3->base.stream_enc_inst = vpg->inst; + enc3->base.inst = enc3->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c index 85b7a44c0a11..4b14a3bfe56d 100644 --- a/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c @@ -904,4 +904,6 @@ void dcn401_hpo_frl_stream_encoder_construct( enc401->hpo_se_shift = hpo_se_shift; enc401->hpo_se_mask = hpo_se_mask; enc401->base.stream_enc_inst = vpg->inst; + enc401->base.inst = enc401->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c index 43870d84ca2f..1aed194b58bd 100644 --- a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c @@ -209,4 +209,6 @@ void dcn42_hpo_frl_stream_encoder_construct( enc42->hpo_se_shift = hpo_se_shift; enc42->hpo_se_mask = hpo_se_mask; enc42->base.stream_enc_inst = vpg->inst; + enc42->base.inst = enc42->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c index b5397d6760b1..de42f8c5f7f0 100644 --- a/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c @@ -231,4 +231,6 @@ void dcn60_hpo_frl_stream_encoder_construct( enc401->hpo_se_shift = hpo_se_shift; enc401->hpo_se_mask = hpo_se_mask; enc401->base.stream_enc_inst = vpg->inst; + enc401->base.inst = enc401->base.stream_enc_inst; + } diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index 70545df981ef..f3ef5bbfad81 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -100,6 +100,7 @@ struct link_encoder { struct graphics_object_id connector; uint32_t output_signals; enum engine_id preferred_engine; + unsigned int inst; enum engine_id analog_engine; struct encoder_feature_support features; enum transmitter transmitter; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 2b95cb11eede..5b8688b3aaef 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -126,6 +126,7 @@ struct stream_encoder { struct dc_bios *bp; enum engine_id id; uint32_t stream_enc_inst; + unsigned int inst; struct vpg *vpg; struct afmt *afmt; struct apg *apg; @@ -319,6 +320,7 @@ struct hpo_frl_stream_encoder { * @stream_enc_inst: Instance ID reference. */ uint32_t stream_enc_inst; + unsigned int inst; /** * @ctx: DC context. From 58c864f52e087da10973e294fe8d4d26e6bc503c Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Sun, 6 Sep 2026 16:48:02 -0400 Subject: [PATCH 069/103] drm/amd/display: Add inst field to clock_source and dio Add an inst member to struct clock_source and struct dio. The DCE110 and DCE112 clock sources derive it from their clock_source_id; the DCN10 DIO is a singleton and uses 0. Also move the (void)encoding cast in dcn401_program_pix_clk() below the local declarations, where it belongs. No functional change; the inst field has no readers yet. Reviewed-by: Jun Lei Reviewed-by: Alex Hung Signed-off-by: Tony Cheng Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c | 4 +++- drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c | 1 + drivers/gpu/drm/amd/display/dc/inc/clock_source.h | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/dio.h | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) 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 54ef1808ca35..145c993342bd 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 @@ -1074,7 +1074,6 @@ static bool dcn401_program_pix_clk( enum dp_link_encoding encoding, struct pll_settings *pll_settings) { - (void)encoding; struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; const struct pixel_rate_range_table_entry *e = @@ -1082,6 +1081,7 @@ static bool dcn401_program_pix_clk( struct bp_pixel_clock_parameters bp_pc_params = {0}; enum transmitter_color_depth bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24; struct dp_dto_params dto_params = { 0 }; + (void)encoding; dto_params.otg_inst = inst; dto_params.signal = pix_clk_params->signal_type; @@ -1757,6 +1757,7 @@ bool dce110_clk_src_construct( clk_src->base.ctx = ctx; clk_src->bios = bios; clk_src->base.id = id; + clk_src->base.inst = (unsigned int)id; clk_src->base.funcs = &dce110_clk_src_funcs; clk_src->regs = regs; @@ -1855,6 +1856,7 @@ bool dce112_clk_src_construct( clk_src->base.ctx = ctx; clk_src->bios = bios; clk_src->base.id = id; + clk_src->base.inst = (unsigned int)id; clk_src->base.funcs = &dce112_clk_src_funcs; clk_src->regs = regs; diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c index edcf4e67483b..458ce1053c96 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c @@ -40,6 +40,7 @@ void dcn10_dio_construct( { dio10->base.ctx = ctx; dio10->base.funcs = &dcn10_dio_funcs; + dio10->base.inst = 0; dio10->regs = regs; dio10->shifts = shifts; diff --git a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h index 9e2dac044495..0bf5419d9d9f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h @@ -186,6 +186,7 @@ struct clock_source { const struct clock_source_funcs *funcs; struct dc_context *ctx; enum clock_source_id id; + unsigned int inst; bool dp_clk_src; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h index 532bf54cf2c4..916ac15b6b58 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h @@ -17,6 +17,7 @@ struct dio_funcs { struct dio { const struct dio_funcs *funcs; struct dc_context *ctx; + unsigned int inst; }; #endif /* __DC_DIO_H__ */ From 1817b5dca2232c88c678ca0f05c5179e669d2f6e Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Mon, 7 Sep 2026 17:39:14 +0800 Subject: [PATCH 070/103] drm/amd/display: Fix missing gaps for link lock with inbox0 [Why] Inbox1 was previously being used for cursor and DIG locking with DMUB doing the relevant programming on behalf of driver. With the Inbox0 lock the driver is expected to do the programming itself and the Inbox0 lock acts as nothing more than a SW mutex. There are still a few gaps in how Inbox1 was being leveraged in the cursor path that need to be addressed for Inbox0. [How] Add a `should_use_dmub_inbox0_lock_for_link` helper to help check if we support the Inbox0 locking infrastructure and we should be locking it if the specific link in question requires it. Reviewed-by: Nicholas Kazlauskas Signed-off-by: Nicholas Kazlauskas Signed-off-by: Zhikai Zhai Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_stream.c | 21 +++++++++++++++++++ .../drm/amd/display/dc/dce/dmub_hw_lock_mgr.c | 10 ++++++++- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 3 ++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 8d3aacc7b96c..88ac4a4cfd6e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -34,6 +34,7 @@ #include "dc_dmub_srv.h" #include "dc_state_priv.h" #include "dc_stream_priv.h" +#include "dce/dmub_hw_lock_mgr.h" #define DC_LOGGER dc->ctx->logger #ifndef MIN @@ -307,6 +308,7 @@ void program_cursor_attributes( struct resource_context *res_ctx; struct pipe_ctx *pipe_to_program = NULL; bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); + bool unlock_dmub = false; if (!stream) return; @@ -330,6 +332,12 @@ void program_cursor_attributes( pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp, top_pipe->pipe_idx); } else { + if (dc->hwss.dmub_hw_control_lock && pipe_ctx->stream && + should_use_dmub_inbox0_lock_for_link(dc, pipe_ctx->stream->link)) { + dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true); + unlock_dmub = true; + } + dc->hwss.cursor_lock(dc, pipe_to_program, true); if (pipe_to_program->next_odm_pipe) dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true); @@ -362,6 +370,9 @@ void program_cursor_attributes( dc->hwss.cursor_lock(dc, pipe_to_program, false); if (pipe_to_program->next_odm_pipe) dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false); + + if (unlock_dmub) + dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false); } } } @@ -481,6 +492,7 @@ void program_cursor_position( struct resource_context *res_ctx; struct pipe_ctx *pipe_to_program = NULL; bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); + bool unlock_dmub = false; if (!stream) return; @@ -508,6 +520,12 @@ void program_cursor_position( pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp, top_pipe->pipe_idx); } else { + if (dc->hwss.dmub_hw_control_lock && pipe_ctx->stream && + should_use_dmub_inbox0_lock_for_link(dc, pipe_ctx->stream->link)) { + dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true); + unlock_dmub = true; + } + dc->hwss.cursor_lock(dc, pipe_to_program, true); } } @@ -535,6 +553,9 @@ void program_cursor_position( top_pipe->pipe_idx); } else { dc->hwss.cursor_lock(dc, pipe_to_program, false); + + if (unlock_dmub) + dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false); } } } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c index 52673e2f504c..2ac1485a3438 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c @@ -36,6 +36,14 @@ static bool dmub_hw_lock_has_inbox0_lock(const struct dc *dc) dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_support; } +static bool dmub_hw_lock_has_inbox0_lock_split(const struct dc *dc) +{ + return dc->ctx && dc->ctx->dmub_srv && + dc->hwss.dmub_hw_control_lock && + dc->hwss.dmub_hw_control_lock_fast && + dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_split; +} + void dmub_hw_lock_mgr_cmd(struct dc_dmub_srv *dmub_srv, bool lock, union dmub_hw_lock_flags *hw_locks, @@ -121,5 +129,5 @@ bool should_use_dmub_inbox1_lock(const struct dc *dc, const struct dc_link *link bool should_use_dmub_inbox0_lock_for_link(const struct dc *dc, const struct dc_link *link) { - return dmub_hw_lock_has_inbox0_lock(dc) && dmub_hw_lock_mgr_does_link_require_lock(dc, link); + return dmub_hw_lock_has_inbox0_lock_split(dc) && dmub_hw_lock_mgr_does_link_require_lock(dc, link); } diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 45385f9eb893..f3e1a41897bf 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -1004,7 +1004,8 @@ union dmub_fw_meta_feature_bits { uint32_t shared_state_link_detection : 1; /**< 1 supports link detection via shared state */ uint32_t cursor_offload_v1_support: 1; /**< 1 supports cursor offload */ uint32_t inbox0_lock_support: 1; /**< 1 supports inbox0 lock mechanism */ - uint32_t reserved : 29; + uint32_t inbox0_lock_split: 1; /**< 1 supports inbox0 lock acquire/release split mechanism */ + uint32_t reserved : 28; } bits; /**< status bits */ uint32_t all; /**< 32-bit access to status bits */ }; From 64cb7e42934dc363215064c4411d5d803dd7873a Mon Sep 17 00:00:00 2001 From: Dillon Varone Date: Thu, 3 Sep 2026 14:23:49 -0400 Subject: [PATCH 071/103] drm/amd/display: Add more diagnostic logs for DMU [WHY&HOW] Adds diagnostic logs for recent DMU traces. Reviewed-by: Nicholas Kazlauskas Reviewed-by: Aric Cyr Signed-off-by: Dillon Varone Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 125 ++++++++++++------ drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 58 +++++++- .../gpu/drm/amd/display/dmub/src/dmub_dcn20.c | 74 +++++------ .../gpu/drm/amd/display/dmub/src/dmub_dcn20.h | 2 +- .../gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 82 ++++++------ .../gpu/drm/amd/display/dmub/src/dmub_dcn31.h | 2 +- .../gpu/drm/amd/display/dmub/src/dmub_dcn32.c | 82 ++++++------ .../gpu/drm/amd/display/dmub/src/dmub_dcn32.h | 2 +- .../gpu/drm/amd/display/dmub/src/dmub_dcn35.c | 82 ++++++------ .../gpu/drm/amd/display/dmub/src/dmub_dcn35.h | 2 +- .../drm/amd/display/dmub/src/dmub_dcn401.c | 86 ++++++------ .../drm/amd/display/dmub/src/dmub_dcn401.h | 2 +- .../gpu/drm/amd/display/dmub/src/dmub_dcn42.c | 86 ++++++------ .../gpu/drm/amd/display/dmub/src/dmub_dcn42.h | 2 +- .../gpu/drm/amd/display/dmub/src/dmub_dcn60.c | 86 ++++++------ .../gpu/drm/amd/display/dmub/src/dmub_dcn60.h | 2 +- .../gpu/drm/amd/display/dmub/src/dmub_srv.c | 54 +++++++- 17 files changed, 470 insertions(+), 359 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 1e7071f8d53f..37248ecc3c08 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -273,6 +273,49 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv, return dc_dmub_srv_cmd_list_queue_execute_timeout(dc_dmub_srv, count, cmd_list, DMUB_CMD_DEFAULT_MAX_WAIT_US); } +static void dc_dmub_srv_log_timeout(const struct dc_dmub_srv *dc_dmub_srv, + struct dmub_timeout_info *timeout_info, + union dmub_rb_cmd *cmd) +{ + struct dmub_srv *dmub; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return; + + dmub = dc_dmub_srv->dmub; + + // timeout already ocurred, do not overwrite + if (timeout_info->timeout_occured) + return; + + timeout_info->timeout_occured = true; + if (cmd) + timeout_info->timeout_cmd = *cmd; + timeout_info->timestamp = dm_get_timestamp(dc_dmub_srv->ctx); + + // capture last trace entries from the DMCUB trace buffer + dmub_srv_get_trace_snapshot(dmub, + &timeout_info->trace_snapshot); +} + +static void dc_dmub_srv_log_timeouts(struct dc_dmub_srv *dc_dmub_srv, + union dmub_rb_cmd *cmd) +{ + struct dmub_srv *dmub; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return; + + dmub = dc_dmub_srv->dmub; + + // log if this is the first timeout + dc_dmub_srv_log_timeout(dc_dmub_srv, &dmub->debug.first_timeout_info, cmd); + + // clear valid flag and log latest timeout + dmub->debug.latest_timeout_info.timeout_occured = false; + dc_dmub_srv_log_timeout(dc_dmub_srv, &dmub->debug.latest_timeout_info, cmd); +} + bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv, enum dm_dmub_wait_type wait_type, union dmub_rb_cmd *cmd_list, @@ -294,12 +337,8 @@ bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv, if (status != DMUB_STATUS_OK) { DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); - if (!dmub->debug.timeout_info.timeout_occured) { - dmub->debug.timeout_info.timeout_occured = true; - if (cmd_list) - dmub->debug.timeout_info.timeout_cmd = *cmd_list; - dmub->debug.timeout_info.timestamp = dm_get_timestamp(dc_dmub_srv->ctx); - } + + dc_dmub_srv_log_timeouts(dc_dmub_srv, cmd_list); dc_dmub_srv_handle_failure(dc_dmub_srv); return false; } @@ -985,44 +1024,44 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) } DC_LOG_DEBUG("DMCUB STATE:"); - DC_LOG_DEBUG(" dmcub_version : %08x", dc_dmub_srv->dmub->debug.dmcub_version); - DC_LOG_DEBUG(" scratch [0] : %08x", dc_dmub_srv->dmub->debug.scratch[0]); - DC_LOG_DEBUG(" scratch [1] : %08x", dc_dmub_srv->dmub->debug.scratch[1]); - DC_LOG_DEBUG(" scratch [2] : %08x", dc_dmub_srv->dmub->debug.scratch[2]); - DC_LOG_DEBUG(" scratch [3] : %08x", dc_dmub_srv->dmub->debug.scratch[3]); - DC_LOG_DEBUG(" scratch [4] : %08x", dc_dmub_srv->dmub->debug.scratch[4]); - DC_LOG_DEBUG(" scratch [5] : %08x", dc_dmub_srv->dmub->debug.scratch[5]); - DC_LOG_DEBUG(" scratch [6] : %08x", dc_dmub_srv->dmub->debug.scratch[6]); - DC_LOG_DEBUG(" scratch [7] : %08x", dc_dmub_srv->dmub->debug.scratch[7]); - DC_LOG_DEBUG(" scratch [8] : %08x", dc_dmub_srv->dmub->debug.scratch[8]); - DC_LOG_DEBUG(" scratch [9] : %08x", dc_dmub_srv->dmub->debug.scratch[9]); - DC_LOG_DEBUG(" scratch [10] : %08x", dc_dmub_srv->dmub->debug.scratch[10]); - DC_LOG_DEBUG(" scratch [11] : %08x", dc_dmub_srv->dmub->debug.scratch[11]); - DC_LOG_DEBUG(" scratch [12] : %08x", dc_dmub_srv->dmub->debug.scratch[12]); - DC_LOG_DEBUG(" scratch [13] : %08x", dc_dmub_srv->dmub->debug.scratch[13]); - DC_LOG_DEBUG(" scratch [14] : %08x", dc_dmub_srv->dmub->debug.scratch[14]); - DC_LOG_DEBUG(" scratch [15] : %08x", dc_dmub_srv->dmub->debug.scratch[15]); + DC_LOG_DEBUG(" dmcub_version : %08x", dc_dmub_srv->dmub->debug.hw.dmcub_version); + DC_LOG_DEBUG(" scratch [0] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[0]); + DC_LOG_DEBUG(" scratch [1] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[1]); + DC_LOG_DEBUG(" scratch [2] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[2]); + DC_LOG_DEBUG(" scratch [3] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[3]); + DC_LOG_DEBUG(" scratch [4] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[4]); + DC_LOG_DEBUG(" scratch [5] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[5]); + DC_LOG_DEBUG(" scratch [6] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[6]); + DC_LOG_DEBUG(" scratch [7] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[7]); + DC_LOG_DEBUG(" scratch [8] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[8]); + DC_LOG_DEBUG(" scratch [9] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[9]); + DC_LOG_DEBUG(" scratch [10] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[10]); + DC_LOG_DEBUG(" scratch [11] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[11]); + DC_LOG_DEBUG(" scratch [12] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[12]); + DC_LOG_DEBUG(" scratch [13] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[13]); + DC_LOG_DEBUG(" scratch [14] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[14]); + DC_LOG_DEBUG(" scratch [15] : %08x", dc_dmub_srv->dmub->debug.hw.scratch[15]); for (i = 0; i < DMUB_PC_SNAPSHOT_COUNT; i++) - DC_LOG_DEBUG(" pc[%d] : %08x", i, dc_dmub_srv->dmub->debug.pc[i]); - DC_LOG_DEBUG(" unk_fault_addr : %08x", dc_dmub_srv->dmub->debug.undefined_address_fault_addr); - DC_LOG_DEBUG(" inst_fault_addr : %08x", dc_dmub_srv->dmub->debug.inst_fetch_fault_addr); - DC_LOG_DEBUG(" data_fault_addr : %08x", dc_dmub_srv->dmub->debug.data_write_fault_addr); - DC_LOG_DEBUG(" inbox1_rptr : %08x", dc_dmub_srv->dmub->debug.inbox1_rptr); - DC_LOG_DEBUG(" inbox1_wptr : %08x", dc_dmub_srv->dmub->debug.inbox1_wptr); - DC_LOG_DEBUG(" inbox1_size : %08x", dc_dmub_srv->dmub->debug.inbox1_size); - DC_LOG_DEBUG(" inbox0_rptr : %08x", dc_dmub_srv->dmub->debug.inbox0_rptr); - DC_LOG_DEBUG(" inbox0_wptr : %08x", dc_dmub_srv->dmub->debug.inbox0_wptr); - DC_LOG_DEBUG(" inbox0_size : %08x", dc_dmub_srv->dmub->debug.inbox0_size); - DC_LOG_DEBUG(" outbox1_rptr : %08x", dc_dmub_srv->dmub->debug.outbox1_rptr); - DC_LOG_DEBUG(" outbox1_wptr : %08x", dc_dmub_srv->dmub->debug.outbox1_wptr); - DC_LOG_DEBUG(" outbox1_size : %08x", dc_dmub_srv->dmub->debug.outbox1_size); - DC_LOG_DEBUG(" is_enabled : %d", dc_dmub_srv->dmub->debug.is_dmcub_enabled); - DC_LOG_DEBUG(" is_soft_reset : %d", dc_dmub_srv->dmub->debug.is_dmcub_soft_reset); - DC_LOG_DEBUG(" is_secure_reset : %d", dc_dmub_srv->dmub->debug.is_dmcub_secure_reset); - DC_LOG_DEBUG(" is_traceport_en : %d", dc_dmub_srv->dmub->debug.is_traceport_en); - DC_LOG_DEBUG(" is_cw0_en : %d", dc_dmub_srv->dmub->debug.is_cw0_enabled); - DC_LOG_DEBUG(" is_cw6_en : %d", dc_dmub_srv->dmub->debug.is_cw6_enabled); - DC_LOG_DEBUG(" is_pwait : %d", dc_dmub_srv->dmub->debug.is_pwait); + DC_LOG_DEBUG(" pc[%d] : %08x", i, dc_dmub_srv->dmub->debug.hw.pc[i]); + DC_LOG_DEBUG(" unk_fault_addr : %08x", dc_dmub_srv->dmub->debug.hw.undefined_address_fault_addr); + DC_LOG_DEBUG(" inst_fault_addr : %08x", dc_dmub_srv->dmub->debug.hw.inst_fetch_fault_addr); + DC_LOG_DEBUG(" data_fault_addr : %08x", dc_dmub_srv->dmub->debug.hw.data_write_fault_addr); + DC_LOG_DEBUG(" inbox1_rptr : %08x", dc_dmub_srv->dmub->debug.hw.inbox1_rptr); + DC_LOG_DEBUG(" inbox1_wptr : %08x", dc_dmub_srv->dmub->debug.hw.inbox1_wptr); + DC_LOG_DEBUG(" inbox1_size : %08x", dc_dmub_srv->dmub->debug.hw.inbox1_size); + DC_LOG_DEBUG(" inbox0_rptr : %08x", dc_dmub_srv->dmub->debug.hw.inbox0_rptr); + DC_LOG_DEBUG(" inbox0_wptr : %08x", dc_dmub_srv->dmub->debug.hw.inbox0_wptr); + DC_LOG_DEBUG(" inbox0_size : %08x", dc_dmub_srv->dmub->debug.hw.inbox0_size); + DC_LOG_DEBUG(" outbox1_rptr : %08x", dc_dmub_srv->dmub->debug.hw.outbox1_rptr); + DC_LOG_DEBUG(" outbox1_wptr : %08x", dc_dmub_srv->dmub->debug.hw.outbox1_wptr); + DC_LOG_DEBUG(" outbox1_size : %08x", dc_dmub_srv->dmub->debug.hw.outbox1_size); + DC_LOG_DEBUG(" is_enabled : %d", dc_dmub_srv->dmub->debug.hw.is_dmcub_enabled); + DC_LOG_DEBUG(" is_soft_reset : %d", dc_dmub_srv->dmub->debug.hw.is_dmcub_soft_reset); + DC_LOG_DEBUG(" is_secure_reset : %d", dc_dmub_srv->dmub->debug.hw.is_dmcub_secure_reset); + DC_LOG_DEBUG(" is_traceport_en : %d", dc_dmub_srv->dmub->debug.hw.is_traceport_en); + DC_LOG_DEBUG(" is_cw0_en : %d", dc_dmub_srv->dmub->debug.hw.is_cw0_enabled); + DC_LOG_DEBUG(" is_cw6_en : %d", dc_dmub_srv->dmub->debug.hw.is_cw6_enabled); + DC_LOG_DEBUG(" is_pwait : %d", dc_dmub_srv->dmub->debug.hw.is_pwait); } bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index a5222ffc8ab6..17579ff2e1bf 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -69,6 +69,7 @@ #include "dc/dc_types.h" #define DMUB_PC_SNAPSHOT_COUNT 10 +#define DMUB_TRACE_SNAPSHOT_COUNT 8 /* Default tracebuffer size if meta is absent. */ #define DMUB_TRACE_BUFFER_SIZE (64 * 1024) @@ -81,6 +82,7 @@ struct dmub_srv; struct dmub_srv_common_regs; struct dmub_srv_dcn31_regs; +struct dmcub_trace_buf; struct dmcub_trace_buf_entry; /* enum dmub_window_memory_type - memory location type specification for windows */ @@ -358,6 +360,26 @@ struct dmub_srv_hw_params { bool disable_dpia_bw_allocation; }; +#define DMUB_TIMEOUT_TRACE_COUNT 8 + +/** + * struct dmub_trace_buf_header - Header for the DMUB trace buffer + * @entry_count: Number of valid entries in the trace buffer + * @reserved: Reserved for future use + */ +struct dmub_trace_buf_header { + uint32_t entry_count; + uint32_t reserved[3]; +}; + +/** + * struct dmub_trace_snapshot - Snapshot of the DMUB trace buffer + * @traces: Array of trace buffer entries + */ +struct dmub_trace_snapshot { + struct dmcub_trace_buf_entry traces[DMUB_TRACE_SNAPSHOT_COUNT]; +}; + /** * struct dmub_srv_debug - Debug info for dmub_srv * @timeout_occured: Indicates a timeout occured on any message from driver to dmub @@ -367,13 +389,13 @@ struct dmub_timeout_info { bool timeout_occured; union dmub_rb_cmd timeout_cmd; unsigned long long timestamp; + struct dmub_trace_snapshot trace_snapshot; }; /** - * struct dmub_diagnostic_data - Diagnostic data retrieved from DMCUB for - * debugging purposes, including logging, crash analysis, etc. + * struct dmub_hw_diagnostic_data - Hardware diagnostic data for the DMUB */ -struct dmub_diagnostic_data { +struct dmub_hw_diagnostic_data { uint32_t dmcub_version; uint32_t scratch[17]; uint32_t pc[DMUB_PC_SNAPSHOT_COUNT]; @@ -390,7 +412,6 @@ struct dmub_diagnostic_data { uint32_t outbox1_wptr; uint32_t outbox1_size; uint32_t gpint_datain0; - struct dmub_timeout_info timeout_info; uint8_t is_dmcub_enabled : 1; uint8_t is_dmcub_soft_reset : 1; uint8_t is_dmcub_secure_reset : 1; @@ -400,6 +421,17 @@ struct dmub_diagnostic_data { uint8_t is_pwait : 1; }; +/** + * struct dmub_diagnostic_data - Diagnostic data retrieved from DMCUB for + * debugging purposes, including logging, crash analysis, etc. + */ +struct dmub_diagnostic_data { + struct dmub_hw_diagnostic_data hw; + struct dmub_timeout_info first_timeout_info; + struct dmub_timeout_info latest_timeout_info; + struct dmub_trace_snapshot trace_snapshot; +}; + /** * struct dmub_preos_info - preos fw info before loading post os fw. */ @@ -537,7 +569,7 @@ struct dmub_srv_hw_funcs { void (*send_inbox0_cmd)(struct dmub_srv *dmub, union dmub_inbox0_data_register data); uint32_t (*get_current_time)(struct dmub_srv *dmub); - void (*get_diagnostic_data)(struct dmub_srv *dmub); + void (*get_diagnostic_data)(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); bool (*get_preos_fw_info)(struct dmub_srv *dmub); bool (*should_detect)(struct dmub_srv *dmub); @@ -992,6 +1024,14 @@ enum dmub_status dmub_srv_set_skip_panel_power_sequence(struct dmub_srv *dmub, bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entry *entry); +/** + * dmub_srv_get_diagnostic_data() - Get diagnostic data from the DMUB. + * @dmub: the dmub service + * + * Returns: + * true - if the diagnostic data was successfully retrieved + * false - otherwise + */ bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub); bool dmub_srv_should_detect(struct dmub_srv *dmub); @@ -1151,4 +1191,12 @@ bool dmub_srv_get_preos_info(struct dmub_srv *dmub); enum dmub_status dmub_srv_get_fw_meta_info_from_raw_fw(struct dmub_srv_fw_meta_info_params *params, struct dmub_fw_meta_info *fw_info_out); +/** + * dmub_srv_get_trace_snapshot() - Fetch the latest trace entries from the DMCUB trace buffer + * @dmub: the dmub service + * @trace_snapshot: output buffer for trace entries + * + */ +void dmub_srv_get_trace_snapshot(struct dmub_srv *dmub, struct dmub_trace_snapshot *trace_snapshot); + #endif /* _DMUB_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c index 0b152926f75b..08c23ca47094 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c @@ -416,72 +416,68 @@ uint32_t dmub_dcn20_get_current_time(struct dmub_srv *dmub) return REG_READ(DMCUB_TIMER_CURRENT); } -void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub) +void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data) { uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset; uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; - struct dmub_timeout_info timeout = {0}; - if (!dmub) + if (!dmub || !hw_data) return; - /* timeout data filled externally, cache before resetting memory */ - timeout = dmub->debug.timeout_info; - memset(&dmub->debug, 0, sizeof(dmub->debug)); - dmub->debug.timeout_info = timeout; + memset(hw_data, 0, sizeof(*hw_data)); - dmub->debug.dmcub_version = dmub->fw_version; + hw_data->dmcub_version = dmub->fw_version; - dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); - dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); - dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); - dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); - dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); - dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); - dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); - dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); - dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); - dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); - dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); - dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); - dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); - dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); - dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); - dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); + hw_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + hw_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + hw_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + hw_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + hw_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + hw_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + hw_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + hw_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + hw_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + hw_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + hw_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + hw_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + hw_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + hw_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + hw_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + hw_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); - dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); - dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); - dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + hw_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + hw_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + hw_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); - dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); - dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); - dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + hw_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + hw_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + hw_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); - dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); - dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); - dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + hw_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + hw_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + hw_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); ASSERT(is_dmub_enabled <= 0xFF); - dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; + hw_data->is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_SOFT_RESET, &is_soft_reset); ASSERT(is_soft_reset <= 0xFF); - dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; + hw_data->is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); ASSERT(is_sec_reset <= 0xFF); - dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; + hw_data->is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); ASSERT(is_traceport_enabled <= 0xFF); - dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; + hw_data->is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); ASSERT(is_cw0_enabled <= 0xFF); - dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; + hw_data->is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); ASSERT(is_cw6_enabled <= 0xFF); - dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; + hw_data->is_cw6_enabled = (uint8_t)is_cw6_enabled; } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h index 42c1fb4bc73f..fd89d341573b 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h @@ -247,6 +247,6 @@ bool dmub_dcn20_use_cached_trace_buffer(struct dmub_srv *dmub); uint32_t dmub_dcn20_get_current_time(struct dmub_srv *dmub); -void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub); +void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); #endif /* _DMUB_DCN20_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c index 478d79a6e246..cd0ba8d41357 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -418,82 +418,78 @@ uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub) return REG_READ(DMCUB_TIMER_CURRENT); } -void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub) +void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data) { uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset, is_pwait; uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; - struct dmub_timeout_info timeout = {0}; - if (!dmub) + if (!dmub || !hw_data) return; - /* timeout data filled externally, cache before resetting memory */ - timeout = dmub->debug.timeout_info; - memset(&dmub->debug, 0, sizeof(dmub->debug)); - dmub->debug.timeout_info = timeout; + memset(hw_data, 0, sizeof(*hw_data)); - dmub->debug.dmcub_version = dmub->fw_version; + hw_data->dmcub_version = dmub->fw_version; - dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); - dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); - dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); - dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); - dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); - dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); - dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); - dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); - dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); - dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); - dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); - dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); - dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); - dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); - dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); - dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); + hw_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + hw_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + hw_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + hw_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + hw_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + hw_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + hw_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + hw_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + hw_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + hw_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + hw_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + hw_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + hw_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + hw_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + hw_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + hw_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); - dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); - dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); - dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + hw_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + hw_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + hw_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); - dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); - dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); - dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + hw_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + hw_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + hw_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); - dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); - dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); - dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + hw_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + hw_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + hw_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); - dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); - dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); - dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); + hw_data->outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); + hw_data->outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); + hw_data->outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); ASSERT(is_dmub_enabled <= 0xFF); - dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; + hw_data->is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); ASSERT(is_pwait <= 0xFF); - dmub->debug.is_pwait = (uint8_t)is_pwait; + hw_data->is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); ASSERT(is_soft_reset <= 0xFF); - dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; + hw_data->is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); ASSERT(is_sec_reset <= 0xFF); - dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; + hw_data->is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); ASSERT(is_traceport_enabled <= 0xFF); - dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; + hw_data->is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); ASSERT(is_cw0_enabled <= 0xFF); - dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; + hw_data->is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); ASSERT(is_cw6_enabled <= 0xFF); - dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; + hw_data->is_cw6_enabled = (uint8_t)is_cw6_enabled; } bool dmub_dcn31_should_detect(struct dmub_srv *dmub) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h index 1c43ef2bca66..ec878c58d09b 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h @@ -251,7 +251,7 @@ void dmub_dcn31_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub); -void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub); +void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); bool dmub_dcn31_should_detect(struct dmub_srv *dmub); diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c index 3f9fb9e05b79..0d585dc63364 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c @@ -437,77 +437,73 @@ uint32_t dmub_dcn32_get_current_time(struct dmub_srv *dmub) return REG_READ(DMCUB_TIMER_CURRENT); } -void dmub_dcn32_get_diagnostic_data(struct dmub_srv *dmub) +void dmub_dcn32_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data) { uint32_t is_dmub_enabled, is_soft_reset, is_pwait; uint32_t is_traceport_enabled, is_cw6_enabled; - struct dmub_timeout_info timeout = {0}; - if (!dmub) + if (!dmub || !hw_data) return; - /* timeout data filled externally, cache before resetting memory */ - timeout = dmub->debug.timeout_info; - memset(&dmub->debug, 0, sizeof(dmub->debug)); - dmub->debug.timeout_info = timeout; + memset(hw_data, 0, sizeof(*hw_data)); - dmub->debug.dmcub_version = dmub->fw_version; + hw_data->dmcub_version = dmub->fw_version; - dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); - dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); - dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); - dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); - dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); - dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); - dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); - dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); - dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); - dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); - dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); - dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); - dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); - dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); - dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); - dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); - dmub->debug.scratch[16] = REG_READ(DMCUB_SCRATCH16); + hw_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + hw_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + hw_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + hw_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + hw_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + hw_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + hw_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + hw_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + hw_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + hw_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + hw_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + hw_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + hw_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + hw_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + hw_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + hw_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + hw_data->scratch[16] = REG_READ(DMCUB_SCRATCH16); - dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); - dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); - dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + hw_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + hw_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + hw_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); - dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); - dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); - dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + hw_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + hw_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + hw_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); - dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); - dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); - dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + hw_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + hw_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + hw_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); - dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); - dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); - dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); + hw_data->outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); + hw_data->outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); + hw_data->outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); ASSERT(is_dmub_enabled <= 0xFF); - dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; + hw_data->is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); ASSERT(is_pwait <= 0xFF); - dmub->debug.is_pwait = (uint8_t)is_pwait; + hw_data->is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); ASSERT(is_soft_reset <= 0xFF); - dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; + hw_data->is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); ASSERT(is_traceport_enabled <= 0xFF); - dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; + hw_data->is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); ASSERT(is_cw6_enabled <= 0xFF); - dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; + hw_data->is_cw6_enabled = (uint8_t)is_cw6_enabled; - dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); + hw_data->gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } void dmub_dcn32_configure_dmub_in_system_memory(struct dmub_srv *dmub) { diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.h index daf81027d663..ccf849e07b38 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.h @@ -260,7 +260,7 @@ void dmub_dcn32_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); uint32_t dmub_dcn32_get_current_time(struct dmub_srv *dmub); -void dmub_dcn32_get_diagnostic_data(struct dmub_srv *dmub); +void dmub_dcn32_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); void dmub_dcn32_configure_dmub_in_system_memory(struct dmub_srv *dmub); void dmub_dcn32_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data); diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c index 69fb6084232e..bd7637276aa6 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c @@ -458,77 +458,73 @@ uint32_t dmub_dcn35_get_current_time(struct dmub_srv *dmub) return REG_READ(DMCUB_TIMER_CURRENT); } -void dmub_dcn35_get_diagnostic_data(struct dmub_srv *dmub) +void dmub_dcn35_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data) { uint32_t is_dmub_enabled, is_soft_reset, is_pwait; uint32_t is_traceport_enabled, is_cw6_enabled; - struct dmub_timeout_info timeout = {0}; - if (!dmub) + if (!dmub || !hw_data) return; - /* timeout data filled externally, cache before resetting memory */ - timeout = dmub->debug.timeout_info; - memset(&dmub->debug, 0, sizeof(dmub->debug)); - dmub->debug.timeout_info = timeout; + memset(hw_data, 0, sizeof(*hw_data)); - dmub->debug.dmcub_version = dmub->fw_version; + hw_data->dmcub_version = dmub->fw_version; - dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); - dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); - dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); - dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); - dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); - dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); - dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); - dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); - dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); - dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); - dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); - dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); - dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); - dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); - dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); - dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); - dmub->debug.scratch[16] = REG_READ(DMCUB_SCRATCH16); + hw_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + hw_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + hw_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + hw_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + hw_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + hw_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + hw_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + hw_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + hw_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + hw_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + hw_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + hw_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + hw_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + hw_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + hw_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + hw_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + hw_data->scratch[16] = REG_READ(DMCUB_SCRATCH16); - dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); - dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); - dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + hw_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + hw_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + hw_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); - dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); - dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); - dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + hw_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + hw_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + hw_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); - dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); - dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); - dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + hw_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + hw_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + hw_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); - dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); - dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); - dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); + hw_data->outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); + hw_data->outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); + hw_data->outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); ASSERT(is_dmub_enabled <= 0xFF); - dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; + hw_data->is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); ASSERT(is_pwait <= 0xFF); - dmub->debug.is_pwait = (uint8_t)is_pwait; + hw_data->is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); ASSERT(is_soft_reset <= 0xFF); - dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; + hw_data->is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); ASSERT(is_traceport_enabled <= 0xFF); - dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; + hw_data->is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); ASSERT(is_cw6_enabled <= 0xFF); - dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; + hw_data->is_cw6_enabled = (uint8_t)is_cw6_enabled; - dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); + hw_data->gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } bool dmub_dcn35_get_preos_fw_info(struct dmub_srv *dmub) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.h index 92e6695a2c9b..869095284993 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.h @@ -269,7 +269,7 @@ void dmub_dcn35_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); uint32_t dmub_dcn35_get_current_time(struct dmub_srv *dmub); -void dmub_dcn35_get_diagnostic_data(struct dmub_srv *dmub); +void dmub_dcn35_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); void dmub_dcn35_configure_dmub_in_system_memory(struct dmub_srv *dmub); diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c index 3444eb7d7d81..02ab26516584 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c @@ -423,85 +423,81 @@ uint32_t dmub_dcn401_get_current_time(struct dmub_srv *dmub) return REG_READ(DMCUB_TIMER_CURRENT); } -void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub) +void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data) { uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset, is_pwait; uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; - struct dmub_timeout_info timeout = {0}; - if (!dmub) + if (!dmub || !hw_data) return; - /* timeout data filled externally, cache before resetting memory */ - timeout = dmub->debug.timeout_info; - memset(&dmub->debug, 0, sizeof(dmub->debug)); - dmub->debug.timeout_info = timeout; + memset(hw_data, 0, sizeof(*hw_data)); - dmub->debug.dmcub_version = dmub->fw_version; + hw_data->dmcub_version = dmub->fw_version; - dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); - dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); - dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); - dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); - dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); - dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); - dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); - dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); - dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); - dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); - dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); - dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); - dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); - dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); - dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); - dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); - dmub->debug.scratch[16] = REG_READ(DMCUB_SCRATCH16); + hw_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + hw_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + hw_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + hw_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + hw_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + hw_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + hw_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + hw_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + hw_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + hw_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + hw_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + hw_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + hw_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + hw_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + hw_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + hw_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + hw_data->scratch[16] = REG_READ(DMCUB_SCRATCH16); - dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); - dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); - dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + hw_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + hw_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + hw_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); - dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); - dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); - dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + hw_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + hw_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + hw_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); - dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); - dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); - dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + hw_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + hw_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + hw_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); - dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); - dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); - dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); + hw_data->outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); + hw_data->outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); + hw_data->outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); ASSERT(is_dmub_enabled <= 0xFF); - dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; + hw_data->is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); ASSERT(is_pwait <= 0xFF); - dmub->debug.is_pwait = (uint8_t)is_pwait; + hw_data->is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); ASSERT(is_soft_reset <= 0xFF); - dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; + hw_data->is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); ASSERT(is_sec_reset <= 0xFF); - dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; + hw_data->is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); ASSERT(is_traceport_enabled <= 0xFF); - dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; + hw_data->is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); ASSERT(is_cw0_enabled <= 0xFF); - dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; + hw_data->is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); ASSERT(is_cw6_enabled <= 0xFF); - dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; + hw_data->is_cw6_enabled = (uint8_t)is_cw6_enabled; - dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); + hw_data->gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } void dmub_dcn401_configure_dmub_in_system_memory(struct dmub_srv *dmub) { diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h index 88c3a44d67d9..de7840d93592 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h @@ -264,7 +264,7 @@ void dmub_dcn401_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); uint32_t dmub_dcn401_get_current_time(struct dmub_srv *dmub); -void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub); +void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); void dmub_dcn401_configure_dmub_in_system_memory(struct dmub_srv *dmub); void dmub_dcn401_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data); diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c index e86fcfc74985..53e70c682a77 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c @@ -626,85 +626,81 @@ uint32_t dmub_dcn42_get_current_time(struct dmub_srv *dmub) return REG_READ(DMCUB_TIMER_CURRENT); } -void dmub_dcn42_get_diagnostic_data(struct dmub_srv *dmub) +void dmub_dcn42_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data) { uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset, is_pwait; uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; - struct dmub_timeout_info timeout = {0}; - if (!dmub) + if (!dmub || !hw_data) return; - /* timeout data filled externally, cache before resetting memory */ - timeout = dmub->debug.timeout_info; - memset(&dmub->debug, 0, sizeof(dmub->debug)); - dmub->debug.timeout_info = timeout; + memset(hw_data, 0, sizeof(*hw_data)); - dmub->debug.dmcub_version = dmub->fw_version; + hw_data->dmcub_version = dmub->fw_version; - dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); - dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); - dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); - dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); - dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); - dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); - dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); - dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); - dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); - dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); - dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); - dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); - dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); - dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); - dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); - dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); - dmub->debug.scratch[16] = REG_READ(DMCUB_SCRATCH16); + hw_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + hw_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + hw_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + hw_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + hw_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + hw_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + hw_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + hw_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + hw_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + hw_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + hw_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + hw_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + hw_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + hw_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + hw_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + hw_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + hw_data->scratch[16] = REG_READ(DMCUB_SCRATCH16); - dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); - dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); - dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + hw_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + hw_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + hw_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); - dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); - dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); - dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + hw_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + hw_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + hw_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); - dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); - dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); - dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + hw_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + hw_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + hw_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); - dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); - dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); - dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); + hw_data->outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); + hw_data->outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); + hw_data->outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); ASSERT(is_dmub_enabled <= 0xFF); - dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; + hw_data->is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); ASSERT(is_pwait <= 0xFF); - dmub->debug.is_pwait = (uint8_t)is_pwait; + hw_data->is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); ASSERT(is_soft_reset <= 0xFF); - dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; + hw_data->is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); ASSERT(is_sec_reset <= 0xFF); - dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; + hw_data->is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); ASSERT(is_traceport_enabled <= 0xFF); - dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; + hw_data->is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); ASSERT(is_cw0_enabled <= 0xFF); - dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; + hw_data->is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); ASSERT(is_cw6_enabled <= 0xFF); - dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; + hw_data->is_cw6_enabled = (uint8_t)is_cw6_enabled; - dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); + hw_data->gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } bool dmub_dcn42_get_preos_fw_info(struct dmub_srv *dmub) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h index c53f7691d1a8..c879e94272d7 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h @@ -297,7 +297,7 @@ union dmub_fw_boot_options dmub_dcn42_get_fw_boot_option(struct dmub_srv *dmub); /* Timing and diagnostics */ uint32_t dmub_dcn42_get_current_time(struct dmub_srv *dmub); -void dmub_dcn42_get_diagnostic_data(struct dmub_srv *dmub); +void dmub_dcn42_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); bool dmub_dcn42_get_preos_fw_info(struct dmub_srv *dmub); #endif /* _DMUB_DCN42_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.c index 5c524f8d3fdf..8c3cc51c07a3 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.c @@ -469,85 +469,81 @@ uint32_t dmub_dcn60_get_current_time(struct dmub_srv *dmub) return REG_READ(DMCUB_TIMER_CURRENT); } -void dmub_dcn60_get_diagnostic_data(struct dmub_srv *dmub) +void dmub_dcn60_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data) { uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset, is_pwait; uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; - struct dmub_timeout_info timeout = {0}; - if (!dmub) + if (!dmub || !hw_data) return; - /* timeout data filled externally, cache before resetting memory */ - timeout = dmub->debug.timeout_info; - memset(&dmub->debug, 0, sizeof(dmub->debug)); - dmub->debug.timeout_info = timeout; + memset(hw_data, 0, sizeof(*hw_data)); - dmub->debug.dmcub_version = dmub->fw_version; + hw_data->dmcub_version = dmub->fw_version; - dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); - dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); - dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); - dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); - dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); - dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); - dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); - dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); - dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); - dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); - dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); - dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); - dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); - dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); - dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); - dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); - dmub->debug.scratch[16] = REG_READ(DMCUB_SCRATCH16); + hw_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + hw_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + hw_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + hw_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + hw_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + hw_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + hw_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + hw_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + hw_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + hw_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + hw_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + hw_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + hw_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + hw_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + hw_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + hw_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + hw_data->scratch[16] = REG_READ(DMCUB_SCRATCH16); - dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); - dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); - dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + hw_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + hw_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + hw_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); - dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); - dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); - dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + hw_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + hw_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + hw_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); - dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); - dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); - dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + hw_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + hw_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + hw_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); - dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); - dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); - dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); + hw_data->outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); + hw_data->outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); + hw_data->outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); ASSERT(is_dmub_enabled <= 0xFF); - dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; + hw_data->is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); ASSERT(is_pwait <= 0xFF); - dmub->debug.is_pwait = (uint8_t)is_pwait; + hw_data->is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); ASSERT(is_soft_reset <= 0xFF); - dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; + hw_data->is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); ASSERT(is_sec_reset <= 0xFF); - dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; + hw_data->is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); ASSERT(is_traceport_enabled <= 0xFF); - dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; + hw_data->is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); ASSERT(is_cw0_enabled <= 0xFF); - dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; + hw_data->is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); ASSERT(is_cw6_enabled <= 0xFF); - dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; + hw_data->is_cw6_enabled = (uint8_t)is_cw6_enabled; - dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); + hw_data->gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } void dmub_dcn60_configure_dmub_in_system_memory(struct dmub_srv *dmub) { diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.h index 5007ed1c19d7..238cba46d366 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn60.h @@ -277,7 +277,7 @@ void dmub_dcn60_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); uint32_t dmub_dcn60_get_current_time(struct dmub_srv *dmub); -void dmub_dcn60_get_diagnostic_data(struct dmub_srv *dmub); +void dmub_dcn60_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_hw_diagnostic_data *hw_data); void dmub_dcn60_configure_dmub_in_system_memory(struct dmub_srv *dmub); void dmub_dcn60_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data); diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index dd868e38e0b0..41b14b137643 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -1315,11 +1315,63 @@ bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entr return dmub_rb_out_trace_buffer_front(&dmub->outbox0_rb, (void *)entry); } +void dmub_srv_get_trace_snapshot(struct dmub_srv *dmub, struct dmub_trace_snapshot *trace_snapshot) +{ + const unsigned int snapshot_max_entry_count = + sizeof(trace_snapshot->traces) / sizeof(struct dmcub_trace_buf_entry); + + struct dmub_trace_buf_header *trace_buf_header; + struct dmcub_trace_buf_entry *trace_buf; + unsigned int trace_buf_max_entry_count; + unsigned int entry_count, start_idx, first_chunk_entry_count; + + if (!dmub || !dmub->fb_info || !trace_snapshot) + return; + + // capture last trace entries from the DMCUB trace buffer + trace_buf_header = (struct dmub_trace_buf_header *)dmub->fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].cpu_addr; + trace_buf_max_entry_count = dmub->fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].size == 0 ? 0 : + (dmub->fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].size - + sizeof(struct dmub_trace_buf_header)) / + sizeof(struct dmcub_trace_buf_entry); + trace_buf_max_entry_count = trace_buf_max_entry_count > DMUB_TRACE_BUFFER_SIZE ? + DMUB_TRACE_BUFFER_SIZE : trace_buf_max_entry_count; + + if (trace_buf_header && trace_buf_max_entry_count > 0) { + entry_count = trace_buf_header->entry_count; + start_idx = 0; + if (entry_count >= snapshot_max_entry_count) { + start_idx = (entry_count - snapshot_max_entry_count) % trace_buf_max_entry_count; + } + + trace_buf = (struct dmcub_trace_buf_entry *)(trace_buf_header + 1); + + if (start_idx + snapshot_max_entry_count <= trace_buf_max_entry_count) { + // contiguous + memcpy(trace_snapshot->traces, + &trace_buf[start_idx], + sizeof(struct dmcub_trace_buf_entry) * snapshot_max_entry_count); + } else { + // wraparound case + first_chunk_entry_count = trace_buf_max_entry_count - start_idx; + + memcpy(trace_snapshot->traces, + &trace_buf[start_idx], + sizeof(struct dmcub_trace_buf_entry) * first_chunk_entry_count); + memcpy(&trace_snapshot->traces[first_chunk_entry_count], + &trace_buf[0], + sizeof(struct dmcub_trace_buf_entry) * (snapshot_max_entry_count - first_chunk_entry_count)); + } + } +} + bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub) { if (!dmub || !dmub->hw_funcs.get_diagnostic_data) return false; - dmub->hw_funcs.get_diagnostic_data(dmub); + + dmub->hw_funcs.get_diagnostic_data(dmub, &dmub->debug.hw); + dmub_srv_get_trace_snapshot(dmub, &dmub->debug.trace_snapshot); return true; } From 972dc9b7c107648ce5087aea2963e5fce4c39547 Mon Sep 17 00:00:00 2001 From: Matthew Stewart Date: Wed, 9 Sep 2026 16:10:56 -0400 Subject: [PATCH 072/103] drm/amd/display: Fix DCN42B plane alpha Like DCN42, the alpha field is 12 bits compared to the 16 bit value in plane_state; must convert it. Reviewed-by: Gabe Teeger Signed-off-by: Matthew Stewart Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 2f88b9d65b82..eb17d3d7d3c6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -147,6 +147,7 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state * 16-bit, so scale it down to the width the hardware expects. */ if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) + || amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) || amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(6, 0, 0)) *global_alpha_value = plane_state->alpha >> 4; else From c7a6a646807b3c210474a4f3c7c296d22e7e5ef1 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:10 -0600 Subject: [PATCH 073/103] drm/amd/display: Fix KUnit connector warnings [WHY] Connector mode population without mode_config.mutex produces warning stack traces. Legacy property reads also warn on atomic DRM devices. [HOW] Lock mode-population calls and release the mutex before assertions. Read stored property values with the atomic-compatible default getter. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../tests/amdgpu_dm_connector_test.c | 53 +++++++++++++++---- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c index 8117aaf41f22..e049d1a32979 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c @@ -2735,7 +2735,7 @@ static void dm_test_update_subconnector_dp_with_sink(struct kunit *test) update_subconnector_property(aconnector); - KUNIT_EXPECT_EQ(test, drm_object_property_get_value(&aconnector->base.base, + KUNIT_EXPECT_EQ(test, drm_object_property_get_default_value(&aconnector->base.base, aconnector->base.dev->mode_config.dp_subconnector_property, &val), 0); KUNIT_EXPECT_EQ(test, (int)val, (int)DRM_MODE_SUBCONNECTOR_VGA); @@ -2778,7 +2778,7 @@ static void dm_test_update_subconnector_dp_no_sink(struct kunit *test) update_subconnector_property(aconnector); - KUNIT_EXPECT_EQ(test, drm_object_property_get_value(&aconnector->base.base, + KUNIT_EXPECT_EQ(test, drm_object_property_get_default_value(&aconnector->base.base, aconnector->base.dev->mode_config.dp_subconnector_property, &val), 0); KUNIT_EXPECT_EQ(test, (int)val, (int)DRM_MODE_SUBCONNECTOR_Unknown); @@ -2827,7 +2827,7 @@ static void dm_test_update_subconnector_non_dp_noop(struct kunit *test) update_subconnector_property(aconnector); /* Non-DP connector: value must remain what we seeded */ - KUNIT_EXPECT_EQ(test, drm_object_property_get_value(&aconnector->base.base, + KUNIT_EXPECT_EQ(test, drm_object_property_get_default_value(&aconnector->base.base, aconnector->base.dev->mode_config.dp_subconnector_property, &val), 0); KUNIT_EXPECT_EQ(test, (int)val, (int)DRM_MODE_SUBCONNECTOR_VGA); @@ -3339,7 +3339,7 @@ static uint64_t dm_test_panel_prop_value(struct kunit *test, uint64_t val = ~0ULL; KUNIT_EXPECT_EQ(test, - drm_object_property_get_value(&ctx->aconnector->base.base, + drm_object_property_get_default_value(&ctx->aconnector->base.base, ctx->drm->mode_config.panel_type_property, &val), 0); return val; } @@ -5733,9 +5733,11 @@ static void dm_test_native_mode_copies_preferred(struct kunit *test) mode->clock = 148500; mode->hdisplay = 1920; mode->vdisplay = 1080; + mutex_lock(&ctx->drm->mode_config.mutex); drm_mode_probed_add(&ctx->aconnector->base, mode); amdgpu_dm_get_native_mode(&ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); KUNIT_EXPECT_EQ(test, ctx->aenc->native_mode.hdisplay, 1920); KUNIT_EXPECT_EQ(test, ctx->aenc->native_mode.vdisplay, 1080); @@ -5788,8 +5790,10 @@ static void dm_test_add_common_modes_non_edp_noop(struct kunit *test) ctx->aenc->native_mode.hdisplay = 1920; ctx->aenc->native_mode.vdisplay = 1200; + mutex_lock(&ctx->drm->mode_config.mutex); amdgpu_dm_connector_add_common_modes(&ctx->aenc->base, &ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 0); } @@ -5809,8 +5813,10 @@ static void dm_test_add_common_modes_edp_adds(struct kunit *test) ctx->aenc->native_mode.hdisplay = 1920; ctx->aenc->native_mode.vdisplay = 1200; + mutex_lock(&ctx->drm->mode_config.mutex); amdgpu_dm_connector_add_common_modes(&ctx->aenc->base, &ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 10); } @@ -5887,12 +5893,18 @@ static struct amdgpu_dm_connector *dm_test_fs_setup(struct kunit *test) static void dm_test_add_fs_modes_generates(struct kunit *test) { struct amdgpu_dm_connector *aconnector = dm_test_fs_setup(test); + unsigned int count, duplicate_count; aconnector->min_vfreq = 20; aconnector->max_vfreq = 60; - KUNIT_EXPECT_EQ(test, (int)add_fs_modes(aconnector), 8); - KUNIT_EXPECT_EQ(test, (int)add_fs_modes(aconnector), 0); + mutex_lock(&aconnector->base.dev->mode_config.mutex); + count = add_fs_modes(aconnector); + duplicate_count = add_fs_modes(aconnector); + mutex_unlock(&aconnector->base.dev->mode_config.mutex); + + KUNIT_EXPECT_EQ(test, count, 8); + KUNIT_EXPECT_EQ(test, duplicate_count, 0); } /** @@ -8010,9 +8022,13 @@ static void dm_test_get_modes_noedid_default(struct kunit *test) { struct dm_test_gm_ctx *ctx = dm_test_gm_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort); + int count; - KUNIT_EXPECT_GT(test, - amdgpu_dm_connector_get_modes(&ctx->aconnector->base), 0); + mutex_lock(&ctx->drm->mode_config.mutex); + count = amdgpu_dm_connector_get_modes(&ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); + + KUNIT_EXPECT_GT(test, count, 0); } /** @@ -8028,10 +8044,12 @@ static void dm_test_get_modes_noedid_128b_adds_more(struct kunit *test) dm_test_gm_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort); int n_8b, n_128b; + mutex_lock(&ctx->drm->mode_config.mutex); n_8b = amdgpu_dm_connector_get_modes(&ctx->aconnector->base); ctx->link_srv->dp_get_encoding_format = dm_test_gm_enc_128b; n_128b = amdgpu_dm_connector_get_modes(&ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); KUNIT_EXPECT_GT(test, n_128b, n_8b); } @@ -8050,7 +8068,9 @@ static void dm_test_get_modes_noedid_analog_adds_common(struct kunit *test) struct dc_sink *sink; int n_base, n_analog; + mutex_lock(&ctx->drm->mode_config.mutex); n_base = amdgpu_dm_connector_get_modes(&ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, sink); @@ -8058,7 +8078,9 @@ static void dm_test_get_modes_noedid_analog_adds_common(struct kunit *test) ctx->aconnector->dc_sink = sink; ctx->link->link_id.id = CONNECTOR_ID_VGA; + mutex_lock(&ctx->drm->mode_config.mutex); n_analog = amdgpu_dm_connector_get_modes(&ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); KUNIT_EXPECT_GT(test, n_analog, n_base); } @@ -8075,6 +8097,7 @@ static void dm_test_get_modes_with_edid(struct kunit *test) struct dm_test_gm_ctx *ctx = dm_test_gm_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP); const struct drm_edid *drm_edid; + int count; drm_edid = drm_edid_alloc(dm_test_uad_edid, sizeof(dm_test_uad_edid)); KUNIT_ASSERT_NOT_NULL(test, drm_edid); @@ -8084,8 +8107,11 @@ static void dm_test_get_modes_with_edid(struct kunit *test) ctx->aenc->native_mode.hdisplay = 1920; ctx->aenc->native_mode.vdisplay = 1200; - KUNIT_EXPECT_GT(test, - amdgpu_dm_connector_get_modes(&ctx->aconnector->base), 0); + mutex_lock(&ctx->drm->mode_config.mutex); + count = amdgpu_dm_connector_get_modes(&ctx->aconnector->base); + mutex_unlock(&ctx->drm->mode_config.mutex); + + KUNIT_EXPECT_GT(test, count, 0); drm_edid_free(drm_edid); ctx->aconnector->drm_edid = NULL; @@ -9607,6 +9633,7 @@ static void dm_test_conn_init_get_modes_hook(struct kunit *test) dm_test_conn_init_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A); const struct drm_connector_helper_funcs *helper; struct drm_connector *connector = &ctx->aconnector->base; + int count; KUNIT_ASSERT_EQ(test, amdgpu_dm_connector_init(ctx->dm, ctx->aconnector, 0, @@ -9616,7 +9643,11 @@ static void dm_test_conn_init_get_modes_hook(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, helper); KUNIT_ASSERT_NOT_NULL(test, helper->get_modes); - KUNIT_EXPECT_GT(test, helper->get_modes(connector), 0); + mutex_lock(&ctx->drm->mode_config.mutex); + count = helper->get_modes(connector); + mutex_unlock(&ctx->drm->mode_config.mutex); + + KUNIT_EXPECT_GT(test, count, 0); KUNIT_EXPECT_GT(test, ctx->aconnector->num_modes, 0); } From cbb329ca3b386399fb33947275cf3368890ad23a Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:10 -0600 Subject: [PATCH 074/103] drm/amd/display: Fix KUnit CRTC warnings [WHY] Incomplete CRTC callbacks and vblank teardown cause DRM warnings in CRTC tests. [HOW] Provide the required CRTC callbacks, link fake CRTCs for vblank lookup, and register cleanup actions to disable vblank before unlinking them. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_crtc_test.c | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c index 4668dc362544..e4396ad8934e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c @@ -877,10 +877,39 @@ static bool dm_test_crtc_get_vblank_timestamp(struct drm_crtc *crtc, return false; } +static int dm_test_crtc_enable_vblank(struct drm_crtc *crtc) +{ + return 0; +} + +static void dm_test_crtc_disable_vblank(struct drm_crtc *crtc) +{ +} + +static u32 dm_test_crtc_get_vblank_counter(struct drm_crtc *crtc) +{ + return 0; +} + static const struct drm_crtc_funcs dm_test_crtc_funcs = { + .destroy = amdgpu_dm_crtc_destroy, + .atomic_duplicate_state = amdgpu_dm_crtc_duplicate_state, + .atomic_destroy_state = amdgpu_dm_crtc_destroy_state, + .enable_vblank = dm_test_crtc_enable_vblank, + .disable_vblank = dm_test_crtc_disable_vblank, + .get_vblank_counter = dm_test_crtc_get_vblank_counter, .get_vblank_timestamp = dm_test_crtc_get_vblank_timestamp, }; +static void dm_test_crtc_cleanup(void *data) +{ + struct amdgpu_crtc *acrtc = data; + + if (acrtc->base.dev && drm_dev_has_vblank(acrtc->base.dev)) + drm_crtc_vblank_off(&acrtc->base); + list_del_init(&acrtc->base.head); +} + /* * dm_test_crtc_arm_irq_src - Prime an IRQ source so get()/put() short-circuit. * @test: The KUnit test context @@ -947,8 +976,13 @@ dm_test_crtc_setup_enable(struct kunit *test, struct amdgpu_device **adev_out, acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; + acrtc->base.funcs = &dm_test_crtc_funcs; acrtc->base.enabled = true; acrtc->crtc_id = 0; + INIT_LIST_HEAD(&acrtc->base.head); + list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list); + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, dm_test_crtc_cleanup, acrtc), 0); link = dm_kunit_alloc_link(test); stream = dm_kunit_alloc_stream(test, link); @@ -1782,6 +1816,11 @@ static void dm_test_crtc_handle_vblank_skips_when_flip_submitted(struct kunit *t KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); acrtc->base.dev = &adev->ddev; + acrtc->base.funcs = &dm_test_crtc_funcs; + INIT_LIST_HEAD(&acrtc->base.head); + list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list); + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, dm_test_crtc_cleanup, acrtc), 0); acrtc->event = event; acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; @@ -1818,6 +1857,11 @@ static void dm_test_crtc_handle_vblank_completes_cursor_only(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); acrtc->base.dev = &adev->ddev; + acrtc->base.funcs = &dm_test_crtc_funcs; + INIT_LIST_HEAD(&acrtc->base.head); + list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list); + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, dm_test_crtc_cleanup, acrtc), 0); acrtc->event = event; acrtc->pflip_status = AMDGPU_FLIP_NONE; From 92900d4f381c30775158d255097dc52ad729b0bf Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:10 -0600 Subject: [PATCH 075/103] drm/amd/display: Fix KUnit cursor warning [WHY] The cursor offset test binds a CRTC without a framebuffer, triggering a plane-state consistency warning before the intended offset check. [HOW] Provide a test framebuffer in the new plane state while retaining the invalid offset and its expected rejection. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c index 9026c6ce7336..2212451043fb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c @@ -365,6 +365,7 @@ static void dm_test_check_native_cursor_state_rejects_offset(struct kunit *test) struct amdgpu_device *adev = dm_kunit_alloc_adev(test); struct amdgpu_crtc *acrtc; struct drm_plane *plane; + struct drm_framebuffer *fb; struct drm_plane_state *old_plane_state; struct drm_plane_state *new_plane_state; int ret; @@ -373,6 +374,8 @@ static void dm_test_check_native_cursor_state_rejects_offset(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, acrtc); plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, plane); + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fb); old_plane_state = kunit_kzalloc(test, sizeof(*old_plane_state), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, old_plane_state); new_plane_state = kunit_kzalloc(test, sizeof(*new_plane_state), GFP_KERNEL); @@ -381,6 +384,7 @@ static void dm_test_check_native_cursor_state_rejects_offset(struct kunit *test) acrtc->base.dev = &adev->ddev; old_plane_state->crtc = &acrtc->base; new_plane_state->crtc = &acrtc->base; + new_plane_state->fb = fb; new_plane_state->src_x = 1; plane->state = old_plane_state; From 20f1647b4c3af9a1a6ea8d50c90a001aba1fb63a Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:10 -0600 Subject: [PATCH 076/103] drm/amd/display: Fix KUnit VRR warnings [WHY] The VRR transition test needs a discoverable CRTC and balanced vblank teardown. Assertion failures must not leave freed CRTCs linked. [HOW] Supply a vblank counter callback and link the test CRTC. Register a KUnit cleanup action to disable vblank and unlink it on every exit. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amdgpu_dm/tests/amdgpu_dm_freesync_test.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c index 82982553e8f3..5ad50bc31613 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c @@ -21,6 +21,23 @@ #include "amdgpu_dm_freesync.h" #include "amdgpu_dm_kunit_test_helpers.h" +static u32 dm_test_freesync_vblank_counter(struct drm_crtc *crtc) +{ + return 0; +} + +static const struct drm_crtc_funcs dm_test_freesync_crtc_funcs = { + .get_vblank_counter = dm_test_freesync_vblank_counter, +}; + +static void dm_test_freesync_crtc_cleanup(void *data) +{ + struct amdgpu_crtc *acrtc = data; + + drm_crtc_vblank_off(&acrtc->base); + list_del_init(&acrtc->base.head); +} + /* Tests for amdgpu_dm_is_timing_unchanged_for_freesync() */ /** @@ -782,6 +799,11 @@ static void dm_test_handle_vrr_transition_round_trip(struct kunit *test) acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; + acrtc->base.funcs = &dm_test_freesync_crtc_funcs; + INIT_LIST_HEAD(&acrtc->base.head); + list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list); + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, dm_test_freesync_crtc_cleanup, acrtc), 0); acrtc->otg_inst = -1; vblank = drm_crtc_vblank_crtc(&acrtc->base); adev->ddev.vblank[0].enabled = true; From fa165dd5903270579577ffb48aedf92b49178a03 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:10 -0600 Subject: [PATCH 077/103] drm/amd/display: Fix KUnit helper warnings [WHY] The real connector fixture lacks atomic state callbacks required by DRM connector initialization. [HOW] Install the DRM atomic connector duplicate and destroy state helpers alongside the existing reset callback. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c index 09eba15c2705..d37fe26eecea 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c @@ -4293,6 +4293,8 @@ static void dm_test_is_dp_sink_present_queries_link_service(struct kunit *test) */ static const struct drm_connector_funcs dm_test_connector_funcs = { .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static struct amdgpu_dm_connector *dm_test_alloc_real_connector(struct kunit *test, From 400b1961051f3fe3706677b44c53605526b04bc7 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:11 -0600 Subject: [PATCH 078/103] drm/amd/display: Fix KUnit IRQ warnings [WHY] IRQ tests leave vblank active when removing their fake CRTCs, causing warnings during DRM device teardown. [HOW] Turn off initialized vblank before unlinking each test CRTC in the existing cleanup action. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index 13beaeb34de1..6e599657dac1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -480,6 +480,9 @@ static void dm_test_crtc_list_del(void *data) { struct amdgpu_crtc *acrtc = data; + if (acrtc->base.dev && drm_dev_has_vblank(acrtc->base.dev)) + drm_crtc_vblank_off(&acrtc->base); + list_del_init(&acrtc->base.head); } From 846b74b1bd1200e4940c166bcd5835e60929a723 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:11 -0600 Subject: [PATCH 079/103] drm/amd/display: Fix KUnit MST warnings [WHY] The MST add-connector fixture registers an unmanaged master connector but does not clean it up before its KUnit-owned storage is released. [HOW] Register a KUnit action after successful connector initialization to run drm_connector_cleanup before freeing the master connector. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c index 382eafab2d43..eafa3e6733a6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c @@ -1311,6 +1311,13 @@ struct dm_mst_test_add_ctx { struct dc_link *link; }; +static void dm_mst_test_cleanup_add_ctx(void *data) +{ + struct amdgpu_dm_connector *master = data; + + drm_connector_cleanup(&master->base); +} + /* * Stand in for amdgpu_display_modeset_create_props(), which the test module * cannot link against. Only the properties amdgpu_dm_connector_init_helper() @@ -1368,6 +1375,8 @@ static void dm_mst_test_init_add_ctx(struct kunit *test, struct dm_mst_test_add_ ret = drm_connector_init(drm, &ctx->master->base, &dm_mst_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, dm_mst_test_cleanup_add_ctx, ctx->master), 0); ctx->port = kunit_kzalloc(test, sizeof(*ctx->port), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, ctx->port); From 2e6d5212d4795ac818317b91823fe3c281135a60 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:11 -0600 Subject: [PATCH 080/103] drm/amd/display: Fix KUnit DM warnings [WHY] Vblank and interrupt-management tests need discoverable CRTCs with complete vblank callbacks and balanced teardown. [HOW] Add the callbacks, link the fake CRTCs, and register cleanup actions to disable vblank before unlinking. Pass the CRTC directly so cleanup does not reinterpret two different fixture types through one layout. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../display/amdgpu_dm/tests/amdgpu_dm_test.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c index e27f6e504395..4c6e9e5d4d72 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c @@ -1681,6 +1681,35 @@ struct dm_test_vblank_ctx { struct drm_pending_vblank_event *event; }; +static int dm_test_vblank_enable(struct drm_crtc *crtc) +{ + return 0; +} + +static void dm_test_vblank_disable(struct drm_crtc *crtc) +{ +} + +static u32 dm_test_vblank_counter(struct drm_crtc *crtc) +{ + return 0; +} + +static const struct drm_crtc_funcs dm_test_vblank_crtc_funcs = { + .enable_vblank = dm_test_vblank_enable, + .disable_vblank = dm_test_vblank_disable, + .get_vblank_counter = dm_test_vblank_counter, +}; + +static void dm_test_vblank_ctx_cleanup(void *data) +{ + struct amdgpu_crtc *acrtc = data; + + if (drm_dev_has_vblank(acrtc->base.dev)) + drm_crtc_vblank_off(&acrtc->base); + list_del_init(&acrtc->base.head); +} + /* * A CRTC with one active plane and a pending vblank event. There is no * initialised vblank, so drm_crtc_vblank_get() fails, which the function under @@ -1702,9 +1731,15 @@ static struct dm_test_vblank_ctx *dm_test_vblank_ctx_alloc(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, ctx->event); ctx->acrtc->base.dev = &ctx->adev->ddev; + ctx->acrtc->base.funcs = &dm_test_vblank_crtc_funcs; + INIT_LIST_HEAD(&ctx->acrtc->base.head); + list_add_tail(&ctx->acrtc->base.head, + &ctx->adev->ddev.mode_config.crtc_list); ctx->acrtc->base.state = &ctx->acrtc_state->base; ctx->acrtc_state->base.event = ctx->event; ctx->acrtc_state->active_planes = 1; + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, dm_test_vblank_ctx_cleanup, ctx->acrtc), 0); return ctx; } @@ -4186,7 +4221,13 @@ static struct dm_test_irq_mgmt_ctx *dm_test_irq_mgmt_ctx_alloc(struct kunit *tes ctx->adev->mode_info.num_crtc = 1; ctx->acrtc->base.dev = &ctx->adev->ddev; + ctx->acrtc->base.funcs = &dm_test_vblank_crtc_funcs; + INIT_LIST_HEAD(&ctx->acrtc->base.head); + list_add_tail(&ctx->acrtc->base.head, + &ctx->adev->ddev.mode_config.crtc_list); ctx->acrtc->crtc_id = 0; + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, dm_test_vblank_ctx_cleanup, ctx->acrtc), 0); ctx->acrtc_state->stream = dm_kunit_alloc_stream(test, NULL); timing = &ctx->acrtc_state->stream->timing; From 47a84adcade0000dbc05dbc90229f7adcea17618 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 10:28:11 -0600 Subject: [PATCH 081/103] drm/amd/display: Fix KUnit writeback warnings [WHY] Writeback mode tests call drm_mode_probed_add without holding mode_config.mutex, producing a warning for every generated mode. [HOW] Hold the mutex around writeback mode enumeration and release it before checking the returned count or inspecting the generated modes. Assisted-by: Copilot:GPT-6-Astra Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c index 03036f906385..4bc033fdfa97 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c @@ -418,7 +418,9 @@ static void dm_test_wb_get_modes_returns_modes(struct kunit *test) drmm_connector_init(drm, connector, &dm_wb_test_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL, NULL); + mutex_lock(&drm->mode_config.mutex); count = amdgpu_dm_wb_connector_get_modes(connector); + mutex_unlock(&drm->mode_config.mutex); /* drm_add_modes_noedid should return at least one mode */ KUNIT_EXPECT_GT(test, count, 0); @@ -453,7 +455,9 @@ static void dm_test_wb_get_modes_bounded_by_max(struct kunit *test) drmm_connector_init(drm, connector, &dm_wb_test_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL, NULL); + mutex_lock(&drm->mode_config.mutex); amdgpu_dm_wb_connector_get_modes(connector); + mutex_unlock(&drm->mode_config.mutex); /* All modes must fit within 3840x2160 */ list_for_each_entry(mode, &connector->probed_modes, head) { From e4dca268eea60bcae566262daecc5e067799528d Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Wed, 9 Sep 2026 20:26:03 -0400 Subject: [PATCH 082/103] drm/amd/display: Restore FreeSync VCP code check for HDMI/PCON sinks [WHAT] Folding the MCCS FreeSync checks into the do_mccs block dropped the other half of the original condition: the check that clears freesync_capable for HDMI or PCON-in-whitelist sinks that expose no EDID FreeSync VCP code. That check does not depend on the MCCS caps and must run regardless of do_mccs. As a result, when do_mccs is false such a sink without a FreeSync VCP code is still reported as FreeSync-capable. [HOW] Restore the VCP code check outside the do_mccs block so it is evaluated whether or not MCCS caps were read. Fixes: 115bf5ca318e ("drm/amd/display: Consult MCCS FreeSync cap only if requested & supported") Reviewed-by: Roman Li Reviewed-by: Alex Hung Signed-off-by: Fangzhi Zuo Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c index 31e9f029a707..2a63a1c9b79d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c @@ -3875,6 +3875,12 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, amdgpu_dm_connector->min_vfreq; } + /* HDMI/PCON without an EDID FreeSync VCP code is not FreeSync-capable. */ + if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || + as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) && + !sink->edid_caps.freesync_vcp_code) + freesync_capable = false; + /* Handle MCCS */ if (do_mccs) { dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); From a3e8dc37a616db6fddbae80a83f95a3ac9a949a7 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 10 Sep 2026 14:06:40 -0600 Subject: [PATCH 083/103] drm/amd/display: Fix KUnit checkpatch warnings [WHY] Clean up the AMDGPU DM KUnit tests after checkpatch reported an invalid sizeof(void) allocation, typed kzalloc patterns, and a repeated word in a kernel-doc summary. Clarify the test name that covers an active CRTC state transition. [HOW] - Use sizeof(cpu_ptr) for the fake CPU pointer allocation. - Replace typed kzalloc(sizeof(*object), ...) calls with kzalloc_obj(*object, ...) in the connector, IRQ, plane, and atomic-state tests. - Rename the CRTC active-state test and update its kernel-doc and suite registration. Assisted-by: Copilot:GPT-5.6-Luna Reviewed-by: Jerry Zuo Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c | 6 +++--- .../drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c | 2 +- .../amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c index e4396ad8934e..489dd56474b9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c @@ -42,10 +42,10 @@ static void dm_test_crtc_modeset_required_active_mode_changed(struct kunit *test } /** - * dm_test_crtc_modeset_required_active_active_changed - Test Crtc modeset required active active changed + * dm_test_crtc_modeset_required_active_state_changed - Test modeset required when the active state changes * @test: The KUnit test context */ -static void dm_test_crtc_modeset_required_active_active_changed(struct kunit *test) +static void dm_test_crtc_modeset_required_active_state_changed(struct kunit *test) { struct drm_crtc_state state = {}; @@ -2621,7 +2621,7 @@ static void dm_test_crtc_atomic_check_invalid_stream_fails(struct kunit *test) static struct kunit_case amdgpu_dm_crtc_tests[] = { /* amdgpu_dm_crtc_modeset_required */ KUNIT_CASE(dm_test_crtc_modeset_required_active_mode_changed), - KUNIT_CASE(dm_test_crtc_modeset_required_active_active_changed), + KUNIT_CASE(dm_test_crtc_modeset_required_active_state_changed), KUNIT_CASE(dm_test_crtc_modeset_required_active_connectors_changed), KUNIT_CASE(dm_test_crtc_modeset_required_inactive), KUNIT_CASE(dm_test_crtc_modeset_required_no_changes), diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index 776272cd93ae..7422e8ba9564 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -2448,7 +2448,7 @@ static void dm_test_plane_destroy_state_releases_resources(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, dc_plane_state); /* destroy_state frees the state itself, so use a plain allocation. */ - dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL); + dm_plane_state = kzalloc_obj(*dm_plane_state, GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, dm_plane_state); /* Hold an extra reference so the release does not free KUnit memory. */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c index 4ff430e4b23b..bdbceb83a8a8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c @@ -337,7 +337,7 @@ static int dm_test_gpu_mem_init(struct kunit *test) { void *cpu_ptr; - cpu_ptr = kunit_kzalloc(test, sizeof(*cpu_ptr), GFP_KERNEL); + cpu_ptr = kunit_kzalloc(test, sizeof(cpu_ptr), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, cpu_ptr); dm_test_bo_ctx = (struct dm_test_bo_ops_ctx) { From 4040f1c11cb1c3300fcd0a3f7c72c84de24d7a1a Mon Sep 17 00:00:00 2001 From: Rafal Ostrowski Date: Wed, 9 Sep 2026 11:12:47 +0200 Subject: [PATCH 084/103] drm/amd/display: Drop pipe_ctx from hwss block sequence operations [Why] pipe_ctx is not allowed to reach a block sequence step. Several operations still carried it into the executor, which then walked the logical state at execute time (pipe_ctx->stream->timing, pipe_ctx->plane_state and similar) instead of acting on data resolved during build. [How] Give each operation a flat parameter list holding only the hardware objects and values the final hwss call needs, and change the matching hooks to take it. The function pointer, the params struct, the executor, the builder helpers and all call sites are updated together. Operations covered: - OPTC_PROGRAM_MANUAL_TRIGGER - takes tg - HUBP_PROGRAM_TRIPLEBUFFER - program_triplebuffer takes (hubp, bool) - DPP_SETUP_DPP, DPP_PROGRAM_BIAS_AND_SCALE - take (dpp, plane_state) - DSC_ENABLE_WITH_OPP - takes (dsc, opp_inst) - OPP_PROGRAM_BIT_DEPTH_REDUCTION - opp Reviewed-by: Alvin Lee Signed-off-by: Rafal Ostrowski Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 4 +- .../drm/amd/display/dc/core/dc_hw_sequencer.c | 165 ++++++++++-------- .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 12 +- .../amd/display/dc/hwss/dcn20/dcn20_hwseq.h | 3 +- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 6 +- .../amd/display/dc/hwss/dcn50/dcn50_hwseq.c | 4 +- .../drm/amd/display/dc/hwss/hw_sequencer.h | 34 ++-- 7 files changed, 128 insertions(+), 100 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 8839568e2adc..c7e34502a81f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -5139,7 +5139,7 @@ static void commit_planes_for_stream(struct dc *dc, if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { /*turn off triple buffer for full update*/ dc->hwss.program_triplebuffer( - dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); + pipe_ctx->plane_res.hubp, pipe_ctx->plane_state->triplebuffer_flips); } } @@ -5214,7 +5214,7 @@ static void commit_planes_for_stream(struct dc *dc, if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { /*only enable triplebuffer for fast_update*/ dc->hwss.program_triplebuffer( - dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); + pipe_ctx->plane_res.hubp, pipe_ctx->plane_state->triplebuffer_flips); } if (pipe_ctx->plane_state->update_bits.addr_update) dc->hwss.update_plane_addr(dc, pipe_ctx); 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 2c13f76d764b..f33562dff6ac 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 @@ -855,7 +855,9 @@ void hwss_build_full_sequence(struct dc *dc, if (pipe->plane_state) { /* Turn off triple buffer for full update */ - hwss_add_hubp_program_triplebuffer(&seq_state, dc, pipe, pipe->plane_state->triplebuffer_flips); + hwss_add_hubp_program_triplebuffer(&seq_state, + pipe->plane_res.hubp, + pipe->plane_state->triplebuffer_flips); } } } @@ -1465,11 +1467,9 @@ void hwss_build_fast_sequence(struct dc *dc, (*num_steps)++; } if (dc->hwss.program_triplebuffer && dc->debug.enable_tri_buf && dc_pipe_update_bits_is_any_set(¤t_mpc_pipe->plane_state->update_bits)) { - block_sequence[*num_steps].params.program_triplebuffer_params.dc = dc; - block_sequence[*num_steps].params.program_triplebuffer_params.pipe_ctx = current_mpc_pipe; - block_sequence[*num_steps].params.program_triplebuffer_params.enableTripleBuffer = current_mpc_pipe->plane_state->triplebuffer_flips; - block_sequence[*num_steps].func = HUBP_PROGRAM_TRIPLEBUFFER; - (*num_steps)++; + hwss_add_hubp_program_triplebuffer(&seq_state, + current_mpc_pipe->plane_res.hubp, + current_mpc_pipe->plane_state->triplebuffer_flips); } if (dc->hwss.prepare_plane_addr_update && current_mpc_pipe->plane_state->update_bits.addr_update) { if (resource_is_pipe_type(current_mpc_pipe, OTG_MASTER) && @@ -1551,14 +1551,14 @@ void hwss_build_fast_sequence(struct dc *dc, (*num_steps)++; } if (current_mpc_pipe->plane_state->update_bits.input_csc_change) { - block_sequence[*num_steps].params.setup_dpp_params.pipe_ctx = current_mpc_pipe; - block_sequence[*num_steps].func = DPP_SETUP_DPP; - (*num_steps)++; + hwss_add_dpp_setup_dpp(&seq_state, + current_mpc_pipe->plane_res.dpp, + current_mpc_pipe->plane_state); } if (current_mpc_pipe->plane_state->update_bits.coeff_reduction_change) { - block_sequence[*num_steps].params.program_bias_and_scale_params.pipe_ctx = current_mpc_pipe; - block_sequence[*num_steps].func = DPP_PROGRAM_BIAS_AND_SCALE; - (*num_steps)++; + hwss_add_dpp_program_bias_and_scale(&seq_state, + current_mpc_pipe->plane_res.dpp, + current_mpc_pipe->plane_state); } if (current_mpc_pipe->plane_state->update_bits.cm_hist_change) { block_sequence[*num_steps].params.control_cm_hist_params.dpp @@ -1665,9 +1665,7 @@ void hwss_build_fast_sequence(struct dc *dc, (*num_steps)++; } - block_sequence[*num_steps].params.program_manual_trigger_params.pipe_ctx = current_mpc_pipe; - block_sequence[*num_steps].func = OPTC_PROGRAM_MANUAL_TRIGGER; - (*num_steps)++; + hwss_add_optc_program_manual_trigger(&seq_state, current_mpc_pipe->stream_res.tg); } current_mpc_pipe = current_mpc_pipe->bottom_pipe; } @@ -1705,9 +1703,7 @@ void hwss_execute_sequence(struct dc *dc, params->set_flip_control_gsl_params.flip_immediate); break; case HUBP_PROGRAM_TRIPLEBUFFER: - dc->hwss.program_triplebuffer(params->program_triplebuffer_params.dc, - params->program_triplebuffer_params.pipe_ctx, - params->program_triplebuffer_params.enableTripleBuffer); + hwss_program_triplebuffer(params); break; case HUBP_UPDATE_PLANE_ADDR: params->update_plane_addr_params.hubp->funcs->hubp_program_surface_flip_and_addr( @@ -2317,13 +2313,14 @@ void hwss_add_hubp_set_flip_control_gsl(struct block_sequence_state *seq_state, * Helper function to add HUBP program triplebuffer to block sequence */ void hwss_add_hubp_program_triplebuffer(struct block_sequence_state *seq_state, - struct dc *dc, - struct pipe_ctx *pipe_ctx, + struct hubp *hubp, bool enableTripleBuffer) { + if (!hubp || !hubp->funcs->hubp_enable_tripleBuffer) + return; + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { - seq_state->steps[*seq_state->num_steps].params.program_triplebuffer_params.dc = dc; - seq_state->steps[*seq_state->num_steps].params.program_triplebuffer_params.pipe_ctx = pipe_ctx; + seq_state->steps[*seq_state->num_steps].params.program_triplebuffer_params.hubp = hubp; seq_state->steps[*seq_state->num_steps].params.program_triplebuffer_params.enableTripleBuffer = enableTripleBuffer; seq_state->steps[*seq_state->num_steps].func = HUBP_PROGRAM_TRIPLEBUFFER; (*seq_state->num_steps)++; @@ -2406,11 +2403,18 @@ void hwss_add_dpp_program_gamut_remap(struct block_sequence_state *seq_state, /* * Helper function to add DPP program bias and scale to block sequence */ -void hwss_add_dpp_program_bias_and_scale(struct block_sequence_state *seq_state, struct pipe_ctx *pipe_ctx) +void hwss_add_dpp_program_bias_and_scale(struct block_sequence_state *seq_state, + struct dpp *dpp, + struct dc_plane_state *plane_state) { + if (!plane_state) + return; + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { - seq_state->steps[*seq_state->num_steps].params.program_bias_and_scale_params.pipe_ctx = pipe_ctx; seq_state->steps[*seq_state->num_steps].func = DPP_PROGRAM_BIAS_AND_SCALE; + seq_state->steps[*seq_state->num_steps].params.program_bias_and_scale_params.dpp = dpp; + seq_state->steps[*seq_state->num_steps].params.program_bias_and_scale_params.bias_and_scale = + plane_state->bias_and_scale; (*seq_state->num_steps)++; } } @@ -2419,10 +2423,13 @@ void hwss_add_dpp_program_bias_and_scale(struct block_sequence_state *seq_state, * Helper function to add OPTC program manual trigger to block sequence */ void hwss_add_optc_program_manual_trigger(struct block_sequence_state *seq_state, - struct pipe_ctx *pipe_ctx) + struct timing_generator *tg) { + if (!tg) + return; + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { - seq_state->steps[*seq_state->num_steps].params.program_manual_trigger_params.pipe_ctx = pipe_ctx; + seq_state->steps[*seq_state->num_steps].params.program_manual_trigger_params.tg = tg; seq_state->steps[*seq_state->num_steps].func = OPTC_PROGRAM_MANUAL_TRIGGER; (*seq_state->num_steps)++; } @@ -2929,44 +2936,44 @@ void hwss_add_hubp_enable_3dlut_fl(struct block_sequence_state *seq_state, } } +void hwss_program_triplebuffer(union block_sequence_params *params) +{ + struct hubp *hubp = params->program_triplebuffer_params.hubp; + + if (hubp && hubp->funcs->hubp_enable_tripleBuffer) + hubp->funcs->hubp_enable_tripleBuffer(hubp, + params->program_triplebuffer_params.enableTripleBuffer); +} + void hwss_program_manual_trigger(union block_sequence_params *params) { - struct pipe_ctx *pipe_ctx = params->program_manual_trigger_params.pipe_ctx; + struct timing_generator *tg = params->program_manual_trigger_params.tg; - if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger) - pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg); + if (tg && tg->funcs->program_manual_trigger) + tg->funcs->program_manual_trigger(tg); } void hwss_setup_dpp(union block_sequence_params *params) { - struct pipe_ctx *pipe_ctx = params->setup_dpp_params.pipe_ctx; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct setup_dpp_params *p = ¶ms->setup_dpp_params; - if (!plane_state) - return; - - if (dpp && dpp->funcs->dpp_setup) { - // program the input csc - dpp->funcs->dpp_setup(dpp, - plane_state->format, + if (p->dpp && p->dpp->funcs->dpp_setup) { + p->dpp->funcs->dpp_setup(p->dpp, + p->format, EXPANSION_MODE_ZERO, - plane_state->input_csc_color_matrix, - plane_state->color_space, + p->input_csc_color_matrix, + p->color_space, NULL); } } void hwss_program_bias_and_scale(union block_sequence_params *params) { - struct pipe_ctx *pipe_ctx = params->program_bias_and_scale_params.pipe_ctx; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct dc_bias_and_scale bns_params = plane_state->bias_and_scale; + struct program_bias_and_scale_params *p = ¶ms->program_bias_and_scale_params; //TODO :for CNVC set scale and bias registers if necessary - if (dpp->funcs->dpp_program_bias_and_scale) - dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); + if (p->dpp && p->dpp->funcs->dpp_program_bias_and_scale) + p->dpp->funcs->dpp_program_bias_and_scale(p->dpp, &p->bias_and_scale); } void hwss_program_upsp(union block_sequence_params *params) @@ -3366,11 +3373,10 @@ void hwss_dsc_calculate_and_set_config(union block_sequence_params *params) void hwss_dsc_enable_with_opp(union block_sequence_params *params) { - struct pipe_ctx *pipe_ctx = params->dsc_enable_with_opp_params.pipe_ctx; - struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct display_stream_compressor *dsc = params->dsc_enable_with_opp_params.dsc; if (dsc && dsc->funcs->dsc_enable) - dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + dsc->funcs->dsc_enable(dsc, params->dsc_enable_with_opp_params.opp_inst); } void hwss_tg_program_global_sync(union block_sequence_params *params) @@ -3509,17 +3515,10 @@ void hwss_opp_program_fmt(union block_sequence_params *params) void hwss_opp_program_bit_depth_reduction(union block_sequence_params *params) { struct output_pixel_processor *opp = params->opp_program_bit_depth_reduction_params.opp; - bool use_default_params = params->opp_program_bit_depth_reduction_params.use_default_params; - struct pipe_ctx *pipe_ctx = params->opp_program_bit_depth_reduction_params.pipe_ctx; - struct bit_depth_reduction_params bit_depth_params; - if (use_default_params) - memset(&bit_depth_params, 0, sizeof(bit_depth_params)); - else - resource_build_bit_depth_reduction_params(pipe_ctx->stream, &bit_depth_params); - - if (opp->funcs->opp_program_bit_depth_reduction) - opp->funcs->opp_program_bit_depth_reduction(opp, &bit_depth_params); + if (opp && opp->funcs->opp_program_bit_depth_reduction) + opp->funcs->opp_program_bit_depth_reduction(opp, + ¶ms->opp_program_bit_depth_reduction_params.bit_depth_params); } void hwss_opp_set_disp_pattern_generator(union block_sequence_params *params) @@ -4774,9 +4773,15 @@ void hwss_add_hubp_disconnect(struct block_sequence_state *seq_state, void hwss_add_dsc_enable_with_opp(struct block_sequence_state *seq_state, struct pipe_ctx *pipe_ctx) { + if (!pipe_ctx || !pipe_ctx->stream_res.dsc || !pipe_ctx->stream_res.opp) + return; + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { seq_state->steps[*seq_state->num_steps].func = DSC_ENABLE_WITH_OPP; - seq_state->steps[*seq_state->num_steps].params.dsc_enable_with_opp_params.pipe_ctx = pipe_ctx; + seq_state->steps[*seq_state->num_steps].params.dsc_enable_with_opp_params.dsc = + pipe_ctx->stream_res.dsc; + seq_state->steps[*seq_state->num_steps].params.dsc_enable_with_opp_params.opp_inst = + pipe_ctx->stream_res.opp->inst; (*seq_state->num_steps)++; } } @@ -4928,13 +4933,23 @@ void hwss_add_opp_program_bit_depth_reduction(struct block_sequence_state *seq_s bool use_default_params, struct pipe_ctx *pipe_ctx) { - if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { - seq_state->steps[*seq_state->num_steps].func = OPP_PROGRAM_BIT_DEPTH_REDUCTION; - seq_state->steps[*seq_state->num_steps].params.opp_program_bit_depth_reduction_params.opp = opp; - seq_state->steps[*seq_state->num_steps].params.opp_program_bit_depth_reduction_params.use_default_params = use_default_params; - seq_state->steps[*seq_state->num_steps].params.opp_program_bit_depth_reduction_params.pipe_ctx = pipe_ctx; - (*seq_state->num_steps)++; - } + struct opp_program_bit_depth_reduction_params *bdr_params; + + if (!opp) + return; + + if (*seq_state->num_steps >= MAX_HWSS_BLOCK_SEQUENCE_SIZE) + return; + + bdr_params = &seq_state->steps[*seq_state->num_steps].params.opp_program_bit_depth_reduction_params; + memset(bdr_params, 0, sizeof(*bdr_params)); + bdr_params->opp = opp; + + if (!use_default_params && pipe_ctx) + resource_build_bit_depth_reduction_params(pipe_ctx->stream, &bdr_params->bit_depth_params); + + seq_state->steps[*seq_state->num_steps].func = OPP_PROGRAM_BIT_DEPTH_REDUCTION; + (*seq_state->num_steps)++; } void hwss_add_dpp_program_cm_hist(struct block_sequence_state *seq_state, @@ -5657,11 +5672,21 @@ void hwss_add_hubp_program_surface_config(struct block_sequence_state *seq_state } void hwss_add_dpp_setup_dpp(struct block_sequence_state *seq_state, - struct pipe_ctx *pipe_ctx) + struct dpp *dpp, + struct dc_plane_state *plane_state) { + if (!plane_state) + return; + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + struct setup_dpp_params *p = + &seq_state->steps[*seq_state->num_steps].params.setup_dpp_params; + seq_state->steps[*seq_state->num_steps].func = DPP_SETUP_DPP; - seq_state->steps[*seq_state->num_steps].params.setup_dpp_params.pipe_ctx = pipe_ctx; + p->dpp = dpp; + p->format = plane_state->format; + p->input_csc_color_matrix = plane_state->input_csc_color_matrix; + p->color_space = plane_state->color_space; (*seq_state->num_steps)++; } } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index e5f266b0013d..e7ca38bcaabf 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -394,14 +394,12 @@ void dcn20_disable_vga( } void dcn20_program_triple_buffer( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, + struct hubp *hubp, bool enable_triple_buffer) { - (void)dc; - if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) { - pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer( - pipe_ctx->plane_res.hubp, + if (hubp && hubp->funcs) { + hubp->funcs->hubp_enable_tripleBuffer( + hubp, enable_triple_buffer); } } @@ -2110,7 +2108,7 @@ void dcn20_program_front_end_for_ctx( ASSERT(!pipe->plane_state->triplebuffer_flips); /*turn off triple buffer for full update*/ dc->hwss.program_triplebuffer( - dc, pipe, pipe->plane_state->triplebuffer_flips); + pipe->plane_res.hubp, pipe->plane_state->triplebuffer_flips); } } } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h index 9711b8bc9083..9a5addaa9a03 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h @@ -114,8 +114,7 @@ void dcn20_hubp_pg_control( unsigned int hubp_inst, bool power_on); void dcn20_program_triple_buffer( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, + struct hubp *hubp, bool enable_triple_buffer); void dcn20_enable_writeback( struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 8f202206c3c4..3dd3dacfe5ee 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -2533,7 +2533,7 @@ void dcn401_program_front_end_for_ctx( /*turn off triple buffer for full update*/ dc->hwss.program_triplebuffer( - dc, pipe, pipe->plane_state->triplebuffer_flips); + pipe->plane_res.hubp, pipe->plane_state->triplebuffer_flips); } } } @@ -3686,7 +3686,7 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, plane_state->update_bits.input_csc_change || plane_state->update_bits.color_space_change || plane_state->update_bits.coeff_reduction_change) { - hwss_add_dpp_setup_dpp(seq_state, pipe_ctx); + hwss_add_dpp_setup_dpp(seq_state, dpp, plane_state); /* Step 8: DPP cursor matrix setup */ if (dpp->funcs->set_cursor_matrix) { @@ -3696,7 +3696,7 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, /* Step 9: DPP program bias and scale */ if (dpp->funcs->dpp_program_bias_and_scale) - hwss_add_dpp_program_bias_and_scale(seq_state, pipe_ctx); + hwss_add_dpp_program_bias_and_scale(seq_state, dpp, plane_state); } /* Step 10: MPCC updates */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c index b1a916ac04e7..f1c044fe0ba2 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c @@ -315,7 +315,7 @@ void dcn50_update_dchubp_dpp_sequence(struct dc *dc, plane_state->update_bits.input_csc_change || plane_state->update_bits.color_space_change || plane_state->update_bits.coeff_reduction_change) { - hwss_add_dpp_setup_dpp(seq_state, pipe_ctx); + hwss_add_dpp_setup_dpp(seq_state, dpp, plane_state); /* Step 8: DPP cursor matrix setup */ if (dpp->funcs->set_cursor_matrix) { @@ -325,7 +325,7 @@ void dcn50_update_dchubp_dpp_sequence(struct dc *dc, /* Step 9: DPP program bias and scale */ if (dpp->funcs->dpp_program_bias_and_scale) - hwss_add_dpp_program_bias_and_scale(seq_state, pipe_ctx); + hwss_add_dpp_program_bias_and_scale(seq_state, dpp, plane_state); } /* Step 10: MPCC updates */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index cc1c54c46e25..c902a28b3220 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -87,8 +87,7 @@ struct set_flip_control_gsl_params { }; struct program_triplebuffer_params { - const struct dc *dc; - struct pipe_ctx *pipe_ctx; + struct hubp *hubp; bool enableTripleBuffer; }; @@ -138,7 +137,7 @@ struct update_info_frame_params { }; struct program_manual_trigger_params { - struct pipe_ctx *pipe_ctx; + struct timing_generator *tg; }; struct send_dmcub_cmd_params { @@ -156,11 +155,15 @@ struct lsdma_send_pio_copy_params { }; struct setup_dpp_params { - struct pipe_ctx *pipe_ctx; + struct dpp *dpp; + enum surface_pixel_format format; + struct dc_csc_transform input_csc_color_matrix; + enum dc_color_space color_space; }; struct program_bias_and_scale_params { - struct pipe_ctx *pipe_ctx; + struct dpp *dpp; + struct dc_bias_and_scale bias_and_scale; }; struct set_output_transfer_func_params { @@ -313,7 +316,8 @@ struct dsc_calculate_and_set_config_params { }; struct dsc_enable_with_opp_params { - struct pipe_ctx *pipe_ctx; + struct display_stream_compressor *dsc; + int opp_inst; }; struct program_tg_params { @@ -412,8 +416,7 @@ struct opp_program_fmt_params { struct opp_program_bit_depth_reduction_params { struct output_pixel_processor *opp; - bool use_default_params; - struct pipe_ctx *pipe_ctx; + struct bit_depth_reduction_params bit_depth_params; }; struct opp_set_disp_pattern_generator_params { @@ -1463,8 +1466,7 @@ struct hw_sequencer_funcs { void (*edp_backlight_control)( struct dc_link *link, bool enable); - void (*program_triplebuffer)(const struct dc *dc, - struct pipe_ctx *pipe_ctx, bool enableTripleBuffer); + void (*program_triplebuffer)(struct hubp *hubp, bool enableTripleBuffer); void (*update_pending_status)(struct pipe_ctx *pipe_ctx); void (*update_dsc_pg)(struct dc *dc, struct dc_state *context, bool safe_to_disable); void (*clear_surface_dcc_and_tiling)(struct pipe_ctx *pipe_ctx, struct dc_plane_state *plane_state, bool clear_tiling); @@ -1871,6 +1873,8 @@ void hwss_process_outstanding_hw_updates(struct dc *dc, void hwss_send_dmcub_cmd(union block_sequence_params *params); void hwss_lsdma_send_pio_copy(union block_sequence_params *params); +void hwss_program_triplebuffer(union block_sequence_params *params); + void hwss_program_manual_trigger(union block_sequence_params *params); void hwss_setup_dpp(union block_sequence_params *params); @@ -2188,7 +2192,7 @@ void hwss_add_hubp_set_flip_control_gsl(struct block_sequence_state *seq_state, struct hubp *hubp, bool flip_immediate); void hwss_add_hubp_program_triplebuffer(struct block_sequence_state *seq_state, - struct dc *dc, struct pipe_ctx *pipe_ctx, bool enableTripleBuffer); + struct hubp *hubp, bool enableTripleBuffer); void hwss_add_hubp_update_plane_addr(struct block_sequence_state *seq_state, struct dc *dc, struct pipe_ctx *pipe_ctx); @@ -2200,10 +2204,11 @@ void hwss_add_dpp_program_gamut_remap(struct block_sequence_state *seq_state, struct pipe_ctx *pipe_ctx); void hwss_add_dpp_program_bias_and_scale(struct block_sequence_state *seq_state, - struct pipe_ctx *pipe_ctx); + struct dpp *dpp, + struct dc_plane_state *plane_state); void hwss_add_optc_program_manual_trigger(struct block_sequence_state *seq_state, - struct pipe_ctx *pipe_ctx); + struct timing_generator *tg); void hwss_add_dpp_set_output_transfer_func(struct block_sequence_state *seq_state, struct dc *dc, struct pipe_ctx *pipe_ctx); @@ -2581,7 +2586,8 @@ void hwss_add_hubp_program_surface_config(struct block_sequence_state *seq_state int compat_level); void hwss_add_dpp_setup_dpp(struct block_sequence_state *seq_state, - struct pipe_ctx *pipe_ctx); + struct dpp *dpp, + struct dc_plane_state *plane_state); void hwss_add_dpp_set_cursor_matrix(struct block_sequence_state *seq_state, struct dpp *dpp, From 1569ef0881fd78db5f6865b1a204cff6c0e05e52 Mon Sep 17 00:00:00 2001 From: Rafal Ostrowski Date: Fri, 19 Jun 2026 11:02:22 +0200 Subject: [PATCH 085/103] drm/amd/display: refactor hwss SET_CURSOR_POSITION block sequence Flatten the executor params for the initial set of HWSS block sequence ops for SET_CURSOR_POSITION to separate SW and HW logic Reviewed-by: Alvin Lee Signed-off-by: Rafal Ostrowski Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/core/dc_hw_sequencer.c | 52 +++++++++++++-- .../gpu/drm/amd/display/dc/core/dc_stream.c | 2 +- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 3 + .../amd/display/dc/hubp/dcn401/dcn401_hubp.c | 51 ++------------ .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 2 +- .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 20 ++++-- .../amd/display/dc/hwss/dcn10/dcn10_hwseq.h | 7 +- .../amd/display/dc/hwss/dcn10/dcn10_init.c | 1 + .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 2 +- .../amd/display/dc/hwss/dcn20/dcn20_init.c | 1 + .../amd/display/dc/hwss/dcn201/dcn201_init.c | 1 + .../amd/display/dc/hwss/dcn21/dcn21_init.c | 1 + .../amd/display/dc/hwss/dcn30/dcn30_init.c | 1 + .../amd/display/dc/hwss/dcn301/dcn301_init.c | 1 + .../amd/display/dc/hwss/dcn31/dcn31_init.c | 1 + .../amd/display/dc/hwss/dcn314/dcn314_init.c | 1 + .../amd/display/dc/hwss/dcn32/dcn32_init.c | 1 + .../amd/display/dc/hwss/dcn35/dcn35_init.c | 1 + .../amd/display/dc/hwss/dcn351/dcn351_init.c | 1 + .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 66 +++++++++++++++++-- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 7 +- .../amd/display/dc/hwss/dcn401/dcn401_init.c | 1 + .../amd/display/dc/hwss/dcn42/dcn42_init.c | 1 + .../amd/display/dc/hwss/dcn50/dcn50_hwseq.c | 2 +- .../amd/display/dc/hwss/dcn60/dcn60_init.c | 1 + .../drm/amd/display/dc/hwss/hw_sequencer.h | 13 +++- .../display/dc/hwss/hw_sequencer_private.h | 3 + 27 files changed, 172 insertions(+), 72 deletions(-) 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 f33562dff6ac..3bc0362d9dc0 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 @@ -1304,7 +1304,8 @@ void hwss_build_fast_sequence(struct dc *dc, bool enable_cursor_offload = false; if ((dc->hwss.set_cursor_attribute && stream->update_flags.bits.cursor_attr) || - (dc->hwss.set_cursor_position && stream->update_flags.bits.cursor_pos)) + (dc->hwseq && dc->hwseq->funcs.build_cursor_position && + dc->hwss.set_cursor_position && stream->update_flags.bits.cursor_pos)) enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); /* Cursor attribute updates - separate lock/iterate/unlock */ @@ -1390,7 +1391,8 @@ void hwss_build_fast_sequence(struct dc *dc, } /* Cursor position updates */ - if (dc->hwss.set_cursor_position && stream->update_flags.bits.cursor_pos) { + if (dc->hwseq && dc->hwseq->funcs.build_cursor_position && + dc->hwss.set_cursor_position && stream->update_flags.bits.cursor_pos) { struct pipe_ctx *cursor_pipe_to_program = NULL; for (i = 0; i < MAX_PIPES; i++) { @@ -1417,8 +1419,16 @@ void hwss_build_fast_sequence(struct dc *dc, } } + struct dc_cursor_position pos; + struct dc_cursor_mi_param param; + + dc->hwseq->funcs.build_cursor_position(current_pipe, &pos, ¶m); + block_sequence[*num_steps].params.set_cursor_position_params.dc = dc; - block_sequence[*num_steps].params.set_cursor_position_params.pipe_ctx = current_pipe; + block_sequence[*num_steps].params.set_cursor_position_params.hubp = current_pipe->plane_res.hubp; + block_sequence[*num_steps].params.set_cursor_position_params.dpp = current_pipe->plane_res.dpp; + block_sequence[*num_steps].params.set_cursor_position_params.pos = pos; + block_sequence[*num_steps].params.set_cursor_position_params.param = param; block_sequence[*num_steps].func = SET_CURSOR_POSITION; (*num_steps)++; @@ -4357,10 +4367,28 @@ void hwss_dpp_set_cursor_attributes(union block_sequence_params *params) void hwss_set_cursor_position(union block_sequence_params *params) { struct dc *dc = params->set_cursor_position_params.dc; - struct pipe_ctx *pipe_ctx = params->set_cursor_position_params.pipe_ctx; + struct hubp *hubp = params->set_cursor_position_params.hubp; + struct dpp *dpp = params->set_cursor_position_params.dpp; + const struct dc_cursor_position *pos = ¶ms->set_cursor_position_params.pos; + const struct dc_cursor_mi_param *param = ¶ms->set_cursor_position_params.param; + /* DCN path: SW logic ran in the builder; just invoke the BLCs */ if (dc && dc->hwss.set_cursor_position) - dc->hwss.set_cursor_position(pipe_ctx); + dc->hwss.set_cursor_position(hubp, dpp, pos, param); +} + +void hwss_program_cursor_position(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + if (dc->hwseq && dc->hwseq->funcs.build_cursor_position && dc->hwss.set_cursor_position) { + struct dc_cursor_position pos; + struct dc_cursor_mi_param param; + + dc->hwseq->funcs.build_cursor_position(pipe_ctx, &pos, ¶m); + dc->hwss.set_cursor_position(pipe_ctx->plane_res.hubp, + pipe_ctx->plane_res.dpp, &pos, ¶m); + } else if (dc->hwss.set_cursor_position_legacy) { + dc->hwss.set_cursor_position_legacy(pipe_ctx); + } } void hwss_set_cursor_sdr_white_level(union block_sequence_params *params) @@ -5783,10 +5811,20 @@ void hwss_add_set_cursor_position(struct block_sequence_state *seq_state, struct dc *dc, struct pipe_ctx *pipe_ctx) { - if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE && + dc->hwseq && dc->hwseq->funcs.build_cursor_position && + dc->hwss.set_cursor_position) { + struct dc_cursor_position pos; + struct dc_cursor_mi_param param; + + dc->hwseq->funcs.build_cursor_position(pipe_ctx, &pos, ¶m); + seq_state->steps[*seq_state->num_steps].func = SET_CURSOR_POSITION; seq_state->steps[*seq_state->num_steps].params.set_cursor_position_params.dc = dc; - seq_state->steps[*seq_state->num_steps].params.set_cursor_position_params.pipe_ctx = pipe_ctx; + seq_state->steps[*seq_state->num_steps].params.set_cursor_position_params.hubp = pipe_ctx->plane_res.hubp; + seq_state->steps[*seq_state->num_steps].params.set_cursor_position_params.dpp = pipe_ctx->plane_res.dpp; + seq_state->steps[*seq_state->num_steps].params.set_cursor_position_params.pos = pos; + seq_state->steps[*seq_state->num_steps].params.set_cursor_position_params.param = param; (*seq_state->num_steps)++; } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 88ac4a4cfd6e..b446c311e662 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -530,7 +530,7 @@ void program_cursor_position( } } - dc->hwss.set_cursor_position(pipe_ctx); + hwss_program_cursor_position(dc, pipe_ctx); if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) { struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 084c506a8a94..40cd4e5d1340 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -562,6 +562,9 @@ struct dc_cursor_mi_param { enum dc_rotation_angle rotation; bool mirror; struct dc_stream_state *stream; + int dst_x_offset; + int cur_rect_x; + int cur_rect_y; }; /* IPP related types */ diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c index 5ca40941c355..a985c3e00dca 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c @@ -816,24 +816,9 @@ void hubp401_cursor_set_position( const struct dc_cursor_mi_param *param) { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); - int rec_x_offset = pos->x - pos->x_hotspot; - int rec_y_offset = pos->y - pos->y_hotspot; - int dst_x_offset; - int x_pos_viewport = 0; - int x_hot_viewport = 0; + int dst_x_offset = param->dst_x_offset; uint32_t cur_en = pos->enable ? 1 : 0; - uint32_t x_hotspot_clamped = pos->x_hotspot; hubp->curs_pos = *pos; - /* Recout is zero for pipes if the entire dst_rect is contained - * within preceeding ODM slices. - */ - if (param->recout.width) { - x_pos_viewport = pos->x * param->viewport.width / param->recout.width; - x_hot_viewport = pos->x_hotspot * param->viewport.width / param->recout.width; - } else { - ASSERT(!cur_en || pos->x == 0); - ASSERT(!cur_en || pos->x_hotspot == 0); - } /* * Guard aganst cursor_set_position() from being called with invalid @@ -842,25 +827,6 @@ void hubp401_cursor_set_position( if (hubp->curs_attr.address.quad_part == 0) return; - /* Translate the x position of the cursor from rect - * space into viewport space. CURSOR_DST_X_OFFSET - * is the offset relative to viewport start position. - */ - dst_x_offset = x_pos_viewport - x_hot_viewport * - (1 + hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION); - dst_x_offset = (dst_x_offset >= 0) ? dst_x_offset : 0; - dst_x_offset *= param->ref_clk_khz; - dst_x_offset /= param->pixel_clk_khz; - - ASSERT(param->h_scale_ratio.value); - - if (x_hotspot_clamped > 0xFF) - x_hotspot_clamped = 0xFF; - if (param->h_scale_ratio.value) - dst_x_offset = dc_fixpt_floor(dc_fixpt_div( - dc_fixpt_from_int(dst_x_offset), - param->h_scale_ratio)); - if (hubp->pos.cur_ctl.bits.cur_enable != cur_en) { if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) hubp->funcs->set_cursor_attributes(hubp, &hubp->curs_attr); @@ -876,7 +842,7 @@ void hubp401_cursor_set_position( CURSOR_Y_POSITION, pos->y); REG_SET_2(CURSOR_HOT_SPOT, 0, - CURSOR_HOT_SPOT_X, x_hotspot_clamped, + CURSOR_HOT_SPOT_X, pos->x_hotspot, CURSOR_HOT_SPOT_Y, pos->y_hotspot); REG_SET(CURSOR_DST_OFFSET, 0, @@ -889,18 +855,9 @@ void hubp401_cursor_set_position( hubp->pos.hot_spot.bits.x_hot = pos->x_hotspot; hubp->pos.hot_spot.bits.y_hot = pos->y_hotspot; hubp->pos.dst_offset.bits.dst_x_offset = dst_x_offset; - /* Cursor Rectangle Cache - * Cursor bitmaps have different hotspot values - * There's a possibility that the above logic returns a negative value, - * so we clamp them to 0 - */ - if (rec_x_offset < 0) - rec_x_offset = 0; - if (rec_y_offset < 0) - rec_y_offset = 0; /* Save necessary cursor info x, y position. w, h is saved in attribute func. */ - hubp->cur_rect.x = rec_x_offset + param->recout.x; - hubp->cur_rect.y = rec_y_offset + param->recout.y; + hubp->cur_rect.x = param->cur_rect_x; + hubp->cur_rect.y = param->cur_rect_y; } void hubp401_read_state(struct hubp *hubp) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index bb46d7249025..d48894017c0e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -3655,7 +3655,7 @@ static const struct hw_sequencer_funcs dce110_funcs = { .edp_backlight_control = dce110_edp_backlight_control, .edp_power_control = dce110_edp_power_control, .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dce110_set_cursor_position, + .set_cursor_position_legacy = dce110_set_cursor_position, .set_cursor_attribute = dce110_set_cursor_attribute, .set_backlight_level = dce110_set_backlight_level, .set_abm_immediate_disable = dce110_set_abm_immediate_disable, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index 84e146f2509c..613f1f62cd80 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -3176,7 +3176,7 @@ static void dcn10_update_dchubp_dpp( } dc->hwss.set_cursor_attribute(pipe_ctx); - dc->hwss.set_cursor_position(pipe_ctx); + hwss_program_cursor_position(dc, pipe_ctx); if (dc->hwss.set_cursor_sdr_white_level) dc->hwss.set_cursor_sdr_white_level(pipe_ctx); @@ -3729,11 +3729,11 @@ void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) hubbub->funcs->update_dchub(hubbub, dh_data); } -void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) +void dcn10_build_cursor_position(struct pipe_ctx *pipe_ctx, + struct dc_cursor_position *pos_out, + struct dc_cursor_mi_param *param_out) { struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_cursor_mi_param param = { .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, @@ -3949,8 +3949,16 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; } - hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); - dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); + *pos_out = pos_cpy; + *param_out = param; +} + +void dcn10_set_cursor_position(struct hubp *hubp, struct dpp *dpp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param) +{ + hubp->funcs->set_cursor_position(hubp, pos, param); + dpp->funcs->set_cursor_position(dpp, pos, param, hubp->curs_attr.width, hubp->curs_attr.height); } void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h index 5cb109040d3d..9c4f1186ca9f 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h @@ -177,7 +177,12 @@ void dce110_edp_power_control( void dce110_edp_wait_for_hpd_ready( struct dc_link *link, bool power_up); -void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx); +void dcn10_build_cursor_position(struct pipe_ctx *pipe_ctx, + struct dc_cursor_position *pos, + struct dc_cursor_mi_param *param); +void dcn10_set_cursor_position(struct hubp *hubp, struct dpp *dpp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param); void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx); void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx); void dcn10_setup_periodic_interrupt( diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c index 07e92742c11a..ddd52722bc49 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c @@ -94,6 +94,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { }; static const struct hwseq_private_funcs dcn10_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .program_pipe = dcn10_program_pipe, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index e7ca38bcaabf..45a4a7707507 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -1846,7 +1846,7 @@ void dcn20_update_dchubp_dpp( } dc->hwss.set_cursor_attribute(pipe_ctx); - dc->hwss.set_cursor_position(pipe_ctx); + hwss_program_cursor_position(dc, pipe_ctx); if (dc->hwss.set_cursor_sdr_white_level) dc->hwss.set_cursor_sdr_white_level(pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c index c4de9cf11c23..5817fb44d2e0 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c @@ -107,6 +107,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = { }; static const struct hwseq_private_funcs dcn20_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c index be1fb2366c8a..d421bc813cbd 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c @@ -99,6 +99,7 @@ static const struct hw_sequencer_funcs dcn201_funcs = { }; static const struct hwseq_private_funcs dcn201_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = NULL, .plane_atomic_disconnect = dcn201_plane_atomic_disconnect, .program_pipe = dcn10_program_pipe, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c index 20c6e7d7c897..e691e86629c5 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c @@ -110,6 +110,7 @@ static const struct hw_sequencer_funcs dcn21_funcs = { }; static const struct hwseq_private_funcs dcn21_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c index f62f1c6efff8..f7a095796039 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c @@ -117,6 +117,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = { }; static const struct hwseq_private_funcs dcn30_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c index a62434138eca..191245bde1ca 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c @@ -113,6 +113,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = { }; static const struct hwseq_private_funcs dcn301_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c index 30ad41d08d6e..5500eb46dedb 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c @@ -119,6 +119,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = { }; static const struct hwseq_private_funcs dcn31_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c index a53e7fb6f23f..b278f58b844d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c @@ -122,6 +122,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = { }; static const struct hwseq_private_funcs dcn314_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c index 7e68029f1e12..49387de29382 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c @@ -130,6 +130,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { }; static const struct hwseq_private_funcs dcn32_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c index 69fa91aeb836..e4864b9606ff 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c @@ -140,6 +140,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = { }; static const struct hwseq_private_funcs dcn35_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn35_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c index 3ceaa4590148..f57c0f6adccf 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c @@ -129,6 +129,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = { }; static const struct hwseq_private_funcs dcn351_private_funcs = { + .build_cursor_position = dcn10_build_cursor_position, .init_pipes = dcn35_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 3dd3dacfe5ee..8fd60ed7669b 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -1045,11 +1045,12 @@ void dcn401_disable_link_output(struct dc_link *link, dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); } -void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) +void dcn401_build_cursor_position(struct pipe_ctx *pipe_ctx, + struct dc_cursor_position *pos_out, + struct dc_cursor_mi_param *param_out) { struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_cursor_mi_param param = { .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, @@ -1073,6 +1074,11 @@ void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) int y_pos = pos_cpy.y; int recout_x_pos = 0; int recout_y_pos = 0; + int x_pos_viewport = 0; + int x_hot_viewport = 0; + int dst_x_offset = 0; + int rec_x_offset = 0; + int rec_y_offset = 0; if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) || @@ -1215,8 +1221,60 @@ void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) pos_cpy.x = x_pos; pos_cpy.y = y_pos; - hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); - dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); + /* Precompute the HW destination offset so the executor only programs + * registers. Translate cursor x position from rect space into viewport + * space; CURSOR_DST_X_OFFSET is relative to the viewport start position. + */ + if (param.recout.width) { + x_pos_viewport = pos_cpy.x * param.viewport.width / param.recout.width; + x_hot_viewport = pos_cpy.x_hotspot * param.viewport.width / param.recout.width; + } else { + ASSERT(!pos_cpy.enable || pos_cpy.x == 0); + ASSERT(!pos_cpy.enable || pos_cpy.x_hotspot == 0); + } + + dst_x_offset = x_pos_viewport - x_hot_viewport * + (1 + hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION); + dst_x_offset = (dst_x_offset >= 0) ? dst_x_offset : 0; + dst_x_offset *= param.ref_clk_khz; + dst_x_offset /= param.pixel_clk_khz; + + ASSERT(param.h_scale_ratio.value); + + if (param.h_scale_ratio.value) + dst_x_offset = dc_fixpt_floor(dc_fixpt_div( + dc_fixpt_from_int(dst_x_offset), + param.h_scale_ratio)); + + param.dst_x_offset = dst_x_offset; + + /* Cursor rectangle cache origin: derived from the final cursor position + * minus hotspot, clamped to 0, offset by the recout origin. Precompute + * here so the executor only stores the value. + */ + rec_x_offset = pos_cpy.x - pos_cpy.x_hotspot; + rec_y_offset = pos_cpy.y - pos_cpy.y_hotspot; + if (rec_x_offset < 0) + rec_x_offset = 0; + if (rec_y_offset < 0) + rec_y_offset = 0; + param.cur_rect_x = rec_x_offset + param.recout.x; + param.cur_rect_y = rec_y_offset + param.recout.y; + + /* Clamp hotspot to the CURSOR_HOT_SPOT_X register field width */ + if (pos_cpy.x_hotspot > 0xFF) + pos_cpy.x_hotspot = 0xFF; + + *pos_out = pos_cpy; + *param_out = param; +} + +void dcn401_set_cursor_position(struct hubp *hubp, struct dpp *dpp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param) +{ + hubp->funcs->set_cursor_position(hubp, pos, param); + dpp->funcs->set_cursor_position(dpp, pos, param, hubp->curs_attr.width, hubp->curs_attr.height); } static bool dcn401_check_no_memory_request_for_cab(struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h index 43bea09fb205..f958ea34a3c6 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h @@ -55,7 +55,12 @@ void dcn401_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); -void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx); +void dcn401_build_cursor_position(struct pipe_ctx *pipe_ctx, + struct dc_cursor_position *pos, + struct dc_cursor_mi_param *param); +void dcn401_set_cursor_position(struct hubp *hubp, struct dpp *dpp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param); bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c index 5ac79c32ee48..ac5ebe546d0c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c @@ -125,6 +125,7 @@ static const struct hw_sequencer_funcs dcn401_funcs = { }; static const struct hwseq_private_funcs dcn401_private_funcs = { + .build_cursor_position = dcn401_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .plane_atomic_disconnect_sequence = dcn401_plane_atomic_disconnect_sequence, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c index faeb365dbcab..eba34f124e39 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c @@ -129,6 +129,7 @@ static const struct hw_sequencer_funcs dcn42_funcs = { }; static const struct hwseq_private_funcs dcn42_private_funcs = { + .build_cursor_position = dcn401_build_cursor_position, .init_pipes = dcn35_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn42_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c index f1c044fe0ba2..0361c520b7d9 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c @@ -212,7 +212,7 @@ void dcn50_update_dchubp_dpp( } dc->hwss.set_cursor_attribute(pipe_ctx); - dc->hwss.set_cursor_position(pipe_ctx); + hwss_program_cursor_position(dc, pipe_ctx); if (dc->hwss.set_cursor_sdr_white_level) dc->hwss.set_cursor_sdr_white_level(pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c index 4aaecd6f8bb7..ce0905820f7e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c @@ -128,6 +128,7 @@ static const struct hw_sequencer_funcs dcn60_funcs = { }; static const struct hwseq_private_funcs dcn60_private_funcs = { + .build_cursor_position = dcn401_build_cursor_position, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .plane_atomic_disconnect_sequence = dcn401_plane_atomic_disconnect_sequence, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index c902a28b3220..7c5f88bf44c7 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -874,7 +874,10 @@ struct dpp_set_cursor_attributes_params { struct set_cursor_position_params { struct dc *dc; - struct pipe_ctx *pipe_ctx; + struct hubp *hubp; + struct dpp *dpp; + struct dc_cursor_position pos; + struct dc_cursor_mi_param param; }; struct set_cursor_sdr_white_level_params { @@ -1539,7 +1542,11 @@ struct hw_sequencer_funcs { bool (*dmdata_status_done)(struct pipe_ctx *pipe_ctx); /* Cursor Related */ - void (*set_cursor_position)(struct pipe_ctx *pipe); + void (*set_cursor_position)(struct hubp *hubp, struct dpp *dpp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param); + /* Fallback for DCE */ + void (*set_cursor_position_legacy)(struct pipe_ctx *pipe); void (*set_cursor_attribute)(struct pipe_ctx *pipe); void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe); void (*abort_cursor_offload_update)(struct dmub_srv *dmub, struct dpp *dpp, @@ -2152,6 +2159,8 @@ void hwss_dpp_set_cursor_attributes(union block_sequence_params *params); void hwss_set_cursor_position(union block_sequence_params *params); +void hwss_program_cursor_position(struct dc *dc, struct pipe_ctx *pipe_ctx); + void hwss_set_cursor_sdr_white_level(union block_sequence_params *params); void hwss_program_gamut_remap(struct pipe_ctx *pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index b6932b9bc206..136c2c2eab1c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -229,6 +229,9 @@ struct hwseq_private_funcs { void (*program_cm_hist)(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); + void (*build_cursor_position)(struct pipe_ctx *pipe_ctx, + struct dc_cursor_position *pos, + struct dc_cursor_mi_param *param); }; struct dce_hwseq { From 08a07e8c254c40f6c23089d259b26a3e51bfbb4f Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 17 Aug 2026 13:38:33 +0200 Subject: [PATCH 086/103] drm/amd/display: fix cursor refactor fallout and sync UT headers [Why] UT mirror headers still declared the old prototypes and hwss_gtest still called the callback directly. Separately, the divide by param.pixel_clk_khz used to sit after hubp401_cursor_set_position()'s "curs_attr.address == 0" early return; hoisting the math into the builder moved it ahead of that guard, so it now traps on streams with no timing programmed. [How] Guard the dst_x_offset block with "if (param.pixel_clk_khz)" Route the test through hwss_program_cursor_position(). Update dc_hwss_ut.h / dc_hwseq_ut.h and the BLS docs to the new signatures. Move the pos/param declarations to the top of the loop body. Reviewed-by: Alvin Lee Signed-off-by: Piotr Maziarz Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/core/dc_hw_sequencer.c | 6 ++--- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 14 deletions(-) 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 3bc0362d9dc0..0a7408692cbe 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 @@ -1396,6 +1396,9 @@ void hwss_build_fast_sequence(struct dc *dc, struct pipe_ctx *cursor_pipe_to_program = NULL; for (i = 0; i < MAX_PIPES; i++) { + struct dc_cursor_position pos; + struct dc_cursor_mi_param param; + current_pipe = &context->res_ctx.pipe_ctx[i]; if (current_pipe->stream != stream || @@ -1419,9 +1422,6 @@ void hwss_build_fast_sequence(struct dc *dc, } } - struct dc_cursor_position pos; - struct dc_cursor_mi_param param; - dc->hwseq->funcs.build_cursor_position(current_pipe, &pos, ¶m); block_sequence[*num_steps].params.set_cursor_position_params.dc = dc; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 8fd60ed7669b..37b699c69144 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -1233,20 +1233,23 @@ void dcn401_build_cursor_position(struct pipe_ctx *pipe_ctx, ASSERT(!pos_cpy.enable || pos_cpy.x_hotspot == 0); } - dst_x_offset = x_pos_viewport - x_hot_viewport * - (1 + hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION); - dst_x_offset = (dst_x_offset >= 0) ? dst_x_offset : 0; - dst_x_offset *= param.ref_clk_khz; - dst_x_offset /= param.pixel_clk_khz; + /* pixel_clk_khz is 0 when no timing is programmed on the stream */ + if (param.pixel_clk_khz) { + dst_x_offset = x_pos_viewport - x_hot_viewport * + (1 + hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION); + dst_x_offset = (dst_x_offset >= 0) ? dst_x_offset : 0; + dst_x_offset *= param.ref_clk_khz; + dst_x_offset /= param.pixel_clk_khz; - ASSERT(param.h_scale_ratio.value); + ASSERT(param.h_scale_ratio.value); - if (param.h_scale_ratio.value) - dst_x_offset = dc_fixpt_floor(dc_fixpt_div( - dc_fixpt_from_int(dst_x_offset), - param.h_scale_ratio)); + if (param.h_scale_ratio.value) + dst_x_offset = dc_fixpt_floor(dc_fixpt_div( + dc_fixpt_from_int(dst_x_offset), + param.h_scale_ratio)); - param.dst_x_offset = dst_x_offset; + param.dst_x_offset = dst_x_offset; + } /* Cursor rectangle cache origin: derived from the final cursor position * minus hotspot, clamped to 0, offset by the recout origin. Precompute From 184a71e58b2e98b6b273ac277687bbf186226971 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 17 Aug 2026 14:25:34 +0200 Subject: [PATCH 087/103] drm/amd/display: clamp cursor hotspot at the register write [Why] dcn401_build_cursor_position() clamped x_hotspot to 0xFF before publishing *pos_out, but that field is also stored into hubp->curs_pos and forwarded to dpp1_set_cursor_position(), which derives src_x_offset from it. The ODM/MPC slice adjustments earlier in the same function deliberately grow x_hotspot past 255 to keep the cursor visible across a slice boundary, so the clamp corrupted DPP source addressing in exactly the case it was meant to handle. [How] Clamp in hubp401_cursor_set_position() instead, where the 8-bit CURSOR_HOT_SPOT_X field lives. A local is used for the register write only; pos->x_hotspot passes through unmodified. Reviewed-by: Alvin Lee Signed-off-by: Piotr Maziarz Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c | 4 +++- drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c index a985c3e00dca..91e87fb51fe4 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c @@ -818,6 +818,8 @@ void hubp401_cursor_set_position( struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); int dst_x_offset = param->dst_x_offset; uint32_t cur_en = pos->enable ? 1 : 0; + /* CURSOR_HOT_SPOT_X is 8 bits wide; clamp only the register write */ + uint32_t x_hotspot_clamped = pos->x_hotspot > 0xFF ? 0xFF : pos->x_hotspot; hubp->curs_pos = *pos; /* @@ -842,7 +844,7 @@ void hubp401_cursor_set_position( CURSOR_Y_POSITION, pos->y); REG_SET_2(CURSOR_HOT_SPOT, 0, - CURSOR_HOT_SPOT_X, pos->x_hotspot, + CURSOR_HOT_SPOT_X, x_hotspot_clamped, CURSOR_HOT_SPOT_Y, pos->y_hotspot); REG_SET(CURSOR_DST_OFFSET, 0, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 37b699c69144..98398dac9861 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -1264,10 +1264,6 @@ void dcn401_build_cursor_position(struct pipe_ctx *pipe_ctx, param.cur_rect_x = rec_x_offset + param.recout.x; param.cur_rect_y = rec_y_offset + param.recout.y; - /* Clamp hotspot to the CURSOR_HOT_SPOT_X register field width */ - if (pos_cpy.x_hotspot > 0xFF) - pos_cpy.x_hotspot = 0xFF; - *pos_out = pos_cpy; *param_out = param; } From fd1ebd27a414460d1c8e6a9475eefa790817426a Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 7 Sep 2026 12:07:01 +0200 Subject: [PATCH 088/103] drm/amd/display: Rename build_cursor_position to dcn10_build_cursor_pos_update_params This commit contains renames, adding const to pipe_ctx in build_cursor_pos_update_params and also removing unnecessary checks before dc_dmub_srv_is_cursor_offload_enabled(). [Why] It improves code clarity. Reviewed-by: Alvin Lee Signed-off-by: Piotr Maziarz Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/core/dc_hw_sequencer.c | 19 +++++++------------ .../gpu/drm/amd/display/dc/core/dc_resource.c | 6 +++--- .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 2 +- .../amd/display/dc/hwss/dcn10/dcn10_hwseq.h | 2 +- .../amd/display/dc/hwss/dcn10/dcn10_init.c | 2 +- .../amd/display/dc/hwss/dcn20/dcn20_init.c | 2 +- .../amd/display/dc/hwss/dcn201/dcn201_init.c | 2 +- .../amd/display/dc/hwss/dcn21/dcn21_init.c | 2 +- .../amd/display/dc/hwss/dcn30/dcn30_init.c | 2 +- .../amd/display/dc/hwss/dcn301/dcn301_init.c | 2 +- .../amd/display/dc/hwss/dcn31/dcn31_init.c | 2 +- .../amd/display/dc/hwss/dcn314/dcn314_init.c | 2 +- .../amd/display/dc/hwss/dcn32/dcn32_init.c | 2 +- .../amd/display/dc/hwss/dcn35/dcn35_init.c | 2 +- .../amd/display/dc/hwss/dcn351/dcn351_init.c | 2 +- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 2 +- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 2 +- .../amd/display/dc/hwss/dcn401/dcn401_init.c | 2 +- .../amd/display/dc/hwss/dcn42/dcn42_init.c | 2 +- .../amd/display/dc/hwss/dcn60/dcn60_init.c | 2 +- .../display/dc/hwss/hw_sequencer_private.h | 2 +- drivers/gpu/drm/amd/display/dc/inc/resource.h | 2 +- 22 files changed, 30 insertions(+), 35 deletions(-) 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 0a7408692cbe..28897addb553 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 @@ -1301,12 +1301,7 @@ void hwss_build_fast_sequence(struct dc *dc, } /* Track cursor lock state - separate locks for attribute and position updates */ - bool enable_cursor_offload = false; - - if ((dc->hwss.set_cursor_attribute && stream->update_flags.bits.cursor_attr) || - (dc->hwseq && dc->hwseq->funcs.build_cursor_position && - dc->hwss.set_cursor_position && stream->update_flags.bits.cursor_pos)) - enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); + bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); /* Cursor attribute updates - separate lock/iterate/unlock */ if (dc->hwss.set_cursor_attribute && stream->update_flags.bits.cursor_attr) { @@ -1391,7 +1386,7 @@ void hwss_build_fast_sequence(struct dc *dc, } /* Cursor position updates */ - if (dc->hwseq && dc->hwseq->funcs.build_cursor_position && + if (dc->hwseq && dc->hwseq->funcs.build_cursor_pos_update_params && dc->hwss.set_cursor_position && stream->update_flags.bits.cursor_pos) { struct pipe_ctx *cursor_pipe_to_program = NULL; @@ -1422,7 +1417,7 @@ void hwss_build_fast_sequence(struct dc *dc, } } - dc->hwseq->funcs.build_cursor_position(current_pipe, &pos, ¶m); + dc->hwseq->funcs.build_cursor_pos_update_params(current_pipe, &pos, ¶m); block_sequence[*num_steps].params.set_cursor_position_params.dc = dc; block_sequence[*num_steps].params.set_cursor_position_params.hubp = current_pipe->plane_res.hubp; @@ -4379,11 +4374,11 @@ void hwss_set_cursor_position(union block_sequence_params *params) void hwss_program_cursor_position(struct dc *dc, struct pipe_ctx *pipe_ctx) { - if (dc->hwseq && dc->hwseq->funcs.build_cursor_position && dc->hwss.set_cursor_position) { + if (dc->hwseq && dc->hwseq->funcs.build_cursor_pos_update_params && dc->hwss.set_cursor_position) { struct dc_cursor_position pos; struct dc_cursor_mi_param param; - dc->hwseq->funcs.build_cursor_position(pipe_ctx, &pos, ¶m); + dc->hwseq->funcs.build_cursor_pos_update_params(pipe_ctx, &pos, ¶m); dc->hwss.set_cursor_position(pipe_ctx->plane_res.hubp, pipe_ctx->plane_res.dpp, &pos, ¶m); } else if (dc->hwss.set_cursor_position_legacy) { @@ -5812,12 +5807,12 @@ void hwss_add_set_cursor_position(struct block_sequence_state *seq_state, struct pipe_ctx *pipe_ctx) { if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE && - dc->hwseq && dc->hwseq->funcs.build_cursor_position && + dc->hwseq && dc->hwseq->funcs.build_cursor_pos_update_params && dc->hwss.set_cursor_position) { struct dc_cursor_position pos; struct dc_cursor_mi_param param; - dc->hwseq->funcs.build_cursor_position(pipe_ctx, &pos, ¶m); + dc->hwseq->funcs.build_cursor_pos_update_params(pipe_ctx, &pos, ¶m); seq_state->steps[*seq_state->num_steps].func = SET_CURSOR_POSITION; seq_state->steps[*seq_state->num_steps].params.set_cursor_position_params.dc = dc; 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 ecbd2b4a0c22..549f9885b762 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1049,7 +1049,7 @@ static struct rect calculate_mpc_slice_in_timing_active( return mpc_rec; } -static void calculate_adjust_recout_for_visual_confirm(struct pipe_ctx *pipe_ctx, +static void calculate_adjust_recout_for_visual_confirm(const struct pipe_ctx *pipe_ctx, unsigned int *base_offset, unsigned int *dpp_offset) { struct dc *dc = pipe_ctx->stream->ctx->dc; @@ -1070,7 +1070,7 @@ static void calculate_adjust_recout_for_visual_confirm(struct pipe_ctx *pipe_ctx } static void reverse_adjust_recout_for_visual_confirm(struct rect *recout, - struct pipe_ctx *pipe_ctx) + const struct pipe_ctx *pipe_ctx) { unsigned int dpp_offset, base_offset; @@ -1775,7 +1775,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) return res; } -bool resource_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) +bool resource_can_pipe_disable_cursor(const struct pipe_ctx *pipe_ctx) { struct pipe_ctx *test_pipe, *split_pipe; struct rect r1 = pipe_ctx->plane_res.scl_data.recout; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index 613f1f62cd80..884319b22cc1 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -3729,7 +3729,7 @@ void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) hubbub->funcs->update_dchub(hubbub, dh_data); } -void dcn10_build_cursor_position(struct pipe_ctx *pipe_ctx, +void dcn10_build_cursor_pos_update_params(const struct pipe_ctx *pipe_ctx, struct dc_cursor_position *pos_out, struct dc_cursor_mi_param *param_out) { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h index 9c4f1186ca9f..383998531503 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h @@ -177,7 +177,7 @@ void dce110_edp_power_control( void dce110_edp_wait_for_hpd_ready( struct dc_link *link, bool power_up); -void dcn10_build_cursor_position(struct pipe_ctx *pipe_ctx, +void dcn10_build_cursor_pos_update_params(const struct pipe_ctx *pipe_ctx, struct dc_cursor_position *pos, struct dc_cursor_mi_param *param); void dcn10_set_cursor_position(struct hubp *hubp, struct dpp *dpp, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c index ddd52722bc49..bc3ac96de688 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c @@ -94,7 +94,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { }; static const struct hwseq_private_funcs dcn10_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .program_pipe = dcn10_program_pipe, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c index 5817fb44d2e0..789bde439192 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c @@ -107,7 +107,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = { }; static const struct hwseq_private_funcs dcn20_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c index d421bc813cbd..33c22d9bbd2e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c @@ -99,7 +99,7 @@ static const struct hw_sequencer_funcs dcn201_funcs = { }; static const struct hwseq_private_funcs dcn201_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = NULL, .plane_atomic_disconnect = dcn201_plane_atomic_disconnect, .program_pipe = dcn10_program_pipe, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c index e691e86629c5..39bf0e51ec7c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c @@ -110,7 +110,7 @@ static const struct hw_sequencer_funcs dcn21_funcs = { }; static const struct hwseq_private_funcs dcn21_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c index f7a095796039..ce42b8216f3b 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c @@ -117,7 +117,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = { }; static const struct hwseq_private_funcs dcn30_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c index 191245bde1ca..5ed4305e4663 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c @@ -113,7 +113,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = { }; static const struct hwseq_private_funcs dcn301_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c index 5500eb46dedb..c7055312cc3d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c @@ -119,7 +119,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = { }; static const struct hwseq_private_funcs dcn31_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c index b278f58b844d..2b04598b0935 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c @@ -122,7 +122,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = { }; static const struct hwseq_private_funcs dcn314_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c index 49387de29382..9d3c7b40b21f 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c @@ -130,7 +130,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { }; static const struct hwseq_private_funcs dcn32_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c index e4864b9606ff..b1933a80fc47 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c @@ -140,7 +140,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = { }; static const struct hwseq_private_funcs dcn35_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn35_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c index f57c0f6adccf..dbd8480b9e05 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c @@ -129,7 +129,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = { }; static const struct hwseq_private_funcs dcn351_private_funcs = { - .build_cursor_position = dcn10_build_cursor_position, + .build_cursor_pos_update_params = dcn10_build_cursor_pos_update_params, .init_pipes = dcn35_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn20_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 98398dac9861..7780f37c615c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -1045,7 +1045,7 @@ void dcn401_disable_link_output(struct dc_link *link, dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); } -void dcn401_build_cursor_position(struct pipe_ctx *pipe_ctx, +void dcn401_build_cursor_pos_update_params(const struct pipe_ctx *pipe_ctx, struct dc_cursor_position *pos_out, struct dc_cursor_mi_param *param_out) { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h index f958ea34a3c6..66a0fc8de8ba 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h @@ -55,7 +55,7 @@ void dcn401_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); -void dcn401_build_cursor_position(struct pipe_ctx *pipe_ctx, +void dcn401_build_cursor_pos_update_params(const struct pipe_ctx *pipe_ctx, struct dc_cursor_position *pos, struct dc_cursor_mi_param *param); void dcn401_set_cursor_position(struct hubp *hubp, struct dpp *dpp, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c index ac5ebe546d0c..2d3c46c4e00c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c @@ -125,7 +125,7 @@ static const struct hw_sequencer_funcs dcn401_funcs = { }; static const struct hwseq_private_funcs dcn401_private_funcs = { - .build_cursor_position = dcn401_build_cursor_position, + .build_cursor_pos_update_params = dcn401_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .plane_atomic_disconnect_sequence = dcn401_plane_atomic_disconnect_sequence, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c index eba34f124e39..a28149411821 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c @@ -129,7 +129,7 @@ static const struct hw_sequencer_funcs dcn42_funcs = { }; static const struct hwseq_private_funcs dcn42_private_funcs = { - .build_cursor_position = dcn401_build_cursor_position, + .build_cursor_pos_update_params = dcn401_build_cursor_pos_update_params, .init_pipes = dcn35_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .update_mpcc = dcn42_update_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c index ce0905820f7e..c89051a542cb 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c @@ -128,7 +128,7 @@ static const struct hw_sequencer_funcs dcn60_funcs = { }; static const struct hwseq_private_funcs dcn60_private_funcs = { - .build_cursor_position = dcn401_build_cursor_position, + .build_cursor_pos_update_params = dcn401_build_cursor_pos_update_params, .init_pipes = dcn10_init_pipes, .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, .plane_atomic_disconnect_sequence = dcn401_plane_atomic_disconnect_sequence, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index 136c2c2eab1c..9586029dcec1 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -229,7 +229,7 @@ struct hwseq_private_funcs { void (*program_cm_hist)(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); - void (*build_cursor_position)(struct pipe_ctx *pipe_ctx, + void (*build_cursor_pos_update_params)(const struct pipe_ctx *pipe_ctx, struct dc_cursor_position *pos, struct dc_cursor_mi_param *param); }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 21a6f90956e8..0d9c9771ea7c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -172,7 +172,7 @@ bool resource_attach_surfaces_to_context( struct dc_state *context, const struct resource_pool *pool); -bool resource_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx); +bool resource_can_pipe_disable_cursor(const struct pipe_ctx *pipe_ctx); #define FREE_PIPE_INDEX_NOT_FOUND -1 From ad1f4faa76d4aee438e89993403a8f6f67ed9431 Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Wed, 9 Sep 2026 13:14:03 -0400 Subject: [PATCH 089/103] drm/amd/display: Remove DCN6 DCFCLK num assert [Why&How] There can be more than 2 DCFCLK values for DCN6, so the assert is not applicable. Remove it. Reviewed-by: Alvin Lee Signed-off-by: Ivan Lipski Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c index c69a0c44eccc..9fce6b472aa6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c @@ -288,8 +288,6 @@ static void dcn6_copy_utm_qos_model(struct utm_qos_model *dest, struct utm_qos_m static void dcn6_initialize_from_soc_bb(struct dml2_utm_soc_bb *utm_soc_bb, const struct dml2_soc_bb *soc_bb) { - DML_ASSERT_MSG(soc_bb->clk_table.dcfclk.num_clk_values == 2, "soc_bb must provide min and max dcfclk values!\n"); - /* initialize based on soc bb */ utm_soc_bb->max_dispclk_khz = soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values - 1]; utm_soc_bb->max_dppclk_khz = soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values - 1]; From c66847b01c5d8e8b2eb24b4370a277f557a74218 Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Thu, 10 Sep 2026 15:44:20 -0400 Subject: [PATCH 090/103] drm/amd/display: Resync cursor cache after offload abort on DCN60 [Why&How] The cursor programming path caches the last-written cursor state in SW and, for the enable bit, skips the register write when the cache already matches the request. Under cursor offload the SW cache is updated even though the actual register write is deferred to firmware. When an offloaded cursor update is aborted (e.g. an overlay geometry change reprograms the cursor directly in the same frame), the queued firmware write is dropped but the cache is left stale, so the following direct programming pass skips the enable write and the cursor disappears over the overlay plane. Add a refresh_cursor_state() hubp/dpp hook that reads the cursor position and attribute registers back from hardware into the SW cache, and call it from dcn35_abort_cursor_offload_update() so the cache is truthful after an abort. This keeps the enable-change optimization intact for all ASICs and is race-robust regardless of whether firmware applied the queued write before the abort. Only dcn60 (the sole offload user) wires up the hook. Assisted-by: Copilot:Claude-Opus-4.8 Reviewed-by: Nicholas Kazlauskas Signed-off-by: Ivan Lipski Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/dpp/dcn401/dcn401_dpp.h | 2 + .../amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c | 19 +++++++ .../drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c | 1 + .../amd/display/dc/hubp/dcn401/dcn401_hubp.c | 54 +++++++++++++++++++ .../amd/display/dc/hubp/dcn401/dcn401_hubp.h | 2 + .../amd/display/dc/hubp/dcn60/dcn60_hubp.c | 1 + .../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 11 ++++ drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 2 + drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 2 + 9 files changed, 94 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp.h b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp.h index a57eb1cd77a6..e34d291de37b 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp.h @@ -725,6 +725,8 @@ void dpp401_set_cursor_position( uint32_t width, uint32_t height); +void dpp401_cursor_refresh_state(struct dpp *dpp_base); + void dpp401_set_optional_cursor_attributes( struct dpp *dpp_base, struct dpp_cursor_attributes *attr); diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c index 340111e3deac..c6de8518108e 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c @@ -144,6 +144,25 @@ void dpp401_set_cursor_position( dpp_base->att.cur0_ctl.bits.cur0_enable = cur_en; } +/* Resync the SW cursor cache from real hardware state. */ +void dpp401_cursor_refresh_state(struct dpp *dpp_base) +{ + struct dcn401_dpp *dpp = TO_DCN401_DPP(dpp_base); + uint32_t cur0_enable = 0, mode = 0, expansion_mode = 0, rom_en = 0; + + REG_GET_4(CURSOR0_CONTROL, + CUR0_ENABLE, &cur0_enable, + CUR0_MODE, &mode, + CUR0_EXPANSION_MODE, &expansion_mode, + CUR0_ROM_EN, &rom_en); + + dpp_base->pos.cur0_ctl.bits.cur0_enable = cur0_enable; + dpp_base->att.cur0_ctl.bits.cur0_enable = cur0_enable; + dpp_base->att.cur0_ctl.bits.mode = mode; + dpp_base->att.cur0_ctl.bits.expansion_mode = expansion_mode; + dpp_base->att.cur0_ctl.bits.cur0_rom_en = rom_en; +} + void dpp401_set_optional_cursor_attributes( struct dpp *dpp_base, struct dpp_cursor_attributes *attr) diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c index 24a686e94171..f02aebcedd70 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn60/dcn60_dpp.c @@ -308,6 +308,7 @@ static struct dpp_funcs dcn60_dpp_funcs = { .dpp_cnv_set_alpha_keyer = dpp2_cnv_set_alpha_keyer, .set_cursor_attributes = dpp401_set_cursor_attributes, .set_cursor_position = dpp401_set_cursor_position, + .refresh_cursor_state = dpp401_cursor_refresh_state, .set_optional_cursor_attributes = dpp401_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp3_set_hdr_multiplier, diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c index 91e87fb51fe4..798d0dad9153 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c @@ -862,6 +862,60 @@ void hubp401_cursor_set_position( hubp->cur_rect.y = param->cur_rect_y; } +void hubp401_cursor_refresh_state(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t enable = 0, x_pos = 0, y_pos = 0, x_hot = 0, y_hot = 0, dst_x_offset = 0; + uint32_t addr_high = 0, addr_low = 0, width = 0, height = 0; + uint32_t mode = 0, magnify = 0, pitch = 0, lpc = 0; + uint32_t dst_y_offset = 0, chunk_hdl_adjust = 0; + + /* Resync the SW cursor cache from real hardware state. */ + + /* Position */ + REG_GET(CURSOR_CONTROL, CURSOR_ENABLE, &enable); + REG_GET_2(CURSOR_POSITION, + CURSOR_X_POSITION, &x_pos, + CURSOR_Y_POSITION, &y_pos); + REG_GET_2(CURSOR_HOT_SPOT, + CURSOR_HOT_SPOT_X, &x_hot, + CURSOR_HOT_SPOT_Y, &y_hot); + REG_GET(CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, &dst_x_offset); + + hubp->pos.cur_ctl.bits.cur_enable = enable; + hubp->pos.position.bits.x_pos = x_pos; + hubp->pos.position.bits.y_pos = y_pos; + hubp->pos.hot_spot.bits.x_hot = x_hot; + hubp->pos.hot_spot.bits.y_hot = y_hot; + hubp->pos.dst_offset.bits.dst_x_offset = dst_x_offset; + + /* Attributes */ + REG_GET(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, &addr_high); + REG_GET(CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, &addr_low); + REG_GET_2(CURSOR_SIZE, + CURSOR_WIDTH, &width, + CURSOR_HEIGHT, &height); + REG_GET_4(CURSOR_CONTROL, + CURSOR_MODE, &mode, + CURSOR_2X_MAGNIFY, &magnify, + CURSOR_PITCH, &pitch, + CURSOR_LINES_PER_CHUNK, &lpc); + REG_GET_2(CURSOR_SETTINGS, + CURSOR0_DST_Y_OFFSET, &dst_y_offset, + CURSOR0_CHUNK_HDL_ADJUST, &chunk_hdl_adjust); + + hubp->att.SURFACE_ADDR_HIGH = addr_high; + hubp->att.SURFACE_ADDR = addr_low; + hubp->att.size.bits.width = width; + hubp->att.size.bits.height = height; + hubp->att.cur_ctl.bits.mode = mode; + hubp->att.cur_ctl.bits.cur_2x_magnify = magnify; + hubp->att.cur_ctl.bits.pitch = pitch; + hubp->att.cur_ctl.bits.line_per_chunk = lpc; + hubp->att.settings.bits.dst_y_offset = dst_y_offset; + hubp->att.settings.bits.chunk_hdl_adjust = chunk_hdl_adjust; +} + void hubp401_read_state(struct hubp *hubp) { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h index 818cea479272..05078a21a123 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h @@ -313,6 +313,8 @@ void hubp401_cursor_set_position( const struct dc_cursor_position *pos, const struct dc_cursor_mi_param *param); +void hubp401_cursor_refresh_state(struct hubp *hubp); + void hubp401_read_state(struct hubp *hubp); bool hubp401_construct( diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn60/dcn60_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn60/dcn60_hubp.c index 01b6b3ed5a99..4af60e473bd9 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn60/dcn60_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn60/dcn60_hubp.c @@ -427,6 +427,7 @@ static struct hubp_funcs dcn60_hubp_funcs = { .mem_program_viewport = hubp401_set_viewport, .set_cursor_attributes = hubp60_cursor_set_attributes, .set_cursor_position = hubp401_cursor_set_position, + .refresh_cursor_state = hubp401_cursor_refresh_state, .hubp_clk_cntl = hubp2_clk_cntl, .hubp_vtg_sel = hubp2_vtg_sel, .dmdata_set_attributes = hubp3_dmdata_set_attributes, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index f9d8ff6ce010..a959d8c37b6a 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -1671,6 +1671,17 @@ void dcn35_abort_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, s if (dc->hwss.commit_cursor_offload_update) dc->hwss.commit_cursor_offload_update(dmub, dpp, hubp, stream_idx); + + /* + * The aborted payload is dropped by firmware, so resync the SW cursor + * cache from real hardware state. This lets the next direct + * set_cursor_position re-program CURSOR_ENABLE instead of skipping it + * because of a stale cache. + */ + if (dpp->funcs->refresh_cursor_state) + dpp->funcs->refresh_cursor_state(dpp); + if (hubp && hubp->funcs->refresh_cursor_state) + hubp->funcs->refresh_cursor_state(hubp); } void dcn35_begin_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 930b5533256f..71244d3b6c90 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -330,6 +330,8 @@ struct dpp_funcs { uint32_t height ); + void (*refresh_cursor_state)(struct dpp *dpp_base); + void (*dpp_set_hdr_multiplier)( struct dpp *dpp_base, uint32_t multiplier); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index a648ed3b012a..d1cbcb87d271 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -219,6 +219,8 @@ struct hubp_funcs { const struct dc_cursor_position *pos, const struct dc_cursor_mi_param *param); + void (*refresh_cursor_state)(struct hubp *hubp); + void (*hubp_disconnect)(struct hubp *hubp); void (*hubp_clk_cntl)(struct hubp *hubp, bool enable); From 708d3e7aeec1cfd53fe6b9b048e92ac3eca6c59a Mon Sep 17 00:00:00 2001 From: Tony Qi Date: Wed, 9 Sep 2026 09:41:25 -0400 Subject: [PATCH 091/103] drm/amd/display: Revert "request DMUB HW cursor offload" This reverts commit 555641725f21 ("drm/amd/display: Request DMUB HW cursor offload"). [WHY] This commit causes the following failures on DCN42: igt@kms_plane_cursor@viewport igt@kms_plane_cursor@overlay Reviewed-by: Alex Hung Signed-off-by: Tony Qi Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ---------- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 9 +-------- 2 files changed, 1 insertion(+), 18 deletions(-) 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 86c7e16ba9c5..2b0686bcc7fd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -605,13 +605,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.flags.enable_mipi_converter_optimization = true; - /* - * Request HW cursor offload so DMUB programs the cursor; cursor - * updates then avoid the DMUB inbox0 HW lock during mclk switches. - * dc_dmub_srv_cursor_offload_init() self-gates on FW capability. - */ - init_data.flags.enable_cursor_offload = true; - init_data.dcn_reg_offsets = adev->reg_offset[DCE_HWIP][0]; init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0]; init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0]; @@ -729,9 +722,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) dc_hardware_init(adev->dm.dc); - /* Enable cursor offload if the DMUB firmware supports it. */ - dc_dmub_srv_cursor_offload_init(adev->dm.dc); - /* GOP/vBIOS may leave an OPTC enabled for a display present at power-on * but no longer driven (e.g. an external DP unplugged at boot). Such a * dangling pipe keeps DCN out of idle and blocks s0i3. Power it down diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 37248ecc3c08..d9af53f720f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -1250,16 +1250,9 @@ void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, con void dc_dmub_srv_cursor_offload_init(struct dc *dc) { struct dmub_rb_cmd_cursor_offload_init *init; - struct dc_dmub_srv *dc_dmub_srv; + struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; union dmub_rb_cmd cmd; - if (!dc || !dc->ctx) - return; - - dc_dmub_srv = dc->ctx->dmub_srv; - if (!dc_dmub_srv || !dc_dmub_srv->dmub) - return; - if (!dc->config.enable_cursor_offload) return; From 92dd8d3edf395efbe812d29dba763098885befbe Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 11 Sep 2026 10:29:02 -0600 Subject: [PATCH 092/103] drm/amd/display: Fix LSDMA divide by zero [WHY] element_size_to_bytes_per_pixel() handled only element sizes 0 to 4 and returned 0 for every other value, and an unexpected element size caused a divide by zero. [HOW] Derive the size as 1 << element_size, which matches the existing encoding, and fall back to 1 for values of 8 or more to keep the result nonzero. Reviewed-by: Austin Zheng Signed-off-by: Alex Hung Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../alternate_pstate_shared_lib.c | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/alternate_pstate_shared_lib.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/alternate_pstate_shared_lib.c index 53ead9f687ac..f082f058001e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/alternate_pstate_shared_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_standalone_libraries/alternate_pstate_shared_lib.c @@ -884,27 +884,7 @@ static void populate_lsdma_start_end_lines( static uint8_t element_size_to_bytes_per_pixel(uint8_t element_size) { - uint8_t bytes_per_pixel = 0; - - switch (element_size) { // 0: 8bpp, 1: 16bpp, 2: 32bpp, 3: 64bpp, 4: 128bpp - Values supported by LSDMA Controller - case 0: - bytes_per_pixel = 1; - break; - case 1: - bytes_per_pixel = 2; - break; - case 2: - bytes_per_pixel = 4; - break; - case 3: - bytes_per_pixel = 8; - break; - case 4: - bytes_per_pixel = 16; - break; - } - - return bytes_per_pixel; + return element_size < 8 ? (uint8_t)(1U << element_size) : 1; } static void populate_lsdma( From ded0ecb2453351b72a4e0fee82b519484419cfd7 Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Sat, 12 Sep 2026 12:03:40 -0400 Subject: [PATCH 093/103] drm/amd/display: [FW Promotion] Release 0.1.76.0 Updated DMUB interface - Add OEM visual debug flags - Updated HW lock pending error - Add new DMUB_CMD__NBIF_AZ_PME_RESTORE command Reviewed-by: Alex Hung Signed-off-by: Taimur Hassan Signed-off-by: George Zhang Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index f3e1a41897bf..525e679b81d5 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -582,7 +582,14 @@ union replay_debug_flags { */ uint32_t enable_sub_feature_visual_confirm : 1; - uint32_t reserved : 16; + /** + * 0x10000 (bit 16) + * @enable_oem_visual_confirm: Enable OEM visual confirm + * Black = state 0, Blue = state non-zero, Green = frame skipping active + */ + uint32_t enable_oem_visual_confirm : 1; + + uint32_t reserved : 15; } bitfields; uint32_t u32All; @@ -743,7 +750,14 @@ union pr_debug_flags { */ uint32_t force_hubp_on : 1; - uint32_t reserved : 24; + /** + * 0x100 (bit 8) + * @enable_oem_visual_confirm: Enable OEM visual confirm + * Black = state 0, Blue = state non-zero + */ + uint32_t enable_oem_visual_confirm : 1; + + uint32_t reserved : 23; } bitfields; uint32_t u32All; @@ -2044,6 +2058,11 @@ enum dmub_cmd_type { */ DMUB_CMD__DC_BLS = 98, + /** + * Command type used to notify nbif az pme restore. + */ + DMUB_CMD__NBIF_AZ_PME_RESTORE = 99, + /** * Command type use for VBIOS shared commands. */ @@ -3633,6 +3652,28 @@ struct dmub_rb_cmd_query_hpd_state { struct dmub_cmd_hpd_state_query_data data; }; +/** + * Data passed from driver to FW in a DMUB_CMD__NBIF_AZ_PME_RESTORE command. + */ +struct dmub_cmd_nbif_az_pme_restore_data { + uint8_t az_inst; /**< Azalia codec endpoint instance */ + uint8_t pad[3]; /**< Alignment */ +}; + +/** + * Definition of a DMUB_CMD__NBIF_AZ_PME_RESTORE command. + */ +struct dmub_rb_cmd_nbif_az_pme_restore { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Data passed from driver to FW in a DMUB_CMD__NBIF_AZ_PME_RESTORE command. + */ + struct dmub_cmd_nbif_az_pme_restore_data data; +}; + /** * struct dmub_rb_cmd_hpd_sense_notify - HPD sense notification data. */ @@ -7807,6 +7848,11 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__QUERY_HPD_STATE command. */ struct dmub_rb_cmd_query_hpd_state query_hpd; + + /** + * Definition of a DMUB_CMD__NBIF_AZ_PME_RESTORE command. + */ + struct dmub_rb_cmd_nbif_az_pme_restore nbif_az_pme_restore; /** * Definition of a DMUB_CMD__SECURE_DISPLAY command. */ From 2e81792c39d696333c046cd9f01d6b8aff76bff4 Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Sat, 12 Sep 2026 13:02:23 -0500 Subject: [PATCH 094/103] drm/amd/display: Promote DC to 3.2.399 This DC patchset brings improvements in multiple areas. In summary, we have: - Increased KUnit coverage - Reverts a patch causing regression on DCN42 - Fixes for cursor - Imporvements for ABM Reviewed-by: George Zhang Signed-off-by: Taimur Hassan 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(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 5174a0098e75..c8e6e949ce79 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -67,7 +67,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.398" +#define DC_VER "3.2.399" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC From b51576a5d53eaf53e07b07c4841f6981e542b63c Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Fri, 18 Sep 2026 10:44:39 -0400 Subject: [PATCH 095/103] drm/amd/display: Fix null deref of link_enc in dce110_enable_tmds_link_output Smatch reports that link->link_enc is unconditionally dereferenced at the top of dce110_enable_tmds_link_output() while the later setup_ri_pj_check_in_sw_or_hw_mode calls guard against it being NULL, making those checks contradictory. Add an early return when link_enc is NULL and drop the redundant NULL checks from the two call sites that follow, since link_enc is guaranteed non-NULL past the guard Fixes: 992694ad2858 ("drm/amd/display: Enable DCN6 sources compilation") Reported-by: Dan Carpenter Cc: Aurabindo Pillai Cc: Roman Li Cc: Ivan Lipski Cc: Dan Wheeler Cc: Alex Hung Cc: Tom Chung Signed-off-by: Srinivasan Shanmugam Reviewed-by: Alex Hung Reviewed-by: Fangzhi Zuo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index d48894017c0e..a7e535639245 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -3487,6 +3487,10 @@ void dce110_enable_tmds_link_output(struct dc_link *link, uint32_t pixel_clock) { (void)link_res; + + if (!link->link_enc) + return; + link->link_enc->funcs->enable_tmds_output( link->link_enc, clock_source, @@ -3497,12 +3501,12 @@ void dce110_enable_tmds_link_output(struct dc_link *link, // For dongle Type 2 with no I2C support on board, setup sw mode of Ri/Pj check with proper aux instance if (link->force_to_use_aux) { - if (link->link_enc && link->link_enc->funcs->setup_ri_pj_check_in_sw_or_hw_mode) + if (link->link_enc->funcs->setup_ri_pj_check_in_sw_or_hw_mode) link->link_enc->funcs->setup_ri_pj_check_in_sw_or_hw_mode(link->link_enc, link->aux_hw_inst, true); } else // For HDMI setup hw mode of Ri/Pj check with proper ddc pin instance - if (link->link_enc && link->link_enc->funcs->setup_ri_pj_check_in_sw_or_hw_mode) + if (link->link_enc->funcs->setup_ri_pj_check_in_sw_or_hw_mode) link->link_enc->funcs->setup_ri_pj_check_in_sw_or_hw_mode(link->link_enc, link->ddc_hw_inst, false); } From e53e12cb4ccb95e19c5efeb8172ff79a7ace963d Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 18 Sep 2026 09:15:48 +0530 Subject: [PATCH 096/103] drm/amd/pm: Create NPM sysfs files from capability Advertise each NPM board attribute from a per-field R/W bitmap instead of probing a single sensor. SMU 13.0.6/13.0.12 reports the cap only when NPM metrics and MaxNodePowerLimit are present. Signed-off-by: Lijo Lazar Assisted-by: Cursor Grok 4.6 Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- .../gpu/drm/amd/include/kgd_pp_interface.h | 16 +++++++ drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 23 +++++++++ drivers/gpu/drm/amd/pm/amdgpu_pm.c | 47 +++++++++++++------ drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 1 + drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 11 +++++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 7 +++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 19 ++++++++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 1 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h | 1 + 9 files changed, 111 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 606d48115301..5e8476c4b808 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -174,6 +174,21 @@ enum amd_pp_sensors { AMDGPU_PP_SENSOR_UBB_POWER_LIMIT, }; +/* + * NPM sysfs capability bitmap: two bits per field, R then W. + * 00 = unsupported, 01 = read-only, 1x = writable (or RW). + */ +enum amdgpu_npm_cap_field { + AMDGPU_NPM_CAP_CUR_NODE_POWER_LIMIT, + AMDGPU_NPM_CAP_NODE_POWER, + AMDGPU_NPM_CAP_GLOBAL_PPT_RESID, + AMDGPU_NPM_CAP_MAX_NODE_POWER_LIMIT, + AMDGPU_NPM_CAP_NPM_STATUS, +}; + +#define AMDGPU_NPM_CAP_R(field) BIT_ULL((field) * 2) +#define AMDGPU_NPM_CAP_W(field) BIT_ULL((field) * 2 + 1) + enum amd_pp_task { AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, AMD_PP_TASK_ENABLE_USER_STATE, @@ -513,6 +528,7 @@ struct amd_pm_funcs { ssize_t (*get_gpu_metrics)(void *handle, void **table); ssize_t (*get_temp_metrics)(void *handle, enum smu_temp_metric_type type, void *table); bool (*temp_metrics_is_supported)(void *handle, enum smu_temp_metric_type type); + u64 (*get_npm_cap)(void *handle); ssize_t (*get_xcp_metrics)(void *handle, int xcp_id, void *table); ssize_t (*get_pm_metrics)(void *handle, void *pmmetrics, size_t size); int (*set_watermarks_for_clock_ranges)(void *handle, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index c70fd6691461..df5bbdab1ea3 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -2101,6 +2101,29 @@ bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev, return support_temp_metrics; } +/** + * amdgpu_dpm_get_npm_cap - Return NPM sysfs capability bitmap + * @adev: Pointer to the device. + * + * Two bits per field (R then W). Both 0 means the field is unsupported. + * + * Return: Capability bitmap, or 0 if NPM is not supported. + */ +u64 amdgpu_dpm_get_npm_cap(struct amdgpu_device *adev) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + u64 cap = 0; + + if (!pp_funcs || !pp_funcs->get_npm_cap) + return 0; + + mutex_lock(&adev->pm.mutex); + cap = pp_funcs->get_npm_cap(adev->powerplay.pp_handle); + mutex_unlock(&adev->pm.mutex); + + return cap; +} + /** * amdgpu_dpm_get_xcp_metrics - Retrieve metrics for a specific compute * partition diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index c0e677328af5..6f8252376127 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -4726,6 +4726,37 @@ err_out: return ret; } +static void amdgpu_pm_npm_sysfs_init(struct amdgpu_device *adev) +{ + static const struct { + struct device_attribute *attr; + unsigned int field; + } files[] = { + { &dev_attr_cur_node_power_limit, AMDGPU_NPM_CAP_CUR_NODE_POWER_LIMIT }, + { &dev_attr_node_power, AMDGPU_NPM_CAP_NODE_POWER }, + { &dev_attr_global_ppt_resid, AMDGPU_NPM_CAP_GLOBAL_PPT_RESID }, + { &dev_attr_max_node_power_limit, AMDGPU_NPM_CAP_MAX_NODE_POWER_LIMIT }, + { &dev_attr_npm_status, AMDGPU_NPM_CAP_NPM_STATUS }, + }; + u64 cap = amdgpu_dpm_get_npm_cap(adev); + int i; + + if (!cap) + return; + + for (i = 0; i < ARRAY_SIZE(files); i++) { + unsigned int bits = (cap >> (files[i].field * 2)) & 0x3; + struct device_attribute *attr = files[i].attr; + + if (!bits) + continue; + + attr->attr.mode = ((bits & BIT(1)) && attr->store) ? 0644 : 0444; + sysfs_add_file_to_group(&adev->dev->kobj, &attr->attr, + amdgpu_board_attr_group.name); + } +} + int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) { enum amdgpu_sriov_vf_mode mode; @@ -4797,21 +4828,7 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) &amdgpu_board_attr_group); if (ret) goto err_out1; - if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT, - (void *)&tmp) != -EOPNOTSUPP) { - sysfs_add_file_to_group(&adev->dev->kobj, - &dev_attr_cur_node_power_limit.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_node_power.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_global_ppt_resid.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, - &dev_attr_max_node_power_limit.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_npm_status.attr, - amdgpu_board_attr_group.name); - } + amdgpu_pm_npm_sysfs_init(adev); if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER_LIMIT, (void *)&tmp) != -EOPNOTSUPP) { sysfs_add_file_to_group(&adev->dev->kobj, diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index 8e8a052e1d53..ed1e7385243d 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -614,5 +614,6 @@ int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask); bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev); bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev, enum smu_temp_metric_type type); +u64 amdgpu_dpm_get_npm_cap(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 3d143caecfc1..a65aa2129845 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -3985,6 +3985,16 @@ static bool smu_temp_metrics_is_supported(void *handle, enum smu_temp_metric_typ return ret; } +static u64 smu_get_npm_cap(void *handle) +{ + struct smu_context *smu = handle; + + if (!smu->pm_enabled || !smu->ppt_funcs || !smu->ppt_funcs->get_npm_cap) + return 0; + + return smu->ppt_funcs->get_npm_cap(smu); +} + static ssize_t smu_sys_get_xcp_metrics(void *handle, int xcp_id, void *table) { struct smu_context *smu = handle; @@ -4059,6 +4069,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_xcp_metrics = smu_sys_get_xcp_metrics, .get_temp_metrics = smu_sys_get_temp_metrics, .temp_metrics_is_supported = smu_temp_metrics_is_supported, + .get_npm_cap = smu_get_npm_cap, }; int smu_wait_for_event(struct smu_context *smu, enum smu_event_type event, 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 cad8b1cce794..1e5fc6ff76c8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1619,6 +1619,13 @@ struct pptable_funcs { */ ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id, void *table); + /** + * @get_npm_cap: Return NPM sysfs capability bitmap. + * + * Two bits per field (R then W). Both 0 means the field is + * unsupported. + */ + u64 (*get_npm_cap)(struct smu_context *smu); /** * @ras_send_msg: Send a message with a parameter from Ras * &msg: Type of message. diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index d8ddad531d26..0ca5973391e8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -695,6 +695,25 @@ int smu_v13_0_12_get_npm_data(struct smu_context *smu, return ret; } +u64 smu_v13_0_12_get_npm_cap(struct smu_context *smu) +{ + struct PPTable_t *pptable = + (struct PPTable_t *)smu->smu_table.driver_pptable; + u64 cap = 0; + + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(NPM_METRICS)) || + !pptable->MaxNodePowerLimit) + return 0; + + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_CUR_NODE_POWER_LIMIT); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_NODE_POWER); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_GLOBAL_PPT_RESID); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_MAX_NODE_POWER_LIMIT); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_NPM_STATUS); + + return cap; +} + static ssize_t smu_v13_0_12_get_temp_metrics(struct smu_context *smu, enum smu_temp_metric_type type, void *table) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index ee380488d212..83a5a4614a4b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -3312,6 +3312,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .get_gpu_metrics = smu_v13_0_6_get_gpu_metrics, .get_pm_metrics = smu_v13_0_6_get_pm_metrics, .get_xcp_metrics = smu_v13_0_6_get_xcp_metrics, + .get_npm_cap = smu_v13_0_12_get_npm_cap, .get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range, .mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported, .mode1_reset = smu_v13_0_6_mode1_reset, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h index 6554780afff7..1b6926625cc3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h @@ -111,6 +111,7 @@ void smu_v13_0_12_tables_fini(struct smu_context *smu); int smu_v13_0_12_get_npm_data(struct smu_context *smu, enum amd_pp_sensors sensor, uint32_t *value); +u64 smu_v13_0_12_get_npm_cap(struct smu_context *smu); int smu_v13_0_12_get_system_power(struct smu_context *smu, enum amd_pp_sensors sensor, uint32_t *value); From 29529ded8645855bc397476aca26610e6017a502 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 18 Sep 2026 11:38:16 +0530 Subject: [PATCH 097/103] drm/amd/pm: Add NPM status sensor The logic for checking whether NPM is enabled/disabled stays within the particular IP version. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 + drivers/gpu/drm/amd/pm/amdgpu_pm.c | 9 ++++----- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 3 +++ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 4 ++++ 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 5e8476c4b808..4b863a2e38f1 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -172,6 +172,7 @@ enum amd_pp_sensors { AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT, AMDGPU_PP_SENSOR_UBB_POWER, AMDGPU_PP_SENSOR_UBB_POWER_LIMIT, + AMDGPU_PP_SENSOR_NPMSTATUS, }; /* diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 6f8252376127..c6e3748bb11b 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2266,16 +2266,15 @@ static ssize_t amdgpu_show_npm_status(struct device *dev, { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - u32 npower; + u32 npm_status; int r; - /* get the node power */ - r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NODEPOWER, - (void *)&npower); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NPMSTATUS, + (void *)&npm_status); if (r) return r; - return sysfs_emit(buf, "%s\n", str_enabled_disabled(npower)); + return sysfs_emit(buf, "%s\n", str_enabled_disabled(npm_status)); } /** diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 0ca5973391e8..1691a0be4f7d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -685,6 +685,9 @@ int smu_v13_0_12_get_npm_data(struct smu_context *smu, case AMDGPU_PP_SENSOR_NODEPOWER: *value = SMUQ10_ROUND(metrics->NodePower); break; + case AMDGPU_PP_SENSOR_NPMSTATUS: + *value = !!SMUQ10_ROUND(metrics->NodePower); + break; case AMDGPU_PP_SENSOR_GPPTRESIDENCY: *value = SMUQ10_ROUND(metrics->GlobalPPTResidencyAcc); break; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 83a5a4614a4b..95e288327e45 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -1678,6 +1678,7 @@ static int smu_v13_0_6_read_sensor(struct smu_context *smu, case AMDGPU_PP_SENSOR_NODEPOWER: case AMDGPU_PP_SENSOR_GPPTRESIDENCY: case AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT: + case AMDGPU_PP_SENSOR_NPMSTATUS: ret = smu_v13_0_12_get_npm_data(smu, sensor, (uint32_t *)data); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index d6cc603de7b6..93486be4e17b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -618,6 +618,9 @@ static int smu_v15_0_8_get_npm_data(struct smu_context *smu, case AMDGPU_PP_SENSOR_NODEPOWER: *value = SMUQ10_ROUND(metrics->NodePower); break; + case AMDGPU_PP_SENSOR_NPMSTATUS: + *value = !!SMUQ10_ROUND(metrics->NodePower); + break; case AMDGPU_PP_SENSOR_GPPTRESIDENCY: *value = SMUQ10_ROUND(metrics->GlobalPPTResidencyAcc); break; @@ -681,6 +684,7 @@ static int smu_v15_0_8_read_sensor(struct smu_context *smu, case AMDGPU_PP_SENSOR_NODEPOWER: case AMDGPU_PP_SENSOR_GPPTRESIDENCY: case AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT: + case AMDGPU_PP_SENSOR_NPMSTATUS: ret = smu_v15_0_8_get_npm_data(smu, sensor, (uint32_t *)data); if (ret) return ret; From fc6275c7fc9d0b9c590d23d01033613aa26b14c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 26 May 2026 15:20:28 +0200 Subject: [PATCH 098/103] drm/amdgpu: nuke most amdgpu_vm_eviction_(try)lock uses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use scoped_guard/scoped_cond_guard instead. Saving and restoring the GFP flags is not necessary in those use case. Signed-off-by: Christian König Reviewed-by: Natalie Vock Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 27 +++++++++---------- .../gpu/drm/amd/amdgpu/amdgpu_vm_internal.h | 9 ------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index ed92dc1a29e7..0b8a8f82ecab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -617,9 +617,8 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, * As soon as all page tables are in place we can start updating them * again. */ - amdgpu_vm_eviction_lock(vm); - vm->evicting = false; - amdgpu_vm_eviction_unlock(vm); + scoped_guard(mutex, &vm->eviction_lock) + vm->evicting = false; list_for_each_entry_safe(bo_base, tmp, &vm->always_valid.evicted, vm_status) { @@ -679,9 +678,8 @@ bool amdgpu_vm_ready(struct amdgpu_vm *vm) amdgpu_vm_assert_locked(vm); - amdgpu_vm_eviction_lock(vm); - ret = !vm->evicting; - amdgpu_vm_eviction_unlock(vm); + scoped_guard(mutex, &vm->eviction_lock) + ret = !vm->evicting; ret &= list_empty(&vm->kernel.evicted); @@ -2275,6 +2273,7 @@ void amdgpu_vm_bo_del(struct amdgpu_device *adev, bool amdgpu_vm_evictable(struct amdgpu_bo *bo) { struct amdgpu_vm_bo_base *bo_base = bo->vm_bo; + struct amdgpu_vm *vm; /* Page tables of a destroyed VM can go away immediately */ if (!bo_base || !bo_base->vm) @@ -2285,17 +2284,15 @@ bool amdgpu_vm_evictable(struct amdgpu_bo *bo) return false; /* Try to block ongoing updates */ - if (!amdgpu_vm_eviction_trylock(bo_base->vm)) - return false; + vm = bo_base->vm; + scoped_cond_guard(mutex_try, return false, &vm->eviction_lock) { - /* Don't evict VM page tables while they are updated */ - if (!dma_fence_is_signaled(bo_base->vm->last_unlocked)) { - amdgpu_vm_eviction_unlock(bo_base->vm); - return false; + /* Don't evict VM page tables while they are updated */ + if (!dma_fence_is_signaled(vm->last_unlocked)) + return false; + + vm->evicting = true; } - - bo_base->vm->evicting = true; - amdgpu_vm_eviction_unlock(bo_base->vm); return true; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h index 447195cc4593..ca86eaac7523 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h @@ -137,15 +137,6 @@ static inline void amdgpu_vm_eviction_lock(struct amdgpu_vm *vm) vm->saved_flags = memalloc_noreclaim_save(); } -static inline bool amdgpu_vm_eviction_trylock(struct amdgpu_vm *vm) -{ - if (mutex_trylock(&vm->eviction_lock)) { - vm->saved_flags = memalloc_noreclaim_save(); - return true; - } - return false; -} - static inline void amdgpu_vm_eviction_unlock(struct amdgpu_vm *vm) { memalloc_noreclaim_restore(vm->saved_flags); From 57ec117d628e232b59c0328a52f63b1f43a1e2d9 Mon Sep 17 00:00:00 2001 From: Jay Cornwall Date: Thu, 17 Sep 2026 18:06:19 -0500 Subject: [PATCH 099/103] drm/amdkfd: Preserve v1 in gfx12.1 trap workaround If MODE.DST_VGPR_MSB != MODE.SRC0_VGPR_MSB upon trap entry then v1 would be trashed. Adjust workaround to prefetch random address 0xFFFFFFFFxxxxxxxx. This address space is unavailable to userspace on gfx12.1, ensuring no functional side-effects of prefetch. Also remove unused WAVE_START exception handler. Fixes: 0e1e0f87af55 ("drm/amdkfd: gfx12.1 add no-op prefetch on trap entry") Signed-off-by: Jay Cornwall Reviewed-by: Lancelot Six Cc: Joseph Greathouse Cc: Vladimir Indic Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdkfd/cwsr_trap_handler.h | 1262 ++++++++--------- .../amd/amdkfd/cwsr_trap_handler_gfx12.asm | 23 +- 2 files changed, 632 insertions(+), 653 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index 8cf3527dc156..5cf306de0d96 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -4601,415 +4601,373 @@ static const uint32_t cwsr_trap_gfx9_5_0_hex[] = { }; static const uint32_t cwsr_trap_gfx12_1_0_hex[] = { - 0xbfa00001, 0xbfa003f1, + 0xbfa00001, 0xbfa003e2, 0xb0804009, 0xb8f8f804, - 0xb8faf811, 0xbf0d887a, - 0xbfa10008, 0xb9800211, - 0x00000000, 0xbeee0180, - 0x7e020280, 0xee17406e, - 0x00040000, 0x00000001, - 0xbe804a6c, 0xbefa007e, - 0xbefe0081, 0xd760007b, - 0x00010101, 0xbeee0180, - 0x7e020280, 0xee17406e, - 0x00040000, 0x00000001, - 0xd7610001, 0x0001007b, - 0xbefe007a, 0x9178ff78, - 0x00008c00, 0xb8fbf811, - 0xbf0c877b, 0xbfa20002, - 0x916dff6d, 0xf0000000, - 0xbf0d857b, 0xbfa10006, - 0x917bff7b, 0x00000480, + 0xbefa007e, 0xbefe0081, + 0xbeee0080, 0xbeef00c1, + 0xee17406e, 0x00040000, + 0x00000000, 0xbefe007a, + 0x9178ff78, 0x00008c00, + 0xb8fbf811, 0xbf0c877b, + 0xbfa20002, 0x916dff6d, + 0xf0000000, 0xbf0d857b, + 0xbfa10006, 0x917bff7b, + 0x00000480, 0xb98001d1, + 0x00000000, 0xb9800291, + 0x00000000, 0x8b6eff78, + 0x00004000, 0xbfa10008, + 0x8b6eff7b, 0x00000480, + 0xbfa20018, 0x8b6ea07b, + 0xbfa200ea, 0xbf830010, + 0xb8fbf811, 0xbfa0fffb, + 0x8b6eff7b, 0x00000bd0, + 0xbfa20010, 0xb8eef812, + 0x8b6f8f7b, 0xbfa10002, + 0x8c6eff6e, 0x00000080, + 0xb8eff813, 0x8b6e6e6f, + 0xbfa20008, 0x8b6eff6d, + 0xf0000000, 0xbfa20005, + 0x8b6fff6f, 0x00000200, + 0xbfa20002, 0x8b6ea07b, + 0xbfa200d4, 0x9177ff77, + 0x007fc000, 0xb8fa04a1, + 0x847a967a, 0x8c777a77, + 0xb8fa0421, 0x847a957a, + 0x8c777a77, 0xb8fa3021, + 0x847a8e7a, 0x8c777a77, + 0xb980f821, 0x00000000, + 0xbeef007b, 0xbefa4d82, + 0xbf8a0000, 0x84fa887a, + 0xbf0d987b, 0xbfa10002, + 0x8c7bff7b, 0xfe000000, + 0xf4601bbd, 0xf8000010, + 0xbf8a0000, 0x846e976e, + 0x9177ff77, 0x03800000, + 0x8c776e77, 0x8b6eff6f, + 0x00000480, 0xbfa1000c, + 0xbf0d8e78, 0xbfa20002, + 0xbf0d9877, 0xbfa20002, 0xb98001d1, 0x00000000, + 0xbf0d8e78, 0xbfa20002, + 0xbf0d9977, 0xbfa20002, 0xb9800291, 0x00000000, - 0x8b6eff78, 0x00004000, - 0xbfa10008, 0x8b6eff7b, - 0x00000480, 0xbfa20018, - 0x8b6ea07b, 0xbfa200ea, - 0xbf830010, 0xb8fbf811, - 0xbfa0fffb, 0x8b6eff7b, - 0x00000bd0, 0xbfa20010, - 0xb8eef812, 0x8b6f8f7b, - 0xbfa10002, 0x8c6eff6e, - 0x00000080, 0xb8eff813, - 0x8b6e6e6f, 0xbfa20008, - 0x8b6eff6d, 0xf0000000, - 0xbfa20005, 0x8b6fff6f, - 0x00000200, 0xbfa20002, - 0x8b6ea07b, 0xbfa200d4, - 0x9177ff77, 0x007fc000, - 0xb8fa04a1, 0x847a967a, - 0x8c777a77, 0xb8fa0421, - 0x847a957a, 0x8c777a77, - 0xb8fa3021, 0x847a8e7a, - 0x8c777a77, 0xb980f821, - 0x00000000, 0xbeef007b, - 0xbefa4d82, 0xbf8a0000, - 0x84fa887a, 0xbf0d987b, - 0xbfa10002, 0x8c7bff7b, - 0xfe000000, 0xf4601bbd, - 0xf8000010, 0xbf8a0000, - 0x846e976e, 0x9177ff77, - 0x03800000, 0x8c776e77, - 0x8b6eff6f, 0x00000480, - 0xbfa1000c, 0xbf0d8e78, - 0xbfa20002, 0xbf0d9877, - 0xbfa20002, 0xb98001d1, - 0x00000000, 0xbf0d8e78, - 0xbfa20002, 0xbf0d9977, - 0xbfa20002, 0xb9800291, - 0x00000000, 0xf4603bbd, - 0xf8000000, 0xbf8a0000, - 0xf4603ebd, 0xf8000008, - 0xbf8a0000, 0x8bee6e6e, - 0xbfa10001, 0xbe80486e, - 0x8b6eff6d, 0xf0000000, - 0xbfa20009, 0xb8eef811, - 0x8b6eff6e, 0x00000080, - 0xbfa20007, 0x8c78ff78, - 0x00004000, 0x80ec886c, - 0x82ed806d, 0xbfa00002, - 0x806c846c, 0x826d806d, - 0x8b6dff6d, 0x01ffffff, - 0xb8fbf811, 0xbf0d847b, - 0xbfa20081, 0xf4003eb6, - 0xf8000000, 0xbfc70000, - 0xf4003bb6, 0xf8000008, - 0x8b76ff7a, 0x80000000, - 0xbfa20027, 0x9376ff7a, - 0x00060019, 0x81f9a376, - 0xbf0b8179, 0xbfa2006e, - 0x81f9ac76, 0xbf0b8179, - 0xbfa20068, 0x81f9b776, - 0xbf0b8179, 0xbfa20065, - 0x8b76ff7a, 0x000001ff, - 0xbf06ff76, 0x000000fe, - 0xbfa20063, 0xbf06ff76, - 0x000000ff, 0xbfa2005d, - 0xbf06ff76, 0x000000fa, - 0xbfa2005a, 0x81f9ff76, - 0x000000e9, 0xbf0b8179, - 0xbfa20056, 0x8b76ff7b, - 0xffff0000, 0xbf06ff76, - 0xbf860000, 0xbfa1005a, - 0x9376ff7b, 0x0002000e, - 0x8b79ff7b, 0x00003f00, - 0x85798679, 0x8c767976, - 0xb9763b01, 0xbfa00052, - 0x8b76ff7a, 0xfc000000, - 0xbf06ff76, 0xd4000000, - 0xbfa20019, 0xbf06ff76, - 0xc8000000, 0xbfa2002d, - 0x8b76ff7a, 0xff000000, - 0xbf06ff76, 0xcf000000, - 0xbfa2003f, 0x8b79ff7a, - 0xffff0000, 0xbf06ff79, - 0xcc330000, 0xbfa2003d, - 0xbf06ff79, 0xcc880000, - 0xbfa2003a, 0xbf06ff79, - 0xcc350000, 0xbfa2003a, - 0xbf06ff79, 0xcc3a0000, - 0xbfa20037, 0xbf06ff76, - 0xcc000000, 0xbfa10034, - 0x8b76ff7b, 0x000001ff, - 0xbf06ff76, 0x000000ff, - 0xbfa20029, 0xbf06ff76, - 0x000000fa, 0xbfa20026, - 0x81f6ff76, 0x000000e9, - 0xbf0b8176, 0xbfa20022, - 0x8b76ff7b, 0x0003fe00, - 0xbf06ff76, 0x0001fe00, - 0xbfa2001d, 0x8b76ff7b, - 0x07fc0000, 0xbf06ff76, - 0x03fc0000, 0xbfa20018, - 0xbfa00014, 0x9376ff7a, - 0x00040016, 0x81f68176, - 0xbf0b8176, 0xbfa20012, - 0x9376ff7a, 0x00050011, - 0x81f68176, 0xbf0b8176, - 0xbfa2000d, 0x8b76ff7a, + 0xf4603bbd, 0xf8000000, + 0xbf8a0000, 0xf4603ebd, + 0xf8000008, 0xbf8a0000, + 0x8bee6e6e, 0xbfa10001, + 0xbe80486e, 0x8b6eff6d, + 0xf0000000, 0xbfa20009, + 0xb8eef811, 0x8b6eff6e, + 0x00000080, 0xbfa20007, + 0x8c78ff78, 0x00004000, + 0x80ec886c, 0x82ed806d, + 0xbfa00002, 0x806c846c, + 0x826d806d, 0x8b6dff6d, + 0x01ffffff, 0xb8fbf811, + 0xbf0d847b, 0xbfa20081, + 0xf4003eb6, 0xf8000000, + 0xbfc70000, 0xf4003bb6, + 0xf8000008, 0x8b76ff7a, + 0x80000000, 0xbfa20027, + 0x9376ff7a, 0x00060019, + 0x81f9a376, 0xbf0b8179, + 0xbfa2006e, 0x81f9ac76, + 0xbf0b8179, 0xbfa20068, + 0x81f9b776, 0xbf0b8179, + 0xbfa20065, 0x8b76ff7a, 0x000001ff, 0xbf06ff76, - 0x000000ff, 0xbfa20008, - 0x8b76ff7b, 0x000001ff, + 0x000000fe, 0xbfa20063, 0xbf06ff76, 0x000000ff, - 0xbfa20003, 0xbfc70000, - 0xbefb006e, 0xbfa0ffa7, - 0xbfc70000, 0xbefb006f, - 0xbfa0ffa4, 0x80ec886c, - 0x82ed806d, 0xbfa0fff7, - 0xbfc70000, 0x857a9677, - 0xb97a04a1, 0x857a9577, - 0xb97a0421, 0x857a8e77, - 0xb97a3021, 0x8bfe7e7e, - 0x8bea6a6a, 0x85788978, - 0xb9783244, 0xbe804a6c, - 0xb8faf802, 0xbf0d987a, - 0xbfa10001, 0xbfb00000, - 0x8b6dff6d, 0x01ffffff, - 0xbefa0080, 0xb97a0151, - 0x9177ff77, 0x007fc000, - 0xb8fa04a1, 0x847a967a, - 0x8c777a77, 0xb8fa0421, - 0x847a957a, 0x8c777a77, - 0xb8fa3021, 0x847a8e7a, - 0x8c777a77, 0xb980f821, - 0x00000000, 0xbf0d847b, - 0xbfa20081, 0xf4003eb6, - 0xf8000000, 0xbfc70000, - 0xf4003bb6, 0xf8000008, - 0x8b76ff7a, 0x80000000, - 0xbfa20027, 0x9376ff7a, - 0x00060019, 0x81f9a376, - 0xbf0b8179, 0xbfa2006e, - 0x81f9ac76, 0xbf0b8179, - 0xbfa20068, 0x81f9b776, - 0xbf0b8179, 0xbfa20065, - 0x8b76ff7a, 0x000001ff, - 0xbf06ff76, 0x000000fe, - 0xbfa20063, 0xbf06ff76, - 0x000000ff, 0xbfa2005d, - 0xbf06ff76, 0x000000fa, - 0xbfa2005a, 0x81f9ff76, - 0x000000e9, 0xbf0b8179, - 0xbfa20056, 0x8b76ff7b, - 0xffff0000, 0xbf06ff76, - 0xbf860000, 0xbfa1005a, - 0x9376ff7b, 0x0002000e, - 0x8b79ff7b, 0x00003f00, - 0x85798679, 0x8c767976, - 0xb9763b01, 0xbfa00052, - 0x8b76ff7a, 0xfc000000, - 0xbf06ff76, 0xd4000000, - 0xbfa20019, 0xbf06ff76, - 0xc8000000, 0xbfa2002d, - 0x8b76ff7a, 0xff000000, - 0xbf06ff76, 0xcf000000, - 0xbfa2003f, 0x8b79ff7a, - 0xffff0000, 0xbf06ff79, - 0xcc330000, 0xbfa2003d, - 0xbf06ff79, 0xcc880000, + 0xbfa2005d, 0xbf06ff76, + 0x000000fa, 0xbfa2005a, + 0x81f9ff76, 0x000000e9, + 0xbf0b8179, 0xbfa20056, + 0x8b76ff7b, 0xffff0000, + 0xbf06ff76, 0xbf860000, + 0xbfa1005a, 0x9376ff7b, + 0x0002000e, 0x8b79ff7b, + 0x00003f00, 0x85798679, + 0x8c767976, 0xb9763b01, + 0xbfa00052, 0x8b76ff7a, + 0xfc000000, 0xbf06ff76, + 0xd4000000, 0xbfa20019, + 0xbf06ff76, 0xc8000000, + 0xbfa2002d, 0x8b76ff7a, + 0xff000000, 0xbf06ff76, + 0xcf000000, 0xbfa2003f, + 0x8b79ff7a, 0xffff0000, + 0xbf06ff79, 0xcc330000, + 0xbfa2003d, 0xbf06ff79, + 0xcc880000, 0xbfa2003a, + 0xbf06ff79, 0xcc350000, 0xbfa2003a, 0xbf06ff79, - 0xcc350000, 0xbfa2003a, - 0xbf06ff79, 0xcc3a0000, - 0xbfa20037, 0xbf06ff76, - 0xcc000000, 0xbfa10034, - 0x8b76ff7b, 0x000001ff, - 0xbf06ff76, 0x000000ff, - 0xbfa20029, 0xbf06ff76, - 0x000000fa, 0xbfa20026, - 0x81f6ff76, 0x000000e9, - 0xbf0b8176, 0xbfa20022, - 0x8b76ff7b, 0x0003fe00, - 0xbf06ff76, 0x0001fe00, - 0xbfa2001d, 0x8b76ff7b, - 0x07fc0000, 0xbf06ff76, - 0x03fc0000, 0xbfa20018, - 0xbfa00014, 0x9376ff7a, - 0x00040016, 0x81f68176, - 0xbf0b8176, 0xbfa20012, - 0x9376ff7a, 0x00050011, - 0x81f68176, 0xbf0b8176, - 0xbfa2000d, 0x8b76ff7a, + 0xcc3a0000, 0xbfa20037, + 0xbf06ff76, 0xcc000000, + 0xbfa10034, 0x8b76ff7b, 0x000001ff, 0xbf06ff76, - 0x000000ff, 0xbfa20008, - 0x8b76ff7b, 0x000001ff, + 0x000000ff, 0xbfa20029, + 0xbf06ff76, 0x000000fa, + 0xbfa20026, 0x81f6ff76, + 0x000000e9, 0xbf0b8176, + 0xbfa20022, 0x8b76ff7b, + 0x0003fe00, 0xbf06ff76, + 0x0001fe00, 0xbfa2001d, + 0x8b76ff7b, 0x07fc0000, + 0xbf06ff76, 0x03fc0000, + 0xbfa20018, 0xbfa00014, + 0x9376ff7a, 0x00040016, + 0x81f68176, 0xbf0b8176, + 0xbfa20012, 0x9376ff7a, + 0x00050011, 0x81f68176, + 0xbf0b8176, 0xbfa2000d, + 0x8b76ff7a, 0x000001ff, 0xbf06ff76, 0x000000ff, - 0xbfa20003, 0xbfc70000, - 0xbefb006e, 0xbfa0ffa7, - 0xbfc70000, 0xbefb006f, - 0xbfa0ffa4, 0x80ec886c, - 0x82ed806d, 0xbfa0fff7, - 0xbfc70000, 0xbeee007e, - 0xbeef007f, 0xbefe0180, - 0xbefe4d84, 0xbf8a0000, - 0x8b7aff7f, 0x04000000, - 0x847a857a, 0x8c6d7a6d, - 0xb8eff822, 0xb980f822, - 0x00000000, 0xb8fa2b01, - 0x847a997a, 0x8c6d7a6d, - 0xbefa0080, 0xb97a2b01, - 0xbefa007e, 0x8b7bff7f, - 0x01ffffff, 0xbefe00c1, - 0xbeff00c1, 0xee0a407a, - 0x000c0000, 0x00000000, - 0x7e000280, 0xbefe007a, - 0xbeff007b, 0xb8fb0742, - 0x847b997b, 0xb8fa3b05, - 0x807a817a, 0xbf0d997b, - 0xbfa20002, 0x847a897a, - 0xbfa00001, 0x847a8a7a, + 0xbfa20008, 0x8b76ff7b, + 0x000001ff, 0xbf06ff76, + 0x000000ff, 0xbfa20003, + 0xbfc70000, 0xbefb006e, + 0xbfa0ffa7, 0xbfc70000, + 0xbefb006f, 0xbfa0ffa4, + 0x80ec886c, 0x82ed806d, + 0xbfa0fff7, 0xbfc70000, + 0x857a9677, 0xb97a04a1, + 0x857a9577, 0xb97a0421, + 0x857a8e77, 0xb97a3021, + 0x8bfe7e7e, 0x8bea6a6a, + 0x85788978, 0xb9783244, + 0xbe804a6c, 0xb8faf802, + 0xbf0d987a, 0xbfa10001, + 0xbfb00000, 0x8b6dff6d, + 0x01ffffff, 0xbefa0080, + 0xb97a0151, 0x9177ff77, + 0x007fc000, 0xb8fa04a1, + 0x847a967a, 0x8c777a77, + 0xb8fa0421, 0x847a957a, + 0x8c777a77, 0xb8fa3021, + 0x847a8e7a, 0x8c777a77, + 0xb980f821, 0x00000000, + 0xbf0d847b, 0xbfa20081, + 0xf4003eb6, 0xf8000000, + 0xbfc70000, 0xf4003bb6, + 0xf8000008, 0x8b76ff7a, + 0x80000000, 0xbfa20027, + 0x9376ff7a, 0x00060019, + 0x81f9a376, 0xbf0b8179, + 0xbfa2006e, 0x81f9ac76, + 0xbf0b8179, 0xbfa20068, + 0x81f9b776, 0xbf0b8179, + 0xbfa20065, 0x8b76ff7a, + 0x000001ff, 0xbf06ff76, + 0x000000fe, 0xbfa20063, + 0xbf06ff76, 0x000000ff, + 0xbfa2005d, 0xbf06ff76, + 0x000000fa, 0xbfa2005a, + 0x81f9ff76, 0x000000e9, + 0xbf0b8179, 0xbfa20056, + 0x8b76ff7b, 0xffff0000, + 0xbf06ff76, 0xbf860000, + 0xbfa1005a, 0x9376ff7b, + 0x0002000e, 0x8b79ff7b, + 0x00003f00, 0x85798679, + 0x8c767976, 0xb9763b01, + 0xbfa00052, 0x8b76ff7a, + 0xfc000000, 0xbf06ff76, + 0xd4000000, 0xbfa20019, + 0xbf06ff76, 0xc8000000, + 0xbfa2002d, 0x8b76ff7a, + 0xff000000, 0xbf06ff76, + 0xcf000000, 0xbfa2003f, + 0x8b79ff7a, 0xffff0000, + 0xbf06ff79, 0xcc330000, + 0xbfa2003d, 0xbf06ff79, + 0xcc880000, 0xbfa2003a, + 0xbf06ff79, 0xcc350000, + 0xbfa2003a, 0xbf06ff79, + 0xcc3a0000, 0xbfa20037, + 0xbf06ff76, 0xcc000000, + 0xbfa10034, 0x8b76ff7b, + 0x000001ff, 0xbf06ff76, + 0x000000ff, 0xbfa20029, + 0xbf06ff76, 0x000000fa, + 0xbfa20026, 0x81f6ff76, + 0x000000e9, 0xbf0b8176, + 0xbfa20022, 0x8b76ff7b, + 0x0003fe00, 0xbf06ff76, + 0x0001fe00, 0xbfa2001d, + 0x8b76ff7b, 0x07fc0000, + 0xbf06ff76, 0x03fc0000, + 0xbfa20018, 0xbfa00014, + 0x9376ff7a, 0x00040016, + 0x81f68176, 0xbf0b8176, + 0xbfa20012, 0x9376ff7a, + 0x00050011, 0x81f68176, + 0xbf0b8176, 0xbfa2000d, + 0x8b76ff7a, 0x000001ff, + 0xbf06ff76, 0x000000ff, + 0xbfa20008, 0x8b76ff7b, + 0x000001ff, 0xbf06ff76, + 0x000000ff, 0xbfa20003, + 0xbfc70000, 0xbefb006e, + 0xbfa0ffa7, 0xbfc70000, + 0xbefb006f, 0xbfa0ffa4, + 0x80ec886c, 0x82ed806d, + 0xbfa0fff7, 0xbfc70000, + 0xbeee007e, 0xbeef007f, + 0xbefe0180, 0xbefe4d84, + 0xbf8a0000, 0x8b7aff7f, + 0x04000000, 0x847a857a, + 0x8c6d7a6d, 0xb8eff822, + 0xb980f822, 0x00000000, + 0xb8fa2b01, 0x847a997a, + 0x8c6d7a6d, 0xbefa0080, + 0xb97a2b01, 0xbefa007e, 0x8b7bff7f, 0x01ffffff, - 0x807aff7a, 0x000001c0, - 0x807a7e7a, 0x827b807b, - 0xd7610000, 0x00010870, - 0xd7610000, 0x00010a71, - 0xd7610000, 0x00010c72, - 0xd7610000, 0x00010e73, - 0xd7610000, 0x00011074, - 0xd7610000, 0x00011275, - 0xd7610000, 0x00011476, - 0xd7610000, 0x00011677, - 0xd7610000, 0x00011a79, - 0xd7610000, 0x00011c7e, - 0xd7610000, 0x00011e7f, - 0xbefe00ff, 0x00003fff, - 0xbeff0080, 0xee0a407a, - 0x000c0000, 0x00000000, - 0xd760007a, 0x00011d00, - 0xd760007b, 0x00011f00, + 0xbefe00c1, 0xbeff00c1, + 0xee0a407a, 0x000c0000, + 0x00000000, 0x7e000280, 0xbefe007a, 0xbeff007b, - 0xbef4007e, 0x8b75ff7f, - 0x01ffffff, 0xbef1007d, - 0xb8f30742, 0x84739973, - 0xbefe00c1, 0x857d9973, - 0x8b7d817d, 0xbf06817d, - 0xbfa20002, 0xbeff0080, - 0xbfa00002, 0xbeff00c1, - 0xbfa0000a, 0xee0a4074, - 0x008c0000, 0x00008000, - 0xee0a4074, 0x010c0000, + 0xb8fb0742, 0x847b997b, + 0xb8fa3b05, 0x807a817a, + 0xbf0d997b, 0xbfa20002, + 0x847a897a, 0xbfa00001, + 0x847a8a7a, 0x8b7bff7f, + 0x01ffffff, 0x807aff7a, + 0x000001c0, 0x807a7e7a, + 0x827b807b, 0xd7610000, + 0x00010870, 0xd7610000, + 0x00010a71, 0xd7610000, + 0x00010c72, 0xd7610000, + 0x00010e73, 0xd7610000, + 0x00011074, 0xd7610000, + 0x00011275, 0xd7610000, + 0x00011476, 0xd7610000, + 0x00011677, 0xd7610000, + 0x00011a79, 0xd7610000, + 0x00011c7e, 0xd7610000, + 0x00011e7f, 0xbefe00ff, + 0x00003fff, 0xbeff0080, + 0xee0a407a, 0x000c0000, + 0x00000000, 0xd760007a, + 0x00011d00, 0xd760007b, + 0x00011f00, 0xbefe007a, + 0xbeff007b, 0xbef4007e, + 0x8b75ff7f, 0x01ffffff, + 0xbef1007d, 0xb8f30742, + 0x84739973, 0xbefe00c1, + 0x857d9973, 0x8b7d817d, + 0xbf06817d, 0xbfa20002, + 0xbeff0080, 0xbfa00002, + 0xbeff00c1, 0xbfa0000a, + 0xee0a4074, 0x008c0000, + 0x00008000, 0xee0a4074, + 0x010c0000, 0x00010000, + 0xee0a4074, 0x018c0000, + 0x00018000, 0xbfa00009, + 0xee0a4074, 0x008c0000, 0x00010000, 0xee0a4074, - 0x018c0000, 0x00018000, - 0xbfa00009, 0xee0a4074, - 0x008c0000, 0x00010000, - 0xee0a4074, 0x010c0000, - 0x00020000, 0xee0a4074, - 0x018c0000, 0x00030000, - 0xb8f03b05, 0x80708170, - 0xbf0d9973, 0xbfa20002, - 0x84708970, 0xbfa00001, - 0x84708a70, 0x8070ff70, - 0x00000200, 0x7e000280, - 0x7e020280, 0x7e040280, - 0xbefd0080, 0xd7610002, - 0x0000fa71, 0x807d817d, - 0xb8faf802, 0xbf0c8b7a, - 0xbfa20003, 0xbe804fc2, - 0xbf94fffe, 0xbfa10001, - 0xbe804ec4, 0xbf94fffc, - 0xbefa4c88, 0xbfc70000, - 0xbf0c807a, 0xbfa20006, - 0x9371ff7a, 0x00070004, - 0x937aff7a, 0x00070010, - 0xbf06717a, 0xbfa2fff6, - 0xb8faf804, 0x8b7aff7a, - 0x0001000c, 0x9178ff78, - 0x0001000c, 0x8c787a78, - 0xd7610002, 0x0000fa6c, - 0x807d817d, 0x8b7aff6d, - 0x01ffffff, 0xd7610002, - 0x0000fa7a, 0x807d817d, - 0xd7610002, 0x0000fa6e, - 0x807d817d, 0xbefa0080, - 0xd7610002, 0x0000fa7a, - 0x807d817d, 0xd7610002, - 0x0000fa78, 0x807d817d, - 0xb8faf811, 0xd7610002, - 0x0000fa7a, 0x807d817d, - 0xd7610002, 0x0000fa6f, - 0x807d817d, 0xb8f1f801, - 0x937aff6d, 0x00060019, - 0x847a8c7a, 0x8c717a71, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xb8f1f814, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xb8f1f815, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xb8f1f812, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xb8f1f813, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xb8faf802, - 0xd7610002, 0x0000fa7a, - 0x807d817d, 0xbefa50c1, - 0xbfc70000, 0xd7610002, - 0x0000fa7a, 0x807d817d, - 0xbefa4c88, 0xbfc70000, - 0xd7610002, 0x0000fa7a, - 0x807d817d, 0xb8faf81a, - 0xd7610002, 0x0000fa7a, - 0x807d817d, 0xbefe00c1, - 0xbeff0080, 0x80767074, - 0x82778075, 0xee0a4076, - 0x010c0000, 0x00000000, - 0xbefe00c1, 0x7e040280, - 0xbefa5081, 0xbfc70000, - 0xd7610002, 0x0001007a, - 0xbefa5082, 0xbfc70000, - 0xd7610002, 0x0001027a, - 0xbefa5083, 0xbfc70000, - 0xd7610002, 0x0001047a, - 0xbefa5084, 0xbfc70000, - 0xd7610002, 0x0001067a, - 0xbefa5085, 0xbfc70000, - 0xd7610002, 0x0001087a, - 0xbefa5086, 0xbfc70000, - 0xd7610002, 0x00010a7a, - 0xbefa5087, 0xbfc70000, - 0xd7610002, 0x00010c7a, - 0xbefa5088, 0xbfc70000, - 0xd7610002, 0x00010e7a, - 0xbefa5089, 0xbfc70000, - 0xd7610002, 0x0001107a, - 0xbefa508a, 0xbfc70000, - 0xd7610002, 0x0001127a, - 0xbefa508b, 0xbfc70000, - 0xd7610002, 0x0001147a, - 0xbefa508c, 0xbfc70000, - 0xd7610002, 0x0001167a, - 0xbefa508d, 0xbfc70000, - 0xd7610002, 0x0001187a, - 0xbefa508e, 0xbfc70000, - 0xd7610002, 0x00011a7a, - 0xbefa508f, 0xbfc70000, - 0xd7610002, 0x00011c7a, - 0xbefa5090, 0xbfc70000, - 0xd7610002, 0x00011e7a, - 0xee0a4076, 0x010c0000, - 0x00008000, 0xb8f03b05, + 0x010c0000, 0x00020000, + 0xee0a4074, 0x018c0000, + 0x00030000, 0xb8f03b05, 0x80708170, 0xbf0d9973, 0xbfa20002, 0x84708970, 0xbfa00001, 0x84708a70, - 0xbef90080, 0xbefd0080, - 0xbf800000, 0xbe804100, - 0xbe824102, 0xbe844104, - 0xbe864106, 0xbe884108, - 0xbe8a410a, 0xbe8c410c, - 0xbe8e410e, 0xd7610002, - 0x0000f200, 0x80798179, - 0xd7610002, 0x0000f201, - 0x80798179, 0xd7610002, - 0x0000f202, 0x80798179, - 0xd7610002, 0x0000f203, - 0x80798179, 0xd7610002, - 0x0000f204, 0x80798179, - 0xd7610002, 0x0000f205, - 0x80798179, 0xd7610002, - 0x0000f206, 0x80798179, - 0xd7610002, 0x0000f207, - 0x80798179, 0xd7610002, - 0x0000f208, 0x80798179, - 0xd7610002, 0x0000f209, - 0x80798179, 0xd7610002, - 0x0000f20a, 0x80798179, - 0xd7610002, 0x0000f20b, - 0x80798179, 0xd7610002, - 0x0000f20c, 0x80798179, - 0xd7610002, 0x0000f20d, - 0x80798179, 0xd7610002, - 0x0000f20e, 0x80798179, - 0xd7610002, 0x0000f20f, - 0x80798179, 0xbf06a079, - 0xbfa10009, 0x80767074, - 0x82778075, 0xee0a4076, - 0x010c0000, 0x00000000, - 0x8070ff70, 0x00000080, - 0xbef90080, 0x7e040280, - 0x807d907d, 0xbf0aff7d, - 0x00000060, 0xbfa2ffb9, + 0x8070ff70, 0x00000200, + 0x7e000280, 0x7e020280, + 0x7e040280, 0xbefd0080, + 0xd7610002, 0x0000fa71, + 0x807d817d, 0xb8faf802, + 0xbf0c8b7a, 0xbfa20003, + 0xbe804fc2, 0xbf94fffe, + 0xbfa10001, 0xbe804ec4, + 0xbf94fffc, 0xbefa4c88, + 0xbfc70000, 0xbf0c807a, + 0xbfa20006, 0x9371ff7a, + 0x00070004, 0x937aff7a, + 0x00070010, 0xbf06717a, + 0xbfa2fff6, 0xb8faf804, + 0x8b7aff7a, 0x0001000c, + 0x9178ff78, 0x0001000c, + 0x8c787a78, 0xd7610002, + 0x0000fa6c, 0x807d817d, + 0x8b7aff6d, 0x01ffffff, + 0xd7610002, 0x0000fa7a, + 0x807d817d, 0xd7610002, + 0x0000fa6e, 0x807d817d, + 0xbefa0080, 0xd7610002, + 0x0000fa7a, 0x807d817d, + 0xd7610002, 0x0000fa78, + 0x807d817d, 0xb8faf811, + 0xd7610002, 0x0000fa7a, + 0x807d817d, 0xd7610002, + 0x0000fa6f, 0x807d817d, + 0xb8f1f801, 0x937aff6d, + 0x00060019, 0x847a8c7a, + 0x8c717a71, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xb8f1f814, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xb8f1f815, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xb8f1f812, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xb8f1f813, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xb8faf802, 0xd7610002, + 0x0000fa7a, 0x807d817d, + 0xbefa50c1, 0xbfc70000, + 0xd7610002, 0x0000fa7a, + 0x807d817d, 0xbefa4c88, + 0xbfc70000, 0xd7610002, + 0x0000fa7a, 0x807d817d, + 0xb8faf81a, 0xd7610002, + 0x0000fa7a, 0x807d817d, + 0xbefe00c1, 0xbeff0080, + 0x80767074, 0x82778075, + 0xee0a4076, 0x010c0000, + 0x00000000, 0xbefe00c1, + 0x7e040280, 0xbefa5081, + 0xbfc70000, 0xd7610002, + 0x0001007a, 0xbefa5082, + 0xbfc70000, 0xd7610002, + 0x0001027a, 0xbefa5083, + 0xbfc70000, 0xd7610002, + 0x0001047a, 0xbefa5084, + 0xbfc70000, 0xd7610002, + 0x0001067a, 0xbefa5085, + 0xbfc70000, 0xd7610002, + 0x0001087a, 0xbefa5086, + 0xbfc70000, 0xd7610002, + 0x00010a7a, 0xbefa5087, + 0xbfc70000, 0xd7610002, + 0x00010c7a, 0xbefa5088, + 0xbfc70000, 0xd7610002, + 0x00010e7a, 0xbefa5089, + 0xbfc70000, 0xd7610002, + 0x0001107a, 0xbefa508a, + 0xbfc70000, 0xd7610002, + 0x0001127a, 0xbefa508b, + 0xbfc70000, 0xd7610002, + 0x0001147a, 0xbefa508c, + 0xbfc70000, 0xd7610002, + 0x0001167a, 0xbefa508d, + 0xbfc70000, 0xd7610002, + 0x0001187a, 0xbefa508e, + 0xbfc70000, 0xd7610002, + 0x00011a7a, 0xbefa508f, + 0xbfc70000, 0xd7610002, + 0x00011c7a, 0xbefa5090, + 0xbfc70000, 0xd7610002, + 0x00011e7a, 0xee0a4076, + 0x010c0000, 0x00008000, + 0xb8f03b05, 0x80708170, + 0xbf0d9973, 0xbfa20002, + 0x84708970, 0xbfa00001, + 0x84708a70, 0xbef90080, + 0xbefd0080, 0xbf800000, 0xbe804100, 0xbe824102, 0xbe844104, 0xbe864106, 0xbe884108, 0xbe8a410a, + 0xbe8c410c, 0xbe8e410e, 0xd7610002, 0x0000f200, 0x80798179, 0xd7610002, 0x0000f201, 0x80798179, @@ -5028,39 +4986,63 @@ static const uint32_t cwsr_trap_gfx12_1_0_hex[] = { 0xd7610002, 0x0000f20a, 0x80798179, 0xd7610002, 0x0000f20b, 0x80798179, - 0xbefe00ff, 0x0000ffff, + 0xd7610002, 0x0000f20c, + 0x80798179, 0xd7610002, + 0x0000f20d, 0x80798179, + 0xd7610002, 0x0000f20e, + 0x80798179, 0xd7610002, + 0x0000f20f, 0x80798179, + 0xbf06a079, 0xbfa10009, 0x80767074, 0x82778075, 0xee0a4076, 0x010c0000, - 0x00000000, 0xbefe00c1, - 0x857d9973, 0x8b7d817d, - 0xbf06817d, 0xbfa20002, - 0xbeff0080, 0xbfa00001, - 0xbeff00c1, 0xb8fb4306, - 0x8b7bc17b, 0xbfa10042, - 0x8b7aff6d, 0x80000000, - 0xbfa1003f, 0x847b8a7b, - 0xb8f03b05, 0x80708170, - 0xbf0d9973, 0xbfa20002, - 0x84708970, 0xbfa00001, - 0x84708a70, 0x8070ff70, - 0x00000200, 0x8070ff70, - 0x00000200, 0xd71f0000, - 0x000100c1, 0xd7200000, - 0x000200c1, 0x16000084, - 0x857d9973, 0x8b7d817d, - 0xbf06817d, 0xbefd0080, - 0xbfa20015, 0xbe8300ff, - 0x00000080, 0xbf800000, - 0xbf800000, 0xbf800000, - 0xd8d80000, 0x01000000, - 0xbf8a0000, 0x80767074, + 0x00000000, 0x8070ff70, + 0x00000080, 0xbef90080, + 0x7e040280, 0x807d907d, + 0xbf0aff7d, 0x00000060, + 0xbfa2ffb9, 0xbe804100, + 0xbe824102, 0xbe844104, + 0xbe864106, 0xbe884108, + 0xbe8a410a, 0xd7610002, + 0x0000f200, 0x80798179, + 0xd7610002, 0x0000f201, + 0x80798179, 0xd7610002, + 0x0000f202, 0x80798179, + 0xd7610002, 0x0000f203, + 0x80798179, 0xd7610002, + 0x0000f204, 0x80798179, + 0xd7610002, 0x0000f205, + 0x80798179, 0xd7610002, + 0x0000f206, 0x80798179, + 0xd7610002, 0x0000f207, + 0x80798179, 0xd7610002, + 0x0000f208, 0x80798179, + 0xd7610002, 0x0000f209, + 0x80798179, 0xd7610002, + 0x0000f20a, 0x80798179, + 0xd7610002, 0x0000f20b, + 0x80798179, 0xbefe00ff, + 0x0000ffff, 0x80767074, 0x82778075, 0xee0a4076, - 0x008c0000, 0x00000000, - 0x807d037d, 0x80700370, - 0xd5250000, 0x0001ff00, - 0x00000080, 0xbf0a7b7d, - 0xbfa2fff1, 0xbfa00014, - 0xbe8300ff, 0x00000100, + 0x010c0000, 0x00000000, + 0xbefe00c1, 0x857d9973, + 0x8b7d817d, 0xbf06817d, + 0xbfa20002, 0xbeff0080, + 0xbfa00001, 0xbeff00c1, + 0xb8fb4306, 0x8b7bc17b, + 0xbfa10042, 0x8b7aff6d, + 0x80000000, 0xbfa1003f, + 0x847b8a7b, 0xb8f03b05, + 0x80708170, 0xbf0d9973, + 0xbfa20002, 0x84708970, + 0xbfa00001, 0x84708a70, + 0x8070ff70, 0x00000200, + 0x8070ff70, 0x00000200, + 0xd71f0000, 0x000100c1, + 0xd7200000, 0x000200c1, + 0x16000084, 0x857d9973, + 0x8b7d817d, 0xbf06817d, + 0xbefd0080, 0xbfa20015, + 0xbe8300ff, 0x00000080, 0xbf800000, 0xbf800000, 0xbf800000, 0xd8d80000, 0x01000000, 0xbf8a0000, @@ -5068,244 +5050,254 @@ static const uint32_t cwsr_trap_gfx12_1_0_hex[] = { 0xee0a4076, 0x008c0000, 0x00000000, 0x807d037d, 0x80700370, 0xd5250000, - 0x0001ff00, 0x00000100, + 0x0001ff00, 0x00000080, 0xbf0a7b7d, 0xbfa2fff1, - 0xbefe00c1, 0x857d9973, - 0x8b7d817d, 0xbf06817d, - 0xbfa20004, 0xbef000ff, - 0x00000200, 0xbeff0080, - 0xbfa00003, 0xbef000ff, - 0x00000400, 0xbeff00c1, - 0xb8fb3b05, 0x807b817b, - 0x847b827b, 0x857d9973, - 0x8b7d817d, 0xbf06817d, - 0xbfa2001b, 0xbefd0084, - 0xbf0a7b7d, 0xbfa10032, - 0x7e008700, 0x7e028701, - 0x7e048702, 0x7e068703, - 0x80767074, 0x82778075, - 0xee0a4076, 0x000c0000, - 0x00000000, 0xee0a4076, - 0x008c0000, 0x00008000, - 0xee0a4076, 0x010c0000, - 0x00010000, 0xee0a4076, - 0x018c0000, 0x00018000, - 0x807d847d, 0x8070ff70, - 0x00000200, 0xbf0a7b7d, - 0xbfa2ffe9, 0xbfa0001a, + 0xbfa00014, 0xbe8300ff, + 0x00000100, 0xbf800000, + 0xbf800000, 0xbf800000, + 0xd8d80000, 0x01000000, + 0xbf8a0000, 0x80767074, + 0x82778075, 0xee0a4076, + 0x008c0000, 0x00000000, + 0x807d037d, 0x80700370, + 0xd5250000, 0x0001ff00, + 0x00000100, 0xbf0a7b7d, + 0xbfa2fff1, 0xbefe00c1, + 0x857d9973, 0x8b7d817d, + 0xbf06817d, 0xbfa20004, + 0xbef000ff, 0x00000200, + 0xbeff0080, 0xbfa00003, + 0xbef000ff, 0x00000400, + 0xbeff00c1, 0xb8fb3b05, + 0x807b817b, 0x847b827b, + 0x857d9973, 0x8b7d817d, + 0xbf06817d, 0xbfa2001b, 0xbefd0084, 0xbf0a7b7d, - 0xbfa10017, 0x7e008700, + 0xbfa10032, 0x7e008700, 0x7e028701, 0x7e048702, 0x7e068703, 0x80767074, 0x82778075, 0xee0a4076, 0x000c0000, 0x00000000, 0xee0a4076, 0x008c0000, - 0x00010000, 0xee0a4076, - 0x010c0000, 0x00020000, + 0x00008000, 0xee0a4076, + 0x010c0000, 0x00010000, 0xee0a4076, 0x018c0000, - 0x00030000, 0x807d847d, - 0x8070ff70, 0x00000400, + 0x00018000, 0x807d847d, + 0x8070ff70, 0x00000200, 0xbf0a7b7d, 0xbfa2ffe9, - 0xbfa00184, 0xbef4007e, - 0x8b75ff7f, 0x01ffffff, - 0xbef1007f, 0xb8f20742, - 0x84729972, 0x8b6eff7f, - 0x04000000, 0xbfa10044, + 0xbfa0001a, 0xbefd0084, + 0xbf0a7b7d, 0xbfa10017, + 0x7e008700, 0x7e028701, + 0x7e048702, 0x7e068703, + 0x80767074, 0x82778075, + 0xee0a4076, 0x000c0000, + 0x00000000, 0xee0a4076, + 0x008c0000, 0x00010000, + 0xee0a4076, 0x010c0000, + 0x00020000, 0xee0a4076, + 0x018c0000, 0x00030000, + 0x807d847d, 0x8070ff70, + 0x00000400, 0xbf0a7b7d, + 0xbfa2ffe9, 0xbfa00184, + 0xbef4007e, 0x8b75ff7f, + 0x01ffffff, 0xbef1007f, + 0xb8f20742, 0x84729972, + 0x8b6eff7f, 0x04000000, + 0xbfa10044, 0xbefe00c1, + 0x857d9972, 0x8b7d817d, + 0xbf06817d, 0xbfa20002, + 0xbeff0080, 0xbfa00001, + 0xbeff00c1, 0xb8ef4306, + 0x8b6fc16f, 0xbfa10039, + 0x846f8a6f, 0xb8f83b05, + 0x80788178, 0xbf0d9972, + 0xbfa20002, 0x84788978, + 0xbfa00001, 0x84788a78, + 0x8078ff78, 0x00000200, + 0x8078ff78, 0x00000200, + 0x857d9972, 0x8b7d817d, + 0xbf06817d, 0xbefd0080, + 0xd71f0001, 0x000100c1, + 0xd7200001, 0x000202c1, + 0x30020282, 0xbfa20012, + 0x80767874, 0x82778075, + 0xee0a0076, 0x000c0000, + 0x00000000, 0xbf8a0000, + 0xd8340000, 0x00000001, + 0xd5250001, 0x0001ff01, + 0x00000080, 0x807dff7d, + 0x00000080, 0x8078ff78, + 0x00000080, 0xbf0a6f7d, + 0xbfa2ffef, 0xbfa00011, + 0x80767874, 0x82778075, + 0xee0a0076, 0x000c0000, + 0x00000000, 0xbf8a0000, + 0xd8340000, 0x00000001, + 0xd5250001, 0x0001ff01, + 0x00000100, 0x807dff7d, + 0x00000100, 0x8078ff78, + 0x00000100, 0xbf0a6f7d, + 0xbfa2ffef, 0xbef80080, 0xbefe00c1, 0x857d9972, 0x8b7d817d, 0xbf06817d, 0xbfa20002, 0xbeff0080, 0xbfa00001, 0xbeff00c1, - 0xb8ef4306, 0x8b6fc16f, - 0xbfa10039, 0x846f8a6f, + 0xb8ef3b05, 0x806f816f, + 0x846f826f, 0x857d9972, + 0x8b7d817d, 0xbf06817d, + 0xbfa2002c, 0xbeee0078, + 0x8078ff78, 0x00000200, + 0xbefd0084, 0x80767874, + 0x82778075, 0xee0a0076, + 0x000c0000, 0x00000000, + 0xee0a0076, 0x000c0001, + 0x00008000, 0xee0a0076, + 0x000c0002, 0x00010000, + 0xee0a0076, 0x000c0003, + 0x00018000, 0xbf8a0000, + 0x7e008500, 0x7e028501, + 0x7e048502, 0x7e068503, + 0x807d847d, 0x8078ff78, + 0x00000200, 0xbf0a6f7d, + 0xbfa2ffe8, 0x80766e74, + 0x82778075, 0xee0a0076, + 0x000c0000, 0x00000000, + 0xee0a0076, 0x000c0001, + 0x00008000, 0xee0a0076, + 0x000c0002, 0x00010000, + 0xee0a0076, 0x000c0003, + 0x00018000, 0xbf8a0000, + 0xbfa0002d, 0xbeee0078, + 0x8078ff78, 0x00000400, + 0xbefd0084, 0xbf0a6f7d, + 0xbfa10018, 0x80767874, + 0x82778075, 0xee0a0076, + 0x000c0000, 0x00000000, + 0xee0a0076, 0x000c0001, + 0x00010000, 0xee0a0076, + 0x000c0002, 0x00020000, + 0xee0a0076, 0x000c0003, + 0x00030000, 0xbf8a0000, + 0x7e008500, 0x7e028501, + 0x7e048502, 0x7e068503, + 0x807d847d, 0x8078ff78, + 0x00000400, 0xbf0a6f7d, + 0xbfa2ffe8, 0x80766e74, + 0x82778075, 0xee0a0076, + 0x000c0000, 0x00000000, + 0xee0a0076, 0x000c0001, + 0x00010000, 0xee0a0076, + 0x000c0002, 0x00020000, + 0xee0a0076, 0x000c0003, + 0x00030000, 0xbf8a0000, 0xb8f83b05, 0x80788178, 0xbf0d9972, 0xbfa20002, 0x84788978, 0xbfa00001, 0x84788a78, 0x8078ff78, - 0x00000200, 0x8078ff78, - 0x00000200, 0x857d9972, - 0x8b7d817d, 0xbf06817d, - 0xbefd0080, 0xd71f0001, - 0x000100c1, 0xd7200001, - 0x000202c1, 0x30020282, - 0xbfa20012, 0x80767874, - 0x82778075, 0xee0a0076, - 0x000c0000, 0x00000000, - 0xbf8a0000, 0xd8340000, - 0x00000001, 0xd5250001, - 0x0001ff01, 0x00000080, - 0x807dff7d, 0x00000080, - 0x8078ff78, 0x00000080, - 0xbf0a6f7d, 0xbfa2ffef, - 0xbfa00011, 0x80767874, - 0x82778075, 0xee0a0076, - 0x000c0000, 0x00000000, - 0xbf8a0000, 0xd8340000, - 0x00000001, 0xd5250001, - 0x0001ff01, 0x00000100, - 0x807dff7d, 0x00000100, - 0x8078ff78, 0x00000100, - 0xbf0a6f7d, 0xbfa2ffef, - 0xbef80080, 0xbefe00c1, - 0x857d9972, 0x8b7d817d, - 0xbf06817d, 0xbfa20002, - 0xbeff0080, 0xbfa00001, - 0xbeff00c1, 0xb8ef3b05, - 0x806f816f, 0x846f826f, - 0x857d9972, 0x8b7d817d, - 0xbf06817d, 0xbfa2002c, - 0xbeee0078, 0x8078ff78, - 0x00000200, 0xbefd0084, - 0x80767874, 0x82778075, - 0xee0a0076, 0x000c0000, - 0x00000000, 0xee0a0076, - 0x000c0001, 0x00008000, - 0xee0a0076, 0x000c0002, - 0x00010000, 0xee0a0076, - 0x000c0003, 0x00018000, - 0xbf8a0000, 0x7e008500, - 0x7e028501, 0x7e048502, - 0x7e068503, 0x807d847d, - 0x8078ff78, 0x00000200, - 0xbf0a6f7d, 0xbfa2ffe8, - 0x80766e74, 0x82778075, - 0xee0a0076, 0x000c0000, - 0x00000000, 0xee0a0076, - 0x000c0001, 0x00008000, - 0xee0a0076, 0x000c0002, - 0x00010000, 0xee0a0076, - 0x000c0003, 0x00018000, - 0xbf8a0000, 0xbfa0002d, - 0xbeee0078, 0x8078ff78, - 0x00000400, 0xbefd0084, - 0xbf0a6f7d, 0xbfa10018, - 0x80767874, 0x82778075, - 0xee0a0076, 0x000c0000, - 0x00000000, 0xee0a0076, - 0x000c0001, 0x00010000, - 0xee0a0076, 0x000c0002, - 0x00020000, 0xee0a0076, - 0x000c0003, 0x00030000, - 0xbf8a0000, 0x7e008500, - 0x7e028501, 0x7e048502, - 0x7e068503, 0x807d847d, - 0x8078ff78, 0x00000400, - 0xbf0a6f7d, 0xbfa2ffe8, - 0x80766e74, 0x82778075, - 0xee0a0076, 0x000c0000, - 0x00000000, 0xee0a0076, - 0x000c0001, 0x00010000, - 0xee0a0076, 0x000c0002, - 0x00020000, 0xee0a0076, - 0x000c0003, 0x00030000, - 0xbf8a0000, 0xb8f83b05, - 0x80788178, 0xbf0d9972, - 0xbfa20002, 0x84788978, - 0xbfa00001, 0x84788a78, - 0x8078ff78, 0x00000200, - 0x80f8ff78, 0x00000060, - 0x80767874, 0x82778075, - 0xbefd00ff, 0x0000006c, - 0xf460403b, 0xf8000000, - 0xbf8a0000, 0x80fd847d, - 0xbf800000, 0xbe804300, - 0xbe824302, 0x80f6a076, - 0x82f78077, 0xf460603b, + 0x00000200, 0x80f8ff78, + 0x00000060, 0x80767874, + 0x82778075, 0xbefd00ff, + 0x0000006c, 0xf460403b, 0xf8000000, 0xbf8a0000, - 0x80fd887d, 0xbf800000, + 0x80fd847d, 0xbf800000, 0xbe804300, 0xbe824302, - 0xbe844304, 0xbe864306, - 0x80f6c076, 0x82f78077, - 0xf460803b, 0xf8000000, - 0xbf8a0000, 0x80fd907d, + 0x80f6a076, 0x82f78077, + 0xf460603b, 0xf8000000, + 0xbf8a0000, 0x80fd887d, 0xbf800000, 0xbe804300, 0xbe824302, 0xbe844304, - 0xbe864306, 0xbe884308, - 0xbe8a430a, 0xbe8c430c, - 0xbe8e430e, 0xbf06807d, - 0xbfa1ffef, 0xb980f801, - 0x00000000, 0xb8f83b05, - 0x80788178, 0xbf0d9972, - 0xbfa20002, 0x84788978, - 0xbfa00001, 0x84788a78, - 0x8078ff78, 0x00000200, - 0x80767874, 0x82778075, - 0xbeff0071, 0xf4601bfb, - 0xf8000000, 0xf4601b3b, - 0xf8000004, 0xf4601b7b, - 0xf8000008, 0xf4601c3b, - 0xf800000c, 0xf4601c7b, - 0xf8000010, 0xf4601ebb, - 0xf8000014, 0xf4601efb, - 0xf8000018, 0xf4601e7b, - 0xf800001c, 0xf4601cfb, - 0xf8000020, 0xf4601bbb, - 0xf8000024, 0xbf8a0000, - 0xb96ef814, 0xf4601bbb, - 0xf8000028, 0xbf8a0000, - 0xb96ef815, 0xf4601bbb, - 0xf800002c, 0xbf8a0000, - 0xb96ef812, 0xf4601bbb, - 0xf8000030, 0xbf8a0000, - 0xb96ef813, 0x8b6eff7f, - 0x04000000, 0xbfa10022, - 0xf4601bbb, 0xf8000038, - 0xbf8a0000, 0xbf0d806e, - 0xbfa1001d, 0x856e906e, - 0x8b6e6e6e, 0xbfa10003, - 0xbe804ec1, 0x816ec16e, - 0xbfa0fffb, 0xbef800ff, - 0x00000080, 0xbefd0081, - 0xf4601bbb, 0xf0000000, - 0xbfc70000, 0x80788478, - 0x937eff6e, 0x00070004, - 0x847e907e, 0x8c7d7e7d, - 0xbe80517d, 0x917dff7d, - 0x007f0000, 0x856e906e, - 0x8b6e6e6e, 0xbfa10003, - 0xbe804e7d, 0x816ec16e, - 0xbfa0fffb, 0x807d817d, - 0xbf08907d, 0xbfa1ffec, - 0xf4601bbb, 0xf800003c, - 0xbfc70000, 0xbf0d806e, - 0xbfa1000c, 0xbf0d9a7f, - 0xbfa10002, 0xbf068180, - 0xbe804fc4, 0xbf94fffc, - 0xbfa10006, 0x856e906e, - 0x8b6e6e6e, 0xbfa10003, - 0xbe804ec3, 0x816ec16e, - 0xbfa0fffb, 0xf4601bbb, - 0xf8000040, 0xbfc70000, - 0xb96ef81a, 0xbefd006f, - 0xbefe0070, 0xbeff0071, - 0xb979f822, 0xb97b2011, - 0x857b867b, 0xb97b0191, - 0x857b827b, 0xb97bba11, - 0xb973f801, 0xb8ee3b05, - 0x806e816e, 0xbf0d9972, - 0xbfa20002, 0x846e896e, - 0xbfa00001, 0x846e8a6e, - 0x806eff6e, 0x000001c0, - 0x806e746e, 0x826f8075, - 0xf4605c37, 0xf8000010, - 0xf4605d37, 0xf8000020, - 0xf4601e77, 0xf8000034, - 0xbf8a0000, 0x856e9677, - 0xb96e04a1, 0x856e9577, - 0xb96e0421, 0x856e8e77, - 0xb96e3021, 0x8b6dff6d, - 0x01ffffff, 0x8bfe7e7e, - 0x8bea6a6a, 0xb97af804, + 0xbe864306, 0x80f6c076, + 0x82f78077, 0xf460803b, + 0xf8000000, 0xbf8a0000, + 0x80fd907d, 0xbf800000, + 0xbe804300, 0xbe824302, + 0xbe844304, 0xbe864306, + 0xbe884308, 0xbe8a430a, + 0xbe8c430c, 0xbe8e430e, + 0xbf06807d, 0xbfa1ffef, + 0xb980f801, 0x00000000, + 0xb8f83b05, 0x80788178, + 0xbf0d9972, 0xbfa20002, + 0x84788978, 0xbfa00001, + 0x84788a78, 0x8078ff78, + 0x00000200, 0x80767874, + 0x82778075, 0xbeff0071, + 0xf4601bfb, 0xf8000000, + 0xf4601b3b, 0xf8000004, + 0xf4601b7b, 0xf8000008, + 0xf4601c3b, 0xf800000c, + 0xf4601c7b, 0xf8000010, + 0xf4601ebb, 0xf8000014, + 0xf4601efb, 0xf8000018, + 0xf4601e7b, 0xf800001c, + 0xf4601cfb, 0xf8000020, + 0xf4601bbb, 0xf8000024, + 0xbf8a0000, 0xb96ef814, + 0xf4601bbb, 0xf8000028, + 0xbf8a0000, 0xb96ef815, + 0xf4601bbb, 0xf800002c, + 0xbf8a0000, 0xb96ef812, + 0xf4601bbb, 0xf8000030, + 0xbf8a0000, 0xb96ef813, + 0x8b6eff7f, 0x04000000, + 0xbfa10022, 0xf4601bbb, + 0xf8000038, 0xbf8a0000, + 0xbf0d806e, 0xbfa1001d, + 0x856e906e, 0x8b6e6e6e, + 0xbfa10003, 0xbe804ec1, + 0x816ec16e, 0xbfa0fffb, + 0xbef800ff, 0x00000080, + 0xbefd0081, 0xf4601bbb, + 0xf0000000, 0xbfc70000, + 0x80788478, 0x937eff6e, + 0x00070004, 0x847e907e, + 0x8c7d7e7d, 0xbe80517d, + 0x917dff7d, 0x007f0000, + 0x856e906e, 0x8b6e6e6e, + 0xbfa10003, 0xbe804e7d, + 0x816ec16e, 0xbfa0fffb, + 0x807d817d, 0xbf08907d, + 0xbfa1ffec, 0xf4601bbb, + 0xf800003c, 0xbfc70000, + 0xbf0d806e, 0xbfa1000c, + 0xbf0d9a7f, 0xbfa10002, + 0xbf068180, 0xbe804fc4, + 0xbf94fffc, 0xbfa10006, + 0x856e906e, 0x8b6e6e6e, + 0xbfa10003, 0xbe804ec3, + 0x816ec16e, 0xbfa0fffb, + 0xf4601bbb, 0xf8000040, + 0xbfc70000, 0xb96ef81a, + 0xbefd006f, 0xbefe0070, + 0xbeff0071, 0xb979f822, + 0xb97b2011, 0x857b867b, + 0xb97b0191, 0x857b827b, + 0xb97bba11, 0xb973f801, + 0xb8ee3b05, 0x806e816e, + 0xbf0d9972, 0xbfa20002, + 0x846e896e, 0xbfa00001, + 0x846e8a6e, 0x806eff6e, + 0x000001c0, 0x806e746e, + 0x826f8075, 0xf4605c37, + 0xf8000010, 0xf4605d37, + 0xf8000020, 0xf4601e77, + 0xf8000034, 0xbf8a0000, + 0x856e9677, 0xb96e04a1, + 0x856e9577, 0xb96e0421, + 0x856e8e77, 0xb96e3021, + 0x8b6dff6d, 0x01ffffff, + 0x8bfe7e7e, 0x8bea6a6a, + 0xb97af804, 0xb8eef802, + 0xbf0c8b6e, 0xbfa20003, + 0xbe804fc2, 0xbf94fffe, + 0xbfa10001, 0xbe804ec4, + 0xbf94fffc, 0x857a897a, + 0xb97a0244, 0xbe804a6c, 0xb8eef802, 0xbf0c8b6e, 0xbfa20003, 0xbe804fc2, 0xbf94fffe, 0xbfa10001, 0xbe804ec4, 0xbf94fffc, - 0x857a897a, 0xb97a0244, - 0xbe804a6c, 0xb8eef802, - 0xbf0c8b6e, 0xbfa20003, - 0xbe804fc2, 0xbf94fffe, - 0xbfa10001, 0xbe804ec4, - 0xbf94fffc, 0xbfb10000, + 0xbfb10000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, - 0xbf9f0000, 0x00000000, }; diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm index 233ed8b6d122..b5af2c97a091 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm @@ -246,28 +246,15 @@ L_SKIP_RESTORE: s_getreg_b32 s_save_state_priv, hwreg(HW_REG_WAVE_STATE_PRIV) //save STATUS since we will change SCC #if VMEM_ON_TRAP_ENTRY_WA - s_getreg_b32 ttmp14, hwreg(HW_REG_WAVE_EXCP_FLAG_PRIV) - s_bitcmp1_b32 ttmp14, SQ_WAVE_EXCP_FLAG_PRIV_WAVE_START_SHIFT - s_cbranch_scc0 L_NOT_WAVE_START - - s_setreg_imm32_b32 hwreg(HW_REG_WAVE_EXCP_FLAG_PRIV, SQ_WAVE_EXCP_FLAG_PRIV_WAVE_START_SHIFT, 1), 0 - - s_mov_b64 [ttmp2, ttmp3], 0 - v_mov_b32 v1, 0 - global_prefetch_b8 v1, [ttmp2, ttmp3] scope:SCOPE_SE th:TH_LOAD_RT - - s_rfe_b64 [ttmp0, ttmp1] - -L_NOT_WAVE_START: s_mov_b32 ttmp14, exec_lo s_mov_b32 exec_lo, 1 - v_readlane_b32 ttmp15, v1, 0 - s_mov_b64 [ttmp2, ttmp3], 0 - v_mov_b32 v1, 0 - global_prefetch_b8 v1, [ttmp2, ttmp3] scope:SCOPE_SE th:TH_LOAD_RT + // No-op prefetch to random address 0xFFFFFFFFxxxxxxxx. + // Avoids user allocations which may be functionally affected by prefetch. + s_mov_b32 ttmp2, 0 + s_mov_b32 ttmp3, 0xFFFFFFFF + global_prefetch_b8 v0, [ttmp2, ttmp3] scope:SCOPE_SE th:TH_LOAD_RT - v_writelane_b32 v1, ttmp15, 0 s_mov_b32 exec_lo, ttmp14 #endif From f05e235a54c0e7eedf7fe251db4dd5a58655ed3d Mon Sep 17 00:00:00 2001 From: Dominik Kaszewski Date: Wed, 23 Sep 2026 12:20:13 -0400 Subject: [PATCH 100/103] drm/amd/display: Fix compound literal stackframe limit [Why] Use of compound literals to initialize heap objects may create stack temporaries when compiling in debug mode. For large objects such as dc_memory_pool which is 2 pages large to avoid cacheline sharing, this causes function stackframe to exceed kernel limit. [How] Replace compound literal with field-by-field initialization. Reported-by: Mark Brown Link: https://lore.kernel.org/all/aq0vYhZXtMqA41wZ@sirena.org.uk/ Signed-off-by: Dominik Kaszewski Signed-off-by: Leo Li Reviewed-by: Nicholas Kazlauskas Reviewed-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_memory_pool.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c index 904f8c4a4783..087f04d31459 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c +++ b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c @@ -107,16 +107,14 @@ __must_check struct dc_memory_pool *dc_memory_pool_create(size_t size, struct dc_memory_pool *pool = page_align_up(unaligned_pool); - *pool = (struct dc_memory_pool){ - .size = size, - .capacity = capacity, - .unaligned_pool = unaligned_pool, - .unaligned_memory = kcalloc(lines + 1, PAGE_SIZE, GFP_KERNEL), - .free_list = kcalloc((uint32_t)capacity, sizeof(atomic_t), - GFP_KERNEL), - .free_head = ATOMIC_INIT(0), - }; + // Compound literals create temporary in debug driver, exceeding stack size + pool->size = size; + pool->capacity = capacity; + pool->unaligned_pool = unaligned_pool; + pool->unaligned_memory = kcalloc(lines + 1, PAGE_SIZE, GFP_KERNEL); pool->memory = page_align_up(pool->unaligned_memory); + pool->free_list = kcalloc((uint32_t)capacity, sizeof(atomic_t), GFP_KERNEL); + pool->free_head = (atomic64_t)ATOMIC_INIT(0); if (!pool->unaligned_memory || !pool->free_list) { dc_memory_pool_destroy(pool); From ebf8b0fd8508b744f85a8eee82b745b1d3502dd0 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 23 Sep 2026 11:31:18 -0600 Subject: [PATCH 101/103] drm/amd/display: Relax DML frame limit with UBSAN [WHY] UBSAN instrumentation adds checks and handler calls and increases stack usage in the large DML calculation functions, similar to KASAN and KCSAN. With UBSAN enabled these files exceed the default -Wframe-larger-than limit and fail to build when -Werror is in effect. Reproduced with LLVM (make LLVM=1, clang 19.1.1), CONFIG_UBSAN=y, CONFIG_GCOV_PROFILE_ALL=y and CONFIG_DRM_AMDGPU_WERROR=y on x86_64. [HOW] Include CONFIG_UBSAN in the sanitizer check that selects the higher per-file frame warning limit in the dml and dml2_0 Makefiles. Suggested-by: Leo Li Assisted-by: Copilot:Claude-Opus-5.5 Signed-off-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dml2_0/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 10d4ace04d4f..096520bd27c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -29,7 +29,7 @@ dml_ccflags := $(CC_FLAGS_FPU) dml_rcflags := $(CC_FLAGS_NO_FPU) ifneq ($(CONFIG_FRAME_WARN),0) - ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) + ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)$(CONFIG_UBSAN)),y) ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy) frame_warn_limit := 4096 else diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile index 7ebe799e3b24..615cd0ca9450 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile @@ -28,7 +28,7 @@ dml2_ccflags := $(CC_FLAGS_FPU) dml2_rcflags := $(CC_FLAGS_NO_FPU) ifneq ($(CONFIG_FRAME_WARN),0) - ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) + ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)$(CONFIG_UBSAN)),y) ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy) frame_warn_limit := 4096 else From 21711b6e66bb7b41b1aec67b2d99aafe768c8fcb Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Fri, 21 Aug 2026 00:04:53 -0400 Subject: [PATCH 102/103] drm/amd/display: Bump frame warning limit for clang builds of dml [Why&How] When building the DML files with clang without any sanitizer or LTO, the following -Wframe-larger-than errors break the build under CONFIG_WERROR: display_mode_vba_30.c: error: stack frame size (2512) exceeds limit (2048) in 'dml30_ModeSupportAndSystemConfigurationFull' display_mode_vba_31.c: error: stack frame size (2416) exceeds limit (2048) in 'dml31_ModeSupportAndSystemConfigurationFull' display_mode_vba_314.c: error: stack frame size (2392) exceeds limit (2048) in 'dml314_ModeSupportAndSystemConfigurationFull' Clang consistently spills more than gcc, pushing the frame past the 2048 byte limit. Apply an existing approach of increasing the warn stack size to the non-sanitizer path so plain clang builds use a 3072 byte limit. Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5642 Signed-off-by: Ivan Lipski Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 096520bd27c6..79eeb3721b99 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -36,7 +36,11 @@ ifneq ($(CONFIG_FRAME_WARN),0) frame_warn_limit := 3072 endif else - frame_warn_limit := 2048 + ifeq ($(CONFIG_CC_IS_CLANG),y) + frame_warn_limit := 3072 + else + frame_warn_limit := 2048 + endif endif ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y) From 76b9706e7fa1a6e374703170128b1be2f590cda7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 23 Sep 2026 21:44:30 -0400 Subject: [PATCH 103/103] drm/amd/display: Bump frame warning limit for all builds of dml Some configs with gcc are also now affected. Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 +----- drivers/gpu/drm/amd/display/dc/dml2_0/Makefile | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 79eeb3721b99..91465ac05c97 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -36,11 +36,7 @@ ifneq ($(CONFIG_FRAME_WARN),0) frame_warn_limit := 3072 endif else - ifeq ($(CONFIG_CC_IS_CLANG),y) - frame_warn_limit := 3072 - else - frame_warn_limit := 2048 - endif + frame_warn_limit := 3072 endif ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile index 615cd0ca9450..e8bd061be05c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile @@ -35,7 +35,7 @@ ifneq ($(CONFIG_FRAME_WARN),0) frame_warn_limit := 3072 endif else - frame_warn_limit := 2056 + frame_warn_limit := 3072 endif ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y)