linux/arch/powerpc/mm/hugetlbpage-book3e.c
<<
>>
Prefs
   1/*
   2 * PPC Huge TLB Page Support for Book3E MMU
   3 *
   4 * Copyright (C) 2009 David Gibson, IBM Corporation.
   5 * Copyright (C) 2011 Becky Bruce, Freescale Semiconductor
   6 *
   7 */
   8#include <linux/mm.h>
   9#include <linux/hugetlb.h>
  10
  11static inline int mmu_get_tsize(int psize)
  12{
  13        return mmu_psize_defs[psize].enc;
  14}
  15
  16static inline int book3e_tlb_exists(unsigned long ea, unsigned long pid)
  17{
  18        int found = 0;
  19
  20        mtspr(SPRN_MAS6, pid << 16);
  21        if (mmu_has_feature(MMU_FTR_USE_TLBRSRV)) {
  22                asm volatile(
  23                        "li     %0,0\n"
  24                        "tlbsx. 0,%1\n"
  25                        "bne    1f\n"
  26                        "li     %0,1\n"
  27                        "1:\n"
  28                        : "=&r"(found) : "r"(ea));
  29        } else {
  30                asm volatile(
  31                        "tlbsx  0,%1\n"
  32                        "mfspr  %0,0x271\n"
  33                        "srwi   %0,%0,31\n"
  34                        : "=&r"(found) : "r"(ea));
  35        }
  36
  37        return found;
  38}
  39
  40void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
  41                            pte_t pte)
  42{
  43        unsigned long mas1, mas2;
  44        u64 mas7_3;
  45        unsigned long psize, tsize, shift;
  46        unsigned long flags;
  47        struct mm_struct *mm;
  48
  49#ifdef CONFIG_PPC_FSL_BOOK3E
  50        int index, ncams;
  51#endif
  52
  53        if (unlikely(is_kernel_addr(ea)))
  54                return;
  55
  56        mm = vma->vm_mm;
  57
  58#ifdef CONFIG_PPC_MM_SLICES
  59        psize = get_slice_psize(mm, ea);
  60        tsize = mmu_get_tsize(psize);
  61        shift = mmu_psize_defs[psize].shift;
  62#else
  63        psize = vma_mmu_pagesize(vma);
  64        shift = __ilog2(psize);
  65        tsize = shift - 10;
  66#endif
  67
  68        /*
  69         * We can't be interrupted while we're setting up the MAS
  70         * regusters or after we've confirmed that no tlb exists.
  71         */
  72        local_irq_save(flags);
  73
  74        if (unlikely(book3e_tlb_exists(ea, mm->context.id))) {
  75                local_irq_restore(flags);
  76                return;
  77        }
  78
  79#ifdef CONFIG_PPC_FSL_BOOK3E
  80        ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
  81
  82        /* We have to use the CAM(TLB1) on FSL parts for hugepages */
  83        index = __get_cpu_var(next_tlbcam_idx);
  84        mtspr(SPRN_MAS0, MAS0_ESEL(index) | MAS0_TLBSEL(1));
  85
  86        /* Just round-robin the entries and wrap when we hit the end */
  87        if (unlikely(index == ncams - 1))
  88                __get_cpu_var(next_tlbcam_idx) = tlbcam_index;
  89        else
  90                __get_cpu_var(next_tlbcam_idx)++;
  91#endif
  92        mas1 = MAS1_VALID | MAS1_TID(mm->context.id) | MAS1_TSIZE(tsize);
  93        mas2 = ea & ~((1UL << shift) - 1);
  94        mas2 |= (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK;
  95        mas7_3 = (u64)pte_pfn(pte) << PAGE_SHIFT;
  96        mas7_3 |= (pte_val(pte) >> PTE_BAP_SHIFT) & MAS3_BAP_MASK;
  97        if (!pte_dirty(pte))
  98                mas7_3 &= ~(MAS3_SW|MAS3_UW);
  99
 100        mtspr(SPRN_MAS1, mas1);
 101        mtspr(SPRN_MAS2, mas2);
 102
 103        if (mmu_has_feature(MMU_FTR_USE_PAIRED_MAS)) {
 104                mtspr(SPRN_MAS7_MAS3, mas7_3);
 105        } else {
 106                mtspr(SPRN_MAS7, upper_32_bits(mas7_3));
 107                mtspr(SPRN_MAS3, lower_32_bits(mas7_3));
 108        }
 109
 110        asm volatile ("tlbwe");
 111
 112        local_irq_restore(flags);
 113}
 114
 115void flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 116{
 117        struct hstate *hstate = hstate_file(vma->vm_file);
 118        unsigned long tsize = huge_page_shift(hstate) - 10;
 119
 120        __flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr, tsize, 0);
 121
 122}
 123