aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>2018-08-22 13:16:05 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2018-08-23 07:56:48 -0400
commitf08d08f3db55452d31ba4a37c702da6245876b96 (patch)
tree288a41b58b8e75c13572658eb8898aa220ebcd7e
parentbd0dbb73e01306a1060e56f81e5fe287be936477 (diff)
powerpc/mm/radix: Only need the Nest MMU workaround for R -> RW transition
The Nest MMU workaround is only needed for RW upgrades. Avoid doing that for other PTE updates. We also avoid clearing the PTE while marking it invalid. This is because other page table walkers will find this PTE none and can result in unexpected behaviour due to that. Instead we clear _PAGE_PRESENT and set the software PTE bit _PAGE_INVALID. pte_present() is already updated to check for both bits. This makes sure page table walkers will find the PTE present and things like pte_pfn(pte) returns the right value. Based on an original patch from Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com> Reviewed-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/mm/pgtable-radix.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c
index 7be99fd9af15..c879979faa73 100644
--- a/arch/powerpc/mm/pgtable-radix.c
+++ b/arch/powerpc/mm/pgtable-radix.c
@@ -1045,20 +1045,22 @@ void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep,
1045 struct mm_struct *mm = vma->vm_mm; 1045 struct mm_struct *mm = vma->vm_mm;
1046 unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | 1046 unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED |
1047 _PAGE_RW | _PAGE_EXEC); 1047 _PAGE_RW | _PAGE_EXEC);
1048
1049 unsigned long change = pte_val(entry) ^ pte_val(*ptep);
1048 /* 1050 /*
1049 * To avoid NMMU hang while relaxing access, we need mark 1051 * To avoid NMMU hang while relaxing access, we need mark
1050 * the pte invalid in between. 1052 * the pte invalid in between.
1051 */ 1053 */
1052 if (atomic_read(&mm->context.copros) > 0) { 1054 if ((change & _PAGE_RW) && atomic_read(&mm->context.copros) > 0) {
1053 unsigned long old_pte, new_pte; 1055 unsigned long old_pte, new_pte;
1054 1056
1055 old_pte = __radix_pte_update(ptep, ~0, 0); 1057 old_pte = __radix_pte_update(ptep, _PAGE_PRESENT, _PAGE_INVALID);
1056 /* 1058 /*
1057 * new value of pte 1059 * new value of pte
1058 */ 1060 */
1059 new_pte = old_pte | set; 1061 new_pte = old_pte | set;
1060 radix__flush_tlb_page_psize(mm, address, psize); 1062 radix__flush_tlb_page_psize(mm, address, psize);
1061 __radix_pte_update(ptep, 0, new_pte); 1063 __radix_pte_update(ptep, _PAGE_INVALID, new_pte);
1062 } else { 1064 } else {
1063 __radix_pte_update(ptep, 0, set); 1065 __radix_pte_update(ptep, 0, set);
1064 /* 1066 /*