xref: /OK3568_Linux_fs/kernel/arch/sparc/mm/hugetlbpage.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SPARC64 Huge TLB page support.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net)
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/fs.h>
9*4882a593Smuzhiyun #include <linux/mm.h>
10*4882a593Smuzhiyun #include <linux/sched/mm.h>
11*4882a593Smuzhiyun #include <linux/hugetlb.h>
12*4882a593Smuzhiyun #include <linux/pagemap.h>
13*4882a593Smuzhiyun #include <linux/sysctl.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <asm/mman.h>
16*4882a593Smuzhiyun #include <asm/pgalloc.h>
17*4882a593Smuzhiyun #include <asm/tlb.h>
18*4882a593Smuzhiyun #include <asm/tlbflush.h>
19*4882a593Smuzhiyun #include <asm/cacheflush.h>
20*4882a593Smuzhiyun #include <asm/mmu_context.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /* Slightly simplified from the non-hugepage variant because by
23*4882a593Smuzhiyun  * definition we don't have to worry about any page coloring stuff
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
hugetlb_get_unmapped_area_bottomup(struct file * filp,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)26*4882a593Smuzhiyun static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp,
27*4882a593Smuzhiyun 							unsigned long addr,
28*4882a593Smuzhiyun 							unsigned long len,
29*4882a593Smuzhiyun 							unsigned long pgoff,
30*4882a593Smuzhiyun 							unsigned long flags)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	struct hstate *h = hstate_file(filp);
33*4882a593Smuzhiyun 	unsigned long task_size = TASK_SIZE;
34*4882a593Smuzhiyun 	struct vm_unmapped_area_info info;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	if (test_thread_flag(TIF_32BIT))
37*4882a593Smuzhiyun 		task_size = STACK_TOP32;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	info.flags = 0;
40*4882a593Smuzhiyun 	info.length = len;
41*4882a593Smuzhiyun 	info.low_limit = TASK_UNMAPPED_BASE;
42*4882a593Smuzhiyun 	info.high_limit = min(task_size, VA_EXCLUDE_START);
43*4882a593Smuzhiyun 	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
44*4882a593Smuzhiyun 	info.align_offset = 0;
45*4882a593Smuzhiyun 	addr = vm_unmapped_area(&info);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) {
48*4882a593Smuzhiyun 		VM_BUG_ON(addr != -ENOMEM);
49*4882a593Smuzhiyun 		info.low_limit = VA_EXCLUDE_END;
50*4882a593Smuzhiyun 		info.high_limit = task_size;
51*4882a593Smuzhiyun 		addr = vm_unmapped_area(&info);
52*4882a593Smuzhiyun 	}
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	return addr;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun static unsigned long
hugetlb_get_unmapped_area_topdown(struct file * filp,const unsigned long addr0,const unsigned long len,const unsigned long pgoff,const unsigned long flags)58*4882a593Smuzhiyun hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
59*4882a593Smuzhiyun 				  const unsigned long len,
60*4882a593Smuzhiyun 				  const unsigned long pgoff,
61*4882a593Smuzhiyun 				  const unsigned long flags)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	struct hstate *h = hstate_file(filp);
64*4882a593Smuzhiyun 	struct mm_struct *mm = current->mm;
65*4882a593Smuzhiyun 	unsigned long addr = addr0;
66*4882a593Smuzhiyun 	struct vm_unmapped_area_info info;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	/* This should only ever run for 32-bit processes.  */
69*4882a593Smuzhiyun 	BUG_ON(!test_thread_flag(TIF_32BIT));
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
72*4882a593Smuzhiyun 	info.length = len;
73*4882a593Smuzhiyun 	info.low_limit = PAGE_SIZE;
74*4882a593Smuzhiyun 	info.high_limit = mm->mmap_base;
75*4882a593Smuzhiyun 	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
76*4882a593Smuzhiyun 	info.align_offset = 0;
77*4882a593Smuzhiyun 	addr = vm_unmapped_area(&info);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	/*
80*4882a593Smuzhiyun 	 * A failed mmap() very likely causes application failure,
81*4882a593Smuzhiyun 	 * so fall back to the bottom-up function here. This scenario
82*4882a593Smuzhiyun 	 * can happen with large stack limits and large mmap()
83*4882a593Smuzhiyun 	 * allocations.
84*4882a593Smuzhiyun 	 */
85*4882a593Smuzhiyun 	if (addr & ~PAGE_MASK) {
86*4882a593Smuzhiyun 		VM_BUG_ON(addr != -ENOMEM);
87*4882a593Smuzhiyun 		info.flags = 0;
88*4882a593Smuzhiyun 		info.low_limit = TASK_UNMAPPED_BASE;
89*4882a593Smuzhiyun 		info.high_limit = STACK_TOP32;
90*4882a593Smuzhiyun 		addr = vm_unmapped_area(&info);
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	return addr;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun unsigned long
hugetlb_get_unmapped_area(struct file * file,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)97*4882a593Smuzhiyun hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
98*4882a593Smuzhiyun 		unsigned long len, unsigned long pgoff, unsigned long flags)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	struct hstate *h = hstate_file(file);
101*4882a593Smuzhiyun 	struct mm_struct *mm = current->mm;
102*4882a593Smuzhiyun 	struct vm_area_struct *vma;
103*4882a593Smuzhiyun 	unsigned long task_size = TASK_SIZE;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (test_thread_flag(TIF_32BIT))
106*4882a593Smuzhiyun 		task_size = STACK_TOP32;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	if (len & ~huge_page_mask(h))
109*4882a593Smuzhiyun 		return -EINVAL;
110*4882a593Smuzhiyun 	if (len > task_size)
111*4882a593Smuzhiyun 		return -ENOMEM;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	if (flags & MAP_FIXED) {
114*4882a593Smuzhiyun 		if (prepare_hugepage_range(file, addr, len))
115*4882a593Smuzhiyun 			return -EINVAL;
116*4882a593Smuzhiyun 		return addr;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if (addr) {
120*4882a593Smuzhiyun 		addr = ALIGN(addr, huge_page_size(h));
121*4882a593Smuzhiyun 		vma = find_vma(mm, addr);
122*4882a593Smuzhiyun 		if (task_size - len >= addr &&
123*4882a593Smuzhiyun 		    (!vma || addr + len <= vm_start_gap(vma)))
124*4882a593Smuzhiyun 			return addr;
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun 	if (mm->get_unmapped_area == arch_get_unmapped_area)
127*4882a593Smuzhiyun 		return hugetlb_get_unmapped_area_bottomup(file, addr, len,
128*4882a593Smuzhiyun 				pgoff, flags);
129*4882a593Smuzhiyun 	else
130*4882a593Smuzhiyun 		return hugetlb_get_unmapped_area_topdown(file, addr, len,
131*4882a593Smuzhiyun 				pgoff, flags);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
sun4u_hugepage_shift_to_tte(pte_t entry,unsigned int shift)134*4882a593Smuzhiyun static pte_t sun4u_hugepage_shift_to_tte(pte_t entry, unsigned int shift)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	return entry;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
sun4v_hugepage_shift_to_tte(pte_t entry,unsigned int shift)139*4882a593Smuzhiyun static pte_t sun4v_hugepage_shift_to_tte(pte_t entry, unsigned int shift)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	unsigned long hugepage_size = _PAGE_SZ4MB_4V;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	pte_val(entry) = pte_val(entry) & ~_PAGE_SZALL_4V;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	switch (shift) {
146*4882a593Smuzhiyun 	case HPAGE_16GB_SHIFT:
147*4882a593Smuzhiyun 		hugepage_size = _PAGE_SZ16GB_4V;
148*4882a593Smuzhiyun 		pte_val(entry) |= _PAGE_PUD_HUGE;
149*4882a593Smuzhiyun 		break;
150*4882a593Smuzhiyun 	case HPAGE_2GB_SHIFT:
151*4882a593Smuzhiyun 		hugepage_size = _PAGE_SZ2GB_4V;
152*4882a593Smuzhiyun 		pte_val(entry) |= _PAGE_PMD_HUGE;
153*4882a593Smuzhiyun 		break;
154*4882a593Smuzhiyun 	case HPAGE_256MB_SHIFT:
155*4882a593Smuzhiyun 		hugepage_size = _PAGE_SZ256MB_4V;
156*4882a593Smuzhiyun 		pte_val(entry) |= _PAGE_PMD_HUGE;
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 	case HPAGE_SHIFT:
159*4882a593Smuzhiyun 		pte_val(entry) |= _PAGE_PMD_HUGE;
160*4882a593Smuzhiyun 		break;
161*4882a593Smuzhiyun 	case HPAGE_64K_SHIFT:
162*4882a593Smuzhiyun 		hugepage_size = _PAGE_SZ64K_4V;
163*4882a593Smuzhiyun 		break;
164*4882a593Smuzhiyun 	default:
165*4882a593Smuzhiyun 		WARN_ONCE(1, "unsupported hugepage shift=%u\n", shift);
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	pte_val(entry) = pte_val(entry) | hugepage_size;
169*4882a593Smuzhiyun 	return entry;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
hugepage_shift_to_tte(pte_t entry,unsigned int shift)172*4882a593Smuzhiyun static pte_t hugepage_shift_to_tte(pte_t entry, unsigned int shift)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	if (tlb_type == hypervisor)
175*4882a593Smuzhiyun 		return sun4v_hugepage_shift_to_tte(entry, shift);
176*4882a593Smuzhiyun 	else
177*4882a593Smuzhiyun 		return sun4u_hugepage_shift_to_tte(entry, shift);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
arch_make_huge_pte(pte_t entry,struct vm_area_struct * vma,struct page * page,int writeable)180*4882a593Smuzhiyun pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
181*4882a593Smuzhiyun 			 struct page *page, int writeable)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	unsigned int shift = huge_page_shift(hstate_vma(vma));
184*4882a593Smuzhiyun 	pte_t pte;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	pte = hugepage_shift_to_tte(entry, shift);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun #ifdef CONFIG_SPARC64
189*4882a593Smuzhiyun 	/* If this vma has ADI enabled on it, turn on TTE.mcd
190*4882a593Smuzhiyun 	 */
191*4882a593Smuzhiyun 	if (vma->vm_flags & VM_SPARC_ADI)
192*4882a593Smuzhiyun 		return pte_mkmcd(pte);
193*4882a593Smuzhiyun 	else
194*4882a593Smuzhiyun 		return pte_mknotmcd(pte);
195*4882a593Smuzhiyun #else
196*4882a593Smuzhiyun 	return pte;
197*4882a593Smuzhiyun #endif
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
sun4v_huge_tte_to_shift(pte_t entry)200*4882a593Smuzhiyun static unsigned int sun4v_huge_tte_to_shift(pte_t entry)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	unsigned long tte_szbits = pte_val(entry) & _PAGE_SZALL_4V;
203*4882a593Smuzhiyun 	unsigned int shift;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	switch (tte_szbits) {
206*4882a593Smuzhiyun 	case _PAGE_SZ16GB_4V:
207*4882a593Smuzhiyun 		shift = HPAGE_16GB_SHIFT;
208*4882a593Smuzhiyun 		break;
209*4882a593Smuzhiyun 	case _PAGE_SZ2GB_4V:
210*4882a593Smuzhiyun 		shift = HPAGE_2GB_SHIFT;
211*4882a593Smuzhiyun 		break;
212*4882a593Smuzhiyun 	case _PAGE_SZ256MB_4V:
213*4882a593Smuzhiyun 		shift = HPAGE_256MB_SHIFT;
214*4882a593Smuzhiyun 		break;
215*4882a593Smuzhiyun 	case _PAGE_SZ4MB_4V:
216*4882a593Smuzhiyun 		shift = REAL_HPAGE_SHIFT;
217*4882a593Smuzhiyun 		break;
218*4882a593Smuzhiyun 	case _PAGE_SZ64K_4V:
219*4882a593Smuzhiyun 		shift = HPAGE_64K_SHIFT;
220*4882a593Smuzhiyun 		break;
221*4882a593Smuzhiyun 	default:
222*4882a593Smuzhiyun 		shift = PAGE_SHIFT;
223*4882a593Smuzhiyun 		break;
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 	return shift;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
sun4u_huge_tte_to_shift(pte_t entry)228*4882a593Smuzhiyun static unsigned int sun4u_huge_tte_to_shift(pte_t entry)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	unsigned long tte_szbits = pte_val(entry) & _PAGE_SZALL_4U;
231*4882a593Smuzhiyun 	unsigned int shift;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	switch (tte_szbits) {
234*4882a593Smuzhiyun 	case _PAGE_SZ256MB_4U:
235*4882a593Smuzhiyun 		shift = HPAGE_256MB_SHIFT;
236*4882a593Smuzhiyun 		break;
237*4882a593Smuzhiyun 	case _PAGE_SZ4MB_4U:
238*4882a593Smuzhiyun 		shift = REAL_HPAGE_SHIFT;
239*4882a593Smuzhiyun 		break;
240*4882a593Smuzhiyun 	case _PAGE_SZ64K_4U:
241*4882a593Smuzhiyun 		shift = HPAGE_64K_SHIFT;
242*4882a593Smuzhiyun 		break;
243*4882a593Smuzhiyun 	default:
244*4882a593Smuzhiyun 		shift = PAGE_SHIFT;
245*4882a593Smuzhiyun 		break;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	return shift;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
huge_tte_to_shift(pte_t entry)250*4882a593Smuzhiyun static unsigned int huge_tte_to_shift(pte_t entry)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	unsigned long shift;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	if (tlb_type == hypervisor)
255*4882a593Smuzhiyun 		shift = sun4v_huge_tte_to_shift(entry);
256*4882a593Smuzhiyun 	else
257*4882a593Smuzhiyun 		shift = sun4u_huge_tte_to_shift(entry);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (shift == PAGE_SHIFT)
260*4882a593Smuzhiyun 		WARN_ONCE(1, "tto_to_shift: invalid hugepage tte=0x%lx\n",
261*4882a593Smuzhiyun 			  pte_val(entry));
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return shift;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
huge_tte_to_size(pte_t pte)266*4882a593Smuzhiyun static unsigned long huge_tte_to_size(pte_t pte)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	unsigned long size = 1UL << huge_tte_to_shift(pte);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	if (size == REAL_HPAGE_SIZE)
271*4882a593Smuzhiyun 		size = HPAGE_SIZE;
272*4882a593Smuzhiyun 	return size;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
huge_pte_alloc(struct mm_struct * mm,struct vm_area_struct * vma,unsigned long addr,unsigned long sz)275*4882a593Smuzhiyun pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
276*4882a593Smuzhiyun 			unsigned long addr, unsigned long sz)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	pgd_t *pgd;
279*4882a593Smuzhiyun 	p4d_t *p4d;
280*4882a593Smuzhiyun 	pud_t *pud;
281*4882a593Smuzhiyun 	pmd_t *pmd;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	pgd = pgd_offset(mm, addr);
284*4882a593Smuzhiyun 	p4d = p4d_offset(pgd, addr);
285*4882a593Smuzhiyun 	pud = pud_alloc(mm, p4d, addr);
286*4882a593Smuzhiyun 	if (!pud)
287*4882a593Smuzhiyun 		return NULL;
288*4882a593Smuzhiyun 	if (sz >= PUD_SIZE)
289*4882a593Smuzhiyun 		return (pte_t *)pud;
290*4882a593Smuzhiyun 	pmd = pmd_alloc(mm, pud, addr);
291*4882a593Smuzhiyun 	if (!pmd)
292*4882a593Smuzhiyun 		return NULL;
293*4882a593Smuzhiyun 	if (sz >= PMD_SIZE)
294*4882a593Smuzhiyun 		return (pte_t *)pmd;
295*4882a593Smuzhiyun 	return pte_alloc_map(mm, pmd, addr);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
huge_pte_offset(struct mm_struct * mm,unsigned long addr,unsigned long sz)298*4882a593Smuzhiyun pte_t *huge_pte_offset(struct mm_struct *mm,
299*4882a593Smuzhiyun 		       unsigned long addr, unsigned long sz)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	pgd_t *pgd;
302*4882a593Smuzhiyun 	p4d_t *p4d;
303*4882a593Smuzhiyun 	pud_t *pud;
304*4882a593Smuzhiyun 	pmd_t *pmd;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	pgd = pgd_offset(mm, addr);
307*4882a593Smuzhiyun 	if (pgd_none(*pgd))
308*4882a593Smuzhiyun 		return NULL;
309*4882a593Smuzhiyun 	p4d = p4d_offset(pgd, addr);
310*4882a593Smuzhiyun 	if (p4d_none(*p4d))
311*4882a593Smuzhiyun 		return NULL;
312*4882a593Smuzhiyun 	pud = pud_offset(p4d, addr);
313*4882a593Smuzhiyun 	if (pud_none(*pud))
314*4882a593Smuzhiyun 		return NULL;
315*4882a593Smuzhiyun 	if (is_hugetlb_pud(*pud))
316*4882a593Smuzhiyun 		return (pte_t *)pud;
317*4882a593Smuzhiyun 	pmd = pmd_offset(pud, addr);
318*4882a593Smuzhiyun 	if (pmd_none(*pmd))
319*4882a593Smuzhiyun 		return NULL;
320*4882a593Smuzhiyun 	if (is_hugetlb_pmd(*pmd))
321*4882a593Smuzhiyun 		return (pte_t *)pmd;
322*4882a593Smuzhiyun 	return pte_offset_map(pmd, addr);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
set_huge_pte_at(struct mm_struct * mm,unsigned long addr,pte_t * ptep,pte_t entry)325*4882a593Smuzhiyun void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
326*4882a593Smuzhiyun 		     pte_t *ptep, pte_t entry)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	unsigned int nptes, orig_shift, shift;
329*4882a593Smuzhiyun 	unsigned long i, size;
330*4882a593Smuzhiyun 	pte_t orig;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	size = huge_tte_to_size(entry);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	shift = PAGE_SHIFT;
335*4882a593Smuzhiyun 	if (size >= PUD_SIZE)
336*4882a593Smuzhiyun 		shift = PUD_SHIFT;
337*4882a593Smuzhiyun 	else if (size >= PMD_SIZE)
338*4882a593Smuzhiyun 		shift = PMD_SHIFT;
339*4882a593Smuzhiyun 	else
340*4882a593Smuzhiyun 		shift = PAGE_SHIFT;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	nptes = size >> shift;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	if (!pte_present(*ptep) && pte_present(entry))
345*4882a593Smuzhiyun 		mm->context.hugetlb_pte_count += nptes;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	addr &= ~(size - 1);
348*4882a593Smuzhiyun 	orig = *ptep;
349*4882a593Smuzhiyun 	orig_shift = pte_none(orig) ? PAGE_SHIFT : huge_tte_to_shift(orig);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	for (i = 0; i < nptes; i++)
352*4882a593Smuzhiyun 		ptep[i] = __pte(pte_val(entry) + (i << shift));
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	maybe_tlb_batch_add(mm, addr, ptep, orig, 0, orig_shift);
355*4882a593Smuzhiyun 	/* An HPAGE_SIZE'ed page is composed of two REAL_HPAGE_SIZE'ed pages */
356*4882a593Smuzhiyun 	if (size == HPAGE_SIZE)
357*4882a593Smuzhiyun 		maybe_tlb_batch_add(mm, addr + REAL_HPAGE_SIZE, ptep, orig, 0,
358*4882a593Smuzhiyun 				    orig_shift);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
huge_ptep_get_and_clear(struct mm_struct * mm,unsigned long addr,pte_t * ptep)361*4882a593Smuzhiyun pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
362*4882a593Smuzhiyun 			      pte_t *ptep)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	unsigned int i, nptes, orig_shift, shift;
365*4882a593Smuzhiyun 	unsigned long size;
366*4882a593Smuzhiyun 	pte_t entry;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	entry = *ptep;
369*4882a593Smuzhiyun 	size = huge_tte_to_size(entry);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	shift = PAGE_SHIFT;
372*4882a593Smuzhiyun 	if (size >= PUD_SIZE)
373*4882a593Smuzhiyun 		shift = PUD_SHIFT;
374*4882a593Smuzhiyun 	else if (size >= PMD_SIZE)
375*4882a593Smuzhiyun 		shift = PMD_SHIFT;
376*4882a593Smuzhiyun 	else
377*4882a593Smuzhiyun 		shift = PAGE_SHIFT;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	nptes = size >> shift;
380*4882a593Smuzhiyun 	orig_shift = pte_none(entry) ? PAGE_SHIFT : huge_tte_to_shift(entry);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (pte_present(entry))
383*4882a593Smuzhiyun 		mm->context.hugetlb_pte_count -= nptes;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	addr &= ~(size - 1);
386*4882a593Smuzhiyun 	for (i = 0; i < nptes; i++)
387*4882a593Smuzhiyun 		ptep[i] = __pte(0UL);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	maybe_tlb_batch_add(mm, addr, ptep, entry, 0, orig_shift);
390*4882a593Smuzhiyun 	/* An HPAGE_SIZE'ed page is composed of two REAL_HPAGE_SIZE'ed pages */
391*4882a593Smuzhiyun 	if (size == HPAGE_SIZE)
392*4882a593Smuzhiyun 		maybe_tlb_batch_add(mm, addr + REAL_HPAGE_SIZE, ptep, entry, 0,
393*4882a593Smuzhiyun 				    orig_shift);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	return entry;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
pmd_huge(pmd_t pmd)398*4882a593Smuzhiyun int pmd_huge(pmd_t pmd)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	return !pmd_none(pmd) &&
401*4882a593Smuzhiyun 		(pmd_val(pmd) & (_PAGE_VALID|_PAGE_PMD_HUGE)) != _PAGE_VALID;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
pud_huge(pud_t pud)404*4882a593Smuzhiyun int pud_huge(pud_t pud)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	return !pud_none(pud) &&
407*4882a593Smuzhiyun 		(pud_val(pud) & (_PAGE_VALID|_PAGE_PUD_HUGE)) != _PAGE_VALID;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
hugetlb_free_pte_range(struct mmu_gather * tlb,pmd_t * pmd,unsigned long addr)410*4882a593Smuzhiyun static void hugetlb_free_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
411*4882a593Smuzhiyun 			   unsigned long addr)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun 	pgtable_t token = pmd_pgtable(*pmd);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	pmd_clear(pmd);
416*4882a593Smuzhiyun 	pte_free_tlb(tlb, token, addr);
417*4882a593Smuzhiyun 	mm_dec_nr_ptes(tlb->mm);
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
hugetlb_free_pmd_range(struct mmu_gather * tlb,pud_t * pud,unsigned long addr,unsigned long end,unsigned long floor,unsigned long ceiling)420*4882a593Smuzhiyun static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
421*4882a593Smuzhiyun 				   unsigned long addr, unsigned long end,
422*4882a593Smuzhiyun 				   unsigned long floor, unsigned long ceiling)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	pmd_t *pmd;
425*4882a593Smuzhiyun 	unsigned long next;
426*4882a593Smuzhiyun 	unsigned long start;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	start = addr;
429*4882a593Smuzhiyun 	pmd = pmd_offset(pud, addr);
430*4882a593Smuzhiyun 	do {
431*4882a593Smuzhiyun 		next = pmd_addr_end(addr, end);
432*4882a593Smuzhiyun 		if (pmd_none(*pmd))
433*4882a593Smuzhiyun 			continue;
434*4882a593Smuzhiyun 		if (is_hugetlb_pmd(*pmd))
435*4882a593Smuzhiyun 			pmd_clear(pmd);
436*4882a593Smuzhiyun 		else
437*4882a593Smuzhiyun 			hugetlb_free_pte_range(tlb, pmd, addr);
438*4882a593Smuzhiyun 	} while (pmd++, addr = next, addr != end);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	start &= PUD_MASK;
441*4882a593Smuzhiyun 	if (start < floor)
442*4882a593Smuzhiyun 		return;
443*4882a593Smuzhiyun 	if (ceiling) {
444*4882a593Smuzhiyun 		ceiling &= PUD_MASK;
445*4882a593Smuzhiyun 		if (!ceiling)
446*4882a593Smuzhiyun 			return;
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 	if (end - 1 > ceiling - 1)
449*4882a593Smuzhiyun 		return;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	pmd = pmd_offset(pud, start);
452*4882a593Smuzhiyun 	pud_clear(pud);
453*4882a593Smuzhiyun 	pmd_free_tlb(tlb, pmd, start);
454*4882a593Smuzhiyun 	mm_dec_nr_pmds(tlb->mm);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun 
hugetlb_free_pud_range(struct mmu_gather * tlb,p4d_t * p4d,unsigned long addr,unsigned long end,unsigned long floor,unsigned long ceiling)457*4882a593Smuzhiyun static void hugetlb_free_pud_range(struct mmu_gather *tlb, p4d_t *p4d,
458*4882a593Smuzhiyun 				   unsigned long addr, unsigned long end,
459*4882a593Smuzhiyun 				   unsigned long floor, unsigned long ceiling)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	pud_t *pud;
462*4882a593Smuzhiyun 	unsigned long next;
463*4882a593Smuzhiyun 	unsigned long start;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	start = addr;
466*4882a593Smuzhiyun 	pud = pud_offset(p4d, addr);
467*4882a593Smuzhiyun 	do {
468*4882a593Smuzhiyun 		next = pud_addr_end(addr, end);
469*4882a593Smuzhiyun 		if (pud_none_or_clear_bad(pud))
470*4882a593Smuzhiyun 			continue;
471*4882a593Smuzhiyun 		if (is_hugetlb_pud(*pud))
472*4882a593Smuzhiyun 			pud_clear(pud);
473*4882a593Smuzhiyun 		else
474*4882a593Smuzhiyun 			hugetlb_free_pmd_range(tlb, pud, addr, next, floor,
475*4882a593Smuzhiyun 					       ceiling);
476*4882a593Smuzhiyun 	} while (pud++, addr = next, addr != end);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	start &= PGDIR_MASK;
479*4882a593Smuzhiyun 	if (start < floor)
480*4882a593Smuzhiyun 		return;
481*4882a593Smuzhiyun 	if (ceiling) {
482*4882a593Smuzhiyun 		ceiling &= PGDIR_MASK;
483*4882a593Smuzhiyun 		if (!ceiling)
484*4882a593Smuzhiyun 			return;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 	if (end - 1 > ceiling - 1)
487*4882a593Smuzhiyun 		return;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	pud = pud_offset(p4d, start);
490*4882a593Smuzhiyun 	p4d_clear(p4d);
491*4882a593Smuzhiyun 	pud_free_tlb(tlb, pud, start);
492*4882a593Smuzhiyun 	mm_dec_nr_puds(tlb->mm);
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
hugetlb_free_pgd_range(struct mmu_gather * tlb,unsigned long addr,unsigned long end,unsigned long floor,unsigned long ceiling)495*4882a593Smuzhiyun void hugetlb_free_pgd_range(struct mmu_gather *tlb,
496*4882a593Smuzhiyun 			    unsigned long addr, unsigned long end,
497*4882a593Smuzhiyun 			    unsigned long floor, unsigned long ceiling)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun 	pgd_t *pgd;
500*4882a593Smuzhiyun 	p4d_t *p4d;
501*4882a593Smuzhiyun 	unsigned long next;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	addr &= PMD_MASK;
504*4882a593Smuzhiyun 	if (addr < floor) {
505*4882a593Smuzhiyun 		addr += PMD_SIZE;
506*4882a593Smuzhiyun 		if (!addr)
507*4882a593Smuzhiyun 			return;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 	if (ceiling) {
510*4882a593Smuzhiyun 		ceiling &= PMD_MASK;
511*4882a593Smuzhiyun 		if (!ceiling)
512*4882a593Smuzhiyun 			return;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 	if (end - 1 > ceiling - 1)
515*4882a593Smuzhiyun 		end -= PMD_SIZE;
516*4882a593Smuzhiyun 	if (addr > end - 1)
517*4882a593Smuzhiyun 		return;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	pgd = pgd_offset(tlb->mm, addr);
520*4882a593Smuzhiyun 	p4d = p4d_offset(pgd, addr);
521*4882a593Smuzhiyun 	do {
522*4882a593Smuzhiyun 		next = p4d_addr_end(addr, end);
523*4882a593Smuzhiyun 		if (p4d_none_or_clear_bad(p4d))
524*4882a593Smuzhiyun 			continue;
525*4882a593Smuzhiyun 		hugetlb_free_pud_range(tlb, p4d, addr, next, floor, ceiling);
526*4882a593Smuzhiyun 	} while (p4d++, addr = next, addr != end);
527*4882a593Smuzhiyun }
528