sparc: tsb must be flushed before tlb
[pandora-kernel.git] / arch / sparc / mm / tlb.c
index d8f21e2..072f553 100644 (file)
 
 /* Heavily inspired by the ppc64 code.  */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
 
 void flush_tlb_pending(void)
 {
-       struct mmu_gather *mp = &get_cpu_var(mmu_gathers);
+       struct tlb_batch *tb = &get_cpu_var(tlb_batch);
+       struct mm_struct *mm = tb->mm;
 
-       if (mp->tlb_nr) {
-               flush_tsb_user(mp);
+       if (!tb->tlb_nr)
+               goto out;
 
-               if (CTX_VALID(mp->mm->context)) {
+       flush_tsb_user(tb);
+
+       if (CTX_VALID(mm->context)) {
+               if (tb->tlb_nr == 1) {
+                       global_flush_tlb_page(mm, tb->vaddrs[0]);
+               } else {
 #ifdef CONFIG_SMP
-                       smp_flush_tlb_pending(mp->mm, mp->tlb_nr,
-                                             &mp->vaddrs[0]);
+                       smp_flush_tlb_pending(tb->mm, tb->tlb_nr,
+                                             &tb->vaddrs[0]);
 #else
-                       __flush_tlb_pending(CTX_HWBITS(mp->mm->context),
-                                           mp->tlb_nr, &mp->vaddrs[0]);
+                       __flush_tlb_pending(CTX_HWBITS(tb->mm->context),
+                                           tb->tlb_nr, &tb->vaddrs[0]);
 #endif
                }
-               mp->tlb_nr = 0;
        }
 
-       put_cpu_var(mmu_gathers);
+       tb->tlb_nr = 0;
+
+out:
+       put_cpu_var(tlb_batch);
+}
+
+void arch_enter_lazy_mmu_mode(void)
+{
+       struct tlb_batch *tb = &__get_cpu_var(tlb_batch);
+
+       tb->active = 1;
 }
 
-void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig)
+void arch_leave_lazy_mmu_mode(void)
 {
-       struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
+       struct tlb_batch *tb = &__get_cpu_var(tlb_batch);
+
+       if (tb->tlb_nr)
+               flush_tlb_pending();
+       tb->active = 0;
+}
+
+void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+                  pte_t *ptep, pte_t orig, int fullmm)
+{
+       struct tlb_batch *tb = &get_cpu_var(tlb_batch);
        unsigned long nr;
 
        vaddr &= PAGE_MASK;
@@ -77,21 +102,32 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t
 
 no_cache_flush:
 
-       if (mp->fullmm)
+       if (fullmm) {
+               put_cpu_var(tlb_batch);
                return;
+       }
 
-       nr = mp->tlb_nr;
+       nr = tb->tlb_nr;
 
-       if (unlikely(nr != 0 && mm != mp->mm)) {
+       if (unlikely(nr != 0 && mm != tb->mm)) {
                flush_tlb_pending();
                nr = 0;
        }
 
+       if (!tb->active) {
+               flush_tsb_user_page(mm, vaddr);
+               global_flush_tlb_page(mm, vaddr);
+               goto out;
+       }
+
        if (nr == 0)
-               mp->mm = mm;
+               tb->mm = mm;
 
-       mp->vaddrs[nr] = vaddr;
-       mp->tlb_nr = ++nr;
+       tb->vaddrs[nr] = vaddr;
+       tb->tlb_nr = ++nr;
        if (nr >= TLB_BATCH_NR)
                flush_tlb_pending();
+
+out:
+       put_cpu_var(tlb_batch);
 }