1fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 2fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> 3fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Copyright (C) 2008-2009 PetaLogix 4fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Copyright (C) 2006 Atmark Techno, Inc. 5fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * 6fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * This file is subject to the terms and conditions of the GNU General Public 7fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * License. See the file "COPYING" in the main directory of this archive 8fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * for more details. 9fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 10fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 11fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek#ifndef _ASM_MICROBLAZE_MMU_CONTEXT_H 12fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek#define _ASM_MICROBLAZE_MMU_CONTEXT_H 13fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 1460063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h> 15fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek#include <asm/bitops.h> 16fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek#include <asm/mmu.h> 17fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek#include <asm-generic/mm_hooks.h> 18fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 19fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek# ifdef __KERNEL__ 20fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 21fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * This function defines the mapping from contexts to VSIDs (virtual 22fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * segment IDs). We use a skew on both the context and the high 4 bits 23fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * of the 32-bit virtual address (the "effective segment ID") in order 24fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * to spread out the entries in the MMU hash table. 25fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 26fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek# define CTX_TO_VSID(ctx, va) (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \ 27fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek & 0xffffff) 28fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 29fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 30fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek MicroBlaze has 256 contexts, so we can just rotate through these 31fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek as a way of "switching" contexts. If the TID of the TLB is zero, 32fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek the PID/TID comparison is disabled, so we can use a TID of zero 33fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek to represent all kernel pages as shared among all contexts. 34fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 35fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 36fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekstatic inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) 37fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek{ 38fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek} 39fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 40fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek# define NO_CONTEXT 256 41fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek# define LAST_CONTEXT 255 42fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek# define FIRST_CONTEXT 1 43fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 44fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 45fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Set the current MMU context. 46fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * This is done byloading up the segment registers for the user part of the 47fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * address space. 48fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * 49fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Since the PGD is immediately available, it is much faster to simply 50fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * pass this along as a second parameter, which is required for 8xx and 51fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * can be used for debugging on all processors (if you happen to have 52fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * an Abatron). 53fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 54fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekextern void set_context(mm_context_t context, pgd_t *pgd); 55fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 56fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 57fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Bitmap of contexts in use. 58fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * The size of this bitmap is LAST_CONTEXT + 1 bits. 59fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 60fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekextern unsigned long context_map[]; 61fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 62fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 63fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * This caches the next context number that we expect to be free. 64fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Its use is an optimization only, we can't rely on this context 65fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * number to be free, but it usually will be. 66fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 67fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekextern mm_context_t next_mmu_context; 68fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 69fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 70fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Since we don't have sufficient contexts to give one to every task 71fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * that could be in the system, we need to be able to steal contexts. 72fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * These variables support that. 73fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 74fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekextern atomic_t nr_free_contexts; 75fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekextern struct mm_struct *context_mm[LAST_CONTEXT+1]; 76fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekextern void steal_context(void); 77fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 78fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 79fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Get a new mmu context for the address space described by `mm'. 80fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 81fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekstatic inline void get_mmu_context(struct mm_struct *mm) 82fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek{ 83fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek mm_context_t ctx; 84fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 85fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek if (mm->context != NO_CONTEXT) 86fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek return; 87fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek while (atomic_dec_if_positive(&nr_free_contexts) < 0) 88fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek steal_context(); 89fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek ctx = next_mmu_context; 90fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek while (test_and_set_bit(ctx, context_map)) { 91fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); 92fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek if (ctx > LAST_CONTEXT) 93fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek ctx = 0; 94fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek } 95fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek next_mmu_context = (ctx + 1) & LAST_CONTEXT; 96fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek mm->context = ctx; 97fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek context_mm[ctx] = mm; 98fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek} 99fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 100fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 101fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * Set up the context for a new address space. 102fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 103fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek# define init_new_context(tsk, mm) (((mm)->context = NO_CONTEXT), 0) 104fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 105fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 106fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * We're finished using the context for an address space. 107fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 108fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekstatic inline void destroy_context(struct mm_struct *mm) 109fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek{ 110fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek if (mm->context != NO_CONTEXT) { 111fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek clear_bit(mm->context, context_map); 112fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek mm->context = NO_CONTEXT; 113fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek atomic_inc(&nr_free_contexts); 114fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek } 115fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek} 116fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 117fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekstatic inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 118fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek struct task_struct *tsk) 119fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek{ 120fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek tsk->thread.pgdir = next->pgd; 121fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek get_mmu_context(next); 122fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek set_context(next->context, next->pgd); 123fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek} 124fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 125fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek/* 126fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * After we have set current->mm to a new value, this activates 127fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek * the context for the new mm so we see the new mappings. 128fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek */ 129fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekstatic inline void activate_mm(struct mm_struct *active_mm, 130fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek struct mm_struct *mm) 131fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek{ 132fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek current->thread.pgdir = mm->pgd; 133fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek get_mmu_context(mm); 134fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek set_context(mm->context, mm->pgd); 135fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek} 136fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 137fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simekextern void mmu_context_init(void); 138fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek 139fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek# endif /* __KERNEL__ */ 140fc34d1eb1ca09d3450508e2cf9cf511364c2c460Michal Simek#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */ 141