From f5998f4d71b233c88f0661ace2f36a6dcb9d689a Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 4 Aug 2026 13:11:51 +0530 Subject: [PATCH 01/29] drm/amd/pm: Simplify SoC power printing in debugfs Convert SoC power directly from milliwatts using MILLIWATT_PER_WATT and remove redundant variables. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 15b2923d5378..c0e677328af5 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #define MAX_NUM_OF_FEATURES_PER_SUBSET 8 @@ -4876,9 +4877,8 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a { uint32_t mp1_ver = amdgpu_ip_version(adev, MP1_HWIP, 0); uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0); - uint32_t value, mwatt, centiwatt; uint64_t value64 = 0; - uint32_t query = 0; + uint32_t value; int size; /* GPU Clocks */ @@ -4899,25 +4899,22 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a seq_printf(m, "\t%u mV (VDDGFX)\n", value); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&value, &size)) seq_printf(m, "\t%u mV (VDDNB)\n", value); - size = sizeof(uint32_t); - if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) { - mwatt = query; - centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&value, &size)) { if (adev->flags & AMD_IS_APU) - seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", centiwatt / 100, centiwatt % 100); + seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", + (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10); else - seq_printf(m, "\t%u.%02u W (average SoC)\n", centiwatt / 100, centiwatt % 100); + seq_printf(m, "\t%u.%02u W (average SoC)\n", + (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10); } - size = sizeof(uint32_t); - if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) { - mwatt = query; - centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&value, &size)) { if (adev->flags & AMD_IS_APU) - seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", centiwatt / 100, centiwatt % 100); + seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", + (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10); else - seq_printf(m, "\t%u.%02u W (current SoC)\n", centiwatt / 100, centiwatt % 100); + seq_printf(m, "\t%u.%02u W (current SoC)\n", + (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10); } - size = sizeof(value); seq_printf(m, "\n"); /* GPU Temp */ From a01ff85d6f09d83786233c6defe4f5bdfc5ff695 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 4 Aug 2026 14:11:47 +0530 Subject: [PATCH 02/29] drm/amd/pm: Keep sub-watt precision in Q10 socket power The Q10 socket power was rounded to whole watts before scaling to milliwatts, so the reported value lost its sub-watt precision. Add SMUQ10_TO_MILLIWATT to convert while keeping the fractional bits. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 +++ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 3 +-- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 3 +-- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 6 ++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 5e7d80e8b26b..238dcc468557 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -55,6 +55,9 @@ #define SMUQ10_TO_UINT(x) ((x) >> 10) #define SMUQ10_FRAC(x) ((x) & 0x3ff) #define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) +/* Convert Q10 watts to milliwatts, preserving the fractional part */ +#define SMUQ10_TO_MILLIWATT(x) (SMUQ10_TO_UINT(x) * MILLIWATT_PER_WATT + \ + ((SMUQ10_FRAC(x) * MILLIWATT_PER_WATT) >> 10)) #define SMU_V13_SOFT_FREQ_ROUND(x) ((x) + 1) extern const int pmfw_decoded_link_speed[5]; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 8c719fff754a..f0f789c4ff22 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -434,8 +434,7 @@ int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_ROUND(metrics->DramBandwidthUtilization); break; case METRICS_CURR_SOCKETPOWER: - *value = SMUQ10_ROUND(metrics->SocketPower) * - MILLIWATT_PER_WATT; + *value = SMUQ10_TO_MILLIWATT(metrics->SocketPower); break; case METRICS_TEMPERATURE_HOTSPOT: *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) * diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 39f5ed5da58f..fe0443a07b4c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -1303,8 +1303,7 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, version)); break; case METRICS_CURR_SOCKETPOWER: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version)) * - MILLIWATT_PER_WATT; + *value = SMUQ10_TO_MILLIWATT(GET_METRIC_FIELD(SocketPower, version)); break; case METRICS_TEMPERATURE_HOTSPOT: *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)) * diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index 01b91c9e3c28..92897843be24 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -55,6 +55,9 @@ #define SMUQ10_TO_UINT(x) ((x) >> 10) #define SMUQ10_FRAC(x) ((x) & 0x3ff) #define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) +/* Convert Q10 watts to milliwatts, preserving the fractional part */ +#define SMUQ10_TO_MILLIWATT(x) (SMUQ10_TO_UINT(x) * MILLIWATT_PER_WATT + \ + ((SMUQ10_FRAC(x) * MILLIWATT_PER_WATT) >> 10)) #define hbm_stack_mask_valid(umc_mask) \ (((umc_mask) & 0xF) == 0xF) @@ -413,8 +416,7 @@ static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_ROUND(metrics->DramBandwidthUtilization); break; case METRICS_CURR_SOCKETPOWER: - *value = SMUQ10_ROUND(metrics->SocketPower) * - MILLIWATT_PER_WATT; + *value = SMUQ10_TO_MILLIWATT(metrics->SocketPower); break; case METRICS_TEMPERATURE_HOTSPOT: *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) * From 1f33a9688f2018aba8c9b7476f50999c10c6a921 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 4 Aug 2026 14:28:12 +0530 Subject: [PATCH 03/29] drm/amd/pm: Keep sub-degree precision in Q10 temperatures The Q10 temperatures were rounded to whole degrees before being scaled to millidegrees, losing sub-degree precision. Convert them while preserving the fractional part. Also, use the standard MILLIDEGREE_PER_DEGREE to represent SMU_TEMPERATURE_UNITS_PER_CENTIGRADES. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 2 +- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 4 ++++ .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 9 +++------ .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 9 +++------ .../gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 14 ++++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 00d075cb86b8..3ec65630ab99 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -34,7 +34,7 @@ #define SMU_THERMAL_MINIMUM_ALERT_TEMP 0 #define SMU_THERMAL_MAXIMUM_ALERT_TEMP 255 -#define SMU_TEMPERATURE_UNITS_PER_CENTIGRADES 1000 +#define SMU_TEMPERATURE_UNITS_PER_CENTIGRADES MILLIDEGREE_PER_DEGREE #define SMU_FW_NAME_LEN 0x24 #define SMU_DPM_USER_PROFILE_RESTORE (1 << 0) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 238dcc468557..ffff02489c3e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -58,6 +58,10 @@ /* Convert Q10 watts to milliwatts, preserving the fractional part */ #define SMUQ10_TO_MILLIWATT(x) (SMUQ10_TO_UINT(x) * MILLIWATT_PER_WATT + \ ((SMUQ10_FRAC(x) * MILLIWATT_PER_WATT) >> 10)) +/* Convert Q10 degrees Celsius to millidegrees, preserving the fractional part */ +#define SMUQ10_TO_MILLICELSIUS(x) \ + (SMUQ10_TO_UINT(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES + \ + ((SMUQ10_FRAC(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES) >> 10)) #define SMU_V13_SOFT_FREQ_ROUND(x) ((x) + 1) extern const int pmfw_decoded_link_speed[5]; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index f0f789c4ff22..0033453f27e5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -437,19 +437,16 @@ int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_TO_MILLIWATT(metrics->SocketPower); break; case METRICS_TEMPERATURE_HOTSPOT: - *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxSocketTemperature); break; case METRICS_TEMPERATURE_MEM: - *value = SMUQ10_ROUND(metrics->MaxHbmTemperature) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxHbmTemperature); break; /* This is the max of all VRs and not just SOC VR. * No need to define another data type for the same. */ case METRICS_TEMPERATURE_VRSOC: - *value = SMUQ10_ROUND(metrics->MaxVrTemperature) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxVrTemperature); break; default: *value = UINT_MAX; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index fe0443a07b4c..84c02e6d9673 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -1306,19 +1306,16 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_TO_MILLIWATT(GET_METRIC_FIELD(SocketPower, version)); break; case METRICS_TEMPERATURE_HOTSPOT: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(GET_METRIC_FIELD(MaxSocketTemperature, version)); break; case METRICS_TEMPERATURE_MEM: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, version)) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(GET_METRIC_FIELD(MaxHbmTemperature, version)); break; /* This is the max of all VRs and not just SOC VR. * No need to define another data type for the same. */ case METRICS_TEMPERATURE_VRSOC: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, version)) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(GET_METRIC_FIELD(MaxVrTemperature, version)); break; default: *value = UINT_MAX; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index 92897843be24..fd3fca217e31 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -58,6 +58,10 @@ /* Convert Q10 watts to milliwatts, preserving the fractional part */ #define SMUQ10_TO_MILLIWATT(x) (SMUQ10_TO_UINT(x) * MILLIWATT_PER_WATT + \ ((SMUQ10_FRAC(x) * MILLIWATT_PER_WATT) >> 10)) +/* Convert Q10 degrees Celsius to millidegrees, preserving the fractional part */ +#define SMUQ10_TO_MILLICELSIUS(x) \ + (SMUQ10_TO_UINT(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES + \ + ((SMUQ10_FRAC(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES) >> 10)) #define hbm_stack_mask_valid(umc_mask) \ (((umc_mask) & 0xF) == 0xF) @@ -419,8 +423,7 @@ static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_TO_MILLIWATT(metrics->SocketPower); break; case METRICS_TEMPERATURE_HOTSPOT: - *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxSocketTemperature); break; case METRICS_TEMPERATURE_MEM: { @@ -438,19 +441,18 @@ static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu, if (!hbm_stack_mask_valid(mask)) continue; - temp = SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]); + temp = metrics->HbmTemperature[stack_idx]; if (temp > max_hbm_temp) max_hbm_temp = temp; } } - *value = max_hbm_temp * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(max_hbm_temp); break; } /* This is the max of all VRs and not just SOC VR. */ case METRICS_TEMPERATURE_VRSOC: - *value = SMUQ10_ROUND(metrics->MaxVrTemperature) * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxVrTemperature); break; default: *value = UINT_MAX; From 92b0cbfbba4a162831128c4b339a45b2ab5fc351 Mon Sep 17 00:00:00 2001 From: Shubhankar Milind Sardeshpande Date: Wed, 5 Aug 2026 17:13:00 +0530 Subject: [PATCH 04/29] drm/amdgpu: Enable GFXOFF functionality for SMU IP v15.0.5 Add clockgating and powergating flags for GC 11.5.6 and allow/disallow GFXOFF for SMU 15.0.5 Signed-off-by: Shubhankar Milind Sardeshpande Acked-by: Alex Deucher Reviewed-by: Pratik Vishwakarma Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/soc21.c | 21 +++++++++++++++++-- .../gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 1f9a9c46377a..5a6c84c802f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -825,8 +825,25 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block) adev->external_rev_id = adev->rev_id + 0x1; break; case IP_VERSION(11, 5, 6): - adev->cg_flags = 0; - adev->pg_flags = 0; + adev->cg_flags = AMD_CG_SUPPORT_GFX_CGCG | + AMD_CG_SUPPORT_GFX_CGLS | + AMD_CG_SUPPORT_GFX_MGCG | + AMD_CG_SUPPORT_GFX_FGCG | + AMD_CG_SUPPORT_REPEATER_FGCG | + AMD_CG_SUPPORT_GFX_PERF_CLK | + AMD_CG_SUPPORT_GFX_3D_CGCG | + AMD_CG_SUPPORT_GFX_3D_CGLS | + AMD_CG_SUPPORT_MC_MGCG | + AMD_CG_SUPPORT_MC_LS | + AMD_CG_SUPPORT_HDP_LS | + AMD_CG_SUPPORT_HDP_DS | + AMD_CG_SUPPORT_HDP_SD | + AMD_CG_SUPPORT_ATHUB_MGCG | + AMD_CG_SUPPORT_ATHUB_LS | + AMD_CG_SUPPORT_IH_CG | + AMD_CG_SUPPORT_BIF_MGCG | + AMD_CG_SUPPORT_BIF_LS; + adev->pg_flags = AMD_PG_SUPPORT_GFX_PG; adev->external_rev_id = adev->rev_id + 0xd0; break; case IP_VERSION(11, 7, 0): diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c index 14d0eb296a00..4c0236196de4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -583,6 +583,7 @@ int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable) switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(15, 0, 0): + case IP_VERSION(15, 0, 5): case IP_VERSION(15, 0, 9): if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) return 0; From 665b1fc2a1845206408f9a2c6da67101789edb82 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Thu, 6 Aug 2026 12:45:24 +0800 Subject: [PATCH 05/29] drm/amdgpu: disallow multiple FENCE chunks in one submit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amdgpu_cs_pass1() dispatches on chunk_id once per chunk without rejecting repeated ids. p->uf_bo is a single-slot field, so a submission carrying two AMDGPU_CHUNK_ID_FENCE chunks runs amdgpu_cs_p1_user_fence() twice, and the second run overwrites p->uf_bo with a freshly referenced BO without dropping the reference taken by the first. amdgpu_cs_parser_fini() only unrefs the final p->uf_bo, so every FENCE chunk but the last leaks a BO reference. The leaked BO outlives handle close and process exit. Reject duplicate FENCE chunks the same way commit fec5f8e8c6bc ("drm/amdgpu: disallow multiple BO_HANDLES chunks in one submit") did for p->bo_list. Fixes: d38ceaf99ed0 ("drm/amdgpu: add core driver (v4)") Reported-by: Yuhao Jiang Assisted-by: Claude:claude-opus-5 Cc: stable@vger.kernel.org Reviewed-by: Christian König Signed-off-by: Junrui Luo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 47a45d0451fd..67b4ea772030 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -243,6 +243,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, if (size < sizeof(struct drm_amdgpu_cs_chunk_fence)) goto free_partial_kdata; + /* Only a single user fence is allowed to simplify handling. */ + if (p->uf_bo) + goto free_partial_kdata; + ret = amdgpu_cs_p1_user_fence(p, p->chunks[i].kdata, &uf_offset); if (ret) From ab916ec45777cd30512892d610e25d4cba5f7a0b Mon Sep 17 00:00:00 2001 From: Shikang Fan Date: Fri, 7 Aug 2026 11:12:26 +0800 Subject: [PATCH 06/29] drm/amdkfd: preserve VRAM MQD across hibernation via unpin/repin On gfx9 ASICs with mqd_on_vram(), a compute queue MQD lives in a pinned VRAM buffer object. Pinned BOs are skipped by the VRAM eviction done at S4 suspend, so the MQD contents are lost across hibernation and the first submission after resume page-faults on a stale MQD. Unpin the MQD BO at suspend so the eviction migrates it into the hibernation image, and pin it back to VRAM on resume. The BO may return at a different VRAM address, so refresh the kernel mapping and cached GPU addresses and patch the MQD self-address via a new update_mqd_gpu_addr() mqd_manager op; skip eviction with a warning if that op is not implemented. v3: use unpin/repin instead of shadowing the MQD into a separate buffer. v4: drop the explicit VRAM->GTT placement at evict (a bare unpin is enough for the eviction pass to move the BO out of VRAM), and also repin at queue destroy. KFD queue restore runs late - user processes thaw before it, and under SR-IOV it is deferred until the VF exits full access - so once the VM has resumed an application can destroy a queue before its MQD BO is repinned, which would otherwise unpin an already-unpinned BO and touch a stale q->mqd. v5: drop support for no-HWS mode, and set q->mqd to NULL at eviction. Signed-off-by: Shikang Fan Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 106 ++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h | 8 ++ .../gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 40 +++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 6 + 4 files changed, 160 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index ea9d87450eae..a23384571193 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1257,6 +1257,99 @@ static int resume_single_queue(struct device_queue_manager *dqm, return 0; } +/* Unpin the MQD BO at S4 suspend so it is evicted into the hibernation image; + * dqm_repin_mqd_bo() pins it back on resume. Gated on adev->in_s4 so runtime + * eviction is untouched. + */ +static void dqm_evict_mqd_bo(struct device_queue_manager *dqm, struct queue *q) +{ + struct mqd_manager *mqd_mgr; + struct amdgpu_bo *bo; + + if (!dqm->dev->adev->in_s4) + return; + if (!mqd_on_vram(dqm->dev->adev)) + return; + if (q->properties.type != KFD_QUEUE_TYPE_COMPUTE) + return; + if (!q->mqd_mem_obj || !q->mqd_mem_obj->mem) + return; + + /* Without update_mqd_gpu_addr() the MQD self-address cannot be fixed up + * after a repin, so skip eviction (with a warning) instead of faulting. + */ + mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(q->properties.type)]; + if (!mqd_mgr->update_mqd_gpu_addr) { + dev_warn_once(dqm->dev->adev->dev, + "MQD is in VRAM but update_mqd_gpu_addr is not implemented; skipping hibernation eviction\n"); + return; + } + + bo = q->mqd_mem_obj->mem; + if (amdgpu_bo_reserve(bo, false)) + return; + + amdgpu_bo_unpin(bo); + amdgpu_bo_unreserve(bo); + q->mqd = NULL; + q->needs_mqd_repin = true; +} + +/* Repin the MQD BO to VRAM and refresh the cached mapping and GPU addresses. + * Used both on resume and when a queue is destroyed before resume has repinned + * it. A no-op unless a repin is owed (needs_mqd_repin set). + */ +static int dqm_repin_mqd_bo(struct device_queue_manager *dqm, struct queue *q) +{ + struct mqd_manager *mqd_mgr; + struct amdgpu_bo *bo; + void *cpu_ptr; + int r; + + if (!q->needs_mqd_repin) + return 0; + if (!q->mqd_mem_obj || !q->mqd_mem_obj->mem) + return 0; + + bo = q->mqd_mem_obj->mem; + r = amdgpu_bo_reserve(bo, false); + if (r) + return r; + r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_VRAM); + if (r) { + amdgpu_bo_unreserve(bo); + dev_err(dqm->dev->adev->dev, + "Failed to repin MQD of queue %d to VRAM: %d\n", + q->properties.queue_id, r); + return r; + } + /* The BO may have moved; refresh the kernel mapping and gpu address. */ + amdgpu_bo_kunmap(bo); + r = amdgpu_bo_kmap(bo, &cpu_ptr); + amdgpu_bo_unreserve(bo); + if (r) { + dev_err(dqm->dev->adev->dev, + "Failed to remap MQD of queue %d: %d\n", + q->properties.queue_id, r); + return r; + } + + q->mqd_mem_obj->cpu_ptr = cpu_ptr; + q->mqd_mem_obj->gpu_addr = amdgpu_bo_gpu_offset(bo); + q->gart_mqd_addr = q->mqd_mem_obj->gpu_addr; + q->mqd = cpu_ptr; + + mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type( + q->properties.type)]; + if (mqd_mgr->update_mqd_gpu_addr) + mqd_mgr->update_mqd_gpu_addr(mqd_mgr, q->mqd, + q->mqd_mem_obj, + &q->properties); + + q->needs_mqd_repin = false; + return 0; +} + static int evict_process_queues_nocpsch(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { @@ -1353,6 +1446,8 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, goto out; } } + + dqm_evict_mqd_bo(dqm, q); } if (!dqm->dev->kfd->shared_resources.enable_mes) { @@ -1492,6 +1587,13 @@ static int restore_process_queues_cpsch(struct device_queue_manager *dqm, q->properties.is_active = true; increment_queue_count(dqm, &pdd->qpd, q); + retval = dqm_repin_mqd_bo(dqm, q); + if (retval) { + dev_err(dev, "Failed to repin MQD for queue %d\n", + q->properties.queue_id); + goto out; + } + if (dqm->dev->kfd->shared_resources.enable_mes) { retval = add_queue_mes(dqm, q, qpd); if (retval) { @@ -2763,6 +2865,8 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, qpd->pqm->process, q->device, -1, false, NULL, 0); + /* Repin the MQD BO if still evicted for hibernation, before it is freed. */ + dqm_repin_mqd_bo(dqm, q); mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj); return retval; @@ -3020,6 +3124,8 @@ static int process_termination_cpsch(struct device_queue_manager *dqm, list_del(&q->list); qpd->queue_count--; dqm_unlock(dqm); + /* Repin the MQD BO if still evicted for hibernation, before free. */ + dqm_repin_mqd_bo(dqm, q); mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj); dqm_lock(dqm); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h index 59eff3389d39..38b46b696243 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h @@ -117,6 +117,14 @@ struct mqd_manager { const void *ctl_stack_src, const u32 ctl_stack_size); + /* Patch the MQD's cached self GPU address after the MQD BO has moved + * (e.g. repinned to a new VRAM location on hibernation resume). The MQD + * contents are otherwise preserved. + */ + void (*update_mqd_gpu_addr)(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj, + struct queue_properties *p); + #if defined(CONFIG_DEBUG_FS) int (*debugfs_show_mqd)(struct seq_file *m, void *data); #endif 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 75e5a9f67d50..b95720198e28 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -476,6 +476,20 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, qp->is_active = 0; } +static void update_mqd_gpu_addr(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj, + struct queue_properties *qp) +{ + struct v9_mqd *m = get_mqd(mqd); + uint64_t addr = mqd_mem_obj->gpu_addr; + + m->cp_mqd_base_addr_lo = lower_32_bits(addr); + m->cp_mqd_base_addr_hi = upper_32_bits(addr); + + if (mqd_on_vram(mm->dev->adev)) + amdgpu_device_flush_hdp(mm->dev->adev, NULL); +} + static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) @@ -860,6 +874,30 @@ static void restore_mqd_v9_4_3(struct mqd_manager *mm, void **mqd, if (mqd_on_vram(mm->dev->adev)) amdgpu_device_flush_hdp(mm->dev->adev, NULL); } + +static void update_mqd_gpu_addr_v9_4_3(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj, + struct queue_properties *qp) +{ + struct kfd_mem_obj xcc_mqd_mem_obj; + uint64_t offset = mm->mqd_stride(mm, qp); + u32 num_xcc = NUM_XCC(mm->dev->xcc_mask); + struct v9_mqd *m; + int xcc; + + memset(&xcc_mqd_mem_obj, 0x0, sizeof(struct kfd_mem_obj)); + + for (xcc = 0; xcc < num_xcc; xcc++) { + get_xcc_mqd(mqd_mem_obj, &xcc_mqd_mem_obj, offset * xcc); + m = get_mqd(mqd + offset * xcc); + m->cp_mqd_base_addr_lo = lower_32_bits(xcc_mqd_mem_obj.gpu_addr); + m->cp_mqd_base_addr_hi = upper_32_bits(xcc_mqd_mem_obj.gpu_addr); + } + + if (mqd_on_vram(mm->dev->adev)) + amdgpu_device_flush_hdp(mm->dev->adev, NULL); +} + static int destroy_mqd_v9_4_3(struct mqd_manager *mm, void *mqd, enum kfd_preempt_type type, unsigned int timeout, uint32_t pipe_id, uint32_t queue_id) @@ -1017,6 +1055,7 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type, mqd->get_wave_state = get_wave_state_v9_4_3; mqd->checkpoint_mqd = checkpoint_mqd_v9_4_3; mqd->restore_mqd = restore_mqd_v9_4_3; + mqd->update_mqd_gpu_addr = update_mqd_gpu_addr_v9_4_3; } else { mqd->init_mqd = init_mqd; mqd->load_mqd = load_mqd; @@ -1025,6 +1064,7 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type, mqd->get_wave_state = get_wave_state; mqd->checkpoint_mqd = checkpoint_mqd; mqd->restore_mqd = restore_mqd; + mqd->update_mqd_gpu_addr = update_mqd_gpu_addr; } break; case KFD_MQD_TYPE_HIQ: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 2ea1cfd330a9..d8631847f0eb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -638,6 +638,12 @@ struct queue { uint32_t gang_ctx_array_index; struct amdgpu_bo *wptr_bo_gart; + + /* The VRAM-resident MQD BO (mqd_on_vram()) is unpinned at S4 suspend so + * TTM evicts it into the hibernation image, and repinned on resume. Set + * while the BO is unpinned so the resume path knows to repin it. + */ + bool needs_mqd_repin; }; enum KFD_MQD_TYPE { From db39852d0c39843cb02048dfb47e4b8c703e9080 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Mon, 27 Jul 2026 11:51:37 +0800 Subject: [PATCH 07/29] drm/amdgpu: validate GEM_CREATE domain combinations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AMDGPU_GEM_CREATE checked domain bits against AMDGPU_GEM_DOMAIN_MASK, but did not validate domain combinations. Userspace could combine CPU|GTT|VRAM with DOORBELL, GDS, GWS, or OA, making amdgpu_bo_placement_from_domain() exceed AMDGPU_BO_MAX_PLACEMENTS and hit BUG_ON(). Allow combinations only within CPU/GTT/VRAM, and require non-CPU/GTT/ VRAM domains to be specified one at a time. Return -EINVAL for invalid combinations in amdgpu_gem_create_ioctl(). v2: Rename helper from amdgpu_gem_domain_valid() to amdgpu_gem_are_domains_valid() (Christian) Signed-off-by: Candice Li Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 6a0699746fbc..f754a4a3a1c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -397,6 +397,25 @@ const struct drm_gem_object_funcs amdgpu_gem_object_funcs = { .vm_ops = &amdgpu_gem_vm_ops, }; +static bool amdgpu_gem_are_domains_valid(u32 domains) +{ + u32 normal = AMDGPU_GEM_DOMAIN_CPU | + AMDGPU_GEM_DOMAIN_GTT | + AMDGPU_GEM_DOMAIN_VRAM; + /* Treat all non CPU/GTT/VRAM domains as special domains. */ + u32 special = AMDGPU_GEM_DOMAIN_MASK & ~normal; + u32 normal_mask = domains & normal; + u32 special_mask = domains & special; + + if (!special_mask) + return true; + + if (normal_mask) + return false; + + return !(special_mask & (special_mask - 1)); +} + /* * GEM ioctls. */ @@ -421,6 +440,8 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, /* reject invalid gem domains */ if (args->in.domains & ~AMDGPU_GEM_DOMAIN_MASK) return -EINVAL; + if (!amdgpu_gem_are_domains_valid(args->in.domains)) + return -EINVAL; if (!amdgpu_is_tmz(adev) && (flags & AMDGPU_GEM_CREATE_ENCRYPTED)) { DRM_NOTE_ONCE("Cannot allocate secure buffer since TMZ is disabled\n"); From fb8379680c8292bfe3b0855a7bed94d9749a92b5 Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Mon, 15 Jun 2026 13:44:13 +0200 Subject: [PATCH 08/29] drm/amdgpu: don't disable ttm buffer funcs on reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access to hw is already suspended so there are no reasons to disable ttm buffer funcs. Signed-off-by: Pierre-Eric Pelloux-Prayer Reviewed-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 964efec0d335..b7751dde2894 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3162,8 +3162,6 @@ static int amdgpu_device_ip_suspend(struct amdgpu_device *adev) amdgpu_virt_request_full_gpu(adev, false); } - amdgpu_ttm_disable_buffer_funcs(adev); - r = amdgpu_device_ip_suspend_phase1(adev); if (r) return r; From 7b1b31bf6942e6f43509b48da23f8e27269aac39 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Fri, 7 Aug 2026 16:58:55 +0200 Subject: [PATCH 09/29] drm/amd/display: Fix NULL pointer dereference in amdgpu_dm_crtc_set_vblank() amdgpu_dm_crtc_set_vblank() dereferences acrtc_state->stream when vblank is enabled/queried from DRM_IOCTL_MODE_CRTC_GET_SEQUENCE before a stream is attached to it. BUG: kernel NULL pointer dereference, address: 0000000000000008 RIP: amdgpu_dm_crtc_set_vblank+0x6b/0x4d0 [amdgpu] Call Trace: drm_vblank_enable drm_vblank_get drm_crtc_get_sequence_ioctl drm_ioctl_kernel drm_ioctl Reproduced by running VKCTS with WSI tests enabled on RADV. Guard the enable path on acrtc_state->stream being non-NULL, matching the existing checks in this function. Fixes: 34d66bc7ff10 ("drm/amd/display: Fix Xorg desktop unresponsive on Replay panel") Reviewed-by: Melissa Wen Signed-off-by: Samuel Pitoiset Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 46d85457c77b..62eac6e65334 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 @@ -268,7 +268,7 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable) irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id); - if (enable) { + if (enable && acrtc_state->stream) { struct dc *dc = adev->dm.dc; struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); struct psr_settings *psr = &acrtc_state->stream->link->psr_settings; From 5b1541c7b0dae224bec29c626ca31a0c31b57d6b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 30 Jul 2026 12:47:47 -0700 Subject: [PATCH 10/29] drm/amdkfd: kfd_ioctl.h: fix most kernel-doc warnings Make corrections to kernel-doc comments: - use the struct keyword when describing structs - use the enum keyword when describing enums - insert colons (':') as needed in struct member descriptions - add missing short descriptions - convert some comments to kernel-doc format to prevent these warnings: Warning: include/uapi/linux/kfd_ioctl.h:708 cannot understand function prototype: 'struct kfd_ioctl_criu_args' Warning: include/uapi/linux/kfd_ioctl.h:771 cannot understand function prototype: 'enum kfd_ioctl_svm_op' Warning: include/uapi/linux/kfd_ioctl.h:805 cannot understand function prototype: 'enum kfd_ioctl_svm_attr_type' Warning: include/uapi/linux/kfd_ioctl.h:824 cannot understand function prototype: 'struct kfd_ioctl_svm_attribute' Warning: include/uapi/linux/kfd_ioctl.h:867 cannot understand function prototype: 'struct kfd_ioctl_svm_args' Warning: include/uapi/linux/kfd_ioctl.h:910 cannot understand function prototype: 'struct kfd_ioctl_set_xnack_mode_args' Warning: include/uapi/linux/kfd_ioctl.h:1075 cannot understand function prototype: 'struct kfd_ioctl_runtime_enable_args' Warning: include/uapi/linux/kfd_ioctl.h:1160 missing initial short description on line: * kfd_ioctl_dbg_trap_enable_args Warning: include/uapi/linux/kfd_ioctl.h:1182 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_enable_args' Warning: include/uapi/linux/kfd_ioctl.h:1190 missing initial short description on line: * kfd_ioctl_dbg_trap_send_runtime_event_args Warning: include/uapi/linux/kfd_ioctl.h:1208 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_send_runtime_event_args' Warning: include/uapi/linux/kfd_ioctl.h:1215 missing initial short description on line: * kfd_ioctl_dbg_trap_set_exceptions_enabled_args Warning: include/uapi/linux/kfd_ioctl.h:1225 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_set_exceptions_enabled_args' Warning: include/uapi/linux/kfd_ioctl.h:1230 missing initial short description on line: * kfd_ioctl_dbg_trap_set_wave_launch_override_args Warning: include/uapi/linux/kfd_ioctl.h:1252 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_set_wave_launch_override_args' Warning: include/uapi/linux/kfd_ioctl.h:1260 missing initial short description on line: * kfd_ioctl_dbg_trap_set_wave_launch_mode_args Warning: include/uapi/linux/kfd_ioctl.h:1270 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_set_wave_launch_mode_args' Warning: include/uapi/linux/kfd_ioctl.h:1276 missing initial short description on line: * kfd_ioctl_dbg_trap_suspend_queues_ags Warning: include/uapi/linux/kfd_ioctl.h:1305 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_suspend_queues_args' Warning: include/uapi/linux/kfd_ioctl.h:1313 missing initial short description on line: * kfd_ioctl_dbg_trap_resume_queues_args Warning: include/uapi/linux/kfd_ioctl.h:1330 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_resume_queues_args' Warning: include/uapi/linux/kfd_ioctl.h:1337 missing initial short description on line: * kfd_ioctl_dbg_trap_set_node_address_watch_args Warning: include/uapi/linux/kfd_ioctl.h:1354 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_set_node_address_watch_args' Warning: include/uapi/linux/kfd_ioctl.h:1363 missing initial short description on line: * kfd_ioctl_dbg_trap_clear_node_address_watch_args Warning: include/uapi/linux/kfd_ioctl.h:1376 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_clear_node_address_watch_args' Warning: include/uapi/linux/kfd_ioctl.h:1382 missing initial short description on line: * kfd_ioctl_dbg_trap_set_flags_args Warning: include/uapi/linux/kfd_ioctl.h:1393 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_set_flags_args' Warning: include/uapi/linux/kfd_ioctl.h:1399 missing initial short description on line: * kfd_ioctl_dbg_trap_query_debug_event_args Warning: include/uapi/linux/kfd_ioctl.h:1421 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_query_debug_event_args' Warning: include/uapi/linux/kfd_ioctl.h:1428 missing initial short description on line: * kfd_ioctl_dbg_trap_query_exception_info_args Warning: include/uapi/linux/kfd_ioctl.h:1448 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_query_exception_info_args' Warning: include/uapi/linux/kfd_ioctl.h:1457 missing initial short description on line: * kfd_ioctl_dbg_trap_get_queue_snapshot_args Warning: include/uapi/linux/kfd_ioctl.h:1485 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_queue_snapshot_args' Warning: include/uapi/linux/kfd_ioctl.h:1493 missing initial short description on line: * kfd_ioctl_dbg_trap_get_device_snapshot_args Warning: include/uapi/linux/kfd_ioctl.h:1521 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_device_snapshot_args' Warning: include/uapi/linux/kfd_ioctl.h:1529 missing initial short description on line: * kfd_ioctl_dbg_trap_args Warning: include/uapi/linux/kfd_ioctl.h:1539 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1569 This comment starts with '/**', but isn't a kernel-doc comment. * Enables/Disables GPU Specific profiler settings Warning: include/uapi/linux/kfd_ioctl.h:718 struct member 'num_bos' not described in 'kfd_ioctl_criu_args' Warning: include/uapi/linux/kfd_ioctl.h:718 struct member 'op' not described in 'kfd_ioctl_criu_args' Warning: include/uapi/linux/kfd_ioctl.h:874 struct member 'start_addr' not described in 'kfd_ioctl_svm_args' Warning: include/uapi/linux/kfd_ioctl.h:874 struct member 'size' not described in 'kfd_ioctl_svm_args' Warning: include/uapi/linux/kfd_ioctl.h:874 struct member 'op' not described in 'kfd_ioctl_svm_args' Warning: include/uapi/linux/kfd_ioctl.h:874 struct member 'nattr' not described in 'kfd_ioctl_svm_args' Warning: include/uapi/linux/kfd_ioctl.h:874 struct member 'attrs' not described in 'kfd_ioctl_svm_args' Warning: include/uapi/linux/kfd_ioctl.h:1079 struct member 'r_debug' not described in 'kfd_ioctl_runtime_enable_args' Warning: include/uapi/linux/kfd_ioctl.h:1079 struct member 'mode_mask' not described in 'kfd_ioctl_runtime_enable_args' Warning: include/uapi/linux/kfd_ioctl.h:1079 struct member 'capabilities_mask' not described in 'kfd_ioctl_runtime_enable_args' Warning: include/uapi/linux/kfd_ioctl.h:1254 struct member 'pad' not described in 'kfd_ioctl_dbg_trap_set_wave_launch_override_args' Warning: include/uapi/linux/kfd_ioctl.h:1267 cannot understand function prototype: 'struct kfd_ioctl_dbg_trap_set_wave_launch_mode_args' Warning: include/uapi/linux/kfd_ioctl.h:1308 expecting prototype for struct kfd_ioctl_dbg_trap_suspend_queues_ags. Prototype was for struct kfd_ioctl_dbg_trap_suspend_queues_args instead Warning: include/uapi/linux/kfd_ioctl.h:1332 struct member 'pad' not described in 'kfd_ioctl_dbg_trap_resume_queues_args' Warning: include/uapi/linux/kfd_ioctl.h:1488 expecting prototype for struct kfd_ioctl_dbg_trap_get_queue_snapshot_args. Prototype was for struct kfd_ioctl_dbg_trap_queue_snapshot_args instead Warning: include/uapi/linux/kfd_ioctl.h:1524 expecting prototype for struct kfd_ioctl_dbg_trap_get_device_snapshot_args. Prototype was for struct kfd_ioctl_dbg_trap_device_snapshot_args instead * This leaves the following struct members undescribed in kernel-doc comments: Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'enable' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'send_runtime_event' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'set_exceptions_enabled' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'launch_override' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'launch_mode' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'suspend_queues' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'resume_queues' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'set_node_address_watch' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'clear_node_address_watch' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'set_flags' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'query_debug_event' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'query_exception_info' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'queue_snapshot' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1555 struct member 'device_snapshot' not described in 'kfd_ioctl_dbg_trap_args' Warning: include/uapi/linux/kfd_ioctl.h:1571 struct member 'gpu_id' not described in 'kfd_ioctl_pmc_settings' Warning: include/uapi/linux/kfd_ioctl.h:1571 struct member 'lock' not described in 'kfd_ioctl_pmc_settings' Warning: include/uapi/linux/kfd_ioctl.h:1571 struct member 'perfcount_enable' not described in 'kfd_ioctl_pmc_settings' All amdgpu object files before/after compare equal after this change. Signed-off-by: Randy Dunlap Signed-off-by: Alex Deucher --- include/uapi/linux/kfd_ioctl.h | 180 ++++++++++++++++----------------- 1 file changed, 89 insertions(+), 91 deletions(-) diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index 9584b5aab727..749d196e2114 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -690,7 +690,7 @@ enum kfd_criu_op { }; /** - * kfd_ioctl_criu_args - Arguments perform CRIU operation + * struct kfd_ioctl_criu_args - Arguments perform CRIU operation * @devices: [in/out] User pointer to memory location for devices information. * This is an array of type kfd_criu_device_bucket. * @bos: [in/out] User pointer to memory location for BOs information @@ -698,11 +698,11 @@ enum kfd_criu_op { * @priv_data: [in/out] User pointer to memory location for private data * @priv_data_size: [in/out] Size of priv_data in bytes * @num_devices: [in/out] Number of GPUs used by process. Size of @devices array. - * @num_bos [in/out] Number of BOs used by process. Size of @bos array. + * @num_bos: [in/out] Number of BOs used by process. Size of @bos array. * @num_objects: [in/out] Number of objects used by process. Objects are opaque to * user application. * @pid: [in/out] PID of the process being checkpointed - * @op [in] Type of operation (kfd_criu_op) + * @op: [in] Type of operation (kfd_criu_op) * * Return: 0 on success, -errno on failure */ @@ -764,7 +764,7 @@ enum kfd_mmio_remap { #define KFD_IOCTL_SVM_FLAG_EXT_COHERENT 0x00000080 /** - * kfd_ioctl_svm_op - SVM ioctl operations + * enum kfd_ioctl_svm_op - SVM ioctl operations * * @KFD_IOCTL_SVM_OP_SET_ATTR: Modify one or more attributes * @KFD_IOCTL_SVM_OP_GET_ATTR: Query one or more attributes @@ -786,7 +786,7 @@ enum kfd_ioctl_svm_location { }; /** - * kfd_ioctl_svm_attr_type - SVM attribute types + * enum kfd_ioctl_svm_attr_type - SVM attribute types * * @KFD_IOCTL_SVM_ATTR_PREFERRED_LOC: gpuid of the preferred location, 0 for * system memory @@ -815,7 +815,7 @@ enum kfd_ioctl_svm_attr_type { }; /** - * kfd_ioctl_svm_attribute - Attributes as pairs of type and value + * struct kfd_ioctl_svm_attribute - Attributes as pairs of type and value * * The meaning of the @value depends on the attribute type. * @@ -828,7 +828,7 @@ struct kfd_ioctl_svm_attribute { }; /** - * kfd_ioctl_svm_args - Arguments for SVM ioctl + * struct kfd_ioctl_svm_args - Arguments for SVM ioctl * * @op specifies the operation to perform (see enum * @kfd_ioctl_svm_op). @start_addr and @size are common for all @@ -875,7 +875,7 @@ struct kfd_ioctl_svm_args { }; /** - * kfd_ioctl_set_xnack_mode_args - Arguments for set_xnack_mode + * struct kfd_ioctl_set_xnack_mode_args - Arguments for set_xnack_mode * * @xnack_enabled: [in/out] Whether to enable XNACK mode for this process * @@ -1055,15 +1055,15 @@ struct kfd_runtime_info { #define KFD_RUNTIME_ENABLE_MODE_TTMP_SAVE_MASK 2 /** - * kfd_ioctl_runtime_enable_args - Arguments for runtime enable + * struct kfd_ioctl_runtime_enable_args - Arguments for runtime enable * * Coordinates debug exception signalling and debug device enablement with runtime. * - * @r_debug - pointer to user struct for sharing information between ROCr and the debuggger - * @mode_mask - mask to set mode + * @r_debug: pointer to user struct for sharing information between ROCr and the debuggger + * @mode_mask: mask to set mode * KFD_RUNTIME_ENABLE_MODE_ENABLE_MASK - enable runtime for debugging, otherwise disable * KFD_RUNTIME_ENABLE_MODE_TTMP_SAVE_MASK - enable trap temporary setup (ignore on disable) - * @capabilities_mask - mask to notify runtime on what KFD supports + * @capabilities_mask: mask to notify runtime on what KFD supports * * Return - 0 on SUCCESS. * - EBUSY if runtime enable call already pending. @@ -1158,17 +1158,15 @@ enum kfd_dbg_trap_operations { }; /** - * kfd_ioctl_dbg_trap_enable_args - * - * Arguments for KFD_IOC_DBG_TRAP_ENABLE. + * struct kfd_ioctl_dbg_trap_enable_args - Arguments for KFD_IOC_DBG_TRAP_ENABLE. * * Enables debug session for target process. Call @op KFD_IOC_DBG_TRAP_DISABLE in * kfd_ioctl_dbg_trap_args to disable debug session. * - * @exception_mask (IN) - exceptions to raise to the debugger - * @rinfo_ptr (IN) - pointer to runtime info buffer (see kfd_runtime_info) - * @rinfo_size (IN/OUT) - size of runtime info buffer in bytes - * @dbg_fd (IN) - fd the KFD will nofify the debugger with of raised + * @exception_mask: (IN) - exceptions to raise to the debugger + * @rinfo_ptr: (IN) - pointer to runtime info buffer (see kfd_runtime_info) + * @rinfo_size: (IN/OUT) - size of runtime info buffer in bytes + * @dbg_fd: (IN) - fd the KFD will nofify the debugger with of raised * exceptions set in exception_mask. * * Generic errors apply (see kfd_dbg_trap_operations). @@ -1188,15 +1186,14 @@ struct kfd_ioctl_dbg_trap_enable_args { }; /** - * kfd_ioctl_dbg_trap_send_runtime_event_args + * struct kfd_ioctl_dbg_trap_send_runtime_event_args - Arguments for + * KFD_IOC_DBG_TRAP_SEND_RUNTIME_EVENT. * - * - * Arguments for KFD_IOC_DBG_TRAP_SEND_RUNTIME_EVENT. * Raises exceptions to runtime. * - * @exception_mask (IN) - exceptions to raise to runtime - * @gpu_id (IN) - target device id - * @queue_id (IN) - target queue id + * @exception_mask: (IN) - exceptions to raise to runtime + * @gpu_id: (IN) - target device id + * @queue_id: (IN) - target queue id * * Generic errors apply (see kfd_dbg_trap_operations). * Return - 0 on SUCCESS. @@ -1213,12 +1210,12 @@ struct kfd_ioctl_dbg_trap_send_runtime_event_args { }; /** - * kfd_ioctl_dbg_trap_set_exceptions_enabled_args + * struct kfd_ioctl_dbg_trap_set_exceptions_enabled_args - Arguments for + * KFD_IOC_SET_EXCEPTIONS_ENABLED * - * Arguments for KFD_IOC_SET_EXCEPTIONS_ENABLED * Set new exceptions to be raised to the debugger. * - * @exception_mask (IN) - new exceptions to raise the debugger + * @exception_mask: (IN) - new exceptions to raise the debugger * * Generic errors apply (see kfd_dbg_trap_operations). * Return - 0 on SUCCESS. @@ -1228,16 +1225,16 @@ struct kfd_ioctl_dbg_trap_set_exceptions_enabled_args { }; /** - * kfd_ioctl_dbg_trap_set_wave_launch_override_args + * struct kfd_ioctl_dbg_trap_set_wave_launch_override_args - Arguments for + * KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_OVERRIDE * - * Arguments for KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_OVERRIDE * Enable HW exceptions to raise trap. * - * @override_mode (IN) - see kfd_dbg_trap_override_mode - * @enable_mask (IN/OUT) - reference kfd_dbg_trap_mask. + * @override_mode: (IN) - see kfd_dbg_trap_override_mode + * @enable_mask: (IN/OUT) - reference kfd_dbg_trap_mask. * IN is the override modes requested to be enabled. * OUT is referenced in Return below. - * @support_request_mask (IN/OUT) - reference kfd_dbg_trap_mask. + * @support_request_mask: (IN/OUT) - reference kfd_dbg_trap_mask. * IN is the override modes requested for support check. * OUT is referenced in Return below. * @@ -1254,36 +1251,38 @@ struct kfd_ioctl_dbg_trap_set_wave_launch_override_args { __u32 override_mode; __u32 enable_mask; __u32 support_request_mask; + /* private: */ __u32 pad; }; /** - * kfd_ioctl_dbg_trap_set_wave_launch_mode_args + * struct kfd_ioctl_dbg_trap_set_wave_launch_mode_args - Arguments for + * KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_MODE * - * Arguments for KFD_IOC_DBG_TRAP_SET_WAVE_LAUNCH_MODE * Set wave launch mode. * - * @mode (IN) - see kfd_dbg_trap_wave_launch_mode + * @launch_mode: (IN) - see kfd_dbg_trap_wave_launch_mode * * Generic errors apply (see kfd_dbg_trap_operations). * Return - 0 on SUCCESS. */ struct kfd_ioctl_dbg_trap_set_wave_launch_mode_args { __u32 launch_mode; + /* private: */ __u32 pad; }; /** - * kfd_ioctl_dbg_trap_suspend_queues_ags + * struct kfd_ioctl_dbg_trap_suspend_queues_args - Arguments for + * KFD_IOC_DBG_TRAP_SUSPEND_QUEUES * - * Arguments for KFD_IOC_DBG_TRAP_SUSPEND_QUEUES * Suspend queues. * - * @exception_mask (IN) - raised exceptions to clear - * @queue_array_ptr (IN) - pointer to array of queue ids (u32 per queue id) + * @exception_mask: (IN) - raised exceptions to clear + * @queue_array_ptr: (IN) - pointer to array of queue ids (u32 per queue id) * to suspend - * @num_queues (IN) - number of queues to suspend in @queue_array_ptr - * @grace_period (IN) - wave time allowance before preemption + * @num_queues: (IN) - number of queues to suspend in @queue_array_ptr + * @grace_period: (IN) - wave time allowance before preemption * per 1K GPU clock cycle unit * * Generic errors apply (see kfd_dbg_trap_operations). @@ -1311,14 +1310,14 @@ struct kfd_ioctl_dbg_trap_suspend_queues_args { }; /** - * kfd_ioctl_dbg_trap_resume_queues_args + * struct kfd_ioctl_dbg_trap_resume_queues_args - Arguments for + * KFD_IOC_DBG_TRAP_RESUME_QUEUES * - * Arguments for KFD_IOC_DBG_TRAP_RESUME_QUEUES * Resume queues. * - * @queue_array_ptr (IN) - pointer to array of queue ids (u32 per queue id) + * @queue_array_ptr: (IN) - pointer to array of queue ids (u32 per queue id) * to resume - * @num_queues (IN) - number of queues to resume in @queue_array_ptr + * @num_queues: (IN) - number of queues to resume in @queue_array_ptr * * Generic errors apply (see kfd_dbg_trap_operations). * Return - Number of queues resumed on SUCCESS. @@ -1331,20 +1330,21 @@ struct kfd_ioctl_dbg_trap_suspend_queues_args { struct kfd_ioctl_dbg_trap_resume_queues_args { __u64 queue_array_ptr; __u32 num_queues; + /* private: */ __u32 pad; }; /** - * kfd_ioctl_dbg_trap_set_node_address_watch_args + * struct kfd_ioctl_dbg_trap_set_node_address_watch_args - Arguments for + * KFD_IOC_DBG_TRAP_SET_NODE_ADDRESS_WATCH * - * Arguments for KFD_IOC_DBG_TRAP_SET_NODE_ADDRESS_WATCH * Sets address watch for device. * - * @address (IN) - watch address to set - * @mode (IN) - see kfd_dbg_trap_address_watch_mode - * @mask (IN) - watch address mask - * @gpu_id (IN) - target gpu to set watch point - * @id (OUT) - watch id allocated + * @address: (IN) - watch address to set + * @mode: (IN) - see kfd_dbg_trap_address_watch_mode + * @mask: (IN) - watch address mask + * @gpu_id: (IN) - target gpu to set watch point + * @id: (OUT) - watch id allocated * * Generic errors apply (see kfd_dbg_trap_operations). * Return - 0 on SUCCESS. @@ -1361,13 +1361,13 @@ struct kfd_ioctl_dbg_trap_set_node_address_watch_args { }; /** - * kfd_ioctl_dbg_trap_clear_node_address_watch_args + * struct kfd_ioctl_dbg_trap_clear_node_address_watch_args - Arguments for + * KFD_IOC_DBG_TRAP_CLEAR_NODE_ADDRESS_WATCH * - * Arguments for KFD_IOC_DBG_TRAP_CLEAR_NODE_ADDRESS_WATCH * Clear address watch for device. * - * @gpu_id (IN) - target device to clear watch point - * @id (IN) - allocated watch id to clear + * @gpu_id: (IN) - target device to clear watch point + * @id: (IN) - allocated watch id to clear * * Generic errors apply (see kfd_dbg_trap_operations). * Return - 0 on SUCCESS. @@ -1380,12 +1380,12 @@ struct kfd_ioctl_dbg_trap_clear_node_address_watch_args { }; /** - * kfd_ioctl_dbg_trap_set_flags_args + * struct kfd_ioctl_dbg_trap_set_flags_args - Arguments for + * KFD_IOC_DBG_TRAP_SET_FLAGS * - * Arguments for KFD_IOC_DBG_TRAP_SET_FLAGS * Sets flags for wave behaviour. * - * @flags (IN/OUT) - IN = flags to enable, OUT = flags previously enabled + * @flags: (IN/OUT) - IN = flags to enable, OUT = flags previously enabled * * Generic errors apply (see kfd_dbg_trap_operations). * Return - 0 on SUCCESS. @@ -1393,13 +1393,13 @@ struct kfd_ioctl_dbg_trap_clear_node_address_watch_args { */ struct kfd_ioctl_dbg_trap_set_flags_args { __u32 flags; + /* private: */ __u32 pad; }; /** - * kfd_ioctl_dbg_trap_query_debug_event_args - * - * Arguments for KFD_IOC_DBG_TRAP_QUERY_DEBUG_EVENT + * struct kfd_ioctl_dbg_trap_query_debug_event_args - Arguments for + * KFD_IOC_DBG_TRAP_QUERY_DEBUG_EVENT * * Find one or more raised exceptions. This function can return multiple * exceptions from a single queue or a single device with one call. To find @@ -1409,9 +1409,9 @@ struct kfd_ioctl_dbg_trap_set_flags_args { * However, clearing an exception prevents retrieving further information * about it with KFD_IOC_DBG_TRAP_QUERY_EXCEPTION_INFO. * - * @exception_mask (IN/OUT) - exception to clear (IN) and raised (OUT) - * @gpu_id (OUT) - gpu id of exceptions raised - * @queue_id (OUT) - queue id of exceptions raised + * @exception_mask: (IN/OUT) - exception to clear (IN) and raised (OUT) + * @gpu_id: (OUT) - gpu id of exceptions raised + * @queue_id: (OUT) - queue id of exceptions raised * * Generic errors apply (see kfd_dbg_trap_operations). * Return - 0 on raised exception found @@ -1426,16 +1426,16 @@ struct kfd_ioctl_dbg_trap_query_debug_event_args { }; /** - * kfd_ioctl_dbg_trap_query_exception_info_args + * struct kfd_ioctl_dbg_trap_query_exception_info_args - Arguments for + * KFD_IOC_DBG_TRAP_QUERY_EXCEPTION_INFO * - * Arguments KFD_IOC_DBG_TRAP_QUERY_EXCEPTION_INFO * Get additional info on raised exception. * - * @info_ptr (IN) - pointer to exception info buffer to copy to - * @info_size (IN/OUT) - exception info buffer size (bytes) - * @source_id (IN) - target gpu or queue id - * @exception_code (IN) - target exception - * @clear_exception (IN) - clear raised @exception_code exception + * @info_ptr: (IN) - pointer to exception info buffer to copy to + * @info_size: (IN/OUT) - exception info buffer size (bytes) + * @source_id: (IN) - target gpu or queue id + * @exception_code: (IN) - target exception + * @clear_exception: (IN) - clear raised @exception_code exception * (0 = false, 1 = true) * * Generic errors apply (see kfd_dbg_trap_operations). @@ -1455,20 +1455,20 @@ struct kfd_ioctl_dbg_trap_query_exception_info_args { }; /** - * kfd_ioctl_dbg_trap_get_queue_snapshot_args + * struct kfd_ioctl_dbg_trap_queue_snapshot_args - Arguments for + * KFD_IOC_DBG_TRAP_GET_QUEUE_SNAPSHOT * - * Arguments KFD_IOC_DBG_TRAP_GET_QUEUE_SNAPSHOT * Get queue information. * - * @exception_mask (IN) - exceptions raised to clear - * @snapshot_buf_ptr (IN) - queue snapshot entry buffer (see kfd_queue_snapshot_entry) - * @num_queues (IN/OUT) - number of queue snapshot entries + * @exception_mask: (IN) - exceptions raised to clear + * @snapshot_buf_ptr: (IN) - queue snapshot entry buffer (see kfd_queue_snapshot_entry) + * @num_queues: (IN/OUT) - number of queue snapshot entries * The debugger specifies the size of the array allocated in @num_queues. * KFD returns the number of queues that actually existed. If this is * larger than the size specified by the debugger, KFD will not overflow * the array allocated by the debugger. * - * @entry_size (IN/OUT) - size per entry in bytes + * @entry_size: (IN/OUT) - size per entry in bytes * The debugger specifies sizeof(struct kfd_queue_snapshot_entry) in * @entry_size. KFD returns the number of bytes actually populated per * entry. The debugger should use the KFD_IOCTL_MINOR_VERSION to determine, @@ -1491,20 +1491,20 @@ struct kfd_ioctl_dbg_trap_queue_snapshot_args { }; /** - * kfd_ioctl_dbg_trap_get_device_snapshot_args + * struct kfd_ioctl_dbg_trap_device_snapshot_args - Arguments for + * KFD_IOC_DBG_TRAP_GET_DEVICE_SNAPSHOT * - * Arguments for KFD_IOC_DBG_TRAP_GET_DEVICE_SNAPSHOT * Get device information. * - * @exception_mask (IN) - exceptions raised to clear - * @snapshot_buf_ptr (IN) - pointer to snapshot buffer (see kfd_dbg_device_info_entry) - * @num_devices (IN/OUT) - number of debug devices to snapshot + * @exception_mask: (IN) - exceptions raised to clear + * @snapshot_buf_ptr: (IN) - pointer to snapshot buffer (see kfd_dbg_device_info_entry) + * @num_devices: (IN/OUT) - number of debug devices to snapshot * The debugger specifies the size of the array allocated in @num_devices. * KFD returns the number of devices that actually existed. If this is * larger than the size specified by the debugger, KFD will not overflow * the array allocated by the debugger. * - * @entry_size (IN/OUT) - size per entry in bytes + * @entry_size: (IN/OUT) - size per entry in bytes * The debugger specifies sizeof(struct kfd_dbg_device_info_entry) in * @entry_size. KFD returns the number of bytes actually populated. The * debugger should use KFD_IOCTL_MINOR_VERSION to determine, which fields @@ -1527,12 +1527,10 @@ struct kfd_ioctl_dbg_trap_device_snapshot_args { }; /** - * kfd_ioctl_dbg_trap_args + * struct kfd_ioctl_dbg_trap_args - Arguments to debug target process. * - * Arguments to debug target process. - * - * @pid - target process to debug - * @op - debug operation (see kfd_dbg_trap_operations) + * @pid: target process to debug + * @op: debug operation (see kfd_dbg_trap_operations) * * @op determines which union struct args to use. * Refer to kern docs for each kfd_ioctl_dbg_trap_*_args struct. @@ -1567,7 +1565,7 @@ enum kfd_profiler_ops { }; /** - * Enables/Disables GPU Specific profiler settings + * struct kfd_ioctl_pmc_settings - Enables/Disables GPU Specific profiler settings */ struct kfd_ioctl_pmc_settings { __u32 gpu_id; /* This is the user_gpu_id */ From c56525193b5a4d5a302cdc91ed23facbb060673c Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Fri, 7 Aug 2026 17:31:48 +0800 Subject: [PATCH 11/29] drm/amdgpu/mes11: disable MES RS64 process/gang context loading The MES RS64 local memory process/gang context index may be updated, saved, or restored improperly during queue eviction and restore cycles. Enabling RS64 memory for MES process/gang context loading introduces two known issues: 1. Performance regression on userq due to improper context index handling during RS64 memory access. 2. KFDIPCTest.BasicTest failure on Navi31/32/33: the IPC buffer GPU VA mapping is not correctly reflected in the restored RS64 process context, causing GPU page faults on the IPC shared buffer address, which eventually leads to MES firmware becoming unresponsive and requiring a full GPU reset to recover. Temporarily disable MES RS64 process/gang context loading until both issues are resolved. Signed-off-by: Prike Liang Reviewed-by: Michael Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index a0b874c9ee7b..c57bcb9a98b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -1954,7 +1954,7 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block) if (adev->mes.ring[0].sched.ready) goto out; - adev->mes.use_rs64mem = true; + adev->mes.use_rs64mem = false; if (!adev->enable_mes_kiq) { if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) { From d03d1ac2b00896618aecdd3cd56e8e08ce731edd Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Fri, 7 Aug 2026 23:29:58 -0400 Subject: [PATCH 12/29] drm/amd/display: Relax frame size limit for dcn5/6 DML core funcs files [Why] During compilation with allmodconfig with KASAN, there appears a Werror: dml2_core_dcn5_funcs_mode_programming.c:11:13: error: stack frame size (2400) exceeds limit (2048) in 'dcn5_mode_programming' [-Werror,-Wframe-larger-than] The dcn5/dcn6 dml2_core_*_funcs_mode_{programming,support} files were split out of dml2_core_dcn4_calcs.o, which carries a relaxed -Wframe-larger-than limit via $(frame_warn_flag) (2056 normally, or 4096 for clang + KASAN/KCSAN + COMPILE_TEST). The split-out files were never added to the per-file CFLAGS override list, so they inherited the strict global default of 2048. This is why these files trip the frame size warning under KASAN while the larger dml2_core_dcn4_calcs.o does not. [How] Apply the same $(frame_warn_flag) and CFLAGS_REMOVE handling used for dml2_core_dcn4_calcs.o to the split-out files: - dml2_core_dcn5_funcs_mode_programming.o - dml2_core_dcn5_funcs_mode_support.o - dml2_core_dcn6_funcs_mode_programming.o - dml2_core_dcn6_funcs_mode_support.o Fixes: 7f7d7ea1fa51 ("drm/amd/display: Add new sources for DCN6") Reviewed-by: Dillon Varone Signed-off-by: Ivan Lipski Reported-by: Mark Brown Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml2_0/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile index 35d697872a9a..5388bf094fbc 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile @@ -75,11 +75,19 @@ $(foreach obj,$(DML2_RELATIVE_O_FILES),$(eval CFLAGS_REMOVE_$(AMDDALPATH)/$(obj) CFLAGS_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_ccflags) $(frame_warn_flag) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_programming.o := $(dml2_ccflags) $(frame_warn_flag) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_support.o := $(dml2_ccflags) $(frame_warn_flag) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.o := $(dml2_ccflags) $(frame_warn_flag) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.o := $(dml2_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper.o := $(dml2_rcflags) CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_wrapper.o := $(dml2_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_programming.o := $(dml2_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_support.o := $(dml2_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.o := $(dml2_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.o := $(dml2_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper.o := $(dml2_ccflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_wrapper.o := $(dml2_ccflags) From 54a118f1d7e184fcbb18f83889f48f17a767878a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 5 Jun 2026 17:46:19 -0400 Subject: [PATCH 13/29] drm/amdgpu: fix missing check in vm_flush() We shouldn't return early if we need to emit spm update. Reviewed-by: David Rosca Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 4c90e88e2e30..fd563cd9d46a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -800,6 +800,7 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, mutex_unlock(&id_mgr->lock); gds_switch_needed &= !!ring->funcs->emit_gds_switch; + spm_update_needed &= !!adev->gfx.rlc.funcs->update_spm_vmid; vm_flush_needed &= !!ring->funcs->emit_vm_flush && job->vm_pd_addr != AMDGPU_BO_INVALID_OFFSET; pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping && @@ -811,7 +812,7 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, &job->base.s_fence->scheduled == isolation->spearhead; if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync && - !cleaner_shader_needed) + !cleaner_shader_needed && !spm_update_needed) return; amdgpu_ring_ib_begin(ring); From cb1e657ccac89bee3569d85dfa3fe6d9bde9a33b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 5 Jun 2026 18:06:15 -0400 Subject: [PATCH 14/29] drm/amdgpu: handle GDS and SPM without a VM fence If we end up emitting a VM fence keep GDS and SPM associated with that fence. If not, emit them as part of the IB fence. Reviewed-by: David Rosca Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 14 +++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 46 +++++++++++++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 4 ++- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 634b3f7a5fff..da4dc489e80b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -131,6 +131,8 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs, struct amdgpu_fence *af; struct amdgpu_fence *vm_af; bool need_ctx_switch; + bool emit_spm_needed = false; + bool emit_gds_needed = false; struct amdgpu_vm *vm; uint64_t fence_ctx; uint32_t status = 0, alloc_size; @@ -220,7 +222,8 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs, vm_af = job->hw_vm_fence; /* VM sequence */ vm_af->ib_wptr = ring->wptr; - amdgpu_vm_flush(ring, job, need_pipe_sync); + amdgpu_vm_flush(ring, job, need_pipe_sync, &emit_spm_needed, + &emit_gds_needed); vm_af->ib_dw_size = amdgpu_ring_get_dw_distance(ring, vm_af->ib_wptr, ring->wptr); } @@ -232,6 +235,15 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs, if (ring->funcs->insert_start) ring->funcs->insert_start(ring); + if (emit_spm_needed) + adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid); + + if (emit_gds_needed) + amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base, + job->gds_size, job->gws_base, + job->gws_size, job->oa_base, + job->oa_size); + if ((ib->flags & AMDGPU_IB_FLAG_EMIT_MEM_SYNC) && ring->funcs->emit_mem_sync) ring->funcs->emit_mem_sync(ring); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index fd563cd9d46a..86aab37cbdc4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -766,18 +766,22 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, * @ring: ring to use for flush * @job: related job * @need_pipe_sync: is pipe sync needed + * @emit_spm_needed: does the caller need to emit spm + * @emit_gds_needed: does the caller need to emit gds * * Emit a VM flush when it is necessary. */ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, - bool need_pipe_sync) + bool need_pipe_sync, bool *emit_spm_needed, + bool *emit_gds_needed) { struct amdgpu_device *adev = ring->adev; struct amdgpu_isolation *isolation = &adev->isolation[ring->xcp_id]; unsigned vmhub = ring->vm_hub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; struct amdgpu_vmid *id = &id_mgr->ids[job->vmid]; - bool spm_update_needed = job->spm_update_needed; + bool spm_update_needed = adev->gfx.rlc.funcs->update_spm_vmid && + job->spm_update_needed; bool gds_switch_needed = ring->funcs->emit_gds_switch && job->gds_switch_needed; bool vm_flush_needed = job->vm_needs_flush; @@ -785,6 +789,7 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool pasid_mapping_needed = false; struct dma_fence *fence = NULL; unsigned int patch = 0; + bool emit_fence; if (amdgpu_vmid_had_gpu_reset(adev, id)) { gds_switch_needed = true; @@ -811,6 +816,17 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, ring->funcs->emit_cleaner_shader && job->base.s_fence && &job->base.s_fence->scheduled == isolation->spearhead; + emit_fence = vm_flush_needed || pasid_mapping_needed || + cleaner_shader_needed; + + *emit_spm_needed = spm_update_needed; + if (spm_update_needed && emit_fence) + *emit_spm_needed = false; + + *emit_gds_needed = gds_switch_needed; + if (gds_switch_needed && emit_fence) + *emit_gds_needed = false; + if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync && !cleaner_shader_needed && !spm_update_needed) return; @@ -845,22 +861,22 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, if (pasid_mapping_needed) amdgpu_gmc_emit_pasid_mapping(ring, job->vmid, job->pasid); - if (spm_update_needed && adev->gfx.rlc.funcs->update_spm_vmid) - adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid); + if (emit_fence) { + if (spm_update_needed) + adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid); - if (ring->funcs->emit_gds_switch && - gds_switch_needed) { - amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base, - job->gds_size, job->gws_base, - job->gws_size, job->oa_base, - job->oa_size); + if (gds_switch_needed) + amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base, + job->gds_size, job->gws_base, + job->gws_size, job->oa_base, + job->oa_size); + + amdgpu_fence_emit(ring, job->hw_vm_fence, 0); + fence = &job->hw_vm_fence->base; + /* get a ref for the job */ + dma_fence_get(fence); } - amdgpu_fence_emit(ring, job->hw_vm_fence, 0); - fence = &job->hw_vm_fence->base; - /* get a ref for the job */ - dma_fence_get(fence); - if (vm_flush_needed) { mutex_lock(&id_mgr->lock); dma_fence_put(id->last_flush); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 2f8234560764..7f2ba728e3ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -511,7 +511,9 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket, int (*callback)(void *p, struct amdgpu_bo *bo), void *param); -void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_pipe_sync); +void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, + bool need_pipe_sync, bool *emit_spm_needed, + bool *emit_gds_needed); int amdgpu_vm_update_pdes(struct amdgpu_device *adev, struct amdgpu_vm *vm, bool immediate); int amdgpu_vm_clear_freed(struct amdgpu_device *adev, From 0fdc1ff82ea14844c22795e9e0813c3ca03235e1 Mon Sep 17 00:00:00 2001 From: Guangshuo Li Date: Sat, 8 Aug 2026 21:59:42 +0800 Subject: [PATCH 15/29] drm/radeon: fix autosuspend cleanup during teardown radeon_driver_load_kms() calls pm_runtime_use_autosuspend() for PX devices, but radeon_driver_unload_kms() does not call the matching pm_runtime_dont_use_autosuspend() during teardown. If the autosuspend delay is set to a negative value while autosuspend is enabled, the runtime PM core increments usage_count to prevent runtime suspend. Without calling pm_runtime_dont_use_autosuspend() during teardown, this reference is not dropped. The documentation for pm_runtime_use_autosuspend() also notes that it is important to undo it with pm_runtime_dont_use_autosuspend() at driver exit time, unless runtime PM was initially enabled with devm_pm_runtime_enable(). Add the missing pm_runtime_dont_use_autosuspend() call to the driver unload path. This issue was found by manual code inspection. Fixes: 10ebc0bc0934 ("drm/radeon: add runtime PM support (v2)") Signed-off-by: Guangshuo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_kms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index dc43fd790a9c..4a99c09f4164 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -71,6 +71,7 @@ void radeon_driver_unload_kms(struct drm_device *dev) if (radeon_is_px(dev)) { pm_runtime_get_sync(dev->dev); pm_runtime_forbid(dev->dev); + pm_runtime_dont_use_autosuspend(dev->dev); } radeon_acpi_fini(rdev); From 4e0d6f2876e704fff707b18c40dbd383aea4a1c9 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Wed, 5 Aug 2026 20:39:18 +0800 Subject: [PATCH 16/29] drm/amdgpu: check ASPM on the dGPU host link dGPUs with an internal PCIe switch expose graphics functions below the switch downstream port. The automatic ASPM check uses the display endpoint and evaluates the internal link instead of the host link. Use the switch upstream port for the check and report the selected link. Fixes: 0ab5d711ec74 ("drm/amd: Refactor `amdgpu_aspm` to be evaluated per device") Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Reviewed-by: Kenneth Feng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 50 +++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index b7751dde2894..520fd59036d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1338,6 +1338,31 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev) #endif } +/* + * Some dGPUs expose their display endpoint below an internal PCIe switch. + * Use the switch upstream port to query the host-facing link. + */ +static struct pci_dev *amdgpu_device_get_aspm_pdev(struct amdgpu_device *adev) +{ + struct pci_dev *swds, *swus; + + swds = pci_upstream_bridge(adev->pdev); + if (!swds || + (swds->vendor != PCI_VENDOR_ID_ATI && + swds->vendor != PCI_VENDOR_ID_AMD) || + pci_pcie_type(swds) != PCI_EXP_TYPE_DOWNSTREAM) + return adev->pdev; + + swus = pci_upstream_bridge(swds); + if (!swus || + (swus->vendor != PCI_VENDOR_ID_ATI && + swus->vendor != PCI_VENDOR_ID_AMD) || + pci_pcie_type(swus) != PCI_EXP_TYPE_UPSTREAM) + return adev->pdev; + + return swus; +} + /** * amdgpu_device_should_use_aspm - check if the device should program ASPM * @@ -1350,6 +1375,9 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev) */ bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev) { + struct pci_dev *aspm_pdev, *parent; + bool enabled; + switch (amdgpu_aspm) { case -1: break; @@ -1364,7 +1392,27 @@ bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev) return false; if (amdgpu_device_aspm_support_quirk(adev)) return false; - return pcie_aspm_enabled(adev->pdev); + + /* + * pcie_aspm_enabled() checks the link between its argument and + * the immediate upstream bridge. Use SWUS for dGPUs with an + * internal switch so that this is the host-facing link. + */ + aspm_pdev = amdgpu_device_get_aspm_pdev(adev); + parent = pci_upstream_bridge(aspm_pdev); + if (!parent) { + dev_dbg(adev->dev, "ASPM: no upstream PCIe link for %s\n", + pci_name(aspm_pdev)); + return false; + } + + enabled = pcie_aspm_enabled(aspm_pdev); + /* Report the exact link used for the automatic ASPM decision. */ + dev_dbg(adev->dev, "ASPM: link %s <-> %s is %s\n", + pci_name(parent), pci_name(aspm_pdev), + enabled ? "enabled" : "disabled"); + + return enabled; } /* if we get transitioned to only one device, take VGA back */ From 05e1387d151f71569fbe122d2c89f9db0c21dc10 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Thu, 30 Jul 2026 17:37:44 +0200 Subject: [PATCH 17/29] drm/amdgpu: Reject UVD message with dimensions above 4096 Fixes potential overflow in DPB size calculations. Signed-off-by: David Rosca Acked-by: Leo Liu Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index e8b0c62f72be..63561d1d7963 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -655,8 +655,8 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer; unsigned int min_ctx_size = ~0; - /* Reject invalid dimensions to prevent division by zero */ - if (width < 16 || height < 16) { + /* Reject invalid dimensions */ + if (width < 16 || height < 16 || width > 4096 || height > 4096) { dev_WARN_ONCE(adev->dev, 1, "Invalid UVD decoding dimensions (%dx%d)!\n", width, height); From 64b525edb7e7bdfcdc77883c5e413804e2396856 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Thu, 30 Jul 2026 17:56:17 +0200 Subject: [PATCH 18/29] drm/amdgpu: Fix UVD dpb min size calculation for H264 This should use actual number of references from the decode message, instead of maximum derived from level. Signed-off-by: David Rosca Acked-by: Leo Liu Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 62 ++----------------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 63561d1d7963..fa899e321f48 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -646,11 +646,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, unsigned int height = msg[7]; unsigned int dpb_size = msg[9]; unsigned int pitch = msg[28]; - unsigned int level = msg[57]; unsigned int width_in_mb = width / 16; unsigned int height_in_mb = ALIGN(height / 16, 2); - unsigned int fs_in_mb = width_in_mb * height_in_mb; unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer; unsigned int min_ctx_size = ~0; @@ -669,35 +667,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, switch (stream_type) { case 0: /* H264 */ - switch (level) { - case 30: - num_dpb_buffer = 8100 / fs_in_mb; - break; - case 31: - num_dpb_buffer = 18000 / fs_in_mb; - break; - case 32: - num_dpb_buffer = 20480 / fs_in_mb; - break; - case 41: - num_dpb_buffer = 32768 / fs_in_mb; - break; - case 42: - num_dpb_buffer = 34816 / fs_in_mb; - break; - case 50: - num_dpb_buffer = 110400 / fs_in_mb; - break; - case 51: - num_dpb_buffer = 184320 / fs_in_mb; - break; - default: - num_dpb_buffer = 184320 / fs_in_mb; - break; - } - num_dpb_buffer++; + num_dpb_buffer = ((msg[61] >> 16) & 0xff) + 1; if (num_dpb_buffer > 17) - num_dpb_buffer = 17; + return -EINVAL; /* reference picture buffer */ min_dpb_size = image_size * num_dpb_buffer; @@ -747,35 +719,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, break; case 7: /* H264 Perf */ - switch (level) { - case 30: - num_dpb_buffer = 8100 / fs_in_mb; - break; - case 31: - num_dpb_buffer = 18000 / fs_in_mb; - break; - case 32: - num_dpb_buffer = 20480 / fs_in_mb; - break; - case 41: - num_dpb_buffer = 32768 / fs_in_mb; - break; - case 42: - num_dpb_buffer = 34816 / fs_in_mb; - break; - case 50: - num_dpb_buffer = 110400 / fs_in_mb; - break; - case 51: - num_dpb_buffer = 184320 / fs_in_mb; - break; - default: - num_dpb_buffer = 184320 / fs_in_mb; - break; - } - num_dpb_buffer++; + num_dpb_buffer = ((msg[61] >> 16) & 0xff) + 1; if (num_dpb_buffer > 17) - num_dpb_buffer = 17; + return -EINVAL; /* reference picture buffer */ min_dpb_size = image_size * num_dpb_buffer; From b41c8cb12e202b220353332ab87dc01a11f69304 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Thu, 30 Jul 2026 18:01:51 +0200 Subject: [PATCH 19/29] drm/amdgpu: Fix UVD decode image min size calculation This needs to use pitch instead of width. Also reject pitch over 4096 to avoid overflow. Signed-off-by: David Rosca Acked-by: Leo Liu Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index fa899e321f48..947a6cd45881 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -759,7 +759,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, return -EINVAL; } - if (width > pitch) { + if (width > pitch || pitch > 4096) { DRM_ERROR("Invalid UVD decoding target pitch!\n"); return -EINVAL; } @@ -771,7 +771,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, } buf_sizes[0x1] = dpb_size; - buf_sizes[0x2] = image_size; + buf_sizes[0x2] = (pitch * height) * 3 / 2; buf_sizes[0x4] = min_ctx_size; /* store image width to adjust nb memory pstate */ adev->uvd.decode_image_width = width; From 37519d007e4261febbcf35b3045f8344f3145497 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Thu, 30 Jul 2026 18:05:52 +0200 Subject: [PATCH 20/29] drm/amdgpu: Fix UVD min buffer sizes Use correct size for message buffer = sizeof(struct ruvd_msg). Add ITSCALING_TABLE_BUFFER size. Signed-off-by: David Rosca Acked-by: Leo Liu Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 947a6cd45881..e2d0f23d48aa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -918,15 +918,16 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx) ctx->buf_sizes[cmd]); return -EINVAL; } + } else if (cmd == 0x204 || cmd == 0x206) { + unsigned int min_size = ctx->buf_sizes[cmd == 0x204 ? 5 : 4]; - } else if (cmd == 0x206) { - if ((end - start) < ctx->buf_sizes[4]) { + if ((end - start) < min_size) { DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd, (unsigned int)(end - start), - ctx->buf_sizes[4]); + min_size); return -EINVAL; } - } else if ((cmd != 0x100) && (cmd != 0x204)) { + } else if ((cmd != 0x100)) { DRM_ERROR("invalid UVD command %X!\n", cmd); return -EINVAL; } @@ -1056,11 +1057,12 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, { struct amdgpu_uvd_cs_ctx ctx = {}; unsigned int buf_sizes[] = { - [0x00000000] = 2048, + [0x00000000] = 3556, [0x00000001] = 0xFFFFFFFF, [0x00000002] = 0xFFFFFFFF, [0x00000003] = 2048, [0x00000004] = 0xFFFFFFFF, + [0x00000005] = 992, }; int r; From 8897ea8c761b856f02061848a7908040a1fe5e68 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Mon, 10 Aug 2026 11:11:35 +0200 Subject: [PATCH 21/29] drm/amdgpu: Implement insert_end for VCE 3 After a recent change VCE now hangs when VCE_CMD_END is emitted after a pipeline sync without VM flush. Implement insert_end to correctly insert only one VCE_CMD_END per job. Fixes: bc639a9eadc7 ("drm/amdgpu: always emit the job vm fence") Signed-off-by: David Rosca Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 9f4e88440c0a..a9497e2e07f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -809,6 +809,23 @@ static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, ib->length_dw); } +static void vce_v3_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, + u64 seq, unsigned flags) +{ + WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); + + amdgpu_ring_write(ring, VCE_CMD_FENCE); + amdgpu_ring_write(ring, addr); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, seq); + amdgpu_ring_write(ring, VCE_CMD_TRAP); +} + +static void vce_v3_0_ring_insert_end(struct amdgpu_ring *ring) +{ + amdgpu_ring_write(ring, VCE_CMD_END); +} + static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring, unsigned int vmid, uint64_t pd_addr) { @@ -818,7 +835,6 @@ static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring, amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB); amdgpu_ring_write(ring, vmid); - amdgpu_ring_write(ring, VCE_CMD_END); } static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring) @@ -884,17 +900,19 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { .set_wptr = vce_v3_0_ring_set_wptr, .patch_cs_in_place = amdgpu_vce_ring_parse_cs_vm, .emit_frame_size = - 6 + /* vce_v3_0_emit_vm_flush */ + 5 + /* vce_v3_0_emit_vm_flush */ 4 + /* vce_v3_0_emit_pipeline_sync */ - 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ + 5 + 5 + /* vce_v3_0_ring_emit_fence x2 vm fence */ + 1, /* vce_v3_0_ring_insert_end */ .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ .emit_ib = vce_v3_0_ring_emit_ib, .emit_vm_flush = vce_v3_0_emit_vm_flush, .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, - .emit_fence = amdgpu_vce_ring_emit_fence, + .emit_fence = vce_v3_0_ring_emit_fence, .test_ring = amdgpu_vce_ring_test_ring, .test_ib = amdgpu_vce_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, + .insert_end = vce_v3_0_ring_insert_end, .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_vce_ring_begin_use, .end_use = amdgpu_vce_ring_end_use, From 3b906e1dc7e3c9ff9f7940f6828b367a6a9ec73c Mon Sep 17 00:00:00 2001 From: Nathan Lucas Date: Sun, 2 Aug 2026 08:35:23 -0600 Subject: [PATCH 22/29] drm/amd/display: fix BT.2020 YCbCr limited output CSC matrix COLOR_SPACE_YCBCR2020_TYPE, which is selected for COLOR_SPACE_2020_YCBCR_LIMITED color_space, has coefficients that are incorrect for limited-range output. Its luma and chroma scaling is full-range so output is too bright and colors are incorrect. COLOR_SPACE_YCBCR2020_TYPE is closer to a full-range conversion matrix with incorrect luma offset, so correct the luma offset for full-range and rename it to COLOR_SPACE_YCBCR2020_FULL_TYPE. Add COLOR_SPACE_YCBCR2020_LIMITED_TYPE with correct scaling and range for limited-range output. Fix related functions so COLOR_SPACE_YCBCR2020_LIMITED_TYPE and COLOR_SPACE_YCBCR2020_FULL_TYPE are correctly selected based on dc_color_space. Derivation of both matrices follows ITU-T H.273: Table 4, MatrixCoefficients 9, BT.2020-NCL weights: KR = 0.2627, KB = 0.0593, KG = 1 - KR - KB = 0.6780. Equations 45-47 in matrix form: [ KR KG KB 0 ] M2020_NCL = [ -KR/(2(1-KB)) -KG/(2(1-KB)) 1/2 0 ] [ 1/2 -KG/(2(1-KR)) -KB/(2(1-KR)) 0 ] [ 0 0 0 1 ] Limited and Full transforms based on equations 30-32 and 36-38 with bit depth 10, normalized by 1023: [ 876/1023 0 0 64/1023 ] MLimited = [ 0 896/1023 0 512/1023 ] [ 0 0 896/1023 512/1023 ] [ 0 0 0 1 ] [ 1023/1023 0 0 0 ] MFull = [ 0 1023/1023 0 512/1023 ] [ 0 0 1023/1023 512/1023 ] [ 0 0 0 1 ] M2020_NCL_Limited = MLimited x M2020_NCL M2020_NCL_Full = MFull x M2020_NCL The upper three rows of M2020_NCL_* are stored in CR, Y, CB order. Each M2020_NCL_* value is stored as Round(value * 8192) in its 16-bit two's-complement representation. Fixes: 973a9c810c78 ("drm/amd/display: Fix COLOR_SPACE_YCBCR2020_TYPE matrix") Assisted-by: OpenAI-Codex:GPT-5.6-Sol Tested-by: Igor Paunovic Tested-by: Satyajit Roy Signed-off-by: Nathan Lucas Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/core/dc_hw_sequencer.c | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 90d754d192f1..ef4987d449cb 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -60,7 +60,8 @@ enum dc_color_space_type { COLOR_SPACE_RGB_LIMITED_TYPE, COLOR_SPACE_YCBCR601_TYPE, COLOR_SPACE_YCBCR709_TYPE, - COLOR_SPACE_YCBCR2020_TYPE, + COLOR_SPACE_YCBCR2020_LIMITED_TYPE, + COLOR_SPACE_YCBCR2020_FULL_TYPE, COLOR_SPACE_YCBCR601_LIMITED_TYPE, COLOR_SPACE_YCBCR709_LIMITED_TYPE, COLOR_SPACE_YCBCR709_BLACK_TYPE, @@ -112,9 +113,15 @@ static const struct out_csc_color_matrix_type output_csc_matrix[] = { { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3, 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }, - { COLOR_SPACE_YCBCR2020_TYPE, + /* Corrected. Not included in the TODO above. */ + { COLOR_SPACE_YCBCR2020_LIMITED_TYPE, + { 0x0E04, 0xF31D, 0xFEDF, 0x1004, + 0x0733, 0x1294, 0x01A0, 0x0201, + 0xFC16, 0xF5E6, 0x0E04, 0x1004} }, + /* Corrected. Not included in the TODO above. */ + { COLOR_SPACE_YCBCR2020_FULL_TYPE, { 0x1000, 0xF149, 0xFEB7, 0x1004, - 0x0868, 0x15B2, 0x01E6, 0x201, + 0x0868, 0x15B2, 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} }, { COLOR_SPACE_YCBCR709_BLACK_TYPE, { 0x0000, 0x0000, 0x0000, 0x1000, @@ -181,14 +188,14 @@ static bool is_ycbcr709_type( return ret; } -static bool is_ycbcr2020_type( - enum dc_color_space color_space) +static bool is_ycbcr2020_limited_type(enum dc_color_space color_space) { - bool ret = false; + return color_space == COLOR_SPACE_2020_YCBCR_LIMITED; +} - if (color_space == COLOR_SPACE_2020_YCBCR_LIMITED || color_space == COLOR_SPACE_2020_YCBCR_FULL) - ret = true; - return ret; +static bool is_ycbcr2020_full_type(enum dc_color_space color_space) +{ + return color_space == COLOR_SPACE_2020_YCBCR_FULL; } static bool is_ycbcr709_limited_type( @@ -217,8 +224,10 @@ static enum dc_color_space_type get_color_space_type(enum dc_color_space color_s type = COLOR_SPACE_YCBCR601_LIMITED_TYPE; else if (is_ycbcr709_limited_type(color_space)) type = COLOR_SPACE_YCBCR709_LIMITED_TYPE; - else if (is_ycbcr2020_type(color_space)) - type = COLOR_SPACE_YCBCR2020_TYPE; + else if (is_ycbcr2020_limited_type(color_space)) + type = COLOR_SPACE_YCBCR2020_LIMITED_TYPE; + else if (is_ycbcr2020_full_type(color_space)) + type = COLOR_SPACE_YCBCR2020_FULL_TYPE; else if (color_space == COLOR_SPACE_YCBCR709) type = COLOR_SPACE_YCBCR709_BLACK_TYPE; else if (color_space == COLOR_SPACE_YCBCR709_BLACK) From 14c8726b79d19934d6eb6d35c612e3f7204af2c6 Mon Sep 17 00:00:00 2001 From: Nathan Lucas Date: Sun, 2 Aug 2026 08:35:24 -0600 Subject: [PATCH 23/29] drm/amd/display: fix BT.2020 YCbCr output CSC matrices for DCE The commit cited by the Fixes tag added separate limited and full-range BT.2020 YCbCr entries to the DCE output CSC tables, but populated both entries with the same matrix copied from the common DC table. That matrix combined full-range scaling with limited-range luma offset and was incorrect for both limited and full-range output. Replace the coefficients in both entries in the DCE paths with those from the new COLOR_SPACE_YCBCR2020_LIMITED_TYPE and COLOR_SPACE_YCBCR2020_FULL_TYPE entries in the preceding commit ("drm/amd/display: fix BT.2020 YCbCr limited output CSC matrix"). Fixes: 51e6668ab4ba ("drm/amd/display: add missing CSC entries for BT.2020 for DCE IPs") Assisted-by: OpenAI-Codex:GPT-5.6-Sol Tested-by: Igor Paunovic Tested-by: Satyajit Roy Signed-off-by: Nathan Lucas Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_transform.c | 7 ++++--- drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index 864491bfd7f7..83f819890020 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -115,10 +115,11 @@ static const struct out_csc_color_matrix global_color_matrix[] = { { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, { COLOR_SPACE_2020_RGB_LIMITEDRANGE, { 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} }, -{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, - 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }, +/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */ +{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733, + 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} }, { COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2, - 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} } + 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} } }; static bool setup_scaling_configuration( diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c index 1ed018aaa4bb..f5f8cd2d47a5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c @@ -93,10 +93,11 @@ static const struct out_csc_color_matrix global_color_matrix[] = { { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, { COLOR_SPACE_2020_RGB_LIMITEDRANGE, { 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} }, -{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, - 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }, +/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */ +{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733, + 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} }, { COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2, - 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} } + 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} } }; enum csc_color_mode { From c2417f9fd7049d5a8d87eefd82fd6e36ba1ff7b6 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 10 Aug 2026 12:48:19 +0800 Subject: [PATCH 24/29] drm/amdgpu: fix nbif 6.3.1 l1 low power not functional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCIe L1 low‑power settings for NBIF 6.3.1 were never applied due to unresolved register mapping, which caused the relevant code to be compiled out. As a result, the PCIe link could not enter L1/L23 power‑down states or transition to L0s. Properly configure the link control register to enable L1 and L23 power‑down, and permit L0s link transitions. Keep LTR disabled and let the PCI core enable it only after verifying end‑to‑end root complex support across switches. Fixes: 894c6d3522d1 ("drm/amdgpu: Add nbif v6_3_1 ip block support") Signed-off-by: Yang Wang Signed-off-by: Kenneth Feng Reviewed-by: Kenneth Feng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c | 42 ++++++++++-------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c index 000516b5845a..61eb0513dc97 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c @@ -500,7 +500,6 @@ static u32 nbif_v6_3_1_get_rom_offset(struct amdgpu_device *adev) static void nbif_v6_3_1_program_ltr(struct amdgpu_device *adev) { uint32_t def, data; - u16 devctl2; def = RREG32_SOC15(NBIO, 0, regRCC_EP_DEV0_0_EP_PCIE_TX_LTR_CNTL); data = 0x35EB; @@ -514,15 +513,8 @@ static void nbif_v6_3_1_program_ltr(struct amdgpu_device *adev) if (def != data) WREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP2, data); - pcie_capability_read_word(adev->pdev, PCI_EXP_DEVCTL2, &devctl2); - - if (adev->pdev->ltr_path == (devctl2 & PCI_EXP_DEVCTL2_LTR_EN)) - return; - - if (adev->pdev->ltr_path) - pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN); - else - pcie_capability_clear_word(adev->pdev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN); + pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_LTR_EN); } #endif @@ -530,7 +522,7 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev) { #ifdef CONFIG_PCIEASPM uint32_t def, data; - u16 devctl2, ltr; + u16 ltr; def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL); data &= ~PCIE_LC_CNTL__LC_L1_INACTIVITY_MASK; @@ -560,11 +552,8 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev) if (def != data) WREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP5, data); - pcie_capability_read_word(adev->pdev, PCI_EXP_DEVCTL2, &devctl2); - data = def = devctl2; - data &= ~PCI_EXP_DEVCTL2_LTR_EN; - if (def != data) - pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2, (u16)data); + pcie_capability_clear_word(adev->pdev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_LTR_EN); ltr = pci_find_ext_capability(adev->pdev, PCI_EXT_CAP_ID_LTR); @@ -572,15 +561,13 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev) pci_write_config_dword(adev->pdev, ltr + PCI_LTR_MAX_SNOOP_LAT, 0x10011001); } -#if 0 - /* regPSWUSP0_PCIE_LC_CNTL2 should be replace by PCIE_LC_CNTL2 or someone else ? */ - def = data = RREG32_SOC15(NBIO, 0, regPSWUSP0_PCIE_LC_CNTL2); - data |= PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK | - PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK; - data &= ~PSWUSP0_PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK; + def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL2); + data |= PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK | + PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK; + data &= ~PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK; if (def != data) - WREG32_SOC15(NBIO, 0, regPSWUSP0_PCIE_LC_CNTL2, data); -#endif + WREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL2, data); + def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL4); data |= PCIE_LC_CNTL4__LC_L1_POWERDOWN_MASK; if (def != data) @@ -591,7 +578,12 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev) if (def != data) WREG32_SOC15(PCIE, 0, regPCIE_LC_RXRECOVER_RXSTANDBY_CNTL, data); - nbif_v6_3_1_program_ltr(adev); + /* + * Do not enable endpoint LTR unless the Root Complex and every + * upstream switch support it. + */ + if (adev->pdev->ltr_path) + nbif_v6_3_1_program_ltr(adev); def = data = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP3); data |= 0x5DE0 << RCC_STRAP0_RCC_BIF_STRAP3__STRAP_VLINK_ASPM_IDLE_TIMER__SHIFT; From 04b48274e985250a0f14b57245391560f8073246 Mon Sep 17 00:00:00 2001 From: Jesse Zhang Date: Wed, 5 Aug 2026 13:42:32 +0800 Subject: [PATCH 25/29] drm/amdgpu: keep PRT mappings off the vm_bo state lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A PRT/sparse mapping has no backing BO, so its bo_va->base.bo is NULL. amdgpu_vm_bo_base_init() deliberately keeps such a bo_va off the vm_bo state lists, but the tail of amdgpu_vm_bo_update() unconditionally called amdgpu_vm_bo_idle() for the !always_valid case, putting the NULL-bo PRT bo_va onto the individual.idle list. On a GPU reset amdgpu_vm_bo_reset_state_machine() moves individual.idle to individual.needs_update with moved=true, and amdgpu_vm_handle_moved() then dereferences bo_va->base.bo to read its reservation object, crashing on the NULL bo (e.g. the userq eviction restore worker running during a reset while a user queue is torn down): BUG: kernel NULL pointer dereference, address: 0000000000000158 RIP: 0010:amdgpu_vm_handle_moved+0x17a/0x200 [amdgpu] Call Trace: amdgpu_userq_vm_validate_and_restore_queue+0x2ce/0x920 [amdgpu] amdgpu_userq_restore_worker+0xce/0x210 [amdgpu] Skip amdgpu_vm_bo_idle() when bo is NULL so a PRT mapping never lands on a state list in the first place, and refresh the PRT page tables explicitly in the userq restore path (as the CS path already does) so sparse mappings survive a VRAM-lost reset. Because the PRT bo_va is off the state lists, its PTE update fence lands in prt_va->last_pt_update rather than vm->last_update, so wait on it explicitly before restarting the queues (mirroring how the CS path syncs that fence). v2: - keep the PRT bo_va off the vm_bo state lists instead of NULL-guarding bo inside amdgpu_vm_handle_moved(); a PRT mapping should never be on the moved list in the first place (Christian) v3: - the PRT PTEs are updated separately, so their fence is in prt_va->last_pt_update, not vm->last_update; wait on it in the userq restore path before restarting queues, otherwise the queues could restart before the sparse PTEs are written (Christian) Suggested-by: Christian König Reviewed-by: Christian König Signed-off-by: Jesse Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 6d3ed55e9ab4..bcfbd7213dd6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1070,6 +1070,16 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) if (ret) goto unlock_all; + /* + * PRT/sparse mappings are kept off the vm_bo state lists, so + * amdgpu_vm_handle_moved() does not touch them. Refresh their PTEs + * explicitly here (as the CS path does) so sparse mappings survive a + * VRAM-lost reset. + */ + ret = amdgpu_vm_bo_update(adev, fpriv->prt_va, false); + if (ret) + goto unlock_all; + key = 0; /* Validate User Ptr BOs */ list_for_each_entry(bo_va, &vm->always_valid.idle, base.vm_status) { @@ -1127,6 +1137,12 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) */ list_for_each_entry(bo_va, &vm->always_valid.idle, base.vm_status) dma_fence_wait(bo_va->last_pt_update, false); + /* + * The PRT bo_va is kept off the state lists, so its PTE update fence + * lands in prt_va->last_pt_update rather than vm->last_update; wait on + * it explicitly (as the CS path syncs it) before restarting queues. + */ + dma_fence_wait(fpriv->prt_va->last_pt_update, false); dma_fence_wait(vm->last_update, false); xa_for_each(&uq_mgr->userq_xa, tmp_key, queue) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 86aab37cbdc4..71050a86bcc3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1408,7 +1408,13 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, amdgpu_vm_bo_evicted(&bo_va->base); else amdgpu_vm_bo_idle(&bo_va->base); - } else { + } else if (bo) { + /* + * A PRT/sparse mapping has no BO and is kept off the vm_bo + * state lists (see amdgpu_vm_bo_base_init()); putting it on the + * idle list here would let amdgpu_vm_handle_moved() dereference + * the NULL bo after a reset. + */ amdgpu_vm_bo_idle(&bo_va->base); } From a4b0720e4f1601f97f59a2be9c1b4b94fa6527d5 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Tue, 11 Aug 2026 11:03:10 +0200 Subject: [PATCH 26/29] drm/amdgpu: Reject UVD message with invalid number of h265 refs Same change as for h264, avoids overflow later when calculating min dpb size. Signed-off-by: David Rosca Reviewed-by: Leo Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index e2d0f23d48aa..228a405a94c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -749,6 +749,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, image_size = ALIGN(image_size, 256); num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2; + if (num_dpb_buffer > 17) + return -EINVAL; + min_dpb_size = image_size * num_dpb_buffer; min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16) * 16 * num_dpb_buffer + 52 * 1024; From 24775b2e8bce78157acdae30adba4a68039187d7 Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Thu, 23 Jul 2026 13:11:14 +0800 Subject: [PATCH 27/29] drm/amdgpu: skip BOs being torn down during GTT recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A GPU reset can race with BO teardown after the BO's GTT resource has been marked for deletion but before its drm_mm node is removed. In this window, amdgpu_gtt_mgr_recover() can treat the node as a live BO and try to restore its GART mapping while its TT backing is being destroyed. Recolor the GTT node from amdgpu_bo_delete_mem_notify() so that recovery skips it, reusing the existing color for ranges without a BO. The range stays allocated until the resource is freed. This prevents reset recovery from accessing a BO whose backing storage is no longer valid. v2: refine commit message. (David Francis) v3: Remove new BO color. (Christian) Signed-off-by: Yifan Zhang Acked-by: Christian König Reviewed-by: Perry Yuan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | 23 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 1 + 3 files changed, 27 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index 0ea32561c4bc..6219233ff712 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -102,6 +102,29 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res) return drm_mm_node_allocated(&node->mm_nodes[0]); } +/** + * amdgpu_gtt_mgr_mark_bo_teardown - exclude a BO from GART recovery + * + * @tbo: TTM BO whose TT backing is about to be destroyed + * + * Keep the GART range allocated until the resource is freed, but make recovery + * treat it like a range without a BO so it isn't touched after TT teardown has + * started. + */ +void amdgpu_gtt_mgr_mark_bo_teardown(struct ttm_buffer_object *tbo) +{ + struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); + struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(tbo->resource); + struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; + + dma_resv_assert_held(tbo->base.resv); + + spin_lock(&mgr->lock); + if (drm_mm_node_allocated(&node->mm_nodes[0])) + node->mm_nodes[0].color = GART_ENTRY_WITHOUT_BO_COLOR; + spin_unlock(&mgr->lock); +} + /** * amdgpu_gtt_mgr_new - allocate a new node * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 74c1521b8efc..d5a419776e93 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1694,6 +1694,9 @@ static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo, static void amdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo) { + if (bo->resource && bo->resource->mem_type == TTM_PL_TT) + amdgpu_gtt_mgr_mark_bo_teardown(bo); + amdgpu_bo_move_notify(bo, false, NULL); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index ff9e2e346609..af1e7fcc7175 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -145,6 +145,7 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev); void amdgpu_vram_mgr_fini(struct amdgpu_device *adev); bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem); +void amdgpu_gtt_mgr_mark_bo_teardown(struct ttm_buffer_object *tbo); void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr); int amdgpu_gtt_mgr_alloc_entries(struct amdgpu_gtt_mgr *mgr, From b4cb43789b6ac0f25fc0d9b21c5e7a6225cf6a31 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 8 Aug 2026 22:41:28 +0300 Subject: [PATCH 28/29] drm/amd/pm: silence uninitialized variable warnings Smatch complains that: drivers/gpu/drm/amd/amdgpu/../pm/swsmu/smu15/smu_v15_0_8_ppt.c:1964 smu_v15_0_8_set_performance_level() error: uninitialized symbol 'ret'. In this line there is an "if (ret)" condition where "ret" is either zero or uninitialized. Initialize "ret" at the start of the function to avoid a potential uninitialized variable bug. But also delete the condition since it is never true. Fixes: 422b399b09c7 ("drm/amd/pm: Add od_edit_dpm_table support") Reviewed-by: Lijo Lazar Signed-off-by: Dan Carpenter Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index fd3fca217e31..aa4daf8f7d6f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -1951,7 +1951,7 @@ static int smu_v15_0_8_set_performance_level(struct smu_context *smu, struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; - int ret; + int ret = 0; switch (level) { case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM: @@ -1992,9 +1992,6 @@ static int smu_v15_0_8_set_performance_level(struct smu_context *smu, SMU_DPM_TABLE_MAX(uclk_table); } - if (ret) - goto out; - smu_cmn_reset_custom_level(smu); break; From 0d710af8e4abdd1fa500bddbab7c0ee47fc98143 Mon Sep 17 00:00:00 2001 From: Mikhail Gavrilov Date: Thu, 30 Jul 2026 11:53:00 +0500 Subject: [PATCH 29/29] drm/amd/display: make DC_RUN_WITH_PREEMPTION_ENABLED misuse a build error Inside an FPU compilation unit DC_FP_START() and DC_FP_END() are defined as BUILD_BUG(), so using them there fails the build. That was done on purpose by commit a574f53ed52e ("drm/amd/display: Permit DC_FP_START/END only in non-FP compilation units"). DC_RUN_WITH_PREEMPTION_ENABLED() was added later by commit 3539437f354b ("drm/amd/display: Move FPU Guards From DML To DC - Part 1") and defined as a plain pass-through in that same branch instead. A wrap placed inside an FPU compilation unit therefore compiles cleanly, reads as correct during review, and does nothing at all. This is not hypothetical. While chasing a "scheduling while atomic" splat in dc_create_plane_state() on PREEMPT_RT, an attempt to place the guard further up the call chain, in dml21_add_phantom_plane() in dc/dml2_0/dml21/dml21_utils.c, had no effect for exactly this reason: dc/dml2_0/Makefile applies CC_FLAGS_FPU to every object under that directory, and the top level Makefile adds -D_LINUX_FPU_COMPILATION_UNIT to CC_FLAGS_FPU. Define the macro as BUILD_BUG() there as well, so that the mistake is a compile error rather than a guard that silently does nothing. The code argument is kept in the expansion so the BUILD_BUG() failure is not accompanied by set-but-unused diagnostics for variables assigned inside it. No current user is affected. dc/core/dc_stream.c and dc/resource/dcn32/dcn32_resource.c are outside the dml directories, and dc/dml2_0/dml2_wrapper.c and dc/dml2_0/dml21/dml21_wrapper.c are built without the FPU flags because dc/dml2_0/Makefile replaces their CFLAGS with CC_FLAGS_NO_FPU and removes CC_FLAGS_FPU. Link: https://lore.kernel.org/all/1ead313022bc62dce1f42af9f855727eb9074443.camel@web.de/ Signed-off-by: Mikhail Gavrilov Reviewed-by: Tom Chung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h index 5e95419d3798..e89b39a4aa83 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h @@ -51,7 +51,11 @@ void dc_fpu_end(const char *function_name, const int line); #else #define DC_FP_START() BUILD_BUG() #define DC_FP_END() BUILD_BUG() -#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code +#define DC_RUN_WITH_PREEMPTION_ENABLED(code) \ + do { \ + BUILD_BUG(); \ + code; \ + } while (0) #endif // !_LINUX_FPU_COMPILATION_UNIT #endif /* __DC_FPU_H__ */