powerpc/mm/radix: Change pte relax sequence to handle nest MMU hang
authorAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Tue, 29 May 2018 14:28:41 +0000 (19:58 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Sun, 3 Jun 2018 10:40:34 +0000 (20:40 +1000)
When relaxing access (read -> read_write update), pte needs to be marked invalid
to handle a nest MMU bug. We also need to do a tlb flush after the pte is
marked invalid before updating the pte with new access bits.

We also move tlb flush to platform specific __ptep_set_access_flags. This will
help us to gerid of unnecessary tlb flush on BOOK3S 64 later. We don't do that
in this patch. This also helps in avoiding multiple tlbies with coprocessor
attached.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/book3s/32/pgtable.h
arch/powerpc/include/asm/nohash/32/pgtable.h
arch/powerpc/include/asm/nohash/64/pgtable.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/mm/pgtable-book3s64.c
arch/powerpc/mm/pgtable-radix.c
arch/powerpc/mm/pgtable.c

index 39d3a4245694a0d93d748e11e059edea1be87639..02f5acd7ccc4d4a954b72b7ea1d8792912bf557a 100644 (file)
@@ -245,6 +245,8 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
        unsigned long clr = ~pte_val(entry) & _PAGE_RO;
 
        pte_update(ptep, clr, set);
+
+       flush_tlb_page(vma, address);
 }
 
 #define __HAVE_ARCH_PTE_SAME
index c2471bac86b9de46c4c3de287816d58c8ed60ab5..7c46a98cc7f4700d7361c8f4a5571bef9f1e3cfd 100644 (file)
@@ -266,6 +266,8 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
        unsigned long clr = ~pte_val(entry) & (_PAGE_RO | _PAGE_NA);
 
        pte_update(ptep, clr, set);
+
+       flush_tlb_page(vma, address);
 }
 
 static inline int pte_young(pte_t pte)
index 180161d714fb2f7eb7e92af14fc29a1a3e4e8cf3..dd0c7236208f243d7f4503dec5dd4391844d1c46 100644 (file)
@@ -304,6 +304,8 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
        unsigned long old = pte_val(*ptep);
        *ptep = __pte(old | bits);
 #endif
+
+       flush_tlb_page(vma, address);
 }
 
 #define __HAVE_ARCH_PTE_SAME
index ab7d2d996be4d25a352a07488fc1a4aa66a9935a..14c79a7dc855062e65ff314b2e28961f47538bbf 100644 (file)
@@ -8,6 +8,7 @@
 #include <asm/processor.h>             /* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
+#include <asm/tlbflush.h>
 
 struct mm_struct;
 
index 4a8150481a8893781478374fdad69c36a7bacf73..82fed87289de83dd5f8ab083c426c6177c5b120b 100644 (file)
@@ -52,7 +52,6 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
                 */
                __ptep_set_access_flags(vma, pmdp_ptep(pmdp),
                                        pmd_pte(entry), address, MMU_PAGE_2M);
-               flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
        }
        return changed;
 }
index 2034cbc9aa5605a22d56190531e0378b98fbff18..0ddfe591cd246c274933b9ce1caa715137982fbe 100644 (file)
@@ -1091,8 +1091,12 @@ void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep,
        struct mm_struct *mm = vma->vm_mm;
        unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED |
                                              _PAGE_RW | _PAGE_EXEC);
-
-       if (cpu_has_feature(CPU_FTR_POWER9_DD1)) {
+       /*
+        * To avoid NMMU hang while relaxing access, we need mark
+        * the pte invalid in between.
+        */
+       if (cpu_has_feature(CPU_FTR_POWER9_DD1) ||
+           atomic_read(&mm->context.copros) > 0) {
                unsigned long old_pte, new_pte;
 
                old_pte = __radix_pte_update(ptep, ~0, 0);
@@ -1100,9 +1104,11 @@ void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep,
                 * new value of pte
                 */
                new_pte = old_pte | set;
-               radix__flush_tlb_pte_p9_dd1(old_pte, mm, address);
+               radix__flush_tlb_page_psize(mm, address, psize);
                __radix_pte_update(ptep, 0, new_pte);
-       } else
+       } else {
                __radix_pte_update(ptep, 0, set);
+               radix__flush_tlb_page_psize(mm, address, psize);
+       }
        asm volatile("ptesync" : : : "memory");
 }
index 20cacd33e5be2bc133e73f27081bbf8d1d061ffc..5281c2c064af2e8ce1f9f8fbcf92a0ae56c8faa8 100644 (file)
@@ -224,7 +224,6 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
                assert_pte_locked(vma->vm_mm, address);
                __ptep_set_access_flags(vma, ptep, entry,
                                        address, mmu_virtual_psize);
-               flush_tlb_page(vma, address);
        }
        return changed;
 }
@@ -263,7 +262,6 @@ extern int huge_ptep_set_access_flags(struct vm_area_struct *vma,
                assert_spin_locked(&vma->vm_mm->page_table_lock);
 #endif
                __ptep_set_access_flags(vma, ptep, pte, addr, psize);
-               flush_hugetlb_page(vma, addr);
        }
        return changed;
 #endif