diff options
| author | Russell King <rmk@flint.arm.linux.org.uk> | 2003-08-14 17:51:39 +0100 |
|---|---|---|
| committer | Russell King <rmk@flint.arm.linux.org.uk> | 2003-08-14 17:51:39 +0100 |
| commit | f1a3a362000963535d0be3d6fcac8f25c4569dcb (patch) | |
| tree | 2a3fc4ad028dd3732011a2e6de00fdd3d35ca02d | |
| parent | aa5f1ea77b7d635db0345ee068b68f595c265193 (diff) | |
[ARM] Add ARMv6 MMU context handling.
Add MMU context ID handling.
| -rw-r--r-- | arch/arm/mm/mmu.c | 46 | ||||
| -rw-r--r-- | include/asm-arm/mmu.h | 17 | ||||
| -rw-r--r-- | include/asm-arm/mmu_context.h | 40 |
3 files changed, 99 insertions, 4 deletions
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c new file mode 100644 index 000000000000..3fd17d897f57 --- /dev/null +++ b/arch/arm/mm/mmu.c @@ -0,0 +1,46 @@ +/* + * linux/arch/arm/mm/mmu.c + * + * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/mmu_context.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> + +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. + */ +void __init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + mm->context.id = 0; +} + +void __new_context(struct mm_struct *mm) +{ + unsigned int asid; + + asid = ++cpu_last_asid; + if (asid == 0) + asid = cpu_last_asid = 1 << ASID_BITS; + + /* + * If we've used up all our ASIDs, we need + * to start a new version and flush the TLB. + */ + if ((asid & ~ASID_MASK) == 0) + flush_tlb_all(); + + mm->context.id = asid; +} diff --git a/include/asm-arm/mmu.h b/include/asm-arm/mmu.h index 9b8d3d781a1e..c33797d6cc7b 100644 --- a/include/asm-arm/mmu.h +++ b/include/asm-arm/mmu.h @@ -1,9 +1,18 @@ #ifndef __ARM_MMU_H #define __ARM_MMU_H -/* - * The ARM doesn't have a mmu context - */ -typedef struct { } mm_context_t; +#include <linux/config.h> + +typedef struct { +#if __LINUX_ARM_ARCH__ >= 6 + unsigned int id; +#endif +} mm_context_t; + +#if __LINUX_ARM_ARCH__ >= 6 +#define ASID(mm) ((mm)->context.id & 255) +#else +#define ASID(mm) (0) +#endif #endif diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h index e0340f5fbf32..a4cb79241a73 100644 --- a/include/asm-arm/mmu_context.h +++ b/include/asm-arm/mmu_context.h @@ -15,7 +15,45 @@ #include <asm/proc-fns.h> +#if __LINUX_ARM_ARCH__ >= 6 + +/* + * On ARMv6, we have the following structure in the Context ID: + * + * 31 7 0 + * +-------------------------+-----------+ + * | process ID | ASID | + * +-------------------------+-----------+ + * | context ID | + * +-------------------------------------+ + * + * The ASID is used to tag entries in the CPU caches and TLBs. + * The context ID is used by debuggers and trace logic, and + * should be unique within all running processes. + */ +#define ASID_BITS 8 +#define ASID_MASK ((~0) << ASID_BITS) + +extern unsigned int cpu_last_asid; + +void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); +void __new_context(struct mm_struct *mm); + +static inline void check_context(struct mm_struct *mm) +{ + if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) + __new_context(mm); +} + +#define init_new_context(tsk,mm) (__init_new_context(tsk,mm),0) + +#else + +#define check_context(mm) do { } while (0) #define init_new_context(tsk,mm) 0 + +#endif + #define destroy_context(mm) do { } while(0) /* @@ -43,6 +81,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { if (prev != next) { + check_context(next); cpu_switch_mm(next->pgd, next); } } @@ -51,6 +90,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) { + check_context(next); cpu_switch_mm(next->pgd, next); } |
