aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/smp.c')
-rw-r--r--kernel/smp.c83
1 files changed, 44 insertions, 39 deletions
diff --git a/kernel/smp.c b/kernel/smp.c
index bbedbb7efe32..6ecf4b9895d4 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -74,9 +74,16 @@ static void generic_exec_single(int cpu, struct call_single_data *data)
74 spin_unlock_irqrestore(&dst->lock, flags); 74 spin_unlock_irqrestore(&dst->lock, flags);
75 75
76 /* 76 /*
77 * Make the list addition visible before sending the ipi. 77 * The list addition should be visible before sending the IPI
78 * handler locks the list to pull the entry off it because of
79 * normal cache coherency rules implied by spinlocks.
80 *
81 * If IPIs can go out of order to the cache coherency protocol
82 * in an architecture, sufficient synchronisation should be added
83 * to arch code to make it appear to obey cache coherency WRT
84 * locking and barrier primitives. Generic code isn't really equipped
85 * to do the right thing...
78 */ 86 */
79 smp_mb();
80 87
81 if (ipi) 88 if (ipi)
82 arch_send_call_function_single_ipi(cpu); 89 arch_send_call_function_single_ipi(cpu);
@@ -104,6 +111,14 @@ void generic_smp_call_function_interrupt(void)
104 int cpu = get_cpu(); 111 int cpu = get_cpu();
105 112
106 /* 113 /*
114 * Ensure entry is visible on call_function_queue after we have
115 * entered the IPI. See comment in smp_call_function_many.
116 * If we don't have this, then we may miss an entry on the list
117 * and never get another IPI to process it.
118 */
119 smp_mb();
120
121 /*
107 * It's ok to use list_for_each_rcu() here even though we may delete 122 * It's ok to use list_for_each_rcu() here even though we may delete
108 * 'pos', since list_del_rcu() doesn't clear ->next 123 * 'pos', since list_del_rcu() doesn't clear ->next
109 */ 124 */
@@ -154,49 +169,37 @@ void generic_smp_call_function_single_interrupt(void)
154{ 169{
155 struct call_single_queue *q = &__get_cpu_var(call_single_queue); 170 struct call_single_queue *q = &__get_cpu_var(call_single_queue);
156 LIST_HEAD(list); 171 LIST_HEAD(list);
172 unsigned int data_flags;
157 173
158 /* 174 spin_lock(&q->lock);
159 * Need to see other stores to list head for checking whether 175 list_replace_init(&q->list, &list);
160 * list is empty without holding q->lock 176 spin_unlock(&q->lock);
161 */
162 smp_read_barrier_depends();
163 while (!list_empty(&q->list)) {
164 unsigned int data_flags;
165
166 spin_lock(&q->lock);
167 list_replace_init(&q->list, &list);
168 spin_unlock(&q->lock);
169 177
170 while (!list_empty(&list)) { 178 while (!list_empty(&list)) {
171 struct call_single_data *data; 179 struct call_single_data *data;
172 180
173 data = list_entry(list.next, struct call_single_data, 181 data = list_entry(list.next, struct call_single_data,
174 list); 182 list);
175 list_del(&data->list); 183 list_del(&data->list);
176 184
177 /*
178 * 'data' can be invalid after this call if
179 * flags == 0 (when called through
180 * generic_exec_single(), so save them away before
181 * making the call.
182 */
183 data_flags = data->flags;
184
185 data->func(data->info);
186
187 if (data_flags & CSD_FLAG_WAIT) {
188 smp_wmb();
189 data->flags &= ~CSD_FLAG_WAIT;
190 } else if (data_flags & CSD_FLAG_LOCK) {
191 smp_wmb();
192 data->flags &= ~CSD_FLAG_LOCK;
193 } else if (data_flags & CSD_FLAG_ALLOC)
194 kfree(data);
195 }
196 /* 185 /*
197 * See comment on outer loop 186 * 'data' can be invalid after this call if
187 * flags == 0 (when called through
188 * generic_exec_single(), so save them away before
189 * making the call.
198 */ 190 */
199 smp_read_barrier_depends(); 191 data_flags = data->flags;
192
193 data->func(data->info);
194
195 if (data_flags & CSD_FLAG_WAIT) {
196 smp_wmb();
197 data->flags &= ~CSD_FLAG_WAIT;
198 } else if (data_flags & CSD_FLAG_LOCK) {
199 smp_wmb();
200 data->flags &= ~CSD_FLAG_LOCK;
201 } else if (data_flags & CSD_FLAG_ALLOC)
202 kfree(data);
200 } 203 }
201} 204}
202 205
@@ -375,6 +378,8 @@ void smp_call_function_many(const struct cpumask *mask,
375 378
376 /* 379 /*
377 * Make the list addition visible before sending the ipi. 380 * Make the list addition visible before sending the ipi.
381 * (IPIs must obey or appear to obey normal Linux cache coherency
382 * rules -- see comment in generic_exec_single).
378 */ 383 */
379 smp_mb(); 384 smp_mb();
380 385