summaryrefslogtreecommitdiff
path: root/arch/arm/mm
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2007-02-05 14:47:40 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-02-08 14:49:24 +0000
commit9d99df4b10eef130dacb5f772cd589c625b03634 (patch)
treebf1cea618ef9380cdce9cfea8897da9fb961787b /arch/arm/mm
parent620879c9e33262426db0ade650be5d7a2046377b (diff)
[ARM] 4128/1: Architecture compliant TTBR changing sequence
On newer architectures (ARMv6, ARMv7), the depth of the prefetch and branch prediction is implementation defined and there is a small risk of wrong ASID tagging when changing TTBR0 before setting the new context id. The recommended solution is to set a reserved ASID during TTBR changing. This patch reserves ASID 0. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/context.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 79e800202424..9da43a0fdcdf 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -19,7 +19,8 @@ unsigned int cpu_last_asid = { 1 << ASID_BITS };
/*
* We fork()ed a process, and we need a new context for the child
* to run in. We reserve version 0 for initial tasks so we will
- * always allocate an ASID.
+ * always allocate an ASID. The ASID 0 is reserved for the TTBR
+ * register changing sequence.
*/
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
@@ -38,8 +39,15 @@ void __new_context(struct mm_struct *mm)
* If we've used up all our ASIDs, we need
* to start a new version and flush the TLB.
*/
- if ((asid & ~ASID_MASK) == 0)
+ if ((asid & ~ASID_MASK) == 0) {
+ asid = ++cpu_last_asid;
+ /* set the reserved ASID before flushing the TLB */
+ asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n"
+ :
+ : "r" (0));
+ isb();
flush_tlb_all();
+ }
mm->context.id = asid;
}