xref: /openbmc/linux/mm/pgtable-generic.c (revision d8c37c480678ebe09bc570f33e085e28049db035)
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 
13e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
14e2cda322SAndrea Arcangeli /*
15e2cda322SAndrea Arcangeli  * Only sets the access flags (dirty, accessed, and
16e2cda322SAndrea Arcangeli  * writable). Furthermore, we know it always gets set to a "more
17e2cda322SAndrea Arcangeli  * permissive" setting, which allows most architectures to optimize
18e2cda322SAndrea Arcangeli  * this. We return whether the PTE actually changed, which in turn
19e2cda322SAndrea Arcangeli  * instructs the caller to do things like update__mmu_cache.  This
20e2cda322SAndrea Arcangeli  * used to be done in the caller, but sparc needs minor faults to
21e2cda322SAndrea Arcangeli  * force that call on sun4c so we changed this macro slightly
22e2cda322SAndrea Arcangeli  */
23e2cda322SAndrea Arcangeli int ptep_set_access_flags(struct vm_area_struct *vma,
24e2cda322SAndrea Arcangeli 			  unsigned long address, pte_t *ptep,
25e2cda322SAndrea Arcangeli 			  pte_t entry, int dirty)
26e2cda322SAndrea Arcangeli {
27e2cda322SAndrea Arcangeli 	int changed = !pte_same(*ptep, entry);
28e2cda322SAndrea Arcangeli 	if (changed) {
29e2cda322SAndrea Arcangeli 		set_pte_at(vma->vm_mm, address, ptep, entry);
30e2cda322SAndrea Arcangeli 		flush_tlb_page(vma, address);
31e2cda322SAndrea Arcangeli 	}
32e2cda322SAndrea Arcangeli 	return changed;
33e2cda322SAndrea Arcangeli }
34e2cda322SAndrea Arcangeli #endif
35e2cda322SAndrea Arcangeli 
36e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
37e2cda322SAndrea Arcangeli int pmdp_set_access_flags(struct vm_area_struct *vma,
38e2cda322SAndrea Arcangeli 			  unsigned long address, pmd_t *pmdp,
39e2cda322SAndrea Arcangeli 			  pmd_t entry, int dirty)
40e2cda322SAndrea Arcangeli {
41e2cda322SAndrea Arcangeli #ifdef CONFIG_TRANSPARENT_HUGEPAGE
42e2cda322SAndrea Arcangeli 	int changed = !pmd_same(*pmdp, entry);
43e2cda322SAndrea Arcangeli 	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
44e2cda322SAndrea Arcangeli 	if (changed) {
45e2cda322SAndrea Arcangeli 		set_pmd_at(vma->vm_mm, address, pmdp, entry);
46e2cda322SAndrea Arcangeli 		flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
47e2cda322SAndrea Arcangeli 	}
48e2cda322SAndrea Arcangeli 	return changed;
49e2cda322SAndrea Arcangeli #else /* CONFIG_TRANSPARENT_HUGEPAGE */
50e2cda322SAndrea Arcangeli 	BUG();
51e2cda322SAndrea Arcangeli 	return 0;
52e2cda322SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
53e2cda322SAndrea Arcangeli }
54e2cda322SAndrea Arcangeli #endif
55e2cda322SAndrea Arcangeli 
56e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
57e2cda322SAndrea Arcangeli int ptep_clear_flush_young(struct vm_area_struct *vma,
58e2cda322SAndrea Arcangeli 			   unsigned long address, pte_t *ptep)
59e2cda322SAndrea Arcangeli {
60e2cda322SAndrea Arcangeli 	int young;
61e2cda322SAndrea Arcangeli 	young = ptep_test_and_clear_young(vma, address, ptep);
62e2cda322SAndrea Arcangeli 	if (young)
63e2cda322SAndrea Arcangeli 		flush_tlb_page(vma, address);
64e2cda322SAndrea Arcangeli 	return young;
65e2cda322SAndrea Arcangeli }
66e2cda322SAndrea Arcangeli #endif
67e2cda322SAndrea Arcangeli 
68e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
69e2cda322SAndrea Arcangeli int pmdp_clear_flush_young(struct vm_area_struct *vma,
70e2cda322SAndrea Arcangeli 			   unsigned long address, pmd_t *pmdp)
71e2cda322SAndrea Arcangeli {
72e2cda322SAndrea Arcangeli 	int young;
73*d8c37c48SNaoya Horiguchi #ifdef CONFIG_TRANSPARENT_HUGEPAGE
74*d8c37c48SNaoya Horiguchi 	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
75*d8c37c48SNaoya Horiguchi #else
76e2cda322SAndrea Arcangeli 	BUG();
77e2cda322SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
78e2cda322SAndrea Arcangeli 	young = pmdp_test_and_clear_young(vma, address, pmdp);
79e2cda322SAndrea Arcangeli 	if (young)
80e2cda322SAndrea Arcangeli 		flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
81e2cda322SAndrea Arcangeli 	return young;
82e2cda322SAndrea Arcangeli }
83e2cda322SAndrea Arcangeli #endif
84e2cda322SAndrea Arcangeli 
85e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
86e2cda322SAndrea Arcangeli pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address,
87e2cda322SAndrea Arcangeli 		       pte_t *ptep)
88e2cda322SAndrea Arcangeli {
89e2cda322SAndrea Arcangeli 	pte_t pte;
90e2cda322SAndrea Arcangeli 	pte = ptep_get_and_clear((vma)->vm_mm, address, ptep);
91e2cda322SAndrea Arcangeli 	flush_tlb_page(vma, address);
92e2cda322SAndrea Arcangeli 	return pte;
93e2cda322SAndrea Arcangeli }
94e2cda322SAndrea Arcangeli #endif
95e2cda322SAndrea Arcangeli 
96e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_CLEAR_FLUSH
97b3697c02SAndrea Arcangeli #ifdef CONFIG_TRANSPARENT_HUGEPAGE
98e2cda322SAndrea Arcangeli pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address,
99e2cda322SAndrea Arcangeli 		       pmd_t *pmdp)
100e2cda322SAndrea Arcangeli {
101e2cda322SAndrea Arcangeli 	pmd_t pmd;
102e2cda322SAndrea Arcangeli 	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
103e2cda322SAndrea Arcangeli 	pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp);
104e2cda322SAndrea Arcangeli 	flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
105e2cda322SAndrea Arcangeli 	return pmd;
106e2cda322SAndrea Arcangeli }
107b3697c02SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
108e2cda322SAndrea Arcangeli #endif
109e2cda322SAndrea Arcangeli 
110e2cda322SAndrea Arcangeli #ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH
111b3697c02SAndrea Arcangeli #ifdef CONFIG_TRANSPARENT_HUGEPAGE
112e2cda322SAndrea Arcangeli pmd_t pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
113e2cda322SAndrea Arcangeli 			   pmd_t *pmdp)
114e2cda322SAndrea Arcangeli {
115e2cda322SAndrea Arcangeli 	pmd_t pmd = pmd_mksplitting(*pmdp);
116e2cda322SAndrea Arcangeli 	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
117e2cda322SAndrea Arcangeli 	set_pmd_at(vma->vm_mm, address, pmdp, pmd);
118e2cda322SAndrea Arcangeli 	/* tlb flush only to serialize against gup-fast */
119e2cda322SAndrea Arcangeli 	flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
120e2cda322SAndrea Arcangeli }
121b3697c02SAndrea Arcangeli #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
122e2cda322SAndrea Arcangeli #endif
123