Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.10 122 lines 2.8 kB view raw
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}