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