From: Greg Kroah-Hartman Date: Wed, 29 Jul 2026 12:45:23 +0000 (+0200) Subject: 6.18-stable patches X-Git-Tag: v6.1.179~42 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=cd0e07beacb4f976bf9e83db085c066139cdf2d6;p=thirdparty%2Fkernel%2Fstable-queue.git 6.18-stable patches added patches: drm-amd-display-consolidate-dcn-vblank-flip-handling-onto-vupdate_no_lock.patch drm-amd-display-dce100-skip-non-dp-stream-encoders-for-dp-mst.patch drm-amd-display-fix-backlight-max_brightness-to-match-exported-range.patch drm-amd-display-force-pwm-backlight-on-lenovo-legion-5-15arh05.patch drm-amd-display-set-new_stream-to-null-after-release.patch drm-amd-pm-ci-don-t-disable-mclk-dpm-on-bonaire-0x6658-r7-260x.patch drm-amdgpu-fix-vfct-bus-number-matching-with-soft-filter.patch drm-amdgpu-release-vfct-acpi-table-reference.patch drm-panthor-return-error-on-truncated-firmware.patch drm-ttm-account-for-null-and-handle-pages-in-ttm_pool_backup.patch --- diff --git a/queue-6.18/drm-amd-display-consolidate-dcn-vblank-flip-handling-onto-vupdate_no_lock.patch b/queue-6.18/drm-amd-display-consolidate-dcn-vblank-flip-handling-onto-vupdate_no_lock.patch new file mode 100644 index 0000000000..b6e627a167 --- /dev/null +++ b/queue-6.18/drm-amd-display-consolidate-dcn-vblank-flip-handling-onto-vupdate_no_lock.patch @@ -0,0 +1,659 @@ +From 8382cd234981ae36299bb66a10bac2cd8ff1b99d Mon Sep 17 00:00:00 2001 +From: Leo Li +Date: Fri, 12 Jun 2026 13:29:31 -0400 +Subject: drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock + +From: Leo Li + +commit 8382cd234981ae36299bb66a10bac2cd8ff1b99d upstream. + +[Why] + +On DCN, vblank events were delivered from VSTARTUP/VUPDATE +(dm_crtc_high_irq/dm_vupdate_high_irq) and pageflip completion from +GRPH_PFLIP (dm_pflip_high_irq). These signals can be masked by hardware +by a few things: + +* DPG - DCN can Dynamically Power Gate parts of the display pipe when a + self-refresh capable eDP is connected. DPG is engaged when there's + enough static frames (detected through drm_vblank_off). Once gated, + even though the OTG (output timing generator) is still enabled, + VSTARTUP and GRPH_FLIP are masked. + +* GSL - Driver can use the Global Sync Lock to block HW from latching + onto double-buffered registers during programming, to prevent HW from + latching onto a partially programmed state. This will mask VSTARTUP, + GRPH_FLIP, and VUPDATE. See dcn20_pipe_control_lock(). + +* MALL - A DCN accessible cache introduced in DCN32+ DGPUs that can + store fb data to allow for longer DRAM sleep. When scanning out from + MALL, VSTARTUP is masked. + +When masked, events are never delivered, which can show up as flip_done +timeouts in the wild. + +However, there is an interrupt source on DCN that is never masked: +VUPDATE_NO_LOCK. It's simply an unmasked variant of VUPDATE, which fires +while the OTG is active, at the exact point hardware latches +double-buffered registers. It is therefore the natural single signal for +delivering both vblank and flip-completion events on DCN, and the +correct point to timestamp both VRR and non-VRR vblanks. + +DCE's interrupt sources are different, it does not have an unmaskable +VUPDATE_NO_LOCK. The only unmaskable DCE interrupt is VLINE0, but it can +only be programmed as a vline offset from vsync_start, making it +unsuitable for VRR. Thus, we keep DCE untouched and use the existing mix +of interrupt sources. + +[How] + +For DCN1 and newer only: + +* Factor the body of dm_crtc_high_irq() into dm_crtc_high_irq_handler() + and drive it from dm_vupdate_high_irq() (VUPDATE_NO_LOCK). DCE keeps + using dm_crtc_high_irq() (VSTARTUP) and dm_pflip_high_irq() + (GRPH_PFLIP) unchanged. + +* Stop registering VSTARTUP (crtc_irq) and GRPH_PFLIP (pageflip_irq) on + DCN, and stop enabling them in amdgpu_dm_crtc_set_vblank() / + manage_dm_interrupts(). Enable VUPDATE whenever vblank is enabled on + DCN (previously only in VRR mode). The secure-display vline0 interrupt + is left untouched. + +* VUPDATE_NO_LOCK does not early-fire on an immediate (tearing / async) + flip, since HW latches the new address right away. Deliver the flip + completion event immediately after programming such flips in + amdgpu_dm_commit_planes(), and clear pflip_status so the next vupdate + handler does not double-send. + +v2: Do not gate VUPDATE_NO_LOCK on DCN in dm_handle_vrr_transition() + Also toggle VUPDATE_NO_LOCK on DCN in dm_gpureset_toggle_interrupts() + Re-cook vblank event count and timestamp for immediate flips + +Fixes: 9b47278cec98 ("drm/amd/display: temp w/a for dGPU to enter idle optimizations") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/3787 +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/4141 +Assisted-by: Copilot:claude-opus-4.8 +Co-developed-by: Matthew Schwartz +Signed-off-by: Matthew Schwartz +Tested-by: Mario Limonciello (AMD) +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Leo Li +Signed-off-by: Alex Deucher +(cherry picked from commit c87e6635d2db02c88ae8d09529362da672d34770) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 349 +++++++++-------- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 70 ++- + 2 files changed, 229 insertions(+), 190 deletions(-) + +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -575,89 +575,25 @@ static void schedule_dc_vmin_vmax(struct + queue_work(system_wq, &offload_work->work); + } + +-static void dm_vupdate_high_irq(void *interrupt_params) +-{ +- struct common_irq_params *irq_params = interrupt_params; +- struct amdgpu_device *adev = irq_params->adev; +- struct amdgpu_crtc *acrtc; +- struct drm_device *drm_dev; +- struct drm_vblank_crtc *vblank; +- ktime_t frame_duration_ns, previous_timestamp; +- unsigned long flags; +- int vrr_active; +- +- acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE); +- +- if (acrtc) { +- vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); +- drm_dev = acrtc->base.dev; +- vblank = drm_crtc_vblank_crtc(&acrtc->base); +- previous_timestamp = atomic64_read(&irq_params->previous_timestamp); +- frame_duration_ns = vblank->time - previous_timestamp; +- +- if (frame_duration_ns > 0) { +- trace_amdgpu_refresh_rate_track(acrtc->base.index, +- frame_duration_ns, +- ktime_divns(NSEC_PER_SEC, frame_duration_ns)); +- atomic64_set(&irq_params->previous_timestamp, vblank->time); +- } +- +- drm_dbg_vbl(drm_dev, +- "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id, +- vrr_active); +- +- /* Core vblank handling is done here after end of front-porch in +- * vrr mode, as vblank timestamping will give valid results +- * while now done after front-porch. This will also deliver +- * page-flip completion events that have been queued to us +- * if a pageflip happened inside front-porch. +- */ +- if (vrr_active && acrtc->dm_irq_params.stream) { +- bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; +- bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; +- bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state +- == VRR_STATE_ACTIVE_VARIABLE; +- +- amdgpu_dm_crtc_handle_vblank(acrtc); +- +- /* BTR processing for pre-DCE12 ASICs */ +- if (adev->family < AMDGPU_FAMILY_AI) { +- spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); +- mod_freesync_handle_v_update( +- adev->dm.freesync_module, +- acrtc->dm_irq_params.stream, +- &acrtc->dm_irq_params.vrr_params); +- +- if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { +- schedule_dc_vmin_vmax(adev, +- acrtc->dm_irq_params.stream, +- &acrtc->dm_irq_params.vrr_params.adjust); +- } +- spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); +- } +- } +- } +-} +- + /** +- * dm_crtc_high_irq() - Handles CRTC interrupt +- * @interrupt_params: used for determining the CRTC instance ++ * dm_crtc_high_irq_handler() - Common OTG vblank/flip event handling ++ * @adev: amdgpu device ++ * @acrtc: the CRTC to service + * +- * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK +- * event handler. ++ * Performs writeback completion, vblank event handling, CRC processing, VRR BTR ++ * updates and pageflip completion delivery. ++ * ++ * On DCN this is driven by VUPDATE_NO_LOCK (the register latch point) from ++ * dm_vupdate_high_irq(); on DCE it is driven by VLINE0 at the start of vblank ++ * from dm_crtc_high_irq(). + */ +-static void dm_crtc_high_irq(void *interrupt_params) ++static void dm_crtc_high_irq_handler(struct amdgpu_device *adev, ++ struct amdgpu_crtc *acrtc) + { +- struct common_irq_params *irq_params = interrupt_params; +- struct amdgpu_device *adev = irq_params->adev; + struct drm_writeback_job *job; +- struct amdgpu_crtc *acrtc; + unsigned long flags; + int vrr_active; +- +- acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); +- if (!acrtc) +- return; ++ bool is_dcn = amdgpu_ip_version(adev, DCE_HWIP, 0) != 0; + + if (acrtc->wb_conn) { + spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); +@@ -694,12 +630,17 @@ static void dm_crtc_high_irq(void *inter + vrr_active, acrtc->dm_irq_params.active_planes); + + /** +- * Core vblank handling at start of front-porch is only possible +- * in non-vrr mode, as only there vblank timestamping will give +- * valid results while done in front-porch. Otherwise defer it +- * to dm_vupdate_high_irq after end of front-porch. ++ * Core vblank handling. ++ * ++ * On DCN this handler runs at VUPDATE_NO_LOCK, the register latch ++ * point, which is the correct place to timestamp both VRR and non-VRR ++ * vblanks. ++ * ++ * On DCE this handler runs at the start of front-porch, where only ++ * non-VRR timestamping is valid; VRR vblank is deferred to ++ * dm_vupdate_high_irq() after end of front-porch. + */ +- if (!vrr_active) ++ if (is_dcn || !vrr_active) + amdgpu_dm_crtc_handle_vblank(acrtc); + + /** +@@ -732,18 +673,16 @@ static void dm_crtc_high_irq(void *inter + } + + /* +- * If there aren't any active_planes then DCH HUBP may be clock-gated. +- * In that case, pageflip completion interrupts won't fire and pageflip +- * completion events won't get delivered. Prevent this by sending +- * pending pageflip events from here if a flip is still pending. ++ * Deliver pageflip completion events (DCN only). + * +- * If any planes are enabled, use dm_pflip_high_irq() instead, to +- * avoid race conditions between flip programming and completion, +- * which could cause too early flip completion events. +- */ +- if (adev->family >= AMDGPU_FAMILY_RV && +- acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED && +- acrtc->dm_irq_params.active_planes == 0) { ++ * Since GRPH_PFLIP is not used, VUPDATE_NO_LOCK is the flip latch ++ * point. Deliver any pending pageflip completion event from here. ++ * ++ * NOTE: This can deliver an event for a flip that was armed but not yet ++ * programmed into HW; that race is closed in a follow-up change by ++ * checking the programmed flip status. ++ */ ++ if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED) { + if (acrtc->event) { + drm_crtc_send_vblank_event(&acrtc->base, acrtc->event); + acrtc->event = NULL; +@@ -755,6 +694,104 @@ static void dm_crtc_high_irq(void *inter + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); + } + ++static void dm_vupdate_high_irq(void *interrupt_params) ++{ ++ struct common_irq_params *irq_params = interrupt_params; ++ struct amdgpu_device *adev = irq_params->adev; ++ struct amdgpu_crtc *acrtc; ++ struct drm_device *drm_dev; ++ struct drm_vblank_crtc *vblank; ++ ktime_t frame_duration_ns, previous_timestamp; ++ unsigned long flags; ++ int vrr_active; ++ ++ acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE); ++ if (!acrtc) ++ return; ++ ++ vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); ++ drm_dev = acrtc->base.dev; ++ vblank = drm_crtc_vblank_crtc(&acrtc->base); ++ previous_timestamp = atomic64_read(&irq_params->previous_timestamp); ++ frame_duration_ns = vblank->time - previous_timestamp; ++ ++ if (frame_duration_ns > 0) { ++ trace_amdgpu_refresh_rate_track(acrtc->base.index, ++ frame_duration_ns, ++ ktime_divns(NSEC_PER_SEC, frame_duration_ns)); ++ atomic64_set(&irq_params->previous_timestamp, vblank->time); ++ } ++ ++ drm_dbg_vbl(drm_dev, ++ "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id, ++ vrr_active); ++ ++ /* ++ * On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver ++ * vblank and pageflip completion events; VSTARTUP and GRPH_PFLIP are ++ * not used. Run the full handler here. ++ */ ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) { ++ dm_crtc_high_irq_handler(adev, acrtc); ++ return; ++ } ++ ++ /* DCE only below. */ ++ ++ /* Core vblank handling is done here after end of front-porch in ++ * vrr mode, as vblank timestamping will give valid results ++ * while now done after front-porch. This will also deliver ++ * page-flip completion events that have been queued to us ++ * if a pageflip happened inside front-porch. ++ */ ++ if (vrr_active && acrtc->dm_irq_params.stream) { ++ bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; ++ bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; ++ bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state ++ == VRR_STATE_ACTIVE_VARIABLE; ++ ++ amdgpu_dm_crtc_handle_vblank(acrtc); ++ ++ /* BTR processing for pre-DCE12 ASICs */ ++ if (adev->family < AMDGPU_FAMILY_AI) { ++ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); ++ mod_freesync_handle_v_update( ++ adev->dm.freesync_module, ++ acrtc->dm_irq_params.stream, ++ &acrtc->dm_irq_params.vrr_params); ++ ++ if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { ++ schedule_dc_vmin_vmax(adev, ++ acrtc->dm_irq_params.stream, ++ &acrtc->dm_irq_params.vrr_params.adjust); ++ } ++ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); ++ } ++ } ++} ++ ++/** ++ * dm_crtc_high_irq() - Handles CRTC interrupt ++ * @interrupt_params: used for determining the CRTC instance ++ * ++ * Handles the CRTC/VSYNC interrupt by notifying DRM's VBLANK event handler. ++ * ++ * Used on DCE (VLINE0, set to vblank start). On DCN the equivalent handling is ++ * driven by VUPDATE_NO_LOCK in dm_vupdate_high_irq(). ++ */ ++static void dm_crtc_high_irq(void *interrupt_params) ++{ ++ struct common_irq_params *irq_params = interrupt_params; ++ struct amdgpu_device *adev = irq_params->adev; ++ struct amdgpu_crtc *acrtc; ++ ++ acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); ++ if (!acrtc) ++ return; ++ ++ dm_crtc_high_irq_handler(adev, acrtc); ++} ++ + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + /** + * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for +@@ -3059,6 +3096,13 @@ static void dm_gpureset_toggle_interrupt + */ + if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) + drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis"); ++ ++ } else if (acrtc && state->stream_status[i].plane_count != 0) { ++ /* DCN only needs to toggle VUPDATE_NO_LOCK */ ++ rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, enable); ++ if (rc) ++ drm_warn(adev_to_drm(adev), "Failed to %sable vupdate interrupt\n", ++ enable ? "en" : "dis"); + } + } + +@@ -4558,38 +4602,6 @@ static int dcn10_register_irq_handlers(s + * for acknowledging and handling. + */ + +- /* Use VSTARTUP interrupt */ +- for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP; +- i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1; +- i++) { +- r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq); +- +- if (r) { +- drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n"); +- return r; +- } +- +- int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; +- int_params.irq_source = +- dc_interrupt_to_irq_source(dc, i, 0); +- +- if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || +- int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || +- int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { +- drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n"); +- return -EINVAL; +- } +- +- c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; +- +- c_irq_params->adev = adev; +- c_irq_params->irq_src = int_params.irq_source; +- +- if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, +- dm_crtc_high_irq, c_irq_params)) +- return -ENOMEM; +- } +- + /* Use otg vertical line interrupt */ + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) { +@@ -4661,37 +4673,6 @@ static int dcn10_register_irq_handlers(s + return -ENOMEM; + } + +- /* Use GRPH_PFLIP interrupt */ +- for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT; +- i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num - 1; +- i++) { +- r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq); +- if (r) { +- drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n"); +- return r; +- } +- +- int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; +- int_params.irq_source = +- dc_interrupt_to_irq_source(dc, i, 0); +- +- if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || +- int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || +- int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { +- drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n"); +- return -EINVAL; +- } +- +- c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; +- +- c_irq_params->adev = adev; +- c_irq_params->irq_src = int_params.irq_source; +- +- if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, +- dm_pflip_high_irq, c_irq_params)) +- return -ENOMEM; +- } +- + /* HPD */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, + &adev->hpd_irq); +@@ -9118,14 +9099,22 @@ static void manage_dm_interrupts(struct + + drm_crtc_vblank_on_config(&acrtc->base, + &config); +- /* Allow RX6xxx, RX7700, RX7800 GPUs to call amdgpu_irq_get.*/ ++ /* ++ * Since pflip_high_irq is no longer registered for DCN, grab an ++ * extra reference to vupdate irq instead to workaround this ++ * issue: ++ * https://gitlab.freedesktop.org/drm/amd/-/work_items/3936 ++ * ++ * The callbacks to drm_vblank_on/off should really take care of ++ * this though. ++ */ + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 0, 0): + case IP_VERSION(3, 0, 2): + case IP_VERSION(3, 0, 3): + case IP_VERSION(3, 2, 0): +- if (amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type)) +- drm_err(dev, "DM_IRQ: Cannot get pageflip irq!\n"); ++ if (amdgpu_irq_get(adev, &adev->vupdate_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot get vupdate irq!\n"); + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + if (amdgpu_irq_get(adev, &adev->vline0_irq, irq_type)) + drm_err(dev, "DM_IRQ: Cannot get vline0 irq!\n"); +@@ -9143,8 +9132,8 @@ static void manage_dm_interrupts(struct + if (amdgpu_irq_put(adev, &adev->vline0_irq, irq_type)) + drm_err(dev, "DM_IRQ: Cannot put vline0 irq!\n"); + #endif +- if (amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type)) +- drm_err(dev, "DM_IRQ: Cannot put pageflip irq!\n"); ++ if (amdgpu_irq_put(adev, &adev->vupdate_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot put vupdate irq!\n"); + } + + drm_crtc_vblank_off(&acrtc->base); +@@ -9157,6 +9146,10 @@ static void dm_update_pflip_irq_state(st + int irq_type = + amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id); + ++ /* GRPH_PFLIP is not used on DCN; nothing to reapply. */ ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) ++ return; ++ + /** + * This reads the current state for the IRQ and force reapplies + * the setting to hardware. +@@ -9488,9 +9481,13 @@ static void update_stream_irq_parameters + static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state, + struct dm_crtc_state *new_state) + { ++ struct amdgpu_device *adev = drm_to_adev(new_state->base.crtc->dev); + bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state); + bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state); + ++ /* Only DCE gates vupdate on VRR, keep it enabled for DCN */ ++ bool vrr_gates_vupdate = amdgpu_ip_version(adev, DCE_HWIP, 0) == 0; ++ + if (!old_vrr_active && new_vrr_active) { + /* Transition VRR inactive -> active: + * While VRR is active, we must not disable vblank irq, as a +@@ -9500,7 +9497,8 @@ static void amdgpu_dm_handle_vrr_transit + * We also need vupdate irq for the actual core vblank handling + * at end of vblank. + */ +- WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0); ++ if (vrr_gates_vupdate) ++ WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0); + WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0); + drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n", + __func__, new_state->base.crtc->base.id); +@@ -9508,7 +9506,8 @@ static void amdgpu_dm_handle_vrr_transit + /* Transition VRR active -> inactive: + * Allow vblank irq disable again for fixed refresh rate. + */ +- WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0); ++ if (vrr_gates_vupdate) ++ WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0); + drm_crtc_vblank_put(new_state->base.crtc); + drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n", + __func__, new_state->base.crtc->base.id); +@@ -9683,6 +9682,7 @@ static void amdgpu_dm_commit_planes(stru + bool vrr_active = amdgpu_dm_crtc_vrr_active(acrtc_state); + bool cursor_update = false; + bool pflip_present = false; ++ bool immediate_flip = false; + bool dirty_rects_changed = false; + bool updated_planes_and_streams = false; + struct { +@@ -9848,6 +9848,8 @@ static void amdgpu_dm_commit_planes(stru + acrtc_state->update_type == UPDATE_TYPE_FAST && + get_mem_type(old_plane_state->fb) == get_mem_type(fb); + ++ immediate_flip |= bundle->flip_addrs[planes_count].flip_immediate; ++ + timestamp_ns = ktime_get_ns(); + bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); + bundle->surface_updates[planes_count].flip_addr = &bundle->flip_addrs[planes_count]; +@@ -10049,6 +10051,29 @@ static void amdgpu_dm_commit_planes(stru + acrtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE) + amdgpu_dm_commit_cursors(state); + ++ /* ++ * On DCN, flip completion is normally delivered from VUPDATE_NO_LOCK. ++ * However, an immediate (tearing / async) flip is latched by HW right ++ * away and does not wait for the next vupdate, so deliver its ++ * completion event here after programming. ++ * ++ * On DCE, GRPH_PFLIP already fires immediately for immediate flips, so ++ * this is DCN-only. ++ */ ++ if (immediate_flip && amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0) { ++ spin_lock_irqsave(&pcrtc->dev->event_lock, flags); ++ if (acrtc_attach->pflip_status == AMDGPU_FLIP_SUBMITTED && ++ acrtc_attach->event) { ++ drm_crtc_accurate_vblank_count(&acrtc_attach->base); ++ drm_crtc_send_vblank_event(&acrtc_attach->base, ++ acrtc_attach->event); ++ acrtc_attach->event = NULL; ++ drm_crtc_vblank_put(&acrtc_attach->base); ++ acrtc_attach->pflip_status = AMDGPU_FLIP_NONE; ++ } ++ spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags); ++ } ++ + cleanup: + kfree(bundle); + } +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +@@ -327,7 +327,14 @@ static inline int amdgpu_dm_crtc_set_vbl + drm_crtc_vblank_restore(crtc); + } + +- if (dc_supports_vrr(dm->dc->ctx->dce_version)) { ++ /* ++ * On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver ++ * vblank and pageflip completion events, so enable it whenever vblank ++ * is enabled. On DCE, vupdate is only needed in VRR mode. ++ */ ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) { ++ rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, enable); ++ } else if (dc_supports_vrr(dm->dc->ctx->dce_version)) { + if (enable) { + /* vblank irq on -> Only need vupdate irq in vrr mode */ + if (amdgpu_dm_crtc_vrr_active(acrtc_state)) +@@ -341,36 +348,43 @@ static inline int amdgpu_dm_crtc_set_vbl + if (rc) + return rc; + +- /* crtc vblank or vstartup interrupt */ +- if (enable) { +- rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc); +- } else { +- rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc); +- } +- +- if (rc) +- return rc; +- + /* +- * hubp surface flip interrupt +- * +- * We have no guarantee that the frontend index maps to the same +- * backend index - some even map to more than one. +- * +- * TODO: Use a different interrupt or check DC itself for the mapping. ++ * VLINE0 (crtc_irq) and GRPH_PFLIP (pageflip_irq) are only used on ++ * DCE. On DCN, vblank and pageflip completion are delivered from ++ * VUPDATE_NO_LOCK (enabled above), so don't touch them here. + */ +- if (enable) { +- rc = amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Get pageflip_irq ret=%d\n", rc); +- } else { +- rc = amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Put pageflip_irq ret=%d\n", rc); +- } ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) { ++ /* crtc vblank or vstartup interrupt */ ++ if (enable) { ++ rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc); ++ } else { ++ rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc); ++ } + +- if (rc) +- return rc; ++ if (rc) ++ return rc; ++ ++ /* ++ * hubp surface flip interrupt ++ * ++ * We have no guarantee that the frontend index maps to the same ++ * backend index - some even map to more than one. ++ * ++ * TODO: Use a different interrupt or check DC itself for the mapping. ++ */ ++ if (enable) { ++ rc = amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Get pageflip_irq ret=%d\n", rc); ++ } else { ++ rc = amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Put pageflip_irq ret=%d\n", rc); ++ } ++ ++ if (rc) ++ return rc; ++ } + + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + /* crtc vline0 interrupt, only available on DCN+ */ diff --git a/queue-6.18/drm-amd-display-dce100-skip-non-dp-stream-encoders-for-dp-mst.patch b/queue-6.18/drm-amd-display-dce100-skip-non-dp-stream-encoders-for-dp-mst.patch new file mode 100644 index 0000000000..392205d96d --- /dev/null +++ b/queue-6.18/drm-amd-display-dce100-skip-non-dp-stream-encoders-for-dp-mst.patch @@ -0,0 +1,62 @@ +From d340cba0df4cf327c7e89c7c1a4e79d4771d7dd5 Mon Sep 17 00:00:00 2001 +From: Andriy Korud +Date: Fri, 10 Jul 2026 12:52:26 +0200 +Subject: drm/amd/display: dce100: skip non-DP stream encoders for DP MST + +From: Andriy Korud + +commit d340cba0df4cf327c7e89c7c1a4e79d4771d7dd5 upstream. + +On DCE8-class ASICs (e.g. Bonaire), the resource pool contains digital +DIG stream encoders plus one analog DAC encoder. When assigning a stream +encoder for a second DisplayPort MST stream, if the preferred digital +encoder is already acquired, dce100_find_first_free_match_stream_enc_for_link() +falls back to the first free pool entry. That entry may be the analog +encoder, whose funcs table lacks DP hooks such as dp_set_stream_attribute. +The subsequent atomic commit then dereferences NULL function pointers in +link_set_dpms_on() and crashes. + +Skip encoders without dp_set_stream_attribute when the stream uses a DP +signal (including MST). Use dc_is_dp_signal(stream->signal) for the MST +fallback path instead of checking only the link connector signal. + +Tested on: +- GPU: AMD Radeon R7 260X (Bonaire / DCE8) +- Board: Supermicro C9X299-PG300 +- Setup: DP MST daisy chain, hotplug second monitor or have it connected on boot +- Kernel: 7.1.3 (issue observed since 6.19) +- Result: kernel oops without patch; dual monitors stable with patch + +Signed-off-by: Andriy Korud +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5162 +Signed-off-by: Alex Deucher +(cherry picked from commit 28ec64943e3ee4d9b8d30cea61e380f1429953a8) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +@@ -957,6 +957,11 @@ struct stream_encoder *dce100_find_first + for (i = 0; i < pool->stream_enc_count; i++) { + if (!res_ctx->is_stream_enc_acquired[i] && + pool->stream_enc[i]) { ++ /* DP/MST needs a digital encoder; skip analog/no-DP encoders */ ++ if (dc_is_dp_signal(stream->signal) && ++ (!pool->stream_enc[i]->funcs || ++ !pool->stream_enc[i]->funcs->dp_set_stream_attribute)) ++ continue; + /* Store first available for MST second display + * in daisy chain use case + */ +@@ -980,7 +985,7 @@ struct stream_encoder *dce100_find_first + * required for non DP connectors. + */ + +- if (j >= 0 && link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) ++ if (j >= 0 && dc_is_dp_signal(stream->signal)) + return pool->stream_enc[j]; + + return NULL; diff --git a/queue-6.18/drm-amd-display-fix-backlight-max_brightness-to-match-exported-range.patch b/queue-6.18/drm-amd-display-fix-backlight-max_brightness-to-match-exported-range.patch new file mode 100644 index 0000000000..e22123eecf --- /dev/null +++ b/queue-6.18/drm-amd-display-fix-backlight-max_brightness-to-match-exported-range.patch @@ -0,0 +1,55 @@ +From f1b5d8f9cc54ae8a2567ac126867ae488e1bf625 Mon Sep 17 00:00:00 2001 +From: Mario Limonciello +Date: Mon, 29 Jun 2026 15:27:00 -0500 +Subject: drm/amd/display: Fix backlight max_brightness to match exported range + +From: Mario Limonciello + +commit f1b5d8f9cc54ae8a2567ac126867ae488e1bf625 upstream. + +[Why] +FWTS autobrightness fails on eDP panels because actual_brightness can +read higher than the advertised max_brightness (e.g. 63576 vs 62451). + +The conversion helpers expose the firmware PWM range to userspace as +[0..max]. But max_brightness is advertised as (max - min), which is +smaller. So reading the level can return a value above max_brightness. + +This regressed in commit 4b61b8a39051 ("drm/amd/display: Add debugging +message for brightness caps"), which changed max_brightness to +(max - min) and undid commit 8dbd72cb7900 ("drm/amd/display: Export full +brightness range to userspace"). + +[How] +Advertise max_brightness as max, and scale the initial AC/DC brightness +against max too. Update the KUnit expectations to match. + +Fixes: 4b61b8a39051 ("drm/amd/display: Add debugging message for brightness caps") +Reviewed-by: Alex Hung +Signed-off-by: Mario Limonciello +Signed-off-by: George Zhang +Signed-off-by: Alex Deucher +(cherry picked from commit bd9e2b5b0473c75abc0f4134dfe79ecbfb16610d) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5204,11 +5204,11 @@ amdgpu_dm_register_backlight_device(stru + caps = &dm->backlight_caps[aconnector->bl_idx]; + if (get_brightness_range(caps, &min, &max)) { + if (power_supply_is_system_supplied() > 0) +- props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->ac_level, 100); ++ props.brightness = DIV_ROUND_CLOSEST(max * caps->ac_level, 100); + else +- props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->dc_level, 100); ++ props.brightness = DIV_ROUND_CLOSEST(max * caps->dc_level, 100); + /* min is zero, so max needs to be adjusted */ +- props.max_brightness = max - min; ++ props.max_brightness = max; + drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max, + caps->ac_level, caps->dc_level); + } else diff --git a/queue-6.18/drm-amd-display-force-pwm-backlight-on-lenovo-legion-5-15arh05.patch b/queue-6.18/drm-amd-display-force-pwm-backlight-on-lenovo-legion-5-15arh05.patch new file mode 100644 index 0000000000..dcc4c564bd --- /dev/null +++ b/queue-6.18/drm-amd-display-force-pwm-backlight-on-lenovo-legion-5-15arh05.patch @@ -0,0 +1,97 @@ +From bad177fa75e607e396cd57daaaed881450d7a471 Mon Sep 17 00:00:00 2001 +From: Alessandro Rinaldi +Date: Fri, 26 Jun 2026 16:36:00 +0200 +Subject: drm/amd/display: Force PWM backlight on Lenovo Legion 5 15ARH05 + +From: Alessandro Rinaldi + +commit bad177fa75e607e396cd57daaaed881450d7a471 upstream. + +The Lenovo Legion 5 15ARH05 (Renoir) ships a BOE 0x08DF eDP panel that +advertises AUX/DPCD backlight control, so amdgpu's automatic detection +(amdgpu_backlight == -1) selects AUX. On this panel the AUX backlight +path has no effect: brightness writes are accepted but the panel level +never changes, the display is stuck at a fixed brightness and +max_brightness is reported as a bogus 511000. As a result neither the +desktop brightness slider nor the brightness hotkeys do anything. + +Forcing PWM backlight (amdgpu.backlight=0) restores working control: +max_brightness becomes 65535 and the level tracks writes. This has long +been applied by users as a manual kernel-parameter workaround. + +Extend the generic panel backlight quirk with a force_pwm flag, add an +entry for the Legion 5 15ARH05 / BOE 0x08DF panel, and have amdgpu +disable AUX backlight (use PWM) when the quirk matches and the user +lets the driver auto-select the backlight type. + +Signed-off-by: Alessandro Rinaldi +Tested-by: Alessandro Rinaldi +Reviewed-by: George Zhang +Signed-off-by: Alex Deucher +(cherry picked from commit 81b39f43e7e53589491e2eef6bad5389626b4b9c) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++-- + drivers/gpu/drm/drm_panel_backlight_quirks.c | 9 +++++++++ + include/drm/drm_utils.h | 1 + + 3 files changed, 15 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -3724,6 +3724,8 @@ static void update_connector_ext_caps(st + caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; + caps->aux_support = false; + ++ panel_backlight_quirk = drm_get_panel_backlight_quirk(aconnector->drm_edid); ++ + if (caps->ext_caps->bits.oled == 1 + /* + * || +@@ -3736,6 +3738,9 @@ static void update_connector_ext_caps(st + caps->aux_support = false; + else if (amdgpu_backlight == 1) + caps->aux_support = true; ++ else if (!IS_ERR_OR_NULL(panel_backlight_quirk) && ++ panel_backlight_quirk->force_pwm) ++ caps->aux_support = false; + if (caps->aux_support) + aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; + +@@ -3751,8 +3756,6 @@ static void update_connector_ext_caps(st + else + caps->aux_min_input_signal = 1; + +- panel_backlight_quirk = +- drm_get_panel_backlight_quirk(aconnector->drm_edid); + if (!IS_ERR_OR_NULL(panel_backlight_quirk)) { + if (panel_backlight_quirk->min_brightness) { + caps->min_input_signal = +--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c ++++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c +@@ -21,6 +21,15 @@ struct drm_get_panel_backlight_quirk { + }; + + static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks[] = { ++ /* Lenovo Legion 5 15ARH05, AUX backlight non-functional, force PWM */ ++ { ++ .dmi_match.field = DMI_SYS_VENDOR, ++ .dmi_match.value = "LENOVO", ++ .dmi_match_other.field = DMI_PRODUCT_VERSION, ++ .dmi_match_other.value = "Lenovo Legion 5 15ARH05", ++ .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x08df), ++ .quirk = { .force_pwm = true, }, ++ }, + /* 13 inch matte panel */ + { + .dmi_match.field = DMI_BOARD_VENDOR, +--- a/include/drm/drm_utils.h ++++ b/include/drm/drm_utils.h +@@ -19,6 +19,7 @@ int drm_get_panel_orientation_quirk(int + struct drm_panel_backlight_quirk { + u16 min_brightness; + u32 brightness_mask; ++ bool force_pwm; + }; + + const struct drm_panel_backlight_quirk * diff --git a/queue-6.18/drm-amd-display-set-new_stream-to-null-after-release.patch b/queue-6.18/drm-amd-display-set-new_stream-to-null-after-release.patch new file mode 100644 index 0000000000..fc01122baa --- /dev/null +++ b/queue-6.18/drm-amd-display-set-new_stream-to-null-after-release.patch @@ -0,0 +1,39 @@ +From 9fa26b9eed6195bf840f39ac183b9a6237548755 Mon Sep 17 00:00:00 2001 +From: WenTao Liang +Date: Sun, 28 Jun 2026 15:27:40 +0800 +Subject: drm/amd/display: set new_stream to NULL after release + +From: WenTao Liang + +commit 9fa26b9eed6195bf840f39ac183b9a6237548755 upstream. + +In dm_update_crtc_state(), the skip_modeset path releases new_stream +via dc_stream_release() but does not set the pointer to NULL. + +If a later error (e.g., color management failure) triggers the fail +label, the error path calls dc_stream_release() again on the same +dangling pointer, causing a double release and potential use-after-free. + +Fix this by setting new_stream to NULL after the initial release. + +Fixes: 9b690ef3c704 ("drm/amd/display: Avoid full modeset when not required") +Signed-off-by: WenTao Liang +Reviewed-by: George Zhang +Signed-off-by: Alex Deucher +(cherry picked from commit 99f3af19073b3ddbfd96e789124cce12c4277b28) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -11383,6 +11383,7 @@ skip_modeset: + /* Release extra reference */ + if (new_stream) + dc_stream_release(new_stream); ++ new_stream = NULL; + + /* + * We want to do dc stream updates that do not require a diff --git a/queue-6.18/drm-amd-pm-ci-don-t-disable-mclk-dpm-on-bonaire-0x6658-r7-260x.patch b/queue-6.18/drm-amd-pm-ci-don-t-disable-mclk-dpm-on-bonaire-0x6658-r7-260x.patch new file mode 100644 index 0000000000..667903af3d --- /dev/null +++ b/queue-6.18/drm-amd-pm-ci-don-t-disable-mclk-dpm-on-bonaire-0x6658-r7-260x.patch @@ -0,0 +1,63 @@ +From 85371c5ef502d10add72eab38711e191dccea981 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timur=20Krist=C3=B3f?= +Date: Mon, 13 Jul 2026 08:14:43 +0200 +Subject: drm/amd/pm/ci: Don't disable MCLK DPM on Bonaire 0x6658 (R7 260X) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +commit 85371c5ef502d10add72eab38711e191dccea981 upstream. + +The old radeon driver has a documented workaround in ci_dpm.c +which claims that Bonaire 0x6658 with old memory controller +firmware is unstable with MCLK DPM, so as a precaution I +disabled MCLK DPM on this ASIC in amdgpu. + +Note that the old MC firmware is not actually used with +amdgpu, but in theory it's possible that the VBIOS sets +up the ASIC with an old MC firmware that is already running +when amdgpu initializes (in which case amdgpu doesn't +load its own firmware). + +What I expected to happen is that the GPU would simply use +its maximum memory clock, and indeed this is what seemed +to happen according to amdgpu_pm_info which reads the +current MCLK value from the SMU. +However, some users reported a huge perf regression +and upon a closer look it seems that the GPU seems to +not actually use the highest MCLK value, despite the SMU +reporting that it does. + +Let's not disable MCLK DPM on Bonaire 0x6658 (R7 260X). + +Keep MCLK DPM disabled on R9 M380 in the 2015 iMac +because that still hangs if we enable it. + +Fixes: 9851f29cb06c ("drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit d34acad064ee7d82bd18f5d87592c422d4d323ac) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -106,11 +106,8 @@ int hwmgr_early_init(struct pp_hwmgr *hw + hwmgr->od_enabled = false; + switch (hwmgr->chip_id) { + case CHIP_BONAIRE: +- /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM +- * R7 260X cards with old MC ucode: MCLK DPM is unstable +- */ +- if (adev->pdev->subsystem_vendor == 0x106B || +- adev->pdev->device == 0x6658) { ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM */ ++ if (adev->pdev->subsystem_vendor == 0x106B) { + dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); + adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; + hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; diff --git a/queue-6.18/drm-amdgpu-fix-vfct-bus-number-matching-with-soft-filter.patch b/queue-6.18/drm-amdgpu-fix-vfct-bus-number-matching-with-soft-filter.patch new file mode 100644 index 0000000000..7739535894 --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-vfct-bus-number-matching-with-soft-filter.patch @@ -0,0 +1,95 @@ +From db7e8108809a2245f0a17ba323f027cac0941ffb Mon Sep 17 00:00:00 2001 +From: Mario Limonciello +Date: Wed, 8 Jul 2026 14:35:14 -0500 +Subject: drm/amdgpu: Fix VFCT bus number matching with soft filter + +From: Mario Limonciello + +commit db7e8108809a2245f0a17ba323f027cac0941ffb upstream. + +On systems where PCI bus renumbering occurs (e.g. pci=realloc, +resource conflicts), the runtime bus number may differ from the +BIOS POST bus number recorded in the VFCT table. This causes +amdgpu_acpi_vfct_bios() to fail finding the VBIOS even though +the correct device entry exists. + +Introduce amdgpu_acpi_vfct_match() which treats the bus number +as a soft filter: vendor/device/function identity is the hard +requirement, while exact bus match is the preferred path. When +bus numbers disagree but device identity matches, accept the +VFCT entry and log a dev_notice for diagnostics. + +Reported-by: Oz Tiram +Closes: https://lore.kernel.org/amd-gfx/20260621173211.28443-1-oz@shift-computing.de/ +Reviewed-by: Alex Deucher +Link: https://patch.msgid.link/20260708193518.702584-2-mario.limonciello@amd.com +Signed-off-by: Mario Limonciello +Signed-off-by: Alex Deucher +(cherry picked from commit 11c141672045ffc0187aa604f2c0f597bc334fb2) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 45 +++++++++++++++++++++++++++---- + 1 file changed, 40 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +@@ -355,6 +355,45 @@ static bool amdgpu_read_disabled_bios(st + } + + #ifdef CONFIG_ACPI ++/** ++ * amdgpu_acpi_vfct_match() - Check if a VFCT entry matches the device ++ * @adev: AMDGPU device ++ * @vhdr: VFCT image header to check ++ * ++ * VFCT entries contain the PCI bus number as recorded during BIOS POST. ++ * On systems where the kernel renumbers PCI buses (e.g. pci=realloc or ++ * resource conflicts), the runtime bus number may differ from the POST ++ * value. Match by device identity (vendor + device + function) and use ++ * the bus number as a preference: exact bus match is preferred, but when ++ * the bus numbers disagree we accept the entry if the device identity ++ * matches. ++ * ++ * Returns: 0 on match, -ENODEV on no match ++ */ ++static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev, ++ VFCT_IMAGE_HEADER *vhdr) ++{ ++ /* Vendor and device IDs must always match */ ++ if (vhdr->VendorID != adev->pdev->vendor || ++ vhdr->DeviceID != adev->pdev->device) ++ return -ENODEV; ++ ++ if (vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) || ++ vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn)) ++ return -ENODEV; ++ ++ /* Exact bus number match - preferred */ ++ if (vhdr->PCIBus == adev->pdev->bus->number) ++ return 0; ++ ++ /* Bus mismatch but device identity matches (PCI renumbering case) */ ++ dev_notice(adev->dev, ++ "VFCT bus number mismatch: table %u != runtime %u, matching by device identity (vendor 0x%04x device 0x%04x)\n", ++ vhdr->PCIBus, adev->pdev->bus->number, ++ adev->pdev->vendor, adev->pdev->device); ++ return 0; ++} ++ + static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) + { + struct acpi_table_header *hdr; +@@ -391,11 +430,7 @@ static bool amdgpu_acpi_vfct_bios(struct + } + + if (vhdr->ImageLength && +- vhdr->PCIBus == adev->pdev->bus->number && +- vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) && +- vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) && +- vhdr->VendorID == adev->pdev->vendor && +- vhdr->DeviceID == adev->pdev->device) { ++ !amdgpu_acpi_vfct_match(adev, vhdr)) { + adev->bios = kmemdup(&vbios->VbiosContent, + vhdr->ImageLength, + GFP_KERNEL); diff --git a/queue-6.18/drm-amdgpu-release-vfct-acpi-table-reference.patch b/queue-6.18/drm-amdgpu-release-vfct-acpi-table-reference.patch new file mode 100644 index 0000000000..7064475c42 --- /dev/null +++ b/queue-6.18/drm-amdgpu-release-vfct-acpi-table-reference.patch @@ -0,0 +1,87 @@ +From 65bff26617607c1331283232016c0e89088c5b78 Mon Sep 17 00:00:00 2001 +From: Mario Limonciello +Date: Wed, 8 Jul 2026 14:35:15 -0500 +Subject: drm/amdgpu: Release VFCT ACPI table reference + +From: Mario Limonciello + +commit 65bff26617607c1331283232016c0e89088c5b78 upstream. + +amdgpu_acpi_vfct_bios() fetches the VFCT table with acpi_get_table() +but never releases it. acpi_get_table() takes a reference on the +table (incrementing its validation_count and mapping it on the 0->1 +transition); without a paired acpi_put_table() the mapping is leaked +on every call, whether or not a matching VBIOS image is found. + +Route all exit paths after the table is acquired through a common +acpi_put_table(). The VBIOS image is copied out with kmemdup() before +the table is released, so it remains valid for the caller. + +Reviewed-by: Alex Deucher +Link: https://patch.msgid.link/20260708193518.702584-3-mario.limonciello@amd.com +Signed-off-by: Mario Limonciello +Signed-off-by: Alex Deucher +(cherry picked from commit ca5988682b4cba4cd125a0fa99b2de1239164ae4) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +@@ -361,13 +361,14 @@ static bool amdgpu_acpi_vfct_bios(struct + acpi_size tbl_size; + UEFI_ACPI_VFCT *vfct; + unsigned int offset; ++ bool r = false; + + if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) + return false; + tbl_size = hdr->length; + if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { + dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n"); +- return false; ++ goto out; + } + + vfct = (UEFI_ACPI_VFCT *)hdr; +@@ -380,13 +381,13 @@ static bool amdgpu_acpi_vfct_bios(struct + offset += sizeof(VFCT_IMAGE_HEADER); + if (offset > tbl_size) { + dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n"); +- return false; ++ goto out; + } + + offset += vhdr->ImageLength; + if (offset > tbl_size) { + dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n"); +- return false; ++ goto out; + } + + if (vhdr->ImageLength && +@@ -401,15 +402,19 @@ static bool amdgpu_acpi_vfct_bios(struct + + if (!check_atom_bios(adev, vhdr->ImageLength)) { + amdgpu_bios_release(adev); +- return false; ++ goto out; + } + adev->bios_size = vhdr->ImageLength; +- return true; ++ r = true; ++ goto out; + } + } + + dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n"); +- return false; ++ ++out: ++ acpi_put_table(hdr); ++ return r; + } + #else + static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) diff --git a/queue-6.18/drm-panthor-return-error-on-truncated-firmware.patch b/queue-6.18/drm-panthor-return-error-on-truncated-firmware.patch new file mode 100644 index 0000000000..e3979173f1 --- /dev/null +++ b/queue-6.18/drm-panthor-return-error-on-truncated-firmware.patch @@ -0,0 +1,38 @@ +From 4a2c8cbe9bcba170706fdf08b1c84b6cbcf5b044 Mon Sep 17 00:00:00 2001 +From: Osama Abdelkader +Date: Tue, 14 Jul 2026 18:30:55 +0200 +Subject: drm/panthor: return error on truncated firmware + +From: Osama Abdelkader + +commit 4a2c8cbe9bcba170706fdf08b1c84b6cbcf5b044 upstream. + +panthor_fw_load() detects truncated firmware images, but jumps to the +common cleanup path without setting ret. If no previous error was recorded, +the function can return 0 and treat the invalid firmware as successfully +loaded. + +Set ret to -EINVAL before leaving the truncated-image path. + +Fixes: 2718d91816ee ("drm/panthor: Add the FW logical block") +Cc: stable@vger.kernel.org +Signed-off-by: Osama Abdelkader +Reviewed-by: Liviu Dudau +Reviewed-by: Boris Brezillon +Link: https://patch.msgid.link/20260714163056.22329-1-osama.abdelkader@gmail.com +Signed-off-by: Liviu Dudau +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/panthor/panthor_fw.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/panthor/panthor_fw.c ++++ b/drivers/gpu/drm/panthor/panthor_fw.c +@@ -777,6 +777,7 @@ static int panthor_fw_load(struct pantho + } + + if (hdr.size > iter.size) { ++ ret = -EINVAL; + drm_err(&ptdev->base, "Firmware image is truncated\n"); + goto out; + } diff --git a/queue-6.18/drm-ttm-account-for-null-and-handle-pages-in-ttm_pool_backup.patch b/queue-6.18/drm-ttm-account-for-null-and-handle-pages-in-ttm_pool_backup.patch new file mode 100644 index 0000000000..a6d7225050 --- /dev/null +++ b/queue-6.18/drm-ttm-account-for-null-and-handle-pages-in-ttm_pool_backup.patch @@ -0,0 +1,144 @@ +From 5b7b3b6595ee77d01c7463757baed114786094dd Mon Sep 17 00:00:00 2001 +From: Matthew Brost +Date: Thu, 2 Jul 2026 14:48:15 -0700 +Subject: drm/ttm: Account for NULL and handle pages in ttm_pool_backup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Matthew Brost + +commit 5b7b3b6595ee77d01c7463757baed114786094dd upstream. + +Pages in ttm_pool_backup can be NULL or backup handles +(ttm_backup_page_ptr_is_handle()), neither of which can be passed to +set_pages_array_wb() or freed. Add a dedicated WB pass before the +dma/purge loop that walks allocations using the same i += num_pages +stride, skipping NULL and handle entries, and calls set_pages_array_wb() +once per contiguous run of real pages. Apply the same NULL/handle guard +to the dma/purge loop. + +Fixes the following oops: + +Oops: general protection fault, kernel NULL pointer dereference 0x0: 0000 [#1] SMP NOPTI +RIP: 0010:__cpa_process_fault+0xf8/0x770 +RSP: 0018:ffffc90000a87718 EFLAGS: 00010287 +RAX: 0000000000000000 RBX: ffffc90000a87868 RCX: 0000000000000000 +RDX: 0000000000001000 RSI: 0005088000000000 RDI: ffffffff827c5f34 +RBP: 0005088000000000 R08: ffffc90000a877cb R09: ffffc90000a877d0 +R10: 0000000000000000 R11: 000000000000001b R12: 000ffffffffff000 +R13: ffffc90000a87868 R14: ffffc90000a87868 R15: ffff88815b882ae0 +FS: 0000000000000000(0000) GS:ffff8884ec840000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f930b844000 CR3: 000000000262e003 CR4: 0000000008f70ef0 +PKRU: 55555554 +Call Trace: + + __change_page_attr_set_clr+0x989/0xe90 + ? __purge_vmap_area_lazy+0x6c/0x3a0 + ? _vm_unmap_aliases+0x250/0x2a0 + set_pages_array_wb+0x7f/0x120 + ttm_pool_backup+0x4c9/0x5b0 [ttm] + ? dma_resv_wait_timeout+0x3b/0xf0 + ttm_tt_backup+0x32/0x60 [ttm] + ttm_bo_shrink+0x66/0x110 [ttm] + xe_bo_shrink_purge+0x12b/0x1b0 [xe] + xe_bo_shrink+0xbb/0x270 [xe] + __xe_shrinker_walk+0xf7/0x160 [xe] + xe_shrinker_walk+0x9d/0xc0 [xe] + xe_shrinker_scan+0x11f/0x210 [xe] + do_shrink_slab+0x13b/0x270 + shrink_slab+0xf1/0x400 + shrink_node+0x352/0x8a0 + balance_pgdat+0x32c/0x700 + kswapd+0x205/0x2f0 + ? __pfx_autoremove_wake_function+0x10/0x10 + ? __pfx_kswapd+0x10/0x10 + kthread+0xd1/0x110 + ? __pfx_kthread+0x10/0x10 + ret_from_fork+0x1b1/0x200 + ? __pfx_kthread+0x10/0x10 + ret_from_fork_asm+0x1a/0x30 + + +Cc: Christian Koenig +Cc: Huang Rui +Cc: Matthew Auld +Cc: Matthew Brost +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Thomas Zimmermann +Cc: David Airlie +Cc: Simona Vetter +Cc: Thomas Hellström +Cc: dri-devel@lists.freedesktop.org +Cc: linux-kernel@vger.kernel.org +Cc: stable@vger.kernel.org +Fixes: b63d715b8090 ("drm/ttm/pool, drm/ttm/tt: Provide a helper to shrink pages") +Cc: stable@vger.kernel.org +Assisted-by: GitHub_Copilot:claude-opus-4.8 +Signed-off-by: Matthew Brost +Reviewed-by: Thomas Hellström +Link: https://patch.msgid.link/20260702214815.4009271-1-matthew.brost@intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/ttm/ttm_pool.c | 34 ++++++++++++++++++++++++++++++---- + 1 file changed, 30 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/ttm/ttm_pool.c ++++ b/drivers/gpu/drm/ttm/ttm_pool.c +@@ -981,9 +981,31 @@ long ttm_pool_backup(struct ttm_pool *po + return -EBUSY; + + #ifdef CONFIG_X86 +- /* Anything returned to the system needs to be cached. */ +- if (tt->caching != ttm_cached) +- set_pages_array_wb(tt->pages, tt->num_pages); ++ /* Anything returned to the system needs to be cached. Walk allocations ++ * skipping NULL pages and issue set_pages_array_wb() per contiguous run. ++ */ ++ if (tt->caching != ttm_cached) { ++ pgoff_t run_start = 0, run_count = 0; ++ ++ for (i = 0; i < tt->num_pages; i += num_pages) { ++ page = tt->pages[i]; ++ if (unlikely(!page || ttm_backup_page_ptr_is_handle(page))) { ++ if (run_count) { ++ set_pages_array_wb(&tt->pages[run_start], ++ run_count); ++ run_count = 0; ++ } ++ num_pages = 1; ++ continue; ++ } ++ num_pages = 1UL << ttm_pool_page_order(pool, page); ++ if (!run_count) ++ run_start = i; ++ run_count += num_pages; ++ } ++ if (run_count) ++ set_pages_array_wb(&tt->pages[run_start], run_count); ++ } + #endif + + if (tt->dma_address || flags->purge) { +@@ -991,7 +1013,7 @@ long ttm_pool_backup(struct ttm_pool *po + unsigned int order; + + page = tt->pages[i]; +- if (unlikely(!page)) { ++ if (unlikely(!page || ttm_backup_page_ptr_is_handle(page))) { + num_pages = 1; + continue; + } +@@ -1034,6 +1056,10 @@ long ttm_pool_backup(struct ttm_pool *po + if (unlikely(!page)) + continue; + ++ /* Already-handled entry from a previous attempt. */ ++ if (unlikely(ttm_backup_page_ptr_is_handle(page))) ++ continue; ++ + ttm_pool_split_for_swap(pool, page); + + shandle = ttm_backup_backup_page(backup, page, flags->writeback, i, diff --git a/queue-6.18/series b/queue-6.18/series index 101a64ae40..66902fb5b2 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -381,3 +381,13 @@ drm-i915-mst-limit-dp-mst-esi-service-loop.patch drm-amd-pm-fix-smu14-power-limit-range-calculation.patch drm-gfx10-program-db_ring_control.patch drm-virtio-don-t-detach-gem-from-a-non-created-context.patch +drm-ttm-account-for-null-and-handle-pages-in-ttm_pool_backup.patch +drm-panthor-return-error-on-truncated-firmware.patch +drm-amdgpu-release-vfct-acpi-table-reference.patch +drm-amdgpu-fix-vfct-bus-number-matching-with-soft-filter.patch +drm-amd-pm-ci-don-t-disable-mclk-dpm-on-bonaire-0x6658-r7-260x.patch +drm-amd-display-set-new_stream-to-null-after-release.patch +drm-amd-display-consolidate-dcn-vblank-flip-handling-onto-vupdate_no_lock.patch +drm-amd-display-dce100-skip-non-dp-stream-encoders-for-dp-mst.patch +drm-amd-display-force-pwm-backlight-on-lenovo-legion-5-15arh05.patch +drm-amd-display-fix-backlight-max_brightness-to-match-exported-range.patch