From: Greg Kroah-Hartman Date: Mon, 15 Jun 2026 15:53:04 +0000 (+0200) Subject: 7.0-stable patches X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7c847e32103d26f94b16baa5287f0f9893016aec;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches added patches: drm-gem-try-to-fix-change_handle-ioctl-attempt-4.patch drm-i915-fix-color-blob-reference-handling-in-intel_plane_state.patch mm-cma-fix-reserved-page-leak-on-activation-failure.patch mm-cma_debug-fix-invalid-accesses-for-inactive-cma-areas.patch mm-damon-lru_sort-handle-ctx-allocation-failure.patch mm-damon-reclaim-handle-ctx-allocation-failure.patch mm-huge_memory-use-correct-flags-for-device-private-pmd-entry.patch mm-hugetlb-avoid-false-positive-lockdep-assertion.patch mm-hugetlb-restore-reservation-on-error-in-hugetlb-folio-copy-paths.patch mm-list_lru-drain-before-clearing-xarray-entry-on-reparent.patch mm-mincore-handle-non-swap-entries-before-config_swap-guard.patch mmc-core-fix-host-controller-programming-for-fixed-driver-type.patch mmc-dw_mmc-rockchip-add-missing-private-data-for-very-old-controllers.patch mmc-litex_mmc-set-mandatory-idle-clocks-before-cmd0.patch mmc-renesas_sdhi-add-of-entry-for-rz-g2h-soc.patch mmc-sdhci-add-signal-voltage-switch-in-sdhci_resume_host.patch mmc-sdhci-of-dwcmshc-fix-reset-clk-and-sdio-support-for-eswin-eic7700.patch pmdomain-imx-fix-of-node-refcount.patch pmdomain-ti_sci-add-wakeup-constraint-to-parent-devices-of-wakeup-source.patch rtase-avoid-sleeping-in-get_stats64.patch rtase-reset-tx-subqueue-when-clearing-tx-ring.patch rxrpc-fix-the-ack-parser-to-extract-the-sack-table-for-parsing.patch sctp-diag-reject-stale-associations-in-dump_one-path.patch sctp-stream-fully-roll-back-denied-add-stream-state.patch slimbus-qcom-ngd-ctrl-avoid-abba-on-tx_lock-ctrl-lock.patch slimbus-qcom-ngd-ctrl-balance-pm_runtime-enablement-for-ngd.patch slimbus-qcom-ngd-ctrl-correct-pdr-and-ssr-cleanup-ownership.patch slimbus-qcom-ngd-ctrl-fix-of-node-refcount.patch slimbus-qcom-ngd-ctrl-fix-probe-error-path-ordering.patch slimbus-qcom-ngd-ctrl-fix-up-platform_driver-registration.patch slimbus-qcom-ngd-ctrl-initialize-controller-resources-in-controller.patch slimbus-qcom-ngd-ctrl-register-callbacks-after-creating-the-ngd.patch thunderbolt-bound-root-directory-content-to-block-size.patch thunderbolt-clamp-xdomain-response-data-copy-to-allocation-size.patch thunderbolt-limit-xdomain-response-copy-to-actual-frame-size.patch thunderbolt-reject-zero-length-property-entries-in-validator.patch thunderbolt-validate-xdomain-request-packet-size-before-type-cast.patch --- diff --git a/queue-7.0/drm-gem-try-to-fix-change_handle-ioctl-attempt-4.patch b/queue-7.0/drm-gem-try-to-fix-change_handle-ioctl-attempt-4.patch new file mode 100644 index 0000000000..a41c0f11f3 --- /dev/null +++ b/queue-7.0/drm-gem-try-to-fix-change_handle-ioctl-attempt-4.patch @@ -0,0 +1,228 @@ +From 1a4f03d22fb655e5f192244fb2c87d8066fcfca2 Mon Sep 17 00:00:00 2001 +From: Simona Vetter +Date: Thu, 4 Jun 2026 21:44:37 +0200 +Subject: drm/gem: Try to fix change_handle ioctl, attempt 4 + +From: Simona Vetter + +commit 1a4f03d22fb655e5f192244fb2c87d8066fcfca2 upstream. + +[airlied: just added some comments on how to reenable] +On-list because the cat is out of the bag and we're clearly not good +enough to figure this out in private. The story thus far: + +5e28b7b94408 ("drm: Set old handle to NULL before prime swap in +change_handle") tried to fix a race condition between the gem_close and +gem_change_handle ioctls, but got a few things wrong: + +- There's a confusion with the local variable handle, which is actually + the new handle, and so the two-stage trick was actually applied to the + wrong idr slot. 7164d78559b0 ("drm/gem: fix race between + change_handle and handle_delete") tried to fix that by adding yet + another code block, but forgot to add the error handling. Which meant + we now have two paths, both kinda wrong. + +- dc366607c41c ("drm: Replace old pointer to new idr") tried to apply + another fix, but inconsistently, again because of the handle confusion + - this would be the right fix (kinda, somewhat, it's a mess) if we'd + do the two-stage approach for the new handle. Except that wasn't the + intent of the original fix. + +We also didn't have an igt merged for the original ioctl, which is a big +no-go. This was attempted to address off-list in the original bugfix, +and amd QA people claimed the bug was fixed now. Very clearly that's not +the case. Here's my attempt to sort this out: + +- Rename the local variable to new_handle, the old aliasing with + args->handle is just too dangerously confusing. + +- Merge the gem obj lookup with the two-stage idr_replace so that we + avoid getting ourselves confused there. + +- This means we don't have a surplus temporary reference anymore, only + an inherited from the idr. A concurrent gem_close on the new_handle + could steal that. Fix that with the same two-stage approach + create_tail uses. This is a bit overkill as documented in the comment, + but I also don't trust my ability to understand this all correctly, so + go with the established pattern we have from other ioctls instead for + maximum paranoia. + +- Adjust error paths. I've tried to make the error and success paths + common, because they are identical except for which handle is removed + and on which we call idr_replace to (re)install the object again. But + that made things messier to read, so I've left it at the more verbose + version, which unfortunately hides the symmetry in the entire code + flow a bit. + +- While at it, also replace the 7 space indent with 1 tab. + +And finally, because I flat out don't trust my abilities here at all +anymore: + +- Disable the ioctl until we have the igt situation and everything else + sorted out on-list and with full consensus. + +v2: + +Sashiko noticed that I didn't handle the error path for idr_replace +correctly, it must be checked with IS_ERR_OR_NULL like in +gem_handle_delete. So yeah, definitely should just the existing paths +1:1 because this is endless amounts of tricky. + +Also add the Fixes: line for the original ioctl, I forgot that too. + +Reported-by: DARKNAVY (@DarkNavyOrg) +Signed-off-by: Simona Vetter +Fixes: dc366607c41c ("drm: Replace old pointer to new idr") +Cc: syzbot+d7c9eed171647e421013@syzkaller.appspotmail.com +Cc: stable@vger.kernel.org +Cc: Edward Adam Davis +Cc: Dave Airlie +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Thomas Zimmermann +Fixes: 5e28b7b94408 ("drm: Set old handle to NULL before prime swap in change_handle") +Cc: David Francis +Cc: Puttimet Thammasaeng +Cc: Christian Koenig +Fixes: 7164d78559b0 ("drm/gem: fix race between change_handle and handle_delete") +Cc: Zhenghang Xiao +Fixes: 5e28b7b94408 ("drm: Set old handle to NULL before prime swap in change_handle") +Reviewed-by: David Francis +Signed-off-by: Dave Airlie +Link: https://patch.msgid.link/20260604194437.1725314-1-simona.vetter@ffwll.ch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/drm_gem.c | 73 ++++++++++++++++++++------------------------ + drivers/gpu/drm/drm_ioctl.c | 3 + + 2 files changed, 36 insertions(+), 40 deletions(-) + +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -997,12 +997,25 @@ err: + return ret; + } + ++/* ++ * This ioctl is disabled for security reasons but also it failed ++ * to follow process in terms of adding testing in igt and verifying ++ * all the corner cases which made fixing security bugs in it even ++ * harder than necessary. ++ * ++ * To re-enable this ioctl ++ * 1. land working IGT tests in igt-gpu-tools that cover ++ * all corner cases and race conditions. ++ * 2. handle idr_preload ++ * 3. handle == 0 ++ * 4. handle == new_handle semantics definition. ++ */ + int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) + { + struct drm_gem_change_handle *args = data; +- struct drm_gem_object *obj, *idrobj; +- int handle, ret; ++ struct drm_gem_object *obj; ++ int new_handle, ret; + + if (!drm_core_check_feature(dev, DRIVER_GEM)) + return -EOPNOTSUPP; +@@ -1010,52 +1023,36 @@ int drm_gem_change_handle_ioctl(struct d + /* idr_alloc() limitation. */ + if (args->new_handle > INT_MAX) + return -EINVAL; +- handle = args->new_handle; ++ new_handle = args->new_handle; + +- obj = drm_gem_object_lookup(file_priv, args->handle); +- if (!obj) +- return -ENOENT; +- +- if (args->handle == handle) { +- ret = 0; +- goto out; +- } ++ if (args->handle == new_handle) ++ return 0; + + mutex_lock(&file_priv->prime.lock); +- + spin_lock(&file_priv->table_lock); +- +- /* When create_tail allocs an obj idr, it needs to first alloc as NULL, +- * then later replace with the correct object. This is not necessary +- * here, because the only operations that could race are drm_prime +- * bookkeeping, and we hold the prime lock. +- */ +- ret = idr_alloc(&file_priv->object_idr, obj, handle, handle + 1, ++ ret = idr_alloc(&file_priv->object_idr, NULL, new_handle, new_handle + 1, + GFP_NOWAIT); + +- if (ret < 0) { +- spin_unlock(&file_priv->table_lock); +- goto out_unlock; +- } +- +- idrobj = idr_replace(&file_priv->object_idr, NULL, handle); +- if (idrobj != obj) { +- idr_replace(&file_priv->object_idr, idrobj, handle); +- idr_remove(&file_priv->object_idr, args->new_handle); +- spin_unlock(&file_priv->table_lock); +- ret = -ENOENT; +- goto out_unlock; +- } ++ if (ret < 0) { ++ spin_unlock(&file_priv->table_lock); ++ goto out_unlock; ++ } + +- idr_replace(&file_priv->object_idr, NULL, args->handle); ++ obj = idr_replace(&file_priv->object_idr, NULL, args->handle); ++ if (IS_ERR_OR_NULL(obj)) { ++ idr_remove(&file_priv->object_idr, new_handle); ++ spin_unlock(&file_priv->table_lock); ++ ret = -ENOENT; ++ goto out_unlock; ++ } + spin_unlock(&file_priv->table_lock); + + if (obj->dma_buf) { + ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf, +- handle); ++ new_handle); + if (ret < 0) { + spin_lock(&file_priv->table_lock); +- idr_remove(&file_priv->object_idr, handle); ++ idr_remove(&file_priv->object_idr, new_handle); + idr_replace(&file_priv->object_idr, obj, args->handle); + spin_unlock(&file_priv->table_lock); + goto out_unlock; +@@ -1068,14 +1065,12 @@ int drm_gem_change_handle_ioctl(struct d + + spin_lock(&file_priv->table_lock); + idr_remove(&file_priv->object_idr, args->handle); +- idrobj = idr_replace(&file_priv->object_idr, obj, handle); ++ obj = idr_replace(&file_priv->object_idr, obj, new_handle); + spin_unlock(&file_priv->table_lock); +- WARN_ON(idrobj != NULL); ++ WARN_ON(obj != NULL); + + out_unlock: + mutex_unlock(&file_priv->prime.lock); +-out: +- drm_gem_object_put(obj); + + return ret; + } +--- a/drivers/gpu/drm/drm_ioctl.c ++++ b/drivers/gpu/drm/drm_ioctl.c +@@ -660,7 +660,8 @@ static const struct drm_ioctl_desc drm_i + DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_gem_change_handle_ioctl, DRM_RENDER_ALLOW), ++ /* see drm_gem.c:drm_gem_change_handle_ioctl for why this is invalid */ ++ DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_invalid_op, DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0), + diff --git a/queue-7.0/drm-i915-fix-color-blob-reference-handling-in-intel_plane_state.patch b/queue-7.0/drm-i915-fix-color-blob-reference-handling-in-intel_plane_state.patch new file mode 100644 index 0000000000..c767aa5fe8 --- /dev/null +++ b/queue-7.0/drm-i915-fix-color-blob-reference-handling-in-intel_plane_state.patch @@ -0,0 +1,82 @@ +From 26eb7c0a7ab09d83eec833db6a5a2bc60b9d4d9a Mon Sep 17 00:00:00 2001 +From: Chaitanya Kumar Borah +Date: Mon, 1 Jun 2026 13:59:53 +0530 +Subject: drm/i915: Fix color blob reference handling in intel_plane_state + +From: Chaitanya Kumar Borah + +commit 26eb7c0a7ab09d83eec833db6a5a2bc60b9d4d9a upstream. + +Take proper references for hw color blobs (degamma_lut, gamma_lut, +ctm, lut_3d) in intel_plane_duplicate_state() and drop them in +intel_plane_destroy_state(). + +v2: +- handle blobs in hw state clear + +Cc: #v6.19+ +Fixes: 3b7476e786c2 ("drm/i915/color: Add framework to program PRE/POST CSC LUT") +Fixes: a78f1b6baf4d ("drm/i915/color: Add framework to program CSC") +Fixes: 65db7a1f9cf7 ("drm/i915/color: Add 3D LUT to color pipeline") +Reviewed-by: Pranay Samala #v1 +Reviewed-by: Uma Shankar +Signed-off-by: Chaitanya Kumar Borah +Signed-off-by: Uma Shankar +Link: https://patch.msgid.link/20260601082953.128539-4-chaitanya.kumar.borah@intel.com +(cherry picked from commit c6eea1925154b6697fe22b217faab9bb30635e6b) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_plane.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +--- a/drivers/gpu/drm/i915/display/intel_plane.c ++++ b/drivers/gpu/drm/i915/display/intel_plane.c +@@ -144,6 +144,15 @@ intel_plane_duplicate_state(struct drm_p + if (intel_state->hw.fb) + drm_framebuffer_get(intel_state->hw.fb); + ++ if (intel_state->hw.degamma_lut) ++ drm_property_blob_get(intel_state->hw.degamma_lut); ++ if (intel_state->hw.gamma_lut) ++ drm_property_blob_get(intel_state->hw.gamma_lut); ++ if (intel_state->hw.ctm) ++ drm_property_blob_get(intel_state->hw.ctm); ++ if (intel_state->hw.lut_3d) ++ drm_property_blob_get(intel_state->hw.lut_3d); ++ + return &intel_state->uapi; + } + +@@ -167,6 +176,16 @@ intel_plane_destroy_state(struct drm_pla + __drm_atomic_helper_plane_destroy_state(&plane_state->uapi); + if (plane_state->hw.fb) + drm_framebuffer_put(plane_state->hw.fb); ++ ++ if (plane_state->hw.degamma_lut) ++ drm_property_blob_put(plane_state->hw.degamma_lut); ++ if (plane_state->hw.gamma_lut) ++ drm_property_blob_put(plane_state->hw.gamma_lut); ++ if (plane_state->hw.ctm) ++ drm_property_blob_put(plane_state->hw.ctm); ++ if (plane_state->hw.lut_3d) ++ drm_property_blob_put(plane_state->hw.lut_3d); ++ + kfree(plane_state); + } + +@@ -317,6 +336,14 @@ static void intel_plane_clear_hw_state(s + { + if (plane_state->hw.fb) + drm_framebuffer_put(plane_state->hw.fb); ++ if (plane_state->hw.degamma_lut) ++ drm_property_blob_put(plane_state->hw.degamma_lut); ++ if (plane_state->hw.gamma_lut) ++ drm_property_blob_put(plane_state->hw.gamma_lut); ++ if (plane_state->hw.ctm) ++ drm_property_blob_put(plane_state->hw.ctm); ++ if (plane_state->hw.lut_3d) ++ drm_property_blob_put(plane_state->hw.lut_3d); + + memset(&plane_state->hw, 0, sizeof(plane_state->hw)); + } diff --git a/queue-7.0/mm-cma-fix-reserved-page-leak-on-activation-failure.patch b/queue-7.0/mm-cma-fix-reserved-page-leak-on-activation-failure.patch new file mode 100644 index 0000000000..a616859267 --- /dev/null +++ b/queue-7.0/mm-cma-fix-reserved-page-leak-on-activation-failure.patch @@ -0,0 +1,68 @@ +From 00739e4dd46dde2b39dd9dd19a27e3c8af4ca0d0 Mon Sep 17 00:00:00 2001 +From: Muchun Song +Date: Sat, 23 May 2026 14:01:23 +0800 +Subject: mm/cma: fix reserved page leak on activation failure + +From: Muchun Song + +commit 00739e4dd46dde2b39dd9dd19a27e3c8af4ca0d0 upstream. + +If cma_activate_area() fails after allocating only part of the range +bitmaps, the cleanup path still has to release the reserved pages when +CMA_RESERVE_PAGES_ON_ERROR is clear. + +That is still worth doing even in this __init path. A bitmap_zalloc() +failure does not necessarily mean the system cannot make further progress: +freeing the reserved CMA pages can return a substantial amount of memory +to the buddy allocator and may relieve the temporary memory shortage that +caused the allocation failure in the first place. + +However, the cleanup path currently uses the bitmap-freeing bound for page +release as well. That is only correct for ranges whose bitmap allocation +already succeeded. The failed range and all later ranges still keep their +reserved pages, so a partial bitmap allocation failure can permanently +leak them. + +Fix this by releasing reserved pages for all ranges. Use the saved +early_pfn[] value for ranges whose bitmap allocation already succeeded and +for the failed range, and use cmr->early_pfn for later ranges whose bitmap +allocation was never attempted. + +Link: https://lore.kernel.org/20260523060123.2207992-1-songmuchun@bytedance.com +Fixes: c009da4258f9 ("mm, cma: support multiple contiguous ranges, if requested") +Signed-off-by: Muchun Song +Reviewed-by: Oscar Salvador (SUSE) +Acked-by: Usama Arif +Cc: David Hildenbrand +Cc: Frank van der Linden +Cc: Liam R. Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/cma.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/mm/cma.c ++++ b/mm/cma.c +@@ -187,10 +187,13 @@ cleanup: + + /* Expose all pages to the buddy, they are useless for CMA. */ + if (!test_bit(CMA_RESERVE_PAGES_ON_ERROR, &cma->flags)) { +- for (r = 0; r < allocrange; r++) { ++ for (r = 0; r < cma->nranges; r++) { ++ unsigned long start_pfn; ++ + cmr = &cma->ranges[r]; ++ start_pfn = r <= allocrange ? early_pfn[r] : cmr->early_pfn; + end_pfn = cmr->base_pfn + cmr->count; +- for (pfn = early_pfn[r]; pfn < end_pfn; pfn++) ++ for (pfn = start_pfn; pfn < end_pfn; pfn++) + free_reserved_page(pfn_to_page(pfn)); + } + } diff --git a/queue-7.0/mm-cma_debug-fix-invalid-accesses-for-inactive-cma-areas.patch b/queue-7.0/mm-cma_debug-fix-invalid-accesses-for-inactive-cma-areas.patch new file mode 100644 index 0000000000..bb791f9e35 --- /dev/null +++ b/queue-7.0/mm-cma_debug-fix-invalid-accesses-for-inactive-cma-areas.patch @@ -0,0 +1,62 @@ +From c0ca59beb5252ea2bd4fdaef009d003dedc2030e Mon Sep 17 00:00:00 2001 +From: Muchun Song +Date: Wed, 20 May 2026 14:10:25 +0800 +Subject: mm/cma_debug: fix invalid accesses for inactive CMA areas + +From: Muchun Song + +commit c0ca59beb5252ea2bd4fdaef009d003dedc2030e upstream. + +cma_activate_area() can fail after allocating range bitmaps. Its cleanup +path frees those bitmaps, but only clears cma->count and +cma->available_count. It leaves cma->nranges and each range's count in +place, so cma_debugfs_init() can still register debugfs files for an area +that never activated successfully. + +That exposes two problems. Reading the bitmap file can make debugfs walk +a freed range bitmap and trigger an invalid memory access. Reading +maxchunk can also take cma->lock even though that lock is initialized only +on the successful activation path. + +Fix this by creating debugfs entries only for CMA areas that reached +CMA_ACTIVATED. + +c009da4258f9 introduced the invalid access to bitmap file. 2e32b947606d +introduced the invalid access to cma->lock. This change applies to both +issues. So I added two Fixes tags. + +Link: https://lore.kernel.org/20260520061025.3971821-1-songmuchun@bytedance.com +Fixes: c009da4258f9 ("mm, cma: support multiple contiguous ranges, if requested") +Fixes: 2e32b947606d ("mm: cma: add functions to get region pages counters") +Signed-off-by: Muchun Song +Acked-by: Mike Rapoport (Microsoft) +Acked-by: Oscar Salvador (SUSE) +Acked-by: David Hildenbrand (Arm) +Cc: Dmitry Safonov <0x7f454c46@gmail.com> +Cc: Frank van der Linden +Cc: Liam R. Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Michal Nazarewicz +Cc: Stefan Strogin +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/cma_debug.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/mm/cma_debug.c ++++ b/mm/cma_debug.c +@@ -205,7 +205,8 @@ static int __init cma_debugfs_init(void) + cma_debugfs_root = debugfs_create_dir("cma", NULL); + + for (i = 0; i < cma_area_count; i++) +- cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root); ++ if (test_bit(CMA_ACTIVATED, &cma_areas[i].flags)) ++ cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root); + + return 0; + } diff --git a/queue-7.0/mm-damon-lru_sort-handle-ctx-allocation-failure.patch b/queue-7.0/mm-damon-lru_sort-handle-ctx-allocation-failure.patch new file mode 100644 index 0000000000..01111d83db --- /dev/null +++ b/queue-7.0/mm-damon-lru_sort-handle-ctx-allocation-failure.patch @@ -0,0 +1,39 @@ +From ab04340b5ae5d52c1d46b750538febcde9d889e7 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Thu, 28 May 2026 17:01:03 -0700 +Subject: mm/damon/lru_sort: handle ctx allocation failure + +From: SeongJae Park + +commit ab04340b5ae5d52c1d46b750538febcde9d889e7 upstream. + +DAMON_LRU_SORT allocates the damon_ctx object for its kdamond in its init +function. damon_lru_sort_enabled_store() wrongly assumes the allocation +will always succeed once tried. If the damon_ctx allocation was failed, +therefore, code execution reaches to damon_commit_ctx() while 'ctx' is +NULL. As a result, it dereferences the NULL 'ctx' pointer. Avoid the +NULL dereference by returning -ENOMEM if 'ctx' is NULL. + +Link: https://lore.kernel.org/20260529000104.7006-3-sj@kernel.org +Fixes: c4a8e662c839 ("mm/damon/lru_sort: use damon_initialized()") +Signed-off-by: SeongJae Park +Cc: # 6.18.x +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/damon/lru_sort.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/mm/damon/lru_sort.c ++++ b/mm/damon/lru_sort.c +@@ -442,6 +442,10 @@ static int damon_lru_sort_enabled_store( + if (!damon_initialized()) + return 0; + ++ /* damon_modules_new_paddr_ctx_target() in the init function failed. */ ++ if (!ctx) ++ return -ENOMEM; ++ + return damon_lru_sort_turn(enabled); + } + diff --git a/queue-7.0/mm-damon-reclaim-handle-ctx-allocation-failure.patch b/queue-7.0/mm-damon-reclaim-handle-ctx-allocation-failure.patch new file mode 100644 index 0000000000..aca75cc240 --- /dev/null +++ b/queue-7.0/mm-damon-reclaim-handle-ctx-allocation-failure.patch @@ -0,0 +1,53 @@ +From 7e2ed8a29427af534bf2cb9b8bc51762b8b6e654 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Thu, 28 May 2026 17:01:02 -0700 +Subject: mm/damon/reclaim: handle ctx allocation failure + +From: SeongJae Park + +commit 7e2ed8a29427af534bf2cb9b8bc51762b8b6e654 upstream. + +Patch series "mm/damon/{reclaim,lru_sort}: handle ctx allocation failures". + +DAMON_RECLAIM and DAMON_LRU_SORT could dereference NULL pointers if their +damon_ctx object allocations fail. The bugs are expected to happen +infrequently because the allocations are arguably too small to fail on +common setups. But theoretically they are possible and the consequences +are bad. Fix those. + +The issues were discovered [1] by Sashiko. + + +This patch (of 2): + +DAMON_RECLAIM allocates the damon_ctx object for its kdamond in its init +function. damon_reclaim_enabled_store() wrongly assumes the allocation +will always succeed once tried. If the damon_ctx allocation was failed, +therefore, code execution reaches to damon_commit_ctx() while 'ctx' is +NULL. As a result, it dereferences the NULL 'ctx' pointer. Avoid the +NULL dereference by returning -ENOMEM if 'ctx' is NULL. + +Link: https://lore.kernel.org/20260529000104.7006-2-sj@kernel.org +Link: https://lore.kernel.org/20260419014800.877-1-sj@kernel.org [1] +Fixes: 3f7a914ab9a5 ("mm/damon/reclaim: use damon_initialized()") +Signed-off-by: SeongJae Park +Cc: # 6.18.x +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/damon/reclaim.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/mm/damon/reclaim.c ++++ b/mm/damon/reclaim.c +@@ -344,6 +344,10 @@ static int damon_reclaim_enabled_store(c + if (!damon_initialized()) + return 0; + ++ /* damon_modules_new_paddr_ctx_target() in the init function failed. */ ++ if (!ctx) ++ return -ENOMEM; ++ + return damon_reclaim_turn(enabled); + } + diff --git a/queue-7.0/mm-huge_memory-use-correct-flags-for-device-private-pmd-entry.patch b/queue-7.0/mm-huge_memory-use-correct-flags-for-device-private-pmd-entry.patch new file mode 100644 index 0000000000..3027155098 --- /dev/null +++ b/queue-7.0/mm-huge_memory-use-correct-flags-for-device-private-pmd-entry.patch @@ -0,0 +1,179 @@ +From 43e7f189769c512c843184a8a5892ac779a6bd90 Mon Sep 17 00:00:00 2001 +From: Lorenzo Stoakes +Date: Mon, 1 Jun 2026 09:30:44 +0100 +Subject: mm/huge_memory: use correct flags for device private PMD entry + +From: Lorenzo Stoakes + +commit 43e7f189769c512c843184a8a5892ac779a6bd90 upstream. + +Commit 65edfda6f3f2 ("mm/rmap: extend rmap and migration support +device-private entries") updated set_pmd_migration_entry() to use +pmdp_huge_get_and_clear() in the softleaf case, but made no further +adjustments to the function itself. + +Therefore this function continues to incorrectly use pmd_write(), +pmd_soft_dirty() and pmd_uffd_wp() to determine whether the installed +migration entry should be marked writable, softdirty or uffd-wp +respectively. + +Whilst all are incorrect, the most problematic of these is pmd_write(), as +this can lead to corrupted rmap state. + +On x86-64 _PAGE_SWP_SOFT_DIRTY is aliased to _PAGE_RW. So calling +pmd_write() on a softleaf will return the softdirty state encoded in the +entry, assuming CONFIG_MEM_SOFT_DIRTY was enabled. + +This was observed when running the hmm.hmm_device_private.anon_write_child +selftest: + +1. The test faults in a range then migrates it such that a device-private + THP range is established. + +2. The parent then migrates it to a device-private writable PMD entry whose + folio is entirely AnonExclusive with entire_mapcount=1, softdirty set + (accidentally correct write state). + +3. The parent forks and the PMD entries are set to device-private read only + entries, entire_mapcount=2, softdirty still set. + +4. [BUG] The child writes to the range then migrates to RAM - intending to + install non-writable migration entries - but replacing parent and child + PMD mappings with WRITABLE entries due to misinterpreting the softdirty + bit. + +5. In remove_migration_pmd(), if !softleaf_is_migration_read(entry) we + set the RMAP_EXCLUSIVE flag when calling folio_add_anon_rmap_pmd() for + both parent and child, which are therefore AnonExclusive. + +6. [SPLAT] Child sets migrated folio entire_mapcount=1, parent sets + entire_mapcount=2 and we end up with an AnonExclusive folio with + entire_mapcount=2! Assert fires in __folio_add_anon_rmap(): + + VM_WARN_ON_FOLIO(folio_test_large(folio) && + folio_entire_mapcount(folio) > 1 && + PageAnonExclusive(cur_page), folio) + +This patch fixes the issue by correctly referencing the softleaf entry +fields for writable, softdirty and uffd-wp in set_pmd_migration_entry(). + +It also only updates A/D flags if the entry is present as these are +otherwise not meaningful for a softleaf entry. + +This patch also flips the if (!present) { ... } else { ... } logic in +set_pmd_migration_entry() so it is easier to understand, and adds some +comments to make things clearer. + +I was able to bisect this to commit 775465fd26a3 ("lib/test_hmm: add zone +device private THP test infrastructure") which first exposes this bug as +it was the commit that permitted test_hmm to generate the test. + +However commit 65edfda6f3f2 ("mm/rmap: extend rmap and migration support +device-private entries") is the commit that actually enabled this +behaviour. + +Link: https://lore.kernel.org/20260601083044.57132-1-ljs@kernel.org +Fixes: 65edfda6f3f2 ("mm/rmap: extend rmap and migration support device-private entries") +Signed-off-by: Lorenzo Stoakes +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Dev Jain +Reviewed-by: Balbir Singh +Reviewed-by: Baolin Wang +Reviewed-by: Oscar Salvador (SUSE) +Reviewed-by: Barry Song +Reviewed-by: Lance Yang +Reviewed-by: Zi Yan +Cc: Baolin Wang +Cc: Liam R. Howlett +Cc: Nico Pache +Cc: Ryan Roberts +Cc: SeongJae Park +Cc: Wei Yang +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/huge_memory.c | 45 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 33 insertions(+), 12 deletions(-) + +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -4873,7 +4873,7 @@ int set_pmd_migration_entry(struct page_ + struct vm_area_struct *vma = pvmw->vma; + struct mm_struct *mm = vma->vm_mm; + unsigned long address = pvmw->address; +- bool anon_exclusive; ++ bool anon_exclusive, present, writable, softdirty, uffd_wp; + pmd_t pmdval; + swp_entry_t entry; + pmd_t pmdswp; +@@ -4881,12 +4881,26 @@ int set_pmd_migration_entry(struct page_ + if (!(pvmw->pmd && !pvmw->pte)) + return 0; + +- flush_cache_range(vma, address, address + HPAGE_PMD_SIZE); +- if (unlikely(!pmd_present(*pvmw->pmd))) +- pmdval = pmdp_huge_get_and_clear(vma->vm_mm, address, pvmw->pmd); +- else ++ present = pmd_present(*pvmw->pmd); ++ if (likely(present)) { ++ flush_cache_range(vma, address, address + HPAGE_PMD_SIZE); ++ + pmdval = pmdp_invalidate(vma, address, pvmw->pmd); + ++ writable = pmd_write(pmdval); ++ softdirty = pmd_soft_dirty(pmdval); ++ uffd_wp = pmd_uffd_wp(pmdval); ++ } else { ++ softleaf_t old_entry; ++ ++ pmdval = pmdp_huge_get_and_clear(vma->vm_mm, address, pvmw->pmd); ++ old_entry = softleaf_from_pmd(pmdval); ++ ++ writable = softleaf_is_device_private_write(old_entry); ++ softdirty = pmd_swp_soft_dirty(pmdval); ++ uffd_wp = pmd_swp_uffd_wp(pmdval); ++ } ++ + /* See folio_try_share_anon_rmap_pmd(): invalidate PMD first. */ + anon_exclusive = folio_test_anon(folio) && PageAnonExclusive(page); + if (anon_exclusive && folio_try_share_anon_rmap_pmd(folio, page)) { +@@ -4894,24 +4908,31 @@ int set_pmd_migration_entry(struct page_ + return -EBUSY; + } + +- if (pmd_dirty(pmdval)) +- folio_mark_dirty(folio); +- if (pmd_write(pmdval)) ++ /* Determine type of migration entry. */ ++ if (writable) + entry = make_writable_migration_entry(page_to_pfn(page)); + else if (anon_exclusive) + entry = make_readable_exclusive_migration_entry(page_to_pfn(page)); + else + entry = make_readable_migration_entry(page_to_pfn(page)); +- if (pmd_young(pmdval)) ++ ++ /* Set A/D bits as necessary. */ ++ if (present && pmd_young(pmdval)) + entry = make_migration_entry_young(entry); +- if (pmd_dirty(pmdval)) ++ if (present && pmd_dirty(pmdval)) { ++ folio_mark_dirty(folio); + entry = make_migration_entry_dirty(entry); ++ } ++ ++ /* Set PMD. */ + pmdswp = swp_entry_to_pmd(entry); +- if (pmd_soft_dirty(pmdval)) ++ if (softdirty) + pmdswp = pmd_swp_mksoft_dirty(pmdswp); +- if (pmd_uffd_wp(pmdval)) ++ if (uffd_wp) + pmdswp = pmd_swp_mkuffd_wp(pmdswp); + set_pmd_at(mm, address, pvmw->pmd, pmdswp); ++ ++ /* Migration entry installed: cleanup rmap, folio. */ + folio_remove_rmap_pmd(folio, page, vma); + folio_put(folio); + trace_set_migration_pmd(address, pmd_val(pmdswp)); diff --git a/queue-7.0/mm-hugetlb-avoid-false-positive-lockdep-assertion.patch b/queue-7.0/mm-hugetlb-avoid-false-positive-lockdep-assertion.patch new file mode 100644 index 0000000000..531de0e676 --- /dev/null +++ b/queue-7.0/mm-hugetlb-avoid-false-positive-lockdep-assertion.patch @@ -0,0 +1,249 @@ +From b4aea43cd37afad714b5684fe9fdfcb0e78dba26 Mon Sep 17 00:00:00 2001 +From: Lorenzo Stoakes +Date: Wed, 13 May 2026 09:56:58 +0100 +Subject: mm/hugetlb: avoid false positive lockdep assertion + +From: Lorenzo Stoakes + +commit b4aea43cd37afad714b5684fe9fdfcb0e78dba26 upstream. + +Commit 081056dc00a2 ("mm/hugetlb: unshare page tables during VMA split, +not before") changed the locking model around hugetlbfs PMD unsharing on +VMA split, but did not update the function which asserts the locks, +hugetlb_vma_assert_locked(). + +This function asserts that either the hugetlb VMA lock is held (if a +shared mapping) or that the reservation map lock is held (if private). + +If you get an unfortunate race between something which results in one of +these locks being released and a hugetlb VMA split and you have +CONFIG_LOCKDEP enabled, you can therefore see a false positive assertion +arise when there is in fact no issue. + +Since this change introduced a new take_locks parameter to +hugetlb_unshare_pmds(), which, when set to false, indicates that locking +is sufficient, simply pass this to the unsharing logic and predicate the +lock assertions on this. + +This is safe, as we already asserted the file rmap lock and the VMA write +lock prior to this (implying exclusive mmap write lock), so we cannot be +raced by either rmap or page fault page table walkers which the asserted +locks are intended to protect against (we don't mind GUP-fast). + +Separate out huge_pmd_unshare() into __huge_pmd_unshare() to add a +check_locks parameter, and update hugetlb_unshare_pmds() to pass this +parameter to it. + +This leaves all other callers of huge_pmd_unshare() still correctly +asserting the locks. + +The below reproducer will trigger the assert in a kernel with +CONFIG_LOCKDEP enabled by racing process teardown (which will release the +hugetlb lock) against a hugetlb split. + +void execute_one(void) +{ + void *ptr; + pid_t pid; + + /* + * Create a hugetlb mapping spanning a PUD entry. + * + * We force the hugetlb page allocation with populate and + * noreserve. + * + * |---------------------| + * | | + * |---------------------| + * 0 PUD boundary + */ + ptr = mmap(0, PUD_SIZE, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED | MAP_ANON | + MAP_NORESERVE | MAP_HUGETLB | MAP_POPULATE, + -1, 0); + if (ptr == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + + /* + * Fork but with a bogus stack pointer so we try to execute code in + * a non-VM_EXEC VMA, causing segfault + teardown via exit_mmap(). + * + * The clone will cause PMD page table sharing between the + * processes first via: + * copy_process() -> ... -> huge_pte_alloc() -> huge_pmd_share() + * + * Then tear down and release the hugetlb 'VMA' lock via: + * exit_mmap() -> ... -> vma_close() -> hugetlb_vma_lock_free() + */ + pid = syscall(__NR_clone, 0, 2 * PMD_SIZE, 0, 0, 0); + if (pid < 0) { + perror("clone"); + exit(EXIT_FAILURE); + } if (pid == 0) { + /* Pop stack... */ + return; + } + + /* + * We are the parent process. + * + * Race the child process's teardown with a PMD unshare. + * + * We do this by triggering: + * + * __split_vma() -> hugetlb_split() -> hugetlb_unshare_pmds() + * + * Which, importantly, doesn't hold the hugetlb VMA lock (nor can + * it), meaning we assert in hugetlb_vma_assert_locked(). + * + * . + * |----------.----------| + * | . | + * |----------.----------| + * 0 . PUD boundary + */ + mmap(0, PUD_SIZE / 2, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); +} + +int main(void) +{ + int i; + + /* Kick off fork children. */ + for (i = 0; i < NUM_FORKS; i++) { + pid_t pid = fork(); + + if (pid < 0) { + perror("fork"); + exit(EXIT_FAILURE); + } + + /* Fork children do their work and exit. */ + if (!pid) { + int j; + + for (j = 0; j < NUM_ITERS; j++) + execute_one(); + return EXIT_SUCCESS; + } + } + + /* If we succeeded, wait on children. */ + for (i = 0; i < NUM_FORKS; i++) + wait(NULL); + + return EXIT_SUCCESS; +} + +[ljs@kernel.org: account for the !CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING case] + Link: https://lore.kernel.org/agWZsPGYid08uU6O@lucifer +Link: https://lore.kernel.org/20260513085658.45264-1-ljs@kernel.org +Fixes: 081056dc00a2 ("mm/hugetlb: unshare page tables during VMA split, not before") +Signed-off-by: Lorenzo Stoakes +Acked-by: David Hildenbrand (Arm) +Acked-by: Oscar Salvador +Cc: Jann Horn +Cc: Muchun Song +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/hugetlb.c | 56 +++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 37 insertions(+), 19 deletions(-) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -118,6 +118,9 @@ static int hugetlb_acct_memory(struct hs + static void hugetlb_vma_lock_free(struct vm_area_struct *vma); + static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma); + static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma); ++static int __huge_pmd_unshare(struct mmu_gather *tlb, ++ struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, ++ bool check_locks); + static void hugetlb_unshare_pmds(struct vm_area_struct *vma, + unsigned long start, unsigned long end, bool take_locks); + static struct resv_map *vma_resv_map(struct vm_area_struct *vma); +@@ -6910,6 +6913,31 @@ out: + return pte; + } + ++static int __huge_pmd_unshare(struct mmu_gather *tlb, ++ struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, ++ bool check_locks) ++{ ++ unsigned long sz = huge_page_size(hstate_vma(vma)); ++ struct mm_struct *mm = vma->vm_mm; ++ pgd_t *pgd = pgd_offset(mm, addr); ++ p4d_t *p4d = p4d_offset(pgd, addr); ++ pud_t *pud = pud_offset(p4d, addr); ++ ++ if (sz != PMD_SIZE) ++ return 0; ++ if (!ptdesc_pmd_is_shared(virt_to_ptdesc(ptep))) ++ return 0; ++ i_mmap_assert_write_locked(vma->vm_file->f_mapping); ++ if (check_locks) ++ hugetlb_vma_assert_locked(vma); ++ pud_clear(pud); ++ ++ tlb_unshare_pmd_ptdesc(tlb, virt_to_ptdesc(ptep), addr); ++ ++ mm_dec_nr_pmds(mm); ++ return 1; ++} ++ + /** + * huge_pmd_unshare - Unmap a pmd table if it is shared by multiple users + * @tlb: the current mmu_gather. +@@ -6929,24 +6957,7 @@ out: + int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) + { +- unsigned long sz = huge_page_size(hstate_vma(vma)); +- struct mm_struct *mm = vma->vm_mm; +- pgd_t *pgd = pgd_offset(mm, addr); +- p4d_t *p4d = p4d_offset(pgd, addr); +- pud_t *pud = pud_offset(p4d, addr); +- +- if (sz != PMD_SIZE) +- return 0; +- if (!ptdesc_pmd_is_shared(virt_to_ptdesc(ptep))) +- return 0; +- i_mmap_assert_write_locked(vma->vm_file->f_mapping); +- hugetlb_vma_assert_locked(vma); +- pud_clear(pud); +- +- tlb_unshare_pmd_ptdesc(tlb, virt_to_ptdesc(ptep), addr); +- +- mm_dec_nr_pmds(mm); +- return 1; ++ return __huge_pmd_unshare(tlb, vma, addr, ptep, /*check_locks=*/true); + } + + /* +@@ -6980,6 +6991,13 @@ pte_t *huge_pmd_share(struct mm_struct * + return NULL; + } + ++static int __huge_pmd_unshare(struct mmu_gather *tlb, ++ struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, ++ bool check_locks) ++{ ++ return 0; ++} ++ + int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) + { +@@ -7277,7 +7295,7 @@ static void hugetlb_unshare_pmds(struct + if (!ptep) + continue; + ptl = huge_pte_lock(h, mm, ptep); +- huge_pmd_unshare(&tlb, vma, address, ptep); ++ __huge_pmd_unshare(&tlb, vma, address, ptep, take_locks); + spin_unlock(ptl); + } + huge_pmd_unshare_flush(&tlb, vma); diff --git a/queue-7.0/mm-hugetlb-restore-reservation-on-error-in-hugetlb-folio-copy-paths.patch b/queue-7.0/mm-hugetlb-restore-reservation-on-error-in-hugetlb-folio-copy-paths.patch new file mode 100644 index 0000000000..f07d087d2a --- /dev/null +++ b/queue-7.0/mm-hugetlb-restore-reservation-on-error-in-hugetlb-folio-copy-paths.patch @@ -0,0 +1,68 @@ +From 40c81856e622a9dc59294a90d169ac07ea25b0b0 Mon Sep 17 00:00:00 2001 +From: David Carlier +Date: Wed, 20 May 2026 05:49:12 +0100 +Subject: mm/hugetlb: restore reservation on error in hugetlb folio copy paths + +From: David Carlier + +commit 40c81856e622a9dc59294a90d169ac07ea25b0b0 upstream. + +Two sites in mm/hugetlb.c allocate a hugetlb folio via +alloc_hugetlb_folio() (consuming a VMA reservation) and then call +copy_user_large_folio(), which became int-returning in commit 1cb9dc4b475c +("mm: hwpoison: support recovery from HugePage copy-on-write faults") and +can now fail (e.g. -EHWPOISON on a hwpoisoned source page). On the +failure path, folio_put() restores the global hugetlb pool count through +free_huge_folio(), but the per-VMA reservation map entry is left marked +consumed: + + - hugetlb_mfill_atomic_pte() resubmission path (UFFDIO_COPY) + - copy_hugetlb_page_range() fork-time CoW path when + hugetlb_try_dup_anon_rmap() fails (rare: pinned hugetlb anon + folio under fork) + +User-visible effect: on UFFDIO_COPY into a private hugetlb VMA where the +resubmission copy fails, the reservation for that address is leaked from +the VMA's reserve map. A subsequent fault at the same address takes the +no-reservation path, and under hugetlb pool pressure the task is SIGBUSed +at an address it had previously reserved. The fork-time CoW path leaks +the same way in the child VMA's reserve map, though it requires the much +rarer combination of pinned hugetlb anon page + hwpoisoned source. + +Add the missing restore_reserve_on_error() call before folio_put() on both +error paths. + +Link: https://lore.kernel.org/20260520044912.6751-1-devnexen@gmail.com +Fixes: 1cb9dc4b475c ("mm: hwpoison: support recovery from HugePage copy-on-write faults") +Signed-off-by: David Carlier +Reviewed-by: Muchun Song +Cc: David Hildenbrand +Cc: Mina Almasry +Cc: Muchun Song +Cc: Oscar Salvador +Cc: yuehaibing +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/hugetlb.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -4996,6 +4996,7 @@ again: + addr, dst_vma); + folio_put(pte_folio); + if (ret) { ++ restore_reserve_on_error(h, dst_vma, addr, new_folio); + folio_put(new_folio); + break; + } +@@ -6292,6 +6293,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_ + folio_put(*foliop); + *foliop = NULL; + if (ret) { ++ restore_reserve_on_error(h, dst_vma, dst_addr, folio); + folio_put(folio); + goto out; + } diff --git a/queue-7.0/mm-list_lru-drain-before-clearing-xarray-entry-on-reparent.patch b/queue-7.0/mm-list_lru-drain-before-clearing-xarray-entry-on-reparent.patch new file mode 100644 index 0000000000..4d329ff9db --- /dev/null +++ b/queue-7.0/mm-list_lru-drain-before-clearing-xarray-entry-on-reparent.patch @@ -0,0 +1,86 @@ +From 98733f3f0becb1ae0701d021c1748e974e5fa55c Mon Sep 17 00:00:00 2001 +From: Shakeel Butt +Date: Mon, 1 Jun 2026 09:15:01 -0700 +Subject: mm/list_lru: drain before clearing xarray entry on reparent + +From: Shakeel Butt + +commit 98733f3f0becb1ae0701d021c1748e974e5fa55c upstream. + +memcg_reparent_list_lrus() clears the dying memcg's xarray entry with +xas_store(&xas, NULL) before reparenting its per-node lists into the +parent. This opens a window where a concurrent list_lru_del() arriving +for the dying memcg sees xa_load() == NULL, walks to the parent in +lock_list_lru_of_memcg(), takes the parent's per-node lock, and calls +list_del_init() on an item still physically linked on the dying memcg's +list. + +If another in-flight thread holds the dying memcg's per-node lock at the +same moment (another list_lru_del, or a list_lru_walk_one running an +isolate callback), both threads modify ->next/->prev pointers on the same +physical list under different locks. Adjacent items can corrupt each +other's links. + +Fix it by reversing the order: reparent each per-node list and mark the +child's list lru dead and then clear the xarray entry. Any concurrent +list_lru op that finds the still-set xarray entry either takes the dying +memcg's per-node lock (synchronizing with the drain) or sees LONG_MIN and +walks to the parent, where the items now live. + +Link: https://lore.kernel.org/20260601161501.1444829-1-shakeel.butt@linux.dev +Fixes: fb56fdf8b9a2 ("mm/list_lru: split the lock to per-cgroup scope") +Signed-off-by: Shakeel Butt +Reported-by: Chris Mason +Reviewed-by: Kairui Song +Acked-by: Muchun Song +Cc: Dave Chinner +Cc: Johannes Weiner +Cc: Roman Gushchin +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/list_lru.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +--- a/mm/list_lru.c ++++ b/mm/list_lru.c +@@ -472,26 +472,29 @@ void memcg_reparent_list_lrus(struct mem + mutex_lock(&list_lrus_mutex); + list_for_each_entry(lru, &memcg_list_lrus, list) { + struct list_lru_memcg *mlru; +- XA_STATE(xas, &lru->xa, memcg->kmemcg_id); + + /* +- * Lock the Xarray to ensure no on going list_lru_memcg +- * allocation and further allocation will see css_is_dying(). ++ * css_is_dying() check in memcg_list_lru_alloc() avoids ++ * allocating a new mlru since CSS_DYING is already set for this ++ * memcg a rcu grace period ago. + */ +- xas_lock_irq(&xas); +- mlru = xas_store(&xas, NULL); +- xas_unlock_irq(&xas); ++ mlru = xa_load(&lru->xa, memcg->kmemcg_id); + if (!mlru) + continue; + + /* +- * With Xarray value set to NULL, holding the lru lock below +- * prevents list_lru_{add,del,isolate} from touching the lru, +- * safe to reparent. ++ * Reparent each per-node list and mark the child dead ++ * (LONG_MIN) before clearing xarray entry otherwise a ++ * concurrent list_lru_del() may corrupt the list if it arrives ++ * after xarray clear but before reparenting as ++ * lock_list_lru_of_memcg will acquire parent's lock while the ++ * item is still on child's list. + */ + for_each_node(i) + memcg_reparent_list_lru_one(lru, i, &mlru->node[i], parent); + ++ xa_erase_irq(&lru->xa, memcg->kmemcg_id); ++ + /* + * Here all list_lrus corresponding to the cgroup are guaranteed + * to remain empty, we can safely free this lru, any further diff --git a/queue-7.0/mm-mincore-handle-non-swap-entries-before-config_swap-guard.patch b/queue-7.0/mm-mincore-handle-non-swap-entries-before-config_swap-guard.patch new file mode 100644 index 0000000000..35ce07203e --- /dev/null +++ b/queue-7.0/mm-mincore-handle-non-swap-entries-before-config_swap-guard.patch @@ -0,0 +1,67 @@ +From 0c25b8734367574e21aeb8468c2e522713134da7 Mon Sep 17 00:00:00 2001 +From: Usama Arif +Date: Tue, 2 Jun 2026 10:22:47 -0700 +Subject: mm/mincore: handle non-swap entries before !CONFIG_SWAP guard + +From: Usama Arif + +commit 0c25b8734367574e21aeb8468c2e522713134da7 upstream. + +mincore_swap() also fields migration/hwpoison entries (and shmem +swapin-error entries), which can exist on !CONFIG_SWAP builds when +CONFIG_MIGRATION or CONFIG_MEMORY_FAILURE is enabled. The +!IS_ENABLED(CONFIG_SWAP) guard ran before the non-swap-entry early return, +so mincore_pte_range() can spuriously WARN and report these pages +nonresident on !CONFIG_SWAP kernels. + +Move the guard below the non-swap-entry check so only true swap entries +trip the WARN, and migration/hwpoison entries take the existing "uptodate +/ non-shmem" path. + +Link: https://lore.kernel.org/20260602172247.279421-1-usama.arif@linux.dev +Fixes: 1f2052755c15 ("mm/mincore: use a helper for checking the swap cache") +Signed-off-by: Usama Arif +Reviewed-by: Pedro Falcato +Reviewed-by: Kairui Song +Reviewed-by: Lorenzo Stoakes +Acked-by: Johannes Weiner +Cc: Baoquan He +Cc: Chris Li +Cc: Jann Horn +Cc: Liam R. Howlett +Cc: Rik van Riel +Cc: Shakeel Butt +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/mincore.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/mm/mincore.c ++++ b/mm/mincore.c +@@ -64,11 +64,6 @@ static unsigned char mincore_swap(swp_en + struct folio *folio = NULL; + unsigned char present = 0; + +- if (!IS_ENABLED(CONFIG_SWAP)) { +- WARN_ON(1); +- return 0; +- } +- + /* + * Shmem mapping may contain swapin error entries, which are + * absent. Page table may contain migration or hwpoison +@@ -77,6 +72,11 @@ static unsigned char mincore_swap(swp_en + if (!softleaf_is_swap(entry)) + return !shmem; + ++ if (!IS_ENABLED(CONFIG_SWAP)) { ++ WARN_ON(1); ++ return 0; ++ } ++ + /* + * Shmem mapping lookup is lockless, so we need to grab the swap + * device. mincore page table walk locks the PTL, and the swap diff --git a/queue-7.0/mmc-core-fix-host-controller-programming-for-fixed-driver-type.patch b/queue-7.0/mmc-core-fix-host-controller-programming-for-fixed-driver-type.patch new file mode 100644 index 0000000000..8fe7f8cd82 --- /dev/null +++ b/queue-7.0/mmc-core-fix-host-controller-programming-for-fixed-driver-type.patch @@ -0,0 +1,46 @@ +From 5a52c5701a67d5176eb1afbf1bdaf7d6dfeec597 Mon Sep 17 00:00:00 2001 +From: Kamal Dasu +Date: Thu, 23 Apr 2026 15:18:55 -0400 +Subject: mmc: core: Fix host controller programming for fixed driver type + +From: Kamal Dasu + +commit 5a52c5701a67d5176eb1afbf1bdaf7d6dfeec597 upstream. + +When using the fixed-emmc-driver-type device tree property, the MMC core +correctly selects the driver strength for the card but fails to program +the host controller accordingly. This causes a mismatch where the card +uses the specified driver type while the host controller defaults to +Type B (since ios->drv_type remains zero). + +Split the driver type programming logic to handle both fixed and dynamic +driver type selection paths. For fixed driver types, program the host +controller with the selected drive_strength value. For dynamic selection, +use the existing drv_type as before. + +This ensures both the eMMC device and host controller use matching driver +strengths, preventing potential signal integrity issues. + +Fixes: 6186d06c519e ("mmc: parse new binding for eMMC fixed driver type") +Signed-off-by: Kamal Dasu +Reviewed-by: Shawn Lin +Cc: stable@vger.kernel.org +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/core/mmc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -1371,7 +1371,9 @@ static void mmc_select_driver_type(struc + + card->drive_strength = drive_strength; + +- if (drv_type) ++ if (fixed_drv_type >= 0 && drive_strength) ++ mmc_set_driver_type(card->host, drive_strength); ++ else if (drv_type) + mmc_set_driver_type(card->host, drv_type); + } + diff --git a/queue-7.0/mmc-dw_mmc-rockchip-add-missing-private-data-for-very-old-controllers.patch b/queue-7.0/mmc-dw_mmc-rockchip-add-missing-private-data-for-very-old-controllers.patch new file mode 100644 index 0000000000..b0cd23583f --- /dev/null +++ b/queue-7.0/mmc-dw_mmc-rockchip-add-missing-private-data-for-very-old-controllers.patch @@ -0,0 +1,69 @@ +From 1e9a4850afa0ceb63984fb1a9f3e86d0fc4fd18f Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 22 May 2026 20:43:07 +0200 +Subject: mmc: dw_mmc-rockchip: Add missing private data for very old controllers + +From: Heiko Stuebner + +commit 1e9a4850afa0ceb63984fb1a9f3e86d0fc4fd18f upstream. + +The really old controllers (rk2928, rk3066, rk3188) do not support UHS +speeds at all, and thus never handled phase data. + +For that reason it never had a parse_dt callback and no driver private +data at all. + +Commit ff6f0286c896 ("mmc: dw_mmc-rockchip: Add memory clock auto-gating +support") makes the private data sort of mandatory, because the init +function checks whether phases are configured internally or through the +clock controller. + +This results in the old SoCs then experiencing NULL-pointer dereferences +when they try to access that private-data struct. + +While we could have if (priv) conditionals in all places, it's way less +cluttery to just give the old types their private-data struct. + +Fixes: ff6f0286c896 ("mmc: dw_mmc-rockchip: Add memory clock auto-gating support") +Cc: stable@vger.kernel.org +Signed-off-by: Heiko Stuebner +Acked-by: Shawn Lin +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/host/dw_mmc-rockchip.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/drivers/mmc/host/dw_mmc-rockchip.c ++++ b/drivers/mmc/host/dw_mmc-rockchip.c +@@ -433,6 +433,22 @@ static int dw_mci_common_parse_dt(struct + return 0; + } + ++static int dw_mci_rk2928_parse_dt(struct dw_mci *host) ++{ ++ struct dw_mci_rockchip_priv_data *priv; ++ int err; ++ ++ err = dw_mci_common_parse_dt(host); ++ if (err) ++ return err; ++ ++ priv = host->priv; ++ ++ priv->internal_phase = false; ++ ++ return 0; ++} ++ + static int dw_mci_rk3288_parse_dt(struct dw_mci *host) + { + struct dw_mci_rockchip_priv_data *priv; +@@ -506,6 +522,7 @@ static int dw_mci_rockchip_init(struct d + + static const struct dw_mci_drv_data rk2928_drv_data = { + .init = dw_mci_rockchip_init, ++ .parse_dt = dw_mci_rk2928_parse_dt, + }; + + static const struct dw_mci_drv_data rk3288_drv_data = { diff --git a/queue-7.0/mmc-litex_mmc-set-mandatory-idle-clocks-before-cmd0.patch b/queue-7.0/mmc-litex_mmc-set-mandatory-idle-clocks-before-cmd0.patch new file mode 100644 index 0000000000..e212dd869a --- /dev/null +++ b/queue-7.0/mmc-litex_mmc-set-mandatory-idle-clocks-before-cmd0.patch @@ -0,0 +1,63 @@ +From 99982b743e5ba72bd1f5de0e03e3b96ae70b1e51 Mon Sep 17 00:00:00 2001 +From: Inochi Amaoto +Date: Thu, 21 May 2026 15:21:21 +0800 +Subject: mmc: litex_mmc: Set mandatory idle clocks before CMD0 + +From: Inochi Amaoto + +commit 99982b743e5ba72bd1f5de0e03e3b96ae70b1e51 upstream. + +The litex_mmc driver assumes the card is already probed in the BIOS +and skip the phy initialization. This will cause the command fail +like the following when the old card is unplugged and then insert +a new card: + +[ 62.923593] litex-mmc f0004000.mmc: Command (cmd 8) error, status -110 +[ 62.949717] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110 +[ 62.976606] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110 +[ 63.002516] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110 +[ 63.028442] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110 + +Add required clock settings and initialization for the CMD 0, so it can +probe the new card. + +Fixes: 92e099104729 ("mmc: Add driver for LiteX's LiteSDCard interface") +Signed-off-by: Inochi Amaoto +Reviewed-by: Gabriel Somlo +Cc: stable@vger.kernel.org +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/host/litex_mmc.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/mmc/host/litex_mmc.c ++++ b/drivers/mmc/host/litex_mmc.c +@@ -69,6 +69,9 @@ + #define SD_SLEEP_US 5 + #define SD_TIMEOUT_US 20000 + ++#define SD_INIT_DELAY_US 1000 ++#define SD_INIT_CLK_HZ 400000 ++ + #define SDIRQ_CARD_DETECT 1 + #define SDIRQ_SD_TO_MEM_DONE 2 + #define SDIRQ_MEM_TO_SD_DONE 4 +@@ -450,6 +453,17 @@ static void litex_mmc_set_ios(struct mmc + struct litex_mmc_host *host = mmc_priv(mmc); + + /* ++ * The SD specification requires at least 74 idle clocks before CMD0. ++ * These dummy cycles is generated by writing LITEX_PHY_INITIALIZE. ++ */ ++ if (ios->chip_select == MMC_CS_HIGH) { ++ litex_mmc_setclk(host, SD_INIT_CLK_HZ); ++ litex_write8(host->sdphy + LITEX_PHY_INITIALIZE, 1); ++ fsleep(SD_INIT_DELAY_US); ++ return; ++ } ++ ++ /* + * NOTE: Ignore any ios->bus_width updates; they occur right after + * the mmc core sends its own acmd6 bus-width change notification, + * which is redundant since we snoop on the command flow and inject diff --git a/queue-7.0/mmc-renesas_sdhi-add-of-entry-for-rz-g2h-soc.patch b/queue-7.0/mmc-renesas_sdhi-add-of-entry-for-rz-g2h-soc.patch new file mode 100644 index 0000000000..f07a70a51b --- /dev/null +++ b/queue-7.0/mmc-renesas_sdhi-add-of-entry-for-rz-g2h-soc.patch @@ -0,0 +1,40 @@ +From f48ee49726ee4ab545fd2dc644f169c0809b19b3 Mon Sep 17 00:00:00 2001 +From: Lad Prabhakar +Date: Tue, 19 May 2026 14:53:40 +0100 +Subject: mmc: renesas_sdhi: Add OF entry for RZ/G2H SoC + +From: Lad Prabhakar + +commit f48ee49726ee4ab545fd2dc644f169c0809b19b3 upstream. + +The RZ/G2H (R8A774E1) SoC was previously handled via the generic +"renesas,rcar-gen3-sdhi" fallback compatible string. However, because +the SDHI IP on RZ/G2H is identical with the R-Car H3-N (R8A77951), it +requires the specific quirks and configuration defined in +`of_r8a7795_compatible` rather than the generic Gen3 data. + +Add the explicit "renesas,sdhi-r8a774e1" match entry to map it correctly. +Note that the DT binding file renesas,sdhi.yaml does not need an update +as the entry for this SoC is already present. + +Fixes: 31941342888d ("arm64: dts: renesas: r8a774e1: Add SDHI nodes") +Cc: stable@vger.kernel.org +Signed-off-by: Lad Prabhakar +Reviewed-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c ++++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c +@@ -279,6 +279,7 @@ static const struct renesas_sdhi_of_data + static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { + { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, }, + { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, }, ++ { .compatible = "renesas,sdhi-r8a774e1", .data = &of_r8a7795_compatible, }, + { .compatible = "renesas,sdhi-r8a7795", .data = &of_r8a7795_compatible, }, + { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, }, + { .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, }, diff --git a/queue-7.0/mmc-sdhci-add-signal-voltage-switch-in-sdhci_resume_host.patch b/queue-7.0/mmc-sdhci-add-signal-voltage-switch-in-sdhci_resume_host.patch new file mode 100644 index 0000000000..fbdc5cbcae --- /dev/null +++ b/queue-7.0/mmc-sdhci-add-signal-voltage-switch-in-sdhci_resume_host.patch @@ -0,0 +1,47 @@ +From f595e8e77a51eee35e331f69321766593a845ef2 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Sun, 24 May 2026 10:34:55 +0800 +Subject: mmc: sdhci: add signal voltage switch in sdhci_resume_host + +From: Jisheng Zhang + +commit f595e8e77a51eee35e331f69321766593a845ef2 upstream. + +I met one suspend/resume issue with sdr104 capable sdio wifi card (with +"keep-power-in-suspend" set in DT property): +After resuming from suspend to ram, the sdio wifi card stops working. +Further debug shows that although ios shows the sdio card is at sdr104 +mode, the voltage is still at 3V3. This is due to missing the calling +of ->start_signal_voltage_switch() in sdhci_resume_host(). + +Fix this issue by adding ->start_signal_voltage_switch() in +sdhci_resume_host(). This also matches what we do for +sdhci_runtime_resume_host(). + +Then the question is: why this issue hasn't reported and fixed for so +long time. IMHO, several reasons: Some host controllers just kick off +the runtime resume for system resume, so they benefit from the well +supported runtime pm code; Some platforms just use the old sdio wifi +card which doesn't need signal voltage switch at all, the default +voltage is 3v3 after resuming. + +Fixes: 6308d2905bd3 ("mmc: sdhci: add quirk for keeping card power during suspend") +Signed-off-by: Jisheng Zhang +Acked-by: Adrian Hunter +Cc: stable@vger.kernel.org +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/host/sdhci.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -3836,6 +3836,7 @@ int sdhci_resume_host(struct sdhci_host + host->pwr = 0; + host->clock = 0; + host->reinit_uhs = true; ++ mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios); + mmc->ops->set_ios(mmc, &mmc->ios); + } else { + sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER)); diff --git a/queue-7.0/mmc-sdhci-of-dwcmshc-fix-reset-clk-and-sdio-support-for-eswin-eic7700.patch b/queue-7.0/mmc-sdhci-of-dwcmshc-fix-reset-clk-and-sdio-support-for-eswin-eic7700.patch new file mode 100644 index 0000000000..8e26ea7083 --- /dev/null +++ b/queue-7.0/mmc-sdhci-of-dwcmshc-fix-reset-clk-and-sdio-support-for-eswin-eic7700.patch @@ -0,0 +1,172 @@ +From 8d4ae34e997062076a9098602eaca43353665bd9 Mon Sep 17 00:00:00 2001 +From: Huan He +Date: Sat, 9 May 2026 16:49:07 +0800 +Subject: mmc: sdhci-of-dwcmshc: Fix reset, clk, and SDIO support for Eswin EIC7700 + +From: Huan He + +commit 8d4ae34e997062076a9098602eaca43353665bd9 upstream. + +The EIC7700 code in sdhci-of-dwcmshc uses host->mmc->caps2 to select +different configuration paths for different card types. The current logic +distinguishes eMMC and SD, but does not handle SDIO separately. + +Update the EIC7700 card-type checks so that eMMC, SD and SDIO are +distinguished explicitly. + +Switch the reset path to dwcmshc_reset() so that pending interrupt state +is cleared consistently, and use sdhci_enable_clk() so the clock enable +sequence follows the standard SDHCI flow. + +Fixes: 32b2633219d3 ("mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700") +Signed-off-by: Huan He +Acked-by: Adrian Hunter +Cc: stable@vger.kernel.org +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 44 ++++++++++++++++++------------------ + 1 file changed, 22 insertions(+), 22 deletions(-) + +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -251,6 +251,7 @@ + #define PHY_DELAY_CODE_MAX 0x7f + #define PHY_DELAY_CODE_EMMC 0x17 + #define PHY_DELAY_CODE_SD 0x55 ++#define PHY_DELAY_CODE_SDIO 0x29 + + enum dwcmshc_rk_type { + DWCMSHC_RK3568, +@@ -1273,10 +1274,7 @@ static void sdhci_eic7700_set_clock(stru + clk_set_rate(pltfm_host->clk, clock); + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); +- clk |= SDHCI_CLOCK_INT_EN; +- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); +- +- dwcmshc_enable_card_clk(host); ++ sdhci_enable_clk(host, clk); + } + + static void sdhci_eic7700_config_phy_delay(struct sdhci_host *host, int delay) +@@ -1337,7 +1335,7 @@ static void sdhci_eic7700_config_phy(str + + static void sdhci_eic7700_reset(struct sdhci_host *host, u8 mask) + { +- sdhci_reset(host, mask); ++ dwcmshc_reset(host, mask); + + /* after reset all, the phy's config will be clear */ + if (mask == SDHCI_RESET_ALL) +@@ -1434,18 +1432,17 @@ static int sdhci_eic7700_phase_code_tuni + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); +- u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO; ++ u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + int phase_code = -1; + int code_range = -1; +- bool is_sd = false; + int code_min = -1; + int code_max = -1; + int cmd_error = 0; ++ bool is_emmc; + int ret = 0; + int i = 0; + +- if ((host->mmc->caps2 & sd_caps) == sd_caps) +- is_sd = true; ++ is_emmc = (host->mmc->caps2 & emmc_caps) == emmc_caps; + + for (i = 0; i <= MAX_PHASE_CODE; i++) { + /* Centered Phase code */ +@@ -1454,8 +1451,8 @@ static int sdhci_eic7700_phase_code_tuni + host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + + if (ret) { +- /* SD specific range tracking */ +- if (is_sd && code_min != -1 && code_max != -1) { ++ /* SD/SDIO specific range tracking */ ++ if (!is_emmc && code_min != -1 && code_max != -1) { + if (code_max - code_min > code_range) { + code_range = code_max - code_min; + phase_code = (code_min + code_max) / 2; +@@ -1466,17 +1463,17 @@ static int sdhci_eic7700_phase_code_tuni + code_max = -1; + } + /* EMMC breaks after first valid range */ +- if (!is_sd && code_min != -1 && code_max != -1) ++ if (is_emmc && code_min != -1 && code_max != -1) + break; + } else { + /* Track valid phase code range */ + if (code_min == -1) { + code_min = i; +- if (!is_sd) ++ if (is_emmc) + continue; + } + code_max = i; +- if (is_sd && i == MAX_PHASE_CODE) { ++ if (!is_emmc && i == MAX_PHASE_CODE) { + if (code_max - code_min > code_range) { + code_range = code_max - code_min; + phase_code = (code_min + code_max) / 2; +@@ -1486,19 +1483,19 @@ static int sdhci_eic7700_phase_code_tuni + } + + /* Handle tuning failure case */ +- if ((is_sd && phase_code == -1) || +- (!is_sd && code_min == -1 && code_max == -1)) { ++ if ((!is_emmc && phase_code == -1) || ++ (is_emmc && code_min == -1 && code_max == -1)) { + pr_err("%s: phase code tuning failed!\n", mmc_hostname(host->mmc)); + sdhci_writew(host, 0, priv->vendor_specific_area1 + DWCMSHC_AT_STAT); + return -EIO; + } +- if (!is_sd) ++ if (is_emmc) + phase_code = (code_min + code_max) / 2; + + sdhci_writew(host, phase_code, priv->vendor_specific_area1 + DWCMSHC_AT_STAT); + +- /* SD specific final verification */ +- if (is_sd) { ++ /* SD/SDIO specific final verification */ ++ if (!is_emmc) { + ret = mmc_send_tuning(host->mmc, opcode, &cmd_error); + host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + if (ret) { +@@ -1596,9 +1593,9 @@ static void sdhci_eic7700_set_uhs_signal + + static void sdhci_eic7700_set_uhs_wrapper(struct sdhci_host *host, unsigned int timing) + { +- u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO; ++ u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + +- if ((host->mmc->caps2 & sd_caps) == sd_caps) ++ if ((host->mmc->caps2 & emmc_caps) != emmc_caps) + sdhci_set_uhs_signaling(host, timing); + else + sdhci_eic7700_set_uhs_signaling(host, timing); +@@ -1607,6 +1604,7 @@ static void sdhci_eic7700_set_uhs_wrappe + static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) + { + u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; ++ u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO; + unsigned int val, hsp_int_status, hsp_pwr_ctrl; + static const char * const clk_ids[] = {"axi"}; + struct of_phandle_args args; +@@ -1661,8 +1659,10 @@ static int eic7700_init(struct device *d + + if ((host->mmc->caps2 & emmc_caps) == emmc_caps) + dwc_priv->delay_line = PHY_DELAY_CODE_EMMC; +- else ++ else if ((host->mmc->caps2 & sd_caps) == sd_caps) + dwc_priv->delay_line = PHY_DELAY_CODE_SD; ++ else ++ dwc_priv->delay_line = PHY_DELAY_CODE_SDIO; + + if (!of_property_read_u32(dev->of_node, "eswin,drive-impedance-ohms", &val)) + priv->drive_impedance = eic7700_convert_drive_impedance_ohm(dev, val); diff --git a/queue-7.0/pmdomain-imx-fix-of-node-refcount.patch b/queue-7.0/pmdomain-imx-fix-of-node-refcount.patch new file mode 100644 index 0000000000..86e0a537f9 --- /dev/null +++ b/queue-7.0/pmdomain-imx-fix-of-node-refcount.patch @@ -0,0 +1,34 @@ +From fba0510cd62666951dcc0221527edc0c47ae6599 Mon Sep 17 00:00:00 2001 +From: Bartosz Golaszewski +Date: Thu, 21 May 2026 10:36:27 +0200 +Subject: pmdomain: imx: fix OF node refcount + +From: Bartosz Golaszewski + +commit fba0510cd62666951dcc0221527edc0c47ae6599 upstream. + +for_each_child_of_node_scoped() decrements the reference count of the +nod after each iteration. Assigning it without incrementing the refcount +to a dynamically allocated platform device will result in a double put +in platform_device_release(). Add the missing call to of_node_get(). + +Cc: stable@vger.kernel.org +Fixes: 3e4d109ee8fc ("pmdomain: imx: gpc: Simplify with scoped for each OF child loop") +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pmdomain/imx/gpc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pmdomain/imx/gpc.c ++++ b/drivers/pmdomain/imx/gpc.c +@@ -487,7 +487,7 @@ static int imx_gpc_probe(struct platform + domain->ipg_rate_mhz = ipg_rate_mhz; + + pd_pdev->dev.parent = &pdev->dev; +- pd_pdev->dev.of_node = np; ++ pd_pdev->dev.of_node = of_node_get(np); + pd_pdev->dev.fwnode = of_fwnode_handle(np); + + ret = platform_device_add(pd_pdev); diff --git a/queue-7.0/pmdomain-ti_sci-add-wakeup-constraint-to-parent-devices-of-wakeup-source.patch b/queue-7.0/pmdomain-ti_sci-add-wakeup-constraint-to-parent-devices-of-wakeup-source.patch new file mode 100644 index 0000000000..ed74a7b70e --- /dev/null +++ b/queue-7.0/pmdomain-ti_sci-add-wakeup-constraint-to-parent-devices-of-wakeup-source.patch @@ -0,0 +1,36 @@ +From 4db207599acfc9d676340daa2dc6b52bfca17db4 Mon Sep 17 00:00:00 2001 +From: Kendall Willis +Date: Wed, 6 May 2026 22:16:45 -0500 +Subject: pmdomain: ti_sci: add wakeup constraint to parent devices of wakeup source + +From: Kendall Willis + +commit 4db207599acfc9d676340daa2dc6b52bfca17db4 upstream. + +Set wakeup constraint for any device in a wakeup path. All parent devices +of a wakeup device should not be turned off during suspend. This ensures +the wakeup device is kept on while the system is suspended. + +Cc: stable@vger.kernel.org +Fixes: 9d8aa0dd3be4 ("pmdomain: ti_sci: add wakeup constraint management") +Reported-by: Vitor Soares +Closes: https://lore.kernel.org/linux-pm/c0fe43a2339c802e9ce5900092cd530a2ba17a6b.camel@gmail.com/ +Signed-off-by: Kendall Willis +Reviewed-by: Sebin Francis +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pmdomain/ti/ti_sci_pm_domains.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pmdomain/ti/ti_sci_pm_domains.c ++++ b/drivers/pmdomain/ti/ti_sci_pm_domains.c +@@ -86,7 +86,7 @@ static inline void ti_sci_pd_set_wkup_co + const struct ti_sci_handle *ti_sci = pd->parent->ti_sci; + int ret; + +- if (device_may_wakeup(dev)) { ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + /* + * If device can wakeup using IO daisy chain wakeups, + * we do not want to set a constraint. diff --git a/queue-7.0/rtase-avoid-sleeping-in-get_stats64.patch b/queue-7.0/rtase-avoid-sleeping-in-get_stats64.patch new file mode 100644 index 0000000000..0c84b6524b --- /dev/null +++ b/queue-7.0/rtase-avoid-sleeping-in-get_stats64.patch @@ -0,0 +1,43 @@ +From 9fc237f8d49f06d05f0f8e80361047b718894e81 Mon Sep 17 00:00:00 2001 +From: Justin Lai +Date: Wed, 3 Jun 2026 14:18:16 +0800 +Subject: rtase: Avoid sleeping in get_stats64() + +From: Justin Lai + +commit 9fc237f8d49f06d05f0f8e80361047b718894e81 upstream. + +The .ndo_get_stats64 callback must not sleep because it can be +called when reading /proc/net/dev. + +rtase_get_stats64() calls rtase_dump_tally_counter(), which polls +the tally counter dump bit with read_poll_timeout(). This may +sleep while waiting for the hardware counter dump to complete. + +Use read_poll_timeout_atomic() instead to avoid sleeping in the +get_stats64() path. + +Fixes: 079600489960 ("rtase: Implement net_device_ops") +Cc: stable@vger.kernel.org +Signed-off-by: Justin Lai +Link: https://patch.msgid.link/20260603061816.31356-1-justinlai0215@realtek.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/realtek/rtase/rtase_main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c ++++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c +@@ -1563,8 +1563,9 @@ static void rtase_dump_tally_counter(con + rtase_w32(tp, RTASE_DTCCR0, cmd); + rtase_w32(tp, RTASE_DTCCR0, cmd | RTASE_COUNTER_DUMP); + +- err = read_poll_timeout(rtase_r32, val, !(val & RTASE_COUNTER_DUMP), +- 10, 250, false, tp, RTASE_DTCCR0); ++ err = read_poll_timeout_atomic(rtase_r32, val, ++ !(val & RTASE_COUNTER_DUMP), ++ 10, 250, false, tp, RTASE_DTCCR0); + + if (err == -ETIMEDOUT) + netdev_err(tp->dev, "error occurred in dump tally counter\n"); diff --git a/queue-7.0/rtase-reset-tx-subqueue-when-clearing-tx-ring.patch b/queue-7.0/rtase-reset-tx-subqueue-when-clearing-tx-ring.patch new file mode 100644 index 0000000000..45741ee91e --- /dev/null +++ b/queue-7.0/rtase-reset-tx-subqueue-when-clearing-tx-ring.patch @@ -0,0 +1,41 @@ +From ab1ecaabe74b7d86c38ab2ab44bd56cdcc33645a Mon Sep 17 00:00:00 2001 +From: Justin Lai +Date: Tue, 2 Jun 2026 19:46:59 +0800 +Subject: rtase: Reset TX subqueue when clearing TX ring + +From: Justin Lai + +commit ab1ecaabe74b7d86c38ab2ab44bd56cdcc33645a upstream. + +rtase_tx_clear() clears the TX ring and resets the ring indexes. +However, the TX queue state and BQL accounting are not reset at +the same time. + +This may leave __QUEUE_STATE_STACK_XOFF asserted after +rtase_sw_reset(), preventing new TX packets from being scheduled. + +Reset the TX subqueue when clearing the TX ring so the TX queue +state and BQL accounting are restored together. + +Fixes: 5a2a2f15244c ("rtase: Implement the rtase_down function") +Cc: stable@vger.kernel.org +Signed-off-by: Justin Lai +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260602114659.12335-1-justinlai0215@realtek.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/realtek/rtase/rtase_main.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c ++++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c +@@ -239,6 +239,8 @@ static void rtase_tx_clear(struct rtase_ + rtase_tx_clear_range(ring, ring->dirty_idx, RTASE_NUM_DESC); + ring->cur_idx = 0; + ring->dirty_idx = 0; ++ ++ netdev_tx_reset_subqueue(tp->dev, i); + } + } + diff --git a/queue-7.0/rxrpc-fix-the-ack-parser-to-extract-the-sack-table-for-parsing.patch b/queue-7.0/rxrpc-fix-the-ack-parser-to-extract-the-sack-table-for-parsing.patch new file mode 100644 index 0000000000..d4f65c77a8 --- /dev/null +++ b/queue-7.0/rxrpc-fix-the-ack-parser-to-extract-the-sack-table-for-parsing.patch @@ -0,0 +1,100 @@ +From 333b6d5bb9f87827ac2639c737bf9613dbae7253 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 4 Jun 2026 12:46:00 +0100 +Subject: rxrpc: Fix the ACK parser to extract the SACK table for parsing + +From: David Howells + +commit 333b6d5bb9f87827ac2639c737bf9613dbae7253 upstream. + +Fix modification of the received skbuff in rxrpc_input_soft_acks() and a +potential incorrect access of the buffer in a fragmented UDP packet (the +packet would probably have to be deliberately pre-generated as fragmented) +when AF_RXRPC tries to extract the contents of the SACK table by copying +out the contents of the SACK table into a buffer before attempting to parse + +AF_RXRPC assumes that it can just call skb_condense() and then validly +access the SACK table from skb->data and that it will be a flat buffer - +but skb_condense() can silently fail to do anything under some +circumstances. + +Note that whilst rxrpc_input_soft_acks() should be able to parse extended +ACKs, the rest of AF_RXRPC doesn't currently support that. + +Further, there's then no need to call skb_condense() in rxrpc_input_ack(), +so don't. + +Fixes: d57a3a151660 ("rxrpc: Save last ACK's SACK table rather than marking txbufs") +Reported-by: Michael Bommarito +Link: https://lore.kernel.org/r/20260513180907.2061972-1-michael.bommarito@gmail.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Eric Dumazet +cc: "David S. Miller" +cc: Jakub Kicinski +cc: Paolo Abeni +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: netdev@vger.kernel.org +cc: stable@kernel.org +Link: https://patch.msgid.link/105362.1780573560@warthog.procyon.org.uk +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/input.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +--- a/net/rxrpc/input.c ++++ b/net/rxrpc/input.c +@@ -963,23 +963,34 @@ static void rxrpc_input_soft_acks(struct + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); + struct rxrpc_txqueue *tq = call->tx_queue; + unsigned long extracted = ~0UL; +- unsigned int nr = 0; ++ unsigned int nr = 0, nsack; + rxrpc_seq_t seq = call->acks_hard_ack + 1; + rxrpc_seq_t lowest_nak = seq + sp->ack.nr_acks; +- u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket); ++ u8 sack[256] __aligned(sizeof(unsigned long)); ++ u8 *acks = sack; + + _enter("%x,%x,%u", tq->qbase, seq, sp->ack.nr_acks); + + while (after(seq, tq->qbase + RXRPC_NR_TXQUEUE - 1)) + tq = tq->next; + ++ /* Extract an individual SACK table. A normal SACK table is up to 255 ++ * bytes with 1 ACK flag per byte, but an extended SACK table can be up ++ * to 256 bytes with up to 8 ACK/NACK flags per byte. The ACK flags go ++ * across all bit 0's then all bit 1's, then all bit 2's, ... ++ */ ++ memset(sack, 0, sizeof(sack)); ++ nsack = umin(sp->ack.nr_acks, 256); ++ if (skb_copy_bits(skb, ++ sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket), ++ sack, nsack) < 0) ++ return; ++ + for (unsigned int i = 0; i < sp->ack.nr_acks; i++) { + /* Decant ACKs until we hit a txqueue boundary. */ ++ if ((i & 255) == 0) ++ acks = sack; + shiftr_adv_rotr(acks, extracted); +- if (i == 256) { +- acks -= i; +- i = 0; +- } + seq++; + nr++; + if ((seq & RXRPC_TXQ_MASK) != 0) +@@ -1117,9 +1128,6 @@ static void rxrpc_input_ack(struct rxrpc + skb_copy_bits(skb, ioffset, &trailer, sizeof(trailer)) < 0) + return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack_trailer); + +- if (nr_acks > 0) +- skb_condense(skb); +- + call->acks_latest_ts = ktime_get_real(); + call->acks_hard_ack = hard_ack; + call->acks_prev_seq = prev_pkt; diff --git a/queue-7.0/sctp-diag-reject-stale-associations-in-dump_one-path.patch b/queue-7.0/sctp-diag-reject-stale-associations-in-dump_one-path.patch new file mode 100644 index 0000000000..8b05822df7 --- /dev/null +++ b/queue-7.0/sctp-diag-reject-stale-associations-in-dump_one-path.patch @@ -0,0 +1,78 @@ +From 5eba3e48d78edd7551b992cb7ba687019b3a78da Mon Sep 17 00:00:00 2001 +From: Zhao Zhang +Date: Sat, 30 May 2026 23:57:14 +0800 +Subject: sctp: diag: reject stale associations in dump_one path + +From: Zhao Zhang + +commit 5eba3e48d78edd7551b992cb7ba687019b3a78da upstream. + +The SCTP exact sock_diag lookup can hold a transport reference, block on +lock_sock(sk), and then resume after sctp_association_free() has marked +the association dead and freed its bind address list. + +When that happens, inet_assoc_attr_size() and +inet_diag_msg_sctpasoc_fill() can still dereference association state +that is no longer valid for reporting. In particular, +inet_diag_msg_sctpasoc_fill() may read an empty bind-address list as a +real sctp_sockaddr_entry and trigger an out-of-bounds read from +unrelated association memory. + +Reject the association after taking the socket lock if it has been +reaped or detached from the endpoint, and report the lookup as stale. +This keeps the exact dump-one path from formatting torn association +state. + +Fixes: 8f840e47f190 ("sctp: add the sctp_diag.c file") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Signed-off-by: Zhao Zhang +Signed-off-by: Ren Wei +Acked-by: Xin Long +Link: https://patch.msgid.link/fac6043fa20a2ff68e12958c431836f692c51268.1780113823.git.zzhan461@ucr.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/diag.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +--- a/net/sctp/diag.c ++++ b/net/sctp/diag.c +@@ -266,15 +266,15 @@ static int sctp_sock_dump_one(struct sct + + lock_sock(sk); + +- rep = nlmsg_new(inet_assoc_attr_size(sk, assoc), GFP_KERNEL); +- if (!rep) { +- release_sock(sk); +- return -ENOMEM; ++ if (ep != assoc->ep || assoc->base.dead) { ++ err = -ESTALE; ++ goto out_unlock; + } + +- if (ep != assoc->ep) { +- err = -EAGAIN; +- goto out; ++ rep = nlmsg_new(inet_assoc_attr_size(sk, assoc), GFP_KERNEL); ++ if (!rep) { ++ err = -ENOMEM; ++ goto out_unlock; + } + + err = inet_sctp_diag_fill(sk, assoc, rep, req, sk_user_ns(NETLINK_CB(skb).sk), +@@ -289,8 +289,9 @@ static int sctp_sock_dump_one(struct sct + return nlmsg_unicast(sock_net(skb->sk)->diag_nlsk, rep, NETLINK_CB(skb).portid); + + out: +- release_sock(sk); + kfree_skb(rep); ++out_unlock: ++ release_sock(sk); + return err; + } + diff --git a/queue-7.0/sctp-stream-fully-roll-back-denied-add-stream-state.patch b/queue-7.0/sctp-stream-fully-roll-back-denied-add-stream-state.patch new file mode 100644 index 0000000000..3da2d88952 --- /dev/null +++ b/queue-7.0/sctp-stream-fully-roll-back-denied-add-stream-state.patch @@ -0,0 +1,61 @@ +From a5f8a90ac9f77c678a9781c0a464b635e0d63e49 Mon Sep 17 00:00:00 2001 +From: Wyatt Feng +Date: Fri, 5 Jun 2026 13:53:42 +0800 +Subject: sctp: stream: fully roll back denied add-stream state + +From: Wyatt Feng + +commit a5f8a90ac9f77c678a9781c0a464b635e0d63e49 upstream. + +When ADD_OUT_STREAMS is denied, SCTP only shrinks the queued chunks and +then lowers outcnt. That leaves removed stream metadata behind, so a +later re-add can reuse a stale ext and hit a null-pointer dereference in +the scheduler get path. + +Fix the rollback by tearing down the removed stream state the same way +other stream resizes do. Unschedule the current scheduler state, drop +the removed stream ext state with sctp_stream_outq_migrate(), and then +reschedule the remaining streams. + +This keeps scheduler-private RR/FC/PRIO lists consistent while fully +rolling back denied outgoing stream additions. + +Fixes: 637784ade221 ("sctp: introduce priority based stream scheduler") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Signed-off-by: Wyatt Feng +Signed-off-by: Ren Wei +Acked-by: Xin Long +Link: https://patch.msgid.link/d78954ecd94954653ee299400e98d74a03a6f7d3.1780603399.git.bronzed_45_vested@icloud.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/stream.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/net/sctp/stream.c ++++ b/net/sctp/stream.c +@@ -1038,6 +1038,7 @@ struct sctp_chunk *sctp_process_strreset + stsn, rtsn, GFP_ATOMIC); + } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) { + struct sctp_strreset_addstrm *addstrm; ++ const struct sctp_sched_ops *sched; + __u16 number; + + addstrm = (struct sctp_strreset_addstrm *)req; +@@ -1048,7 +1049,10 @@ struct sctp_chunk *sctp_process_strreset + for (i = number; i < stream->outcnt; i++) + SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; + } else { +- sctp_stream_shrink_out(stream, number); ++ sched = sctp_sched_ops_from_stream(stream); ++ sched->unsched_all(stream); ++ sctp_stream_outq_migrate(stream, NULL, number); ++ sched->sched_all(stream); + stream->outcnt = number; + } + diff --git a/queue-7.0/series b/queue-7.0/series index 5e49ab677e..29d3827388 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -295,3 +295,40 @@ nvmem-core-fix-use-after-free-bugs-in-error-paths.patch nvmem-layouts-onie-tlv-fix-hang-on-unknown-types.patch octeontx2-af-fix-memory-leak-in-rvu_setup_hw_resources.patch pinctrl-mcp23s08-read-spi-present-mask-as-u8-not-u32.patch +mm-cma-fix-reserved-page-leak-on-activation-failure.patch +mm-cma_debug-fix-invalid-accesses-for-inactive-cma-areas.patch +mm-damon-lru_sort-handle-ctx-allocation-failure.patch +mm-damon-reclaim-handle-ctx-allocation-failure.patch +mm-huge_memory-use-correct-flags-for-device-private-pmd-entry.patch +mm-hugetlb-avoid-false-positive-lockdep-assertion.patch +mm-hugetlb-restore-reservation-on-error-in-hugetlb-folio-copy-paths.patch +mm-list_lru-drain-before-clearing-xarray-entry-on-reparent.patch +mm-mincore-handle-non-swap-entries-before-config_swap-guard.patch +mmc-core-fix-host-controller-programming-for-fixed-driver-type.patch +mmc-dw_mmc-rockchip-add-missing-private-data-for-very-old-controllers.patch +mmc-litex_mmc-set-mandatory-idle-clocks-before-cmd0.patch +mmc-renesas_sdhi-add-of-entry-for-rz-g2h-soc.patch +mmc-sdhci-of-dwcmshc-fix-reset-clk-and-sdio-support-for-eswin-eic7700.patch +mmc-sdhci-add-signal-voltage-switch-in-sdhci_resume_host.patch +pmdomain-imx-fix-of-node-refcount.patch +pmdomain-ti_sci-add-wakeup-constraint-to-parent-devices-of-wakeup-source.patch +rtase-avoid-sleeping-in-get_stats64.patch +rtase-reset-tx-subqueue-when-clearing-tx-ring.patch +rxrpc-fix-the-ack-parser-to-extract-the-sack-table-for-parsing.patch +sctp-diag-reject-stale-associations-in-dump_one-path.patch +sctp-stream-fully-roll-back-denied-add-stream-state.patch +thunderbolt-reject-zero-length-property-entries-in-validator.patch +thunderbolt-bound-root-directory-content-to-block-size.patch +thunderbolt-clamp-xdomain-response-data-copy-to-allocation-size.patch +thunderbolt-validate-xdomain-request-packet-size-before-type-cast.patch +thunderbolt-limit-xdomain-response-copy-to-actual-frame-size.patch +slimbus-qcom-ngd-ctrl-fix-of-node-refcount.patch +slimbus-qcom-ngd-ctrl-fix-up-platform_driver-registration.patch +slimbus-qcom-ngd-ctrl-fix-probe-error-path-ordering.patch +slimbus-qcom-ngd-ctrl-register-callbacks-after-creating-the-ngd.patch +slimbus-qcom-ngd-ctrl-initialize-controller-resources-in-controller.patch +slimbus-qcom-ngd-ctrl-correct-pdr-and-ssr-cleanup-ownership.patch +slimbus-qcom-ngd-ctrl-balance-pm_runtime-enablement-for-ngd.patch +slimbus-qcom-ngd-ctrl-avoid-abba-on-tx_lock-ctrl-lock.patch +drm-gem-try-to-fix-change_handle-ioctl-attempt-4.patch +drm-i915-fix-color-blob-reference-handling-in-intel_plane_state.patch diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-avoid-abba-on-tx_lock-ctrl-lock.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-avoid-abba-on-tx_lock-ctrl-lock.patch new file mode 100644 index 0000000000..e62bfa7db9 --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-avoid-abba-on-tx_lock-ctrl-lock.patch @@ -0,0 +1,76 @@ +From 55f2ea9ff83cc27a85526b14bc9b32f96a08d6ec Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Sat, 30 May 2026 21:44:21 +0100 +Subject: slimbus: qcom-ngd-ctrl: Avoid ABBA on tx_lock/ctrl->lock + +From: Bjorn Andersson + +commit 55f2ea9ff83cc27a85526b14bc9b32f96a08d6ec upstream. + +During the SSR/PDR down notification the tx_lock is taken with the +intent to provide synchronization with active DMA transfers. + +But during this period qcom_slim_ngd_down() is invoked, which ends up in +slim_report_absent(), which takes the slim_controller lock. In multiple +other codepaths these two locks are taken in the opposite order (i.e. +slim_controller then tx_lock). + +The result is a lockdep splat, and a possible deadlock: + + rprocctl/449 is trying to acquire lock: + ffff00009793e620 (&ctrl->lock){+.+.}-{4:4}, at: slim_report_absent (drivers/slimbus/core.c:322) slimbus + + but task is already holding lock: + ffff00009793fb50 (&ctrl->tx_lock){+.+.}-{4:4}, at: qcom_slim_ngd_ssr_pdr_notify (drivers/slimbus/qcom-ngd-ctrl.c:1475) slim_qcom_ngd_ctrl + + which lock already depends on the new lock. + + Possible unsafe locking scenario: + + CPU0 CPU1 + ---- ---- + lock(&ctrl->tx_lock); + lock(&ctrl->lock); + lock(&ctrl->tx_lock); + lock(&ctrl->lock); + +The assumption is that the comment refers to the desire to not call +qcom_slim_ngd_exit_dma() while we have an ongoing DMA TX transaction. +But any such transaction is initiated and completed within a single +qcom_slim_ngd_xfer_msg(). + +Prior to calling qcom_slim_ngd_exit_dma() the slim_controller is torn +down, all child devices are notified that the slimbus is gone and the +child devices are removed. + +Stop taking the tx_lock in qcom_slim_ngd_ssr_pdr_notify() to avoid the +deadlock. + +Fixes: a899d324863a ("slimbus: qcom-ngd-ctrl: add Sub System Restart support") +Cc: stable@vger.kernel.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-9-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1471,15 +1471,12 @@ static int qcom_slim_ngd_ssr_pdr_notify( + switch (action) { + case QCOM_SSR_BEFORE_SHUTDOWN: + case SERVREG_SERVICE_STATE_DOWN: +- /* Make sure the last dma xfer is finished */ +- mutex_lock(&ctrl->tx_lock); + if (ctrl->state != QCOM_SLIM_NGD_CTRL_DOWN) { + pm_runtime_get_noresume(ctrl->ctrl.dev); + ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN; + qcom_slim_ngd_down(ctrl); + qcom_slim_ngd_exit_dma(ctrl); + } +- mutex_unlock(&ctrl->tx_lock); + break; + case QCOM_SSR_AFTER_POWERUP: + case SERVREG_SERVICE_STATE_UP: diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-balance-pm_runtime-enablement-for-ngd.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-balance-pm_runtime-enablement-for-ngd.patch new file mode 100644 index 0000000000..a146014b1a --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-balance-pm_runtime-enablement-for-ngd.patch @@ -0,0 +1,45 @@ +From 6a003446b725c44b9e3ffa111b0effbaa2d43085 Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Sat, 30 May 2026 21:44:20 +0100 +Subject: slimbus: qcom-ngd-ctrl: Balance pm_runtime enablement for NGD + +From: Bjorn Andersson + +commit 6a003446b725c44b9e3ffa111b0effbaa2d43085 upstream. + +The pm_runtime_enable() and pm_runtime_use_autosuspend() calls are +supposed to be balanced on exit, add these calls. + +Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver") +Cc: stable@vger.kernel.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-8-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1582,8 +1582,11 @@ static int qcom_slim_ngd_probe(struct pl + pm_runtime_enable(dev); + pm_runtime_get_noresume(dev); + ret = qcom_slim_ngd_qmi_svc_event_init(ctrl); +- if (ret) ++ if (ret) { + dev_err(&pdev->dev, "QMI service registration failed:%d", ret); ++ pm_runtime_dont_use_autosuspend(dev); ++ pm_runtime_disable(dev); ++ } + + return ret; + } +@@ -1696,6 +1699,7 @@ static void qcom_slim_ngd_remove(struct + { + struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); + ++ pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + qcom_slim_ngd_enable(ctrl, false); + qcom_slim_ngd_exit_dma(ctrl); diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-correct-pdr-and-ssr-cleanup-ownership.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-correct-pdr-and-ssr-cleanup-ownership.patch new file mode 100644 index 0000000000..49e9314e06 --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-correct-pdr-and-ssr-cleanup-ownership.patch @@ -0,0 +1,49 @@ +From 960b53a3f76fa214c2fc493734ae7b3c5e713bbf Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Sat, 30 May 2026 21:44:17 +0100 +Subject: slimbus: qcom-ngd-ctrl: Correct PDR and SSR cleanup ownership + +From: Bjorn Andersson + +commit 960b53a3f76fa214c2fc493734ae7b3c5e713bbf upstream. + +PDR and SSR callbacks are registred from the controller probe function, +but currently released from the child device's remove function. + +The remove() function should only be unwinding what was done in the +same device's probe() function. + +Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver") +Cc: stable@vger.kernel.org +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Mukesh Ojha +Signed-off-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-5-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1684,6 +1684,9 @@ static void qcom_slim_ngd_ctrl_remove(st + { + struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); + ++ pdr_handle_release(ctrl->pdr); ++ qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); ++ + qcom_slim_ngd_unregister(ctrl); + + destroy_workqueue(ctrl->mwq); +@@ -1694,8 +1697,6 @@ static void qcom_slim_ngd_remove(struct + struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); +- pdr_handle_release(ctrl->pdr); +- qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); + qcom_slim_ngd_enable(ctrl, false); + qcom_slim_ngd_exit_dma(ctrl); + qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-fix-of-node-refcount.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-fix-of-node-refcount.patch new file mode 100644 index 0000000000..619240433b --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-fix-of-node-refcount.patch @@ -0,0 +1,39 @@ +From 120134fe75c6b0ae38f14eb8b548ad1e5761f912 Mon Sep 17 00:00:00 2001 +From: Bartosz Golaszewski +Date: Sat, 30 May 2026 21:44:14 +0100 +Subject: slimbus: qcom-ngd-ctrl: fix OF node refcount + +From: Bartosz Golaszewski + +commit 120134fe75c6b0ae38f14eb8b548ad1e5761f912 upstream. + +Platform devices created with platform_device_alloc() call +platform_device_release() when the last reference to the device's +kobject is dropped. This function calls of_node_put() unconditionally. +This works fine for devices created with platform_device_register_full() +but users of the split approach (platform_device_alloc() + +platform_device_add()) must bump the reference of the of_node they +assign manually. Add the missing call to of_node_get(). + +Cc: stable@vger.kernel.org +Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver") +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-2-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1542,7 +1542,7 @@ static int of_qcom_slim_ngd_register(str + kfree(ngd); + return ret; + } +- ngd->pdev->dev.of_node = node; ++ ngd->pdev->dev.of_node = of_node_get(node); + ctrl->ngd = ngd; + + ret = platform_device_add(ngd->pdev); diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-fix-probe-error-path-ordering.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-fix-probe-error-path-ordering.patch new file mode 100644 index 0000000000..e731bf5a44 --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-fix-probe-error-path-ordering.patch @@ -0,0 +1,55 @@ +From 2c22ff152d380ec3d3af099fa05d0ac5ca9b4c1e Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Sat, 30 May 2026 21:44:16 +0100 +Subject: slimbus: qcom-ngd-ctrl: Fix probe error path ordering + +From: Bjorn Andersson + +commit 2c22ff152d380ec3d3af099fa05d0ac5ca9b4c1e upstream. + +qcom_slim_ngd_ctrl_probe() first registers the SSR callback then +allocates the PDR context, as such the error path needs to come in +opposite order to allow us to unroll each step. + +Fixes: 16f14551d0df ("slimbus: qcom-ngd: cleanup in probe error path") +Cc: stable@vger.kernel.org +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Mukesh Ojha +Signed-off-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-4-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1660,22 +1660,21 @@ static int qcom_slim_ngd_ctrl_probe(stru + if (IS_ERR(ctrl->pdr)) { + ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), + "Failed to init PDR handle\n"); +- goto err_pdr_alloc; ++ goto err_unregister_ssr; + } + + pds = pdr_add_lookup(ctrl->pdr, "avs/audio", "msm/adsp/audio_pd"); + if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { + ret = dev_err_probe(dev, PTR_ERR(pds), "pdr add lookup failed\n"); +- goto err_pdr_lookup; ++ goto err_pdr_release; + } + + return of_qcom_slim_ngd_register(dev, ctrl); + +-err_pdr_alloc: +- qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); +- +-err_pdr_lookup: ++err_pdr_release: + pdr_handle_release(ctrl->pdr); ++err_unregister_ssr: ++ qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); + + return ret; + } diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-fix-up-platform_driver-registration.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-fix-up-platform_driver-registration.patch new file mode 100644 index 0000000000..df109dc1e1 --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-fix-up-platform_driver-registration.patch @@ -0,0 +1,94 @@ +From 8663e8334d7b6007f5d8a4e5dd270246f35107a6 Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Sat, 30 May 2026 21:44:15 +0100 +Subject: slimbus: qcom-ngd-ctrl: Fix up platform_driver registration + +From: Bjorn Andersson + +commit 8663e8334d7b6007f5d8a4e5dd270246f35107a6 upstream. + +Device drivers should not invoke platform_driver_register()/unregister() +in their probe and remove paths. They should further not rely on +platform_driver_unregister() as their only means of "deleting" their +child devices. + +Introduce a helper to unregister the child device and move the +platform_driver_register()/unregister() to module_init()/exit(). + +Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver") +Cc: stable@vger.kernel.org +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Mukesh Ojha +Signed-off-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-3-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 36 +++++++++++++++++++++++++++++++++--- + 1 file changed, 33 insertions(+), 3 deletions(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1560,6 +1560,13 @@ static int of_qcom_slim_ngd_register(str + return -ENODEV; + } + ++static void qcom_slim_ngd_unregister(struct qcom_slim_ngd_ctrl *ctrl) ++{ ++ struct qcom_slim_ngd *ngd = ctrl->ngd; ++ ++ platform_device_del(ngd->pdev); ++} ++ + static int qcom_slim_ngd_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -1662,7 +1669,6 @@ static int qcom_slim_ngd_ctrl_probe(stru + goto err_pdr_lookup; + } + +- platform_driver_register(&qcom_slim_ngd_driver); + return of_qcom_slim_ngd_register(dev, ctrl); + + err_pdr_alloc: +@@ -1676,7 +1682,9 @@ err_pdr_lookup: + + static void qcom_slim_ngd_ctrl_remove(struct platform_device *pdev) + { +- platform_driver_unregister(&qcom_slim_ngd_driver); ++ struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); ++ ++ qcom_slim_ngd_unregister(ctrl); + } + + static void qcom_slim_ngd_remove(struct platform_device *pdev) +@@ -1752,6 +1760,28 @@ static struct platform_driver qcom_slim_ + }, + }; + +-module_platform_driver(qcom_slim_ngd_ctrl_driver); ++static int qcom_slim_ngd_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&qcom_slim_ngd_driver); ++ if (ret) ++ return ret; ++ ++ ret = platform_driver_register(&qcom_slim_ngd_ctrl_driver); ++ if (ret) ++ platform_driver_unregister(&qcom_slim_ngd_driver); ++ ++ return ret; ++} ++ ++static void qcom_slim_ngd_exit(void) ++{ ++ platform_driver_unregister(&qcom_slim_ngd_ctrl_driver); ++ platform_driver_unregister(&qcom_slim_ngd_driver); ++} ++ ++module_init(qcom_slim_ngd_init); ++module_exit(qcom_slim_ngd_exit); + MODULE_LICENSE("GPL v2"); + MODULE_DESCRIPTION("Qualcomm SLIMBus NGD controller"); diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-initialize-controller-resources-in-controller.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-initialize-controller-resources-in-controller.patch new file mode 100644 index 0000000000..3636e9d133 --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-initialize-controller-resources-in-controller.patch @@ -0,0 +1,108 @@ +From 07c564ea5fb859b7381429de935d5df4781947c6 Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Sat, 30 May 2026 21:44:19 +0100 +Subject: slimbus: qcom-ngd-ctrl: Initialize controller resources in controller + +From: Bjorn Andersson + +commit 07c564ea5fb859b7381429de935d5df4781947c6 upstream. + +The work structs and work queue are controller resources, create and +destroy them in the controller context. Creating them as part of the +child device's probe path seems to be okay now that the controller's +probe has been updated, but if for some reason the child does not probe +successfully a SSR or PDR notification will schedule_work() on an +uninitialized "ngd_up_work". + +Move the initialization of these controller resources to the controller +probe function to avoid any issues, and to clarify the ownership. + +Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver") +Cc: stable@vger.kernel.org +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Mukesh Ojha +Signed-off-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-7-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 38 ++++++++++++++++---------------------- + 1 file changed, 16 insertions(+), 22 deletions(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1582,25 +1582,8 @@ static int qcom_slim_ngd_probe(struct pl + pm_runtime_enable(dev); + pm_runtime_get_noresume(dev); + ret = qcom_slim_ngd_qmi_svc_event_init(ctrl); +- if (ret) { ++ if (ret) + dev_err(&pdev->dev, "QMI service registration failed:%d", ret); +- return ret; +- } +- +- INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker); +- INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker); +- ctrl->mwq = create_singlethread_workqueue("ngd_master"); +- if (!ctrl->mwq) { +- dev_err(&pdev->dev, "Failed to start master worker\n"); +- ret = -ENOMEM; +- goto wq_err; +- } +- +- return 0; +-wq_err: +- qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); +- if (ctrl->mwq) +- destroy_workqueue(ctrl->mwq); + + return ret; + } +@@ -1653,9 +1636,18 @@ static int qcom_slim_ngd_ctrl_probe(stru + init_completion(&ctrl->qmi.qmi_comp); + init_completion(&ctrl->qmi_up); + ++ INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker); ++ INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker); ++ ++ ctrl->mwq = create_singlethread_workqueue("ngd_master"); ++ if (!ctrl->mwq) ++ return dev_err_probe(dev, -ENOMEM, "Failed to start master worker\n"); ++ + ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl); +- if (IS_ERR(ctrl->pdr)) +- return dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n"); ++ if (IS_ERR(ctrl->pdr)) { ++ ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n"); ++ goto err_destroy_mwq; ++ } + + ret = of_qcom_slim_ngd_register(dev, ctrl); + if (ret) +@@ -1682,6 +1674,8 @@ err_unregister_ngd: + qcom_slim_ngd_unregister(ctrl); + err_pdr_release: + pdr_handle_release(ctrl->pdr); ++err_destroy_mwq: ++ destroy_workqueue(ctrl->mwq); + + return ret; + } +@@ -1691,6 +1685,8 @@ static void qcom_slim_ngd_ctrl_remove(st + struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); + + qcom_slim_ngd_unregister(ctrl); ++ ++ destroy_workqueue(ctrl->mwq); + } + + static void qcom_slim_ngd_remove(struct platform_device *pdev) +@@ -1703,8 +1699,6 @@ static void qcom_slim_ngd_remove(struct + qcom_slim_ngd_enable(ctrl, false); + qcom_slim_ngd_exit_dma(ctrl); + qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); +- if (ctrl->mwq) +- destroy_workqueue(ctrl->mwq); + + kfree(ctrl->ngd); + ctrl->ngd = NULL; diff --git a/queue-7.0/slimbus-qcom-ngd-ctrl-register-callbacks-after-creating-the-ngd.patch b/queue-7.0/slimbus-qcom-ngd-ctrl-register-callbacks-after-creating-the-ngd.patch new file mode 100644 index 0000000000..28b12de29e --- /dev/null +++ b/queue-7.0/slimbus-qcom-ngd-ctrl-register-callbacks-after-creating-the-ngd.patch @@ -0,0 +1,133 @@ +From 2a9d50e9ea406e0c8735938484adc20515ef1b47 Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Sat, 30 May 2026 21:44:18 +0100 +Subject: slimbus: qcom-ngd-ctrl: Register callbacks after creating the ngd + +From: Bjorn Andersson + +commit 2a9d50e9ea406e0c8735938484adc20515ef1b47 upstream. + +When the remoteproc starts in parallel with the NGD driver being probed, +or the remoteproc is already up when the PDR lookup is being registered, +or in the theoretical event that we get an interrupt from the hardware, +these callbacks will operate on uninitialized data. This result in +issues to boot the affected boards. + +One such example can be seen in the following fault, where +qcom_slim_ngd_ssr_pdr_notify() schedules work on the NULL ngd_up_work. + +[ 21.858578] ------------[ cut here ]------------ +[ 21.858745] WARNING: kernel/workqueue.c:2338 at __queue_work+0x5e0/0x790, CPU#2: kworker/2:2/116 +... +[ 21.859251] Call trace: +[ 21.859255] __queue_work+0x5e0/0x790 (P) +[ 21.859265] queue_work_on+0x6c/0xf0 +[ 21.859273] qcom_slim_ngd_ssr_pdr_notify+0x110/0x150 [slim_qcom_ngd_ctrl] +[ 21.859304] qcom_slim_ngd_ssr_notify+0x24/0x40 [slim_qcom_ngd_ctrl] +[ 21.859318] notifier_call_chain+0xa4/0x230 +[ 21.859329] srcu_notifier_call_chain+0x64/0xb8 +[ 21.859338] ssr_notify_start+0x40/0x78 [qcom_common] +[ 21.859355] rproc_start+0x130/0x230 +[ 21.859367] rproc_boot+0x3d4/0x518 +... + +Move the enablement of interrupts, and the registration of SSR and PDR +until after the NGD device has been registered. + +This could be further refined by moving initialization to the control +driver probe and by removing the platform driver model from the picture. + +Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver") +Cc: stable@vger.kernel.org +Reviewed-by: Mukesh Ojha +Signed-off-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260530204421.116824-6-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/slimbus/qcom-ngd-ctrl.c | 47 ++++++++++++++++++++++------------------ + 1 file changed, 27 insertions(+), 20 deletions(-) + +--- a/drivers/slimbus/qcom-ngd-ctrl.c ++++ b/drivers/slimbus/qcom-ngd-ctrl.c +@@ -1609,6 +1609,7 @@ static int qcom_slim_ngd_ctrl_probe(stru + { + struct device *dev = &pdev->dev; + struct qcom_slim_ngd_ctrl *ctrl; ++ int irq; + int ret; + struct pdr_service *pds; + +@@ -1622,20 +1623,16 @@ static int qcom_slim_ngd_ctrl_probe(stru + if (IS_ERR(ctrl->base)) + return PTR_ERR(ctrl->base); + +- ret = platform_get_irq(pdev, 0); +- if (ret < 0) +- return ret; +- +- ret = devm_request_irq(dev, ret, qcom_slim_ngd_interrupt, +- IRQF_TRIGGER_HIGH, "slim-ngd", ctrl); ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_irq(dev, irq, qcom_slim_ngd_interrupt, ++ IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, ++ "slim-ngd", ctrl); + if (ret) + return dev_err_probe(&pdev->dev, ret, "request IRQ failed\n"); + +- ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify; +- ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb); +- if (IS_ERR(ctrl->notifier)) +- return PTR_ERR(ctrl->notifier); +- + ctrl->dev = dev; + ctrl->framer.rootfreq = SLIM_ROOT_FREQ >> 3; + ctrl->framer.superfreq = +@@ -1657,24 +1654,34 @@ static int qcom_slim_ngd_ctrl_probe(stru + init_completion(&ctrl->qmi_up); + + ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl); +- if (IS_ERR(ctrl->pdr)) { +- ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), +- "Failed to init PDR handle\n"); +- goto err_unregister_ssr; +- } ++ if (IS_ERR(ctrl->pdr)) ++ return dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n"); ++ ++ ret = of_qcom_slim_ngd_register(dev, ctrl); ++ if (ret) ++ goto err_pdr_release; + + pds = pdr_add_lookup(ctrl->pdr, "avs/audio", "msm/adsp/audio_pd"); + if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { + ret = dev_err_probe(dev, PTR_ERR(pds), "pdr add lookup failed\n"); +- goto err_pdr_release; ++ goto err_unregister_ngd; + } + +- return of_qcom_slim_ngd_register(dev, ctrl); ++ ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify; ++ ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb); ++ if (IS_ERR(ctrl->notifier)) { ++ ret = PTR_ERR(ctrl->notifier); ++ goto err_unregister_ngd; ++ } ++ ++ enable_irq(irq); ++ ++ return 0; + ++err_unregister_ngd: ++ qcom_slim_ngd_unregister(ctrl); + err_pdr_release: + pdr_handle_release(ctrl->pdr); +-err_unregister_ssr: +- qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); + + return ret; + } diff --git a/queue-7.0/thunderbolt-bound-root-directory-content-to-block-size.patch b/queue-7.0/thunderbolt-bound-root-directory-content-to-block-size.patch new file mode 100644 index 0000000000..b8df5697a8 --- /dev/null +++ b/queue-7.0/thunderbolt-bound-root-directory-content-to-block-size.patch @@ -0,0 +1,40 @@ +From 65423079c7420e3dbf9a7aa345c243a3f5752e5d Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Mon, 25 May 2026 05:28:26 -0400 +Subject: thunderbolt: Bound root directory content to block size + +From: Michael Bommarito + +commit 65423079c7420e3dbf9a7aa345c243a3f5752e5d upstream. + +__tb_property_parse_dir() does not check that content_offset + +content_len fits within block_len for the root directory case. +When rootdir->length equals or exceeds block_len - 2, the entry +loop reads past the allocated property block. + +Add a bounds check after computing content_offset and content_len +to reject directories whose content extends past the block. + +Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties") +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: Greg Kroah-Hartman +--- + drivers/thunderbolt/property.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/thunderbolt/property.c ++++ b/drivers/thunderbolt/property.c +@@ -187,6 +187,10 @@ static struct tb_property_dir *__tb_prop + if (is_root) { + content_offset = dir_offset + 2; + content_len = dir_len; ++ if (content_offset + content_len > block_len) { ++ tb_property_free_dir(dir); ++ return NULL; ++ } + } else { + if (dir_len < 4) { + tb_property_free_dir(dir); diff --git a/queue-7.0/thunderbolt-clamp-xdomain-response-data-copy-to-allocation-size.patch b/queue-7.0/thunderbolt-clamp-xdomain-response-data-copy-to-allocation-size.patch new file mode 100644 index 0000000000..3236418b98 --- /dev/null +++ b/queue-7.0/thunderbolt-clamp-xdomain-response-data-copy-to-allocation-size.patch @@ -0,0 +1,39 @@ +From 322e93448d908434ae5545660fcbe8f5a7a8e141 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Mon, 25 May 2026 05:28:27 -0400 +Subject: thunderbolt: Clamp XDomain response data copy to allocation size + +From: Michael Bommarito + +commit 322e93448d908434ae5545660fcbe8f5a7a8e141 upstream. + +tb_xdp_properties_request() derives the per-packet copy length from +the response header without checking that it fits in the previously +allocated data buffer. A malicious peer can set its length field +larger than the declared data_length, causing memcpy to write past +the kcalloc allocation. + +Clamp the per-packet copy length so that the cumulative offset +never exceeds data_len. + +Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties") +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: Greg Kroah-Hartman +--- + drivers/thunderbolt/xdomain.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/thunderbolt/xdomain.c ++++ b/drivers/thunderbolt/xdomain.c +@@ -393,6 +393,8 @@ static int tb_xdp_properties_request(str + } + } + ++ if (req.offset + len > data_len) ++ len = data_len - req.offset; + memcpy(data + req.offset, res->data, len * 4); + req.offset += len; + } while (!data_len || req.offset < data_len); diff --git a/queue-7.0/thunderbolt-limit-xdomain-response-copy-to-actual-frame-size.patch b/queue-7.0/thunderbolt-limit-xdomain-response-copy-to-actual-frame-size.patch new file mode 100644 index 0000000000..046d0e8e0f --- /dev/null +++ b/queue-7.0/thunderbolt-limit-xdomain-response-copy-to-actual-frame-size.patch @@ -0,0 +1,40 @@ +From 4db2bd2ed4785dbadaeeab9f4e346b21ac5fb8eb Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Mon, 25 May 2026 05:28:29 -0400 +Subject: thunderbolt: Limit XDomain response copy to actual frame size + +From: Michael Bommarito + +commit 4db2bd2ed4785dbadaeeab9f4e346b21ac5fb8eb upstream. + +tb_xdomain_copy() copies req->response_size bytes from the received +packet buffer regardless of the actual frame size. When a short +response arrives, this reads past the valid frame data in the DMA +pool buffer into stale contents from previous transactions. + +Use the minimum of frame size and expected response size for the +copy length. + +Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties") +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: Greg Kroah-Hartman +--- + drivers/thunderbolt/xdomain.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/thunderbolt/xdomain.c ++++ b/drivers/thunderbolt/xdomain.c +@@ -123,7 +123,9 @@ static bool tb_xdomain_match(const struc + static bool tb_xdomain_copy(struct tb_cfg_request *req, + const struct ctl_pkg *pkg) + { +- memcpy(req->response, pkg->buffer, req->response_size); ++ size_t len = min_t(size_t, pkg->frame.size, req->response_size); ++ ++ memcpy(req->response, pkg->buffer, len); + req->result.err = 0; + return true; + } diff --git a/queue-7.0/thunderbolt-reject-zero-length-property-entries-in-validator.patch b/queue-7.0/thunderbolt-reject-zero-length-property-entries-in-validator.patch new file mode 100644 index 0000000000..8fecdf80c2 --- /dev/null +++ b/queue-7.0/thunderbolt-reject-zero-length-property-entries-in-validator.patch @@ -0,0 +1,42 @@ +From cff8eb65d1eafe7793e54b4d0cf6bf831644630b Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Mon, 25 May 2026 05:28:25 -0400 +Subject: thunderbolt: Reject zero-length property entries in validator + +From: Michael Bommarito + +commit cff8eb65d1eafe7793e54b4d0cf6bf831644630b upstream. + +tb_property_entry_valid() accepts entries with length == 0 for +DIRECTORY, DATA, and TEXT types. A zero-length TEXT entry passes +validation but causes an underflow in the null-termination logic: + + property->value.text[property->length * 4 - 1] = '\0'; + +When property->length is 0 this writes to offset -1 relative to +the allocation. + +Reject zero-length entries early in the validator since they have no +valid representation in the XDomain property protocol. + +Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties") +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: Greg Kroah-Hartman +--- + drivers/thunderbolt/property.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/thunderbolt/property.c ++++ b/drivers/thunderbolt/property.c +@@ -60,6 +60,8 @@ static bool tb_property_entry_valid(cons + case TB_PROPERTY_TYPE_DIRECTORY: + case TB_PROPERTY_TYPE_DATA: + case TB_PROPERTY_TYPE_TEXT: ++ if (!entry->length) ++ return false; + if (entry->length > block_len) + return false; + if (check_add_overflow(entry->value, entry->length, &end) || diff --git a/queue-7.0/thunderbolt-validate-xdomain-request-packet-size-before-type-cast.patch b/queue-7.0/thunderbolt-validate-xdomain-request-packet-size-before-type-cast.patch new file mode 100644 index 0000000000..181bcba326 --- /dev/null +++ b/queue-7.0/thunderbolt-validate-xdomain-request-packet-size-before-type-cast.patch @@ -0,0 +1,75 @@ +From a504b9f2797b739e0304d537e8aa4ce883ecce39 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Mon, 25 May 2026 05:28:28 -0400 +Subject: thunderbolt: Validate XDomain request packet size before type cast + +From: Michael Bommarito + +commit a504b9f2797b739e0304d537e8aa4ce883ecce39 upstream. + +tb_xdp_handle_request() casts the received packet buffer to +protocol-specific structs without verifying that the allocation +is large enough for the target type. A peer can send a minimal +XDomain packet that passes the generic header length check but is +shorter than the struct accessed after the cast, causing out-of- +bounds reads from the kmemdup allocation. + +Plumb the packet length through xdomain_request_work and validate +it against the expected struct size before each cast. + +Fixes: 8e1de7042596 ("thunderbolt: Add support for XDomain lane bonding") +Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties") +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: Greg Kroah-Hartman +--- + drivers/thunderbolt/xdomain.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/thunderbolt/xdomain.c ++++ b/drivers/thunderbolt/xdomain.c +@@ -55,6 +55,7 @@ static const char * const state_names[] + struct xdomain_request_work { + struct work_struct work; + struct tb_xdp_header *pkg; ++ size_t pkg_len; + struct tb *tb; + }; + +@@ -733,6 +734,7 @@ static void tb_xdp_handle_request(struct + struct xdomain_request_work *xw = container_of(work, typeof(*xw), work); + const struct tb_xdp_header *pkg = xw->pkg; + const struct tb_xdomain_header *xhdr = &pkg->xd_hdr; ++ size_t pkg_len = xw->pkg_len; + struct tb *tb = xw->tb; + struct tb_ctl *ctl = tb->ctl; + struct tb_xdomain *xd; +@@ -764,7 +766,7 @@ static void tb_xdp_handle_request(struct + switch (pkg->type) { + case PROPERTIES_REQUEST: + tb_dbg(tb, "%llx: received XDomain properties request\n", route); +- if (xd) { ++ if (xd && pkg_len >= sizeof(struct tb_xdp_properties)) { + ret = tb_xdp_properties_response(tb, ctl, xd, sequence, + (const struct tb_xdp_properties *)pkg); + } +@@ -818,7 +820,8 @@ static void tb_xdp_handle_request(struct + tb_dbg(tb, "%llx: received XDomain link state change request\n", + route); + +- if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH) { ++ if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH && ++ pkg_len >= sizeof(struct tb_xdp_link_state_change)) { + const struct tb_xdp_link_state_change *lsc = + (const struct tb_xdp_link_state_change *)pkg; + +@@ -870,6 +873,7 @@ tb_xdp_schedule_request(struct tb *tb, c + kfree(xw); + return false; + } ++ xw->pkg_len = size; + xw->tb = tb_domain_get(tb); + + schedule_work(&xw->work);