From: Sasha Levin Date: Sun, 2 Aug 2026 03:01:41 +0000 (-0400) Subject: drop 22 patches based on RC review feedback X-Git-Tag: v6.6.148~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b51643fffe8090bef86b6c39f87d5c98622f522b;p=thirdparty%2Fkernel%2Fstable-queue.git drop 22 patches based on RC review feedback Dropped patches: - "thunderbolt: Prevent XDomain delayed work use-after-free on disconnect" Upstream: 2c5d2d3c3f70cde2565d7b279b544893a2035842 Queues: 7.1, 6.18, 6.12, 6.6 Reason: the queued backport contains none of the upstream fix -- it is a semantically inert relocation of the unmodified update_xdomain() with no upstream provenance. Upstream is 5 in-place guard hunks in xdomain.c plus 2 in include/linux/thunderbolt.h (xd->removing set under xd->lock in tb_xdomain_remove(), checked at each queue_delayed_work() site); none of that is present, so the use-after-free is not fixed. Requeue candidate: the real upstream commit applies cleanly to all four branches. Report: https://lore.kernel.org/stable/2eae07c3-848e-4bc8-a444-f8274692f653@oracle.com/ - "thunderbolt: Keep XDomain reference during the lifetime of a service" [dependency] Upstream: 8b4060998637f06975fceee9b73845d8672d411e Queues: 7.1, 6.18, 6.12, 6.6 Reason: depends on dropped patch above (Stable-dep-of: 2c5d2d3c3f70) - "thunderbolt: Remove service debugfs entries during unregister" [dependency] Upstream: 4d5fc3f4068568dfcb8cbe2852b4adc56394aa26 Queues: 7.1, 6.18, 6.12, 6.6 Reason: depends on dropped patch above (Stable-dep-of: 2c5d2d3c3f70) - "thunderbolt: Remove XDomain from the bus without holding tb->lock" [dependency] Upstream: a8937f35cf39c39c64325aa84d0463d866850857 Queues: 7.1, 6.18, 6.12, 6.6 Reason: depends on dropped patch above (Stable-dep-of: 2c5d2d3c3f70) - "thunderbolt: Handle lane bonding of Gen 4 XDomain links properly" [dependency] Upstream: 36b6ad6ad0350554e611a8cb754ccd40857416a8 Queues: 6.6 Reason: depends on dropped patch above (Stable-dep-of: 2c5d2d3c3f70) - "thunderbolt: Remove usage of the deprecated ida_simple_xx() API" [dependency] Upstream: dec6a613574cd3dea799170b7aaa8fd76e22f176 Queues: 6.6 Reason: depends on dropped patch above (Stable-dep-of: 2c5d2d3c3f70) - "thunderbolt: Update property.c function documentation" [dependency] Upstream: d015642ad36d78e6eba12d8ab96cea6fd4602b49 Queues: 6.6 Reason: depends on dropped patch above (Stable-dep-of: 2c5d2d3c3f70) - "bpf: Refactor {acquire,release}_reference_state" Upstream: 769b0f1c821455ab29baf42491e1ea1d726451fa Queues: 6.12 Reason: spurious dependency -- the queued patch carries none of 769b0f1c8214's semantics (no acquire_reference(), no release_reference_nomark()) and has zero references to the fix it is supposed to enable. Its diff is actually the first half of 201b62ccc831, which was adapted for 6.12 and split across two output slots while the SHA metadata stayed aligned to the original commit list. Report: https://lore.kernel.org/stable/129ad991-e9fa-4f6b-bc1a-a1d78eff6145@oracle.com/ - "bpf: Refactor check_ctx_access()" [dependency] Upstream: 201b62ccc83153d2925d310a2afe762905e0c455 Queues: 6.12 Reason: carries the second half of the mis-split adaptation above and will not apply without it - "bpf: Reset register bounds before narrowing retval range in check_mem_access()" [dependency] Upstream: 5e0b273e0a62cc04ec338c7b502797c66c2ed42a Queues: 6.12 Reason: the target fix -- has a hard textual dependency on the mis-split refactor above. Will be requeued next cycle with a corrected dependency set. Signed-off-by: Sasha Levin --- diff --git a/queue-6.12/bpf-refactor-acquire-release-_reference_state.patch b/queue-6.12/bpf-refactor-acquire-release-_reference_state.patch deleted file mode 100644 index ea2841921d..0000000000 --- a/queue-6.12/bpf-refactor-acquire-release-_reference_state.patch +++ /dev/null @@ -1,116 +0,0 @@ -From stable+bounces-289595-greg=kroah.com@vger.kernel.org Mon Jul 27 17:52:10 2026 -From: Sasha Levin -Date: Mon, 27 Jul 2026 11:41:01 -0400 -Subject: bpf: Refactor {acquire,release}_reference_state -To: stable@vger.kernel.org -Cc: Kumar Kartikeya Dwivedi , Eduard Zingerman , Alexei Starovoitov , Sasha Levin -Message-ID: <20260727154103.1515347-1-sashal@kernel.org> - -From: Kumar Kartikeya Dwivedi - -[ Upstream commit 769b0f1c821455ab29baf42491e1ea1d726451fa ] - -In preparation for introducing support for more reference types which -have to add and remove reference state, refactor the -acquire_reference_state and release_reference_state functions to share -common logic. - -The acquire_reference_state function simply handles growing the acquired -refs and returning the pointer to the new uninitialized element, which -can be filled in by the caller. - -The release_reference_state function simply erases a reference state -entry in the acquired_refs array and shrinks it. The callers are -responsible for finding the suitable element by matching on various -fields of the reference state and requesting deletion through this -function. It is not supposed to be called directly. - -Existing callers of release_reference_state were using it to find and -remove state for a given ref_obj_id without scrubbing the associated -registers in the verifier state. Introduce release_reference_nomark to -provide this functionality and convert callers. We now use this new -release_reference_nomark function within release_reference as well. -It needs to operate on a verifier state instead of taking verifier env -as mark_ptr_or_null_regs requires operating on verifier state of the -two branches of a NULL condition check, therefore env->cur_state cannot -be used directly. - -Acked-by: Eduard Zingerman -Signed-off-by: Kumar Kartikeya Dwivedi -Link: https://lore.kernel.org/r/20241204030400.208005-3-memxor@gmail.com -Signed-off-by: Alexei Starovoitov -Stable-dep-of: 5e0b273e0a62 ("bpf: Reset register bounds before narrowing retval range in check_mem_access()") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - kernel/bpf/verifier.c | 28 +++++++++++++++------------- - 1 file changed, 15 insertions(+), 13 deletions(-) - ---- a/kernel/bpf/verifier.c -+++ b/kernel/bpf/verifier.c -@@ -7207,11 +7207,12 @@ static int check_mem_access(struct bpf_v - if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem)) - mark_reg_unknown(env, regs, value_regno); - } else if (reg->type == PTR_TO_CTX) { -- bool is_retval = false; -+ struct bpf_insn_access_aux info = { -+ .reg_type = SCALAR_VALUE, -+ .is_ldsx = is_ldsx, -+ .log = &env->log, -+ }; - struct bpf_retval_range range; -- enum bpf_reg_type reg_type = SCALAR_VALUE; -- struct btf *btf = NULL; -- u32 btf_id = 0; - - if (t == BPF_WRITE && value_regno >= 0 && - is_pointer_value(env, value_regno)) { -@@ -7223,8 +7224,9 @@ static int check_mem_access(struct bpf_v - if (err < 0) - return err; - -- err = check_ctx_access(env, insn_idx, off, size, t, ®_type, &btf, -- &btf_id, &is_retval, is_ldsx); -+ err = check_ctx_access(env, insn_idx, off, size, t, &info.reg_type, -+ &info.btf, &info.btf_id, &info.is_retval, -+ info.is_ldsx); - if (err) - verbose_linfo(env, insn_idx, "; "); - if (!err && t == BPF_READ && value_regno >= 0) { -@@ -7232,8 +7234,8 @@ static int check_mem_access(struct bpf_v - * PTR_TO_PACKET[_META,_END]. In the latter - * case, we know the offset is zero. - */ -- if (reg_type == SCALAR_VALUE) { -- if (is_retval && get_func_retval_range(env->prog, &range)) { -+ if (info.reg_type == SCALAR_VALUE) { -+ if (info.is_retval && get_func_retval_range(env->prog, &range)) { - err = __mark_reg_s32_range(env, regs, value_regno, - range.minval, range.maxval); - if (err) -@@ -7244,7 +7246,7 @@ static int check_mem_access(struct bpf_v - } else { - mark_reg_known_zero(env, regs, - value_regno); -- if (type_may_be_null(reg_type)) -+ if (type_may_be_null(info.reg_type)) - regs[value_regno].id = ++env->id_gen; - /* A load of ctx field could have different - * actual load size with the one encoded in the -@@ -7252,12 +7254,12 @@ static int check_mem_access(struct bpf_v - * a sub-register. - */ - regs[value_regno].subreg_def = DEF_NOT_SUBREG; -- if (base_type(reg_type) == PTR_TO_BTF_ID) { -- regs[value_regno].btf = btf; -- regs[value_regno].btf_id = btf_id; -+ if (base_type(info.reg_type) == PTR_TO_BTF_ID) { -+ regs[value_regno].btf = info.btf; -+ regs[value_regno].btf_id = info.btf_id; - } - } -- regs[value_regno].type = reg_type; -+ regs[value_regno].type = info.reg_type; - } - - } else if (reg->type == PTR_TO_STACK) { diff --git a/queue-6.12/bpf-refactor-check_ctx_access.patch b/queue-6.12/bpf-refactor-check_ctx_access.patch deleted file mode 100644 index 8de02f3b86..0000000000 --- a/queue-6.12/bpf-refactor-check_ctx_access.patch +++ /dev/null @@ -1,84 +0,0 @@ -From stable+bounces-289596-greg=kroah.com@vger.kernel.org Mon Jul 27 17:49:26 2026 -From: Sasha Levin -Date: Mon, 27 Jul 2026 11:41:02 -0400 -Subject: bpf: Refactor check_ctx_access() -To: stable@vger.kernel.org -Cc: Amery Hung , Alexei Starovoitov , Sasha Levin -Message-ID: <20260727154103.1515347-2-sashal@kernel.org> - -From: Amery Hung - -[ Upstream commit 201b62ccc83153d2925d310a2afe762905e0c455 ] - -Reduce the variable passing madness surrounding check_ctx_access(). -Currently, check_mem_access() passes many pointers to local variables to -check_ctx_access(). They are used to initialize "struct -bpf_insn_access_aux info" in check_ctx_access() and then passed to -is_valid_access(). Then, check_ctx_access() takes the data our from -info and write them back the pointers to pass them back. This can be -simpilified by moving info up to check_mem_access(). - -No functional change. - -Signed-off-by: Amery Hung -Link: https://lore.kernel.org/r/20250221175644.1822383-1-ameryhung@gmail.com -Signed-off-by: Alexei Starovoitov -Stable-dep-of: 5e0b273e0a62 ("bpf: Reset register bounds before narrowing retval range in check_mem_access()") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - kernel/bpf/verifier.c | 27 +++++---------------------- - 1 file changed, 5 insertions(+), 22 deletions(-) - ---- a/kernel/bpf/verifier.c -+++ b/kernel/bpf/verifier.c -@@ -5829,18 +5829,10 @@ static int check_packet_access(struct bp - - /* check access to 'struct bpf_context' fields. Supports fixed offsets only */ - static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off, int size, -- enum bpf_access_type t, enum bpf_reg_type *reg_type, -- struct btf **btf, u32 *btf_id, bool *is_retval, bool is_ldsx) -+ enum bpf_access_type t, struct bpf_insn_access_aux *info) - { -- struct bpf_insn_access_aux info = { -- .reg_type = *reg_type, -- .log = &env->log, -- .is_retval = false, -- .is_ldsx = is_ldsx, -- }; -- - if (env->ops->is_valid_access && -- env->ops->is_valid_access(off, size, t, env->prog, &info)) { -+ env->ops->is_valid_access(off, size, t, env->prog, info)) { - /* A non zero info.ctx_field_size indicates that this field is a - * candidate for later verifier transformation to load the whole - * field and then apply a mask when accessed with a narrower -@@ -5848,15 +5840,8 @@ static int check_ctx_access(struct bpf_v - * will only allow for whole field access and rejects any other - * type of narrower access. - */ -- *reg_type = info.reg_type; -- *is_retval = info.is_retval; -- -- if (base_type(*reg_type) == PTR_TO_BTF_ID) { -- *btf = info.btf; -- *btf_id = info.btf_id; -- } else { -- env->insn_aux_data[insn_idx].ctx_field_size = info.ctx_field_size; -- } -+ if (base_type(info->reg_type) != PTR_TO_BTF_ID) -+ env->insn_aux_data[insn_idx].ctx_field_size = info->ctx_field_size; - /* remember the offset of last byte accessed in ctx */ - if (env->prog->aux->max_ctx_offset < off + size) - env->prog->aux->max_ctx_offset = off + size; -@@ -7224,9 +7209,7 @@ static int check_mem_access(struct bpf_v - if (err < 0) - return err; - -- err = check_ctx_access(env, insn_idx, off, size, t, &info.reg_type, -- &info.btf, &info.btf_id, &info.is_retval, -- info.is_ldsx); -+ err = check_ctx_access(env, insn_idx, off, size, t, &info); - if (err) - verbose_linfo(env, insn_idx, "; "); - if (!err && t == BPF_READ && value_regno >= 0) { diff --git a/queue-6.12/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch b/queue-6.12/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch deleted file mode 100644 index 519de4ea0d..0000000000 --- a/queue-6.12/bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch +++ /dev/null @@ -1,51 +0,0 @@ -From stable+bounces-289597-greg=kroah.com@vger.kernel.org Mon Jul 27 17:52:29 2026 -From: Sasha Levin -Date: Mon, 27 Jul 2026 11:41:03 -0400 -Subject: bpf: Reset register bounds before narrowing retval range in check_mem_access() -To: stable@vger.kernel.org -Cc: Tristan Madani , Eduard Zingerman , Alexei Starovoitov , Sasha Levin -Message-ID: <20260727154103.1515347-3-sashal@kernel.org> - -From: Tristan Madani - -[ Upstream commit 5e0b273e0a62cc04ec338c7b502797c66c2ed42a ] - -When the BPF verifier processes a context load of an LSM hook return -value, it calls __mark_reg_s32_range() to narrow the register to the -hook's valid range. However, __mark_reg_s32_range() intersects the new -range with the register's existing bounds using max_t()/min_t() rather -than replacing them. - -If the destination register carries stale bounds from a prior instruction -(e.g. BPF_MOV64_IMM), the intersection can produce a range narrower than -reality. The verifier then believes it knows the register's exact value, -while at runtime the actual hook return value is loaded, creating a -verifier/runtime mismatch that can be used to bypass BPF memory safety -checks. - -The else branch already calls mark_reg_unknown() to reset register state -before any narrowing. Apply the same reset in the is_retval path so -stale bounds are cleared before __mark_reg_s32_range() intersects. - -Fixes: 5d99e198be27 ("bpf, lsm: Add check for BPF LSM return value") -Cc: stable@vger.kernel.org -Signed-off-by: Tristan Madani -Acked-by: Eduard Zingerman -Link: https://lore.kernel.org/r/20260622230123.3695446-2-tristmd@gmail.com -Signed-off-by: Alexei Starovoitov -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - kernel/bpf/verifier.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/kernel/bpf/verifier.c -+++ b/kernel/bpf/verifier.c -@@ -7219,6 +7219,7 @@ static int check_mem_access(struct bpf_v - */ - if (info.reg_type == SCALAR_VALUE) { - if (info.is_retval && get_func_retval_range(env->prog, &range)) { -+ mark_reg_unknown(env, regs, value_regno); - err = __mark_reg_s32_range(env, regs, value_regno, - range.minval, range.maxval); - if (err) diff --git a/queue-6.12/series b/queue-6.12/series index 44fc93d108..220373f050 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -520,10 +520,6 @@ mm-mm_init-fix-pageblock-migratetype-for-zone_device-compound-pages.patch mtd-maps-vmu-flash-fix-fault-in-unaligned-fixup.patch mm-prepare-to-move-subsection_map_init-to-mm-sparse-vmemmap.c.patch mm-sparse-vmemmap-fix-dax-vmemmap-accounting-with-optimization.patch -thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch -thunderbolt-remove-service-debugfs-entries-during-unregister.patch -thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch -thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch dma-dw-edma-fix-build-warning-in-dw_edma_pcie_probe.patch dmaengine-dw-edma-fix-confusing-cleanup.h-syntax.patch dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch @@ -536,9 +532,6 @@ tcp-decrement-tcp_md5_needed-static-branch.patch nvmet-introduce-nvmet_req_transfer_len.patch nvmet-auth-reject-short-auth_receive-buffers.patch ovl-use-linked-upper-dentry-in-copy-up-tmpfile.patch -bpf-refactor-acquire-release-_reference_state.patch -bpf-refactor-check_ctx_access.patch -bpf-reset-register-bounds-before-narrowing-retval-range-in-check_mem_access.patch block-add-helper-add_disk_final.patch block-remove-redundant-gd_need_part_scan-in-add_disk_final.patch dm-integrity-fix-leaking-uninitialized-kernel-memory.patch diff --git a/queue-6.12/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch b/queue-6.12/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch deleted file mode 100644 index 2a19366fa9..0000000000 --- a/queue-6.12/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch +++ /dev/null @@ -1,42 +0,0 @@ -From stable+bounces-289260-greg=kroah.com@vger.kernel.org Sun Jul 26 14:36:19 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:36:10 -0400 -Subject: thunderbolt: Keep XDomain reference during the lifetime of a service -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726123613.37376-1-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 8b4060998637f06975fceee9b73845d8672d411e ] - -This is needed because we release the service ID in tb_service_release() -and the ID array is owned by the parent XDomain. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1008,6 +1008,7 @@ static void tb_service_release(struct de - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -+ tb_xdomain_put(xd); - } - - const struct device_type tb_service_type = { -@@ -1116,7 +1117,7 @@ static void enumerate_services(struct tb - svc->id = id; - svc->dev.bus = &tb_bus_type; - svc->dev.type = &tb_service_type; -- svc->dev.parent = &xd->dev; -+ svc->dev.parent = get_device(&xd->dev); - dev_set_name(&svc->dev, "%s.%d", dev_name(&xd->dev), svc->id); - - tb_service_debugfs_init(svc); diff --git a/queue-6.12/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch b/queue-6.12/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch deleted file mode 100644 index b23599bf7b..0000000000 --- a/queue-6.12/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch +++ /dev/null @@ -1,90 +0,0 @@ -From stable+bounces-289263-greg=kroah.com@vger.kernel.org Sun Jul 26 14:36:20 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:36:13 -0400 -Subject: thunderbolt: Prevent XDomain delayed work use-after-free on disconnect -To: stable@vger.kernel.org -Cc: Michael Bommarito , Mika Westerberg , Sasha Levin -Message-ID: <20260726123613.37376-4-sashal@kernel.org> - -From: Michael Bommarito - -[ Upstream commit 2c5d2d3c3f70cde2565d7b279b544893a2035842 ] - -tb_xdp_handle_request() runs on system_wq and queues -xd->state_work via queue_delayed_work() in three request handlers: -PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), -and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues -xd->properties_changed_work when local properties change. - -Concurrently, tb_xdomain_remove() calls stop_handshake() which does -cancel_delayed_work_sync() on both delayed works. Later, -tb_xdomain_unregister() calls device_unregister() which eventually -frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run -tb_xdp_handle_request() in system workqueue") moved the request -handler off tb->wq, the handler and the remove path are no longer -serialized. If queue_delayed_work() executes after -cancel_delayed_work_sync() but before the xdomain is freed, the -delayed work fires on a freed object. - -Add xd->removing that tb_xdomain_remove() sets under xd->lock -before calling stop_handshake(). Each external queue site holds -the same lock and checks removing before calling -queue_delayed_work(). This provides the mutual exclusion needed: -either the queue site acquires the lock first and queues work that -the subsequent cancel will see, or the remove path acquires the -lock first and the queue site observes removing == true and skips -the queue. - -Fixes: 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") -Cc: stable@vger.kernel.org -Assisted-by: Claude:claude-opus-4-7 -Signed-off-by: Michael Bommarito -Signed-off-by: Mika Westerberg -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -905,6 +905,19 @@ void tb_unregister_service_driver(struct - } - EXPORT_SYMBOL_GPL(tb_unregister_service_driver); - -+static int update_xdomain(struct device *dev, void *data) -+{ -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd) { -+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -+ msecs_to_jiffies(50)); -+ } -+ -+ return 0; -+} -+ - static ssize_t key_show(struct device *dev, struct device_attribute *attr, - char *buf) - { -@@ -2480,19 +2493,6 @@ bool tb_xdomain_handle_request(struct tb - return ret > 0; - } - --static int update_xdomain(struct device *dev, void *data) --{ -- struct tb_xdomain *xd; -- -- xd = tb_to_xdomain(dev); -- if (xd) { -- queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -- msecs_to_jiffies(50)); -- } -- -- return 0; --} -- - static void update_all_xdomains(void) - { - bus_for_each_dev(&tb_bus_type, NULL, NULL, update_xdomain); diff --git a/queue-6.12/thunderbolt-remove-service-debugfs-entries-during-unregister.patch b/queue-6.12/thunderbolt-remove-service-debugfs-entries-during-unregister.patch deleted file mode 100644 index 0bce7b9cd6..0000000000 --- a/queue-6.12/thunderbolt-remove-service-debugfs-entries-during-unregister.patch +++ /dev/null @@ -1,76 +0,0 @@ -From stable+bounces-289261-greg=kroah.com@vger.kernel.org Sun Jul 26 14:36:19 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:36:11 -0400 -Subject: thunderbolt: Remove service debugfs entries during unregister -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726123613.37376-2-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 4d5fc3f4068568dfcb8cbe2852b4adc56394aa26 ] - -We add them as part of the register path so to keep it symmetric remove -them as part of the unregister path. This also removes them even if the -service itself is not yet released (but is unregistered), thus allowing -new register with the same service name to happen. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1004,7 +1004,6 @@ static void tb_service_release(struct de - struct tb_service *svc = container_of(dev, struct tb_service, dev); - struct tb_xdomain *xd = tb_service_parent(svc); - -- tb_service_debugfs_remove(svc); - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -@@ -1019,6 +1018,14 @@ const struct device_type tb_service_type - }; - EXPORT_SYMBOL_GPL(tb_service_type); - -+static void __unregister_service(struct device *dev) -+{ -+ struct tb_service *svc = tb_to_service(dev); -+ -+ tb_service_debugfs_remove(svc); -+ device_unregister(&svc->dev); -+} -+ - static int remove_missing_service(struct device *dev, void *data) - { - struct tb_xdomain *xd = data; -@@ -1030,7 +1037,7 @@ static int remove_missing_service(struct - - if (!tb_property_find(xd->remote_properties, svc->key, - TB_PROPERTY_TYPE_DIRECTORY)) -- device_unregister(dev); -+ __unregister_service(dev); - - return 0; - } -@@ -1123,6 +1130,7 @@ static void enumerate_services(struct tb - tb_service_debugfs_init(svc); - - if (device_register(&svc->dev)) { -+ tb_service_debugfs_remove(svc); - put_device(&svc->dev); - break; - } -@@ -2053,7 +2061,7 @@ void tb_xdomain_add(struct tb_xdomain *x - - static int unregister_service(struct device *dev, void *data) - { -- device_unregister(dev); -+ __unregister_service(dev); - return 0; - } - diff --git a/queue-6.12/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch b/queue-6.12/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch deleted file mode 100644 index ead1e29de1..0000000000 --- a/queue-6.12/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch +++ /dev/null @@ -1,337 +0,0 @@ -From stable+bounces-289262-greg=kroah.com@vger.kernel.org Sun Jul 26 14:36:20 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:36:12 -0400 -Subject: thunderbolt: Remove XDomain from the bus without holding tb->lock -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726123613.37376-3-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit a8937f35cf39c39c64325aa84d0463d866850857 ] - -Currently we call device_unregister() for services and the XDomain -itself with tb->lock held. This prevents the service drivers from -calling any functions that may take it. For this reason separate -removing the XDomain from the topology data structures (where we need -the lock) from unregistering the device from the bus (where remove -callbacks of the drivers are being called). - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/debugfs.c | 2 + - drivers/thunderbolt/domain.c | 30 +++++++++++++++++++++ - drivers/thunderbolt/icm.c | 5 +++ - drivers/thunderbolt/switch.c | 14 +++++++++ - drivers/thunderbolt/tb.c | 59 ++++++++++++++++++++---------------------- - drivers/thunderbolt/tb.h | 2 + - drivers/thunderbolt/xdomain.c | 53 +++++++++++++++++++++++-------------- - 7 files changed, 115 insertions(+), 50 deletions(-) - ---- a/drivers/thunderbolt/debugfs.c -+++ b/drivers/thunderbolt/debugfs.c -@@ -1508,6 +1508,8 @@ static void margining_port_remove(struct - - if (!port->usb4) - return; -+ if (!port->usb4->margining) -+ return; - - snprintf(dir_name, sizeof(dir_name), "port%d", port->port); - parent = debugfs_lookup(dir_name, port->sw->debugfs_dir); ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -871,6 +871,36 @@ int tb_domain_disconnect_all_paths(struc - return bus_for_each_dev(&tb_bus_type, NULL, tb, disconnect_xdomain); - } - -+struct unregister_context { -+ const struct tb *tb; -+ int n; -+}; -+ -+static int unregister_unplugged_xdomain(struct device *dev, void *data) -+{ -+ struct unregister_context *ctx = data; -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd && xd->tb == ctx->tb && xd->is_unplugged) { -+ tb_xdomain_unregister(xd); -+ ctx->n++; -+ } -+ return 0; -+} -+ -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb) -+{ -+ struct unregister_context ctx; -+ -+ ctx.tb = tb_domain_get(tb); -+ ctx.n = 0; -+ bus_for_each_dev(&tb_bus_type, NULL, &ctx, unregister_unplugged_xdomain); -+ tb_domain_put(tb); -+ -+ return ctx.n; -+} -+ - int tb_domain_init(void) - { - int ret; ---- a/drivers/thunderbolt/icm.c -+++ b/drivers/thunderbolt/icm.c -@@ -713,6 +713,7 @@ static void remove_xdomain(struct tb_xdo - - sw = tb_to_switch(xd->dev.parent); - tb_port_at(xd->route, sw)->xdomain = NULL; -+ xd->is_unplugged = true; - tb_xdomain_remove(xd); - } - -@@ -1728,6 +1729,8 @@ static void icm_handle_notification(stru - - kfree(n->pkg); - kfree(n); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type, -@@ -2078,6 +2081,8 @@ static void icm_rescan_work(struct work_ - if (tb->root_switch) - icm_free_unplugged_children(tb->root_switch); - mutex_unlock(&tb->lock); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_complete(struct tb *tb) ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -3554,6 +3554,20 @@ int tb_switch_resume(struct tb_switch *s - tb_port_warn(port, - "lost during suspend, disconnecting\n"); - tb_sw_set_unplugged(port->remote->sw); -+ } else if (port->xdomain) { -+ /* -+ * If the user replaced the XDomain with -+ * another router, this will succeed in -+ * which case we must remove the XDomain -+ * before adding the new router. -+ */ -+ err = tb_cfg_get_upstream_port(sw->tb->ctl, -+ port->xdomain->route); -+ if (err > 0) { -+ tb_port_warn(port, -+ "XDomain was disconnected\n"); -+ port->xdomain->is_unplugged = true; -+ } - } - } - } ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -2450,6 +2450,8 @@ put_sw: - out: - mutex_unlock(&tb->lock); - -+ tb_domain_unregister_unplugged_xdomains(tb); -+ - pm_runtime_mark_last_busy(&tb->dev); - pm_runtime_put_autosuspend(&tb->dev); - -@@ -3008,6 +3010,24 @@ static void tb_restore_children(struct t - } - } - -+static void tb_free_unplugged_xdomains(struct tb_switch *sw) -+{ -+ struct tb_port *port; -+ -+ tb_switch_for_each_port(sw, port) { -+ if (tb_is_upstream_port(port)) -+ continue; -+ if (port->xdomain && port->xdomain->is_unplugged) { -+ tb_retimer_remove_all(port); -+ tb_xdomain_remove(port->xdomain); -+ tb_port_unconfigure_xdomain(port); -+ port->xdomain = NULL; -+ } else if (port->remote) { -+ tb_free_unplugged_xdomains(port->remote->sw); -+ } -+ } -+} -+ - static int tb_resume_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -3027,6 +3047,7 @@ static int tb_resume_noirq(struct tb *tb - tb_switch_resume(tb->root_switch, false); - tb_free_invalid_tunnels(tb); - tb_free_unplugged_children(tb->root_switch); -+ tb_free_unplugged_xdomains(tb->root_switch); - tb_restore_children(tb->root_switch); - - /* -@@ -3069,28 +3090,6 @@ static int tb_resume_noirq(struct tb *tb - return 0; - } - --static int tb_free_unplugged_xdomains(struct tb_switch *sw) --{ -- struct tb_port *port; -- int ret = 0; -- -- tb_switch_for_each_port(sw, port) { -- if (tb_is_upstream_port(port)) -- continue; -- if (port->xdomain && port->xdomain->is_unplugged) { -- tb_retimer_remove_all(port); -- tb_xdomain_remove(port->xdomain); -- tb_port_unconfigure_xdomain(port); -- port->xdomain = NULL; -- ret++; -- } else if (port->remote) { -- ret += tb_free_unplugged_xdomains(port->remote->sw); -- } -- } -- -- return ret; --} -- - static int tb_freeze_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -3110,14 +3109,14 @@ static int tb_thaw_noirq(struct tb *tb) - static void tb_complete(struct tb *tb) - { - /* -- * Release any unplugged XDomains and if there is a case where -+ * Unregister unplugged XDomains and if there is a case where - * another domain is swapped in place of unplugged XDomain we - * need to run another rescan. - */ -- mutex_lock(&tb->lock); -- if (tb_free_unplugged_xdomains(tb->root_switch)) -- tb_scan_switch(tb->root_switch); -- mutex_unlock(&tb->lock); -+ if (tb_domain_unregister_unplugged_xdomains(tb)) { -+ scoped_guard(mutex, &tb->lock) -+ tb_scan_switch(tb->root_switch); -+ } - } - - static int tb_runtime_suspend(struct tb *tb) -@@ -3144,11 +3143,11 @@ static void tb_remove_work(struct work_s - struct tb *tb = tcm_to_tb(tcm); - - mutex_lock(&tb->lock); -- if (tb->root_switch) { -+ if (tb->root_switch) - tb_free_unplugged_children(tb->root_switch); -- tb_free_unplugged_xdomains(tb->root_switch); -- } - mutex_unlock(&tb->lock); -+ -+ tb_free_unplugged_xdomains(tb->root_switch); - } - - static int tb_runtime_resume(struct tb *tb) ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -786,6 +786,7 @@ int tb_domain_disconnect_xdomain_paths(s - int transmit_path, int transmit_ring, - int receive_path, int receive_ring); - int tb_domain_disconnect_all_paths(struct tb *tb); -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb); - - static inline struct tb *tb_domain_get(struct tb *tb) - { -@@ -1233,6 +1234,7 @@ struct tb_xdomain *tb_xdomain_alloc(stru - const uuid_t *remote_uuid); - void tb_xdomain_add(struct tb_xdomain *xd); - void tb_xdomain_remove(struct tb_xdomain *xd); -+void tb_xdomain_unregister(struct tb_xdomain *xd); - struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, - u8 depth); - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -2066,41 +2066,54 @@ static int unregister_service(struct dev - } - - /** -- * tb_xdomain_remove() - Remove XDomain from the bus -+ * tb_xdomain_remove() - Remove XDomain - * @xd: XDomain to remove - * -- * This will stop all ongoing configuration work and remove the XDomain -- * along with any services from the bus. When the last reference to @xd -- * is released the object will be released as well. -+ * This will stop all ongoing configuration work. XDomain is not removed -+ * from the bus if it was added. That needs to be done separately by -+ * calling tb_xdomain_unregister(). -+ * -+ * Called with @tb->lock held. - */ - void tb_xdomain_remove(struct tb_xdomain *xd) - { - tb_xdomain_debugfs_remove(xd); -- - stop_handshake(xd); -- -- device_for_each_child_reverse(&xd->dev, xd, unregister_service); -- - tb_xdomain_link_exit(xd); - -- /* -- * Undo runtime PM here explicitly because it is possible that -- * the XDomain was never added to the bus and thus device_del() -- * is not called for it (device_del() would handle this otherwise). -- */ -- pm_runtime_disable(&xd->dev); -- pm_runtime_put_noidle(&xd->dev); -- pm_runtime_set_suspended(&xd->dev); -- - if (!device_is_registered(&xd->dev)) { -+ /* -+ * Undo runtime PM here explicitly because it is -+ * possible that the XDomain was never added to the bus -+ * and thus device_del() is not called for it -+ * (device_del() would handle this otherwise). -+ */ -+ pm_runtime_disable(&xd->dev); -+ pm_runtime_put_noidle(&xd->dev); -+ pm_runtime_set_suspended(&xd->dev); - put_device(&xd->dev); -- } else { -- dev_info(&xd->dev, "host disconnected\n"); -- device_unregister(&xd->dev); - } - } - - /** -+ * tb_xdomain_unregister() - Unregister XDomain -+ * @xd: XDomain to unregister -+ * -+ * This will unregister the XDomain along with any services from the -+ * bus. When the last reference to @xd is released the object will be -+ * released as well. -+ */ -+void tb_xdomain_unregister(struct tb_xdomain *xd) -+{ -+ lockdep_assert_not_held(&xd->tb->lock); -+ -+ device_for_each_child_reverse(&xd->dev, xd, unregister_service); -+ -+ dev_info(&xd->dev, "host disconnected\n"); -+ device_unregister(&xd->dev); -+} -+ -+/** - * tb_xdomain_lane_bonding_enable() - Enable lane bonding on XDomain - * @xd: XDomain connection - * diff --git a/queue-6.18/series b/queue-6.18/series index be7e90b5a3..6eff602582 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -634,10 +634,6 @@ remoteproc-xlnx-check-remote-core-state.patch mm-sparse-vmemmap-fix-vmemmap-accounting-underflow.patch kho-make-sure-scratch-size-is-always-aligned-by-cma_min_alignment_bytes.patch mtd-maps-vmu-flash-fix-fault-in-unaligned-fixup.patch -thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch -thunderbolt-remove-service-debugfs-entries-during-unregister.patch -thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch -thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch dmaengine-dw-edma-fix-confusing-cleanup.h-syntax.patch dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch ovl-use-linked-upper-dentry-in-copy-up-tmpfile.patch diff --git a/queue-6.18/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch b/queue-6.18/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch deleted file mode 100644 index 5ab39f8d21..0000000000 --- a/queue-6.18/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch +++ /dev/null @@ -1,42 +0,0 @@ -From stable+bounces-289230-greg=kroah.com@vger.kernel.org Sun Jul 26 14:00:55 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:00:47 -0400 -Subject: thunderbolt: Keep XDomain reference during the lifetime of a service -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726120050.4138299-1-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 8b4060998637f06975fceee9b73845d8672d411e ] - -This is needed because we release the service ID in tb_service_release() -and the ID array is owned by the parent XDomain. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1012,6 +1012,7 @@ static void tb_service_release(struct de - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -+ tb_xdomain_put(xd); - } - - const struct device_type tb_service_type = { -@@ -1120,7 +1121,7 @@ static void enumerate_services(struct tb - svc->id = id; - svc->dev.bus = &tb_bus_type; - svc->dev.type = &tb_service_type; -- svc->dev.parent = &xd->dev; -+ svc->dev.parent = get_device(&xd->dev); - dev_set_name(&svc->dev, "%s.%d", dev_name(&xd->dev), svc->id); - - tb_service_debugfs_init(svc); diff --git a/queue-6.18/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch b/queue-6.18/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch deleted file mode 100644 index b7f10fbc15..0000000000 --- a/queue-6.18/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch +++ /dev/null @@ -1,90 +0,0 @@ -From stable+bounces-289233-greg=kroah.com@vger.kernel.org Sun Jul 26 14:03:26 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:00:50 -0400 -Subject: thunderbolt: Prevent XDomain delayed work use-after-free on disconnect -To: stable@vger.kernel.org -Cc: Michael Bommarito , Mika Westerberg , Sasha Levin -Message-ID: <20260726120050.4138299-4-sashal@kernel.org> - -From: Michael Bommarito - -[ Upstream commit 2c5d2d3c3f70cde2565d7b279b544893a2035842 ] - -tb_xdp_handle_request() runs on system_wq and queues -xd->state_work via queue_delayed_work() in three request handlers: -PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), -and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues -xd->properties_changed_work when local properties change. - -Concurrently, tb_xdomain_remove() calls stop_handshake() which does -cancel_delayed_work_sync() on both delayed works. Later, -tb_xdomain_unregister() calls device_unregister() which eventually -frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run -tb_xdp_handle_request() in system workqueue") moved the request -handler off tb->wq, the handler and the remove path are no longer -serialized. If queue_delayed_work() executes after -cancel_delayed_work_sync() but before the xdomain is freed, the -delayed work fires on a freed object. - -Add xd->removing that tb_xdomain_remove() sets under xd->lock -before calling stop_handshake(). Each external queue site holds -the same lock and checks removing before calling -queue_delayed_work(). This provides the mutual exclusion needed: -either the queue site acquires the lock first and queues work that -the subsequent cancel will see, or the remove path acquires the -lock first and the queue site observes removing == true and skips -the queue. - -Fixes: 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") -Cc: stable@vger.kernel.org -Assisted-by: Claude:claude-opus-4-7 -Signed-off-by: Michael Bommarito -Signed-off-by: Mika Westerberg -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -909,6 +909,19 @@ void tb_unregister_service_driver(struct - } - EXPORT_SYMBOL_GPL(tb_unregister_service_driver); - -+static int update_xdomain(struct device *dev, void *data) -+{ -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd) { -+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -+ msecs_to_jiffies(50)); -+ } -+ -+ return 0; -+} -+ - static ssize_t key_show(struct device *dev, struct device_attribute *attr, - char *buf) - { -@@ -2500,19 +2513,6 @@ bool tb_xdomain_handle_request(struct tb - return ret > 0; - } - --static int update_xdomain(struct device *dev, void *data) --{ -- struct tb_xdomain *xd; -- -- xd = tb_to_xdomain(dev); -- if (xd) { -- queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -- msecs_to_jiffies(50)); -- } -- -- return 0; --} -- - static void update_all_xdomains(void) - { - bus_for_each_dev(&tb_bus_type, NULL, NULL, update_xdomain); diff --git a/queue-6.18/thunderbolt-remove-service-debugfs-entries-during-unregister.patch b/queue-6.18/thunderbolt-remove-service-debugfs-entries-during-unregister.patch deleted file mode 100644 index 6deb25e221..0000000000 --- a/queue-6.18/thunderbolt-remove-service-debugfs-entries-during-unregister.patch +++ /dev/null @@ -1,76 +0,0 @@ -From stable+bounces-289231-greg=kroah.com@vger.kernel.org Sun Jul 26 14:00:57 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:00:48 -0400 -Subject: thunderbolt: Remove service debugfs entries during unregister -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726120050.4138299-2-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 4d5fc3f4068568dfcb8cbe2852b4adc56394aa26 ] - -We add them as part of the register path so to keep it symmetric remove -them as part of the unregister path. This also removes them even if the -service itself is not yet released (but is unregistered), thus allowing -new register with the same service name to happen. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1008,7 +1008,6 @@ static void tb_service_release(struct de - struct tb_service *svc = container_of(dev, struct tb_service, dev); - struct tb_xdomain *xd = tb_service_parent(svc); - -- tb_service_debugfs_remove(svc); - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -@@ -1023,6 +1022,14 @@ const struct device_type tb_service_type - }; - EXPORT_SYMBOL_GPL(tb_service_type); - -+static void __unregister_service(struct device *dev) -+{ -+ struct tb_service *svc = tb_to_service(dev); -+ -+ tb_service_debugfs_remove(svc); -+ device_unregister(&svc->dev); -+} -+ - static int remove_missing_service(struct device *dev, void *data) - { - struct tb_xdomain *xd = data; -@@ -1034,7 +1041,7 @@ static int remove_missing_service(struct - - if (!tb_property_find(xd->remote_properties, svc->key, - TB_PROPERTY_TYPE_DIRECTORY)) -- device_unregister(dev); -+ __unregister_service(dev); - - return 0; - } -@@ -1127,6 +1134,7 @@ static void enumerate_services(struct tb - tb_service_debugfs_init(svc); - - if (device_register(&svc->dev)) { -+ tb_service_debugfs_remove(svc); - put_device(&svc->dev); - break; - } -@@ -2059,7 +2067,7 @@ void tb_xdomain_add(struct tb_xdomain *x - - static int unregister_service(struct device *dev, void *data) - { -- device_unregister(dev); -+ __unregister_service(dev); - return 0; - } - diff --git a/queue-6.18/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch b/queue-6.18/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch deleted file mode 100644 index f5081f7ff4..0000000000 --- a/queue-6.18/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch +++ /dev/null @@ -1,337 +0,0 @@ -From stable+bounces-289232-greg=kroah.com@vger.kernel.org Sun Jul 26 14:00:59 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 08:00:49 -0400 -Subject: thunderbolt: Remove XDomain from the bus without holding tb->lock -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726120050.4138299-3-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit a8937f35cf39c39c64325aa84d0463d866850857 ] - -Currently we call device_unregister() for services and the XDomain -itself with tb->lock held. This prevents the service drivers from -calling any functions that may take it. For this reason separate -removing the XDomain from the topology data structures (where we need -the lock) from unregistering the device from the bus (where remove -callbacks of the drivers are being called). - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/debugfs.c | 2 + - drivers/thunderbolt/domain.c | 30 +++++++++++++++++++++ - drivers/thunderbolt/icm.c | 5 +++ - drivers/thunderbolt/switch.c | 14 +++++++++ - drivers/thunderbolt/tb.c | 59 ++++++++++++++++++++---------------------- - drivers/thunderbolt/tb.h | 2 + - drivers/thunderbolt/xdomain.c | 53 +++++++++++++++++++++++-------------- - 7 files changed, 115 insertions(+), 50 deletions(-) - ---- a/drivers/thunderbolt/debugfs.c -+++ b/drivers/thunderbolt/debugfs.c -@@ -1786,6 +1786,8 @@ static void margining_port_remove(struct - - if (!port->usb4) - return; -+ if (!port->usb4->margining) -+ return; - - snprintf(dir_name, sizeof(dir_name), "port%d", port->port); - parent = debugfs_lookup(dir_name, port->sw->debugfs_dir); ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -850,6 +850,36 @@ int tb_domain_disconnect_all_paths(struc - return bus_for_each_dev(&tb_bus_type, NULL, tb, disconnect_xdomain); - } - -+struct unregister_context { -+ const struct tb *tb; -+ int n; -+}; -+ -+static int unregister_unplugged_xdomain(struct device *dev, void *data) -+{ -+ struct unregister_context *ctx = data; -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd && xd->tb == ctx->tb && xd->is_unplugged) { -+ tb_xdomain_unregister(xd); -+ ctx->n++; -+ } -+ return 0; -+} -+ -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb) -+{ -+ struct unregister_context ctx; -+ -+ ctx.tb = tb_domain_get(tb); -+ ctx.n = 0; -+ bus_for_each_dev(&tb_bus_type, NULL, &ctx, unregister_unplugged_xdomain); -+ tb_domain_put(tb); -+ -+ return ctx.n; -+} -+ - int tb_domain_init(void) - { - int ret; ---- a/drivers/thunderbolt/icm.c -+++ b/drivers/thunderbolt/icm.c -@@ -738,6 +738,7 @@ static void remove_xdomain(struct tb_xdo - - sw = tb_to_switch(xd->dev.parent); - tb_port_at(xd->route, sw)->xdomain = NULL; -+ xd->is_unplugged = true; - tb_xdomain_remove(xd); - } - -@@ -1762,6 +1763,8 @@ static void icm_handle_notification(stru - - kfree(n->pkg); - kfree(n); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type, -@@ -2112,6 +2115,8 @@ static void icm_rescan_work(struct work_ - if (tb->root_switch) - icm_free_unplugged_children(tb->root_switch); - mutex_unlock(&tb->lock); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_complete(struct tb *tb) ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -3603,6 +3603,20 @@ int tb_switch_resume(struct tb_switch *s - tb_port_warn(port, - "lost during suspend, disconnecting\n"); - tb_sw_set_unplugged(port->remote->sw); -+ } else if (port->xdomain) { -+ /* -+ * If the user replaced the XDomain with -+ * another router, this will succeed in -+ * which case we must remove the XDomain -+ * before adding the new router. -+ */ -+ err = tb_cfg_get_upstream_port(sw->tb->ctl, -+ port->xdomain->route); -+ if (err > 0) { -+ tb_port_warn(port, -+ "XDomain was disconnected\n"); -+ port->xdomain->is_unplugged = true; -+ } - } - } - } ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -2524,6 +2524,8 @@ put_sw: - out: - mutex_unlock(&tb->lock); - -+ tb_domain_unregister_unplugged_xdomains(tb); -+ - pm_runtime_mark_last_busy(&tb->dev); - pm_runtime_put_autosuspend(&tb->dev); - -@@ -3110,6 +3112,24 @@ static void tb_restore_children(struct t - } - } - -+static void tb_free_unplugged_xdomains(struct tb_switch *sw) -+{ -+ struct tb_port *port; -+ -+ tb_switch_for_each_port(sw, port) { -+ if (tb_is_upstream_port(port)) -+ continue; -+ if (port->xdomain && port->xdomain->is_unplugged) { -+ tb_retimer_remove_all(port); -+ tb_xdomain_remove(port->xdomain); -+ tb_port_unconfigure_xdomain(port); -+ port->xdomain = NULL; -+ } else if (port->remote) { -+ tb_free_unplugged_xdomains(port->remote->sw); -+ } -+ } -+} -+ - static int tb_resume_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -3129,6 +3149,7 @@ static int tb_resume_noirq(struct tb *tb - tb_switch_resume(tb->root_switch, false); - tb_free_invalid_tunnels(tb); - tb_free_unplugged_children(tb->root_switch); -+ tb_free_unplugged_xdomains(tb->root_switch); - tb_restore_children(tb->root_switch); - - /* -@@ -3171,28 +3192,6 @@ static int tb_resume_noirq(struct tb *tb - return 0; - } - --static int tb_free_unplugged_xdomains(struct tb_switch *sw) --{ -- struct tb_port *port; -- int ret = 0; -- -- tb_switch_for_each_port(sw, port) { -- if (tb_is_upstream_port(port)) -- continue; -- if (port->xdomain && port->xdomain->is_unplugged) { -- tb_retimer_remove_all(port); -- tb_xdomain_remove(port->xdomain); -- tb_port_unconfigure_xdomain(port); -- port->xdomain = NULL; -- ret++; -- } else if (port->remote) { -- ret += tb_free_unplugged_xdomains(port->remote->sw); -- } -- } -- -- return ret; --} -- - static int tb_freeze_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -3212,14 +3211,14 @@ static int tb_thaw_noirq(struct tb *tb) - static void tb_complete(struct tb *tb) - { - /* -- * Release any unplugged XDomains and if there is a case where -+ * Unregister unplugged XDomains and if there is a case where - * another domain is swapped in place of unplugged XDomain we - * need to run another rescan. - */ -- mutex_lock(&tb->lock); -- if (tb_free_unplugged_xdomains(tb->root_switch)) -- tb_scan_switch(tb->root_switch); -- mutex_unlock(&tb->lock); -+ if (tb_domain_unregister_unplugged_xdomains(tb)) { -+ scoped_guard(mutex, &tb->lock) -+ tb_scan_switch(tb->root_switch); -+ } - } - - static int tb_runtime_suspend(struct tb *tb) -@@ -3246,11 +3245,11 @@ static void tb_remove_work(struct work_s - struct tb *tb = tcm_to_tb(tcm); - - mutex_lock(&tb->lock); -- if (tb->root_switch) { -+ if (tb->root_switch) - tb_free_unplugged_children(tb->root_switch); -- tb_free_unplugged_xdomains(tb->root_switch); -- } - mutex_unlock(&tb->lock); -+ -+ tb_free_unplugged_xdomains(tb->root_switch); - } - - static int tb_runtime_resume(struct tb *tb) ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -792,6 +792,7 @@ int tb_domain_disconnect_xdomain_paths(s - int transmit_path, int transmit_ring, - int receive_path, int receive_ring); - int tb_domain_disconnect_all_paths(struct tb *tb); -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb); - - static inline struct tb *tb_domain_get(struct tb *tb) - { -@@ -1262,6 +1263,7 @@ struct tb_xdomain *tb_xdomain_alloc(stru - const uuid_t *remote_uuid); - void tb_xdomain_add(struct tb_xdomain *xd); - void tb_xdomain_remove(struct tb_xdomain *xd); -+void tb_xdomain_unregister(struct tb_xdomain *xd); - struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, - u8 depth); - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -2072,41 +2072,54 @@ static int unregister_service(struct dev - } - - /** -- * tb_xdomain_remove() - Remove XDomain from the bus -+ * tb_xdomain_remove() - Remove XDomain - * @xd: XDomain to remove - * -- * This will stop all ongoing configuration work and remove the XDomain -- * along with any services from the bus. When the last reference to @xd -- * is released the object will be released as well. -+ * This will stop all ongoing configuration work. XDomain is not removed -+ * from the bus if it was added. That needs to be done separately by -+ * calling tb_xdomain_unregister(). -+ * -+ * Called with @tb->lock held. - */ - void tb_xdomain_remove(struct tb_xdomain *xd) - { - tb_xdomain_debugfs_remove(xd); -- - stop_handshake(xd); -- -- device_for_each_child_reverse(&xd->dev, xd, unregister_service); -- - tb_xdomain_link_exit(xd); - -- /* -- * Undo runtime PM here explicitly because it is possible that -- * the XDomain was never added to the bus and thus device_del() -- * is not called for it (device_del() would handle this otherwise). -- */ -- pm_runtime_disable(&xd->dev); -- pm_runtime_put_noidle(&xd->dev); -- pm_runtime_set_suspended(&xd->dev); -- - if (!device_is_registered(&xd->dev)) { -+ /* -+ * Undo runtime PM here explicitly because it is -+ * possible that the XDomain was never added to the bus -+ * and thus device_del() is not called for it -+ * (device_del() would handle this otherwise). -+ */ -+ pm_runtime_disable(&xd->dev); -+ pm_runtime_put_noidle(&xd->dev); -+ pm_runtime_set_suspended(&xd->dev); - put_device(&xd->dev); -- } else { -- dev_info(&xd->dev, "host disconnected\n"); -- device_unregister(&xd->dev); - } - } - - /** -+ * tb_xdomain_unregister() - Unregister XDomain -+ * @xd: XDomain to unregister -+ * -+ * This will unregister the XDomain along with any services from the -+ * bus. When the last reference to @xd is released the object will be -+ * released as well. -+ */ -+void tb_xdomain_unregister(struct tb_xdomain *xd) -+{ -+ lockdep_assert_not_held(&xd->tb->lock); -+ -+ device_for_each_child_reverse(&xd->dev, xd, unregister_service); -+ -+ dev_info(&xd->dev, "host disconnected\n"); -+ device_unregister(&xd->dev); -+} -+ -+/** - * tb_xdomain_lane_bonding_enable() - Enable lane bonding on XDomain - * @xd: XDomain connection - * diff --git a/queue-6.6/series b/queue-6.6/series index 8d2a43f411..3c605e3471 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -428,13 +428,6 @@ taskstats-retain-dead-thread-stats-in-tgid-queries.patch dma-dw-edma-fix-build-warning-in-dw_edma_pcie_probe.patch dmaengine-dw-edma-fix-confusing-cleanup.h-syntax.patch dmaengine-dw-edma-pcie-reject-devices-without-driver-data.patch -thunderbolt-handle-lane-bonding-of-gen-4-xdomain-links-properly.patch -thunderbolt-remove-usage-of-the-deprecated-ida_simple_xx-api.patch -thunderbolt-update-property.c-function-documentation.patch -thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch -thunderbolt-remove-service-debugfs-entries-during-unregister.patch -thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch -thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch platform-x86-dell-smbios-move-request-functions-for-reuse.patch platform-x86-dell-laptop-fix-missing-cleanups-in-init-error-path.patch i2c-imx-separate-atomic-dma-and-non-dma-use-case.patch diff --git a/queue-6.6/thunderbolt-handle-lane-bonding-of-gen-4-xdomain-links-properly.patch b/queue-6.6/thunderbolt-handle-lane-bonding-of-gen-4-xdomain-links-properly.patch deleted file mode 100644 index 6f77eae0a2..0000000000 --- a/queue-6.6/thunderbolt-handle-lane-bonding-of-gen-4-xdomain-links-properly.patch +++ /dev/null @@ -1,110 +0,0 @@ -From stable+bounces-289294-greg=kroah.com@vger.kernel.org Sun Jul 26 16:01:51 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 09:59:49 -0400 -Subject: thunderbolt: Handle lane bonding of Gen 4 XDomain links properly -To: stable@vger.kernel.org -Cc: Gil Fine , Mika Westerberg , Sasha Levin -Message-ID: <20260726135955.668115-1-sashal@kernel.org> - -From: Gil Fine - -[ Upstream commit 36b6ad6ad0350554e611a8cb754ccd40857416a8 ] - -Gen 4 links come up as bonded already so we are not supposed to initiate -lane bonding on them. However, we should still update the port -structures accordingly. Split these into their own functions to make it -easier to follow. - -Signed-off-by: Gil Fine -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/tb.c | 2 - - drivers/thunderbolt/xdomain.c | 49 +++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 48 insertions(+), 3 deletions(-) - ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -539,8 +539,6 @@ static void tb_port_unconfigure_xdomain( - usb4_port_unconfigure_xdomain(port); - else - tb_lc_unconfigure_xdomain(port); -- -- tb_port_enable(port->dual_link_port); - } - - static void tb_scan_xdomain(struct tb_port *port) ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1903,6 +1903,50 @@ struct device_type tb_xdomain_type = { - }; - EXPORT_SYMBOL_GPL(tb_xdomain_type); - -+static void tb_xdomain_link_init(struct tb_xdomain *xd, struct tb_port *down) -+{ -+ if (!down->dual_link_port) -+ return; -+ -+ /* -+ * Gen 4 links come up already as bonded so only update the port -+ * structures here. -+ */ -+ if (tb_port_get_link_generation(down) >= 4) { -+ down->bonded = true; -+ down->dual_link_port->bonded = true; -+ } else { -+ xd->bonding_possible = true; -+ } -+} -+ -+static void tb_xdomain_link_exit(struct tb_xdomain *xd) -+{ -+ struct tb_port *down = tb_xdomain_downstream_port(xd); -+ -+ if (!down->dual_link_port) -+ return; -+ -+ if (tb_port_get_link_generation(down) >= 4) { -+ down->bonded = false; -+ down->dual_link_port->bonded = false; -+ } else if (xd->link_width > TB_LINK_WIDTH_SINGLE) { -+ /* -+ * Just return port structures back to way they were and -+ * update credits. No need to update userspace because -+ * the XDomain is removed soon anyway. -+ */ -+ tb_port_lane_bonding_disable(down); -+ tb_port_update_credits(down); -+ } else if (down->dual_link_port) { -+ /* -+ * Re-enable the lane 1 adapter we disabled at the end -+ * of tb_xdomain_get_properties(). -+ */ -+ tb_port_enable(down->dual_link_port); -+ } -+} -+ - /** - * tb_xdomain_alloc() - Allocate new XDomain object - * @tb: Domain where the XDomain belongs -@@ -1953,7 +1997,8 @@ struct tb_xdomain *tb_xdomain_alloc(stru - goto err_free_local_uuid; - } else { - xd->needs_uuid = true; -- xd->bonding_possible = !!down->dual_link_port; -+ -+ tb_xdomain_link_init(xd, down); - } - - device_initialize(&xd->dev); -@@ -2022,6 +2067,8 @@ void tb_xdomain_remove(struct tb_xdomain - - device_for_each_child_reverse(&xd->dev, xd, unregister_service); - -+ tb_xdomain_link_exit(xd); -+ - /* - * Undo runtime PM here explicitly because it is possible that - * the XDomain was never added to the bus and thus device_del() diff --git a/queue-6.6/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch b/queue-6.6/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch deleted file mode 100644 index 9171c6bf94..0000000000 --- a/queue-6.6/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch +++ /dev/null @@ -1,42 +0,0 @@ -From stable+bounces-289297-greg=kroah.com@vger.kernel.org Sun Jul 26 16:00:04 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 09:59:52 -0400 -Subject: thunderbolt: Keep XDomain reference during the lifetime of a service -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726135955.668115-4-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 8b4060998637f06975fceee9b73845d8672d411e ] - -This is needed because we release the service ID in tb_service_release() -and the ID array is owned by the parent XDomain. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1008,6 +1008,7 @@ static void tb_service_release(struct de - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -+ tb_xdomain_put(xd); - } - - struct device_type tb_service_type = { -@@ -1116,7 +1117,7 @@ static void enumerate_services(struct tb - svc->id = id; - svc->dev.bus = &tb_bus_type; - svc->dev.type = &tb_service_type; -- svc->dev.parent = &xd->dev; -+ svc->dev.parent = get_device(&xd->dev); - dev_set_name(&svc->dev, "%s.%d", dev_name(&xd->dev), svc->id); - - tb_service_debugfs_init(svc); diff --git a/queue-6.6/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch b/queue-6.6/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch deleted file mode 100644 index 21e9b75cdf..0000000000 --- a/queue-6.6/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch +++ /dev/null @@ -1,90 +0,0 @@ -From stable+bounces-289300-greg=kroah.com@vger.kernel.org Sun Jul 26 16:00:09 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 09:59:55 -0400 -Subject: thunderbolt: Prevent XDomain delayed work use-after-free on disconnect -To: stable@vger.kernel.org -Cc: Michael Bommarito , Mika Westerberg , Sasha Levin -Message-ID: <20260726135955.668115-7-sashal@kernel.org> - -From: Michael Bommarito - -[ Upstream commit 2c5d2d3c3f70cde2565d7b279b544893a2035842 ] - -tb_xdp_handle_request() runs on system_wq and queues -xd->state_work via queue_delayed_work() in three request handlers: -PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), -and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues -xd->properties_changed_work when local properties change. - -Concurrently, tb_xdomain_remove() calls stop_handshake() which does -cancel_delayed_work_sync() on both delayed works. Later, -tb_xdomain_unregister() calls device_unregister() which eventually -frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run -tb_xdp_handle_request() in system workqueue") moved the request -handler off tb->wq, the handler and the remove path are no longer -serialized. If queue_delayed_work() executes after -cancel_delayed_work_sync() but before the xdomain is freed, the -delayed work fires on a freed object. - -Add xd->removing that tb_xdomain_remove() sets under xd->lock -before calling stop_handshake(). Each external queue site holds -the same lock and checks removing before calling -queue_delayed_work(). This provides the mutual exclusion needed: -either the queue site acquires the lock first and queues work that -the subsequent cancel will see, or the remove path acquires the -lock first and the queue site observes removing == true and skips -the queue. - -Fixes: 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") -Cc: stable@vger.kernel.org -Assisted-by: Claude:claude-opus-4-7 -Signed-off-by: Michael Bommarito -Signed-off-by: Mika Westerberg -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -905,6 +905,19 @@ void tb_unregister_service_driver(struct - } - EXPORT_SYMBOL_GPL(tb_unregister_service_driver); - -+static int update_xdomain(struct device *dev, void *data) -+{ -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd) { -+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -+ msecs_to_jiffies(50)); -+ } -+ -+ return 0; -+} -+ - static ssize_t key_show(struct device *dev, struct device_attribute *attr, - char *buf) - { -@@ -2475,19 +2488,6 @@ bool tb_xdomain_handle_request(struct tb - return ret > 0; - } - --static int update_xdomain(struct device *dev, void *data) --{ -- struct tb_xdomain *xd; -- -- xd = tb_to_xdomain(dev); -- if (xd) { -- queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -- msecs_to_jiffies(50)); -- } -- -- return 0; --} -- - static void update_all_xdomains(void) - { - bus_for_each_dev(&tb_bus_type, NULL, NULL, update_xdomain); diff --git a/queue-6.6/thunderbolt-remove-service-debugfs-entries-during-unregister.patch b/queue-6.6/thunderbolt-remove-service-debugfs-entries-during-unregister.patch deleted file mode 100644 index ecf78726bc..0000000000 --- a/queue-6.6/thunderbolt-remove-service-debugfs-entries-during-unregister.patch +++ /dev/null @@ -1,76 +0,0 @@ -From stable+bounces-289298-greg=kroah.com@vger.kernel.org Sun Jul 26 16:00:05 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 09:59:53 -0400 -Subject: thunderbolt: Remove service debugfs entries during unregister -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726135955.668115-5-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 4d5fc3f4068568dfcb8cbe2852b4adc56394aa26 ] - -We add them as part of the register path so to keep it symmetric remove -them as part of the unregister path. This also removes them even if the -service itself is not yet released (but is unregistered), thus allowing -new register with the same service name to happen. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1004,7 +1004,6 @@ static void tb_service_release(struct de - struct tb_service *svc = container_of(dev, struct tb_service, dev); - struct tb_xdomain *xd = tb_service_parent(svc); - -- tb_service_debugfs_remove(svc); - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -@@ -1019,6 +1018,14 @@ struct device_type tb_service_type = { - }; - EXPORT_SYMBOL_GPL(tb_service_type); - -+static void __unregister_service(struct device *dev) -+{ -+ struct tb_service *svc = tb_to_service(dev); -+ -+ tb_service_debugfs_remove(svc); -+ device_unregister(&svc->dev); -+} -+ - static int remove_missing_service(struct device *dev, void *data) - { - struct tb_xdomain *xd = data; -@@ -1030,7 +1037,7 @@ static int remove_missing_service(struct - - if (!tb_property_find(xd->remote_properties, svc->key, - TB_PROPERTY_TYPE_DIRECTORY)) -- device_unregister(dev); -+ __unregister_service(dev); - - return 0; - } -@@ -1123,6 +1130,7 @@ static void enumerate_services(struct tb - tb_service_debugfs_init(svc); - - if (device_register(&svc->dev)) { -+ tb_service_debugfs_remove(svc); - put_device(&svc->dev); - break; - } -@@ -2048,7 +2056,7 @@ void tb_xdomain_add(struct tb_xdomain *x - - static int unregister_service(struct device *dev, void *data) - { -- device_unregister(dev); -+ __unregister_service(dev); - return 0; - } - diff --git a/queue-6.6/thunderbolt-remove-usage-of-the-deprecated-ida_simple_xx-api.patch b/queue-6.6/thunderbolt-remove-usage-of-the-deprecated-ida_simple_xx-api.patch deleted file mode 100644 index bbe56395cd..0000000000 --- a/queue-6.6/thunderbolt-remove-usage-of-the-deprecated-ida_simple_xx-api.patch +++ /dev/null @@ -1,159 +0,0 @@ -From stable+bounces-289295-greg=kroah.com@vger.kernel.org Sun Jul 26 16:02:04 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 09:59:50 -0400 -Subject: thunderbolt: Remove usage of the deprecated ida_simple_xx() API -To: stable@vger.kernel.org -Cc: Christophe JAILLET , Mika Westerberg , Sasha Levin -Message-ID: <20260726135955.668115-2-sashal@kernel.org> - -From: Christophe JAILLET - -[ Upstream commit dec6a613574cd3dea799170b7aaa8fd76e22f176 ] - -ida_alloc() and ida_free() should be preferred to the deprecated -ida_simple_get() and ida_simple_remove(). - -Note that the upper limit of ida_simple_get() is exclusive, but the one of -ida_alloc_range()/ida_alloc_max() is inclusive. So a -1 has been added -when needed. - -Signed-off-by: Christophe JAILLET -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/domain.c | 6 +++--- - drivers/thunderbolt/nhi.c | 6 +++--- - drivers/thunderbolt/nvm.c | 4 ++-- - drivers/thunderbolt/switch.c | 6 +++--- - drivers/thunderbolt/xdomain.c | 4 ++-- - 5 files changed, 13 insertions(+), 13 deletions(-) - ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -321,7 +321,7 @@ static void tb_domain_release(struct dev - - tb_ctl_free(tb->ctl); - destroy_workqueue(tb->wq); -- ida_simple_remove(&tb_domain_ida, tb->index); -+ ida_free(&tb_domain_ida, tb->index); - mutex_destroy(&tb->lock); - kfree(tb); - } -@@ -389,7 +389,7 @@ struct tb *tb_domain_alloc(struct tb_nhi - tb->nhi = nhi; - mutex_init(&tb->lock); - -- tb->index = ida_simple_get(&tb_domain_ida, 0, 0, GFP_KERNEL); -+ tb->index = ida_alloc(&tb_domain_ida, GFP_KERNEL); - if (tb->index < 0) - goto err_free; - -@@ -413,7 +413,7 @@ struct tb *tb_domain_alloc(struct tb_nhi - err_destroy_wq: - destroy_workqueue(tb->wq); - err_remove_ida: -- ida_simple_remove(&tb_domain_ida, tb->index); -+ ida_free(&tb_domain_ida, tb->index); - err_free: - kfree(tb); - ---- a/drivers/thunderbolt/nhi.c -+++ b/drivers/thunderbolt/nhi.c -@@ -465,7 +465,7 @@ static int ring_request_msix(struct tb_r - if (!nhi->pdev->msix_enabled) - return 0; - -- ret = ida_simple_get(&nhi->msix_ida, 0, MSIX_MAX_VECS, GFP_KERNEL); -+ ret = ida_alloc_max(&nhi->msix_ida, MSIX_MAX_VECS - 1, GFP_KERNEL); - if (ret < 0) - return ret; - -@@ -485,7 +485,7 @@ static int ring_request_msix(struct tb_r - return 0; - - err_ida_remove: -- ida_simple_remove(&nhi->msix_ida, ring->vector); -+ ida_free(&nhi->msix_ida, ring->vector); - - return ret; - } -@@ -496,7 +496,7 @@ static void ring_release_msix(struct tb_ - return; - - free_irq(ring->irq, ring); -- ida_simple_remove(&ring->nhi->msix_ida, ring->vector); -+ ida_free(&ring->nhi->msix_ida, ring->vector); - ring->vector = 0; - ring->irq = 0; - } ---- a/drivers/thunderbolt/nvm.c -+++ b/drivers/thunderbolt/nvm.c -@@ -330,7 +330,7 @@ struct tb_nvm *tb_nvm_alloc(struct devic - if (!nvm) - return ERR_PTR(-ENOMEM); - -- ret = ida_simple_get(&nvm_ida, 0, 0, GFP_KERNEL); -+ ret = ida_alloc(&nvm_ida, GFP_KERNEL); - if (ret < 0) { - kfree(nvm); - return ERR_PTR(ret); -@@ -528,7 +528,7 @@ void tb_nvm_free(struct tb_nvm *nvm) - nvmem_unregister(nvm->non_active); - nvmem_unregister(nvm->active); - vfree(nvm->buf); -- ida_simple_remove(&nvm_ida, nvm->id); -+ ida_free(&nvm_ida, nvm->id); - } - kfree(nvm); - } ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -777,7 +777,7 @@ static int tb_port_alloc_hopid(struct tb - if (max_hopid < 0 || max_hopid > port_max_hopid) - max_hopid = port_max_hopid; - -- return ida_simple_get(ida, min_hopid, max_hopid + 1, GFP_KERNEL); -+ return ida_alloc_range(ida, min_hopid, max_hopid, GFP_KERNEL); - } - - /** -@@ -815,7 +815,7 @@ int tb_port_alloc_out_hopid(struct tb_po - */ - void tb_port_release_in_hopid(struct tb_port *port, int hopid) - { -- ida_simple_remove(&port->in_hopids, hopid); -+ ida_free(&port->in_hopids, hopid); - } - - /** -@@ -825,7 +825,7 @@ void tb_port_release_in_hopid(struct tb_ - */ - void tb_port_release_out_hopid(struct tb_port *port, int hopid) - { -- ida_simple_remove(&port->out_hopids, hopid); -+ ida_free(&port->out_hopids, hopid); - } - - static inline bool tb_switch_is_reachable(const struct tb_switch *parent, ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1005,7 +1005,7 @@ static void tb_service_release(struct de - struct tb_xdomain *xd = tb_service_parent(svc); - - tb_service_debugfs_remove(svc); -- ida_simple_remove(&xd->service_ids, svc->id); -+ ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); - } -@@ -1107,7 +1107,7 @@ static void enumerate_services(struct tb - break; - } - -- id = ida_simple_get(&xd->service_ids, 0, 0, GFP_KERNEL); -+ id = ida_alloc(&xd->service_ids, GFP_KERNEL); - if (id < 0) { - kfree(svc->key); - kfree(svc); diff --git a/queue-6.6/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch b/queue-6.6/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch deleted file mode 100644 index f41c1de7ae..0000000000 --- a/queue-6.6/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch +++ /dev/null @@ -1,337 +0,0 @@ -From stable+bounces-289299-greg=kroah.com@vger.kernel.org Sun Jul 26 16:00:09 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 09:59:54 -0400 -Subject: thunderbolt: Remove XDomain from the bus without holding tb->lock -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260726135955.668115-6-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit a8937f35cf39c39c64325aa84d0463d866850857 ] - -Currently we call device_unregister() for services and the XDomain -itself with tb->lock held. This prevents the service drivers from -calling any functions that may take it. For this reason separate -removing the XDomain from the topology data structures (where we need -the lock) from unregistering the device from the bus (where remove -callbacks of the drivers are being called). - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/debugfs.c | 2 + - drivers/thunderbolt/domain.c | 30 +++++++++++++++++++++ - drivers/thunderbolt/icm.c | 5 +++ - drivers/thunderbolt/switch.c | 14 +++++++++ - drivers/thunderbolt/tb.c | 59 ++++++++++++++++++++---------------------- - drivers/thunderbolt/tb.h | 2 + - drivers/thunderbolt/xdomain.c | 53 +++++++++++++++++++++++-------------- - 7 files changed, 115 insertions(+), 50 deletions(-) - ---- a/drivers/thunderbolt/debugfs.c -+++ b/drivers/thunderbolt/debugfs.c -@@ -956,6 +956,8 @@ static void margining_port_remove(struct - - if (!port->usb4) - return; -+ if (!port->usb4->margining) -+ return; - - snprintf(dir_name, sizeof(dir_name), "port%d", port->port); - parent = debugfs_lookup(dir_name, port->sw->debugfs_dir); ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -867,6 +867,36 @@ int tb_domain_disconnect_all_paths(struc - return bus_for_each_dev(&tb_bus_type, NULL, tb, disconnect_xdomain); - } - -+struct unregister_context { -+ const struct tb *tb; -+ int n; -+}; -+ -+static int unregister_unplugged_xdomain(struct device *dev, void *data) -+{ -+ struct unregister_context *ctx = data; -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd && xd->tb == ctx->tb && xd->is_unplugged) { -+ tb_xdomain_unregister(xd); -+ ctx->n++; -+ } -+ return 0; -+} -+ -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb) -+{ -+ struct unregister_context ctx; -+ -+ ctx.tb = tb_domain_get(tb); -+ ctx.n = 0; -+ bus_for_each_dev(&tb_bus_type, NULL, &ctx, unregister_unplugged_xdomain); -+ tb_domain_put(tb); -+ -+ return ctx.n; -+} -+ - int tb_domain_init(void) - { - int ret; ---- a/drivers/thunderbolt/icm.c -+++ b/drivers/thunderbolt/icm.c -@@ -713,6 +713,7 @@ static void remove_xdomain(struct tb_xdo - - sw = tb_to_switch(xd->dev.parent); - tb_port_at(xd->route, sw)->xdomain = NULL; -+ xd->is_unplugged = true; - tb_xdomain_remove(xd); - } - -@@ -1728,6 +1729,8 @@ static void icm_handle_notification(stru - - kfree(n->pkg); - kfree(n); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type, -@@ -2078,6 +2081,8 @@ static void icm_rescan_work(struct work_ - if (tb->root_switch) - icm_free_unplugged_children(tb->root_switch); - mutex_unlock(&tb->lock); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_complete(struct tb *tb) ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -3556,6 +3556,20 @@ int tb_switch_resume(struct tb_switch *s - tb_port_warn(port, - "lost during suspend, disconnecting\n"); - tb_sw_set_unplugged(port->remote->sw); -+ } else if (port->xdomain) { -+ /* -+ * If the user replaced the XDomain with -+ * another router, this will succeed in -+ * which case we must remove the XDomain -+ * before adding the new router. -+ */ -+ err = tb_cfg_get_upstream_port(sw->tb->ctl, -+ port->xdomain->route); -+ if (err > 0) { -+ tb_port_warn(port, -+ "XDomain was disconnected\n"); -+ port->xdomain->is_unplugged = true; -+ } - } - } - } ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -2319,6 +2319,8 @@ put_sw: - out: - mutex_unlock(&tb->lock); - -+ tb_domain_unregister_unplugged_xdomains(tb); -+ - pm_runtime_mark_last_busy(&tb->dev); - pm_runtime_put_autosuspend(&tb->dev); - -@@ -2787,6 +2789,24 @@ static void tb_restore_children(struct t - } - } - -+static void tb_free_unplugged_xdomains(struct tb_switch *sw) -+{ -+ struct tb_port *port; -+ -+ tb_switch_for_each_port(sw, port) { -+ if (tb_is_upstream_port(port)) -+ continue; -+ if (port->xdomain && port->xdomain->is_unplugged) { -+ tb_retimer_remove_all(port); -+ tb_xdomain_remove(port->xdomain); -+ tb_port_unconfigure_xdomain(port); -+ port->xdomain = NULL; -+ } else if (port->remote) { -+ tb_free_unplugged_xdomains(port->remote->sw); -+ } -+ } -+} -+ - static int tb_resume_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -2806,6 +2826,7 @@ static int tb_resume_noirq(struct tb *tb - tb_switch_resume(tb->root_switch, false); - tb_free_invalid_tunnels(tb); - tb_free_unplugged_children(tb->root_switch); -+ tb_free_unplugged_xdomains(tb->root_switch); - tb_restore_children(tb->root_switch); - - /* -@@ -2848,28 +2869,6 @@ static int tb_resume_noirq(struct tb *tb - return 0; - } - --static int tb_free_unplugged_xdomains(struct tb_switch *sw) --{ -- struct tb_port *port; -- int ret = 0; -- -- tb_switch_for_each_port(sw, port) { -- if (tb_is_upstream_port(port)) -- continue; -- if (port->xdomain && port->xdomain->is_unplugged) { -- tb_retimer_remove_all(port); -- tb_xdomain_remove(port->xdomain); -- tb_port_unconfigure_xdomain(port); -- port->xdomain = NULL; -- ret++; -- } else if (port->remote) { -- ret += tb_free_unplugged_xdomains(port->remote->sw); -- } -- } -- -- return ret; --} -- - static int tb_freeze_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -2889,14 +2888,14 @@ static int tb_thaw_noirq(struct tb *tb) - static void tb_complete(struct tb *tb) - { - /* -- * Release any unplugged XDomains and if there is a case where -+ * Unregister unplugged XDomains and if there is a case where - * another domain is swapped in place of unplugged XDomain we - * need to run another rescan. - */ -- mutex_lock(&tb->lock); -- if (tb_free_unplugged_xdomains(tb->root_switch)) -- tb_scan_switch(tb->root_switch); -- mutex_unlock(&tb->lock); -+ if (tb_domain_unregister_unplugged_xdomains(tb)) { -+ scoped_guard(mutex, &tb->lock) -+ tb_scan_switch(tb->root_switch); -+ } - } - - static int tb_runtime_suspend(struct tb *tb) -@@ -2923,11 +2922,11 @@ static void tb_remove_work(struct work_s - struct tb *tb = tcm_to_tb(tcm); - - mutex_lock(&tb->lock); -- if (tb->root_switch) { -+ if (tb->root_switch) - tb_free_unplugged_children(tb->root_switch); -- tb_free_unplugged_xdomains(tb->root_switch); -- } - mutex_unlock(&tb->lock); -+ -+ tb_free_unplugged_xdomains(tb->root_switch); - } - - static int tb_runtime_resume(struct tb *tb) ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -752,6 +752,7 @@ int tb_domain_disconnect_xdomain_paths(s - int transmit_path, int transmit_ring, - int receive_path, int receive_ring); - int tb_domain_disconnect_all_paths(struct tb *tb); -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb); - - static inline struct tb *tb_domain_get(struct tb *tb) - { -@@ -1200,6 +1201,7 @@ struct tb_xdomain *tb_xdomain_alloc(stru - const uuid_t *remote_uuid); - void tb_xdomain_add(struct tb_xdomain *xd); - void tb_xdomain_remove(struct tb_xdomain *xd); -+void tb_xdomain_unregister(struct tb_xdomain *xd); - struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, - u8 depth); - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -2061,41 +2061,54 @@ static int unregister_service(struct dev - } - - /** -- * tb_xdomain_remove() - Remove XDomain from the bus -+ * tb_xdomain_remove() - Remove XDomain - * @xd: XDomain to remove - * -- * This will stop all ongoing configuration work and remove the XDomain -- * along with any services from the bus. When the last reference to @xd -- * is released the object will be released as well. -+ * This will stop all ongoing configuration work. XDomain is not removed -+ * from the bus if it was added. That needs to be done separately by -+ * calling tb_xdomain_unregister(). -+ * -+ * Called with @tb->lock held. - */ - void tb_xdomain_remove(struct tb_xdomain *xd) - { - tb_xdomain_debugfs_remove(xd); -- - stop_handshake(xd); -- -- device_for_each_child_reverse(&xd->dev, xd, unregister_service); -- - tb_xdomain_link_exit(xd); - -- /* -- * Undo runtime PM here explicitly because it is possible that -- * the XDomain was never added to the bus and thus device_del() -- * is not called for it (device_del() would handle this otherwise). -- */ -- pm_runtime_disable(&xd->dev); -- pm_runtime_put_noidle(&xd->dev); -- pm_runtime_set_suspended(&xd->dev); -- - if (!device_is_registered(&xd->dev)) { -+ /* -+ * Undo runtime PM here explicitly because it is -+ * possible that the XDomain was never added to the bus -+ * and thus device_del() is not called for it -+ * (device_del() would handle this otherwise). -+ */ -+ pm_runtime_disable(&xd->dev); -+ pm_runtime_put_noidle(&xd->dev); -+ pm_runtime_set_suspended(&xd->dev); - put_device(&xd->dev); -- } else { -- dev_info(&xd->dev, "host disconnected\n"); -- device_unregister(&xd->dev); - } - } - - /** -+ * tb_xdomain_unregister() - Unregister XDomain -+ * @xd: XDomain to unregister -+ * -+ * This will unregister the XDomain along with any services from the -+ * bus. When the last reference to @xd is released the object will be -+ * released as well. -+ */ -+void tb_xdomain_unregister(struct tb_xdomain *xd) -+{ -+ lockdep_assert_not_held(&xd->tb->lock); -+ -+ device_for_each_child_reverse(&xd->dev, xd, unregister_service); -+ -+ dev_info(&xd->dev, "host disconnected\n"); -+ device_unregister(&xd->dev); -+} -+ -+/** - * tb_xdomain_lane_bonding_enable() - Enable lane bonding on XDomain - * @xd: XDomain connection - * diff --git a/queue-6.6/thunderbolt-update-property.c-function-documentation.patch b/queue-6.6/thunderbolt-update-property.c-function-documentation.patch deleted file mode 100644 index f01daf2095..0000000000 --- a/queue-6.6/thunderbolt-update-property.c-function-documentation.patch +++ /dev/null @@ -1,137 +0,0 @@ -From stable+bounces-289296-greg=kroah.com@vger.kernel.org Sun Jul 26 16:00:04 2026 -From: Sasha Levin -Date: Sun, 26 Jul 2026 09:59:51 -0400 -Subject: thunderbolt: Update property.c function documentation -To: stable@vger.kernel.org -Cc: Alan Borzeszkowski , Mika Westerberg , Sasha Levin -Message-ID: <20260726135955.668115-3-sashal@kernel.org> - -From: Alan Borzeszkowski - -[ Upstream commit d015642ad36d78e6eba12d8ab96cea6fd4602b49 ] - -Make property.c function documentation compliant with current kernel-doc -standards. No functional changes. - -Signed-off-by: Alan Borzeszkowski -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/property.c | 38 ++++++++++++++++++++++++++++---------- - 1 file changed, 28 insertions(+), 10 deletions(-) - ---- a/drivers/thunderbolt/property.c -+++ b/drivers/thunderbolt/property.c -@@ -231,11 +231,13 @@ static struct tb_property_dir *__tb_prop - * - * This function parses the XDomain properties data block into format that - * can be traversed using the helper functions provided by this module. -- * Upon success returns the parsed directory. In case of error returns -- * %NULL. The resulting &struct tb_property_dir needs to be released by -+ * -+ * The resulting &struct tb_property_dir needs to be released by - * calling tb_property_free_dir() when not needed anymore. - * - * The @block is expected to be root directory. -+ * -+ * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. - */ - struct tb_property_dir *tb_property_parse_dir(const u32 *block, - size_t block_len) -@@ -258,6 +260,8 @@ struct tb_property_dir *tb_property_pars - * - * Creates new, empty property directory. If @uuid is %NULL then the - * directory is assumed to be root directory. -+ * -+ * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. - */ - struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid) - { -@@ -501,9 +505,11 @@ static ssize_t __tb_property_format_dir( - * @block_len: Length of the property block - * - * This function formats the directory to the packed format that can be -- * then send over the thunderbolt fabric to receiving host. Returns %0 in -- * case of success and negative errno on faulure. Passing %NULL in @block -- * returns number of entries the block takes. -+ * then sent over the thunderbolt fabric to receiving host. -+ * -+ * Passing %NULL in @block returns number of entries the block takes. -+ * -+ * Return: %0 on success, negative errno otherwise. - */ - ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, - size_t block_len) -@@ -525,9 +531,9 @@ ssize_t tb_property_format_dir(const str - * tb_property_copy_dir() - Take a deep copy of directory - * @dir: Directory to copy - * -- * This function takes a deep copy of @dir and returns back the copy. In -- * case of error returns %NULL. The resulting directory needs to be -- * released by calling tb_property_free_dir(). -+ * The resulting directory needs to be released by calling tb_property_free_dir(). -+ * -+ * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. - */ - struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir) - { -@@ -597,6 +603,8 @@ err_free: - * @parent: Directory to add the property - * @key: Key for the property - * @value: Immediate value to store with the property -+ * -+ * Return: %0 on success, negative errno otherwise. - */ - int tb_property_add_immediate(struct tb_property_dir *parent, const char *key, - u32 value) -@@ -626,6 +634,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_immedi - * @buflen: Number of bytes in the data buffer - * - * Function takes a copy of @buf and adds it to the directory. -+ * -+ * Return: %0 on success, negative errno otherwise. - */ - int tb_property_add_data(struct tb_property_dir *parent, const char *key, - const void *buf, size_t buflen) -@@ -662,6 +672,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_data); - * @text: String to add - * - * Function takes a copy of @text and adds it to the directory. -+ * -+ * Return: %0 on success, negative errno otherwise. - */ - int tb_property_add_text(struct tb_property_dir *parent, const char *key, - const char *text) -@@ -696,6 +708,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_text); - * @parent: Directory to add the property - * @key: Key for the property - * @dir: Directory to add -+ * -+ * Return: %0 on success, negative errno otherwise. - */ - int tb_property_add_dir(struct tb_property_dir *parent, const char *key, - struct tb_property_dir *dir) -@@ -736,8 +750,10 @@ EXPORT_SYMBOL_GPL(tb_property_remove); - * @key: Key to look for - * @type: Type of the property - * -- * Finds and returns property from the given directory. Does not recurse -- * into sub-directories. Returns %NULL if the property was not found. -+ * Finds and returns property from the given directory. Does not -+ * recurse into sub-directories. -+ * -+ * Return: Pointer to &struct tb_property, %NULL if the property was not found. - */ - struct tb_property *tb_property_find(struct tb_property_dir *dir, - const char *key, enum tb_property_type type) -@@ -757,6 +773,8 @@ EXPORT_SYMBOL_GPL(tb_property_find); - * tb_property_get_next() - Get next property from directory - * @dir: Directory holding properties - * @prev: Previous property in the directory (%NULL returns the first) -+ * -+ * Return: Pointer to &struct tb_property, %NULL if property was not found. - */ - struct tb_property *tb_property_get_next(struct tb_property_dir *dir, - struct tb_property *prev) diff --git a/queue-7.1/series b/queue-7.1/series index d04f2dd00f..116a1d1ce5 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -729,10 +729,6 @@ sunrpc-add-helpers-to-convert-xdr_buf-byte-ranges-to-scatterlists.patch sunrpc-return-an-error-from-xdr_buf_to_bvec-on-overflow.patch mm-sparse-vmemmap-pass-pgmap-argument-to-memory-deactivation-paths.patch mm-sparse-vmemmap-fix-dax-vmemmap-accounting-with-optimization.patch -thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch -thunderbolt-remove-service-debugfs-entries-during-unregister.patch -thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch -thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch net-mana-optimize-irq-affinity-for-low-vcpu-configs.patch bootconfig-move-xbc_snprint_cmdline-to-lib-bootconfig.c.patch bootconfig-fix-null-pointer-arithmetic-in-xbc_snprint_cmdline.patch diff --git a/queue-7.1/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch b/queue-7.1/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch deleted file mode 100644 index 2530717565..0000000000 --- a/queue-7.1/thunderbolt-keep-xdomain-reference-during-the-lifetime-of-a-service.patch +++ /dev/null @@ -1,42 +0,0 @@ -From stable+bounces-289101-greg=kroah.com@vger.kernel.org Sat Jul 25 16:12:32 2026 -From: Sasha Levin -Date: Sat, 25 Jul 2026 10:12:19 -0400 -Subject: thunderbolt: Keep XDomain reference during the lifetime of a service -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260725141222.3814514-1-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 8b4060998637f06975fceee9b73845d8672d411e ] - -This is needed because we release the service ID in tb_service_release() -and the ID array is owned by the parent XDomain. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1012,6 +1012,7 @@ static void tb_service_release(struct de - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -+ tb_xdomain_put(xd); - } - - const struct device_type tb_service_type = { -@@ -1120,7 +1121,7 @@ static void enumerate_services(struct tb - svc->id = id; - svc->dev.bus = &tb_bus_type; - svc->dev.type = &tb_service_type; -- svc->dev.parent = &xd->dev; -+ svc->dev.parent = get_device(&xd->dev); - dev_set_name(&svc->dev, "%s.%d", dev_name(&xd->dev), svc->id); - - tb_service_debugfs_init(svc); diff --git a/queue-7.1/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch b/queue-7.1/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch deleted file mode 100644 index ab87522b85..0000000000 --- a/queue-7.1/thunderbolt-prevent-xdomain-delayed-work-use-after-free-on-disconnect.patch +++ /dev/null @@ -1,90 +0,0 @@ -From stable+bounces-289104-greg=kroah.com@vger.kernel.org Sat Jul 25 16:13:42 2026 -From: Sasha Levin -Date: Sat, 25 Jul 2026 10:12:22 -0400 -Subject: thunderbolt: Prevent XDomain delayed work use-after-free on disconnect -To: stable@vger.kernel.org -Cc: Michael Bommarito , Mika Westerberg , Sasha Levin -Message-ID: <20260725141222.3814514-4-sashal@kernel.org> - -From: Michael Bommarito - -[ Upstream commit 2c5d2d3c3f70cde2565d7b279b544893a2035842 ] - -tb_xdp_handle_request() runs on system_wq and queues -xd->state_work via queue_delayed_work() in three request handlers: -PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), -and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues -xd->properties_changed_work when local properties change. - -Concurrently, tb_xdomain_remove() calls stop_handshake() which does -cancel_delayed_work_sync() on both delayed works. Later, -tb_xdomain_unregister() calls device_unregister() which eventually -frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run -tb_xdp_handle_request() in system workqueue") moved the request -handler off tb->wq, the handler and the remove path are no longer -serialized. If queue_delayed_work() executes after -cancel_delayed_work_sync() but before the xdomain is freed, the -delayed work fires on a freed object. - -Add xd->removing that tb_xdomain_remove() sets under xd->lock -before calling stop_handshake(). Each external queue site holds -the same lock and checks removing before calling -queue_delayed_work(). This provides the mutual exclusion needed: -either the queue site acquires the lock first and queues work that -the subsequent cancel will see, or the remove path acquires the -lock first and the queue site observes removing == true and skips -the queue. - -Fixes: 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") -Cc: stable@vger.kernel.org -Assisted-by: Claude:claude-opus-4-7 -Signed-off-by: Michael Bommarito -Signed-off-by: Mika Westerberg -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -909,6 +909,19 @@ void tb_unregister_service_driver(struct - } - EXPORT_SYMBOL_GPL(tb_unregister_service_driver); - -+static int update_xdomain(struct device *dev, void *data) -+{ -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd) { -+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -+ msecs_to_jiffies(50)); -+ } -+ -+ return 0; -+} -+ - static ssize_t key_show(struct device *dev, struct device_attribute *attr, - char *buf) - { -@@ -2500,19 +2513,6 @@ bool tb_xdomain_handle_request(struct tb - return ret > 0; - } - --static int update_xdomain(struct device *dev, void *data) --{ -- struct tb_xdomain *xd; -- -- xd = tb_to_xdomain(dev); -- if (xd) { -- queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, -- msecs_to_jiffies(50)); -- } -- -- return 0; --} -- - static void update_all_xdomains(void) - { - bus_for_each_dev(&tb_bus_type, NULL, NULL, update_xdomain); diff --git a/queue-7.1/thunderbolt-remove-service-debugfs-entries-during-unregister.patch b/queue-7.1/thunderbolt-remove-service-debugfs-entries-during-unregister.patch deleted file mode 100644 index 49469d5484..0000000000 --- a/queue-7.1/thunderbolt-remove-service-debugfs-entries-during-unregister.patch +++ /dev/null @@ -1,76 +0,0 @@ -From stable+bounces-289102-greg=kroah.com@vger.kernel.org Sat Jul 25 16:12:32 2026 -From: Sasha Levin -Date: Sat, 25 Jul 2026 10:12:20 -0400 -Subject: thunderbolt: Remove service debugfs entries during unregister -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260725141222.3814514-2-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit 4d5fc3f4068568dfcb8cbe2852b4adc56394aa26 ] - -We add them as part of the register path so to keep it symmetric remove -them as part of the unregister path. This also removes them even if the -service itself is not yet released (but is unregistered), thus allowing -new register with the same service name to happen. - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/xdomain.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1008,7 +1008,6 @@ static void tb_service_release(struct de - struct tb_service *svc = container_of(dev, struct tb_service, dev); - struct tb_xdomain *xd = tb_service_parent(svc); - -- tb_service_debugfs_remove(svc); - ida_free(&xd->service_ids, svc->id); - kfree(svc->key); - kfree(svc); -@@ -1023,6 +1022,14 @@ const struct device_type tb_service_type - }; - EXPORT_SYMBOL_GPL(tb_service_type); - -+static void __unregister_service(struct device *dev) -+{ -+ struct tb_service *svc = tb_to_service(dev); -+ -+ tb_service_debugfs_remove(svc); -+ device_unregister(&svc->dev); -+} -+ - static int remove_missing_service(struct device *dev, void *data) - { - struct tb_xdomain *xd = data; -@@ -1034,7 +1041,7 @@ static int remove_missing_service(struct - - if (!tb_property_find(xd->remote_properties, svc->key, - TB_PROPERTY_TYPE_DIRECTORY)) -- device_unregister(dev); -+ __unregister_service(dev); - - return 0; - } -@@ -1127,6 +1134,7 @@ static void enumerate_services(struct tb - tb_service_debugfs_init(svc); - - if (device_register(&svc->dev)) { -+ tb_service_debugfs_remove(svc); - put_device(&svc->dev); - break; - } -@@ -2059,7 +2067,7 @@ void tb_xdomain_add(struct tb_xdomain *x - - static int unregister_service(struct device *dev, void *data) - { -- device_unregister(dev); -+ __unregister_service(dev); - return 0; - } - diff --git a/queue-7.1/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch b/queue-7.1/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch deleted file mode 100644 index d2658453c4..0000000000 --- a/queue-7.1/thunderbolt-remove-xdomain-from-the-bus-without-holding-tb-lock.patch +++ /dev/null @@ -1,337 +0,0 @@ -From stable+bounces-289103-greg=kroah.com@vger.kernel.org Sat Jul 25 16:12:40 2026 -From: Sasha Levin -Date: Sat, 25 Jul 2026 10:12:21 -0400 -Subject: thunderbolt: Remove XDomain from the bus without holding tb->lock -To: stable@vger.kernel.org -Cc: Mika Westerberg , Sasha Levin -Message-ID: <20260725141222.3814514-3-sashal@kernel.org> - -From: Mika Westerberg - -[ Upstream commit a8937f35cf39c39c64325aa84d0463d866850857 ] - -Currently we call device_unregister() for services and the XDomain -itself with tb->lock held. This prevents the service drivers from -calling any functions that may take it. For this reason separate -removing the XDomain from the topology data structures (where we need -the lock) from unregistering the device from the bus (where remove -callbacks of the drivers are being called). - -Signed-off-by: Mika Westerberg -Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect") -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - drivers/thunderbolt/debugfs.c | 2 + - drivers/thunderbolt/domain.c | 30 +++++++++++++++++++++ - drivers/thunderbolt/icm.c | 5 +++ - drivers/thunderbolt/switch.c | 14 +++++++++ - drivers/thunderbolt/tb.c | 59 ++++++++++++++++++++---------------------- - drivers/thunderbolt/tb.h | 2 + - drivers/thunderbolt/xdomain.c | 53 +++++++++++++++++++++++-------------- - 7 files changed, 115 insertions(+), 50 deletions(-) - ---- a/drivers/thunderbolt/debugfs.c -+++ b/drivers/thunderbolt/debugfs.c -@@ -1786,6 +1786,8 @@ static void margining_port_remove(struct - - if (!port->usb4) - return; -+ if (!port->usb4->margining) -+ return; - - snprintf(dir_name, sizeof(dir_name), "port%d", port->port); - parent = debugfs_lookup(dir_name, port->sw->debugfs_dir); ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -850,6 +850,36 @@ int tb_domain_disconnect_all_paths(struc - return bus_for_each_dev(&tb_bus_type, NULL, tb, disconnect_xdomain); - } - -+struct unregister_context { -+ const struct tb *tb; -+ int n; -+}; -+ -+static int unregister_unplugged_xdomain(struct device *dev, void *data) -+{ -+ struct unregister_context *ctx = data; -+ struct tb_xdomain *xd; -+ -+ xd = tb_to_xdomain(dev); -+ if (xd && xd->tb == ctx->tb && xd->is_unplugged) { -+ tb_xdomain_unregister(xd); -+ ctx->n++; -+ } -+ return 0; -+} -+ -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb) -+{ -+ struct unregister_context ctx; -+ -+ ctx.tb = tb_domain_get(tb); -+ ctx.n = 0; -+ bus_for_each_dev(&tb_bus_type, NULL, &ctx, unregister_unplugged_xdomain); -+ tb_domain_put(tb); -+ -+ return ctx.n; -+} -+ - int tb_domain_init(void) - { - int ret; ---- a/drivers/thunderbolt/icm.c -+++ b/drivers/thunderbolt/icm.c -@@ -738,6 +738,7 @@ static void remove_xdomain(struct tb_xdo - - sw = tb_to_switch(xd->dev.parent); - tb_port_at(xd->route, sw)->xdomain = NULL; -+ xd->is_unplugged = true; - tb_xdomain_remove(xd); - } - -@@ -1762,6 +1763,8 @@ static void icm_handle_notification(stru - - kfree(n->pkg); - kfree(n); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type, -@@ -2112,6 +2115,8 @@ static void icm_rescan_work(struct work_ - if (tb->root_switch) - icm_free_unplugged_children(tb->root_switch); - mutex_unlock(&tb->lock); -+ -+ tb_domain_unregister_unplugged_xdomains(tb); - } - - static void icm_complete(struct tb *tb) ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -3625,6 +3625,20 @@ int tb_switch_resume(struct tb_switch *s - tb_port_warn(port, - "lost during suspend, disconnecting\n"); - tb_sw_set_unplugged(port->remote->sw); -+ } else if (port->xdomain) { -+ /* -+ * If the user replaced the XDomain with -+ * another router, this will succeed in -+ * which case we must remove the XDomain -+ * before adding the new router. -+ */ -+ err = tb_cfg_get_upstream_port(sw->tb->ctl, -+ port->xdomain->route); -+ if (err > 0) { -+ tb_port_warn(port, -+ "XDomain was disconnected\n"); -+ port->xdomain->is_unplugged = true; -+ } - } - } - } ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -2524,6 +2524,8 @@ put_sw: - out: - mutex_unlock(&tb->lock); - -+ tb_domain_unregister_unplugged_xdomains(tb); -+ - pm_runtime_mark_last_busy(&tb->dev); - pm_runtime_put_autosuspend(&tb->dev); - -@@ -3110,6 +3112,24 @@ static void tb_restore_children(struct t - } - } - -+static void tb_free_unplugged_xdomains(struct tb_switch *sw) -+{ -+ struct tb_port *port; -+ -+ tb_switch_for_each_port(sw, port) { -+ if (tb_is_upstream_port(port)) -+ continue; -+ if (port->xdomain && port->xdomain->is_unplugged) { -+ tb_retimer_remove_all(port); -+ tb_xdomain_remove(port->xdomain); -+ tb_port_unconfigure_xdomain(port); -+ port->xdomain = NULL; -+ } else if (port->remote) { -+ tb_free_unplugged_xdomains(port->remote->sw); -+ } -+ } -+} -+ - static int tb_resume_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -3129,6 +3149,7 @@ static int tb_resume_noirq(struct tb *tb - tb_switch_resume(tb->root_switch, false); - tb_free_invalid_tunnels(tb); - tb_free_unplugged_children(tb->root_switch); -+ tb_free_unplugged_xdomains(tb->root_switch); - tb_restore_children(tb->root_switch); - - /* -@@ -3171,28 +3192,6 @@ static int tb_resume_noirq(struct tb *tb - return 0; - } - --static int tb_free_unplugged_xdomains(struct tb_switch *sw) --{ -- struct tb_port *port; -- int ret = 0; -- -- tb_switch_for_each_port(sw, port) { -- if (tb_is_upstream_port(port)) -- continue; -- if (port->xdomain && port->xdomain->is_unplugged) { -- tb_retimer_remove_all(port); -- tb_xdomain_remove(port->xdomain); -- tb_port_unconfigure_xdomain(port); -- port->xdomain = NULL; -- ret++; -- } else if (port->remote) { -- ret += tb_free_unplugged_xdomains(port->remote->sw); -- } -- } -- -- return ret; --} -- - static int tb_freeze_noirq(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -3212,14 +3211,14 @@ static int tb_thaw_noirq(struct tb *tb) - static void tb_complete(struct tb *tb) - { - /* -- * Release any unplugged XDomains and if there is a case where -+ * Unregister unplugged XDomains and if there is a case where - * another domain is swapped in place of unplugged XDomain we - * need to run another rescan. - */ -- mutex_lock(&tb->lock); -- if (tb_free_unplugged_xdomains(tb->root_switch)) -- tb_scan_switch(tb->root_switch); -- mutex_unlock(&tb->lock); -+ if (tb_domain_unregister_unplugged_xdomains(tb)) { -+ scoped_guard(mutex, &tb->lock) -+ tb_scan_switch(tb->root_switch); -+ } - } - - static int tb_runtime_suspend(struct tb *tb) -@@ -3246,11 +3245,11 @@ static void tb_remove_work(struct work_s - struct tb *tb = tcm_to_tb(tcm); - - mutex_lock(&tb->lock); -- if (tb->root_switch) { -+ if (tb->root_switch) - tb_free_unplugged_children(tb->root_switch); -- tb_free_unplugged_xdomains(tb->root_switch); -- } - mutex_unlock(&tb->lock); -+ -+ tb_free_unplugged_xdomains(tb->root_switch); - } - - static int tb_runtime_resume(struct tb *tb) ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -793,6 +793,7 @@ int tb_domain_disconnect_xdomain_paths(s - int transmit_path, int transmit_ring, - int receive_path, int receive_ring); - int tb_domain_disconnect_all_paths(struct tb *tb); -+int tb_domain_unregister_unplugged_xdomains(struct tb *tb); - - static inline struct tb *tb_domain_get(struct tb *tb) - { -@@ -1263,6 +1264,7 @@ struct tb_xdomain *tb_xdomain_alloc(stru - const uuid_t *remote_uuid); - void tb_xdomain_add(struct tb_xdomain *xd); - void tb_xdomain_remove(struct tb_xdomain *xd); -+void tb_xdomain_unregister(struct tb_xdomain *xd); - struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, - u8 depth); - ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -2072,41 +2072,54 @@ static int unregister_service(struct dev - } - - /** -- * tb_xdomain_remove() - Remove XDomain from the bus -+ * tb_xdomain_remove() - Remove XDomain - * @xd: XDomain to remove - * -- * This will stop all ongoing configuration work and remove the XDomain -- * along with any services from the bus. When the last reference to @xd -- * is released the object will be released as well. -+ * This will stop all ongoing configuration work. XDomain is not removed -+ * from the bus if it was added. That needs to be done separately by -+ * calling tb_xdomain_unregister(). -+ * -+ * Called with @tb->lock held. - */ - void tb_xdomain_remove(struct tb_xdomain *xd) - { - tb_xdomain_debugfs_remove(xd); -- - stop_handshake(xd); -- -- device_for_each_child_reverse(&xd->dev, xd, unregister_service); -- - tb_xdomain_link_exit(xd); - -- /* -- * Undo runtime PM here explicitly because it is possible that -- * the XDomain was never added to the bus and thus device_del() -- * is not called for it (device_del() would handle this otherwise). -- */ -- pm_runtime_disable(&xd->dev); -- pm_runtime_put_noidle(&xd->dev); -- pm_runtime_set_suspended(&xd->dev); -- - if (!device_is_registered(&xd->dev)) { -+ /* -+ * Undo runtime PM here explicitly because it is -+ * possible that the XDomain was never added to the bus -+ * and thus device_del() is not called for it -+ * (device_del() would handle this otherwise). -+ */ -+ pm_runtime_disable(&xd->dev); -+ pm_runtime_put_noidle(&xd->dev); -+ pm_runtime_set_suspended(&xd->dev); - put_device(&xd->dev); -- } else { -- dev_info(&xd->dev, "host disconnected\n"); -- device_unregister(&xd->dev); - } - } - - /** -+ * tb_xdomain_unregister() - Unregister XDomain -+ * @xd: XDomain to unregister -+ * -+ * This will unregister the XDomain along with any services from the -+ * bus. When the last reference to @xd is released the object will be -+ * released as well. -+ */ -+void tb_xdomain_unregister(struct tb_xdomain *xd) -+{ -+ lockdep_assert_not_held(&xd->tb->lock); -+ -+ device_for_each_child_reverse(&xd->dev, xd, unregister_service); -+ -+ dev_info(&xd->dev, "host disconnected\n"); -+ device_unregister(&xd->dev); -+} -+ -+/** - * tb_xdomain_lane_bonding_enable() - Enable lane bonding on XDomain - * @xd: XDomain connection - *