aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2011-01-13 18:47:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 20:32:44 -0500
commitf2d6bfe9ff0acec30b713614260e78b03d20e909 (patch)
tree835dd9f4167513d94ae542cf92347ea98bff5ddc
parent5f24ce5fd34c3ca1b3d10d30da754732da64d5c0 (diff)
thp: add x86 32bit support
Add support for transparent hugepages to x86 32bit. Share the same VM_ bitflag for VM_MAPPED_COPY. mm/nommu.c will never support transparent hugepages. Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Reviewed-by: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/x86/include/asm/pgtable-2level.h9
-rw-r--r--arch/x86/include/asm/pgtable-3level.h23
-rw-r--r--arch/x86/include/asm/pgtable.h117
-rw-r--r--arch/x86/include/asm/pgtable_64.h109
-rw-r--r--arch/x86/mm/pgtable.c4
-rw-r--r--include/linux/mm.h7
-rw-r--r--mm/Kconfig2
7 files changed, 156 insertions, 115 deletions
diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h
index 2334982b339e..98391db840c6 100644
--- a/arch/x86/include/asm/pgtable-2level.h
+++ b/arch/x86/include/asm/pgtable-2level.h
@@ -46,6 +46,15 @@ static inline pte_t native_ptep_get_and_clear(pte_t *xp)
46#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp) 46#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp)
47#endif 47#endif
48 48
49#ifdef CONFIG_SMP
50static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp)
51{
52 return __pmd(xchg((pmdval_t *)xp, 0));
53}
54#else
55#define native_pmdp_get_and_clear(xp) native_local_pmdp_get_and_clear(xp)
56#endif
57
49/* 58/*
50 * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken, 59 * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken,
51 * split up the 29 bits of offset into this range: 60 * split up the 29 bits of offset into this range:
diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h
index 177b0165ea01..94b979d1b58d 100644
--- a/arch/x86/include/asm/pgtable-3level.h
+++ b/arch/x86/include/asm/pgtable-3level.h
@@ -104,6 +104,29 @@ static inline pte_t native_ptep_get_and_clear(pte_t *ptep)
104#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp) 104#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp)
105#endif 105#endif
106 106
107#ifdef CONFIG_SMP
108union split_pmd {
109 struct {
110 u32 pmd_low;
111 u32 pmd_high;
112 };
113 pmd_t pmd;
114};
115static inline pmd_t native_pmdp_get_and_clear(pmd_t *pmdp)
116{
117 union split_pmd res, *orig = (union split_pmd *)pmdp;
118
119 /* xchg acts as a barrier before setting of the high bits */
120 res.pmd_low = xchg(&orig->pmd_low, 0);
121 res.pmd_high = orig->pmd_high;
122 orig->pmd_high = 0;
123
124 return res.pmd;
125}
126#else
127#define native_pmdp_get_and_clear(xp) native_local_pmdp_get_and_clear(xp)
128#endif
129
107/* 130/*
108 * Bits 0, 6 and 7 are taken in the low part of the pte, 131 * Bits 0, 6 and 7 are taken in the low part of the pte,
109 * put the 32 bits of offset into the high part. 132 * put the 32 bits of offset into the high part.
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 3278038e9706..001a3831567a 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -97,6 +97,11 @@ static inline int pte_young(pte_t pte)
97 return pte_flags(pte) & _PAGE_ACCESSED; 97 return pte_flags(pte) & _PAGE_ACCESSED;
98} 98}
99 99
100static inline int pmd_young(pmd_t pmd)
101{
102 return pmd_flags(pmd) & _PAGE_ACCESSED;
103}
104
100static inline int pte_write(pte_t pte) 105static inline int pte_write(pte_t pte)
101{ 106{
102 return pte_flags(pte) & _PAGE_RW; 107 return pte_flags(pte) & _PAGE_RW;
@@ -145,6 +150,18 @@ static inline int pmd_large(pmd_t pte)
145 (_PAGE_PSE | _PAGE_PRESENT); 150 (_PAGE_PSE | _PAGE_PRESENT);
146} 151}
147 152
153#ifdef CONFIG_TRANSPARENT_HUGEPAGE
154static inline int pmd_trans_splitting(pmd_t pmd)
155{
156 return pmd_val(pmd) & _PAGE_SPLITTING;
157}
158
159static inline int pmd_trans_huge(pmd_t pmd)
160{
161 return pmd_val(pmd) & _PAGE_PSE;
162}
163#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
164
148static inline pte_t pte_set_flags(pte_t pte, pteval_t set) 165static inline pte_t pte_set_flags(pte_t pte, pteval_t set)
149{ 166{
150 pteval_t v = native_pte_val(pte); 167 pteval_t v = native_pte_val(pte);
@@ -219,6 +236,55 @@ static inline pte_t pte_mkspecial(pte_t pte)
219 return pte_set_flags(pte, _PAGE_SPECIAL); 236 return pte_set_flags(pte, _PAGE_SPECIAL);
220} 237}
221 238
239static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
240{
241 pmdval_t v = native_pmd_val(pmd);
242
243 return __pmd(v | set);
244}
245
246static inline pmd_t pmd_clear_flags(pmd_t pmd, pmdval_t clear)
247{
248 pmdval_t v = native_pmd_val(pmd);
249
250 return __pmd(v & ~clear);
251}
252
253static inline pmd_t pmd_mkold(pmd_t pmd)
254{
255 return pmd_clear_flags(pmd, _PAGE_ACCESSED);
256}
257
258static inline pmd_t pmd_wrprotect(pmd_t pmd)
259{
260 return pmd_clear_flags(pmd, _PAGE_RW);
261}
262
263static inline pmd_t pmd_mkdirty(pmd_t pmd)
264{
265 return pmd_set_flags(pmd, _PAGE_DIRTY);
266}
267
268static inline pmd_t pmd_mkhuge(pmd_t pmd)
269{
270 return pmd_set_flags(pmd, _PAGE_PSE);
271}
272
273static inline pmd_t pmd_mkyoung(pmd_t pmd)
274{
275 return pmd_set_flags(pmd, _PAGE_ACCESSED);
276}
277
278static inline pmd_t pmd_mkwrite(pmd_t pmd)
279{
280 return pmd_set_flags(pmd, _PAGE_RW);
281}
282
283static inline pmd_t pmd_mknotpresent(pmd_t pmd)
284{
285 return pmd_clear_flags(pmd, _PAGE_PRESENT);
286}
287
222/* 288/*
223 * Mask out unsupported bits in a present pgprot. Non-present pgprots 289 * Mask out unsupported bits in a present pgprot. Non-present pgprots
224 * can use those bits for other purposes, so leave them be. 290 * can use those bits for other purposes, so leave them be.
@@ -527,6 +593,14 @@ static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
527 return res; 593 return res;
528} 594}
529 595
596static inline pmd_t native_local_pmdp_get_and_clear(pmd_t *pmdp)
597{
598 pmd_t res = *pmdp;
599
600 native_pmd_clear(pmdp);
601 return res;
602}
603
530static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr, 604static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
531 pte_t *ptep , pte_t pte) 605 pte_t *ptep , pte_t pte)
532{ 606{
@@ -616,6 +690,49 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm,
616 690
617#define flush_tlb_fix_spurious_fault(vma, address) 691#define flush_tlb_fix_spurious_fault(vma, address)
618 692
693#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot))
694
695#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
696extern int pmdp_set_access_flags(struct vm_area_struct *vma,
697 unsigned long address, pmd_t *pmdp,
698 pmd_t entry, int dirty);
699
700#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
701extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
702 unsigned long addr, pmd_t *pmdp);
703
704#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
705extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
706 unsigned long address, pmd_t *pmdp);
707
708
709#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
710extern void pmdp_splitting_flush(struct vm_area_struct *vma,
711 unsigned long addr, pmd_t *pmdp);
712
713#define __HAVE_ARCH_PMD_WRITE
714static inline int pmd_write(pmd_t pmd)
715{
716 return pmd_flags(pmd) & _PAGE_RW;
717}
718
719#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
720static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, unsigned long addr,
721 pmd_t *pmdp)
722{
723 pmd_t pmd = native_pmdp_get_and_clear(pmdp);
724 pmd_update(mm, addr, pmdp);
725 return pmd;
726}
727
728#define __HAVE_ARCH_PMDP_SET_WRPROTECT
729static inline void pmdp_set_wrprotect(struct mm_struct *mm,
730 unsigned long addr, pmd_t *pmdp)
731{
732 clear_bit(_PAGE_BIT_RW, (unsigned long *)pmdp);
733 pmd_update(mm, addr, pmdp);
734}
735
619/* 736/*
620 * clone_pgd_range(pgd_t *dst, pgd_t *src, int count); 737 * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
621 * 738 *
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index b2df039a4119..975f709e09ae 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -182,115 +182,6 @@ extern void cleanup_highmap(void);
182 182
183#define __HAVE_ARCH_PTE_SAME 183#define __HAVE_ARCH_PTE_SAME
184 184
185#ifdef CONFIG_TRANSPARENT_HUGEPAGE
186static inline int pmd_trans_splitting(pmd_t pmd)
187{
188 return pmd_val(pmd) & _PAGE_SPLITTING;
189}
190
191static inline int pmd_trans_huge(pmd_t pmd)
192{
193 return pmd_val(pmd) & _PAGE_PSE;
194}
195#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
196
197#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot))
198
199#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
200extern int pmdp_set_access_flags(struct vm_area_struct *vma,
201 unsigned long address, pmd_t *pmdp,
202 pmd_t entry, int dirty);
203
204#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
205extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
206 unsigned long addr, pmd_t *pmdp);
207
208#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
209extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
210 unsigned long address, pmd_t *pmdp);
211
212
213#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
214extern void pmdp_splitting_flush(struct vm_area_struct *vma,
215 unsigned long addr, pmd_t *pmdp);
216
217#define __HAVE_ARCH_PMD_WRITE
218static inline int pmd_write(pmd_t pmd)
219{
220 return pmd_flags(pmd) & _PAGE_RW;
221}
222
223#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
224static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, unsigned long addr,
225 pmd_t *pmdp)
226{
227 pmd_t pmd = native_pmdp_get_and_clear(pmdp);
228 pmd_update(mm, addr, pmdp);
229 return pmd;
230}
231
232#define __HAVE_ARCH_PMDP_SET_WRPROTECT
233static inline void pmdp_set_wrprotect(struct mm_struct *mm,
234 unsigned long addr, pmd_t *pmdp)
235{
236 clear_bit(_PAGE_BIT_RW, (unsigned long *)&pmdp->pmd);
237 pmd_update(mm, addr, pmdp);
238}
239
240static inline int pmd_young(pmd_t pmd)
241{
242 return pmd_flags(pmd) & _PAGE_ACCESSED;
243}
244
245static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
246{
247 pmdval_t v = native_pmd_val(pmd);
248
249 return native_make_pmd(v | set);
250}
251
252static inline pmd_t pmd_clear_flags(pmd_t pmd, pmdval_t clear)
253{
254 pmdval_t v = native_pmd_val(pmd);
255
256 return native_make_pmd(v & ~clear);
257}
258
259static inline pmd_t pmd_mkold(pmd_t pmd)
260{
261 return pmd_clear_flags(pmd, _PAGE_ACCESSED);
262}
263
264static inline pmd_t pmd_wrprotect(pmd_t pmd)
265{
266 return pmd_clear_flags(pmd, _PAGE_RW);
267}
268
269static inline pmd_t pmd_mkdirty(pmd_t pmd)
270{
271 return pmd_set_flags(pmd, _PAGE_DIRTY);
272}
273
274static inline pmd_t pmd_mkhuge(pmd_t pmd)
275{
276 return pmd_set_flags(pmd, _PAGE_PSE);
277}
278
279static inline pmd_t pmd_mkyoung(pmd_t pmd)
280{
281 return pmd_set_flags(pmd, _PAGE_ACCESSED);
282}
283
284static inline pmd_t pmd_mkwrite(pmd_t pmd)
285{
286 return pmd_set_flags(pmd, _PAGE_RW);
287}
288
289static inline pmd_t pmd_mknotpresent(pmd_t pmd)
290{
291 return pmd_clear_flags(pmd, _PAGE_PRESENT);
292}
293
294#endif /* !__ASSEMBLY__ */ 185#endif /* !__ASSEMBLY__ */
295 186
296#endif /* _ASM_X86_PGTABLE_64_H */ 187#endif /* _ASM_X86_PGTABLE_64_H */
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 65e92d58f942..500242d3c96d 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -362,7 +362,7 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma,
362 362
363 if (pmd_young(*pmdp)) 363 if (pmd_young(*pmdp))
364 ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, 364 ret = test_and_clear_bit(_PAGE_BIT_ACCESSED,
365 (unsigned long *) &pmdp->pmd); 365 (unsigned long *)pmdp);
366 366
367 if (ret) 367 if (ret)
368 pmd_update(vma->vm_mm, addr, pmdp); 368 pmd_update(vma->vm_mm, addr, pmdp);
@@ -404,7 +404,7 @@ void pmdp_splitting_flush(struct vm_area_struct *vma,
404 int set; 404 int set;
405 VM_BUG_ON(address & ~HPAGE_PMD_MASK); 405 VM_BUG_ON(address & ~HPAGE_PMD_MASK);
406 set = !test_and_set_bit(_PAGE_BIT_SPLITTING, 406 set = !test_and_set_bit(_PAGE_BIT_SPLITTING,
407 (unsigned long *)&pmdp->pmd); 407 (unsigned long *)pmdp);
408 if (set) { 408 if (set) {
409 pmd_update(vma->vm_mm, address, pmdp); 409 pmd_update(vma->vm_mm, address, pmdp);
410 /* need tlb flush only to serialize against gup-fast */ 410 /* need tlb flush only to serialize against gup-fast */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7ab7d2b60041..9c2695beab86 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -102,7 +102,11 @@ extern unsigned int kobjsize(const void *objp);
102#define VM_NORESERVE 0x00200000 /* should the VM suppress accounting */ 102#define VM_NORESERVE 0x00200000 /* should the VM suppress accounting */
103#define VM_HUGETLB 0x00400000 /* Huge TLB Page VM */ 103#define VM_HUGETLB 0x00400000 /* Huge TLB Page VM */
104#define VM_NONLINEAR 0x00800000 /* Is non-linear (remap_file_pages) */ 104#define VM_NONLINEAR 0x00800000 /* Is non-linear (remap_file_pages) */
105#ifndef CONFIG_TRANSPARENT_HUGEPAGE
105#define VM_MAPPED_COPY 0x01000000 /* T if mapped copy of data (nommu mmap) */ 106#define VM_MAPPED_COPY 0x01000000 /* T if mapped copy of data (nommu mmap) */
107#else
108#define VM_HUGEPAGE 0x01000000 /* MADV_HUGEPAGE marked this vma */
109#endif
106#define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it */ 110#define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it */
107#define VM_ALWAYSDUMP 0x04000000 /* Always include in core dumps */ 111#define VM_ALWAYSDUMP 0x04000000 /* Always include in core dumps */
108 112
@@ -111,9 +115,6 @@ extern unsigned int kobjsize(const void *objp);
111#define VM_SAO 0x20000000 /* Strong Access Ordering (powerpc) */ 115#define VM_SAO 0x20000000 /* Strong Access Ordering (powerpc) */
112#define VM_PFN_AT_MMAP 0x40000000 /* PFNMAP vma that is fully mapped at mmap time */ 116#define VM_PFN_AT_MMAP 0x40000000 /* PFNMAP vma that is fully mapped at mmap time */
113#define VM_MERGEABLE 0x80000000 /* KSM may merge identical pages */ 117#define VM_MERGEABLE 0x80000000 /* KSM may merge identical pages */
114#if BITS_PER_LONG > 32
115#define VM_HUGEPAGE 0x100000000UL /* MADV_HUGEPAGE marked this vma */
116#endif
117 118
118/* Bits set in the VMA until the stack is in its final location */ 119/* Bits set in the VMA until the stack is in its final location */
119#define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ) 120#define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ)
diff --git a/mm/Kconfig b/mm/Kconfig
index 3982be2d721a..d774f77538ce 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -304,7 +304,7 @@ config NOMMU_INITIAL_TRIM_EXCESS
304 304
305config TRANSPARENT_HUGEPAGE 305config TRANSPARENT_HUGEPAGE
306 bool "Transparent Hugepage Support" if EMBEDDED 306 bool "Transparent Hugepage Support" if EMBEDDED
307 depends on X86_64 && MMU 307 depends on X86 && MMU
308 default y 308 default y
309 help 309 help
310 Transparent Hugepages allows the kernel to use huge pages and 310 Transparent Hugepages allows the kernel to use huge pages and