/* $Id: mmu_context.h,v 1.2 1998/05/07 03:02:50 ralf Exp $ * * Switch a MMU context. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1996, 1997, 1998 by Ralf Baechle */ #ifndef __ASM_MIPS_MMU_CONTEXT_H #define __ASM_MIPS_MMU_CONTEXT_H /* Fuck. The f-word is here so you can grep for it :-) */ extern unsigned long asid_cache; /* I patch, therefore I am ... */ #define ASID_INC(asid) \ ({ unsigned long __asid = asid; \ __asm__("1:\taddiu\t%0,0\t\t\t\t# patched\n\t" \ ".section\t__asid_inc,\"a\"\n\t" \ ".word\t1b\n\t" \ ".previous" \ :"=r" (__asid) \ :"0" (__asid)); \ __asid; }) #define ASID_MASK(asid) \ ({ unsigned long __asid = asid; \ __asm__("1:\tandi\t%0,%1,0\t\t\t# patched\n\t" \ ".section\t__asid_mask,\"a\"\n\t" \ ".word\t1b\n\t" \ ".previous" \ :"=r" (__asid) \ :"r" (__asid)); \ __asid; }) #define ASID_VERSION_MASK \ ({ unsigned long __asid; \ __asm__("1:\tli\t%0,0\t\t\t\t# patched\n\t" \ ".section\t__asid_version_mask,\"a\"\n\t" \ ".word\t1b\n\t" \ ".previous" \ :"=r" (__asid)); \ __asid; }) #define ASID_FIRST_VERSION \ ({ unsigned long __asid = asid; \ __asm__("1:\tli\t%0,0\t\t\t\t# patched\n\t" \ ".section\t__asid_first_version,\"a\"\n\t" \ ".word\t1b\n\t" \ ".previous" \ :"=r" (__asid)); \ __asid; }) #define ASID_FIRST_VERSION_R3000 0x1000 #define ASID_FIRST_VERSION_R4000 0x100 extern inline void get_new_mmu_context(struct mm_struct *mm, unsigned long asid) { if (!ASID_MASK((asid = ASID_INC(asid)))) { flush_tlb_all(); /* start new asid cycle */ if (!asid) /* fix version if needed */ asid = ASID_FIRST_VERSION; } mm->context = asid_cache = asid; } extern inline void get_mmu_context(struct task_struct *p) { struct mm_struct *mm = p->mm; if (mm) { unsigned long asid = asid_cache; /* Check if our ASID is of an older version and thus invalid */ if ((mm->context ^ asid) & ASID_VERSION_MASK) get_new_mmu_context(mm, asid); } } /* * Initialize the context related info for a new mm_struct * instance. */ extern inline void init_new_context(struct mm_struct *mm) { mm->context = 0; } /* * Destroy context related info for an mm_struct that is about * to be put to rest. */ extern inline void destroy_context(struct mm_struct *mm) { mm->context = 0; } /* * After we have set current->mm to a new value, this activates * the context for the new mm so we see the new mappings. */ extern inline void activate_context(struct task_struct *tsk) { get_mmu_context(tsk); set_entryhi(tsk->mm->context); } extern void __asid_setup(unsigned int inc, unsigned int mask, unsigned int version_mask, unsigned int first_version); extern inline void r3000_asid_setup(void) { __asid_setup(0x40, 0xfc0, 0xf000, ASID_FIRST_VERSION_R3000); } extern inline void r6000_asid_setup(void) { panic("r6000_asid_setup: implement me"); /* No idea ... */ } extern inline void tfp_asid_setup(void) { panic("tfp_asid_setup: implement me"); /* No idea ... */ } extern inline void r4xx0_asid_setup(void) { __asid_setup(1, 0xff, 0xff00, ASID_FIRST_VERSION_R4000); } /* R10000 has the same ASID mechanism as the R4000. */ #define andes_asid_setup r4xx0_asid_setup #endif /* __ASM_MIPS_MMU_CONTEXT_H */