/*1* MMU context handling.2*3* Copyright (C) 2011 Tobias Klauser <[email protected]>4* Copyright (C) 2009 Wind River Systems Inc5* Implemented by [email protected] and [email protected]6*7* This file is subject to the terms and conditions of the GNU General Public8* License. See the file "COPYING" in the main directory of this archive9* for more details.10*/1112#include <linux/mm.h>1314#include <asm/cpuinfo.h>15#include <asm/mmu_context.h>16#include <asm/tlb.h>1718/* The pids position and mask in context */19#define PID_SHIFT 020#define PID_BITS (cpuinfo.tlb_pid_num_bits)21#define PID_MASK ((1UL << PID_BITS) - 1)2223/* The versions position and mask in context */24#define VERSION_BITS (32 - PID_BITS)25#define VERSION_SHIFT (PID_SHIFT + PID_BITS)26#define VERSION_MASK ((1UL << VERSION_BITS) - 1)2728/* Return the version part of a context */29#define CTX_VERSION(c) (((c) >> VERSION_SHIFT) & VERSION_MASK)3031/* Return the pid part of a context */32#define CTX_PID(c) (((c) >> PID_SHIFT) & PID_MASK)3334/* Value of the first context (version 1, pid 0) */35#define FIRST_CTX ((1UL << VERSION_SHIFT) | (0 << PID_SHIFT))3637static mm_context_t next_mmu_context;3839/*40* Initialize MMU context management stuff.41*/42void __init mmu_context_init(void)43{44/* We need to set this here because the value depends on runtime data45* from cpuinfo */46next_mmu_context = FIRST_CTX;47}4849/*50* Set new context (pid), keep way51*/52static void set_context(mm_context_t context)53{54set_mmu_pid(CTX_PID(context));55}5657static mm_context_t get_new_context(void)58{59/* Return the next pid */60next_mmu_context += (1UL << PID_SHIFT);6162/* If the pid field wraps around we increase the version and63* flush the tlb */64if (unlikely(CTX_PID(next_mmu_context) == 0)) {65/* Version is incremented since the pid increment above66* overflows info version */67flush_cache_all();68flush_tlb_all();69}7071/* If the version wraps we start over with the first generation, we do72* not need to flush the tlb here since it's always done above */73if (unlikely(CTX_VERSION(next_mmu_context) == 0))74next_mmu_context = FIRST_CTX;7576return next_mmu_context;77}7879void switch_mm(struct mm_struct *prev, struct mm_struct *next,80struct task_struct *tsk)81{82unsigned long flags;8384local_irq_save(flags);8586/* If the process context we are swapping in has a different context87* generation then we have it should get a new generation/pid */88if (unlikely(CTX_VERSION(next->context) !=89CTX_VERSION(next_mmu_context)))90next->context = get_new_context();9192/* Save the current pgd so the fast tlb handler can find it */93pgd_current = next->pgd;9495/* Set the current context */96set_context(next->context);9798local_irq_restore(flags);99}100101/*102* After we have set current->mm to a new value, this activates103* the context for the new mm so we see the new mappings.104*/105void activate_mm(struct mm_struct *prev, struct mm_struct *next)106{107next->context = get_new_context();108set_context(next->context);109pgd_current = next->pgd;110}111112unsigned long get_pid_from_context(mm_context_t *context)113{114return CTX_PID((*context));115}116117118