]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Jul 2026 12:45:23 +0000 (14:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Jul 2026 12:45:23 +0000 (14:45 +0200)
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

queue-6.18/drm-amd-display-consolidate-dcn-vblank-flip-handling-onto-vupdate_no_lock.patch [new file with mode: 0644]
queue-6.18/drm-amd-display-dce100-skip-non-dp-stream-encoders-for-dp-mst.patch [new file with mode: 0644]
queue-6.18/drm-amd-display-fix-backlight-max_brightness-to-match-exported-range.patch [new file with mode: 0644]
queue-6.18/drm-amd-display-force-pwm-backlight-on-lenovo-legion-5-15arh05.patch [new file with mode: 0644]
queue-6.18/drm-amd-display-set-new_stream-to-null-after-release.patch [new file with mode: 0644]
queue-6.18/drm-amd-pm-ci-don-t-disable-mclk-dpm-on-bonaire-0x6658-r7-260x.patch [new file with mode: 0644]
queue-6.18/drm-amdgpu-fix-vfct-bus-number-matching-with-soft-filter.patch [new file with mode: 0644]
queue-6.18/drm-amdgpu-release-vfct-acpi-table-reference.patch [new file with mode: 0644]
queue-6.18/drm-panthor-return-error-on-truncated-firmware.patch [new file with mode: 0644]
queue-6.18/drm-ttm-account-for-null-and-handle-pages-in-ttm_pool_backup.patch [new file with mode: 0644]
queue-6.18/series

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 (file)
index 0000000..b6e627a
--- /dev/null
@@ -0,0 +1,659 @@
+From 8382cd234981ae36299bb66a10bac2cd8ff1b99d Mon Sep 17 00:00:00 2001
+From: Leo Li <sunpeng.li@amd.com>
+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 <sunpeng.li@amd.com>
+
+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 <matthew.schwartz@linux.dev>
+Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
+Tested-by: Mario Limonciello (AMD) <superm1@kernel.org>
+Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
+Signed-off-by: Leo Li <sunpeng.li@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit c87e6635d2db02c88ae8d09529362da672d34770)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..392205d
--- /dev/null
@@ -0,0 +1,62 @@
+From d340cba0df4cf327c7e89c7c1a4e79d4771d7dd5 Mon Sep 17 00:00:00 2001
+From: Andriy Korud <a.korud@gmail.com>
+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 <a.korud@gmail.com>
+
+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 <a.korud@gmail.com>
+Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5162
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 28ec64943e3ee4d9b8d30cea61e380f1429953a8)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e22123e
--- /dev/null
@@ -0,0 +1,55 @@
+From f1b5d8f9cc54ae8a2567ac126867ae488e1bf625 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 29 Jun 2026 15:27:00 -0500
+Subject: drm/amd/display: Fix backlight max_brightness to match exported range
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+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 <alex.hung@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: George Zhang <george.zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit bd9e2b5b0473c75abc0f4134dfe79ecbfb16610d)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..dcc4c56
--- /dev/null
@@ -0,0 +1,97 @@
+From bad177fa75e607e396cd57daaaed881450d7a471 Mon Sep 17 00:00:00 2001
+From: Alessandro Rinaldi <ale@alerinaldi.it>
+Date: Fri, 26 Jun 2026 16:36:00 +0200
+Subject: drm/amd/display: Force PWM backlight on Lenovo Legion 5 15ARH05
+
+From: Alessandro Rinaldi <ale@alerinaldi.it>
+
+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 <ale@alerinaldi.it>
+Tested-by: Alessandro Rinaldi <ale@alerinaldi.it>
+Reviewed-by: George Zhang <george.zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 81b39f43e7e53589491e2eef6bad5389626b4b9c)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..fc01122
--- /dev/null
@@ -0,0 +1,39 @@
+From 9fa26b9eed6195bf840f39ac183b9a6237548755 Mon Sep 17 00:00:00 2001
+From: WenTao Liang <vulab@iscas.ac.cn>
+Date: Sun, 28 Jun 2026 15:27:40 +0800
+Subject: drm/amd/display: set new_stream to NULL after release
+
+From: WenTao Liang <vulab@iscas.ac.cn>
+
+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 <vulab@iscas.ac.cn>
+Reviewed-by: George Zhang <george.zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 99f3af19073b3ddbfd96e789124cce12c4277b28)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..667903a
--- /dev/null
@@ -0,0 +1,63 @@
+From 85371c5ef502d10add72eab38711e191dccea981 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Timur=20Krist=C3=B3f?= <timur.kristof@gmail.com>
+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 <timur.kristof@gmail.com>
+
+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 <timur.kristof@gmail.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit d34acad064ee7d82bd18f5d87592c422d4d323ac)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7739535
--- /dev/null
@@ -0,0 +1,95 @@
+From db7e8108809a2245f0a17ba323f027cac0941ffb Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Wed, 8 Jul 2026 14:35:14 -0500
+Subject: drm/amdgpu: Fix VFCT bus number matching with soft filter
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+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 <oz@shift-computing.de>
+Closes: https://lore.kernel.org/amd-gfx/20260621173211.28443-1-oz@shift-computing.de/
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Link: https://patch.msgid.link/20260708193518.702584-2-mario.limonciello@amd.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 11c141672045ffc0187aa604f2c0f597bc334fb2)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7064475
--- /dev/null
@@ -0,0 +1,87 @@
+From 65bff26617607c1331283232016c0e89088c5b78 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Wed, 8 Jul 2026 14:35:15 -0500
+Subject: drm/amdgpu: Release VFCT ACPI table reference
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+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 <alexander.deucher@amd.com>
+Link: https://patch.msgid.link/20260708193518.702584-3-mario.limonciello@amd.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit ca5988682b4cba4cd125a0fa99b2de1239164ae4)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e397917
--- /dev/null
@@ -0,0 +1,38 @@
+From 4a2c8cbe9bcba170706fdf08b1c84b6cbcf5b044 Mon Sep 17 00:00:00 2001
+From: Osama Abdelkader <osama.abdelkader@gmail.com>
+Date: Tue, 14 Jul 2026 18:30:55 +0200
+Subject: drm/panthor: return error on truncated firmware
+
+From: Osama Abdelkader <osama.abdelkader@gmail.com>
+
+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 <osama.abdelkader@gmail.com>
+Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Link: https://patch.msgid.link/20260714163056.22329-1-osama.abdelkader@gmail.com
+Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a6d7225
--- /dev/null
@@ -0,0 +1,144 @@
+From 5b7b3b6595ee77d01c7463757baed114786094dd Mon Sep 17 00:00:00 2001
+From: Matthew Brost <matthew.brost@intel.com>
+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 <matthew.brost@intel.com>
+
+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:
+ <TASK>
+ __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
+ </TASK>
+
+Cc: Christian Koenig <christian.koenig@amd.com>
+Cc: Huang Rui <ray.huang@amd.com>
+Cc: Matthew Auld <matthew.auld@intel.com>
+Cc: Matthew Brost <matthew.brost@intel.com>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Maxime Ripard <mripard@kernel.org>
+Cc: Thomas Zimmermann <tzimmermann@suse.de>
+Cc: David Airlie <airlied@gmail.com>
+Cc: Simona Vetter <simona@ffwll.ch>
+Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+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 <matthew.brost@intel.com>
+Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Link: https://patch.msgid.link/20260702214815.4009271-1-matthew.brost@intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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,
index 101a64ae40f0a256e7078735a8969e3961252947..66902fb5b225b68a0d630b3186242d0cd61de96a 100644 (file)
@@ -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