blob: fc10b39893d42ee0cd4ed8a3e1102a79d7d51273 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/m32r/kernel/smp.c
3 *
4 * M32R SMP support routines.
5 *
6 * Copyright (c) 2001, 2002 Hitoshi Yamamoto
7 *
8 * Taken from i386 version.
9 * (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
10 * (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
11 *
12 * This code is released under the GNU General Public License version 2 or
13 * later.
14 */
15
16#undef DEBUG_SMP
17
18#include <linux/irq.h>
19#include <linux/interrupt.h>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040020#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/spinlock.h>
22#include <linux/mm.h>
23#include <linux/smp.h>
24#include <linux/profile.h>
25#include <linux/cpu.h>
26
27#include <asm/cacheflush.h>
28#include <asm/pgalloc.h>
29#include <asm/atomic.h>
30#include <asm/io.h>
31#include <asm/mmu_context.h>
32#include <asm/m32r.h>
33
34/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
35/* Data structures and variables */
36/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
37
38/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 * For flush_cache_all()
40 */
41static DEFINE_SPINLOCK(flushcache_lock);
42static volatile unsigned long flushcache_cpumask = 0;
43
44/*
45 * For flush_tlb_others()
46 */
47static volatile cpumask_t flush_cpumask;
48static struct mm_struct *flush_mm;
49static struct vm_area_struct *flush_vma;
50static volatile unsigned long flush_va;
51static DEFINE_SPINLOCK(tlbstate_lock);
52#define FLUSH_ALL 0xffffffff
53
54DECLARE_PER_CPU(int, prof_multiplier);
55DECLARE_PER_CPU(int, prof_old_multiplier);
56DECLARE_PER_CPU(int, prof_counter);
57
58extern spinlock_t ipi_lock[];
59
60/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
61/* Function Prototypes */
62/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
63
64void smp_send_reschedule(int);
65void smp_reschedule_interrupt(void);
66
67void smp_flush_cache_all(void);
68void smp_flush_cache_all_interrupt(void);
69
70void smp_flush_tlb_all(void);
71static void flush_tlb_all_ipi(void *);
72
73void smp_flush_tlb_mm(struct mm_struct *);
74void smp_flush_tlb_range(struct vm_area_struct *, unsigned long, \
75 unsigned long);
76void smp_flush_tlb_page(struct vm_area_struct *, unsigned long);
77static void flush_tlb_others(cpumask_t, struct mm_struct *,
78 struct vm_area_struct *, unsigned long);
79void smp_invalidate_interrupt(void);
80
81void smp_send_stop(void);
82static void stop_this_cpu(void *);
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084void smp_send_timer(void);
85void smp_ipi_timer_interrupt(struct pt_regs *);
Al Viro9c8e7f52006-10-07 16:29:18 +010086void smp_local_timer_interrupt(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Adrian Bunk81e48072008-09-24 15:01:47 +090088static void send_IPI_allbutself(int, int);
Rusty Russellc2a3a482009-09-24 09:34:43 -060089static void send_IPI_mask(const struct cpumask *, int, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090unsigned long send_IPI_mask_phys(cpumask_t, int, int);
91
92/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
93/* Rescheduling request Routines */
94/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
95
96/*==========================================================================*
97 * Name: smp_send_reschedule
98 *
99 * Description: This routine requests other CPU to execute rescheduling.
100 * 1.Send 'RESCHEDULE_IPI' to other CPU.
101 * Request other CPU to execute 'smp_reschedule_interrupt()'.
102 *
103 * Born on Date: 2002.02.05
104 *
105 * Arguments: cpu_id - Target CPU ID
106 *
107 * Returns: void (cannot fail)
108 *
109 * Modification log:
110 * Date Who Description
111 * ---------- --- --------------------------------------------------------
112 *
113 *==========================================================================*/
114void smp_send_reschedule(int cpu_id)
115{
116 WARN_ON(cpu_is_offline(cpu_id));
Rusty Russellc2a3a482009-09-24 09:34:43 -0600117 send_IPI_mask(cpumask_of(cpu_id), RESCHEDULE_IPI, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118}
119
120/*==========================================================================*
121 * Name: smp_reschedule_interrupt
122 *
123 * Description: This routine executes on CPU which received
124 * 'RESCHEDULE_IPI'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 *
126 * Born on Date: 2002.02.05
127 *
128 * Arguments: NONE
129 *
130 * Returns: void (cannot fail)
131 *
132 * Modification log:
133 * Date Who Description
134 * ---------- --- --------------------------------------------------------
135 *
136 *==========================================================================*/
137void smp_reschedule_interrupt(void)
138{
Peter Zijlstra184748c2011-04-05 17:23:39 +0200139 scheduler_ipi();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140}
141
142/*==========================================================================*
143 * Name: smp_flush_cache_all
144 *
145 * Description: This routine sends a 'INVALIDATE_CACHE_IPI' to all other
146 * CPUs in the system.
147 *
148 * Born on Date: 2003-05-28
149 *
150 * Arguments: NONE
151 *
152 * Returns: void (cannot fail)
153 *
154 * Modification log:
155 * Date Who Description
156 * ---------- --- --------------------------------------------------------
157 *
158 *==========================================================================*/
159void smp_flush_cache_all(void)
160{
161 cpumask_t cpumask;
162 unsigned long *mask;
163
164 preempt_disable();
165 cpumask = cpu_online_map;
166 cpu_clear(smp_processor_id(), cpumask);
167 spin_lock(&flushcache_lock);
168 mask=cpus_addr(cpumask);
169 atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask);
Rusty Russellc2a3a482009-09-24 09:34:43 -0600170 send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 _flush_cache_copyback_all();
172 while (flushcache_cpumask)
173 mb();
174 spin_unlock(&flushcache_lock);
175 preempt_enable();
176}
177
178void smp_flush_cache_all_interrupt(void)
179{
180 _flush_cache_copyback_all();
181 clear_bit(smp_processor_id(), &flushcache_cpumask);
182}
183
184/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200185/* TLB flush request Routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
187
188/*==========================================================================*
189 * Name: smp_flush_tlb_all
190 *
191 * Description: This routine flushes all processes TLBs.
192 * 1.Request other CPU to execute 'flush_tlb_all_ipi()'.
193 * 2.Execute 'do_flush_tlb_all_local()'.
194 *
195 * Born on Date: 2002.02.05
196 *
197 * Arguments: NONE
198 *
199 * Returns: void (cannot fail)
200 *
201 * Modification log:
202 * Date Who Description
203 * ---------- --- --------------------------------------------------------
204 *
205 *==========================================================================*/
206void smp_flush_tlb_all(void)
207{
208 unsigned long flags;
209
210 preempt_disable();
211 local_irq_save(flags);
212 __flush_tlb_all();
213 local_irq_restore(flags);
Jens Axboe8691e5a2008-06-06 11:18:06 +0200214 smp_call_function(flush_tlb_all_ipi, NULL, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 preempt_enable();
216}
217
218/*==========================================================================*
219 * Name: flush_tlb_all_ipi
220 *
221 * Description: This routine flushes all local TLBs.
222 * 1.Execute 'do_flush_tlb_all_local()'.
223 *
224 * Born on Date: 2002.02.05
225 *
226 * Arguments: *info - not used
227 *
228 * Returns: void (cannot fail)
229 *
230 * Modification log:
231 * Date Who Description
232 * ---------- --- --------------------------------------------------------
233 *
234 *==========================================================================*/
235static void flush_tlb_all_ipi(void *info)
236{
237 __flush_tlb_all();
238}
239
240/*==========================================================================*
241 * Name: smp_flush_tlb_mm
242 *
243 * Description: This routine flushes the specified mm context TLB's.
244 *
245 * Born on Date: 2002.02.05
246 *
247 * Arguments: *mm - a pointer to the mm struct for flush TLB
248 *
249 * Returns: void (cannot fail)
250 *
251 * Modification log:
252 * Date Who Description
253 * ---------- --- --------------------------------------------------------
254 *
255 *==========================================================================*/
256void smp_flush_tlb_mm(struct mm_struct *mm)
257{
Hirokazu Takataa90933f2005-10-14 15:59:07 -0700258 int cpu_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 cpumask_t cpu_mask;
Hirokazu Takataa90933f2005-10-14 15:59:07 -0700260 unsigned long *mmc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 unsigned long flags;
262
263 preempt_disable();
Hirokazu Takataa90933f2005-10-14 15:59:07 -0700264 cpu_id = smp_processor_id();
265 mmc = &mm->context[cpu_id];
Rusty Russell49b92052009-09-24 09:34:49 -0600266 cpu_mask = *mm_cpumask(mm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 cpu_clear(cpu_id, cpu_mask);
268
269 if (*mmc != NO_CONTEXT) {
270 local_irq_save(flags);
271 *mmc = NO_CONTEXT;
272 if (mm == current->mm)
273 activate_context(mm);
274 else
Rusty Russell49b92052009-09-24 09:34:49 -0600275 cpumask_clear_cpu(cpu_id, mm_cpumask(mm));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 local_irq_restore(flags);
277 }
278 if (!cpus_empty(cpu_mask))
279 flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL);
280
281 preempt_enable();
282}
283
284/*==========================================================================*
285 * Name: smp_flush_tlb_range
286 *
287 * Description: This routine flushes a range of pages.
288 *
289 * Born on Date: 2002.02.05
290 *
291 * Arguments: *mm - a pointer to the mm struct for flush TLB
292 * start - not used
293 * end - not used
294 *
295 * Returns: void (cannot fail)
296 *
297 * Modification log:
298 * Date Who Description
299 * ---------- --- --------------------------------------------------------
300 *
301 *==========================================================================*/
302void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
303 unsigned long end)
304{
305 smp_flush_tlb_mm(vma->vm_mm);
306}
307
308/*==========================================================================*
309 * Name: smp_flush_tlb_page
310 *
311 * Description: This routine flushes one page.
312 *
313 * Born on Date: 2002.02.05
314 *
315 * Arguments: *vma - a pointer to the vma struct include va
316 * va - virtual address for flush TLB
317 *
318 * Returns: void (cannot fail)
319 *
320 * Modification log:
321 * Date Who Description
322 * ---------- --- --------------------------------------------------------
323 *
324 *==========================================================================*/
325void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
326{
327 struct mm_struct *mm = vma->vm_mm;
Hirokazu Takataa90933f2005-10-14 15:59:07 -0700328 int cpu_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 cpumask_t cpu_mask;
Hirokazu Takataa90933f2005-10-14 15:59:07 -0700330 unsigned long *mmc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 unsigned long flags;
332
333 preempt_disable();
Hirokazu Takataa90933f2005-10-14 15:59:07 -0700334 cpu_id = smp_processor_id();
335 mmc = &mm->context[cpu_id];
Rusty Russell49b92052009-09-24 09:34:49 -0600336 cpu_mask = *mm_cpumask(mm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 cpu_clear(cpu_id, cpu_mask);
338
339#ifdef DEBUG_SMP
340 if (!mm)
341 BUG();
342#endif
343
344 if (*mmc != NO_CONTEXT) {
345 local_irq_save(flags);
346 va &= PAGE_MASK;
347 va |= (*mmc & MMU_CONTEXT_ASID_MASK);
348 __flush_tlb_page(va);
349 local_irq_restore(flags);
350 }
351 if (!cpus_empty(cpu_mask))
352 flush_tlb_others(cpu_mask, mm, vma, va);
353
354 preempt_enable();
355}
356
357/*==========================================================================*
358 * Name: flush_tlb_others
359 *
360 * Description: This routine requests other CPU to execute flush TLB.
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200361 * 1.Setup parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 * 2.Send 'INVALIDATE_TLB_IPI' to other CPU.
363 * Request other CPU to execute 'smp_invalidate_interrupt()'.
364 * 3.Wait for other CPUs operation finished.
365 *
366 * Born on Date: 2002.02.05
367 *
368 * Arguments: cpumask - bitmap of target CPUs
369 * *mm - a pointer to the mm struct for flush TLB
370 * *vma - a pointer to the vma struct include va
371 * va - virtual address for flush TLB
372 *
373 * Returns: void (cannot fail)
374 *
375 * Modification log:
376 * Date Who Description
377 * ---------- --- --------------------------------------------------------
378 *
379 *==========================================================================*/
380static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
381 struct vm_area_struct *vma, unsigned long va)
382{
383 unsigned long *mask;
384#ifdef DEBUG_SMP
385 unsigned long flags;
386 __save_flags(flags);
387 if (!(flags & 0x0040)) /* Interrupt Disable NONONO */
388 BUG();
389#endif /* DEBUG_SMP */
390
391 /*
392 * A couple of (to be removed) sanity checks:
393 *
394 * - we do not send IPIs to not-yet booted CPUs.
395 * - current CPU must not be in mask
396 * - mask must exist :)
397 */
398 BUG_ON(cpus_empty(cpumask));
399
400 BUG_ON(cpu_isset(smp_processor_id(), cpumask));
401 BUG_ON(!mm);
402
403 /* If a CPU which we ran on has gone down, OK. */
404 cpus_and(cpumask, cpumask, cpu_online_map);
405 if (cpus_empty(cpumask))
406 return;
407
408 /*
409 * i'm not happy about this global shared spinlock in the
410 * MM hot path, but we'll see how contended it is.
411 * Temporarily this turns IRQs off, so that lockups are
412 * detected by the NMI watchdog.
413 */
414 spin_lock(&tlbstate_lock);
415
416 flush_mm = mm;
417 flush_vma = vma;
418 flush_va = va;
419 mask=cpus_addr(cpumask);
420 atomic_set_mask(*mask, (atomic_t *)&flush_cpumask);
421
422 /*
423 * We have to send the IPI only to
424 * CPUs affected.
425 */
Rusty Russellc2a3a482009-09-24 09:34:43 -0600426 send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 while (!cpus_empty(flush_cpumask)) {
429 /* nothing. lockup detection does not belong here */
430 mb();
431 }
432
433 flush_mm = NULL;
434 flush_vma = NULL;
435 flush_va = 0;
436 spin_unlock(&tlbstate_lock);
437}
438
439/*==========================================================================*
440 * Name: smp_invalidate_interrupt
441 *
442 * Description: This routine executes on CPU which received
443 * 'INVALIDATE_TLB_IPI'.
444 * 1.Flush local TLB.
445 * 2.Report flush TLB process was finished.
446 *
447 * Born on Date: 2002.02.05
448 *
449 * Arguments: NONE
450 *
451 * Returns: void (cannot fail)
452 *
453 * Modification log:
454 * Date Who Description
455 * ---------- --- --------------------------------------------------------
456 *
457 *==========================================================================*/
458void smp_invalidate_interrupt(void)
459{
460 int cpu_id = smp_processor_id();
461 unsigned long *mmc = &flush_mm->context[cpu_id];
462
463 if (!cpu_isset(cpu_id, flush_cpumask))
464 return;
465
466 if (flush_va == FLUSH_ALL) {
467 *mmc = NO_CONTEXT;
468 if (flush_mm == current->active_mm)
469 activate_context(flush_mm);
470 else
Rusty Russell49b92052009-09-24 09:34:49 -0600471 cpumask_clear_cpu(cpu_id, mm_cpumask(flush_mm));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 } else {
473 unsigned long va = flush_va;
474
475 if (*mmc != NO_CONTEXT) {
476 va &= PAGE_MASK;
477 va |= (*mmc & MMU_CONTEXT_ASID_MASK);
478 __flush_tlb_page(va);
479 }
480 }
481 cpu_clear(cpu_id, flush_cpumask);
482}
483
484/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200485/* Stop CPU request Routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
487
488/*==========================================================================*
489 * Name: smp_send_stop
490 *
491 * Description: This routine requests stop all CPUs.
492 * 1.Request other CPU to execute 'stop_this_cpu()'.
493 *
494 * Born on Date: 2002.02.05
495 *
496 * Arguments: NONE
497 *
498 * Returns: void (cannot fail)
499 *
500 * Modification log:
501 * Date Who Description
502 * ---------- --- --------------------------------------------------------
503 *
504 *==========================================================================*/
505void smp_send_stop(void)
506{
Jens Axboe8691e5a2008-06-06 11:18:06 +0200507 smp_call_function(stop_this_cpu, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
510/*==========================================================================*
511 * Name: stop_this_cpu
512 *
513 * Description: This routine halt CPU.
514 *
515 * Born on Date: 2002.02.05
516 *
517 * Arguments: NONE
518 *
519 * Returns: void (cannot fail)
520 *
521 * Modification log:
522 * Date Who Description
523 * ---------- --- --------------------------------------------------------
524 *
525 *==========================================================================*/
526static void stop_this_cpu(void *dummy)
527{
528 int cpu_id = smp_processor_id();
529
530 /*
531 * Remove this CPU:
532 */
533 cpu_clear(cpu_id, cpu_online_map);
534
535 /*
536 * PSW IE = 1;
537 * IMASK = 0;
538 * goto SLEEP
539 */
540 local_irq_disable();
541 outl(0, M32R_ICU_IMASK_PORTL);
542 inl(M32R_ICU_IMASK_PORTL); /* dummy read */
543 local_irq_enable();
544
545 for ( ; ; );
546}
547
Rusty Russellc2a3a482009-09-24 09:34:43 -0600548void arch_send_call_function_ipi_mask(const struct cpumask *mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
Jens Axboe7b7426c2008-06-10 20:49:30 +0200550 send_IPI_mask(mask, CALL_FUNCTION_IPI, 0);
551}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Jens Axboe7b7426c2008-06-10 20:49:30 +0200553void arch_send_call_function_single_ipi(int cpu)
554{
Rusty Russellc2a3a482009-09-24 09:34:43 -0600555 send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556}
557
558/*==========================================================================*
559 * Name: smp_call_function_interrupt
560 *
561 * Description: This routine executes on CPU which received
562 * 'CALL_FUNCTION_IPI'.
563 *
564 * Born on Date: 2002.02.05
565 *
566 * Arguments: NONE
567 *
568 * Returns: void (cannot fail)
569 *
570 * Modification log:
571 * Date Who Description
572 * ---------- --- --------------------------------------------------------
573 *
574 *==========================================================================*/
575void smp_call_function_interrupt(void)
576{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 irq_enter();
Jens Axboe7b7426c2008-06-10 20:49:30 +0200578 generic_smp_call_function_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 irq_exit();
Jens Axboe7b7426c2008-06-10 20:49:30 +0200580}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Jens Axboe7b7426c2008-06-10 20:49:30 +0200582void smp_call_function_single_interrupt(void)
583{
584 irq_enter();
585 generic_smp_call_function_single_interrupt();
586 irq_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587}
588
589/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200590/* Timer Routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
592
593/*==========================================================================*
594 * Name: smp_send_timer
595 *
596 * Description: This routine sends a 'LOCAL_TIMER_IPI' to all other CPUs
597 * in the system.
598 *
599 * Born on Date: 2002.02.05
600 *
601 * Arguments: NONE
602 *
603 * Returns: void (cannot fail)
604 *
605 * Modification log:
606 * Date Who Description
607 * ---------- --- --------------------------------------------------------
608 *
609 *==========================================================================*/
610void smp_send_timer(void)
611{
612 send_IPI_allbutself(LOCAL_TIMER_IPI, 1);
613}
614
615/*==========================================================================*
616 * Name: smp_send_timer
617 *
618 * Description: This routine executes on CPU which received
619 * 'LOCAL_TIMER_IPI'.
620 *
621 * Born on Date: 2002.02.05
622 *
623 * Arguments: *regs - a pointer to the saved regster info
624 *
625 * Returns: void (cannot fail)
626 *
627 * Modification log:
628 * Date Who Description
629 * ---------- --- --------------------------------------------------------
630 *
631 *==========================================================================*/
632void smp_ipi_timer_interrupt(struct pt_regs *regs)
633{
Al Viro9c8e7f52006-10-07 16:29:18 +0100634 struct pt_regs *old_regs;
635 old_regs = set_irq_regs(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 irq_enter();
Al Viro9c8e7f52006-10-07 16:29:18 +0100637 smp_local_timer_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 irq_exit();
Al Viro9c8e7f52006-10-07 16:29:18 +0100639 set_irq_regs(old_regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
642/*==========================================================================*
643 * Name: smp_local_timer_interrupt
644 *
645 * Description: Local timer interrupt handler. It does both profiling and
646 * process statistics/rescheduling.
647 * We do profiling in every local tick, statistics/rescheduling
648 * happen only every 'profiling multiplier' ticks. The default
649 * multiplier is 1 and it can be changed by writing the new
650 * multiplier value into /proc/profile.
651 *
652 * Born on Date: 2002.02.05
653 *
654 * Arguments: *regs - a pointer to the saved regster info
655 *
656 * Returns: void (cannot fail)
657 *
658 * Original: arch/i386/kernel/apic.c
659 *
660 * Modification log:
661 * Date Who Description
662 * ---------- --- --------------------------------------------------------
663 * 2003-06-24 hy use per_cpu structure.
664 *==========================================================================*/
Al Viro9c8e7f52006-10-07 16:29:18 +0100665void smp_local_timer_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
Al Viro9c8e7f52006-10-07 16:29:18 +0100667 int user = user_mode(get_irq_regs());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 int cpu_id = smp_processor_id();
669
670 /*
671 * The profiling function is SMP safe. (nothing can mess
672 * around with "current", and the profiling counters are
673 * updated with atomic operations). This is especially
674 * useful with a profiling multiplier != 1
675 */
676
Al Viro9c8e7f52006-10-07 16:29:18 +0100677 profile_tick(CPU_PROFILING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 if (--per_cpu(prof_counter, cpu_id) <= 0) {
680 /*
681 * The multiplier may have changed since the last time we got
682 * to this point as a result of the user writing to
683 * /proc/profile. In this case we need to adjust the APIC
684 * timer accordingly.
685 *
686 * Interrupts are already masked off at this point.
687 */
688 per_cpu(prof_counter, cpu_id)
689 = per_cpu(prof_multiplier, cpu_id);
690 if (per_cpu(prof_counter, cpu_id)
691 != per_cpu(prof_old_multiplier, cpu_id))
692 {
693 per_cpu(prof_old_multiplier, cpu_id)
694 = per_cpu(prof_counter, cpu_id);
695 }
696
697 update_process_times(user);
698 }
699}
700
701/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200702/* Send IPI Routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
704
705/*==========================================================================*
706 * Name: send_IPI_allbutself
707 *
708 * Description: This routine sends a IPI to all other CPUs in the system.
709 *
710 * Born on Date: 2002.02.05
711 *
712 * Arguments: ipi_num - Number of IPI
713 * try - 0 : Send IPI certainly.
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200714 * !0 : The following IPI is not sent when Target CPU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 * has not received the before IPI.
716 *
717 * Returns: void (cannot fail)
718 *
719 * Modification log:
720 * Date Who Description
721 * ---------- --- --------------------------------------------------------
722 *
723 *==========================================================================*/
Adrian Bunk81e48072008-09-24 15:01:47 +0900724static void send_IPI_allbutself(int ipi_num, int try)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
726 cpumask_t cpumask;
727
728 cpumask = cpu_online_map;
729 cpu_clear(smp_processor_id(), cpumask);
730
Rusty Russellc2a3a482009-09-24 09:34:43 -0600731 send_IPI_mask(&cpumask, ipi_num, try);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
734/*==========================================================================*
735 * Name: send_IPI_mask
736 *
737 * Description: This routine sends a IPI to CPUs in the system.
738 *
739 * Born on Date: 2002.02.05
740 *
741 * Arguments: cpu_mask - Bitmap of target CPUs logical ID
742 * ipi_num - Number of IPI
743 * try - 0 : Send IPI certainly.
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200744 * !0 : The following IPI is not sent when Target CPU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 * has not received the before IPI.
746 *
747 * Returns: void (cannot fail)
748 *
749 * Modification log:
750 * Date Who Description
751 * ---------- --- --------------------------------------------------------
752 *
753 *==========================================================================*/
Rusty Russellc2a3a482009-09-24 09:34:43 -0600754static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755{
756 cpumask_t physid_mask, tmp;
757 int cpu_id, phys_id;
758 int num_cpus = num_online_cpus();
759
760 if (num_cpus <= 1) /* NO MP */
761 return;
762
Rusty Russellc2a3a482009-09-24 09:34:43 -0600763 cpumask_and(&tmp, cpumask, cpu_online_mask);
764 BUG_ON(!cpumask_equal(cpumask, &tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 physid_mask = CPU_MASK_NONE;
Rusty Russellc2a3a482009-09-24 09:34:43 -0600767 for_each_cpu(cpu_id, cpumask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if ((phys_id = cpu_to_physid(cpu_id)) != -1)
769 cpu_set(phys_id, physid_mask);
770 }
771
772 send_IPI_mask_phys(physid_mask, ipi_num, try);
773}
774
775/*==========================================================================*
776 * Name: send_IPI_mask_phys
777 *
778 * Description: This routine sends a IPI to other CPUs in the system.
779 *
780 * Born on Date: 2002.02.05
781 *
782 * Arguments: cpu_mask - Bitmap of target CPUs physical ID
783 * ipi_num - Number of IPI
784 * try - 0 : Send IPI certainly.
Simon Arlott5aa8b6c2007-10-20 01:14:39 +0200785 * !0 : The following IPI is not sent when Target CPU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 * has not received the before IPI.
787 *
788 * Returns: IPICRi regster value.
789 *
790 * Modification log:
791 * Date Who Description
792 * ---------- --- --------------------------------------------------------
793 *
794 *==========================================================================*/
795unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num,
796 int try)
797{
798 spinlock_t *ipilock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 volatile unsigned long *ipicr_addr;
800 unsigned long ipicr_val;
801 unsigned long my_physid_mask;
802 unsigned long mask = cpus_addr(physid_mask)[0];
803
804
805 if (mask & ~physids_coerce(phys_cpu_present_map))
806 BUG();
Roel Kluin45cdd472009-11-01 15:33:06 +0100807 if (ipi_num >= NR_IPIS || ipi_num < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 BUG();
809
810 mask <<= IPI_SHIFT;
811 ipilock = &ipi_lock[ipi_num];
812 ipicr_addr = (volatile unsigned long *)(M32R_ICU_IPICR_ADDR
813 + (ipi_num << 2));
814 my_physid_mask = ~(1 << smp_processor_id());
815
816 /*
817 * lock ipi_lock[i]
818 * check IPICRi == 0
819 * write IPICRi (send IPIi)
820 * unlock ipi_lock[i]
821 */
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700822 spin_lock(ipilock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 __asm__ __volatile__ (
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 ";; CHECK IPICRi == 0 \n\t"
825 ".fillinsn \n"
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700826 "1: \n\t"
827 "ld %0, @%1 \n\t"
828 "and %0, %4 \n\t"
829 "beqz %0, 2f \n\t"
830 "bnez %3, 3f \n\t"
831 "bra 1b \n\t"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 ";; WRITE IPICRi (send IPIi) \n\t"
833 ".fillinsn \n"
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700834 "2: \n\t"
835 "st %2, @%1 \n\t"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 ".fillinsn \n"
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700837 "3: \n\t"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 : "=&r"(ipicr_val)
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700839 : "r"(ipicr_addr), "r"(mask), "r"(try), "r"(my_physid_mask)
840 : "memory"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 );
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700842 spin_unlock(ipilock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
844 return ipicr_val;
845}