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