1e2cda322SAndrea Arcangeli /* 2e2cda322SAndrea Arcangeli * mm/pgtable-generic.c 3e2cda322SAndrea Arcangeli * 4e2cda322SAndrea Arcangeli * Generic pgtable methods declared in asm-generic/pgtable.h 5e2cda322SAndrea Arcangeli * 6e2cda322SAndrea Arcangeli * Copyright (C) 2010 Linus Torvalds 7e2cda322SAndrea Arcangeli */ 8e2cda322SAndrea Arcangeli 9f95ba941SAndrew Morton #include <linux/pagemap.h> 10e2cda322SAndrea Arcangeli #include <asm/tlb.h> 11e2cda322SAndrea Arcangeli #include <asm-generic/pgtable.h> 12e2cda322SAndrea Arcangeli 13bc4b4448SJoonsoo Kim /* 14bc4b4448SJoonsoo Kim * If a p?d_bad entry is found while walking page tables, report 15bc4b4448SJoonsoo Kim * the error, before resetting entry to p?d_none. Usually (but 16bc4b4448SJoonsoo Kim * very seldom) called out from the p?d_none_or_clear_bad macros. 17bc4b4448SJoonsoo Kim */ 18bc4b4448SJoonsoo Kim 19bc4b4448SJoonsoo Kim void pgd_clear_bad(pgd_t *pgd) 20bc4b4448SJoonsoo Kim { 21bc4b4448SJoonsoo Kim pgd_ERROR(*pgd); 22bc4b4448SJoonsoo Kim pgd_clear(pgd); 23bc4b4448SJoonsoo Kim } 24bc4b4448SJoonsoo Kim 25bc4b4448SJoonsoo Kim void pud_clear_bad(pud_t *pud) 26bc4b4448SJoonsoo Kim { 27bc4b4448SJoonsoo Kim pud_ERROR(*pud); 28bc4b4448SJoonsoo Kim pud_clear(pud); 29bc4b4448SJoonsoo Kim } 30bc4b4448SJoonsoo Kim 31bc4b4448SJoonsoo Kim void pmd_clear_bad(pmd_t *pmd) 32bc4b4448SJoonsoo Kim { 33bc4b4448SJoonsoo Kim pmd_ERROR(*pmd); 34bc4b4448SJoonsoo Kim pmd_clear(pmd); 35bc4b4448SJoonsoo Kim } 36bc4b4448SJoonsoo Kim 37e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS 38e2cda322SAndrea Arcangeli /* 39cef23d9dSRik van Riel * Only sets the access flags (dirty, accessed), as well as write 40cef23d9dSRik van Riel * permission. Furthermore, we know it always gets set to a "more 41e2cda322SAndrea Arcangeli * permissive" setting, which allows most architectures to optimize 42e2cda322SAndrea Arcangeli * this. We return whether the PTE actually changed, which in turn 43e2cda322SAndrea Arcangeli * instructs the caller to do things like update__mmu_cache. This 44e2cda322SAndrea Arcangeli * used to be done in the caller, but sparc needs minor faults to 45e2cda322SAndrea Arcangeli * force that call on sun4c so we changed this macro slightly 46e2cda322SAndrea Arcangeli */ 47e2cda322SAndrea Arcangeli int ptep_set_access_flags(struct vm_area_struct *vma, 48e2cda322SAndrea Arcangeli unsigned long address, pte_t *ptep, 49e2cda322SAndrea Arcangeli pte_t entry, int dirty) 50e2cda322SAndrea Arcangeli { 51e2cda322SAndrea Arcangeli int changed = !pte_same(*ptep, entry); 52e2cda322SAndrea Arcangeli if (changed) { 53e2cda322SAndrea Arcangeli set_pte_at(vma->vm_mm, address, ptep, entry); 54cef23d9dSRik van Riel flush_tlb_fix_spurious_fault(vma, address); 55e2cda322SAndrea Arcangeli } 56e2cda322SAndrea Arcangeli return changed; 57e2cda322SAndrea Arcangeli } 58e2cda322SAndrea Arcangeli #endif 59e2cda322SAndrea Arcangeli 60e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS 61e2cda322SAndrea Arcangeli int pmdp_set_access_flags(struct vm_area_struct *vma, 62e2cda322SAndrea Arcangeli unsigned long address, pmd_t *pmdp, 63e2cda322SAndrea Arcangeli pmd_t entry, int dirty) 64e2cda322SAndrea Arcangeli { 65e2cda322SAndrea Arcangeli #ifdef CONFIG_TRANSPARENT_HUGEPAGE 66e2cda322SAndrea Arcangeli int changed = !pmd_same(*pmdp, entry); 67e2cda322SAndrea Arcangeli VM_BUG_ON(address & ~HPAGE_PMD_MASK); 68e2cda322SAndrea Arcangeli if (changed) { 69e2cda322SAndrea Arcangeli set_pmd_at(vma->vm_mm, address, pmdp, entry); 70e2cda322SAndrea Arcangeli flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 71e2cda322SAndrea Arcangeli } 72e2cda322SAndrea Arcangeli return changed; 73e2cda322SAndrea Arcangeli #else /* CONFIG_TRANSPARENT_HUGEPAGE */ 74e2cda322SAndrea Arcangeli BUG(); 75e2cda322SAndrea Arcangeli return 0; 76e2cda322SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 77e2cda322SAndrea Arcangeli } 78e2cda322SAndrea Arcangeli #endif 79e2cda322SAndrea Arcangeli 80e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH 81e2cda322SAndrea Arcangeli int ptep_clear_flush_young(struct vm_area_struct *vma, 82e2cda322SAndrea Arcangeli unsigned long address, pte_t *ptep) 83e2cda322SAndrea Arcangeli { 84e2cda322SAndrea Arcangeli int young; 85e2cda322SAndrea Arcangeli young = ptep_test_and_clear_young(vma, address, ptep); 86e2cda322SAndrea Arcangeli if (young) 87e2cda322SAndrea Arcangeli flush_tlb_page(vma, address); 88e2cda322SAndrea Arcangeli return young; 89e2cda322SAndrea Arcangeli } 90e2cda322SAndrea Arcangeli #endif 91e2cda322SAndrea Arcangeli 92e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH 93e2cda322SAndrea Arcangeli int pmdp_clear_flush_young(struct vm_area_struct *vma, 94e2cda322SAndrea Arcangeli unsigned long address, pmd_t *pmdp) 95e2cda322SAndrea Arcangeli { 96e2cda322SAndrea Arcangeli int young; 97d8c37c48SNaoya Horiguchi #ifdef CONFIG_TRANSPARENT_HUGEPAGE 98d8c37c48SNaoya Horiguchi VM_BUG_ON(address & ~HPAGE_PMD_MASK); 99d8c37c48SNaoya Horiguchi #else 100e2cda322SAndrea Arcangeli BUG(); 101e2cda322SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 102e2cda322SAndrea Arcangeli young = pmdp_test_and_clear_young(vma, address, pmdp); 103e2cda322SAndrea Arcangeli if (young) 104e2cda322SAndrea Arcangeli flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 105e2cda322SAndrea Arcangeli return young; 106e2cda322SAndrea Arcangeli } 107e2cda322SAndrea Arcangeli #endif 108e2cda322SAndrea Arcangeli 109e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH 110e2cda322SAndrea Arcangeli pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address, 111e2cda322SAndrea Arcangeli pte_t *ptep) 112e2cda322SAndrea Arcangeli { 113e2cda322SAndrea Arcangeli pte_t pte; 114e2cda322SAndrea Arcangeli pte = ptep_get_and_clear((vma)->vm_mm, address, ptep); 1158d1acce4SRik van Riel if (pte_accessible(pte)) 116e2cda322SAndrea Arcangeli flush_tlb_page(vma, address); 117e2cda322SAndrea Arcangeli return pte; 118e2cda322SAndrea Arcangeli } 119e2cda322SAndrea Arcangeli #endif 120e2cda322SAndrea Arcangeli 121e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_CLEAR_FLUSH 122b3697c02SAndrea Arcangeli #ifdef CONFIG_TRANSPARENT_HUGEPAGE 123e2cda322SAndrea Arcangeli pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address, 124e2cda322SAndrea Arcangeli pmd_t *pmdp) 125e2cda322SAndrea Arcangeli { 126e2cda322SAndrea Arcangeli pmd_t pmd; 127e2cda322SAndrea Arcangeli VM_BUG_ON(address & ~HPAGE_PMD_MASK); 128e2cda322SAndrea Arcangeli pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp); 129e2cda322SAndrea Arcangeli flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 130e2cda322SAndrea Arcangeli return pmd; 131e2cda322SAndrea Arcangeli } 132b3697c02SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 133e2cda322SAndrea Arcangeli #endif 134e2cda322SAndrea Arcangeli 135e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH 136b3697c02SAndrea Arcangeli #ifdef CONFIG_TRANSPARENT_HUGEPAGE 13773636b1aSChris Metcalf void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address, 138e2cda322SAndrea Arcangeli pmd_t *pmdp) 139e2cda322SAndrea Arcangeli { 140e2cda322SAndrea Arcangeli pmd_t pmd = pmd_mksplitting(*pmdp); 141e2cda322SAndrea Arcangeli VM_BUG_ON(address & ~HPAGE_PMD_MASK); 142e2cda322SAndrea Arcangeli set_pmd_at(vma->vm_mm, address, pmdp, pmd); 143e2cda322SAndrea Arcangeli /* tlb flush only to serialize against gup-fast */ 144e2cda322SAndrea Arcangeli flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 145e2cda322SAndrea Arcangeli } 146b3697c02SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 147e2cda322SAndrea Arcangeli #endif 148e3ebcf64SGerald Schaefer 149e3ebcf64SGerald Schaefer #ifndef __HAVE_ARCH_PGTABLE_DEPOSIT 150e3ebcf64SGerald Schaefer #ifdef CONFIG_TRANSPARENT_HUGEPAGE 1516b0b50b0SAneesh Kumar K.V void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, 1526b0b50b0SAneesh Kumar K.V pgtable_t pgtable) 153e3ebcf64SGerald Schaefer { 154e3ebcf64SGerald Schaefer assert_spin_locked(&mm->page_table_lock); 155e3ebcf64SGerald Schaefer 156e3ebcf64SGerald Schaefer /* FIFO */ 157*c389a250SKirill A. Shutemov if (!pmd_huge_pte(mm, pmdp)) 158e3ebcf64SGerald Schaefer INIT_LIST_HEAD(&pgtable->lru); 159e3ebcf64SGerald Schaefer else 160*c389a250SKirill A. Shutemov list_add(&pgtable->lru, &pmd_huge_pte(mm, pmdp)->lru); 161*c389a250SKirill A. Shutemov pmd_huge_pte(mm, pmdp) = pgtable; 162e3ebcf64SGerald Schaefer } 163e3ebcf64SGerald Schaefer #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 164e3ebcf64SGerald Schaefer #endif 165e3ebcf64SGerald Schaefer 166e3ebcf64SGerald Schaefer #ifndef __HAVE_ARCH_PGTABLE_WITHDRAW 167e3ebcf64SGerald Schaefer #ifdef CONFIG_TRANSPARENT_HUGEPAGE 168e3ebcf64SGerald Schaefer /* no "address" argument so destroys page coloring of some arch */ 1696b0b50b0SAneesh Kumar K.V pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp) 170e3ebcf64SGerald Schaefer { 171e3ebcf64SGerald Schaefer pgtable_t pgtable; 172e3ebcf64SGerald Schaefer 173e3ebcf64SGerald Schaefer assert_spin_locked(&mm->page_table_lock); 174e3ebcf64SGerald Schaefer 175e3ebcf64SGerald Schaefer /* FIFO */ 176*c389a250SKirill A. Shutemov pgtable = pmd_huge_pte(mm, pmdp); 177e3ebcf64SGerald Schaefer if (list_empty(&pgtable->lru)) 178*c389a250SKirill A. Shutemov pmd_huge_pte(mm, pmdp) = NULL; 179e3ebcf64SGerald Schaefer else { 180*c389a250SKirill A. Shutemov pmd_huge_pte(mm, pmdp) = list_entry(pgtable->lru.next, 181e3ebcf64SGerald Schaefer struct page, lru); 182e3ebcf64SGerald Schaefer list_del(&pgtable->lru); 183e3ebcf64SGerald Schaefer } 184e3ebcf64SGerald Schaefer return pgtable; 185e3ebcf64SGerald Schaefer } 186e3ebcf64SGerald Schaefer #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 187e3ebcf64SGerald Schaefer #endif 18846dcde73SGerald Schaefer 18946dcde73SGerald Schaefer #ifndef __HAVE_ARCH_PMDP_INVALIDATE 19046dcde73SGerald Schaefer #ifdef CONFIG_TRANSPARENT_HUGEPAGE 19146dcde73SGerald Schaefer void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, 19246dcde73SGerald Schaefer pmd_t *pmdp) 19346dcde73SGerald Schaefer { 19446dcde73SGerald Schaefer set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(*pmdp)); 19546dcde73SGerald Schaefer flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 19646dcde73SGerald Schaefer } 19746dcde73SGerald Schaefer #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 19846dcde73SGerald Schaefer #endif 199