mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	powerpc/mm: Add radix support for hugetlb
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
		
							parent
							
								
									2f5f0dfd1e
								
							
						
					
					
						commit
						484837601d
					
				
					 6 changed files with 132 additions and 1 deletions
				
			
		
							
								
								
									
										14
									
								
								arch/powerpc/include/asm/book3s/64/hugetlb-radix.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								arch/powerpc/include/asm/book3s/64/hugetlb-radix.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
#ifndef _ASM_POWERPC_BOOK3S_64_HUGETLB_RADIX_H
 | 
			
		||||
#define _ASM_POWERPC_BOOK3S_64_HUGETLB_RADIX_H
 | 
			
		||||
/*
 | 
			
		||||
 * For radix we want generic code to handle hugetlb. But then if we want
 | 
			
		||||
 * both hash and radix to be enabled together we need to workaround the
 | 
			
		||||
 * limitations.
 | 
			
		||||
 */
 | 
			
		||||
void radix__flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 | 
			
		||||
void radix__local_flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 | 
			
		||||
extern unsigned long
 | 
			
		||||
radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 | 
			
		||||
				unsigned long len, unsigned long pgoff,
 | 
			
		||||
				unsigned long flags);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +8,8 @@
 | 
			
		|||
extern struct kmem_cache *hugepte_cache;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PPC_BOOK3S_64
 | 
			
		||||
 | 
			
		||||
#include <asm/book3s/64/hugetlb-radix.h>
 | 
			
		||||
/*
 | 
			
		||||
 * This should work for other subarchs too. But right now we use the
 | 
			
		||||
 * new format only for 64bit book3s
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +33,19 @@ static inline unsigned int hugepd_shift(hugepd_t hpd)
 | 
			
		|||
{
 | 
			
		||||
	return mmu_psize_to_shift(hugepd_mmu_psize(hpd));
 | 
			
		||||
}
 | 
			
		||||
static inline void flush_hugetlb_page(struct vm_area_struct *vma,
 | 
			
		||||
				      unsigned long vmaddr)
 | 
			
		||||
{
 | 
			
		||||
	if (radix_enabled())
 | 
			
		||||
		return radix__flush_hugetlb_page(vma, vmaddr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __local_flush_hugetlb_page(struct vm_area_struct *vma,
 | 
			
		||||
					      unsigned long vmaddr)
 | 
			
		||||
{
 | 
			
		||||
	if (radix_enabled())
 | 
			
		||||
		return radix__local_flush_hugetlb_page(vma, vmaddr);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static inline pte_t *hugepd_page(hugepd_t hpd)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ obj-$(CONFIG_PPC_MM_SLICES)	+= slice.o
 | 
			
		|||
obj-y				+= hugetlbpage.o
 | 
			
		||||
ifeq ($(CONFIG_HUGETLB_PAGE),y)
 | 
			
		||||
obj-$(CONFIG_PPC_STD_MMU_64)	+= hugetlbpage-hash64.o
 | 
			
		||||
obj-$(CONFIG_PPC_RADIX_MMU)	+= hugetlbpage-radix.o
 | 
			
		||||
obj-$(CONFIG_PPC_BOOK3E_MMU)	+= hugetlbpage-book3e.o
 | 
			
		||||
endif
 | 
			
		||||
obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += hugepage-hash64.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										87
									
								
								arch/powerpc/mm/hugetlbpage-radix.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								arch/powerpc/mm/hugetlbpage-radix.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
#include <linux/mm.h>
 | 
			
		||||
#include <linux/hugetlb.h>
 | 
			
		||||
#include <asm/pgtable.h>
 | 
			
		||||
#include <asm/pgalloc.h>
 | 
			
		||||
#include <asm/cacheflush.h>
 | 
			
		||||
#include <asm/machdep.h>
 | 
			
		||||
#include <asm/mman.h>
 | 
			
		||||
 | 
			
		||||
void radix__flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long ap, shift;
 | 
			
		||||
	struct hstate *hstate = hstate_file(vma->vm_file);
 | 
			
		||||
 | 
			
		||||
	shift = huge_page_shift(hstate);
 | 
			
		||||
	if (shift == mmu_psize_defs[MMU_PAGE_2M].shift)
 | 
			
		||||
		ap = mmu_get_ap(MMU_PAGE_2M);
 | 
			
		||||
	else if (shift == mmu_psize_defs[MMU_PAGE_1G].shift)
 | 
			
		||||
		ap = mmu_get_ap(MMU_PAGE_1G);
 | 
			
		||||
	else {
 | 
			
		||||
		WARN(1, "Wrong huge page shift\n");
 | 
			
		||||
		return ;
 | 
			
		||||
	}
 | 
			
		||||
	radix___flush_tlb_page(vma->vm_mm, vmaddr, ap, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix__local_flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long ap, shift;
 | 
			
		||||
	struct hstate *hstate = hstate_file(vma->vm_file);
 | 
			
		||||
 | 
			
		||||
	shift = huge_page_shift(hstate);
 | 
			
		||||
	if (shift == mmu_psize_defs[MMU_PAGE_2M].shift)
 | 
			
		||||
		ap = mmu_get_ap(MMU_PAGE_2M);
 | 
			
		||||
	else if (shift == mmu_psize_defs[MMU_PAGE_1G].shift)
 | 
			
		||||
		ap = mmu_get_ap(MMU_PAGE_1G);
 | 
			
		||||
	else {
 | 
			
		||||
		WARN(1, "Wrong huge page shift\n");
 | 
			
		||||
		return ;
 | 
			
		||||
	}
 | 
			
		||||
	radix___local_flush_tlb_page(vma->vm_mm, vmaddr, ap, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A vairant of hugetlb_get_unmapped_area doing topdown search
 | 
			
		||||
 * FIXME!! should we do as x86 does or non hugetlb area does ?
 | 
			
		||||
 * ie, use topdown or not based on mmap_is_legacy check ?
 | 
			
		||||
 */
 | 
			
		||||
unsigned long
 | 
			
		||||
radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 | 
			
		||||
				unsigned long len, unsigned long pgoff,
 | 
			
		||||
				unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	struct mm_struct *mm = current->mm;
 | 
			
		||||
	struct vm_area_struct *vma;
 | 
			
		||||
	struct hstate *h = hstate_file(file);
 | 
			
		||||
	struct vm_unmapped_area_info info;
 | 
			
		||||
 | 
			
		||||
	if (len & ~huge_page_mask(h))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (len > TASK_SIZE)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	if (flags & MAP_FIXED) {
 | 
			
		||||
		if (prepare_hugepage_range(file, addr, len))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		return addr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (addr) {
 | 
			
		||||
		addr = ALIGN(addr, huge_page_size(h));
 | 
			
		||||
		vma = find_vma(mm, addr);
 | 
			
		||||
		if (TASK_SIZE - len >= addr &&
 | 
			
		||||
		    (!vma || addr + len <= vma->vm_start))
 | 
			
		||||
			return addr;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
	 * We are always doing an topdown search here. Slice code
 | 
			
		||||
	 * does that too.
 | 
			
		||||
	 */
 | 
			
		||||
	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
 | 
			
		||||
	info.length = len;
 | 
			
		||||
	info.low_limit = PAGE_SIZE;
 | 
			
		||||
	info.high_limit = current->mm->mmap_base;
 | 
			
		||||
	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
 | 
			
		||||
	info.align_offset = 0;
 | 
			
		||||
	return vm_unmapped_area(&info);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -711,6 +711,9 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 | 
			
		|||
	struct hstate *hstate = hstate_file(file);
 | 
			
		||||
	int mmu_psize = shift_to_mmu_psize(huge_page_shift(hstate));
 | 
			
		||||
 | 
			
		||||
	if (radix_enabled())
 | 
			
		||||
		return radix__hugetlb_get_unmapped_area(file, addr, len,
 | 
			
		||||
						       pgoff, flags);
 | 
			
		||||
	return slice_get_unmapped_area(addr, len, flags, mmu_psize, 1);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -823,7 +826,7 @@ static int __init hugetlbpage_init(void)
 | 
			
		|||
{
 | 
			
		||||
	int psize;
 | 
			
		||||
 | 
			
		||||
	if (!mmu_has_feature(MMU_FTR_16M_PAGE))
 | 
			
		||||
	if (!radix_enabled() && !mmu_has_feature(MMU_FTR_16M_PAGE))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
 | 
			
		||||
| 
						 | 
				
			
			@ -863,6 +866,9 @@ static int __init hugetlbpage_init(void)
 | 
			
		|||
		HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_16M].shift;
 | 
			
		||||
	else if (mmu_psize_defs[MMU_PAGE_1M].shift)
 | 
			
		||||
		HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_1M].shift;
 | 
			
		||||
	else if (mmu_psize_defs[MMU_PAGE_2M].shift)
 | 
			
		||||
		HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_2M].shift;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,6 +141,11 @@ void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
 | 
			
		|||
 | 
			
		||||
void radix__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_HUGETLB_PAGE
 | 
			
		||||
	/* need the return fix for nohash.c */
 | 
			
		||||
	if (vma && is_vm_hugetlb_page(vma))
 | 
			
		||||
		return __local_flush_hugetlb_page(vma, vmaddr);
 | 
			
		||||
#endif
 | 
			
		||||
	radix___local_flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
 | 
			
		||||
			       mmu_get_ap(mmu_virtual_psize), 0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +207,10 @@ void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
 | 
			
		|||
 | 
			
		||||
void radix__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_HUGETLB_PAGE
 | 
			
		||||
	if (vma && is_vm_hugetlb_page(vma))
 | 
			
		||||
		return flush_hugetlb_page(vma, vmaddr);
 | 
			
		||||
#endif
 | 
			
		||||
	radix___flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
 | 
			
		||||
			 mmu_get_ap(mmu_virtual_psize), 0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue