Commit | Line | Data |
---|---|---|
14cf11af PM |
1 | /* |
2 | * MMU context allocation for 64-bit kernels. | |
3 | * | |
4 | * Copyright (C) 2004 Anton Blanchard, IBM Corp. <anton@samba.org> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | */ | |
12 | ||
14cf11af PM |
13 | #include <linux/sched.h> |
14 | #include <linux/kernel.h> | |
15 | #include <linux/errno.h> | |
16 | #include <linux/string.h> | |
17 | #include <linux/types.h> | |
18 | #include <linux/mm.h> | |
19 | #include <linux/spinlock.h> | |
20 | #include <linux/idr.h> | |
4b16f8e2 | 21 | #include <linux/export.h> |
5a0e3ad6 | 22 | #include <linux/gfp.h> |
851d2e2f | 23 | #include <linux/slab.h> |
14cf11af PM |
24 | |
25 | #include <asm/mmu_context.h> | |
26 | ||
9d670280 | 27 | #include "icswx.h" |
851d2e2f | 28 | |
14cf11af | 29 | static DEFINE_SPINLOCK(mmu_context_lock); |
7317ac87 | 30 | static DEFINE_IDA(mmu_context_ida); |
14cf11af | 31 | |
e85a4710 | 32 | int __init_new_context(void) |
14cf11af PM |
33 | { |
34 | int index; | |
35 | int err; | |
36 | ||
37 | again: | |
7317ac87 | 38 | if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL)) |
14cf11af PM |
39 | return -ENOMEM; |
40 | ||
41 | spin_lock(&mmu_context_lock); | |
7317ac87 | 42 | err = ida_get_new_above(&mmu_context_ida, 1, &index); |
14cf11af PM |
43 | spin_unlock(&mmu_context_lock); |
44 | ||
45 | if (err == -EAGAIN) | |
46 | goto again; | |
47 | else if (err) | |
48 | return err; | |
49 | ||
c60ac569 | 50 | if (index > MAX_USER_CONTEXT) { |
f86c9747 | 51 | spin_lock(&mmu_context_lock); |
7317ac87 | 52 | ida_remove(&mmu_context_ida, index); |
f86c9747 | 53 | spin_unlock(&mmu_context_lock); |
14cf11af PM |
54 | return -ENOMEM; |
55 | } | |
56 | ||
e85a4710 AG |
57 | return index; |
58 | } | |
59 | EXPORT_SYMBOL_GPL(__init_new_context); | |
60 | ||
61 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | |
62 | { | |
63 | int index; | |
64 | ||
65 | index = __init_new_context(); | |
66 | if (index < 0) | |
67 | return index; | |
68 | ||
d0f13e3c BH |
69 | /* The old code would re-promote on fork, we don't do that |
70 | * when using slices as it could cause problem promoting slices | |
71 | * that have been forced down to 4K | |
72 | */ | |
e8ff0646 | 73 | if (slice_mm_new_context(mm)) |
d0f13e3c | 74 | slice_set_user_psize(mm, mmu_virtual_psize); |
d28513bc | 75 | subpage_prot_init_new_context(mm); |
9dfe5c53 | 76 | mm->context.id = index; |
851d2e2f THFL |
77 | #ifdef CONFIG_PPC_ICSWX |
78 | mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL); | |
79 | if (!mm->context.cop_lockp) { | |
80 | __destroy_context(index); | |
81 | subpage_prot_free(mm); | |
79af2187 | 82 | mm->context.id = MMU_NO_CONTEXT; |
851d2e2f THFL |
83 | return -ENOMEM; |
84 | } | |
85 | spin_lock_init(mm->context.cop_lockp); | |
86 | #endif /* CONFIG_PPC_ICSWX */ | |
14cf11af PM |
87 | |
88 | return 0; | |
89 | } | |
90 | ||
e85a4710 | 91 | void __destroy_context(int context_id) |
14cf11af PM |
92 | { |
93 | spin_lock(&mmu_context_lock); | |
7317ac87 | 94 | ida_remove(&mmu_context_ida, context_id); |
14cf11af | 95 | spin_unlock(&mmu_context_lock); |
e85a4710 AG |
96 | } |
97 | EXPORT_SYMBOL_GPL(__destroy_context); | |
14cf11af | 98 | |
e85a4710 AG |
99 | void destroy_context(struct mm_struct *mm) |
100 | { | |
851d2e2f THFL |
101 | #ifdef CONFIG_PPC_ICSWX |
102 | drop_cop(mm->context.acop, mm); | |
103 | kfree(mm->context.cop_lockp); | |
104 | mm->context.cop_lockp = NULL; | |
105 | #endif /* CONFIG_PPC_ICSWX */ | |
e85a4710 | 106 | __destroy_context(mm->context.id); |
d28513bc | 107 | subpage_prot_free(mm); |
5e8e7b40 | 108 | mm->context.id = MMU_NO_CONTEXT; |
14cf11af | 109 | } |