]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm64/mm: Hoist barriers out of set_ptes_anysz() loop
authorRyan Roberts <ryan.roberts@arm.com>
Tue, 22 Apr 2025 08:18:14 +0000 (09:18 +0100)
committerWill Deacon <will@kernel.org>
Fri, 9 May 2025 12:43:07 +0000 (13:43 +0100)
set_ptes_anysz() previously called __set_pte() for each PTE in the
range, which would conditionally issue a DSB and ISB to make the new PTE
value immediately visible to the table walker if the new PTE was valid
and for kernel space.

We can do better than this; let's hoist those barriers out of the loop
so that they are only issued once at the end of the loop. We then reduce
the cost by the number of PTEs in the range.

Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Tested-by: Luiz Capitulino <luizcap@redhat.com>
Link: https://lore.kernel.org/r/20250422081822.1836315-7-ryan.roberts@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/include/asm/pgtable.h

index d80aa9ba0a16d754ba68d2686fd990d9ada5995c..39c331743b69e70b4893e24c6f69118582c06d83 100644 (file)
@@ -320,13 +320,11 @@ static inline void __set_pte_nosync(pte_t *ptep, pte_t pte)
        WRITE_ONCE(*ptep, pte);
 }
 
-static inline void __set_pte(pte_t *ptep, pte_t pte)
+static inline void __set_pte_complete(pte_t pte)
 {
-       __set_pte_nosync(ptep, pte);
-
        /*
         * Only if the new pte is valid and kernel, otherwise TLB maintenance
-        * or update_mmu_cache() have the necessary barriers.
+        * has the necessary barriers.
         */
        if (pte_valid_not_user(pte)) {
                dsb(ishst);
@@ -334,6 +332,12 @@ static inline void __set_pte(pte_t *ptep, pte_t pte)
        }
 }
 
+static inline void __set_pte(pte_t *ptep, pte_t pte)
+{
+       __set_pte_nosync(ptep, pte);
+       __set_pte_complete(pte);
+}
+
 static inline pte_t __ptep_get(pte_t *ptep)
 {
        return READ_ONCE(*ptep);
@@ -658,12 +662,14 @@ static inline void __set_ptes_anysz(struct mm_struct *mm, pte_t *ptep,
 
        for (;;) {
                __check_safe_pte_update(mm, ptep, pte);
-               __set_pte(ptep, pte);
+               __set_pte_nosync(ptep, pte);
                if (--nr == 0)
                        break;
                ptep++;
                pte = pte_advance_pfn(pte, stride);
        }
+
+       __set_pte_complete(pte);
 }
 
 static inline void __set_ptes(struct mm_struct *mm,