]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 7 Jun 2026 07:22:52 +0000 (09:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 7 Jun 2026 07:22:52 +0000 (09:22 +0200)
added patches:
drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch
mailbox-fix-null-message-support-in-mbox_send_message.patch
thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch

queue-6.18/drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch [new file with mode: 0644]
queue-6.18/mailbox-fix-null-message-support-in-mbox_send_message.patch [new file with mode: 0644]
queue-6.18/series
queue-6.18/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch [new file with mode: 0644]

diff --git a/queue-6.18/drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch b/queue-6.18/drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch
new file mode 100644 (file)
index 0000000..4f65ce6
--- /dev/null
@@ -0,0 +1,140 @@
+From stable+bounces-260838-greg=kroah.com@vger.kernel.org Sat Jun  6 04:18:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 22:18:39 -0400
+Subject: drm/i915/psr: Use DC_OFF wake reference to block DC6 on vblank enable
+To: stable@vger.kernel.org
+Cc: "Jouni Högander" <jouni.hogander@intel.com>, "Michał Grzelak" <michal.grzelak@intel.com>, "Tvrtko Ursulin" <tursulin@ursulin.net>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260606021839.2487627-2-sashal@kernel.org>
+
+From: Jouni Högander <jouni.hogander@intel.com>
+
+[ Upstream commit 3549a9649dc7c5fc586ab12f675279283cdcb2a7 ]
+
+We are observing following warnings:
+
+*ERROR* power well DC_off state mismatch (refcount 0/enabled 1)
+
+gen9_dc_off_power_well_enabled is considering target state DC_STATE_DISABLE
+as DC_OFF power well being enabled. Fix this by using wakeref for the
+purpose.
+
+To achieve this we need to modify notification code as well. Currently it
+is possible that PSR gets notified vblank enable/disable twice on same
+status. This is currently not a problem as it is just triggering call to
+intel_display_power_set_target_dc_state with same target state as a
+parameter. When using wakeref this becomes a problem due to reference
+counting. Fix this storing vbank status on last notification and use that
+to ensure there are no more than one notification with same vblank status.
+
+v2: ensure there is no subsequent notifications with same status
+
+Fixes: aa451abcffb5 ("drm/i915/display: Prevent DC6 while vblank is enabled for Panel Replay")
+Cc: <stable@vger.kernel.org> # v6.13+
+Signed-off-by: Jouni Högander <jouni.hogander@intel.com>
+Reviewed-by: Michał Grzelak <michal.grzelak@intel.com>
+Link: https://patch.msgid.link/20260520104944.239797-2-jouni.hogander@intel.com
+(cherry picked from commit 35485ac56d878192a3829a58cb26503125ec7104)
+Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/display/intel_display_core.h  |    1 
+ drivers/gpu/drm/i915/display/intel_display_irq.c   |    8 +++++--
+ drivers/gpu/drm/i915/display/intel_display_types.h |    2 +
+ drivers/gpu/drm/i915/display/intel_psr.c           |   24 +++++++--------------
+ 4 files changed, 18 insertions(+), 17 deletions(-)
+
+--- a/drivers/gpu/drm/i915/display/intel_display_core.h
++++ b/drivers/gpu/drm/i915/display/intel_display_core.h
+@@ -472,6 +472,7 @@ struct intel_display {
+               u8 vblank_enabled;
+               int vblank_enable_count;
++              bool vblank_status_last_notified;
+               struct work_struct vblank_notify_work;
+--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
++++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
+@@ -1707,8 +1707,12 @@ static void intel_display_vblank_notify_
+       struct intel_display *display =
+               container_of(work, typeof(*display), irq.vblank_notify_work);
+       int vblank_enable_count = READ_ONCE(display->irq.vblank_enable_count);
++      bool vblank_status = !!vblank_enable_count;
+-      intel_psr_notify_vblank_enable_disable(display, vblank_enable_count);
++      if (display->irq.vblank_status_last_notified != vblank_status) {
++              intel_psr_notify_vblank_enable_disable(display, vblank_status);
++              display->irq.vblank_status_last_notified = vblank_status;
++      }
+ }
+ int bdw_enable_vblank(struct drm_crtc *_crtc)
+@@ -1721,10 +1725,10 @@ int bdw_enable_vblank(struct drm_crtc *_
+       if (gen11_dsi_configure_te(crtc, true))
+               return 0;
++      spin_lock_irqsave(&display->irq.lock, irqflags);
+       if (crtc->vblank_psr_notify && display->irq.vblank_enable_count++ == 0)
+               schedule_work(&display->irq.vblank_notify_work);
+-      spin_lock_irqsave(&display->irq.lock, irqflags);
+       bdw_enable_pipe_irq(display, pipe, GEN8_PIPE_VBLANK);
+       spin_unlock_irqrestore(&display->irq.lock, irqflags);
+--- a/drivers/gpu/drm/i915/display/intel_display_types.h
++++ b/drivers/gpu/drm/i915/display/intel_display_types.h
+@@ -1690,6 +1690,8 @@ struct intel_psr {
+       bool pkg_c_latency_used;
+       u8 active_non_psr_pipes;
++
++      struct ref_tracker *vblank_wakeref;
+ };
+ struct intel_dp {
+--- a/drivers/gpu/drm/i915/display/intel_psr.c
++++ b/drivers/gpu/drm/i915/display/intel_psr.c
+@@ -3982,14 +3982,20 @@ void intel_psr_notify_vblank_enable_disa
+                                           bool enable)
+ {
+       struct intel_encoder *encoder;
+-      bool block_dc_states = false;
+       for_each_intel_encoder_with_psr(display->drm, encoder) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+               mutex_lock(&intel_dp->psr.lock);
+-              if (CAN_PANEL_REPLAY(intel_dp))
+-                      block_dc_states = true;
++              if (CAN_PANEL_REPLAY(intel_dp)) {
++                      if (enable)
++                              intel_dp->psr.vblank_wakeref =
++                                      intel_display_power_get(display,
++                                                              POWER_DOMAIN_DC_OFF);
++                      else
++                              intel_display_power_put(display, POWER_DOMAIN_DC_OFF,
++                                                      intel_dp->psr.vblank_wakeref);
++              }
+               if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled &&
+                   intel_dp->psr.pkg_c_latency_used)
+@@ -3997,18 +4003,6 @@ void intel_psr_notify_vblank_enable_disa
+               mutex_unlock(&intel_dp->psr.lock);
+       }
+-
+-      /*
+-       * NOTE: intel_display_power_set_target_dc_state is used
+-       * only by PSR code for DC3CO handling. DC3CO target
+-       * state is currently disabled in * PSR code. If DC3CO
+-       * is taken into use we need take that into account here
+-       * as well.
+-       */
+-      if (block_dc_states)
+-              intel_display_power_set_target_dc_state(display, enable ?
+-                                                      DC_STATE_DISABLE :
+-                                                      DC_STATE_EN_UPTO_DC6);
+ }
+ static void
diff --git a/queue-6.18/mailbox-fix-null-message-support-in-mbox_send_message.patch b/queue-6.18/mailbox-fix-null-message-support-in-mbox_send_message.patch
new file mode 100644 (file)
index 0000000..4f6197f
--- /dev/null
@@ -0,0 +1,160 @@
+From c58e9456e30c7098cbcd9f04571992be8a2e4e63 Mon Sep 17 00:00:00 2001
+From: Jassi Brar <jassisinghbrar@gmail.com>
+Date: Fri, 27 Mar 2026 17:00:40 -0500
+Subject: mailbox: Fix NULL message support in mbox_send_message()
+
+From: Jassi Brar <jassisinghbrar@gmail.com>
+
+commit c58e9456e30c7098cbcd9f04571992be8a2e4e63 upstream.
+
+The active_req field serves double duty as both the "is a TX in
+flight" flag (NULL means idle) and the storage for the in-flight
+message pointer. When a client sends NULL via mbox_send_message(),
+active_req is set to NULL, which the framework misinterprets as
+"no active request". This breaks the TX state machine by:
+
+ - tx_tick() short-circuits on (!mssg), skipping the tx_done
+   callback and the tx_complete completion
+ - txdone_hrtimer() skips the channel entirely since active_req
+   is NULL, so poll-based TX-done detection never fires.
+
+Fix this by introducing a MBOX_NO_MSG sentinel value that means
+"no active request," freeing NULL to be valid message data. The
+sentinel is defined in the subsystem-internal mailbox.h so that
+controller drivers within drivers/mailbox/ can reference it, but
+it is not exposed to clients outside the subsystem.
+
+Fifteen in-tree callers send NULL (doorbell-style IPCs on Qualcomm,
+Tegra, TI, Xilinx, i.MX, SCMI, and PCC platforms). All were
+audited for regression:
+
+ - Most already work around the bug via knows_txdone=true with a
+   manual mbox_client_txdone() call, making the framework's
+   tracking irrelevant. These are unaffected.
+
+ - Poll-based callers (Xilinx zynqmp/r5) are strictly better off:
+   the poll timer now correctly detects NULL-active channels
+   instead of silently skipping them.
+
+ - irq-qcom-mpm.c was a pre-existing bug -- the only Qualcomm
+   caller that omitted the knows_txdone + mbox_client_txdone()
+   pattern. Fixed in a companion commit ("irqchip/qcom-mpm: Fix
+   missing mailbox TX done acknowledgment").
+
+ - No caller sets both a tx_done callback and sends NULL, nor
+   combines tx_block=true with NULL sends, so the newly reachable
+   callback/completion paths are never exercised.
+
+Also update tegra-hsp's flush callback, which directly inspects
+active_req to wait for the channel to drain: the old "!= NULL"
+check becomes "!= MBOX_NO_MSG", otherwise flush spins until
+timeout since the sentinel is non-NULL.
+
+The only tradeoff is that 'MBOX_NO_MSG' can not be used as a message
+by clients.
+
+Reported-by: Joonwon Kang <joonwonkang@google.com>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>
+Signed-off-by: Joonwon Kang <joonwonkang@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mailbox/mailbox.c          |   15 ++++++++-------
+ drivers/mailbox/tegra-hsp.c        |    2 +-
+ include/linux/mailbox_controller.h |    3 +++
+ 3 files changed, 12 insertions(+), 8 deletions(-)
+
+--- a/drivers/mailbox/mailbox.c
++++ b/drivers/mailbox/mailbox.c
+@@ -52,7 +52,7 @@ static void msg_submit(struct mbox_chan
+       int err = -EBUSY;
+       scoped_guard(spinlock_irqsave, &chan->lock) {
+-              if (!chan->msg_count || chan->active_req)
++              if (!chan->msg_count || chan->active_req != MBOX_NO_MSG)
+                       break;
+               count = chan->msg_count;
+@@ -87,13 +87,13 @@ static void tx_tick(struct mbox_chan *ch
+       scoped_guard(spinlock_irqsave, &chan->lock) {
+               mssg = chan->active_req;
+-              chan->active_req = NULL;
++              chan->active_req = MBOX_NO_MSG;
+       }
+       /* Submit next message */
+       msg_submit(chan);
+-      if (!mssg)
++      if (mssg == MBOX_NO_MSG)
+               return;
+       /* Notify the client */
+@@ -114,7 +114,7 @@ static enum hrtimer_restart txdone_hrtim
+       for (i = 0; i < mbox->num_chans; i++) {
+               struct mbox_chan *chan = &mbox->chans[i];
+-              if (chan->active_req && chan->cl) {
++              if (chan->active_req != MBOX_NO_MSG && chan->cl) {
+                       txdone = chan->mbox->ops->last_tx_done(chan);
+                       if (txdone)
+                               tx_tick(chan, 0);
+@@ -246,7 +246,7 @@ int mbox_send_message(struct mbox_chan *
+ {
+       int t;
+-      if (!chan || !chan->cl)
++      if (!chan || !chan->cl || mssg == MBOX_NO_MSG)
+               return -EINVAL;
+       t = add_to_rbuf(chan, mssg);
+@@ -319,7 +319,7 @@ static int __mbox_bind_client(struct mbo
+       scoped_guard(spinlock_irqsave, &chan->lock) {
+               chan->msg_free = 0;
+               chan->msg_count = 0;
+-              chan->active_req = NULL;
++              chan->active_req = MBOX_NO_MSG;
+               chan->cl = cl;
+               init_completion(&chan->tx_complete);
+@@ -477,7 +477,7 @@ void mbox_free_channel(struct mbox_chan
+       /* The queued TX requests are simply aborted, no callbacks are made */
+       scoped_guard(spinlock_irqsave, &chan->lock) {
+               chan->cl = NULL;
+-              chan->active_req = NULL;
++              chan->active_req = MBOX_NO_MSG;
+               if (chan->txdone_method == TXDONE_BY_ACK)
+                       chan->txdone_method = TXDONE_BY_POLL;
+       }
+@@ -531,6 +531,7 @@ int mbox_controller_register(struct mbox
+               chan->cl = NULL;
+               chan->mbox = mbox;
++              chan->active_req = MBOX_NO_MSG;
+               chan->txdone_method = txdone;
+               spin_lock_init(&chan->lock);
+       }
+--- a/drivers/mailbox/tegra-hsp.c
++++ b/drivers/mailbox/tegra-hsp.c
+@@ -497,7 +497,7 @@ static int tegra_hsp_mailbox_flush(struc
+                       mbox_chan_txdone(chan, 0);
+                       /* Wait until channel is empty */
+-                      if (chan->active_req != NULL)
++                      if (chan->active_req != MBOX_NO_MSG)
+                               continue;
+                       return 0;
+--- a/include/linux/mailbox_controller.h
++++ b/include/linux/mailbox_controller.h
+@@ -11,6 +11,9 @@
+ struct mbox_chan;
++/* Sentinel value distinguishing "no active request" from "NULL message data" */
++#define MBOX_NO_MSG   ((void *)-1)
++
+ /**
+  * struct mbox_chan_ops - methods to control mailbox channels
+  * @send_data:        The API asks the MBOX controller driver, in atomic
index dd2be7c583502c34bed0c811bb4a1b77ad05b572..ef27d78d09e680d00e80831d740483d483c203f6 100644 (file)
@@ -310,3 +310,6 @@ hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch
 mm-slub-hold-cpus_read_lock-around-flush_rcu_sheaves_on_cache.patch
 net-phy-micrel-fix-lan8814-qsgmii-soft-reset.patch
 xhci-tegra-fix-ghost-usb-device-on-dual-role-port-un.patch
+mailbox-fix-null-message-support-in-mbox_send_message.patch
+drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch
+thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch
diff --git a/queue-6.18/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch b/queue-6.18/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch
new file mode 100644 (file)
index 0000000..c30d639
--- /dev/null
@@ -0,0 +1,112 @@
+From stable+bounces-260779-greg=kroah.com@vger.kernel.org Fri Jun  5 21:33:43 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 15:30:29 -0400
+Subject: thunderbolt: property: Cap recursion depth in __tb_property_parse_dir()
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Mika Westerberg <mika.westerberg@linux.intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605193029.2155718-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit 928abe19fbf0127003abcb1ea69cabc1c897d0ab ]
+
+A DIRECTORY entry's value field is used as the dir_offset for a
+recursive call into __tb_property_parse_dir() with no depth counter.
+A crafted peer that chains DIRECTORY entries into a back-reference
+loop drives the parser until the kernel stack is exhausted and the
+guard page fires.  Any untrusted XDomain peer (cable, dock, in-line
+inspector, adjacent host) that reaches the PROPERTIES_REQUEST
+control-plane exchange can trigger this without authentication.
+
+Thread a depth counter through tb_property_parse() and
+__tb_property_parse_dir(), and reject blocks that exceed
+TB_PROPERTY_MAX_DEPTH = 8.  That is comfortably larger than any
+observed legitimate XDomain layout.
+
+Operators who do not need XDomain host-to-host discovery can disable
+the path entirely with thunderbolt.xdomain=0 on the kernel command
+line.
+
+Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/property.c |   18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+--- a/drivers/thunderbolt/property.c
++++ b/drivers/thunderbolt/property.c
+@@ -35,10 +35,11 @@ struct tb_property_dir_entry {
+ };
+ #define TB_PROPERTY_ROOTDIR_MAGIC     0x55584401
++#define TB_PROPERTY_MAX_DEPTH         8
+ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
+       size_t block_len, unsigned int dir_offset, size_t dir_len,
+-      bool is_root);
++      bool is_root, unsigned int depth);
+ static inline void parse_dwdata(void *dst, const void *src, size_t dwords)
+ {
+@@ -97,7 +98,8 @@ tb_property_alloc(const char *key, enum
+ }
+ static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,
+-                                      const struct tb_property_entry *entry)
++                                      const struct tb_property_entry *entry,
++                                      unsigned int depth)
+ {
+       char key[TB_PROPERTY_KEY_SIZE + 1];
+       struct tb_property *property;
+@@ -118,7 +120,7 @@ static struct tb_property *tb_property_p
+       switch (property->type) {
+       case TB_PROPERTY_TYPE_DIRECTORY:
+               dir = __tb_property_parse_dir(block, block_len, entry->value,
+-                                            entry->length, false);
++                                            entry->length, false, depth + 1);
+               if (!dir) {
+                       kfree(property);
+                       return NULL;
+@@ -163,13 +165,17 @@ static struct tb_property *tb_property_p
+ }
+ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
+-      size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root)
++      size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root,
++      unsigned int depth)
+ {
+       const struct tb_property_entry *entries;
+       size_t i, content_len, nentries;
+       unsigned int content_offset;
+       struct tb_property_dir *dir;
++      if (depth > TB_PROPERTY_MAX_DEPTH)
++              return NULL;
++
+       dir = kzalloc(sizeof(*dir), GFP_KERNEL);
+       if (!dir)
+               return NULL;
+@@ -200,7 +206,7 @@ static struct tb_property_dir *__tb_prop
+       for (i = 0; i < nentries; i++) {
+               struct tb_property *property;
+-              property = tb_property_parse(block, block_len, &entries[i]);
++              property = tb_property_parse(block, block_len, &entries[i], depth);
+               if (!property) {
+                       tb_property_free_dir(dir);
+                       return NULL;
+@@ -239,7 +245,7 @@ struct tb_property_dir *tb_property_pars
+               return NULL;
+       return __tb_property_parse_dir(block, block_len, 0, rootdir->length,
+-                                     true);
++                                     true, 0);
+ }
+ /**