From: Greg Kroah-Hartman Date: Sun, 7 Jun 2026 07:22:52 +0000 (+0200) Subject: 6.18-stable patches X-Git-Tag: v6.12.93~22 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=91cf66045f80ef08e8d12f558726e0fed6e1e520;p=thirdparty%2Fkernel%2Fstable-queue.git 6.18-stable patches 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 --- 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 index 0000000000..4f65ce6fa9 --- /dev/null +++ b/queue-6.18/drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch @@ -0,0 +1,140 @@ +From stable+bounces-260838-greg=kroah.com@vger.kernel.org Sat Jun 6 04:18:53 2026 +From: Sasha Levin +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" , "Michał Grzelak" , "Tvrtko Ursulin" , "Sasha Levin" +Message-ID: <20260606021839.2487627-2-sashal@kernel.org> + +From: Jouni Högander + +[ 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: # v6.13+ +Signed-off-by: Jouni Högander +Reviewed-by: Michał Grzelak +Link: https://patch.msgid.link/20260520104944.239797-2-jouni.hogander@intel.com +(cherry picked from commit 35485ac56d878192a3829a58cb26503125ec7104) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..4f6197fcf8 --- /dev/null +++ b/queue-6.18/mailbox-fix-null-message-support-in-mbox_send_message.patch @@ -0,0 +1,160 @@ +From c58e9456e30c7098cbcd9f04571992be8a2e4e63 Mon Sep 17 00:00:00 2001 +From: Jassi Brar +Date: Fri, 27 Mar 2026 17:00:40 -0500 +Subject: mailbox: Fix NULL message support in mbox_send_message() + +From: Jassi Brar + +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 +Reviewed-by: Douglas Anderson +Signed-off-by: Jassi Brar +Signed-off-by: Joonwon Kang +Signed-off-by: Greg Kroah-Hartman +--- + 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 diff --git a/queue-6.18/series b/queue-6.18/series index dd2be7c583..ef27d78d09 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -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 index 0000000000..c30d639a98 --- /dev/null +++ b/queue-6.18/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch @@ -0,0 +1,112 @@ +From stable+bounces-260779-greg=kroah.com@vger.kernel.org Fri Jun 5 21:33:43 2026 +From: Sasha Levin +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 , Mika Westerberg , Sasha Levin +Message-ID: <20260605193029.2155718-1-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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); + } + + /**