patch-2.3.13 linux/include/asm-sparc64/mmu_context.h
Next file: linux/include/asm-sparc64/page.h
Previous file: linux/include/asm-sparc64/init.h
Back to the patch index
Back to the overall index
- Lines: 240
- Date:
Mon Aug 2 22:07:16 1999
- Orig file:
v2.3.12/linux/include/asm-sparc64/mmu_context.h
- Orig date:
Thu May 27 09:55:22 1999
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.36 1999/05/25 16:53:34 jj Exp $ */
+/* $Id: mmu_context.h,v 1.39 1999/08/02 08:39:57 davem Exp $ */
#ifndef __SPARC64_MMU_CONTEXT_H
#define __SPARC64_MMU_CONTEXT_H
@@ -8,122 +8,140 @@
#include <asm/spitfire.h>
#include <asm/spinlock.h>
-#define NO_CONTEXT 0
-
#ifndef __ASSEMBLY__
+extern spinlock_t ctx_alloc_lock;
extern unsigned long tlb_context_cache;
extern unsigned long mmu_context_bmap[];
#define CTX_VERSION_SHIFT (PAGE_SHIFT - 3)
#define CTX_VERSION_MASK ((~0UL) << CTX_VERSION_SHIFT)
#define CTX_FIRST_VERSION ((1UL << CTX_VERSION_SHIFT) + 1UL)
+#define CTX_VALID(__ctx) \
+ (!(((__ctx) ^ tlb_context_cache) & CTX_VERSION_MASK))
+#define CTX_HWBITS(__ctx) ((__ctx) & ~CTX_VERSION_MASK)
extern void get_new_mmu_context(struct mm_struct *mm);
-/* Initialize/destroy the context related info for a new mm_struct
- * instance.
+/* Initialize a new mmu context. This is invoked when a new
+ * address space instance (unique or shared) is instantiated.
+ * A fresh mm_struct is cleared out to zeros, so this need not
+ * do anything on Sparc64 since the only thing we care about
+ * is that mm->context is an invalid context (ie. zero).
*/
-#define init_new_context(__mm) ((__mm)->context = NO_CONTEXT)
+#define init_new_context(__tsk, __mm) do { } while(0)
-/* Kernel threads like rpciod and nfsd drop their mm, and then use
- * init_mm, when this happens we must make sure the secondary context is
- * updated as well. Otherwise we have disasters relating to
- * set_fs/get_fs usage later on.
- *
- * Also we can only clear the mmu_context_bmap bit when this is
- * the final reference to the address space.
+/* Destroy a dead context. This occurs when mmput drops the
+ * mm_users count to zero, the mmaps have been released, and
+ * all the page tables have been flushed. Our job is to destroy
+ * any remaining processor-specific state, and in the sparc64
+ * case this just means freeing up the mmu context ID held by
+ * this task if valid.
*/
-#define destroy_context(__mm) do { \
- if ((__mm)->context != NO_CONTEXT && \
- atomic_read(&(__mm)->count) == 1) { \
- if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
- clear_bit((__mm)->context & ~(CTX_VERSION_MASK), \
- mmu_context_bmap); \
- (__mm)->context = NO_CONTEXT; \
- if(current->mm == (__mm)) { \
- current->tss.ctx = 0; \
- spitfire_set_secondary_context(0); \
- __asm__ __volatile__("flush %g6"); \
- } \
- } \
-} while (0)
+#define destroy_context(__mm) \
+do { spin_lock(&ctx_alloc_lock); \
+ if (CTX_VALID((__mm)->context)) { \
+ unsigned long nr = CTX_HWBITS((__mm)->context); \
+ mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63)); \
+ } \
+ spin_unlock(&ctx_alloc_lock); \
+} while(0)
+
+/* Reload the two core values used by TLB miss handler
+ * processing on sparc64. They are:
+ * 1) The physical address of mm->pgd, when full page
+ * table walks are necessary, this is where the
+ * search begins.
+ * 2) A "PGD cache". For 32-bit tasks only pgd[0] is
+ * ever used since that maps the entire low 4GB
+ * completely. To speed up TLB miss processing we
+ * make this value available to the handlers. This
+ * decreases the amount of memory traffic incurred.
+ */
+#define reload_tlbmiss_state(__tsk, __mm) \
+do { \
+ register unsigned long paddr asm("o5"); \
+ register unsigned long pgd_cache asm("o4"); \
+ paddr = __pa((__mm)->pgd); \
+ pgd_cache = 0UL; \
+ if ((__tsk)->thread.flags & SPARC_FLAG_32BIT) \
+ pgd_cache = pgd_val((__mm)->pgd[0]) << 11UL; \
+ __asm__ __volatile__("wrpr %%g0, 0x494, %%pstate\n\t" \
+ "mov %3, %%g4\n\t" \
+ "mov %0, %%g7\n\t" \
+ "stxa %1, [%%g4] %2\n\t" \
+ "wrpr %%g0, 0x096, %%pstate" \
+ : /* no outputs */ \
+ : "r" (paddr), "r" (pgd_cache),\
+ "i" (ASI_DMMU), "i" (TSB_REG)); \
+} while(0)
-/* The caller must flush the current set of user windows
- * to the stack (if necessary) before we get here.
+/* Set MMU context in the actual hardware. */
+#define load_secondary_context(__mm) \
+ __asm__ __volatile__("stxa %0, [%1] %2\n\t" \
+ "flush %%g6" \
+ : /* No outputs */ \
+ : "r" (CTX_HWBITS((__mm)->context)), \
+ "r" (0x10), "i" (0x58))
+
+/* Clean out potential stale TLB entries due to previous
+ * users of this TLB context. We flush TLB contexts
+ * lazily on sparc64.
*/
-extern __inline__ void __get_mmu_context(struct task_struct *tsk)
+#define clean_secondary_context() \
+ __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" \
+ "stxa %%g0, [%0] %2\n\t" \
+ "flush %%g6" \
+ : /* No outputs */ \
+ : "r" (0x50), "i" (0x5f), "i" (0x57))
+
+/* Switch the current MM context. */
+static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
{
- register unsigned long paddr asm("o5");
- register unsigned long pgd_cache asm("o4");
- struct mm_struct *mm = tsk->mm;
- unsigned long asi;
-
- if(!(tsk->tss.flags & SPARC_FLAG_KTHREAD) &&
- !(tsk->flags & PF_EXITING)) {
- unsigned long ctx = tlb_context_cache;
- if((mm->context ^ ctx) & CTX_VERSION_MASK)
+ long dirty;
+
+ spin_lock(&mm->page_table_lock);
+ if (CTX_VALID(mm->context))
+ dirty = 0;
+ else
+ dirty = 1;
+ if (dirty || (old_mm != mm)) {
+ unsigned long vm_mask;
+
+ if (dirty)
get_new_mmu_context(mm);
- tsk->tss.ctx = mm->context & 0x3ff;
- spitfire_set_secondary_context(mm->context & 0x3ff);
- __asm__ __volatile__("flush %g6");
- if(!(mm->cpu_vm_mask & (1UL<<smp_processor_id()))) {
- spitfire_flush_dtlb_secondary_context();
- spitfire_flush_itlb_secondary_context();
- __asm__ __volatile__("flush %g6");
+
+ vm_mask = (1UL << cpu);
+ if (!(mm->cpu_vm_mask & vm_mask)) {
+ mm->cpu_vm_mask |= vm_mask;
+ dirty = 1;
}
- asi = tsk->tss.current_ds.seg;
- } else {
- tsk->tss.ctx = 0;
- spitfire_set_secondary_context(0);
- __asm__ __volatile__("flush %g6");
- asi = ASI_P;
+
+ load_secondary_context(mm);
+ if (dirty != 0)
+ clean_secondary_context();
+ reload_tlbmiss_state(tsk, mm);
}
- /* Sigh, damned include loops... just poke seg directly. */
- __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" (asi));
- paddr = __pa(mm->pgd);
- if((tsk->tss.flags & (SPARC_FLAG_32BIT|SPARC_FLAG_KTHREAD)) ==
- (SPARC_FLAG_32BIT))
- pgd_cache = ((unsigned long) mm->pgd[0]) << 11UL;
- else
- pgd_cache = 0;
- __asm__ __volatile__("
- rdpr %%pstate, %%o2
- andn %%o2, %2, %%o3
- wrpr %%o3, %5, %%pstate
- mov %4, %%g4
- mov %0, %%g7
- stxa %1, [%%g4] %3
- wrpr %%o2, 0x0, %%pstate
- " : /* no outputs */
- : "r" (paddr), "r" (pgd_cache), "i" (PSTATE_IE),
- "i" (ASI_DMMU), "i" (TSB_REG), "i" (PSTATE_MG)
- : "o2", "o3");
+ spin_unlock(&mm->page_table_lock);
}
-/* Now we define this as a do nothing macro, because the only
- * generic user right now is the scheduler, and we handle all
- * the atomicity issues by having switch_to() call the above
- * function itself.
- */
-#define get_mmu_context(x) do { } while(0)
+/* Activate a new MM instance for the current task. */
+static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
+{
+ unsigned long vm_mask;
-/*
- * After we have set current->mm to a new value, this activates
- * the context for the new mm so we see the new mappings. Currently,
- * this is always called for 'current', if that changes put appropriate
- * checks here.
- *
- * We set the cpu_vm_mask first to zero to enforce a tlb flush for
- * the new context above, then we set it to the current cpu so the
- * smp tlb flush routines do not get confused.
- */
-#define activate_context(__tsk) \
-do { flushw_user(); \
- (__tsk)->mm->cpu_vm_mask = 0; \
- __get_mmu_context(__tsk); \
- (__tsk)->mm->cpu_vm_mask = (1UL<<smp_processor_id()); \
-} while(0)
+ spin_lock(&mm->page_table_lock);
+ if (!CTX_VALID(mm->context))
+ get_new_mmu_context(mm);
+ vm_mask = (1UL << smp_processor_id());
+ if (!(mm->cpu_vm_mask & vm_mask))
+ mm->cpu_vm_mask |= vm_mask;
+ spin_unlock(&mm->page_table_lock);
+
+ load_secondary_context(mm);
+ clean_secondary_context();
+ reload_tlbmiss_state(current, mm);
+}
#endif /* !(__ASSEMBLY__) */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)