powerpc/mm/book3s: Update pmd_present to look at _PAGE_PRESENT bit
authorAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Thu, 20 Sep 2018 18:09:42 +0000 (23:39 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 3 Oct 2018 05:39:58 +0000 (15:39 +1000)
With this patch we use 0x8000000000000000UL (_PAGE_PRESENT) to indicate a valid
pgd/pud/pmd entry. We also switch the p**_present() to look at this bit.

With pmd_present, we have a special case. We need to make sure we consider a
pmd marked invalid during THP split as present. Right now we clear the
_PAGE_PRESENT bit during a pmdp_invalidate. Inorder to consider this special
case we add a new pte bit _PAGE_INVALID (mapped to _RPAGE_SW0). This bit is
only used with _PAGE_PRESENT cleared. Hence we are not really losing a pte bit
for this special case. pmd_present is also updated to look at _PAGE_INVALID.

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/64/hash.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/pgtable-book3s64.c
arch/powerpc/mm/pgtable.c

index d52a51b2ce7baf170af224d2264a88f746ef58a3..fcf8b10a209feff70217c0bfc88b41ad0192fb56 100644 (file)
 #include <asm/book3s/64/hash-4k.h>
 #endif
 
+/* Bits to set in a PMD/PUD/PGD entry valid bit*/
+#define HASH_PMD_VAL_BITS              (0x8000000000000000UL)
+#define HASH_PUD_VAL_BITS              (0x8000000000000000UL)
+#define HASH_PGD_VAL_BITS              (0x8000000000000000UL)
+
 /*
  * Size of EA range mapped by our pagetables.
  */
index 13a688fc8cd0c90177493aee7f3b2f1806843dd3..8feb4a3240d523a6de36638bcaa0b5e6c402c5fd 100644 (file)
@@ -875,8 +875,16 @@ static inline int pmd_none(pmd_t pmd)
 
 static inline int pmd_present(pmd_t pmd)
 {
+       /*
+        * A pmd is considerent present if _PAGE_PRESENT is set.
+        * We also need to consider the pmd present which is marked
+        * invalid during a split. Hence we look for _PAGE_INVALID
+        * if we find _PAGE_PRESENT cleared.
+        */
+       if (pmd_raw(pmd) & cpu_to_be64(_PAGE_PRESENT | _PAGE_INVALID))
+               return true;
 
-       return !pmd_none(pmd);
+       return false;
 }
 
 static inline int pmd_bad(pmd_t pmd)
@@ -903,7 +911,7 @@ static inline int pud_none(pud_t pud)
 
 static inline int pud_present(pud_t pud)
 {
-       return !pud_none(pud);
+       return (pud_raw(pud) & cpu_to_be64(_PAGE_PRESENT));
 }
 
 extern struct page *pud_page(pud_t pud);
@@ -950,7 +958,7 @@ static inline int pgd_none(pgd_t pgd)
 
 static inline int pgd_present(pgd_t pgd)
 {
-       return !pgd_none(pgd);
+       return (pgd_raw(pgd) & cpu_to_be64(_PAGE_PRESENT));
 }
 
 static inline pte_t pgd_pte(pgd_t pgd)
index f23a89d8e4ce6c8fecf0816d23b88d621c68428b..8ff03c7205a0403d2f0093dde099956c29d63608 100644 (file)
@@ -1001,9 +1001,9 @@ void __init hash__early_init_mmu(void)
         * 4k use hugepd format, so for hash set then to
         * zero
         */
-       __pmd_val_bits = 0;
-       __pud_val_bits = 0;
-       __pgd_val_bits = 0;
+       __pmd_val_bits = HASH_PMD_VAL_BITS;
+       __pud_val_bits = HASH_PUD_VAL_BITS;
+       __pgd_val_bits = HASH_PGD_VAL_BITS;
 
        __kernel_virt_start = H_KERN_VIRT_START;
        __kernel_virt_size = H_KERN_VIRT_SIZE;
index 01d7c0f7c4f0c2a12d15cd09bd66c88609dd235e..654000da8b156592a361e9fcd7f2f9d3947a7ae8 100644 (file)
@@ -69,7 +69,11 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                pmd_t *pmdp, pmd_t pmd)
 {
 #ifdef CONFIG_DEBUG_VM
-       WARN_ON(pte_present(pmd_pte(*pmdp)) && !pte_protnone(pmd_pte(*pmdp)));
+       /*
+        * Make sure hardware valid bit is not set. We don't do
+        * tlb flush for this update.
+        */
+       WARN_ON(pte_val(pmd_pte(*pmdp)) & _PAGE_PRESENT);
        assert_spin_locked(pmd_lockptr(mm, pmdp));
        WARN_ON(!(pmd_trans_huge(pmd) || pmd_devmap(pmd)));
 #endif
@@ -106,7 +110,7 @@ pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
 {
        unsigned long old_pmd;
 
-       old_pmd = pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
+       old_pmd = pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, _PAGE_INVALID);
        flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
        /*
         * This ensures that generic code that rely on IRQ disabling
index d71c7777669cd367ba400d5afa497752066b23a8..aee04b209b51e143c9a737b212c829075686b06b 100644 (file)
@@ -188,11 +188,10 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
                pte_t pte)
 {
        /*
-        * When handling numa faults, we already have the pte marked
-        * _PAGE_PRESENT, but we can be sure that it is not in hpte.
-        * Hence we can use set_pte_at for them.
+        * Make sure hardware valid bit is not set. We don't do
+        * tlb flush for this update.
         */
-       VM_WARN_ON(pte_present(*ptep) && !pte_protnone(*ptep));
+       VM_WARN_ON(pte_val(*ptep) & _PAGE_PRESENT);
 
        /* Add the pte bit when trying to set a pte */
        pte = __pte(pte_val(pte) | _PAGE_PTE);