Commit f1a3a362 authored by Russell King's avatar Russell King

[ARM] Add ARMv6 MMU context handling.

Add MMU context ID handling.
parent aa5f1ea7
/*
* 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;
}
#ifndef __ARM_MMU_H #ifndef __ARM_MMU_H
#define __ARM_MMU_H #define __ARM_MMU_H
/* #include <linux/config.h>
* The ARM doesn't have a mmu context
*/ typedef struct {
typedef struct { } mm_context_t; #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 #endif
...@@ -15,7 +15,45 @@ ...@@ -15,7 +15,45 @@
#include <asm/proc-fns.h> #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 #define init_new_context(tsk,mm) 0
#endif
#define destroy_context(mm) do { } while(0) #define destroy_context(mm) do { } while(0)
/* /*
...@@ -43,6 +81,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -43,6 +81,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk) struct task_struct *tsk)
{ {
if (prev != next) { if (prev != next) {
check_context(next);
cpu_switch_mm(next->pgd, next); cpu_switch_mm(next->pgd, next);
} }
} }
...@@ -51,6 +90,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *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) static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
{ {
check_context(next);
cpu_switch_mm(next->pgd, next); cpu_switch_mm(next->pgd, next);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment