]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ARC: [ASID] get_new_mmu_context() refactoring
authorVineet Gupta <vgupta@synopsys.com>
Wed, 24 Jul 2013 20:53:45 +0000 (13:53 -0700)
committerVineet Gupta <vgupta@synopsys.com>
Tue, 30 Jul 2013 08:57:33 +0000 (01:57 -0700)
ASID allocation changes/1

This patch does 2 things:

(1) get_new_mmu_context() moves mm->ASID to a new value ONLY if it was
    from a prev allocation cycle/generation OR if mm had no ASID
    allocated (as opposed to before where it would unconditionally
    assign it a new ASID)

    Callers desiring unconditional update of ASID, e.g.local_flush_tlb_mm()
    (for parent's addess space invalidation at fork) need to first force
    the parent to an unallocated ASID.

(2) get_new_mmu_context() always sets the MMU PID reg with unchanged/new
    ASID value.

The gains are:
- consolidation of all asid alloc logic into get_new_mmu_context()
- avoiding code duplication in switch_mm() for PID reg setting
- Enables future change to fold activate_mm() into switch_mm()

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
arch/arc/include/asm/mmu_context.h
arch/arc/mm/tlb.c

index 0d71fb11b57c753c5b1cb4dd13bd7b731b196e18..2079c883c704b1a983e69b831ca8ab6768be880f 100644 (file)
@@ -69,8 +69,8 @@ extern struct mm_struct *asid_mm_map[NUM_ASID + 1];
 extern int asid_cache;
 
 /*
- * Assign a new ASID to task. If the task already has an ASID, it is
- * relinquished.
+ * Get a new ASID if task doesn't have a valid one (unalloc or from prev cycle)
+ * Also set the MMU PID register to existing/updated ASID
  */
 static inline void get_new_mmu_context(struct mm_struct *mm)
 {
@@ -79,6 +79,16 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
 
        local_irq_save(flags);
 
+       /*
+        * Move to new ASID if it was not from current alloc cycle/generation.
+        * Callers needing new ASID unconditionally, independent of alloc-cycle
+        * (local_flush_tlb_mm() for forking  parent) first need to destroy the
+        * context, setting it to invalid value, which the check below would
+        * catch too
+        */
+       if (mm->context.asid <= asid_cache)
+               goto set_hw;
+
        /*
         * Relinquish the currently owned ASID (if any).
         * Doing unconditionally saves a cmp-n-branch; for already unused
@@ -99,9 +109,9 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
         * task with ASID from prev allocation cycle (before ASID roll-over).
         *
         * This might look wrong - if we are re-using some other task's ASID,
-        * won't we use it's stale TLB entries too. Actually switch_mm( ) takes
+        * won't we use it's stale TLB entries too. Actually the algorithm takes
         * care of such a case: it ensures that task with ASID from prev alloc
-        * cycle, when scheduled will refresh it's ASID: see switch_mm( ) below
+        * cycle, when scheduled will refresh it's ASID
         * The stealing scenario described here will only happen if that task
         * didn't get a chance to refresh it's ASID - implying stale entries
         * won't exist.
@@ -122,7 +132,8 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
               (mm->context.tsk)->pid, mm->context.asid);
 #endif
 
-       write_aux_reg(ARC_REG_PID, asid_cache | MMU_ENABLE);
+set_hw:
+       write_aux_reg(ARC_REG_PID, mm->context.asid | MMU_ENABLE);
 
        local_irq_restore(flags);
 }
@@ -152,28 +163,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
 #endif
 
-       /*
-        * Get a new ASID if task doesn't have a valid one. Possible when
-        *  -task never had an ASID (fresh after fork)
-        *  -it's ASID was stolen - past an ASID roll-over.
-        *  -There's a third obscure scenario (if this task is running for the
-        *   first time afer an ASID rollover), where despite having a valid
-        *   ASID, we force a get for new ASID - see comments at top.
-        *
-        * Both the non-alloc scenario and first-use-after-rollover can be
-        * detected using the single condition below:  NO_ASID = 256
-        * while asid_cache is always a valid ASID value (0-255).
-        */
-       if (next->context.asid > asid_cache) {
-               get_new_mmu_context(next);
-       } else {
-               /*
-                * XXX: This will never happen given the chks above
-                * BUG_ON(next->context.asid > MAX_ASID);
-                */
-               write_aux_reg(ARC_REG_PID, next->context.asid | MMU_ENABLE);
-       }
-
+       get_new_mmu_context(next);
 }
 
 static inline void destroy_context(struct mm_struct *mm)
index 8f92665d083932542d923e2198bf46263dedbf75..53c4101dd35295daf596ae04144c735acc015321 100644 (file)
@@ -259,13 +259,14 @@ noinline void local_flush_tlb_mm(struct mm_struct *mm)
                return;
 
        /*
-        * Workaround for Android weirdism:
-        * A binder VMA could end up in a task such that vma->mm != tsk->mm
-        * old code would cause h/w - s/w ASID to get out of sync
+        * - Move to a new ASID, but only if the mm is still wired in
+        *   (Android Binders ended up calling this for vma->mm != tsk->mm,
+        *    causing h/w - s/w ASID to get out of sync)
+        * - Also get_new_mmu_context() new implementation allocates a new
+        *   ASID only if it is not allocated already - so unallocate first
         */
-       if (current->mm != mm)
-               destroy_context(mm);
-       else
+       destroy_context(mm);
+       if (current->mm == mm)
                get_new_mmu_context(mm);
 }