Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * MMU context handling.
  3 *
  4 * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
  5 * Copyright (C) 2009 Wind River Systems Inc
  6 *   Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
  7 *
  8 * This file is subject to the terms and conditions of the GNU General Public
  9 * License.  See the file "COPYING" in the main directory of this archive
 10 * for more details.
 11 */
 12
 13#include <linux/mm.h>
 14
 15#include <asm/cpuinfo.h>
 16#include <asm/mmu_context.h>
 17#include <asm/tlb.h>
 18
 19/* The pids position and mask in context */
 20#define PID_SHIFT	0
 21#define PID_BITS	(cpuinfo.tlb_pid_num_bits)
 22#define PID_MASK	((1UL << PID_BITS) - 1)
 23
 24/* The versions position and mask in context */
 25#define VERSION_BITS	(32 - PID_BITS)
 26#define VERSION_SHIFT	(PID_SHIFT + PID_BITS)
 27#define VERSION_MASK	((1UL << VERSION_BITS) - 1)
 28
 29/* Return the version part of a context */
 30#define CTX_VERSION(c)	(((c) >> VERSION_SHIFT) & VERSION_MASK)
 31
 32/* Return the pid part of a context */
 33#define CTX_PID(c)	(((c) >> PID_SHIFT) & PID_MASK)
 34
 35/* Value of the first context (version 1, pid 0) */
 36#define FIRST_CTX	((1UL << VERSION_SHIFT) | (0 << PID_SHIFT))
 37
 38static mm_context_t next_mmu_context;
 39
 40/*
 41 * Initialize MMU context management stuff.
 42 */
 43void __init mmu_context_init(void)
 44{
 45	/* We need to set this here because the value depends on runtime data
 46	 * from cpuinfo */
 47	next_mmu_context = FIRST_CTX;
 48}
 49
 50/*
 51 * Set new context (pid), keep way
 52 */
 53static void set_context(mm_context_t context)
 54{
 55	set_mmu_pid(CTX_PID(context));
 56}
 57
 58static mm_context_t get_new_context(void)
 59{
 60	/* Return the next pid */
 61	next_mmu_context += (1UL << PID_SHIFT);
 62
 63	/* If the pid field wraps around we increase the version and
 64	 * flush the tlb */
 65	if (unlikely(CTX_PID(next_mmu_context) == 0)) {
 66		/* Version is incremented since the pid increment above
 67		 * overflows info version */
 68		flush_cache_all();
 69		flush_tlb_all();
 70	}
 71
 72	/* If the version wraps we start over with the first generation, we do
 73	 * not need to flush the tlb here since it's always done above */
 74	if (unlikely(CTX_VERSION(next_mmu_context) == 0))
 75		next_mmu_context = FIRST_CTX;
 76
 77	return next_mmu_context;
 78}
 79
 80void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 81	       struct task_struct *tsk)
 82{
 83	unsigned long flags;
 84
 85	local_irq_save(flags);
 86
 87	/* If the process context we are swapping in has a different context
 88	 * generation then we have it should get a new generation/pid */
 89	if (unlikely(CTX_VERSION(next->context) !=
 90		CTX_VERSION(next_mmu_context)))
 91		next->context = get_new_context();
 92
 93	/* Save the current pgd so the fast tlb handler can find it */
 94	pgd_current = next->pgd;
 95
 96	/* Set the current context */
 97	set_context(next->context);
 98
 99	local_irq_restore(flags);
100}
101
102/*
103 * After we have set current->mm to a new value, this activates
104 * the context for the new mm so we see the new mappings.
105 */
106void activate_mm(struct mm_struct *prev, struct mm_struct *next)
107{
108	next->context = get_new_context();
109	set_context(next->context);
110	pgd_current = next->pgd;
111}
112
113unsigned long get_pid_from_context(mm_context_t *context)
114{
115	return CTX_PID((*context));
116}