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/init.h> 827137e52SSam Ravnborg #include <linux/module.h> 927137e52SSam Ravnborg #include <linux/fs.h> 1027137e52SSam Ravnborg #include <linux/mm.h> 1127137e52SSam Ravnborg #include <linux/hugetlb.h> 1227137e52SSam Ravnborg #include <linux/pagemap.h> 1327137e52SSam Ravnborg #include <linux/sysctl.h> 1427137e52SSam Ravnborg 1527137e52SSam Ravnborg #include <asm/mman.h> 1627137e52SSam Ravnborg #include <asm/pgalloc.h> 1727137e52SSam Ravnborg #include <asm/tlb.h> 1827137e52SSam Ravnborg #include <asm/tlbflush.h> 1927137e52SSam Ravnborg #include <asm/cacheflush.h> 2027137e52SSam Ravnborg #include <asm/mmu_context.h> 2127137e52SSam Ravnborg 2227137e52SSam Ravnborg /* Slightly simplified from the non-hugepage variant because by 2327137e52SSam Ravnborg * definition we don't have to worry about any page coloring stuff 2427137e52SSam Ravnborg */ 2527137e52SSam Ravnborg #define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL)) 2627137e52SSam Ravnborg #define VA_EXCLUDE_END (0xfffff80000000000UL + (1UL << 32UL)) 2727137e52SSam Ravnborg 2827137e52SSam Ravnborg static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp, 2927137e52SSam Ravnborg unsigned long addr, 3027137e52SSam Ravnborg unsigned long len, 3127137e52SSam Ravnborg unsigned long pgoff, 3227137e52SSam Ravnborg unsigned long flags) 3327137e52SSam Ravnborg { 3427137e52SSam Ravnborg struct mm_struct *mm = current->mm; 3527137e52SSam Ravnborg struct vm_area_struct * vma; 3627137e52SSam Ravnborg unsigned long task_size = TASK_SIZE; 3727137e52SSam Ravnborg unsigned long start_addr; 3827137e52SSam Ravnborg 3927137e52SSam Ravnborg if (test_thread_flag(TIF_32BIT)) 4027137e52SSam Ravnborg task_size = STACK_TOP32; 4127137e52SSam Ravnborg if (unlikely(len >= VA_EXCLUDE_START)) 4227137e52SSam Ravnborg return -ENOMEM; 4327137e52SSam Ravnborg 4427137e52SSam Ravnborg if (len > mm->cached_hole_size) { 4527137e52SSam Ravnborg start_addr = addr = mm->free_area_cache; 4627137e52SSam Ravnborg } else { 4727137e52SSam Ravnborg start_addr = addr = TASK_UNMAPPED_BASE; 4827137e52SSam Ravnborg mm->cached_hole_size = 0; 4927137e52SSam Ravnborg } 5027137e52SSam Ravnborg 5127137e52SSam Ravnborg task_size -= len; 5227137e52SSam Ravnborg 5327137e52SSam Ravnborg full_search: 5427137e52SSam Ravnborg addr = ALIGN(addr, HPAGE_SIZE); 5527137e52SSam Ravnborg 5627137e52SSam Ravnborg for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { 5727137e52SSam Ravnborg /* At this point: (!vma || addr < vma->vm_end). */ 5827137e52SSam Ravnborg if (addr < VA_EXCLUDE_START && 5927137e52SSam Ravnborg (addr + len) >= VA_EXCLUDE_START) { 6027137e52SSam Ravnborg addr = VA_EXCLUDE_END; 6127137e52SSam Ravnborg vma = find_vma(mm, VA_EXCLUDE_END); 6227137e52SSam Ravnborg } 6327137e52SSam Ravnborg if (unlikely(task_size < addr)) { 6427137e52SSam Ravnborg if (start_addr != TASK_UNMAPPED_BASE) { 6527137e52SSam Ravnborg start_addr = addr = TASK_UNMAPPED_BASE; 6627137e52SSam Ravnborg mm->cached_hole_size = 0; 6727137e52SSam Ravnborg goto full_search; 6827137e52SSam Ravnborg } 6927137e52SSam Ravnborg return -ENOMEM; 7027137e52SSam Ravnborg } 7127137e52SSam Ravnborg if (likely(!vma || addr + len <= vma->vm_start)) { 7227137e52SSam Ravnborg /* 7327137e52SSam Ravnborg * Remember the place where we stopped the search: 7427137e52SSam Ravnborg */ 7527137e52SSam Ravnborg mm->free_area_cache = addr + len; 7627137e52SSam Ravnborg return addr; 7727137e52SSam Ravnborg } 7827137e52SSam Ravnborg if (addr + mm->cached_hole_size < vma->vm_start) 7927137e52SSam Ravnborg mm->cached_hole_size = vma->vm_start - addr; 8027137e52SSam Ravnborg 8127137e52SSam Ravnborg addr = ALIGN(vma->vm_end, HPAGE_SIZE); 8227137e52SSam Ravnborg } 8327137e52SSam Ravnborg } 8427137e52SSam Ravnborg 8527137e52SSam Ravnborg static unsigned long 8627137e52SSam Ravnborg hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, 8727137e52SSam Ravnborg const unsigned long len, 8827137e52SSam Ravnborg const unsigned long pgoff, 8927137e52SSam Ravnborg const unsigned long flags) 9027137e52SSam Ravnborg { 9127137e52SSam Ravnborg struct vm_area_struct *vma; 9227137e52SSam Ravnborg struct mm_struct *mm = current->mm; 9327137e52SSam Ravnborg unsigned long addr = addr0; 9427137e52SSam Ravnborg 9527137e52SSam Ravnborg /* This should only ever run for 32-bit processes. */ 9627137e52SSam Ravnborg BUG_ON(!test_thread_flag(TIF_32BIT)); 9727137e52SSam Ravnborg 9827137e52SSam Ravnborg /* check if free_area_cache is useful for us */ 9927137e52SSam Ravnborg if (len <= mm->cached_hole_size) { 10027137e52SSam Ravnborg mm->cached_hole_size = 0; 10127137e52SSam Ravnborg mm->free_area_cache = mm->mmap_base; 10227137e52SSam Ravnborg } 10327137e52SSam Ravnborg 10427137e52SSam Ravnborg /* either no address requested or can't fit in requested address hole */ 10527137e52SSam Ravnborg addr = mm->free_area_cache & HPAGE_MASK; 10627137e52SSam Ravnborg 10727137e52SSam Ravnborg /* make sure it can fit in the remaining address space */ 10827137e52SSam Ravnborg if (likely(addr > len)) { 10927137e52SSam Ravnborg vma = find_vma(mm, addr-len); 11027137e52SSam Ravnborg if (!vma || addr <= vma->vm_start) { 11127137e52SSam Ravnborg /* remember the address as a hint for next time */ 11227137e52SSam Ravnborg return (mm->free_area_cache = addr-len); 11327137e52SSam Ravnborg } 11427137e52SSam Ravnborg } 11527137e52SSam Ravnborg 11627137e52SSam Ravnborg if (unlikely(mm->mmap_base < len)) 11727137e52SSam Ravnborg goto bottomup; 11827137e52SSam Ravnborg 11927137e52SSam Ravnborg addr = (mm->mmap_base-len) & HPAGE_MASK; 12027137e52SSam Ravnborg 12127137e52SSam Ravnborg do { 12227137e52SSam Ravnborg /* 12327137e52SSam Ravnborg * Lookup failure means no vma is above this address, 12427137e52SSam Ravnborg * else if new region fits below vma->vm_start, 12527137e52SSam Ravnborg * return with success: 12627137e52SSam Ravnborg */ 12727137e52SSam Ravnborg vma = find_vma(mm, addr); 12827137e52SSam Ravnborg if (likely(!vma || addr+len <= vma->vm_start)) { 12927137e52SSam Ravnborg /* remember the address as a hint for next time */ 13027137e52SSam Ravnborg return (mm->free_area_cache = addr); 13127137e52SSam Ravnborg } 13227137e52SSam Ravnborg 13327137e52SSam Ravnborg /* remember the largest hole we saw so far */ 13427137e52SSam Ravnborg if (addr + mm->cached_hole_size < vma->vm_start) 13527137e52SSam Ravnborg mm->cached_hole_size = vma->vm_start - addr; 13627137e52SSam Ravnborg 13727137e52SSam Ravnborg /* try just below the current vma->vm_start */ 13827137e52SSam Ravnborg addr = (vma->vm_start-len) & HPAGE_MASK; 13927137e52SSam Ravnborg } while (likely(len < vma->vm_start)); 14027137e52SSam Ravnborg 14127137e52SSam Ravnborg bottomup: 14227137e52SSam Ravnborg /* 14327137e52SSam Ravnborg * A failed mmap() very likely causes application failure, 14427137e52SSam Ravnborg * so fall back to the bottom-up function here. This scenario 14527137e52SSam Ravnborg * can happen with large stack limits and large mmap() 14627137e52SSam Ravnborg * allocations. 14727137e52SSam Ravnborg */ 14827137e52SSam Ravnborg mm->cached_hole_size = ~0UL; 14927137e52SSam Ravnborg mm->free_area_cache = TASK_UNMAPPED_BASE; 15027137e52SSam Ravnborg addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); 15127137e52SSam Ravnborg /* 15227137e52SSam Ravnborg * Restore the topdown base: 15327137e52SSam Ravnborg */ 15427137e52SSam Ravnborg mm->free_area_cache = mm->mmap_base; 15527137e52SSam Ravnborg mm->cached_hole_size = ~0UL; 15627137e52SSam Ravnborg 15727137e52SSam Ravnborg return addr; 15827137e52SSam Ravnborg } 15927137e52SSam Ravnborg 16027137e52SSam Ravnborg unsigned long 16127137e52SSam Ravnborg hugetlb_get_unmapped_area(struct file *file, unsigned long addr, 16227137e52SSam Ravnborg unsigned long len, unsigned long pgoff, unsigned long flags) 16327137e52SSam Ravnborg { 16427137e52SSam Ravnborg struct mm_struct *mm = current->mm; 16527137e52SSam Ravnborg struct vm_area_struct *vma; 16627137e52SSam Ravnborg unsigned long task_size = TASK_SIZE; 16727137e52SSam Ravnborg 16827137e52SSam Ravnborg if (test_thread_flag(TIF_32BIT)) 16927137e52SSam Ravnborg task_size = STACK_TOP32; 17027137e52SSam Ravnborg 17127137e52SSam Ravnborg if (len & ~HPAGE_MASK) 17227137e52SSam Ravnborg return -EINVAL; 17327137e52SSam Ravnborg if (len > task_size) 17427137e52SSam Ravnborg return -ENOMEM; 17527137e52SSam Ravnborg 17627137e52SSam Ravnborg if (flags & MAP_FIXED) { 17727137e52SSam Ravnborg if (prepare_hugepage_range(file, addr, len)) 17827137e52SSam Ravnborg return -EINVAL; 17927137e52SSam Ravnborg return addr; 18027137e52SSam Ravnborg } 18127137e52SSam Ravnborg 18227137e52SSam Ravnborg if (addr) { 18327137e52SSam Ravnborg addr = ALIGN(addr, HPAGE_SIZE); 18427137e52SSam Ravnborg vma = find_vma(mm, addr); 18527137e52SSam Ravnborg if (task_size - len >= addr && 18627137e52SSam Ravnborg (!vma || addr + len <= vma->vm_start)) 18727137e52SSam Ravnborg return addr; 18827137e52SSam Ravnborg } 18927137e52SSam Ravnborg if (mm->get_unmapped_area == arch_get_unmapped_area) 19027137e52SSam Ravnborg return hugetlb_get_unmapped_area_bottomup(file, addr, len, 19127137e52SSam Ravnborg pgoff, flags); 19227137e52SSam Ravnborg else 19327137e52SSam Ravnborg return hugetlb_get_unmapped_area_topdown(file, addr, len, 19427137e52SSam Ravnborg pgoff, flags); 19527137e52SSam Ravnborg } 19627137e52SSam Ravnborg 19727137e52SSam Ravnborg pte_t *huge_pte_alloc(struct mm_struct *mm, 19827137e52SSam Ravnborg unsigned long addr, unsigned long sz) 19927137e52SSam Ravnborg { 20027137e52SSam Ravnborg pgd_t *pgd; 20127137e52SSam Ravnborg pud_t *pud; 20227137e52SSam Ravnborg pmd_t *pmd; 20327137e52SSam Ravnborg pte_t *pte = NULL; 20427137e52SSam Ravnborg 20527137e52SSam Ravnborg /* We must align the address, because our caller will run 20627137e52SSam Ravnborg * set_huge_pte_at() on whatever we return, which writes out 20727137e52SSam Ravnborg * all of the sub-ptes for the hugepage range. So we have 20827137e52SSam Ravnborg * to give it the first such sub-pte. 20927137e52SSam Ravnborg */ 21027137e52SSam Ravnborg addr &= HPAGE_MASK; 21127137e52SSam Ravnborg 21227137e52SSam Ravnborg pgd = pgd_offset(mm, addr); 21327137e52SSam Ravnborg pud = pud_alloc(mm, pgd, addr); 21427137e52SSam Ravnborg if (pud) { 21527137e52SSam Ravnborg pmd = pmd_alloc(mm, pud, addr); 21627137e52SSam Ravnborg if (pmd) 217*8ac1f832SAndrea Arcangeli pte = pte_alloc_map(mm, NULL, pmd, addr); 21827137e52SSam Ravnborg } 21927137e52SSam Ravnborg return pte; 22027137e52SSam Ravnborg } 22127137e52SSam Ravnborg 22227137e52SSam Ravnborg pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) 22327137e52SSam Ravnborg { 22427137e52SSam Ravnborg pgd_t *pgd; 22527137e52SSam Ravnborg pud_t *pud; 22627137e52SSam Ravnborg pmd_t *pmd; 22727137e52SSam Ravnborg pte_t *pte = NULL; 22827137e52SSam Ravnborg 22927137e52SSam Ravnborg addr &= HPAGE_MASK; 23027137e52SSam Ravnborg 23127137e52SSam Ravnborg pgd = pgd_offset(mm, addr); 23227137e52SSam Ravnborg if (!pgd_none(*pgd)) { 23327137e52SSam Ravnborg pud = pud_offset(pgd, addr); 23427137e52SSam Ravnborg if (!pud_none(*pud)) { 23527137e52SSam Ravnborg pmd = pmd_offset(pud, addr); 23627137e52SSam Ravnborg if (!pmd_none(*pmd)) 23727137e52SSam Ravnborg pte = pte_offset_map(pmd, addr); 23827137e52SSam Ravnborg } 23927137e52SSam Ravnborg } 24027137e52SSam Ravnborg return pte; 24127137e52SSam Ravnborg } 24227137e52SSam Ravnborg 24327137e52SSam Ravnborg int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) 24427137e52SSam Ravnborg { 24527137e52SSam Ravnborg return 0; 24627137e52SSam Ravnborg } 24727137e52SSam Ravnborg 24827137e52SSam Ravnborg void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, 24927137e52SSam Ravnborg pte_t *ptep, pte_t entry) 25027137e52SSam Ravnborg { 25127137e52SSam Ravnborg int i; 25227137e52SSam Ravnborg 25327137e52SSam Ravnborg if (!pte_present(*ptep) && pte_present(entry)) 25427137e52SSam Ravnborg mm->context.huge_pte_count++; 25527137e52SSam Ravnborg 25627137e52SSam Ravnborg addr &= HPAGE_MASK; 25727137e52SSam Ravnborg for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { 25827137e52SSam Ravnborg set_pte_at(mm, addr, ptep, entry); 25927137e52SSam Ravnborg ptep++; 26027137e52SSam Ravnborg addr += PAGE_SIZE; 26127137e52SSam Ravnborg pte_val(entry) += PAGE_SIZE; 26227137e52SSam Ravnborg } 26327137e52SSam Ravnborg } 26427137e52SSam Ravnborg 26527137e52SSam Ravnborg pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, 26627137e52SSam Ravnborg pte_t *ptep) 26727137e52SSam Ravnborg { 26827137e52SSam Ravnborg pte_t entry; 26927137e52SSam Ravnborg int i; 27027137e52SSam Ravnborg 27127137e52SSam Ravnborg entry = *ptep; 27227137e52SSam Ravnborg if (pte_present(entry)) 27327137e52SSam Ravnborg mm->context.huge_pte_count--; 27427137e52SSam Ravnborg 27527137e52SSam Ravnborg addr &= HPAGE_MASK; 27627137e52SSam Ravnborg 27727137e52SSam Ravnborg for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { 27827137e52SSam Ravnborg pte_clear(mm, addr, ptep); 27927137e52SSam Ravnborg addr += PAGE_SIZE; 28027137e52SSam Ravnborg ptep++; 28127137e52SSam Ravnborg } 28227137e52SSam Ravnborg 28327137e52SSam Ravnborg return entry; 28427137e52SSam Ravnborg } 28527137e52SSam Ravnborg 28627137e52SSam Ravnborg struct page *follow_huge_addr(struct mm_struct *mm, 28727137e52SSam Ravnborg unsigned long address, int write) 28827137e52SSam Ravnborg { 28927137e52SSam Ravnborg return ERR_PTR(-EINVAL); 29027137e52SSam Ravnborg } 29127137e52SSam Ravnborg 29227137e52SSam Ravnborg int pmd_huge(pmd_t pmd) 29327137e52SSam Ravnborg { 29427137e52SSam Ravnborg return 0; 29527137e52SSam Ravnborg } 29627137e52SSam Ravnborg 29727137e52SSam Ravnborg int pud_huge(pud_t pud) 29827137e52SSam Ravnborg { 29927137e52SSam Ravnborg return 0; 30027137e52SSam Ravnborg } 30127137e52SSam Ravnborg 30227137e52SSam Ravnborg struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, 30327137e52SSam Ravnborg pmd_t *pmd, int write) 30427137e52SSam Ravnborg { 30527137e52SSam Ravnborg return NULL; 30627137e52SSam Ravnborg } 30727137e52SSam Ravnborg 30827137e52SSam Ravnborg static void context_reload(void *__data) 30927137e52SSam Ravnborg { 31027137e52SSam Ravnborg struct mm_struct *mm = __data; 31127137e52SSam Ravnborg 31227137e52SSam Ravnborg if (mm == current->mm) 31327137e52SSam Ravnborg load_secondary_context(mm); 31427137e52SSam Ravnborg } 31527137e52SSam Ravnborg 31627137e52SSam Ravnborg void hugetlb_prefault_arch_hook(struct mm_struct *mm) 31727137e52SSam Ravnborg { 31827137e52SSam Ravnborg struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE]; 31927137e52SSam Ravnborg 32027137e52SSam Ravnborg if (likely(tp->tsb != NULL)) 32127137e52SSam Ravnborg return; 32227137e52SSam Ravnborg 32327137e52SSam Ravnborg tsb_grow(mm, MM_TSB_HUGE, 0); 32427137e52SSam Ravnborg tsb_context_switch(mm); 32527137e52SSam Ravnborg smp_tsb_sync(mm); 32627137e52SSam Ravnborg 32727137e52SSam Ravnborg /* On UltraSPARC-III+ and later, configure the second half of 32827137e52SSam Ravnborg * the Data-TLB for huge pages. 32927137e52SSam Ravnborg */ 33027137e52SSam Ravnborg if (tlb_type == cheetah_plus) { 33127137e52SSam Ravnborg unsigned long ctx; 33227137e52SSam Ravnborg 33327137e52SSam Ravnborg spin_lock(&ctx_alloc_lock); 33427137e52SSam Ravnborg ctx = mm->context.sparc64_ctx_val; 33527137e52SSam Ravnborg ctx &= ~CTX_PGSZ_MASK; 33627137e52SSam Ravnborg ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT; 33727137e52SSam Ravnborg ctx |= CTX_PGSZ_HUGE << CTX_PGSZ1_SHIFT; 33827137e52SSam Ravnborg 33927137e52SSam Ravnborg if (ctx != mm->context.sparc64_ctx_val) { 34027137e52SSam Ravnborg /* When changing the page size fields, we 34127137e52SSam Ravnborg * must perform a context flush so that no 34227137e52SSam Ravnborg * stale entries match. This flush must 34327137e52SSam Ravnborg * occur with the original context register 34427137e52SSam Ravnborg * settings. 34527137e52SSam Ravnborg */ 34627137e52SSam Ravnborg do_flush_tlb_mm(mm); 34727137e52SSam Ravnborg 34827137e52SSam Ravnborg /* Reload the context register of all processors 34927137e52SSam Ravnborg * also executing in this address space. 35027137e52SSam Ravnborg */ 35127137e52SSam Ravnborg mm->context.sparc64_ctx_val = ctx; 35227137e52SSam Ravnborg on_each_cpu(context_reload, mm, 0); 35327137e52SSam Ravnborg } 35427137e52SSam Ravnborg spin_unlock(&ctx_alloc_lock); 35527137e52SSam Ravnborg } 35627137e52SSam Ravnborg } 357