summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Roberts <ryan.roberts@arm.com>2025-04-22 11:18:14 +0300
committerWill Deacon <will@kernel.org>2025-05-09 15:43:07 +0300
commitf89b399e8d6e9fdef92b15164c2737ac8ef5831a (patch)
tree4f4fe9c602d2573c0ed5316727b114f801b8136b
parenta899b7d0673cc7c53545a4c9c30c2c93f2f8cc7d (diff)
downloadlinux-f89b399e8d6e9fdef92b15164c2737ac8ef5831a.tar.xz
arm64/mm: Hoist barriers out of set_ptes_anysz() loop
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>
-rw-r--r--arch/arm64/include/asm/pgtable.h16
1 files changed, 11 insertions, 5 deletions
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index d80aa9ba0a16..39c331743b69 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -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,