Compare commits

...

63 Commits

Author SHA1 Message Date
Linus Torvalds ba3e43a9e6 soc: fixes for 7.1, part 2
Following the previous set of fixes, this addresses another significant
 number of small issues found in firmware drivers (tee, optee, qcomtee,
 qcom ice, exynos acpm) drivers through various tools. This is about
 error handling, resource leaks, concurrency and a use-after-free bug.
 
 The fixes for the Qualcomm ICE driver also introduce interface changes
 in the UFS and MMC drivers using it.
 
 Outside of firmware drivers, there are a few fixes across the tree:
 
  - Minor driver code mistakes in the Atmel EBI memory controller,
    the i.MX soc ID driver and socfpga boot logic
 
  - A defconfig change to avoid a boot time regression on multiple
    qualcomm boards
 
  - Device tree fixes for qualcomm, at91 and gemini, addressing
    mostly minor configuration mistakes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmofFFQACgkQmmx57+YA
 GNkoZxAAjEoE6xgVJjQBQug02+puOll3DSjYjYahg434nUoIpfY4bU4247eUtvxi
 QU5kSRQbMaYBpBM5pqgqdG0P0KiP8UsrDWgGr1CbHhCtO2H2cJ6ICUFAXmgpZ+n3
 P7R4hROu+EoRb6urgRG6koL6LYId1nRSKOvWsPEz8cXcVE/nwdaYgU6GB9aS2B0v
 zAcLGMtACNU9iiDZNW+pt97CkMr38pjEkcmWxfQBSqcjck0JsujHCuCWLwPALKAo
 V1aSKPgg1YUMs3+2LeXyhv5rFrBmXfRJ1v7unLKXAvJ9k+DZb63D5AIFT6xjD7Qh
 nF/IgPmiFPaYKVskTWS7UHWVLZY7mBstb4gWei1fNE8deCXA35ntuNSg1YkIabvF
 s/g5g2/EuiCTobZLO+xAGHJvfB/iVx2k2w6CzYpxXtOOf8CNzskWkRnerK3RF+TM
 LIN1JhrZJzAnHL+Z8jv3z2+vo1sUOMuQax723xYoh/7LUUr1yp0hBJExkjJJ8s3q
 5GOob3WnjH9n15OAsJvNXlKIWstIi/BPSXyATmca6tDsEnuv3KE9Sok4ZT/Gsjxk
 2L/aIlnnu6qX4BlQ7Hrfl2+LDp7jX1RP7MFMGxHscD36ws7ZU9asoUc5MxPrnZno
 Oay2HTyiA42YvsN+R6oI331VSTd/hXLemqvP9JpENvSbpuGm2So=
 =uqVQ
 -----END PGP SIGNATURE-----

Merge tag 'soc-fixes-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc

Pull SoC fixes from Arnd Bergmann:
 "Following the previous set of fixes, this addresses another
  significant number of small issues found in firmware drivers (tee,
  optee, qcomtee, qcom ice, exynos acpm) drivers through various tools.

  This is about error handling, resource leaks, concurrency and a
  use-after-free bug.

  The fixes for the Qualcomm ICE driver also introduce interface changes
  in the UFS and MMC drivers using it.

  Outside of firmware drivers, there are a few fixes across the tree:

   - Minor driver code mistakes in the Atmel EBI memory controller, the
     i.MX soc ID driver and socfpga boot logic

   - A defconfig change to avoid a boot time regression on multiple
     qualcomm boards

   - Device tree fixes for qualcomm, at91 and gemini, addressing mostly
     minor configuration mistakes"

* tag 'soc-fixes-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (28 commits)
  firmware: samsung: acpm: Fix infinite loop on sequence number exhaustion
  firmware: samsung: acpm: Fix missing LKMM barriers in sequence allocator
  firmware: samsung: acpm: Fix false timeouts and Use-After-Free in polling
  ARM: dts: gemini: Fix partition offsets
  ARM: socfpga: Fix OF node refcount leak in SMP setup
  soc: qcom: ice: Fix the error code when 'qcom,ice' property is not found
  arm64: dts: qcom: eliza: Add power-domain and iface clk for ice node
  arm64: dts: qcom: milos: Add power-domain and iface clk for ice node
  tee: qcomtee: add missing va_end in early return qcomtee_object_user_init()
  tee: fix params_from_user() error path in tee_ioctl_supp_recv
  tee: shm: fix shm leak in register_shm_helper()
  tee: fix tee_ioctl_object_invoke_arg padding
  arm64: defconfig: Enable PCI M.2 power sequencing driver
  scsi: ufs: ufs-qcom: Remove NULL check from devm_of_qcom_ice_get()
  mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get()
  soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL
  soc: qcom: ice: Return -ENODEV if the ICE platform device is not found
  soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
  ARM: dts: microchip: sam9x7: fix GMAC clock configuration
  firmware: samsung: acpm: Fix mailbox channel leak on probe error
  ...
2026-06-02 10:54:11 -07:00
Linus Torvalds 4a694a77c3 13 hotfixes. All are for MM. 10 are cc:stable and the remaining 3
address post-7.1 issues or aren't considered suitable for backporting.
 
 There's a 3 patch series "userfaultfd: verify VMA state across UFFDIO_COPY
 retry" from Mike Rapoport which fixes a few uffd things.  The rest are
 singletons - please see the individual changelogs for details.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTTMBEPP41GrTpTJgfdBJ7gKXxAjgUCah5U6wAKCRDdBJ7gKXxA
 jmzcAP9N+WQo4qNZYYjSURqJof48Q4nght5C0ZHtsVk5itNJEQEAiecouCreqDSE
 VUY9mQHyEawIfORkPTUijnkjV8b+lwc=
 =m8J3
 -----END PGP SIGNATURE-----

Merge tag 'mm-hotfixes-stable-2026-06-01-20-58' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull MM fixes from Andrew Morton:
 "13 hotfixes. All are for MM. 10 are cc:stable and the remaining 3
  address post-7.1 issues or aren't considered suitable for backporting.

  There's a three-patch series "userfaultfd: verify VMA state across
  UFFDIO_COPY retry" from Mike Rapoport which fixes a few uffd things.
  The rest are singletons - please see the individual changelogs for
  details"

* tag 'mm-hotfixes-stable-2026-06-01-20-58' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  userfaultfd: remove redundant check in vm_uffd_ops()
  userfaultfd: refuse to __mfill_atomic_pte() for unsupported VMAs
  userfaultfd: verify VMA state across UFFDIO_COPY retry
  mm/huge_memory: update file PMD counter before folio_put()
  mm/huge_memory: update file PUD counter before folio_put()
  mm/hugetlb_vmemmap: fix incorrect vmemmap restore in rollback
  mm/damon/ops-common: call folio_test_lru() after folio_get()
  mm/cma: fix reserved page leak on activation failure
  mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison
  mm/hugetlb: restore reservation on error in hugetlb folio copy paths
  mm/cma_debug: fix invalid accesses for inactive CMA areas
  memcg: use round-robin victim selection in refill_stock
  mm/hugetlb: avoid false positive lockdep assertion
2026-06-02 08:59:35 -07:00
Linus Torvalds 6f3ed7fec7 - fix race condition in dm-cache-policy-smq
-----BEGIN PGP SIGNATURE-----
 
 iIoEABYIADIWIQRnH8MwLyZDhyYfesYTAyx9YGnhbQUCah2mPxQcbXBhdG9ja2FA
 cmVkaGF0LmNvbQAKCRATAyx9YGnhbVGGAQDNaDwK2kE1az7Jpgu91U23R8fSxeBz
 SomeFHmqEHcEQAEAk2/3vG20zshIWFbz9Y1ZdZ9q9RKLrAh/83i3YVLbkQQ=
 =D0RT
 -----END PGP SIGNATURE-----

Merge tag 'for-7.1/dm-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fix from Mikulas Patocka:

 - fix race condition in dm-cache-policy-smq

* tag 'for-7.1/dm-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm cache policy smq: check allocation under invalidate lock
2026-06-01 19:55:30 -07:00
Linus Torvalds 4b5821f73b auxdisplay for v7.2-1
* Fix potential out-of-bound access in line-display library
 * Miscellaneous refactoring and cleaning up
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEqaflIX74DDDzMJJtb7wzTHR8rCgFAmodSKkACgkQb7wzTHR8
 rCgnTBAAoHqEq6XKc6qqsShvyDhcyiyGdGasF1a1kfMVRTjRYa/KytEgD8Jl27N/
 MTmN3mq+Z2INKovcs4iGoRUAFxMAs9pzRqBQHI6u98mhwbMuWklCzaRa9NyrdEAI
 iHYpWZ557qGsn+aU/N9Q9Dy78FIOFlKSuvgbLQmjr1XQUwpbc7EkPO0o3QD/o7qP
 BphL0FpP6CMhLsb7+ZyFjjN+ntftvZ92LGVaBBiZA+xqDHHTzcEVHDNdl4C/0ZjS
 JIDTtStCgcCBHg/EUHJ68Oa2yEqOuWsuclX+YoL22Zu2qi7UW0FFhQEXiKtx/eMi
 HS2C1aYGVQVLvFjuTe1lYO1PbxCL5ddhvZarz+8LfvK03T6ExPHkB/Z1VUWJoE+L
 3ZrGpjFw6LOkk3MkeCul2MNclmvspPz2XKUern9+pX62NWbOxSbzRNknDH87muSF
 iQMpo8qTNf+9XlyxC2EGNS6IqwAJ/qXCXUmXdFJzRoWtwLmm6CBiwZGxaPE5XwsB
 iWvitQj0dkPjcgungKhl0c/eZ0wpZ8HFEh4muUIEIP/uZWiNjQywGGXyuduhlKvs
 ro2uDWSBG/7EVds676abD3Po/PRYUzxD3KgrN2CG0C+8YuqWc8tO7pcWtKWgI+yt
 tw143EAS30/HBCsP7A+wdNG0Rddlv4NaE5PTaz7zbQmOc5YqFho=
 =VUfV
 -----END PGP SIGNATURE-----

Merge tag 'auxdisplay-v7.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-auxdisplay

Pull auxdisplay updates from Andy Shevchenko:

 - Fix potential out-of-bound access in line-display library

 - Miscellaneous refactoring and cleaning up

[ Andy says this could easily be delayed until 7.2, but it's _so_ tiny
  that it's more work for me to schedule it for later than to just take
  it now, and just doesn't seem worth delaying    - Linus ]

* tag 'auxdisplay-v7.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-auxdisplay:
  auxdisplay: Kconfig: drop unneeded quotes in PANEL_BOOT_MESSAGE dep
  auxdisplay: line-display: fix OOB read on zero-length message_store()
  auxdisplay: max6959: use regmap_assign_bits() in max6959_enable()
2026-06-01 19:50:33 -07:00
Guangshuo Li d3f0a606b9 dm cache policy smq: check allocation under invalidate lock
commit 2d1f7b65f5 ("dm cache policy smq: fix missing locks in
invalidating cache blocks") added mq->lock around the destructive part of
smq_invalidate_mapping(), but left the e->allocated check outside the
critical section.

That leaves a check-then-act race. Two concurrent invalidators can both
observe e->allocated as true before either of them takes mq->lock. The
first invalidator that acquires the lock removes the entry from the
queues and hash table and then calls free_entry(), which clears
e->allocated and puts the entry back on the free list. The second
invalidator can then acquire mq->lock and continue with the stale result
of the unlocked check.

This can corrupt the SMQ queues or hash table by deleting an entry that
is no longer on those structures. It can also hit the allocation check in
free_entry() when the same entry is freed again.

Move the allocation check under mq->lock so the predicate and the
destructive operations are serialized by the same lock.

Fixes: 2d1f7b65f5 ("dm cache policy smq: fix missing locks in invalidating cache blocks")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-06-01 17:30:24 +02:00
Arnd Bergmann fce4668a01 SoCFPGA dts fix for v7.1
- Fix OF node refcount leak
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEoHhMeiyk5VmwVMwNGZQEC4GjKPQFAmoVtIMACgkQGZQEC4Gj
 KPR1iA/+PXPSx51qgfkJKNUrEzAq8WOrsjDMrLI596unfXVpi4thWy5+4DaSIk8A
 o+1u8iXwHTNFeBcG+KUKqVmCAgyVLc3ZZ3OkaCH2+y0MBa6qKXI/+7/0yd/4F5Hu
 5L+e0QrUdUEJKvjAXZAIym8RqYnXR53P0Ur3imGqkJlqZFwnME+Eez0Uvtj5fIZA
 NEDeSbbrwVsQ4etOfI0HjyI/lkEFEJqcgVg2APOraDtPmM9Wmf9XXh5BRUvgLptK
 JTtYa7exiLyX0qbgWE/+7w7omjruDYOgXTrzjrpuW+rlH/jvh+ATJrl2R7bIR6lJ
 0Ez2T/9W1WD6p8LxgMIyg8eFXfKf+cVFIyGmS95F0Q5jC1cRRdM84JPDHHcO5QYO
 tr3m4IwORyQbzAyAjbq/KRiBEx0LsjuBTLQez/YrDbMdy0BrgTIYvT26taV+bSXF
 4iF50SbtGuQz3A8N5USOD4mo1bkx7QI1ezVNqXZJuuJ9+B4ieeOPzcg9s0Y4D+6z
 qP2OdaaaU9c8IYLxClHk3k5QMiPP9PgosPMfrCd1Iw18qaUNIaTMbc+3k4sAyMpz
 WNbKgIHgOR/amWGrUgoyAYwvs5IYOhJvU1L3yslgRxzMMrvW5Mx13nuCVw/44gD8
 BS5VwUyfPjeOxfkZJVOtUxwBX3znQJkHjIUFD6lfDAHTjFlSn/M=
 =Qs3M
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmodllEACgkQmmx57+YA
 GNlnnA/+PO0ieAuD1mwzSgcPhWeT9r9x33s4YrjYvzXtm+WW5G7tRcdlPzFkIIbP
 nbvU2/0h2nNcxH2fr3HcTqEy2BHVoE0M5rJ0+K806XIfIJPP1BAVUguTUi8BojFF
 fLILUVVCsc0dmMduvBkD0HjDR+ZxRxw21NzMtG3ufCp095bk6YZD/D6rrYAvLSRd
 sxotmyBdoIYL755/BOeNWNT362c8NvK6p2j3VAItozJeGT7c37t4x6tu4hbzWh6H
 cxJodqQFRhIbURiDc6tMGoUOAM1bpnX0z7l/swnRT9aQo3oAzhwkas2RBhfVUmDi
 c2Z+4s1INMRnkPIyOtjwNsIUrRukNXaS5WpnWjkEc7xtdjmfw9jwnmkbHqx80nHq
 qY688wZ2u+UFFJuX6MQxJ2J6Iu2ws8w+ZnMSgR46SRv3wiEHUUFJVvVnk8SAyZ6D
 y0JMstYbPHIkF0cWc9SA2FZE524ak6X2qJCSro+VVRne2RaDFgJv1Q6rSWPCU9Cd
 75wO6MXI0TP5bTm0wCYe6OPvNErsG0O7ezs4H48tofU8kL0vfpmAoLnrzG3xq/9g
 HaUea7kOtekkfdicnjnV9hK6PhUHrhxfbCkNkLsZCbRnqsQim/B/3Hyi+jwFvDhe
 Rlu4/qwTp9c8Zk+hyEDuNF2uORiSNS3dF5EGdDGCiGF6t5cR5fY=
 =p4Za
 -----END PGP SIGNATURE-----

Merge tag 'socfpga_fix_for_v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux into arm/fixes

SoCFPGA dts fix for v7.1
- Fix OF node refcount leak

* tag 'socfpga_fix_for_v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux:
  ARM: socfpga: Fix OF node refcount leak in SMP setup

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-06-01 16:25:19 +02:00
Arnd Bergmann d4715546cc Microchip AT91 fixes for v7.1
This update includes:
 - a fix for the GMAC DT node on SAM9X7 SoC to properly describe the
   available clocks
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTsZ8eserC1pmhwqDmejrg/N2X7/QUCahxHEwAKCRCejrg/N2X7
 /aZcAP9W2CfnPGFuBHoT4DR3NLDcqgt0p6hni2RpV3P+ELK1NgEAqIYlIyf0RXbV
 j4TU9cbq6Z7iXb2hsMjF1gebKj1V6QU=
 =Z26Y
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmodlkkACgkQmmx57+YA
 GNkk2BAAsLgM/0tVJsx22CF0KouOrDhyjjbKt7/i70qnCkhC9K831X9O8dFBYIma
 8hZT/Rc0PWX9KueQl2IqiI+KKY2kjZ+zJGS64j21LVmdzPgVgR3/gzgf81IIzJMO
 aBuL7JbOZAO8aZ5sJQc6xvPo+fdO1sZmBU0yMRLZbSiOyH3rbpDO7KVAJzOo95F5
 GC3cNPGqSt91ytNSBI8E8OhVrJktr7ssgKOsIaGRxfERVTBA+utGfqJucDQJHIOC
 VDGg/31KQfvkz2cgrqFKzP6xAKk2drqM5Z5b7jZpu4FQkSEz2lAeqQEE1i+9eDx4
 EntZUaro1xQUOmk4J2MYLb0Kbf89jEvQ33wZogYpjLWsUt4nSAeviS2fcN4B8OQ7
 L7oYHeQh2hZoqncaz8xRT8R5WHvN8udI29LHsPBVNaka/BTphkgE35Ggxww5H0Ij
 XeWxyx4+DpxJk2NZ0UdlF1tUCSz5hEInLMkJ8uOsY5FFmBa8h57KHnCymu/wxn8G
 CFm/lc4p/VkIrivU0Kn9YHYT1HtBpYE2q9U9clLPthxI/IGma7DjF8qy+FXXQ51m
 0zdp/OcCVcVWIpOPj+iFyucQUpxY+mdAEWN5ppIf3yZVYxcxFWVOW6ADzHP1G9N2
 1ryn6jJIqp6mm9W+T7hNbgUqzraTGH4gHGjUD+79dVQeL1HVZZk=
 =xRm6
 -----END PGP SIGNATURE-----

Merge tag 'at91-fixes-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux into arm/fixes

Microchip AT91 fixes for v7.1

This update includes:
- a fix for the GMAC DT node on SAM9X7 SoC to properly describe the
  available clocks

* tag 'at91-fixes-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux:
  ARM: dts: microchip: sam9x7: fix GMAC clock configuration

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-06-01 16:25:03 +02:00
Mike Rapoport (Microsoft) 9d7bea186b userfaultfd: remove redundant check in vm_uffd_ops()
Lorenzo says:

  static const struct vm_uffd_ops *vma_uffd_ops(struct vm_area_struct *vma)
  {
          if (vma_is_anonymous(vma))
                  return &anon_uffd_ops;
          return vma->vm_ops ? vma->vm_ops->uffd_ops : NULL;
  }

  This is doing a redundant check _and_ making life confusing, as if
  !vma->vm_ops is a condition that can be reached there, it can't, as
  vma_is_anonymous() is literally a !vma->vm_ops check :)

Remove the redundant check.

Link: https://lore.kernel.org/20260527184751.4147364-4-rppt@kernel.org
Fixes: 0f48947c42 ("userfaultfd: introduce vm_uffd_ops")
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Suggested-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Peter Xu <peterx@redhat.com>
Cc: David Carlier <devnexen@gmail.com>
Cc: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-31 21:50:26 -07:00
Mike Rapoport (Microsoft) df3ee3b3bb userfaultfd: refuse to __mfill_atomic_pte() for unsupported VMAs
__mfill_atomic_pte() unconditionally dereferences ops because there is an
assumption that VMAs that can undergo mfill_* operations are vetted on
registration and must have valid vm_uffd_ops.

Add a guard against potential bugs and make sure __mfill_atomic_pte()
bails out if ops is NULL.

Link: https://lore.kernel.org/20260527184751.4147364-3-rppt@kernel.org
Fixes: ad9ac30813 ("userfaultfd: introduce vm_uffd_ops->alloc_folio()")
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Suggested-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: David CARLIER <devnexen@gmail.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Michael Bommarito <michael.bommarito@gmail.com>
Cc: Peter Xu <peterx@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-31 21:50:25 -07:00
Mike Rapoport (Microsoft) 85668fda93 userfaultfd: verify VMA state across UFFDIO_COPY retry
Patch series "userfaultfd: verify VMA state across UFFDIO_COPY retry", v2.

... and two more small fixes.


This patch (of 3):

mfill_copy_folio_retry() drops the VMA lock for copy_from_user() and
reacquires it afterwards.  The destination VMA can be replaced during that
window.

The existing check compares vma_uffd_ops() before and after the retry, but
if a shmem VMA with MAP_SHARED is replaced with a shmem VMA with
MAP_PRIVATE (or vice versa) the replacement goes undetected.

The change from MAP_PRIVATE to MAP_SHARED will treat the folio allocated
with shmem_alloc_folio() as anonymous and this will cause BUG() when
mfill_atomic_install_pte() will try to folio_add_new_anon_rmap().

The change from MAP_SHARED to MAP_PRIVATE allows injection of folios into
the page cache of the original VMA.

There is no need to change for hugetlb because it never uses
mfill_copy_folio_retry().

Introduce helpers for more comprehensive comparison of VMA state:
- mfill_retry_state_save() to save the relevant VMA state into a struct
  mfill_retry_state (original uffd_ops, relevant VMA flags, vm_file and
  pgoff) before dropping the lock
- mfill_retry_state_changed() to compare the saved state with the state
  of the VMA acquired after retaking the locks
- mfill_retry_state_put() to release vm_file pinning.

Use DEFINE_FREE() cleanup to wrap mfill_retry_state_put() to avoid
complicating error handling paths in mfill_copy_folio_retry().

Link: https://lore.kernel.org/20260527184751.4147364-1-rppt@kernel.org
Link: https://lore.kernel.org/20260527184751.4147364-2-rppt@kernel.org
Fixes: 292411fda2 ("mm/userfaultfd: detect VMA type change after copy retry in mfill_copy_folio_retry()")
Fixes: 6ab703034f ("userfaultfd: mfill_atomic(): remove retry logic")
Co-developed-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Suggested-by: Peter Xu <peterx@redhat.com>
Co-developed-by: David Carlier <devnexen@gmail.com>
Signed-off-by: David Carlier <devnexen@gmail.com>
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-31 21:50:25 -07:00
Yin Tirui 8d87805992 mm/huge_memory: update file PMD counter before folio_put()
__split_huge_pmd_locked() updates the file/shmem RSS counter after
dropping the PMD mapping's folio reference.  If folio_put() drops the last
reference, mm_counter_file() can later read freed folio state via
folio_test_swapbacked().

Move the counter update before folio_put().

Link: https://lore.kernel.org/20260526101337.1984081-1-yintirui@huawei.com
Fixes: fadae29530 ("thp: use mm_file_counter to determine update which rss counter")
Signed-off-by: Yin Tirui <yintirui@huawei.com>
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
Acked-by: David Hildenbrand (arm) <david@kernel.org>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Chen Jun <chenjun102@huawei.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Yang Shi <yang.shi@linux.alibaba.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-31 21:50:25 -07:00
Yin Tirui 40990c87a2 mm/huge_memory: update file PUD counter before folio_put()
__split_huge_pud_locked() updates the file/shmem RSS counter after
dropping the PUD mapping's folio reference.  If folio_put() drops the last
reference, mm_counter_file() can later read freed folio state via
folio_test_swapbacked().

Move the counter update before folio_put().

Link: https://lore.kernel.org/20260526101355.1984244-1-yintirui@huawei.com
Fixes: dbe5415329 ("mm/huge_memory: add vmf_insert_folio_pud()")
Signed-off-by: Yin Tirui <yintirui@huawei.com>
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
Acked-by: David Hildenbrand (arm) <david@kernel.org>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Chen Jun <chenjun102@huawei.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-31 21:50:25 -07:00
Muchun Song c7bde43f6d mm/hugetlb_vmemmap: fix incorrect vmemmap restore in rollback
vmemmap_restore_pte() rebuilds restored vmemmap pages from a tail-page
template derived from compound_head().  This is wrong when the current PTE
already maps a page whose contents are not tail-page metadata.

In the rollback path of vmemmap_remap_free(), the first restored PTE is
backed by vmemmap_head and contains head-page metadata.  Reconstructing
that page from a tail-page template overwrites the head-page state and
corrupts the restored vmemmap page.

Fix this by copying the full page from the page currently mapped by the
PTE.  Also pass vmemmap_tail to the rollback walk so only PTEs backed by
the shared tail page are restored, while the head PTE remains mapped to
vmemmap_head.  Add VM_WARN_ON_ONCE() checks for unexpected cases.

Link: https://lore.kernel.org/20260525025213.2229628-1-songmuchun@bytedance.com
Fixes: c0b495b91a ("mm/hugetlb: refactor code around vmemmap_walk")
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Acked-by: Kiryl Shutsemau <kas@kernel.org>
Acked-by: Oscar Salvador (SUSE) <osalvador@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-31 21:50:24 -07:00
SeongJae Park d6b8b02a27 mm/damon/ops-common: call folio_test_lru() after folio_get()
damon_get_folio() speculatively calls folio_test_lru() before
folio_try_get().  The folio can get freed and reallocated to a tail page. 
In the case, VM_BUG_ON_PGFLAGS() in const_folio_flags() can be triggered. 
Remove the speculative call.

Also mark folio_test_lru() check right after folio_try_get() success as no
more unlikely.

The race should be rare.  Also the problem can happen only if the kernel
has enabled CONFIG_DEBUG_VM_PGFLAGS.  No real world report of this issue
has been made so far.  This fix is based on only theoretical analysis. 
That said, a bug is a bug.  A similar issue was also fixed via commit
3203b3ab0f ("mm/filemap: don't call folio_test_locked() without a
reference in next_uptodate_folio()").  I don't expect this change will
make a meaningful impact to DAMON performance in the real world, though I
will be happy to be corrected from the real world reports.

The issue was discovered [1] by Sashiko.


Link: https://lore.kernel.org/20260525162256.8317-1-sj@kernel.org
Link: https://lore.kernel.org/20260517234112.89245-1-sj@kernel.org [1]
Fixes: 3f49584b26 ("mm/damon: implement primitives for the virtual memory address spaces")
Signed-off-by: SeongJae Park <sj@kernel.org>
Cc: Fernand Sieber <sieberf@amazon.com>
Cc: Leonard Foerster <foersleo@amazon.de>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: <stable@vger.kernel.org> # 5.15.x
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-31 21:50:24 -07:00
Arnd Bergmann 930c882020 Memory controller drivers - fixes for v7.1
Fix probing of Atmel EBI memory controller driver e.g. on at91
 sam9x60-curiosity board due to usage of platform_driver_probe() which is
 not handling deferred probe.  Lack of EBI driver caused dependant NAND
 controller to fail to probe, basically failing entire board boot.
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmoZPZ4QHGtyemtAa2Vy
 bmVsLm9yZwAKCRDBN2bmhouD1wBTEACWlhnslXLbIma+QXkLDvVG4wi+WvDLMM+q
 nQGXDwFa5bkmE9dwlkVeLiDMIhBj+q0WMgH3ctHQCPyde2l8vIvdkuWM+HyGgFTs
 eNmQTIFyn09YayZTzWE/5q/fJcIBMeFyfLPDnf562qs+cWu7BxfT8M4jvvdpQ9QH
 BJZbBLq4l80+X6Q1AlLP4djklY7CRosV/8Acuo2cIaiIEPVEWaGdFX5EcGSqSvFf
 3uMIHw/X+BiHpsZv02NLFOF57El3COEJNrgaiSUM9NtUkPfgvrIIBZgUwhdvG81r
 0+3eUKqL1jvZc2K6QLUvNR9lWuCE+5g4jVhgF+mPkXyIKu5Nl1x1JO09Q+IBTkZd
 r+rJFn+mBdAFGc0gHufHNyP8QiXntmCn0BVp6paBH0RQUroC3MWaJaYGxyk1fUA4
 ohCtRqFUqkDyDebqLrtZAe1R87B382Ia+477h5pRvivEViVrRFm+n3TJl2k54Gcw
 eTs/HFv58jn2122Uz2vOmUMVlVQsbrzrm1LpPHoAmkcDkogkRSDaGUK/o3RLvh1l
 nzIelNNL3KNpw6R6wHzEJUINS31VgVxc6WadK60py5MmmoGvS1hIXOF6/iBx8Vk6
 RAyuW1LNuj6eAhwmBK6h2tQn+Gs/pidymlrassdxzPUwrft7mMuc2CwfL92QAwtN
 X3eFiWuayw==
 =4VXt
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoaB6MACgkQmmx57+YA
 GNl5aQ/+LKUsj8Z1+ldO3y8RznLbgD4eszkgT3vjUrGj1VxdBijHL/EWqBtfacoJ
 Lat6nNMmFeE8LcDqStm3SwM20N2m5PaXFPcIeDaDL/ZiM+v3YfCTvX4lkzQGJ1B7
 dIs89cPyMQX2qwF8+uKRZou80RNAwRWTp/zT0Q7sIxnzsQ6Gz2tybuxEZ2abgdmT
 X2F1HY3ex8TXTA+NqfJLubf9eHtbXxI1KqFtjU9+YI83OHFqSPNHLNmKCNH0uHkn
 vhGXZgX6RuebtYCw0Fo73cLm3UUj24204pVuujA07OmQmPiZ5Xvp1wMGZtmNkzQU
 L1f3Pav+UDopM6IIzbc2d+Y/YSvupS8ADkaYmcsxLo2KTpdRyRrEf3If2AiQGpxG
 kTCLKWkXDVg8SQic0W+jHC+8wnm9Ec8Idp08s/4XPlA1vSo8MRSE+TDHBmDGgDhQ
 IqvddJE+uT2ZW1yU2Wao7rfQ3KRaWuz7xPYb7ySilAn1i6LtCjysUaDISxRBCiYQ
 bQoxXvvWdmqg8aDpsRyhW2mwQN+4vEeq/IH73XoiZH6jzTj9wReHbudKDG1gREFx
 X/0tBBwuuJhwNbtOj+DVrJlM1WqPDjb7zw6yzEinf3LzvEYR8BGK+R0w3mWa8Eal
 bJCEjHg4mx6LEkFdleFmhLyAL7fVJoxydmpb3HpQ+5r0xk01YhM=
 =8TQP
 -----END PGP SIGNATURE-----

Merge tag 'memory-controller-drv-fixes-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/fixes

Memory controller drivers - fixes for v7.1

Fix probing of Atmel EBI memory controller driver e.g. on at91
sam9x60-curiosity board due to usage of platform_driver_probe() which is
not handling deferred probe.  Lack of EBI driver caused dependant NAND
controller to fail to probe, basically failing entire board boot.

* tag 'memory-controller-drv-fixes-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl:
  memory: atmel-ebi: Allow deferred probing

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-29 23:39:46 +02:00
Arnd Bergmann f5e70b3f30 Samsung SoC driver fixes for v7.1
Fix several concurrency issues present in Samsung ACPM firmware drivers,
 used currently only on Google GS101.  Tudor with help of Sashiko
 identified several missing barriers and incomplete synchronization,
 leading to possible transfer data corruption or use after free.  Few
 other issues related to probe, including missing mailbox cleanup, were
 also fixed.
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmoZgsoQHGtyemtAa2Vy
 bmVsLm9yZwAKCRDBN2bmhouD1wmbEACCXrSzY82MLt6XmVByWQy9U9OBLkC471qA
 GhcVdC0uMs6hD5prvJCnHVP236XKUZnT6EZjpBW+8Me3Yw4z4j9Wdd5j0z1haEF5
 DdldsjBjrawsXazVVlj4J7iE1fv83dZrgOASDXFhP+GHRPsfrCYWlNIPhWcG8wwp
 68yYY8FT4hQ4/i5otWixHSdeaadPV/TWf+W90l/1Z6uXdt/9CzAcavHiLOkLWji+
 dy87ZNTcpZoCqa12sPz2wkmMXj5ET5vUsuvoVZu3376ViU8q/6kSIRYtIQjCgM8J
 cMNArDequv6g24ra+W8D234qo50fBAVpeYHFyZKDJYekkJ9HJyQ2NXarJz/kvEUw
 ZkmUA/SgZUc0hM5i0J+5O6K7lTed6eMmkR72QTT/uQZOAcEkqsFpkuZhAetxguR8
 vO7p99+QAS/grHKiXaLKTOYgpoxitqx0int0FZ1shWbeO/OYorrZ00x0OkK++V++
 WsI7SJVNco/LM4APdSIRBphZ5ULl6xgu2SLO05J7uQFgiUWU0Q9v+t1MxIbvmL0T
 HH5H1STGr12LOBwnJDjK/AYbAhFFM9pZxgPJU9S4NzKu3peQJjgLvnOeEEmLkmeQ
 47bKUlrOMQIP5lpzLBYtL9NT/7fyQKfl8fbdq5O3KwthMvOiit6mGD+ExDoptIp4
 4T+NBiG08A==
 =hb6T
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoaByIACgkQmmx57+YA
 GNmeiA/9EZ+LO2JUrUVhMNXOfUmDGrpfL/mVqcGL9ksK+EkOW+9Fae8f9hWrvBFh
 exeMRTwKDcA2hag6AnBiKhctLYFIZ7+nRb/xu2ybasdIAloR10oDKlmgzH/Yj4c9
 MsIgfuK+q5FnOxyhtNEZ4JszYYvAl3wfFvBR1241L52tJ+vyOLxEjk/8rhESFv1P
 rTeCXlRA/dJ4hqpP9j+QflgrvrIYe1vhsBdNFXQEcjUgQnqySPY7Ynlnr1BJMyWQ
 N4x+gJ9ZITr75kzMJCwqGXfktwPP6+BahBHDk8i6U6zfFwb2DJFHx0OSYf3Z1s1w
 V7wxIMiGr/XZ/r0D6prlqYAjLZS8KL9sYEC/UB+WB95SwnFWm3J1K895rt4awuzY
 HD6jhgPlyvIBEJRI7ZNMB4Hg0p9Z5pXse1EDseDdAnAth9brbFN7d/JbbtTMKfny
 jyQJG8rEUvmSF+No35VprFW6JhyDHFlnrQvoSQdLgxsKHrMRcI1xYnQXi2aILlYI
 cYCYzL2lAeteaMHVMrPDoLQGCbKnvTz+pAhiOXTX2ie6XS8JuYPhf1H+Pp8GTozp
 P+Iy995FZ92aaCyPmINa8lN2hfuC3qhxNZehZ8bEShKQ+44wab1SV6q/shM+HPt2
 i1OLt9Kg/CWt6hVXW3jkZvdNry1HuPP3f4jrQwquOFh6h2VlnXw=
 =zqbF
 -----END PGP SIGNATURE-----

Merge tag 'samsung-drivers-fixes-7.1-2' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into arm/fixes

Samsung SoC driver fixes for v7.1

Fix several concurrency issues present in Samsung ACPM firmware drivers,
used currently only on Google GS101.  Tudor with help of Sashiko
identified several missing barriers and incomplete synchronization,
leading to possible transfer data corruption or use after free.  Few
other issues related to probe, including missing mailbox cleanup, were
also fixed.

* tag 'samsung-drivers-fixes-7.1-2' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux:
  firmware: samsung: acpm: Fix infinite loop on sequence number exhaustion
  firmware: samsung: acpm: Fix missing LKMM barriers in sequence allocator
  firmware: samsung: acpm: Fix false timeouts and Use-After-Free in polling
  firmware: samsung: acpm: Fix mailbox channel leak on probe error
  firmware: samsung: acpm: Fix cross-thread RX length corruption

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-29 23:37:36 +02:00
Tudor Ambarus 7fe40c32a3 firmware: samsung: acpm: Fix infinite loop on sequence number exhaustion
Sashiko identified a possible infinite loop [1].

ACPM IPC sequence numbers are tracked via a 64-bit bitmap. Previously,
acpm_prepare_xfer() used a do...while loop to search for a free
sequence number.

If all 63 available sequence numbers are leaked due to transient
hardware timeouts or mailbox failures, the bitmap becomes full.
The next call to acpm_prepare_xfer() would enter an infinite loop.

Fix this by utilizing the kernel's optimized bitmap search functions
(find_next_zero_bit / find_first_zero_bit). If the pool is completely
exhausted, log the failure and return -EBUSY to allow the kernel to
fail gracefully instead of hanging.

Furthermore, drop the allocation loop entirely. Because
acpm_prepare_xfer() is strictly called under the 'tx_lock' mutex,
sequence number allocations are perfectly serialized. If
find_next_zero_bit() locates a free bit, a single
test_and_set_bit_lock() is mathematically guaranteed to succeed.

To enforce this locking invariant, wrap the allocation in a
WARN_ON_ONCE. If the atomic set fails, it indicates the driver's
mutex serialization is fundamentally broken. The warning generates a
stack trace for debugging, while returning -EIO immediately aborts the
transfer to prevent silent payload corruption.

Cc: stable@vger.kernel.org
Fixes: a88927b534 ("firmware: add Exynos ACPM protocol driver")
Closes: https://sashiko.dev/#/patchset/20260420-acpm-tmu-v3-0-3dc8e93f0b26%40linaro.org [1]
Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
Link: https://patch.msgid.link/20260505-acpm-fixes-sashiko-reports-v5-7-43b5ee7f1674@linaro.org
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
2026-05-29 14:11:23 +02:00
Tudor Ambarus bf296f83a3 firmware: samsung: acpm: Fix missing LKMM barriers in sequence allocator
Sashiko identified memory ordering races in [1].

The ACPM driver uses a globally shared 'bitmap_seqnum' to track
available sequence numbers. Even though threads now strictly free their
own sequence numbers, the allocation and freeing of these bits across
concurrent threads are effectively lockless operations and require
explicit LKMM memory barriers.

Previously, the driver used plain bitwise operators (test_bit, set_bit,
clear_bit), which lack ordering guarantees. This creates two race
conditions on weakly ordered architectures like ARM64:

1. Polling Release Violation: The polling thread copies its payload and
   calls clear_bit(). Without a release barrier, the CPU can reorder
   the memory operations, making the cleared bit globally visible
   before the payload reads have fully completed.
2. TX Acquire Violation: The TX thread loops on test_bit(), calls
   set_bit(), and then wipes the payload buffer via memset(). Without
   an acquire barrier, the CPU can speculatively execute the memset()
   before the bit is safely and formally claimed.

If these reorderings overlap, a new TX thread can claim the sequence
number and overwrite the buffer while the original polling thread is
still actively reading from it.

Fix this by upgrading the bitwise operators. Wrap the TX allocation in
test_and_set_bit_lock() to establish formal LKMM Acquire semantics, and
pair it with clear_bit_unlock() in the polling path to enforce Release
semantics.

Cc: stable@vger.kernel.org
Fixes: a88927b534 ("firmware: add Exynos ACPM protocol driver")
Closes: https://sashiko.dev/#/patchset/20260423-acpm-fixes-sashiko-reports-v1-0-2217b790925e%40linaro.org [1]
Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
Link: https://patch.msgid.link/20260505-acpm-fixes-sashiko-reports-v5-6-43b5ee7f1674@linaro.org
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
2026-05-29 14:11:22 +02:00
Tudor Ambarus c889b14647 firmware: samsung: acpm: Fix false timeouts and Use-After-Free in polling
Sashiko identified severe races in the polling state machine [1].

In the ACPM driver's polling mode, threads waited for responses by
monitoring the globally shared 'bitmap_seqnum'. This caused false
timeouts because if a thread processed its response and freed the
sequence number, a concurrent TX thread could immediately reallocate
it before the polling thread woke up.

Additionally, the driver suffered from a cross-thread Use-After-Free
(UAF) preemption race. Previously, acpm_get_rx() cleared the sequence
number of whichever RX message it drained from the hardware queue. This
meant Thread A could globally free Thread B's sequence slot while
Thread B was asleep. A new Thread C could then steal the slot,
overwrite the buffer, and leave Thread B to wake up to corrupted state
or a timeout.

Fix this by rewriting the polling state machine:
1. Decouple polling from the global allocator by introducing a per-slot
   'completed' flag, synchronized via smp_store_release() and
   smp_load_acquire().
2. Strip acpm_get_saved_rx() out of acpm_get_rx() to make it a pure
   queue-draining function. Introduce a 'native_match' boolean argument
   which evaluates to true only if the thread natively processed its
   own sequence number during the call. This explicitly informs the
   polling loop whether it must retrieve its payload from the
   cross-thread cache.
3. Centralize the cache fallback and sequence number free (clear_bit)
   inside the polling loop. Crucially, the free operation now strictly
   targets the thread's own TX sequence number (xfer->txd[0]), rather
   than the drained RX sequence number. This enforces strict ownership:
   a thread only ever frees its own allocated sequence slot, and only
   at the exact moment it completes its poll, eliminating the UAF
   window.

Furthermore, explicitly guard the 'native_match' assignment with an
if (rx_seqnum == tx_seqnum) check, even for zero-length (no payload)
responses. While an unguarded assignment wouldn't crash (because the
cache fallback acpm_get_saved_rx() safely returns early on zero-length
transfers) doing so would "lie" to the state machine. If a thread
drained the queue and found another thread's zero-length message,
setting native_match = true would falsely convince the polling loop
that it natively handled its own response. Maintaining a rigorous state
machine requires that native_match is only set when a thread explicitly
processes its own sequence number.

Cc: stable@vger.kernel.org
Fixes: a88927b534 ("firmware: add Exynos ACPM protocol driver")
Closes: https://sashiko.dev/#/patchset/20260429-acpm-fixes-sashiko-reports-v3-0-47cf74ab09ad%40linaro.org [1]
Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
Link: https://patch.msgid.link/20260505-acpm-fixes-sashiko-reports-v5-5-43b5ee7f1674@linaro.org
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
2026-05-29 14:11:22 +02:00
Muchun Song 00739e4dd4 mm/cma: fix reserved page leak on activation failure
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: c009da4258 ("mm, cma: support multiple contiguous ranges, if requested")
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Reviewed-by: Oscar Salvador (SUSE) <osalvador@kernel.org>
Acked-by: Usama Arif <usama.arif@linux.dev>
Cc: David Hildenbrand <david@kernel.org>
Cc: Frank van der Linden <fvdl@google.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28 20:50:34 -07:00
Wupeng Ma 3c2d42b8ee mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison
Two concurrent madvise(MADV_HWPOISON) calls on the same hugetlb page can
trigger a recursive spinlock self-deadlock (AA deadlock) on hugetlb_lock
when racing with a concurrent unmap:

  thread#0                              thread#1
  --------                              --------
  madvise(folio, MADV_HWPOISON)
    -> poisons the folio successfully
  madvise(folio, MADV_HWPOISON)         unmap(folio)
    try_memory_failure_hugetlb
      get_huge_page_for_hwpoison
        spin_lock_irq(&hugetlb_lock)    <- held
        __get_huge_page_for_hwpoison
          hugetlb_update_hwpoison()
            -> MF_HUGETLB_FOLIO_PRE_POISONED
          goto out:
            folio_put()
              refcount: 1 -> 0
              free_huge_folio()
                spin_lock_irqsave(&hugetlb_lock)
                  -> AA DEADLOCK!

The out: path in __get_huge_page_for_hwpoison() calls folio_put() to drop
the GUP reference while the hugetlb_lock is still held by the hugetlb.c
wrapper get_huge_page_for_hwpoison().  If concurrent unmap has released
the page table mapping reference, folio_put() drops the folio refcount to
zero, triggering free_huge_folio() which attempts to re-acquire the
non-recursive hugetlb_lock.

Fix this by moving hugetlb_lock acquisition from the hugetlb.c wrapper
into get_huge_page_for_hwpoison().  Place spin_unlock_irq() before the
folio_put() at the out: label so the folio is always released outside the
lock.

[akpm@linux-foundation.org: fix race, rename label per Miaohe]
  Link: https://sashiko.dev/#/patchset/20260522010305.4099834-1-mawupeng1@huawei.com
  Link: https://lore.kernel.org/f39f405e-4b4b-8f79-70fe-a2b5b62114eb@huawei.com
Link: https://lore.kernel.org/20260522010305.4099834-1-mawupeng1@huawei.com
Fixes: 405ce05123 ("mm/hwpoison: fix race between hugetlb free/demotion and memory_failure_hugetlb()")
Signed-off-by: Wupeng Ma <mawupeng1@huawei.com>
Acked-by: Oscar Salvador (SUSE) <osalvador@kernel.org>
Acked-by: Muchun Song <muchun.song@linux.dev>
Reviewed-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Acked-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28 20:50:34 -07:00
David Carlier 40c81856e6 mm/hugetlb: restore reservation on error in hugetlb folio copy paths
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 1cb9dc4b47
("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: 1cb9dc4b47 ("mm: hwpoison: support recovery from HugePage copy-on-write faults")
Signed-off-by: David Carlier <devnexen@gmail.com>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Cc: David Hildenbrand <david@kernel.org>
Cc: Mina Almasry <almasrymina@google.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: yuehaibing <yuehaibing@huawei.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28 20:50:33 -07:00
Muchun Song c0ca59beb5 mm/cma_debug: fix invalid accesses for inactive CMA areas
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.

c009da4258 introduced the invalid access to bitmap file.  2e32b94760
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: c009da4258 ("mm, cma: support multiple contiguous ranges, if requested")
Fixes: 2e32b94760 ("mm: cma: add functions to get region pages counters")
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Oscar Salvador (SUSE) <osalvador@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Dmitry Safonov <0x7f454c46@gmail.com>
Cc: Frank van der Linden <fvdl@google.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Michal Nazarewicz <mina86@mina86.com>
Cc: Stefan Strogin <stefan.strogin@gmail.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28 20:50:33 -07:00
Shakeel Butt c0cafe24d3 memcg: use round-robin victim selection in refill_stock
Harry Yoo reported that get_random_u32_below() is not safe to call in the
nmi context and memcg charge draining can happen in nmi context.

More specifically get_random_u32_below() is neither reentrant- nor
NMI-safe: it acquires a per-cpu local_lock via local_lock_irqsave() on the
batched_entropy_u32 state.  An NMI that lands on a CPU mid-update of the
ChaCha batch state and recurses into the random subsystem would corrupt
that state.  The memcg_stock local_trylock prevents re-entry on the percpu
stock itself, but cannot protect an unrelated subsystem's per-cpu lock.

Replace the random pick with a per-cpu round-robin counter stored in
memcg_stock_pcp and serialized by the same local_trylock that already
guards cached[] and nr_pages[].  No atomics, no random calls, no extra
locks needed.

Link: https://lore.kernel.org/20260521223751.3794625-1-shakeel.butt@linux.dev
Fixes: f735eebe55 ("memcg: multi-memcg percpu charge cache")
Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
Reported-by: Harry Yoo <harry@kernel.org>
Closes: https://lore.kernel.org/4e20f643-6983-4b6e-b12d-c6c4eb20ae0c@kernel.org/
Acked-by: Harry Yoo (Oracle) <harry@kernel.org>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28 20:50:33 -07:00
Lorenzo Stoakes b4aea43cd3 mm/hugetlb: avoid false positive lockdep assertion
Commit 081056dc00 ("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: 081056dc00 ("mm/hugetlb: unshare page tables during VMA split, not before")
Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Oscar Salvador <osalvador@suse.de>
Cc: Jann Horn <jannh@google.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28 20:50:33 -07:00
Arnd Bergmann 04e12996da i.MX SoC fixes for v7.1
Fix CAAM driver probe failures caused by missing SoC information by
 retrieving the match data directly through of_machine_get_match_data(),
 which provides the correct SoC-specific data.
 -----BEGIN PGP SIGNATURE-----
 
 iQHFBAABCgAvFiEEJS45w2QNr0ezLVaoNF3oRQ23YkwFAmoYj2MRHGZyYW5rLmxp
 QG54cC5jb20ACgkQNF3oRQ23YkxPwQwAq95b24f+LRSLuQjyfQVi6SbuGwufVtMp
 zsrwiZKfyWAkvxHa7CLHKaIC7x60J3YTUc5BdB7vQ/uDaZZwEnn/1rnUD4vvjTkd
 vODYZ2DYdZERE3UrljAdxEcuXBH496s+eDybVf4oVk5V5/rQ6TCbnK+rxXB+fXS+
 dkzUOL1j4fX1XsaGNICsCLJuSNLsxr9ja9CNJLFpr6fnncnmx8kKHSP1PHKseF+N
 qwOw5Iv2Cwp4EQZGfm54j/k7pAMlJljzWy+X5qNInUsvEBMUKa97apiMVBCfYfTB
 qDIYGA6KNd/7kMMkam2DusrOLitFpQtUFtjlMwee3BoYls3d2OkdpH1EilyoZoEg
 MCF7wd7PzD7jenVC4Z1S1BW0AdG+n3Pyxnh9iW3grljYsXE/sFRx/U13JN32EqoU
 vWshLNvNX4XH4iZKDNt+mvoCTzcnlkIZYcM4mR+JjXUpmFhcsOIpAFD2RhE/0jta
 qJOLvCddLfqkf3VPXK/sRRE48Pkw8kJs
 =freo
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYurAACgkQmmx57+YA
 GNkMKQ//f/kQ6VT0fovp6yM60tEAPsVtt5U8zpSsQpuv1joJqS9FgSx13Z6XlLsq
 IIyGPxlzsTnCke3UHo0poiGUlNrOvY87fQ8ZeU7ItpxoKLSHmLUwXZAzmlVy+yj/
 WSly0Ns3VURXhlbdQ14mQE+kxZTOBb9L02K3iIGjgIda5fbG+12IvB0cPxPUv3Oi
 +Uw2H4D5S17FxYlQoVtxPL6D/GcqBVSSCaqVHJdvpS4wmoCKvycK9yYymJnbRxIf
 /QBwpfR6QON4wxpFk7lF0s7+DWfk88qeZOvf+sDyMRGbDLsNU9C6zmjVD6y2lT3N
 kHjrnZUqdg3DgwHhc/+sXJgW4cNsDisz/L27lHwMDzzFuvz6+SB7xXn1k0cDuyGt
 5HVmdTuRRAYyolzTXCPgxvP1j11xGcOueNR7fQDbQKPDUm9OpgT0X0fPaG/w6H35
 qq1VBxJDMV+0DPOgBzHniC2CNBdADZ6Og14wQPEdVTsQUaWH66aXS8iQrcKbjwEw
 rDFS3eiOu8s+iP4wccSgKvJs0vn0fRmc2AVA74awwmoyUowwA2lT5hWKhKVuWlJN
 Zs4Bw/bk+DQAeCzUvswYdEnb1tTO4l95jHh9b4p3qkU9N8vZOmsQSwoy2XjzseLo
 Z14PuXI4R5+4LXgR26doMqonYvVkvblqETt4IkBGrUzUyaRifMM=
 =Kz7A
 -----END PGP SIGNATURE-----

Merge tag 'imx-soc-fixes-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/frank.li/linux into arm/fixes

i.MX SoC fixes for v7.1

Fix CAAM driver probe failures caused by missing SoC information by
retrieving the match data directly through of_machine_get_match_data(),
which provides the correct SoC-specific data.

* tag 'imx-soc-fixes-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/frank.li/linux:
  soc: imx8m: Fix match data lookup for soc device

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 23:59:10 +02:00
Linus Walleij 66ac2df408
ARM: dts: gemini: Fix partition offsets
These FIS partition offsets were never right: the comment clearly
states the FIS index is at 0xfe0000 and 0x7f * 0x200000 is
0xfe0000.

Tested on the iTian SQ201.

Fixes: d88b11ef91 ("ARM: dts: Fix up SQ201 flash access")
Fixes: b5a923f8c7 ("ARM: dts: gemini: Switch to redboot partition parsing")
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 23:58:35 +02:00
Arnd Bergmann acbfa4ed97 Qualcomm Arm64 defconfig fixes for v7.1
A number of targets now depends on the M.2 PCIe power sequencing driver,
 enable this to keep these devices functional with a defconfig build.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCgAsFiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmoVtMkOHGJqb3JuQGty
 eW8uc2UACgkQCx85Pw2ZrcUL2w/8CkfdKhdB8BOe/X9t72nNwjVwq/+BTTlpZxR0
 pNn5TvBhJWedzLq7Q2R7RU9CF74wGosT9JAX8jb45NHoemH4ia7aj5uHks2rMIU9
 i+XI78VT9MwF13ls9yCjLGcqquowEpQzVMNfGwLZO5dp46wZ59GPIUcwoOmr6VqF
 G1Ps3T1mkkALB1RDQitad6Ey3xaMZqA38mFhfByz/ELGSuhWaG7sjGSy6HVEVtzd
 RIdFEdx+6Ez08V6tvKP82ljWljKDCeAlOggD9BbpTUVq1zGCdqQIaeG/O1nNJzaf
 buQH5iqI7HGFtEmXTHCRFzUUKdD/hi5HyYvIF7PWBswqAfoC70Gb9NozFYnNvXac
 eCJK6NNc6jCt42W4iZGAD74lr0UDGK2L+ymztJfRU+0v/PTxY40NmIX0GwRN2JKc
 zwg6IKhyhwg9IOoBAQpVJLgVx7dUBk8sVj3yJAk/B+C8vOVoCQbde6FIJf6pJRS7
 Ms8ZeJ4eGOcVTgdrzaJTxWN5xJzD7Y92KelzlhGN/l35QbYkf9DwEtIm+g816qBX
 be6suWXMhZ+aYmrrAJB4yaXfqghDHC2pAaykH3b1J17FyvZIwWTDEJmcxTMHqaha
 i+2l8Elrz/VlqC4ugrm0tzbQ6xIv7BeImUcC3fPKi/Whoxv/oZDbaR+RYDMs0R3n
 SL15hhw=
 =+XU9
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYukwACgkQmmx57+YA
 GNnagRAAj360SPhrfkWQ94jIqQNoVThrfD3t25JhgSyrrghYQiRf6zTSCRrIDqBl
 21JzjbYhT/pd+wvs5AVlyTaY00fVIJtv81s3s5CYUKkonKK0wEG7y7bmHTb2HQIr
 1t76jS0Zbj4+HE0eYcvfVQD++sZ+dL1b93HmGDjTm47lsUvdd2OsfaCChS/OkT4H
 u9q/PT8iekXgEFY1Q4A6z+D8XE+k0UFsalZaCcEn/eo11ZluBNhX00TsGoIIYDyR
 OkfRsyjqc3X3zAqLvsiNUlTtSrAKXXFIUUEGpvEUWRapCgiwqk0XHPSVfExn7C4r
 ZSORwoxI7tIbTjNvn9iKZS2KGDUDr8fpe5TKrJvB1IM+4JnzNSU1sSTxrG21jCqA
 hvIATBYzHfdE3525A9ANauMbG42zKWvQFwG0/Sege0t6W9Q895jjOH+bH2ku2mFb
 /bQ3WF7IsoSFv48u47ISPZJMSZOjC12gJ+NIlouzt0JNmPQJI6Hu5adY9T2OrWtu
 ovq6CnZO52V+uTcM6W/VxrdhstUVXJQY3zhbVPSWPu94sfes3a4wmDkZELFy9GdN
 SFVZoL1gK4qojrjgLSniBnL0MNpv71coh1cx0j6xonDZqvWrXi9wtx6dpFFTVYyB
 UWBZiOFnqeYttwJ1+FZilUsYET9BZt9xpFQBSo2eyVlMGF80n2U=
 =M655
 -----END PGP SIGNATURE-----

Merge tag 'qcom-arm64-defconfig-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/fixes

Qualcomm Arm64 defconfig fixes for v7.1

A number of targets now depends on the M.2 PCIe power sequencing driver,
enable this to keep these devices functional with a defconfig build.

* tag 'qcom-arm64-defconfig-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux:
  arm64: defconfig: Enable PCI M.2 power sequencing driver

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 23:57:25 +02:00
Arnd Bergmann d1b9036513 Qualcomm Arm64 DeviceTree fixes for v7.1
Add missing power-domain and iface clocks for the ICE node of Eliza and
 Milos to avoid the validation errors that resulted from late binding
 changes. Also drop the reference clock for the USB QMP PHYs, for the
 same reason.
 
 Avoid touching the 20'th I2C bus on the Hamoa-based (X Elite) Dell
 laptops, as this conflicts with the battery management firmware.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCgAsFiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmoVs6MOHGJqb3JuQGty
 eW8uc2UACgkQCx85Pw2ZrcUHfA/+MoI7gAkKpGLLY3z7ZZUfcAgjD9shIaH2lvZU
 JV8gvlP3QZSngm65qeADClnzD8aca/ufrp3tyW6aqQUccWmVfXDOV/K2L2DrjYRQ
 8m5KyeZD0te1RensSfmHD0J74IhAfwX3vuHFONjRWSQ9+BGRubgnqYoFUG8qVVkZ
 jhMFdDerjUBmwiQsg7jkhQrnc3SjUyuXLstB78KBejJ9oHMch0c6Nrt/LeX/T04w
 hpldA+C3Gx5R7RAWTNQtQiVzR7uAnbgJci3hmJ0S7prCCPuNEF2lc7pCXaLwqbIu
 /wsjorqDE39TizuLkDPdTgD/p9Ec8p4kkBlnNsgVrHuHYYQKP5TF8t/JmllMOy5X
 U+96eYNENqjXkezKO69/6yqeTsqJAL1rNRIcauF/p0eNNOU4wUBnEsXnxoxK7TPM
 HuvD48wLIxT4eK4nnna7397ZwuSzkvpPxAzL0Opq6nNKMreGVoBLZ2hQgiZXv1tC
 zgSmT4Jr4LKk3Cl6RM6KmwpZ1H7DcQB8Me6tgfkApcNbbNLci/D70pG19ikmh8TX
 rk18Cfnp5jJvjgE0Hv00PzuzkzmPj2nRTIExb4Cw17n+LAkyC2eifu1O7J7FPW4a
 mxkxe9EQ2OdfAKy3jrysvvqMpIK1mH0d1COoKz9OGSrXubYearjhtuC8KaSrZNo5
 4LiykTY=
 =/uFW
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYucwACgkQmmx57+YA
 GNmK7Q/9EbFgk/uOiiyEhjPVudQHSR/JxEs7TQMbnxEOMmXvQ01FHnRlfqDSgZqx
 X+7UgrFCTIHSIaD/O29WIapW2TN4OGBI2gwHNsnWFCWbC8ZZGo+HoU3V7Fjzk8D+
 9A36G3myRerPuKWmPHQSkjfQHUKkmWUmLBCXGBwRxd3YZvjSZxeaYfDm+n9CVsIi
 NelVe42QvwP2U+FPBYXARfawn9MEBY267s8PBVaqz+k159gqSfCS5UHHQjzg1d/F
 KD7FX0y3B7EkmwpyEElapjPiXs3Mi/5PYa+C9f0zCIdRfU6H70cHcNO2OlXucq5A
 PQ79gdTI7Om9uH4gdXEyGg7Qcu2+rz0WKjFjyYBxYpgsEpCYxUVjkRpCZ1Nn34iz
 nDqVKY3jmiAws1omP51YPtFNLVw3K0ZmKMka1M7AR7wdK2115l+XUSDze6pTXazL
 RBO6DCVZEs9AikhOX+p5VF3Brmupf9lhM7Ixml4E/EOu2jAsfTnKe+3v1IUxAQ4K
 rllnn19NntTg7qIcuX+jDAkxY0mwD1JVSR4UYAahPHFfOZYqq++gLE9BcT0IGj47
 mo6wL01Niu7OU5hkQlq6fJib1tyiv12zdHYOJt7u85eiT6hXwxjx4iMEnTROCTuI
 uaV9Qzfd3EujRnwho4QnOrV8bNwcS9GpBXNz/MaYrjOrxEmn9G0=
 =qWqc
 -----END PGP SIGNATURE-----

Merge tag 'qcom-arm64-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/fixes

Qualcomm Arm64 DeviceTree fixes for v7.1

Add missing power-domain and iface clocks for the ICE node of Eliza and
Milos to avoid the validation errors that resulted from late binding
changes. Also drop the reference clock for the USB QMP PHYs, for the
same reason.

Avoid touching the 20'th I2C bus on the Hamoa-based (X Elite) Dell
laptops, as this conflicts with the battery management firmware.

* tag 'qcom-arm64-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux:
  arm64: dts: qcom: eliza: Add power-domain and iface clk for ice node
  arm64: dts: qcom: milos: Add power-domain and iface clk for ice node
  arm64: dts: qcom: x1-dell-thena: remove i2c20 (battery SMBus) and reserve its pins
  arm64: dts: qcom: glymur: Drop RPMh CXO clocks from QMP PHYs

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 23:55:18 +02:00
Arnd Bergmann a3a7c05272 Qualcomm driver fixes for v7.1
The Qualcomm ICE driver suffers from race conditions between probe() and
 get() and will in certain cases return the wrong error code, which
 results in storage drivers failing to probe. Fix these issues.
 
 Also correct the DeviceTree binding, to ensure that relevant clocks are
 described and voted for, to prevent the driver from accessing unclocked
 hardware during boot.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCgAsFiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmoVsj8OHGJqb3JuQGty
 eW8uc2UACgkQCx85Pw2ZrcVLlhAAjW6WvbknpvjbJEwVjsFCdi9wtplLibtTBU+q
 7HcPCdtN+kWSu1H1F6b/B5ugpfdroy+UK0P6tV2glOQW5h5JIVwCktT4ucPgSrld
 UyAcx9EuupyYFy/qCLz6gZ82JMAjzKyFDa2F4IEp3VbAUFneVOgg87XXDPvD8tmU
 9VsbLsXJYUaFGixFqpuG2fzSZGH6GSSd493HziyKZL43kskfH4cJOQ6LiQL5RhhE
 GuEs9Oqerv+uisS3dq4nqf7pbZEP+SetlQOuj/LcGP0gibZf4W0gvx0RuN9gj0oJ
 THeOdn1cf3mEY3wnCwrCTm4t5qn+k85EP5nVN2gmQTSgU/QIkDYNeNUydFn0rvPJ
 LlaSMaU5zDI68s+xXfm+8uGZecdRV97VLifUc0OBBh2pdy3gXgNlmctyEKES/lYR
 kUVakLcFszElfdsChRNw230MzM5wm9wjsag3KtBua5pqiGiMsfVgU59ejBR9tI6C
 tQZrPZotk4mMcljO1f9GO5swJKt5mznQ1XVabTz8NzNHJycBkCJSIA1IDxzjATt0
 9IQqtK8fULVtD5gPpwF1tEigIEy0mL1QDv4qDZWS2KkElYOrRWQVwRoP1Ba3ZqSI
 gnBTVlULNftodxbLW32ujgBDBQoEAeNBkA9Nfy9HTiYapbCqrlr7fne29+YTj2lz
 dR7+CXw=
 =QdJR
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYt/4ACgkQmmx57+YA
 GNkgIA//S0tL8vyZ4kVKetG1ZUSSTZkX1IzmNLyiroaIk1mIFIepnaLI37MU6Yiq
 RZUZsXPsHX2mPOVXSqIA0imwKn5fAVR8HgoQE8Tng0U2t9KTEW9NCgvPjLWlwpPe
 kKZlxnk3wxoD+tlEBYisjc44MLLo2pS+lrrFGd9Ki03r+Gt+jnfb/icxMnHYRSIu
 fBrsPaAzPsGuIzGUrNJcm0FzDMcLq2SJ9cIka8QUQSJR0+rugvC0thZxExAo1zt8
 UnlMrpTDcuCTzxgVdiQMj9ThhplvAqobOrgadq6h91OQtPKwGaFQ8cXnTBvX1ILk
 tFhNKTNp3hOxbPYy4km5+TCfmjI1X4b6i9hQGeP/3FTsB8L/twYQd135SDeV6Mmy
 /zgDWFd2ZyEI/DtMauOTFs8bt3Cq9Lpq0wzwOxXdknZapXDbhdidIJloX+bAmS0D
 BI6uRXEnEJQPWeHd452gJSJ9tJLqYRbSiw0KH0T430YnhwN4wx5owMyFPmGawVUj
 D6AuGaWwpTtX1velVQD6cGGMxjw2RYfMw4tNWsxB9c6BoB8dR+K5jXGi0vfE5Hk0
 6Lh09zvsc2hfIlT5gELMEkiKbEyrkAD48wUh9ZAZ1LMwIChZ6sq2JnTtaZzufetX
 HdnsUDOVCgcrjb4UEMDUq6VNwXM2M/7PKmS2q/rRdDrU7OP7hhM=
 =o97B
 -----END PGP SIGNATURE-----

Merge tag 'qcom-drivers-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/fixes

Qualcomm driver fixes for v7.1

The Qualcomm ICE driver suffers from race conditions between probe() and
get() and will in certain cases return the wrong error code, which
results in storage drivers failing to probe. Fix these issues.

Also correct the DeviceTree binding, to ensure that relevant clocks are
described and voted for, to prevent the driver from accessing unclocked
hardware during boot.

* tag 'qcom-drivers-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux:
  soc: qcom: ice: Fix the error code when 'qcom,ice' property is not found
  scsi: ufs: ufs-qcom: Remove NULL check from devm_of_qcom_ice_get()
  mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get()
  soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL
  soc: qcom: ice: Return -ENODEV if the ICE platform device is not found
  soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
  soc: qcom: ice: Allow explicit votes on 'iface' clock for ICE
  dt-bindings: crypto: qcom,ice: Fix missing power-domain and iface clk

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 23:47:40 +02:00
Arnd Bergmann c6066e3295 QCOMTEE fix for v7.1
Adding a missing va_end in early return qcomtee_object_user_init()
 -----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCgA4FiEE0qerISgy2SKkqO79Wr/6JGat8H4FAmoPEU4aHGplbnMud2lr
 bGFuZGVyQGxpbmFyby5vcmcACgkQWr/6JGat8H6ZURAAjCri3rT6c+r96CdEDJoY
 /3KobFqqfWIg8F4owuzS2mctyAcyM8mtRDmXK1bNNYhfPV4xecydZ2VRpD0BGjHD
 SDze0lnj2hY4UOnumUlWcSkdthmM9ejdQlcWupT66E5kGZpRyTH2w9p5Od69Pt3s
 5/z39jlRPu1+HIK1+1Sxh4kUdTnJvG4uUFQppnIkDLxh0leHoe1B98P6FLcpIFOq
 j+KFL1l5SiIJ2yvGu4qQoX3MB1QY8vpHTSQjik5kretAMwAZRYWH3pbKi8H8ekG+
 xmm64YBa7dRGMPohicllKrvtYUbzZMJ2I33QG16RmgeTy3J3rVOeN4WDXbDLlZrO
 BkJ7pH2dQzTuEWkRVCM8uWtCRUjZB9asCvP+nl5rHO3TsW2rZ63IOdeR+1gDoxqb
 Wsx20S0vDJUEN+1ZMYwSlW9x7ooSTGMjEpS4zrwcaC7XtuJCfihzHSzJdfl7OcaE
 oWm9/A9sjIYP/HWmgCuZAC9aCj+b06dvbphYW40Gr65fMWY7V0fD/y233DDM7mcH
 d9rW2r23Ex9qbwLeiiPFCfl1pUQSvEXMjGqDHbmb/g+hL7tJiO514TEpws0QRbtd
 QKlcUh8oaGBxbMwXd0QwjW+njj+WYEIORJ6KaqyuK3pLQEekol3WMDPXSGCIWgqA
 nTXHafKcLzj19UU913KN5Ok=
 =TQL8
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYQ8YACgkQmmx57+YA
 GNnw7g//ch+N50wQYlhYywzhTbtyyJxC1Hcfz3q45Ss2QQKeskxsbao3rdWibpOA
 cGLWGBu6nZ2ZjRVFeXNlHcE7A/RI7nJOPg1if59OaIr68QNOihE3x0HwytaJEhWv
 +dfZXerO3fEc9VzIiL4jDVn8RgqlSaZYqkcu4aIdWUCMa2iYhWWvgF7bN2MFQoEs
 EAhQXDEI3s+90zwa3LVZgyxJADO5OzdUrk6zAaWx44af0m4xO/mD/FVXOHKzCY0B
 eiHse7xjghlSFmTh7wkZ6UU/sNCkao534HU6P1/Ghq7dxMnIa3TUSJWuxa3igjpp
 818SpADP+FOyRFmCgXMYv9xMKMdNopKr0jkuRjcg9PCAs1cVD+T3IsaDc3PB1Xlr
 Hb3nVQ7S/Q5qcIZD8xHXGBWZfJJFxOcQkAXCmis9AjF2moyWDCaJJb2UckzIENmQ
 J9azKikgEpsKOoZ4JcMJIHuLNc4t2wX8YE5o6XpFyJCleeg0ElLL7/M+0pu2WLtf
 drLHtiEaBfVPc1mfzX1ZOG4ns76CxULv3Nz63GujEJY3wvqPj8NUVDskjhxknmFz
 E+3RZNvwxPqpXcwLyPoRKTmBzeo+YnpFN+IJ0eqHpE3h9gMNz526jsU2iwDwuEQv
 gzoFYx3w0TyXZssd+nJ462xhaXFOdTeGbH+IERysh2gnav71srI=
 =aUkT
 -----END PGP SIGNATURE-----

Merge tag 'qcomtee-fix-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee into arm/fixes

QCOMTEE fix for v7.1

Adding a missing va_end in early return qcomtee_object_user_init()

* tag 'qcomtee-fix-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee:
  tee: qcomtee: add missing va_end in early return qcomtee_object_user_init()

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 15:31:48 +02:00
Arnd Bergmann 56d5829720 OP-TEE fix for v7.1
Prevent possible use after free in supplicant communication.
 -----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCgA4FiEE0qerISgy2SKkqO79Wr/6JGat8H4FAmoPEQQaHGplbnMud2lr
 bGFuZGVyQGxpbmFyby5vcmcACgkQWr/6JGat8H6i7g/+IKeDvegjBiud2okBgEq3
 5yMYhmHP/ycgnAaQkpqvtZP41I4ar0LAbresNWEvmuAR71rirWSCDKRHbm0xv8Ww
 UJ1xyDxnIdNQe8sBBqrYe4QBq80l9gKpX5Tmi8eQkFGfDX+DWet0fdYBW/pKoSaI
 M/ciBORdbwYFPPb7hGBpuZ/tUuFNlRo4tcW14mM9v64m5pOe94RR92Dshf8fCwWk
 +4HmMBldBCUHz1j4hjzwEunq3aMVFHobUozssk3A0eLIpEPla0OqeO4vT1UpskfL
 nXiJCvioKH/X6/xKzhuumPN7Bvkq1eMZAQy+4N4wNJShzJJtqokAjDBUjc42576l
 7xKoNNa+mSNfrpu9RABC0hdpcTRxIbcgE70tViyeUIPOfhryAAlhaUe/iN1O4HYf
 dfwqWVGwosGUbXb8vZUvggR1GmLSLrN5H/PhXg7hb6RDveDD2eSgHWsh/+CGDrYq
 quWOamOeodblIrjOnRKsBVLuBLXJ3muIsED9HrCfChlS/EMGQYSWqr7KP+MIBQuQ
 Q9TzrBZ0j7m2MOwEzmLssa5nmbIxB7bnVOO/46xqQv4ktRC335/IYVpsQrD0AJ2B
 XM4raWikXLNIxNAwkzzDzP2Tu67zKxNtiPi1z4S0UeMY90NSJZ5Z4E7AEe8iSL1P
 Z3oXjhxDyv7aJFzYnxBApgI=
 =aOSI
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYQvUACgkQmmx57+YA
 GNkRcxAAjiVXyEFwLErRTJlQ9Tq00axugkt0YJW5LxDixuqXjfmPp6TpsATm1Np7
 Xx2eplkEhMZiIgP0nDQkT/31kFlLUd3nOQiJv9Cz8ZwwZulCWMlMeTPZ773MwlmO
 rIuo+cBaQhkYp3e3mglWLuAXR4MtW4GQzZ42jRXYvOz+3HrG3Zb8C/CfOQfMlFU0
 17M+HMBq6FAGjJEhH1sZEb19WEE87ZiH2aee1+HQ+FgzfDtW0QD+9bhlxpIsFkak
 NRKoD58ixobSy1SuMSPQ4liK76VEdP6UQDZ2R4IyhO6/QM1ZE5JRpAf9RWAy4Mqi
 4gcHrBXdME2hJUrXLtV6PdQMXPq9+/yphs+JWXwRfns+uL9ltDYwxk14Tc+hshGk
 jM0qcfPvF/s/6Med+oCnSGQn8CYYOblwi/qhpWLqyl6Rrpag1kkTqVXmOsJ0J71m
 J59fIEjqcYkv8y+46Pj3ZxNXVgXlhREpsp/gg/FAkJ5bNpKxWqdqPba4gy/rhZFh
 x2TOpfzMHMQS9MrfbLtlu4HshbwDqEyiThTgUc5c1njYwb3Mao//QxwmjLBQesWY
 sZSfl+26rF/fyPcaHne5nZ3JSKE0FGxnHot+jPDS6OURAhF8AwhKFjLnzIFnmWhy
 kqsrVQCrDySP1rzm23A9pFcpx7mlR4tZM4q4xRb4DujPHiIYK9w=
 =jbl0
 -----END PGP SIGNATURE-----

Merge tag 'optee-fix-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee into arm/fixes

OP-TEE fix for v7.1

Prevent possible use after free in supplicant communication.

* tag 'optee-fix-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee:
  tee: optee: prevent use-after-free when the client exits before the supplicant

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 15:28:19 +02:00
Arnd Bergmann 9193ffe5b4 TEE fixes for v7.1
Fixing:
 - params_from_user() cleanup in error path in tee_ioctl_supp_recv()
 - possible tee_shm leak in error path in register_shm_helper()
 - padding in struct tee_ioctl_object_invoke_arg
 -----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCgA4FiEE0qerISgy2SKkqO79Wr/6JGat8H4FAmoNXF4aHGplbnMud2lr
 bGFuZGVyQGxpbmFyby5vcmcACgkQWr/6JGat8H7G0xAA4+Rytz+NnQJk/qh+6crH
 so6W3QtQPOlPcXRbiUO/eYQLiuhxP3OHvy1v+FGk9/InRDIL2WEPaglKzeHw1k7Z
 dtHc3fte9+rMpXQi0VpWle+iIDmbcSZo6i0LEq4K6K0zR+uHLvDiye31SN7Xh9y+
 M2kmu3EYEuCnYcLScJASWXFh8zkBuE3ouxlRd237qy1ZaqirPSIBLfukES2/nKnd
 q16nSAb55oASCFE1tAJ/7p7ADIogYwY8zdIC9wPidcmCLC43cBpKcGMVukXY1TM/
 H8qjY+eNQXu5wZbs08DXAFZcqfoPykUKtN66gaKj+eHfEuu/y67Fs1RV/L1fY4ER
 82S69KGUY+uh9xBLV4WIAmF79VZLtFX9y55DyfzPIC7PLlu0/ov2+1pWcy5h/5Xl
 W2gQOTap0MnhTBPOzBN2kFArkC/lmgoufUGifIKGbxYw06ZaORUnIAUOorcItoq4
 Sl1Yl48hQ5Wr1J6N++sa75O7cvoNX3zgLSEfJkZv8IvebZH2U8coTJBdmr1lD7pI
 6W/QwQ4ZbNN2fhmQ1262coDddMEUFbDe60bKWDfnO9gCCvYtRSbWxX5j2ksclRw2
 gr6t9giURM9H2IYMEDA5UaXH7WRCmKU1Mu3SqdsklHCwoXA6ie3gg1xRn3gY1Bw+
 mGG1LrAIVXbVuDvoLEa2PE8=
 =iyqH
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYQSwACgkQmmx57+YA
 GNltaw/8CTK3hikzjTaIbJBDsXE46oNAn244rAYo8HXMM64sqrPHyEBIKPfdRpEp
 /jshVeNAfT6nA7qnt+PLPfB3w45L0Ugl29DmSIc2Drsb7Mzs0TCVfiW4tkBITbd5
 9/n7FKNnIMvtEpUhZRSvgGZiJ98dC16R5aTmnCgXNSild6VLpu3sCrResX15Mkj5
 SbKjOZmv7NziUEWAROrnznYZV+VIQiXLbYV5a66NxgSUptud55dcJWoyXXqTczzj
 +mA7RVPErcbNOCtBRzLmPVN0J9bIFQg8HGqacEhwQtslixkz2zcriNLQN/KjtXtF
 TDs3vy0LFb8TCYbe9P8QJHAuoKSVhCuifLy0v28Z7ozf5cIZ4nEPuvjomC8Mcr6e
 MjArB4Zb8QGk9MVAKg0Pt6a1tkA+5Ij1sxHJks4n3hGw0O1WJAH65VI2q53FoHPq
 7isFbT5DS21OuoxUSZF+i+VacDsD5HEOfQVuoD3LNhKyRAlhaLA2ytf37ZOQtTAQ
 RR8ccjyssZbCqXMvyjcOiIgNwAmRQ/KkDNzWLNTdCPp7lZ6OzNfWKG5ljx9QG4zV
 qzcE8GgUjZnyuy+C8yN15vGhvXW6WSYfSQBzN7lpJI0Crq9IoUTch2aKjxBiXlhD
 MpXD/8FVueRXtLRj7h8nmVGSFP82lR15EPfYImpSe8WXVIs7Tyw=
 =CNbC
 -----END PGP SIGNATURE-----

Merge tag 'tee-fixes-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee into arm/fixes

TEE fixes for v7.1

Fixing:
- params_from_user() cleanup in error path in tee_ioctl_supp_recv()
- possible tee_shm leak in error path in register_shm_helper()
- padding in struct tee_ioctl_object_invoke_arg

* tag 'tee-fixes-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee:
  tee: fix params_from_user() error path in tee_ioctl_supp_recv
  tee: shm: fix shm leak in register_shm_helper()
  tee: fix tee_ioctl_object_invoke_arg padding

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2026-05-28 15:20:37 +02:00
Yuho Choi 63838c3239 ARM: socfpga: Fix OF node refcount leak in SMP setup
socfpga_smp_prepare_cpus() looks up the Cortex-A9 SCU node with
of_find_compatible_node(), which returns a node reference that must be
released with of_node_put().

The function maps the SCU registers and then returns without dropping
that reference, leaking the node on both the success path and the
of_iomap() failure path.

Drop the reference once the mapping attempt is complete. The returned
MMIO mapping does not depend on keeping the device node reference held.

Fixes: 122694a0c7 ("ARM: socfpga: use of_iomap to map the SCU")
Cc: stable@vger.kernel.org
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
2026-05-26 09:53:20 -05:00
Manivannan Sadhasivam 462a85f9f8 soc: qcom: ice: Fix the error code when 'qcom,ice' property is not found
When both 'ice' reg entry and 'qcom,ice' property are not found in DT, then
it implies that ICE is not supported. So return -EOPNOTSUPP instead of
-ENODEV to client drivers to specify ICE functionality is not supported.

Fixes: b9ab7217dd ("soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL")
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Closes: https://lore.kernel.org/linux-arm-msm/8bac0358-9da0-4cbb-98ee-333b85ba4908@samsung.com
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260520155704.130803-1-manivannan.sadhasivam@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-21 18:18:44 -05:00
Bjorn Andersson 67802f9813 Merge branch '20260416-qcom_ice_power_and_clk_vote-v5-13-5ccf5d7e2846@oss.qualcomm.com' into arm64-fixes-for-7.1
Merge the fixes to add power-domain and correct clocks for the ICC block
in Eliza and Milos through a topic branch, to allow them to be merged
also into arm64-for-7.2 to resolve the merge conflicts that would
otherwise appear.

Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-21 16:34:26 -05:00
Harshal Dev 90825ab392 arm64: dts: qcom: eliza: Add power-domain and iface clk for ice node
Qualcomm in-line crypto engine (ICE) platform driver specifies and votes
for its own resources. Before accessing ICE hardware during probe, to
avoid potential unclocked register access issues (when clk_ignore_unused
is not passed on the kernel command line), in addition to the 'core' clock
the 'iface' clock should also be turned on by the driver. This can only be
done if the GCC_UFS_PHY_GDSC power domain is enabled. Specify both the
GCC_UFS_PHY_GDSC power domain and the 'iface' clock in the ICE node for
eliza.

Fixes: af20af39fc ("arm64: dts: qcom: Introduce Eliza Soc base dtsi")
Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Fixes: 54a4f0239f ("KVM: MMU: make kvm_mmu_zap_page() return the
Reviewed-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260416-qcom_ice_power_and_clk_vote-v5-13-5ccf5d7e2846@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-21 16:29:07 -05:00
Harshal Dev b7c9047f85 arm64: dts: qcom: milos: Add power-domain and iface clk for ice node
Qualcomm in-line crypto engine (ICE) platform driver specifies and votes
for its own resources. Before accessing ICE hardware during probe, to
avoid potential unclocked register access issues (when clk_ignore_unused
is not passed on the kernel command line), in addition to the 'core' clock
the 'iface' clock should also be turned on by the driver. This can only be
done if the UFS_PHY_GDSC power domain is enabled. Specify both the
UFS_PHY_GDSC power domain and the 'iface' clock in the ICE node for milos.

Fixes: 04bb374333 ("arm64: dts: qcom: milos: Add UFS nodes")
Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260416-qcom_ice_power_and_clk_vote-v5-12-5ccf5d7e2846@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-21 16:29:07 -05:00
Robertus Diawan Chris 471c18323d tee: qcomtee: add missing va_end in early return qcomtee_object_user_init()
qcomtee_object_user_init() is a variadic function and when the function
return because there's no dispatch callback in QCOMTEE_OBJECT_TYPE_CB
case, there's no va_end to cleanup "ap" object initialized by va_start
and that can cause undefined behavior. So make sure to use va_end before
returning the error code when there's no dispatch callback.

This is reported by Coverity Scan as "Missing varargs init or cleanup".

Fixes: d6e290837e ("tee: add Qualcomm TEE driver")
Signed-off-by: Robertus Diawan Chris <robertusdchris@gmail.com>
Reviewed-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
2026-05-20 09:22:52 +02:00
Qihang 6fa9b543f6 tee: fix params_from_user() error path in tee_ioctl_supp_recv
params_from_user() may acquire tee_shm references for MEMREF parameters
before failing after partially processing the supplied parameter array.

In tee_ioctl_supp_recv(), those references are currently not released on
that error path.

Fix this by freeing MEMREF references before returning when
params_from_user() fails.

Keep the final cleanup path in tee_ioctl_supp_recv() unchanged since
supp_recv() may consume and replace the supplied parameters, unlike the
other TEE ioctl callback paths.

Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
2026-05-20 08:49:09 +02:00
Georgiy Osokin 26682f5efc tee: shm: fix shm leak in register_shm_helper()
register_shm_helper() allocates shm before calling
iov_iter_npages(). If iov_iter_npages() returns 0, the function
jumps to err_ctx_put and leaks shm.

This can be triggered by TEE_IOC_SHM_REGISTER with
struct tee_ioctl_shm_register_data where length is 0.

Jump to err_free_shm instead.

Fixes: 7bdee41575 ("tee: Use iov_iter to better support shared buffer registration")
Cc: stable@vger.kernel.org
Cc: lvc-project@linuxtesting.org
Signed-off-by: Georgiy Osokin <g.osokin@auroraos.dev>
Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
2026-05-20 08:49:09 +02:00
Arnd Bergmann c15d7a2a11 tee: fix tee_ioctl_object_invoke_arg padding
The tee_ioctl_object_invoke_arg structure has padding on some
architectures but not on x86-32 and a few others:

include/linux/tee.h:474:32: error: padding struct to align 'params' [-Werror=padded]

I expect that all current users of this are on architectures that do
have implicit padding here (arm64, arm, x86, riscv), so make the padding
explicit in order to avoid surprises if this later gets used elsewhere.

Fixes: d5b8b0fa17 ("tee: add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Tested-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
2026-05-20 08:49:09 +02:00
Manivannan Sadhasivam b73953af9b arm64: defconfig: Enable PCI M.2 power sequencing driver
POWER_SEQUENCING_PCIE_M2 driver handles power supply to the PCIe M.2
connectors and is required on wide variety of ARM64 platforms such as
Qcom Snapdragon X Elite laptops and Mediatek Dojo Chromebooks.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260514065017.11305-1-manivannan.sadhasivam@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-18 09:56:50 -05:00
Bjorn Andersson 06b2e78c45 Merge branch '20260518-qcom-ice-fix-v7-0-2a595382185b@oss.qualcomm.com' into drivers-for-7.2
Merge the fixes for ICE driver race condition through a topic branch, to
allow sharing it with other subsystems as well.
2026-05-18 09:45:57 -05:00
Manivannan Sadhasivam 4ac19b36bf scsi: ufs: ufs-qcom: Remove NULL check from devm_of_qcom_ice_get()
Now since the devm_of_qcom_ice_get() API never returns NULL, remove the
NULL check and also simplify the error handling.

Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Acked-by: Martin K. Petersen <martin.petersen@oracle.com> # UFS
Tested-by: Sumit Garg <sumit.garg@oss.qualcomm.com> # OP-TEE as TZ
Acked-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-5-2a595382185b@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-18 09:43:25 -05:00
Manivannan Sadhasivam 2ccbb3fa5c mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get()
Now since the devm_of_qcom_ice_get() API never returns NULL, remove the
NULL check and also simplify the error handling.

Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Tested-by: Sumit Garg <sumit.garg@oss.qualcomm.com> # OP-TEE as TZ
Acked-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-4-2a595382185b@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-18 09:43:25 -05:00
Manivannan Sadhasivam b9ab7217dd soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL
devm_of_qcom_ice_get() currently returns NULL if ICE SCM is not available
or "qcom,ice" property is not found in DT. But this confuses the clients
since NULL doesn't convey the reason for failure. So return proper error
codes instead of NULL.

Reported-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Tested-by: Sumit Garg <sumit.garg@oss.qualcomm.com> # OP-TEE as TZ
Acked-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-3-2a595382185b@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-18 09:43:25 -05:00
Manivannan Sadhasivam 5a4dc805a8 soc: qcom: ice: Return -ENODEV if the ICE platform device is not found
By the time the consumer driver calls devm_of_qcom_ice_get(), all the
platform devices for ICE nodes would've been created by
of_platform_default_populate().

So for the absence of any platform device, -ENODEV should not returned, not
-EPROBE_DEFER.

Fixes: 2afbf43a4a ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver")
Tested-by: Sumit Garg <sumit.garg@oss.qualcomm.com> # OP-TEE as TZ
Acked-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-2-2a595382185b@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-18 09:43:25 -05:00
Manivannan Sadhasivam d922113ef9 soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
The current platform driver design causes probe ordering races with
consumers (UFS, eMMC) due to ICE's dependency on SCM firmware calls. If ICE
probe fails (missing ICE SCM or DT registers), devm_of_qcom_ice_get() loops
with -EPROBE_DEFER, leaving consumers non-functional even when ICE should
be gracefully disabled. devm_of_qcom_ice_get() doesn't know if the ICE
driver probe has failed due to above reasons or it is waiting for the SCM
driver.

Moreover, there is no devlink dependency between ICE and consumer drivers
as 'qcom,ice' is not considered as a DT 'supplier'. So the consumer drivers
have no idea of when the ICE driver is going to probe.

To address these issues, store the error pointer in a global xarray with
ice node phandle as a key during probe in addition to the valid ice pointer
and synchronize both qcom_ice_probe() and of_qcom_ice_get() using a mutex.

If the xarray entry is NULL, then it implies that the driver is not
probed yet, so return -EPROBE_DEFER. If it has any error pointer, return
that error pointer directly. Otherwise, add the devlink as usual and return
the valid pointer to the consumer.

Xarray is used instead of platform drvdata, since driver core frees the
drvdata during probe failure. So it cannot be used to pass the error
pointer to the consumers.

Note that this change only fixes the standalone ICE DT node bindings and
not the ones with 'ice' range embedded in the consumer nodes, where there
is no issue.

Fixes: 2afbf43a4a ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver")
Reported-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Tested-by: Sumit Garg <sumit.garg@oss.qualcomm.com> # OP-TEE as TZ
Acked-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Cc: stable@vger.kernel.org # 6.4
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260518-qcom-ice-fix-v7-1-2a595382185b@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-18 09:43:25 -05:00
Stepan Ionichev 4dc76c305a auxdisplay: Kconfig: drop unneeded quotes in PANEL_BOOT_MESSAGE dep
The PANEL_BOOT_MESSAGE dependency uses a quoted-string comparison
against the PANEL_CHANGE_MESSAGE bool symbol:

	depends on PANEL_CHANGE_MESSAGE="y"

This is the only such pattern under drivers/auxdisplay/ (grep shows
no other Kconfig file in the tree uses depends on FOO="y" with
quotes for a plain bool symbol). The quoted form is parsed by
Kconfig but is not idiomatic; the common form for the same intent
is the unquoted tristate-style dependency:

	depends on PANEL_CHANGE_MESSAGE

which evaluates true when PANEL_CHANGE_MESSAGE is y or m. Since
PANEL_CHANGE_MESSAGE is declared as bool (not tristate), there is
no behaviour change in practice: y is the only enabled value
either form can match.

Drop the quoted comparison so the dependency matches the prevailing
kernel Kconfig style and so it is obvious to readers that the
comparison works.

Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/CAHp75VfsA_LsbEKjxoeMdbhPbWj7OHZ7=0SYNA3c=ZLj_M94Bw@mail.gmail.com
Signed-off-by: Stepan Ionichev <sozdayvek@gmail.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
2026-05-17 07:58:30 +02:00
Stepan Ionichev a7511dcd9d auxdisplay: line-display: fix OOB read on zero-length message_store()
linedisp_display() unconditionally reads msg[count - 1] before
checking whether count is zero, so a write of zero bytes to the
message sysfs attribute hits msg[-1]:

	write(fd, "", 0);

	-> message_store(..., buf, count=0)
	   -> linedisp_display(linedisp, buf, count=0)
	      -> msg[count - 1] == '\n'  ; OOB read

The kernfs write buffer for that store is a 1-byte allocation
(kernfs_fop_write_iter() does kmalloc(len + 1) with len == 0),
so msg[-1] is a 1-byte read before the slab object. On a
KASAN-enabled kernel this trips an out-of-bounds report and
panics; on stock kernels it silently reads adjacent slab data
and, if that byte happens to be '\n', the following count--
wraps ssize_t 0 to -1 and is then passed to kmemdup_nul().

linedisp_display() is reached from the message_store() sysfs
callback (drivers/auxdisplay/line-display.c message attribute,
mode 0644) and from the in-tree initial-message setup with
count == -1, so the OOB path is only userspace-triggerable via
zero-byte writes; vfs_write() does not short-circuit on
count == 0 and kernfs_fop_write_iter() dispatches the store
callback regardless.

Guard the trailing-newline trim with a count check. The
existing if (!count) block then takes the clear-display path
unchanged.

Affects every auxdisplay driver that registers via
linedisp_register() / linedisp_attach(): ht16k33, max6959,
img-ascii-lcd, seg-led-gpio.

Fixes: 7e76aece6f ("auxdisplay: Extract character line display core support")
Signed-off-by: Stepan Ionichev <sozdayvek@gmail.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
2026-05-17 07:53:33 +02:00
Mihai Sain 765aaba184 ARM: dts: microchip: sam9x7: fix GMAC clock configuration
The GMAC node incorrectly listed four clocks, including a separate tx_clk
and a TSU GCK clock sourced from ID 67. According to the SAM9X7 clocking
scheme, the GMAC uses only three clocks: HCLK, PCLK, and the TSU GCK
derived from the GMAC peripheral clock (ID 24).

Remove the unused tx_clk, update the clock-names accordingly, and correct
the assigned clock to use GCK 24 instead of GCK 67. This aligns the device
tree with the actual hardware clock topology and prevents misconfiguration
of the GMAC clock tree.

[root@SAM9X75 ~]$ cat /sys/kernel/debug/clk/clk_summary | grep gmac

gmac_gclk      1       1        1        266666666   0          0     50000      Y         f802c000.ethernet           tsu_clk
                                                                                           f802c000.ethernet           tsu_clk
gmac_clk       2       2        0        266666666   0          0     50000      Y         f802c000.ethernet           hclk
                                                                                           f802c000.ethernet           pclk

Fixes: 41af45af8b ("ARM: dts: at91: sam9x7: add device tree for SoC")
Signed-off-by: Mihai Sain <mihai.sain@microchip.com>
Link: https://lore.kernel.org/r/20260309075329.1528-5-mihai.sain@microchip.com
[claudiu.beznea: massaged the patch description]
Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
2026-05-16 19:52:37 +03:00
Tudor Ambarus b66829b17f firmware: samsung: acpm: Fix mailbox channel leak on probe error
Sashiko identified the leak at [1].

The ACPM driver allocates hardware mailbox channels using
`mbox_request_channel()` during `acpm_channels_init()`. However, the
driver lacked a `.remove` callback and did not free these channels on
subsequent error paths inside `acpm_probe()`.

Additionally, if `acpm_achan_alloc_cmds()` failed during the channel
initialization loop, the function returned immediately, bypassing the
manual cleanup and permanently leaking any channels successfully
requested in previous loop iterations.

Fix this by modifying `acpm_free_mbox_chans()` to match the `devres`
action signature and registering it via `devm_add_action_or_reset()`.

Cc: stable@vger.kernel.org
Fixes: a88927b534 ("firmware: add Exynos ACPM protocol driver")
Closes: https://sashiko.dev/#/patchset/20260420-acpm-tmu-v3-0-3dc8e93f0b26%40linaro.org [1]
Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
Link: https://patch.msgid.link/20260505-acpm-fixes-sashiko-reports-v5-2-43b5ee7f1674@linaro.org
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
2026-05-14 18:54:58 +02:00
Tudor Ambarus f133bd4b5d firmware: samsung: acpm: Fix cross-thread RX length corruption
Sashiko identified a cross-thread RX length corruption bug when
reviewing the thermal addition to ACPM [1].

When multiple threads concurrently send IPC requests, the ACPM polling
mechanism can encounter responses belonging to other threads. To drain
the queue, the driver saves these concurrent responses into an internal
cache (`rx_data->cmd`) to be retrieved later by the owning thread.

Previously, the driver incorrectly used `xfer->rxcnt` (the expected
receive length of the *current* polling thread) when copying data for
*other* threads into this cache. If the threads expected responses of
different lengths, this resulted in buffer underflows (leading to reads
of uninitialized memory) or potential buffer overflows.

Fix this by replacing the boolean `response` flag in
`struct acpm_rx_data` with `rxcnt`, caching the exact expected receive
length for each specific transaction during transfer preparation. Use
this cached length when saving concurrent responses.

Consequently, ensure that `xfer->rxcnt` is explicitly zeroed in driver
helpers (e.g., `acpm_dvfs_set_xfer`) for fire-and-forget messages to
prevent uninitialized stack garbage from being interpreted as a massive
expected receive length.

Cc: stable@vger.kernel.org
Fixes: a88927b534 ("firmware: add Exynos ACPM protocol driver")
Closes: https://sashiko.dev/#/patchset/20260420-acpm-tmu-v3-0-3dc8e93f0b26%40linaro.org [1]
Reported-by: Titouan Ameline de Cadeville <titouan.ameline@gmail.com>
Closes: https://lore.kernel.org/r/20260426210255.73674-1-titouan.ameline@gmail.com/
Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
Link: https://patch.msgid.link/20260505-acpm-fixes-sashiko-reports-v5-1-43b5ee7f1674@linaro.org
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
2026-05-14 18:54:34 +02:00
Val Packett 4b15b03166 arm64: dts: qcom: x1-dell-thena: remove i2c20 (battery SMBus) and reserve its pins
i2c20 is used by the battmgr service on the ADSP to communicate with the
SBS interface of the battery. Initializing it from Linux would break the
battmgr functionality when booted in EL2. Mark those pins as reserved.

Fixes: e7733b4211 ("arm64: dts: qcom: Add support for Dell Inspiron 7441 / Latitude 7455")
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
Signed-off-by: Val Packett <val@packett.cool>
Link: https://lore.kernel.org/r/20260312005731.12488-2-val@packett.cool
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-12 15:41:13 -05:00
Abel Vesa 12c97d1c15 arm64: dts: qcom: glymur: Drop RPMh CXO clocks from QMP PHYs
On Glymur, all QMP PHYs except the one used by USB SS0 take their
reference clock from the TCSR clock controller. Since these TCSR clocks
already derive from RPMH_CXO_CLK as their sole parent, there is no need
to provide an extra `clkref` clock to the PHY nodes.

Drop the extra RPMh CXO clock inputs and use the TCSR clocks as the PHY
reference clocks instead.

This also fixes the devicetree schema validation, as the bindings do not
allow a separate `clkref` clock.

Fixes: 4eee57dd4d ("arm64: dts: qcom: glymur: Add USB related nodes")
Reported-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reported-by: Rob Herring <robh@kernel.org>
Closes: https://lore.kernel.org/r/20260410145205.GA554754-robh@kernel.org/
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260414-dts-glymur-drop-rpmh-cxo-clk-from-qmpphys-v1-1-ab12d77c4aec@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-11 20:00:11 -05:00
Harshal Dev 0d5dc58181 soc: qcom: ice: Allow explicit votes on 'iface' clock for ICE
Since Qualcomm inline-crypto engine (ICE) is now a dedicated driver
de-coupled from the QCOM UFS driver, it explicitly votes for its required
clocks during probe. For scenarios where the 'clk_ignore_unused' flag is
not passed on the kernel command line, to avoid potential unclocked ICE
hardware register access during probe the ICE driver should additionally
vote on the 'iface' clock.
Also update the suspend and resume callbacks to handle un-voting and voting
on the 'iface' clock.

Fixes: 2afbf43a4a ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver")
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260416-qcom_ice_power_and_clk_vote-v5-2-5ccf5d7e2846@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-11 09:06:29 -05:00
Bjorn Andersson e13617b594 Merge branch '20260416-qcom_ice_power_and_clk_vote-v5-1-5ccf5d7e2846@oss.qualcomm.com' into drivers-fixes-for-7.1
Merge the qcom,ice DeviceTree binding update through a topic branch to
allow sharing it with the DeviceTree branch.
2026-05-11 09:05:50 -05:00
Harshal Dev e27264daac dt-bindings: crypto: qcom,ice: Fix missing power-domain and iface clk
The DT bindings for inline-crypto engine do not specify the UFS_PHY_GDSC
power-domain and iface clock. Without enabling the iface clock and the
associated power-domain the ICE hardware cannot function correctly and
leads to unclocked hardware accesses being observed during probe.

Fix the DT bindings for inline-crypto engine to require the UFS_PHY_GDSC
power-domain and iface clock for new devices (Eliza and Milos) introduced
in the current release (7.1) with yet-to-stabilize ABI, while preserving
backward compatibility for older devices.

Fixes: 618195a7ac ("dt-bindings: crypto: qcom,inline-crypto-engine: Document the Eliza ICE")
Fixes: 85faec1e85 ("dt-bindings: crypto: qcom,inline-crypto-engine: document the Milos ICE")
Reviewed-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260416-qcom_ice_power_and_clk_vote-v5-1-5ccf5d7e2846@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
2026-05-11 09:05:19 -05:00
Peng Fan 2c6821657c soc: imx8m: Fix match data lookup for soc device
The i.MX8M soc device is registered via platform_device_register_simple(),
so it is not associated with a Device Tree node and the imx8m_soc_driver
has no of_match_table.

As a result, device_get_match_data() always returns NULL when probing
the soc device.

Retrieve the match data directly from the machine compatible using
of_machine_get_match_data(imx8_soc_match), which provides the correct SoC
data.

Fixes: 2524b293a5 ("soc: imx8m: don't access of_root directly")
Signed-off-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
2026-05-07 11:45:36 -04:00
Andy Shevchenko d25e5cbac4 auxdisplay: max6959: use regmap_assign_bits() in max6959_enable()
Replace the ternary with a direct call to the regmap_assign_bits()
helper and save a couple lines of code.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
2026-05-05 11:07:46 +02:00
Alexander Dahl 754d60ad1c memory: atmel-ebi: Allow deferred probing
After removing of_platform_default_populate() calls the atmel-ebi driver
was affected by deferred probing.  platform_driver_probe() is
incompatible with deferred probing.  This led to atmel-ebi driver
eventually not being probed on at91 sam9x60-curiosity and other sam9x60
based boards.  Subsequently the nand-controller driver (nand-controller
being a child node of ebi) on that platform was not probed and thus raw
NAND flash was inaccessible, preventing devices to boot with rootfs on
raw NAND flash (e.g. with UBI/UBIFS).

Fixes: 0b0f7e6539 ("ARM: at91: remove unnecessary of_platform_default_populate calls")
Cc: stable@vger.kernel.org
Suggested-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Alexander Dahl <ada@thorsis.com>
Link: https://patch.msgid.link/20260429125930.844790-1-ada@thorsis.com
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
2026-05-04 19:15:59 +02:00
Amirreza Zarrabi 387a926ee1 tee: optee: prevent use-after-free when the client exits before the supplicant
Commit 70b0d6b0a1 ("tee: optee: Fix supplicant wait loop") made the
client wait as killable so it can be interrupted during shutdown or
after a supplicant crash. This changes the original lifetime expectations:
the client task can now terminate while the supplicant is still processing
its request.

If the client exits first it removes the request from its queue and
kfree()s it, while the request ID remains in supp->idr. A subsequent
lookup on the supplicant path then dereferences freed memory, leading to
a use-after-free.

Serialise access to the request with supp->mutex:

  * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while
    looking up and touching the request.
  * Let optee_supp_thrd_req() notice that the client has terminated and
    signal optee_supp_send() accordingly.

With these changes the request cannot be freed while the supplicant still
has a reference, eliminating the race.

Fixes: 70b0d6b0a1 ("tee: optee: Fix supplicant wait loop")
Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Tested-by: Ox Yeh <ox.yeh@mediatek.com>
Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
2026-03-02 14:36:50 +01:00
37 changed files with 502 additions and 271 deletions

View File

@ -30,6 +30,16 @@ properties:
maxItems: 1 maxItems: 1
clocks: clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
items:
- const: core
- const: iface
power-domains:
maxItems: 1 maxItems: 1
operating-points-v2: true operating-points-v2: true
@ -44,6 +54,25 @@ required:
additionalProperties: false additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,eliza-inline-crypto-engine
- qcom,milos-inline-crypto-engine
then:
required:
- power-domains
- clock-names
properties:
clocks:
minItems: 2
clock-names:
minItems: 2
examples: examples:
- | - |
#include <dt-bindings/clock/qcom,sm8550-gcc.h> #include <dt-bindings/clock/qcom,sm8550-gcc.h>
@ -52,7 +81,11 @@ examples:
compatible = "qcom,sm8550-inline-crypto-engine", compatible = "qcom,sm8550-inline-crypto-engine",
"qcom,inline-crypto-engine"; "qcom,inline-crypto-engine";
reg = <0x01d88000 0x8000>; reg = <0x01d88000 0x8000>;
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
<&gcc GCC_UFS_PHY_AHB_CLK>;
clock-names = "core",
"iface";
power-domains = <&gcc UFS_PHY_GDSC>;
operating-points-v2 = <&ice_opp_table>; operating-points-v2 = <&ice_opp_table>;

View File

@ -146,7 +146,7 @@
partitions { partitions {
compatible = "redboot-fis"; compatible = "redboot-fis";
/* Eraseblock at 0xfe0000 */ /* Eraseblock at 0xfe0000 */
fis-index-block = <0x1fc>; fis-index-block = <0x7f>;
}; };
}; };

View File

@ -134,7 +134,7 @@
partitions { partitions {
compatible = "redboot-fis"; compatible = "redboot-fis";
/* Eraseblock at 0xfe0000 */ /* Eraseblock at 0xfe0000 */
fis-index-block = <0x1fc>; fis-index-block = <0x7f>;
}; };
}; };

View File

@ -990,9 +990,9 @@
<62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */ <62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */
<63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */ <63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */
<64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */ <64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */
clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>, <&pmc PMC_TYPE_GCK 67>; clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>;
clock-names = "hclk", "pclk", "tx_clk", "tsu_clk"; clock-names = "hclk", "pclk", "tsu_clk";
assigned-clocks = <&pmc PMC_TYPE_GCK 67>; assigned-clocks = <&pmc PMC_TYPE_GCK 24>;
assigned-clock-rates = <266666666>; assigned-clock-rates = <266666666>;
status = "disabled"; status = "disabled";
}; };

View File

@ -78,6 +78,7 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
} }
socfpga_scu_base_addr = of_iomap(np, 0); socfpga_scu_base_addr = of_iomap(np, 0);
of_node_put(np);
if (!socfpga_scu_base_addr) if (!socfpga_scu_base_addr)
return; return;
scu_enable(socfpga_scu_base_addr); scu_enable(socfpga_scu_base_addr);

View File

@ -843,7 +843,11 @@
"qcom,inline-crypto-engine"; "qcom,inline-crypto-engine";
reg = <0x0 0x01d88000 0x0 0x18000>; reg = <0x0 0x01d88000 0x0 0x18000>;
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
<&gcc GCC_UFS_PHY_AHB_CLK>;
clock-names = "core",
"iface";
power-domains = <&gcc GCC_UFS_PHY_GDSC>;
}; };
tcsr_mutex: hwlock@1f40000 { tcsr_mutex: hwlock@1f40000 {

View File

@ -2314,11 +2314,9 @@
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>, clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
<&tcsr TCSR_USB3_0_CLKREF_EN>, <&tcsr TCSR_USB3_0_CLKREF_EN>,
<&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>, <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
<&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>; <&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
clock-names = "aux", clock-names = "aux",
"clkref",
"ref", "ref",
"com_aux", "com_aux",
"pipe"; "pipe";
@ -2343,11 +2341,9 @@
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>, clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
<&tcsr TCSR_USB3_1_CLKREF_EN>, <&tcsr TCSR_USB3_1_CLKREF_EN>,
<&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>, <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
<&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>; <&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
clock-names = "aux", clock-names = "aux",
"clkref",
"ref", "ref",
"com_aux", "com_aux",
"pipe"; "pipe";
@ -2482,15 +2478,13 @@
reg = <0x0 0x00fde000 0x0 0x8000>; reg = <0x0 0x00fde000 0x0 0x8000>;
clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
<&rpmhcc RPMH_CXO_CLK>, <&tcsr TCSR_USB4_1_CLKREF_EN>,
<&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>,
<&gcc GCC_USB3_SEC_PHY_PIPE_CLK>, <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
<&tcsr TCSR_USB4_1_CLKREF_EN>;
clock-names = "aux", clock-names = "aux",
"ref", "ref",
"com_aux", "com_aux",
"usb3_pipe", "usb3_pipe";
"clkref";
power-domains = <&gcc GCC_USB_1_PHY_GDSC>; power-domains = <&gcc GCC_USB_1_PHY_GDSC>;
@ -3750,15 +3744,13 @@
reg = <0x0 0x088e1000 0x0 0x8000>; reg = <0x0 0x088e1000 0x0 0x8000>;
clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>, clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>,
<&rpmhcc RPMH_CXO_CLK>, <&tcsr TCSR_USB4_2_CLKREF_EN>,
<&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>, <&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>,
<&gcc GCC_USB3_TERT_PHY_PIPE_CLK>, <&gcc GCC_USB3_TERT_PHY_PIPE_CLK>;
<&tcsr TCSR_USB4_2_CLKREF_EN>;
clock-names = "aux", clock-names = "aux",
"ref", "ref",
"com_aux", "com_aux",
"usb3_pipe", "usb3_pipe";
"clkref";
power-domains = <&gcc GCC_USB_2_PHY_GDSC>; power-domains = <&gcc GCC_USB_2_PHY_GDSC>;

View File

@ -1275,7 +1275,11 @@
"qcom,inline-crypto-engine"; "qcom,inline-crypto-engine";
reg = <0x0 0x01d88000 0x0 0x18000>; reg = <0x0 0x01d88000 0x0 0x18000>;
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
<&gcc GCC_UFS_PHY_AHB_CLK>;
clock-names = "core",
"iface";
power-domains = <&gcc UFS_PHY_GDSC>;
}; };
tcsr_mutex: hwlock@1f40000 { tcsr_mutex: hwlock@1f40000 {

View File

@ -982,12 +982,6 @@
status = "okay"; status = "okay";
}; };
&i2c20 {
clock-frequency = <400000>;
status = "okay";
};
&lpass_tlmm { &lpass_tlmm {
spkr_01_sd_n_active: spkr-01-sd-n-active-state { spkr_01_sd_n_active: spkr-01-sd-n-active-state {
pins = "gpio12"; pins = "gpio12";
@ -1308,6 +1302,7 @@
&tlmm { &tlmm {
gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */ gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */
<76 4>, /* SPI19 (TZ Protected) */ <76 4>, /* SPI19 (TZ Protected) */
<80 2>, /* I2C20 (Battery SMBus) */
<238 1>; /* UFS Reset */ <238 1>; /* UFS Reset */
cam_rgb_default: cam-rgb-default-state { cam_rgb_default: cam-rgb-default-state {

View File

@ -260,6 +260,7 @@ CONFIG_PCI_ENDPOINT=y
CONFIG_PCI_ENDPOINT_CONFIGFS=y CONFIG_PCI_ENDPOINT_CONFIGFS=y
CONFIG_PCI_EPF_TEST=m CONFIG_PCI_EPF_TEST=m
CONFIG_PCI_PWRCTRL_GENERIC=m CONFIG_PCI_PWRCTRL_GENERIC=m
CONFIG_POWER_SEQUENCING_PCIE_M2=m
CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y CONFIG_DEVTMPFS_MOUNT=y
CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER=y

View File

@ -327,7 +327,7 @@ config PANEL_CHANGE_MESSAGE
say 'N' and keep the default message with the version. say 'N' and keep the default message with the version.
config PANEL_BOOT_MESSAGE config PANEL_BOOT_MESSAGE
depends on PANEL_CHANGE_MESSAGE="y" depends on PANEL_CHANGE_MESSAGE
string "New initialization message" string "New initialization message"
default "" default ""
help help

View File

@ -173,7 +173,7 @@ static int linedisp_display(struct linedisp *linedisp, const char *msg,
count = strlen(msg); count = strlen(msg);
/* if the string ends with a newline, trim it */ /* if the string ends with a newline, trim it */
if (msg[count - 1] == '\n') if (count && msg[count - 1] == '\n')
count--; count--;
if (!count) { if (!count) {

View File

@ -86,10 +86,7 @@ static const struct linedisp_ops max6959_linedisp_ops = {
static int max6959_enable(struct max6959_priv *priv, bool enable) static int max6959_enable(struct max6959_priv *priv, bool enable)
{ {
u8 mask = REG_CONFIGURATION_S_BIT; return regmap_assign_bits(priv->regmap, REG_CONFIGURATION, REG_CONFIGURATION_S_BIT, enable);
u8 value = enable ? mask : 0;
return regmap_update_bits(priv->regmap, REG_CONFIGURATION, mask, value);
} }
static void max6959_power_off(void *priv) static void max6959_power_off(void *priv)

View File

@ -31,6 +31,9 @@ static void acpm_dvfs_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
if (response) { if (response) {
xfer->rxcnt = cmdlen; xfer->rxcnt = cmdlen;
xfer->rxd = cmd; xfer->rxd = cmd;
} else {
xfer->rxcnt = 0;
xfer->rxd = NULL;
} }
} }

View File

@ -7,11 +7,12 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/bits.h> #include <linux/bitops.h>
#include <linux/cleanup.h> #include <linux/cleanup.h>
#include <linux/container_of.h> #include <linux/container_of.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/find.h>
#include <linux/firmware/samsung/exynos-acpm-protocol.h> #include <linux/firmware/samsung/exynos-acpm-protocol.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
@ -104,12 +105,15 @@ struct acpm_queue {
* *
* @cmd: pointer to where the data shall be saved. * @cmd: pointer to where the data shall be saved.
* @n_cmd: number of 32-bit commands. * @n_cmd: number of 32-bit commands.
* @response: true if the client expects the RX data. * @rxcnt: expected length of the response in 32-bit words.
* @completed: flag indicating if the firmware response has been fully
* processed.
*/ */
struct acpm_rx_data { struct acpm_rx_data {
u32 *cmd; u32 *cmd;
size_t n_cmd; size_t n_cmd;
bool response; size_t rxcnt;
bool completed;
}; };
#define ACPM_SEQNUM_MAX 64 #define ACPM_SEQNUM_MAX 64
@ -199,31 +203,33 @@ static void acpm_get_saved_rx(struct acpm_chan *achan,
const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1]; const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1];
u32 rx_seqnum; u32 rx_seqnum;
if (!rx_data->response) if (!rx_data->rxcnt)
return; return;
rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]); rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);
if (rx_seqnum == tx_seqnum) { if (rx_seqnum == tx_seqnum)
memcpy(xfer->rxd, rx_data->cmd, xfer->rxcnt * sizeof(*xfer->rxd)); memcpy(xfer->rxd, rx_data->cmd, xfer->rxcnt * sizeof(*xfer->rxd));
clear_bit(rx_seqnum - 1, achan->bitmap_seqnum);
}
} }
/** /**
* acpm_get_rx() - get response from RX queue. * acpm_get_rx() - get response from RX queue.
* @achan: ACPM channel info. * @achan: ACPM channel info.
* @xfer: reference to the transfer to get response for. * @xfer: reference to the transfer to get response for.
* @native_match: pointer to a boolean set to true if the thread natively
* processed its own sequence number during this call.
* *
* Return: 0 on success, -errno otherwise. * Return: 0 on success, -errno otherwise.
*/ */
static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer) static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer,
bool *native_match)
{ {
u32 rx_front, rx_seqnum, tx_seqnum, seqnum; u32 rx_front, rx_seqnum, tx_seqnum, seqnum;
const void __iomem *base, *addr; const void __iomem *base, *addr;
struct acpm_rx_data *rx_data; struct acpm_rx_data *rx_data;
u32 i, val, mlen; u32 i, val, mlen;
bool rx_set = false;
*native_match = false;
guard(mutex)(&achan->rx_lock); guard(mutex)(&achan->rx_lock);
@ -232,10 +238,8 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
tx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]); tx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]);
if (i == rx_front) { if (i == rx_front)
acpm_get_saved_rx(achan, xfer, tx_seqnum);
return 0; return 0;
}
base = achan->rx.base; base = achan->rx.base;
mlen = achan->mlen; mlen = achan->mlen;
@ -256,11 +260,16 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
seqnum = rx_seqnum - 1; seqnum = rx_seqnum - 1;
rx_data = &achan->rx_data[seqnum]; rx_data = &achan->rx_data[seqnum];
if (rx_data->response) { if (rx_data->rxcnt) {
if (rx_seqnum == tx_seqnum) { if (rx_seqnum == tx_seqnum) {
__ioread32_copy(xfer->rxd, addr, xfer->rxcnt); __ioread32_copy(xfer->rxd, addr, xfer->rxcnt);
rx_set = true; /*
clear_bit(seqnum, achan->bitmap_seqnum); * Signal completion to the polling thread.
* Pairs with smp_load_acquire() in polling
* loop.
*/
smp_store_release(&rx_data->completed, true);
*native_match = true;
} else { } else {
/* /*
* The RX data corresponds to another request. * The RX data corresponds to another request.
@ -268,10 +277,23 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
* clear yet the bitmap. It will be cleared * clear yet the bitmap. It will be cleared
* after the response is copied to the request. * after the response is copied to the request.
*/ */
__ioread32_copy(rx_data->cmd, addr, xfer->rxcnt); __ioread32_copy(rx_data->cmd, addr,
rx_data->rxcnt);
/*
* Signal completion to the polling thread.
* Pairs with smp_load_acquire() in polling
* loop.
*/
smp_store_release(&rx_data->completed, true);
} }
} else { } else {
clear_bit(seqnum, achan->bitmap_seqnum); /*
* Signal completion to the polling thread.
* Pairs with smp_load_acquire() in polling loop.
*/
smp_store_release(&rx_data->completed, true);
if (rx_seqnum == tx_seqnum)
*native_match = true;
} }
i = (i + 1) % achan->qlen; i = (i + 1) % achan->qlen;
@ -280,13 +302,6 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
/* We saved all responses, mark RX empty. */ /* We saved all responses, mark RX empty. */
writel(rx_front, achan->rx.rear); writel(rx_front, achan->rx.rear);
/*
* If the response was not in this iteration of the queue, check if the
* RX data was previously saved.
*/
if (!rx_set)
acpm_get_saved_rx(achan, xfer, tx_seqnum);
return 0; return 0;
} }
@ -301,6 +316,7 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
const struct acpm_xfer *xfer) const struct acpm_xfer *xfer)
{ {
struct device *dev = achan->acpm->dev; struct device *dev = achan->acpm->dev;
bool native_match;
ktime_t timeout; ktime_t timeout;
u32 seqnum; u32 seqnum;
int ret; int ret;
@ -309,12 +325,25 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US); timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US);
do { do {
ret = acpm_get_rx(achan, xfer); ret = acpm_get_rx(achan, xfer, &native_match);
if (ret) if (ret)
return ret; return ret;
if (!test_bit(seqnum - 1, achan->bitmap_seqnum)) /*
* Safely check if our specific transaction has been processed.
* smp_load_acquire prevents the CPU from speculatively
* executing subsequent instructions before the transaction is
* synchronized.
*/
if (smp_load_acquire(&achan->rx_data[seqnum - 1].completed)) {
/* Retrieve payload if another thread cached it for us */
if (!native_match)
acpm_get_saved_rx(achan, xfer, seqnum);
/* Relinquish ownership of the sequence slot */
clear_bit_unlock(seqnum - 1, achan->bitmap_seqnum);
return 0; return 0;
}
/* Determined experimentally. */ /* Determined experimentally. */
udelay(20); udelay(20);
@ -362,29 +391,48 @@ static int acpm_wait_for_queue_slots(struct acpm_chan *achan, u32 next_tx_front)
* TX queue. * TX queue.
* @achan: ACPM channel info. * @achan: ACPM channel info.
* @xfer: reference to the transfer being prepared. * @xfer: reference to the transfer being prepared.
*
* Return: 0 on success, -errno otherwise.
*/ */
static void acpm_prepare_xfer(struct acpm_chan *achan, static int acpm_prepare_xfer(struct acpm_chan *achan,
const struct acpm_xfer *xfer) const struct acpm_xfer *xfer)
{ {
struct acpm_rx_data *rx_data; struct acpm_rx_data *rx_data;
u32 *txd = (u32 *)xfer->txd; u32 *txd = (u32 *)xfer->txd;
unsigned long size = ACPM_SEQNUM_MAX - 1;
unsigned long bit = achan->seqnum;
/* Prevent chan->seqnum from being re-used */ bit = find_next_zero_bit(achan->bitmap_seqnum, size, bit);
do { if (bit >= size) {
if (++achan->seqnum == ACPM_SEQNUM_MAX) bit = find_first_zero_bit(achan->bitmap_seqnum, size);
achan->seqnum = 1; if (bit >= size) {
} while (test_bit(achan->seqnum - 1, achan->bitmap_seqnum)); dev_err_ratelimited(achan->acpm->dev,
"ACPM sequence number pool exhausted\n");
return -EBUSY;
}
}
/*
* Execute the atomic set to formally claim the bit and establish
* LKMM Acquire semantics against the RX thread's clear_bit_unlock().
* A loop is unnecessary because allocations are strictly serialized
* by tx_lock.
*/
if (WARN_ON_ONCE(test_and_set_bit_lock(bit, achan->bitmap_seqnum)))
return -EIO;
/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */
achan->seqnum = bit + 1;
txd[0] |= FIELD_PREP(ACPM_PROTOCOL_SEQNUM, achan->seqnum); txd[0] |= FIELD_PREP(ACPM_PROTOCOL_SEQNUM, achan->seqnum);
/* Clear data for upcoming responses */ /* Clear data for upcoming responses */
rx_data = &achan->rx_data[achan->seqnum - 1]; rx_data = &achan->rx_data[bit];
rx_data->completed = false;
memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd); memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd);
if (xfer->rxd) /* zero means no response expected */
rx_data->response = true; rx_data->rxcnt = xfer->rxcnt;
/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */ return 0;
set_bit(achan->seqnum - 1, achan->bitmap_seqnum);
} }
/** /**
@ -444,7 +492,9 @@ int acpm_do_xfer(struct acpm_handle *handle, const struct acpm_xfer *xfer)
if (ret) if (ret)
return ret; return ret;
acpm_prepare_xfer(achan, xfer); ret = acpm_prepare_xfer(achan, xfer);
if (ret)
return ret;
/* Write TX command. */ /* Write TX command. */
__iowrite32_copy(achan->tx.base + achan->mlen * tx_front, __iowrite32_copy(achan->tx.base + achan->mlen * tx_front,
@ -526,10 +576,11 @@ static int acpm_achan_alloc_cmds(struct acpm_chan *achan)
/** /**
* acpm_free_mbox_chans() - free mailbox channels. * acpm_free_mbox_chans() - free mailbox channels.
* @acpm: pointer to driver data. * @data: pointer to driver data.
*/ */
static void acpm_free_mbox_chans(struct acpm_info *acpm) static void acpm_free_mbox_chans(void *data)
{ {
struct acpm_info *acpm = data;
int i; int i;
for (i = 0; i < acpm->num_chans; i++) for (i = 0; i < acpm->num_chans; i++)
@ -557,6 +608,10 @@ static int acpm_channels_init(struct acpm_info *acpm)
if (!acpm->chans) if (!acpm->chans)
return -ENOMEM; return -ENOMEM;
ret = devm_add_action_or_reset(dev, acpm_free_mbox_chans, acpm);
if (ret)
return dev_err_probe(dev, ret, "Failed to add mbox free action.\n");
chans_shmem = acpm->sram_base + readl(&shmem->chans); chans_shmem = acpm->sram_base + readl(&shmem->chans);
for (i = 0; i < acpm->num_chans; i++) { for (i = 0; i < acpm->num_chans; i++) {
@ -578,10 +633,8 @@ static int acpm_channels_init(struct acpm_info *acpm)
cl->dev = dev; cl->dev = dev;
achan->chan = mbox_request_channel(cl, 0); achan->chan = mbox_request_channel(cl, 0);
if (IS_ERR(achan->chan)) { if (IS_ERR(achan->chan))
acpm_free_mbox_chans(acpm);
return PTR_ERR(achan->chan); return PTR_ERR(achan->chan);
}
} }
return 0; return 0;

View File

@ -1590,18 +1590,22 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock)
struct smq_policy *mq = to_smq_policy(p); struct smq_policy *mq = to_smq_policy(p);
struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
unsigned long flags; unsigned long flags;
int r = 0;
if (!e->allocated)
return -ENODATA;
spin_lock_irqsave(&mq->lock, flags); spin_lock_irqsave(&mq->lock, flags);
if (!e->allocated) {
r = -ENODATA;
goto out;
}
// FIXME: what if this block has pending background work? // FIXME: what if this block has pending background work?
del_queue(mq, e); del_queue(mq, e);
h_remove(&mq->table, e); h_remove(&mq->table, e);
free_entry(&mq->cache_alloc, e); free_entry(&mq->cache_alloc, e);
out:
spin_unlock_irqrestore(&mq->lock, flags); spin_unlock_irqrestore(&mq->lock, flags);
return 0; return r;
} }
static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock)

View File

@ -628,10 +628,11 @@ static __maybe_unused int atmel_ebi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume); static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume);
static struct platform_driver atmel_ebi_driver = { static struct platform_driver atmel_ebi_driver = {
.probe = atmel_ebi_probe,
.driver = { .driver = {
.name = "atmel-ebi", .name = "atmel-ebi",
.of_match_table = atmel_ebi_id_table, .of_match_table = atmel_ebi_id_table,
.pm = &atmel_ebi_pm_ops, .pm = &atmel_ebi_pm_ops,
}, },
}; };
builtin_platform_driver_probe(atmel_ebi_driver, atmel_ebi_probe); builtin_platform_driver(atmel_ebi_driver);

View File

@ -1918,13 +1918,13 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
return 0; return 0;
ice = devm_of_qcom_ice_get(dev); ice = devm_of_qcom_ice_get(dev);
if (ice == ERR_PTR(-EOPNOTSUPP)) { if (IS_ERR(ice)) {
dev_warn(dev, "Disabling inline encryption support\n"); if (ice != ERR_PTR(-EOPNOTSUPP))
ice = NULL; return PTR_ERR(ice);
}
if (IS_ERR_OR_NULL(ice)) dev_warn(dev, "Disabling inline encryption support\n");
return PTR_ERR_OR_ZERO(ice); return 0;
}
msm_host->ice = ice; msm_host->ice = ice;

View File

@ -247,7 +247,7 @@ static int imx8m_soc_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
data = device_get_match_data(dev); data = of_machine_get_match_data(imx8_soc_match);
if (data) { if (data) {
soc_dev_attr->soc_id = data->name; soc_dev_attr->soc_id = data->name;
ret = imx8m_soc_prepare(pdev, data->ocotp_compatible); ret = imx8m_soc_prepare(pdev, data->ocotp_compatible);

View File

@ -16,6 +16,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/xarray.h>
#include <linux/firmware/qcom/qcom_scm.h> #include <linux/firmware/qcom/qcom_scm.h>
@ -108,11 +109,15 @@ struct qcom_ice {
void __iomem *base; void __iomem *base;
struct clk *core_clk; struct clk *core_clk;
struct clk *iface_clk;
bool use_hwkm; bool use_hwkm;
bool hwkm_init_complete; bool hwkm_init_complete;
u8 hwkm_version; u8 hwkm_version;
}; };
static DEFINE_XARRAY(ice_handles);
static DEFINE_MUTEX(ice_mutex);
static bool qcom_ice_check_supported(struct qcom_ice *ice) static bool qcom_ice_check_supported(struct qcom_ice *ice)
{ {
u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION); u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
@ -312,8 +317,13 @@ int qcom_ice_resume(struct qcom_ice *ice)
err = clk_prepare_enable(ice->core_clk); err = clk_prepare_enable(ice->core_clk);
if (err) { if (err) {
dev_err(dev, "failed to enable core clock (%d)\n", dev_err(dev, "Failed to enable core clock: %d\n", err);
err); return err;
}
err = clk_prepare_enable(ice->iface_clk);
if (err) {
dev_err(dev, "Failed to enable iface clock: %d\n", err);
return err; return err;
} }
qcom_ice_hwkm_init(ice); qcom_ice_hwkm_init(ice);
@ -323,6 +333,7 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume);
int qcom_ice_suspend(struct qcom_ice *ice) int qcom_ice_suspend(struct qcom_ice *ice)
{ {
clk_disable_unprepare(ice->iface_clk);
clk_disable_unprepare(ice->core_clk); clk_disable_unprepare(ice->core_clk);
ice->hwkm_init_complete = false; ice->hwkm_init_complete = false;
@ -559,7 +570,7 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
if (!qcom_scm_ice_available()) { if (!qcom_scm_ice_available()) {
dev_warn(dev, "ICE SCM interface not found\n"); dev_warn(dev, "ICE SCM interface not found\n");
return NULL; return ERR_PTR(-EOPNOTSUPP);
} }
engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL); engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
@ -579,11 +590,17 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk"); engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
if (!engine->core_clk) if (!engine->core_clk)
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice"); engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
if (!engine->core_clk)
engine->core_clk = devm_clk_get_optional_enabled(dev, "core");
if (!engine->core_clk) if (!engine->core_clk)
engine->core_clk = devm_clk_get_enabled(dev, NULL); engine->core_clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(engine->core_clk)) if (IS_ERR(engine->core_clk))
return ERR_CAST(engine->core_clk); return ERR_CAST(engine->core_clk);
engine->iface_clk = devm_clk_get_optional_enabled(dev, "iface");
if (IS_ERR(engine->iface_clk))
return ERR_CAST(engine->iface_clk);
if (!qcom_ice_check_supported(engine)) if (!qcom_ice_check_supported(engine))
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
@ -631,6 +648,8 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
return qcom_ice_create(&pdev->dev, base); return qcom_ice_create(&pdev->dev, base);
} }
guard(mutex)(&ice_mutex);
/* /*
* If the consumer node does not provider an 'ice' reg range * If the consumer node does not provider an 'ice' reg range
* (legacy DT binding), then it must at least provide a phandle * (legacy DT binding), then it must at least provide a phandle
@ -639,20 +658,21 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node, struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node,
"qcom,ice", 0); "qcom,ice", 0);
if (!node) if (!node)
return NULL; return ERR_PTR(-EOPNOTSUPP);
pdev = of_find_device_by_node(node); pdev = of_find_device_by_node(node);
if (!pdev) { if (!pdev) {
dev_err(dev, "Cannot find device node %s\n", node->name); dev_err(dev, "Cannot find device node %s\n", node->name);
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-ENODEV);
} }
ice = platform_get_drvdata(pdev); ice = xa_load(&ice_handles, pdev->dev.of_node->phandle);
if (!ice) { if (IS_ERR_OR_NULL(ice)) {
dev_err(dev, "Cannot get ice instance from %s\n",
dev_name(&pdev->dev));
platform_device_put(pdev); platform_device_put(pdev);
return ERR_PTR(-EPROBE_DEFER); if (!ice)
return ERR_PTR(-EPROBE_DEFER);
else
return ice;
} }
link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
@ -691,8 +711,7 @@ static void devm_of_qcom_ice_put(struct device *dev, void *res)
* phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
* be created and so this function will return that instead. * be created and so this function will return that instead.
* *
* Return: ICE pointer on success, NULL if there is no ICE data provided by the * Return: ICE pointer on success, ERR_PTR() on error.
* consumer or ERR_PTR() on error.
*/ */
struct qcom_ice *devm_of_qcom_ice_get(struct device *dev) struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
{ {
@ -703,7 +722,7 @@ struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ice = of_qcom_ice_get(dev); ice = of_qcom_ice_get(dev);
if (!IS_ERR_OR_NULL(ice)) { if (!IS_ERR(ice)) {
*dr = ice; *dr = ice;
devres_add(dev, dr); devres_add(dev, dr);
} else { } else {
@ -716,24 +735,40 @@ EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get);
static int qcom_ice_probe(struct platform_device *pdev) static int qcom_ice_probe(struct platform_device *pdev)
{ {
unsigned long phandle = pdev->dev.of_node->phandle;
struct qcom_ice *engine; struct qcom_ice *engine;
void __iomem *base; void __iomem *base;
guard(mutex)(&ice_mutex);
base = devm_platform_ioremap_resource(pdev, 0); base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) { if (IS_ERR(base)) {
dev_warn(&pdev->dev, "ICE registers not found\n"); dev_warn(&pdev->dev, "ICE registers not found\n");
/* Store the error pointer for devm_of_qcom_ice_get() */
xa_store(&ice_handles, phandle, (__force void *)base, GFP_KERNEL);
return PTR_ERR(base); return PTR_ERR(base);
} }
engine = qcom_ice_create(&pdev->dev, base); engine = qcom_ice_create(&pdev->dev, base);
if (IS_ERR(engine)) if (IS_ERR(engine)) {
/* Store the error pointer for devm_of_qcom_ice_get() */
xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
return PTR_ERR(engine); return PTR_ERR(engine);
}
platform_set_drvdata(pdev, engine); xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
return 0; return 0;
} }
static void qcom_ice_remove(struct platform_device *pdev)
{
unsigned long phandle = pdev->dev.of_node->phandle;
guard(mutex)(&ice_mutex);
xa_store(&ice_handles, phandle, NULL, GFP_KERNEL);
}
static const struct of_device_id qcom_ice_of_match_table[] = { static const struct of_device_id qcom_ice_of_match_table[] = {
{ .compatible = "qcom,inline-crypto-engine" }, { .compatible = "qcom,inline-crypto-engine" },
{ }, { },
@ -742,6 +777,7 @@ MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);
static struct platform_driver qcom_ice_driver = { static struct platform_driver qcom_ice_driver = {
.probe = qcom_ice_probe, .probe = qcom_ice_probe,
.remove = qcom_ice_remove,
.driver = { .driver = {
.name = "qcom-ice", .name = "qcom-ice",
.of_match_table = qcom_ice_of_match_table, .of_match_table = qcom_ice_of_match_table,

View File

@ -10,7 +10,11 @@
struct optee_supp_req { struct optee_supp_req {
struct list_head link; struct list_head link;
int id;
bool in_queue; bool in_queue;
bool processed;
u32 func; u32 func;
u32 ret; u32 ret;
size_t num_params; size_t num_params;
@ -19,6 +23,9 @@ struct optee_supp_req {
struct completion c; struct completion c;
}; };
/* It is temporary request used for revoked pending request in supp->idr. */
#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF))
void optee_supp_init(struct optee_supp *supp) void optee_supp_init(struct optee_supp *supp)
{ {
memset(supp, 0, sizeof(*supp)); memset(supp, 0, sizeof(*supp));
@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp)
{ {
int id; int id;
struct optee_supp_req *req; struct optee_supp_req *req;
struct optee_supp_req *req_tmp;
mutex_lock(&supp->mutex); mutex_lock(&supp->mutex);
/* Abort all request retrieved by supplicant */ /* Abort all request */
idr_for_each_entry(&supp->idr, req, id) { idr_for_each_entry(&supp->idr, req, id) {
idr_remove(&supp->idr, id); idr_remove(&supp->idr, id);
req->ret = TEEC_ERROR_COMMUNICATION; /* Skip if request was already marked invalid */
complete(&req->c); if (IS_ERR(req))
} continue;
/* Abort all queued requests */ /* For queued requests where supplicant has not seen it */
list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { if (req->in_queue) {
list_del(&req->link); list_del(&req->link);
req->in_queue = false; req->in_queue = false;
}
req->processed = true;
req->ret = TEEC_ERROR_COMMUNICATION; req->ret = TEEC_ERROR_COMMUNICATION;
complete(&req->c); complete(&req->c);
} }
@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
/* Insert the request in the request list */ /* Insert the request in the request list */
mutex_lock(&supp->mutex); mutex_lock(&supp->mutex);
req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
if (req->id < 0) {
mutex_unlock(&supp->mutex);
kfree(req);
return TEEC_ERROR_OUT_OF_MEMORY;
}
list_add_tail(&req->link, &supp->reqs); list_add_tail(&req->link, &supp->reqs);
req->in_queue = true; req->in_queue = true;
req->processed = false;
mutex_unlock(&supp->mutex); mutex_unlock(&supp->mutex);
/* Tell an eventual waiter there's a new request */ /* Tell an eventual waiter there's a new request */
@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
if (wait_for_completion_killable(&req->c)) { if (wait_for_completion_killable(&req->c)) {
mutex_lock(&supp->mutex); mutex_lock(&supp->mutex);
if (req->in_queue) { if (req->in_queue) {
/* Supplicant has not seen this request yet. */
idr_remove(&supp->idr, req->id);
list_del(&req->link); list_del(&req->link);
req->in_queue = false; req->in_queue = false;
ret = TEEC_ERROR_COMMUNICATION;
} else if (req->processed) {
/*
* Supplicant has processed this request. Ignore the
* kill signal for now and submit the result. req is not
* in supp->reqs (removed by supp_pop_entry()) nor in
* supp->idr (removed by supp_pop_req()).
*/
ret = req->ret;
} else {
/*
* Supplicant is in the middle of processing this
* request. Replace req with INVALID_REQ_PTR so that
* the ID remains busy, causing optee_supp_send() to
* fail on the next call to supp_pop_req() with this ID.
*/
idr_replace(&supp->idr, INVALID_REQ_PTR, req->id);
ret = TEEC_ERROR_COMMUNICATION;
} }
mutex_unlock(&supp->mutex); mutex_unlock(&supp->mutex);
req->ret = TEEC_ERROR_COMMUNICATION; } else {
ret = req->ret;
} }
ret = req->ret;
kfree(req); kfree(req);
return ret; return ret;
} }
static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp,
int num_params, int *id) int num_params)
{ {
struct optee_supp_req *req; struct optee_supp_req *req;
@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
*id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
if (*id < 0)
return ERR_PTR(-ENOMEM);
list_del(&req->link); list_del(&req->link);
req->in_queue = false; req->in_queue = false;
@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
struct optee *optee = tee_get_drvdata(teedev); struct optee *optee = tee_get_drvdata(teedev);
struct optee_supp *supp = &optee->supp; struct optee_supp *supp = &optee->supp;
struct optee_supp_req *req = NULL; struct optee_supp_req *req = NULL;
int id;
size_t num_meta; size_t num_meta;
int rc; int rc;
@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
while (true) { while (true) {
mutex_lock(&supp->mutex); mutex_lock(&supp->mutex);
req = supp_pop_entry(supp, *num_params - num_meta, &id); req = supp_pop_entry(supp, *num_params - num_meta);
if (req)
break; /* Keep mutex held. */
mutex_unlock(&supp->mutex); mutex_unlock(&supp->mutex);
if (req) {
if (IS_ERR(req))
return PTR_ERR(req);
break;
}
/* /*
* If we didn't get a request we'll block in * If we didn't get a request we'll block in
* wait_for_completion() to avoid needless spinning. * wait_for_completion() to avoid needless spinning.
@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
return -ERESTARTSYS; return -ERESTARTSYS;
} }
/* supp->mutex held and req != NULL. */
if (IS_ERR(req)) {
mutex_unlock(&supp->mutex);
return PTR_ERR(req);
}
if (num_meta) { if (num_meta) {
/* /*
* tee-supplicant support meta parameters -> requsts can be * tee-supplicant support meta parameters -> requsts can be
@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
*/ */
param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
TEE_IOCTL_PARAM_ATTR_META; TEE_IOCTL_PARAM_ATTR_META;
param->u.value.a = id; param->u.value.a = req->id;
param->u.value.b = 0; param->u.value.b = 0;
param->u.value.c = 0; param->u.value.c = 0;
} else { } else {
mutex_lock(&supp->mutex); supp->req_id = req->id;
supp->req_id = id;
mutex_unlock(&supp->mutex);
} }
*func = req->func; *func = req->func;
@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
memcpy(param + num_meta, req->param, memcpy(param + num_meta, req->param,
sizeof(struct tee_param) * req->num_params); sizeof(struct tee_param) * req->num_params);
mutex_unlock(&supp->mutex);
return 0; return 0;
} }
@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
if (!req) if (!req)
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
/* optee_supp_thrd_req() already returned to optee. */
if (IS_ERR(req))
goto failed_req;
if ((num_params - nm) != req->num_params) if ((num_params - nm) != req->num_params)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
*num_meta = nm;
failed_req:
idr_remove(&supp->idr, id); idr_remove(&supp->idr, id);
supp->req_id = -1; supp->req_id = -1;
*num_meta = nm;
return req; return req;
} }
@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
mutex_lock(&supp->mutex); mutex_lock(&supp->mutex);
req = supp_pop_req(supp, num_params, param, &num_meta); req = supp_pop_req(supp, num_params, param, &num_meta);
mutex_unlock(&supp->mutex);
if (IS_ERR(req)) { if (IS_ERR(req)) {
/* Something is wrong, let supplicant restart. */ mutex_unlock(&supp->mutex);
/* Something is wrong, let supplicant handel it. */
return PTR_ERR(req); return PTR_ERR(req);
} }
@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
} }
} }
req->ret = ret; req->ret = ret;
req->processed = true;
/* Let the requesting thread continue */ /* Let the requesting thread continue */
complete(&req->c); complete(&req->c);
mutex_unlock(&supp->mutex);
return 0; return 0;
} }

View File

@ -306,8 +306,10 @@ int qcomtee_object_user_init(struct qcomtee_object *object,
break; break;
case QCOMTEE_OBJECT_TYPE_CB: case QCOMTEE_OBJECT_TYPE_CB:
object->ops = ops; object->ops = ops;
if (!object->ops->dispatch) if (!object->ops->dispatch) {
return -EINVAL; ret = -EINVAL;
break;
}
/* If failed, "no-name". */ /* If failed, "no-name". */
object->name = kvasprintf_const(GFP_KERNEL, fmt, ap); object->name = kvasprintf_const(GFP_KERNEL, fmt, ap);

View File

@ -530,11 +530,24 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
return 0; return 0;
} }
static void free_params(struct tee_param *params, size_t num_params)
{
size_t n;
if (!params)
return;
for (n = 0; n < num_params; n++)
if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
tee_shm_put(params[n].u.memref.shm);
kfree(params);
}
static int tee_ioctl_open_session(struct tee_context *ctx, static int tee_ioctl_open_session(struct tee_context *ctx,
struct tee_ioctl_buf_data __user *ubuf) struct tee_ioctl_buf_data __user *ubuf)
{ {
int rc; int rc;
size_t n;
struct tee_ioctl_buf_data buf; struct tee_ioctl_buf_data buf;
struct tee_ioctl_open_session_arg __user *uarg; struct tee_ioctl_open_session_arg __user *uarg;
struct tee_ioctl_open_session_arg arg; struct tee_ioctl_open_session_arg arg;
@ -595,16 +608,7 @@ out:
*/ */
if (rc && have_session && ctx->teedev->desc->ops->close_session) if (rc && have_session && ctx->teedev->desc->ops->close_session)
ctx->teedev->desc->ops->close_session(ctx, arg.session); ctx->teedev->desc->ops->close_session(ctx, arg.session);
free_params(params, arg.num_params);
if (params) {
/* Decrease ref count for all valid shared memory pointers */
for (n = 0; n < arg.num_params; n++)
if (tee_param_is_memref(params + n) &&
params[n].u.memref.shm)
tee_shm_put(params[n].u.memref.shm);
kfree(params);
}
return rc; return rc;
} }
@ -612,7 +616,6 @@ static int tee_ioctl_invoke(struct tee_context *ctx,
struct tee_ioctl_buf_data __user *ubuf) struct tee_ioctl_buf_data __user *ubuf)
{ {
int rc; int rc;
size_t n;
struct tee_ioctl_buf_data buf; struct tee_ioctl_buf_data buf;
struct tee_ioctl_invoke_arg __user *uarg; struct tee_ioctl_invoke_arg __user *uarg;
struct tee_ioctl_invoke_arg arg; struct tee_ioctl_invoke_arg arg;
@ -657,14 +660,7 @@ static int tee_ioctl_invoke(struct tee_context *ctx,
} }
rc = params_to_user(uparams, arg.num_params, params); rc = params_to_user(uparams, arg.num_params, params);
out: out:
if (params) { free_params(params, arg.num_params);
/* Decrease ref count for all valid shared memory pointers */
for (n = 0; n < arg.num_params; n++)
if (tee_param_is_memref(params + n) &&
params[n].u.memref.shm)
tee_shm_put(params[n].u.memref.shm);
kfree(params);
}
return rc; return rc;
} }
@ -672,7 +668,6 @@ static int tee_ioctl_object_invoke(struct tee_context *ctx,
struct tee_ioctl_buf_data __user *ubuf) struct tee_ioctl_buf_data __user *ubuf)
{ {
int rc; int rc;
size_t n;
struct tee_ioctl_buf_data buf; struct tee_ioctl_buf_data buf;
struct tee_ioctl_object_invoke_arg __user *uarg; struct tee_ioctl_object_invoke_arg __user *uarg;
struct tee_ioctl_object_invoke_arg arg; struct tee_ioctl_object_invoke_arg arg;
@ -716,14 +711,7 @@ static int tee_ioctl_object_invoke(struct tee_context *ctx,
} }
rc = params_to_user(uparams, arg.num_params, params); rc = params_to_user(uparams, arg.num_params, params);
out: out:
if (params) { free_params(params, arg.num_params);
/* Decrease ref count for all valid shared memory pointers */
for (n = 0; n < arg.num_params; n++)
if (tee_param_is_memref(params + n) &&
params[n].u.memref.shm)
tee_shm_put(params[n].u.memref.shm);
kfree(params);
}
return rc; return rc;
} }
@ -846,9 +834,15 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
return -ENOMEM; return -ENOMEM;
rc = params_from_user(ctx, params, num_params, uarg->params); rc = params_from_user(ctx, params, num_params, uarg->params);
if (rc) if (rc) {
goto out; free_params(params, num_params);
return rc;
}
/*
* supp_recv() may consume and replace the supplied parameters, so the
* final cleanup cannot use free_params() like the other ioctl paths.
*/
rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
if (rc) if (rc)
goto out; goto out;

View File

@ -435,7 +435,7 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags,
num_pages = iov_iter_npages(iter, INT_MAX); num_pages = iov_iter_npages(iter, INT_MAX);
if (!num_pages) { if (!num_pages) {
ret = ERR_PTR(-ENOMEM); ret = ERR_PTR(-ENOMEM);
goto err_ctx_put; goto err_free_shm;
} }
shm->pages = kzalloc_objs(*shm->pages, num_pages); shm->pages = kzalloc_objs(*shm->pages, num_pages);

View File

@ -177,13 +177,13 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host)
int i; int i;
ice = devm_of_qcom_ice_get(dev); ice = devm_of_qcom_ice_get(dev);
if (ice == ERR_PTR(-EOPNOTSUPP)) { if (IS_ERR(ice)) {
dev_warn(dev, "Disabling inline encryption support\n"); if (ice != ERR_PTR(-EOPNOTSUPP))
ice = NULL; return PTR_ERR(ice);
}
if (IS_ERR_OR_NULL(ice)) dev_warn(dev, "Disabling inline encryption support\n");
return PTR_ERR_OR_ZERO(ice); return 0;
}
host->ice = ice; host->ice = ice;

View File

@ -153,8 +153,6 @@ long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
long freed); long freed);
bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list); bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list);
int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison); int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison);
int get_huge_page_for_hwpoison(unsigned long pfn, int flags,
bool *migratable_cleared);
void folio_putback_hugetlb(struct folio *folio); void folio_putback_hugetlb(struct folio *folio);
void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int reason); void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int reason);
void hugetlb_fix_reserve_counts(struct inode *inode); void hugetlb_fix_reserve_counts(struct inode *inode);
@ -421,12 +419,6 @@ static inline int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb,
return 0; return 0;
} }
static inline int get_huge_page_for_hwpoison(unsigned long pfn, int flags,
bool *migratable_cleared)
{
return 0;
}
static inline void folio_putback_hugetlb(struct folio *folio) static inline void folio_putback_hugetlb(struct folio *folio)
{ {
} }

View File

@ -4975,8 +4975,6 @@ extern int soft_offline_page(unsigned long pfn, int flags);
*/ */
extern const struct attribute_group memory_failure_attr_group; extern const struct attribute_group memory_failure_attr_group;
extern void memory_failure_queue(unsigned long pfn, int flags); extern void memory_failure_queue(unsigned long pfn, int flags);
extern int __get_huge_page_for_hwpoison(unsigned long pfn, int flags,
bool *migratable_cleared);
void num_poisoned_pages_inc(unsigned long pfn); void num_poisoned_pages_inc(unsigned long pfn);
void num_poisoned_pages_sub(unsigned long pfn, long i); void num_poisoned_pages_sub(unsigned long pfn, long i);
#else #else
@ -4984,12 +4982,6 @@ static inline void memory_failure_queue(unsigned long pfn, int flags)
{ {
} }
static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flags,
bool *migratable_cleared)
{
return 0;
}
static inline void num_poisoned_pages_inc(unsigned long pfn) static inline void num_poisoned_pages_inc(unsigned long pfn)
{ {
} }

View File

@ -470,6 +470,7 @@ struct tee_ioctl_object_invoke_arg {
__u32 op; __u32 op;
__u32 ret; __u32 ret;
__u32 num_params; __u32 num_params;
__u32 :32;
/* num_params tells the actual number of element in params */ /* num_params tells the actual number of element in params */
struct tee_ioctl_param params[]; struct tee_ioctl_param params[];
}; };

View File

@ -188,10 +188,13 @@ cleanup:
/* Expose all pages to the buddy, they are useless for CMA. */ /* Expose all pages to the buddy, they are useless for CMA. */
if (!test_bit(CMA_RESERVE_PAGES_ON_ERROR, &cma->flags)) { 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]; cmr = &cma->ranges[r];
start_pfn = r <= allocrange ? early_pfn[r] : cmr->early_pfn;
end_pfn = cmr->base_pfn + cmr->count; 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)); free_reserved_page(pfn_to_page(pfn));
} }
} }

View File

@ -205,7 +205,8 @@ static int __init cma_debugfs_init(void)
cma_debugfs_root = debugfs_create_dir("cma", NULL); cma_debugfs_root = debugfs_create_dir("cma", NULL);
for (i = 0; i < cma_area_count; i++) 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; return 0;
} }

View File

@ -32,9 +32,9 @@ struct folio *damon_get_folio(unsigned long pfn)
return NULL; return NULL;
folio = page_folio(page); folio = page_folio(page);
if (!folio_test_lru(folio) || !folio_try_get(folio)) if (!folio_try_get(folio))
return NULL; return NULL;
if (unlikely(page_folio(page) != folio || !folio_test_lru(folio))) { if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio)) {
folio_put(folio); folio_put(folio);
folio = NULL; folio = NULL;
} }

View File

@ -3015,9 +3015,9 @@ static void __split_huge_pud_locked(struct vm_area_struct *vma, pud_t *pud,
if (!folio_test_referenced(folio) && pud_young(old_pud)) if (!folio_test_referenced(folio) && pud_young(old_pud))
folio_set_referenced(folio); folio_set_referenced(folio);
folio_remove_rmap_pud(folio, page, vma); folio_remove_rmap_pud(folio, page, vma);
folio_put(folio);
add_mm_counter(vma->vm_mm, mm_counter_file(folio), add_mm_counter(vma->vm_mm, mm_counter_file(folio),
-HPAGE_PUD_NR); -HPAGE_PUD_NR);
folio_put(folio);
} }
void __split_huge_pud(struct vm_area_struct *vma, pud_t *pud, void __split_huge_pud(struct vm_area_struct *vma, pud_t *pud,
@ -3133,7 +3133,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (!folio_test_referenced(folio) && pmd_young(old_pmd)) if (!folio_test_referenced(folio) && pmd_young(old_pmd))
folio_set_referenced(folio); folio_set_referenced(folio);
folio_remove_rmap_pmd(folio, page, vma); folio_remove_rmap_pmd(folio, page, vma);
add_mm_counter(mm, mm_counter_file(folio), -HPAGE_PMD_NR);
folio_put(folio); folio_put(folio);
return;
} }
add_mm_counter(mm, mm_counter_file(folio), -HPAGE_PMD_NR); add_mm_counter(mm, mm_counter_file(folio), -HPAGE_PMD_NR);
return; return;

View File

@ -118,6 +118,9 @@ static int hugetlb_acct_memory(struct hstate *h, long delta);
static void hugetlb_vma_lock_free(struct vm_area_struct *vma); 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_lock_alloc(struct vm_area_struct *vma);
static void __hugetlb_vma_unlock_write_free(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, static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
unsigned long start, unsigned long end, bool take_locks); unsigned long start, unsigned long end, bool take_locks);
static struct resv_map *vma_resv_map(struct vm_area_struct *vma); static struct resv_map *vma_resv_map(struct vm_area_struct *vma);
@ -4974,6 +4977,7 @@ again:
addr, dst_vma); addr, dst_vma);
folio_put(pte_folio); folio_put(pte_folio);
if (ret) { if (ret) {
restore_reserve_on_error(h, dst_vma, addr, new_folio);
folio_put(new_folio); folio_put(new_folio);
break; break;
} }
@ -6270,6 +6274,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
folio_put(*foliop); folio_put(*foliop);
*foliop = NULL; *foliop = NULL;
if (ret) { if (ret) {
restore_reserve_on_error(h, dst_vma, dst_addr, folio);
folio_put(folio); folio_put(folio);
goto out; goto out;
} }
@ -6891,6 +6896,31 @@ out:
return pte; 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 * huge_pmd_unshare - Unmap a pmd table if it is shared by multiple users
* @tlb: the current mmu_gather. * @tlb: the current mmu_gather.
@ -6910,24 +6940,7 @@ out:
int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma, int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep) unsigned long addr, pte_t *ptep)
{ {
unsigned long sz = huge_page_size(hstate_vma(vma)); return __huge_pmd_unshare(tlb, vma, addr, ptep, /*check_locks=*/true);
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;
} }
/* /*
@ -6961,6 +6974,13 @@ pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma,
return NULL; 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, int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep) unsigned long addr, pte_t *ptep)
{ {
@ -7141,17 +7161,6 @@ int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison
return ret; return ret;
} }
int get_huge_page_for_hwpoison(unsigned long pfn, int flags,
bool *migratable_cleared)
{
int ret;
spin_lock_irq(&hugetlb_lock);
ret = __get_huge_page_for_hwpoison(pfn, flags, migratable_cleared);
spin_unlock_irq(&hugetlb_lock);
return ret;
}
/** /**
* folio_putback_hugetlb - unisolate a hugetlb folio * folio_putback_hugetlb - unisolate a hugetlb folio
* @folio: the isolated hugetlb folio * @folio: the isolated hugetlb folio
@ -7269,7 +7278,7 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
if (!ptep) if (!ptep)
continue; continue;
ptl = huge_pte_lock(h, mm, ptep); 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); spin_unlock(ptl);
} }
huge_pmd_unshare_flush(&tlb, vma); huge_pmd_unshare_flush(&tlb, vma);

View File

@ -207,6 +207,8 @@ static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
/* Remapping the head page requires r/w */ /* Remapping the head page requires r/w */
if (unlikely(walk->nr_walked == 0 && walk->vmemmap_head)) { if (unlikely(walk->nr_walked == 0 && walk->vmemmap_head)) {
VM_WARN_ON_ONCE(!PageHead((const struct page *)addr));
list_del(&walk->vmemmap_head->lru); list_del(&walk->vmemmap_head->lru);
/* /*
@ -218,6 +220,8 @@ static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
entry = mk_pte(walk->vmemmap_head, PAGE_KERNEL); entry = mk_pte(walk->vmemmap_head, PAGE_KERNEL);
} else { } else {
VM_WARN_ON_ONCE(!PageTail((const struct page *)addr));
/* /*
* Remap the tail pages as read-only to catch illegal write * Remap the tail pages as read-only to catch illegal write
* operation to the tail pages. * operation to the tail pages.
@ -232,33 +236,28 @@ static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
static void vmemmap_restore_pte(pte_t *pte, unsigned long addr, static void vmemmap_restore_pte(pte_t *pte, unsigned long addr,
struct vmemmap_remap_walk *walk) struct vmemmap_remap_walk *walk)
{ {
struct page *page; struct page *src = pte_page(ptep_get(pte)), *dst;
struct page *from, *to;
page = list_first_entry(walk->vmemmap_pages, struct page, lru);
list_del(&page->lru);
/* /*
* Initialize tail pages in the newly allocated vmemmap page. * When rolling back vmemmap_remap_free(), keep the copied head page
* * mapping and restore only PTEs currently pointing at the shared tail
* There is folio-scope metadata that is encoded in the first few * page.
* tail pages.
*
* Use the value last tail page in the page with the head page
* to initialize the rest of tail pages.
*/ */
from = compound_head((struct page *)addr) + if (walk->vmemmap_tail && walk->vmemmap_tail != src)
PAGE_SIZE / sizeof(struct page) - 1; return;
to = page_to_virt(page);
for (int i = 0; i < PAGE_SIZE / sizeof(struct page); i++, to++) VM_WARN_ON_ONCE(PageHead((const struct page *)addr));
*to = *from;
dst = list_first_entry(walk->vmemmap_pages, struct page, lru);
list_del(&dst->lru);
copy_page(page_to_virt(dst), page_to_virt(src));
/* /*
* Makes sure that preceding stores to the page contents become visible * Makes sure that preceding stores to the page contents become visible
* before the set_pte_at() write. * before the set_pte_at() write.
*/ */
smp_wmb(); smp_wmb();
set_pte_at(&init_mm, addr, pte, mk_pte(page, PAGE_KERNEL)); set_pte_at(&init_mm, addr, pte, mk_pte(dst, PAGE_KERNEL));
} }
/** /**
@ -324,6 +323,7 @@ static int vmemmap_remap_free(unsigned long start, unsigned long end,
*/ */
walk = (struct vmemmap_remap_walk) { walk = (struct vmemmap_remap_walk) {
.remap_pte = vmemmap_restore_pte, .remap_pte = vmemmap_restore_pte,
.vmemmap_tail = vmemmap_tail,
.vmemmap_pages = vmemmap_pages, .vmemmap_pages = vmemmap_pages,
.flags = 0, .flags = 0,
}; };

View File

@ -2011,6 +2011,7 @@ struct memcg_stock_pcp {
struct work_struct work; struct work_struct work;
unsigned long flags; unsigned long flags;
uint8_t drain_idx;
}; };
static DEFINE_PER_CPU_ALIGNED(struct memcg_stock_pcp, memcg_stock) = { static DEFINE_PER_CPU_ALIGNED(struct memcg_stock_pcp, memcg_stock) = {
@ -2194,7 +2195,9 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
if (!success) { if (!success) {
i = empty_slot; i = empty_slot;
if (i == -1) { if (i == -1) {
i = get_random_u32_below(NR_MEMCG_STOCK); i = stock->drain_idx++;
if (stock->drain_idx == NR_MEMCG_STOCK)
stock->drain_idx = 0;
drain_stock(stock, i); drain_stock(stock, i);
} }
css_get(&memcg->css); css_get(&memcg->css);

View File

@ -1966,20 +1966,19 @@ void folio_clear_hugetlb_hwpoison(struct folio *folio)
folio_free_raw_hwp(folio, true); folio_free_raw_hwp(folio, true);
} }
/* static int get_huge_page_for_hwpoison(unsigned long pfn, int flags,
* Called from hugetlb code with hugetlb_lock held.
*/
int __get_huge_page_for_hwpoison(unsigned long pfn, int flags,
bool *migratable_cleared) bool *migratable_cleared)
{ {
struct page *page = pfn_to_page(pfn); struct page *page = pfn_to_page(pfn);
struct folio *folio = page_folio(page); struct folio *folio;
bool count_increased = false; bool count_increased = false;
int ret, rc; int ret, rc;
spin_lock_irq(&hugetlb_lock);
folio = page_folio(page);
if (!folio_test_hugetlb(folio)) { if (!folio_test_hugetlb(folio)) {
ret = MF_HUGETLB_NON_HUGEPAGE; ret = MF_HUGETLB_NON_HUGEPAGE;
goto out; goto out_unlock;
} else if (flags & MF_COUNT_INCREASED) { } else if (flags & MF_COUNT_INCREASED) {
ret = MF_HUGETLB_IN_USED; ret = MF_HUGETLB_IN_USED;
count_increased = true; count_increased = true;
@ -1995,13 +1994,13 @@ int __get_huge_page_for_hwpoison(unsigned long pfn, int flags,
} else { } else {
ret = MF_HUGETLB_RETRY; ret = MF_HUGETLB_RETRY;
if (!(flags & MF_NO_RETRY)) if (!(flags & MF_NO_RETRY))
goto out; goto out_unlock;
} }
rc = hugetlb_update_hwpoison(folio, page); rc = hugetlb_update_hwpoison(folio, page);
if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) { if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) {
ret = rc; ret = rc;
goto out; goto out_unlock;
} }
/* /*
@ -2013,8 +2012,10 @@ int __get_huge_page_for_hwpoison(unsigned long pfn, int flags,
*migratable_cleared = true; *migratable_cleared = true;
} }
spin_unlock_irq(&hugetlb_lock);
return ret; return ret;
out: out_unlock:
spin_unlock_irq(&hugetlb_lock);
if (count_increased) if (count_increased)
folio_put(folio); folio_put(folio);
return ret; return ret;

View File

@ -14,6 +14,8 @@
#include <linux/userfaultfd_k.h> #include <linux/userfaultfd_k.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/file.h>
#include <linux/cleanup.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/tlb.h> #include <asm/tlb.h>
#include "internal.h" #include "internal.h"
@ -66,7 +68,7 @@ static const struct vm_uffd_ops *vma_uffd_ops(struct vm_area_struct *vma)
{ {
if (vma_is_anonymous(vma)) if (vma_is_anonymous(vma))
return &anon_uffd_ops; return &anon_uffd_ops;
return vma->vm_ops ? vma->vm_ops->uffd_ops : NULL; return vma->vm_ops->uffd_ops;
} }
static __always_inline static __always_inline
@ -443,16 +445,80 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
return ret; return ret;
} }
static int mfill_copy_folio_retry(struct mfill_state *state, #define MFILL_RETRY_STATE_VMA_FLAGS \
append_vma_flags(__VMA_UFFD_FLAGS, VMA_SHARED_BIT)
/*
* VMA state saved before dropping the locks in mfill_copy_folio_retry().
* Used to detect VMA replacement or incompatible changes after reacquiring the
* locks.
*/
struct mfill_retry_state {
const struct vm_uffd_ops *ops;
struct file *file;
vma_flags_t flags;
pgoff_t pgoff;
};
static void mfill_retry_state_save(struct mfill_retry_state *s,
struct vm_area_struct *vma)
{
s->flags = vma_flags_and_mask(&vma->flags, MFILL_RETRY_STATE_VMA_FLAGS);
s->ops = vma_uffd_ops(vma);
s->pgoff = vma->vm_pgoff;
if (vma->vm_file)
s->file = get_file(vma->vm_file);
}
static bool mfill_retry_state_changed(struct mfill_retry_state *state,
struct vm_area_struct *vma)
{
vma_flags_t flags = vma_flags_and_mask(&vma->flags,
MFILL_RETRY_STATE_VMA_FLAGS);
/* Have any UFFD flags (missing, WP, minor) changed? */
if (!vma_flags_same_pair(&state->flags, &flags))
return true;
/* VMA type or effective uffd_ops changed while the lock was dropped */
if (state->ops != vma_uffd_ops(vma))
return true;
/* VMA was anonymous before; changed only if it no longer is */
if (!state->file)
return !vma_is_anonymous(vma);
/* VMA was file backed, but file, inode or offset has changed */
if (!vma->vm_file || vma->vm_file->f_inode != state->file->f_inode ||
state->file != vma->vm_file || vma->vm_pgoff != state->pgoff)
return true;
return false;
}
static void mfill_retry_state_put(struct mfill_retry_state *s)
{
if (s->file)
fput(s->file);
}
DEFINE_FREE(retry_put, struct mfill_retry_state *,
if (_T) mfill_retry_state_put(_T));
static int mfill_copy_folio_retry(struct mfill_state *mfill_state,
struct folio *folio) struct folio *folio)
{ {
const struct vm_uffd_ops *orig_ops = vma_uffd_ops(state->vma); struct mfill_retry_state retry_state = { 0 };
unsigned long src_addr = state->src_addr; struct mfill_retry_state *for_free __free(retry_put) = &retry_state;
unsigned long src_addr = mfill_state->src_addr;
void *kaddr; void *kaddr;
int err; int err;
mfill_retry_state_save(&retry_state, mfill_state->vma);
/* retry copying with mm_lock dropped */ /* retry copying with mm_lock dropped */
mfill_put_vma(state); mfill_put_vma(mfill_state);
kaddr = kmap_local_folio(folio, 0); kaddr = kmap_local_folio(folio, 0);
err = copy_from_user(kaddr, (const void __user *) src_addr, PAGE_SIZE); err = copy_from_user(kaddr, (const void __user *) src_addr, PAGE_SIZE);
@ -463,19 +529,14 @@ static int mfill_copy_folio_retry(struct mfill_state *state,
flush_dcache_folio(folio); flush_dcache_folio(folio);
/* reget VMA and PMD, they could change underneath us */ /* reget VMA and PMD, they could change underneath us */
err = mfill_get_vma(state); err = mfill_get_vma(mfill_state);
if (err) if (err)
return err; return err;
/* if (mfill_retry_state_changed(&retry_state, mfill_state->vma))
* The VMA type may have changed while the lock was dropped
* (e.g. replaced with a hugetlb mapping), making the caller's
* ops pointer stale.
*/
if (vma_uffd_ops(state->vma) != orig_ops)
return -EAGAIN; return -EAGAIN;
err = mfill_establish_pmd(state); err = mfill_establish_pmd(mfill_state);
if (err) if (err)
return err; return err;
@ -491,6 +552,11 @@ static int __mfill_atomic_pte(struct mfill_state *state,
struct folio *folio; struct folio *folio;
int ret; int ret;
if (!ops) {
VM_WARN_ONCE(1, "UFFDIO_COPY for unsupported VMA");
return -EOPNOTSUPP;
}
folio = ops->alloc_folio(state->vma, state->dst_addr); folio = ops->alloc_folio(state->vma, state->dst_addr);
if (!folio) if (!folio)
return -ENOMEM; return -ENOMEM;