xref: /openbmc/linux/arch/sparc/mm/hugetlbpage.c (revision c7d9f77d33a779ad582d8b2284ba007931ebd894)
127137e52SSam Ravnborg /*
227137e52SSam Ravnborg  * SPARC64 Huge TLB page support.
327137e52SSam Ravnborg  *
427137e52SSam Ravnborg  * Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net)
527137e52SSam Ravnborg  */
627137e52SSam Ravnborg 
727137e52SSam Ravnborg #include <linux/fs.h>
827137e52SSam Ravnborg #include <linux/mm.h>
927137e52SSam Ravnborg #include <linux/hugetlb.h>
1027137e52SSam Ravnborg #include <linux/pagemap.h>
1127137e52SSam Ravnborg #include <linux/sysctl.h>
1227137e52SSam Ravnborg 
1327137e52SSam Ravnborg #include <asm/mman.h>
1427137e52SSam Ravnborg #include <asm/pgalloc.h>
157bc3777cSNitin Gupta #include <asm/pgtable.h>
1627137e52SSam Ravnborg #include <asm/tlb.h>
1727137e52SSam Ravnborg #include <asm/tlbflush.h>
1827137e52SSam Ravnborg #include <asm/cacheflush.h>
1927137e52SSam Ravnborg #include <asm/mmu_context.h>
2027137e52SSam Ravnborg 
2127137e52SSam Ravnborg /* Slightly simplified from the non-hugepage variant because by
2227137e52SSam Ravnborg  * definition we don't have to worry about any page coloring stuff
2327137e52SSam Ravnborg  */
2427137e52SSam Ravnborg 
2527137e52SSam Ravnborg static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp,
2627137e52SSam Ravnborg 							unsigned long addr,
2727137e52SSam Ravnborg 							unsigned long len,
2827137e52SSam Ravnborg 							unsigned long pgoff,
2927137e52SSam Ravnborg 							unsigned long flags)
3027137e52SSam Ravnborg {
31*c7d9f77dSNitin Gupta 	struct hstate *h = hstate_file(filp);
3227137e52SSam Ravnborg 	unsigned long task_size = TASK_SIZE;
332aea28b9SMichel Lespinasse 	struct vm_unmapped_area_info info;
3427137e52SSam Ravnborg 
3527137e52SSam Ravnborg 	if (test_thread_flag(TIF_32BIT))
3627137e52SSam Ravnborg 		task_size = STACK_TOP32;
3727137e52SSam Ravnborg 
382aea28b9SMichel Lespinasse 	info.flags = 0;
392aea28b9SMichel Lespinasse 	info.length = len;
402aea28b9SMichel Lespinasse 	info.low_limit = TASK_UNMAPPED_BASE;
412aea28b9SMichel Lespinasse 	info.high_limit = min(task_size, VA_EXCLUDE_START);
42*c7d9f77dSNitin Gupta 	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
432aea28b9SMichel Lespinasse 	info.align_offset = 0;
442aea28b9SMichel Lespinasse 	addr = vm_unmapped_area(&info);
452aea28b9SMichel Lespinasse 
462aea28b9SMichel Lespinasse 	if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) {
472aea28b9SMichel Lespinasse 		VM_BUG_ON(addr != -ENOMEM);
482aea28b9SMichel Lespinasse 		info.low_limit = VA_EXCLUDE_END;
492aea28b9SMichel Lespinasse 		info.high_limit = task_size;
502aea28b9SMichel Lespinasse 		addr = vm_unmapped_area(&info);
5127137e52SSam Ravnborg 	}
5227137e52SSam Ravnborg 
5327137e52SSam Ravnborg 	return addr;
5427137e52SSam Ravnborg }
5527137e52SSam Ravnborg 
5627137e52SSam Ravnborg static unsigned long
5727137e52SSam Ravnborg hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
5827137e52SSam Ravnborg 				  const unsigned long len,
5927137e52SSam Ravnborg 				  const unsigned long pgoff,
6027137e52SSam Ravnborg 				  const unsigned long flags)
6127137e52SSam Ravnborg {
62*c7d9f77dSNitin Gupta 	struct hstate *h = hstate_file(filp);
6327137e52SSam Ravnborg 	struct mm_struct *mm = current->mm;
6427137e52SSam Ravnborg 	unsigned long addr = addr0;
652aea28b9SMichel Lespinasse 	struct vm_unmapped_area_info info;
6627137e52SSam Ravnborg 
6727137e52SSam Ravnborg 	/* This should only ever run for 32-bit processes.  */
6827137e52SSam Ravnborg 	BUG_ON(!test_thread_flag(TIF_32BIT));
6927137e52SSam Ravnborg 
702aea28b9SMichel Lespinasse 	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
712aea28b9SMichel Lespinasse 	info.length = len;
722aea28b9SMichel Lespinasse 	info.low_limit = PAGE_SIZE;
732aea28b9SMichel Lespinasse 	info.high_limit = mm->mmap_base;
74*c7d9f77dSNitin Gupta 	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
752aea28b9SMichel Lespinasse 	info.align_offset = 0;
762aea28b9SMichel Lespinasse 	addr = vm_unmapped_area(&info);
7727137e52SSam Ravnborg 
7827137e52SSam Ravnborg 	/*
7927137e52SSam Ravnborg 	 * A failed mmap() very likely causes application failure,
8027137e52SSam Ravnborg 	 * so fall back to the bottom-up function here. This scenario
8127137e52SSam Ravnborg 	 * can happen with large stack limits and large mmap()
8227137e52SSam Ravnborg 	 * allocations.
8327137e52SSam Ravnborg 	 */
842aea28b9SMichel Lespinasse 	if (addr & ~PAGE_MASK) {
852aea28b9SMichel Lespinasse 		VM_BUG_ON(addr != -ENOMEM);
862aea28b9SMichel Lespinasse 		info.flags = 0;
872aea28b9SMichel Lespinasse 		info.low_limit = TASK_UNMAPPED_BASE;
882aea28b9SMichel Lespinasse 		info.high_limit = STACK_TOP32;
892aea28b9SMichel Lespinasse 		addr = vm_unmapped_area(&info);
902aea28b9SMichel Lespinasse 	}
9127137e52SSam Ravnborg 
9227137e52SSam Ravnborg 	return addr;
9327137e52SSam Ravnborg }
9427137e52SSam Ravnborg 
9527137e52SSam Ravnborg unsigned long
9627137e52SSam Ravnborg hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
9727137e52SSam Ravnborg 		unsigned long len, unsigned long pgoff, unsigned long flags)
9827137e52SSam Ravnborg {
99*c7d9f77dSNitin Gupta 	struct hstate *h = hstate_file(file);
10027137e52SSam Ravnborg 	struct mm_struct *mm = current->mm;
10127137e52SSam Ravnborg 	struct vm_area_struct *vma;
10227137e52SSam Ravnborg 	unsigned long task_size = TASK_SIZE;
10327137e52SSam Ravnborg 
10427137e52SSam Ravnborg 	if (test_thread_flag(TIF_32BIT))
10527137e52SSam Ravnborg 		task_size = STACK_TOP32;
10627137e52SSam Ravnborg 
107*c7d9f77dSNitin Gupta 	if (len & ~huge_page_mask(h))
10827137e52SSam Ravnborg 		return -EINVAL;
10927137e52SSam Ravnborg 	if (len > task_size)
11027137e52SSam Ravnborg 		return -ENOMEM;
11127137e52SSam Ravnborg 
11227137e52SSam Ravnborg 	if (flags & MAP_FIXED) {
11327137e52SSam Ravnborg 		if (prepare_hugepage_range(file, addr, len))
11427137e52SSam Ravnborg 			return -EINVAL;
11527137e52SSam Ravnborg 		return addr;
11627137e52SSam Ravnborg 	}
11727137e52SSam Ravnborg 
11827137e52SSam Ravnborg 	if (addr) {
119*c7d9f77dSNitin Gupta 		addr = ALIGN(addr, huge_page_size(h));
12027137e52SSam Ravnborg 		vma = find_vma(mm, addr);
12127137e52SSam Ravnborg 		if (task_size - len >= addr &&
12227137e52SSam Ravnborg 		    (!vma || addr + len <= vma->vm_start))
12327137e52SSam Ravnborg 			return addr;
12427137e52SSam Ravnborg 	}
12527137e52SSam Ravnborg 	if (mm->get_unmapped_area == arch_get_unmapped_area)
12627137e52SSam Ravnborg 		return hugetlb_get_unmapped_area_bottomup(file, addr, len,
12727137e52SSam Ravnborg 				pgoff, flags);
12827137e52SSam Ravnborg 	else
12927137e52SSam Ravnborg 		return hugetlb_get_unmapped_area_topdown(file, addr, len,
13027137e52SSam Ravnborg 				pgoff, flags);
13127137e52SSam Ravnborg }
13227137e52SSam Ravnborg 
133*c7d9f77dSNitin Gupta static pte_t sun4u_hugepage_shift_to_tte(pte_t entry, unsigned int shift)
134*c7d9f77dSNitin Gupta {
135*c7d9f77dSNitin Gupta 	return entry;
136*c7d9f77dSNitin Gupta }
137*c7d9f77dSNitin Gupta 
138*c7d9f77dSNitin Gupta static pte_t sun4v_hugepage_shift_to_tte(pte_t entry, unsigned int shift)
139*c7d9f77dSNitin Gupta {
140*c7d9f77dSNitin Gupta 	unsigned long hugepage_size = _PAGE_SZ4MB_4V;
141*c7d9f77dSNitin Gupta 
142*c7d9f77dSNitin Gupta 	pte_val(entry) = pte_val(entry) & ~_PAGE_SZALL_4V;
143*c7d9f77dSNitin Gupta 
144*c7d9f77dSNitin Gupta 	switch (shift) {
145*c7d9f77dSNitin Gupta 	case HPAGE_256MB_SHIFT:
146*c7d9f77dSNitin Gupta 		hugepage_size = _PAGE_SZ256MB_4V;
147*c7d9f77dSNitin Gupta 		pte_val(entry) |= _PAGE_PMD_HUGE;
148*c7d9f77dSNitin Gupta 		break;
149*c7d9f77dSNitin Gupta 	case HPAGE_SHIFT:
150*c7d9f77dSNitin Gupta 		pte_val(entry) |= _PAGE_PMD_HUGE;
151*c7d9f77dSNitin Gupta 		break;
152*c7d9f77dSNitin Gupta 	default:
153*c7d9f77dSNitin Gupta 		WARN_ONCE(1, "unsupported hugepage shift=%u\n", shift);
154*c7d9f77dSNitin Gupta 	}
155*c7d9f77dSNitin Gupta 
156*c7d9f77dSNitin Gupta 	pte_val(entry) = pte_val(entry) | hugepage_size;
157*c7d9f77dSNitin Gupta 	return entry;
158*c7d9f77dSNitin Gupta }
159*c7d9f77dSNitin Gupta 
160*c7d9f77dSNitin Gupta static pte_t hugepage_shift_to_tte(pte_t entry, unsigned int shift)
161*c7d9f77dSNitin Gupta {
162*c7d9f77dSNitin Gupta 	if (tlb_type == hypervisor)
163*c7d9f77dSNitin Gupta 		return sun4v_hugepage_shift_to_tte(entry, shift);
164*c7d9f77dSNitin Gupta 	else
165*c7d9f77dSNitin Gupta 		return sun4u_hugepage_shift_to_tte(entry, shift);
166*c7d9f77dSNitin Gupta }
167*c7d9f77dSNitin Gupta 
168*c7d9f77dSNitin Gupta pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
169*c7d9f77dSNitin Gupta 			 struct page *page, int writeable)
170*c7d9f77dSNitin Gupta {
171*c7d9f77dSNitin Gupta 	unsigned int shift = huge_page_shift(hstate_vma(vma));
172*c7d9f77dSNitin Gupta 
173*c7d9f77dSNitin Gupta 	return hugepage_shift_to_tte(entry, shift);
174*c7d9f77dSNitin Gupta }
175*c7d9f77dSNitin Gupta 
176*c7d9f77dSNitin Gupta static unsigned int sun4v_huge_tte_to_shift(pte_t entry)
177*c7d9f77dSNitin Gupta {
178*c7d9f77dSNitin Gupta 	unsigned long tte_szbits = pte_val(entry) & _PAGE_SZALL_4V;
179*c7d9f77dSNitin Gupta 	unsigned int shift;
180*c7d9f77dSNitin Gupta 
181*c7d9f77dSNitin Gupta 	switch (tte_szbits) {
182*c7d9f77dSNitin Gupta 	case _PAGE_SZ256MB_4V:
183*c7d9f77dSNitin Gupta 		shift = HPAGE_256MB_SHIFT;
184*c7d9f77dSNitin Gupta 		break;
185*c7d9f77dSNitin Gupta 	case _PAGE_SZ4MB_4V:
186*c7d9f77dSNitin Gupta 		shift = REAL_HPAGE_SHIFT;
187*c7d9f77dSNitin Gupta 		break;
188*c7d9f77dSNitin Gupta 	default:
189*c7d9f77dSNitin Gupta 		shift = PAGE_SHIFT;
190*c7d9f77dSNitin Gupta 		break;
191*c7d9f77dSNitin Gupta 	}
192*c7d9f77dSNitin Gupta 	return shift;
193*c7d9f77dSNitin Gupta }
194*c7d9f77dSNitin Gupta 
195*c7d9f77dSNitin Gupta static unsigned int sun4u_huge_tte_to_shift(pte_t entry)
196*c7d9f77dSNitin Gupta {
197*c7d9f77dSNitin Gupta 	unsigned long tte_szbits = pte_val(entry) & _PAGE_SZALL_4U;
198*c7d9f77dSNitin Gupta 	unsigned int shift;
199*c7d9f77dSNitin Gupta 
200*c7d9f77dSNitin Gupta 	switch (tte_szbits) {
201*c7d9f77dSNitin Gupta 	case _PAGE_SZ256MB_4U:
202*c7d9f77dSNitin Gupta 		shift = HPAGE_256MB_SHIFT;
203*c7d9f77dSNitin Gupta 		break;
204*c7d9f77dSNitin Gupta 	case _PAGE_SZ4MB_4U:
205*c7d9f77dSNitin Gupta 		shift = REAL_HPAGE_SHIFT;
206*c7d9f77dSNitin Gupta 		break;
207*c7d9f77dSNitin Gupta 	default:
208*c7d9f77dSNitin Gupta 		shift = PAGE_SHIFT;
209*c7d9f77dSNitin Gupta 		break;
210*c7d9f77dSNitin Gupta 	}
211*c7d9f77dSNitin Gupta 	return shift;
212*c7d9f77dSNitin Gupta }
213*c7d9f77dSNitin Gupta 
214*c7d9f77dSNitin Gupta static unsigned int huge_tte_to_shift(pte_t entry)
215*c7d9f77dSNitin Gupta {
216*c7d9f77dSNitin Gupta 	unsigned long shift;
217*c7d9f77dSNitin Gupta 
218*c7d9f77dSNitin Gupta 	if (tlb_type == hypervisor)
219*c7d9f77dSNitin Gupta 		shift = sun4v_huge_tte_to_shift(entry);
220*c7d9f77dSNitin Gupta 	else
221*c7d9f77dSNitin Gupta 		shift = sun4u_huge_tte_to_shift(entry);
222*c7d9f77dSNitin Gupta 
223*c7d9f77dSNitin Gupta 	if (shift == PAGE_SHIFT)
224*c7d9f77dSNitin Gupta 		WARN_ONCE(1, "tto_to_shift: invalid hugepage tte=0x%lx\n",
225*c7d9f77dSNitin Gupta 			  pte_val(entry));
226*c7d9f77dSNitin Gupta 
227*c7d9f77dSNitin Gupta 	return shift;
228*c7d9f77dSNitin Gupta }
229*c7d9f77dSNitin Gupta 
230*c7d9f77dSNitin Gupta static unsigned long huge_tte_to_size(pte_t pte)
231*c7d9f77dSNitin Gupta {
232*c7d9f77dSNitin Gupta 	unsigned long size = 1UL << huge_tte_to_shift(pte);
233*c7d9f77dSNitin Gupta 
234*c7d9f77dSNitin Gupta 	if (size == REAL_HPAGE_SIZE)
235*c7d9f77dSNitin Gupta 		size = HPAGE_SIZE;
236*c7d9f77dSNitin Gupta 	return size;
237*c7d9f77dSNitin Gupta }
238*c7d9f77dSNitin Gupta 
23927137e52SSam Ravnborg pte_t *huge_pte_alloc(struct mm_struct *mm,
24027137e52SSam Ravnborg 			unsigned long addr, unsigned long sz)
24127137e52SSam Ravnborg {
24227137e52SSam Ravnborg 	pgd_t *pgd;
24327137e52SSam Ravnborg 	pud_t *pud;
24427137e52SSam Ravnborg 	pte_t *pte = NULL;
24527137e52SSam Ravnborg 
24627137e52SSam Ravnborg 	pgd = pgd_offset(mm, addr);
24727137e52SSam Ravnborg 	pud = pud_alloc(mm, pgd, addr);
2487bc3777cSNitin Gupta 	if (pud)
2497bc3777cSNitin Gupta 		pte = (pte_t *)pmd_alloc(mm, pud, addr);
2507bc3777cSNitin Gupta 
25127137e52SSam Ravnborg 	return pte;
25227137e52SSam Ravnborg }
25327137e52SSam Ravnborg 
25427137e52SSam Ravnborg pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
25527137e52SSam Ravnborg {
25627137e52SSam Ravnborg 	pgd_t *pgd;
25727137e52SSam Ravnborg 	pud_t *pud;
25827137e52SSam Ravnborg 	pte_t *pte = NULL;
25927137e52SSam Ravnborg 
26027137e52SSam Ravnborg 	pgd = pgd_offset(mm, addr);
26127137e52SSam Ravnborg 	if (!pgd_none(*pgd)) {
26227137e52SSam Ravnborg 		pud = pud_offset(pgd, addr);
2637bc3777cSNitin Gupta 		if (!pud_none(*pud))
2647bc3777cSNitin Gupta 			pte = (pte_t *)pmd_offset(pud, addr);
26527137e52SSam Ravnborg 	}
26627137e52SSam Ravnborg 	return pte;
26727137e52SSam Ravnborg }
26827137e52SSam Ravnborg 
26927137e52SSam Ravnborg void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
27027137e52SSam Ravnborg 		     pte_t *ptep, pte_t entry)
27127137e52SSam Ravnborg {
272*c7d9f77dSNitin Gupta 	unsigned int i, nptes, hugepage_shift;
273*c7d9f77dSNitin Gupta 	unsigned long size;
2747bc3777cSNitin Gupta 	pte_t orig;
27527137e52SSam Ravnborg 
276*c7d9f77dSNitin Gupta 	size = huge_tte_to_size(entry);
277*c7d9f77dSNitin Gupta 	nptes = size >> PMD_SHIFT;
278*c7d9f77dSNitin Gupta 
27927137e52SSam Ravnborg 	if (!pte_present(*ptep) && pte_present(entry))
280*c7d9f77dSNitin Gupta 		mm->context.hugetlb_pte_count += nptes;
28127137e52SSam Ravnborg 
282*c7d9f77dSNitin Gupta 	addr &= ~(size - 1);
2837bc3777cSNitin Gupta 	orig = *ptep;
284*c7d9f77dSNitin Gupta 	hugepage_shift = pte_none(orig) ? PAGE_SIZE : huge_tte_to_shift(orig);
28524e49ee3SNitin Gupta 
286*c7d9f77dSNitin Gupta 	for (i = 0; i < nptes; i++)
287*c7d9f77dSNitin Gupta 		ptep[i] = __pte(pte_val(entry) + (i << PMD_SHIFT));
288*c7d9f77dSNitin Gupta 
289*c7d9f77dSNitin Gupta 	maybe_tlb_batch_add(mm, addr, ptep, orig, 0, hugepage_shift);
290*c7d9f77dSNitin Gupta 	/* An HPAGE_SIZE'ed page is composed of two REAL_HPAGE_SIZE'ed pages */
291*c7d9f77dSNitin Gupta 	if (size == HPAGE_SIZE)
292*c7d9f77dSNitin Gupta 		maybe_tlb_batch_add(mm, addr + REAL_HPAGE_SIZE, ptep, orig, 0,
293*c7d9f77dSNitin Gupta 				    hugepage_shift);
29427137e52SSam Ravnborg }
29527137e52SSam Ravnborg 
29627137e52SSam Ravnborg pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
29727137e52SSam Ravnborg 			      pte_t *ptep)
29827137e52SSam Ravnborg {
299*c7d9f77dSNitin Gupta 	unsigned int i, nptes, hugepage_shift;
300*c7d9f77dSNitin Gupta 	unsigned long size;
30127137e52SSam Ravnborg 	pte_t entry;
30227137e52SSam Ravnborg 
30327137e52SSam Ravnborg 	entry = *ptep;
304*c7d9f77dSNitin Gupta 	size = huge_tte_to_size(entry);
305*c7d9f77dSNitin Gupta 	nptes = size >> PMD_SHIFT;
306*c7d9f77dSNitin Gupta 	hugepage_shift = pte_none(entry) ? PAGE_SIZE : huge_tte_to_shift(entry);
307*c7d9f77dSNitin Gupta 
30827137e52SSam Ravnborg 	if (pte_present(entry))
309*c7d9f77dSNitin Gupta 		mm->context.hugetlb_pte_count -= nptes;
31027137e52SSam Ravnborg 
311*c7d9f77dSNitin Gupta 	addr &= ~(size - 1);
312*c7d9f77dSNitin Gupta 	for (i = 0; i < nptes; i++)
313*c7d9f77dSNitin Gupta 		ptep[i] = __pte(0UL);
31427137e52SSam Ravnborg 
315*c7d9f77dSNitin Gupta 	maybe_tlb_batch_add(mm, addr, ptep, entry, 0, hugepage_shift);
316*c7d9f77dSNitin Gupta 	/* An HPAGE_SIZE'ed page is composed of two REAL_HPAGE_SIZE'ed pages */
317*c7d9f77dSNitin Gupta 	if (size == HPAGE_SIZE)
318*c7d9f77dSNitin Gupta 		maybe_tlb_batch_add(mm, addr + REAL_HPAGE_SIZE, ptep, entry, 0,
319*c7d9f77dSNitin Gupta 				    hugepage_shift);
32024e49ee3SNitin Gupta 
32127137e52SSam Ravnborg 	return entry;
32227137e52SSam Ravnborg }
32327137e52SSam Ravnborg 
32427137e52SSam Ravnborg int pmd_huge(pmd_t pmd)
32527137e52SSam Ravnborg {
3267bc3777cSNitin Gupta 	return !pmd_none(pmd) &&
3277bc3777cSNitin Gupta 		(pmd_val(pmd) & (_PAGE_VALID|_PAGE_PMD_HUGE)) != _PAGE_VALID;
32827137e52SSam Ravnborg }
32927137e52SSam Ravnborg 
33027137e52SSam Ravnborg int pud_huge(pud_t pud)
33127137e52SSam Ravnborg {
33227137e52SSam Ravnborg 	return 0;
33327137e52SSam Ravnborg }
3347bc3777cSNitin Gupta 
3357bc3777cSNitin Gupta static void hugetlb_free_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
3367bc3777cSNitin Gupta 			   unsigned long addr)
3377bc3777cSNitin Gupta {
3387bc3777cSNitin Gupta 	pgtable_t token = pmd_pgtable(*pmd);
3397bc3777cSNitin Gupta 
3407bc3777cSNitin Gupta 	pmd_clear(pmd);
3417bc3777cSNitin Gupta 	pte_free_tlb(tlb, token, addr);
3427bc3777cSNitin Gupta 	atomic_long_dec(&tlb->mm->nr_ptes);
3437bc3777cSNitin Gupta }
3447bc3777cSNitin Gupta 
3457bc3777cSNitin Gupta static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
3467bc3777cSNitin Gupta 				   unsigned long addr, unsigned long end,
3477bc3777cSNitin Gupta 				   unsigned long floor, unsigned long ceiling)
3487bc3777cSNitin Gupta {
3497bc3777cSNitin Gupta 	pmd_t *pmd;
3507bc3777cSNitin Gupta 	unsigned long next;
3517bc3777cSNitin Gupta 	unsigned long start;
3527bc3777cSNitin Gupta 
3537bc3777cSNitin Gupta 	start = addr;
3547bc3777cSNitin Gupta 	pmd = pmd_offset(pud, addr);
3557bc3777cSNitin Gupta 	do {
3567bc3777cSNitin Gupta 		next = pmd_addr_end(addr, end);
3577bc3777cSNitin Gupta 		if (pmd_none(*pmd))
3587bc3777cSNitin Gupta 			continue;
3597bc3777cSNitin Gupta 		if (is_hugetlb_pmd(*pmd))
3607bc3777cSNitin Gupta 			pmd_clear(pmd);
3617bc3777cSNitin Gupta 		else
3627bc3777cSNitin Gupta 			hugetlb_free_pte_range(tlb, pmd, addr);
3637bc3777cSNitin Gupta 	} while (pmd++, addr = next, addr != end);
3647bc3777cSNitin Gupta 
3657bc3777cSNitin Gupta 	start &= PUD_MASK;
3667bc3777cSNitin Gupta 	if (start < floor)
3677bc3777cSNitin Gupta 		return;
3687bc3777cSNitin Gupta 	if (ceiling) {
3697bc3777cSNitin Gupta 		ceiling &= PUD_MASK;
3707bc3777cSNitin Gupta 		if (!ceiling)
3717bc3777cSNitin Gupta 			return;
3727bc3777cSNitin Gupta 	}
3737bc3777cSNitin Gupta 	if (end - 1 > ceiling - 1)
3747bc3777cSNitin Gupta 		return;
3757bc3777cSNitin Gupta 
3767bc3777cSNitin Gupta 	pmd = pmd_offset(pud, start);
3777bc3777cSNitin Gupta 	pud_clear(pud);
3787bc3777cSNitin Gupta 	pmd_free_tlb(tlb, pmd, start);
3797bc3777cSNitin Gupta 	mm_dec_nr_pmds(tlb->mm);
3807bc3777cSNitin Gupta }
3817bc3777cSNitin Gupta 
3827bc3777cSNitin Gupta static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
3837bc3777cSNitin Gupta 				   unsigned long addr, unsigned long end,
3847bc3777cSNitin Gupta 				   unsigned long floor, unsigned long ceiling)
3857bc3777cSNitin Gupta {
3867bc3777cSNitin Gupta 	pud_t *pud;
3877bc3777cSNitin Gupta 	unsigned long next;
3887bc3777cSNitin Gupta 	unsigned long start;
3897bc3777cSNitin Gupta 
3907bc3777cSNitin Gupta 	start = addr;
3917bc3777cSNitin Gupta 	pud = pud_offset(pgd, addr);
3927bc3777cSNitin Gupta 	do {
3937bc3777cSNitin Gupta 		next = pud_addr_end(addr, end);
3947bc3777cSNitin Gupta 		if (pud_none_or_clear_bad(pud))
3957bc3777cSNitin Gupta 			continue;
3967bc3777cSNitin Gupta 		hugetlb_free_pmd_range(tlb, pud, addr, next, floor,
3977bc3777cSNitin Gupta 				       ceiling);
3987bc3777cSNitin Gupta 	} while (pud++, addr = next, addr != end);
3997bc3777cSNitin Gupta 
4007bc3777cSNitin Gupta 	start &= PGDIR_MASK;
4017bc3777cSNitin Gupta 	if (start < floor)
4027bc3777cSNitin Gupta 		return;
4037bc3777cSNitin Gupta 	if (ceiling) {
4047bc3777cSNitin Gupta 		ceiling &= PGDIR_MASK;
4057bc3777cSNitin Gupta 		if (!ceiling)
4067bc3777cSNitin Gupta 			return;
4077bc3777cSNitin Gupta 	}
4087bc3777cSNitin Gupta 	if (end - 1 > ceiling - 1)
4097bc3777cSNitin Gupta 		return;
4107bc3777cSNitin Gupta 
4117bc3777cSNitin Gupta 	pud = pud_offset(pgd, start);
4127bc3777cSNitin Gupta 	pgd_clear(pgd);
4137bc3777cSNitin Gupta 	pud_free_tlb(tlb, pud, start);
4147bc3777cSNitin Gupta }
4157bc3777cSNitin Gupta 
4167bc3777cSNitin Gupta void hugetlb_free_pgd_range(struct mmu_gather *tlb,
4177bc3777cSNitin Gupta 			    unsigned long addr, unsigned long end,
4187bc3777cSNitin Gupta 			    unsigned long floor, unsigned long ceiling)
4197bc3777cSNitin Gupta {
4207bc3777cSNitin Gupta 	pgd_t *pgd;
4217bc3777cSNitin Gupta 	unsigned long next;
4227bc3777cSNitin Gupta 
4237bc3777cSNitin Gupta 	pgd = pgd_offset(tlb->mm, addr);
4247bc3777cSNitin Gupta 	do {
4257bc3777cSNitin Gupta 		next = pgd_addr_end(addr, end);
4267bc3777cSNitin Gupta 		if (pgd_none_or_clear_bad(pgd))
4277bc3777cSNitin Gupta 			continue;
4287bc3777cSNitin Gupta 		hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling);
4297bc3777cSNitin Gupta 	} while (pgd++, addr = next, addr != end);
4307bc3777cSNitin Gupta }
431