Commit | Line | Data |
---|---|---|
41151e77 BB |
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 | ||
11 | static inline int mmu_get_tsize(int psize) | |
12 | { | |
13 | return mmu_psize_defs[psize].enc; | |
14 | } | |
15 | ||
16 | static 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 | ||
d93e4d7d BB |
40 | void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, |
41 | pte_t pte) | |
41151e77 BB |
42 | { |
43 | unsigned long mas1, mas2; | |
44 | u64 mas7_3; | |
45 | unsigned long psize, tsize, shift; | |
46 | unsigned long flags; | |
d93e4d7d | 47 | struct mm_struct *mm; |
41151e77 BB |
48 | |
49 | #ifdef CONFIG_PPC_FSL_BOOK3E | |
8c1674de | 50 | int index, ncams; |
41151e77 BB |
51 | #endif |
52 | ||
53 | if (unlikely(is_kernel_addr(ea))) | |
54 | return; | |
55 | ||
d93e4d7d BB |
56 | mm = vma->vm_mm; |
57 | ||
25c29f9e | 58 | #ifdef CONFIG_PPC_MM_SLICES |
8c1674de BB |
59 | psize = get_slice_psize(mm, ea); |
60 | tsize = mmu_get_tsize(psize); | |
41151e77 BB |
61 | shift = mmu_psize_defs[psize].shift; |
62 | #else | |
d93e4d7d | 63 | psize = vma_mmu_pagesize(vma); |
8c1674de BB |
64 | shift = __ilog2(psize); |
65 | tsize = shift - 10; | |
41151e77 BB |
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 | ||
115 | void 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 | } |