diff options
Diffstat (limited to 'arch/sparc/mm/tlb.c')
-rw-r--r-- | arch/sparc/mm/tlb.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index 9df2190c097e..f81cd9736700 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c | |||
@@ -67,7 +67,7 @@ void arch_leave_lazy_mmu_mode(void) | |||
67 | } | 67 | } |
68 | 68 | ||
69 | static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, | 69 | static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, |
70 | bool exec) | 70 | bool exec, bool huge) |
71 | { | 71 | { |
72 | struct tlb_batch *tb = &get_cpu_var(tlb_batch); | 72 | struct tlb_batch *tb = &get_cpu_var(tlb_batch); |
73 | unsigned long nr; | 73 | unsigned long nr; |
@@ -84,13 +84,21 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, | |||
84 | } | 84 | } |
85 | 85 | ||
86 | if (!tb->active) { | 86 | if (!tb->active) { |
87 | flush_tsb_user_page(mm, vaddr); | 87 | flush_tsb_user_page(mm, vaddr, huge); |
88 | global_flush_tlb_page(mm, vaddr); | 88 | global_flush_tlb_page(mm, vaddr); |
89 | goto out; | 89 | goto out; |
90 | } | 90 | } |
91 | 91 | ||
92 | if (nr == 0) | 92 | if (nr == 0) { |
93 | tb->mm = mm; | 93 | tb->mm = mm; |
94 | tb->huge = huge; | ||
95 | } | ||
96 | |||
97 | if (tb->huge != huge) { | ||
98 | flush_tlb_pending(); | ||
99 | tb->huge = huge; | ||
100 | nr = 0; | ||
101 | } | ||
94 | 102 | ||
95 | tb->vaddrs[nr] = vaddr; | 103 | tb->vaddrs[nr] = vaddr; |
96 | tb->tlb_nr = ++nr; | 104 | tb->tlb_nr = ++nr; |
@@ -104,6 +112,8 @@ out: | |||
104 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | 112 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, |
105 | pte_t *ptep, pte_t orig, int fullmm) | 113 | pte_t *ptep, pte_t orig, int fullmm) |
106 | { | 114 | { |
115 | bool huge = is_hugetlb_pte(orig); | ||
116 | |||
107 | if (tlb_type != hypervisor && | 117 | if (tlb_type != hypervisor && |
108 | pte_dirty(orig)) { | 118 | pte_dirty(orig)) { |
109 | unsigned long paddr, pfn = pte_pfn(orig); | 119 | unsigned long paddr, pfn = pte_pfn(orig); |
@@ -129,7 +139,7 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | |||
129 | 139 | ||
130 | no_cache_flush: | 140 | no_cache_flush: |
131 | if (!fullmm) | 141 | if (!fullmm) |
132 | tlb_batch_add_one(mm, vaddr, pte_exec(orig)); | 142 | tlb_batch_add_one(mm, vaddr, pte_exec(orig), huge); |
133 | } | 143 | } |
134 | 144 | ||
135 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 145 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
@@ -145,7 +155,7 @@ static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr, | |||
145 | if (pte_val(*pte) & _PAGE_VALID) { | 155 | if (pte_val(*pte) & _PAGE_VALID) { |
146 | bool exec = pte_exec(*pte); | 156 | bool exec = pte_exec(*pte); |
147 | 157 | ||
148 | tlb_batch_add_one(mm, vaddr, exec); | 158 | tlb_batch_add_one(mm, vaddr, exec, false); |
149 | } | 159 | } |
150 | pte++; | 160 | pte++; |
151 | vaddr += PAGE_SIZE; | 161 | vaddr += PAGE_SIZE; |
@@ -185,8 +195,9 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, | |||
185 | pte_t orig_pte = __pte(pmd_val(orig)); | 195 | pte_t orig_pte = __pte(pmd_val(orig)); |
186 | bool exec = pte_exec(orig_pte); | 196 | bool exec = pte_exec(orig_pte); |
187 | 197 | ||
188 | tlb_batch_add_one(mm, addr, exec); | 198 | tlb_batch_add_one(mm, addr, exec, true); |
189 | tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec); | 199 | tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec, |
200 | true); | ||
190 | } else { | 201 | } else { |
191 | tlb_batch_pmd_scan(mm, addr, orig); | 202 | tlb_batch_pmd_scan(mm, addr, orig); |
192 | } | 203 | } |