arm64: mm: convert cpu_do_switch_mm() to C
authorMark Rutland <mark.rutland@arm.com>
Thu, 13 Feb 2020 12:14:52 +0000 (12:14 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Thu, 27 Feb 2020 14:30:50 +0000 (14:30 +0000)
There's no reason that cpu_do_switch_mm() needs to be written as an
assembly function, and having it as a C function would make it easier to
maintain.

This patch converts cpu_do_switch_mm() to C, removing code that this
change makes redundant (e.g. the mmid macro). Since the header comment
was stale and the prototype now implies all the necessary information,
this comment is removed. The 'pgd_phys' argument is made a phys_addr_t
to match the return type of virt_to_phys().

At the same time, post_ttbr_update_workaround() is updated to use
IS_ENABLED(), which allows the compiler to figure out it can elide calls
for !CONFIG_CAVIUM_ERRATUM_27456 builds.

There should be no functional change as a result of this patch.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
[catalin.marinas@arm.com: change comments from asm-style to C-style]
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/proc-fns.h
arch/arm64/mm/context.c
arch/arm64/mm/proc.S

index aca337d79d12ab288cf186fa619e608847e224f7..af03001293c6f3e66eb92adef7577b919fe189d2 100644 (file)
@@ -256,12 +256,6 @@ alternative_endif
        ldr     \rd, [\rn, #VMA_VM_MM]
        .endm
 
-/*
- * mmid - get context id from mm pointer (mm->context.id)
- */
-       .macro  mmid, rd, rn
-       ldr     \rd, [\rn, #MM_CONTEXT_ID]
-       .endm
 /*
  * read_ctr - read CTR_EL0. If the system has mismatched register fields,
  * provide the system wide safe value from arm64_ftr_reg_ctrel0.sys_val
index 3827ff4040a3f71da95de705ac5e905b25b8a15d..ab46187c63001660d9f64ea505e4251d31a12ffd 100644 (file)
@@ -46,6 +46,8 @@ static inline void cpu_set_reserved_ttbr0(void)
        isb();
 }
 
+void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
+
 static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm)
 {
        BUG_ON(pgd == swapper_pg_dir);
index a2ce65a0c1fa9d539e1f38a73d18ae11537f7b27..0d5d1f0525eb39558c96e4cc627e2db0519d699b 100644 (file)
 
 #include <asm/page.h>
 
-struct mm_struct;
 struct cpu_suspend_ctx;
 
 extern void cpu_do_idle(void);
-extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
 extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr);
 extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 
index 8ef73e89d51485950b0bc05689c64120b8fedebc..8524f03d629c951fe0cdb5e1891786048929b71e 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2012 ARM Ltd.
  */
 
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -254,10 +255,37 @@ switch_mm_fastpath:
 /* Errata workaround post TTBRx_EL1 update. */
 asmlinkage void post_ttbr_update_workaround(void)
 {
+       if (!IS_ENABLED(CONFIG_CAVIUM_ERRATUM_27456))
+               return;
+
        asm(ALTERNATIVE("nop; nop; nop",
                        "ic iallu; dsb nsh; isb",
-                       ARM64_WORKAROUND_CAVIUM_27456,
-                       CONFIG_CAVIUM_ERRATUM_27456));
+                       ARM64_WORKAROUND_CAVIUM_27456));
+}
+
+void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
+{
+       unsigned long ttbr1 = read_sysreg(ttbr1_el1);
+       unsigned long asid = ASID(mm);
+       unsigned long ttbr0 = phys_to_ttbr(pgd_phys);
+
+       /* Skip CNP for the reserved ASID */
+       if (system_supports_cnp() && asid)
+               ttbr0 |= TTBR_CNP_BIT;
+
+       /* SW PAN needs a copy of the ASID in TTBR0 for entry */
+       if (IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN))
+               ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid);
+
+       /* Set ASID in TTBR1 since TCR.A1 is set */
+       ttbr1 &= ~TTBR_ASID_MASK;
+       ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
+
+       write_sysreg(ttbr1, ttbr1_el1);
+       isb();
+       write_sysreg(ttbr0, ttbr0_el1);
+       isb();
+       post_ttbr_update_workaround();
 }
 
 static int asids_init(void)
index aafed690241147f661b000532d4d0b788b37b04d..76899c6eee2b812aa926bb9a5dc0c090d66b912d 100644 (file)
@@ -142,34 +142,6 @@ SYM_FUNC_END(cpu_do_resume)
        .popsection
 #endif
 
-/*
- *     cpu_do_switch_mm(pgd_phys, tsk)
- *
- *     Set the translation table base pointer to be pgd_phys.
- *
- *     - pgd_phys - physical address of new TTB
- */
-SYM_FUNC_START(cpu_do_switch_mm)
-       mrs     x2, ttbr1_el1
-       mmid    x1, x1                          // get mm->context.id
-       phys_to_ttbr x3, x0
-
-alternative_if ARM64_HAS_CNP
-       cbz     x1, 1f                          // skip CNP for reserved ASID
-       orr     x3, x3, #TTBR_CNP_BIT
-1:
-alternative_else_nop_endif
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
-       bfi     x3, x1, #48, #16                // set the ASID field in TTBR0
-#endif
-       bfi     x2, x1, #48, #16                // set the ASID
-       msr     ttbr1_el1, x2                   // in TTBR1 (since TCR.A1 is set)
-       isb
-       msr     ttbr0_el1, x3                   // now update TTBR0
-       isb
-       b       post_ttbr_update_workaround     // Back to C code...
-SYM_FUNC_END(cpu_do_switch_mm)
-
        .pushsection ".idmap.text", "awx"
 
 .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2