Merge tag 'char-misc-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[linux-2.6-microblaze.git] / arch / powerpc / mm / mmu_context_book3s64.c
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
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/pkeys.h>
20 #include <linux/spinlock.h>
21 #include <linux/idr.h>
22 #include <linux/export.h>
23 #include <linux/gfp.h>
24 #include <linux/slab.h>
25
26 #include <asm/mmu_context.h>
27 #include <asm/pgalloc.h>
28
29 static DEFINE_IDA(mmu_context_ida);
30
31 static int alloc_context_id(int min_id, int max_id)
32 {
33         return ida_alloc_range(&mmu_context_ida, min_id, max_id, GFP_KERNEL);
34 }
35
36 void hash__reserve_context_id(int id)
37 {
38         int result = ida_alloc_range(&mmu_context_ida, id, id, GFP_KERNEL);
39
40         WARN(result != id, "mmu: Failed to reserve context id %d (rc %d)\n", id, result);
41 }
42
43 int hash__alloc_context_id(void)
44 {
45         unsigned long max;
46
47         if (mmu_has_feature(MMU_FTR_68_BIT_VA))
48                 max = MAX_USER_CONTEXT;
49         else
50                 max = MAX_USER_CONTEXT_65BIT_VA;
51
52         return alloc_context_id(MIN_USER_CONTEXT, max);
53 }
54 EXPORT_SYMBOL_GPL(hash__alloc_context_id);
55
56 void slb_setup_new_exec(void);
57
58 static int hash__init_new_context(struct mm_struct *mm)
59 {
60         int index;
61
62         index = hash__alloc_context_id();
63         if (index < 0)
64                 return index;
65
66         /*
67          * The old code would re-promote on fork, we don't do that when using
68          * slices as it could cause problem promoting slices that have been
69          * forced down to 4K.
70          *
71          * For book3s we have MMU_NO_CONTEXT set to be ~0. Hence check
72          * explicitly against context.id == 0. This ensures that we properly
73          * initialize context slice details for newly allocated mm's (which will
74          * have id == 0) and don't alter context slice inherited via fork (which
75          * will have id != 0).
76          *
77          * We should not be calling init_new_context() on init_mm. Hence a
78          * check against 0 is OK.
79          */
80         if (mm->context.id == 0)
81                 slice_init_new_context_exec(mm);
82
83         subpage_prot_init_new_context(mm);
84
85         pkey_mm_init(mm);
86         return index;
87 }
88
89 void hash__setup_new_exec(void)
90 {
91         slice_setup_new_exec();
92
93         slb_setup_new_exec();
94 }
95
96 static int radix__init_new_context(struct mm_struct *mm)
97 {
98         unsigned long rts_field;
99         int index, max_id;
100
101         max_id = (1 << mmu_pid_bits) - 1;
102         index = alloc_context_id(mmu_base_pid, max_id);
103         if (index < 0)
104                 return index;
105
106         /*
107          * set the process table entry,
108          */
109         rts_field = radix__get_tree_size();
110         process_tb[index].prtb0 = cpu_to_be64(rts_field | __pa(mm->pgd) | RADIX_PGD_INDEX_SIZE);
111
112         /*
113          * Order the above store with subsequent update of the PID
114          * register (at which point HW can start loading/caching
115          * the entry) and the corresponding load by the MMU from
116          * the L2 cache.
117          */
118         asm volatile("ptesync;isync" : : : "memory");
119
120         mm->context.npu_context = NULL;
121
122         return index;
123 }
124
125 int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
126 {
127         int index;
128
129         if (radix_enabled())
130                 index = radix__init_new_context(mm);
131         else
132                 index = hash__init_new_context(mm);
133
134         if (index < 0)
135                 return index;
136
137         mm->context.id = index;
138
139         mm->context.pte_frag = NULL;
140         mm->context.pmd_frag = NULL;
141 #ifdef CONFIG_SPAPR_TCE_IOMMU
142         mm_iommu_init(mm);
143 #endif
144         atomic_set(&mm->context.active_cpus, 0);
145         atomic_set(&mm->context.copros, 0);
146
147         return 0;
148 }
149
150 void __destroy_context(int context_id)
151 {
152         ida_free(&mmu_context_ida, context_id);
153 }
154 EXPORT_SYMBOL_GPL(__destroy_context);
155
156 static void destroy_contexts(mm_context_t *ctx)
157 {
158         int index, context_id;
159
160         for (index = 0; index < ARRAY_SIZE(ctx->extended_id); index++) {
161                 context_id = ctx->extended_id[index];
162                 if (context_id)
163                         ida_free(&mmu_context_ida, context_id);
164         }
165 }
166
167 static void pmd_frag_destroy(void *pmd_frag)
168 {
169         int count;
170         struct page *page;
171
172         page = virt_to_page(pmd_frag);
173         /* drop all the pending references */
174         count = ((unsigned long)pmd_frag & ~PAGE_MASK) >> PMD_FRAG_SIZE_SHIFT;
175         /* We allow PTE_FRAG_NR fragments from a PTE page */
176         if (atomic_sub_and_test(PMD_FRAG_NR - count, &page->pt_frag_refcount)) {
177                 pgtable_pmd_page_dtor(page);
178                 __free_page(page);
179         }
180 }
181
182 static void destroy_pagetable_cache(struct mm_struct *mm)
183 {
184         void *frag;
185
186         frag = mm->context.pte_frag;
187         if (frag)
188                 pte_frag_destroy(frag);
189
190         frag = mm->context.pmd_frag;
191         if (frag)
192                 pmd_frag_destroy(frag);
193         return;
194 }
195
196 void destroy_context(struct mm_struct *mm)
197 {
198 #ifdef CONFIG_SPAPR_TCE_IOMMU
199         WARN_ON_ONCE(!list_empty(&mm->context.iommu_group_mem_list));
200 #endif
201         if (radix_enabled())
202                 WARN_ON(process_tb[mm->context.id].prtb0 != 0);
203         else
204                 subpage_prot_free(mm);
205         destroy_contexts(&mm->context);
206         mm->context.id = MMU_NO_CONTEXT;
207 }
208
209 void arch_exit_mmap(struct mm_struct *mm)
210 {
211         destroy_pagetable_cache(mm);
212
213         if (radix_enabled()) {
214                 /*
215                  * Radix doesn't have a valid bit in the process table
216                  * entries. However we know that at least P9 implementation
217                  * will avoid caching an entry with an invalid RTS field,
218                  * and 0 is invalid. So this will do.
219                  *
220                  * This runs before the "fullmm" tlb flush in exit_mmap,
221                  * which does a RIC=2 tlbie to clear the process table
222                  * entry. See the "fullmm" comments in tlb-radix.c.
223                  *
224                  * No barrier required here after the store because
225                  * this process will do the invalidate, which starts with
226                  * ptesync.
227                  */
228                 process_tb[mm->context.id].prtb0 = 0;
229         }
230 }
231
232 #ifdef CONFIG_PPC_RADIX_MMU
233 void radix__switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
234 {
235         mtspr(SPRN_PID, next->context.id);
236         isync();
237 }
238 #endif