Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nios2: Process management

This patch adds support for thread creation and context switching.

Signed-off-by: Ley Foon Tan <lftan@altera.com>

+694
+66
arch/nios2/include/asm/mmu_context.h
··· 1 + /* 2 + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 3 + * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle 4 + * Copyright (C) 1999 Silicon Graphics, Inc. 5 + * 6 + * based on MIPS asm/mmu_context.h 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 + #ifndef _ASM_NIOS2_MMU_CONTEXT_H 14 + #define _ASM_NIOS2_MMU_CONTEXT_H 15 + 16 + #include <asm-generic/mm_hooks.h> 17 + 18 + extern void mmu_context_init(void); 19 + extern unsigned long get_pid_from_context(mm_context_t *ctx); 20 + 21 + /* 22 + * For the fast tlb miss handlers, we keep a pointer to the current pgd. 23 + * processor. 24 + */ 25 + extern pgd_t *pgd_current; 26 + 27 + static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) 28 + { 29 + } 30 + 31 + /* 32 + * Initialize the context related info for a new mm_struct instance. 33 + * 34 + * Set all new contexts to 0, that way the generation will never match 35 + * the currently running generation when this context is switched in. 36 + */ 37 + static inline int init_new_context(struct task_struct *tsk, 38 + struct mm_struct *mm) 39 + { 40 + mm->context = 0; 41 + return 0; 42 + } 43 + 44 + /* 45 + * Destroy context related info for an mm_struct that is about 46 + * to be put to rest. 47 + */ 48 + static inline void destroy_context(struct mm_struct *mm) 49 + { 50 + } 51 + 52 + void switch_mm(struct mm_struct *prev, struct mm_struct *next, 53 + struct task_struct *tsk); 54 + 55 + static inline void deactivate_mm(struct task_struct *tsk, 56 + struct mm_struct *mm) 57 + { 58 + } 59 + 60 + /* 61 + * After we have set current->mm to a new value, this activates 62 + * the context for the new mm so we see the new mappings. 63 + */ 64 + void activate_mm(struct mm_struct *prev, struct mm_struct *next); 65 + 66 + #endif /* _ASM_NIOS2_MMU_CONTEXT_H */
+103
arch/nios2/include/asm/processor.h
··· 1 + /* 2 + * Copyright (C) 2013 Altera Corporation 3 + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 4 + * Copyright (C) 2004 Microtronix Datacom Ltd 5 + * Copyright (C) 2001 Ken Hill (khill@microtronix.com) 6 + * Vic Phillips (vic@microtronix.com) 7 + * 8 + * based on SPARC asm/processor_32.h which is: 9 + * 10 + * Copyright (C) 1994 David S. Miller 11 + * 12 + * This file is subject to the terms and conditions of the GNU General Public 13 + * License. See the file "COPYING" in the main directory of this archive 14 + * for more details. 15 + */ 16 + 17 + #ifndef _ASM_NIOS2_PROCESSOR_H 18 + #define _ASM_NIOS2_PROCESSOR_H 19 + 20 + #include <asm/ptrace.h> 21 + #include <asm/registers.h> 22 + #include <asm/page.h> 23 + 24 + #define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */ 25 + 26 + #define NIOS2_OP_NOP 0x1883a 27 + #define NIOS2_OP_BREAK 0x3da03a 28 + 29 + #ifdef __KERNEL__ 30 + 31 + #define STACK_TOP TASK_SIZE 32 + #define STACK_TOP_MAX STACK_TOP 33 + 34 + #endif /* __KERNEL__ */ 35 + 36 + /* Kuser helpers is mapped to this user space address */ 37 + #define KUSER_BASE 0x1000 38 + #define KUSER_SIZE (PAGE_SIZE) 39 + #ifndef __ASSEMBLY__ 40 + 41 + /* 42 + * Default implementation of macro that returns current 43 + * instruction pointer ("program counter"). 44 + */ 45 + #define current_text_addr() ({ __label__ _l; _l: &&_l; }) 46 + 47 + # define TASK_SIZE 0x7FFF0000UL 48 + # define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) 49 + 50 + /* The Nios processor specific thread struct. */ 51 + struct thread_struct { 52 + struct pt_regs *kregs; 53 + 54 + /* Context switch saved kernel state. */ 55 + unsigned long ksp; 56 + unsigned long kpsr; 57 + }; 58 + 59 + #define INIT_MMAP \ 60 + { &init_mm, (0), (0), __pgprot(0x0), VM_READ | VM_WRITE | VM_EXEC } 61 + 62 + # define INIT_THREAD { \ 63 + .kregs = NULL, \ 64 + .ksp = 0, \ 65 + .kpsr = 0, \ 66 + } 67 + 68 + extern void start_thread(struct pt_regs *regs, unsigned long pc, 69 + unsigned long sp); 70 + 71 + struct task_struct; 72 + 73 + /* Free all resources held by a thread. */ 74 + static inline void release_thread(struct task_struct *dead_task) 75 + { 76 + } 77 + 78 + /* Free current thread data structures etc.. */ 79 + static inline void exit_thread(void) 80 + { 81 + } 82 + 83 + /* Return saved PC of a blocked thread. */ 84 + #define thread_saved_pc(tsk) ((tsk)->thread.kregs->ea) 85 + 86 + extern unsigned long get_wchan(struct task_struct *p); 87 + 88 + /* Prepare to copy thread state - unlazy all lazy status */ 89 + #define prepare_to_copy(tsk) do { } while (0) 90 + 91 + #define task_pt_regs(p) \ 92 + ((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1) 93 + 94 + /* Used by procfs */ 95 + #define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea) 96 + #define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp) 97 + 98 + #define cpu_relax() barrier() 99 + #define cpu_relax_lowlatency() cpu_relax() 100 + 101 + #endif /* __ASSEMBLY__ */ 102 + 103 + #endif /* _ASM_NIOS2_PROCESSOR_H */
+31
arch/nios2/include/asm/switch_to.h
··· 1 + /* 2 + * Copyright (C) 2004 Microtronix Datacom Ltd. 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + */ 8 + #ifndef _ASM_NIOS2_SWITCH_TO_H 9 + #define _ASM_NIOS2_SWITCH_TO_H 10 + 11 + /* 12 + * switch_to(n) should switch tasks to task ptr, first checking that 13 + * ptr isn't the current task, in which case it does nothing. This 14 + * also clears the TS-flag if the task we switched to has used the 15 + * math co-processor latest. 16 + */ 17 + #define switch_to(prev, next, last) \ 18 + { \ 19 + void *_last; \ 20 + __asm__ __volatile__ ( \ 21 + "mov r4, %1\n" \ 22 + "mov r5, %2\n" \ 23 + "call resume\n" \ 24 + "mov %0,r4\n" \ 25 + : "=r" (_last) \ 26 + : "r" (prev), "r" (next) \ 27 + : "r4", "r5", "r7", "r8", "ra"); \ 28 + (last) = _last; \ 29 + } 30 + 31 + #endif /* _ASM_NIOS2_SWITCH_TO_H */
+120
arch/nios2/include/asm/thread_info.h
··· 1 + /* 2 + * NiosII low-level thread information 3 + * 4 + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> 5 + * Copyright (C) 2004 Microtronix Datacom Ltd. 6 + * 7 + * Based on asm/thread_info_no.h from m68k which is: 8 + * 9 + * Copyright (C) 2002 David Howells <dhowells@redhat.com> 10 + * 11 + * This file is subject to the terms and conditions of the GNU General Public 12 + * License. See the file "COPYING" in the main directory of this archive 13 + * for more details. 14 + */ 15 + 16 + #ifndef _ASM_NIOS2_THREAD_INFO_H 17 + #define _ASM_NIOS2_THREAD_INFO_H 18 + 19 + #ifdef __KERNEL__ 20 + 21 + /* 22 + * Size of the kernel stack for each process. 23 + */ 24 + #define THREAD_SIZE_ORDER 1 25 + #define THREAD_SIZE 8192 /* 2 * PAGE_SIZE */ 26 + 27 + #ifndef __ASSEMBLY__ 28 + 29 + typedef struct { 30 + unsigned long seg; 31 + } mm_segment_t; 32 + 33 + /* 34 + * low level task data that entry.S needs immediate access to 35 + * - this struct should fit entirely inside of one cache line 36 + * - this struct shares the supervisor stack pages 37 + * - if the contents of this structure are changed, the assembly constants 38 + * must also be changed 39 + */ 40 + struct thread_info { 41 + struct task_struct *task; /* main task structure */ 42 + struct exec_domain *exec_domain; /* execution domain */ 43 + unsigned long flags; /* low level flags */ 44 + __u32 cpu; /* current CPU */ 45 + int preempt_count; /* 0 => preemptable,<0 => BUG */ 46 + mm_segment_t addr_limit; /* thread address space: 47 + 0-0x7FFFFFFF for user-thead 48 + 0-0xFFFFFFFF for kernel-thread 49 + */ 50 + struct restart_block restart_block; 51 + struct pt_regs *regs; 52 + }; 53 + 54 + /* 55 + * macros/functions for gaining access to the thread information structure 56 + * 57 + * preempt_count needs to be 1 initially, until the scheduler is functional. 58 + */ 59 + #define INIT_THREAD_INFO(tsk) \ 60 + { \ 61 + .task = &tsk, \ 62 + .exec_domain = &default_exec_domain, \ 63 + .flags = 0, \ 64 + .cpu = 0, \ 65 + .preempt_count = INIT_PREEMPT_COUNT, \ 66 + .addr_limit = KERNEL_DS, \ 67 + .restart_block = { \ 68 + .fn = do_no_restart_syscall, \ 69 + }, \ 70 + } 71 + 72 + #define init_thread_info (init_thread_union.thread_info) 73 + #define init_stack (init_thread_union.stack) 74 + 75 + /* how to get the thread information struct from C */ 76 + static inline struct thread_info *current_thread_info(void) 77 + { 78 + register unsigned long sp asm("sp"); 79 + 80 + return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); 81 + } 82 + #endif /* !__ASSEMBLY__ */ 83 + 84 + /* 85 + * thread information flags 86 + * - these are process state flags that various assembly files may need to 87 + * access 88 + * - pending work-to-be-done flags are in LSW 89 + * - other flags in MSW 90 + */ 91 + #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ 92 + #define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ 93 + #define TIF_SIGPENDING 2 /* signal pending */ 94 + #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ 95 + #define TIF_MEMDIE 4 /* is terminating due to OOM killer */ 96 + #define TIF_SECCOMP 5 /* secure computing */ 97 + #define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ 98 + #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ 99 + 100 + #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling 101 + TIF_NEED_RESCHED */ 102 + 103 + #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) 104 + #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) 105 + #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) 106 + #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) 107 + #define _TIF_SECCOMP (1 << TIF_SECCOMP) 108 + #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) 109 + #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) 110 + #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) 111 + 112 + /* work to do on interrupt/exception return */ 113 + #define _TIF_WORK_MASK 0x0000FFFE 114 + 115 + /* work to do on any return to u-space */ 116 + # define _TIF_ALLWORK_MASK 0x0000FFFF 117 + 118 + #endif /* __KERNEL__ */ 119 + 120 + #endif /* _ASM_NIOS2_THREAD_INFO_H */
+258
arch/nios2/kernel/process.c
··· 1 + /* 2 + * Architecture-dependent parts of process handling. 3 + * 4 + * Copyright (C) 2013 Altera Corporation 5 + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 6 + * Copyright (C) 2009 Wind River Systems Inc 7 + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com 8 + * Copyright (C) 2004 Microtronix Datacom Ltd 9 + * 10 + * This file is subject to the terms and conditions of the GNU General Public 11 + * License. See the file "COPYING" in the main directory of this archive 12 + * for more details. 13 + */ 14 + 15 + #include <linux/export.h> 16 + #include <linux/sched.h> 17 + #include <linux/tick.h> 18 + #include <linux/uaccess.h> 19 + 20 + #include <asm/unistd.h> 21 + #include <asm/traps.h> 22 + #include <asm/cpuinfo.h> 23 + 24 + asmlinkage void ret_from_fork(void); 25 + asmlinkage void ret_from_kernel_thread(void); 26 + 27 + void (*pm_power_off)(void) = NULL; 28 + EXPORT_SYMBOL(pm_power_off); 29 + 30 + void arch_cpu_idle(void) 31 + { 32 + local_irq_enable(); 33 + } 34 + 35 + /* 36 + * The development boards have no way to pull a board reset. Just jump to the 37 + * cpu reset address and let the boot loader or the code in head.S take care of 38 + * resetting peripherals. 39 + */ 40 + void machine_restart(char *__unused) 41 + { 42 + pr_notice("Machine restart (%08x)...\n", cpuinfo.reset_addr); 43 + local_irq_disable(); 44 + __asm__ __volatile__ ( 45 + "jmp %0\n\t" 46 + : 47 + : "r" (cpuinfo.reset_addr) 48 + : "r4"); 49 + } 50 + 51 + void machine_halt(void) 52 + { 53 + pr_notice("Machine halt...\n"); 54 + local_irq_disable(); 55 + for (;;) 56 + ; 57 + } 58 + 59 + /* 60 + * There is no way to power off the development boards. So just spin for now. If 61 + * we ever have a way of resetting a board using a GPIO we should add that here. 62 + */ 63 + void machine_power_off(void) 64 + { 65 + pr_notice("Machine power off...\n"); 66 + local_irq_disable(); 67 + for (;;) 68 + ; 69 + } 70 + 71 + void show_regs(struct pt_regs *regs) 72 + { 73 + pr_notice("\n"); 74 + show_regs_print_info(KERN_DEFAULT); 75 + 76 + pr_notice("r1: %08lx r2: %08lx r3: %08lx r4: %08lx\n", 77 + regs->r1, regs->r2, regs->r3, regs->r4); 78 + 79 + pr_notice("r5: %08lx r6: %08lx r7: %08lx r8: %08lx\n", 80 + regs->r5, regs->r6, regs->r7, regs->r8); 81 + 82 + pr_notice("r9: %08lx r10: %08lx r11: %08lx r12: %08lx\n", 83 + regs->r9, regs->r10, regs->r11, regs->r12); 84 + 85 + pr_notice("r13: %08lx r14: %08lx r15: %08lx\n", 86 + regs->r13, regs->r14, regs->r15); 87 + 88 + pr_notice("ra: %08lx fp: %08lx sp: %08lx gp: %08lx\n", 89 + regs->ra, regs->fp, regs->sp, regs->gp); 90 + 91 + pr_notice("ea: %08lx estatus: %08lx\n", 92 + regs->ea, regs->estatus); 93 + } 94 + 95 + void flush_thread(void) 96 + { 97 + set_fs(USER_DS); 98 + } 99 + 100 + int copy_thread(unsigned long clone_flags, 101 + unsigned long usp, unsigned long arg, struct task_struct *p) 102 + { 103 + struct pt_regs *childregs = task_pt_regs(p); 104 + struct pt_regs *regs; 105 + struct switch_stack *stack; 106 + struct switch_stack *childstack = 107 + ((struct switch_stack *)childregs) - 1; 108 + 109 + if (unlikely(p->flags & PF_KTHREAD)) { 110 + memset(childstack, 0, 111 + sizeof(struct switch_stack) + sizeof(struct pt_regs)); 112 + 113 + childstack->r16 = usp; /* fn */ 114 + childstack->r17 = arg; 115 + childstack->ra = (unsigned long) ret_from_kernel_thread; 116 + childregs->estatus = STATUS_PIE; 117 + childregs->sp = (unsigned long) childstack; 118 + 119 + p->thread.ksp = (unsigned long) childstack; 120 + p->thread.kregs = childregs; 121 + return 0; 122 + } 123 + 124 + regs = current_pt_regs(); 125 + *childregs = *regs; 126 + childregs->r2 = 0; /* Set the return value for the child. */ 127 + childregs->r7 = 0; 128 + 129 + stack = ((struct switch_stack *) regs) - 1; 130 + *childstack = *stack; 131 + childstack->ra = (unsigned long)ret_from_fork; 132 + p->thread.kregs = childregs; 133 + p->thread.ksp = (unsigned long) childstack; 134 + 135 + if (usp) 136 + childregs->sp = usp; 137 + 138 + /* Initialize tls register. */ 139 + if (clone_flags & CLONE_SETTLS) 140 + childstack->r23 = regs->r8; 141 + 142 + return 0; 143 + } 144 + 145 + /* 146 + * Generic dumping code. Used for panic and debug. 147 + */ 148 + void dump(struct pt_regs *fp) 149 + { 150 + unsigned long *sp; 151 + unsigned char *tp; 152 + int i; 153 + 154 + pr_emerg("\nCURRENT PROCESS:\n\n"); 155 + pr_emerg("COMM=%s PID=%d\n", current->comm, current->pid); 156 + 157 + if (current->mm) { 158 + pr_emerg("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", 159 + (int) current->mm->start_code, 160 + (int) current->mm->end_code, 161 + (int) current->mm->start_data, 162 + (int) current->mm->end_data, 163 + (int) current->mm->end_data, 164 + (int) current->mm->brk); 165 + pr_emerg("USER-STACK=%08x KERNEL-STACK=%08x\n\n", 166 + (int) current->mm->start_stack, 167 + (int)(((unsigned long) current) + THREAD_SIZE)); 168 + } 169 + 170 + pr_emerg("PC: %08lx\n", fp->ea); 171 + pr_emerg("SR: %08lx SP: %08lx\n", 172 + (long) fp->estatus, (long) fp); 173 + 174 + pr_emerg("r1: %08lx r2: %08lx r3: %08lx\n", 175 + fp->r1, fp->r2, fp->r3); 176 + 177 + pr_emerg("r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", 178 + fp->r4, fp->r5, fp->r6, fp->r7); 179 + pr_emerg("r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", 180 + fp->r8, fp->r9, fp->r10, fp->r11); 181 + pr_emerg("r12: %08lx r13: %08lx r14: %08lx r15: %08lx\n", 182 + fp->r12, fp->r13, fp->r14, fp->r15); 183 + pr_emerg("or2: %08lx ra: %08lx fp: %08lx sp: %08lx\n", 184 + fp->orig_r2, fp->ra, fp->fp, fp->sp); 185 + pr_emerg("\nUSP: %08x TRAPFRAME: %08x\n", 186 + (unsigned int) fp->sp, (unsigned int) fp); 187 + 188 + pr_emerg("\nCODE:"); 189 + tp = ((unsigned char *) fp->ea) - 0x20; 190 + for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { 191 + if ((i % 0x10) == 0) 192 + pr_emerg("\n%08x: ", (int) (tp + i)); 193 + pr_emerg("%08x ", (int) *sp++); 194 + } 195 + pr_emerg("\n"); 196 + 197 + pr_emerg("\nKERNEL STACK:"); 198 + tp = ((unsigned char *) fp) - 0x40; 199 + for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { 200 + if ((i % 0x10) == 0) 201 + pr_emerg("\n%08x: ", (int) (tp + i)); 202 + pr_emerg("%08x ", (int) *sp++); 203 + } 204 + pr_emerg("\n"); 205 + pr_emerg("\n"); 206 + 207 + pr_emerg("\nUSER STACK:"); 208 + tp = (unsigned char *) (fp->sp - 0x10); 209 + for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { 210 + if ((i % 0x10) == 0) 211 + pr_emerg("\n%08x: ", (int) (tp + i)); 212 + pr_emerg("%08x ", (int) *sp++); 213 + } 214 + pr_emerg("\n\n"); 215 + } 216 + 217 + unsigned long get_wchan(struct task_struct *p) 218 + { 219 + unsigned long fp, pc; 220 + unsigned long stack_page; 221 + int count = 0; 222 + 223 + if (!p || p == current || p->state == TASK_RUNNING) 224 + return 0; 225 + 226 + stack_page = (unsigned long)p; 227 + fp = ((struct switch_stack *)p->thread.ksp)->fp; /* ;dgt2 */ 228 + do { 229 + if (fp < stack_page+sizeof(struct task_struct) || 230 + fp >= 8184+stack_page) /* ;dgt2;tmp */ 231 + return 0; 232 + pc = ((unsigned long *)fp)[1]; 233 + if (!in_sched_functions(pc)) 234 + return pc; 235 + fp = *(unsigned long *) fp; 236 + } while (count++ < 16); /* ;dgt2;tmp */ 237 + return 0; 238 + } 239 + 240 + /* 241 + * Do necessary setup to start up a newly executed thread. 242 + * Will startup in user mode (status_extension = 0). 243 + */ 244 + void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) 245 + { 246 + memset((void *) regs, 0, sizeof(struct pt_regs)); 247 + regs->estatus = ESTATUS_EPIE | ESTATUS_EU; 248 + regs->ea = pc; 249 + regs->sp = sp; 250 + } 251 + 252 + #include <linux/elfcore.h> 253 + 254 + /* Fill in the FPU structure for a core dump. */ 255 + int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) 256 + { 257 + return 0; /* Nios2 has no FPU and thus no FPU registers */ 258 + }
+116
arch/nios2/mm/mmu_context.c
··· 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 + 38 + static mm_context_t next_mmu_context; 39 + 40 + /* 41 + * Initialize MMU context management stuff. 42 + */ 43 + void __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 + */ 53 + static void set_context(mm_context_t context) 54 + { 55 + set_mmu_pid(CTX_PID(context)); 56 + } 57 + 58 + static 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 + 80 + void 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 + */ 106 + void 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 + 113 + unsigned long get_pid_from_context(mm_context_t *context) 114 + { 115 + return CTX_PID((*context)); 116 + }