diff options
author | Jimi Xenidis <jimix@pobox.com> | 2011-09-29 06:55:12 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-11-24 22:11:27 -0500 |
commit | 9d670280908013004f173b2b86414d9b6918511b (patch) | |
tree | bd7a7483ae7455cb481c72df907a3b4362e121c2 /arch/powerpc/mm | |
parent | 5182a131ddf988fe4f5cef9964dbfb64a188b0c3 (diff) |
powerpc: Split ICSWX ACOP and PID processing
Some processors, like embedded, that already have a PID register that
is managed by the system. This patch separates the ACOP and PID
processing into separate files so that the ACOP code can be shared.
Signed-off-by: Jimi Xenidis <jimix@pobox.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/mm/icswx.c | 160 | ||||
-rw-r--r-- | arch/powerpc/mm/icswx.h | 39 | ||||
-rw-r--r-- | arch/powerpc/mm/icswx_pid.c | 87 | ||||
-rw-r--r-- | arch/powerpc/mm/mmu_context_hash64.c | 195 |
5 files changed, 289 insertions, 194 deletions
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 991ee813d2a8..3787b61f7d20 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile | |||
@@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o | |||
21 | obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ | 21 | obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ |
22 | tlb_hash$(CONFIG_WORD_SIZE).o \ | 22 | tlb_hash$(CONFIG_WORD_SIZE).o \ |
23 | mmu_context_hash$(CONFIG_WORD_SIZE).o | 23 | mmu_context_hash$(CONFIG_WORD_SIZE).o |
24 | obj-$(CONFIG_PPC_ICSWX) += icswx.o | ||
25 | obj-$(CONFIG_PPC_ICSWX_PID) += icswx_pid.o | ||
24 | obj-$(CONFIG_40x) += 40x_mmu.o | 26 | obj-$(CONFIG_40x) += 40x_mmu.o |
25 | obj-$(CONFIG_44x) += 44x_mmu.o | 27 | obj-$(CONFIG_44x) += 44x_mmu.o |
26 | obj-$(CONFIG_PPC_FSL_BOOK3E) += fsl_booke_mmu.o | 28 | obj-$(CONFIG_PPC_FSL_BOOK3E) += fsl_booke_mmu.o |
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c new file mode 100644 index 000000000000..a98850fd7777 --- /dev/null +++ b/arch/powerpc/mm/icswx.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * ICSWX and ACOP Management | ||
3 | * | ||
4 | * Copyright (C) 2011 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/types.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/module.h> | ||
20 | #include "icswx.h" | ||
21 | |||
22 | /* | ||
23 | * The processor and its L2 cache cause the icswx instruction to | ||
24 | * generate a COP_REQ transaction on PowerBus. The transaction has no | ||
25 | * address, and the processor does not perform an MMU access to | ||
26 | * authenticate the transaction. The command portion of the PowerBus | ||
27 | * COP_REQ transaction includes the LPAR_ID (LPID) and the coprocessor | ||
28 | * Process ID (PID), which the coprocessor compares to the authorized | ||
29 | * LPID and PID held in the coprocessor, to determine if the process | ||
30 | * is authorized to generate the transaction. The data of the COP_REQ | ||
31 | * transaction is 128-byte or less in size and is placed in cacheable | ||
32 | * memory on a 128-byte cache line boundary. | ||
33 | * | ||
34 | * The task to use a coprocessor should use use_cop() to mark the use | ||
35 | * of the Coprocessor Type (CT) and context switching. On a server | ||
36 | * class processor, the PID register is used only for coprocessor | ||
37 | * management + * and so a coprocessor PID is allocated before | ||
38 | * executing icswx + * instruction. Drop_cop() is used to free the | ||
39 | * coprocessor PID. | ||
40 | * | ||
41 | * Example: | ||
42 | * Host Fabric Interface (HFI) is a PowerPC network coprocessor. | ||
43 | * Each HFI have multiple windows. Each HFI window serves as a | ||
44 | * network device sending to and receiving from HFI network. | ||
45 | * HFI immediate send function uses icswx instruction. The immediate | ||
46 | * send function allows small (single cache-line) packets be sent | ||
47 | * without using the regular HFI send FIFO and doorbell, which are | ||
48 | * much slower than immediate send. | ||
49 | * | ||
50 | * For each task intending to use HFI immediate send, the HFI driver | ||
51 | * calls use_cop() to obtain a coprocessor PID for the task. | ||
52 | * The HFI driver then allocate a free HFI window and save the | ||
53 | * coprocessor PID to the HFI window to allow the task to use the | ||
54 | * HFI window. | ||
55 | * | ||
56 | * The HFI driver repeatedly creates immediate send packets and | ||
57 | * issues icswx instruction to send data through the HFI window. | ||
58 | * The HFI compares the coprocessor PID in the CPU PID register | ||
59 | * to the PID held in the HFI window to determine if the transaction | ||
60 | * is allowed. | ||
61 | * | ||
62 | * When the task to release the HFI window, the HFI driver calls | ||
63 | * drop_cop() to release the coprocessor PID. | ||
64 | */ | ||
65 | |||
66 | void switch_cop(struct mm_struct *next) | ||
67 | { | ||
68 | #ifdef CONFIG_ICSWX_PID | ||
69 | mtspr(SPRN_PID, next->context.cop_pid); | ||
70 | #endif | ||
71 | mtspr(SPRN_ACOP, next->context.acop); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * Start using a coprocessor. | ||
76 | * @acop: mask of coprocessor to be used. | ||
77 | * @mm: The mm the coprocessor to associate with. Most likely current mm. | ||
78 | * | ||
79 | * Return a positive PID if successful. Negative errno otherwise. | ||
80 | * The returned PID will be fed to the coprocessor to determine if an | ||
81 | * icswx transaction is authenticated. | ||
82 | */ | ||
83 | int use_cop(unsigned long acop, struct mm_struct *mm) | ||
84 | { | ||
85 | int ret; | ||
86 | |||
87 | if (!cpu_has_feature(CPU_FTR_ICSWX)) | ||
88 | return -ENODEV; | ||
89 | |||
90 | if (!mm || !acop) | ||
91 | return -EINVAL; | ||
92 | |||
93 | /* The page_table_lock ensures mm_users won't change under us */ | ||
94 | spin_lock(&mm->page_table_lock); | ||
95 | spin_lock(mm->context.cop_lockp); | ||
96 | |||
97 | ret = get_cop_pid(mm); | ||
98 | if (ret < 0) | ||
99 | goto out; | ||
100 | |||
101 | /* update acop */ | ||
102 | mm->context.acop |= acop; | ||
103 | |||
104 | sync_cop(mm); | ||
105 | |||
106 | /* | ||
107 | * If this is a threaded process then there might be other threads | ||
108 | * running. We need to send an IPI to force them to pick up any | ||
109 | * change in PID and ACOP. | ||
110 | */ | ||
111 | if (atomic_read(&mm->mm_users) > 1) | ||
112 | smp_call_function(sync_cop, mm, 1); | ||
113 | |||
114 | out: | ||
115 | spin_unlock(mm->context.cop_lockp); | ||
116 | spin_unlock(&mm->page_table_lock); | ||
117 | |||
118 | return ret; | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(use_cop); | ||
121 | |||
122 | /** | ||
123 | * Stop using a coprocessor. | ||
124 | * @acop: mask of coprocessor to be stopped. | ||
125 | * @mm: The mm the coprocessor associated with. | ||
126 | */ | ||
127 | void drop_cop(unsigned long acop, struct mm_struct *mm) | ||
128 | { | ||
129 | int free_pid; | ||
130 | |||
131 | if (!cpu_has_feature(CPU_FTR_ICSWX)) | ||
132 | return; | ||
133 | |||
134 | if (WARN_ON_ONCE(!mm)) | ||
135 | return; | ||
136 | |||
137 | /* The page_table_lock ensures mm_users won't change under us */ | ||
138 | spin_lock(&mm->page_table_lock); | ||
139 | spin_lock(mm->context.cop_lockp); | ||
140 | |||
141 | mm->context.acop &= ~acop; | ||
142 | |||
143 | free_pid = disable_cop_pid(mm); | ||
144 | sync_cop(mm); | ||
145 | |||
146 | /* | ||
147 | * If this is a threaded process then there might be other threads | ||
148 | * running. We need to send an IPI to force them to pick up any | ||
149 | * change in PID and ACOP. | ||
150 | */ | ||
151 | if (atomic_read(&mm->mm_users) > 1) | ||
152 | smp_call_function(sync_cop, mm, 1); | ||
153 | |||
154 | if (free_pid != COP_PID_NONE) | ||
155 | free_cop_pid(free_pid); | ||
156 | |||
157 | spin_unlock(mm->context.cop_lockp); | ||
158 | spin_unlock(&mm->page_table_lock); | ||
159 | } | ||
160 | EXPORT_SYMBOL_GPL(drop_cop); | ||
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h new file mode 100644 index 000000000000..07514e49498e --- /dev/null +++ b/arch/powerpc/mm/icswx.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef _ARCH_POWERPC_MM_ICSWX_H_ | ||
2 | #define _ARCH_POWERPC_MM_ICSWX_H_ | ||
3 | |||
4 | /* | ||
5 | * ICSWX and ACOP Management | ||
6 | * | ||
7 | * Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <asm/mmu_context.h> | ||
17 | |||
18 | /* also used to denote that PIDs are not used */ | ||
19 | #define COP_PID_NONE 0 | ||
20 | |||
21 | static inline void sync_cop(void *arg) | ||
22 | { | ||
23 | struct mm_struct *mm = arg; | ||
24 | |||
25 | if (mm == current->active_mm) | ||
26 | switch_cop(current->active_mm); | ||
27 | } | ||
28 | |||
29 | #ifdef CONFIG_PPC_ICSWX_PID | ||
30 | extern int get_cop_pid(struct mm_struct *mm); | ||
31 | extern int disable_cop_pid(struct mm_struct *mm); | ||
32 | extern void free_cop_pid(int free_pid); | ||
33 | #else | ||
34 | #define get_cop_pid(m) (COP_PID_NONE) | ||
35 | #define disable_cop_pid(m) (COP_PID_NONE) | ||
36 | #define free_cop_pid(p) | ||
37 | #endif | ||
38 | |||
39 | #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */ | ||
diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c new file mode 100644 index 000000000000..91e30eb7d054 --- /dev/null +++ b/arch/powerpc/mm/icswx_pid.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * ICSWX and ACOP/PID Management | ||
3 | * | ||
4 | * Copyright (C) 2011 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/types.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/idr.h> | ||
20 | #include <linux/module.h> | ||
21 | #include "icswx.h" | ||
22 | |||
23 | #define COP_PID_MIN (COP_PID_NONE + 1) | ||
24 | #define COP_PID_MAX (0xFFFF) | ||
25 | |||
26 | static DEFINE_SPINLOCK(mmu_context_acop_lock); | ||
27 | static DEFINE_IDA(cop_ida); | ||
28 | |||
29 | static int new_cop_pid(struct ida *ida, int min_id, int max_id, | ||
30 | spinlock_t *lock) | ||
31 | { | ||
32 | int index; | ||
33 | int err; | ||
34 | |||
35 | again: | ||
36 | if (!ida_pre_get(ida, GFP_KERNEL)) | ||
37 | return -ENOMEM; | ||
38 | |||
39 | spin_lock(lock); | ||
40 | err = ida_get_new_above(ida, min_id, &index); | ||
41 | spin_unlock(lock); | ||
42 | |||
43 | if (err == -EAGAIN) | ||
44 | goto again; | ||
45 | else if (err) | ||
46 | return err; | ||
47 | |||
48 | if (index > max_id) { | ||
49 | spin_lock(lock); | ||
50 | ida_remove(ida, index); | ||
51 | spin_unlock(lock); | ||
52 | return -ENOMEM; | ||
53 | } | ||
54 | |||
55 | return index; | ||
56 | } | ||
57 | |||
58 | int get_cop_pid(struct mm_struct *mm) | ||
59 | { | ||
60 | int pid; | ||
61 | |||
62 | if (mm->context.cop_pid == COP_PID_NONE) { | ||
63 | pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX, | ||
64 | &mmu_context_acop_lock); | ||
65 | if (pid >= 0) | ||
66 | mm->context.cop_pid = pid; | ||
67 | } | ||
68 | return mm->context.cop_pid; | ||
69 | } | ||
70 | |||
71 | int disable_cop_pid(struct mm_struct *mm) | ||
72 | { | ||
73 | int free_pid = COP_PID_NONE; | ||
74 | |||
75 | if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) { | ||
76 | free_pid = mm->context.cop_pid; | ||
77 | mm->context.cop_pid = COP_PID_NONE; | ||
78 | } | ||
79 | return free_pid; | ||
80 | } | ||
81 | |||
82 | void free_cop_pid(int free_pid) | ||
83 | { | ||
84 | spin_lock(&mmu_context_acop_lock); | ||
85 | ida_remove(&cop_ida, free_pid); | ||
86 | spin_unlock(&mmu_context_acop_lock); | ||
87 | } | ||
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index ca988a3d5fb2..40677aa0190e 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c | |||
@@ -24,200 +24,7 @@ | |||
24 | 24 | ||
25 | #include <asm/mmu_context.h> | 25 | #include <asm/mmu_context.h> |
26 | 26 | ||
27 | #ifdef CONFIG_PPC_ICSWX | 27 | #include "icswx.h" |
28 | /* | ||
29 | * The processor and its L2 cache cause the icswx instruction to | ||
30 | * generate a COP_REQ transaction on PowerBus. The transaction has | ||
31 | * no address, and the processor does not perform an MMU access | ||
32 | * to authenticate the transaction. The command portion of the | ||
33 | * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and | ||
34 | * the coprocessor Process ID (PID), which the coprocessor compares | ||
35 | * to the authorized LPID and PID held in the coprocessor, to determine | ||
36 | * if the process is authorized to generate the transaction. | ||
37 | * The data of the COP_REQ transaction is 128-byte or less and is | ||
38 | * placed in cacheable memory on a 128-byte cache line boundary. | ||
39 | * | ||
40 | * The task to use a coprocessor should use use_cop() to allocate | ||
41 | * a coprocessor PID before executing icswx instruction. use_cop() | ||
42 | * also enables the coprocessor context switching. Drop_cop() is | ||
43 | * used to free the coprocessor PID. | ||
44 | * | ||
45 | * Example: | ||
46 | * Host Fabric Interface (HFI) is a PowerPC network coprocessor. | ||
47 | * Each HFI have multiple windows. Each HFI window serves as a | ||
48 | * network device sending to and receiving from HFI network. | ||
49 | * HFI immediate send function uses icswx instruction. The immediate | ||
50 | * send function allows small (single cache-line) packets be sent | ||
51 | * without using the regular HFI send FIFO and doorbell, which are | ||
52 | * much slower than immediate send. | ||
53 | * | ||
54 | * For each task intending to use HFI immediate send, the HFI driver | ||
55 | * calls use_cop() to obtain a coprocessor PID for the task. | ||
56 | * The HFI driver then allocate a free HFI window and save the | ||
57 | * coprocessor PID to the HFI window to allow the task to use the | ||
58 | * HFI window. | ||
59 | * | ||
60 | * The HFI driver repeatedly creates immediate send packets and | ||
61 | * issues icswx instruction to send data through the HFI window. | ||
62 | * The HFI compares the coprocessor PID in the CPU PID register | ||
63 | * to the PID held in the HFI window to determine if the transaction | ||
64 | * is allowed. | ||
65 | * | ||
66 | * When the task to release the HFI window, the HFI driver calls | ||
67 | * drop_cop() to release the coprocessor PID. | ||
68 | */ | ||
69 | |||
70 | #define COP_PID_NONE 0 | ||
71 | #define COP_PID_MIN (COP_PID_NONE + 1) | ||
72 | #define COP_PID_MAX (0xFFFF) | ||
73 | |||
74 | static DEFINE_SPINLOCK(mmu_context_acop_lock); | ||
75 | static DEFINE_IDA(cop_ida); | ||
76 | |||
77 | void switch_cop(struct mm_struct *next) | ||
78 | { | ||
79 | mtspr(SPRN_PID, next->context.cop_pid); | ||
80 | mtspr(SPRN_ACOP, next->context.acop); | ||
81 | } | ||
82 | |||
83 | static int new_cop_pid(struct ida *ida, int min_id, int max_id, | ||
84 | spinlock_t *lock) | ||
85 | { | ||
86 | int index; | ||
87 | int err; | ||
88 | |||
89 | again: | ||
90 | if (!ida_pre_get(ida, GFP_KERNEL)) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | spin_lock(lock); | ||
94 | err = ida_get_new_above(ida, min_id, &index); | ||
95 | spin_unlock(lock); | ||
96 | |||
97 | if (err == -EAGAIN) | ||
98 | goto again; | ||
99 | else if (err) | ||
100 | return err; | ||
101 | |||
102 | if (index > max_id) { | ||
103 | spin_lock(lock); | ||
104 | ida_remove(ida, index); | ||
105 | spin_unlock(lock); | ||
106 | return -ENOMEM; | ||
107 | } | ||
108 | |||
109 | return index; | ||
110 | } | ||
111 | |||
112 | static void sync_cop(void *arg) | ||
113 | { | ||
114 | struct mm_struct *mm = arg; | ||
115 | |||
116 | if (mm == current->active_mm) | ||
117 | switch_cop(current->active_mm); | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * Start using a coprocessor. | ||
122 | * @acop: mask of coprocessor to be used. | ||
123 | * @mm: The mm the coprocessor to associate with. Most likely current mm. | ||
124 | * | ||
125 | * Return a positive PID if successful. Negative errno otherwise. | ||
126 | * The returned PID will be fed to the coprocessor to determine if an | ||
127 | * icswx transaction is authenticated. | ||
128 | */ | ||
129 | int use_cop(unsigned long acop, struct mm_struct *mm) | ||
130 | { | ||
131 | int ret; | ||
132 | |||
133 | if (!cpu_has_feature(CPU_FTR_ICSWX)) | ||
134 | return -ENODEV; | ||
135 | |||
136 | if (!mm || !acop) | ||
137 | return -EINVAL; | ||
138 | |||
139 | /* The page_table_lock ensures mm_users won't change under us */ | ||
140 | spin_lock(&mm->page_table_lock); | ||
141 | spin_lock(mm->context.cop_lockp); | ||
142 | |||
143 | if (mm->context.cop_pid == COP_PID_NONE) { | ||
144 | ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX, | ||
145 | &mmu_context_acop_lock); | ||
146 | if (ret < 0) | ||
147 | goto out; | ||
148 | |||
149 | mm->context.cop_pid = ret; | ||
150 | } | ||
151 | mm->context.acop |= acop; | ||
152 | |||
153 | sync_cop(mm); | ||
154 | |||
155 | /* | ||
156 | * If this is a threaded process then there might be other threads | ||
157 | * running. We need to send an IPI to force them to pick up any | ||
158 | * change in PID and ACOP. | ||
159 | */ | ||
160 | if (atomic_read(&mm->mm_users) > 1) | ||
161 | smp_call_function(sync_cop, mm, 1); | ||
162 | |||
163 | ret = mm->context.cop_pid; | ||
164 | |||
165 | out: | ||
166 | spin_unlock(mm->context.cop_lockp); | ||
167 | spin_unlock(&mm->page_table_lock); | ||
168 | |||
169 | return ret; | ||
170 | } | ||
171 | EXPORT_SYMBOL_GPL(use_cop); | ||
172 | |||
173 | /** | ||
174 | * Stop using a coprocessor. | ||
175 | * @acop: mask of coprocessor to be stopped. | ||
176 | * @mm: The mm the coprocessor associated with. | ||
177 | */ | ||
178 | void drop_cop(unsigned long acop, struct mm_struct *mm) | ||
179 | { | ||
180 | int free_pid = COP_PID_NONE; | ||
181 | |||
182 | if (!cpu_has_feature(CPU_FTR_ICSWX)) | ||
183 | return; | ||
184 | |||
185 | if (WARN_ON_ONCE(!mm)) | ||
186 | return; | ||
187 | |||
188 | /* The page_table_lock ensures mm_users won't change under us */ | ||
189 | spin_lock(&mm->page_table_lock); | ||
190 | spin_lock(mm->context.cop_lockp); | ||
191 | |||
192 | mm->context.acop &= ~acop; | ||
193 | |||
194 | if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) { | ||
195 | free_pid = mm->context.cop_pid; | ||
196 | mm->context.cop_pid = COP_PID_NONE; | ||
197 | } | ||
198 | |||
199 | sync_cop(mm); | ||
200 | |||
201 | /* | ||
202 | * If this is a threaded process then there might be other threads | ||
203 | * running. We need to send an IPI to force them to pick up any | ||
204 | * change in PID and ACOP. | ||
205 | */ | ||
206 | if (atomic_read(&mm->mm_users) > 1) | ||
207 | smp_call_function(sync_cop, mm, 1); | ||
208 | |||
209 | if (free_pid != COP_PID_NONE) { | ||
210 | spin_lock(&mmu_context_acop_lock); | ||
211 | ida_remove(&cop_ida, free_pid); | ||
212 | spin_unlock(&mmu_context_acop_lock); | ||
213 | } | ||
214 | |||
215 | spin_unlock(mm->context.cop_lockp); | ||
216 | spin_unlock(&mm->page_table_lock); | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(drop_cop); | ||
219 | |||
220 | #endif /* CONFIG_PPC_ICSWX */ | ||
221 | 28 | ||
222 | static DEFINE_SPINLOCK(mmu_context_lock); | 29 | static DEFINE_SPINLOCK(mmu_context_lock); |
223 | static DEFINE_IDA(mmu_context_ida); | 30 | static DEFINE_IDA(mmu_context_ida); |