summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_job.c24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c26
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v11_0.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v12_0.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v12_1.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c15
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_crat.c35
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c13
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c13
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c10
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c30
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c60
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c21
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c80
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h22
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c11
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c12
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c5
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c24
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c17
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c5
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c84
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c48
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c8
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c80
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c248
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c168
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c24
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c327
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c12
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c30
-rw-r--r--drivers/gpu/drm/amd/display/dc/Makefile7
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h98
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h11
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_legacy_init.h128
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c413
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.h42
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.c1071
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.h18
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_builder/dmub_abi.h13
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c703
-rw-r--r--drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.h21
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c124
-rw-r--r--drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c78
-rw-r--r--drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.c236
-rw-r--r--drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.h17
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h33
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c173
-rw-r--r--drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c22
-rw-r--r--drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.c81
-rw-r--r--drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.h55
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c19
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c48
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c97
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h229
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c19
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dpms.c280
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c22
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.c74
-rw-r--r--drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.h46
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h11
-rw-r--r--drivers/gpu/drm/amd/display/include/gpio_service_interface.h6
-rw-r--r--drivers/gpu/drm/amd/include/cgs_common.h74
-rw-r--r--drivers/gpu/drm/amd/include/mes_v11_api_def.h3
-rw-r--r--drivers/gpu/drm/amd/include/mes_v12_api_def.h3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c193
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c193
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c229
-rw-r--r--drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c25
-rw-r--r--drivers/gpu/drm/drm_kms_helper_common.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c63
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c8
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c14
-rw-r--r--drivers/gpu/drm/radeon/si.c14
-rw-r--r--drivers/gpu/drm/radeon/sid.h2
-rw-r--r--drivers/gpu/drm/radeon/uvd_v1_0.c52
-rw-r--r--drivers/gpu/drm/radeon/vce_v1_0.c9
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c14
-rw-r--r--drivers/gpu/drm/xe/Makefile1
-rw-r--r--drivers/gpu/drm/xe/regs/xe_gt_regs.h4
-rw-r--r--drivers/gpu/drm/xe/regs/xe_lrc_layout.h3
-rw-r--r--drivers/gpu/drm/xe/tests/xe_kunit_helpers.c3
-rw-r--r--drivers/gpu/drm/xe/tests/xe_migrate.c302
-rw-r--r--drivers/gpu/drm/xe/xe_amc.c11
-rw-r--r--drivers/gpu/drm/xe/xe_bo.c46
-rw-r--r--drivers/gpu/drm/xe/xe_bo_types.h8
-rw-r--r--drivers/gpu/drm/xe/xe_configfs.h2
-rw-r--r--drivers/gpu/drm/xe/xe_debugfs.c66
-rw-r--r--drivers/gpu/drm/xe/xe_device.c218
-rw-r--r--drivers/gpu/drm/xe/xe_device.h14
-rw-r--r--drivers/gpu/drm/xe/xe_device_types.h28
-rw-r--r--drivers/gpu/drm/xe/xe_device_wa_oob.rules1
-rw-r--r--drivers/gpu/drm/xe/xe_gsc.c4
-rw-r--r--drivers/gpu/drm/xe/xe_gt.c87
-rw-r--r--drivers/gpu/drm/xe/xe_gt.h2
-rw-r--r--drivers/gpu/drm/xe/xe_gt_sriov_vf.c3
-rw-r--r--drivers/gpu/drm/xe/xe_gt_types.h9
-rw-r--r--drivers/gpu/drm/xe/xe_guc.c5
-rw-r--r--drivers/gpu/drm/xe/xe_guc.h2
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ct.c7
-rw-r--r--drivers/gpu/drm/xe/xe_guc_pc.c11
-rw-r--r--drivers/gpu/drm/xe/xe_guc_rc.c5
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.c62
-rw-r--r--drivers/gpu/drm/xe/xe_guc_tlb_inval.c3
-rw-r--r--drivers/gpu/drm/xe/xe_hw_error.c2
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.c8
-rw-r--r--drivers/gpu/drm/xe/xe_mert.c5
-rw-r--r--drivers/gpu/drm/xe/xe_migrate.c173
-rw-r--r--drivers/gpu/drm/xe/xe_oa.c24
-rw-r--r--drivers/gpu/drm/xe/xe_pat.c114
-rw-r--r--drivers/gpu/drm/xe/xe_pat.h25
-rw-r--r--drivers/gpu/drm/xe/xe_pci_error.c13
-rw-r--r--drivers/gpu/drm/xe/xe_pt.c2
-rw-r--r--drivers/gpu/drm/xe/xe_ras.c11
-rw-r--r--drivers/gpu/drm/xe/xe_shrinker.c3
-rw-r--r--drivers/gpu/drm/xe/xe_sriov_pf.c3
-rw-r--r--drivers/gpu/drm/xe/xe_survivability_mode.c4
-rw-r--r--drivers/gpu/drm/xe/xe_tuning.c2
-rw-r--r--drivers/gpu/drm/xe/xe_uc.c6
-rw-r--r--drivers/gpu/drm/xe/xe_uc.h2
-rw-r--r--drivers/gpu/drm/xe/xe_vm.c18
-rw-r--r--drivers/gpu/drm/xe/xe_vm_madvise.c17
-rw-r--r--drivers/gpu/drm/xe/xe_wa_oob.rules3
-rw-r--r--drivers/gpu/drm/xe/xe_wedge.c262
-rw-r--r--drivers/gpu/drm/xe/xe_wedge.h24
-rw-r--r--drivers/gpu/drm/xe/xe_wedge_types.h44
183 files changed, 6639 insertions, 1909 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index e023cc734ebc..0dab267eb382 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -768,9 +768,8 @@ err:
void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle)
{
enum amd_powergating_state state = idle ? AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE;
- if ((IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 11 &&
- ((adev->mes.kiq_version & AMDGPU_MES_VERSION_MASK) <= 64)) ||
- (IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 12)) {
+ if (IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 11 &&
+ ((adev->mes.kiq_version & AMDGPU_MES_VERSION_MASK) <= 64)) {
pr_debug("GFXOFF is %s\n", idle ? "enabled" : "disabled");
amdgpu_gfx_off_ctrl(adev, idle);
} else if ((IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 9) &&
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
index 04fab30ab5dd..96a308b94646 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
@@ -747,13 +747,9 @@ static uint32_t kgd_gfx_v11_set_address_watch(struct amdgpu_device *adev,
uint32_t debug_vmid,
uint32_t inst)
{
- uint32_t watch_address_high;
- uint32_t watch_address_low;
uint32_t watch_address_cntl;
watch_address_cntl = 0;
- watch_address_low = lower_32_bits(watch_address);
- watch_address_high = upper_32_bits(watch_address) & 0xffff;
watch_address_cntl = REG_SET_FIELD(watch_address_cntl,
TCP_WATCH0_CNTL,
@@ -770,14 +766,6 @@ static uint32_t kgd_gfx_v11_set_address_watch(struct amdgpu_device *adev,
VALID,
1);
- WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_H) +
- (watch_id * TCP_WATCH_STRIDE)),
- watch_address_high);
-
- WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_L) +
- (watch_id * TCP_WATCH_STRIDE)),
- watch_address_low);
-
return watch_address_cntl;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c
index 62b9db64368e..004d0253f60d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c
@@ -322,13 +322,9 @@ static uint32_t kgd_gfx_v12_set_address_watch(struct amdgpu_device *adev,
uint32_t debug_vmid,
uint32_t inst)
{
- uint32_t watch_address_high;
- uint32_t watch_address_low;
uint32_t watch_address_cntl;
watch_address_cntl = 0;
- watch_address_low = lower_32_bits(watch_address);
- watch_address_high = upper_32_bits(watch_address) & 0xffff;
watch_address_cntl = REG_SET_FIELD(watch_address_cntl,
TCP_WATCH0_CNTL,
@@ -345,14 +341,6 @@ static uint32_t kgd_gfx_v12_set_address_watch(struct amdgpu_device *adev,
VALID,
1);
- WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_H) +
- (watch_id * TCP_WATCH_STRIDE)),
- watch_address_high);
-
- WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_L) +
- (watch_id * TCP_WATCH_STRIDE)),
- watch_address_low);
-
return watch_address_cntl;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
index ec095003667f..ddd1140b6e5d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
@@ -331,13 +331,9 @@ static uint32_t kgd_gfx_v12_1_set_address_watch(struct amdgpu_device *adev,
uint32_t debug_vmid,
uint32_t inst)
{
- uint32_t watch_address_high;
- uint32_t watch_address_low;
uint32_t watch_address_cntl;
watch_address_cntl = 0;
- watch_address_low = lower_32_bits(watch_address);
- watch_address_high = upper_32_bits(watch_address) & 0x1ffffff;
watch_address_cntl = REG_SET_FIELD(watch_address_cntl,
TCP_WATCH0_CNTL,
@@ -354,14 +350,6 @@ static uint32_t kgd_gfx_v12_1_set_address_watch(struct amdgpu_device *adev,
VALID,
1);
- WREG32_XCC((SOC15_REG_OFFSET(GC, GET_INST(GC, inst), regTCP_WATCH0_ADDR_H) +
- (watch_id * TCP_WATCH_STRIDE)),
- watch_address_high, inst);
-
- WREG32_XCC((SOC15_REG_OFFSET(GC, GET_INST(GC, inst), regTCP_WATCH0_ADDR_L) +
- (watch_id * TCP_WATCH_STRIDE)),
- watch_address_low, inst);
-
return watch_address_cntl;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index a0ca93ffb00c..ab82ecc9e854 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -2853,6 +2853,7 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work)
struct task_struct *usertask;
struct mm_struct *mm;
uint32_t evicted_bos;
+ int ret;
mutex_lock(&process_info->notifier_lock);
evicted_bos = process_info->evicted_bos;
@@ -2872,14 +2873,16 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work)
mutex_lock(&process_info->lock);
- if (update_invalid_user_pages(process_info, mm))
+ ret = update_invalid_user_pages(process_info, mm);
+ if (ret)
goto unlock_out;
/* userptr_inval_list can be empty if all evicted userptr BOs
* have been freed. In that case there is nothing to validate
* and we can just restart the queues.
*/
if (!list_empty(&process_info->userptr_inval_list)) {
- if (validate_invalid_user_pages(process_info))
+ ret = validate_invalid_user_pages(process_info);
+ if (ret)
goto unlock_out;
}
/* Final check for concurrent evicton and atomic update. If
@@ -2888,11 +2891,14 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work)
* reference counting inside KFD will handle this case.
*/
mutex_lock(&process_info->notifier_lock);
- if (process_info->evicted_bos != evicted_bos)
+ if (process_info->evicted_bos != evicted_bos) {
+ ret = -EAGAIN;
goto unlock_notifier_out;
+ }
if (confirm_valid_user_pages_locked(process_info)) {
WARN(1, "User pages unexpectedly invalid");
+ ret = -EINVAL;
goto unlock_notifier_out;
}
@@ -2910,8 +2916,10 @@ unlock_notifier_out:
unlock_out:
mutex_unlock(&process_info->lock);
- /* If validation failed, reschedule another attempt */
- if (evicted_bos) {
+ /* If validation failed, reschedule another attempt, unless the
+ * device is gone for good
+ */
+ if (evicted_bos && ret != -ENODEV) {
queue_delayed_work(system_freezable_wq,
&process_info->restore_userptr_work,
msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS));
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 3ad3ac658c3d..7edca4f7f583 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -217,6 +217,12 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
size = p->chunks[i].length_dw;
+ if (size > INT_MAX / sizeof(uint32_t)) {
+ ret = -EINVAL;
+ i--;
+ goto free_partial_kdata;
+ }
+
p->chunks[i].kdata = vmemdup_array_user(u64_to_user_ptr(user_chunk.chunk_data),
size,
sizeof(uint32_t));
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 77c42d91fa44..92cc0fa7ba33 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3847,7 +3847,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
/* mutex initialization are all done here so we
* can recall function without having locking issues
*/
- mutex_init(&adev->firmware.mutex);
mutex_init(&adev->pm.mutex);
mutex_init(&adev->gfx.gpu_clock_mutex);
mutex_init(&adev->srbm_mutex);
@@ -4364,8 +4363,11 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
* before ip_fini_early to prevent kfd locking refcount issues by calling
* amdgpu_amdkfd_suspend()
*/
- if (pci_dev_is_disconnected(adev->pdev))
+ if (pci_dev_is_disconnected(adev->pdev)) {
+ /* Drain KFD processes while kfd.dev is still valid */
+ amdgpu_amdkfd_teardown_processes(adev);
amdgpu_amdkfd_device_fini_sw(adev);
+ }
amdgpu_coredump_fini(adev);
amdgpu_device_ip_fini_early(adev);
@@ -5269,8 +5271,6 @@ int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context)
if (r)
goto out;
- drm_client_dev_resume(adev_to_drm(tmp_adev));
-
/*
* The GPU enters bad state once faulty pages
* by ECC has reached the threshold, and ras
@@ -5603,8 +5603,6 @@ static void amdgpu_device_halt_activities(struct amdgpu_device *adev,
*/
amdgpu_unregister_gpu_instance(tmp_adev);
- drm_client_dev_suspend(adev_to_drm(tmp_adev));
-
/* disable ras on ALL IPs */
if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev))
amdgpu_ras_suspend(tmp_adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index 1482fc031d44..9c879ac68352 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -634,8 +634,9 @@ unlock:
* @vm: the VM with the reserved ID
* @vmhub: the VMHUB which should be used
*
- * Waits for all work that used the reserved VMID to finish before unbinding
- * its page table, so submissions still in flight don't suddenly fault.
+ * The caller must wait for all work that used the reserved VMID to finish
+ * before, so submissions still in flight don't suddenly fault when its page
+ * table gets unbound.
*/
void amdgpu_vmid_free_spm(struct amdgpu_device *adev, struct amdgpu_vm *vm,
unsigned vmhub)
@@ -649,9 +650,6 @@ void amdgpu_vmid_free_spm(struct amdgpu_device *adev, struct amdgpu_vm *vm,
vm->reserved_vmid[vmhub] = NULL;
id_mgr->reserved_vmid = false;
- /* Only for kernel queues and kfd/userqueues by pass that */
- amdgpu_sync_wait(&id->active, false);
-
if (adev->vm_manager.spm_vmid && adev->gfxhub.funcs)
amdgpu_gmc_bind_vmid(adev, AMDGPU_GFXHUB(0),
adev->vm_manager.spm_vmid, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index 9cc210198fa4..8689a3c933b2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -313,22 +313,7 @@ void amdgpu_job_free_resources(struct amdgpu_job *job)
static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
{
- struct amdgpu_job *job = to_amdgpu_job(s_job);
-
- drm_sched_job_cleanup(s_job);
-
- amdgpu_sync_free(&job->explicit_sync);
-
- if (dma_fence_was_initialized(&job->hw_fence->base))
- dma_fence_put(&job->hw_fence->base);
- else
- kfree(job->hw_fence);
- if (dma_fence_was_initialized(&job->hw_vm_fence->base))
- dma_fence_put(&job->hw_vm_fence->base);
- else
- kfree(job->hw_vm_fence);
-
- kfree(job);
+ amdgpu_job_free(to_amdgpu_job(s_job));
}
void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
@@ -349,13 +334,14 @@ void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
void amdgpu_job_free(struct amdgpu_job *job)
{
- if (job->base.entity)
+ if (job->gang_submit != &job->base.s_fence->scheduled)
+ dma_fence_put(job->gang_submit);
+
+ if (job->base.s_fence)
drm_sched_job_cleanup(&job->base);
amdgpu_job_free_resources(job);
amdgpu_sync_free(&job->explicit_sync);
- if (job->gang_submit != &job->base.s_fence->scheduled)
- dma_fence_put(job->gang_submit);
if (dma_fence_was_initialized(&job->hw_fence->base))
dma_fence_put(&job->hw_fence->base);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 36bc4b431dd5..01dca6858833 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -4157,8 +4157,6 @@ static int psp_hw_init(struct amdgpu_ip_block *ip_block)
int ret;
struct amdgpu_device *adev = ip_block->adev;
- mutex_lock(&adev->firmware.mutex);
-
ret = amdgpu_ucode_init_bo(adev);
if (ret)
goto failed;
@@ -4169,12 +4167,10 @@ static int psp_hw_init(struct amdgpu_ip_block *ip_block)
goto failed;
}
- mutex_unlock(&adev->firmware.mutex);
return 0;
failed:
adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT;
- mutex_unlock(&adev->firmware.mutex);
return -EINVAL;
}
@@ -4282,8 +4278,6 @@ static int psp_resume(struct amdgpu_ip_block *ip_block)
}
}
- mutex_lock(&adev->firmware.mutex);
-
ret = amdgpu_ucode_init_bo(adev);
if (ret)
goto failed;
@@ -4345,13 +4339,10 @@ static int psp_resume(struct amdgpu_ip_block *ip_block)
"SECUREDISPLAY: Failed to initialize SECUREDISPLAY\n");
}
- mutex_unlock(&adev->firmware.mutex);
-
return 0;
failed:
dev_err(adev->dev, "PSP resume failed\n");
- mutex_unlock(&adev->firmware.mutex);
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index 227734541316..7b67e8cecca2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -213,11 +213,9 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
unsigned int irq_type, unsigned int hw_prio,
atomic_t *sched_score)
{
- int r;
int sched_hw_submission = amdgpu_sched_hw_submission;
- u32 *num_sched;
- u32 hw_ip;
unsigned int max_ibs_dw;
+ int r;
/* Set the hw submission limit higher for KIQ because
* it's used for a number of gfx/compute tasks by both
@@ -359,10 +357,10 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
ring->vmid_wait = dma_fence_get_stub();
if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) {
- hw_ip = ring->funcs->type;
- num_sched = &adev->gpu_sched[hw_ip][hw_prio].num_scheds;
- adev->gpu_sched[hw_ip][hw_prio].sched[(*num_sched)++] =
- &ring->sched;
+ struct amdgpu_sched *gpu_sched =
+ &adev->gpu_sched[ring->funcs->type][hw_prio];
+
+ gpu_sched->sched[gpu_sched->num_scheds++] = &ring->sched;
}
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index adb6cfae5052..9856a2fc2d08 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -30,6 +30,7 @@
#include "amdgpu_vram_mgr.h"
#include "amdgpu_hmm.h"
#include "amdgpu_gmc.h"
+#include "amdgpu_sdma_types.h"
#define AMDGPU_PL_GDS (TTM_PL_PRIV + 0)
#define AMDGPU_PL_GWS (TTM_PL_PRIV + 1)
@@ -89,7 +90,7 @@ struct amdgpu_mman {
/* buffer handling */
const struct amdgpu_buffer_funcs *buffer_funcs;
- struct drm_gpu_scheduler *buffer_funcs_scheds[AMDGPU_MAX_RINGS];
+ struct drm_gpu_scheduler *buffer_funcs_scheds[AMDGPU_MAX_SDMA_INSTANCES];
u32 num_buffer_funcs_scheds;
bool buffer_funcs_enabled;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
index 35277b240f25..7c809692807f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
@@ -612,7 +612,6 @@ struct amdgpu_firmware {
/* firmwares are loaded by psp instead of smu from vega10 */
const struct amdgpu_psp_funcs *funcs;
struct amdgpu_bo *rbuf;
- struct mutex mutex;
/* gpu info firmware data pointer */
const struct firmware *gpu_info_fw;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index ecd7caa95d4b..cd35ff7ca864 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -377,7 +377,8 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev)
void *addr = amdgpu_bo_kptr(adev->uvd.ib_bo);
int i, j;
- drm_sched_entity_destroy(&adev->uvd.entity);
+ if (adev->uvd.entity.rq)
+ drm_sched_entity_destroy(&adev->uvd.entity);
for (j = 0; j < adev->uvd.num_uvd_inst; ++j) {
if (adev->uvd.harvest_config & (1 << j))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 1f7a98cdce5a..3952af9ae115 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -253,7 +253,8 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
if (adev->vce.vcpu_bo == NULL)
return 0;
- drm_sched_entity_destroy(&adev->vce.entity);
+ if (adev->vce.entity.rq)
+ drm_sched_entity_destroy(&adev->vce.entity);
for (i = 0; i < adev->vce.num_rings; i++)
amdgpu_ring_fini(&adev->vce.ring[i]);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 613c0b43ea3d..65974c0e7a16 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -630,7 +630,6 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm,
dma_resv_assert_held(vm->root.bo->tbo.base.resv);
if (vm->generation != new_vm_generation) {
- vm->generation = new_vm_generation;
amdgpu_vm_bo_reset_state_machine(vm);
amdgpu_vm_fini_entities(vm);
r = amdgpu_vm_init_entities(adev, vm);
@@ -645,9 +644,18 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm,
vm->update_funcs->map_table(to_amdgpu_bo_vm(bo_base->bo));
bo_base->moved = true;
+
+ if (vm->generation != new_vm_generation) {
+ r = amdgpu_vm_pt_clear(adev, vm, to_amdgpu_bo_vm(bo_base->bo), false);
+ if (r)
+ return r;
+ }
+
amdgpu_vm_bo_needs_update(bo_base);
}
+ vm->generation = new_vm_generation;
+
/*
* As soon as all page tables are in place we can start updating them
* again.
@@ -2852,6 +2860,10 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
root = amdgpu_bo_ref(vm->root.bo);
amdgpu_bo_reserve(root, true);
+ /* Wait for the jobs which might still use the reserved VMID */
+ if (vm->reserved_vmid[AMDGPU_GFXHUB(0)])
+ dma_resv_wait_timeout(root->tbo.base.resv, DMA_RESV_USAGE_READ,
+ false, MAX_SCHEDULE_TIMEOUT);
dma_fence_wait(vm->last_unlocked, false);
dma_fence_put(vm->last_unlocked);
dma_fence_wait(vm->last_tlb_flush, false);
@@ -3002,9 +3014,19 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
return r;
}
- case AMDGPU_VM_OP_UNRESERVE_VMID:
+ case AMDGPU_VM_OP_UNRESERVE_VMID: {
+ struct amdgpu_bo *root = vm->root.bo;
+
+ amdgpu_bo_reserve(root, true);
+ /* Wait for the jobs which might still use the reserved VMID */
+ if (vm->reserved_vmid[AMDGPU_GFXHUB(0)])
+ dma_resv_wait_timeout(root->tbo.base.resv,
+ DMA_RESV_USAGE_READ, false,
+ MAX_SCHEDULE_TIMEOUT);
amdgpu_vmid_free_spm(adev, vm, AMDGPU_GFXHUB(0));
+ amdgpu_bo_unreserve(root);
break;
+ }
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 2a2a2ccbaa2c..06e0ddd60c7b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -395,7 +395,7 @@ struct amdgpu_vm_manager {
u64 vram_base_offset;
/* vm pte handling */
const struct amdgpu_vm_pte_funcs *vm_pte_funcs;
- struct drm_gpu_scheduler *vm_pte_scheds[AMDGPU_MAX_RINGS];
+ struct drm_gpu_scheduler *vm_pte_scheds[AMDGPU_MAX_SDMA_INSTANCES];
unsigned vm_pte_num_scheds;
struct amdgpu_ring *page_fault;
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
index b2e4da70d208..fa5810209f37 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
@@ -1034,6 +1034,12 @@ static int mes_v11_0_misc_op(struct amdgpu_mes *mes,
memcpy(misc_pkt.set_shader_debugger.tcp_watch_cntl,
input->set_shader_debugger.tcp_watch_cntl,
sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl));
+ for (int i = 0; i < 4; i++) {
+ misc_pkt.set_shader_debugger.tcp_watch_addr_lo[i] =
+ lower_32_bits(input->set_shader_debugger.watch_addresses[i]);
+ misc_pkt.set_shader_debugger.tcp_watch_addr_hi[i] =
+ upper_32_bits(input->set_shader_debugger.watch_addresses[i]) & 0xffff;
+ }
misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en;
break;
case MES_MISC_OP_CHANGE_CONFIG:
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
index ce577f49b630..496ac632c3e5 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
@@ -983,6 +983,12 @@ static int mes_v12_0_misc_op(struct amdgpu_mes *mes,
memcpy(misc_pkt.set_shader_debugger.tcp_watch_cntl,
input->set_shader_debugger.tcp_watch_cntl,
sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl));
+ for (int i = 0; i < 4; i++) {
+ misc_pkt.set_shader_debugger.tcp_watch_addr_lo[i] =
+ lower_32_bits(input->set_shader_debugger.watch_addresses[i]);
+ misc_pkt.set_shader_debugger.tcp_watch_addr_hi[i] =
+ upper_32_bits(input->set_shader_debugger.watch_addresses[i]) & 0xffff;
+ }
misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en;
break;
case MES_MISC_OP_CHANGE_CONFIG:
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
index 99e8a7eeaa4b..5573fe981a22 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
@@ -624,6 +624,12 @@ static int mes_v12_1_misc_op(struct amdgpu_mes *mes,
memcpy(misc_pkt.set_shader_debugger.tcp_watch_cntl,
input->set_shader_debugger.tcp_watch_cntl,
sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl));
+ for (int i = 0; i < 4; i++) {
+ misc_pkt.set_shader_debugger.tcp_watch_addr_lo[i] =
+ lower_32_bits(input->set_shader_debugger.watch_addresses[i]);
+ misc_pkt.set_shader_debugger.tcp_watch_addr_hi[i] =
+ upper_32_bits(input->set_shader_debugger.watch_addresses[i]) & 0xffff;
+ }
misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en;
break;
case MES_MISC_OP_CHANGE_CONFIG:
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 5f8fb934720b..1115f7ebd665 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -2876,6 +2876,7 @@ static int criu_process_info(struct file *filep,
struct kfd_process *p,
struct kfd_ioctl_criu_args *args)
{
+ bool paused_here = false;
int ret = 0;
mutex_lock(&p->mutex);
@@ -2886,11 +2887,15 @@ static int criu_process_info(struct file *filep,
goto err_unlock;
}
- ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_CRIU_CHECKPOINT);
- if (ret)
- goto err_unlock;
+ /* UNPAUSE restores the queues once, so evict them only once */
+ if (!p->queues_paused) {
+ ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_CRIU_CHECKPOINT);
+ if (ret)
+ goto err_unlock;
- p->queues_paused = true;
+ p->queues_paused = true;
+ paused_here = true;
+ }
args->pid = task_pid_nr_ns(p->lead_thread,
task_active_pid_ns(p->lead_thread));
@@ -2905,7 +2910,7 @@ static int criu_process_info(struct file *filep,
args->priv_data_size);
err_unlock:
- if (ret) {
+ if (ret && paused_here) {
kfd_process_restore_queues(p);
p->queues_paused = false;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index 6e0df685503d..32d7573dffc9 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -2056,27 +2056,33 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev)
return;
}
+ if (table_header->length < sizeof(struct acpi_table_srat))
+ goto invalid_srat;
+
table_end = (unsigned long)table_header + table_header->length;
/* Parse all entries looking for a match. */
sub_header = (struct acpi_subtable_header *)
((unsigned long)table_header +
sizeof(struct acpi_table_srat));
- subtable_len = sub_header->length;
- while (((unsigned long)sub_header) + subtable_len < table_end) {
- /*
- * If length is 0, break from this loop to avoid
- * infinite loop.
- */
- if (subtable_len == 0) {
- pr_err("SRAT invalid zero length\n");
- break;
- }
+ while ((unsigned long)sub_header < table_end) {
+ unsigned long start = (unsigned long)sub_header;
+
+ if (table_end - start < sizeof(*sub_header))
+ goto invalid_srat;
+
+ subtable_len = sub_header->length;
+ if (subtable_len < sizeof(*sub_header) ||
+ subtable_len > table_end - start)
+ goto invalid_srat;
switch (sub_header->type) {
case ACPI_SRAT_TYPE_CPU_AFFINITY:
cpu = (struct acpi_srat_cpu_affinity *)sub_header;
+ if (subtable_len < sizeof(*cpu))
+ goto invalid_srat;
+
pxm = *((u32 *)cpu->proximity_domain_hi) << 8 |
cpu->proximity_domain_lo;
if (pxm > max_pxm)
@@ -2084,6 +2090,9 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev)
break;
case ACPI_SRAT_TYPE_GENERIC_AFFINITY:
gpu = (struct acpi_srat_generic_affinity *)sub_header;
+ if (subtable_len < sizeof(*gpu))
+ goto invalid_srat;
+
bdf = *((u16 *)(&gpu->device_handle[0])) << 16 |
*((u16 *)(&gpu->device_handle[2]));
if (bdf == pci_id) {
@@ -2100,9 +2109,13 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev)
sub_header = (struct acpi_subtable_header *)
((unsigned long)sub_header + subtable_len);
- subtable_len = sub_header->length;
}
+ goto out;
+
+invalid_srat:
+ pr_err("SRAT contains an invalid subtable\n");
+out:
acpi_put_table(table_header);
/* Workaround bad cpu-gpu binding case */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index bb4c6695f3cf..0f96c9e3fa4d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -1814,7 +1814,14 @@ void kgd2kfd_teardown_processes(struct amdgpu_device *adev)
mutex_unlock(&kfd_processes_mutex);
- /* wait all kfd processes use adev terminate */
+ /* kfd.dev may already be freed on surprise removal */
+ if (!adev->kfd.dev)
+ return;
+
+ /*
+ * Wait for all KFD processes using adev to terminate. Must be
+ * unbounded: device state is freed once they are gone.
+ */
while (!!atomic_read(&adev->kfd.dev->kfd_processes_count))
cond_resched();
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
index 38b46b696243..d63f7e9fae30 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
@@ -138,6 +138,15 @@ struct mqd_manager {
uint32_t ctl_stack_size;
};
+/* Keep offset <= size <= wave state offset, as init_mqd() and CP do */
+static inline void kfd_mqd_restore_ctl_stack(u32 *size, u32 *offset, u32 *wg_offset,
+ u32 ctl_stack_size)
+{
+ *size = ctl_stack_size;
+ *offset = min(*offset, ctl_stack_size);
+ *wg_offset = max(*wg_offset, ctl_stack_size);
+}
+
struct mqd_user_context_save_area_header {
/* Byte offset from start of user context
* save area to the last saved top (lowest
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
index 4f8a8a1a6186..922615b713a9 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
@@ -305,6 +305,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
@@ -396,6 +398,13 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd,
m->sdma_queue_id = q->sdma_queue_id;
m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT;
+ /* Enable IB execution; allow context switch inside an IB so one
+ * queue cannot starve the engine.
+ */
+ m->sdmax_rlcx_ib_cntl |=
+ SDMA0_RLC0_IB_CNTL__IB_ENABLE_MASK |
+ SDMA0_RLC0_IB_CNTL__SWITCH_INSIDE_IB_MASK;
+
q->is_active = QUEUE_IS_ACTIVE(*q);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
index bf015dc5b868..62c3023152a5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
@@ -340,6 +340,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
@@ -478,6 +480,13 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd,
m->sdma_queue_id = q->sdma_queue_id;
m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT;
+ /* Enable IB execution; allow context switch inside an IB so one
+ * queue cannot starve the engine.
+ */
+ m->sdmax_rlcx_ib_cntl |=
+ SDMA0_QUEUE0_IB_CNTL__IB_ENABLE_MASK |
+ SDMA0_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK;
+
q->is_active = QUEUE_IS_ACTIVE(*q);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
index 6ea09b031caf..1d9b4890909f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
@@ -353,11 +353,12 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd,
m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT;
- /* Allow context switch so we don't cross-process starve with a massive
- * command buffer of long-running SDMA commands
- * sdmax_rlcx_ib_cntl represent SDMA_QUEUE0_IB_CNTL register
- */
- m->sdmax_rlcx_ib_cntl |= SDMA0_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK;
+ /* Enable IB execution; allow context switch inside an IB so one
+ * queue cannot starve the engine.
+ */
+ m->sdmax_rlcx_ib_cntl |=
+ SDMA0_QUEUE0_IB_CNTL__IB_ENABLE_MASK |
+ SDMA0_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK;
q->is_active = QUEUE_IS_ACTIVE(*q);
}
@@ -393,6 +394,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
/* Update MQD base address to the newly allocated location */
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
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 2bbf5e63f615..e34103067fa0 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
@@ -457,11 +457,12 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd,
m->sdmax_queuen_dummy_reg1 = 1;
- /* Allow context switch so we don't cross-process starve with a massive
- * command buffer of long-running SDMA commands
- * sdmax_queuen_ib_cntl represent SDMA_QUEUE0_IB_CNTL register
- */
- m->sdmax_queuen_ib_cntl |= SDMA0_SDMA_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK;
+ /* Enable IB execution; allow context switch inside an IB so one
+ * queue cannot starve the engine.
+ */
+ m->sdmax_queuen_ib_cntl |=
+ SDMA0_SDMA_QUEUE0_IB_CNTL__IB_ENABLE_MASK |
+ SDMA0_SDMA_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK;
q->is_active = QUEUE_IS_ACTIVE(*q);
}
@@ -692,6 +693,8 @@ static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd,
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) *
NUM_XCC(mm->dev->xcc_mask));
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
/* Update MQD base address to the newly allocated location */
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index 6e6bc1ec0b64..e18c86c87d1c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -462,6 +462,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
@@ -569,10 +571,12 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd,
m->sdma_engine_id = q->sdma_engine_id;
m->sdma_queue_id = q->sdma_queue_id;
m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT;
- /* Allow context switch so we don't cross-process starve with a massive
- * command buffer of long-running SDMA commands
+ /* Enable IB execution; allow context switch inside an IB so one
+ * queue cannot starve the engine.
*/
- m->sdmax_rlcx_ib_cntl |= SDMA0_GFX_IB_CNTL__SWITCH_INSIDE_IB_MASK;
+ m->sdmax_rlcx_ib_cntl |=
+ SDMA0_GFX_IB_CNTL__IB_ENABLE_MASK |
+ SDMA0_GFX_IB_CNTL__SWITCH_INSIDE_IB_MASK;
q->is_active = QUEUE_IS_ACTIVE(*q);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
index 029572548c14..5ead0d5613b6 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
@@ -317,6 +317,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index a15a826519ad..78ab759ad854 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -26,6 +26,7 @@
#include <linux/list.h>
#include "kfd_device_queue_manager.h"
#include "kfd_priv.h"
+#include "kfd_topology.h"
#include "kfd_kernel_queue.h"
#include "amdgpu_amdkfd.h"
#include "amdgpu_reset.h"
@@ -983,7 +984,7 @@ int kfd_criu_checkpoint_queues(struct kfd_process *p,
}
static void set_queue_properties_from_criu(struct queue_properties *qp,
- struct kfd_criu_queue_priv_data *q_data, uint32_t num_xcc)
+ struct kfd_criu_queue_priv_data *q_data)
{
qp->is_interop = false;
qp->queue_percent = q_data->q_percent;
@@ -996,11 +997,6 @@ static void set_queue_properties_from_criu(struct queue_properties *qp,
qp->eop_ring_buffer_size = q_data->eop_ring_buffer_size;
qp->ctx_save_restore_area_address = q_data->ctx_save_restore_area_address;
qp->ctx_save_restore_area_size = q_data->ctx_save_restore_area_size;
- if (q_data->type == KFD_QUEUE_TYPE_COMPUTE)
- qp->ctl_stack_size = q_data->ctl_stack_size / num_xcc;
- else
- qp->ctl_stack_size = q_data->ctl_stack_size;
-
qp->type = q_data->type;
qp->format = q_data->format;
}
@@ -1012,6 +1008,7 @@ int kfd_criu_restore_queue(struct kfd_process *p,
{
uint8_t *mqd, *ctl_stack, *q_extra_data = NULL;
struct kfd_criu_queue_priv_data *q_data;
+ struct kfd_topology_device *topo_dev;
struct kfd_process_device *pdd;
uint64_t q_extra_data_size;
struct queue_properties qp;
@@ -1048,6 +1045,24 @@ int kfd_criu_restore_queue(struct kfd_process *p,
goto exit;
}
+ memset(&qp, 0, sizeof(qp));
+ set_queue_properties_from_criu(&qp, q_data);
+
+ /* Per-XCC control stack size from topology, as create-queue requires */
+ if (qp.type == KFD_QUEUE_TYPE_COMPUTE && pdd->dev->kfd->cwsr_enabled) {
+ topo_dev = kfd_topology_device_by_id(pdd->dev->id);
+ if (!topo_dev) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ qp.ctl_stack_size = topo_dev->node_props.ctl_stack_size;
+ }
+
+ if (q_data->ctl_stack_size > (u64)qp.ctl_stack_size * NUM_XCC(pdd->dev->xcc_mask)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
*priv_data_offset += sizeof(*q_data);
q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size;
@@ -1077,9 +1092,6 @@ int kfd_criu_restore_queue(struct kfd_process *p,
mqd = q_extra_data;
ctl_stack = mqd + q_data->mqd_size;
- memset(&qp, 0, sizeof(qp));
- set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->xcc_mask));
-
print_queue_properties(&qp);
ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
index 6a7b4d959541..c87370a9f5f0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
@@ -40,7 +40,7 @@ struct kfd_smi_client {
struct kfd_node *dev;
spinlock_t lock;
struct rcu_head rcu;
- pid_t pid;
+ pid_t tgid;
bool suser;
};
@@ -160,18 +160,18 @@ static int kfd_smi_ev_release(struct inode *inode, struct file *filep)
return 0;
}
-static bool kfd_smi_ev_enabled(pid_t pid, struct kfd_smi_client *client,
+static bool kfd_smi_ev_enabled(pid_t tgid, struct kfd_smi_client *client,
unsigned int event)
{
uint64_t events = READ_ONCE(client->events);
- if (pid && client->pid != pid && !client->suser)
+ if (tgid && client->tgid != tgid && !client->suser)
return false;
return events & KFD_SMI_EVENT_MASK_FROM_INDEX(event);
}
-static void add_event_to_kfifo(pid_t pid, struct kfd_node *dev,
+static void add_event_to_kfifo(pid_t tgid, struct kfd_node *dev,
unsigned int smi_event, char *event_msg, int len)
{
struct kfd_smi_client *client;
@@ -179,7 +179,7 @@ static void add_event_to_kfifo(pid_t pid, struct kfd_node *dev,
rcu_read_lock();
list_for_each_entry_rcu(client, &dev->smi_clients, list) {
- if (!kfd_smi_ev_enabled(pid, client, smi_event))
+ if (!kfd_smi_ev_enabled(tgid, client, smi_event))
continue;
spin_lock(&client->lock);
if (kfifo_avail(&client->fifo) >= len) {
@@ -210,27 +210,33 @@ static inline pid_t kfd_smi_task_to_pid(struct task_struct *task)
return task ? task_tgid_nr_ns(task, task_active_pid_ns(task)) : 0;
}
+/*
+ * Clients are matched by global TGID, which is unique across PID namespaces
+ * and stays valid after the task exited. Events show kfd_smi_task_to_pid().
+ */
+static inline pid_t kfd_smi_task_tgid(struct task_struct *task)
+{
+ return task ? task_tgid_nr(task) : 0;
+}
+
__printf(4, 5)
-static void kfd_smi_event_add(struct task_struct *task, struct kfd_node *dev,
+static void kfd_smi_event_add(pid_t tgid, struct kfd_node *dev,
unsigned int event, char *fmt, ...)
{
char fifo_in[KFD_SMI_EVENT_MSG_SIZE];
int len;
va_list args;
- pid_t pid;
if (list_empty(&dev->smi_clients))
return;
- pid = kfd_smi_task_to_pid(task);
-
len = scnprintf(fifo_in, sizeof(fifo_in), "%x ", event);
va_start(args, fmt);
len += vscnprintf(fifo_in + len, sizeof(fifo_in) - len, fmt, args);
va_end(args);
- add_event_to_kfifo(pid, dev, event, fifo_in, len);
+ add_event_to_kfifo(tgid, dev, event, fifo_in, len);
}
void kfd_smi_event_update_gpu_reset(struct kfd_node *dev, bool post_reset,
@@ -252,14 +258,14 @@ void kfd_smi_event_update_gpu_reset(struct kfd_node *dev, bool post_reset,
amdgpu_reset_get_desc(reset_context, reset_cause,
sizeof(reset_cause));
- kfd_smi_event_add(NULL, dev, event, KFD_EVENT_FMT_UPDATE_GPU_RESET(
+ kfd_smi_event_add(0, dev, event, KFD_EVENT_FMT_UPDATE_GPU_RESET(
dev->reset_seq_num, reset_cause));
}
void kfd_smi_event_update_thermal_throttling(struct kfd_node *dev,
uint64_t throttle_bitmask)
{
- kfd_smi_event_add(NULL, dev, KFD_SMI_EVENT_THERMAL_THROTTLE,
+ kfd_smi_event_add(0, dev, KFD_SMI_EVENT_THERMAL_THROTTLE,
KFD_EVENT_FMT_THERMAL_THROTTLING(
throttle_bitmask,
amdgpu_dpm_get_thermal_throttling_counter(dev->adev)));
@@ -271,10 +277,14 @@ void kfd_smi_event_update_vmfault(struct kfd_node *dev, uint16_t pasid)
task_info = amdgpu_vm_get_task_info_pasid(dev->adev, pasid);
if (task_info) {
- /* Report VM faults from user applications, not retry from kernel */
+ /*
+ * Report VM faults from user applications, not retry from
+ * kernel, and only to clients allowed to see that process.
+ */
if (task_info->task.pid)
- kfd_smi_event_add(NULL, dev, KFD_SMI_EVENT_VMFAULT, KFD_EVENT_FMT_VMFAULT(
- task_info->task.pid, task_info->task.comm));
+ kfd_smi_event_add(task_info->tgid, dev, KFD_SMI_EVENT_VMFAULT,
+ KFD_EVENT_FMT_VMFAULT(task_info->task.pid,
+ task_info->task.comm));
amdgpu_vm_put_task_info(task_info);
}
}
@@ -283,7 +293,7 @@ void kfd_smi_event_page_fault_start(struct kfd_node *node, struct task_struct *t
unsigned long address, bool write_fault,
ktime_t ts)
{
- kfd_smi_event_add(task, node, KFD_SMI_EVENT_PAGE_FAULT_START,
+ kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_PAGE_FAULT_START,
KFD_EVENT_FMT_PAGEFAULT_START(ktime_to_ns(ts),
kfd_smi_task_to_pid(task), address, node->id,
write_fault ? 'W' : 'R'));
@@ -292,7 +302,7 @@ void kfd_smi_event_page_fault_start(struct kfd_node *node, struct task_struct *t
void kfd_smi_event_page_fault_end(struct kfd_node *node, struct task_struct *task,
unsigned long address, bool migration)
{
- kfd_smi_event_add(task, node, KFD_SMI_EVENT_PAGE_FAULT_END,
+ kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_PAGE_FAULT_END,
KFD_EVENT_FMT_PAGEFAULT_END(ktime_get_boottime_ns(),
kfd_smi_task_to_pid(task), address, node->id,
migration ? 'M' : 'U'));
@@ -304,7 +314,7 @@ void kfd_smi_event_migration_start(struct kfd_node *node, struct task_struct *ta
uint32_t prefetch_loc, uint32_t preferred_loc,
uint32_t trigger)
{
- kfd_smi_event_add(task, node, KFD_SMI_EVENT_MIGRATE_START,
+ kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_MIGRATE_START,
KFD_EVENT_FMT_MIGRATE_START(ktime_get_boottime_ns(),
kfd_smi_task_to_pid(task), start, end - start, from,
to, prefetch_loc, preferred_loc, trigger));
@@ -315,7 +325,7 @@ void kfd_smi_event_migration_end(struct kfd_node *node, struct task_struct *task
uint32_t from, uint32_t to, uint32_t trigger,
int error_code)
{
- kfd_smi_event_add(task, node, KFD_SMI_EVENT_MIGRATE_END,
+ kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_MIGRATE_END,
KFD_EVENT_FMT_MIGRATE_END(ktime_get_boottime_ns(),
kfd_smi_task_to_pid(task), start, end - start, from,
to, trigger, error_code));
@@ -324,14 +334,14 @@ void kfd_smi_event_migration_end(struct kfd_node *node, struct task_struct *task
void kfd_smi_event_queue_eviction(struct kfd_node *node, struct task_struct *task,
uint32_t trigger)
{
- kfd_smi_event_add(task, node, KFD_SMI_EVENT_QUEUE_EVICTION,
+ kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_QUEUE_EVICTION,
KFD_EVENT_FMT_QUEUE_EVICTION(ktime_get_boottime_ns(),
kfd_smi_task_to_pid(task), node->id, trigger));
}
void kfd_smi_event_queue_restore(struct kfd_node *node, struct task_struct *task)
{
- kfd_smi_event_add(task, node, KFD_SMI_EVENT_QUEUE_RESTORE,
+ kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_QUEUE_RESTORE,
KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(),
kfd_smi_task_to_pid(task), node->id, '0'));
}
@@ -348,7 +358,7 @@ void kfd_smi_event_queue_restore_rescheduled(struct mm_struct *mm)
for (i = 0; i < p->n_pdds; i++) {
struct kfd_process_device *pdd = p->pdds[i];
- kfd_smi_event_add(p->lead_thread, pdd->dev,
+ kfd_smi_event_add(kfd_smi_task_tgid(p->lead_thread), pdd->dev,
KFD_SMI_EVENT_QUEUE_RESTORE,
KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(),
kfd_smi_task_to_pid(p->lead_thread),
@@ -361,7 +371,7 @@ void kfd_smi_event_unmap_from_gpu(struct kfd_node *node, struct task_struct *tas
unsigned long address, unsigned long last,
uint32_t trigger)
{
- kfd_smi_event_add(task, node, KFD_SMI_EVENT_UNMAP_FROM_GPU,
+ kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_UNMAP_FROM_GPU,
KFD_EVENT_FMT_UNMAP_FROM_GPU(ktime_get_boottime_ns(),
kfd_smi_task_to_pid(task), address,
last - address + 1, node->id, trigger));
@@ -379,7 +389,7 @@ void kfd_smi_event_process(struct kfd_process_device *pdd, bool start)
task_info = amdgpu_vm_get_task_info_vm(avm);
if (task_info) {
- kfd_smi_event_add(NULL, pdd->dev,
+ kfd_smi_event_add(kfd_smi_task_tgid(pdd->process->lead_thread), pdd->dev,
start ? KFD_SMI_EVENT_PROCESS_START :
KFD_SMI_EVENT_PROCESS_END,
KFD_EVENT_FMT_PROCESS(task_info->task.pid,
@@ -408,7 +418,7 @@ int kfd_smi_event_open(struct kfd_node *dev, uint32_t *fd)
spin_lock_init(&client->lock);
client->events = 0;
client->dev = dev;
- client->pid = kfd_smi_task_to_pid(current);
+ client->tgid = kfd_smi_task_tgid(current);
client->suser = capable(CAP_SYS_ADMIN);
spin_lock(&dev->smi_lock);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 1f5d73f0ebce..ed5e3318877b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -1020,9 +1020,12 @@ svm_range_split_pages(struct svm_range *new, struct svm_range *old,
uint64_t start, uint64_t last)
{
uint64_t npages = last - start + 1;
+ bool has_dma_addr = false;
int i, r;
for (i = 0; i < MAX_GPU_INSTANCE; i++) {
+ if (old->dma_addr[i])
+ has_dma_addr = true;
r = svm_range_split_array(&new->dma_addr[i], &old->dma_addr[i],
sizeof(*old->dma_addr[i]), old->start,
npages, new->start, new->npages,
@@ -1030,8 +1033,16 @@ svm_range_split_pages(struct svm_range *new, struct svm_range *old,
if (r)
return r;
}
- if (old->actual_loc)
+ if (old->actual_loc) {
+ /*
+ * Pages migrated by prefetch have no dma_addr until they are
+ * mapped on a GPU. A fully resident range still splits exactly,
+ * old->npages isn't adjusted yet here.
+ */
+ if (!has_dma_addr && old->vram_pages == old->npages)
+ new->vram_pages = new->npages;
old->vram_pages -= new->vram_pages;
+ }
return 0;
}
@@ -1963,7 +1974,7 @@ static void svm_range_restore_work(struct work_struct *work)
struct mm_struct *mm;
int evicted_ranges;
int invalid;
- int r;
+ int r = 0;
svms = container_of(dwork, struct svm_range_list, restore_work);
evicted_ranges = atomic_read(&svms->evicted_ranges);
@@ -2037,8 +2048,10 @@ out_reschedule:
mmap_write_unlock(mm);
mutex_unlock(&process_info->lock);
- /* If validation failed, reschedule another attempt */
- if (evicted_ranges) {
+ /* If validation failed, reschedule another attempt, unless the
+ * device is gone for good
+ */
+ if (evicted_ranges && r != -ENODEV) {
pr_debug("reschedule to restore svm range\n");
queue_delayed_work(system_freezable_wq, &svms->restore_work,
msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS));
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index 35b3abe57b80..1ef4d26a0ac6 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -2091,7 +2091,7 @@ int kfd_topology_add_device(struct kfd_node *gpu)
* needed for the topology
*/
for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1; i++) {
- dev->node_props.name[i] = __tolower(asic_name[i]);
+ dev->node_props.name[i] = tolower(asic_name[i]);
if (asic_name[i] == '\0')
break;
}
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 d740108b1274..56fca4e22df8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -716,9 +716,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
dc_hardware_init(adev->dm.dc);
- /* Enable cursor offload if the ASIC 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
@@ -1775,7 +1772,7 @@ STATIC_IFN_KUNIT void dm_gpureset_commit_state(struct dc_state *dc_state,
struct dc_scaling_info scaling_infos[MAX_SURFACES];
struct dc_flip_addrs flip_addrs[MAX_SURFACES];
struct dc_stream_update stream_update;
- } *bundle __free(kfree);
+ } *bundle __free(kfree) = NULL;
int k, m;
bundle = kzalloc_obj(*bundle);
@@ -2021,10 +2018,6 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
/* On resume we need to rewrite the MSTM control bits to enable MST*/
s3_handle_mst(ddev, false);
- /* Exit IPS before the detection loop's first AUX/DDC access. */
- scoped_guard(mutex, &dm->dc_lock)
- dc_exit_ips_for_hw_access(dm->dc);
-
/* Do detection*/
drm_connector_list_iter_begin(ddev, &iter);
drm_for_each_connector_iter(connector, &iter) {
@@ -4730,8 +4723,6 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
if (dm_old_crtc_state->stream)
remove_stream(adev, acrtc, dm_old_crtc_state->stream);
- pm_runtime_get_noresume(dev->dev);
-
acrtc->enabled = true;
acrtc->hw_mode = new_crtc_state->mode;
crtc->hwmode = new_crtc_state->mode;
@@ -5281,10 +5272,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state)
* To fix this, DC should permit updating only stream properties.
*/
dummy_updates = kzalloc(sizeof(struct dc_surface_update) * MAX_SURFACES, GFP_KERNEL);
- if (!dummy_updates) {
- drm_err(adev_to_drm(adev), "Failed to allocate memory for dummy_updates.\n");
+ if (!dummy_updates)
continue;
- }
for (j = 0; j < status->plane_count; j++)
dummy_updates[j].surface = status->plane_states[j];
@@ -5315,8 +5304,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state)
#ifdef CONFIG_DEBUG_FS
enum amdgpu_dm_pipe_crc_source cur_crc_src;
#endif
- /* Count number of newly disabled CRTCs for dropping PM refs later. */
- if (old_crtc_state->active && !new_crtc_state->active)
+ /*
+ * One runtime PM reference per active CRTC: take it when the
+ * CRTC turns on, count it when it turns off for dropping later.
+ */
+ if (!old_crtc_state->active && new_crtc_state->active)
+ pm_runtime_get_noresume(dev->dev);
+ else if (old_crtc_state->active && !new_crtc_state->active)
crtc_disable_count++;
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
@@ -5342,39 +5336,39 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state)
amdgpu_dm_handle_vrr_transition(dm, dm_old_crtc_state, dm_new_crtc_state);
#ifdef CONFIG_DEBUG_FS
- if (new_crtc_state->active &&
- (!old_crtc_state->active ||
- drm_atomic_crtc_needs_modeset(new_crtc_state))) {
- /**
- * Frontend may have changed so reapply the CRC capture
- * settings for the stream.
- */
- if (amdgpu_dm_is_valid_crc_source(cur_crc_src)) {
+ if (!new_crtc_state->active ||
+ (old_crtc_state->active && !drm_atomic_crtc_needs_modeset(new_crtc_state)))
+ continue;
+
+ /**
+ * Frontend may have changed so reapply the CRC capture
+ * settings for the stream.
+ */
+ if (!amdgpu_dm_is_valid_crc_source(cur_crc_src))
+ continue;
+
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- if (amdgpu_dm_crc_window_is_activated(crtc)) {
- uint8_t cnt;
-
- spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- for (cnt = 0; cnt < MAX_CRC_WINDOW_NUM; cnt++) {
- if (acrtc->dm_irq_params.window_param[cnt].enable) {
- acrtc->dm_irq_params.window_param[cnt].update_win = true;
-
- /**
- * It takes 2 frames for HW to stably generate CRC when
- * resuming from suspend, so we set skip_frame_cnt 2.
- */
- acrtc->dm_irq_params.window_param[cnt].skip_frame_cnt = 2;
- }
- }
- spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
+ if (amdgpu_dm_crc_window_is_activated(crtc)) {
+ uint8_t cnt;
+
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
+ for (cnt = 0; cnt < MAX_CRC_WINDOW_NUM; cnt++) {
+ if (acrtc->dm_irq_params.window_param[cnt].enable) {
+ acrtc->dm_irq_params.window_param[cnt].update_win = true;
+
+ /**
+ * It takes 2 frames for HW to stably generate CRC when
+ * resuming from suspend, so we set skip_frame_cnt 2.
+ */
+ acrtc->dm_irq_params.window_param[cnt].skip_frame_cnt = 2;
}
-#endif
- if (amdgpu_dm_crtc_configure_crc_source(
- crtc, dm_new_crtc_state, cur_crc_src))
- drm_dbg_atomic(dev, "Failed to configure crc source");
}
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
#endif
+ if (amdgpu_dm_crtc_configure_crc_source(crtc, dm_new_crtc_state, cur_crc_src))
+ drm_dbg_atomic(dev, "Failed to configure crc source");
+#endif
}
amdgpu_dm_mod_power_setup_streams(state, dm);
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 1b91fe4c3171..e4fed8c855ab 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -65,9 +65,9 @@ enum amd_vsdb_panel_type {
*/
#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
/*
-#include "include/amdgpu_dal_power_if.h"
-#include "amdgpu_dm_irq.h"
-*/
+ * #include "include/amdgpu_dal_power_if.h"
+ * #include "amdgpu_dm_irq.h"
+ */
#include "irq_types.h"
#include "signal_types.h"
@@ -349,7 +349,7 @@ struct hpd_rx_irq_offload_work {
* @disable_hpd_irq: disables all HPD and HPD RX interrupt handling in the
* driver when true
* @dmub_aux_transfer_done: struct completion used to indicate when DMUB
- * transfers are done
+ * transfers are done
* @delayed_hpd_wq: work queue used to delay DMUB HPD work
*/
struct amdgpu_display_manager {
@@ -833,8 +833,10 @@ struct amdgpu_dm_connector {
struct cec_notifier *notifier;
- /* we need to mind the EDID between detect
- and get modes due to analog/digital/tvencoder */
+ /*
+ * we need to mind the EDID between detect
+ * and get modes due to analog/digital/tvencoder
+ */
const struct drm_edid *drm_edid;
/* shared with amdgpu */
@@ -843,8 +845,10 @@ struct amdgpu_dm_connector {
/* number of modes generated from EDID at 'dc_sink' */
int num_modes;
- /* The 'old' sink - before an HPD.
- * The 'current' sink is in dc_link->sink. */
+ /*
+ * The 'old' sink - before an HPD.
+ * The 'current' sink is in dc_link->sink.
+ */
struct dc_sink *dc_sink;
struct dc_link *dc_link;
@@ -880,7 +884,7 @@ struct amdgpu_dm_connector {
* @max_vfreq: Maximum frequency supported by the display in Hz. This
* value is set to zero when there is no FreeSync support.
*/
- int max_vfreq ;
+ int max_vfreq;
/* Audio instance - protected by audio_lock. */
int audio_inst;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index ebb05a20aa0c..f9dc9f46a446 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1525,7 +1525,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state,
degamma_lut, degamma_size);
if (ret)
return ret;
- } else {
+ } else {
/* Check if format requires post-scale color processing (subsampled formats) */
is_subsampled_format = (dc_plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN &&
dc_plane_state->format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index 47d90b67120e..c6bb9fec9217 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -278,6 +278,10 @@ amdgpu_dm_build_default_pipeline(struct drm_device *dev, struct drm_plane *plane
drm_colorop_set_next_property(ops[i-1], ops[i]);
list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id);
+ if (!list->name) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
return 0;
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 c78e26a145e3..8db7956c01d3 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
@@ -1289,10 +1289,10 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
dc_link_get_link_cap(aconnector->dc_link));
- if (aconnector->dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
- aconnector->dc_link->dpia_bw_alloc_config.bw_alloc_enabled) {
+ if (aconnector->dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
dsc_options.max_target_bpp_limit_override_x16 = 8 * 16;
- dsc_options.force_dsc_when_not_needed = true;
+ if (aconnector->dc_link->dpia_bw_alloc_config.bw_alloc_enabled)
+ dsc_options.force_dsc_when_not_needed = true;
}
/* Set DSC policy according to dsc_clock_en */
@@ -2357,7 +2357,7 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
* Since we check for it a few times below, cache the result.
*/
is_hdmi_ep = (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- signal == SIGNAL_TYPE_HDMI_FRL ||
+ signal == SIGNAL_TYPE_HDMI_FRL ||
aconnector->dc_link->dpcd_caps.dongle_type ==
DISPLAY_DONGLE_DP_HDMI_CONVERTER);
is_dp_or_hdmi = dc_is_hdmi_signal(signal) || dc_is_dp_signal(signal);
@@ -3790,10 +3790,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
parse_edid_displayid_vrr(connector, edid);
has_vsdb = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info) != 0;
+ amdgpu_dm_connector->vsdb_info = vsdb_info;
if (has_vsdb) {
- amdgpu_dm_connector->vsdb_info = vsdb_info;
-
/* copy refresh rate info as long as VSDB advertises FreeSync */
if (vsdb_info.freesync_supported) {
amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 5036ac1c4fd5..3e0128a29d77 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -777,13 +777,15 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
if (!cursor_plane)
goto fail;
- cursor_plane->type = DRM_PLANE_TYPE_CURSOR;
- res = amdgpu_dm_plane_init(dm, cursor_plane, 0, NULL);
-
acrtc = kzalloc_obj(struct amdgpu_crtc);
if (!acrtc)
goto fail;
+ cursor_plane->type = DRM_PLANE_TYPE_CURSOR;
+ res = amdgpu_dm_plane_init(dm, cursor_plane, 0, NULL);
+ if (res)
+ goto fail;
+
res = drm_crtc_init_with_planes(
dm->ddev,
&acrtc->base,
@@ -792,7 +794,7 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
&amdgpu_dm_crtc_funcs, NULL);
if (res)
- goto fail;
+ goto fail_crtc_init;
amdgpu_dm_ism_init(&acrtc->ism, &default_ism_config);
@@ -844,6 +846,8 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
error_ism_fini:
amdgpu_dm_ism_flush(&acrtc->ism);
drm_crtc_cleanup(&acrtc->base);
+fail_crtc_init:
+ drm_plane_cleanup(cursor_plane);
fail:
kfree(acrtc);
kfree(cursor_plane);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 6622a686e5e0..0cef66e20a86 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -2756,6 +2756,7 @@ static int ips_residency_show(struct seq_file *m, void *unused)
seq_printf(m, "ISP query failed\n");
} else {
unsigned int pct, frac;
+
pct = info.residency_millipercent / 1000;
frac = info.residency_millipercent % 1000;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
index f4b0ced7d391..b0325d686b28 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
@@ -319,6 +319,11 @@ int dm_dmub_hw_init(struct amdgpu_device *adev)
return -ENOMEM;
}
+ /* Cursor offload has to be enabled; prime it on every DMUB init,
+ * including post-suspend and GPU-reset.
+ */
+ dc_dmub_srv_cursor_offload_init(adev->dm.dc);
+
drm_info(adev_to_drm(adev), "DMUB hardware initialized: version=0x%08X\n",
adev->dm.dmcub_fw_version);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 9774ea33272d..f0fc6d080c20 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -531,7 +531,7 @@ void dm_helpers_dp_mst_update_mst_mgr_for_deallocation(
amdgpu_dm_set_mst_status(&aconnector->mst_status, set_flag, true);
amdgpu_dm_set_mst_status(&aconnector->mst_status, clr_flag, false);
- }
+}
EXPORT_IF_KUNIT(dm_helpers_dp_mst_update_mst_mgr_for_deallocation);
void dm_dtn_log_begin(struct dc_context *ctx,
@@ -1244,6 +1244,26 @@ void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *hd
}
EXPORT_IF_KUNIT(populate_hdmi_info_from_connector);
+static void dm_helpers_wait_for_edid_ready(struct dc_link *link,
+ struct i2c_adapter *ddc)
+{
+ const unsigned int retry_count = 50;
+ const unsigned int retry_interval_ms = 20;
+ unsigned int retry;
+
+ if (!ddc || link->dpcd_caps.dongle_type !=
+ DISPLAY_DONGLE_DP_DVI_DONGLE)
+ return;
+
+ for (retry = 0; retry < retry_count; retry++) {
+ if (drm_probe_ddc(ddc))
+ return;
+
+ if (retry + 1 < retry_count)
+ msleep(retry_interval_ms);
+ }
+}
+
enum dc_edid_status dm_helpers_read_local_edid(
struct dc_context *ctx,
struct dc_link *link,
@@ -1268,6 +1288,8 @@ enum dc_edid_status dm_helpers_read_local_edid(
if (link->dc->hwss.prepare_ddc)
link->dc->hwss.prepare_ddc(link);
+ dm_helpers_wait_for_edid_ready(link, ddc);
+
/* some dongles read edid incorrectly the first time,
* do check sum and retry to make sure read correct edid.
*/
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 6ba567df5f0a..b9d90b0c62df 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
@@ -71,8 +71,8 @@ void amdgpu_dm_irq_fini(struct amdgpu_device *adev);
* @handler_args: arguments which will be passed to ih
*
* Returns:
- * IRQ Handler Index on success.
- * NULL on failure.
+ * IRQ Handler Index on success.
+ * NULL on failure.
*
* Cannot be called from an interrupt handler.
*/
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index ee3f3df6bb8d..5697645ef7cc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1342,6 +1342,8 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
DRM_DEBUG_DRIVER("%s: MST_DSC Try to set up params from %d streams\n", __func__, dc_state->stream_count);
for (i = 0; i < dc_state->stream_count; i++) {
struct dc_dsc_policy dsc_policy = {0};
+ u32 min_target_bpp_x16;
+ u32 max_target_bpp_x16;
stream = dc_state->streams[i];
@@ -1380,7 +1382,15 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
dc_link->dpia_bw_alloc_config.bw_alloc_enabled)
params[count].clock_force_enable = DSC_CLK_FORCE_ENABLE;
+
dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
+ min_target_bpp_x16 = dsc_policy.min_target_bpp * 16;
+ max_target_bpp_x16 = dsc_policy.max_target_bpp * 16;
+ if (dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
+ max_target_bpp_x16 = min_t(u32, max_target_bpp_x16, 8 * 16);
+ if (dc_link->dpia_bw_alloc_config.bw_alloc_enabled)
+ max_target_bpp_x16 = min_target_bpp_x16;
+ }
is_frl_endpoint_present = get_conv_frl_bw(aconnector, &frl_conv_bw_in_kbps, &frl_conv_dsc_bw_in_kbps);
if (stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported &&
is_frl_endpoint_present &&
@@ -1390,11 +1400,8 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
if (!dc_dsc_compute_bandwidth_range(
stream->sink->ctx->dc->res_pool->dscs[0],
stream->sink->ctx->dc->debug.dsc_min_slice_height_override,
- dsc_policy.min_target_bpp * 16,
- (dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
- dc_link->dpia_bw_alloc_config.bw_alloc_enabled) ?
- dsc_policy.min_target_bpp * 16 :
- dsc_policy.max_target_bpp * 16,
+ min_target_bpp_x16,
+ max_target_bpp_x16,
&stream->sink->dsc_caps.dsc_dec_caps,
&stream->timing,
dc_link_get_highest_encoding_format(dc_link),
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 91398230d408..b224d9596fd2 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
@@ -2132,15 +2132,15 @@ dm_atomic_plane_get_property(struct drm_plane *plane,
} else if (property == adev->mode_info.plane_ctm_property) {
*val = (dm_plane_state->ctm) ?
dm_plane_state->ctm->base.id : 0;
- } else if (property == adev->mode_info.plane_shaper_lut_property) {
+ } else if (property == adev->mode_info.plane_shaper_lut_property) {
*val = (dm_plane_state->shaper_lut) ?
dm_plane_state->shaper_lut->base.id : 0;
} else if (property == adev->mode_info.plane_shaper_tf_property) {
*val = dm_plane_state->shaper_tf;
- } else if (property == adev->mode_info.plane_lut3d_property) {
+ } else if (property == adev->mode_info.plane_lut3d_property) {
*val = (dm_plane_state->lut3d) ?
dm_plane_state->lut3d->base.id : 0;
- } else if (property == adev->mode_info.plane_blend_lut_property) {
+ } else if (property == adev->mode_info.plane_blend_lut_property) {
*val = (dm_plane_state->blend_lut) ?
dm_plane_state->blend_lut->base.id : 0;
} else if (property == adev->mode_info.plane_blend_tf_property) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
index 3469a49d5f56..a432aad41b8f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: MIT
+/* SPDX-License-Identifier: MIT */
/*
* Copyright 2022 Advanced Micro Devices, Inc.
*
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
index 23f1db81a154..b376185875ef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
@@ -1,4 +1,4 @@
-//SPDX-License-Identifier: MIT
+// SPDX-License-Identifier: MIT
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
index 7f05f73e5b33..9027933cec3f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
@@ -1,4 +1,4 @@
-//SPDX-License-Identifier: MIT
+/* SPDX-License-Identifier: MIT */
/*
* Copyright 2018 Advanced Micro Devices, Inc.
*
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
index 172999cc84e5..35331d339780 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
@@ -120,11 +120,10 @@ void dc_fpu_end(const char *function_name, const int line)
int depth;
depth = this_cpu_dec_return(fpu_recursion_depth);
- if (depth == 0) {
+ if (depth == 0)
kernel_fpu_end();
- } else {
+ else
WARN_ON_ONCE(depth < 0);
- }
TRACE_DCN_FPU(false, function_name, line, depth);
preempt_enable();
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c
index 040a7a9c0335..281dac959dca 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c
@@ -77,7 +77,7 @@ static void dm_test_audio_init_disabled(struct kunit *test)
int saved_audio = amdgpu_dm_audio_get_param();
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
amdgpu_dm_audio_set_param(0);
@@ -107,11 +107,11 @@ static void dm_test_audio_init_enabled_success(struct kunit *test)
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
audio0 = kunit_kzalloc(test, sizeof(*audio0), GFP_KERNEL);
audio1 = kunit_kzalloc(test, sizeof(*audio1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio0);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio1);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, audio0);
+ KUNIT_ASSERT_NOT_NULL(test, audio1);
dev = root_device_register("kunit-dm-audio-init");
KUNIT_ASSERT_FALSE(test, IS_ERR(dev));
@@ -151,7 +151,7 @@ static void dm_test_audio_fini_without_enabled_audio(struct kunit *test)
int saved_audio = amdgpu_dm_audio_get_param();
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
amdgpu_dm_audio_set_param(1);
adev->mode_info.audio.enabled = false;
@@ -181,9 +181,9 @@ static void dm_test_fill_audio_info_ids_name_flags(struct kunit *test)
audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL);
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink);
+ KUNIT_ASSERT_NOT_NULL(test, audio_info);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, dc_sink);
dc_sink->edid_caps.manufacturer_id = 0x1234;
dc_sink->edid_caps.product_id = 0xABCD;
@@ -214,9 +214,9 @@ static void dm_test_fill_audio_info_cea_lt_3_skips_modes(struct kunit *test)
audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL);
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink);
+ KUNIT_ASSERT_NOT_NULL(test, audio_info);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, dc_sink);
connector->display_info.cea_rev = 2;
dc_sink->edid_caps.audio_mode_count = 2;
@@ -243,9 +243,9 @@ static void dm_test_fill_audio_info_cea_ge_3_copies_modes(struct kunit *test)
audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL);
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink);
+ KUNIT_ASSERT_NOT_NULL(test, audio_info);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, dc_sink);
connector->display_info.cea_rev = 3;
dc_sink->edid_caps.audio_mode_count = 2;
@@ -288,9 +288,9 @@ static void dm_test_fill_audio_info_latency_present(struct kunit *test)
audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL);
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink);
+ KUNIT_ASSERT_NOT_NULL(test, audio_info);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, dc_sink);
connector->display_info.cea_rev = 3;
connector->latency_present[0] = true;
@@ -316,9 +316,9 @@ static void dm_test_fill_audio_info_latency_absent_keeps_zero(struct kunit *test
audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL);
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink);
+ KUNIT_ASSERT_NOT_NULL(test, audio_info);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, dc_sink);
connector->display_info.cea_rev = 3;
connector->latency_present[0] = false;
@@ -347,9 +347,9 @@ static void dm_test_fill_audio_info_cea_ge_3_zero_modes(struct kunit *test)
audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL);
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink);
+ KUNIT_ASSERT_NOT_NULL(test, audio_info);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, dc_sink);
connector->display_info.cea_rev = 3;
dc_sink->edid_caps.audio_mode_count = 0;
@@ -379,9 +379,9 @@ static void dm_test_audio_component_bind_sets_fields(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
kdev = kunit_kzalloc(test, sizeof(*kdev), GFP_KERNEL);
acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, kdev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, kdev);
+ KUNIT_ASSERT_NOT_NULL(test, acomp);
dev_set_drvdata(kdev, &adev->ddev);
@@ -409,9 +409,9 @@ static void dm_test_audio_component_unbind_clears_fields(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
kdev = kunit_kzalloc(test, sizeof(*kdev), GFP_KERNEL);
acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, kdev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, kdev);
+ KUNIT_ASSERT_NOT_NULL(test, acomp);
dev_set_drvdata(kdev, &adev->ddev);
@@ -472,9 +472,9 @@ static void dm_test_eld_notify_invokes_callback(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL);
audio_ops = kunit_kzalloc(test, sizeof(*audio_ops), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_ops);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, acomp);
+ KUNIT_ASSERT_NOT_NULL(test, audio_ops);
audio_ops->audio_ptr = &marker;
audio_ops->pin_eld_notify = dm_test_pin_eld_notify;
@@ -504,7 +504,7 @@ static void dm_test_eld_notify_no_component(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->dm.audio_component = NULL;
@@ -528,8 +528,8 @@ static void dm_test_eld_notify_null_audio_ops(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, acomp);
acomp->audio_ops = NULL;
adev->dm.audio_component = acomp;
@@ -557,9 +557,9 @@ static void dm_test_eld_notify_null_callback(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL);
audio_ops = kunit_kzalloc(test, sizeof(*audio_ops), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_ops);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, acomp);
+ KUNIT_ASSERT_NOT_NULL(test, audio_ops);
audio_ops->pin_eld_notify = NULL;
acomp->audio_ops = audio_ops;
@@ -589,7 +589,7 @@ static void dm_test_audio_init_pins_sets_defaults(struct kunit *test)
int i;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
amdgpu_dm_audio_init_pins(adev, 2, inst_array);
@@ -619,7 +619,7 @@ static void dm_test_audio_init_pins_zero_count(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
/* Pre-fill a sentinel so we can confirm the loop never ran. */
adev->mode_info.audio.pin[0].channels = 99;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c
index 5221050dec2f..c6d15fb8ad98 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c
@@ -44,9 +44,9 @@ static void setup_test_connector(struct kunit *test,
fixture->adev = kunit_kzalloc(test, sizeof(*fixture->adev), GFP_KERNEL);
fixture->aconnector = kunit_kzalloc(test, sizeof(*fixture->aconnector), GFP_KERNEL);
fixture->link = kunit_kzalloc(test, sizeof(*fixture->link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->aconnector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->link);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->adev);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->link);
fixture->aconnector->bl_idx = bl_idx;
fixture->aconnector->dc_link = fixture->link;
@@ -111,7 +111,7 @@ static void dm_test_backlight_set_level_connector_off(struct kunit *test)
setup_test_dm_ddev(test, dm);
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
INIT_LIST_HEAD(&aconnector->base.head);
aconnector->bl_idx = 1;
aconnector->base.encoder = NULL;
@@ -169,7 +169,7 @@ static void dm_test_backlight_set_level_aux_programs_power_module(struct kunit *
/* Non-matching connector exercises the bl_idx skip (continue). */
other = kunit_kzalloc(test, sizeof(*other), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, other);
+ KUNIT_ASSERT_NOT_NULL(test, other);
INIT_LIST_HEAD(&other->base.head);
other->bl_idx = 0;
list_add_tail(&other->base.head, &dm->ddev->mode_config.connector_list);
@@ -245,16 +245,16 @@ static void dm_test_backlight_set_level_reallows_idle(struct kunit *test)
/* dm_kunit_alloc_dm() leaves dc->ctx NULL; the idle path dereferences it. */
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
dm->dc->ctx = ctx;
logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger);
+ KUNIT_ASSERT_NOT_NULL(test, logger);
logger->dev = &adev->ddev;
dm->dc->ctx->logger = logger;
dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dmub_srv);
dmub_srv->idle_allowed = true;
dm->dc->ctx->dmub_srv = dmub_srv;
dm->dc->caps.ips_support = true;
@@ -286,7 +286,7 @@ static void dm_test_backlight_update_status_no_stream(struct kunit *test)
setup_test_dm_ddev(test, dm);
bd = kunit_kzalloc(test, sizeof(*bd), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bd);
+ KUNIT_ASSERT_NOT_NULL(test, bd);
dev_set_drvdata(&bd->dev, dm);
bd->props.brightness = 3456;
dm->num_of_edps = 2;
@@ -305,9 +305,9 @@ static void setup_test_link_service(struct kunit *test, struct dc_link *link)
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
dc->ctx = ctx;
dc->link_srv = link_srv;
@@ -440,7 +440,7 @@ static void dm_test_backlight_get_brightness_uses_device_index(struct kunit *tes
setup_test_link_service(test, link);
link->dc->link_srv->edp_get_backlight_level = dm_test_get_backlight_level_error;
bd = kunit_kzalloc(test, sizeof(*bd), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bd);
+ KUNIT_ASSERT_NOT_NULL(test, bd);
dev_set_drvdata(&bd->dev, dm);
dm->num_of_edps = 2;
dm->backlight_dev[1] = bd;
@@ -487,7 +487,7 @@ static void dm_test_register_backlight_device_success(struct kunit *test)
setup_test_link_service(test, link);
link->dc->link_srv->edp_get_backlight_level = dm_test_get_backlight_level_error;
primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+ KUNIT_ASSERT_NOT_NULL(test, primary);
adev->ddev.primary = primary;
adev->dm.backlight_link[0] = link;
@@ -531,9 +531,9 @@ static struct drm_connector *setup_panel_power_savings_connector(struct kunit *t
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL);
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, device);
+ KUNIT_ASSERT_NOT_NULL(test, state);
connector->dev = &adev->ddev;
connector->state = &state->base;
@@ -646,9 +646,9 @@ static void dm_test_panel_power_savings_store_rejects_invalid_text(struct kunit
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
drm = kunit_kzalloc(test, sizeof(*drm), GFP_KERNEL);
device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, drm);
+ KUNIT_ASSERT_NOT_NULL(test, device);
connector->dev = drm;
dev_set_drvdata(device, connector);
@@ -669,9 +669,9 @@ static void dm_test_panel_power_savings_store_rejects_out_of_range(struct kunit
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
drm = kunit_kzalloc(test, sizeof(*drm), GFP_KERNEL);
device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, drm);
+ KUNIT_ASSERT_NOT_NULL(test, device);
connector->dev = drm;
dev_set_drvdata(device, connector);
@@ -1518,7 +1518,7 @@ static void dm_test_update_connector_ext_caps_negative_bl_idx(struct kunit *test
struct amdgpu_dm_connector *aconnector;
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
aconnector->bl_idx = -1;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
index 8c2f7ab5f8d3..c07661ef56c1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
@@ -71,7 +71,7 @@ static void dm_test_is_lut_linear_with_linear_lut(struct kunit *test)
int i;
lut = kunit_kcalloc(test, size, sizeof(*lut), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, lut);
+ KUNIT_ASSERT_NOT_NULL(test, lut);
for (i = 0; i < size; i++) {
uint16_t val = (uint16_t)(i * MAX_DRM_LUT_VALUE / (size - 1));
@@ -91,7 +91,7 @@ static void dm_test_is_lut_linear_with_nonlinear_lut(struct kunit *test)
int i;
lut = kunit_kcalloc(test, size, sizeof(*lut), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, lut);
+ KUNIT_ASSERT_NOT_NULL(test, lut);
/* Fill with all-max values: clearly non-linear */
for (i = 0; i < size; i++) {
@@ -110,7 +110,7 @@ static void dm_test_is_lut_linear_rgb_mismatch(struct kunit *test)
int i;
lut = kunit_kcalloc(test, size, sizeof(*lut), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, lut);
+ KUNIT_ASSERT_NOT_NULL(test, lut);
for (i = 0; i < size; i++) {
uint16_t val = (uint16_t)(i * MAX_DRM_LUT_VALUE / (size - 1));
@@ -1871,7 +1871,7 @@ dm_test_colorop_setup(struct kunit *test, enum drm_colorop_type type)
KUNIT_ASSERT_NOT_NULL(test, f.colorop_state);
f.colorop_state->colorop = f.colorop;
- colorops = kunit_kcalloc(test, 1, sizeof(*colorops), GFP_KERNEL);
+ colorops = kunit_kzalloc(test, sizeof(*colorops), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorops);
colorops[0].ptr = f.colorop;
colorops[0].new_state = f.colorop_state;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c
index 90cc5592ef5d..27cd4b8500e8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c
@@ -232,7 +232,7 @@ static void dm_test_initialize_default_pipeline_caps(struct kunit *test,
drm = &adev->ddev;
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
adev->dm.dc->caps.color.dpp.hw_3d_lut = dpp_hw_3d_lut;
adev->dm.dc->caps.color.mpc.preblend = mpc_preblend;
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 5fdf8ce023b9..b6aecb540654 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
@@ -46,7 +46,7 @@ static void dm_test_subconnector_type_none(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Native);
@@ -60,7 +60,7 @@ static void dm_test_subconnector_type_vga(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_VGA);
@@ -74,7 +74,7 @@ static void dm_test_subconnector_type_dvi_converter(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_DVID);
@@ -88,7 +88,7 @@ static void dm_test_subconnector_type_dvi_dongle(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_DONGLE;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_DVID);
@@ -102,7 +102,7 @@ static void dm_test_subconnector_type_hdmi_converter(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_HDMIA);
@@ -116,7 +116,7 @@ static void dm_test_subconnector_type_hdmi_dongle(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_DONGLE;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_HDMIA);
@@ -130,7 +130,7 @@ static void dm_test_subconnector_type_mismatched(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Unknown);
@@ -144,7 +144,7 @@ static void dm_test_subconnector_type_default_unknown(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.dongle_type = (typeof(link->dpcd_caps.dongle_type))0x7f;
KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Unknown);
@@ -842,7 +842,7 @@ static void dm_test_color_depth_from_info_bpc8(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.bpc = 8;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0),
@@ -858,7 +858,7 @@ static void dm_test_color_depth_from_info_bpc10(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.bpc = 10;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0),
@@ -875,7 +875,7 @@ static void dm_test_color_depth_from_info_zero_bpc_defaults_888(struct kunit *te
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.bpc = 0;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0),
@@ -891,7 +891,7 @@ static void dm_test_color_depth_from_info_requested_bpc_caps(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
/* Display supports 12bpc but user requests max 10 */
connector->display_info.bpc = 12;
@@ -908,7 +908,7 @@ static void dm_test_color_depth_from_info_y420_default(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
/* No Y420 DC modes set → 8bpc */
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0),
@@ -924,7 +924,7 @@ static void dm_test_color_depth_from_info_y420_10bpc(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_30;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0),
@@ -940,7 +940,7 @@ static void dm_test_color_depth_from_info_y420_12bpc(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_36;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0),
@@ -956,7 +956,7 @@ static void dm_test_color_depth_from_info_y420_16bpc(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_48;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0),
@@ -972,7 +972,7 @@ static void dm_test_color_depth_from_info_requested_odd_bpc(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.bpc = 12;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 11),
@@ -988,7 +988,7 @@ static void dm_test_color_depth_from_info_unsupported_bpc(struct kunit *test)
struct drm_connector *connector;
connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
connector->display_info.bpc = 9;
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0),
@@ -1133,7 +1133,7 @@ static void dm_test_is_duplicate_mode_empty_list(struct kunit *test)
struct drm_display_mode mode = {};
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
INIT_LIST_HEAD(&aconnector->base.probed_modes);
mode.hdisplay = 1920;
@@ -1153,7 +1153,7 @@ static void dm_test_is_duplicate_mode_match(struct kunit *test)
struct drm_display_mode candidate = {};
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
INIT_LIST_HEAD(&aconnector->base.probed_modes);
existing.hdisplay = 1920;
@@ -1179,7 +1179,7 @@ static void dm_test_is_duplicate_mode_no_match(struct kunit *test)
struct drm_display_mode candidate = {};
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
INIT_LIST_HEAD(&aconnector->base.probed_modes);
existing.hdisplay = 1920;
@@ -1206,7 +1206,7 @@ static void dm_test_is_duplicate_mode_same_size_different_clock(struct kunit *te
struct drm_display_mode candidate = {};
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
INIT_LIST_HEAD(&aconnector->base.probed_modes);
existing.hdisplay = 1920;
@@ -1232,7 +1232,7 @@ static void dm_test_encoder_crtc_mask_1(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->mode_info.num_crtc = 1;
KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x1);
@@ -1247,7 +1247,7 @@ static void dm_test_encoder_crtc_mask_2(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->mode_info.num_crtc = 2;
KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x3);
@@ -1262,7 +1262,7 @@ static void dm_test_encoder_crtc_mask_3(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->mode_info.num_crtc = 3;
KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x7);
@@ -1277,7 +1277,7 @@ static void dm_test_encoder_crtc_mask_4(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->mode_info.num_crtc = 4;
KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0xf);
@@ -1292,7 +1292,7 @@ static void dm_test_encoder_crtc_mask_5(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->mode_info.num_crtc = 5;
KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x1f);
@@ -1307,7 +1307,7 @@ static void dm_test_encoder_crtc_mask_6(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->mode_info.num_crtc = 6;
KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x3f);
@@ -1322,7 +1322,7 @@ static void dm_test_encoder_crtc_mask_default(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
/* Values > 6 use the default case */
adev->mode_info.num_crtc = 8;
@@ -1799,7 +1799,7 @@ static void dm_test_atomic_dup_state_copies_fields(struct kunit *test)
KUNIT_EXPECT_EQ(test, new_dm_state->vcpi_slots, 4);
KUNIT_EXPECT_EQ(test, (int)new_dm_state->pbn, 1234);
- kfree(new_dm_state);
+ connector->funcs->atomic_destroy_state(connector, new_state);
}
/* Tests for amdgpu_dm_fill_hdr_info_packet() */
@@ -2527,9 +2527,9 @@ static void setup_cacp_fixture(struct kunit *test,
fixture->aconnector = kunit_kzalloc(test, sizeof(*fixture->aconnector),
GFP_KERNEL);
fixture->link = kunit_kzalloc(test, sizeof(*fixture->link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->aconnector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->link);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->adev);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->link);
fixture->aconnector->dc_link = fixture->link;
fixture->aconnector->base.dev = &fixture->adev->ddev;
@@ -2675,11 +2675,11 @@ static void setup_panel_type_fixture(struct kunit *test,
fixture->aconnector = drmm_kzalloc(fixture->drm, sizeof(*fixture->aconnector),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->aconnector);
fixture->link = kunit_kzalloc(test, sizeof(*fixture->link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->link);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->link);
fixture->sink = kunit_kzalloc(test, sizeof(*fixture->sink), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->sink);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->sink);
fixture->aconnector->dc_link = fixture->link;
drmm_connector_init(fixture->drm, &fixture->aconnector->base,
@@ -7398,8 +7398,7 @@ static void dm_test_conn_ac_bind_crtc(struct kunit *test,
ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
- ctx->state->crtcs = kunit_kcalloc(test, 1, sizeof(*ctx->state->crtcs),
- GFP_KERNEL);
+ ctx->state->crtcs = kunit_kzalloc(test, sizeof(*ctx->state->crtcs), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ctx->state->crtcs);
ctx->state->crtcs[0].ptr = ctx->crtc;
ctx->state->crtcs[0].new_state = ctx->crtc_state;
@@ -7710,6 +7709,8 @@ static void dm_test_update_after_detect_connect_edid(struct kunit *test)
KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_sink, sink);
KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->timing_requested);
+ drm_edid_free(ctx->aconnector->drm_edid);
+ ctx->aconnector->drm_edid = NULL;
kfree(ctx->aconnector->timing_requested);
ctx->aconnector->timing_requested = NULL;
}
@@ -7744,6 +7745,9 @@ static void dm_test_update_after_detect_replace_no_edid(struct kunit *test)
KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_sink, new_sink);
KUNIT_EXPECT_EQ(test, (int)new_sink->sink_signal,
(int)SIGNAL_TYPE_HDMI_FRL);
+
+ kfree(ctx->aconnector->timing_requested);
+ ctx->aconnector->timing_requested = NULL;
}
/**
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 489dd56474b9..c130d809098c 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
@@ -114,7 +114,7 @@ static void dm_test_crtc_vrr_active_irq_variable(struct kunit *test)
struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
@@ -130,7 +130,7 @@ static void dm_test_crtc_vrr_active_irq_fixed(struct kunit *test)
struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_FIXED;
@@ -146,7 +146,7 @@ static void dm_test_crtc_vrr_active_irq_inactive(struct kunit *test)
struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->dm_irq_params.freesync_config.state = VRR_STATE_INACTIVE;
@@ -162,7 +162,7 @@ static void dm_test_crtc_vrr_active_irq_disabled(struct kunit *test)
struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->dm_irq_params.freesync_config.state = VRR_STATE_DISABLED;
@@ -178,7 +178,7 @@ static void dm_test_crtc_vrr_active_irq_unsupported(struct kunit *test)
struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->dm_irq_params.freesync_config.state = VRR_STATE_UNSUPPORTED;
@@ -197,7 +197,7 @@ static void dm_test_crtc_vrr_active_variable(struct kunit *test)
sizeof(*dm_state),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
@@ -214,7 +214,7 @@ static void dm_test_crtc_vrr_active_fixed(struct kunit *test)
sizeof(*dm_state),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
@@ -231,7 +231,7 @@ static void dm_test_crtc_vrr_active_inactive(struct kunit *test)
sizeof(*dm_state),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->freesync_config.state = VRR_STATE_INACTIVE;
@@ -248,7 +248,7 @@ static void dm_test_crtc_vrr_active_disabled(struct kunit *test)
sizeof(*dm_state),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->freesync_config.state = VRR_STATE_DISABLED;
@@ -265,7 +265,7 @@ static void dm_test_crtc_vrr_active_unsupported(struct kunit *test)
sizeof(*dm_state),
GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->freesync_config.state = VRR_STATE_UNSUPPORTED;
@@ -304,7 +304,7 @@ static void dm_test_crtc_is_headless_no_connectors(struct kunit *test)
struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->dm.ddev = dev;
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_headless(adev));
@@ -320,8 +320,8 @@ static void dm_test_crtc_is_headless_writeback_only(struct kunit *test)
struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test);
struct drm_connector *wb = kunit_kzalloc(test, sizeof(*wb), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, wb);
adev->dm.ddev = dev;
dm_test_add_connector(dev, wb, DRM_MODE_CONNECTOR_WRITEBACK,
@@ -340,8 +340,8 @@ static void dm_test_crtc_is_headless_disconnected_display(struct kunit *test)
struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test);
struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, display);
adev->dm.ddev = dev;
dm_test_add_connector(dev, display, DRM_MODE_CONNECTOR_HDMIA,
@@ -360,8 +360,8 @@ static void dm_test_crtc_is_headless_connected_display(struct kunit *test)
struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test);
struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, display);
adev->dm.ddev = dev;
dm_test_add_connector(dev, display, DRM_MODE_CONNECTOR_HDMIA,
@@ -381,9 +381,9 @@ static void dm_test_crtc_is_headless_mixed_connectors(struct kunit *test)
struct drm_connector *wb = kunit_kzalloc(test, sizeof(*wb), GFP_KERNEL);
struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, wb);
+ KUNIT_ASSERT_NOT_NULL(test, display);
adev->dm.ddev = dev;
dm_test_add_connector(dev, wb, DRM_MODE_CONNECTOR_WRITEBACK,
@@ -426,7 +426,7 @@ static void dm_test_crtc_set_vupdate_irq_no_otg(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->otg_inst = -1;
@@ -451,7 +451,7 @@ static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->otg_inst = 0;
@@ -514,20 +514,19 @@ static void dm_test_crtc_set_vupdate_irq_enable(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
dc = dm_kunit_alloc_dc_with_ctx(test);
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
+ KUNIT_ASSERT_NOT_NULL(test, irqs);
/*
* Populate the per-source info table so amdgpu_dm_irq_set() succeeds.
*/
- info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
- GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+ info = kunit_kcalloc(test, DAL_IRQ_SOURCES_NUMBER, sizeof(*info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, info);
for (i = 0; i < DAL_IRQ_SOURCES_NUMBER; i++)
info[i].funcs = &dm_test_vupdate_irq_src_funcs;
@@ -560,7 +559,7 @@ static void dm_test_idle_create_workqueue(struct kunit *test)
struct idle_workqueue *idle_work;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
idle_work = idle_create_workqueue(adev);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work);
@@ -588,7 +587,7 @@ static void dm_test_idle_worker_disabled_clears_running(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work);
+ KUNIT_ASSERT_NOT_NULL(test, idle_work);
idle_work->dm = &adev->dm;
idle_work->enable = false;
@@ -623,7 +622,7 @@ static void dm_test_idle_worker_enabled_breaks_when_idle_disallowed(struct kunit
adev->dm.dc->idle_optimizations_allowed = false;
idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work);
+ KUNIT_ASSERT_NOT_NULL(test, idle_work);
idle_work->dm = &adev->dm;
idle_work->enable = true;
@@ -668,12 +667,12 @@ static void dm_test_idle_worker_enabled_breaks_when_not_headless(struct kunit *t
/* A connected display makes amdgpu_dm_is_headless() false. */
display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display);
+ KUNIT_ASSERT_NOT_NULL(test, display);
dm_test_add_connector(adev->dm.ddev, display, DRM_MODE_CONNECTOR_HDMIA,
connector_status_connected);
idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work);
+ KUNIT_ASSERT_NOT_NULL(test, idle_work);
idle_work->dm = &adev->dm;
idle_work->enable = true;
adev->dm.idle_workqueue = idle_work;
@@ -727,7 +726,7 @@ static void dm_test_idle_worker_enabled_runs_body(struct kunit *test)
adev->dm.dc->caps.is_apu = true;
/* dc_allow() logs via DC_LOG_DEBUG() when it flips the flag. */
logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger);
+ KUNIT_ASSERT_NOT_NULL(test, logger);
logger->dev = &adev->ddev;
adev->dm.dc->ctx->logger = logger;
/* dc_allow() only flips the flag when clk_mgr and apply() are present. */
@@ -736,7 +735,7 @@ static void dm_test_idle_worker_enabled_runs_body(struct kunit *test)
adev->dm.dc->hwss.apply_idle_power_optimizations = dm_test_idle_apply_flip;
idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work);
+ KUNIT_ASSERT_NOT_NULL(test, idle_work);
idle_work->dm = &adev->dm;
idle_work->enable = true;
adev->dm.idle_workqueue = idle_work;
@@ -764,7 +763,7 @@ static void dm_test_crtc_set_static_screen_optimze_no_sr_entry(struct kunit *tes
struct dc_stream_state *stream;
dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
+ KUNIT_ASSERT_NOT_NULL(test, dm);
link = dm_kunit_alloc_link(test);
stream = dm_kunit_alloc_stream(test, link);
@@ -790,7 +789,7 @@ static void dm_test_crtc_set_static_screen_optimze_sr_entry_psr(struct kunit *te
struct dc_stream_state *stream;
dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
+ KUNIT_ASSERT_NOT_NULL(test, dm);
link = dm_kunit_alloc_link(test);
stream = dm_kunit_alloc_stream(test, link);
@@ -816,7 +815,7 @@ static void dm_test_crtc_set_static_screen_optimze_psr_su_skips(struct kunit *te
struct dc_stream_state *stream;
dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
+ KUNIT_ASSERT_NOT_NULL(test, dm);
link = dm_kunit_alloc_link(test);
stream = dm_kunit_alloc_stream(test, link);
@@ -842,7 +841,7 @@ static void dm_test_crtc_enable_vblank_rejects_unconfigured(struct kunit *test)
struct amdgpu_crtc *acrtc;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->base.enabled = false;
@@ -926,7 +925,7 @@ static void dm_test_crtc_arm_irq_src(struct kunit *test,
atomic_t *enabled;
enabled = kunit_kzalloc(test, sizeof(*enabled), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, enabled);
+ KUNIT_ASSERT_NOT_NULL(test, enabled);
atomic_set(enabled, count);
src->num_types = 1;
@@ -970,11 +969,11 @@ dm_test_crtc_setup_enable(struct kunit *test, struct amdgpu_device **adev_out,
adev->mode_info.num_crtc = 1;
reset_domain = kunit_kzalloc(test, sizeof(*reset_domain), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, reset_domain);
+ KUNIT_ASSERT_NOT_NULL(test, reset_domain);
adev->reset_domain = reset_domain;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->base.funcs = &dm_test_crtc_funcs;
acrtc->base.enabled = true;
@@ -988,7 +987,7 @@ dm_test_crtc_setup_enable(struct kunit *test, struct amdgpu_device **adev_out,
stream = dm_kunit_alloc_stream(test, link);
dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->stream = stream;
acrtc->base.state = &dm_state->base;
@@ -1053,16 +1052,15 @@ static void dm_test_crtc_enable_vblank_vupdate_busy(struct kunit *test)
acrtc_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
+ KUNIT_ASSERT_NOT_NULL(test, irqs);
/*
* Per-source .set fails so amdgpu_dm_irq_set() reports the source busy.
*/
- info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
- GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+ info = kunit_kcalloc(test, DAL_IRQ_SOURCES_NUMBER, sizeof(*info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, info);
for (i = 0; i < DAL_IRQ_SOURCES_NUMBER; i++)
info[i].funcs = &dm_test_vupdate_irq_src_busy_funcs;
@@ -1286,7 +1284,7 @@ static struct drm_crtc *dm_test_crtc_setup_vline0(struct kunit *test,
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
adev->ip_versions[DCE_HWIP][0] = ip_version;
@@ -1375,7 +1373,7 @@ static void dm_test_crtc_update_active_planes_no_stream(struct kunit *test)
struct dm_crtc_state *dm_state;
dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->stream = NULL;
dm_state->active_planes = 5;
@@ -1413,11 +1411,11 @@ static void dm_test_count_crtc_active_planes_none(struct kunit *test)
INIT_LIST_HEAD(&dev->mode_config.plane_list);
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = dev;
crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, crtc_state);
crtc_state->state = state;
crtc_state->plane_mask = 0;
@@ -1452,15 +1450,15 @@ static void dm_test_count_crtc_active_planes_mixed(struct kunit *test)
INIT_LIST_HEAD(&dev->mode_config.plane_list);
plane_no_state = kunit_kzalloc(test, sizeof(*plane_no_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_no_state);
+ KUNIT_ASSERT_NOT_NULL(test, plane_no_state);
plane_cursor = kunit_kzalloc(test, sizeof(*plane_cursor), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cursor);
+ KUNIT_ASSERT_NOT_NULL(test, plane_cursor);
plane_with_fb = kunit_kzalloc(test, sizeof(*plane_with_fb), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_with_fb);
+ KUNIT_ASSERT_NOT_NULL(test, plane_with_fb);
plane_no_fb = kunit_kzalloc(test, sizeof(*plane_no_fb), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_no_fb);
+ KUNIT_ASSERT_NOT_NULL(test, plane_no_fb);
plane_excluded = kunit_kzalloc(test, sizeof(*plane_excluded), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_excluded);
+ KUNIT_ASSERT_NOT_NULL(test, plane_excluded);
dm_test_add_plane(dev, plane_no_state, 0, DRM_PLANE_TYPE_PRIMARY);
dm_test_add_plane(dev, plane_cursor, 1, DRM_PLANE_TYPE_CURSOR);
@@ -1469,19 +1467,19 @@ static void dm_test_count_crtc_active_planes_mixed(struct kunit *test)
dm_test_add_plane(dev, plane_excluded, 4, DRM_PLANE_TYPE_PRIMARY);
fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb);
+ KUNIT_ASSERT_NOT_NULL(test, fb);
ps_fb = kunit_kzalloc(test, sizeof(*ps_fb), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ps_fb);
+ KUNIT_ASSERT_NOT_NULL(test, ps_fb);
ps_fb->fb = fb;
ps_no_fb = kunit_kzalloc(test, sizeof(*ps_no_fb), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ps_no_fb);
+ KUNIT_ASSERT_NOT_NULL(test, ps_no_fb);
ps_no_fb->fb = NULL;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = dev;
- state->planes = kunit_kzalloc(test, sizeof(*state->planes) * 5, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->planes);
+ state->planes = kunit_kcalloc(test, 5, sizeof(*state->planes), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, state->planes);
state->planes[0].new_state = NULL;
state->planes[1].new_state = ps_fb;
state->planes[2].new_state = ps_fb;
@@ -1489,7 +1487,7 @@ static void dm_test_count_crtc_active_planes_mixed(struct kunit *test)
state->planes[4].new_state = ps_fb;
crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, crtc_state);
crtc_state->state = state;
/* Exclude plane index 4 from the CRTC. */
crtc_state->plane_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3);
@@ -1514,9 +1512,9 @@ static void dm_test_crtc_duplicate_state_copies_fields(struct kunit *test)
struct dm_crtc_state *dm_dup;
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
cur = kunit_kzalloc(test, sizeof(*cur), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cur);
+ KUNIT_ASSERT_NOT_NULL(test, cur);
cur->abm_level = 3;
cur->active_planes = 2;
@@ -1560,9 +1558,9 @@ static void dm_test_crtc_duplicate_state_retains_stream(struct kunit *test)
struct dc_link *link;
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
cur = kunit_kzalloc(test, sizeof(*cur), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cur);
+ KUNIT_ASSERT_NOT_NULL(test, cur);
link = dm_kunit_alloc_link(test);
stream = dm_kunit_alloc_stream(test, link);
@@ -1595,7 +1593,7 @@ static void dm_test_crtc_duplicate_state_null_state_returns_null(struct kunit *t
struct drm_crtc *crtc;
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->state = NULL;
KUNIT_EXPECT_NULL(test, amdgpu_dm_crtc_duplicate_state(crtc));
@@ -1629,7 +1627,7 @@ static void dm_test_crtc_destroy_cleans_up_and_frees(struct kunit *test)
/* amdgpu_dm_crtc_destroy() kfree()s the CRTC, so use a plain alloc. */
acrtc = kzalloc_obj(*acrtc, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
ret = drm_crtc_init_with_planes(&adev->ddev, &acrtc->base, plane,
NULL, &dm_test_crtc_funcs, NULL);
@@ -1657,7 +1655,7 @@ static void dm_test_crtc_create_state_allocates_state(struct kunit *test)
struct drm_crtc *crtc;
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
crtc->state = NULL;
@@ -1686,7 +1684,7 @@ static void dm_test_crtc_reset_state_replaces_existing(struct kunit *test)
struct dc_link *link;
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
link = dm_kunit_alloc_link(test);
@@ -1696,7 +1694,7 @@ static void dm_test_crtc_reset_state_replaces_existing(struct kunit *test)
/* reset_state kfree()s the old state, so use a plain (unmanaged) alloc. */
old = kzalloc_obj(*old, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old);
+ KUNIT_ASSERT_NOT_NULL(test, old);
old->stream = stream;
crtc->state = &old->base;
@@ -1725,7 +1723,7 @@ static void dm_test_crtc_destroy_state_no_stream(struct kunit *test)
/* destroy_state kfree()s the state, so use a plain (unmanaged) alloc. */
dm_state = kzalloc_obj(*dm_state);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
amdgpu_dm_crtc_destroy_state(NULL, &dm_state->base);
}
@@ -1755,7 +1753,7 @@ static void dm_test_crtc_destroy_state_releases_stream(struct kunit *test)
/* destroy_state kfree()s the state, so use a plain (unmanaged) alloc. */
dm_state = kzalloc_obj(*dm_state);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
dm_state->stream = stream;
amdgpu_dm_crtc_destroy_state(NULL, &dm_state->base);
@@ -1783,7 +1781,7 @@ static void dm_test_crtc_handle_vblank_no_event(struct kunit *test)
KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->event = NULL;
@@ -1811,9 +1809,9 @@ static void dm_test_crtc_handle_vblank_skips_when_flip_submitted(struct kunit *t
KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
event = kunit_kzalloc(test, sizeof(*event), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event);
+ KUNIT_ASSERT_NOT_NULL(test, event);
acrtc->base.dev = &adev->ddev;
acrtc->base.funcs = &dm_test_crtc_funcs;
@@ -1850,11 +1848,11 @@ static void dm_test_crtc_handle_vblank_completes_cursor_only(struct kunit *test)
KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
/* drm_crtc_send_vblank_event() consumes (kfree()s) the event. */
event = kzalloc_obj(*event);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event);
+ KUNIT_ASSERT_NOT_NULL(test, event);
acrtc->base.dev = &adev->ddev;
acrtc->base.funcs = &dm_test_crtc_funcs;
@@ -1907,7 +1905,7 @@ dm_test_vblank_control_worker_setup(struct kunit *test, bool enable,
adev->dm.active_vblank_irq_count = count;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->base.state = NULL;
@@ -1918,7 +1916,7 @@ dm_test_vblank_control_worker_setup(struct kunit *test, bool enable,
/* Worker kfree()s the work item, so it must be a plain allocation. */
work = kzalloc_obj(*work);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work);
+ KUNIT_ASSERT_NOT_NULL(test, work);
work->dm = &adev->dm;
work->acrtc = acrtc;
work->stream = stream;
@@ -2012,7 +2010,7 @@ static void dm_test_crtc_disable_vblank_no_irq_installed(struct kunit *test)
adev->irq.installed = false;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->crtc_id = 0;
@@ -2047,7 +2045,7 @@ static void dm_test_crtc_disable_vblank_vrr(struct kunit *test)
adev->irq.installed = true;
reset_domain = kunit_kzalloc(test, sizeof(*reset_domain), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, reset_domain);
+ KUNIT_ASSERT_NOT_NULL(test, reset_domain);
adev->reset_domain = reset_domain;
/* Seed with 2 so amdgpu_irq_put() drops to a non-zero refcount. */
@@ -2055,7 +2053,7 @@ static void dm_test_crtc_disable_vblank_vrr(struct kunit *test)
dm_test_crtc_arm_irq_src(test, &adev->pageflip_irq, 2);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->crtc_id = 0;
/* OTG unassigned -> amdgpu_dm_crtc_set_vupdate_irq() returns 0 early. */
@@ -2098,7 +2096,7 @@ static void dm_test_crtc_disable_vblank_queues_work(struct kunit *test)
adev->irq.installed = true;
reset_domain = kunit_kzalloc(test, sizeof(*reset_domain), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, reset_domain);
+ KUNIT_ASSERT_NOT_NULL(test, reset_domain);
adev->reset_domain = reset_domain;
/* Seed with 2 so amdgpu_irq_put() drops to a non-zero refcount. */
@@ -2106,7 +2104,7 @@ static void dm_test_crtc_disable_vblank_queues_work(struct kunit *test)
dm_test_crtc_arm_irq_src(test, &adev->pageflip_irq, 2);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
acrtc->base.dev = &adev->ddev;
acrtc->crtc_id = 0;
acrtc->otg_inst = -1;
@@ -2118,7 +2116,7 @@ static void dm_test_crtc_disable_vblank_queues_work(struct kunit *test)
/* CRTC state with no stream -> the stream-retain branch is skipped. */
dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
acrtc->base.state = &dm_state->base;
/* Real workqueue so the queue_work() branch runs the control worker. */
@@ -2152,7 +2150,7 @@ static void dm_test_crtc_late_register_inits_debugfs(struct kunit *test)
int ret;
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->debugfs_entry = debugfs_create_dir("dm_test_crtc", NULL);
@@ -2304,18 +2302,18 @@ static void dm_test_crtc_atomic_check_no_stream_passes(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
dm_crtc_state->base.crtc = crtc;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = &adev->ddev;
state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
state->crtcs[0].new_state = &dm_crtc_state->base;
dm_crtc_state->base.state = state;
@@ -2364,24 +2362,24 @@ static void dm_test_crtc_atomic_check_enable_without_primary_fails(struct kunit
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+ KUNIT_ASSERT_NOT_NULL(test, primary);
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
crtc->primary = primary;
dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
dm_crtc_state->base.crtc = crtc;
dm_crtc_state->base.enable = true;
dm_crtc_state->base.plane_mask = 0;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = &adev->ddev;
state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
state->crtcs[0].new_state = &dm_crtc_state->base;
dm_crtc_state->base.state = state;
@@ -2409,20 +2407,20 @@ static void dm_test_crtc_atomic_check_async_flip_non_fast_fails(struct kunit *te
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
dm_crtc_state->base.crtc = crtc;
dm_crtc_state->base.async_flip = true;
dm_crtc_state->update_type = UPDATE_TYPE_FULL;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = &adev->ddev;
state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
state->crtcs[0].new_state = &dm_crtc_state->base;
dm_crtc_state->base.state = state;
@@ -2453,33 +2451,33 @@ static void dm_test_crtc_atomic_check_vrr_pulls_primary(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+ KUNIT_ASSERT_NOT_NULL(test, primary);
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
crtc->primary = primary;
dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
dm_crtc_state->base.crtc = crtc;
dm_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = &adev->ddev;
state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
state->crtcs[0].new_state = &dm_crtc_state->base;
dm_crtc_state->base.state = state;
/* acquire ctx must be set; existing plane state avoids taking a lock. */
state->acquire_ctx = kunit_kzalloc(test, sizeof(*state->acquire_ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->acquire_ctx);
+ KUNIT_ASSERT_NOT_NULL(test, state->acquire_ctx);
state->planes = kunit_kzalloc(test, sizeof(*state->planes), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->planes);
+ KUNIT_ASSERT_NOT_NULL(test, state->planes);
primary_plane_state = kunit_kzalloc(test, sizeof(*primary_plane_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary_plane_state);
+ KUNIT_ASSERT_NOT_NULL(test, primary_plane_state);
state->planes[0].new_state = primary_plane_state;
ret = amdgpu_dm_crtc_helper_atomic_check(crtc, state);
@@ -2514,18 +2512,18 @@ static void dm_test_crtc_atomic_check_valid_stream_passes(struct kunit *test)
dc = dm_kunit_alloc_dc_with_ctx(test);
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
tg = kunit_kzalloc(test, sizeof(*tg), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg);
+ KUNIT_ASSERT_NOT_NULL(test, tg);
tg_funcs = kunit_kzalloc(test, sizeof(*tg_funcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg_funcs);
+ KUNIT_ASSERT_NOT_NULL(test, tg_funcs);
tg_funcs->validate_timing = dm_test_atomic_check_validate_timing_ok;
tg->funcs = tg_funcs;
res_pool->timing_generators[0] = tg;
dc->res_pool = res_pool;
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link_srv->validate_mode_timing = dm_test_atomic_check_validate_mode_timing_ok;
dc->link_srv = link_srv;
adev->dm.dc = dc;
@@ -2535,19 +2533,19 @@ static void dm_test_crtc_atomic_check_valid_stream_passes(struct kunit *test)
stream = dm_kunit_alloc_stream(test, link);
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
dm_crtc_state->base.crtc = crtc;
dm_crtc_state->stream = stream;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = &adev->ddev;
state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
state->crtcs[0].new_state = &dm_crtc_state->base;
dm_crtc_state->base.state = state;
@@ -2582,11 +2580,11 @@ static void dm_test_crtc_atomic_check_invalid_stream_fails(struct kunit *test)
dc = dm_kunit_alloc_dc_with_ctx(test);
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
tg = kunit_kzalloc(test, sizeof(*tg), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg);
+ KUNIT_ASSERT_NOT_NULL(test, tg);
tg_funcs = kunit_kzalloc(test, sizeof(*tg_funcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg_funcs);
+ KUNIT_ASSERT_NOT_NULL(test, tg_funcs);
tg_funcs->validate_timing = dm_test_atomic_check_validate_timing_fail;
tg->funcs = tg_funcs;
res_pool->timing_generators[0] = tg;
@@ -2597,19 +2595,19 @@ static void dm_test_crtc_atomic_check_invalid_stream_fails(struct kunit *test)
stream = dm_kunit_alloc_stream(test, link);
crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
crtc->dev = &adev->ddev;
dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
dm_crtc_state->base.crtc = crtc;
dm_crtc_state->stream = stream;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
state->dev = &adev->ddev;
state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
state->crtcs[0].new_state = &dm_crtc_state->base;
dm_crtc_state->base.state = state;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
index 1e499acbcb90..2e273dea17ef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
@@ -90,7 +90,7 @@ static struct dmub_srv *dm_test_alloc_dmub_srv(struct kunit *test)
struct dmub_srv *dmub_srv;
dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dmub_srv);
dmub_srv->sw_init = true;
dmub_srv->hw_init = true;
@@ -110,10 +110,10 @@ static const struct firmware *dm_test_alloc_dmub_fw(struct kunit *test)
u8 *data;
fw = kunit_kzalloc(test, sizeof(*fw), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fw);
+ KUNIT_ASSERT_NOT_NULL(test, fw);
data = kunit_kzalloc(test, DM_TEST_FW_SIZE, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, data);
+ KUNIT_ASSERT_NOT_NULL(test, data);
hdr = (struct dmcub_firmware_header_v1_0 *)data;
hdr->header.ucode_array_offset_bytes = cpu_to_le32(0);
@@ -136,7 +136,7 @@ static void dm_test_register_dmub_notify_callback_null_callback(struct kunit *te
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev,
DMUB_NOTIFICATION_AUX_REPLY, NULL, false));
@@ -151,7 +151,7 @@ static void dm_test_register_dmub_notify_callback_type_out_of_range(struct kunit
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev,
AMDGPU_DMUB_NOTIFICATION_MAX, dummy_callback, false));
@@ -166,7 +166,7 @@ static void dm_test_register_dmub_notify_callback_valid(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev,
DMUB_NOTIFICATION_AUX_REPLY, dummy_callback, true));
@@ -186,7 +186,7 @@ static void dm_test_register_dmub_notify_callback_offload_false(struct kunit *te
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev,
DMUB_NOTIFICATION_HPD, dummy_callback, false));
@@ -210,10 +210,10 @@ static void dm_test_dmub_aux_setconfig_callback_copies_and_completes(struct kuni
struct dmub_notification notify = {};
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify);
+ KUNIT_ASSERT_NOT_NULL(test, dm_notify);
init_completion(&adev->dm.dmub_aux_transfer_done);
adev->dm.dmub_notify = dm_notify;
@@ -249,10 +249,10 @@ static void dm_test_dmub_aux_setconfig_callback_non_aux_no_complete(struct kunit
struct dmub_notification notify = {};
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify);
+ KUNIT_ASSERT_NOT_NULL(test, dm_notify);
init_completion(&adev->dm.dmub_aux_transfer_done);
adev->dm.dmub_notify = dm_notify;
@@ -276,7 +276,7 @@ static void dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify(struct k
struct dmub_notification notify = {};
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
init_completion(&adev->dm.dmub_aux_transfer_done);
adev->dm.dmub_notify = NULL;
@@ -299,10 +299,10 @@ static void dm_test_dmub_aux_setconfig_callback_set_config_reply(struct kunit *t
struct dmub_notification notify = {};
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify);
+ KUNIT_ASSERT_NOT_NULL(test, dm_notify);
init_completion(&adev->dm.dmub_aux_transfer_done);
adev->dm.dmub_notify = dm_notify;
@@ -337,7 +337,7 @@ static void dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes(struct
uint8_t ddc_line = 2;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
init_completion(&adev->dm.fused_io[ddc_line].replied);
@@ -380,7 +380,7 @@ static void dm_test_dmub_aux_fused_io_callback_max_ddc_line(struct kunit *test)
uint8_t ddc_line;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ddc_line = ARRAY_SIZE(adev->dm.fused_io) - 1;
init_completion(&adev->dm.fused_io[ddc_line].replied);
@@ -430,7 +430,7 @@ static void dm_test_get_default_ips_mode_dcn35(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
@@ -447,7 +447,7 @@ static void dm_test_get_default_ips_mode_dcn351(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 1);
@@ -464,7 +464,7 @@ static void dm_test_get_default_ips_mode_dcn36(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 6, 0);
@@ -481,7 +481,7 @@ static void dm_test_get_default_ips_mode_older_than_dcn35(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 2, 0);
@@ -498,7 +498,7 @@ static void dm_test_get_default_ips_mode_newer_default(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
/* DCN 4.0.1 is >= 3.5 but has no explicit case, returns ENABLE */
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 0, 1);
@@ -522,16 +522,16 @@ static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test)
struct resource_pool *res_pool;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
dc->res_pool = res_pool;
dc->ctx = ctx;
@@ -551,20 +551,20 @@ static struct amdgpu_device *dm_test_alloc_adev_with_dmub(struct kunit *test)
adev = dm_test_alloc_adev_with_dc(test);
fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info);
+ KUNIT_ASSERT_NOT_NULL(test, fb_info);
fb_info->num_fb = DMUB_WINDOW_TOTAL;
for (i = 0; i < DMUB_WINDOW_TOTAL; i++) {
fb_info->fb[i].size = PAGE_SIZE;
fb_info->fb[i].cpu_addr = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info->fb[i].cpu_addr);
+ KUNIT_ASSERT_NOT_NULL(test, fb_info->fb[i].cpu_addr);
}
adev->dm.dmub_srv = dm_test_alloc_dmub_srv(test);
adev->dm.dmub_fb_info = fb_info;
adev->dm.dmub_fw = dm_test_alloc_dmub_fw(test);
adev->bios = kunit_kzalloc(test, 4, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->bios);
+ KUNIT_ASSERT_NOT_NULL(test, adev->bios);
adev->bios_size = 4;
adev->dm.fw_inst_size = 0;
@@ -600,7 +600,7 @@ static void dm_test_dmub_hw_init_no_fb_info(struct kunit *test)
struct dmub_srv *dmub_srv;
dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dmub_srv);
adev->dm.dmub_srv = dmub_srv;
adev->dm.dmub_fb_info = NULL;
@@ -622,10 +622,10 @@ static void dm_test_dmub_hw_init_no_firmware(struct kunit *test)
struct dmub_srv_fb_info *fb_info;
dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dmub_srv);
fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info);
+ KUNIT_ASSERT_NOT_NULL(test, fb_info);
adev->dm.dmub_srv = dmub_srv;
adev->dm.dmub_fb_info = fb_info;
@@ -791,10 +791,10 @@ static void dm_test_dmub_hw_init_dmcu_abm(struct kunit *test)
struct abm *abm;
dmcu = kunit_kzalloc(test, sizeof(*dmcu), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmcu);
+ KUNIT_ASSERT_NOT_NULL(test, dmcu);
abm = kunit_kzalloc(test, sizeof(*abm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, abm);
+ KUNIT_ASSERT_NOT_NULL(test, abm);
dmcu->funcs = &dm_test_dmcu_funcs;
dmcu->psp_version = 0x12345678;
@@ -911,7 +911,7 @@ static void dm_test_dmub_sw_init_unsupported_asic(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0);
@@ -932,7 +932,7 @@ static void dm_test_init_microcode_unsupported_asic(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0);
@@ -954,7 +954,7 @@ static void dm_test_dmub_get_vbios_bounding_box_default_null(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
@@ -977,13 +977,13 @@ static void dm_test_execute_dmub_cmd_null_dmub_srv(struct kunit *test)
union dmub_rb_cmd *cmd;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
cmd = kunit_kzalloc(test, sizeof(*cmd), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cmd);
+ KUNIT_ASSERT_NOT_NULL(test, cmd);
spin_lock_init(&adev->dm.dmub_lock);
ctx->driver_context = adev;
@@ -1014,19 +1014,19 @@ static void dm_test_process_dmub_aux_transfer_sync_engine_acquire(struct kunit *
int ret;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+ KUNIT_ASSERT_NOT_NULL(test, payload);
notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+ KUNIT_ASSERT_NOT_NULL(test, notify);
dc->link_count = 0;
ctx->dc = dc;
@@ -1063,28 +1063,28 @@ static void dm_test_process_dmub_aux_transfer_sync_protocol_error(struct kunit *
int ret;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc);
+ KUNIT_ASSERT_NOT_NULL(test, ddc);
payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+ KUNIT_ASSERT_NOT_NULL(test, payload);
notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+ KUNIT_ASSERT_NOT_NULL(test, notify);
link->ddc = ddc;
dc->ctx = dc_ctx;
@@ -1131,28 +1131,28 @@ static void dm_test_process_dmub_aux_transfer_sync_copies_data(struct kunit *tes
int ret;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc);
+ KUNIT_ASSERT_NOT_NULL(test, ddc);
payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+ KUNIT_ASSERT_NOT_NULL(test, payload);
notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+ KUNIT_ASSERT_NOT_NULL(test, notify);
link->ddc = ddc;
dc->ctx = dc_ctx;
@@ -1212,28 +1212,28 @@ static void dm_test_process_dmub_aux_transfer_sync_zero_length(struct kunit *tes
int ret;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc);
+ KUNIT_ASSERT_NOT_NULL(test, ddc);
payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+ KUNIT_ASSERT_NOT_NULL(test, payload);
notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+ KUNIT_ASSERT_NOT_NULL(test, notify);
link->ddc = ddc;
dc->ctx = dc_ctx;
@@ -1286,25 +1286,25 @@ static void dm_test_process_dmub_set_config_sync_unknown_error(struct kunit *tes
int ret;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+ KUNIT_ASSERT_NOT_NULL(test, payload);
notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+ KUNIT_ASSERT_NOT_NULL(test, notify);
dc->ctx = dc_ctx;
dc_ctx->dmub_srv = NULL;
@@ -1338,13 +1338,13 @@ static void dm_test_abort_fused_io_no_dmub_srv(struct kunit *test)
struct dmub_cmd_fused_request *req;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
req = kunit_kzalloc(test, sizeof(*req), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, req);
+ KUNIT_ASSERT_NOT_NULL(test, req);
spin_lock_init(&adev->dm.dmub_lock);
ctx->driver_context = adev;
@@ -1484,7 +1484,7 @@ static int dm_test_dmub_hw_access_init(struct kunit *test)
void *cpu_ptr;
cpu_ptr = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cpu_ptr);
+ KUNIT_ASSERT_NOT_NULL(test, cpu_ptr);
dm_test_bo = (struct dm_test_bo_ctx) { .cpu_ptr = cpu_ptr };
dm_test_cgs = (struct dm_test_cgs_ctx) { .dev.ops = &dm_test_cgs_ops };
@@ -1509,7 +1509,7 @@ static struct amdgpu_device *dm_test_alloc_adev_with_cgs(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->dm.cgs_device = &dm_test_cgs.dev;
INIT_LIST_HEAD(&adev->dm.da_list);
@@ -1532,7 +1532,7 @@ static void dm_test_dmub_reg_write_then_read(struct kunit *test)
struct dc_perf_trace *perf_trace;
perf_trace = kunit_kzalloc(test, sizeof(*perf_trace), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, perf_trace);
+ KUNIT_ASSERT_NOT_NULL(test, perf_trace);
adev->dm.dc->ctx->cgs_device = &dm_test_cgs.dev;
adev->dm.dc->ctx->perf_trace = perf_trace;
@@ -1690,7 +1690,7 @@ static void dm_test_init_microcode_fw_names(struct kunit *test)
unsigned int i;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
for (i = 0; i < ARRAY_SIZE(dm_test_ucode_cases); i++) {
const struct dm_test_ucode_case *c = &dm_test_ucode_cases[i];
@@ -1719,7 +1719,7 @@ static void dm_test_init_microcode_request_fails(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
dm_test_ucode_ret = -ENOENT;
@@ -1735,7 +1735,7 @@ static struct amdgpu_device *dm_test_alloc_adev_for_sw_init(struct kunit *test)
adev->dm.dmub_fw = dm_test_alloc_dmub_fw(test);
adev->bios = kunit_kzalloc(test, 4, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->bios);
+ KUNIT_ASSERT_NOT_NULL(test, adev->bios);
adev->bios_size = 4;
return adev;
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 616a2b385140..710cdc7f40bf 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
@@ -166,11 +166,11 @@ static void dm_test_dc_timing_adjust_pending(struct kunit *test)
struct dc_stream_state *stream;
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
+ KUNIT_ASSERT_NOT_NULL(test, old_state);
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
+ KUNIT_ASSERT_NOT_NULL(test, new_state);
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
new_state->stream = stream;
stream->timing_adjust_pending = 1;
@@ -188,11 +188,11 @@ static void dm_test_dc_timing_adjust_active_fixed(struct kunit *test)
struct dc_stream_state *stream;
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
+ KUNIT_ASSERT_NOT_NULL(test, old_state);
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
+ KUNIT_ASSERT_NOT_NULL(test, new_state);
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
new_state->stream = stream;
new_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
@@ -210,11 +210,11 @@ static void dm_test_dc_timing_adjust_vrr_toggle(struct kunit *test)
struct dc_stream_state *stream;
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
+ KUNIT_ASSERT_NOT_NULL(test, old_state);
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
+ KUNIT_ASSERT_NOT_NULL(test, new_state);
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
new_state->stream = stream;
old_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
@@ -233,11 +233,11 @@ static void dm_test_dc_timing_adjust_not_needed(struct kunit *test)
struct dc_stream_state *stream;
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
+ KUNIT_ASSERT_NOT_NULL(test, old_state);
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
+ KUNIT_ASSERT_NOT_NULL(test, new_state);
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
new_state->stream = stream;
old_state->freesync_config.state = VRR_STATE_INACTIVE;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
index cfdcc44581b1..5af6ae47bb21 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
@@ -1352,9 +1352,9 @@ static void dm_test_hdcp_destroy_frees_and_removes_sysfs(struct kunit *test)
INIT_DELAYED_WORK(&work->watchdog_timer_dwork, dummy_work_fn);
INIT_DELAYED_WORK(&work->property_validate_dwork, dummy_work_fn);
- work->srm = kzalloc(16, GFP_KERNEL);
+ work->srm = kzalloc_objs(*work->srm, 16);
KUNIT_ASSERT_NOT_NULL(test, work->srm);
- work->srm_temp = kzalloc(16, GFP_KERNEL);
+ work->srm_temp = kzalloc_objs(*work->srm_temp, 16);
KUNIT_ASSERT_NOT_NULL(test, work->srm_temp);
kobj = setup_destroy_sysfs(test, work);
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 a2ae30eb55bf..873e7c73e84b 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
@@ -428,17 +428,16 @@ static struct dc *dm_test_alloc_dc_with_irq_service(struct kunit *test,
dc = dm_kunit_alloc_dc_with_ctx(test);
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
+ KUNIT_ASSERT_NOT_NULL(test, irqs);
/*
* Populate the per-source info table so amdgpu_dm_irq_set()/_ack()
* succeed without touching hardware registers.
*/
- info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
- GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+ info = kunit_kcalloc(test, DAL_IRQ_SOURCES_NUMBER, sizeof(*info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, info);
for (i = 0; i < DAL_IRQ_SOURCES_NUMBER; i++)
info[i].funcs = &dm_test_irq_src_funcs;
@@ -504,7 +503,7 @@ static struct amdgpu_crtc *dm_test_add_crtc(struct kunit *test,
struct amdgpu_crtc *acrtc;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
INIT_LIST_HEAD(&acrtc->base.head);
acrtc->base.dev = &adev->ddev;
@@ -577,7 +576,7 @@ 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);
+ KUNIT_ASSERT_NOT_NULL(test, hdcp_work);
mutex_init(&hdcp_work->mutex);
INIT_WORK(&hdcp_work->cpirq_work, dm_test_hdcp_dummy_work);
@@ -679,7 +678,7 @@ static void dm_test_are_sinks_equal_first_null(struct kunit *test)
struct dc_sink *sink2;
sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
+ KUNIT_ASSERT_NOT_NULL(test, sink2);
KUNIT_EXPECT_FALSE(test, are_sinks_equal(NULL, sink2));
}
@@ -693,7 +692,7 @@ static void dm_test_are_sinks_equal_second_null(struct kunit *test)
struct dc_sink *sink1;
sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
+ KUNIT_ASSERT_NOT_NULL(test, sink1);
KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, NULL));
}
@@ -707,9 +706,9 @@ static void dm_test_are_sinks_equal_different_signal(struct kunit *test)
struct dc_sink *sink1, *sink2;
sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
+ KUNIT_ASSERT_NOT_NULL(test, sink1);
sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
+ KUNIT_ASSERT_NOT_NULL(test, sink2);
sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
@@ -726,9 +725,9 @@ static void dm_test_are_sinks_equal_different_edid_length(struct kunit *test)
struct dc_sink *sink1, *sink2;
sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
+ KUNIT_ASSERT_NOT_NULL(test, sink1);
sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
+ KUNIT_ASSERT_NOT_NULL(test, sink2);
sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
@@ -747,9 +746,9 @@ static void dm_test_are_sinks_equal_different_edid_data(struct kunit *test)
struct dc_sink *sink1, *sink2;
sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
+ KUNIT_ASSERT_NOT_NULL(test, sink1);
sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
+ KUNIT_ASSERT_NOT_NULL(test, sink2);
sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
@@ -770,9 +769,9 @@ static void dm_test_are_sinks_equal_zero_length(struct kunit *test)
struct dc_sink *sink1, *sink2;
sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
+ KUNIT_ASSERT_NOT_NULL(test, sink1);
sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
+ KUNIT_ASSERT_NOT_NULL(test, sink2);
sink1->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
@@ -791,9 +790,9 @@ static void dm_test_are_sinks_equal_full_edid_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);
+ KUNIT_ASSERT_NOT_NULL(test, sink1);
sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
+ KUNIT_ASSERT_NOT_NULL(test, sink2);
sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
@@ -814,9 +813,9 @@ static void dm_test_are_sinks_equal_full_edid_last_byte_differs(struct kunit *te
struct dc_sink *sink1, *sink2;
sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
+ KUNIT_ASSERT_NOT_NULL(test, sink1);
sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
+ KUNIT_ASSERT_NOT_NULL(test, sink2);
sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
@@ -928,7 +927,7 @@ static void dm_test_irq_init_initializes_lists(struct kunit *test)
int src;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_EQ(test, amdgpu_dm_irq_init(adev), 0);
@@ -952,7 +951,7 @@ static void dm_test_irq_register_rejects_null_params(struct kunit *test)
struct dc_interrupt_params int_params = { 0 };
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
int_params.irq_source = DC_IRQ_SOURCE_HPD1;
@@ -974,7 +973,7 @@ static void dm_test_irq_register_rejects_invalid_context(struct kunit *test)
struct dc_interrupt_params int_params = { 0 };
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
int_params.int_context = INTERRUPT_CONTEXT_NUMBER;
int_params.irq_source = DC_IRQ_SOURCE_HPD1;
@@ -994,7 +993,7 @@ static void dm_test_irq_register_rejects_invalid_source(struct kunit *test)
struct dc_interrupt_params int_params = { 0 };
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
int_params.irq_source = DC_IRQ_SOURCE_INVALID;
@@ -1015,7 +1014,7 @@ static void dm_test_irq_register_separate_contexts(struct kunit *test)
void *handler;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
int_params.irq_source = DC_IRQ_SOURCE_HPD5;
@@ -1066,7 +1065,7 @@ static void dm_test_irq_unregister_rejects_invalid_source(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_INVALID,
@@ -1087,7 +1086,7 @@ static void dm_test_irq_unregister_rejects_null_handler(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
@@ -1110,7 +1109,7 @@ static void dm_test_irq_unregister_handler_not_found(struct kunit *test)
void *handler;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
@@ -1146,7 +1145,7 @@ static void dm_test_irq_fini_removes_registered_handlers(struct kunit *test)
void *handler;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
@@ -1179,7 +1178,7 @@ static void dm_test_irq_fini_on_empty_tables(struct kunit *test)
int src;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
amdgpu_dm_irq_fini(adev);
@@ -1208,9 +1207,9 @@ static void dm_test_get_crtc_by_otg_inst_returns_match(struct kunit *test)
drm = &adev->ddev;
acrtc_a = kunit_kzalloc(test, sizeof(*acrtc_a), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_a);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc_a);
acrtc_b = kunit_kzalloc(test, sizeof(*acrtc_b), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_b);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc_b);
INIT_LIST_HEAD(&acrtc_a->base.head);
INIT_LIST_HEAD(&acrtc_b->base.head);
@@ -1239,7 +1238,7 @@ static void dm_test_get_crtc_by_otg_inst_returns_null(struct kunit *test)
drm = &adev->ddev;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
INIT_LIST_HEAD(&acrtc->base.head);
acrtc->otg_inst = 2;
@@ -1279,7 +1278,7 @@ static void dm_test_get_crtc_by_otg_inst_unassigned_otg(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
adev->mode_info.crtcs[0] = acrtc;
KUNIT_EXPECT_PTR_EQ(test, amdgpu_dm_get_crtc_by_otg_inst(adev, -1), acrtc);
@@ -1296,7 +1295,7 @@ static void dm_test_set_irq_funcs(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
adev->mode_info.num_crtc = 6;
adev->mode_info.num_hpd = 4;
@@ -1534,12 +1533,12 @@ static void dm_test_hpd_rx_irq_create_workqueue(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
dc->caps.max_links = 4;
adev->dm.dc = dc;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
ctx->wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev);
KUNIT_ASSERT_NOT_NULL(test, ctx->wq);
@@ -1561,7 +1560,7 @@ static void dm_test_hpd_rx_irq_work_suspend_null(struct kunit *test)
struct amdgpu_display_manager *dm;
dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
+ KUNIT_ASSERT_NOT_NULL(test, dm);
/* A NULL hpd_rx_offload_wq must be a safe no-op (DC untouched). */
amdgpu_dm_hpd_rx_irq_work_suspend(dm);
@@ -1580,12 +1579,12 @@ static void dm_test_hpd_rx_irq_work_suspend_flushes(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
dc->caps.max_links = 2;
adev->dm.dc = dc;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
ctx->wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev);
KUNIT_ASSERT_NOT_NULL(test, ctx->wq);
@@ -1608,7 +1607,7 @@ static void dm_test_set_crtc_irq_state_no_crtc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
/* mode_info.crtcs[0] is NULL -> returns 0 without dereferencing DC. */
KUNIT_EXPECT_EQ(test,
@@ -1624,7 +1623,7 @@ static void dm_test_set_pflip_irq_state_no_crtc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_EQ(test,
amdgpu_dm_set_pflip_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_DISABLE), 0);
@@ -1639,7 +1638,7 @@ static void dm_test_set_vline0_irq_state_no_crtc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_EQ(test,
amdgpu_dm_set_vline0_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
@@ -1654,7 +1653,7 @@ static void dm_test_set_vupdate_irq_state_no_crtc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_EQ(test,
amdgpu_dm_set_vupdate_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
@@ -1672,9 +1671,9 @@ static void dm_test_set_crtc_irq_state_otg_disabled(struct kunit *test)
struct amdgpu_crtc *acrtc;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
/* otg_inst == -1 short-circuits before computing the irq source. */
acrtc->otg_inst = -1;
@@ -1694,9 +1693,9 @@ static void dm_test_set_crtc_irq_state_enable(struct kunit *test)
struct amdgpu_crtc *acrtc;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
/*
* otg_inst >= 0 computes the irq source and reaches the NULL-safe
@@ -1719,9 +1718,9 @@ static void dm_test_set_pflip_irq_state_disable(struct kunit *test)
struct amdgpu_crtc *acrtc;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
/* The disable state exercises the st == false path. */
acrtc->otg_inst = 1;
@@ -1749,13 +1748,13 @@ static void dm_test_set_crtc_irq_state_allows_idle(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10);
/* DC_LOG_* dereferences ctx->logger->dev, so wire a real drm device. */
logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger);
+ KUNIT_ASSERT_NOT_NULL(test, logger);
logger->dev = &adev->ddev;
dc->ctx->logger = logger;
@@ -1783,7 +1782,7 @@ static void dm_test_irq_immediate_work_empty(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
/* No registered high-context handlers: must be a safe no-op. */
@@ -1802,7 +1801,7 @@ static void dm_test_irq_immediate_work_invokes_all(struct kunit *test)
void *handler;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
@@ -1833,7 +1832,7 @@ static void dm_test_irq_schedule_work_empty(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
/* Empty handler list: schedule_work returns immediately. */
@@ -1852,7 +1851,7 @@ static void dm_test_irq_schedule_work_queues_handler(struct kunit *test)
void *handler;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
@@ -1893,7 +1892,7 @@ static void dm_test_irq_schedule_work_requeue_fallback(struct kunit *test)
void *handler;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
@@ -1931,7 +1930,7 @@ static void dm_test_irq_schedule_work_no_workqueue(struct kunit *test)
void *handler;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
@@ -1960,7 +1959,7 @@ static void dm_test_set_hpd_irq_state_null_dc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
/* amdgpu_dm_irq_set() is a no-op when dc is NULL, so both states
* return 0 without dereferencing the (absent) DC.
@@ -1982,7 +1981,7 @@ static void dm_test_set_dmub_outbox_irq_state_null_dc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_outbox_irq_state(adev, NULL, 0,
AMDGPU_IRQ_STATE_ENABLE), 0);
@@ -2001,7 +2000,7 @@ static void dm_test_set_dmub_trace_irq_state_null_dc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_trace_irq_state(adev, NULL, 0,
AMDGPU_IRQ_STATE_ENABLE), 0);
@@ -2020,7 +2019,7 @@ static void dm_test_outbox_init_null_dc(struct kunit *test)
struct amdgpu_device *adev;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
/* Single amdgpu_dm_irq_set() call must be skipped when dc is NULL. */
amdgpu_dm_outbox_init(adev);
@@ -2050,7 +2049,7 @@ static void dm_test_hpd_init_empty_connectors(struct kunit *test)
adev->dm.dc = dc;
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX;
dc->links[0] = link;
@@ -2099,7 +2098,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
/* A writeback connector must be skipped by the per-connector loop. */
wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn);
+ KUNIT_ASSERT_NOT_NULL(test, wbconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs,
DRM_MODE_CONNECTOR_WRITEBACK), 0);
KUNIT_ASSERT_EQ(test,
@@ -2107,7 +2106,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
/* A DisplayPort connector with a dc_link exercises the loop body. */
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -2115,7 +2114,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX;
aconn->dc_link = link;
@@ -2146,7 +2145,7 @@ static void dm_test_hpd_init_fini_analog_connector(struct kunit *test)
adev->dm.dc = dc;
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_VGA), 0);
@@ -2154,7 +2153,7 @@ static void dm_test_hpd_init_fini_analog_connector(struct kunit *test)
kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX;
/* An analog connector id makes the loop request polling. */
@@ -2199,7 +2198,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test)
adev->mode_info.num_hpd = 1;
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -2207,7 +2206,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test)
kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
aconn->dc_link = link;
@@ -2237,7 +2236,7 @@ static void dm_test_hpd_init_skips_connector_without_link(struct kunit *test)
adev->dm.dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10);
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -2265,10 +2264,10 @@ static void dm_test_hpd_rx_offload_work_no_connector(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
+ KUNIT_ASSERT_NOT_NULL(test, offload_wq);
offload_work = kzalloc_obj(*offload_work);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work);
+ KUNIT_ASSERT_NOT_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);
@@ -2301,10 +2300,10 @@ dm_test_setup_hpd_rx_offload_work(struct kunit *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);
+ KUNIT_ASSERT_NOT_NULL(test, adev->reset_domain);
offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
+ KUNIT_ASSERT_NOT_NULL(test, offload_wq);
spin_lock_init(&offload_wq->offload_lock);
aconn = dm_kunit_alloc_connector(test, adev, NULL);
@@ -2312,13 +2311,13 @@ dm_test_setup_hpd_rx_offload_work(struct kunit *test,
offload_wq->aconnector = aconn;
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link_srv->detect_connection_type = dm_test_detect_connection_single;
dc->link_srv = link_srv;
@@ -2330,7 +2329,7 @@ dm_test_setup_hpd_rx_offload_work(struct kunit *test,
aconn->dc_link = link;
offload_work = kzalloc_obj(*offload_work, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work);
+ KUNIT_ASSERT_NOT_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);
@@ -2537,13 +2536,13 @@ static struct amdgpu_dm_connector *dm_test_setup_hdmi_debounce(struct kunit *tes
amdgpu_dm_hdmi_hpd_debounce_work);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link_srv->detect_link = dm_test_detect_link_false;
dc->ctx = ctx;
@@ -2595,9 +2594,9 @@ static void dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit *test)
dc = aconn->dc_link->ctx->dc;
logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger);
+ KUNIT_ASSERT_NOT_NULL(test, logger);
dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dmub_srv);
/* DC_LOG_* dereferences ctx->logger->dev, so wire a real drm device. */
logger->dev = aconn->base.dev;
@@ -2698,15 +2697,15 @@ static void dm_test_handle_hpd_irq_disabled(struct kunit *test)
aconn = dm_kunit_alloc_connector(test, adev, NULL);
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
aconn->base.state = &state->base;
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
dc->ctx = ctx;
ctx->dc = dc;
@@ -2747,17 +2746,17 @@ static struct amdgpu_dm_connector *dm_test_setup_hpd_irq_helper(struct kunit *te
amdgpu_dm_hdmi_hpd_debounce_work);
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+ KUNIT_ASSERT_NOT_NULL(test, state);
aconn->base.state = &state->base;
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link_srv->detect_connection_type = dm_test_detect_connection_none;
dc->ctx = ctx;
@@ -3006,19 +3005,19 @@ static void dm_test_handle_hpd_rx_irq_disabled(struct kunit *test)
adev->dm.disable_hpd_irq = true;
offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
+ KUNIT_ASSERT_NOT_NULL(test, offload_wq);
adev->dm.hpd_rx_offload_wq = offload_wq;
aconn = dm_kunit_alloc_connector(test, adev, NULL);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work;
dc->ctx = ctx;
@@ -3045,7 +3044,7 @@ static void dm_test_schedule_hpd_rx_offload_work(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
+ KUNIT_ASSERT_NOT_NULL(test, offload_wq);
offload_wq->wq = create_singlethread_workqueue("dm_irq_test_hpd_rx");
KUNIT_ASSERT_NOT_NULL(test, offload_wq->wq);
@@ -3083,7 +3082,7 @@ static struct amdgpu_dm_connector *dm_test_setup_hpd_rx_irq(struct kunit *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);
+ KUNIT_ASSERT_NOT_NULL(test, offload_wq);
spin_lock_init(&offload_wq->offload_lock);
offload_wq->wq = create_singlethread_workqueue("dm_irq_test_hpd_rx");
KUNIT_ASSERT_NOT_NULL(test, offload_wq->wq);
@@ -3096,13 +3095,13 @@ static struct amdgpu_dm_connector *dm_test_setup_hpd_rx_irq(struct kunit *test,
aconn->mst_mgr.mst_state = true;
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
dc->ctx = ctx;
dc->link_srv = link_srv;
@@ -3327,7 +3326,7 @@ static void dm_test_dmub_hpd_callback_invalid_index(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
notify.link_index = 1;
@@ -3346,7 +3345,7 @@ static void dm_test_dmub_hpd_callback_empty_connectors(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
adev->dm.ddev = &adev->ddev;
dc->link_count = 1;
@@ -3371,7 +3370,7 @@ static void dm_test_dmub_hpd_callback_suspend_skip(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
adev->in_suspend = true;
dc->link_count = 1;
@@ -3403,25 +3402,25 @@ static void dm_test_dmub_hpd_callback_unknown_type_match(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
adev->dm.ddev = &adev->ddev;
dc->link_count = 1;
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
dc->links[0] = link;
/* A writeback connector must be skipped by the loop. */
wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn);
+ KUNIT_ASSERT_NOT_NULL(test, wbconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs,
DRM_MODE_CONNECTOR_WRITEBACK), 0);
KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_connector_cleanup, wbconn), 0);
/* A DisplayPort connector whose dc_link matches drives the match branch. */
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -3458,13 +3457,13 @@ static void dm_test_dmub_hpd_callback_hpd_type(struct kunit *test)
mutex_init(&adev->dm.dc_lock);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link_srv->detect_connection_type = dm_test_detect_connection_none;
link_srv->detect_link = dm_test_detect_link_false;
@@ -3480,7 +3479,7 @@ static void dm_test_dmub_hpd_callback_hpd_type(struct kunit *test)
dc->links[0] = link;
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -3522,18 +3521,18 @@ static void dm_test_dmub_hpd_callback_hpd_irq_type(struct kunit *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);
+ KUNIT_ASSERT_NOT_NULL(test, offload_wq);
spin_lock_init(&offload_wq->offload_lock);
adev->dm.hpd_rx_offload_wq = offload_wq;
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work;
dc->ctx = ctx;
@@ -3550,7 +3549,7 @@ static void dm_test_dmub_hpd_callback_hpd_irq_type(struct kunit *test)
dc->links[0] = link;
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -3579,7 +3578,7 @@ static void dm_test_register_hpd_handlers_empty(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
KUNIT_EXPECT_EQ(test, amdgpu_dm_register_hpd_handlers(adev), 0);
@@ -3604,18 +3603,18 @@ static void dm_test_register_hpd_handlers_valid(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn);
+ KUNIT_ASSERT_NOT_NULL(test, wbconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs,
DRM_MODE_CONNECTOR_WRITEBACK), 0);
KUNIT_ASSERT_EQ(test,
kunit_add_action_or_reset(test, dm_test_connector_cleanup, wbconn), 0);
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -3623,7 +3622,7 @@ static void dm_test_register_hpd_handlers_valid(struct kunit *test)
kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX;
aconn->dc_link = link;
@@ -3651,11 +3650,11 @@ static void dm_test_register_hpd_handlers_invalid_hpd(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -3663,7 +3662,7 @@ static void dm_test_register_hpd_handlers_invalid_hpd(struct kunit *test)
kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->irq_source_hpd = DC_IRQ_SOURCE_HPD1RX;
link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
aconn->dc_link = link;
@@ -3686,11 +3685,11 @@ static void dm_test_register_hpd_handlers_invalid_hpd_rx(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
adev->dm.dc = dc;
aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
+ KUNIT_ASSERT_NOT_NULL(test, aconn);
KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
&dm_test_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort), 0);
@@ -3698,7 +3697,7 @@ static void dm_test_register_hpd_handlers_invalid_hpd_rx(struct kunit *test)
kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1;
aconn->dc_link = link;
@@ -3803,7 +3802,7 @@ static void dm_test_pflip_high_irq_completes_flip(struct kunit *test)
/* drm_crtc_send_vblank_event() consumes (kfree()s) the event. */
event = kzalloc_obj(*event, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event);
+ KUNIT_ASSERT_NOT_NULL(test, event);
acrtc->event = event;
/* Balance the handler's drm_crtc_vblank_put(). */
@@ -3839,7 +3838,7 @@ static struct amdgpu_crtc *dm_test_setup_vrr_pflip_crtc(struct kunit *test,
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);
+ KUNIT_ASSERT_NOT_NULL(test, dc->current_state);
adev->dm.dc = dc;
link = dm_kunit_alloc_link(test);
@@ -3879,7 +3878,7 @@ static void dm_test_pflip_high_irq_vrr_no_scanoutpos(struct kunit *test)
/* drm_crtc_send_vblank_event() consumes (kfree()s) the event. */
event = kzalloc_obj(*event, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event);
+ KUNIT_ASSERT_NOT_NULL(test, event);
acrtc->event = event;
/* Balance the handler's drm_crtc_vblank_put(). */
@@ -3912,14 +3911,14 @@ static void dm_test_pflip_high_irq_vrr_front_porch(struct kunit *test)
struct amdgpu_crtc *acrtc;
tg = kunit_kzalloc(test, sizeof(*tg), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg);
+ KUNIT_ASSERT_NOT_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);
+ KUNIT_ASSERT_NOT_NULL(test, event);
acrtc->event = event;
params.adev = adev;
@@ -3980,7 +3979,7 @@ static void dm_test_vupdate_high_irq_dcn_completes_flip(struct kunit *test)
acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
event = kzalloc_obj(*event, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event);
+ KUNIT_ASSERT_NOT_NULL(test, event);
acrtc->event = event;
adev->ddev.vblank[0].time = ktime_get();
@@ -4052,7 +4051,7 @@ static struct amdgpu_crtc *dm_test_setup_vmin_vmax_crtc(struct kunit *test,
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);
+ KUNIT_ASSERT_NOT_NULL(test, dc->current_state);
adev->dm.dc = dc;
link = dm_kunit_alloc_link(test);
@@ -4209,7 +4208,7 @@ static void dm_test_crtc_high_irq_writeback_disables(struct kunit *test)
acrtc = dm_test_add_crtc(test, adev);
wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb_conn);
+ KUNIT_ASSERT_NOT_NULL(test, wb_conn);
acrtc->wb_conn = wb_conn;
acrtc->wb_pending = true;
@@ -4245,7 +4244,7 @@ static void dm_test_crtc_high_irq_writeback_completes(struct kunit *test)
acrtc = dm_test_add_crtc(test, adev);
wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb_conn);
+ KUNIT_ASSERT_NOT_NULL(test, wb_conn);
spin_lock_init(&wb_conn->job_lock);
INIT_LIST_HEAD(&wb_conn->job_queue);
@@ -4254,7 +4253,7 @@ static void dm_test_crtc_high_irq_writeback_completes(struct kunit *test)
* work only kfree()s it; it needs nothing from this test.
*/
job = kzalloc_obj(*job, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, job);
+ KUNIT_ASSERT_NOT_NULL(test, job);
list_add_tail(&job->list_entry, &wb_conn->job_queue);
acrtc->wb_conn = wb_conn;
@@ -4322,9 +4321,9 @@ static void dm_test_handle_hpd_work_out_of_range(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
hpd_work = kzalloc_obj(*hpd_work);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work);
+ KUNIT_ASSERT_NOT_NULL(test, hpd_work);
hpd_work->dmub_notify = kzalloc_obj(*hpd_work->dmub_notify);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work->dmub_notify);
+ KUNIT_ASSERT_NOT_NULL(test, hpd_work->dmub_notify);
hpd_work->dmub_notify->type =
(enum dmub_notification_type)ARRAY_SIZE(adev->dm.dmub_callback);
hpd_work->adev = adev;
@@ -4346,7 +4345,7 @@ static void dm_test_handle_hpd_work_null_notify(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
hpd_work = kzalloc_obj(*hpd_work, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work);
+ KUNIT_ASSERT_NOT_NULL(test, hpd_work);
hpd_work->adev = adev;
INIT_WORK(&hpd_work->handle_hpd_work, dm_handle_hpd_work);
@@ -4372,9 +4371,9 @@ static void dm_test_dmub_outbox1_low_irq_empty(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = dm_kunit_alloc_dc_with_ctx(test);
dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv);
dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub);
+ KUNIT_ASSERT_NOT_NULL(test, dmub);
dmub->hw_funcs.get_outbox0_wptr = dm_test_dmub_get_outbox0_wptr;
dc_dmub_srv->dmub = dmub;
@@ -4406,11 +4405,11 @@ static void dm_test_dmub_outbox1_low_irq_drains_trace(struct kunit *test)
adev = dm_kunit_alloc_adev(test);
dc = dm_kunit_alloc_dc_with_ctx(test);
dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv);
dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub);
+ KUNIT_ASSERT_NOT_NULL(test, dmub);
rb = kunit_kzalloc(test, DM_TEST_OUTBOX0_RB_SIZE, GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rb);
+ KUNIT_ASSERT_NOT_NULL(test, rb);
dmub->outbox0_rb.base_address = rb;
dmub->outbox0_rb.capacity = DM_TEST_OUTBOX0_RB_SIZE;
@@ -4446,9 +4445,9 @@ static struct amdgpu_device *dm_test_alloc_adev_outbox_notify(struct kunit *test
adev = dm_kunit_alloc_adev(test);
dc = dm_kunit_alloc_dc_with_ctx(test);
dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv);
dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub);
+ KUNIT_ASSERT_NOT_NULL(test, dmub);
dmub->hw_init = true;
dmub->hw_funcs.get_outbox0_wptr = dm_test_dmub_get_outbox0_wptr;
@@ -4926,7 +4925,7 @@ static void dm_test_register_outbox_irq_handlers_with_dmub(struct kunit *test)
adev), 0);
dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10);
dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv);
+ KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv);
dc->ctx->dmub_srv = dc_dmub_srv;
adev->dm.dc = dc;
amdgpu_dm_set_irq_funcs(adev);
@@ -4969,7 +4968,7 @@ static void dm_test_irq_handler_dispatches_work(struct kunit *test)
struct dc *dc;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
dc = dm_test_alloc_dc_with_irq_service(test,
@@ -5029,7 +5028,7 @@ static void dm_test_irq_handler_invalid_source(struct kunit *test)
int low_count = 0;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
/* This stub maps every src_id to DC_IRQ_SOURCE_INVALID. */
@@ -5076,17 +5075,17 @@ static void dm_test_handle_vmin_vmax_update(struct kunit *test)
struct dc *dc;
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
mutex_init(&adev->dm.dc_lock);
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);
+ KUNIT_ASSERT_NOT_NULL(test, dc->current_state);
adev->dm.dc = dc;
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
/*
* Start at two references: the worker's dc_stream_release() drops one,
* leaving the kunit-managed allocation intact (no kfree).
@@ -5096,9 +5095,9 @@ static void dm_test_handle_vmin_vmax_update(struct kunit *test)
/* The worker kfree()s both, so they must come from the slab. */
work = kzalloc_obj(*work);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work);
+ KUNIT_ASSERT_NOT_NULL(test, work);
adjust = kzalloc_obj(*adjust);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adjust);
+ KUNIT_ASSERT_NOT_NULL(test, adjust);
work->adev = adev;
work->stream = stream;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c
index aad122c7229f..f844b644bb77 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c
@@ -182,7 +182,7 @@ struct drm_device *dm_kunit_alloc_drm_with_connector_list(struct kunit *test)
struct drm_device *dev;
dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ KUNIT_ASSERT_NOT_NULL(test, dev);
INIT_LIST_HEAD(&dev->mode_config.connector_list);
spin_lock_init(&dev->mode_config.connector_list_lock);
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 eafa3e6733a6..237431c83a81 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
@@ -203,7 +203,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_match(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14;
@@ -223,7 +223,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_rev12(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
link->dpcd_caps.dpcd_rev.raw = DPCD_REV_12;
@@ -243,7 +243,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_wrong_dev_id(struct kunit *test
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.branch_dev_id = 0x123456;
link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14;
@@ -263,7 +263,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_wrong_rev(struct kunit *test)
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
link->dpcd_caps.dpcd_rev.raw = 0x11; /* DPCD 1.1 */
@@ -283,7 +283,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_low_sink_count(struct kunit *te
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14;
@@ -303,7 +303,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_zero_sink_count(struct kunit *t
{
struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+ KUNIT_ASSERT_NOT_NULL(test, link);
link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c
index 150c53a68bed..8547ac047e7f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c
@@ -27,7 +27,7 @@ static void dm_test_quirks_aux_hpd_discon_reset(struct kunit *test)
struct amdgpu_display_manager *dm;
dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
+ KUNIT_ASSERT_NOT_NULL(test, dm);
dm->aux_hpd_discon_quirk = true;
@@ -54,7 +54,7 @@ static void dm_test_quirks_edp0_on_dp1_reset(struct kunit *test)
struct amdgpu_display_manager *dm;
dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
+ KUNIT_ASSERT_NOT_NULL(test, dm);
dm->edp0_on_dp1_quirk = true;
@@ -76,7 +76,7 @@ static void dm_test_quirks_no_dmi_match_both_false(struct kunit *test)
struct amdgpu_display_manager *dm;
dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
+ KUNIT_ASSERT_NOT_NULL(test, dm);
retrieve_dmi_info(dm);
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 e77e6fa18a72..c375ee68778b 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
@@ -258,9 +258,9 @@ static void dm_test_plane_layer_index_cmp_equal(struct kunit *test)
struct dc_surface_update sa, sb;
plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a);
+ KUNIT_ASSERT_NOT_NULL(test, plane_a);
plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b);
+ KUNIT_ASSERT_NOT_NULL(test, plane_b);
plane_a->layer_index = 5;
plane_b->layer_index = 5;
@@ -281,9 +281,9 @@ static void dm_test_plane_layer_index_cmp_descending(struct kunit *test)
struct dc_surface_update sa, sb;
plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a);
+ KUNIT_ASSERT_NOT_NULL(test, plane_a);
plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b);
+ KUNIT_ASSERT_NOT_NULL(test, plane_b);
plane_a->layer_index = 3;
plane_b->layer_index = 7;
@@ -305,9 +305,9 @@ static void dm_test_plane_layer_index_cmp_ascending(struct kunit *test)
struct dc_surface_update sa, sb;
plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a);
+ KUNIT_ASSERT_NOT_NULL(test, plane_a);
plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b);
+ KUNIT_ASSERT_NOT_NULL(test, plane_b);
plane_a->layer_index = 9;
plane_b->layer_index = 2;
@@ -763,7 +763,7 @@ static void dm_test_multisync_trigger_disabled(struct kunit *test)
struct dc_stream_state *stream;
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
stream->triggered_crtc_reset.enabled = false;
stream->triggered_crtc_reset.event = CRTC_EVENT_VSYNC_FALLING;
@@ -788,9 +788,9 @@ static void dm_test_multisync_trigger_rising(struct kunit *test)
struct dc_stream_state *master;
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
master = kunit_kzalloc(test, sizeof(*master), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, master);
+ KUNIT_ASSERT_NOT_NULL(test, master);
master->timing.flags.VSYNC_POSITIVE_POLARITY = 1;
stream->triggered_crtc_reset.enabled = true;
@@ -814,9 +814,9 @@ static void dm_test_multisync_trigger_falling(struct kunit *test)
struct dc_stream_state *master;
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
master = kunit_kzalloc(test, sizeof(*master), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, master);
+ KUNIT_ASSERT_NOT_NULL(test, master);
master->timing.flags.VSYNC_POSITIVE_POLARITY = 0;
stream->triggered_crtc_reset.enabled = true;
@@ -842,9 +842,9 @@ static void dm_test_master_stream_highest_refresh(struct kunit *test)
struct dc_stream_state *stream_set[2];
stream0 = kunit_kzalloc(test, sizeof(*stream0), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream0);
+ KUNIT_ASSERT_NOT_NULL(test, stream0);
stream1 = kunit_kzalloc(test, sizeof(*stream1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream1);
+ KUNIT_ASSERT_NOT_NULL(test, stream1);
stream_set[0] = stream0;
stream_set[1] = stream1;
@@ -880,9 +880,9 @@ static void dm_test_master_stream_defaults_to_first(struct kunit *test)
struct dc_stream_state *stream_set[2];
stream0 = kunit_kzalloc(test, sizeof(*stream0), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream0);
+ KUNIT_ASSERT_NOT_NULL(test, stream0);
stream1 = kunit_kzalloc(test, sizeof(*stream1), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream1);
+ KUNIT_ASSERT_NOT_NULL(test, stream1);
stream_set[0] = stream0;
stream_set[1] = stream1;
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index 39cffa0a8116..84c68b87210f 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -83,6 +83,13 @@ FILES += core/dc_surface.o
FILES += core/dc_vm_helper.o
FILES += core2/dc_core2.o
FILES += core2/dc_core2_init.o
+FILES += core2/dc_core2_legacy_init.o
+FILES += bls_builder/bls_builder.o
+FILES += bls_builder/dcn401_init_builder.o
+FILES += bls_builder/dcn401_init_builder_legacy.o
+FILES += bls_executor/bls_executor.o
+FILES += workaround_manager/workaround_manager.o
+FILES += dmub_messenger/dmub_messenger.o
AMD_DISPLAY_FILES += $(addprefix $(AMDDALPATH)/dc/, $(FILES))
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.c b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.c
new file mode 100644
index 000000000000..8ac202487189
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include "dm_services.h"
+#include "bls_builder/bls_builder_internal.h"
+
+const struct bls_builder *bls_builder_create(struct dc *dc,
+ enum bls_builder_name name)
+{
+ if (!dc || !dc->ctx)
+ return NULL;
+
+ switch (dc->ctx->dce_version) {
+ case DCN_VERSION_4_01:
+ return dcn401_bls_builder_create(name);
+ default:
+ return NULL;
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h
new file mode 100644
index 000000000000..422ee25cf348
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "dc.h"
+#include "dmub_cmd.h"
+#include "dmub/dmub_srv.h"
+#include "hwss/hw_sequencer.h"
+#include "bls_builder/dmub_abi.h"
+#include "bls_builder/bls_builder_legacy_init.h"
+
+#define DC2_BLS_MAX_STEPS 64
+
+enum bls_builder_result {
+ BLS_BUILD_SUCCESS,
+ BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE,
+ BLS_BUILD_ERROR_RESOURCE_MAPPING,
+ BLS_BUILD_ERROR_DMUB_ABI_UNRESOLVED,
+};
+
+enum bls_builder_name {
+ DCN_DECL_INITIALIZATION,
+ DCN_DECL_INITIALIZATION_LEGACY,
+ BLS_BUILDER_NAME_COUNT,
+};
+
+enum bls_builder_kind {
+ BLS_BUILDER_DECLARATIVE,
+ BLS_BUILDER_IMPERATIVE,
+};
+
+struct bls_builder_output_init {
+ unsigned int xtalin_clock_inKhz;
+ unsigned int dccg_ref_clock_inKhz;
+ unsigned int dchub_ref_clock_inKhz;
+ unsigned int dchub_ref_clock_inKhz_before;
+ unsigned int backlight;
+ bool dcmode_power_limits_present;
+ unsigned int dmub_stop_fw_response;
+ struct dmub_abi dmub_abi;
+ union dmub_rb_cmd dmub_query_feature_caps_cmd;
+ union dmub_rb_cmd dmub_initialize_dcn_cmd;
+};
+
+struct bls_builder_output_targets {
+ union {
+ struct bls_builder_output_init *DCN_DECL_INITIALIZATION;
+ struct bls_builder_legacy_hw_init_info *DCN_DECL_INITIALIZATION_LEGACY;
+ };
+};
+
+struct bls_builder_check_capability_params {
+ struct dc *dc;
+ const struct dc_state *current_state;
+ const struct dc_state *new_state;
+};
+
+struct bls_builder_declarative_params {
+ struct dc *dc;
+ const struct dc_state *current_state;
+ const struct dc_state *new_state;
+ const struct dmub_abi *dmub_abi;
+ const struct dmub_srv_hw_params *dmub_hw_params;
+ /*
+ * Filled when the caller does not pass dmub_hw_params and dmub_srv
+ * already retained framebuffer windows. fb_info on dmub_srv is
+ * const, so the window table is copied here before the PSP entry
+ * points at owned_dmub_hw_params.
+ */
+ struct dmub_srv_hw_params owned_dmub_hw_params;
+ struct dmub_srv_fb_info owned_dmub_fb_info;
+ struct bls_builder_output_targets *out_targets;
+ struct block_sequence head_sequence[DC2_BLS_MAX_STEPS];
+ unsigned int head_num_steps;
+ struct block_sequence tail_sequence[DC2_BLS_MAX_STEPS];
+ unsigned int tail_num_steps;
+};
+
+typedef bool (*bls_builder_check_capability)(
+ const struct bls_builder_check_capability_params *params);
+
+typedef enum bls_builder_result (*bls_builder_build_declarative)(
+ struct bls_builder_declarative_params *params);
+
+struct bls_builder {
+ enum bls_builder_name name;
+ enum bls_builder_kind kind;
+ bls_builder_check_capability check_capability;
+ union {
+ bls_builder_build_declarative declarative;
+ } build;
+};
+
+const struct bls_builder *bls_builder_create(struct dc *dc,
+ enum bls_builder_name name);
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h
new file mode 100644
index 000000000000..216879c93f9e
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "bls_builder/bls_builder.h"
+
+const struct bls_builder *dcn401_bls_builder_create(
+ enum bls_builder_name name);
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_legacy_init.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_legacy_init.h
new file mode 100644
index 000000000000..e9259699a9c0
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_legacy_init.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "dmub_cmd.h"
+#include "grph_object_ctrl_defs.h"
+#include "bios_parser_types.h"
+#include "inc/hw/hw_shared.h"
+
+/*
+ * DC2_DC1_Wrapped hardware init: dcn401_init_hw as twelve BLS stages.
+ * A stage ends on a read that a later stage depends on. Stage N writes
+ * bls_builder_output_legacy_init_stageN; a later stage reads it from
+ * dc_state.hw_init_info.
+ */
+enum bls_builder_legacy_init_stage {
+ LEGACY_INIT_STAGE_CLOCKS = 1,
+ LEGACY_INIT_STAGE_DCHUB_REF,
+ LEGACY_INIT_STAGE_LINK_ENC,
+ LEGACY_INIT_STAGE_FEC,
+ LEGACY_INIT_STAGE_BLANK,
+ LEGACY_INIT_STAGE_POWER_DOWN,
+ LEGACY_INIT_STAGE_MIN_CLOCKS,
+ LEGACY_INIT_STAGE_POWER_DOWN_EDP0,
+ LEGACY_INIT_STAGE_POWER_DOWN_EDP1,
+ LEGACY_INIT_STAGE_GATING,
+ LEGACY_INIT_STAGE_HUBBUB,
+ LEGACY_INIT_STAGE_POWER_STATE,
+ LEGACY_INIT_STAGE_COUNT = LEGACY_INIT_STAGE_POWER_STATE,
+};
+
+/* CLOCKS: DC-mode limits and the DCCG reference clocks. */
+struct bls_builder_output_legacy_init_stage1 {
+ bool dcmode_power_limits_present;
+ unsigned int xtalin_clock_inKhz;
+ unsigned int dccg_ref_clock_inKhz;
+};
+
+/* DCHUB_REF: the DCHUB reference clock, before and after the read. */
+struct bls_builder_output_legacy_init_stage2 {
+ unsigned int dchub_ref_clock_mhz_before;
+ unsigned int dchub_ref_clock_inKhz;
+};
+
+/* LINK_ENC: per dc->links entry, the DIG state and the I2C info. */
+struct bls_builder_output_legacy_init_stage3 {
+ bool link_dig_enabled[MAX_LINKS];
+ struct graphics_object_i2c_info link_i2c_info[MAX_LINKS];
+ enum bp_result link_i2c_result[MAX_LINKS];
+};
+
+/* FEC: per dc->links entry, whether FEC is active. */
+struct bls_builder_output_legacy_init_stage4 {
+ bool link_fec_active[MAX_LINKS];
+};
+
+/* BLANK: the VBIOS accelerated-mode bit after blanking. */
+struct bls_builder_output_legacy_init_stage5 {
+ bool accelerated_mode;
+};
+
+/* POWER_DOWN: the DENTIST dispclk. */
+struct bls_builder_output_legacy_init_stage6 {
+ int dispclk_from_dentist_khz;
+};
+
+/* MIN_CLOCKS: power-down-on-boot DIG reads for eDP slot 0, or every link. */
+struct bls_builder_output_legacy_init_stage7 {
+ bool edp_dig_enabled;
+ bool boot_dig_enabled[MAX_LINKS];
+};
+
+/* POWER_DOWN_EDP0: the power-down-on-boot DIG read for eDP slot 1. */
+struct bls_builder_output_legacy_init_stage8 {
+ bool edp_dig_enabled;
+};
+
+/* POWER_DOWN_EDP1: the backlight panel_cntl reports, and the IHC commands. */
+struct bls_builder_output_legacy_init_stage9 {
+ uint32_t backlight;
+ uint32_t user_level;
+ union dmub_rb_cmd dmub_ihc_cmd[MAX_LINKS];
+};
+
+/* GATING: the VBIOS accelerated-mode bit after gating. */
+struct bls_builder_output_legacy_init_stage10 {
+ bool accelerated_mode;
+};
+
+/*
+ * HUBBUB: whether the DMUB feature caps apply, whether the query was
+ * sent, and the command that holds the reply.
+ */
+struct bls_builder_output_legacy_init_stage11 {
+ bool dmub_caps_read;
+ bool dmub_caps_query_sent;
+ union dmub_rb_cmd dmub_query_feature_caps_cmd;
+};
+
+/* POWER_STATE: the D0 power-state command. */
+struct bls_builder_output_legacy_init_stage12 {
+ union dmub_rb_cmd dmub_power_state_cmd;
+};
+
+/*
+ * next_stage is the stage the builder builds next, and s1 up to the
+ * stage before it are valid. Core stops at init_done.
+ */
+struct bls_builder_legacy_hw_init_info {
+ bool init_done;
+ bool init_success;
+ unsigned int next_stage;
+ struct bls_builder_output_legacy_init_stage1 s1;
+ struct bls_builder_output_legacy_init_stage2 s2;
+ struct bls_builder_output_legacy_init_stage3 s3;
+ struct bls_builder_output_legacy_init_stage4 s4;
+ struct bls_builder_output_legacy_init_stage5 s5;
+ struct bls_builder_output_legacy_init_stage6 s6;
+ struct bls_builder_output_legacy_init_stage7 s7;
+ struct bls_builder_output_legacy_init_stage8 s8;
+ struct bls_builder_output_legacy_init_stage9 s9;
+ struct bls_builder_output_legacy_init_stage10 s10;
+ struct bls_builder_output_legacy_init_stage11 s11;
+ struct bls_builder_output_legacy_init_stage12 s12;
+};
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c
new file mode 100644
index 000000000000..589a950e078b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include "dm_services.h"
+#include "core_types.h"
+#include "clk_mgr.h"
+#include "dccg.h"
+#include "resource.h"
+#include "dc_dmub_srv.h"
+#include "dmub_cmd.h"
+#include "bls_builder/bls_builder_internal.h"
+#include "bls_builder/dcn401_init_builder.h"
+#include "bls_builder/dcn401_init_builder_legacy.h"
+
+static const enum block_sequence_func dcn401_dc2_init_sequence[] = {
+ LEGACY_CLK_MGR_INIT_CLOCKS,
+ LEGACY_CLK_MGR_IS_DC_MODE_PRESENT,
+ DCCG_INITIALIZE_CLOCKS,
+ DMUB_HALT_FW,
+ PSP_RELOAD_DMUB_FW,
+ DMUB_GPINT_SEND_AND_WAIT,
+ DMUB_SEND_DMCUB_CMD,
+ DMUB_INITIALIZE_DCN,
+};
+
+static enum bls_builder_result dcn401_check_initialization_support(
+ const struct bls_builder_check_capability_params *params)
+{
+ struct dc *dc;
+
+ if (!params || !params->dc)
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ dc = params->dc;
+ if (!dc->ctx || !dc->res_pool || !dc->res_pool->dccg)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (dc->config.seamless_boot_edp_requested)
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static bool dcn401_initialization_check_capability(
+ const struct bls_builder_check_capability_params *params)
+{
+ return dcn401_check_initialization_support(params) ==
+ BLS_BUILD_SUCCESS;
+}
+
+static enum bls_builder_result dcn401_validate_initialization_step(
+ const struct bls_builder_declarative_params *params,
+ enum block_sequence_func func)
+{
+ struct bls_builder_output_init *out_init = NULL;
+ struct clk_mgr *clk_mgr = params->dc->clk_mgr;
+ struct dccg *dccg = params->dc->res_pool->dccg;
+
+ if (params->out_targets)
+ out_init = params->out_targets->DCN_DECL_INITIALIZATION;
+
+ switch (func) {
+ case LEGACY_CLK_MGR_INIT_CLOCKS:
+ if (!clk_mgr || !clk_mgr->funcs ||
+ !clk_mgr->funcs->init_clocks)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ return BLS_BUILD_SUCCESS;
+ case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT:
+ if (!clk_mgr || !clk_mgr->funcs ||
+ !clk_mgr->funcs->is_dc_mode_present ||
+ !out_init)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ return BLS_BUILD_SUCCESS;
+ case DCCG_INITIALIZE_CLOCKS:
+ if (!dccg->funcs || !dccg->funcs->dccg_init)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ return BLS_BUILD_SUCCESS;
+ case DMUB_GPINT_SEND_AND_WAIT:
+ case DMUB_HALT_FW: {
+ struct dc_context *ctx = params->dc->ctx;
+ struct dmub_srv *dmub;
+
+ if (!ctx || !ctx->dmub_srv || !ctx->dmub_srv->dmub || !out_init)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ dmub = ctx->dmub_srv->dmub;
+ if (!dmub->sw_init || !dmub->hw_funcs.set_gpint ||
+ !dmub->hw_funcs.is_gpint_acked ||
+ !dmub->hw_funcs.get_gpint_response)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ return BLS_BUILD_SUCCESS;
+ }
+ case PSP_RELOAD_DMUB_FW: {
+ struct dmub_srv *dmub;
+
+ if (!params->dc->ctx || !params->dc->ctx->dmub_srv ||
+ !params->dc->ctx->dmub_srv->dmub)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ /*
+ * An explicit caller pointer wins, including a test double
+ * whose fb_info is still empty. Otherwise use the windows
+ * dmub_srv retained from the DM's earlier hw init.
+ */
+ if (params->dmub_hw_params)
+ return BLS_BUILD_SUCCESS;
+ dmub = params->dc->ctx->dmub_srv->dmub;
+ if (!dmub->fb_info ||
+ dmub->fb_info->num_fb < DMUB_WINDOW_TOTAL)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ return BLS_BUILD_SUCCESS;
+ }
+ case DMUB_SEND_DMCUB_CMD:
+ case DMUB_INITIALIZE_DCN:
+ if (!params->dc->ctx || !params->dc->ctx->dmub_srv ||
+ !params->dc->ctx->dmub_srv->dmub || !out_init)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ return BLS_BUILD_SUCCESS;
+ default:
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+ }
+}
+
+enum bls_builder_result dcn401_build_clk_mgr_init(
+ struct clk_mgr *clk_mgr, struct block_sequence_state *sequence)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.legacy_clk_mgr_init_clocks_params.clk_mgr = clk_mgr;
+ if (!bls_append(sequence, LEGACY_CLK_MGR_INIT_CLOCKS, &bls_params))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+enum bls_builder_result dcn401_build_dc_mode_read(
+ struct clk_mgr *clk_mgr, bool *out_dcmode_power_limits_present,
+ struct block_sequence_state *sequence)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.legacy_clk_mgr_is_dc_mode_present_params.clk_mgr = clk_mgr;
+ bls_params.legacy_clk_mgr_is_dc_mode_present_params
+ .out_dcmode_power_limits_present =
+ out_dcmode_power_limits_present;
+ if (!bls_append(sequence, LEGACY_CLK_MGR_IS_DC_MODE_PRESENT,
+ &bls_params))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+enum bls_builder_result dcn401_build_dccg_init(
+ struct dccg *dccg, struct block_sequence_state *sequence)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.dccg_initialize_clocks_params.dccg = dccg;
+ if (!bls_append(sequence, DCCG_INITIALIZE_CLOCKS, &bls_params))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static inline enum bls_builder_result dcn401_build_dmub_halt_fw(
+ struct bls_builder_declarative_params *params,
+ struct block_sequence_state *sequence)
+{
+ union block_sequence_params bls_params = {0};
+ struct bls_builder_output_init *out_init =
+ params->out_targets->DCN_DECL_INITIALIZATION;
+
+ bls_params.dmub_gpint_params.command_code = DMUB_GPINT__STOP_FW;
+ bls_params.dmub_gpint_params.param = 0;
+ bls_params.dmub_gpint_params.response =
+ &out_init->dmub_stop_fw_response;
+ if (!bls_append(sequence, DMUB_HALT_FW, &bls_params))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static const struct dmub_srv_hw_params *dcn401_psp_hw_params(
+ struct bls_builder_declarative_params *params)
+{
+ struct dmub_srv *dmub;
+
+ if (params->dmub_hw_params)
+ return params->dmub_hw_params;
+
+ dmub = params->dc->ctx->dmub_srv->dmub;
+ params->owned_dmub_fb_info = *dmub->fb_info;
+ memset(&params->owned_dmub_hw_params, 0,
+ sizeof(params->owned_dmub_hw_params));
+ params->owned_dmub_hw_params.fb_info = &params->owned_dmub_fb_info;
+ params->owned_dmub_hw_params.soc_fb_info = dmub->soc_fb_info;
+ params->owned_dmub_hw_params.psp_version = dmub->psp_version;
+ return &params->owned_dmub_hw_params;
+}
+
+static inline enum bls_builder_result dcn401_build_psp_reload(
+ struct bls_builder_declarative_params *params,
+ struct block_sequence_state *sequence)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.psp_reload_dmub_fw_params.dmub =
+ params->dc->ctx->dmub_srv->dmub;
+ bls_params.psp_reload_dmub_fw_params.hw_params =
+ dcn401_psp_hw_params(params);
+ if (!bls_append(sequence, PSP_RELOAD_DMUB_FW, &bls_params))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static inline enum bls_builder_result dcn401_build_dmub_fw_version(
+ struct bls_builder_declarative_params *params,
+ struct block_sequence_state *sequence)
+{
+ union block_sequence_params bls_params = {0};
+ struct bls_builder_output_init *out_init =
+ params->out_targets->DCN_DECL_INITIALIZATION;
+
+ bls_params.dmub_gpint_params.command_code =
+ DMUB_GPINT__GET_FW_VERSION;
+ bls_params.dmub_gpint_params.param = 0;
+ bls_params.dmub_gpint_params.response =
+ &out_init->dmub_abi.fw_version;
+ if (!bls_append(sequence, DMUB_GPINT_SEND_AND_WAIT, &bls_params))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+bool dcn401_add_dmub_cmd(struct block_sequence_state *sequence,
+ struct dc_context *ctx, union dmub_rb_cmd *cmd,
+ enum dm_dmub_wait_type wait_type, bool continue_on_error)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.send_dmcub_cmd_params.ctx = ctx;
+ bls_params.send_dmcub_cmd_params.cmd = cmd;
+ bls_params.send_dmcub_cmd_params.wait_type = wait_type;
+ bls_params.send_dmcub_cmd_params.continue_on_error = continue_on_error;
+ return bls_append(sequence, DMUB_SEND_DMCUB_CMD, &bls_params);
+}
+
+void dcn401_fill_query_feature_caps_cmd(union dmub_rb_cmd *cmd)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->query_feature_caps.header.type = DMUB_CMD__QUERY_FEATURE_CAPS;
+ cmd->query_feature_caps.header.sub_type = 0;
+ cmd->query_feature_caps.header.ret_status = 1;
+ cmd->query_feature_caps.header.payload_bytes =
+ sizeof(struct dmub_cmd_query_feature_caps_data);
+}
+
+static inline enum bls_builder_result dcn401_build_dmub_feature_caps(
+ struct bls_builder_declarative_params *params,
+ struct block_sequence_state *sequence)
+{
+ struct bls_builder_output_init *out_init =
+ params->out_targets->DCN_DECL_INITIALIZATION;
+ union dmub_rb_cmd *cmd = &out_init->dmub_query_feature_caps_cmd;
+
+ dcn401_fill_query_feature_caps_cmd(cmd);
+ if (!dcn401_add_dmub_cmd(sequence, params->dc->ctx, cmd,
+ DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY, false))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static inline enum bls_builder_result dcn401_build_dmub_initialize_dcn(
+ struct bls_builder_declarative_params *params,
+ struct block_sequence_state *sequence)
+{
+ union block_sequence_params bls_params = {0};
+ struct bls_builder_output_init *out_init =
+ params->out_targets->DCN_DECL_INITIALIZATION;
+ union dmub_rb_cmd *cmd = &out_init->dmub_initialize_dcn_cmd;
+
+ /*
+ * No Initialize DCN opcode exists in dmub_cmd.h. A caller-supplied
+ * non-zero type is preserved for tests; zero stays an undefined
+ * command and cannot complete a successful build.
+ */
+ if (!cmd->cmd_common.header.type)
+ memset(cmd, 0, sizeof(*cmd));
+ bls_params.send_dmcub_cmd_params.ctx = params->dc->ctx;
+ bls_params.send_dmcub_cmd_params.cmd = cmd;
+ bls_params.send_dmcub_cmd_params.wait_type =
+ DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY;
+ if (!bls_append(sequence, DMUB_INITIALIZE_DCN, &bls_params))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static enum bls_builder_result dcn401_build_initialization_step(
+ struct bls_builder_declarative_params *params,
+ struct block_sequence_state *sequence,
+ enum block_sequence_func func)
+{
+ switch (func) {
+ case LEGACY_CLK_MGR_INIT_CLOCKS:
+ return dcn401_build_clk_mgr_init(params->dc->clk_mgr, sequence);
+ case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT:
+ return dcn401_build_dc_mode_read(params->dc->clk_mgr,
+ &params->out_targets->DCN_DECL_INITIALIZATION
+ ->dcmode_power_limits_present, sequence);
+ case DCCG_INITIALIZE_CLOCKS:
+ return dcn401_build_dccg_init(params->dc->res_pool->dccg,
+ sequence);
+ case DMUB_HALT_FW:
+ return dcn401_build_dmub_halt_fw(params, sequence);
+ case PSP_RELOAD_DMUB_FW:
+ return dcn401_build_psp_reload(params, sequence);
+ case DMUB_GPINT_SEND_AND_WAIT:
+ return dcn401_build_dmub_fw_version(params, sequence);
+ case DMUB_SEND_DMCUB_CMD:
+ return dcn401_build_dmub_feature_caps(params, sequence);
+ case DMUB_INITIALIZE_DCN:
+ return dcn401_build_dmub_initialize_dcn(params, sequence);
+ default:
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+ }
+}
+
+static enum bls_builder_result dcn401_build_initialization(
+ struct bls_builder_declarative_params *params)
+{
+ struct bls_builder_check_capability_params check_params = {0};
+ enum bls_builder_result result;
+ struct block_sequence_state sequence;
+ struct bls_builder_output_init *out_init = NULL;
+ unsigned int i;
+
+ if (!params)
+ return dcn401_check_initialization_support(NULL);
+
+ check_params.dc = params->dc;
+ check_params.current_state = params->current_state;
+ check_params.new_state = params->new_state;
+ result =
+ dcn401_check_initialization_support(&check_params);
+ if (result != BLS_BUILD_SUCCESS)
+ return result;
+
+ params->head_num_steps = 0;
+ params->tail_num_steps = 0;
+ for (i = 0; i < ARRAY_SIZE(dcn401_dc2_init_sequence); i++) {
+ result = dcn401_validate_initialization_step(params,
+ dcn401_dc2_init_sequence[i]);
+ if (result != BLS_BUILD_SUCCESS)
+ return result;
+ }
+
+ sequence.steps = params->head_sequence;
+ sequence.num_steps = &params->head_num_steps;
+ if (params->out_targets)
+ out_init = params->out_targets->DCN_DECL_INITIALIZATION;
+ if (out_init) {
+ out_init->dcmode_power_limits_present = false;
+ out_init->dmub_stop_fw_response = 0;
+ out_init->dmub_abi.fw_version = 0;
+ memset(&out_init->dmub_abi.feature_caps, 0,
+ sizeof(out_init->dmub_abi.feature_caps));
+ }
+
+ /*
+ * LEGACY/pmfw-msg: preserve the clock-manager entry points until
+ * PMFW Messenger can express the same calls, order, and output.
+ */
+ for (i = 0; i < ARRAY_SIZE(dcn401_dc2_init_sequence); i++) {
+ result = dcn401_build_initialization_step(params, &sequence,
+ dcn401_dc2_init_sequence[i]);
+ if (result != BLS_BUILD_SUCCESS)
+ return result;
+ }
+
+ if (out_init &&
+ out_init->dmub_initialize_dcn_cmd.cmd_common.header.type)
+ return BLS_BUILD_SUCCESS;
+
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+}
+
+const struct bls_builder *dcn401_bls_builder_create(
+ enum bls_builder_name name)
+{
+ static const struct bls_builder initialization_builder = {
+ .name = DCN_DECL_INITIALIZATION,
+ .kind = BLS_BUILDER_DECLARATIVE,
+ .check_capability = dcn401_initialization_check_capability,
+ .build.declarative = dcn401_build_initialization,
+ };
+ static const struct bls_builder legacy_initialization_builder = {
+ .name = DCN_DECL_INITIALIZATION_LEGACY,
+ .kind = BLS_BUILDER_DECLARATIVE,
+ .check_capability = dcn401_dc1_initialization_check_capability,
+ .build.declarative = dcn401_build_dc1_initialization,
+ };
+
+ switch (name) {
+ case DCN_DECL_INITIALIZATION:
+ return &initialization_builder;
+ case DCN_DECL_INITIALIZATION_LEGACY:
+ return &legacy_initialization_builder;
+ default:
+ return NULL;
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.h b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.h
new file mode 100644
index 000000000000..fe70971cb8a5
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "bls_builder/bls_builder.h"
+
+struct clk_mgr;
+struct dccg;
+struct dc_context;
+
+static inline bool bls_append(struct block_sequence_state *sequence,
+ enum block_sequence_func func,
+ const union block_sequence_params *params)
+{
+ struct block_sequence *entry;
+
+ if (!sequence || !sequence->steps || !sequence->num_steps ||
+ !params || *sequence->num_steps >=
+ DC2_BLS_MAX_STEPS)
+ return false;
+
+ entry = &sequence->steps[*sequence->num_steps];
+ entry->params = *params;
+ entry->func = func;
+ (*sequence->num_steps)++;
+ return true;
+}
+
+enum bls_builder_result dcn401_build_clk_mgr_init(
+ struct clk_mgr *clk_mgr, struct block_sequence_state *sequence);
+enum bls_builder_result dcn401_build_dc_mode_read(
+ struct clk_mgr *clk_mgr, bool *out_dcmode_power_limits_present,
+ struct block_sequence_state *sequence);
+enum bls_builder_result dcn401_build_dccg_init(
+ struct dccg *dccg, struct block_sequence_state *sequence);
+bool dcn401_add_dmub_cmd(struct block_sequence_state *sequence,
+ struct dc_context *ctx, union dmub_rb_cmd *cmd,
+ enum dm_dmub_wait_type wait_type, bool continue_on_error);
+void dcn401_fill_query_feature_caps_cmd(union dmub_rb_cmd *cmd);
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.c b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.c
new file mode 100644
index 000000000000..e13c16920a0c
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.c
@@ -0,0 +1,1071 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include "dm_services.h"
+#include "core_types.h"
+#include "clk_mgr.h"
+#include "dccg.h"
+#include "resource.h"
+#include "dc_dmub_srv.h"
+#include "dmub_cmd.h"
+#include "abm.h"
+#include "audio.h"
+#include "dchubbub.h"
+#include "dio.h"
+#include "link_encoder.h"
+#include "panel_cntl.h"
+#include "link_service.h"
+#include "dc_bios_types.h"
+#include "dce/dce_hwseq.h"
+#include "hwss/hw_sequencer_private.h"
+#include "dcn32/dcn32_resource.h"
+#include "bls_builder/dcn401_init_builder.h"
+#include "bls_builder/dcn401_init_builder_legacy.h"
+
+/*
+ * DC2_DC1_Wrapped: dcn401_init_hw as BLS entries, built one stage per
+ * call. A stage ends on a read whose value a later stage needs: Core
+ * executes the stage and retains its output in dc_state.hw_init_info,
+ * where the next build reads it. Same calls in the same order, and an
+ * entry is left out only where dcn401_init_hw skips the call. The build
+ * reads dc and hw_init_info, and writes only the sequence and the
+ * output target.
+ */
+static_assert(LEGACY_INIT_STAGE_POWER_DOWN_EDP1 -
+ LEGACY_INIT_STAGE_POWER_DOWN_EDP0 + 1 == MAX_NUM_EDP,
+ "one power-down-on-boot stage per eDP slot");
+
+static bool dcn401_dc1_is_phy_link(const struct dc_link *link)
+{
+ return link->ep_type == DISPLAY_ENDPOINT_PHY;
+}
+
+static bool dcn401_dc1_powers_down_pipes(struct dc *dc,
+ const struct bls_builder_legacy_hw_init_info *in)
+{
+ return in->s5.accelerated_mode ||
+ !dc->config.seamless_boot_edp_requested;
+}
+
+static bool dcn401_dc1_uses_accelerated_mode(struct dc *dc)
+{
+ return dc->hwss.enable_accelerated_mode &&
+ dc->debug.disable_boot_optimizations;
+}
+
+static bool dcn401_dc1_has_dmub(struct dc *dc)
+{
+ return dc->ctx->dmub_srv && dc->ctx->dmub_srv->dmub;
+}
+
+static enum bls_builder_result dcn401_validate_dc1_links(struct dc *dc)
+{
+ struct dc_bios *dcb = dc->ctx->dc_bios;
+ unsigned int i;
+
+ if (dc->link_count > MAX_LINKS)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ for (i = 0; i < dc->link_count; i++) {
+ const struct dc_link *link = dc->links[i];
+
+ if (!link)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (dcn401_dc1_is_phy_link(link) && (!link->link_enc ||
+ !link->link_enc->funcs ||
+ !link->link_enc->funcs->hw_init))
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (link->panel_cntl && (!link->panel_cntl->funcs ||
+ !link->panel_cntl->funcs->hw_init))
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (link->force_to_use_aux && (!link->ctx ||
+ !dcb->funcs->get_i2c_info))
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ }
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static enum bls_builder_result dcn401_validate_dc1_power_down(struct dc *dc)
+{
+ if (!dcn401_dc1_uses_accelerated_mode(dc) &&
+ !dc->hwseq->funcs.init_pipes)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (!dc->current_state || !dc->clk_mgr || !dc->clk_mgr->funcs ||
+ !dc->clk_mgr->funcs->update_clocks ||
+ !dc->clk_mgr->bw_params)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static enum bls_builder_result dcn401_validate_dc1_hwseq(struct dc *dc)
+{
+ const struct hwseq_private_funcs *funcs = &dc->hwseq->funcs;
+
+ if (dc->debug.enable_mem_low_power.bits.optc &&
+ !funcs->init_odm_mem_power)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (dc->debug.enable_mem_low_power.bits.vga &&
+ !funcs->power_down_vga_mem)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (!dc->debug.disable_clock_gate && !funcs->dcfclk_gating_control)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (!funcs->init_hpo_hw_control)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static enum bls_builder_result dcn401_validate_dc1_initialization(
+ const struct bls_builder_declarative_params *params)
+{
+ const struct bls_builder_legacy_hw_init_info *in;
+ struct dc *dc = params->dc;
+ struct resource_pool *pool;
+ struct dc_bios *dcb;
+ unsigned int i;
+
+ if (!dc || !dc->ctx || !dc->res_pool || !params->current_state ||
+ !params->out_targets ||
+ !params->out_targets->DCN_DECL_INITIALIZATION_LEGACY)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ in = &params->current_state->hw_init_info;
+ if (in->next_stage < LEGACY_INIT_STAGE_CLOCKS ||
+ in->next_stage > LEGACY_INIT_STAGE_COUNT)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW)
+ return BLS_BUILD_SUCCESS;
+
+ pool = dc->res_pool;
+ dcb = dc->ctx->dc_bios;
+ if (!dcb || !dcb->funcs || !dcb->funcs->is_accelerated_mode ||
+ !pool->dccg || !pool->dccg->funcs || !pool->hubbub ||
+ !pool->hubbub->funcs || !dc->hwseq || !dc->link_srv ||
+ !dc->link_srv->blank_all_dp_displays)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ /* Later stages re-check only what a stage read-back decides. */
+ if ((in->next_stage == LEGACY_INIT_STAGE_POWER_DOWN ||
+ in->next_stage == LEGACY_INIT_STAGE_MIN_CLOCKS) &&
+ dcn401_dc1_powers_down_pipes(dc, in))
+ return dcn401_validate_dc1_power_down(dc);
+ if (in->next_stage != LEGACY_INIT_STAGE_CLOCKS)
+ return BLS_BUILD_SUCCESS;
+
+ if (dcb->fw_info_valid && (!pool->dccg->funcs->get_dccg_ref_freq ||
+ !pool->hubbub->funcs->get_dchub_ref_freq))
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (dcn401_validate_dc1_links(dc) != BLS_BUILD_SUCCESS)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (dcn401_validate_dc1_hwseq(dc) != BLS_BUILD_SUCCESS)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ for (i = 0; i < pool->audio_count; i++)
+ if (!pool->audios[i] || !pool->audios[i]->funcs ||
+ !pool->audios[i]->funcs->hw_init)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ for (i = 0; i < pool->pipe_count; i++)
+ if (pool->multiple_abms[i] && pool->multiple_abms[i]->funcs &&
+ !pool->multiple_abms[i]->funcs->abm_init)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ if (pool->dio && !pool->dio->funcs)
+ return BLS_BUILD_ERROR_RESOURCE_MAPPING;
+ /* Without seamless boot the pipes power down whatever the BIOS reads. */
+ if (!dc->config.seamless_boot_edp_requested)
+ return dcn401_validate_dc1_power_down(dc);
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static bool dcn401_add_hwseq_reg(struct block_sequence_state *sequence,
+ enum block_sequence_func func, struct dce_hwseq *hws,
+ bool enable)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.hwseq_reg_control_params.hws = hws;
+ bls_params.hwseq_reg_control_params.enable = enable;
+ return bls_append(sequence, func, &bls_params);
+}
+
+static bool dcn401_add_dc_call(struct block_sequence_state *sequence,
+ enum block_sequence_func func, struct dc *dc, bool enable)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.dc_init_call_params.dc = dc;
+ bls_params.dc_init_call_params.enable = enable;
+ return bls_append(sequence, func, &bls_params);
+}
+
+static bool dcn401_add_dccg_ref_freq(struct block_sequence_state *sequence,
+ struct dc *dc, struct bls_builder_output_legacy_init_stage1 *out)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.dccg_get_ref_freq_params.dccg = dc->res_pool->dccg;
+ bls_params.dccg_get_ref_freq_params.xtalin_khz =
+ dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
+ bls_params.dccg_get_ref_freq_params.out_xtalin_khz =
+ &out->xtalin_clock_inKhz;
+ bls_params.dccg_get_ref_freq_params.out_dccg_ref_khz =
+ &out->dccg_ref_clock_inKhz;
+ return bls_append(sequence, DCCG_GET_REF_FREQ, &bls_params);
+}
+
+/* Core published the DCCG reference clock after the previous stage. */
+static bool dcn401_add_dchub_ref_freq(struct block_sequence_state *sequence,
+ struct dc *dc, struct bls_builder_output_legacy_init_stage2 *out)
+{
+ union block_sequence_params bls_params = {0};
+ struct resource_pool *pool = dc->res_pool;
+
+ out->dchub_ref_clock_mhz_before =
+ pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
+ bls_params.hubbub_get_dchub_ref_freq_params.hubbub = pool->hubbub;
+ bls_params.hubbub_get_dchub_ref_freq_params.dccg_ref_khz =
+ pool->ref_clocks.dccg_ref_clock_inKhz;
+ bls_params.hubbub_get_dchub_ref_freq_params.out_dchub_ref_khz =
+ &out->dchub_ref_clock_inKhz;
+ return bls_append(sequence, HUBBUB_GET_DCHUB_REF_FREQ, &bls_params);
+}
+
+static bool dcn401_add_accelerated_mode_read(
+ struct block_sequence_state *sequence, struct dc *dc,
+ bool *out_accelerated_mode)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.bios_is_accelerated_mode_params.dcb = dc->ctx->dc_bios;
+ bls_params.bios_is_accelerated_mode_params.out_accelerated_mode =
+ out_accelerated_mode;
+ return bls_append(sequence, BIOS_IS_ACCELERATED_MODE, &bls_params);
+}
+
+static bool dcn401_add_link_enc_hw_init(
+ struct block_sequence_state *sequence,
+ struct link_encoder *link_enc)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.link_enc_hw_init_params.link_enc = link_enc;
+ return bls_append(sequence, DIO_LINK_ENC_HW_INIT, &bls_params);
+}
+
+/* Without is_dig_enabled, dcn401_init_hw takes the DIG as disabled. */
+static bool dcn401_add_dig_read(struct block_sequence_state *sequence,
+ struct link_encoder *link_enc, bool *out_dig_enabled)
+{
+ union block_sequence_params bls_params = {0};
+
+ if (!link_enc || !link_enc->funcs || !link_enc->funcs->is_dig_enabled)
+ return true;
+ bls_params.link_enc_is_dig_enabled_params.link_enc = link_enc;
+ bls_params.link_enc_is_dig_enabled_params.out_dig_enabled =
+ out_dig_enabled;
+ return bls_append(sequence, DIO_LINK_ENC_IS_DIG_ENABLED, &bls_params);
+}
+
+static bool dcn401_add_fec_read(struct block_sequence_state *sequence,
+ struct link_encoder *link_enc, bool *out_fec_active)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.link_enc_fec_is_active_params.link_enc = link_enc;
+ bls_params.link_enc_fec_is_active_params.out_fec_active =
+ out_fec_active;
+ return bls_append(sequence, DIO_LINK_ENC_FEC_IS_ACTIVE, &bls_params);
+}
+
+static bool dcn401_add_i2c_info_read(struct block_sequence_state *sequence,
+ struct dc *dc, const struct dc_link *link,
+ struct graphics_object_i2c_info *out_info,
+ enum bp_result *out_result)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.bios_get_i2c_info_params.dcb = dc->ctx->dc_bios;
+ bls_params.bios_get_i2c_info_params.link_id = link->link_id;
+ bls_params.bios_get_i2c_info_params.out_info = out_info;
+ bls_params.bios_get_i2c_info_params.out_result = out_result;
+ return bls_append(sequence, BIOS_GET_I2C_INFO, &bls_params);
+}
+
+static bool dcn401_add_dentist_read(struct block_sequence_state *sequence,
+ struct clk_mgr *clk_mgr, int *out_dispclk_khz)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.clk_mgr_get_dispclk_from_dentist_params.clk_mgr = clk_mgr;
+ bls_params.clk_mgr_get_dispclk_from_dentist_params.out_dispclk_khz =
+ out_dispclk_khz;
+ return bls_append(sequence, CLK_MGR_GET_DISPCLK_FROM_DENTIST,
+ &bls_params);
+}
+
+static bool dcn401_add_edp_control(struct block_sequence_state *sequence,
+ enum block_sequence_func func, struct dc_link *link,
+ bool enable)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.edp_control_params.link = link;
+ bls_params.edp_control_params.enable = enable;
+ return bls_append(sequence, func, &bls_params);
+}
+
+static bool dcn401_add_self_refresh_control(
+ struct block_sequence_state *sequence, struct dc *dc)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.hubbub_allow_self_refresh_control_params.hubbub =
+ dc->res_pool->hubbub;
+ bls_params.hubbub_allow_self_refresh_control_params.allow =
+ !dc->debug.disable_stutter;
+ return bls_append(sequence, HUBBUB_ALLOW_SELF_REFRESH_CONTROL,
+ &bls_params);
+}
+
+/* The clocks dcn401_initialize_min_clocks requests, from software state. */
+static bool dcn401_add_min_clocks(struct block_sequence_state *sequence,
+ struct dc *dc, const struct bls_builder_legacy_hw_init_info *in)
+{
+ union block_sequence_params bls_params = {0};
+ struct clk_mgr_initialize_min_clocks_params *p =
+ &bls_params.clk_mgr_initialize_min_clocks_params;
+ struct clk_mgr *clk_mgr = dc->clk_mgr;
+ const struct clk_limit_table_entry *entry =
+ &clk_mgr->bw_params->clk_table.entries[0];
+
+ p->clk_mgr = clk_mgr;
+ p->context = dc->current_state;
+ p->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
+ p->dcfclk_khz = entry->dcfclk_mhz * 1000;
+ p->socclk_khz = entry->socclk_mhz * 1000;
+ p->dramclk_khz = entry->memclk_mhz * 1000;
+ p->dppclk_khz = entry->dppclk_mhz * 1000;
+ if (dc->debug.disable_boot_optimizations)
+ p->dispclk_khz = entry->dispclk_mhz * 1000;
+ else if (clk_mgr->funcs->get_dispclk_from_dentist)
+ /* Keep the current DISPCLK so a lit display keeps its timing. */
+ p->dispclk_khz = in->s6.dispclk_from_dentist_khz;
+ else
+ p->dispclk_khz = clk_mgr->boot_snapshot.dispclk;
+ p->ref_dtbclk_khz = entry->dtbclk_mhz * 1000;
+ p->fclk_p_state_change_support = true;
+ p->p_state_change_support = true;
+ return bls_append(sequence, LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS,
+ &bls_params);
+}
+
+static bool dcn401_add_audio_hw_init(struct block_sequence_state *sequence,
+ struct audio *audio)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.audio_hw_init_params.audio = audio;
+ return bls_append(sequence, AUDIO_HW_INIT, &bls_params);
+}
+
+static bool dcn401_add_panel_cntl_hw_init(
+ struct block_sequence_state *sequence,
+ struct panel_cntl *panel_cntl, uint32_t *out_backlight,
+ uint32_t *out_user_level)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.panel_cntl_hw_init_params.panel_cntl = panel_cntl;
+ bls_params.panel_cntl_hw_init_params.out_backlight = out_backlight;
+ bls_params.panel_cntl_hw_init_params.out_user_level = out_user_level;
+ return bls_append(sequence, PANEL_CNTL_HW_INIT, &bls_params);
+}
+
+static bool dcn401_add_ddc_open(struct block_sequence_state *sequence,
+ const struct dc_link *link,
+ const struct graphics_object_i2c_info *i2c_info)
+{
+ union block_sequence_params bls_params = {0};
+ struct gpio_ddc_open_params *p = &bls_params.gpio_ddc_open_params;
+
+ p->gpio_service = link->ctx->gpio_service;
+ p->clk_a_register_index = i2c_info->gpio_info.clk_a_register_index;
+ p->clk_a_mask = 1 << i2c_info->gpio_info.clk_a_shift;
+ p->hw_info.ddc_channel = i2c_info->i2c_line;
+ p->hw_info.hw_supported = i2c_info->i2c_hw_assist;
+ return bls_append(sequence, GPIO_DDC_OPEN, &bls_params);
+}
+
+/* dc_dmub_srv_ihc_set_dig_hdcp_interrupt_dest(dmub_srv, eng_id, true) */
+static bool dcn401_add_hdcp_interrupt_dest(
+ struct block_sequence_state *sequence, struct dc *dc,
+ const struct dc_link *link, union dmub_rb_cmd *cmd)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->ihc.header.type = DMUB_CMD__IHC;
+ cmd->ihc.header.sub_type = DMUB_CMD__IHC_SET_DIG_HDCP_INTERRUPT_DEST;
+ cmd->ihc.header.payload_bytes = sizeof(cmd->ihc.data);
+ cmd->ihc.data.dig_id = (uint8_t)link->eng_id;
+ cmd->ihc.data.to_dmu = 1;
+ return dcn401_add_dmub_cmd(sequence, dc->ctx, cmd,
+ DM_DMUB_WAIT_TYPE_WAIT, true);
+}
+
+static bool dcn401_add_abm_init(struct block_sequence_state *sequence,
+ struct abm *abm, const struct bls_builder_legacy_hw_init_info *in)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.abm_init_params.abm = abm;
+ bls_params.abm_init_params.backlight = in->s9.backlight;
+ bls_params.abm_init_params.user_level = in->s9.user_level;
+ return bls_append(sequence, ABM_INIT, &bls_params);
+}
+
+static bool dcn401_add_dio_mem_power(struct block_sequence_state *sequence,
+ struct dio *dio)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.dio_set_mem_power_params.dio = dio;
+ bls_params.dio_set_mem_power_params.enable = false;
+ return bls_append(sequence, DIO_AFMT_SET_MEM_POWER, &bls_params);
+}
+
+static bool dcn401_add_root_clock_gating(
+ struct block_sequence_state *sequence, struct dccg *dccg)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.dccg_set_root_clock_gating_params.dccg = dccg;
+ bls_params.dccg_set_root_clock_gating_params.allow = true;
+ return bls_append(sequence, DCCG_SET_ROOT_CLOCK_GATING, &bls_params);
+}
+
+static bool dcn401_add_init_watermarks(struct block_sequence_state *sequence,
+ struct hubbub *hubbub)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.hubbub_init_watermarks_params.hubbub = hubbub;
+ return bls_append(sequence, HUBBUB_INIT_WATERMARKS, &bls_params);
+}
+
+static bool dcn401_add_notify_wm_ranges(
+ struct block_sequence_state *sequence, struct clk_mgr *clk_mgr)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.clk_mgr_notify_wm_ranges_params.clk_mgr = clk_mgr;
+ return bls_append(sequence, LEGACY_CLK_MGR_NOTIFY_WM_RANGES,
+ &bls_params);
+}
+
+static bool dcn401_add_force_pstate(struct block_sequence_state *sequence,
+ struct hubbub *hubbub)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.hubbub_force_pstate_change_control_params.hubbub = hubbub;
+ bls_params.hubbub_force_pstate_change_control_params.enable = false;
+ bls_params.hubbub_force_pstate_change_control_params.allow = false;
+ return bls_append(sequence, HUBBUB_FORCE_PSTATE_CHANGE_CONTROL,
+ &bls_params);
+}
+
+static bool dcn401_add_init_crb(struct block_sequence_state *sequence,
+ struct hubbub *hubbub)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.hubbub_init_crb_params.hubbub = hubbub;
+ return bls_append(sequence, HUBBUB_INIT_CRB, &bls_params);
+}
+
+static bool dcn401_add_request_limit(struct block_sequence_state *sequence,
+ struct dc *dc)
+{
+ union block_sequence_params bls_params = {0};
+
+ bls_params.hubbub_set_request_limit_params.hubbub =
+ dc->res_pool->hubbub;
+ bls_params.hubbub_set_request_limit_params.num_chans =
+ dc->ctx->dc_bios->vram_info.num_chans;
+ bls_params.hubbub_set_request_limit_params.words_per_umc =
+ dc->config.sdpif_request_limit_words_per_umc;
+ return bls_append(sequence, HUBBUB_SET_REQUEST_LIMIT, &bls_params);
+}
+
+/*
+ * dc_dmub_srv_query_caps_cmd. The reply stays in the command; Core
+ * interprets it. The caps apply whether or not the query is sent.
+ */
+static bool dcn401_add_query_caps(struct block_sequence_state *sequence,
+ struct dc *dc, struct bls_builder_output_legacy_init_stage11 *out)
+{
+ struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
+
+ if (!dc_dmub_srv)
+ return true;
+ if (!dc_dmub_srv->dmub)
+ return false;
+ out->dmub_caps_read = true;
+ dcn401_fill_query_feature_caps_cmd(&out->dmub_query_feature_caps_cmd);
+ out->dmub_caps_query_sent = true;
+ return dcn401_add_dmub_cmd(sequence, dc->ctx,
+ &out->dmub_query_feature_caps_cmd,
+ DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY, true);
+}
+
+/* dc_dmub_srv_notify_fw_dc_power_state(dmub_srv, D0) */
+static bool dcn401_add_notify_power_state(
+ struct block_sequence_state *sequence, struct dc *dc,
+ union dmub_rb_cmd *cmd)
+{
+ if (!dcn401_dc1_has_dmub(dc))
+ return true;
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->idle_opt_set_dc_power_state.header.type = DMUB_CMD__IDLE_OPT;
+ cmd->idle_opt_set_dc_power_state.header.sub_type =
+ DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE;
+ cmd->idle_opt_set_dc_power_state.header.payload_bytes =
+ sizeof(cmd->idle_opt_set_dc_power_state) -
+ sizeof(cmd->idle_opt_set_dc_power_state.header);
+ cmd->idle_opt_set_dc_power_state.data.power_state =
+ DMUB_IDLE_OPT_DC_POWER_STATE_D0;
+ return dcn401_add_dmub_cmd(sequence, dc->ctx, cmd,
+ DM_DMUB_WAIT_TYPE_WAIT, true);
+}
+
+/*
+ * Power down on boot, eDP slot by slot. A slot reads its eDP's DIG only
+ * after the previous slot acted, since power_down can change it. With
+ * no eDP, slot 0 reads every PHY link and powers down once.
+ */
+static bool dcn401_add_boot_dig_read(struct dc *dc,
+ bool *out_edp_dig_enabled, bool *out_boot_dig_enabled,
+ struct block_sequence_state *sequence, unsigned int slot)
+{
+ struct dc_link *edp_links[MAX_NUM_EDP];
+ unsigned int edp_num;
+ unsigned int i;
+
+ if (dc->config.seamless_boot_edp_requested)
+ return true;
+ dc_get_edp_links(dc, edp_links, &edp_num);
+ if (edp_num)
+ return slot >= edp_num || dcn401_add_dig_read(sequence,
+ edp_links[slot]->link_enc, out_edp_dig_enabled);
+ if (slot)
+ return true;
+ for (i = 0; i < dc->link_count; i++)
+ if (dcn401_dc1_is_phy_link(dc->links[i]) &&
+ !dcn401_add_dig_read(sequence,
+ dc->links[i]->link_enc,
+ &out_boot_dig_enabled[i]))
+ return false;
+ return true;
+}
+
+static bool dcn401_add_boot_power_down(struct dc *dc,
+ bool edp_dig_enabled, const bool *boot_dig_enabled,
+ struct block_sequence_state *sequence, unsigned int slot)
+{
+ struct dc_link *edp_links[MAX_NUM_EDP];
+ struct dc_link *link;
+ unsigned int edp_num;
+ unsigned int i;
+
+ if (dc->config.seamless_boot_edp_requested ||
+ !dc->hwseq->funcs.power_down)
+ return true;
+ dc_get_edp_links(dc, edp_links, &edp_num);
+ if (edp_num) {
+ if (slot >= edp_num || !edp_dig_enabled ||
+ !dc->hwss.edp_backlight_control ||
+ !dc->hwss.edp_power_control)
+ return true;
+ link = edp_links[slot];
+ return dcn401_add_edp_control(sequence, EDP_BACKLIGHT_CONTROL,
+ link, false) &&
+ dcn401_add_dc_call(sequence, HWSEQ_POWER_DOWN, dc,
+ false) &&
+ dcn401_add_edp_control(sequence, EDP_POWER_CONTROL,
+ link, false);
+ }
+ if (slot)
+ return true;
+ for (i = 0; i < dc->link_count; i++)
+ if (boot_dig_enabled[i])
+ return dcn401_add_dc_call(sequence, HWSEQ_POWER_DOWN, dc,
+ false);
+ return true;
+}
+
+/*
+ * dcn401_init_hw call order, cut at each read a later stage depends on.
+ * funcs append through dcn401_dc1_add_step: per pipe for the looped
+ * calls, and nothing where dcn401_init_hw skips the call. link_funcs
+ * follow step-major: each link_func expands for every link before the
+ * next link_func. The BLC trace logs only enc401_hw_init per link, and
+ * the panel, DDC and HDCP calls program separate blocks. In funcs,
+ * DIO_LINK_ENC_IS_DIG_ENABLED and HWSEQ_POWER_DOWN are the power down
+ * on boot read and act of the stage's eDP slot, and DMUB_SEND_DMCUB_CMD
+ * is the stage's DMUB command.
+ */
+struct dcn401_dc1_stage_list {
+ const enum block_sequence_func *funcs;
+ unsigned int num_funcs;
+ const enum block_sequence_func *link_funcs;
+ unsigned int num_link_funcs;
+};
+
+static const enum block_sequence_func dcn401_dc1_clocks_stage[] = {
+ LEGACY_CLK_MGR_INIT_CLOCKS,
+ LEGACY_CLK_MGR_IS_DC_MODE_PRESENT,
+ DCCG_INITIALIZE_CLOCKS,
+ OPTC_SET_ODM_MEM_POWER,
+ MMHUBBUB_SET_MEM_POWER,
+ DCCG_GET_REF_FREQ,
+};
+
+static const enum block_sequence_func dcn401_dc1_dchub_ref_stage[] = {
+ HUBBUB_GET_DCHUB_REF_FREQ,
+};
+
+static const enum block_sequence_func dcn401_dc1_link_enc_loop[] = {
+ DIO_LINK_ENC_HW_INIT,
+ DIO_LINK_ENC_IS_DIG_ENABLED,
+ BIOS_GET_I2C_INFO,
+};
+
+static const enum block_sequence_func dcn401_dc1_fec_loop[] = {
+ DIO_LINK_ENC_FEC_IS_ACTIVE,
+};
+
+static const enum block_sequence_func dcn401_dc1_blank_stage[] = {
+ PG_SET_PLANE_POWER_GATING,
+ LINK_BLANK_ALL_DP_DISPLAYS,
+ BIOS_IS_ACCELERATED_MODE,
+};
+
+static const enum block_sequence_func dcn401_dc1_power_down_stage[] = {
+ HWSS_ENABLE_ACCELERATED_MODE,
+ HWSEQ_INIT_PIPES,
+ HUBBUB_ALLOW_SELF_REFRESH_CONTROL,
+ CLK_MGR_GET_DISPCLK_FROM_DENTIST,
+};
+
+static const enum block_sequence_func dcn401_dc1_min_clocks_stage[] = {
+ LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS,
+ DMUB_SET_IDLE_OPTIMIZATION,
+ DIO_LINK_ENC_IS_DIG_ENABLED,
+};
+
+static const enum block_sequence_func dcn401_dc1_power_down_edp0_stage[] = {
+ HWSEQ_POWER_DOWN,
+ DIO_LINK_ENC_IS_DIG_ENABLED,
+};
+
+static const enum block_sequence_func dcn401_dc1_power_down_edp1_stage[] = {
+ HWSEQ_POWER_DOWN,
+ AUDIO_HW_INIT,
+};
+
+static const enum block_sequence_func dcn401_dc1_panel_loop[] = {
+ PANEL_CNTL_HW_INIT,
+ GPIO_DDC_OPEN,
+ DMUB_SEND_DMCUB_CMD,
+};
+
+static const enum block_sequence_func dcn401_dc1_gating_stage[] = {
+ ABM_INIT,
+ DIO_AFMT_SET_MEM_POWER,
+ DCCG_SET_ROOT_CLOCK_GATING,
+ DCCG_SET_DCFCLK_GATING,
+ HPO_SET_HW_CONTROL,
+ BIOS_IS_ACCELERATED_MODE,
+};
+
+static const enum block_sequence_func dcn401_dc1_hubbub_stage[] = {
+ HUBBUB_INIT_WATERMARKS,
+ LEGACY_CLK_MGR_NOTIFY_WM_RANGES,
+ HUBBUB_FORCE_PSTATE_CHANGE_CONTROL,
+ HUBBUB_INIT_CRB,
+ HUBBUB_SET_REQUEST_LIMIT,
+ DMUB_SEND_DMCUB_CMD,
+};
+
+static const enum block_sequence_func dcn401_dc1_power_state_stage[] = {
+ DMUB_SEND_DMCUB_CMD,
+};
+
+#define DCN401_DC1_STAGE(list) { list, ARRAY_SIZE(list), NULL, 0 }
+#define DCN401_DC1_LINK_STAGE(loop) { NULL, 0, loop, ARRAY_SIZE(loop) }
+#define DCN401_DC1_LOOP_STAGE(list, loop) \
+ { list, ARRAY_SIZE(list), loop, ARRAY_SIZE(loop) }
+
+static const struct dcn401_dc1_stage_list
+ dcn401_dc1_stages[LEGACY_INIT_STAGE_COUNT + 1] = {
+ [LEGACY_INIT_STAGE_CLOCKS] = DCN401_DC1_STAGE(dcn401_dc1_clocks_stage),
+ [LEGACY_INIT_STAGE_DCHUB_REF] =
+ DCN401_DC1_STAGE(dcn401_dc1_dchub_ref_stage),
+ [LEGACY_INIT_STAGE_LINK_ENC] =
+ DCN401_DC1_LINK_STAGE(dcn401_dc1_link_enc_loop),
+ [LEGACY_INIT_STAGE_FEC] = DCN401_DC1_LINK_STAGE(dcn401_dc1_fec_loop),
+ [LEGACY_INIT_STAGE_BLANK] = DCN401_DC1_STAGE(dcn401_dc1_blank_stage),
+ [LEGACY_INIT_STAGE_POWER_DOWN] =
+ DCN401_DC1_STAGE(dcn401_dc1_power_down_stage),
+ [LEGACY_INIT_STAGE_MIN_CLOCKS] =
+ DCN401_DC1_STAGE(dcn401_dc1_min_clocks_stage),
+ [LEGACY_INIT_STAGE_POWER_DOWN_EDP0] =
+ DCN401_DC1_STAGE(dcn401_dc1_power_down_edp0_stage),
+ [LEGACY_INIT_STAGE_POWER_DOWN_EDP1] =
+ DCN401_DC1_LOOP_STAGE(dcn401_dc1_power_down_edp1_stage,
+ dcn401_dc1_panel_loop),
+ [LEGACY_INIT_STAGE_GATING] = DCN401_DC1_STAGE(dcn401_dc1_gating_stage),
+ [LEGACY_INIT_STAGE_HUBBUB] = DCN401_DC1_STAGE(dcn401_dc1_hubbub_stage),
+ [LEGACY_INIT_STAGE_POWER_STATE] =
+ DCN401_DC1_STAGE(dcn401_dc1_power_state_stage),
+};
+
+static bool dcn401_dc1_add_link_step(struct dc *dc,
+ const struct bls_builder_legacy_hw_init_info *in,
+ struct bls_builder_legacy_hw_init_info *out,
+ struct block_sequence_state *sequence,
+ enum block_sequence_func func, unsigned int i)
+{
+ const struct dc_link *link = dc->links[i];
+
+ switch (func) {
+ case DIO_LINK_ENC_HW_INIT:
+ return !dcn401_dc1_is_phy_link(link) ||
+ dcn401_add_link_enc_hw_init(sequence,
+ link->link_enc);
+ case DIO_LINK_ENC_IS_DIG_ENABLED:
+ return !dcn401_dc1_is_phy_link(link) ||
+ dcn401_add_dig_read(sequence, link->link_enc,
+ &out->s3.link_dig_enabled[i]);
+ case BIOS_GET_I2C_INFO:
+ return !link->force_to_use_aux ||
+ dcn401_add_i2c_info_read(sequence, dc, link,
+ &out->s3.link_i2c_info[i],
+ &out->s3.link_i2c_result[i]);
+ case DIO_LINK_ENC_FEC_IS_ACTIVE:
+ return !dcn401_dc1_is_phy_link(link) ||
+ !in->s3.link_dig_enabled[i] ||
+ !link->link_enc->funcs->fec_is_active ||
+ dcn401_add_fec_read(sequence, link->link_enc,
+ &out->s4.link_fec_active[i]);
+ case PANEL_CNTL_HW_INIT:
+ return !link->panel_cntl ||
+ dcn401_add_panel_cntl_hw_init(sequence,
+ link->panel_cntl, &out->s9.backlight,
+ &out->s9.user_level);
+ case GPIO_DDC_OPEN:
+ return !link->force_to_use_aux ||
+ in->s3.link_i2c_result[i] != BP_RESULT_OK ||
+ dcn401_add_ddc_open(sequence, link,
+ &in->s3.link_i2c_info[i]);
+ case DMUB_SEND_DMCUB_CMD:
+ /* Sent whatever the I2C info read returned. */
+ return !link->force_to_use_aux || !dcn401_dc1_has_dmub(dc) ||
+ dcn401_add_hdcp_interrupt_dest(sequence, dc, link,
+ &out->s9.dmub_ihc_cmd[i]);
+ default:
+ return false;
+ }
+}
+
+static bool dcn401_dc1_add_step(struct dc *dc,
+ const struct bls_builder_legacy_hw_init_info *in,
+ struct bls_builder_legacy_hw_init_info *out,
+ struct block_sequence_state *sequence,
+ enum block_sequence_func func)
+{
+ struct resource_pool *pool = dc->res_pool;
+ struct clk_mgr *clk_mgr = dc->clk_mgr;
+ struct hubbub *hubbub = pool->hubbub;
+ bool has_init_clocks = clk_mgr && clk_mgr->funcs &&
+ clk_mgr->funcs->init_clocks;
+ unsigned int i;
+
+ switch (func) {
+ case LEGACY_CLK_MGR_INIT_CLOCKS:
+ return !has_init_clocks ||
+ dcn401_build_clk_mgr_init(clk_mgr, sequence) ==
+ BLS_BUILD_SUCCESS;
+ case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT:
+ /* Without the callback the limits stay not present. */
+ return !has_init_clocks ||
+ !clk_mgr->funcs->is_dc_mode_present ||
+ dcn401_build_dc_mode_read(clk_mgr,
+ &out->s1.dcmode_power_limits_present,
+ sequence) == BLS_BUILD_SUCCESS;
+ case DCCG_INITIALIZE_CLOCKS:
+ return !pool->dccg->funcs->dccg_init ||
+ dcn401_build_dccg_init(pool->dccg, sequence) ==
+ BLS_BUILD_SUCCESS;
+ case OPTC_SET_ODM_MEM_POWER:
+ return !dc->debug.enable_mem_low_power.bits.optc ||
+ dcn401_add_hwseq_reg(sequence, func, dc->hwseq,
+ true);
+ case MMHUBBUB_SET_MEM_POWER:
+ return !dc->debug.enable_mem_low_power.bits.vga ||
+ dcn401_add_hwseq_reg(sequence, func, dc->hwseq,
+ true);
+ case DCCG_GET_REF_FREQ:
+ if (!dc->ctx->dc_bios->fw_info_valid) {
+ ASSERT_CRITICAL(false);
+ return true;
+ }
+ return dcn401_add_dccg_ref_freq(sequence, dc, &out->s1);
+ case HUBBUB_GET_DCHUB_REF_FREQ:
+ return !dc->ctx->dc_bios->fw_info_valid ||
+ dcn401_add_dchub_ref_freq(sequence, dc, &out->s2);
+ case PG_SET_PLANE_POWER_GATING:
+ return !dc->hwseq->funcs.enable_power_gating_plane ||
+ dcn401_add_hwseq_reg(sequence, func, dc->hwseq,
+ true);
+ case LINK_BLANK_ALL_DP_DISPLAYS:
+ return dcn401_add_dc_call(sequence, func, dc, false);
+ case BIOS_IS_ACCELERATED_MODE:
+ return dcn401_add_accelerated_mode_read(sequence, dc,
+ in->next_stage == LEGACY_INIT_STAGE_BLANK ?
+ &out->s5.accelerated_mode :
+ &out->s10.accelerated_mode);
+ case HWSS_ENABLE_ACCELERATED_MODE:
+ return !dcn401_dc1_powers_down_pipes(dc, in) ||
+ !dcn401_dc1_uses_accelerated_mode(dc) ||
+ dcn401_add_dc_call(sequence, func, dc, false);
+ case HWSEQ_INIT_PIPES:
+ return !dcn401_dc1_powers_down_pipes(dc, in) ||
+ dcn401_dc1_uses_accelerated_mode(dc) ||
+ dcn401_add_dc_call(sequence, func, dc, false);
+ case HUBBUB_ALLOW_SELF_REFRESH_CONTROL:
+ return !dcn401_dc1_powers_down_pipes(dc, in) ||
+ !hubbub->funcs->allow_self_refresh_control ||
+ dcn401_add_self_refresh_control(sequence, dc);
+ case CLK_MGR_GET_DISPCLK_FROM_DENTIST:
+ return !dcn401_dc1_powers_down_pipes(dc, in) ||
+ dc->debug.disable_boot_optimizations ||
+ !clk_mgr || !clk_mgr->funcs ||
+ !clk_mgr->funcs->get_dispclk_from_dentist ||
+ dcn401_add_dentist_read(sequence, clk_mgr,
+ &out->s6.dispclk_from_dentist_khz);
+ case LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS:
+ return !dcn401_dc1_powers_down_pipes(dc, in) ||
+ dcn401_add_min_clocks(sequence, dc, in);
+ case DMUB_SET_IDLE_OPTIMIZATION:
+ /*
+ * Off, then on: in BOCO / BOMACO the hardware can be reset
+ * while software still has idle optimizations allowed.
+ */
+ return !dcn401_dc1_powers_down_pipes(dc, in) ||
+ (dcn401_add_dc_call(sequence, func, dc, false) &&
+ dcn401_add_dc_call(sequence, func, dc, true));
+ case DIO_LINK_ENC_IS_DIG_ENABLED:
+ if (in->next_stage == LEGACY_INIT_STAGE_MIN_CLOCKS)
+ return dcn401_add_boot_dig_read(dc,
+ &out->s7.edp_dig_enabled,
+ out->s7.boot_dig_enabled, sequence, 0);
+ return dcn401_add_boot_dig_read(dc, &out->s8.edp_dig_enabled,
+ NULL, sequence, 1);
+ case HWSEQ_POWER_DOWN:
+ if (in->next_stage == LEGACY_INIT_STAGE_POWER_DOWN_EDP0)
+ return dcn401_add_boot_power_down(dc,
+ in->s7.edp_dig_enabled,
+ in->s7.boot_dig_enabled, sequence, 0);
+ return dcn401_add_boot_power_down(dc, in->s8.edp_dig_enabled,
+ NULL, sequence, 1);
+ case AUDIO_HW_INIT:
+ for (i = 0; i < pool->audio_count; i++)
+ if (!dcn401_add_audio_hw_init(sequence, pool->audios[i]))
+ return false;
+ return true;
+ case ABM_INIT:
+ for (i = 0; i < pool->pipe_count; i++) {
+ struct abm *abm = pool->multiple_abms[i];
+
+ if (abm && abm->funcs &&
+ !dcn401_add_abm_init(sequence, abm, in))
+ return false;
+ }
+ return true;
+ case DIO_AFMT_SET_MEM_POWER:
+ return !pool->dio || !pool->dio->funcs->mem_pwr_ctrl ||
+ dcn401_add_dio_mem_power(sequence, pool->dio);
+ case DCCG_SET_ROOT_CLOCK_GATING:
+ return dc->debug.disable_clock_gate ||
+ !pool->dccg->funcs->allow_clock_gating ||
+ dcn401_add_root_clock_gating(sequence, pool->dccg);
+ case DCCG_SET_DCFCLK_GATING:
+ return dc->debug.disable_clock_gate ||
+ dcn401_add_hwseq_reg(sequence, func, dc->hwseq,
+ true);
+ case HPO_SET_HW_CONTROL:
+ return dcn401_add_hwseq_reg(sequence, func, dc->hwseq, true);
+ case HUBBUB_INIT_WATERMARKS:
+ return in->s10.accelerated_mode ||
+ !hubbub->funcs->init_watermarks ||
+ dcn401_add_init_watermarks(sequence, hubbub);
+ case LEGACY_CLK_MGR_NOTIFY_WM_RANGES:
+ return !clk_mgr || !clk_mgr->funcs ||
+ !clk_mgr->funcs->notify_wm_ranges ||
+ dcn401_add_notify_wm_ranges(sequence, clk_mgr);
+ case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL:
+ return !hubbub->funcs->force_pstate_change_control ||
+ dcn401_add_force_pstate(sequence, hubbub);
+ case HUBBUB_INIT_CRB:
+ return !hubbub->funcs->init_crb ||
+ dcn401_add_init_crb(sequence, hubbub);
+ case HUBBUB_SET_REQUEST_LIMIT:
+ return !hubbub->funcs->set_request_limit ||
+ dc->config.sdpif_request_limit_words_per_umc == 0 ||
+ dcn401_add_request_limit(sequence, dc);
+ case DMUB_SEND_DMCUB_CMD:
+ if (in->next_stage == LEGACY_INIT_STAGE_POWER_STATE)
+ return dcn401_add_notify_power_state(sequence, dc,
+ &out->s12.dmub_power_state_cmd);
+ return dcn401_add_query_caps(sequence, dc, &out->s11);
+ default:
+ return false;
+ }
+}
+
+static bool dcn401_dc1_add_stage(struct dc *dc,
+ const struct bls_builder_legacy_hw_init_info *in,
+ struct bls_builder_legacy_hw_init_info *out,
+ struct block_sequence_state *sequence)
+{
+ const struct dcn401_dc1_stage_list *stage =
+ &dcn401_dc1_stages[in->next_stage];
+ unsigned int i, j;
+
+ for (i = 0; i < stage->num_funcs; i++)
+ if (!dcn401_dc1_add_step(dc, in, out, sequence,
+ stage->funcs[i]))
+ return false;
+ if (!stage->num_link_funcs)
+ return true;
+ for (j = 0; j < stage->num_link_funcs; j++)
+ for (i = 0; i < dc->link_count; i++)
+ if (!dcn401_dc1_add_link_step(dc, in, out, sequence,
+ stage->link_funcs[j], i))
+ return false;
+
+ return true;
+}
+
+/*
+ * Seed the stage output with the values its reads leave in place when
+ * they are skipped: the current reference clocks, the default
+ * backlight and no I2C info.
+ */
+static void dcn401_dc1_seed_stage_output(struct dc *dc,
+ struct bls_builder_legacy_hw_init_info *out, unsigned int stage)
+{
+ const struct resource_pool *pool = dc->res_pool;
+ unsigned int i;
+
+ switch (stage) {
+ case LEGACY_INIT_STAGE_CLOCKS:
+ memset(&out->s1, 0, sizeof(out->s1));
+ out->s1.xtalin_clock_inKhz = pool->ref_clocks.xtalin_clock_inKhz;
+ out->s1.dccg_ref_clock_inKhz =
+ pool->ref_clocks.dccg_ref_clock_inKhz;
+ break;
+ case LEGACY_INIT_STAGE_DCHUB_REF:
+ memset(&out->s2, 0, sizeof(out->s2));
+ out->s2.dchub_ref_clock_inKhz =
+ pool->ref_clocks.dchub_ref_clock_inKhz;
+ break;
+ case LEGACY_INIT_STAGE_LINK_ENC:
+ memset(&out->s3, 0, sizeof(out->s3));
+ for (i = 0; i < MAX_LINKS; i++)
+ out->s3.link_i2c_result[i] = BP_RESULT_NORECORD;
+ break;
+ case LEGACY_INIT_STAGE_FEC:
+ memset(&out->s4, 0, sizeof(out->s4));
+ break;
+ case LEGACY_INIT_STAGE_BLANK:
+ memset(&out->s5, 0, sizeof(out->s5));
+ break;
+ case LEGACY_INIT_STAGE_POWER_DOWN:
+ memset(&out->s6, 0, sizeof(out->s6));
+ break;
+ case LEGACY_INIT_STAGE_MIN_CLOCKS:
+ memset(&out->s7, 0, sizeof(out->s7));
+ break;
+ case LEGACY_INIT_STAGE_POWER_DOWN_EDP0:
+ memset(&out->s8, 0, sizeof(out->s8));
+ break;
+ case LEGACY_INIT_STAGE_POWER_DOWN_EDP1:
+ memset(&out->s9, 0, sizeof(out->s9));
+ out->s9.backlight = MAX_BACKLIGHT_LEVEL;
+ out->s9.user_level = MAX_BACKLIGHT_LEVEL;
+ break;
+ case LEGACY_INIT_STAGE_GATING:
+ memset(&out->s10, 0, sizeof(out->s10));
+ break;
+ case LEGACY_INIT_STAGE_HUBBUB:
+ memset(&out->s11, 0, sizeof(out->s11));
+ break;
+ case LEGACY_INIT_STAGE_POWER_STATE:
+ memset(&out->s12, 0, sizeof(out->s12));
+ break;
+ }
+}
+
+enum bls_builder_result dcn401_build_dc1_initialization(
+ struct bls_builder_declarative_params *params)
+{
+ const struct bls_builder_legacy_hw_init_info *in;
+ struct bls_builder_legacy_hw_init_info *out;
+ struct block_sequence_state sequence;
+ enum bls_builder_result result;
+ struct dc *dc;
+
+ if (!params)
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+ params->head_num_steps = 0;
+ params->tail_num_steps = 0;
+ result = dcn401_validate_dc1_initialization(params);
+ if (result != BLS_BUILD_SUCCESS)
+ return result;
+
+ dc = params->dc;
+ in = &params->current_state->hw_init_info;
+ out = params->out_targets->DCN_DECL_INITIALIZATION_LEGACY;
+ sequence.steps = params->head_sequence;
+ sequence.num_steps = &params->head_num_steps;
+
+ /* Virtual hardware only notifies DMUB of the power state. */
+ if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW) {
+ dcn401_dc1_seed_stage_output(dc, out,
+ LEGACY_INIT_STAGE_POWER_STATE);
+ if (!dcn401_add_notify_power_state(&sequence, dc,
+ &out->s12.dmub_power_state_cmd))
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+ out->next_stage = LEGACY_INIT_STAGE_COUNT + 1;
+ out->init_done = true;
+ return BLS_BUILD_SUCCESS;
+ }
+
+ dcn401_dc1_seed_stage_output(dc, out, in->next_stage);
+ if (!dcn401_dc1_add_stage(dc, in, out, &sequence)) {
+ params->head_num_steps = 0;
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+ }
+ out->next_stage = in->next_stage + 1;
+ out->init_done = in->next_stage == LEGACY_INIT_STAGE_COUNT;
+
+ return BLS_BUILD_SUCCESS;
+}
+
+bool dcn401_dc1_initialization_check_capability(
+ const struct bls_builder_check_capability_params *params)
+{
+ return params && params->dc && params->dc->ctx &&
+ params->dc->res_pool;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.h b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.h
new file mode 100644
index 000000000000..71a1cdb46527
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "bls_builder/bls_builder.h"
+
+/*
+ * DC2_DC1_Wrapped: build stage params->current_state->hw_init_info
+ * .next_stage of dcn401_init_hw into the head sequence. The stage
+ * outputs land in out_targets->DCN_DECL_INITIALIZATION_LEGACY.
+ */
+enum bls_builder_result dcn401_build_dc1_initialization(
+ struct bls_builder_declarative_params *params);
+bool dcn401_dc1_initialization_check_capability(
+ const struct bls_builder_check_capability_params *params);
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dmub_abi.h b/drivers/gpu/drm/amd/display/dc/bls_builder/dmub_abi.h
new file mode 100644
index 000000000000..1a51af6da94b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dmub_abi.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "dmub_cmd.h"
+
+struct dmub_abi {
+ unsigned int fw_version;
+ struct dmub_feature_caps feature_caps;
+};
diff --git a/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c
new file mode 100644
index 000000000000..7600954c3478
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c
@@ -0,0 +1,703 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ */
+
+#include "dm_services.h"
+#include "clk_mgr.h"
+#include "dccg.h"
+#include "core_types.h"
+#include "dc_dmub_srv.h"
+#include "dmub_cmd.h"
+#include "abm.h"
+#include "audio.h"
+#include "dchubbub.h"
+#include "dio.h"
+#include "link_encoder.h"
+#include "panel_cntl.h"
+#include "link_service.h"
+#include "dc_bios_types.h"
+#include "gpio_service_interface.h"
+#include "hwss/hw_sequencer_private.h"
+#include "bls_executor/bls_executor.h"
+#include "dmub_messenger/dmub_messenger.h"
+
+static noinline_for_stack bool dc2_bls_step_supported(const struct dc2 *dc2,
+ const struct block_sequence *step)
+{
+ const struct dc *dc = dc2 ? &dc2->dc : NULL;
+ struct dmub_srv *dmub;
+ struct clk_mgr *clk_mgr;
+ struct dccg *dccg;
+ struct dc_context *ctx;
+
+ switch (step->func) {
+ case LEGACY_CLK_MGR_INIT_CLOCKS:
+ clk_mgr =
+ step->params.legacy_clk_mgr_init_clocks_params.clk_mgr;
+ return clk_mgr && clk_mgr->funcs &&
+ clk_mgr->funcs->init_clocks;
+ case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT:
+ clk_mgr = step->params
+ .legacy_clk_mgr_is_dc_mode_present_params.clk_mgr;
+ return clk_mgr && clk_mgr->funcs &&
+ clk_mgr->funcs->is_dc_mode_present &&
+ step->params
+ .legacy_clk_mgr_is_dc_mode_present_params
+ .out_dcmode_power_limits_present;
+ case DCCG_INITIALIZE_CLOCKS:
+ dccg = step->params.dccg_initialize_clocks_params.dccg;
+ return dccg && dccg->funcs && dccg->funcs->dccg_init;
+ case DMUB_SEND_DMCUB_CMD:
+ ctx = step->params.send_dmcub_cmd_params.ctx;
+ if (!ctx || !ctx->dmub_srv || !ctx->dmub_srv->dmub ||
+ !step->params.send_dmcub_cmd_params.cmd ||
+ (ctx->dmub_srv->idle_allowed && !ctx->dc))
+ return false;
+ return true;
+ case DMUB_GPINT_SEND_AND_WAIT:
+ case DMUB_HALT_FW:
+ if (!dc || !dc->ctx || !dc->ctx->dmub_srv ||
+ !dc->ctx->dmub_srv->dmub ||
+ (dc->ctx->dmub_srv->idle_allowed &&
+ !dc->ctx->dc))
+ return false;
+ dmub = dc->ctx->dmub_srv->dmub;
+ return dmub->sw_init && dmub->hw_funcs.set_gpint &&
+ dmub->hw_funcs.is_gpint_acked &&
+ dmub->hw_funcs.get_gpint_response &&
+ step->params.dmub_gpint_params.response;
+ case PSP_RELOAD_DMUB_FW: {
+ const struct dmub_srv_hw_params *hw_params =
+ step->params.psp_reload_dmub_fw_params.hw_params;
+
+ return step->params.psp_reload_dmub_fw_params.dmub &&
+ hw_params && hw_params->fb_info &&
+ hw_params->fb_info->num_fb >= DMUB_WINDOW_TOTAL;
+ }
+ case DMUB_INITIALIZE_DCN:
+ ctx = step->params.send_dmcub_cmd_params.ctx;
+ if (!ctx || !ctx->dmub_srv || !ctx->dmub_srv->dmub ||
+ !step->params.send_dmcub_cmd_params.cmd ||
+ !step->params.send_dmcub_cmd_params.cmd->cmd_common
+ .header.type ||
+ (ctx->dmub_srv->idle_allowed && !ctx->dc))
+ return false;
+ return true;
+ case OPTC_SET_ODM_MEM_POWER: {
+ struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws;
+
+ return hws && hws->funcs.init_odm_mem_power;
+ }
+ case MMHUBBUB_SET_MEM_POWER: {
+ struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws;
+
+ return hws && hws->funcs.power_down_vga_mem;
+ }
+ case DCCG_SET_DCFCLK_GATING: {
+ struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws;
+
+ return hws && hws->funcs.dcfclk_gating_control;
+ }
+ case HPO_SET_HW_CONTROL: {
+ struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws;
+
+ return hws && hws->funcs.init_hpo_hw_control;
+ }
+ case PG_SET_PLANE_POWER_GATING: {
+ struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws;
+
+ return hws && hws->funcs.enable_power_gating_plane;
+ }
+ case DCCG_GET_REF_FREQ: {
+ const struct dccg_get_ref_freq_params *p =
+ &step->params.dccg_get_ref_freq_params;
+
+ return p->dccg && p->dccg->funcs &&
+ p->dccg->funcs->get_dccg_ref_freq &&
+ p->out_xtalin_khz && p->out_dccg_ref_khz;
+ }
+ case HUBBUB_GET_DCHUB_REF_FREQ: {
+ const struct hubbub_get_dchub_ref_freq_params *p =
+ &step->params.hubbub_get_dchub_ref_freq_params;
+
+ return p->hubbub && p->hubbub->funcs &&
+ p->hubbub->funcs->get_dchub_ref_freq &&
+ p->out_dchub_ref_khz;
+ }
+ case DIO_LINK_ENC_HW_INIT: {
+ struct link_encoder *enc =
+ step->params.link_enc_hw_init_params.link_enc;
+
+ return enc && enc->funcs && enc->funcs->hw_init;
+ }
+ case DIO_LINK_ENC_IS_DIG_ENABLED: {
+ const struct link_enc_is_dig_enabled_params *p =
+ &step->params.link_enc_is_dig_enabled_params;
+
+ return p->link_enc && p->link_enc->funcs &&
+ p->link_enc->funcs->is_dig_enabled &&
+ p->out_dig_enabled;
+ }
+ case DIO_LINK_ENC_FEC_IS_ACTIVE: {
+ const struct link_enc_fec_is_active_params *p =
+ &step->params.link_enc_fec_is_active_params;
+
+ return p->link_enc && p->link_enc->funcs &&
+ p->link_enc->funcs->fec_is_active &&
+ p->out_fec_active;
+ }
+ case BIOS_GET_I2C_INFO: {
+ const struct bios_get_i2c_info_params *p =
+ &step->params.bios_get_i2c_info_params;
+
+ return p->dcb && p->dcb->funcs && p->dcb->funcs->get_i2c_info &&
+ p->out_info && p->out_result;
+ }
+ case CLK_MGR_GET_DISPCLK_FROM_DENTIST: {
+ const struct clk_mgr_get_dispclk_from_dentist_params *p =
+ &step->params.clk_mgr_get_dispclk_from_dentist_params;
+
+ return p->clk_mgr && p->clk_mgr->funcs &&
+ p->clk_mgr->funcs->get_dispclk_from_dentist &&
+ p->out_dispclk_khz;
+ }
+ case EDP_BACKLIGHT_CONTROL: {
+ struct dc_link *link = step->params.edp_control_params.link;
+
+ return link && link->dc && link->dc->hwss.edp_backlight_control;
+ }
+ case EDP_POWER_CONTROL: {
+ struct dc_link *link = step->params.edp_control_params.link;
+
+ return link && link->dc && link->dc->hwss.edp_power_control;
+ }
+ case LINK_BLANK_ALL_DP_DISPLAYS: {
+ struct dc *init_dc = step->params.dc_init_call_params.dc;
+
+ return init_dc && init_dc->link_srv &&
+ init_dc->link_srv->blank_all_dp_displays;
+ }
+ case HWSS_ENABLE_ACCELERATED_MODE: {
+ struct dc *init_dc = step->params.dc_init_call_params.dc;
+
+ return init_dc && init_dc->hwss.enable_accelerated_mode;
+ }
+ case HWSEQ_INIT_PIPES: {
+ struct dc *init_dc = step->params.dc_init_call_params.dc;
+
+ return init_dc && init_dc->hwseq &&
+ init_dc->hwseq->funcs.init_pipes;
+ }
+ case DMUB_SET_IDLE_OPTIMIZATION:
+ return step->params.dc_init_call_params.dc != NULL;
+ case HWSEQ_POWER_DOWN: {
+ struct dc *init_dc = step->params.dc_init_call_params.dc;
+
+ return init_dc && init_dc->hwseq &&
+ init_dc->hwseq->funcs.power_down;
+ }
+ case HUBBUB_ALLOW_SELF_REFRESH_CONTROL: {
+ struct hubbub *hubbub = step->params
+ .hubbub_allow_self_refresh_control_params.hubbub;
+
+ return hubbub && hubbub->funcs &&
+ hubbub->funcs->allow_self_refresh_control;
+ }
+ case LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS: {
+ const struct clk_mgr_initialize_min_clocks_params *p =
+ &step->params.clk_mgr_initialize_min_clocks_params;
+
+ return p->clk_mgr && p->clk_mgr->funcs &&
+ p->clk_mgr->funcs->update_clocks && p->context;
+ }
+ case AUDIO_HW_INIT: {
+ struct audio *audio = step->params.audio_hw_init_params.audio;
+
+ return audio && audio->funcs && audio->funcs->hw_init;
+ }
+ case PANEL_CNTL_HW_INIT: {
+ const struct panel_cntl_hw_init_params *p =
+ &step->params.panel_cntl_hw_init_params;
+
+ return p->panel_cntl && p->panel_cntl->funcs &&
+ p->panel_cntl->funcs->hw_init &&
+ p->out_backlight && p->out_user_level;
+ }
+ case GPIO_DDC_OPEN:
+ return step->params.gpio_ddc_open_params.gpio_service != NULL;
+ case ABM_INIT: {
+ const struct abm_init_params *p = &step->params.abm_init_params;
+
+ return p->abm && p->abm->funcs && p->abm->funcs->abm_init;
+ }
+ case DIO_AFMT_SET_MEM_POWER: {
+ struct dio *dio = step->params.dio_set_mem_power_params.dio;
+
+ return dio && dio->funcs && dio->funcs->mem_pwr_ctrl;
+ }
+ case DCCG_SET_ROOT_CLOCK_GATING: {
+ struct dccg *gating_dccg =
+ step->params.dccg_set_root_clock_gating_params.dccg;
+
+ return gating_dccg && gating_dccg->funcs &&
+ gating_dccg->funcs->allow_clock_gating;
+ }
+ case HUBBUB_INIT_WATERMARKS: {
+ const struct hubbub_init_watermarks_params *p =
+ &step->params.hubbub_init_watermarks_params;
+
+ return p->hubbub && p->hubbub->funcs &&
+ p->hubbub->funcs->init_watermarks;
+ }
+ case BIOS_IS_ACCELERATED_MODE: {
+ const struct bios_is_accelerated_mode_params *p =
+ &step->params.bios_is_accelerated_mode_params;
+
+ return p->dcb && p->dcb->funcs &&
+ p->dcb->funcs->is_accelerated_mode &&
+ p->out_accelerated_mode;
+ }
+ case LEGACY_CLK_MGR_NOTIFY_WM_RANGES:
+ clk_mgr = step->params.clk_mgr_notify_wm_ranges_params.clk_mgr;
+ return clk_mgr && clk_mgr->funcs &&
+ clk_mgr->funcs->notify_wm_ranges;
+ case HUBBUB_INIT_CRB: {
+ struct hubbub *hubbub =
+ step->params.hubbub_init_crb_params.hubbub;
+
+ return hubbub && hubbub->funcs && hubbub->funcs->init_crb;
+ }
+ case HUBBUB_SET_REQUEST_LIMIT: {
+ struct hubbub *hubbub =
+ step->params.hubbub_set_request_limit_params.hubbub;
+
+ return hubbub && hubbub->funcs &&
+ hubbub->funcs->set_request_limit;
+ }
+ case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL: {
+ struct hubbub *hubbub = step->params
+ .hubbub_force_pstate_change_control_params.hubbub;
+
+ return hubbub && hubbub->funcs &&
+ hubbub->funcs->force_pstate_change_control;
+ }
+ default:
+ return false;
+ }
+}
+
+static noinline_for_stack void dc2_bls_exec_initialize_min_clocks(
+ const struct clk_mgr_initialize_min_clocks_params *p)
+{
+ struct dc_clocks *clocks = &p->context->bw_ctx.bw.dcn.clk;
+
+ clocks->dcfclk_deep_sleep_khz = p->dcfclk_deep_sleep_khz;
+ clocks->dcfclk_khz = p->dcfclk_khz;
+ clocks->socclk_khz = p->socclk_khz;
+ clocks->dramclk_khz = p->dramclk_khz;
+ clocks->dppclk_khz = p->dppclk_khz;
+ clocks->dispclk_khz = p->dispclk_khz;
+ clocks->ref_dtbclk_khz = p->ref_dtbclk_khz;
+ clocks->fclk_p_state_change_support = p->fclk_p_state_change_support;
+ clocks->p_state_change_support = p->p_state_change_support;
+
+ p->clk_mgr->funcs->update_clocks(p->clk_mgr, p->context, true);
+}
+
+static noinline_for_stack enum dc2_bls_exec_result dc2_bls_exec_dmub_send(
+ const struct block_sequence *entry)
+{
+ struct dmub_messenger messenger;
+ struct dmub_messenger_init_data init_data;
+ struct dmub_send_cmd_params params;
+ struct dc_context *ctx;
+
+ ctx = entry->params.send_dmcub_cmd_params.ctx;
+ init_data.ctx = ctx;
+ init_data.dc_dmub_srv = ctx->dmub_srv;
+ params.cmd = entry->params.send_dmcub_cmd_params.cmd;
+ params.wait_type = entry->params.send_dmcub_cmd_params.wait_type;
+
+ dmub_messenger_construct(&messenger, &init_data);
+ if (messenger.funcs->inbox_cmd_send_and_wait(&messenger, &params) !=
+ DMUB_MSG_OK)
+ return entry->params.send_dmcub_cmd_params.continue_on_error ?
+ DC2_BLS_EXEC_CONTINUED_ON_ERROR :
+ DC2_BLS_EXEC_ERROR;
+
+ return DC2_BLS_EXEC_OK;
+}
+
+static noinline_for_stack enum dc2_bls_exec_result dc2_bls_exec_dmub_gpint(
+ struct dc2 *dc2, const struct block_sequence *entry)
+{
+ struct dmub_messenger messenger;
+ struct dmub_messenger_init_data init_data;
+
+ init_data.ctx = dc2->dc.ctx;
+ init_data.dc_dmub_srv = dc2->dc.ctx->dmub_srv;
+ dmub_messenger_construct(&messenger, &init_data);
+ if (messenger.funcs->gpint_send_and_wait(&messenger,
+ &entry->params.dmub_gpint_params) != DMUB_MSG_OK)
+ return DC2_BLS_EXEC_ERROR;
+
+ return DC2_BLS_EXEC_OK;
+}
+
+enum dc2_bls_exec_result dc2_bls_execute(
+ struct dc2 *dc2,
+ const struct block_sequence *steps,
+ unsigned int num_steps)
+{
+ enum dc2_bls_exec_result result = DC2_BLS_EXEC_OK;
+ const struct block_sequence *entry;
+ enum dc2_bls_exec_result sent;
+ unsigned int i;
+
+ if (!steps || num_steps > MAX_HWSS_BLOCK_SEQUENCE_SIZE)
+ return DC2_BLS_EXEC_ERROR;
+
+ for (i = 0; i < num_steps; i++)
+ if (!dc2_bls_step_supported(dc2, &steps[i]))
+ return DC2_BLS_EXEC_ERROR;
+
+ for (i = 0; i < num_steps; i++) {
+ entry = &steps[i];
+ switch (entry->func) {
+ /*
+ * LEGACY/pmfw-msg: remove both cases when PMFW Messenger can
+ * reproduce the same calls, order, and output.
+ */
+ case LEGACY_CLK_MGR_INIT_CLOCKS:
+ entry->params.legacy_clk_mgr_init_clocks_params
+ .clk_mgr->funcs->init_clocks(
+ entry->params
+ .legacy_clk_mgr_init_clocks_params.clk_mgr);
+ break;
+ case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT: {
+ const struct legacy_clk_mgr_is_dc_mode_present_params *p =
+ &entry->params
+ .legacy_clk_mgr_is_dc_mode_present_params;
+
+ *p->out_dcmode_power_limits_present =
+ p->clk_mgr->funcs->is_dc_mode_present(
+ p->clk_mgr);
+ break;
+ }
+ case DCCG_INITIALIZE_CLOCKS:
+ entry->params.dccg_initialize_clocks_params.dccg->funcs->dccg_init(
+ entry->params.dccg_initialize_clocks_params.dccg);
+ break;
+ case DMUB_SEND_DMCUB_CMD:
+ sent = dc2_bls_exec_dmub_send(entry);
+ if (sent == DC2_BLS_EXEC_ERROR)
+ return DC2_BLS_EXEC_ERROR;
+ if (sent == DC2_BLS_EXEC_CONTINUED_ON_ERROR)
+ result = DC2_BLS_EXEC_CONTINUED_ON_ERROR;
+ break;
+ case DMUB_GPINT_SEND_AND_WAIT:
+ case DMUB_HALT_FW:
+ if (dc2_bls_exec_dmub_gpint(dc2, entry) != DC2_BLS_EXEC_OK)
+ return DC2_BLS_EXEC_ERROR;
+ break;
+ case PSP_RELOAD_DMUB_FW:
+ if (dmub_srv_hw_init(
+ entry->params.psp_reload_dmub_fw_params.dmub,
+ entry->params.psp_reload_dmub_fw_params.hw_params) !=
+ DMUB_STATUS_OK)
+ return DC2_BLS_EXEC_ERROR;
+ break;
+ case DMUB_INITIALIZE_DCN:
+ if (dc2_bls_exec_dmub_send(entry) != DC2_BLS_EXEC_OK)
+ return DC2_BLS_EXEC_ERROR;
+ break;
+ /*
+ * S-INT/bld-seq: dce_hwseq init functions. Remove when the
+ * OPTC, MMHUBBUB, DCCG and HPO BLCs expose them.
+ */
+ case OPTC_SET_ODM_MEM_POWER: {
+ struct dce_hwseq *hws =
+ entry->params.hwseq_reg_control_params.hws;
+
+ hws->funcs.init_odm_mem_power(hws);
+ break;
+ }
+ case MMHUBBUB_SET_MEM_POWER: {
+ struct dce_hwseq *hws =
+ entry->params.hwseq_reg_control_params.hws;
+
+ hws->funcs.power_down_vga_mem(hws);
+ break;
+ }
+ case DCCG_SET_DCFCLK_GATING: {
+ struct dce_hwseq *hws =
+ entry->params.hwseq_reg_control_params.hws;
+
+ hws->funcs.dcfclk_gating_control(hws,
+ entry->params.hwseq_reg_control_params
+ .enable);
+ break;
+ }
+ case HPO_SET_HW_CONTROL: {
+ struct dce_hwseq *hws =
+ entry->params.hwseq_reg_control_params.hws;
+
+ hws->funcs.init_hpo_hw_control(hws,
+ entry->params.hwseq_reg_control_params
+ .enable);
+ break;
+ }
+ case PG_SET_PLANE_POWER_GATING: {
+ struct dce_hwseq *hws =
+ entry->params.hwseq_reg_control_params.hws;
+
+ hws->funcs.enable_power_gating_plane(hws,
+ entry->params.hwseq_reg_control_params
+ .enable);
+ break;
+ }
+ case DCCG_GET_REF_FREQ: {
+ const struct dccg_get_ref_freq_params *p =
+ &entry->params.dccg_get_ref_freq_params;
+
+ *p->out_xtalin_khz = p->xtalin_khz;
+ p->dccg->funcs->get_dccg_ref_freq(p->dccg, p->xtalin_khz,
+ p->out_dccg_ref_khz);
+ break;
+ }
+ case HUBBUB_GET_DCHUB_REF_FREQ: {
+ const struct hubbub_get_dchub_ref_freq_params *p =
+ &entry->params.hubbub_get_dchub_ref_freq_params;
+
+ p->hubbub->funcs->get_dchub_ref_freq(p->hubbub,
+ p->dccg_ref_khz, p->out_dchub_ref_khz);
+ break;
+ }
+ case DIO_LINK_ENC_HW_INIT: {
+ struct link_encoder *enc =
+ entry->params.link_enc_hw_init_params.link_enc;
+
+ enc->funcs->hw_init(enc);
+ break;
+ }
+ case DIO_LINK_ENC_IS_DIG_ENABLED: {
+ const struct link_enc_is_dig_enabled_params *p =
+ &entry->params.link_enc_is_dig_enabled_params;
+
+ *p->out_dig_enabled =
+ p->link_enc->funcs->is_dig_enabled(p->link_enc);
+ break;
+ }
+ case DIO_LINK_ENC_FEC_IS_ACTIVE: {
+ const struct link_enc_fec_is_active_params *p =
+ &entry->params.link_enc_fec_is_active_params;
+
+ *p->out_fec_active =
+ p->link_enc->funcs->fec_is_active(p->link_enc);
+ break;
+ }
+ /*
+ * S-INT/bld-seq: VBIOS table read through dc_bios. Remove
+ * when a BLC exposes the DDC GPIO info.
+ */
+ case BIOS_GET_I2C_INFO: {
+ const struct bios_get_i2c_info_params *p =
+ &entry->params.bios_get_i2c_info_params;
+
+ *p->out_result = p->dcb->funcs->get_i2c_info(p->dcb,
+ p->link_id, p->out_info);
+ break;
+ }
+ /*
+ * S-INT/link-seq: composite link call. Remove when Link
+ * builds the blanking through the shared Builder/Executor.
+ */
+ case LINK_BLANK_ALL_DP_DISPLAYS: {
+ struct dc *init_dc = entry->params.dc_init_call_params.dc;
+
+ init_dc->link_srv->blank_all_dp_displays(init_dc);
+ break;
+ }
+ /*
+ * S-INT/bld-seq: composite hwseq calls. Remove each when the
+ * DCN401 BLCs it drives are contract-conformant.
+ */
+ case HWSS_ENABLE_ACCELERATED_MODE: {
+ struct dc *init_dc = entry->params.dc_init_call_params.dc;
+
+ init_dc->hwss.enable_accelerated_mode(init_dc,
+ init_dc->current_state);
+ break;
+ }
+ case HWSEQ_INIT_PIPES: {
+ struct dc *init_dc = entry->params.dc_init_call_params.dc;
+
+ init_dc->hwseq->funcs.init_pipes(init_dc,
+ init_dc->current_state);
+ break;
+ }
+ case HWSEQ_POWER_DOWN: {
+ struct dc *init_dc = entry->params.dc_init_call_params.dc;
+
+ init_dc->hwseq->funcs.power_down(init_dc);
+ break;
+ }
+ case EDP_BACKLIGHT_CONTROL: {
+ struct dc_link *link = entry->params.edp_control_params.link;
+
+ link->dc->hwss.edp_backlight_control(link,
+ entry->params.edp_control_params.enable);
+ break;
+ }
+ case EDP_POWER_CONTROL: {
+ struct dc_link *link = entry->params.edp_control_params.link;
+
+ link->dc->hwss.edp_power_control(link,
+ entry->params.edp_control_params.enable);
+ break;
+ }
+ case HUBBUB_ALLOW_SELF_REFRESH_CONTROL: {
+ const struct hubbub_allow_self_refresh_control_params *p =
+ &entry->params
+ .hubbub_allow_self_refresh_control_params;
+
+ p->hubbub->funcs->allow_self_refresh_control(p->hubbub,
+ p->allow);
+ break;
+ }
+ /*
+ * S-INT/pmfw-msg: remove these cases when PMFW Messenger can
+ * reproduce the same calls, order, and output.
+ */
+ case CLK_MGR_GET_DISPCLK_FROM_DENTIST: {
+ const struct clk_mgr_get_dispclk_from_dentist_params *p =
+ &entry->params
+ .clk_mgr_get_dispclk_from_dentist_params;
+
+ *p->out_dispclk_khz =
+ p->clk_mgr->funcs->get_dispclk_from_dentist(
+ p->clk_mgr);
+ break;
+ }
+ case LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS:
+ dc2_bls_exec_initialize_min_clocks(
+ &entry->params
+ .clk_mgr_initialize_min_clocks_params);
+ break;
+ case LEGACY_CLK_MGR_NOTIFY_WM_RANGES: {
+ struct clk_mgr *wm_clk_mgr = entry->params
+ .clk_mgr_notify_wm_ranges_params.clk_mgr;
+
+ wm_clk_mgr->funcs->notify_wm_ranges(wm_clk_mgr);
+ break;
+ }
+ /*
+ * S-INT/dmub-msg: composite idle call. Remove when DMUB
+ * Messenger carries the idle commands.
+ */
+ case DMUB_SET_IDLE_OPTIMIZATION:
+ dc_allow_idle_optimizations(
+ entry->params.dc_init_call_params.dc,
+ entry->params.dc_init_call_params.enable);
+ break;
+ case AUDIO_HW_INIT: {
+ struct audio *audio =
+ entry->params.audio_hw_init_params.audio;
+
+ audio->funcs->hw_init(audio);
+ break;
+ }
+ case PANEL_CNTL_HW_INIT: {
+ const struct panel_cntl_hw_init_params *p =
+ &entry->params.panel_cntl_hw_init_params;
+
+ *p->out_backlight =
+ p->panel_cntl->funcs->hw_init(p->panel_cntl);
+ *p->out_user_level = p->panel_cntl
+ ->stored_backlight_registers.USER_LEVEL;
+ break;
+ }
+ case GPIO_DDC_OPEN: {
+ const struct gpio_ddc_open_params *p =
+ &entry->params.gpio_ddc_open_params;
+
+ dal_gpio_ddc_open_aux_once(p->gpio_service,
+ p->clk_a_register_index, p->clk_a_mask,
+ &p->hw_info);
+ break;
+ }
+ case ABM_INIT: {
+ const struct abm_init_params *p =
+ &entry->params.abm_init_params;
+
+ p->abm->funcs->abm_init(p->abm, p->backlight,
+ p->user_level);
+ break;
+ }
+ case DIO_AFMT_SET_MEM_POWER: {
+ const struct dio_set_mem_power_params *p =
+ &entry->params.dio_set_mem_power_params;
+
+ p->dio->funcs->mem_pwr_ctrl(p->dio, p->enable);
+ break;
+ }
+ case DCCG_SET_ROOT_CLOCK_GATING: {
+ const struct dccg_set_root_clock_gating_params *p =
+ &entry->params.dccg_set_root_clock_gating_params;
+
+ p->dccg->funcs->allow_clock_gating(p->dccg, p->allow);
+ break;
+ }
+ case HUBBUB_INIT_WATERMARKS: {
+ struct hubbub *hubbub = entry->params
+ .hubbub_init_watermarks_params.hubbub;
+
+ hubbub->funcs->init_watermarks(hubbub);
+ break;
+ }
+ /*
+ * S-INT/bld-seq: VBIOS scratch read through dc_bios. Remove
+ * when a BLC exposes the accelerated-mode bit.
+ */
+ case BIOS_IS_ACCELERATED_MODE: {
+ const struct bios_is_accelerated_mode_params *p =
+ &entry->params.bios_is_accelerated_mode_params;
+
+ *p->out_accelerated_mode =
+ p->dcb->funcs->is_accelerated_mode(p->dcb);
+ break;
+ }
+ case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL: {
+ const struct hubbub_force_pstate_change_control_params *p =
+ &entry->params
+ .hubbub_force_pstate_change_control_params;
+
+ p->hubbub->funcs->force_pstate_change_control(p->hubbub,
+ p->enable, p->allow);
+ break;
+ }
+ case HUBBUB_INIT_CRB: {
+ struct hubbub *hubbub =
+ entry->params.hubbub_init_crb_params.hubbub;
+
+ hubbub->funcs->init_crb(hubbub);
+ break;
+ }
+ case HUBBUB_SET_REQUEST_LIMIT: {
+ const struct hubbub_set_request_limit_params *p =
+ &entry->params.hubbub_set_request_limit_params;
+
+ p->hubbub->funcs->set_request_limit(p->hubbub,
+ p->num_chans, p->words_per_umc);
+ break;
+ }
+ default:
+ ASSERT(false);
+ return DC2_BLS_EXEC_ERROR;
+ }
+ }
+
+ return result;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.h b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.h
new file mode 100644
index 000000000000..d686f03c34c2
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "bls_builder/bls_builder.h"
+#include "dc_api_dispatch/api_shim.h"
+
+enum dc2_bls_exec_result {
+ DC2_BLS_EXEC_OK,
+ DC2_BLS_EXEC_ERROR,
+ /* Every step ran; at least one continue-on-error step failed. */
+ DC2_BLS_EXEC_CONTINUED_ON_ERROR,
+};
+
+enum dc2_bls_exec_result dc2_bls_execute(
+ struct dc2 *dc2,
+ const struct block_sequence *steps,
+ unsigned int num_steps);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 3dbcece49188..ae5f03a73132 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -944,31 +944,23 @@ void dc_stream_set_static_screen_params(struct dc *dc,
static void dc_destruct_update_scratch_pool(struct dc *dc)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
- kfree(dc->update_scratch_pool[i]);
- dc->update_scratch_pool[i] = NULL;
- dc->update_scratch_in_use[i] = false;
- }
+ dc_memory_pool_destroy(dc->update_scratch_pool);
}
static bool dc_construct_update_scratch_pool(struct dc *dc)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
- dc->update_scratch_pool[i] = kzalloc_obj(struct dc_update_scratch_space);
- if (!dc->update_scratch_pool[i])
- return false;
- dc->update_scratch_in_use[i] = false;
- }
+ // +1 to allow updates not tied to any specific stream
+ const size_t size = sizeof(struct dc_update_scratch_space);
+ const size_t capacity = MAX_STREAMS + 1;
- return true;
+ dc->update_scratch_pool = dc_memory_pool_create(size, capacity);
+ return dc->update_scratch_pool != NULL;
}
static void dc_destruct(struct dc *dc)
{
+ unsigned int i;
+
// reset link encoder assignment table on destruct
if (dc->res_pool && dc->res_pool->funcs->link_encs_assign &&
!dc->config.unify_link_enc_assignment)
@@ -981,6 +973,13 @@ static void dc_destruct(struct dc *dc)
dc->current_state = NULL;
}
+ for (i = 0; i < ARRAY_SIZE(dc->scratch_dc_context); i++) {
+ if (dc->scratch_dc_context[i]) {
+ dc_state_release(dc->scratch_dc_context[i]);
+ dc->scratch_dc_context[i] = NULL;
+ }
+ }
+
destroy_links(dc);
destroy_link_encoders(dc);
@@ -1219,6 +1218,22 @@ static bool dc_construct(struct dc *dc,
goto fail;
}
+ /* Pre-allocate the states used by the no-allocation update path, only
+ * for DMs that ask for it.
+ */
+ if (dc->config.preallocate_scratch_state) {
+ unsigned int scratch_idx;
+
+ for (scratch_idx = 0; scratch_idx < ARRAY_SIZE(dc->scratch_dc_context); scratch_idx++) {
+ dc->scratch_dc_context[scratch_idx] = dc_state_create(dc, NULL);
+
+ if (!dc->scratch_dc_context[scratch_idx]) {
+ dm_error("%s: failed to create scratch ctx\n", __func__);
+ goto fail;
+ }
+ }
+ }
+
if (!dc_construct_update_scratch_pool(dc)) {
dm_error("%s: failed to create update scratch pool\n", __func__);
goto fail;
@@ -3828,6 +3843,29 @@ static void restore_minimal_pipe_split_policy(struct dc *dc,
}
/**
+ * dc_state_acquire_scratch: Pick a pre-allocated state safe to build into.
+ * @dc: DC context
+ *
+ * Skips the buffer installed as @dc->current_state, since building into it
+ * would mean copying a state onto itself.
+ *
+ * Return: a usable scratch state, or NULL if none were pre-allocated.
+ */
+static struct dc_state *dc_state_acquire_scratch(struct dc *dc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dc->scratch_dc_context); i++) {
+ struct dc_state *scratch = dc->scratch_dc_context[i];
+
+ if (scratch && scratch != dc->current_state)
+ return scratch;
+ }
+
+ return NULL;
+}
+
+/**
* update_planes_and_stream_state() - The function takes planes and stream
* updates as inputs and determines the appropriate update type. If update type
* is FULL, the function allocates a new context, populates and validates it.
@@ -3933,7 +3971,24 @@ static bool update_planes_and_stream_state(struct dc *dc,
new_planes[i] = srf_updates[i].surface;
/* initialize scratch memory for building context */
- context = dc_state_create_copy(dc->current_state);
+ if (!dc->config.use_preallocated_state) {
+ context = dc_state_create_copy(dc->current_state);
+ } else {
+ context = dc_state_acquire_scratch(dc);
+
+ if (context) {
+ // Drop the references this buffer still holds from its
+ // previous use; dc_state_copy() overwrites the pointers
+ // without releasing them.
+ dc_state_destruct(context);
+ dc_state_copy(context, dc->current_state);
+
+ // Balance the reference that the commit path consumes
+ // when it installs this as current_state, so the buffer
+ // stays owned by dc->scratch_dc_context[] as well.
+ dc_state_retain(context);
+ }
+ }
if (context == NULL) {
DC_ERROR("Failed to allocate new validate context!\n");
return false;
@@ -4014,6 +4069,8 @@ static bool update_planes_and_stream_state(struct dc *dc,
return true;
fail:
+ // For a scratch buffer this drops the reference taken above, leaving it
+ // owned by dc->scratch_dc_context[] rather than freeing it.
dc_state_release(context);
return false;
@@ -6026,32 +6083,17 @@ static void clear_update_bits(struct dc_surface_update *srf_updates,
static struct dc_update_scratch_space *dc_update_scratch_acquire(struct dc *dc)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
- if (dc->update_scratch_in_use[i])
- continue;
-
- dc->update_scratch_in_use[i] = true;
- return dc->update_scratch_pool[i];
- }
+ void *p = dc_memory_pool_acquire(dc->update_scratch_pool);
/* TODO: add recoverable scratch acquisition failure handling. */
- ASSERT(false);
- return NULL;
+ ASSERT(p);
+ return p;
}
static void dc_update_scratch_release(struct dc *dc,
struct dc_update_scratch_space *scratch)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
- if (dc->update_scratch_pool[i] == scratch) {
- dc->update_scratch_in_use[i] = false;
- return;
- }
- }
+ dc_memory_pool_release(dc->update_scratch_pool, scratch);
}
/**
@@ -8117,6 +8159,16 @@ static bool update_planes_and_stream_prepare_v3(
ASSERT(scratch->update_type >= UPDATE_TYPE_FULL);
+ /* The minimal-transition fallbacks below allocate, so the scratch path
+ * commits the new context directly - possibly a non-seamless pipe-topology
+ * transition. Placed after the suspend above to keep the cleanup resume
+ * balanced.
+ */
+ if (scratch->dc->config.use_preallocated_state) {
+ scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS;
+ return true;
+ }
+
const bool seamless = scratch->dc->hwss.is_pipe_topology_transition_seamless(
scratch->dc,
scratch->dc->current_state,
diff --git a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c
index d4777cdbd569..69a376351df1 100644
--- a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c
+++ b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c
@@ -5,9 +5,85 @@
#include "dm_services.h"
#include "dc.h"
+#include "bls_builder/bls_builder.h"
+#include "bls_executor/bls_executor.h"
+#include "workaround_manager/workaround_manager.h"
#include "core2/dc_core2_init.h"
+#include "core2/dc_core2_legacy_init.h"
+#include "dc_api_dispatch/api_shim.h"
+/*
+ * S-INT/link-seq: the eDP sink check legacy_hardware_init runs before
+ * init_hw. Remove when Link owns boot-time eDP detection.
+ */
+static void core2_detect_edp_presence(struct dc *dc)
+{
+ struct dc_link *edp_links[MAX_NUM_EDP];
+ enum dc_connection_type type;
+ unsigned int i, edp_num;
+
+ dc_get_edp_links(dc, edp_links, &edp_num);
+ for (i = 0; i < edp_num; i++) {
+ if (dc->config.edp_not_connected) {
+ edp_links[i]->edp_sink_present = false;
+ } else {
+ edp_links[i]->edp_sink_present =
+ dc_link_detect_connection_type(edp_links[i],
+ &type) && type != dc_connection_none;
+ }
+ }
+}
+
+static void core2_run_native_hardware_init(struct dc *dc)
+{
+ struct bls_builder_declarative_params *params;
+ struct bls_builder_output_init *out_init;
+ struct bls_builder_output_targets out_targets = {0};
+ const struct bls_builder *builder;
+ enum bls_builder_result result;
+
+ builder = bls_builder_create(dc, DCN_DECL_INITIALIZATION);
+ if (!builder || builder->kind != BLS_BUILDER_DECLARATIVE ||
+ !builder->build.declarative)
+ return;
+
+ /*
+ * The declarative params hold 128 block-sequence entries, and the
+ * init output holds DMUB command buffers. Keep both off the stack
+ * so the kernel frame stays under the 2048-byte limit.
+ */
+ params = kvzalloc(sizeof(*params), GFP_KERNEL);
+ out_init = kvzalloc(sizeof(*out_init), GFP_KERNEL);
+ if (!params || !out_init)
+ goto out;
+
+ params->dc = dc;
+ out_targets.DCN_DECL_INITIALIZATION = out_init;
+ params->out_targets = &out_targets;
+ /*
+ * The builder copies DMUB windows retained on dmub_srv. Missing
+ * windows fail the build closed. Execute only a successful build,
+ * and do not fall back to legacy hwseq.
+ */
+ result = builder->build.declarative(params);
+ if (result == BLS_BUILD_SUCCESS)
+ dc2_bls_execute(TO_DC2(dc), params->head_sequence,
+ params->head_num_steps);
+
+out:
+ kvfree(params);
+ kvfree(out_init);
+}
+
+/* CORE2 runs the DC2_DC1_Wrapped init until dcn401 init is native. */
void core2_hardware_init(struct dc *dc)
{
- dc2_legacy_funcs()->hardware_init(dc);
+ if (!dc)
+ return;
+
+ core2_detect_edp_presence(dc);
+ if (TO_DC2(dc)->selection == DC2_SELECTION_CORE2)
+ core2_run_legacy_hardware_init(dc, dc2_workaround_manager_get());
+ else
+ core2_run_native_hardware_init(dc);
}
diff --git a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.c b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.c
new file mode 100644
index 000000000000..285dfc9e6e69
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.c
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include "dm_services.h"
+#include "dc.h"
+#include "core_types.h"
+#include "clk_mgr.h"
+#include "dc_dmub_srv.h"
+#include "bls_builder/bls_builder.h"
+#include "bls_executor/bls_executor.h"
+#include "workaround_manager/workaround_manager.h"
+#include "core2/dc_core2_legacy_init.h"
+#include "dc_api_dispatch/api_shim.h"
+
+/*
+ * dcn401_init_hw marks a link active when its DIG is already enabled,
+ * and FEC enabled when it is also active. Applied after each stage that
+ * reads the DIG or FEC state, before any later stage runs.
+ */
+static void core2_apply_dc1_link_states(struct dc *dc,
+ const struct bls_builder_legacy_hw_init_info *info)
+{
+ unsigned int i;
+
+ for (i = 0; i < dc->link_count; i++) {
+ struct dc_link *link = dc->links[i];
+
+ if (!info->s3.link_dig_enabled[i])
+ continue;
+ link->link_status.link_active = true;
+ link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
+ if (info->s4.link_fec_active[i])
+ link->fec_state = dc_link_fec_enabled;
+ }
+}
+
+/*
+ * The HUBBUB stage resolved the DMUB feature caps. Take the query reply
+ * as dc_dmub_srv_query_caps_cmd does, retain dmub_abi for later builds,
+ * then apply the caps and the bounding-box update, all before the next
+ * stage runs.
+ */
+static void core2_apply_dmub_caps(struct dc *dc,
+ const struct bls_builder_legacy_hw_init_info *info)
+{
+ const union dmub_rb_cmd *reply = &info->s11.dmub_query_feature_caps_cmd;
+ struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub;
+ struct resource_pool *pool = dc->res_pool;
+ struct dc2 *dc2 = TO_DC2(dc);
+ const struct dmub_feature_caps *caps = &dc2->dmub_abi.feature_caps;
+ bool dchub_ref_freq_changed;
+
+ /*
+ * S-INT/dmub-msg: the rest of DC reads feature_caps from dmub_srv.
+ * Remove when those readers take dmub_abi.
+ */
+ if (info->s11.dmub_caps_query_sent &&
+ reply->query_feature_caps.header.ret_status == 0)
+ memcpy(&dmub->feature_caps,
+ &reply->query_feature_caps.query_feature_caps_data,
+ sizeof(dmub->feature_caps));
+ memset(&dc2->dmub_abi, 0, sizeof(dc2->dmub_abi));
+ dc2->dmub_abi.feature_caps = dmub->feature_caps;
+ dc2->dmub_abi_resolved = true;
+
+ dc->caps.dmub_caps.psr = caps->psr;
+ dc->caps.dmub_caps.mclk_sw = caps->fw_assisted_mclk_switch_ver > 0;
+ dc->caps.dmub_caps.fams_ver = caps->fw_assisted_mclk_switch_ver;
+
+ /* sw and fw FAMS versions must match for support */
+ dc->debug.fams2_config.bits.enable &=
+ dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver;
+ dchub_ref_freq_changed = pool->ref_clocks.dchub_ref_clock_inKhz / 1000 !=
+ info->s2.dchub_ref_clock_mhz_before;
+ if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) &&
+ pool->funcs->update_bw_bounding_box &&
+ dc->clk_mgr && dc->clk_mgr->bw_params)
+ pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
+}
+
+/*
+ * Move the output of the stage just executed into dc_state.hw_init_info,
+ * where the next build reads it, then apply what dcn401_init_hw left on
+ * dc by this point: the reference clocks, DC-mode limits, link state and
+ * DMUB caps.
+ */
+static void core2_retain_init_stage(struct dc *dc,
+ const struct bls_builder_legacy_hw_init_info *out)
+{
+ struct bls_builder_legacy_hw_init_info *info =
+ &dc->current_state->hw_init_info;
+ struct resource_pool *pool = dc->res_pool;
+
+ switch (out->next_stage - 1) {
+ case LEGACY_INIT_STAGE_CLOCKS:
+ info->s1 = out->s1;
+ pool->ref_clocks.xtalin_clock_inKhz = info->s1.xtalin_clock_inKhz;
+ pool->ref_clocks.dccg_ref_clock_inKhz =
+ info->s1.dccg_ref_clock_inKhz;
+ if (dc->clk_mgr && dc->clk_mgr->funcs &&
+ dc->clk_mgr->funcs->init_clocks)
+ dc->caps.dcmode_power_limits_present =
+ info->s1.dcmode_power_limits_present;
+ break;
+ case LEGACY_INIT_STAGE_DCHUB_REF:
+ info->s2 = out->s2;
+ pool->ref_clocks.dchub_ref_clock_inKhz =
+ info->s2.dchub_ref_clock_inKhz;
+ break;
+ case LEGACY_INIT_STAGE_LINK_ENC:
+ info->s3 = out->s3;
+ core2_apply_dc1_link_states(dc, info);
+ break;
+ case LEGACY_INIT_STAGE_FEC:
+ info->s4 = out->s4;
+ core2_apply_dc1_link_states(dc, info);
+ break;
+ case LEGACY_INIT_STAGE_BLANK:
+ info->s5 = out->s5;
+ break;
+ case LEGACY_INIT_STAGE_POWER_DOWN:
+ info->s6 = out->s6;
+ break;
+ case LEGACY_INIT_STAGE_MIN_CLOCKS:
+ info->s7 = out->s7;
+ break;
+ case LEGACY_INIT_STAGE_POWER_DOWN_EDP0:
+ info->s8 = out->s8;
+ break;
+ case LEGACY_INIT_STAGE_POWER_DOWN_EDP1:
+ info->s9 = out->s9;
+ break;
+ case LEGACY_INIT_STAGE_GATING:
+ info->s10 = out->s10;
+ break;
+ case LEGACY_INIT_STAGE_HUBBUB:
+ info->s11 = out->s11;
+ if (info->s11.dmub_caps_read)
+ core2_apply_dmub_caps(dc, info);
+ break;
+ case LEGACY_INIT_STAGE_POWER_STATE:
+ info->s12 = out->s12;
+ break;
+ }
+ info->next_stage = out->next_stage;
+ info->init_done = out->init_done;
+}
+
+/*
+ * Build, workaround, execute. Execute only a successful build and a
+ * workaround pass that kept the stage within the sequence storage, and
+ * do not fall back to legacy hwseq.
+ */
+static bool core2_run_init_stage(struct dc *dc,
+ const struct bls_builder *builder,
+ const struct workaround_manager *wam,
+ struct bls_builder_declarative_params *params)
+{
+ struct workaround_context wa_ctx = {0};
+ struct block_sequence_state sequence;
+ enum dc2_bls_exec_result result;
+
+ if (builder->build.declarative(params) != BLS_BUILD_SUCCESS)
+ return false;
+
+ sequence.steps = params->head_sequence;
+ sequence.num_steps = &params->head_num_steps;
+ wa_ctx.current_state = dc->current_state;
+ wa_ctx.builder_name = builder->name;
+ wa_ctx.dcn_version = dc->ctx->dce_version;
+ wa_ctx.bug_wa = &dc->work_arounds;
+ wa_ctx.debug = &dc->debug;
+ if (workaround_manager_apply(wam, &sequence, &wa_ctx) != WAM_OK ||
+ params->head_num_steps > DC2_BLS_MAX_STEPS)
+ return false;
+
+ /* dcn401_init_hw ignores the DMUB sends that continue on error. */
+ result = dc2_bls_execute(TO_DC2(dc), params->head_sequence,
+ params->head_num_steps);
+ return result == DC2_BLS_EXEC_OK ||
+ result == DC2_BLS_EXEC_CONTINUED_ON_ERROR;
+}
+
+bool core2_run_legacy_hardware_init(struct dc *dc,
+ const struct workaround_manager *wam)
+{
+ struct bls_builder_declarative_params *params;
+ struct bls_builder_legacy_hw_init_info *out;
+ struct bls_builder_legacy_hw_init_info *info;
+ struct bls_builder_output_targets out_targets = {0};
+ const struct bls_builder *builder;
+ unsigned int stage;
+
+ if (!dc || !dc->current_state || !wam)
+ return false;
+
+ info = &dc->current_state->hw_init_info;
+ memset(info, 0, sizeof(*info));
+ info->next_stage = LEGACY_INIT_STAGE_CLOCKS;
+ builder = bls_builder_create(dc, DCN_DECL_INITIALIZATION_LEGACY);
+ if (!builder || builder->kind != BLS_BUILDER_DECLARATIVE ||
+ !builder->build.declarative)
+ return false;
+ TO_DC2(dc)->dmub_abi_resolved = false;
+
+ /*
+ * The declarative params hold 128 block-sequence entries, and the
+ * stage outputs hold DMUB command buffers. Keep both off the stack
+ * so the kernel frame stays under the 2048-byte limit.
+ */
+ params = kvzalloc(sizeof(*params), GFP_KERNEL);
+ out = kvzalloc(sizeof(*out), GFP_KERNEL);
+ if (!params || !out)
+ goto out;
+
+ params->dc = dc;
+ params->current_state = dc->current_state;
+ out_targets.DCN_DECL_INITIALIZATION_LEGACY = out;
+ params->out_targets = &out_targets;
+ /* The builder reports init_done no later than its last stage. */
+ for (stage = 0; stage < LEGACY_INIT_STAGE_COUNT && !info->init_done;
+ stage++) {
+ if (!core2_run_init_stage(dc, builder, wam, params))
+ break;
+ core2_retain_init_stage(dc, out);
+ }
+ info->init_success = info->init_done;
+
+out:
+ info->init_done = true;
+ kvfree(params);
+ kvfree(out);
+ return info->init_success;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.h b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.h
new file mode 100644
index 000000000000..d0cd7a5cb2c6
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+struct dc;
+struct workaround_manager;
+
+/*
+ * DC2_DC1_Wrapped hardware init: dcn401_init_hw as twelve staged BLS
+ * builds, each passed through wam. A migration shim; it and
+ * dcn401_init_builder_legacy.c are removed together.
+ */
+bool core2_run_legacy_hardware_init(struct dc *dc,
+ const struct workaround_manager *wam);
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index f4fefa7c9ab8..d983bab7eea3 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -30,6 +30,7 @@
#include "dc_state.h"
#include "dc_plane.h"
#include "dc_probe.h"
+#include "dc_memory_pool.h"
#include "grph_object_defs.h"
#include "logger_types.h"
#include "hdcp_msg_types.h"
@@ -68,7 +69,7 @@ struct dcn_dsc_reg_state;
struct dcn_optc_reg_state;
struct dcn_dccg_reg_state;
-#define DC_VER "3.2.403"
+#define DC_VER "3.2.404"
/**
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
@@ -635,6 +636,15 @@ struct dc_config {
struct spl_sharpness_range dcn_sharpness_range;
struct spl_sharpness_range dcn_override_sharpness_range;
bool no_native422_support;
+
+ // Pre-allocate dc_state buffers at dc_construct time so that a commit can
+ // run on a code path where allocation is not permitted.
+ bool preallocate_scratch_state;
+
+ // Build commits into the pre-allocated buffers instead of allocating.
+ // Set by the DM around a commit that runs where allocation is not
+ // permitted; requires preallocate_scratch_state.
+ bool use_preallocated_state;
};
enum visual_confirm {
@@ -811,9 +821,6 @@ struct dc_clocks {
int idle_fclk_khz;
int subvp_prefetch_dramclk_khz;
int subvp_prefetch_fclk_khz;
- /* deprecated: use _KBps variants — will be removed after DML update */
- unsigned int utm_urgent_bandwidth_lb_Kbps;
- unsigned int utm_nominal_bandwidth_lb_Kbps;
unsigned int utm_urgent_bandwidth_lb_KBps;
unsigned int utm_nominal_bandwidth_lb_KBps;
unsigned int utm_latency_ub_index;
@@ -1104,6 +1111,12 @@ struct dc_debug_options {
*/
enum pipe_split_policy pipe_split_policy;
bool force_single_disp_pipe_split;
+ /*
+ * @force_mpc_combine: Override the DML2.1 per-plane MPC combine
+ * decision. 0 = auto (default), 1 = force single DPP (no MPC combine),
+ * 2 = force 2:1 MPC combine.
+ */
+ uint8_t force_mpc_combine;
bool voltage_align_fclk;
bool disable_min_fclk;
@@ -1321,13 +1334,13 @@ struct dc_debug_options {
unsigned int urgent_watermark_override;
bool enable_block_sequence_programming;
uint32_t custom_psp_footer_size;
+ uint32_t dmcub_fw_load_type;
bool disable_deferred_minimal_transitions;
unsigned int num_fast_flips_to_steady_state_override;
bool enable_dmu_recovery;
unsigned int force_vmin_threshold;
bool enable_otg_frame_sync_pwa;
unsigned int min_deep_sleep_dcfclk_khz;
- unsigned int force_odm2to1_for_edp_pixclk_mhz;
bool enable_replay_esd_recovery;
uint8_t iommu_mismatch_temp_wka;
bool disable_dynamic_expansion_for_test_pattern;
@@ -2023,13 +2036,19 @@ struct dc {
struct link_service *link_srv;
struct dc_state *current_state;
+ /**
+ * @scratch_dc_context: Pre-allocated states for the no-allocation update
+ * path, created only when dc_config.preallocate_scratch_state is set.
+ * Two are kept because the commit path installs the new context as
+ * @current_state, so a single buffer would alias it and self-copy.
+ */
+ struct dc_state *scratch_dc_context[2];
struct resource_pool *res_pool;
/**
* @update_scratch_pool: Per-commit scratch buffers for dc_update_state.
*/
- struct dc_update_scratch_space *update_scratch_pool[MAX_STREAMS + 1];
- bool update_scratch_in_use[MAX_STREAMS + 1];
+ struct dc_memory_pool *update_scratch_pool; // MAX_STREAMS + 1
struct clk_mgr *clk_mgr;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h
index fee03a5dd596..b972ae06663d 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h
@@ -7,11 +7,15 @@
#include "dc.h"
#include "inc/dc_core_interface.h"
+#include "bls_builder/dmub_abi.h"
struct dc2 {
/* First member: TO_DC2 is a typed upcast, not container_of. */
struct dc dc;
enum dc2_selection selection;
+ /* Resolved by hardware init; later builds take it as dmub_abi. */
+ struct dmub_abi dmub_abi;
+ bool dmub_abi_resolved;
};
#define TO_DC2(ptr) ((struct dc2 *)(ptr))
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
index feb6ca92802c..37a010e0bd6e 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
@@ -44,6 +44,7 @@
#include "dcn10/dcn10_hubbub.h"
#include "dcn10_cm_common.h"
#include "clk_mgr.h"
+#include "dsc.h"
__printf(3, 4)
unsigned int snprintf_count(char *pbuf, unsigned int bufsize, const char *fmt, ...)
@@ -488,6 +489,149 @@ static unsigned int dcn10_get_clock_states(struct dc *dc, char *pBuf, unsigned i
return bufSize - remaining_buffer;
}
+static unsigned int dcn10_get_bios_state(struct dc *dc, char *pBuf, unsigned int bufSize)
+{
+ struct dc_bios *bios = dc->ctx->dc_bios;
+ int acc_mode = -1;
+
+ if (bios && bios->funcs->is_accelerated_mode)
+ acc_mode = bios->funcs->is_accelerated_mode(bios);
+
+ return snprintf_count(pBuf, bufSize, "acc_mode\n%d\n", acc_mode);
+}
+
+/* Preset in a read_state struct for fields that only some generations read. */
+#define HW_STATE_NOT_READ 0xFFFFFFFF
+
+static int dcn10_dig_source_otg(struct dc *dc, unsigned int fe)
+{
+ struct resource_pool *pool = dc->res_pool;
+ unsigned int i;
+
+ for (i = 0; i < pool->stream_enc_count; i++) {
+ struct stream_encoder *se = pool->stream_enc[i];
+
+ if (se && se->id == fe && se->funcs->dig_source_otg)
+ return se->funcs->dig_source_otg(se);
+ }
+ return -1;
+}
+
+static unsigned int dcn10_get_link_states(struct dc *dc, char *pBuf, unsigned int bufSize)
+{
+ unsigned int chars_printed = 0;
+ unsigned int remaining_buffer = bufSize;
+ unsigned int i;
+
+ chars_printed = snprintf_count(pBuf, remaining_buffer,
+ "link,enc,hpd,dig_en,dig_mode,dig_fe,src_otg,preferred_otg,phy_on,phy_active\n");
+ remaining_buffer -= chars_printed;
+ pBuf += chars_printed;
+
+ for (i = 0; i < dc->link_count && remaining_buffer > 0; i++) {
+ struct dc_link *link = dc->links[i];
+ struct link_encoder *enc = link ? link->link_enc : NULL;
+ int hpd = -1, dig_en = -1, dig_mode = -1, dig_fe = -1, src_otg = -1;
+ int phy_on = -1, phy_active = -1;
+ struct link_enc_state s = {0};
+
+ if (!enc || link->connector_signal == SIGNAL_TYPE_VIRTUAL)
+ continue;
+
+ if (enc->funcs->get_hpd_state)
+ hpd = enc->funcs->get_hpd_state(enc);
+ if (enc->funcs->is_dig_enabled)
+ dig_en = enc->funcs->is_dig_enabled(enc);
+ if (dig_en == 1 && enc->funcs->get_dig_mode)
+ dig_mode = enc->funcs->get_dig_mode(enc);
+ if (dig_en == 1 && enc->funcs->get_dig_frontend) {
+ dig_fe = enc->funcs->get_dig_frontend(enc);
+ src_otg = dcn10_dig_source_otg(dc, dig_fe);
+ }
+ s.rdpcs_phy_reset = HW_STATE_NOT_READ;
+ s.rdpcs_tx_data_en = HW_STATE_NOT_READ;
+ if (enc->funcs->read_state)
+ enc->funcs->read_state(enc, &s);
+ if (s.rdpcs_phy_reset != HW_STATE_NOT_READ)
+ phy_on = s.rdpcs_phy_reset == 0;
+ if (s.rdpcs_tx_data_en != HW_STATE_NOT_READ)
+ phy_active = s.rdpcs_tx_data_en != 0;
+
+ chars_printed = snprintf_count(pBuf, remaining_buffer,
+ "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ i, enc->transmitter, hpd, dig_en, dig_mode, dig_fe,
+ src_otg, enc->preferred_engine, phy_on, phy_active);
+ remaining_buffer -= chars_printed;
+ pBuf += chars_printed;
+ }
+
+ return bufSize - remaining_buffer;
+}
+
+static unsigned int dcn10_get_dsc_states(struct dc *dc, char *pBuf, unsigned int bufSize)
+{
+ struct resource_pool *pool = dc->res_pool;
+ unsigned int chars_printed = 0;
+ unsigned int remaining_buffer = bufSize;
+ unsigned int i;
+
+ if (pool->res_cap->num_dsc == 0)
+ return 0;
+
+ chars_printed = snprintf_count(pBuf, remaining_buffer,
+ "dsc,clock_en,slice_width,bits_pp\n");
+ remaining_buffer -= chars_printed;
+ pBuf += chars_printed;
+
+ for (i = 0; i < (unsigned int)pool->res_cap->num_dsc && remaining_buffer > 0; i++) {
+ struct display_stream_compressor *dsc = pool->dscs[i];
+ struct dcn_dsc_state s = {0};
+
+ if (!dsc || !dsc->funcs->dsc_read_state)
+ continue;
+
+ dsc->funcs->dsc_read_state(dsc, &s);
+ chars_printed = snprintf_count(pBuf, remaining_buffer,
+ "%d,%d,%d,%d\n", i, s.dsc_clock_en,
+ s.dsc_slice_width, s.dsc_bits_per_pixel);
+ remaining_buffer -= chars_printed;
+ pBuf += chars_printed;
+ }
+
+ return bufSize - remaining_buffer;
+}
+
+static unsigned int dcn10_get_cursor_lock_states(struct dc *dc, char *pBuf, unsigned int bufSize)
+{
+ struct resource_pool *pool = dc->res_pool;
+ unsigned int chars_printed = 0;
+ unsigned int remaining_buffer = bufSize;
+ unsigned int i;
+
+ chars_printed = snprintf_count(pBuf, remaining_buffer, "mpcc,opp,cur_lock\n");
+ remaining_buffer -= chars_printed;
+ pBuf += chars_printed;
+
+ for (i = 0; i < pool->mpcc_count && remaining_buffer > 0; i++) {
+ struct mpcc_state s = {0};
+ int lock = -1;
+
+ s.cur_vupdate_lock = HW_STATE_NOT_READ;
+ pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
+ if (s.opp_id == 0xf)
+ continue;
+ if (s.cur_vupdate_lock != HW_STATE_NOT_READ)
+ lock = s.cur_vupdate_lock;
+
+ chars_printed = snprintf_count(pBuf, remaining_buffer, "%d,%d,%d\n",
+ i, s.opp_id, lock);
+ remaining_buffer -= chars_printed;
+ pBuf += chars_printed;
+ }
+
+ return bufSize - remaining_buffer;
+}
+
static void dcn10_clear_otpc_underflow(struct dc *dc)
{
struct resource_pool *pool = dc->res_pool;
@@ -548,6 +692,7 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne
* Mask Format
* Bit 0 - 15: Hardware block mask
* Bit 15: 1 = Invariant Only, 0 = All
+ * Bit 16 and up: opt-in blocks, never selected by mask 0
*/
const unsigned int DC_HW_STATE_MASK_HUBBUB = 0x1;
const unsigned int DC_HW_STATE_MASK_HUBP = 0x2;
@@ -559,6 +704,10 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne
const unsigned int DC_HW_STATE_MASK_OTG = 0x80;
const unsigned int DC_HW_STATE_MASK_CLOCKS = 0x100;
const unsigned int DC_HW_STATE_INVAR_ONLY = 0x8000;
+ const unsigned int DC_HW_STATE_MASK_BIOS = 0x10000;
+ const unsigned int DC_HW_STATE_MASK_LINK = 0x20000;
+ const unsigned int DC_HW_STATE_MASK_DSC = 0x40000;
+ const unsigned int DC_HW_STATE_MASK_CURSOR_LOCK = 0x80000;
unsigned int chars_printed = 0;
unsigned int remaining_buf_size = bufSize;
@@ -619,4 +768,28 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne
pBuf += chars_printed;
remaining_buf_size -= chars_printed;
}
+
+ if ((mask & DC_HW_STATE_MASK_BIOS) && remaining_buf_size > 0) {
+ chars_printed = dcn10_get_bios_state(dc, pBuf, remaining_buf_size);
+ pBuf += chars_printed;
+ remaining_buf_size -= chars_printed;
+ }
+
+ if ((mask & DC_HW_STATE_MASK_LINK) && remaining_buf_size > 0) {
+ chars_printed = dcn10_get_link_states(dc, pBuf, remaining_buf_size);
+ pBuf += chars_printed;
+ remaining_buf_size -= chars_printed;
+ }
+
+ if ((mask & DC_HW_STATE_MASK_DSC) && remaining_buf_size > 0) {
+ chars_printed = dcn10_get_dsc_states(dc, pBuf, remaining_buf_size);
+ pBuf += chars_printed;
+ remaining_buf_size -= chars_printed;
+ }
+
+ if ((mask & DC_HW_STATE_MASK_CURSOR_LOCK) && remaining_buf_size > 0) {
+ chars_printed = dcn10_get_cursor_lock_states(dc, pBuf, remaining_buf_size);
+ pBuf += chars_printed;
+ remaining_buf_size -= chars_printed;
+ }
}
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 6594fbb3fa43..4d62a5982632 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
@@ -364,6 +364,26 @@ bool dcn401_is_dig_enabled(struct link_encoder *enc)
return (clk_enabled == 1 && dig_enabled == 1);
}
+void dcn401_link_encoder_read_state(struct link_encoder *enc, struct link_enc_state *s)
+{
+ struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+ uint32_t tx0 = 0, tx1 = 0, tx2 = 0, tx3 = 0;
+
+ link_enc2_read_state(enc, s);
+
+ if (enc10->link_regs->RDPCSTX_PHY_CNTL0)
+ REG_GET(RDPCSTX_PHY_CNTL0, RDPCS_PHY_RESET, &s->rdpcs_phy_reset);
+
+ if (enc10->link_regs->RDPCSTX_PHY_CNTL3) {
+ REG_GET_4(RDPCSTX_PHY_CNTL3,
+ RDPCS_PHY_DP_TX0_DATA_EN, &tx0,
+ RDPCS_PHY_DP_TX1_DATA_EN, &tx1,
+ RDPCS_PHY_DP_TX2_DATA_EN, &tx2,
+ RDPCS_PHY_DP_TX3_DATA_EN, &tx3);
+ s->rdpcs_tx_data_en = tx0 | tx1 << 1 | tx2 << 2 | tx3 << 3;
+ }
+}
+
enum signal_type dcn401_get_dig_mode(
struct link_encoder *enc)
{
@@ -399,7 +419,7 @@ void dcn401_setup_ri_pj_check_in_sw_or_hw_mode(
}
static const struct link_encoder_funcs dcn401_link_enc_funcs = {
- .read_state = link_enc2_read_state,
+ .read_state = dcn401_link_encoder_read_state,
.validate_output_with_stream =
dcn30_link_encoder_validate_output_with_stream,
.hw_init = enc401_hw_init,
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h
index 62f8f9098b53..689fc817dbc5 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h
@@ -28,6 +28,13 @@
#include "dcn30/dcn30_dio_link_encoder.h"
+#define LINK_ENCODER_PHY_STATE_MASK_SH_LIST_DCN401(mask_sh) \
+ LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_RESET, mask_sh),\
+ LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_DATA_EN, mask_sh),\
+ LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_DATA_EN, mask_sh),\
+ LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_DATA_EN, mask_sh),\
+ LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_DATA_EN, mask_sh)
+
#define LINK_ENCODER_MASK_SH_LIST_DCN401(mask_sh) \
LE_SF(DIG0_DIG_BE_EN_CNTL, DIG_BE_ENABLE, mask_sh),\
LE_SF(DIG0_DIG_BE_CNTL, DIG_RB_SWITCH_EN, mask_sh),\
@@ -150,6 +157,7 @@ enum signal_type dcn401_get_dig_mode(
struct link_encoder *enc);
bool dcn401_is_dig_enabled(struct link_encoder *enc);
+void dcn401_link_encoder_read_state(struct link_encoder *enc, struct link_enc_state *s);
enum signal_type dcn401_get_dig_mode(struct link_encoder *enc);
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 a4a77e375d9f..c84cbad7fde1 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
@@ -11052,6 +11052,8 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
calculate_tdlut_setting_params->cursor_buffer_size = mode_lib->ip.cursor_buffer_size;
calculate_tdlut_setting_params->gpuvm_enable = display_cfg->gpuvm_enable;
calculate_tdlut_setting_params->gpuvm_page_size_kbytes = display_cfg->plane_descriptors[k].overrides.gpuvm_min_page_size_kbytes;
+ calculate_tdlut_setting_params->tdlut_mpc_width_flag = display_cfg->plane_descriptors[k].tdlut.tdlut_mpc_width_flag;
+ calculate_tdlut_setting_params->is_gfx11 = dml_get_gfx_version(display_cfg->plane_descriptors[k].surface.tiling);
// output
calculate_tdlut_setting_params->tdlut_pte_bytes_per_frame = &s->tdlut_pte_bytes_per_frame[k];
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
index 485ad96f64b1..b3a2858281ec 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
@@ -260,9 +260,10 @@ static unsigned int calculate_max_mem_size_per_plane_per_dpp(const struct dml2_c
odm_slice_pixels = (double)h_active / odm_combine_factor * h_ratio + (odm_combine_factor == 3 ? 2 : 0);
/* Unaligned copy region dimensions (in pixels / lines) prior to tile alignment.
- * Also divide vp_widht/height by NoOfDPP for MPC combine scenarios (i.e., MPC split within an ODM slice). */
- copy_width = vertical_access ? copy_src_lines : (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_width / p->NoOfDPP[plane_idx]));
- copy_height = vertical_access ? (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_height / p->NoOfDPP[plane_idx])) : copy_src_lines;
+ * No need to divide vp width/height by NoOfDPP. The entire viewport could be within a single ODM slice if less than the odm slice pixels
+ * (e.g., multi-plane scenario with ODM combine). */
+ copy_width = vertical_access ? copy_src_lines : (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_width));
+ copy_height = vertical_access ? (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_height)) : copy_src_lines;
return calculate_tile_aligned_size(copy_width, copy_height, tile_width, tile_height, byte_per_pixel);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c
index 0bdf0d902aa0..23bd073f1889 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c
@@ -145,7 +145,7 @@ static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_4_display
static const int base_pstate_strategy_list_4_display_size = sizeof(base_pstate_strategy_list_4_display) / sizeof(struct dml2_pmo_pstate_strategy);
-static void dml2_pmo_dcn6_assign_pstate_strategies(struct dml2_pmo_instance *pmo)
+void dml2_pmo_dcn6_assign_pstate_strategies(struct dml2_pmo_instance *pmo)
{
int i = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h
index dd7d9f855988..b3b297aca47a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h
@@ -6,6 +6,7 @@
#define __DML2_PMO_DCN6_H__
#include "dml2_internal_shared_types.h"
+void dml2_pmo_dcn6_assign_pstate_strategies(struct dml2_pmo_instance *pmo);
bool dml2_pmo_dcn6a_initialize(struct dml2_pmo_initialize_in_out *in_out);
int dml2_pmo_dcn6a_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **optimers);
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
index 366767f4413e..6a9f822b2b33 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
@@ -828,6 +828,9 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm
plane->composition.rect_out_height_spans_vactive =
plane_state->dst_rect.height >= stream->src.height &&
stream->dst.height >= (int)stream->timing.v_addressable;
+
+ if (plane_state->ctx->dc->debug.force_mpc_combine)
+ plane->overrides.mpcc_combine_factor = plane_state->ctx->dc->debug.force_mpc_combine;
}
//TODO : Could be possibly moved to a common helper layer.
@@ -1027,8 +1030,8 @@ void dml21_copy_clocks_to_dc_state(struct dml2_context *in_ctx, struct dc_state
context->bw_ctx.bw.dcn.clk.subvp_prefetch_dramclk_khz = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.svp_prefetch_no_throttle.uclk_khz;
context->bw_ctx.bw.dcn.clk.subvp_prefetch_fclk_khz = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.svp_prefetch_no_throttle.fclk_khz;
context->bw_ctx.bw.dcn.clk.utm_latency_ub_index = 0; /* TODO - derive from qos model */
- context->bw_ctx.bw.dcn.clk.utm_nominal_bandwidth_lb_Kbps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.non_urgent_bandwidth_kbps;
- context->bw_ctx.bw.dcn.clk.utm_urgent_bandwidth_lb_Kbps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.urgent_bandwidth_kbps;
+ context->bw_ctx.bw.dcn.clk.utm_nominal_bandwidth_lb_KBps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.non_urgent_bandwidth_kbps;
+ context->bw_ctx.bw.dcn.clk.utm_urgent_bandwidth_lb_KBps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.urgent_bandwidth_kbps;
context->bw_ctx.bw.dcn.clk.stutter_efficiency.base_efficiency = (uint8_t)in_ctx->v21.mode_programming.programming->stutter.base_percent_efficiency;
context->bw_ctx.bw.dcn.clk.stutter_efficiency.low_power_efficiency = (uint8_t)in_ctx->v21.mode_programming.programming->stutter.low_power_percent_efficiency;
context->bw_ctx.bw.dcn.clk.stutter_efficiency.z8_stutter_efficiency = (uint8_t)in_ctx->v21.mode_programming.programming->informative.power_management.z8.stutter_efficiency;
@@ -1168,8 +1171,8 @@ void dml21_init_min_clocks_for_dc_state(struct dml2_context *in_ctx, struct dc_s
min_clocks->subvp_prefetch_fclk_khz = 0;
min_clocks->phyclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.phyclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->utm_latency_ub_index = 0; /* TODO - derive from qos model */
- min_clocks->utm_nominal_bandwidth_lb_Kbps = 0;
- min_clocks->utm_urgent_bandwidth_lb_Kbps = 0;
+ min_clocks->utm_nominal_bandwidth_lb_KBps = 0;
+ min_clocks->utm_urgent_bandwidth_lb_KBps = 0;
min_clocks->stutter_efficiency.base_efficiency = 1;
min_clocks->stutter_efficiency.low_power_efficiency = 1;
min_clocks->stutter_efficiency.z8_stutter_efficiency = 1;
diff --git a/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.c b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.c
new file mode 100644
index 000000000000..d99c1bd6e914
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include "dm_services.h"
+#include "dc_dmub_srv.h"
+#include "hwss/hw_sequencer.h"
+#include "dmub_messenger/dmub_messenger.h"
+
+static enum dmub_msg_result dmub_inbox_cmd_send_and_wait(
+ struct dmub_messenger *messenger,
+ const struct dmub_send_cmd_params *params)
+{
+ if (!messenger || !messenger->ctx || !messenger->dc_dmub_srv ||
+ !messenger->dc_dmub_srv->dmub || !params ||
+ !params->cmd)
+ return DMUB_MSG_ERROR;
+
+ if (messenger->dc_dmub_srv->idle_allowed && !messenger->ctx->dc)
+ return DMUB_MSG_ERROR;
+
+ /*
+ * Transport only: copy the builder-built command through the
+ * injected DMUB service. Do not read the command header or payload.
+ */
+ if (!dc_wake_and_execute_dmub_cmd(messenger->ctx, params->cmd,
+ params->wait_type))
+ return DMUB_MSG_ERROR;
+
+ return DMUB_MSG_OK;
+}
+
+static enum dmub_msg_result dmub_gpint_send_and_wait(
+ struct dmub_messenger *messenger,
+ const struct dmub_gpint_params *params)
+{
+ struct dmub_srv *dmub;
+
+ if (!messenger || !messenger->ctx || !messenger->dc_dmub_srv ||
+ !messenger->dc_dmub_srv->dmub || !params ||
+ !params->response)
+ return DMUB_MSG_ERROR;
+
+ if (messenger->dc_dmub_srv->idle_allowed && !messenger->ctx->dc)
+ return DMUB_MSG_ERROR;
+
+ dmub = messenger->dc_dmub_srv->dmub;
+ if (!dmub->sw_init || !dmub->hw_funcs.set_gpint ||
+ !dmub->hw_funcs.is_gpint_acked ||
+ !dmub->hw_funcs.get_gpint_response)
+ return DMUB_MSG_ERROR;
+
+ /*
+ * Transport only: issue the builder-selected GPINT and write the
+ * raw response. Do not interpret the command or the result.
+ */
+ if (!dc_wake_and_execute_gpint(messenger->ctx,
+ (enum dmub_gpint_command)params->command_code,
+ (uint16_t)params->param, params->response,
+ DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
+ return DMUB_MSG_ERROR;
+
+ return DMUB_MSG_OK;
+}
+
+static const struct dmub_messenger_funcs dmub_messenger_funcs = {
+ .inbox_cmd_send_and_wait = dmub_inbox_cmd_send_and_wait,
+ .gpint_send_and_wait = dmub_gpint_send_and_wait,
+};
+
+void dmub_messenger_construct(struct dmub_messenger *messenger,
+ const struct dmub_messenger_init_data *init_data)
+{
+ if (!messenger)
+ return;
+
+ messenger->funcs = &dmub_messenger_funcs;
+ messenger->ctx = init_data ? init_data->ctx : NULL;
+ messenger->dc_dmub_srv = init_data ? init_data->dc_dmub_srv : NULL;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.h b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.h
new file mode 100644
index 000000000000..6d3bf5791e28
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "dm_services_types.h"
+
+struct dc_context;
+struct dc_dmub_srv;
+struct dmub_gpint_params;
+union dmub_rb_cmd;
+
+/*
+ * Live DMUB_SEND_DMCUB_CMD still carries wait_type. Distinct inbox
+ * primitives are unresolved in the DMUB Messenger spec, so this shim
+ * forwards the builder-selected wait without interpreting the command.
+ */
+struct dmub_send_cmd_params {
+ union dmub_rb_cmd *cmd;
+ enum dm_dmub_wait_type wait_type;
+};
+
+struct dmub_messenger_init_data {
+ struct dc_context *ctx;
+ struct dc_dmub_srv *dc_dmub_srv;
+};
+
+enum dmub_msg_result {
+ DMUB_MSG_OK,
+ DMUB_MSG_NO_MSG,
+ DMUB_MSG_TIMEOUT,
+ DMUB_MSG_ERROR,
+};
+
+struct dmub_messenger;
+
+struct dmub_messenger_funcs {
+ enum dmub_msg_result (*inbox_cmd_send_and_wait)(
+ struct dmub_messenger *messenger,
+ const struct dmub_send_cmd_params *params);
+ enum dmub_msg_result (*gpint_send_and_wait)(
+ struct dmub_messenger *messenger,
+ const struct dmub_gpint_params *params);
+};
+
+struct dmub_messenger {
+ const struct dmub_messenger_funcs *funcs;
+ struct dc_context *ctx;
+ struct dc_dmub_srv *dc_dmub_srv;
+};
+
+void dmub_messenger_construct(struct dmub_messenger *messenger,
+ const struct dmub_messenger_init_data *init_data);
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
index 95f8b7c7d657..66010841dcf8 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
@@ -552,6 +552,25 @@ void dal_gpio_destroy_ddc(
*ddc = NULL;
}
+/* Switch the DDC pad to AUX mode, one time only. */
+void dal_gpio_ddc_open_aux_once(
+ struct gpio_service *service,
+ uint32_t offset,
+ uint32_t mask,
+ const struct gpio_ddc_hw_info *info)
+{
+ struct gpio_ddc_hw_info hw_info = *info;
+ struct ddc *ddc_pin;
+
+ ddc_pin = dal_gpio_create_ddc(service, offset, mask, &hw_info);
+ if (!ddc_pin)
+ return;
+
+ dal_ddc_open(ddc_pin, GPIO_MODE_HARDWARE,
+ GPIO_DDC_CONFIG_TYPE_MODE_AUX);
+ dal_gpio_destroy_ddc(&ddc_pin);
+}
+
enum gpio_result dal_ddc_open(
struct ddc *ddc,
enum gpio_mode mode,
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 f2391d45d4c5..09692fc817f9 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
@@ -169,15 +169,11 @@ void dcn401_init_hw(struct dc *dc)
//}
// Set default OPTC memory power states
- if (dc->debug.enable_mem_low_power.bits.optc) {
- // Shutdown when unassigned and light sleep in VBLANK
- REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
- }
+ if (dc->debug.enable_mem_low_power.bits.optc)
+ dcn401_init_odm_mem_power(hws);
- if (dc->debug.enable_mem_low_power.bits.vga) {
- // Power down VGA memory
- REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
- }
+ if (dc->debug.enable_mem_low_power.bits.vga)
+ dcn401_power_down_vga_mem(hws);
if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz =
@@ -367,7 +363,7 @@ void dcn401_init_hw(struct dc *dc)
if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating)
dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true);
- REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
+ dcn401_dcfclk_gating_control(hws, true);
}
dcn401_setup_hpo_hw_control(hws, true);
@@ -818,15 +814,6 @@ enum dc_status dcn401_enable_stream_timing(
hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
- /* Legacy code path will enable DSC during DPMS on sequence. Since DSC
- * HW block programming is independent from link and stream encoder operations, it
- * has moved to hwss and should be called when enabling/disabling OTG.
- */
- if (stream->timing.flags.DSC && pipe_ctx->stream_res.dsc) {
- if (dc->hwss.configure_dsc)
- dc->hwss.configure_dsc(pipe_ctx, true);
- }
-
/* VTG is within DCHUB command block. DCFCLK is always on */
if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
BREAK_TO_DEBUGGER();
@@ -981,6 +968,22 @@ void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable);
}
+void dcn401_init_odm_mem_power(struct dce_hwseq *hws)
+{
+ // Shutdown when unassigned and light sleep in VBLANK
+ REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
+}
+
+void dcn401_power_down_vga_mem(struct dce_hwseq *hws)
+{
+ REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
+}
+
+void dcn401_dcfclk_gating_control(struct dce_hwseq *hws, bool enable)
+{
+ REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, !enable);
+}
+
void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy)
{
if (cursor_width <= 128) {
@@ -2125,15 +2128,6 @@ void dcn401_reset_back_end_for_pipe(
pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
- /* Legacy code path will enable DSC during DPMS on sequence. Since DSC
- * HW block programming is independent from backend operations, it
- * has moved to hwss and should be called when enabling/disabling OTG.
- */
- if (pipe_ctx->stream_res.dsc) {
- if (dc->hwss.configure_dsc)
- dc->hwss.configure_dsc(pipe_ctx, false);
- }
-
pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
}
if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
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 9df72e980e7a..d5853cd01a93 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
@@ -50,6 +50,9 @@ enum dc_status dcn401_enable_stream_timing(
struct dc *dc);
void dcn401_enable_stream(struct pipe_ctx *pipe_ctx);
void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable);
+void dcn401_init_odm_mem_power(struct dce_hwseq *hws);
+void dcn401_power_down_vga_mem(struct dce_hwseq *hws);
+void dcn401_dcfclk_gating_control(struct dce_hwseq *hws, bool enable);
void dcn401_disable_link_output(struct dc_link *link,
const struct link_resource *link_res,
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 1a387e52218d..dbeda44ebc8e 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
@@ -150,6 +150,10 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
.plane_atomic_power_down = dcn401_plane_atomic_power_down,
.plane_atomic_power_down_sequence = dcn401_plane_atomic_power_down_sequence,
.enable_power_gating_plane = dcn32_enable_power_gating_plane,
+ .init_hpo_hw_control = dcn401_setup_hpo_hw_control,
+ .init_odm_mem_power = dcn401_init_odm_mem_power,
+ .power_down_vga_mem = dcn401_power_down_vga_mem,
+ .dcfclk_gating_control = dcn401_dcfclk_gating_control,
.hubp_pg_control = dcn32_hubp_pg_control,
.program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
.program_all_writeback_pipes_in_tree_sequence = dcn401_program_all_writeback_pipes_in_tree_sequence,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
index c5fab430b7f7..f8254dfe1ce7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
@@ -53,103 +53,6 @@
#define FN(reg_name, field_name) \
hws->shifts->field_name, hws->masks->field_name
-bool dcn60_configure_dsc(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct pipe_ctx *odm_pipe;
- struct dccg *dccg = dc->res_pool->dccg;
- struct dsc_config dsc_cfg = {0};
- struct dsc_optc_config dsc_optc_cfg = {0};
- uint32_t odm_count = 1;
-
- /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN
- * register access hung. When DSCCLk is based on refclk, DSCCLk is always a
- * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is
- * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings
- * with DSC such as 480p60Hz, the dispclk could be low enough to trigger
- * this problem. We are implementing a workaround here to keep using dscclk
- * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e
- * 48Mhz) pixel clock to avoid hitting this problem.
- */
- bool use_dto = dccg->funcs->set_dto_dscclk && stream->timing.pix_clk_100hz > 480000;
-
- if (!dsc)
- return false;
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- odm_count++;
-
- if (enable) {
- dsc_cfg.pic_width = (stream->timing.h_addressable +
- pipe_ctx->dsc_padding_params.dsc_hactive_padding +
- stream->timing.h_border_left + stream->timing.h_border_right) / odm_count;
- dsc_cfg.pic_height = stream->timing.v_addressable +
- stream->timing.v_border_top + stream->timing.v_border_bottom;
- dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
- dsc_cfg.color_depth = stream->timing.display_color_depth;
- dsc_cfg.is_odm = pipe_ctx->next_odm_pipe != NULL;
- dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
- ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % odm_count == 0);
- dsc_cfg.dc_dsc_cfg.num_slices_h /= odm_count;
-
- if (use_dto)
- dccg->funcs->set_dto_dscclk(dccg, dsc->inst,
- (uint32_t)dsc_cfg.dc_dsc_cfg.num_slices_h);
- if (!dsc->funcs->dsc_prepare_config(dsc, &dsc_cfg, &dsc_optc_cfg)) {
- ASSERT(false);
- return false;
- }
- dsc->funcs->dsc_set_config(dsc);
- dsc->funcs->dsc_enable(dsc, (int)pipe_ctx->stream_res.opp->inst);
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
- struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
-
- ASSERT(odm_dsc);
- if (!odm_dsc)
- return false;
- if (use_dto)
- dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst,
- (uint32_t)dsc_cfg.dc_dsc_cfg.num_slices_h);
- if (!odm_dsc->funcs->dsc_prepare_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg)) {
- ASSERT(false);
- return false;
- }
- odm_dsc->funcs->dsc_set_config(odm_dsc);
- odm_dsc->funcs->dsc_enable(odm_dsc, (int)odm_pipe->stream_res.opp->inst);
- }
-
- {
- enum optc_dsc_mode mode = dsc_optc_cfg.is_pixel_format_444 ?
- OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
-
- DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(
- pipe_ctx->stream_res.tg, mode,
- dsc_optc_cfg.bytes_per_pixel, dsc_optc_cfg.slice_width);
- }
- return true;
- }
-
- DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(
- pipe_ctx->stream_res.tg, OPTC_DSC_DISABLED, 0, 0);
-
- for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
- struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
-
- if (!odm_dsc)
- continue;
- odm_dsc->funcs->dsc_disconnect(odm_dsc);
- odm_dsc->funcs->dsc_disable(odm_dsc);
- if (dccg->funcs->set_ref_dscclk)
- dccg->funcs->set_ref_dscclk(dccg, (uint32_t)odm_dsc->inst);
- }
- return true;
-}
-
bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params)
{
struct dpp *dpp_base = params->dpp;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
index 44eb30608feb..b880988ff1fc 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
@@ -31,6 +31,5 @@ void dcn60_program_perfmon(struct dc *dc, struct dc_state *context);
bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable);
bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params);
-bool dcn60_configure_dsc(struct pipe_ctx *pipe_ctx, bool enable);
#endif /* __DC_HWSS_DCN60_H__ */
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 7b488753fe50..80125c3596ce 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
@@ -25,7 +25,6 @@ static const struct hw_sequencer_funcs dcn60_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn50_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
- .configure_dsc = dcn60_configure_dsc,
.prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
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 8f4ed80385fc..3ee6129a388d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -63,6 +63,7 @@ struct hpo_frl_stream_encoder;
struct link_training_settings;
struct dc_link;
struct dc_crtc_timing;
+struct dmub_srv_hw_params;
struct tg_lock_params {
struct dc *dc;
@@ -140,6 +141,147 @@ struct send_dmcub_cmd_params {
struct dc_context *ctx;
union dmub_rb_cmd *cmd;
enum dm_dmub_wait_type wait_type;
+ bool continue_on_error;
+};
+
+struct dmub_gpint_params {
+ unsigned int command_code;
+ unsigned int param;
+ unsigned int *response;
+};
+
+struct psp_reload_dmub_fw_params {
+ struct dmub_srv *dmub;
+ const struct dmub_srv_hw_params *hw_params;
+};
+
+struct hwseq_reg_control_params {
+ struct dce_hwseq *hws;
+ bool enable;
+};
+
+struct dc_init_call_params {
+ struct dc *dc;
+ bool enable;
+};
+
+struct dccg_get_ref_freq_params {
+ struct dccg *dccg;
+ unsigned int xtalin_khz;
+ unsigned int *out_xtalin_khz;
+ unsigned int *out_dccg_ref_khz;
+};
+
+struct hubbub_get_dchub_ref_freq_params {
+ struct hubbub *hubbub;
+ unsigned int dccg_ref_khz;
+ unsigned int *out_dchub_ref_khz;
+};
+
+struct link_enc_hw_init_params {
+ struct link_encoder *link_enc;
+};
+
+struct link_enc_is_dig_enabled_params {
+ struct link_encoder *link_enc;
+ bool *out_dig_enabled;
+};
+
+struct link_enc_fec_is_active_params {
+ struct link_encoder *link_enc;
+ bool *out_fec_active;
+};
+
+struct clk_mgr_get_dispclk_from_dentist_params {
+ struct clk_mgr *clk_mgr;
+ int *out_dispclk_khz;
+};
+
+struct edp_control_params {
+ struct dc_link *link;
+ bool enable;
+};
+
+struct bios_get_i2c_info_params {
+ struct dc_bios *dcb;
+ struct graphics_object_id link_id;
+ struct graphics_object_i2c_info *out_info;
+ enum bp_result *out_result;
+};
+
+struct hubbub_allow_self_refresh_control_params {
+ struct hubbub *hubbub;
+ bool allow;
+};
+
+struct audio_hw_init_params {
+ struct audio *audio;
+};
+
+struct panel_cntl_hw_init_params {
+ struct panel_cntl *panel_cntl;
+ uint32_t *out_backlight;
+ uint32_t *out_user_level;
+};
+
+struct gpio_ddc_open_params {
+ struct gpio_service *gpio_service;
+ uint32_t clk_a_register_index;
+ uint32_t clk_a_mask;
+ struct gpio_ddc_hw_info hw_info;
+};
+
+struct abm_init_params {
+ struct abm *abm;
+ uint32_t backlight;
+ uint32_t user_level;
+};
+
+struct dio_set_mem_power_params {
+ struct dio *dio;
+ bool enable;
+};
+
+struct dccg_set_root_clock_gating_params {
+ struct dccg *dccg;
+ bool allow;
+};
+
+struct hubbub_init_watermarks_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_init_crb_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_set_request_limit_params {
+ struct hubbub *hubbub;
+ unsigned int num_chans;
+ unsigned int words_per_umc;
+};
+
+struct clk_mgr_initialize_min_clocks_params {
+ struct clk_mgr *clk_mgr;
+ struct dc_state *context;
+ int dcfclk_deep_sleep_khz;
+ int dcfclk_khz;
+ int socclk_khz;
+ int dramclk_khz;
+ int dppclk_khz;
+ int dispclk_khz;
+ int ref_dtbclk_khz;
+ bool fclk_p_state_change_support;
+ bool p_state_change_support;
+};
+
+struct clk_mgr_notify_wm_ranges_params {
+ struct clk_mgr *clk_mgr;
+};
+
+struct bios_is_accelerated_mode_params {
+ struct dc_bios *dcb;
+ bool *out_accelerated_mode;
};
struct lsdma_send_pio_copy_params {
@@ -1003,6 +1145,19 @@ struct clk_mgr_update_clocks_params {
struct clk_mgr *clk_mgr;
};
+struct legacy_clk_mgr_init_clocks_params {
+ struct clk_mgr *clk_mgr;
+};
+
+struct legacy_clk_mgr_is_dc_mode_present_params {
+ struct clk_mgr *clk_mgr;
+ bool *out_dcmode_power_limits_present;
+};
+
+struct dccg_initialize_clocks_params {
+ struct dccg *dccg;
+};
+
struct hubbub_program_watermarks_params {
struct dc *dc;
struct hubbub *hubbub;
@@ -1198,6 +1353,40 @@ union block_sequence_params {
struct link_set_dpms_on_params link_set_dpms_on_params;
struct clk_mgr_set_max_memclk_params clk_mgr_set_max_memclk_params;
struct clk_mgr_update_clocks_params clk_mgr_update_clocks_params;
+ struct legacy_clk_mgr_init_clocks_params
+ legacy_clk_mgr_init_clocks_params;
+ struct legacy_clk_mgr_is_dc_mode_present_params
+ legacy_clk_mgr_is_dc_mode_present_params;
+ struct dccg_initialize_clocks_params dccg_initialize_clocks_params;
+ struct dmub_gpint_params dmub_gpint_params;
+ struct psp_reload_dmub_fw_params psp_reload_dmub_fw_params;
+ struct hwseq_reg_control_params hwseq_reg_control_params;
+ struct dc_init_call_params dc_init_call_params;
+ struct dccg_get_ref_freq_params dccg_get_ref_freq_params;
+ struct hubbub_get_dchub_ref_freq_params hubbub_get_dchub_ref_freq_params;
+ struct link_enc_hw_init_params link_enc_hw_init_params;
+ struct link_enc_is_dig_enabled_params link_enc_is_dig_enabled_params;
+ struct link_enc_fec_is_active_params link_enc_fec_is_active_params;
+ struct clk_mgr_get_dispclk_from_dentist_params
+ clk_mgr_get_dispclk_from_dentist_params;
+ struct edp_control_params edp_control_params;
+ struct bios_get_i2c_info_params bios_get_i2c_info_params;
+ struct hubbub_allow_self_refresh_control_params
+ hubbub_allow_self_refresh_control_params;
+ struct audio_hw_init_params audio_hw_init_params;
+ struct panel_cntl_hw_init_params panel_cntl_hw_init_params;
+ struct gpio_ddc_open_params gpio_ddc_open_params;
+ struct abm_init_params abm_init_params;
+ struct dio_set_mem_power_params dio_set_mem_power_params;
+ struct dccg_set_root_clock_gating_params
+ dccg_set_root_clock_gating_params;
+ struct hubbub_init_watermarks_params hubbub_init_watermarks_params;
+ struct hubbub_init_crb_params hubbub_init_crb_params;
+ struct hubbub_set_request_limit_params hubbub_set_request_limit_params;
+ struct clk_mgr_initialize_min_clocks_params
+ clk_mgr_initialize_min_clocks_params;
+ struct clk_mgr_notify_wm_ranges_params clk_mgr_notify_wm_ranges_params;
+ struct bios_is_accelerated_mode_params bios_is_accelerated_mode_params;
struct hubbub_program_watermarks_params hubbub_program_watermarks_params;
struct hubbub_program_arbiter_params hubbub_program_arbiter_params;
struct hubbub_program_compbuf_segments_params hubbub_program_compbuf_segments_params;
@@ -1368,6 +1557,45 @@ enum block_sequence_func {
HUBBUB_PERFMON_GET_URGENT_ASSERTION_COUNT,
HUBBUB_PERFMON_GET_PREFETCH_DATA_SIZE,
HUBBUB_PERFMON_GET_URGENT_RAMP_LATENCY,
+ LEGACY_CLK_MGR_INIT_CLOCKS,
+ LEGACY_CLK_MGR_IS_DC_MODE_PRESENT,
+ DCCG_INITIALIZE_CLOCKS,
+ DMUB_GPINT_SEND_AND_WAIT,
+ DMUB_HALT_FW,
+ PSP_RELOAD_DMUB_FW,
+ DMUB_INITIALIZE_DCN,
+ OPTC_SET_ODM_MEM_POWER,
+ MMHUBBUB_SET_MEM_POWER,
+ DCCG_GET_REF_FREQ,
+ HUBBUB_GET_DCHUB_REF_FREQ,
+ DIO_LINK_ENC_HW_INIT,
+ DIO_LINK_ENC_IS_DIG_ENABLED,
+ DIO_LINK_ENC_FEC_IS_ACTIVE,
+ BIOS_GET_I2C_INFO,
+ PG_SET_PLANE_POWER_GATING,
+ LINK_BLANK_ALL_DP_DISPLAYS,
+ HWSS_ENABLE_ACCELERATED_MODE,
+ HWSEQ_INIT_PIPES,
+ HUBBUB_ALLOW_SELF_REFRESH_CONTROL,
+ CLK_MGR_GET_DISPCLK_FROM_DENTIST,
+ LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS,
+ DMUB_SET_IDLE_OPTIMIZATION,
+ EDP_BACKLIGHT_CONTROL,
+ HWSEQ_POWER_DOWN,
+ EDP_POWER_CONTROL,
+ AUDIO_HW_INIT,
+ PANEL_CNTL_HW_INIT,
+ GPIO_DDC_OPEN,
+ ABM_INIT,
+ DIO_AFMT_SET_MEM_POWER,
+ DCCG_SET_ROOT_CLOCK_GATING,
+ DCCG_SET_DCFCLK_GATING,
+ HPO_SET_HW_CONTROL,
+ HUBBUB_INIT_WATERMARKS,
+ LEGACY_CLK_MGR_NOTIFY_WM_RANGES,
+ HUBBUB_INIT_CRB,
+ HUBBUB_SET_REQUEST_LIMIT,
+ BIOS_IS_ACCELERATED_MODE,
/* This must be the last value in this enum, add new ones above */
HWSS_BLOCK_SEQUENCE_FUNC_COUNT
};
@@ -1413,7 +1641,6 @@ struct hw_sequencer_funcs {
struct dc_state *context);
void (*update_plane_addr)(const struct dc *dc,
struct pipe_ctx *pipe_ctx);
- bool (*configure_dsc)(struct pipe_ctx *pipe_ctx, bool enable);
void (*prepare_plane_addr_update)(const struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_plane_address *addr_to_program,
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 9c5e9abf5a95..91a84fb50b59 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
@@ -203,6 +203,14 @@ struct hwseq_private_funcs {
void (*PLAT_58856_wa)(struct dc_state *context,
struct pipe_ctx *pipe_ctx);
void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable);
+ /*
+ * Init-time only. setup_hpo_hw_control also drives the HPO toggle
+ * on every commit, so a DCN that leaves it unset keeps it unset.
+ */
+ void (*init_hpo_hw_control)(const struct dce_hwseq *hws, bool enable);
+ void (*init_odm_mem_power)(struct dce_hwseq *hws);
+ void (*power_down_vga_mem)(struct dce_hwseq *hws);
+ void (*dcfclk_gating_control)(struct dce_hwseq *hws, bool enable);
void (*enable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx,
struct dc_state *context);
void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index 6563eaaa0c0c..695eaa5cbf65 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -40,6 +40,7 @@
#include "mcif_wb.h"
#include "panel_cntl.h"
#include "dmub/inc/dmub_cmd.h"
+#include "bls_builder/bls_builder_legacy_init.h"
#include "pg_cntl.h"
#include "sspl/dc_spl.h"
@@ -722,6 +723,12 @@ struct dc_state {
} perf_params;
enum dc_power_source_type power_source;
+
+ /**
+ * @hw_init_info: DC2_DC1_Wrapped hardware init progress and the
+ * outputs of each stage run so far
+ */
+ struct bls_builder_legacy_hw_init_info hw_init_info;
};
struct replay_context {
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 f3ef5bbfad81..1c95d643af14 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
@@ -117,6 +117,8 @@ struct link_enc_state {
uint32_t dphy_fec_ready_shadow;
uint32_t dphy_fec_active_status;
uint32_t dp_link_training_complete;
+ uint32_t rdpcs_phy_reset;
+ uint32_t rdpcs_tx_data_en;
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
index 75ebfab87efc..a0a8ab195533 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
@@ -298,6 +298,7 @@ struct mpcc_state {
uint32_t overlap_only;
uint32_t idle;
uint32_t busy;
+ uint32_t cur_vupdate_lock;
uint32_t shaper_lut_mode;
uint32_t lut3d_mode;
uint32_t lut3d_bit_depth;
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
index d3172dbdcdf0..83f676a49fd1 100644
--- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
@@ -80,6 +80,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link,
struct dc_stream_state *streams_on_link[MAX_PIPES];
int num_streams_on_link = 0;
struct dc *dc = (struct dc *)link->dc;
+ struct dc_surface_update *srf_updates;
needs_divider_update = (link->dc->link_srv->dp_get_encoding_format(link_setting) !=
link->dc->link_srv->dp_get_encoding_format((const struct dc_link_settings *) &link->cur_link_settings))
@@ -151,13 +152,29 @@ static void dp_retrain_link_dp_test(struct dc_link *link,
streams_on_link[num_streams_on_link++] = state->streams[i];
}
+ srf_updates = kcalloc(MAX_SURFACES, sizeof(*srf_updates), GFP_KERNEL);
+
for (i = 0; i < num_streams_on_link; i++) {
if (streams_on_link[i] && streams_on_link[i]->link && streams_on_link[i]->link == link) {
+ struct dc_stream_status *stream_status = dc_stream_get_status(streams_on_link[i]);
+ int surface_count = 0;
+ int j;
+
+ if (srf_updates && stream_status) {
+ memset(srf_updates, 0, MAX_SURFACES * sizeof(*srf_updates));
+ for (j = 0; j < stream_status->plane_count; j++)
+ srf_updates[j].surface = stream_status->plane_states[j];
+ surface_count = stream_status->plane_count;
+ }
+
stream_update.stream = streams_on_link[i];
stream_update.dpms_off = &dpms_off;
- dc_update_planes_and_stream(dc, NULL, 0, streams_on_link[i], &stream_update);
+ dc_update_planes_and_stream(dc, srf_updates, surface_count,
+ streams_on_link[i], &stream_update);
}
}
+
+ kfree(srf_updates);
}
static void dp_test_send_link_training(struct dc_link *link)
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index 9b5b0599d977..75e232ebffe8 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -717,94 +717,21 @@ static bool dp_set_hblank_reduction_on_rx(struct pipe_ctx *pipe_ctx)
return result;
}
-/* TODO - There is overlapping functionality between link_set_dsc_pps_packet,
- * and set_encoder_dsc_config, the two functions should be refactored to avoid code duplication.
- */
-static void set_encoder_dsc_config(struct pipe_ctx *pipe_ctx,
- struct dsc_config *dsc_cfg,
- struct dsc_optc_config *dsc_optc_cfg,
- bool enable)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- enum optc_dsc_mode optc_dsc_mode;
- int odm_count = 1;
- struct pipe_ctx *odm_pipe;
- DC_LOGGER_INIT(dsc->ctx->logger);
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- odm_count++;
-
- if (enable) {
- optc_dsc_mode = dsc_optc_cfg->is_pixel_format_444 ?
- OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
-
- if (dc_is_dp_signal(stream->signal) && !dp_is_128b_132b_signal(pipe_ctx)) {
- DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
- dsc_optc_config_log(dsc, dsc_optc_cfg);
- if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config)
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
- optc_dsc_mode,
- dsc_optc_cfg->bytes_per_pixel,
- dsc_optc_cfg->slice_width);
-
- /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
- } else if (dc_is_hdmi_frl_signal(stream->signal)) {
- uint8_t dsc_packed_pps[128];
- struct dc_crtc_timing patched_crtc_timing = stream->timing;
-
- DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.hpo_frl_stream_enc->id);
- dsc_optc_config_log(dsc, dsc_optc_cfg);
- dsc_cfg->dc_dsc_cfg.num_slices_h *= odm_count;
- dsc_cfg->pic_width *= odm_count;
- dsc_cfg->dsc_padding = pipe_ctx->dsc_padding_params.dsc_hactive_padding;
- if (dc->debug.enable_hblank_borrow)
- dsc_cfg->pic_width = stream->timing.h_addressable;
- dsc->funcs->dsc_get_packed_pps(dsc, dsc_cfg, &dsc_packed_pps[0]);
- pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
- pipe_ctx->stream_res.hpo_frl_stream_enc, &patched_crtc_timing, &dsc_packed_pps[0]);
- }
-
- return;
- }
- if (dc_is_dp_signal(stream->signal)) {
- if (dp_is_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- false,
- NULL,
- true);
- else {
- if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config)
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
- pipe_ctx->stream_res.stream_enc,
- OPTC_DSC_DISABLED, 0, 0);
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc, false, NULL, true);
- }
- } else if (dc_is_hdmi_frl_signal(stream->signal)) {
- pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
- pipe_ctx->stream_res.hpo_frl_stream_enc, &stream->timing, NULL);
- }
-}
-
-/* Legacy implementation of DSC configuration sequence. DSC HW block programming
- * is independent of stream encoder and link configuration operations, and should
- * be configured separately during front-end programming, not within link DPMS sequences.
+/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
+ * i.e. after dp_enable_dsc_on_rx() had been called
*/
-static bool configure_dsc_hw_block(struct pipe_ctx *pipe_ctx, bool enable,
- struct dsc_config *dsc_cfg, struct dsc_optc_config *dsc_optc_cfg)
+void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
{
+ /* TODO: Move this to HWSS as this is hardware programming sequence not a
+ * link layer sequence
+ */
struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
struct dc *dc = pipe_ctx->stream->ctx->dc;
struct dc_stream_state *stream = pipe_ctx->stream;
struct pipe_ctx *odm_pipe;
- struct dccg *dccg = dc->res_pool->dccg;
int opp_cnt = 1;
- DC_LOGGER_INIT(dsc->ctx->logger);
-
+ struct dccg *dccg = dc->res_pool->dccg;
/* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN
* register access hung. When DSCCLk is based on refclk, DSCCLk is always a
* fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is
@@ -814,34 +741,35 @@ static bool configure_dsc_hw_block(struct pipe_ctx *pipe_ctx, bool enable,
* based on fixed value refclk when timing is smaller than 3x16Mhz (i.e
* 48Mhz) pixel clock to avoid hitting this problem.
*/
- bool should_use_dto_dscclk = dccg->funcs->set_dto_dscclk &&
+ bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) &&
stream->timing.pix_clk_100hz > 480000;
+ DC_LOGGER_INIT(dsc->ctx->logger);
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
if (enable) {
+ struct dsc_config dsc_cfg;
+ struct dsc_optc_config dsc_optc_cfg = {0};
enum optc_dsc_mode optc_dsc_mode;
- memset(dsc_cfg, 0, sizeof(*dsc_cfg));
- memset(dsc_optc_cfg, 0, sizeof(*dsc_optc_cfg));
/* Enable DSC hw block */
- dsc_cfg->pic_width = (stream->timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding +
+ dsc_cfg.pic_width = (stream->timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding +
stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
- dsc_cfg->pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
- dsc_cfg->pixel_encoding = stream->timing.pixel_encoding;
- dsc_cfg->color_depth = stream->timing.display_color_depth;
- dsc_cfg->is_odm = pipe_ctx->next_odm_pipe != NULL;
- dsc_cfg->dc_dsc_cfg = stream->timing.dsc_cfg;
- ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_h % opp_cnt == 0);
- dsc_cfg->dc_dsc_cfg.num_slices_h /= opp_cnt;
- dsc_cfg->dsc_padding = 0;
+ dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+ ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
+ dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
+ dsc_cfg.dsc_padding = 0;
if (should_use_dto_dscclk)
- dccg->funcs->set_dto_dscclk(dccg, dsc->inst, dsc_cfg->dc_dsc_cfg.num_slices_h);
- if (!dsc->funcs->dsc_prepare_config(dsc, dsc_cfg, dsc_optc_cfg)) {
+ dccg->funcs->set_dto_dscclk(dccg, dsc->inst, dsc_cfg.dc_dsc_cfg.num_slices_h);
+ if (!dsc->funcs->dsc_prepare_config(dsc, &dsc_cfg, &dsc_optc_cfg)) {
ASSERT(false);
- return false;
+ return;
}
dsc->funcs->dsc_set_config(dsc);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
@@ -850,92 +778,110 @@ static bool configure_dsc_hw_block(struct pipe_ctx *pipe_ctx, bool enable,
ASSERT(odm_dsc);
if (!odm_dsc)
- return false;
+ return;
if (should_use_dto_dscclk)
- dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst,
- dsc_cfg->dc_dsc_cfg.num_slices_h);
- if (!odm_dsc->funcs->dsc_prepare_config(odm_dsc, dsc_cfg, dsc_optc_cfg)) {
+ dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, dsc_cfg.dc_dsc_cfg.num_slices_h);
+ if (!odm_dsc->funcs->dsc_prepare_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg)) {
ASSERT(false);
- return false;
+ return;
}
odm_dsc->funcs->dsc_set_config(odm_dsc);
odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
}
- optc_dsc_mode = dsc_optc_cfg->is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+ dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
+ dsc_cfg.pic_width *= opp_cnt;
+ dsc_cfg.dsc_padding = pipe_ctx->dsc_padding_params.dsc_hactive_padding;
- /* Enable DSC in OPTC */
- DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
- dsc_optc_config_log(dsc, dsc_optc_cfg);
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
- optc_dsc_mode,
- dsc_optc_cfg->bytes_per_pixel,
- dsc_optc_cfg->slice_width);
- return true;
- }
+ optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
- /* disable DSC in OPTC */
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(
- pipe_ctx->stream_res.tg,
- OPTC_DSC_DISABLED, 0, 0);
+ /* Enable DSC in encoder */
+ if (dc_is_dp_signal(stream->signal) && !dp_is_128b_132b_signal(pipe_ctx)) {
+ DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config)
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
- for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
- odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc);
+ /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
+ } else if (dc_is_hdmi_frl_signal(stream->signal)) {
+ uint8_t dsc_packed_pps[128];
+ struct dc_crtc_timing patched_crtc_timing = stream->timing;
- /*
- * dsc_disconnect is a double buffered register.
- * by the time we call dsc_disable, dsc may still remain
- * connected to OPP. In this case OPTC will no longer
- * get correct pixel data because DSCC is off. However
- * we also can't wait for the disconnect pending
- * complete, because this function can be called
- * with/without OTG master lock acquired. When the lock
- * is acquired we will never get pending complete until
- * we release the lock later. So there is no easy way to
- * solve this problem especially when the lock is
- * acquired. DSC is a front end hw block it should be
- * programmed as part of front end sequence, where the
- * commit sequence without lock and update sequence
- * with lock are completely separated. However because
- * we are programming dsc as part of back end link
- * programming sequence, we don't know if front end OPTC
- * master lock is acquired. The back end should be
- * agnostic to front end lock. DSC programming shouldn't
- * belong to this sequence.
- */
- odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
- if (dccg->funcs->set_ref_dscclk)
- dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst);
- }
- return true;
-}
+ DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.hpo_frl_stream_enc->id);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
-/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
- * i.e. after dp_enable_dsc_on_rx() had been called
- */
-void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dsc_config dsc_cfg = {0};
- struct dsc_optc_config dsc_optc_cfg = {0};
+ /* if we are borrowing from hblank, h_addressable and pic_width need to be adjusted */
+ if (dc->debug.enable_hblank_borrow) {
+ dsc_cfg.pic_width = stream->timing.h_addressable;
+ }
- if (!pipe_ctx->stream_res.dsc) {
- ASSERT(false);
- return;
- }
+ dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
+ pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
+ pipe_ctx->stream_res.hpo_frl_stream_enc, &patched_crtc_timing, &dsc_packed_pps[0]);
+ }
- if (dc->hwss.configure_dsc) {
- /* If the hwss configure_dsc function is supported, then DSC will be programmed
- * in the same sequence of OTG enable/disable. Thus, we don't need to configure
- * the DSC hw block here.
- */
- set_encoder_dsc_config(pipe_ctx, &dsc_cfg, &dsc_optc_cfg, false);
+ /* Enable DSC in OPTC */
+ DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
} else {
- if (enable) {
- if (configure_dsc_hw_block(pipe_ctx, true, &dsc_cfg, &dsc_optc_cfg))
- set_encoder_dsc_config(pipe_ctx, &dsc_cfg, &dsc_optc_cfg, true);
- } else {
- set_encoder_dsc_config(pipe_ctx, &dsc_cfg, &dsc_optc_cfg, false);
- configure_dsc_hw_block(pipe_ctx, false, &dsc_cfg, &dsc_optc_cfg);
+ /* disable DSC in OPTC */
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(
+ pipe_ctx->stream_res.tg,
+ OPTC_DSC_DISABLED, 0, 0);
+
+ /* disable DSC in stream encoder */
+ if (dc_is_dp_signal(stream->signal)) {
+ if (dp_is_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ false,
+ NULL,
+ true);
+ else {
+ if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config)
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
+ pipe_ctx->stream_res.stream_enc,
+ OPTC_DSC_DISABLED, 0, 0);
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL, true);
+ }
+ } else if (dc_is_hdmi_frl_signal(stream->signal))
+ pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
+ pipe_ctx->stream_res.hpo_frl_stream_enc, &stream->timing, NULL);
+
+ /* disable DSC block */
+ for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc);
+ /*
+ * TODO - dsc_disconnect is a double buffered register.
+ * by the time we call dsc_disable, dsc may still remain
+ * connected to OPP. In this case OPTC will no longer
+ * get correct pixel data because DSCC is off. However
+ * we also can't wait for the disconnect pending
+ * complete, because this function can be called
+ * with/without OTG master lock acquired. When the lock
+ * is acquired we will never get pending complete until
+ * we release the lock later. So there is no easy way to
+ * solve this problem especially when the lock is
+ * acquired. DSC is a front end hw block it should be
+ * programmed as part of front end sequence, where the
+ * commit sequence without lock and update sequence
+ * with lock are completely separated. However because
+ * we are programming dsc as part of back end link
+ * programming sequence, we don't know if front end OPTC
+ * master lock is acquired. The back end should be
+ * agnostic to front end lock. DSC programming shouldn't
+ * belong to this sequence.
+ */
+ odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
+ if (dccg->funcs->set_ref_dscclk)
+ dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst);
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
index f9bd1d6e1642..a737887b7c71 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
@@ -453,6 +453,8 @@ void mpc1_read_mpcc_state(
MPCC_BLND_ACTIVE_OVERLAP_ONLY, &s->overlap_only);
REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, &s->idle,
MPCC_BUSY, &s->busy);
+ if (s->opp_id < MAX_OPP && mpc10->mpc_regs->CUR[s->opp_id])
+ REG_GET(CUR[s->opp_id], CUR_VUPDATE_LOCK_SET, &s->cur_vupdate_lock);
}
void mpc1_cursor_lock(struct mpc *mpc, int opp_id, bool lock)
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
index 5f5c27eb1d64..a485db71c166 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
@@ -627,7 +627,7 @@ void mpc401_get_lut_mode(struct mpc *mpc,
}
}
-static void mpc401_read_mpcc_state(
+void mpc401_read_mpcc_state(
struct mpc *mpc,
int mpcc_inst,
struct mpcc_state *s)
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h
index 75fa05ed2b22..2731045f277c 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h
@@ -275,4 +275,9 @@ void mpc401_update_3dlut_fast_load_select(
int mpcc_id,
int hubp_idx);
+void mpc401_read_mpcc_state(
+ struct mpc *mpc,
+ int mpcc_inst,
+ struct mpcc_state *s);
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
index 37d024cfb3fb..f15690b026cc 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
@@ -65,16 +65,8 @@ void mpc42_update_blending(
-void mpc42_read_mpcc_state(
- struct mpc *mpc,
- int mpcc_inst,
- struct mpcc_state *s)
-{
- mpc1_read_mpcc_state(mpc, mpcc_inst, s);
-}
-
static const struct mpc_funcs dcn42_mpc_funcs = {
- .read_mpcc_state = mpc42_read_mpcc_state,
+ .read_mpcc_state = mpc401_read_mpcc_state,
.insert_plane = mpc1_insert_plane,
.remove_mpcc = mpc1_remove_mpcc,
.mpc_init = mpc32_mpc_init,
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
index e38582f0a319..89c4d431a82c 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
@@ -229,7 +229,7 @@ static bool mpc60_program_3dlut(
}
static const struct mpc_funcs dcn60_mpc_funcs = {
- .read_mpcc_state = mpc1_read_mpcc_state,
+ .read_mpcc_state = mpc401_read_mpcc_state,
.insert_plane = mpc60_insert_plane,
.remove_mpcc = mpc1_remove_mpcc,
.mpc_init = mpc32_mpc_init,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
index b78b0541d113..19e175f54f68 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
@@ -307,19 +307,23 @@ static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5];
#define link_regs_init(id, phyid) \
LE_DCN401_REG_LIST_RI(id), \
- LE_DCN60_REG_LIST_RI(id)
+ LE_DCN60_REG_LIST_RI(id), \
+ SRI_ARR(RDPCSTX_PHY_CNTL0, RDPCSTX, id), \
+ SRI_ARR(RDPCSTX_PHY_CNTL3, RDPCSTX, id)
static struct dcn10_link_enc_registers link_enc_regs[4];
static const struct dcn10_link_enc_shift le_shift = {
LINK_ENCODER_MASK_SH_LIST_DCN401(__SHIFT), \
- LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(__SHIFT)
+ LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(__SHIFT), \
+ LINK_ENCODER_PHY_STATE_MASK_SH_LIST_DCN401(__SHIFT)
};
static const struct dcn10_link_enc_mask le_mask = {
LINK_ENCODER_MASK_SH_LIST_DCN401(_MASK), \
- LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(_MASK)
+ LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(_MASK), \
+ LINK_ENCODER_PHY_STATE_MASK_SH_LIST_DCN401(_MASK)
};
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
index e172163942b4..2ad191ec5c38 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
@@ -816,7 +816,6 @@ static const struct dc_debug_options debug_defaults_drv = {
.min_deep_sleep_dcfclk_khz = 8000,
.replay_skip_crtc_disabled = true,
.psr_skip_crtc_disable = true,
- .force_odm2to1_for_edp_pixclk_mhz = 0, // disable the policy for now
.iommu_mismatch_temp_wka = 0x7,
};
@@ -1885,10 +1884,6 @@ enum dc_status dcn42_validate_bandwidth(struct dc *dc,
bool out = false;
DC_FP_START();
- if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING) {
- /*only do this when programing HW*/
- dcn42_decide_odm_override(dc, context);
- }
out = dml2_validate(dc, context, context->bw_ctx.dml2,
validate_mode);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c
index ee330559c233..33b9775420d3 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c
@@ -45,25 +45,3 @@ void dcn42_decide_zstate_support(struct dc *dc, struct dc_state *context)
context->bw_ctx.bw.dcn.clk.zstate_support = support;
}
-
-bool dcn42_decide_odm_override(struct dc *dc, struct dc_state *context)
-{
- bool odm_override = false;
-
- DC_LOGGER_INIT(dc->ctx->logger);
- if (dc->ctx->dce_environment == DCE_ENV_DIAG)
- return false;
-
- if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) {
-
- if (dc->debug.force_odm2to1_for_edp_pixclk_mhz != 0 &&
- context->streams[0]->timing.pix_clk_100hz > dc->debug.force_odm2to1_for_edp_pixclk_mhz * 10000) {
- odm_override = true;
- context->streams[0]->debug.force_odm_combine_segments = 2;
- }
- DC_LOG_SMU("odm_override: %d, eDP pixelclock: %d, force_odm2to1_for_edp_pixclk_mhz: %d\n",
- odm_override, context->streams[0]->timing.pix_clk_100hz / 10000, dc->debug.force_odm2to1_for_edp_pixclk_mhz);
- }
- return odm_override;
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h
index aff7be777681..81693c88443e 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h
@@ -29,5 +29,4 @@
#include "core_types.h"
void dcn42_decide_zstate_support(struct dc *dc, struct dc_state *context);
-bool dcn42_decide_odm_override(struct dc *dc, struct dc_state *context);
#endif /* _DCN42_RESOURCE_FPU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.c b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.c
new file mode 100644
index 000000000000..067a7069186b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include "dm_services.h"
+#include "workaround_manager/workaround_manager.h"
+
+static const struct workaround_manager dc2_wam_empty = {
+ .registry = NULL,
+ .count = 0,
+};
+
+/* BSS, not the stack: 64 block_sequence entries exceed the kernel frame limit. */
+static struct block_sequence dc2_wam_saved_steps[DC2_BLS_MAX_STEPS];
+
+const struct workaround_manager *dc2_workaround_manager_get(void)
+{
+ return &dc2_wam_empty;
+}
+
+enum workaround_manager_result workaround_manager_apply(
+ const struct workaround_manager *wam,
+ struct block_sequence_state *bls,
+ const struct workaround_context *ctx)
+{
+ struct block_sequence *saved_steps = dc2_wam_saved_steps;
+ enum workaround_manager_result result;
+ unsigned int saved_num;
+ unsigned int i;
+
+ if (!wam || !bls || !bls->steps || !bls->num_steps || !ctx ||
+ *bls->num_steps > MAX_HWSS_BLOCK_SEQUENCE_SIZE ||
+ (wam->count && !wam->registry))
+ return WAM_INVALID_INPUT;
+
+ /* Snapshot buffer is DC2_BLS_MAX_STEPS; larger built lists stay unmodified. */
+ if (*bls->num_steps > DC2_BLS_MAX_STEPS) {
+ if (!wam->count)
+ return WAM_OK;
+ return WAM_INVALID_INPUT;
+ }
+
+ saved_num = *bls->num_steps;
+ memmove(saved_steps, bls->steps,
+ saved_num * sizeof(saved_steps[0]));
+
+ for (i = 0; i < wam->count; i++) {
+ const struct workaround *wa = &wam->registry[i];
+
+ if (!wa->enabled)
+ continue;
+ if (!wa->is_applicable || !wa->apply) {
+ memmove(bls->steps, saved_steps,
+ saved_num * sizeof(saved_steps[0]));
+ *bls->num_steps = saved_num;
+ return WAM_INTERNAL_ERROR;
+ }
+ if (!wa->is_applicable(bls, ctx))
+ continue;
+ result = wa->apply(bls, ctx);
+ if (result != WAM_OK ||
+ *bls->num_steps > MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ memmove(bls->steps, saved_steps,
+ saved_num * sizeof(saved_steps[0]));
+ *bls->num_steps = saved_num;
+ if (result != WAM_OK)
+ return result;
+ return WAM_SIZE_EXCEEDED;
+ }
+ }
+
+ return WAM_OK;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.h b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.h
new file mode 100644
index 000000000000..4cbadffd6a8b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#pragma once
+
+#include "bls_builder/bls_builder.h"
+
+enum workaround_manager_result {
+ WAM_OK,
+ WAM_INVALID_INPUT,
+ WAM_SIZE_EXCEEDED,
+ WAM_INTERNAL_ERROR,
+};
+
+struct workaround_context {
+ const struct dc_state *current_state;
+ const struct dc_state *target;
+ enum bls_builder_name builder_name;
+ unsigned int dcn_version;
+ const struct dc_bug_wa *bug_wa;
+ const struct dc_debug_options *debug;
+};
+
+struct workaround {
+ const char *name;
+ bool enabled;
+ bool (*is_applicable)(const struct block_sequence_state *bls,
+ const struct workaround_context *ctx);
+ enum workaround_manager_result (*apply)(
+ struct block_sequence_state *bls,
+ const struct workaround_context *ctx);
+};
+
+struct workaround_manager {
+ const struct workaround *registry;
+ unsigned int count;
+};
+
+const struct workaround_manager *dc2_workaround_manager_get(void);
+
+enum workaround_manager_result workaround_manager_apply(
+ const struct workaround_manager *wam,
+ struct block_sequence_state *bls,
+ const struct workaround_context *ctx);
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 31f147547605..a75d38d44916 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -2621,7 +2621,8 @@ struct dmub_fams2_alternate_stream_dynamic_state {
uint16_t vstartup_line;
uint16_t vready_line;
uint8_t cursor_size[3]; // Cursor array per plane for now - if we assume a single cursor, then we don't need an array
- uint8_t pad; // to maintain alignment for below fields - re-arrange structure once all fields are finalized
+ uint8_t disabled_pipe_mask; // bitmask of pipes with RECOUT_HEIGHT == 0 (disabled)
+ struct plane_pipe_rect pipe_viewports[4];
/* outputs: */
uint16_t subvp_start_line_a[3];
uint16_t subvp_height_a[3];
@@ -4800,6 +4801,14 @@ struct dmub_cmd_replay_copy_settings_data {
* @pad: Align structure to 4 byte boundary.
*/
uint8_t pad[1];
+ /**
+ * @frame_update_interval: Frame update interval; 0 disabled.
+ */
+ uint16_t frame_update_interval;
+ /**
+ * @pad2: Align structure to 4 byte boundary.
+ */
+ uint8_t pad2[2];
};
diff --git a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h
index 63813009a3a6..130c78600b6e 100644
--- a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h
+++ b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h
@@ -77,6 +77,12 @@ struct ddc *dal_gpio_create_ddc(
void dal_gpio_destroy_ddc(
struct ddc **ddc);
+void dal_gpio_ddc_open_aux_once(
+ struct gpio_service *service,
+ uint32_t offset,
+ uint32_t mask,
+ const struct gpio_ddc_hw_info *info);
+
void dal_gpio_service_destroy(
struct gpio_service **ptr);
diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h
index f40b6a03fe63..79522e1bec4f 100644
--- a/drivers/gpu/drm/amd/include/cgs_common.h
+++ b/drivers/gpu/drm/amd/include/cgs_common.h
@@ -63,6 +63,14 @@ enum cgs_ucode_id {
/**
* struct cgs_firmware_info - Firmware information
+ * @version: firmware header version
+ * @fw_version: firmware version reported by the IP block
+ * @feature_version: firmware feature version
+ * @image_size: firmware image size in bytes
+ * @mc_addr: GPU address of the firmware image
+ * @ucode_start_address: ucode start address (SMU firmware only)
+ * @kptr: kernel virtual address of the firmware image
+ * @is_kicker: whether this is a "kicker" (k) firmware variant
*/
struct cgs_firmware_info {
uint16_t version;
@@ -78,45 +86,6 @@ struct cgs_firmware_info {
bool is_kicker;
};
-typedef unsigned long cgs_handle_t;
-
-/**
- * cgs_read_register() - Read an MMIO register
- * @cgs_device: opaque device handle
- * @offset: register offset
- *
- * Return: register value
- */
-typedef uint32_t (*cgs_read_register_t)(struct cgs_device *cgs_device, unsigned offset);
-
-/**
- * cgs_write_register() - Write an MMIO register
- * @cgs_device: opaque device handle
- * @offset: register offset
- * @value: register value
- */
-typedef void (*cgs_write_register_t)(struct cgs_device *cgs_device, unsigned offset,
- uint32_t value);
-
-/**
- * cgs_read_ind_register() - Read an indirect register
- * @cgs_device: opaque device handle
- * @offset: register offset
- *
- * Return: register value
- */
-typedef uint32_t (*cgs_read_ind_register_t)(struct cgs_device *cgs_device, enum cgs_ind_reg space,
- unsigned index);
-
-/**
- * cgs_write_ind_register() - Write an indirect register
- * @cgs_device: opaque device handle
- * @offset: register offset
- * @value: register value
- */
-typedef void (*cgs_write_ind_register_t)(struct cgs_device *cgs_device, enum cgs_ind_reg space,
- unsigned index, uint32_t value);
-
#define CGS_REG_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
#define CGS_REG_FIELD_MASK(reg, field) reg##__##field##_MASK
@@ -133,18 +102,27 @@ typedef void (*cgs_write_ind_register_t)(struct cgs_device *cgs_device, enum cgs
#define CGS_WREG32_FIELD_IND(device, space, reg, field, val) \
cgs_write_ind_register(device, space, ix##reg, (cgs_read_ind_register(device, space, ix##reg) & ~CGS_REG_FIELD_MASK(reg, field)) | (val) << CGS_REG_FIELD_SHIFT(reg, field))
-typedef int (*cgs_get_firmware_info)(struct cgs_device *cgs_device,
- enum cgs_ucode_id type,
- struct cgs_firmware_info *info);
-
+/**
+ * struct cgs_ops - Common Graphics Services operations
+ * @read_register: read register value
+ * @write_register: write register value
+ * @read_ind_register: read indirect register value
+ * @write_ind_register: write indirect register value
+ * @get_firmware_info: get firmware information
+ */
struct cgs_ops {
/* MMIO access */
- cgs_read_register_t read_register;
- cgs_write_register_t write_register;
- cgs_read_ind_register_t read_ind_register;
- cgs_write_ind_register_t write_ind_register;
+ uint32_t (*read_register)(struct cgs_device *cgs_device, unsigned int offset);
+ void (*write_register)(struct cgs_device *cgs_device, unsigned int offset,
+ uint32_t value);
+ uint32_t (*read_ind_register)(struct cgs_device *cgs_device, enum cgs_ind_reg space,
+ unsigned int index);
+ void (*write_ind_register)(struct cgs_device *cgs_device, enum cgs_ind_reg space,
+ unsigned int index, uint32_t value);
/* Firmware Info */
- cgs_get_firmware_info get_firmware_info;
+ int (*get_firmware_info)(struct cgs_device *cgs_device,
+ enum cgs_ucode_id type,
+ struct cgs_firmware_info *info);
};
struct cgs_os_ops; /* To be define in OS-specific CGS header */
diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h
index f8eaca8a22f6..6d67d015a74f 100644
--- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h
+++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h
@@ -683,6 +683,9 @@ struct SET_SHADER_DEBUGGER {
uint32_t spi_gdbg_per_vmid_cntl;
uint32_t tcp_watch_cntl[4]; /* TCP_WATCHx_CNTL */
uint32_t trap_en;
+ uint32_t tcp_watch_addr_lo[4]; /* TCP_WATCHx_ADDR_L */
+ uint32_t tcp_watch_addr_hi[4]; /* TCP_WATCHx_ADDR_H */
+ uint32_t process_context_array_index;
};
enum MESAPI_MISC__CHANGE_CONFIG_OPTION {
diff --git a/drivers/gpu/drm/amd/include/mes_v12_api_def.h b/drivers/gpu/drm/amd/include/mes_v12_api_def.h
index 3e214cb4f6e1..090c9142674e 100644
--- a/drivers/gpu/drm/amd/include/mes_v12_api_def.h
+++ b/drivers/gpu/drm/amd/include/mes_v12_api_def.h
@@ -805,6 +805,9 @@ struct SET_SHADER_DEBUGGER {
uint32_t spi_gdbg_per_vmid_cntl;
uint32_t tcp_watch_cntl[4]; // TCP_WATCHx_CNTL
uint32_t trap_en;
+ uint32_t tcp_watch_addr_lo[4]; // TCP_WATCHx_ADDR_L
+ uint32_t tcp_watch_addr_hi[4]; // TCP_WATCHx_ADDR_H
+ uint32_t process_context_array_index;
};
struct SET_GANG_SUBMIT {
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index a9bf686783e9..14b2acd36897 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -63,6 +63,9 @@ static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min, int32_t *max);
static int smu_v13_0_0_init_ppt_limits(struct smu_context *smu);
+static int
+smu_v13_0_0_upload_overdrive_table(struct smu_context *smu,
+ OverDriveTableExternal_t *od_table);
static const struct smu_feature_bits smu_v13_0_0_dpm_features = {
.bits = {
@@ -1079,6 +1082,93 @@ out:
return feature_enabled;
}
+static u32
+smu_v13_0_0_filter_od_feature_mask(struct smu_context *smu, u32 feature_mask)
+{
+ PPTable_t *pptable = smu->smu_table.driver_pptable;
+ u32 supported_mask =
+ pptable->SkuTable.OverDriveLimitsBasicMax.FeatureCtrlMask;
+
+ return feature_mask & supported_mask;
+}
+
+static bool smu_v13_0_0_fan_is_default(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot)
+{
+ return !memcmp(od->FanLinearPwmPoints, boot->FanLinearPwmPoints,
+ sizeof(od->FanLinearPwmPoints)) &&
+ !memcmp(od->FanLinearTempPoints, boot->FanLinearTempPoints,
+ sizeof(od->FanLinearTempPoints)) &&
+ od->FanMinimumPwm == boot->FanMinimumPwm &&
+ od->AcousticTargetRpmThreshold == boot->AcousticTargetRpmThreshold &&
+ od->AcousticLimitRpmThreshold == boot->AcousticLimitRpmThreshold &&
+ od->FanTargetTemperature == boot->FanTargetTemperature &&
+ od->FanMode == boot->FanMode;
+}
+
+static bool smu_v13_0_0_zero_fan_is_default(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot)
+{
+ return od->FanZeroRpmEnable == boot->FanZeroRpmEnable &&
+ od->FanZeroRpmStopTemp == boot->FanZeroRpmStopTemp;
+}
+
+static u32 smu_v13_0_0_normalize_feature_mask(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot,
+ u32 feature_mask)
+{
+ if (od->GfxclkFmin == boot->GfxclkFmin &&
+ od->GfxclkFmax == boot->GfxclkFmax)
+ feature_mask &= ~BIT(PP_OD_FEATURE_GFXCLK_BIT);
+ if (od->UclkFmin == boot->UclkFmin &&
+ od->UclkFmax == boot->UclkFmax)
+ feature_mask &= ~BIT(PP_OD_FEATURE_UCLK_BIT);
+ if (!memcmp(od->VoltageOffsetPerZoneBoundary,
+ boot->VoltageOffsetPerZoneBoundary,
+ sizeof(od->VoltageOffsetPerZoneBoundary)))
+ feature_mask &= ~BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT);
+ if (smu_v13_0_0_fan_is_default(od, boot))
+ feature_mask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ if (smu_v13_0_0_zero_fan_is_default(od, boot))
+ feature_mask &= ~BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
+ if (!od->Ppt)
+ feature_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT);
+
+ return feature_mask;
+}
+
+static int
+smu_v13_0_0_upload_ppt_overdrive_table(struct smu_context *smu, s16 ppt)
+{
+ struct smu_table_context *table_context = &smu->smu_table;
+ OverDriveTableExternal_t *od_table = table_context->overdrive_table;
+ OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ u32 next_mask = table_context->user_od_feature_mask;
+ int ret;
+
+ /* Do not commit OD settings staged after the last c operation. */
+ memcpy(&upload_table, user_od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.Ppt = ppt;
+ if (ppt)
+ next_mask |= BIT(PP_OD_FEATURE_PPT_BIT);
+ else
+ next_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT);
+ upload_table.OverDriveTable.FeatureCtrlMask =
+ smu_v13_0_0_filter_od_feature_mask(smu, next_mask);
+
+ ret = smu_v13_0_0_upload_overdrive_table(smu, &upload_table);
+ if (ret)
+ return ret;
+
+ table_context->user_od_feature_mask =
+ upload_table.OverDriveTable.FeatureCtrlMask;
+ od_table->OverDriveTable.Ppt = ppt;
+ user_od_table->OverDriveTable.Ppt = ppt;
+
+ return 0;
+}
+
static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min,
@@ -1514,41 +1604,30 @@ static int smu_v13_0_0_od_restore_table_single(struct smu_context *smu, long inp
boot_overdrive_table->OverDriveTable.FanLinearPwmPoints[i];
}
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_LIMIT:
od_table->OverDriveTable.AcousticLimitRpmThreshold =
boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_TARGET:
od_table->OverDriveTable.AcousticTargetRpmThreshold =
boot_overdrive_table->OverDriveTable.AcousticTargetRpmThreshold;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_TARGET_TEMPERATURE:
od_table->OverDriveTable.FanTargetTemperature =
boot_overdrive_table->OverDriveTable.FanTargetTemperature;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_MINIMUM_PWM:
od_table->OverDriveTable.FanMinimumPwm =
boot_overdrive_table->OverDriveTable.FanMinimumPwm;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE:
od_table->OverDriveTable.FanZeroRpmEnable =
boot_overdrive_table->OverDriveTable.FanZeroRpmEnable;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
break;
case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP:
od_table->OverDriveTable.FanZeroRpmStopTemp =
boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
break;
default:
dev_info(adev->dev, "Invalid table index: %ld\n", input);
@@ -1566,9 +1645,17 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)table_context->overdrive_table;
+ OverDriveTableExternal_t *user_od_table =
+ (OverDriveTableExternal_t *)table_context->user_overdrive_table;
+ OverDriveTableExternal_t *boot_od_table =
+ (OverDriveTableExternal_t *)table_context->boot_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ OverDriveTable_t *od = &od_table->OverDriveTable;
+ OverDriveTable_t *boot = &boot_od_table->OverDriveTable;
struct amdgpu_device *adev = smu->adev;
uint32_t offset_of_voltageoffset;
int32_t minimum, maximum;
+ u32 next_mask;
int i, ret = 0;
switch (type) {
@@ -1892,36 +1979,41 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
} else {
memcpy(od_table,
table_context->boot_overdrive_table,
- sizeof(OverDriveTableExternal_t));
+ sizeof(OverDriveTableExternal_t));
od_table->OverDriveTable.FeatureCtrlMask = 0;
- table_context->user_od_feature_mask = 0;
}
fallthrough;
case PP_OD_COMMIT_DPM_TABLE:
- table_context->user_od_feature_mask =
- od_table->OverDriveTable.FeatureCtrlMask;
offset_of_voltageoffset = offsetof(OverDriveTable_t, VoltageOffsetPerZoneBoundary);
- if (memcmp((u8 *)od_table + offset_of_voltageoffset,
- table_context->user_overdrive_table + offset_of_voltageoffset,
- sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset)) {
- smu_v13_0_0_dump_od_table(smu, od_table);
+ next_mask = smu_v13_0_0_filter_od_feature_mask(smu,
+ table_context->user_od_feature_mask |
+ od->FeatureCtrlMask);
+ next_mask = smu_v13_0_0_normalize_feature_mask(od, boot,
+ next_mask);
- ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
+ if (memcmp((u8 *)od_table + offset_of_voltageoffset,
+ (u8 *)user_od_table + offset_of_voltageoffset,
+ sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset) ||
+ next_mask != table_context->user_od_feature_mask) {
+ memcpy(&upload_table, od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.FeatureCtrlMask = next_mask;
+ smu_v13_0_0_dump_od_table(smu, &upload_table);
+
+ ret = smu_v13_0_0_upload_overdrive_table(smu, &upload_table);
if (ret) {
dev_err(adev->dev, "Failed to upload overdrive table!\n");
return ret;
}
- memcpy(table_context->user_overdrive_table + offset_of_voltageoffset,
+ table_context->user_od_feature_mask = next_mask;
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
+ memcpy((u8 *)user_od_table + offset_of_voltageoffset,
(u8 *)od_table + offset_of_voltageoffset,
sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset);
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
- if (!memcmp(table_context->user_overdrive_table,
- table_context->boot_overdrive_table,
- sizeof(OverDriveTableExternal_t)))
- smu->user_dpm_profile.user_od = false;
- else
- smu->user_dpm_profile.user_od = true;
+ smu->user_dpm_profile.user_od =
+ !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT));
}
break;
@@ -2186,6 +2278,7 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu)
memcpy(od_table,
boot_od_table,
sizeof(OverDriveTableExternal_t));
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
/*
* For S3/S4/Runpm resume, we need to setup those overdrive tables again,
@@ -2195,6 +2288,7 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu)
memcpy(user_od_table,
boot_od_table,
sizeof(OverDriveTableExternal_t));
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
smu->user_dpm_profile.user_od = false;
smu->smu_table.user_od_feature_mask = 0;
} else if (smu->user_dpm_profile.user_od) {
@@ -2233,6 +2327,14 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu)
user_od_table_bak.OverDriveTable.FanZeroRpmEnable;
user_od_table->OverDriveTable.FanZeroRpmStopTemp =
user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp;
+ user_od_table->OverDriveTable.FanMode =
+ user_od_table_bak.OverDriveTable.FanMode;
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
+ }
+ if (smu->adev->in_suspend) {
+ user_od_table->OverDriveTable.Ppt = 0;
+ smu->smu_table.user_od_feature_mask &=
+ ~BIT(PP_OD_FEATURE_PPT_BIT);
}
smu_v13_0_0_set_supported_od_feature_mask(smu);
@@ -2245,13 +2347,22 @@ static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu)
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table = table_context->overdrive_table;
OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ u32 next_mask;
int res;
- user_od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
- res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table);
- user_od_table->OverDriveTable.FeatureCtrlMask = 0;
- if (res == 0)
+
+ next_mask = smu_v13_0_0_filter_od_feature_mask(smu,
+ table_context->user_od_feature_mask);
+ memcpy(&upload_table, user_od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.FeatureCtrlMask = next_mask;
+ res = smu_v13_0_0_upload_overdrive_table(smu, &upload_table);
+ if (res == 0) {
+ table_context->user_od_feature_mask = next_mask;
+ smu->user_dpm_profile.user_od =
+ !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT));
memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t));
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
+ }
return res;
}
@@ -3045,10 +3156,8 @@ static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu,
SkuTable_t *skutable = &pptable->SkuTable;
uint32_t msg_limit = skutable->MsgLimits.Power
[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
- struct smu_table_context *table_context = &smu->smu_table;
- OverDriveTableExternal_t *od_table =
- (OverDriveTableExternal_t *)table_context->overdrive_table;
OverDriveTableExternal_t current_od_table;
+ s16 ppt;
int ret = 0;
if (limit_type != SMU_PPT_LIMIT_PPT0)
@@ -3060,12 +3169,7 @@ static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu,
return ret;
if (current_od_table.OverDriveTable.Ppt) {
- od_table->OverDriveTable.Ppt = 0;
- table_context->user_od_feature_mask &=
- ~(1U << PP_OD_FEATURE_PPT_BIT);
- od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
- ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
+ ret = smu_v13_0_0_upload_ppt_overdrive_table(smu, 0);
if (ret) {
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
return ret;
@@ -3077,11 +3181,8 @@ static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu,
if (ret)
return ret;
- od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
- table_context->user_od_feature_mask |= 1U << PP_OD_FEATURE_PPT_BIT;
- od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
- ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
+ ppt = (limit * 100) / msg_limit - 100;
+ ret = smu_v13_0_0_upload_ppt_overdrive_table(smu, ppt);
if (ret) {
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index d8715a94ec6a..1530bdf8401b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -63,6 +63,9 @@ static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min, int32_t *max);
static int smu_v13_0_7_init_ppt_limits(struct smu_context *smu);
+static int
+smu_v13_0_7_upload_overdrive_table(struct smu_context *smu,
+ OverDriveTableExternal_t *od_table);
static const struct smu_feature_bits smu_v13_0_7_dpm_features = {
.bits = {
@@ -94,6 +97,7 @@ static const struct smu_feature_bits smu_v13_0_7_dpm_features = {
#define PP_OD_FEATURE_GFXCLK_FMAX 1
#define PP_OD_FEATURE_UCLK_FMIN 2
#define PP_OD_FEATURE_UCLK_FMAX 3
+
#define PP_OD_FEATURE_GFX_VF_CURVE 4
#define PP_OD_FEATURE_FAN_CURVE_TEMP 5
#define PP_OD_FEATURE_FAN_CURVE_PWM 6
@@ -1089,6 +1093,93 @@ out:
return feature_enabled;
}
+static u32
+smu_v13_0_7_filter_od_feature_mask(struct smu_context *smu, u32 feature_mask)
+{
+ PPTable_t *pptable = smu->smu_table.driver_pptable;
+ u32 supported_mask =
+ pptable->SkuTable.OverDriveLimitsBasicMax.FeatureCtrlMask;
+
+ return feature_mask & supported_mask;
+}
+
+static bool smu_v13_0_7_fan_is_default(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot)
+{
+ return !memcmp(od->FanLinearPwmPoints, boot->FanLinearPwmPoints,
+ sizeof(od->FanLinearPwmPoints)) &&
+ !memcmp(od->FanLinearTempPoints, boot->FanLinearTempPoints,
+ sizeof(od->FanLinearTempPoints)) &&
+ od->FanMinimumPwm == boot->FanMinimumPwm &&
+ od->AcousticTargetRpmThreshold == boot->AcousticTargetRpmThreshold &&
+ od->AcousticLimitRpmThreshold == boot->AcousticLimitRpmThreshold &&
+ od->FanTargetTemperature == boot->FanTargetTemperature &&
+ od->FanMode == boot->FanMode;
+}
+
+static bool smu_v13_0_7_zero_fan_is_default(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot)
+{
+ return od->FanZeroRpmEnable == boot->FanZeroRpmEnable &&
+ od->FanZeroRpmStopTemp == boot->FanZeroRpmStopTemp;
+}
+
+static u32 smu_v13_0_7_normalize_feature_mask(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot,
+ u32 feature_mask)
+{
+ if (od->GfxclkFmin == boot->GfxclkFmin &&
+ od->GfxclkFmax == boot->GfxclkFmax)
+ feature_mask &= ~BIT(PP_OD_FEATURE_GFXCLK_BIT);
+ if (od->UclkFmin == boot->UclkFmin &&
+ od->UclkFmax == boot->UclkFmax)
+ feature_mask &= ~BIT(PP_OD_FEATURE_UCLK_BIT);
+ if (!memcmp(od->VoltageOffsetPerZoneBoundary,
+ boot->VoltageOffsetPerZoneBoundary,
+ sizeof(od->VoltageOffsetPerZoneBoundary)))
+ feature_mask &= ~BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT);
+ if (smu_v13_0_7_fan_is_default(od, boot))
+ feature_mask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ if (smu_v13_0_7_zero_fan_is_default(od, boot))
+ feature_mask &= ~BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
+ if (!od->Ppt)
+ feature_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT);
+
+ return feature_mask;
+}
+
+static int
+smu_v13_0_7_upload_ppt_overdrive_table(struct smu_context *smu, s16 ppt)
+{
+ struct smu_table_context *table_context = &smu->smu_table;
+ OverDriveTableExternal_t *od_table = table_context->overdrive_table;
+ OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ u32 next_mask = table_context->user_od_feature_mask;
+ int ret;
+
+ /* Do not commit OD settings staged after the last c operation. */
+ memcpy(&upload_table, user_od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.Ppt = ppt;
+ if (ppt)
+ next_mask |= BIT(PP_OD_FEATURE_PPT_BIT);
+ else
+ next_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT);
+ upload_table.OverDriveTable.FeatureCtrlMask =
+ smu_v13_0_7_filter_od_feature_mask(smu, next_mask);
+
+ ret = smu_v13_0_7_upload_overdrive_table(smu, &upload_table);
+ if (ret)
+ return ret;
+
+ table_context->user_od_feature_mask =
+ upload_table.OverDriveTable.FeatureCtrlMask;
+ od_table->OverDriveTable.Ppt = ppt;
+ user_od_table->OverDriveTable.Ppt = ppt;
+
+ return 0;
+}
+
static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min,
@@ -1523,41 +1614,30 @@ static int smu_v13_0_7_od_restore_table_single(struct smu_context *smu, long inp
boot_overdrive_table->OverDriveTable.FanLinearPwmPoints[i];
}
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_LIMIT:
od_table->OverDriveTable.AcousticLimitRpmThreshold =
boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_TARGET:
od_table->OverDriveTable.AcousticTargetRpmThreshold =
boot_overdrive_table->OverDriveTable.AcousticTargetRpmThreshold;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_TARGET_TEMPERATURE:
od_table->OverDriveTable.FanTargetTemperature =
boot_overdrive_table->OverDriveTable.FanTargetTemperature;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_MINIMUM_PWM:
od_table->OverDriveTable.FanMinimumPwm =
boot_overdrive_table->OverDriveTable.FanMinimumPwm;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE:
od_table->OverDriveTable.FanZeroRpmEnable =
boot_overdrive_table->OverDriveTable.FanZeroRpmEnable;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
break;
case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP:
od_table->OverDriveTable.FanZeroRpmStopTemp =
boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
break;
default:
dev_info(adev->dev, "Invalid table index: %ld\n", input);
@@ -1575,9 +1655,17 @@ static int smu_v13_0_7_od_edit_dpm_table(struct smu_context *smu,
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)table_context->overdrive_table;
+ OverDriveTableExternal_t *user_od_table =
+ (OverDriveTableExternal_t *)table_context->user_overdrive_table;
+ OverDriveTableExternal_t *boot_od_table =
+ (OverDriveTableExternal_t *)table_context->boot_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ OverDriveTable_t *od = &od_table->OverDriveTable;
+ OverDriveTable_t *boot = &boot_od_table->OverDriveTable;
struct amdgpu_device *adev = smu->adev;
uint32_t offset_of_voltageoffset;
int32_t minimum, maximum;
+ u32 next_mask;
int i, ret = 0;
switch (type) {
@@ -1903,35 +1991,40 @@ static int smu_v13_0_7_od_edit_dpm_table(struct smu_context *smu,
table_context->boot_overdrive_table,
sizeof(OverDriveTableExternal_t));
od_table->OverDriveTable.FeatureCtrlMask = 0;
- table_context->user_od_feature_mask = 0;
}
fallthrough;
case PP_OD_COMMIT_DPM_TABLE:
- table_context->user_od_feature_mask =
- od_table->OverDriveTable.FeatureCtrlMask;
offset_of_voltageoffset = offsetof(OverDriveTable_t, VoltageOffsetPerZoneBoundary);
- if (memcmp((u8 *)od_table + offset_of_voltageoffset,
- table_context->user_overdrive_table + offset_of_voltageoffset,
- sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset)) {
- smu_v13_0_7_dump_od_table(smu, od_table);
+ next_mask = smu_v13_0_7_filter_od_feature_mask(smu,
+ table_context->user_od_feature_mask |
+ od->FeatureCtrlMask);
+ next_mask = smu_v13_0_7_normalize_feature_mask(od, boot,
+ next_mask);
- ret = smu_v13_0_7_upload_overdrive_table(smu, od_table);
+ if (memcmp((u8 *)od_table + offset_of_voltageoffset,
+ (u8 *)user_od_table + offset_of_voltageoffset,
+ sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset) ||
+ next_mask != table_context->user_od_feature_mask) {
+ memcpy(&upload_table, od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.FeatureCtrlMask = next_mask;
+ smu_v13_0_7_dump_od_table(smu, &upload_table);
+
+ ret = smu_v13_0_7_upload_overdrive_table(smu, &upload_table);
if (ret) {
dev_err(adev->dev, "Failed to upload overdrive table!\n");
return ret;
}
- memcpy(table_context->user_overdrive_table + offset_of_voltageoffset,
+ table_context->user_od_feature_mask = next_mask;
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
+ memcpy((u8 *)user_od_table + offset_of_voltageoffset,
(u8 *)od_table + offset_of_voltageoffset,
sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset);
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
- if (!memcmp(table_context->user_overdrive_table,
- table_context->boot_overdrive_table,
- sizeof(OverDriveTableExternal_t)))
- smu->user_dpm_profile.user_od = false;
- else
- smu->user_dpm_profile.user_od = true;
+ smu->user_dpm_profile.user_od =
+ !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT));
}
break;
@@ -2187,6 +2280,7 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu)
memcpy(od_table,
boot_od_table,
sizeof(OverDriveTableExternal_t));
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
/*
* For S3/S4/Runpm resume, we need to setup those overdrive tables again,
@@ -2196,6 +2290,7 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu)
memcpy(user_od_table,
boot_od_table,
sizeof(OverDriveTableExternal_t));
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
smu->user_dpm_profile.user_od = false;
smu->smu_table.user_od_feature_mask = 0;
} else if (smu->user_dpm_profile.user_od) {
@@ -2234,6 +2329,14 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu)
user_od_table_bak.OverDriveTable.FanZeroRpmEnable;
user_od_table->OverDriveTable.FanZeroRpmStopTemp =
user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp;
+ user_od_table->OverDriveTable.FanMode =
+ user_od_table_bak.OverDriveTable.FanMode;
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
+ }
+ if (smu->adev->in_suspend) {
+ user_od_table->OverDriveTable.Ppt = 0;
+ smu->smu_table.user_od_feature_mask &=
+ ~BIT(PP_OD_FEATURE_PPT_BIT);
}
smu_v13_0_7_set_supported_od_feature_mask(smu);
@@ -2246,14 +2349,22 @@ static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu)
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table = table_context->overdrive_table;
OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ u32 next_mask;
int res;
- user_od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
- res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table);
- user_od_table->OverDriveTable.FeatureCtrlMask = 0;
- if (res == 0)
+ next_mask = smu_v13_0_7_filter_od_feature_mask(smu,
+ table_context->user_od_feature_mask);
+ memcpy(&upload_table, user_od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.FeatureCtrlMask = next_mask;
+ res = smu_v13_0_7_upload_overdrive_table(smu, &upload_table);
+ if (res == 0) {
+ table_context->user_od_feature_mask = next_mask;
+ smu->user_dpm_profile.user_od =
+ !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT));
memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t));
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
+ }
return res;
}
@@ -2695,10 +2806,8 @@ static int smu_v13_0_7_set_ppt_limit(struct smu_context *smu,
SkuTable_t *skutable = &pptable->SkuTable;
uint32_t msg_limit = skutable->MsgLimits.Power
[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
- struct smu_table_context *table_context = &smu->smu_table;
- OverDriveTableExternal_t *od_table =
- (OverDriveTableExternal_t *)table_context->overdrive_table;
OverDriveTableExternal_t current_od_table;
+ s16 ppt;
int ret = 0;
if (limit_type != SMU_PPT_LIMIT_PPT0)
@@ -2710,13 +2819,7 @@ static int smu_v13_0_7_set_ppt_limit(struct smu_context *smu,
return ret;
if (current_od_table.OverDriveTable.Ppt) {
- od_table->OverDriveTable.Ppt = 0;
- table_context->user_od_feature_mask &=
- ~(1U << PP_OD_FEATURE_PPT_BIT);
- od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
-
- ret = smu_v13_0_7_upload_overdrive_table(smu, od_table);
+ ret = smu_v13_0_7_upload_ppt_overdrive_table(smu, 0);
if (ret) {
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
return ret;
@@ -2728,12 +2831,8 @@ static int smu_v13_0_7_set_ppt_limit(struct smu_context *smu,
if (ret)
return ret;
- od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
- table_context->user_od_feature_mask |= 1U << PP_OD_FEATURE_PPT_BIT;
- od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
-
- ret = smu_v13_0_7_upload_overdrive_table(smu, od_table);
+ ppt = (limit * 100) / msg_limit - 100;
+ ret = smu_v13_0_7_upload_ppt_overdrive_table(smu, ppt);
if (ret) {
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 3f2c120ef2dc..24a3d61d8ea6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -91,6 +91,10 @@ static const struct smu_feature_bits smu_v14_0_2_dpm_features = {
#define PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE 11
#define PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP 12
+#define SMU_14_0_2_OD_FAN_FEATURE_MASK \
+ (BIT(PP_OD_FEATURE_FAN_CURVE_BIT) | \
+ BIT(PP_OD_FEATURE_FAN_LEGACY_BIT))
+
static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1),
@@ -963,6 +967,84 @@ out:
return feature_enabled;
}
+static u32
+smu_v14_0_2_filter_od_feature_mask(struct smu_context *smu, u32 feature_mask)
+{
+ PPTable_t *pptable = smu->smu_table.driver_pptable;
+ u32 supported_mask =
+ pptable->SkuTable.OverDriveLimitsBasicMax.FeatureCtrlMask;
+
+ return feature_mask & supported_mask;
+}
+
+static u32
+smu_v14_0_2_get_od_feature_mask(struct smu_context *smu, u32 pending_mask)
+{
+ u32 supported_mask = smu_v14_0_2_filter_od_feature_mask(smu, ~0U);
+ u32 fan_mask = supported_mask & SMU_14_0_2_OD_FAN_FEATURE_MASK;
+ u32 mask = smu->smu_table.user_od_feature_mask;
+
+ if (pending_mask & fan_mask)
+ mask &= ~fan_mask;
+ mask |= pending_mask;
+
+ return smu_v14_0_2_filter_od_feature_mask(smu, mask);
+}
+
+static bool smu_v14_0_2_fan_is_default(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot)
+{
+ return !memcmp(od->FanLinearPwmPoints, boot->FanLinearPwmPoints,
+ sizeof(od->FanLinearPwmPoints)) &&
+ !memcmp(od->FanLinearTempPoints, boot->FanLinearTempPoints,
+ sizeof(od->FanLinearTempPoints)) &&
+ od->AcousticTargetRpmThreshold == boot->AcousticTargetRpmThreshold &&
+ od->AcousticLimitRpmThreshold == boot->AcousticLimitRpmThreshold &&
+ od->FanTargetTemperature == boot->FanTargetTemperature &&
+ od->FanMode == boot->FanMode;
+}
+
+static bool smu_v14_0_2_legacy_fan_is_default(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot)
+{
+ return od->FanMinimumPwm == boot->FanMinimumPwm &&
+ od->FanMode == boot->FanMode;
+}
+
+static bool smu_v14_0_2_zero_fan_is_default(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot)
+{
+ return od->FanZeroRpmEnable == boot->FanZeroRpmEnable &&
+ od->FanZeroRpmStopTemp == boot->FanZeroRpmStopTemp;
+}
+
+static u32 smu_v14_0_2_normalize_feature_mask(const OverDriveTable_t *od,
+ const OverDriveTable_t *boot,
+ u32 feature_mask)
+{
+ if (od->GfxclkFoffset == boot->GfxclkFoffset)
+ feature_mask &= ~BIT(PP_OD_FEATURE_GFXCLK_BIT);
+ if (od->UclkFmin == boot->UclkFmin &&
+ od->UclkFmax == boot->UclkFmax)
+ feature_mask &= ~BIT(PP_OD_FEATURE_UCLK_BIT);
+ if (!memcmp(od->VoltageOffsetPerZoneBoundary,
+ boot->VoltageOffsetPerZoneBoundary,
+ sizeof(od->VoltageOffsetPerZoneBoundary)))
+ feature_mask &= ~BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT);
+ if ((feature_mask & BIT(PP_OD_FEATURE_FAN_CURVE_BIT)) &&
+ smu_v14_0_2_fan_is_default(od, boot))
+ feature_mask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ if ((feature_mask & BIT(PP_OD_FEATURE_FAN_LEGACY_BIT)) &&
+ smu_v14_0_2_legacy_fan_is_default(od, boot))
+ feature_mask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
+ if (smu_v14_0_2_zero_fan_is_default(od, boot))
+ feature_mask &= ~BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
+ if (!od->Ppt)
+ feature_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT);
+
+ return feature_mask;
+}
+
static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min,
@@ -2320,6 +2402,38 @@ static int smu_v14_0_2_upload_overdrive_table(struct smu_context *smu,
return ret;
}
+static int
+smu_v14_0_2_upload_ppt_overdrive_table(struct smu_context *smu, s16 ppt)
+{
+ struct smu_table_context *table_context = &smu->smu_table;
+ OverDriveTableExternal_t *od_table = table_context->overdrive_table;
+ OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ u32 next_mask = table_context->user_od_feature_mask;
+ int ret;
+
+ /* Do not commit OD settings staged after the last c operation. */
+ memcpy(&upload_table, user_od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.Ppt = ppt;
+ if (ppt)
+ next_mask |= BIT(PP_OD_FEATURE_PPT_BIT);
+ else
+ next_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT);
+ upload_table.OverDriveTable.FeatureCtrlMask =
+ smu_v14_0_2_filter_od_feature_mask(smu, next_mask);
+
+ ret = smu_v14_0_2_upload_overdrive_table(smu, &upload_table);
+ if (ret)
+ return ret;
+
+ table_context->user_od_feature_mask =
+ upload_table.OverDriveTable.FeatureCtrlMask;
+ od_table->OverDriveTable.Ppt = ppt;
+ user_od_table->OverDriveTable.Ppt = ppt;
+
+ return 0;
+}
+
static void smu_v14_0_2_set_supported_od_feature_mask(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -2378,6 +2492,7 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu)
memcpy(od_table,
boot_od_table,
sizeof(OverDriveTableExternal_t));
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
/*
* For S3/S4/Runpm resume, we need to setup those overdrive tables again,
@@ -2387,6 +2502,7 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu)
memcpy(user_od_table,
boot_od_table,
sizeof(OverDriveTableExternal_t));
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
smu->user_dpm_profile.user_od = false;
smu->smu_table.user_od_feature_mask = 0;
} else if (smu->user_dpm_profile.user_od) {
@@ -2423,6 +2539,14 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu)
user_od_table_bak.OverDriveTable.FanZeroRpmEnable;
user_od_table->OverDriveTable.FanZeroRpmStopTemp =
user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp;
+ user_od_table->OverDriveTable.FanMode =
+ user_od_table_bak.OverDriveTable.FanMode;
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
+ }
+ if (smu->adev->in_suspend) {
+ user_od_table->OverDriveTable.Ppt = 0;
+ smu->smu_table.user_od_feature_mask &=
+ ~BIT(PP_OD_FEATURE_PPT_BIT);
}
smu_v14_0_2_set_supported_od_feature_mask(smu);
@@ -2435,14 +2559,22 @@ static int smu_v14_0_2_restore_user_od_settings(struct smu_context *smu)
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table = table_context->overdrive_table;
OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ u32 next_mask;
int res;
- user_od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
- res = smu_v14_0_2_upload_overdrive_table(smu, user_od_table);
- user_od_table->OverDriveTable.FeatureCtrlMask = 0;
- if (res == 0)
+ next_mask = smu_v14_0_2_filter_od_feature_mask(smu,
+ table_context->user_od_feature_mask);
+ memcpy(&upload_table, user_od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.FeatureCtrlMask = next_mask;
+ res = smu_v14_0_2_upload_overdrive_table(smu, &upload_table);
+ if (res == 0) {
+ table_context->user_od_feature_mask = next_mask;
+ smu->user_dpm_profile.user_od =
+ !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT));
memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t));
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
+ }
return res;
}
@@ -2466,13 +2598,10 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp
boot_overdrive_table->OverDriveTable.FanLinearPwmPoints[i];
}
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
- od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
break;
case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE:
od_table->OverDriveTable.FanZeroRpmEnable =
boot_overdrive_table->OverDriveTable.FanZeroRpmEnable;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
break;
case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP:
od_table->OverDriveTable.FanZeroRpmStopTemp =
@@ -2482,27 +2611,18 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp
case PP_OD_EDIT_ACOUSTIC_LIMIT:
od_table->OverDriveTable.AcousticLimitRpmThreshold =
boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_TARGET:
od_table->OverDriveTable.AcousticTargetRpmThreshold =
boot_overdrive_table->OverDriveTable.AcousticTargetRpmThreshold;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_TARGET_TEMPERATURE:
od_table->OverDriveTable.FanTargetTemperature =
boot_overdrive_table->OverDriveTable.FanTargetTemperature;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
case PP_OD_EDIT_FAN_MINIMUM_PWM:
od_table->OverDriveTable.FanMinimumPwm =
boot_overdrive_table->OverDriveTable.FanMinimumPwm;
- od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
- od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
default:
dev_info(adev->dev, "Invalid table index: %ld\n", input);
@@ -2520,9 +2640,17 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)table_context->overdrive_table;
+ OverDriveTableExternal_t *user_od_table =
+ (OverDriveTableExternal_t *)table_context->user_overdrive_table;
+ OverDriveTableExternal_t *boot_od_table =
+ (OverDriveTableExternal_t *)table_context->boot_overdrive_table;
+ OverDriveTableExternal_t upload_table;
+ OverDriveTable_t *od = &od_table->OverDriveTable;
+ OverDriveTable_t *boot = &boot_od_table->OverDriveTable;
struct amdgpu_device *adev = smu->adev;
uint32_t offset_of_voltageoffset;
int32_t minimum, maximum;
+ u32 next_mask;
int i, ret = 0;
switch (type) {
@@ -2694,6 +2822,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
od_table->OverDriveTable.AcousticLimitRpmThreshold = input[0];
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_TARGET:
@@ -2716,6 +2845,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
od_table->OverDriveTable.AcousticTargetRpmThreshold = input[0];
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
break;
case PP_OD_EDIT_FAN_TARGET_TEMPERATURE:
@@ -2738,6 +2868,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
od_table->OverDriveTable.FanTargetTemperature = input[0];
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
break;
case PP_OD_EDIT_FAN_MINIMUM_PWM:
@@ -2815,44 +2946,38 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
table_context->boot_overdrive_table,
sizeof(OverDriveTableExternal_t));
od_table->OverDriveTable.FeatureCtrlMask = 0;
- table_context->user_od_feature_mask = 0;
}
fallthrough;
case PP_OD_COMMIT_DPM_TABLE:
- /*
- * PMFW interprets FeatureCtrlMask as the complete set of OD
- * features that are currently overridden, not as a delta
- * describing this single operation. Any feature whose bit is
- * clear gets reset to its default on import. od_table's mask
- * has accumulated every feature the user touched since the
- * last full restore, so record it and keep restating it on
- * subsequent uploads.
- */
- table_context->user_od_feature_mask =
- od_table->OverDriveTable.FeatureCtrlMask;
-
offset_of_voltageoffset = offsetof(OverDriveTable_t, VoltageOffsetPerZoneBoundary);
- if (memcmp((u8 *)od_table + offset_of_voltageoffset,
- table_context->user_overdrive_table + offset_of_voltageoffset,
- sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset)) {
- smu_v14_0_2_dump_od_table(smu, od_table);
+ next_mask = smu_v14_0_2_get_od_feature_mask(smu,
+ od->FeatureCtrlMask);
+ next_mask = smu_v14_0_2_normalize_feature_mask(od, boot,
+ next_mask);
- ret = smu_v14_0_2_upload_overdrive_table(smu, od_table);
+ if (memcmp((u8 *)od_table + offset_of_voltageoffset,
+ (u8 *)user_od_table + offset_of_voltageoffset,
+ sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset) ||
+ next_mask != table_context->user_od_feature_mask) {
+ memcpy(&upload_table, od_table, sizeof(upload_table));
+ upload_table.OverDriveTable.FeatureCtrlMask = next_mask;
+ smu_v14_0_2_dump_od_table(smu, &upload_table);
+
+ ret = smu_v14_0_2_upload_overdrive_table(smu, &upload_table);
if (ret) {
dev_err(adev->dev, "Failed to upload overdrive table!\n");
return ret;
}
- memcpy(table_context->user_overdrive_table + offset_of_voltageoffset,
+ table_context->user_od_feature_mask = next_mask;
+ od_table->OverDriveTable.FeatureCtrlMask = 0;
+ memcpy((u8 *)user_od_table + offset_of_voltageoffset,
(u8 *)od_table + offset_of_voltageoffset,
sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset);
+ user_od_table->OverDriveTable.FeatureCtrlMask = 0;
- if (!memcmp(table_context->user_overdrive_table,
- table_context->boot_overdrive_table,
- sizeof(OverDriveTableExternal_t)))
- smu->user_dpm_profile.user_od = false;
- else
- smu->user_dpm_profile.user_od = true;
+ smu->user_dpm_profile.user_od =
+ !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT));
}
break;
@@ -2870,10 +2995,8 @@ static int smu_v14_0_2_set_ppt_limit(struct smu_context *smu,
PPTable_t *pptable = smu->smu_table.driver_pptable;
uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power
[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
- struct smu_table_context *table_context = &smu->smu_table;
- OverDriveTableExternal_t *od_table =
- (OverDriveTableExternal_t *)table_context->overdrive_table;
OverDriveTableExternal_t current_od_table;
+ s16 ppt;
int ret = 0;
if (limit_type != SMU_PPT_LIMIT_PPT0)
@@ -2885,13 +3008,7 @@ static int smu_v14_0_2_set_ppt_limit(struct smu_context *smu,
return ret;
if (current_od_table.OverDriveTable.Ppt) {
- od_table->OverDriveTable.Ppt = 0;
- table_context->user_od_feature_mask &=
- ~(1U << PP_OD_FEATURE_PPT_BIT);
- od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
-
- ret = smu_v14_0_2_upload_overdrive_table(smu, od_table);
+ ret = smu_v14_0_2_upload_ppt_overdrive_table(smu, 0);
if (ret) {
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
return ret;
@@ -2903,12 +3020,8 @@ static int smu_v14_0_2_set_ppt_limit(struct smu_context *smu,
if (ret)
return ret;
- od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
- table_context->user_od_feature_mask |= 1U << PP_OD_FEATURE_PPT_BIT;
- od_table->OverDriveTable.FeatureCtrlMask =
- table_context->user_od_feature_mask;
-
- ret = smu_v14_0_2_upload_overdrive_table(smu, od_table);
+ ppt = (limit * 100) / msg_limit - 100;
+ ret = smu_v14_0_2_upload_ppt_overdrive_table(smu, ppt);
if (ret) {
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
return ret;
diff --git a/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c b/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c
index 223e0a791fae..cab2d763fc79 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c
@@ -26,7 +26,6 @@
#include "ras.h"
#include "eeprom.h"
#include "eeprom_fw.h"
-#include "ras_mp1.h"
static bool __ras_eeprom_disabled(struct ras_core_context *ras_core)
{
@@ -37,36 +36,24 @@ static const struct ras_eeprom_ops *ras_eeprom_mgr_get_ip_func(
struct ras_core_context *ras_core, uint32_t ip_version)
{
struct ras_eeprom_mgr *mgr = &ras_core->eeprom_mgr;
- int ret = 0;
- u32 status = 0;
-
- ret = ras_mp1_check_feature_status(ras_core,
- (enum ras_mp1_feature_id)RAS_CORE_FW_FEATURE_BIT__RAS_EEPROM, &status);
- if (ret)
- RAS_DEV_ERR(ras_core->dev, "Check RAS EEPROM feature failed, ret=%d", ret);
switch (ip_version) {
case IP_VERSION(13, 0, 6):
case IP_VERSION(13, 0, 12):
case IP_VERSION(13, 0, 14):
- case IP_VERSION(13, 0, 15):
mgr->eeprom_early_init_service_supported = false;
- break;
+ return &ras_drv_eeprom_ops;
+ case IP_VERSION(13, 0, 15):
case IP_VERSION(15, 0, 8):
mgr->eeprom_early_init_service_supported = true;
- break;
+ mgr->fw_record_enabled = true;
+ return &ras_fw_eeprom_ops;
default:
RAS_DEV_ERR(ras_core->dev,
"EEPROM(MP1) ip version(0x%x) is not supported!\n", ip_version);
- return NULL;
}
- if (status) {
- mgr->fw_record_enabled = true;
- return &ras_fw_eeprom_ops;
- } else {
- return &ras_drv_eeprom_ops;
- }
+ return NULL;
}
int ras_eeprom_mgr_sw_init(struct ras_core_context *ras_core)
@@ -98,7 +85,7 @@ int ras_eeprom_mgr_sw_init(struct ras_core_context *ras_core)
mgr->ras_err_threshold = param_cfg.eeprom_record_threshold_count;
mgr->work_mode_over_thresh = param_cfg.work_mode_over_thresh;
mgr->eeprom_ip_version = param_cfg.eeprom_ip_version;
- mgr->eeprom_ops = ras_eeprom_mgr_get_ip_func(ras_core, mgr->eeprom_ip_version);
+ mgr->eeprom_ops = ras_eeprom_mgr_get_ip_func(ras_core, ras_core->config->psp_ip_version);
if (!mgr->eeprom_ops)
return -ENODEV;
diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c
index 1e55ecac4698..b9e206b7f9e8 100644
--- a/drivers/gpu/drm/drm_kms_helper_common.c
+++ b/drivers/gpu/drm/drm_kms_helper_common.c
@@ -43,7 +43,7 @@ EXPORT_SYMBOL(drm_fbdev_overalloc);
module_param(drm_fbdev_overalloc, int, 0444);
MODULE_PARM_DESC(drm_fbdev_overalloc,
"Overallocation of the fbdev buffer (%) [default="
- __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
+ __stringify(CONFIG_DRM_FBDEV_OVERALLOC) "]");
/*
* In order to keep user-space compatibility, we want in certain use-cases
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index d5aadced7da0..1b7f5bf13e50 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -1522,8 +1522,9 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
/*
* We must check that the entire relocation array is safe
- * to read. However, if the array is not writable the user loses
- * the updated relocation values.
+ * to read. Whether it is also writable only shows when we
+ * write back the presumed offsets below, and if that fails we
+ * fall back to the slow path.
*/
if (unlikely(!access_ok(urelocs, remain * sizeof(*urelocs))))
return -EFAULT;
@@ -1553,6 +1554,7 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
remain -= count;
do {
u64 offset = eb_relocate_entry(eb, ev, r);
+ int err;
if (likely(offset == 0))
continue;
@@ -1562,28 +1564,41 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
goto out;
}
/*
- * Note that reporting an error now
- * leaves everything in an inconsistent
- * state as we have *already* changed
- * the relocation value inside the
- * object. As we have not changed the
- * reloc.presumed_offset or will not
- * change the execobject.offset, on the
- * call we may not rewrite the value
- * inside the object, leaving it
- * dangling and causing a GPU hang. Unless
- * userspace dynamically rebuilds the
- * relocations on each execbuf rather than
- * presume a static tree.
+ * Write back the presumed offset. We hold the
+ * objects' dma_resv locks here, so this must not
+ * take a page fault: that would take mmap_lock
+ * under dma_resv, the opposite of the order our
+ * own fault handler uses.
*
- * We did previously check if the relocations
- * were writable (access_ok), an error now
- * would be a strange race with mprotect,
- * having already demonstrated that we
- * can read from this userspace address.
+ * If the write fails (the page is read-only,
+ * copy-on-write, or gone since we read it), we
+ * must not just carry on. We have already changed
+ * the relocation value inside the object, and a
+ * stale presumed_offset could later match again
+ * and make us skip a relocation that is needed,
+ * hanging the GPU. So fall back to the slow path,
+ * as for a failed read: it retries after
+ * prefaulting and, failing that, marks every
+ * presumed_offset invalid with faults allowed and
+ * no locks held.
*/
offset = gen8_canonical_addr(offset & ~UPDATE);
- __put_user(offset, &urelocs[r - stack].presumed_offset);
+ pagefault_disable();
+ err = put_user(offset, &urelocs[r - stack].presumed_offset);
+ pagefault_enable();
+
+ /*
+ * Error handling is disabled on purpose. No, it makes
+ * no sense, and the code will loop over the relocations
+ * without writing them back and just waste CPU time,
+ * but that's apparently what the mprotect test-cases
+ * want. See commit 97a37c919f62 ("drm/i915/gem: Ignore
+ * readonly failures when updating relocs")
+ */
+ if (unlikely(err) && 0) {
+ remain = -EFAULT;
+ goto out;
+ }
} while (r++, --count);
urelocs += ARRAY_SIZE(stack);
} while (remain);
@@ -1635,11 +1650,11 @@ static int check_relocations(const struct drm_i915_gem_exec_object2 *entry)
end = addr + size;
for (; addr < end; addr += PAGE_SIZE) {
- int err = __get_user(c, addr);
+ int err = get_user(c, addr);
if (err)
return err;
}
- return __get_user(c, end - 1);
+ return get_user(c, end - 1);
}
static int eb_copy_relocations(const struct i915_execbuffer *eb)
@@ -2837,7 +2852,7 @@ add_timeline_fence_array(struct i915_execbuffer *eb,
if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS)
return -EINVAL;
- if (__get_user(point, user_values++))
+ if (get_user(point, user_values++))
return -EFAULT;
syncobj = drm_syncobj_find(eb->file, user_fence.handle);
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
index 4d49fd6c15e3..303be698891f 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -1465,7 +1465,7 @@ static int __igt_mmap_access(struct drm_i915_private *i915,
return addr;
ptr = (unsigned long __user *)addr;
- err = __put_user(A, ptr);
+ err = put_user(A, ptr);
if (err) {
pr_err("%s(%s): failed to write into user mmap\n",
obj->mm.region->name, repr_mmap_type(type));
@@ -1490,7 +1490,7 @@ static int __igt_mmap_access(struct drm_i915_private *i915,
intel_gt_flush_ggtt_writes(to_gt(i915));
- err = __get_user(y, ptr);
+ err = get_user(y, ptr);
if (err) {
pr_err("%s(%s): failed to read from user mmap\n",
obj->mm.region->name, repr_mmap_type(type));
@@ -1738,12 +1738,12 @@ static int prefault_range(u64 start, u64 len)
end = addr + len;
for (; addr < end; addr += PAGE_SIZE) {
- err = __get_user(c, addr);
+ err = get_user(c, addr);
if (err)
return err;
}
- return __get_user(c, end - 1);
+ return get_user(c, end - 1);
}
static int __igt_mmap_revoke(struct drm_i915_private *i915,
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 3cbc6eedbf66..eb94916c8f68 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -4847,6 +4847,20 @@ restart_ih:
drm_dbg(ddev, "IH: UVD int: 0x%08x\n", src_data);
radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
break;
+ case 167: /* VCE */
+ drm_dbg(ddev, "IH: VCE int: 0x%08x\n", src_data);
+ switch (src_data) {
+ case 0:
+ radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX);
+ break;
+ case 1:
+ radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX);
+ break;
+ default:
+ drm_err(ddev, "Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
case 146:
case 147:
addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 4681ff28630a..af3c4026d183 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -6347,6 +6347,20 @@ restart_ih:
DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
break;
+ case 167: /* VCE */
+ DRM_DEBUG("IH: VCE int: 0x%08x\n", src_data);
+ switch (src_data) {
+ case 0:
+ radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX);
+ break;
+ case 1:
+ radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX);
+ break;
+ default:
+ DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
case 146:
case 147:
addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index f9267b026f8d..ba322de844b3 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -1878,6 +1878,8 @@
#define DMA_PACKET_NOP 0xf
#define VCE_STATUS 0x20004
+#define VCE_SYS_INT_EN 0x20d00
+#define VCE_SYS_INT_TRAP_INTERRUPT_EN (1 << 3)
#define VCE_VCPU_CNTL 0x20014
#define VCE_CLK_EN (1 << 0)
#define VCE_VCPU_CACHE_OFFSET0 0x20024
diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c
index 5e6607e16244..3a9672eff3da 100644
--- a/drivers/gpu/drm/radeon/uvd_v1_0.c
+++ b/drivers/gpu/drm/radeon/uvd_v1_0.c
@@ -158,24 +158,48 @@ int uvd_v1_0_init(struct radeon_device *rdev)
{
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
uint32_t tmp;
- int r;
+ int r, retry, clk_err;
+
+ /* after resume the first ring test can race with the hardware; retry */
+ for (retry = 0; retry < 3; retry++) {
+ /* raise clocks while booting up the VCPU */
+ if (rdev->family < CHIP_RV740)
+ clk_err = radeon_set_uvd_clocks(rdev, 10000, 10000);
+ else
+ clk_err = radeon_set_uvd_clocks(rdev, 53300, 40000);
+ r = clk_err;
+ if (r)
+ drm_warn(&rdev->ddev, "radeon: raising UVD clocks failed (%d), attempt %d\n",
+ r, retry + 1);
+
+ if (!r) {
+ r = uvd_v1_0_start(rdev);
+ if (r)
+ drm_warn(&rdev->ddev, "radeon: starting UVD failed (%d), attempt %d\n",
+ r, retry + 1);
+ }
- /* raise clocks while booting up the VCPU */
- if (rdev->family < CHIP_RV740)
- radeon_set_uvd_clocks(rdev, 10000, 10000);
- else
- radeon_set_uvd_clocks(rdev, 53300, 40000);
+ if (!r) {
+ ring->ready = true;
+ r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
+ if (r) {
+ ring->ready = false;
+ drm_warn(&rdev->ddev, "radeon: UVD ring test failed (%d), attempt %d\n",
+ r, retry + 1);
+ }
+ }
- r = uvd_v1_0_start(rdev);
- if (r)
- goto done;
+ if (!r)
+ break;
- ring->ready = true;
- r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
- if (r) {
- ring->ready = false;
- goto done;
+ /* MMIO is only safe when the block is actually clocked */
+ if (!clk_err)
+ uvd_v1_0_stop(rdev);
+ if (retry < 2)
+ mdelay(20);
}
+ if (r)
+ goto done;
r = radeon_ring_lock(rdev, ring, 10);
if (r) {
diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c
index bdfbcf14b864..09fc1572ab0a 100644
--- a/drivers/gpu/drm/radeon/vce_v1_0.c
+++ b/drivers/gpu/drm/radeon/vce_v1_0.c
@@ -350,6 +350,15 @@ int vce_v1_0_start(struct radeon_device *rdev)
return r;
}
+ /*
+ * Enable the trap interrupt so that VCE fences are processed.
+ * CIK also gets here but has VCE_SYS_INT_EN elsewhere and enables
+ * it in vce_v2_0_resume().
+ */
+ if (rdev->family < CHIP_BONAIRE)
+ WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN,
+ ~VCE_SYS_INT_TRAP_INTERRUPT_EN);
+
return 0;
}
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index ff611c618d6b..956be198f8a7 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -652,13 +652,14 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
fence->seqno = exec->seqno;
exec->fence = &fence->base;
+ /* The job can complete and drop exec->fence as soon as job_lock is
+ * released, so hold our own reference.
+ */
if (out_sync)
- drm_syncobj_replace_fence(out_sync, exec->fence);
+ dma_fence_get(&fence->base);
vc4_attach_fences(exec);
- drm_exec_fini(exec_ctx);
-
list_add_tail(&exec->head, &vc4->bin_job_list);
/* If no bin job was executing and if the render job (if any) has the
@@ -675,6 +676,13 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ drm_exec_fini(exec_ctx);
+
+ if (out_sync) {
+ drm_syncobj_replace_fence(out_sync, &fence->base);
+ dma_fence_put(&fence->base);
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 10930c924070..6fb916f1699b 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -154,6 +154,7 @@ xe-y += xe_bb.o \
xe_vsec.o \
xe_wa.o \
xe_wait_user_fence.o \
+ xe_wedge.o \
xe_wopcm.o
xe-$(CONFIG_I2C) += xe_i2c.o \
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index f5cd3a94e47f..1d396bc5833b 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -487,10 +487,6 @@
#define XEHPC_L3CLOS_MASK(i) XE_REG_MCR(0xb194 + (i) * 8)
-#define L2COMPUTESIDECTRL XE_REG_MCR(0xb1c0)
-#define CECTRL REG_GENMASK(2, 1)
-#define CECTRL_CENODATA_ALWAYS REG_FIELD_PREP(CECTRL, 0x0)
-
#define XE2_GLOBAL_INVAL XE_REG(0xb404)
#define XE2LPM_L3SQCREG2 XE_REG_MCR(0xb604)
diff --git a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h
index 6f7abc0181b5..a2795aa9fd71 100644
--- a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h
+++ b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h
@@ -45,4 +45,7 @@
#define INDIRECT_CTX_RING_START_UDW (0x08 + 1)
#define INDIRECT_CTX_RING_CTL (0x0a + 1)
+#define CTX_INDIRECT_CTX_OFFSET_MASK REG_GENMASK(15, 6)
+#define CTX_INDIRECT_CTX_OFFSET_DEFAULT REG_FIELD_PREP(CTX_INDIRECT_CTX_OFFSET_MASK, 0xd)
+
#endif
diff --git a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c
index 27740b40c8ae..57ea88cce92d 100644
--- a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c
+++ b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c
@@ -15,6 +15,7 @@
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_pm.h"
+#include "xe_wedge.h"
/**
* xe_kunit_helper_alloc_xe_device - Allocate a &xe_device for a KUnit test.
@@ -123,7 +124,7 @@ int xe_kunit_helper_xe_device_live_test_init(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
kunit_info(test, "running on %s device\n", xe->info.platform_name);
- KUNIT_ASSERT_FALSE(test, xe_device_wedged(xe));
+ KUNIT_ASSERT_FALSE(test, xe_wedged(xe));
xe_pm_runtime_get(xe);
KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test, put_xe_pm_runtime, xe));
diff --git a/drivers/gpu/drm/xe/tests/xe_migrate.c b/drivers/gpu/drm/xe/tests/xe_migrate.c
index f10d9513747b..a9ef8f2dcebb 100644
--- a/drivers/gpu/drm/xe/tests/xe_migrate.c
+++ b/drivers/gpu/drm/xe/tests/xe_migrate.c
@@ -6,9 +6,12 @@
#include <kunit/test.h>
#include <kunit/visibility.h>
+#include <linux/prandom.h>
+
#include "tests/xe_kunit_helpers.h"
#include "tests/xe_pci_test.h"
+#include "xe_migrate.h"
#include "xe_pat.h"
#include "xe_pci.h"
#include "xe_pm.h"
@@ -770,9 +773,308 @@ static void xe_validate_ccs_kunit(struct kunit *test)
validate_ccs_test_run_device(xe);
}
+#define ACCESS_MEM_BO_SIZE SZ_512K
+#define ACCESS_MEM_NUM_CELLS (ACCESS_MEM_BO_SIZE / sizeof(u32))
+#define ACCESS_MEM_UNALIGNED_OFFSET 0x215ee
+
+/*
+ * Verify byte-by-byte that data read from the BO matches expected cell pattern.
+ * The BO is primed with u32 cells where cell[i] = i, so BO byte at offset B
+ * has value: (B / 4 >> (B%4 * 8)) & 0xFF.
+ *
+ * @buf: the target buffer
+ * @buf_start: index into buf where read data begins
+ * @bo_start: the BO byte offset corresponding to buf[buf_start]
+ * @size: number of bytes to verify
+ * @scenario: label for error messages
+ *
+ * Returns true if all bytes match, false on first mismatch.
+ */
+static bool verify_access_memory_read(struct kunit *test, u8 *buf,
+ u32 buf_start, u32 bo_start,
+ u32 size, const char *scenario)
+{
+ u32 j;
+
+ for (j = 0; j < size; j++) {
+ u32 bo_byte_offset = bo_start + j;
+ u32 byte_in_cell = bo_byte_offset % sizeof(u32);
+ u32 cell_idx = bo_byte_offset / sizeof(u32);
+ u32 cell_value = cell_idx;
+ u8 expected_byte = (cell_value >> (byte_in_cell * 8)) & 0xFF;
+ u8 got_byte = buf[buf_start + j];
+
+ if (got_byte != expected_byte) {
+ u32 context_end = min(j + 8, size - 1);
+ u32 context_start = (j >= 8) ? j - 8 : 0;
+ u32 k;
+
+ KUNIT_FAIL(test,
+ "%s MISMATCH\n"
+ " Buffer index: %u (0x%x)\n"
+ " BO offset: 0x%x\n"
+ " Cell index: %u (BO offset 0x%x..0x%x)\n"
+ " Byte in cell: %u\n"
+ " Expected value: 0x%02x (from cell_value 0x%08x)\n"
+ " Got value: 0x%02x\n",
+ scenario,
+ buf_start + j, buf_start + j,
+ bo_byte_offset,
+ cell_idx, cell_idx * 4, cell_idx * 4 + 3,
+ byte_in_cell,
+ expected_byte, cell_value,
+ got_byte);
+
+ kunit_info(test, "Buffer context around mismatch (buf[%u..%u]):\n",
+ buf_start + context_start,
+ buf_start + context_end);
+
+ for (k = context_start; k <= context_end; k++) {
+ u32 k_bo_offset = bo_start + k;
+ u32 k_cell = k_bo_offset / sizeof(u32);
+ u32 k_byte = k_bo_offset % sizeof(u32);
+ u32 k_cell_val = k_cell;
+ u8 k_expected = (k_cell_val >> (k_byte * 8)) & 0xFF;
+
+ kunit_info(test,
+ " buf[%4u] @ BO 0x%05x: got 0x%02x, expected 0x%02x %s\n",
+ buf_start + k, k_bo_offset,
+ buf[buf_start + k], k_expected,
+ (k == j) ? "<-- MISMATCH" : "");
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+static void access_memory_test_unaligned_bo_offset(struct kunit *test,
+ struct xe_migrate *m,
+ struct xe_bo *bo, u8 *buf,
+ u32 unaligned_offset)
+{
+ u32 partial_size = ACCESS_MEM_BO_SIZE - unaligned_offset;
+ int ret;
+
+ memset(buf, 0, ACCESS_MEM_BO_SIZE);
+
+ kunit_info(test, "Partial read: bo_offset=0x%x bytes=0x%x\n",
+ unaligned_offset, partial_size);
+
+ ret = xe_migrate_access_memory(m, bo, unaligned_offset, buf,
+ partial_size, false);
+ if (ret) {
+ KUNIT_FAIL(test, "Partial read failed: %d\n", ret);
+ return;
+ }
+
+ if (verify_access_memory_read(test, buf, 0, unaligned_offset,
+ partial_size,
+ "Partial read from unaligned BO offset"))
+ kunit_info(test, "Partial read from unaligned BO offset 0x%x verified\n",
+ unaligned_offset);
+}
+
+static void access_memory_test_unaligned_dst(struct kunit *test,
+ struct xe_migrate *m,
+ struct xe_bo *bo, u8 *buf,
+ u32 unaligned_offset)
+{
+ u32 partial_size = ACCESS_MEM_BO_SIZE - unaligned_offset;
+ int ret;
+
+ memset(buf, 0, ACCESS_MEM_BO_SIZE);
+
+ kunit_info(test, "Read to unaligned dst: bo_offset=0x0 dst_offset=0x%x bytes=0x%x\n",
+ unaligned_offset, partial_size);
+
+ ret = xe_migrate_access_memory(m, bo, 0, buf + unaligned_offset,
+ partial_size, false);
+ if (ret) {
+ KUNIT_FAIL(test, "Read to unaligned dst failed: %d\n", ret);
+ return;
+ }
+
+ if (verify_access_memory_read(test, buf, unaligned_offset, 0,
+ partial_size,
+ "Read to unaligned dst"))
+ kunit_info(test, "Read to unaligned dst offset 0x%x verified\n",
+ unaligned_offset);
+}
+
+static void access_memory_test_unaligned_dst_aligned_size(struct kunit *test,
+ struct xe_migrate *m,
+ struct xe_bo *bo,
+ u8 *buf,
+ u32 unaligned_offset)
+{
+ u32 partial_size = round_down(ACCESS_MEM_BO_SIZE - unaligned_offset, 4);
+ int ret;
+
+ memset(buf, 0, ACCESS_MEM_BO_SIZE);
+
+ kunit_info(test, "Read to unaligned dst (aligned size): bo_offset=0x0 dst_offset=0x%x bytes=0x%x\n",
+ unaligned_offset, partial_size);
+
+ ret = xe_migrate_access_memory(m, bo, 0, buf + unaligned_offset,
+ partial_size, false);
+ if (ret) {
+ KUNIT_FAIL(test, "Read to unaligned dst (aligned size) failed: %d\n", ret);
+ return;
+ }
+
+ if (verify_access_memory_read(test, buf, unaligned_offset, 0,
+ partial_size,
+ "Read to unaligned dst (aligned size)"))
+ kunit_info(test, "Read to unaligned dst (aligned size) offset 0x%x verified\n",
+ unaligned_offset);
+}
+
+static void access_memory_test_run_tile(struct xe_device *xe,
+ struct xe_tile *tile,
+ struct kunit *test,
+ bool use_random_offset)
+{
+ struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
+ unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
+ struct xe_migrate *m = tile->migrate;
+ u32 j, unaligned_offset;
+ struct xe_bo *bo;
+ long timeout;
+ u8 *buf;
+ int ret;
+
+ if (use_random_offset) {
+ unaligned_offset = get_random_u32() % (ACCESS_MEM_BO_SIZE / 2);
+ /* Ensure the offset is not 4-byte aligned */
+ if (IS_ALIGNED(unaligned_offset, 4))
+ unaligned_offset |= 2;
+ if (!unaligned_offset)
+ unaligned_offset = 3;
+ } else {
+ unaligned_offset = ACCESS_MEM_UNALIGNED_OFFSET;
+ }
+
+ kunit_info(test, "Using unaligned offset: 0x%x (%s)\n",
+ unaligned_offset, use_random_offset ? "random" : "predefined");
+
+ buf = kvmalloc(ACCESS_MEM_BO_SIZE, GFP_KERNEL);
+ if (!buf) {
+ KUNIT_FAIL(test, "Failed to allocate buffer\n");
+ return;
+ }
+
+ bo = xe_bo_create_user(xe, NULL, ACCESS_MEM_BO_SIZE,
+ DRM_XE_GEM_CPU_CACHING_WC,
+ bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS, NULL);
+ if (IS_ERR(bo)) {
+ KUNIT_FAIL(test, "Failed to create bo: %pe\n", bo);
+ goto free_buf;
+ }
+
+ /* Prime the BO */
+ for (j = 0; j < ACCESS_MEM_NUM_CELLS; j++)
+ ((u32 *)buf)[j] = j;
+
+ kunit_info(test, "Writing %lu KiB to VRAM bo\n",
+ (unsigned long)ACCESS_MEM_BO_SIZE / SZ_1K);
+
+ xe_bo_lock(bo, false);
+
+ /* The BO is unpinned, so make sure it is in VRAM once locked */
+ ret = xe_bo_validate(bo, NULL, false, exec);
+ if (ret) {
+ KUNIT_FAIL(test, "Failed to validate bo: %d\n", ret);
+ goto cleanup_bo;
+ }
+
+ if (!xe_bo_is_vram(bo)) {
+ KUNIT_FAIL(test, "BO is not in VRAM after validation\n");
+ goto cleanup_bo;
+ }
+
+ timeout = dma_resv_wait_timeout(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL,
+ true, 5 * HZ);
+ if (timeout <= 0) {
+ KUNIT_FAIL(test, "Failed to wait for bo to become idle: %ld\n",
+ timeout);
+ goto cleanup_bo;
+ }
+
+ ret = xe_migrate_access_memory(m, bo, 0, buf, ACCESS_MEM_BO_SIZE, true);
+ if (ret) {
+ KUNIT_FAIL(test, "Failed to write bo: %d\n", ret);
+ goto cleanup_bo;
+ }
+
+ /* Full read */
+ memset(buf, 0, ACCESS_MEM_BO_SIZE);
+ kunit_info(test, "Full read: bo_offset=0x0 bytes=0x%x\n", ACCESS_MEM_BO_SIZE);
+
+ ret = xe_migrate_access_memory(m, bo, 0, buf, ACCESS_MEM_BO_SIZE, false);
+ if (ret) {
+ KUNIT_FAIL(test, "Full read failed: %d\n", ret);
+ goto cleanup_bo;
+ }
+
+ for (j = 0; j < ACCESS_MEM_NUM_CELLS; j++) {
+ u32 expected = j;
+ u32 got = ((u32 *)buf)[j];
+
+ if (got != expected) {
+ KUNIT_FAIL(test,
+ "Full read mismatch at cell %u: expected 0x%08x, got 0x%08x\n",
+ j, expected, got);
+ goto cleanup_bo;
+ }
+ }
+ kunit_info(test, "Full read verified\n");
+
+ access_memory_test_unaligned_bo_offset(test, m, bo, buf, unaligned_offset);
+ access_memory_test_unaligned_dst(test, m, bo, buf, unaligned_offset);
+ access_memory_test_unaligned_dst_aligned_size(test, m, bo, buf, unaligned_offset);
+
+cleanup_bo:
+ xe_bo_unlock(bo);
+ xe_bo_put(bo);
+free_buf:
+ kvfree(buf);
+}
+
+static int access_memory_test_run_device(struct xe_device *xe)
+{
+ struct kunit *test = kunit_get_current_test();
+ struct xe_tile *tile;
+ int id;
+
+ if (!IS_DGFX(xe)) {
+ kunit_skip(test, "non-discrete device\n");
+ return 0;
+ }
+
+ guard(xe_pm_runtime)(xe);
+ for_each_tile(tile, xe, id) {
+ kunit_info(test, "Testing tile id %d (predefined offset)\n", id);
+ access_memory_test_run_tile(xe, tile, test, false);
+
+ kunit_info(test, "Testing tile id %d (random offset)\n", id);
+ access_memory_test_run_tile(xe, tile, test, true);
+ }
+
+ return 0;
+}
+
+static void xe_migrate_access_memory_kunit(struct kunit *test)
+{
+ struct xe_device *xe = test->priv;
+
+ access_memory_test_run_device(xe);
+}
+
static struct kunit_case xe_migrate_tests[] = {
KUNIT_CASE_PARAM(xe_migrate_sanity_kunit, xe_pci_live_device_gen_param),
KUNIT_CASE_PARAM(xe_validate_ccs_kunit, xe_pci_live_device_gen_param),
+ KUNIT_CASE_PARAM(xe_migrate_access_memory_kunit, xe_pci_live_device_gen_param),
{}
};
diff --git a/drivers/gpu/drm/xe/xe_amc.c b/drivers/gpu/drm/xe/xe_amc.c
index edd50bf8261e..37694e34271a 100644
--- a/drivers/gpu/drm/xe/xe_amc.c
+++ b/drivers/gpu/drm/xe/xe_amc.c
@@ -15,9 +15,12 @@
#include "regs/xe_i2c_regs.h"
#include "xe_amc.h"
+#include "xe_any.h"
#include "xe_device.h"
#include "xe_i2c.h"
#include "xe_mmio.h"
+#include "xe_pm.h"
+#include "xe_wedge.h"
/**
* DOC: Add-In Management Controller (AMC)
@@ -108,11 +111,14 @@ static void xe_amc_work(struct work_struct *work)
{
const struct amc_request *request = &amc_get_alert_reason;
struct xe_amc *amc = from_work(amc, work, work);
+ struct xe_device *xe = xe_any_to_xe(amc->i2c->drm_dev);
u8 alert_reason = AMC_ALERT_UNKNOWN;
struct amc_response response;
struct i2c_client *client;
int ret;
+ xe_pm_runtime_get(xe);
+
client = amc->i2c->client[XE_I2C_CLIENT_AMC];
if (IS_ERR_OR_NULL(client))
goto out_reassert_interrupt;
@@ -160,12 +166,15 @@ out_reassert_interrupt:
case AMC_ALERT_OOB_RESET:
case AMC_ALERT_CATERR:
dev_warn(amc->i2c->drm_dev, "AMC Alert: %s\n", amc_alert[alert_reason]);
- xe_device_declare_wedged(i2c_client_to_xe_device(client));
+ xe_wedge_declare(i2c_client_to_xe_device(client),
+ DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
break;
default:
dev_warn(amc->i2c->drm_dev, "unknown AMC alert: %d\n", alert_reason);
break;
}
+
+ xe_pm_runtime_put(xe);
}
void xe_amc_handle_alert(struct xe_i2c *i2c)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index 1b74331b15ec..42a6aa1a2e4a 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -41,6 +41,7 @@
#include "xe_ttm_stolen_mgr.h"
#include "xe_vm.h"
#include "xe_vram_types.h"
+#include "xe_wedge.h"
const char *const xe_mem_type_to_name[TTM_NUM_MEM_TYPES] = {
[XE_PL_SYSTEM] = "system",
@@ -992,6 +993,38 @@ static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo,
}
}
+/*
+ * Change @bo's TTM LRU priority to @priority. @bo's dma-resv must be held.
+ *
+ * Private, user BOs of non-fault-mode VMs have bo->ttm.bulk_move set to their
+ * VM's LRU bulk-move range (see xe_bo_create_user()), which tracks a
+ * contiguous [first, last] run of resources per (mem_type, priority) bucket.
+ * Writing bo->ttm.priority while the BO is still attached to that range would
+ * leave the resource linked in the old priority's bucket while the bulk-move
+ * code looks it up under the new one, corrupting both buckets. Temporarily
+ * detaching the BO from its bulk-move range moves it with a plain, non-bulk
+ * LRU update instead, and reattaching afterwards re-inserts it into the new
+ * priority's bucket.
+ */
+static void xe_bo_update_ttm_priority(struct xe_bo *bo, int priority)
+{
+ struct ttm_lru_bulk_move *bulk = bo->ttm.bulk_move;
+
+ xe_bo_assert_held(bo);
+
+ if (bo->ttm.priority == priority)
+ return;
+
+ if (bulk)
+ ttm_bo_set_bulk_move(&bo->ttm, NULL);
+
+ bo->ttm.priority = priority;
+ ttm_bo_move_to_lru_tail_unlocked(&bo->ttm);
+
+ if (bulk)
+ ttm_bo_set_bulk_move(&bo->ttm, bulk);
+}
+
/**
* xe_bo_set_purgeable_state() - Set BO purgeable state with validation
* @bo: Buffer object
@@ -1001,6 +1034,10 @@ static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo,
* transitions. Once a BO is PURGED, it cannot transition to any other state.
* Invalid transitions are caught with xe_assert(). Shrinker page accounting
* is updated automatically.
+ *
+ * A WILLNEED -> DONTNEED transition also lowers the BO's TTM LRU priority to
+ * XE_BO_PRIORITY_LOW. Conversely, a DONTNEED -> WILLNEED transition restores
+ * XE_BO_PRIORITY_NORMAL.
*/
void xe_bo_set_purgeable_state(struct xe_bo *bo,
enum xe_madv_purgeable_state new_state)
@@ -1018,6 +1055,13 @@ void xe_bo_set_purgeable_state(struct xe_bo *bo,
xe_assert(xe, !(bo->purgeable.state == XE_MADV_PURGEABLE_PURGED &&
new_state != XE_MADV_PURGEABLE_PURGED));
+ if (new_state == XE_MADV_PURGEABLE_DONTNEED &&
+ bo->purgeable.state == XE_MADV_PURGEABLE_WILLNEED)
+ xe_bo_update_ttm_priority(bo, XE_BO_PRIORITY_LOW);
+ else if (new_state == XE_MADV_PURGEABLE_WILLNEED &&
+ bo->purgeable.state == XE_MADV_PURGEABLE_DONTNEED)
+ xe_bo_update_ttm_priority(bo, XE_BO_PRIORITY_NORMAL);
+
bo->purgeable.state = new_state;
xe_bo_set_purgeable_shrinker(bo, new_state);
}
@@ -2203,7 +2247,7 @@ static vm_fault_t xe_bo_cpu_fault(struct vm_fault *vmf)
int err = 0;
int idx;
- if (xe_device_wedged(xe) || !drm_dev_enter(&xe->drm, &idx))
+ if (xe_wedged(xe) || !drm_dev_enter(&xe->drm, &idx))
return ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot);
ret = xe_bo_cpu_fault_fastpath(vmf, xe, bo, needs_rpm);
diff --git a/drivers/gpu/drm/xe/xe_bo_types.h b/drivers/gpu/drm/xe/xe_bo_types.h
index 8ec4a01a0092..0265fb314c77 100644
--- a/drivers/gpu/drm/xe/xe_bo_types.h
+++ b/drivers/gpu/drm/xe/xe_bo_types.h
@@ -24,7 +24,13 @@ struct xe_exec_queue;
#define XE_BO_MAX_PLACEMENTS 3
-/* TODO: To be selected with VM_MADVISE */
+/*
+ * TTM LRU priority bands. The LRU is walked in ascending priority order, so
+ * XE_BO_PRIORITY_LOW objects are the first candidates for eviction and
+ * shrinking. BOs advised DONTNEED through DRM_XE_MADVISE live at
+ * XE_BO_PRIORITY_LOW, everything else at XE_BO_PRIORITY_NORMAL.
+ */
+#define XE_BO_PRIORITY_LOW 0
#define XE_BO_PRIORITY_NORMAL 1
/**
diff --git a/drivers/gpu/drm/xe/xe_configfs.h b/drivers/gpu/drm/xe/xe_configfs.h
index 10a00d6bbf8f..327b648944ff 100644
--- a/drivers/gpu/drm/xe/xe_configfs.h
+++ b/drivers/gpu/drm/xe/xe_configfs.h
@@ -14,7 +14,7 @@
struct pci_dev;
-#if IS_ENABLED(CONFIG_CONFIGFS_FS)
+#if IS_REACHABLE(CONFIG_CONFIGFS_FS)
int xe_configfs_init(void);
void xe_configfs_exit(void);
void xe_configfs_check_device(struct pci_dev *pdev);
diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c
index 926020c7526e..e59d4964d811 100644
--- a/drivers/gpu/drm/xe/xe_debugfs.c
+++ b/drivers/gpu/drm/xe/xe_debugfs.c
@@ -18,13 +18,12 @@
#include "xe_force_wake.h"
#include "xe_gt.h"
#include "xe_gt_debugfs.h"
-#include "xe_gt_printk.h"
-#include "xe_guc_ads.h"
#include "xe_hw_engine.h"
#include "xe_mmio.h"
#include "xe_pagefault.h"
#include "xe_pcode.h"
#include "xe_pm.h"
+#include "xe_printk.h"
#include "xe_psmi.h"
#include "xe_pxp_debugfs.h"
#include "xe_sriov.h"
@@ -36,6 +35,7 @@
#include "xe_ttm_vram_mgr.h"
#include "xe_vsec.h"
#include "xe_wa.h"
+#include "xe_wedge.h"
#ifdef CONFIG_DRM_XE_DEBUG
#include "xe_bo_evict.h"
@@ -424,58 +424,6 @@ static ssize_t wedged_mode_show(struct file *f, char __user *ubuf,
return simple_read_from_buffer(ubuf, size, pos, buf, len);
}
-static int __wedged_mode_set_reset_policy(struct xe_gt *gt, enum xe_wedged_mode mode)
-{
- bool enable_engine_reset;
- int ret;
-
- enable_engine_reset = (mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET);
- ret = xe_guc_ads_scheduler_policy_toggle_reset(&gt->uc.guc.ads,
- enable_engine_reset);
- if (ret)
- xe_gt_err(gt, "Failed to update GuC ADS scheduler policy (%pe)\n", ERR_PTR(ret));
-
- return ret;
-}
-
-static int wedged_mode_set_reset_policy(struct xe_device *xe, enum xe_wedged_mode mode)
-{
- struct xe_gt *gt;
- int ret;
- u8 id;
-
- guard(xe_pm_runtime)(xe);
- for_each_gt(gt, xe, id) {
- ret = __wedged_mode_set_reset_policy(gt, mode);
- if (ret) {
- if (id > 0) {
- xe->wedged.inconsistent_reset = true;
- drm_err(&xe->drm, "Inconsistent reset policy state between GTs\n");
- }
- return ret;
- }
- }
-
- xe->wedged.inconsistent_reset = false;
-
- return 0;
-}
-
-static bool wedged_mode_needs_policy_update(struct xe_device *xe, enum xe_wedged_mode mode)
-{
- if (xe->wedged.inconsistent_reset)
- return true;
-
- if (xe->wedged.mode == mode)
- return false;
-
- if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET ||
- mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
- return true;
-
- return false;
-}
-
static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf,
size_t size, loff_t *pos)
{
@@ -487,18 +435,10 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf,
if (ret)
return ret;
- ret = xe_device_validate_wedged_mode(xe, wedged_mode);
+ ret = xe_wedge_set_mode(xe, wedged_mode);
if (ret)
return ret;
- if (wedged_mode_needs_policy_update(xe, wedged_mode)) {
- ret = wedged_mode_set_reset_policy(xe, wedged_mode);
- if (ret)
- return ret;
- }
-
- xe->wedged.mode = wedged_mode;
-
return size;
}
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 4caf86be8c29..07a7ab6ac083 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -81,6 +81,7 @@
#include "xe_vsec.h"
#include "xe_wait_user_fence.h"
#include "xe_wa.h"
+#include "xe_wedge.h"
#include <generated/xe_device_wa_oob.h>
#include <generated/xe_wa_oob.h>
@@ -238,7 +239,7 @@ static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct xe_device *xe = to_xe_device(file_priv->minor->dev);
long ret;
- if (xe_device_wedged(xe))
+ if (xe_wedged(xe))
return -ECANCELED;
ACQUIRE(xe_pm_runtime_ioctl, pm)(xe);
@@ -256,7 +257,7 @@ static long xe_drm_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
struct xe_device *xe = to_xe_device(file_priv->minor->dev);
long ret;
- if (xe_device_wedged(xe))
+ if (xe_wedged(xe))
return -ECANCELED;
ACQUIRE(xe_pm_runtime_ioctl, pm)(xe);
@@ -756,19 +757,37 @@ int xe_device_probe_early(struct xe_device *xe)
*/
assert_lmem_ready(xe);
- xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
- XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
- drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
- xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
-
err = xe_device_vram_alloc(xe);
if (err)
return err;
+ err = xe_wedge_init(xe);
+ if (err)
+ return err;
+
return 0;
}
ALLOW_ERROR_INJECTION(xe_device_probe_early, ERRNO); /* See xe_pci_probe() */
+static void override_has_cached_pt(struct xe_device *xe)
+{
+ struct xe_gt *gt;
+ u8 id;
+
+ for_each_gt(gt, xe, id) {
+ /*
+ * Wa_16029380221: The affected GT will always use
+ * non-coherent access to page tables, so we must do
+ * uncached writes from the CPU.
+ */
+ if (XE_GT_WA(gt, 16029380221))
+ xe->info.has_cached_pt = false;
+
+ if (XE_GT_WA(gt, 14026539277))
+ xe->info.has_cached_pt = false;
+ }
+}
+
static int probe_has_flat_ccs(struct xe_device *xe)
{
struct xe_gt *gt;
@@ -851,14 +870,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
}
}
-static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
-{
- struct xe_device *xe = arg;
-
- if (atomic_read(&xe->wedged.flag))
- xe_pm_runtime_put(xe);
-}
-
#ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
{
@@ -919,14 +930,7 @@ int xe_device_probe(struct xe_device *xe)
return err;
}
- /*
- * Wa_16029380221: The affected GT will always use non-coherent
- * access to page tables, so we must do uncached writes from the
- * CPU.
- */
- for_each_gt(gt, xe, id)
- if (XE_GT_WA(gt, 16029380221))
- xe->info.has_cached_pt = false;
+ override_has_cached_pt(xe);
for_each_tile(tile, xe, id) {
err = xe_ggtt_init_early(tile->mem.ggtt);
@@ -1099,17 +1103,6 @@ int xe_device_probe(struct xe_device *xe)
detect_preproduction_hw(xe);
- err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
- if (err)
- goto err_unregister_display;
-
- /*
- * Process and log any errors detected by hardware. Possible results can
- * include declaring the device as wedged, which must be done only after
- * xe_device_wedged_fini() is registered.
- */
- xe_ras_process_errors(xe);
-
err = devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe);
if (err)
goto err_unregister_display;
@@ -1346,163 +1339,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
}
/**
- * DOC: Xe Device Wedging
- *
- * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
- * When device is in wedged state, every IOCTL will be blocked and GT cannot
- * be used. The conditions under which the driver declares the device wedged
- * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
- * default recovery method for a wedged state is rebind/bus-reset.
- *
- * Another recovery method is vendor-specific. Below are the cases that send
- * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
- *
- * Case: Firmware Flash
- * --------------------
- *
- * Identification Hint
- * +++++++++++++++++++
- *
- * ``WEDGED=vendor-specific`` drm device wedged uevent with
- * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
- * admin/userspace consumer about the need for a firmware flash.
- *
- * Recovery Procedure
- * ++++++++++++++++++
- *
- * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
- * the below steps
- *
- * - Check Runtime Survivability mode sysfs.
- * If enabled, firmware flash is required to recover the device.
- *
- * /sys/bus/pci/devices/<device>/survivability_mode
- *
- * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
- * firmware and restore device to normal operation.
- */
-
-/**
- * xe_device_set_wedged_method - Set wedged recovery method
- * @xe: xe device instance
- * @method: recovery method to set
- *
- * Set wedged recovery method to be sent in drm wedged uevent.
- */
-void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
-{
- xe->wedged.method = method;
-}
-
-#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
-#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
-
-/**
- * xe_device_declare_wedged - Declare device wedged
- * @xe: xe device instance
- *
- * This is a final state that can only be cleared with the recovery method
- * specified in the drm wedged uevent. The method can be set using
- * xe_device_set_wedged_method before declaring the device as wedged. If no method
- * is set, reprobe (unbind/re-bind) will be sent by default.
- *
- * In this state every IOCTL will be blocked so the GT cannot be used.
- * In general it will be called upon any critical error such as gt reset
- * failure or guc loading failure. Userspace will be notified of this state
- * through device wedged uevent.
- * If xe.wedged module parameter is set to 2, this function will be called
- * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
- * snapshot capture. In this mode, GT reset won't be attempted so the state of
- * the issue is preserved for further debugging.
- */
-void xe_device_declare_wedged(struct xe_device *xe)
-{
- struct xe_gt *gt;
- u8 id;
-
- if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
- drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
- return;
- }
-
- if (!atomic_xchg(&xe->wedged.flag, 1)) {
- xe->needs_flr_on_fini = true;
- xe_pm_runtime_get_noresume(xe);
-
- xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
- xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
- "For recovery procedure, refer to %s\n"
- "Please file a _new_ bug report at %s\n",
- WEDGED_URL, XE_BUG_URL);
- }
-
- for_each_gt(gt, xe, id)
- xe_gt_declare_wedged(gt);
-
- if (xe_device_wedged(xe)) {
- /*
- * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
- * hangs, so wedge the device with 'none' recovery method and have
- * it available to the user for debugging.
- */
- if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
- xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
- /* If no wedge recovery method is set, use default */
- else if (!xe->wedged.method)
- xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
- DRM_WEDGE_RECOVERY_BUS_RESET);
-
- /* Notify userspace of wedged device */
- drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
- }
-}
-
-/**
- * xe_device_validate_wedged_mode - Check if given mode is supported
- * @xe: the &xe_device
- * @mode: requested mode to validate
- *
- * Check whether the provided wedged mode is supported.
- *
- * Return: 0 if mode is supported, error code otherwise.
- */
-int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
-{
- if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
- drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
- return -EINVAL;
- } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
- (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
- drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
- mode, xe_wedged_mode_to_string(mode),
- xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
- return -EPERM;
- }
-
- return 0;
-}
-
-/**
- * xe_wedged_mode_to_string - Convert enum value to string.
- * @mode: the &xe_wedged_mode to convert
- *
- * Returns: wedged mode as a user friendly string.
- */
-const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
-{
- switch (mode) {
- case XE_WEDGED_MODE_NEVER:
- return "never";
- case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
- return "upon-critical-error";
- case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
- return "upon-any-hang-no-reset";
- default:
- return "<invalid>";
- }
-}
-
-/**
* xe_device_asid_to_vm() - Find VM from ASID
* @xe: the &xe_device
* @asid: Address space ID
diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
index 83d6dafab53c..6df60edcb8f8 100644
--- a/drivers/gpu/drm/xe/xe_device.h
+++ b/drivers/gpu/drm/xe/xe_device.h
@@ -139,6 +139,10 @@ static inline bool xe_device_uc_enabled(struct xe_device *xe)
for_each_gt((gt__), (tile__)->xe, (id__)) \
for_each_if((gt__)->tile == (tile__))
+#define for_each_initialized_gt(gt__, xe__, id__) \
+ for_each_gt((gt__), (xe__), (id__)) \
+ for_each_if(READ_ONCE((gt__)->initialized))
+
static inline struct xe_force_wake *gt_to_fw(struct xe_gt *gt)
{
return &gt->pm.fw;
@@ -207,11 +211,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
void xe_device_td_flush(struct xe_device *xe);
void xe_device_l2_flush(struct xe_device *xe, bool force);
-static inline bool xe_device_wedged(struct xe_device *xe)
-{
- return atomic_read(&xe->wedged.flag);
-}
-
#ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
static inline bool xe_debug_page_size_supported(struct xe_device *xe)
{
@@ -260,11 +259,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
}
#endif
-void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
-void xe_device_declare_wedged(struct xe_device *xe);
-int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
-const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
-
struct xe_file *xe_file_get(struct xe_file *xef);
void xe_file_put(struct xe_file *xef);
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index aa3a98ddb457..6a6f9a24365c 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -31,6 +31,7 @@
#include "xe_sysctrl_types.h"
#include "xe_tile_types.h"
#include "xe_validation.h"
+#include "xe_wedge_types.h"
#if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
#define TEST_VM_OPS_ERROR
@@ -48,22 +49,6 @@ struct xe_pxp;
struct xe_ttm_stolen_mgr;
struct xe_vram_region;
-/**
- * enum xe_wedged_mode - possible wedged modes
- * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
- * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
- * when critical error occurs like GT reset failure or firmware failure.
- * This is the default mode.
- * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
- * any hang. In this mode, engine resets are disabled to avoid automatic
- * recovery attempts. This mode is primarily intended for debugging hangs.
- */
-enum xe_wedged_mode {
- XE_WEDGED_MODE_NEVER = 0,
- XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
- XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
-};
-
#ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
/**
* enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
@@ -556,16 +541,7 @@ struct xe_device {
atomic_t in_reset;
/** @wedged: Struct to control Wedged States and mode */
- struct {
- /** @wedged.flag: Xe device faced a critical error and is now blocked. */
- atomic_t flag;
- /** @wedged.mode: Mode controlled by kernel parameter and debugfs */
- enum xe_wedged_mode mode;
- /** @wedged.method: Recovery method to be sent in the drm device wedged uevent */
- unsigned long method;
- /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
- bool inconsistent_reset;
- } wedged;
+ struct xe_wedge wedged;
/** @devres_group: devres group */
void *devres_group;
diff --git a/drivers/gpu/drm/xe/xe_device_wa_oob.rules b/drivers/gpu/drm/xe/xe_device_wa_oob.rules
index d8dc41851425..356b4707dafe 100644
--- a/drivers/gpu/drm/xe/xe_device_wa_oob.rules
+++ b/drivers/gpu/drm/xe/xe_device_wa_oob.rules
@@ -3,7 +3,6 @@
PLATFORM(PANTHERLAKE)
22019338487_display PLATFORM(LUNARLAKE)
14022085890 SUBPLATFORM(BATTLEMAGE, G21)
-14026539277 PLATFORM(NOVALAKE_P), PLATFORM_STEP(A0, B0)
14026633728 PLATFORM(CRESCENTISLAND)
14026746987 PLATFORM(CRESCENTISLAND)
14026779378 PLATFORM(CRESCENTISLAND)
diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c
index 524ac56bdcc7..db669a953886 100644
--- a/drivers/gpu/drm/xe/xe_gsc.c
+++ b/drivers/gpu/drm/xe/xe_gsc.c
@@ -31,6 +31,7 @@
#include "xe_sched_job.h"
#include "xe_uc_fw.h"
#include "xe_wa.h"
+#include "xe_wedge.h"
#include "instructions/xe_gsc_commands.h"
#include "regs/xe_gsc_regs.h"
#include "regs/xe_gt_regs.h"
@@ -340,7 +341,8 @@ static int gsc_er_complete(struct xe_gt *gt)
* declare the device as wedged.
*/
xe_gt_err(gt, "GSC ER timed out!\n");
- xe_device_declare_wedged(gt_to_xe(gt));
+ xe_wedge_declare(gt_to_xe(gt),
+ DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
return -EIO;
}
diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c
index bc9bf6f0b5a7..45fb074812a2 100644
--- a/drivers/gpu/drm/xe/xe_gt.c
+++ b/drivers/gpu/drm/xe/xe_gt.c
@@ -12,7 +12,6 @@
#include <drm/drm_managed.h>
#include <uapi/drm/xe_drm.h>
-#include <generated/xe_device_wa_oob.h>
#include <generated/xe_wa_oob.h>
#include "instructions/xe_alu_commands.h"
@@ -68,6 +67,7 @@
#include "xe_uc_fw.h"
#include "xe_vm.h"
#include "xe_wa.h"
+#include "xe_wedge.h"
#include "xe_wopcm.h"
#define GRDOM_RESET_TIMEOUT_MS 5
@@ -175,6 +175,7 @@ static void xe_gt_enable_comp_1wcoh(struct xe_gt *gt)
}
static void gt_reset_worker(struct work_struct *w);
+static void gt_wedge_worker(struct work_struct *w);
static int emit_job_sync(struct xe_exec_queue *q, struct xe_bb *bb,
long timeout_jiffies, bool force_reset)
@@ -458,35 +459,6 @@ put_exec_queue:
return err;
}
-static void wa_14026539277(struct xe_gt *gt)
-{
- struct xe_device *xe = gt_to_xe(gt);
- u32 val;
-
- /*
- * FIXME: We currently can't use FUNC(xe_rtp_match_not_sriov_vf) in the
- * rules for Wa_14026539277 due to xe_wa_process_device_oob() being
- * called before xe_sriov_probe_early(); and we can't move the call to
- * the former to happen after the latter because MMIO read functions
- * already depend on a device OOB workaround. This needs to be fixed by
- * allowing workaround checks to happen at different stages of driver
- * initialization.
- */
- if (IS_SRIOV_VF(xe))
- return;
-
- if (!XE_DEVICE_WA(xe, 14026539277))
- return;
-
- if (!xe_gt_is_main_type(gt))
- return;
-
- val = xe_gt_mcr_unicast_read_any(gt, L2COMPUTESIDECTRL);
- val &= ~CECTRL;
- val |= CECTRL_CENODATA_ALWAYS;
- xe_gt_mcr_multicast_write(gt, L2COMPUTESIDECTRL, val);
-}
-
int xe_gt_init_early(struct xe_gt *gt)
{
int err;
@@ -546,6 +518,8 @@ int xe_gt_init_early(struct xe_gt *gt)
xe_gt_mcr_init_early(gt);
xe_pat_init(gt);
+ INIT_WORK(&gt->reset.worker, gt_reset_worker);
+ INIT_WORK(&gt->wedge.worker, gt_wedge_worker);
return 0;
}
@@ -618,28 +592,24 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt)
else
gt->info.has_wmtp_disabled = 0;
- /*
- * Wa_14026539277 can't be implemented as a regular GT workaround (i.e.
- * as an entry in gt_was[]) for two reasons: it is actually a device
- * workaround that happens to involve programming a GT register; and it
- * needs to be applied early to avoid getting the hardware in a bad
- * state before we have a chance to do the necessary programming.
- */
- wa_14026539277(gt);
-
return 0;
}
-static void gt_reset_worker_disable(void *arg)
+static void gt_worker_disable(void *arg)
{
struct xe_gt *gt = arg;
+ WRITE_ONCE(gt->initialized, false);
+
if (disable_work_sync(&gt->reset.worker))
/*
* If gt_reset_worker was halted from executing, take care of
* releasing the rpm reference here.
*/
xe_pm_runtime_put(gt_to_xe(gt));
+
+ if (disable_work_sync(&gt->wedge.worker))
+ xe_pm_runtime_put(gt_to_xe(gt));
}
static int gt_init_with_all_forcewake(struct xe_gt *gt)
@@ -712,7 +682,7 @@ static int gt_init_with_all_forcewake(struct xe_gt *gt)
xe_gt_sriov_pf_init_hw(gt);
/* Last action registered here so devres drains resets before teardown */
- err = devm_add_action_or_reset(xe->drm.dev, gt_reset_worker_disable, gt);
+ err = devm_add_action_or_reset(xe->drm.dev, gt_worker_disable, gt);
if (err)
return err;
@@ -724,7 +694,7 @@ static void xe_gt_fini(void *arg)
struct xe_gt *gt = arg;
int i;
- gt_reset_worker_disable(gt);
+ gt_worker_disable(gt);
for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i)
xe_hw_fence_irq_finish(&gt->fence_irq[i]);
@@ -737,8 +707,6 @@ int xe_gt_init(struct xe_gt *gt)
int err;
int i;
- INIT_WORK(&gt->reset.worker, gt_reset_worker);
-
for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) {
gt->ring_ops[i] = xe_ring_ops_get(gt, i);
xe_hw_fence_irq_init(&gt->fence_irq[i]);
@@ -768,7 +736,7 @@ int xe_gt_init(struct xe_gt *gt)
err = gt_init_with_all_forcewake(gt);
if (err) {
- gt_reset_worker_disable(gt);
+ gt_worker_disable(gt);
return err;
}
@@ -784,6 +752,8 @@ int xe_gt_init(struct xe_gt *gt)
return err;
}
+ /* Must be last */
+ WRITE_ONCE(gt->initialized, true);
return 0;
}
@@ -942,7 +912,7 @@ static void gt_reset_worker(struct work_struct *w)
unsigned int fw_ref;
int err;
- if (xe_device_wedged(gt_to_xe(gt)))
+ if (xe_wedged(gt_to_xe(gt)))
goto err_pm_put;
if (xe_device_is_in_reset(gt_to_xe(gt)))
@@ -1001,7 +971,7 @@ err_out:
err_fail:
xe_log_err_fatal(gt, GT, err, "reset failed\n");
- xe_device_declare_wedged(gt_to_xe(gt));
+ xe_wedge_declare(gt_to_xe(gt), DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
err_pm_put:
xe_pm_runtime_put(gt_to_xe(gt));
}
@@ -1204,17 +1174,30 @@ struct xe_hw_engine *xe_gt_any_hw_engine(struct xe_gt *gt)
return NULL;
}
+static void gt_wedge_worker(struct work_struct *w)
+{
+ struct xe_gt *gt = container_of(w, typeof(*gt), wedge.worker);
+
+ xe_uc_wedge_declare(&gt->uc);
+ xe_tlb_inval_reset(&gt->tlb_inval);
+ xe_pm_runtime_put(gt_to_xe(gt));
+}
+
/**
- * xe_gt_declare_wedged() - Declare GT wedged
+ * xe_gt_wedge_declare() - Declare GT wedged
* @gt: the GT object
*
* Wedge the GT which stops all submission, saves desired debug state, and
* cleans up anything which could timeout.
*/
-void xe_gt_declare_wedged(struct xe_gt *gt)
+void xe_gt_wedge_declare(struct xe_gt *gt)
{
- xe_gt_assert(gt, gt_to_xe(gt)->wedged.mode);
+ struct xe_device *xe = gt_to_xe(gt);
- xe_uc_declare_wedged(&gt->uc);
- xe_tlb_inval_reset(&gt->tlb_inval);
+ xe_gt_assert(gt, xe->wedged.mode);
+ xe_uc_reset_prepare(&gt->uc);
+
+ xe_pm_runtime_get_noresume(xe);
+ if (!queue_work(gt->ordered_wq, &gt->wedge.worker))
+ xe_pm_runtime_put(xe);
}
diff --git a/drivers/gpu/drm/xe/xe_gt.h b/drivers/gpu/drm/xe/xe_gt.h
index 92d934d50244..7b6952fe804c 100644
--- a/drivers/gpu/drm/xe/xe_gt.h
+++ b/drivers/gpu/drm/xe/xe_gt.h
@@ -40,7 +40,7 @@ struct xe_gt *xe_gt_alloc(struct xe_tile *tile);
int xe_gt_init_early(struct xe_gt *gt);
int xe_gt_init(struct xe_gt *gt);
void xe_gt_mmio_init(struct xe_gt *gt);
-void xe_gt_declare_wedged(struct xe_gt *gt);
+void xe_gt_wedge_declare(struct xe_gt *gt);
int xe_gt_record_default_lrcs(struct xe_gt *gt);
/**
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
index 37899fcf5b22..2a5f2064ad3e 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
@@ -37,6 +37,7 @@
#include "xe_tile_sriov_vf.h"
#include "xe_tlb_inval.h"
#include "xe_uc_fw.h"
+#include "xe_wedge.h"
#include "xe_wopcm.h"
#define make_u64_from_u32(hi, lo) ((u64)((u64)(u32)(hi) << 32 | (u32)(lo)))
@@ -1462,7 +1463,7 @@ static void vf_post_migration_recovery(struct xe_gt *gt)
fail:
vf_post_migration_abort(gt);
xe_gt_sriov_err(gt, "migration recovery failed (%pe)\n", ERR_PTR(err));
- xe_device_declare_wedged(xe);
+ xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
return;
queue:
diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h
index 628911346455..c00a7c171f80 100644
--- a/drivers/gpu/drm/xe/xe_gt_types.h
+++ b/drivers/gpu/drm/xe/xe_gt_types.h
@@ -233,6 +233,12 @@ struct xe_gt {
struct work_struct worker;
} reset;
+ /** @wedge: state for GT wedge */
+ struct {
+ /** @wedge.worker: worker for GT wedge to be done async */
+ struct work_struct worker;
+ } wedge;
+
/** @tlb_inval: TLB invalidation state */
struct xe_tlb_inval tlb_inval;
@@ -419,6 +425,9 @@ struct xe_gt {
/** @eu_stall: EU stall counters subsystem per gt info */
struct xe_eu_stall_gt *eu_stall;
+
+ /** @initialized: GT is initialized */
+ bool initialized;
};
#endif
diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c
index c64cff067e97..ab891e818876 100644
--- a/drivers/gpu/drm/xe/xe_guc.c
+++ b/drivers/gpu/drm/xe/xe_guc.c
@@ -1832,17 +1832,16 @@ int xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p)
}
/**
- * xe_guc_declare_wedged() - Declare GuC wedged
+ * xe_guc_wedge_declare() - Declare GuC wedged
* @guc: the GuC object
*
* Wedge the GuC which stops all submission, saves desired debug state, and
* cleans up anything which could timeout.
*/
-void xe_guc_declare_wedged(struct xe_guc *guc)
+void xe_guc_wedge_declare(struct xe_guc *guc)
{
xe_gt_assert(guc_to_gt(guc), guc_to_xe(guc)->wedged.mode);
- xe_guc_reset_prepare(guc);
xe_guc_ct_stop(&guc->ct);
xe_guc_submit_wedge(guc);
}
diff --git a/drivers/gpu/drm/xe/xe_guc.h b/drivers/gpu/drm/xe/xe_guc.h
index c4eca40d69cf..75c4b9acb065 100644
--- a/drivers/gpu/drm/xe/xe_guc.h
+++ b/drivers/gpu/drm/xe/xe_guc.h
@@ -62,7 +62,7 @@ void xe_guc_reset_wait(struct xe_guc *guc);
void xe_guc_stop_prepare(struct xe_guc *guc);
void xe_guc_stop(struct xe_guc *guc);
int xe_guc_start(struct xe_guc *guc);
-void xe_guc_declare_wedged(struct xe_guc *guc);
+void xe_guc_wedge_declare(struct xe_guc *guc);
bool xe_guc_using_main_gamctrl_queues(struct xe_guc *guc);
bool xe_guc_has_paging_engine(struct xe_guc *guc);
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
index 86246f925203..0a1b37fa0efb 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.c
+++ b/drivers/gpu/drm/xe/xe_guc_ct.c
@@ -37,6 +37,7 @@
#include "xe_sleep.h"
#include "xe_sriov_vf.h"
#include "xe_trace_guc.h"
+#include "xe_wedge.h"
/**
* DOC: GuC CT Error Codes
@@ -1161,7 +1162,7 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action,
xe_gt_assert(gt, g2h_len || !num_g2h);
lockdep_assert_held(&ct->lock);
- if (xe_device_wedged(ct_to_xe(ct))) {
+ if (xe_wedged(ct_to_xe(ct))) {
ret = -ENOTRECOVERABLE;
goto out;
}
@@ -1590,7 +1591,7 @@ wait_again:
if (g2h_fence.fail) {
if (g2h_fence.cancel) {
xe_gt_dbg(gt, "H2G request %#x canceled!\n", action[0]);
- ret = xe_device_wedged(ct_to_xe(ct)) ? -ENOTRECOVERABLE : -ECANCELED;
+ ret = xe_wedged(ct_to_xe(ct)) ? -ENOTRECOVERABLE : -ECANCELED;
goto unlock;
}
xe_gt_err(gt, "H2G request %#x failed: error %#x hint %#x\n",
@@ -1935,7 +1936,7 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path)
lockdep_assert_held(&ct->fast_lock);
/* Keep in sync with g2h_err_is_fatal() */
- if (xe_device_wedged(xe))
+ if (xe_wedged(xe))
return -ENOTRECOVERABLE;
if (ct->state == XE_GUC_CT_STATE_DISABLED)
diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c
index e0105222a2c7..9558d7196a51 100644
--- a/drivers/gpu/drm/xe/xe_guc_pc.c
+++ b/drivers/gpu/drm/xe/xe_guc_pc.c
@@ -36,6 +36,7 @@
#include "xe_pm.h"
#include "xe_sriov.h"
#include "xe_wa.h"
+#include "xe_wedge.h"
#define MCHBAR_MIRROR_BASE_SNB 0x140000
@@ -188,7 +189,7 @@ static int pc_action_reset(struct xe_guc_pc *pc)
int ret;
ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0);
- if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
+ if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
xe_gt_err(pc_to_gt(pc), "GuC PC reset failed: %pe\n",
ERR_PTR(ret));
@@ -212,7 +213,7 @@ static int pc_action_query_task_state(struct xe_guc_pc *pc)
/* Blocking here to ensure the results are ready before reading them */
ret = xe_guc_ct_send_block(ct, action, ARRAY_SIZE(action));
- if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
+ if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
xe_gt_err(pc_to_gt(pc), "GuC PC query task state failed: %pe\n",
ERR_PTR(ret));
@@ -235,7 +236,7 @@ static int pc_action_set_param(struct xe_guc_pc *pc, u8 id, u32 value)
return -EAGAIN;
ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0);
- if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
+ if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
xe_gt_err(pc_to_gt(pc), "GuC PC set param[%u]=%u failed: %pe\n",
id, value, ERR_PTR(ret));
@@ -257,7 +258,7 @@ static int pc_action_unset_param(struct xe_guc_pc *pc, u8 id)
return -EAGAIN;
ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0);
- if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
+ if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED))
xe_gt_err(pc_to_gt(pc), "GuC PC unset param failed: %pe",
ERR_PTR(ret));
@@ -1357,7 +1358,7 @@ static void xe_guc_pc_fini_hw(void *arg)
struct xe_guc_pc *pc = arg;
struct xe_device *xe = pc_to_xe(pc);
- if (xe_device_wedged(xe))
+ if (xe_wedged(xe))
return;
xe_guc_pc_stop(pc);
diff --git a/drivers/gpu/drm/xe/xe_guc_rc.c b/drivers/gpu/drm/xe/xe_guc_rc.c
index 99fa127b261f..fa3062ab134a 100644
--- a/drivers/gpu/drm/xe/xe_guc_rc.c
+++ b/drivers/gpu/drm/xe/xe_guc_rc.c
@@ -16,6 +16,7 @@
#include "xe_guc_pc.h"
#include "xe_guc_rc.h"
#include "xe_pm.h"
+#include "xe_wedge.h"
/**
* DOC: GuC RC (Render C-states)
@@ -40,7 +41,7 @@ static int guc_action_setup_gucrc(struct xe_guc *guc, u32 control)
int ret;
ret = xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0);
- if (ret && !(xe_device_wedged(guc_to_xe(guc)) && ret == -ECANCELED))
+ if (ret && !(xe_wedged(guc_to_xe(guc)) && ret == -ECANCELED))
xe_gt_err(guc_to_gt(guc),
"GuC RC setup %s(%u) failed (%pe)\n",
control == GUCRC_HOST_CONTROL ? "HOST_CONTROL" :
@@ -73,7 +74,7 @@ static void xe_guc_rc_fini_hw(void *arg)
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
- if (xe_device_wedged(xe))
+ if (xe_wedged(xe))
return;
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT);
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index bc39cea08ecc..9e7c2778029c 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -50,6 +50,7 @@
#include "xe_trace.h"
#include "xe_uc_fw.h"
#include "xe_vm.h"
+#include "xe_wedge.h"
#define XE_GUC_EXEC_QUEUE_CGP_CONTEXT_ERROR_LEN 6
@@ -1455,10 +1456,10 @@ static bool guc_submit_hint_wedged(struct xe_guc *guc)
if (xe->wedged.mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
return false;
- if (xe_device_wedged(xe))
+ if (xe_wedged(xe))
return true;
- xe_device_declare_wedged(xe);
+ xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
return true;
}
@@ -1671,7 +1672,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
if (!exec_queue_killed(q))
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
else
- wedged = xe_device_wedged(xe);
+ wedged = xe_wedged(xe);
/*
* Only tag as GPU hang if this is the original timeout, not a
@@ -1791,7 +1792,8 @@ trigger_reset:
}
if (wedge_device)
- xe_device_declare_wedged(gt_to_xe(q->gt));
+ xe_wedge_declare(gt_to_xe(q->gt),
+ DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
/*
* We want the job added back to the pending list so it gets freed; this
@@ -2556,7 +2558,7 @@ retry:
WAIT_COND, HZ * 5);
}
- if (!blocking && vf_recovery(guc) && !xe_device_wedged(xe))
+ if (!blocking && vf_recovery(guc) && !xe_wedged(xe))
return -EAGAIN;
if (!ret)
@@ -2816,7 +2818,7 @@ int xe_guc_submit_reset_prepare(struct xe_guc *guc)
void xe_guc_submit_reset_wait(struct xe_guc *guc)
{
- wait_event(guc->ct.wq, xe_device_wedged(guc_to_xe(guc)) ||
+ wait_event(guc->ct.wq, xe_wedged(guc_to_xe(guc)) ||
!xe_guc_read_stopped(guc));
}
@@ -3368,8 +3370,17 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q,
xe_gt_assert(guc_to_gt(guc), runnable_state == 0);
xe_gt_assert(guc_to_gt(guc), exec_queue_pending_disable(q));
+ /*
+ * A TDR stops the scheduler, which can trap a queued SUSPEND
+ * message, and then issues a disable of its own. suspend_pending
+ * is still set in that case, so only attribute this SCHED_DONE
+ * to a suspend if the SUSPEND message actually ran, i.e. it
+ * marked the queue suspended before disabling scheduling. The
+ * trapped message completes the suspend once submission
+ * restarts.
+ */
xe_sched_msg_lock(&q->guc->sched);
- was_pending = q->guc->suspend_pending;
+ was_pending = q->guc->suspend_pending && exec_queue_suspended(q);
if (was_pending) {
clear_exec_queue_pending_disable(q);
suspend_fence_signal(q);
@@ -3377,26 +3388,27 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q,
xe_sched_msg_unlock(&q->guc->sched);
if (!was_pending) {
- if (exec_queue_banned(q)) {
- smp_wmb();
- wake_up_all(&guc->ct.wq);
- }
- if (exec_queue_destroyed(q)) {
- /*
- * Make sure to clear the pending_disable only
- * after sampling the destroyed state. We want
- * to ensure we don't trigger the unregister too
- * early with something intending to only
- * disable scheduling. The caller doing the
- * destroy must wait for an ongoing
- * pending_disable before marking as destroyed.
- */
- clear_exec_queue_pending_disable(q);
+ /*
+ * Make sure to clear the pending_disable only after
+ * sampling the destroyed state. We want to ensure we
+ * don't trigger the unregister too early with something
+ * intending to only disable scheduling. The caller
+ * doing the destroy must wait for an ongoing
+ * pending_disable before marking as destroyed.
+ */
+ bool destroyed = exec_queue_destroyed(q);
+
+ clear_exec_queue_pending_disable(q);
+ if (destroyed)
deregister_exec_queue(guc, q);
- } else {
- clear_exec_queue_pending_disable(q);
- }
}
+
+ /*
+ * Wake after pending_disable is cleared, not before, so waiters
+ * such as the TDR see the updated state on the first re-check.
+ */
+ smp_wmb();
+ wake_up_all(&guc->ct.wq);
}
}
diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
index 111fef781b2a..dd38d95c6014 100644
--- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
+++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
@@ -19,6 +19,7 @@
#include "xe_sa.h"
#include "xe_tlb_inval.h"
#include "xe_vm.h"
+#include "xe_wedge.h"
#include "regs/xe_guc_regs.h"
@@ -77,7 +78,7 @@ static int send_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval, u32 seqno)
};
return send_tlb_inval(guc, action, ARRAY_SIZE(action));
- } else if (xe_device_uc_enabled(xe) && !xe_device_wedged(xe)) {
+ } else if (xe_device_uc_enabled(xe) && !xe_wedged(xe)) {
struct xe_mmio *mmio = &gt->mmio;
if (IS_SRIOV_VF(xe))
diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c
index f53a6b3055de..ac720710c8e8 100644
--- a/drivers/gpu/drm/xe/xe_hw_error.c
+++ b/drivers/gpu/drm/xe/xe_hw_error.c
@@ -14,6 +14,7 @@
#include "xe_drm_ras.h"
#include "xe_hw_error.h"
#include "xe_mmio.h"
+#include "xe_pm.h"
#include "xe_survivability_mode.h"
#define GT_HW_ERROR_MAX_ERR_BITS 16
@@ -170,6 +171,7 @@ static void csc_hw_error_work(struct work_struct *work)
struct xe_tile *tile = container_of(work, typeof(*tile), csc_hw_error_work);
struct xe_device *xe = tile_to_xe(tile);
+ guard(xe_pm_runtime)(xe);
xe_survivability_mode_runtime_enable(xe);
}
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index fe2909b7b84d..040a52f9320e 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -1469,15 +1469,15 @@ setup_indirect_ctx(struct xe_lrc *lrc, struct xe_hw_engine *hwe)
finish_bo(&state);
kfree(state.buffer);
- /*
- * Enable INDIRECT_CTX leaving INDIRECT_CTX_OFFSET at its default: it
- * varies per engine class, but the default is good enough
- */
xe_lrc_write_ctx_reg(lrc,
CTX_CS_INDIRECT_CTX,
(xe_bo_ggtt_addr(lrc->bo) + state.offset) |
/* Size in CLs. */
(state.written * sizeof(u32) / 64));
+ if (GRAPHICS_VER(lrc_to_xe(lrc)) < 20)
+ xe_lrc_write_ctx_reg(lrc,
+ CTX_CS_INDIRECT_CTX_OFFSET,
+ CTX_INDIRECT_CTX_OFFSET_DEFAULT);
return 0;
}
diff --git a/drivers/gpu/drm/xe/xe_mert.c b/drivers/gpu/drm/xe/xe_mert.c
index 32700c19a1df..a2eae6088c1a 100644
--- a/drivers/gpu/drm/xe/xe_mert.c
+++ b/drivers/gpu/drm/xe/xe_mert.c
@@ -11,6 +11,7 @@
#include "xe_mmio.h"
#include "xe_sriov_printk.h"
#include "xe_tile.h"
+#include "xe_wedge.h"
/**
* xe_mert_init_early() - Initialize MERT data
@@ -74,7 +75,7 @@ static void mert_handle_cat_error(struct xe_device *xe)
break;
case CATERR_UNMAPPED_GGTT:
xe_sriov_err(xe, "MERT: CAT_ERR: Access to an unmapped GGTT!\n");
- xe_device_declare_wedged(xe);
+ xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
break;
case CATERR_LMTT_FAULT:
xe_sriov_dbg_ratelimited(xe, "MERT: CAT_ERR: VF%u LMTT fault!\n", vfid);
@@ -82,7 +83,7 @@ static void mert_handle_cat_error(struct xe_device *xe)
break;
default:
xe_sriov_err(xe, "MERT: Unexpected CAT_ERR code=%#x!\n", code);
- xe_device_declare_wedged(xe);
+ xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET);
break;
}
}
diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c
index fffb3eb6c76e..70408fa0a606 100644
--- a/drivers/gpu/drm/xe/xe_migrate.c
+++ b/drivers/gpu/drm/xe/xe_migrate.c
@@ -2187,17 +2187,18 @@ static bool xe_migrate_vram_use_pde(struct drm_pagemap_addr *sram_addr,
#define XE_CACHELINE_BYTES 64ull
#define XE_CACHELINE_MASK (XE_CACHELINE_BYTES - 1)
-static u32 xe_migrate_copy_pitch(struct xe_device *xe, u32 len)
+static u32 xe_migrate_copy_pitch(struct xe_device *xe, u32 len, u64 dst_addr)
{
+ u64 align_check = len | dst_addr;
u32 pitch;
- if (IS_ALIGNED(len, PAGE_SIZE))
+ if (IS_ALIGNED(align_check, PAGE_SIZE))
pitch = PAGE_SIZE;
- else if (IS_ALIGNED(len, SZ_4K))
+ else if (IS_ALIGNED(align_check, SZ_4K))
pitch = SZ_4K;
- else if (IS_ALIGNED(len, SZ_256))
+ else if (IS_ALIGNED(align_check, SZ_256))
pitch = SZ_256;
- else if (IS_ALIGNED(len, 4))
+ else if (IS_ALIGNED(align_check, 4))
pitch = 4;
else
pitch = 1;
@@ -2206,6 +2207,86 @@ static u32 xe_migrate_copy_pitch(struct xe_device *xe, u32 len)
return pitch;
}
+/**
+ * xe_migrate_dst_pitch() - Determine max pitch supported by dst alignment
+ * @dst_addr: Destination address (page offset)
+ *
+ * Returns the largest pitch (PAGE_SIZE, SZ_4K, SZ_256, or 4) that dst_addr
+ * supports based solely on its alignment. Returns 1 if not even 4-byte aligned.
+ */
+static u32 xe_migrate_dst_pitch(u64 dst_addr)
+{
+ if (IS_ALIGNED(dst_addr, PAGE_SIZE))
+ return PAGE_SIZE;
+ if (IS_ALIGNED(dst_addr, SZ_4K))
+ return SZ_4K;
+ if (IS_ALIGNED(dst_addr, SZ_256))
+ return SZ_256;
+ if (IS_ALIGNED(dst_addr, 4))
+ return 4;
+ return 1;
+}
+
+/**
+ * xe_migrate_bytes_to_align() - Calculate bytes needed to reach target alignment
+ * @dst_addr: Current destination address
+ * @alignment: Target alignment (PAGE_SIZE, SZ_4K, SZ_256, or 4)
+ *
+ * Returns: Number of bytes to copy to reach the target alignment.
+ */
+static u32 xe_migrate_bytes_to_align(u64 dst_addr, u32 alignment)
+{
+ return round_up(dst_addr, alignment) - dst_addr;
+}
+
+/**
+ * xe_migrate_best_alignment() - Find the best alignment reachable within max_bytes
+ * @dst_addr: Current destination address
+ * @max_bytes: Maximum bytes we can copy to reach alignment (typically U16_MAX)
+ *
+ * Returns the largest alignment (PAGE_SIZE, SZ_4K, SZ_256, or 4) that dst_addr
+ * can reach by copying at most max_bytes. Returns 0 if already at best alignment
+ * or if no useful alignment can be reached.
+ */
+static u32 xe_migrate_best_alignment(u64 dst_addr, u32 max_bytes)
+{
+ u32 bytes_to_page = xe_migrate_bytes_to_align(dst_addr, PAGE_SIZE);
+ u32 bytes_to_4k = xe_migrate_bytes_to_align(dst_addr, SZ_4K);
+ u32 bytes_to_256 = xe_migrate_bytes_to_align(dst_addr, SZ_256);
+ u32 bytes_to_4 = xe_migrate_bytes_to_align(dst_addr, 4);
+
+ if (bytes_to_page == 0)
+ return 0;
+
+ if (bytes_to_page <= max_bytes)
+ return PAGE_SIZE;
+
+ if (bytes_to_4k > 0 && bytes_to_4k <= max_bytes)
+ return SZ_4K;
+
+ if (bytes_to_256 > 0 && bytes_to_256 <= max_bytes)
+ return SZ_256;
+
+ if (bytes_to_4 > 0 && bytes_to_4 <= max_bytes)
+ return 4;
+
+ return 0;
+}
+
+/**
+ * xe_migrate_aligned_copy_len() - Calculate the aligned copy length for matrix copy
+ * @len: Remaining bytes
+ * @pitch: The pitch to use for matrix copy
+ *
+ * Returns: Length rounded down to pitch, or 0 if less than pitch.
+ */
+static u32 xe_migrate_aligned_copy_len(u32 len, u32 pitch)
+{
+ if (len < pitch)
+ return 0;
+ return round_down(len, pitch);
+}
+
static struct dma_fence *xe_migrate_vram(struct xe_migrate *m,
unsigned long len,
unsigned long sram_offset,
@@ -2224,16 +2305,11 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m,
struct xe_bb *bb;
u32 update_idx, pt_slot = 0;
unsigned long npages = DIV_ROUND_UP(len + sram_offset, PAGE_SIZE);
- unsigned int pitch = xe_migrate_copy_pitch(xe, len);
+ unsigned int pitch;
int err;
unsigned long i, j;
bool use_pde = xe_migrate_vram_use_pde(sram_addr, len + sram_offset);
- if (!xe->info.has_mem_copy_instr &&
- drm_WARN_ON(&xe->drm,
- (!IS_ALIGNED(len, pitch)) || (sram_offset | vram_addr) & XE_CACHELINE_MASK))
- return ERR_PTR(-EOPNOTSUPP);
-
xe_assert(xe, npages * PAGE_SIZE <= MAX_PREEMPTDISABLE_TRANSFER);
batch_size += pte_update_cmd_size(npages << PAGE_SHIFT);
@@ -2285,6 +2361,15 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m,
dst_L0_ofs = xe_migrate_vm_addr(pt_slot, 0) + sram_offset;
}
+ pitch = xe_migrate_copy_pitch(xe, len, dst_L0_ofs);
+ if (!xe->info.has_mem_copy_instr &&
+ drm_WARN_ON(&xe->drm,
+ (!IS_ALIGNED(len, pitch)) ||
+ (sram_offset | vram_addr) & XE_CACHELINE_MASK)) {
+ err = -EOPNOTSUPP;
+ goto err;
+ }
+
bb->cs[bb->len++] = MI_BATCH_BUFFER_END;
update_idx = bb->len;
@@ -2527,7 +2612,6 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo,
u64 vram_addr = vram_region_gpu_offset(bo->ttm.resource) +
cursor.start;
int current_bytes;
- u32 pitch;
if (cursor.size > MAX_PREEMPTDISABLE_TRANSFER)
current_bytes = min_t(int, bytes_left,
@@ -2535,13 +2619,62 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo,
else
current_bytes = min_t(int, bytes_left, cursor.size);
- pitch = xe_migrate_copy_pitch(xe, current_bytes);
- if (xe->info.has_mem_copy_instr)
- current_bytes = min_t(int, current_bytes, U16_MAX * pitch);
- else
- current_bytes = min_t(int, current_bytes,
- round_down(S16_MAX * pitch,
- XE_CACHELINE_BYTES));
+ {
+ /*
+ * Optimized copy strategy to minimize number of jobs:
+ * 1. Linear copy to align dst to best reachable alignment
+ * 2. Matrix copy for bulk data copy
+ * 3. Single linear copy for remaining bytes
+ *
+ * The phase logic controls transfer chunking; emit_copy() selects
+ * MEM_COPY_CMD or XY_FAST_COPY_BLT based on hardware support.
+ */
+ u64 dst_addr = write ? vram_addr :
+ (unsigned long)buf & ~PAGE_MASK;
+ u32 max_linear = xe->info.has_mem_copy_instr ? U16_MAX :
+ round_down(S16_MAX, XE_CACHELINE_BYTES);
+ u32 best_align = xe_migrate_best_alignment(dst_addr, max_linear);
+ u32 bytes_to_align = best_align ?
+ xe_migrate_bytes_to_align(dst_addr, best_align) : 0;
+
+ if (bytes_to_align > 0 && bytes_to_align <= (u32)current_bytes) {
+ /*
+ * Phase 1: Linear copy to reach best alignment.
+ * Copy just enough bytes to align dst_addr.
+ */
+ current_bytes = min_t(int, bytes_to_align, max_linear);
+ } else if (IS_ALIGNED(dst_addr, 4)) {
+ /*
+ * Phase 2: Matrix copy for aligned bulk data.
+ * Use the best pitch that dst alignment supports,
+ * then round down len to that pitch.
+ */
+ u32 dst_pitch = xe_migrate_dst_pitch(dst_addr);
+ u32 aligned_len = xe_migrate_aligned_copy_len(current_bytes,
+ dst_pitch);
+
+ if (aligned_len >= dst_pitch) {
+ u32 max_bytes = xe->info.has_mem_copy_instr ?
+ U16_MAX * dst_pitch :
+ round_down(S16_MAX * dst_pitch,
+ XE_CACHELINE_BYTES);
+
+ current_bytes = min_t(int, aligned_len, max_bytes);
+ } else {
+ /*
+ * Phase 3: Linear copy for remainder.
+ * Not enough for matrix copy - do single linear copy.
+ */
+ current_bytes = min_t(int, current_bytes, max_linear);
+ }
+ } else {
+ /*
+ * Phase 3: Linear copy for remainder.
+ * dst not 4-aligned and can't reach alignment - linear copy.
+ */
+ current_bytes = min_t(int, current_bytes, max_linear);
+ }
+ }
__fence = xe_migrate_vram(m, current_bytes,
(unsigned long)buf & ~PAGE_MASK,
@@ -2563,7 +2696,7 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo,
buf += current_bytes;
offset += current_bytes;
- current_page = (int)(buf - orig_buf) / PAGE_SIZE;
+ current_page = (int)(buf - orig_buf + page_offset) / PAGE_SIZE;
bytes_left -= current_bytes;
if (bytes_left)
xe_res_next(&cursor, current_bytes);
diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
index c9320feeafba..838802482ada 100644
--- a/drivers/gpu/drm/xe/xe_oa.c
+++ b/drivers/gpu/drm/xe/xe_oa.c
@@ -1751,6 +1751,19 @@ static const struct file_operations xe_oa_fops = {
.mmap = xe_oa_mmap,
};
+static bool oag_has_tail_address_wrap(struct xe_oa_stream *stream)
+{
+ return GRAPHICS_VER(stream->oa->xe) >= 20 &&
+ stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAG;
+}
+
+static bool oam_has_tail_address_wrap(struct xe_oa_stream *stream)
+{
+ return MEDIA_VER(stream->oa->xe) >= 30 &&
+ (stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAM ||
+ stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAM_SAG);
+}
+
static int xe_oa_stream_init(struct xe_oa_stream *stream,
struct xe_oa_open_param *param)
{
@@ -1775,12 +1788,13 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream,
stream->syncs = param->syncs;
/*
- * For Xe2+, when overrun mode is enabled, there are no partial reports at the end
- * of buffer, making the OA buffer effectively a non-power-of-2 size circular
- * buffer whose size, circ_size, is a multiple of the report size
+ * For Xe2+ OAG and Xe3+ OAM, when overrun mode is enabled, there are no
+ * partial reports at the end of buffer, making the OA buffer effectively a
+ * non-power-of-2 size circular buffer whose size, circ_size, is
+ * a multiple of the report size.
*/
- if (GRAPHICS_VER(stream->oa->xe) >= 20 &&
- stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAG && stream->sample)
+ if (stream->sample &&
+ (oag_has_tail_address_wrap(stream) || oam_has_tail_address_wrap(stream)))
stream->oa_buffer.circ_size =
param->oa_buffer_size -
param->oa_buffer_size % stream->oa_buffer.format->size;
diff --git a/drivers/gpu/drm/xe/xe_pat.c b/drivers/gpu/drm/xe/xe_pat.c
index 3dfcd364ac67..5938fef22579 100644
--- a/drivers/gpu/drm/xe/xe_pat.c
+++ b/drivers/gpu/drm/xe/xe_pat.c
@@ -94,29 +94,29 @@ struct xe_pat_ops {
};
static const struct xe_pat_table_entry xelp_pat_table[] = {
- [0] = { XELP_PAT_WB, XE_COH_1WAY },
- [1] = { XELP_PAT_WC, XE_COH_NONE },
- [2] = { XELP_PAT_WT, XE_COH_NONE },
- [3] = { XELP_PAT_UC, XE_COH_NONE },
+ [0] = { XELP_PAT_WB, XE_COH_1WAY, 1 },
+ [1] = { XELP_PAT_WC, XE_COH_NONE, 1 },
+ [2] = { XELP_PAT_WT, XE_COH_NONE, 1 },
+ [3] = { XELP_PAT_UC, XE_COH_NONE, 1 },
};
static const struct xe_pat_table_entry xehpc_pat_table[] = {
- [0] = { XELP_PAT_UC, XE_COH_NONE },
- [1] = { XELP_PAT_WC, XE_COH_NONE },
- [2] = { XELP_PAT_WT, XE_COH_NONE },
- [3] = { XELP_PAT_WB, XE_COH_1WAY },
- [4] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WT, XE_COH_NONE },
- [5] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WB, XE_COH_1WAY },
- [6] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WT, XE_COH_NONE },
- [7] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WB, XE_COH_1WAY },
+ [0] = { XELP_PAT_UC, XE_COH_NONE, 1 },
+ [1] = { XELP_PAT_WC, XE_COH_NONE, 1 },
+ [2] = { XELP_PAT_WT, XE_COH_NONE, 1 },
+ [3] = { XELP_PAT_WB, XE_COH_1WAY, 1 },
+ [4] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WT, XE_COH_NONE, 1 },
+ [5] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WB, XE_COH_1WAY, 1 },
+ [6] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WT, XE_COH_NONE, 1 },
+ [7] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WB, XE_COH_1WAY, 1 },
};
static const struct xe_pat_table_entry xelpg_pat_table[] = {
- [0] = { XELPG_PAT_0_WB, XE_COH_NONE },
- [1] = { XELPG_PAT_1_WT, XE_COH_NONE },
- [2] = { XELPG_PAT_3_UC, XE_COH_NONE },
- [3] = { XELPG_PAT_0_WB | XELPG_2_COH_1W, XE_COH_1WAY },
- [4] = { XELPG_PAT_0_WB | XELPG_3_COH_2W, XE_COH_2WAY },
+ [0] = { XELPG_PAT_0_WB, XE_COH_NONE, 1 },
+ [1] = { XELPG_PAT_1_WT, XE_COH_NONE, 1 },
+ [2] = { XELPG_PAT_3_UC, XE_COH_NONE, 1 },
+ [3] = { XELPG_PAT_0_WB | XELPG_2_COH_1W, XE_COH_1WAY, 1 },
+ [4] = { XELPG_PAT_0_WB | XELPG_3_COH_2W, XE_COH_2WAY, 1 },
};
/*
@@ -295,25 +295,69 @@ static const struct xe_pat_table_entry xe3p_lpg_pat_table[] = {
[31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ),
};
+bool xe_pat_index_is_valid(struct xe_device *xe, u16 pat_index)
+{
+ if (WARN_ON(pat_index >= xe->pat.n_entries))
+ return false;
+
+ return xe->pat.table[pat_index].valid;
+}
+
u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index)
{
- WARN_ON(pat_index >= xe->pat.n_entries);
+ WARN_ON(!xe_pat_index_is_valid(xe, pat_index));
+ WARN_ON(!xe->pat.table[pat_index].coh_mode ||
+ xe->pat.table[pat_index].coh_mode > XE_COH_2WAY);
return xe->pat.table[pat_index].coh_mode;
}
bool xe_pat_index_get_comp_en(struct xe_device *xe, u16 pat_index)
{
- WARN_ON(pat_index >= xe->pat.n_entries);
+ WARN_ON(!xe_pat_index_is_valid(xe, pat_index));
return !!(xe->pat.table[pat_index].value & XE2_COMP_EN);
}
u16 xe_pat_index_get_l3_policy(struct xe_device *xe, u16 pat_index)
{
- WARN_ON(pat_index >= xe->pat.n_entries);
+ WARN_ON(!xe_pat_index_is_valid(xe, pat_index));
return REG_FIELD_GET(XE2_L3_POLICY, xe->pat.table[pat_index].value);
}
+bool xe_pat_wa_14026539277_reserved(struct xe_device *xe, u16 pat_index)
+{
+ struct xe_gt *gt;
+ u8 id;
+ bool has_wa = false;
+
+ for_each_gt(gt, xe, id) {
+ if (XE_GT_WA(gt, 14026539277)) {
+ has_wa = true;
+ break;
+ }
+ }
+
+ /*
+ * Disallow 2-way coherency for any L3 cache policy because
+ * XE_L3_POLICY_UC could still be promoted to a cached policy
+ * by MOCS indices.
+ */
+ return has_wa && xe_pat_index_get_coh_mode(xe, pat_index) == XE_COH_2WAY;
+}
+
+static u32 wa_14026539277_fixup_pat_value(struct xe_gt *gt, u32 value)
+{
+ if (XE_GT_WA(gt, 14026539277)) {
+ if (REG_FIELD_GET(XE2_COH_MODE, value) == XE_COH_2WAY) {
+ value &= ~(XE2_L3_POLICY | XE2_COH_MODE);
+ value |= REG_FIELD_PREP(XE2_L3_POLICY, XE_L3_POLICY_UC) |
+ REG_FIELD_PREP(XE2_COH_MODE, XE_COH_1WAY);
+ }
+ }
+
+ return value;
+}
+
static const struct xe_pat_table_entry *gt_pta_entry(struct xe_gt *gt)
{
struct xe_device *xe = gt_to_xe(gt);
@@ -374,18 +418,22 @@ static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry ta
for (int i = 0; i < n_entries; i++) {
struct xe_reg_mcr reg_mcr = XE_REG_MCR(_PAT_INDEX(i));
+ u32 pat = wa_14026539277_fixup_pat_value(gt, table[i].value);
- xe_gt_mcr_multicast_write(gt, reg_mcr, table[i].value);
+ xe_gt_mcr_multicast_write(gt, reg_mcr, pat);
}
if (xe->pat.pat_ats)
- xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), xe->pat.pat_ats->value);
+ xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS),
+ wa_14026539277_fixup_pat_value(gt, xe->pat.pat_ats->value));
if (pta_entry)
- xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_PTA), pta_entry->value);
+ xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_PTA),
+ wa_14026539277_fixup_pat_value(gt, pta_entry->value));
if (tr_pta_entry)
- xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_TR_PTA), tr_pta_entry->value);
+ xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_TR_PTA),
+ wa_14026539277_fixup_pat_value(gt, tr_pta_entry->value));
}
static int xelp_dump(struct xe_gt *gt, struct drm_printer *p)
@@ -535,13 +583,16 @@ static int xe2_dump(struct xe_gt *gt, struct drm_printer *p)
drm_printf(p, "PAT table: (* = reserved entry)\n");
for (i = 0; i < xe->pat.n_entries; i++) {
+ bool rsvd = !xe->pat.table[i].valid ||
+ xe_pat_wa_14026539277_reserved(xe, i);
+
if (xe_gt_is_media_type(gt))
pat = xe_mmio_read32(&gt->mmio, XE_REG(_PAT_INDEX(i)));
else
pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i)));
xe_pat_index_label(label, sizeof(label), i);
- xe->pat.ops->entry_dump(p, label, pat, !xe->pat.table[i].valid);
+ xe->pat.ops->entry_dump(p, label, pat, rsvd);
}
/*
@@ -758,9 +809,14 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p)
for (u32 i = 0; i < xe->pat.n_entries; i++) {
u32 pat = xe->pat.table[i].value;
+ pat = wa_14026539277_fixup_pat_value(gt, pat);
+
if (GRAPHICS_VER(xe) >= 20) {
+ bool rsvd = !xe->pat.table[i].valid ||
+ xe_pat_wa_14026539277_reserved(xe, i);
+
xe_pat_index_label(label, sizeof(label), i);
- xe->pat.ops->entry_dump(p, label, pat, !xe->pat.table[i].valid);
+ xe->pat.ops->entry_dump(p, label, pat, rsvd);
} else if (xe->info.platform == XE_METEORLAKE) {
xelpg_pat_entry_dump(p, i, pat);
} else if (xe->info.platform == XE_PVC) {
@@ -775,6 +831,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p)
if (pta_entry) {
u32 pat = pta_entry->value;
+ pat = wa_14026539277_fixup_pat_value(gt, pat);
+
drm_printf(p, "Page Table Access:\n");
xe->pat.ops->entry_dump(p, "PTA_MODE", pat, false);
}
@@ -782,6 +840,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p)
if (tr_pta_entry) {
u32 pat = tr_pta_entry->value;
+ pat = wa_14026539277_fixup_pat_value(gt, pat);
+
drm_printf(p, "TRTT Page Table Access:\n");
xe->pat.ops->entry_dump(p, "TR_PTA_MODE", pat, false);
}
@@ -789,6 +849,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p)
if (xe->pat.pat_ats) {
u32 pat = xe->pat.pat_ats->value;
+ pat = wa_14026539277_fixup_pat_value(gt, pat);
+
drm_printf(p, "PCIe ATS/PASID:\n");
xe->pat.ops->entry_dump(p, "PAT_ATS ", pat, false);
}
diff --git a/drivers/gpu/drm/xe/xe_pat.h b/drivers/gpu/drm/xe/xe_pat.h
index 6398c3ab4805..2ac6ddc66587 100644
--- a/drivers/gpu/drm/xe/xe_pat.h
+++ b/drivers/gpu/drm/xe/xe_pat.h
@@ -57,8 +57,18 @@ int xe_pat_dump(struct xe_gt *gt, struct drm_printer *p);
int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p);
/**
+ * xe_pat_index_is_valid - Check whether the given pat_index is valid. Index
+ * must be within valid range.
+ * @xe: xe device
+ * @pat_index: The pat_index to query
+ *
+ * Return: true if the pat_index entry is valid, false if reserved.
+ */
+bool xe_pat_index_is_valid(struct xe_device *xe, u16 pat_index);
+
+/**
* xe_pat_index_get_coh_mode - Extract the coherency mode for the given
- * pat_index.
+ * pat_index. Index must be valid for the hw.
* @xe: xe device
* @pat_index: The pat_index to query
*/
@@ -66,7 +76,7 @@ u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index);
/**
* xe_pat_index_get_comp_en - Extract the compression enable flag for
- * the given pat_index.
+ * the given pat_index. Index must be valid for the hw.
* @xe: xe device
* @pat_index: The pat_index to query
*
@@ -79,11 +89,22 @@ bool xe_pat_index_get_comp_en(struct xe_device *xe, u16 pat_index);
#define XE_L3_POLICY_UC 3 /* Uncached */
/**
* xe_pat_index_get_l3_policy - Extract the L3 policy for the given pat_index.
+ * Index must be valid for the hw.
* @xe: xe device
* @pat_index: The pat_index to query
*/
u16 xe_pat_index_get_l3_policy(struct xe_device *xe, u16 pat_index);
+/**
+ * xe_pat_wa_14026539277_reserved - Is this PAT index reserved from
+ * use due to Wa_14026539277?
+ * @xe: xe device
+ * @pat_index: The pat_index to query
+ *
+ * Return: a boolean indicating whether the PAT index is reserved or not.
+ */
+bool xe_pat_wa_14026539277_reserved(struct xe_device *xe, u16 pat_index);
+
#define xe_cache_pat_idx(xe, cache_mode) ({ \
const struct xe_device *__xedev = (xe); \
enum xe_cache_level __mode = (cache_mode); \
diff --git a/drivers/gpu/drm/xe/xe_pci_error.c b/drivers/gpu/drm/xe/xe_pci_error.c
index 79ce0c671549..9bf0da3a3d15 100644
--- a/drivers/gpu/drm/xe/xe_pci_error.c
+++ b/drivers/gpu/drm/xe/xe_pci_error.c
@@ -13,6 +13,7 @@
#include "xe_printk.h"
#include "xe_ras.h"
#include "xe_survivability_mode.h"
+#include "xe_wedge.h"
static void prepare_device_for_reset(struct pci_dev *pdev)
{
@@ -22,7 +23,7 @@ static void prepare_device_for_reset(struct pci_dev *pdev)
/*
* Wedge the device to prevent userspace access but do not send the uevent.
- * xe_device_wedged_fini() releases runtime pm if wedged flag is set, so acquire a runtime
+ * xe_wedge_fini() releases runtime pm if wedged flag is set, so acquire a runtime
* pm reference to avoid underflow.
*/
if (!atomic_xchg(&xe->wedged.flag, 1))
@@ -30,8 +31,10 @@ static void prepare_device_for_reset(struct pci_dev *pdev)
xe_device_set_in_reset(xe);
- for_each_gt(gt, xe, id)
- xe_gt_declare_wedged(gt);
+ for_each_gt(gt, xe, id) {
+ xe_gt_wedge_declare(gt);
+ flush_work(&gt->wedge.worker);
+ }
pci_disable_device(pdev);
}
@@ -61,7 +64,7 @@ static pci_ers_result_t xe_pci_error_detected(struct pci_dev *pdev, pci_channel_
return PCI_ERS_RESULT_DISCONNECT;
/* If the device is already wedged or in survivability mode, do not attempt recovery */
- if (xe_survivability_mode_is_boot_enabled(xe) || xe_device_wedged(xe))
+ if (xe_survivability_mode_is_boot_enabled(xe) || xe_wedged(xe))
return PCI_ERS_RESULT_DISCONNECT;
switch (state) {
@@ -86,7 +89,7 @@ static pci_ers_result_t xe_pci_error_mmio_enabled(struct pci_dev *pdev)
/* User wants to debug the error, prevent reset */
if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
- xe_device_declare_wedged(xe);
+ xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_NONE);
return PCI_ERS_RESULT_DISCONNECT;
}
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index 8a95d58d9c6f..c8ce37efd042 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -1625,7 +1625,6 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op)
err = vma_check_userptr(vm, gpuva_to_vma(op->base.prefetch.va));
}
break;
-#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
case DRM_GPUVA_OP_DRIVER:
if (op->subop == XE_VMA_SUBOP_MAP_RANGE) {
struct xe_svm_range *range = op->map_range.range;
@@ -1640,7 +1639,6 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op)
}
}
break;
-#endif
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE");
}
diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c
index 9c15ce8f0b6a..db3cbc186a51 100644
--- a/drivers/gpu/drm/xe/xe_ras.c
+++ b/drivers/gpu/drm/xe/xe_ras.c
@@ -19,6 +19,7 @@
#include "xe_sysctrl_mailbox.h"
#include "xe_sysctrl_mailbox_types.h"
#include "xe_ttm_vram_mgr.h"
+#include "xe_wedge.h"
/* Any non-null entry marks the page as offlined by firmware */
#define XE_RAS_PAGE_OFFLINED xa_mk_value(1)
@@ -563,8 +564,7 @@ static u8 handle_core_compute_errors(struct xe_ras_error_array *arr)
static void punit_error_handler(struct xe_device *xe)
{
- xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_COLD_RESET);
- xe_device_declare_wedged(xe);
+ xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_COLD_RESET);
}
static u8 handle_soc_internal_errors(struct xe_device *xe, struct xe_ras_error_array *arr)
@@ -1212,6 +1212,13 @@ int xe_ras_init(struct xe_device *xe)
get_offline_list(xe);
get_offline_queue(xe);
+ /*
+ * During probe, process and log any errors detected by firmware while the driver was not
+ * loaded. Critical errors such as Punit and CSC are reported through Pcode init failure,
+ * causing the driver to enter survivability mode.
+ */
+ xe_ras_process_errors(xe);
+
ret = devm_device_add_group(xe->drm.dev, &gpu_health_group);
if (ret)
xe_err(xe, "Failed to create GPU health sysfs, err=%d\n", ret);
diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c
index 772dab9b3ed7..c86455ea08d1 100644
--- a/drivers/gpu/drm/xe/xe_shrinker.c
+++ b/drivers/gpu/drm/xe/xe_shrinker.c
@@ -133,6 +133,9 @@ static int __xe_shrinker_walk(struct xe_shrinker *shrinker,
}
ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) {
+ if (flags.purge && ttm_bo->priority > XE_BO_PRIORITY_LOW)
+ break;
+
if (!ttm_bo_shrink_suitable(ttm_bo, ctx))
continue;
diff --git a/drivers/gpu/drm/xe/xe_sriov_pf.c b/drivers/gpu/drm/xe/xe_sriov_pf.c
index 33bd754d138f..ce0db26203ec 100644
--- a/drivers/gpu/drm/xe/xe_sriov_pf.c
+++ b/drivers/gpu/drm/xe/xe_sriov_pf.c
@@ -19,6 +19,7 @@
#include "xe_sriov_pf_service.h"
#include "xe_sriov_pf_sysfs.h"
#include "xe_sriov_printk.h"
+#include "xe_wedge.h"
static unsigned int wanted_max_vfs(struct xe_device *xe)
{
@@ -157,7 +158,7 @@ int xe_sriov_pf_wait_ready(struct xe_device *xe)
unsigned int id;
int err;
- if (xe_device_wedged(xe))
+ if (xe_wedged(xe))
return -ECANCELED;
for_each_gt(gt, xe, id) {
diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c
index 45d44ebe288b..d73cdad0b3a9 100644
--- a/drivers/gpu/drm/xe/xe_survivability_mode.c
+++ b/drivers/gpu/drm/xe/xe_survivability_mode.c
@@ -20,6 +20,7 @@
#include "xe_pcode_api.h"
#include "xe_printk.h"
#include "xe_vsec.h"
+#include "xe_wedge.h"
/**
* DOC: Survivability Mode
@@ -446,8 +447,7 @@ void xe_survivability_mode_runtime_enable(struct xe_device *xe)
survivability->type = XE_SURVIVABILITY_TYPE_RUNTIME;
xe_log_err(xe, SURVIVABILITY, 0, "Runtime Mode enabled!\n");
- xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_VENDOR);
- xe_device_declare_wedged(xe);
+ xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_VENDOR);
xe_log_err(xe, SURVIVABILITY, 0, "Firmware flash required!\n");
xe_info(xe, "Please refer to the userspace documentation for more details how to flash the firmware on %s!\n",
diff --git a/drivers/gpu/drm/xe/xe_tuning.c b/drivers/gpu/drm/xe/xe_tuning.c
index 024dd2e71b17..1c230993648f 100644
--- a/drivers/gpu/drm/xe/xe_tuning.c
+++ b/drivers/gpu/drm/xe/xe_tuning.c
@@ -51,7 +51,7 @@ VISIBLE_IF_KUNIT const struct xe_rtp_table_sr gt_tunings = XE_RTP_TABLE_SR(
SET(CCCHKNREG1, L3CMPCTRL))
},
{ XE_RTP_NAME("Tuning: Compression Overfetch - media"),
- XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED)),
+ XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, 3499)),
XE_RTP_ACTIONS(CLR(XE2LPM_CCCHKNREG1, ENCOMPPERFFIX),
SET(XE2LPM_CCCHKNREG1, L3CMPCTRL))
},
diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c
index 65f59f06177f..686c28856014 100644
--- a/drivers/gpu/drm/xe/xe_uc.c
+++ b/drivers/gpu/drm/xe/xe_uc.c
@@ -326,15 +326,15 @@ void xe_uc_runtime_resume(struct xe_uc *uc)
}
/**
- * xe_uc_declare_wedged() - Declare UC wedged
+ * xe_uc_wedge_declare() - Declare UC wedged
* @uc: the UC object
*
* Wedge the UC which stops all submission, saves desired debug state, and
* cleans up anything which could timeout.
*/
-void xe_uc_declare_wedged(struct xe_uc *uc)
+void xe_uc_wedge_declare(struct xe_uc *uc)
{
xe_gt_assert(uc_to_gt(uc), uc_to_xe(uc)->wedged.mode);
- xe_guc_declare_wedged(&uc->guc);
+ xe_guc_wedge_declare(&uc->guc);
}
diff --git a/drivers/gpu/drm/xe/xe_uc.h b/drivers/gpu/drm/xe/xe_uc.h
index 255a54a8f876..23bc0ce1c42f 100644
--- a/drivers/gpu/drm/xe/xe_uc.h
+++ b/drivers/gpu/drm/xe/xe_uc.h
@@ -21,6 +21,6 @@ int xe_uc_start(struct xe_uc *uc);
void xe_uc_suspend_prepare(struct xe_uc *uc);
int xe_uc_suspend(struct xe_uc *uc);
int xe_uc_sanitize_reset(struct xe_uc *uc);
-void xe_uc_declare_wedged(struct xe_uc *uc);
+void xe_uc_wedge_declare(struct xe_uc *uc);
#endif
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 3780d89a9342..dfbabfb19cbb 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -273,8 +273,15 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
* Check to see if a preemption on VM is in flight or userptr
* invalidation, if so trigger this preempt fence to sync state with
* other preempt fences on the VM.
+ *
+ * Also trigger it if eviction or rebinding is pending. BOs evicted
+ * before the first exec queue was added had no preempt fence to
+ * trigger. Suspend this queue until the rebind worker restores
+ * the mappings.
*/
- wait = __xe_vm_userptr_needs_repin(vm) || preempt_fences_waiting(vm);
+ wait = __xe_vm_userptr_needs_repin(vm) || preempt_fences_waiting(vm) ||
+ !list_empty(&vm->gpuvm.evict.list) ||
+ !list_empty(&vm->rebind_list);
if (wait)
dma_fence_enable_signaling(pfence);
@@ -3812,14 +3819,15 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm,
pat_index = array_index_nospec(pat_index, xe->pat.n_entries);
(*bind_ops)[i].pat_index = pat_index;
- coh_mode = xe_pat_index_get_coh_mode(xe, pat_index);
- comp_en = xe_pat_index_get_comp_en(xe, pat_index);
- if (XE_IOCTL_DBG(xe, !coh_mode)) { /* hw reserved */
+ if (XE_IOCTL_DBG(xe, !xe_pat_index_is_valid(xe, pat_index))) {
err = -EINVAL;
goto free_bind_ops;
}
- if (XE_WARN_ON(coh_mode > XE_COH_2WAY)) {
+ coh_mode = xe_pat_index_get_coh_mode(xe, pat_index);
+ comp_en = xe_pat_index_get_comp_en(xe, pat_index);
+
+ if (XE_IOCTL_DBG(xe, xe_pat_wa_14026539277_reserved(xe, pat_index))) {
err = -EINVAL;
goto free_bind_ops;
}
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c
index 5c7aefc641ee..31245c6c96d4 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.c
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.c
@@ -393,17 +393,13 @@ static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madv
break;
case DRM_XE_MEM_RANGE_ATTR_PAT:
{
- u16 pat_index, coh_mode;
+ u16 pat_index;
if (XE_IOCTL_DBG(xe, args->pat_index.val >= xe->pat.n_entries))
return false;
pat_index = array_index_nospec(args->pat_index.val, xe->pat.n_entries);
- coh_mode = xe_pat_index_get_coh_mode(xe, pat_index);
- if (XE_IOCTL_DBG(xe, !coh_mode))
- return false;
-
- if (XE_WARN_ON(coh_mode > XE_COH_2WAY))
+ if (XE_IOCTL_DBG(xe, !xe_pat_index_is_valid(xe, pat_index)))
return false;
if (XE_IOCTL_DBG(xe, args->pat_index.pad))
@@ -411,6 +407,10 @@ static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madv
if (XE_IOCTL_DBG(xe, args->pat_index.reserved))
return false;
+
+ if (XE_IOCTL_DBG(xe, xe_pat_wa_14026539277_reserved(xe, pat_index)))
+ return false;
+
break;
}
case DRM_XE_VMA_ATTR_PURGEABLE_STATE:
@@ -659,11 +659,8 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
err = -EINVAL;
goto free_vmas;
}
- }
- if (args->type == DRM_XE_MEM_RANGE_ATTR_PAT) {
- if (!check_pat_args_are_sane(xe, &madvise_range,
- args->pat_index.val)) {
+ if (!check_pat_args_are_sane(xe, &madvise_range, pat_index)) {
err = -EINVAL;
goto free_vmas;
}
diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules
index f35181fc4e49..96132c6e3340 100644
--- a/drivers/gpu/drm/xe/xe_wa_oob.rules
+++ b/drivers/gpu/drm/xe/xe_wa_oob.rules
@@ -72,7 +72,8 @@
GRAPHICS_VERSION(3511)
16029897822 MEDIA_VERSION(3500)
GRAPHICS_VERSION(3510)
+14026539277 GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0)
14027054324 GRAPHICS_VERSION(3511)
14025941587 GRAPHICS_VERSION_RANGE(2001, 3511), FUNC(xe_rtp_match_not_sriov_vf)
MEDIA_VERSION_RANGE(1301, 3503), FUNC(xe_rtp_match_not_sriov_vf)
-16030224309 GRAPHICS_VERSION(3510)
+16030224309 GRAPHICS_VERSION_RANGE(3510, 3511)
diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
new file mode 100644
index 000000000000..2f35937c5e66
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_wedge.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <drm/drm_drv.h>
+#include <drm/drm_managed.h>
+
+#include "xe_defaults.h"
+#include "xe_device.h"
+#include "xe_gt.h"
+#include "xe_gt_printk.h"
+#include "xe_guc_ads.h"
+#include "xe_log.h"
+#include "xe_module.h"
+#include "xe_pm.h"
+#include "xe_printk.h"
+#include "xe_sriov.h"
+#include "xe_wedge.h"
+
+/**
+ * DOC: Xe Device Wedging
+ *
+ * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
+ * When device is in wedged state, every IOCTL will be blocked and GT cannot
+ * be used. The conditions under which the driver declares the device wedged
+ * depend on the wedge mode configuration (see &enum xe_wedged_mode). The
+ * default recovery method for a wedged state is rebind/bus-reset.
+ *
+ * Another recovery method is vendor-specific. Below are the cases that send
+ * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
+ *
+ * Case: Firmware Flash
+ * --------------------
+ *
+ * Identification Hint
+ * +++++++++++++++++++
+ *
+ * ``WEDGED=vendor-specific`` drm device wedged uevent with
+ * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
+ * admin/userspace consumer about the need for a firmware flash.
+ *
+ * Recovery Procedure
+ * ++++++++++++++++++
+ *
+ * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
+ * the below steps
+ *
+ * - Check Runtime Survivability mode sysfs.
+ * If enabled, firmware flash is required to recover the device.
+ *
+ * /sys/bus/pci/devices/<device>/survivability_mode
+ *
+ * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
+ * firmware and restore device to normal operation.
+ */
+
+static void wedge_work(struct work_struct *work)
+{
+ struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
+
+ /* Notify userspace of wedged device */
+ drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
+}
+
+#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
+#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
+
+/**
+ * xe_wedge_declare() - Declare device wedged
+ * @xe: xe device instance
+ * @method: method(s) to be used for recovery
+ *
+ * This is the final state that can only be cleared with the recovery method
+ * specified in the drm wedged uevent.
+ *
+ * In this state every IOCTL will be blocked so the GT cannot be used.
+ * In general it will be called upon any critical error such as gt reset
+ * failure or guc loading failure. Userspace will be notified of this state
+ * through device wedged uevent.
+ *
+ * If xe.wedged module parameter is set to 2, this function will be called
+ * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
+ * snapshot capture. In this mode, GT reset won't be attempted so the state of
+ * the issue is preserved for further debugging.
+ *
+ * Since the wedge handling is done as part of worker thread, this is safe for
+ * atomic callers.
+ */
+void xe_wedge_declare(struct xe_device *xe, unsigned long method)
+{
+ struct xe_gt *gt;
+ u8 id;
+
+ if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
+ xe_dbg(xe, "Wedged mode is forcibly disabled\n");
+ return;
+ }
+
+ if (atomic_xchg(&xe->wedged.flag, 1))
+ return;
+
+ xe->needs_flr_on_fini = true;
+ xe_pm_runtime_get_noresume(xe);
+
+ xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
+ xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
+ "For recovery procedure, refer to %s\n"
+ "Please file a _new_ bug report at %s\n",
+ WEDGED_URL, XE_BUG_URL);
+
+ for_each_initialized_gt(gt, xe, id)
+ xe_gt_wedge_declare(gt);
+
+ /*
+ * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
+ * hangs, so wedge the device with 'none' recovery method and have
+ * it available to the user for debugging.
+ */
+ if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
+ xe->wedged.method = DRM_WEDGE_RECOVERY_NONE;
+ else
+ xe->wedged.method = method;
+
+ schedule_work(&xe->wedged.work);
+}
+
+static const char *wedge_mode_to_string(enum xe_wedged_mode mode)
+{
+ switch (mode) {
+ case XE_WEDGED_MODE_NEVER:
+ return "never";
+ case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
+ return "upon-critical-error";
+ case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
+ return "upon-any-hang-no-reset";
+ default:
+ return "<invalid>";
+ }
+}
+
+static int wedge_validate_mode(struct xe_device *xe, unsigned int mode)
+{
+ if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
+ xe_dbg(xe, "wedged_mode: invalid value (%u)\n", mode);
+ return -EINVAL;
+ } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
+ (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
+ xe_dbg(xe, "wedged_mode: (%u) %s mode is not supported for %s\n",
+ mode, wedge_mode_to_string(mode),
+ xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static bool wedge_mode_needs_policy_update(struct xe_device *xe, enum xe_wedged_mode mode)
+{
+ if (xe->wedged.inconsistent_reset)
+ return true;
+
+ if (xe->wedged.mode == mode)
+ return false;
+
+ if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET ||
+ mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
+ return true;
+
+ return false;
+}
+
+static int __wedge_mode_set_reset_policy(struct xe_gt *gt, enum xe_wedged_mode mode)
+{
+ bool enable_engine_reset;
+ int ret;
+
+ enable_engine_reset = (mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET);
+ ret = xe_guc_ads_scheduler_policy_toggle_reset(&gt->uc.guc.ads,
+ enable_engine_reset);
+ if (ret)
+ xe_gt_err(gt, "Failed to update GuC ADS scheduler policy (%pe)\n", ERR_PTR(ret));
+
+ return ret;
+}
+
+static int wedge_mode_set_reset_policy(struct xe_device *xe, enum xe_wedged_mode mode)
+{
+ struct xe_gt *gt;
+ int ret;
+ u8 id;
+
+ guard(xe_pm_runtime)(xe);
+ for_each_gt(gt, xe, id) {
+ ret = __wedge_mode_set_reset_policy(gt, mode);
+ if (ret) {
+ if (id > 0) {
+ xe->wedged.inconsistent_reset = true;
+ xe_err(xe, "Inconsistent reset policy state between GTs\n");
+ }
+ return ret;
+ }
+ }
+
+ xe->wedged.inconsistent_reset = false;
+
+ return 0;
+}
+
+/**
+ * xe_wedge_set_mode() - Set wedge mode
+ * @xe: xe device instance
+ * @mode: wedge mode to be set
+ *
+ * Returns: 0 on success, negative error code otherwise.
+ */
+int xe_wedge_set_mode(struct xe_device *xe, enum xe_wedged_mode mode)
+{
+ int ret;
+
+ ret = wedge_validate_mode(xe, mode);
+ if (ret)
+ return ret;
+
+ if (wedge_mode_needs_policy_update(xe, mode)) {
+ ret = wedge_mode_set_reset_policy(xe, mode);
+ if (ret)
+ return ret;
+ }
+
+ xe->wedged.mode = mode;
+
+ return ret;
+}
+
+static void xe_wedge_fini(struct drm_device *drm, void *arg)
+{
+ struct xe_device *xe = arg;
+
+ disable_work_sync(&xe->wedged.work);
+
+ if (atomic_read(&xe->wedged.flag))
+ xe_pm_runtime_put(xe);
+}
+
+/**
+ * xe_wedge_init() - Initialize wedge
+ * @xe: xe device instance
+ *
+ * Returns: 0 on success, negative error code otherwise.
+ */
+int xe_wedge_init(struct xe_device *xe)
+{
+ INIT_WORK(&xe->wedged.work, wedge_work);
+
+ xe->wedged.mode = wedge_validate_mode(xe, xe_modparam.wedged_mode) ?
+ XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
+ xe_dbg(xe, "wedged_mode: setting mode (%u) %s\n",
+ xe->wedged.mode, wedge_mode_to_string(xe->wedged.mode));
+
+ return drmm_add_action_or_reset(&xe->drm, xe_wedge_fini, xe);
+}
diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
new file mode 100644
index 000000000000..3b5499dfc30d
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_wedge.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_WEDGE_H_
+#define _XE_WEDGE_H_
+
+#include <linux/atomic.h>
+#include <linux/types.h>
+
+#include "xe_device_types.h"
+#include "xe_wedge_types.h"
+
+static inline bool xe_wedged(struct xe_device *xe)
+{
+ return atomic_read(&xe->wedged.flag);
+}
+
+void xe_wedge_declare(struct xe_device *xe, unsigned long method);
+int xe_wedge_init(struct xe_device *xe);
+int xe_wedge_set_mode(struct xe_device *xe, enum xe_wedged_mode mode);
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
new file mode 100644
index 000000000000..e472c5fcbd26
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_wedge_types.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_WEDGE_TYPES_H_
+#define _XE_WEDGE_TYPES_H_
+
+#include <linux/types.h>
+#include <linux/workqueue_types.h>
+
+/**
+ * enum xe_wedged_mode - Possible wedge modes
+ * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
+ * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
+ * when critical error occurs like GT reset failure or firmware failure.
+ * This is the default mode.
+ * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
+ * any hang. In this mode, engine resets are disabled to avoid automatic
+ * recovery attempts. This mode is primarily intended for debugging hangs.
+ */
+enum xe_wedged_mode {
+ XE_WEDGED_MODE_NEVER = 0,
+ XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
+ XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
+};
+
+/**
+ * struct xe_wedge - Struct to control Wedged States and mode
+ */
+struct xe_wedge {
+ /** @flag: Xe device faced a critical error and is now blocked. */
+ atomic_t flag;
+ /** @mode: Mode controlled by kernel parameter and debugfs */
+ enum xe_wedged_mode mode;
+ /** @method: Recovery method to be sent in the drm device wedged uevent */
+ unsigned long method;
+ /** @inconsistent_reset: Inconsistent reset policy state between GTs */
+ bool inconsistent_reset;
+ /** @work: Worker to defer non-atomic calls */
+ struct work_struct work;
+};
+
+#endif