aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m32r/kernel/smp.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2018-03-07 15:36:19 -0500
committerArnd Bergmann <arnd@arndb.de>2018-03-09 17:20:00 -0500
commit553b085c2075f6a4a2591108554f830fa61e881f (patch)
tree68d63911f2c12e0fb9fa23498df9300442a88f92 /arch/m32r/kernel/smp.c
parentfd8773f9f544955f6f47dc2ac3ab85ad64376b7f (diff)
arch: remove m32r port
The Mitsubishi/Renesas m32r architecture has been around for many years, but the Linux port has been obsolete for a very long time as well, with the last significant updates done for linux-2.6.14. While some m32r microcontrollers are still being marketed by Renesas, those are apparently no longer possible to support, mainly due to the lack of an external memory interface. Hirokazu Takata was the maintainer until the architecture got marked Orphaned in 2014. Link: http://www.linux-m32r.org/ Link: https://www.renesas.com/en-eu/products/microcontrollers-microprocessors/m32r.html Cc: Hirokazu Takata <takata@linux-m32r.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/m32r/kernel/smp.c')
-rw-r--r--arch/m32r/kernel/smp.c836
1 files changed, 0 insertions, 836 deletions
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
deleted file mode 100644
index 564052e3d3a0..000000000000
--- a/arch/m32r/kernel/smp.c
+++ /dev/null
@@ -1,836 +0,0 @@
1/*
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>
20#include <linux/sched.h>
21#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 <linux/atomic.h>
30#include <asm/io.h>
31#include <asm/mmu_context.h>
32#include <asm/m32r.h>
33#include <asm/tlbflush.h>
34
35/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
36/* Data structures and variables */
37/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
38
39/*
40 * For flush_cache_all()
41 */
42static DEFINE_SPINLOCK(flushcache_lock);
43static volatile unsigned long flushcache_cpumask = 0;
44
45/*
46 * For flush_tlb_others()
47 */
48static cpumask_t flush_cpumask;
49static struct mm_struct *flush_mm;
50static struct vm_area_struct *flush_vma;
51static volatile unsigned long flush_va;
52static DEFINE_SPINLOCK(tlbstate_lock);
53#define FLUSH_ALL 0xffffffff
54
55DECLARE_PER_CPU(int, prof_multiplier);
56DECLARE_PER_CPU(int, prof_old_multiplier);
57DECLARE_PER_CPU(int, prof_counter);
58
59extern spinlock_t ipi_lock[];
60
61/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
62/* Function Prototypes */
63/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
64
65void smp_reschedule_interrupt(void);
66void smp_flush_cache_all_interrupt(void);
67
68static void flush_tlb_all_ipi(void *);
69static void flush_tlb_others(cpumask_t, struct mm_struct *,
70 struct vm_area_struct *, unsigned long);
71
72void smp_invalidate_interrupt(void);
73
74static void stop_this_cpu(void *);
75
76void smp_ipi_timer_interrupt(struct pt_regs *);
77void smp_local_timer_interrupt(void);
78
79static void send_IPI_allbutself(int, int);
80static void send_IPI_mask(const struct cpumask *, int, int);
81
82/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
83/* Rescheduling request Routines */
84/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
85
86/*==========================================================================*
87 * Name: smp_send_reschedule
88 *
89 * Description: This routine requests other CPU to execute rescheduling.
90 * 1.Send 'RESCHEDULE_IPI' to other CPU.
91 * Request other CPU to execute 'smp_reschedule_interrupt()'.
92 *
93 * Born on Date: 2002.02.05
94 *
95 * Arguments: cpu_id - Target CPU ID
96 *
97 * Returns: void (cannot fail)
98 *
99 * Modification log:
100 * Date Who Description
101 * ---------- --- --------------------------------------------------------
102 *
103 *==========================================================================*/
104void smp_send_reschedule(int cpu_id)
105{
106 WARN_ON(cpu_is_offline(cpu_id));
107 send_IPI_mask(cpumask_of(cpu_id), RESCHEDULE_IPI, 1);
108}
109
110/*==========================================================================*
111 * Name: smp_reschedule_interrupt
112 *
113 * Description: This routine executes on CPU which received
114 * 'RESCHEDULE_IPI'.
115 *
116 * Born on Date: 2002.02.05
117 *
118 * Arguments: NONE
119 *
120 * Returns: void (cannot fail)
121 *
122 * Modification log:
123 * Date Who Description
124 * ---------- --- --------------------------------------------------------
125 *
126 *==========================================================================*/
127void smp_reschedule_interrupt(void)
128{
129 scheduler_ipi();
130}
131
132/*==========================================================================*
133 * Name: smp_flush_cache_all
134 *
135 * Description: This routine sends a 'INVALIDATE_CACHE_IPI' to all other
136 * CPUs in the system.
137 *
138 * Born on Date: 2003-05-28
139 *
140 * Arguments: NONE
141 *
142 * Returns: void (cannot fail)
143 *
144 * Modification log:
145 * Date Who Description
146 * ---------- --- --------------------------------------------------------
147 *
148 *==========================================================================*/
149void smp_flush_cache_all(void)
150{
151 cpumask_t cpumask;
152 unsigned long *mask;
153
154 preempt_disable();
155 cpumask_copy(&cpumask, cpu_online_mask);
156 cpumask_clear_cpu(smp_processor_id(), &cpumask);
157 spin_lock(&flushcache_lock);
158 mask=cpumask_bits(&cpumask);
159 atomic_or(*mask, (atomic_t *)&flushcache_cpumask);
160 send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0);
161 _flush_cache_copyback_all();
162 while (flushcache_cpumask)
163 mb();
164 spin_unlock(&flushcache_lock);
165 preempt_enable();
166}
167EXPORT_SYMBOL(smp_flush_cache_all);
168
169void smp_flush_cache_all_interrupt(void)
170{
171 _flush_cache_copyback_all();
172 clear_bit(smp_processor_id(), &flushcache_cpumask);
173}
174
175/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
176/* TLB flush request Routines */
177/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
178
179/*==========================================================================*
180 * Name: smp_flush_tlb_all
181 *
182 * Description: This routine flushes all processes TLBs.
183 * 1.Request other CPU to execute 'flush_tlb_all_ipi()'.
184 * 2.Execute 'do_flush_tlb_all_local()'.
185 *
186 * Born on Date: 2002.02.05
187 *
188 * Arguments: NONE
189 *
190 * Returns: void (cannot fail)
191 *
192 * Modification log:
193 * Date Who Description
194 * ---------- --- --------------------------------------------------------
195 *
196 *==========================================================================*/
197void smp_flush_tlb_all(void)
198{
199 unsigned long flags;
200
201 preempt_disable();
202 local_irq_save(flags);
203 __flush_tlb_all();
204 local_irq_restore(flags);
205 smp_call_function(flush_tlb_all_ipi, NULL, 1);
206 preempt_enable();
207}
208
209/*==========================================================================*
210 * Name: flush_tlb_all_ipi
211 *
212 * Description: This routine flushes all local TLBs.
213 * 1.Execute 'do_flush_tlb_all_local()'.
214 *
215 * Born on Date: 2002.02.05
216 *
217 * Arguments: *info - not used
218 *
219 * Returns: void (cannot fail)
220 *
221 * Modification log:
222 * Date Who Description
223 * ---------- --- --------------------------------------------------------
224 *
225 *==========================================================================*/
226static void flush_tlb_all_ipi(void *info)
227{
228 __flush_tlb_all();
229}
230
231/*==========================================================================*
232 * Name: smp_flush_tlb_mm
233 *
234 * Description: This routine flushes the specified mm context TLB's.
235 *
236 * Born on Date: 2002.02.05
237 *
238 * Arguments: *mm - a pointer to the mm struct for flush TLB
239 *
240 * Returns: void (cannot fail)
241 *
242 * Modification log:
243 * Date Who Description
244 * ---------- --- --------------------------------------------------------
245 *
246 *==========================================================================*/
247void smp_flush_tlb_mm(struct mm_struct *mm)
248{
249 int cpu_id;
250 cpumask_t cpu_mask;
251 unsigned long *mmc;
252 unsigned long flags;
253
254 preempt_disable();
255 cpu_id = smp_processor_id();
256 mmc = &mm->context[cpu_id];
257 cpumask_copy(&cpu_mask, mm_cpumask(mm));
258 cpumask_clear_cpu(cpu_id, &cpu_mask);
259
260 if (*mmc != NO_CONTEXT) {
261 local_irq_save(flags);
262 *mmc = NO_CONTEXT;
263 if (mm == current->mm)
264 activate_context(mm);
265 else
266 cpumask_clear_cpu(cpu_id, mm_cpumask(mm));
267 local_irq_restore(flags);
268 }
269 if (!cpumask_empty(&cpu_mask))
270 flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL);
271
272 preempt_enable();
273}
274
275/*==========================================================================*
276 * Name: smp_flush_tlb_range
277 *
278 * Description: This routine flushes a range of pages.
279 *
280 * Born on Date: 2002.02.05
281 *
282 * Arguments: *mm - a pointer to the mm struct for flush TLB
283 * start - not used
284 * end - not used
285 *
286 * Returns: void (cannot fail)
287 *
288 * Modification log:
289 * Date Who Description
290 * ---------- --- --------------------------------------------------------
291 *
292 *==========================================================================*/
293void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
294 unsigned long end)
295{
296 smp_flush_tlb_mm(vma->vm_mm);
297}
298
299/*==========================================================================*
300 * Name: smp_flush_tlb_page
301 *
302 * Description: This routine flushes one page.
303 *
304 * Born on Date: 2002.02.05
305 *
306 * Arguments: *vma - a pointer to the vma struct include va
307 * va - virtual address for flush TLB
308 *
309 * Returns: void (cannot fail)
310 *
311 * Modification log:
312 * Date Who Description
313 * ---------- --- --------------------------------------------------------
314 *
315 *==========================================================================*/
316void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
317{
318 struct mm_struct *mm = vma->vm_mm;
319 int cpu_id;
320 cpumask_t cpu_mask;
321 unsigned long *mmc;
322 unsigned long flags;
323
324 preempt_disable();
325 cpu_id = smp_processor_id();
326 mmc = &mm->context[cpu_id];
327 cpumask_copy(&cpu_mask, mm_cpumask(mm));
328 cpumask_clear_cpu(cpu_id, &cpu_mask);
329
330#ifdef DEBUG_SMP
331 if (!mm)
332 BUG();
333#endif
334
335 if (*mmc != NO_CONTEXT) {
336 local_irq_save(flags);
337 va &= PAGE_MASK;
338 va |= (*mmc & MMU_CONTEXT_ASID_MASK);
339 __flush_tlb_page(va);
340 local_irq_restore(flags);
341 }
342 if (!cpumask_empty(&cpu_mask))
343 flush_tlb_others(cpu_mask, mm, vma, va);
344
345 preempt_enable();
346}
347
348/*==========================================================================*
349 * Name: flush_tlb_others
350 *
351 * Description: This routine requests other CPU to execute flush TLB.
352 * 1.Setup parameters.
353 * 2.Send 'INVALIDATE_TLB_IPI' to other CPU.
354 * Request other CPU to execute 'smp_invalidate_interrupt()'.
355 * 3.Wait for other CPUs operation finished.
356 *
357 * Born on Date: 2002.02.05
358 *
359 * Arguments: cpumask - bitmap of target CPUs
360 * *mm - a pointer to the mm struct for flush TLB
361 * *vma - a pointer to the vma struct include va
362 * va - virtual address for flush TLB
363 *
364 * Returns: void (cannot fail)
365 *
366 * Modification log:
367 * Date Who Description
368 * ---------- --- --------------------------------------------------------
369 *
370 *==========================================================================*/
371static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
372 struct vm_area_struct *vma, unsigned long va)
373{
374 unsigned long *mask;
375#ifdef DEBUG_SMP
376 unsigned long flags;
377 __save_flags(flags);
378 if (!(flags & 0x0040)) /* Interrupt Disable NONONO */
379 BUG();
380#endif /* DEBUG_SMP */
381
382 /*
383 * A couple of (to be removed) sanity checks:
384 *
385 * - we do not send IPIs to not-yet booted CPUs.
386 * - current CPU must not be in mask
387 * - mask must exist :)
388 */
389 BUG_ON(cpumask_empty(&cpumask));
390
391 BUG_ON(cpumask_test_cpu(smp_processor_id(), &cpumask));
392 BUG_ON(!mm);
393
394 /* If a CPU which we ran on has gone down, OK. */
395 cpumask_and(&cpumask, &cpumask, cpu_online_mask);
396 if (cpumask_empty(&cpumask))
397 return;
398
399 /*
400 * i'm not happy about this global shared spinlock in the
401 * MM hot path, but we'll see how contended it is.
402 * Temporarily this turns IRQs off, so that lockups are
403 * detected by the NMI watchdog.
404 */
405 spin_lock(&tlbstate_lock);
406
407 flush_mm = mm;
408 flush_vma = vma;
409 flush_va = va;
410 mask=cpumask_bits(&cpumask);
411 atomic_or(*mask, (atomic_t *)&flush_cpumask);
412
413 /*
414 * We have to send the IPI only to
415 * CPUs affected.
416 */
417 send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);
418
419 while (!cpumask_empty(&flush_cpumask)) {
420 /* nothing. lockup detection does not belong here */
421 mb();
422 }
423
424 flush_mm = NULL;
425 flush_vma = NULL;
426 flush_va = 0;
427 spin_unlock(&tlbstate_lock);
428}
429
430/*==========================================================================*
431 * Name: smp_invalidate_interrupt
432 *
433 * Description: This routine executes on CPU which received
434 * 'INVALIDATE_TLB_IPI'.
435 * 1.Flush local TLB.
436 * 2.Report flush TLB process was finished.
437 *
438 * Born on Date: 2002.02.05
439 *
440 * Arguments: NONE
441 *
442 * Returns: void (cannot fail)
443 *
444 * Modification log:
445 * Date Who Description
446 * ---------- --- --------------------------------------------------------
447 *
448 *==========================================================================*/
449void smp_invalidate_interrupt(void)
450{
451 int cpu_id = smp_processor_id();
452 unsigned long *mmc = &flush_mm->context[cpu_id];
453
454 if (!cpumask_test_cpu(cpu_id, &flush_cpumask))
455 return;
456
457 if (flush_va == FLUSH_ALL) {
458 *mmc = NO_CONTEXT;
459 if (flush_mm == current->active_mm)
460 activate_context(flush_mm);
461 else
462 cpumask_clear_cpu(cpu_id, mm_cpumask(flush_mm));
463 } else {
464 unsigned long va = flush_va;
465
466 if (*mmc != NO_CONTEXT) {
467 va &= PAGE_MASK;
468 va |= (*mmc & MMU_CONTEXT_ASID_MASK);
469 __flush_tlb_page(va);
470 }
471 }
472 cpumask_clear_cpu(cpu_id, &flush_cpumask);
473}
474
475/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
476/* Stop CPU request Routines */
477/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
478
479/*==========================================================================*
480 * Name: smp_send_stop
481 *
482 * Description: This routine requests stop all CPUs.
483 * 1.Request other CPU to execute 'stop_this_cpu()'.
484 *
485 * Born on Date: 2002.02.05
486 *
487 * Arguments: NONE
488 *
489 * Returns: void (cannot fail)
490 *
491 * Modification log:
492 * Date Who Description
493 * ---------- --- --------------------------------------------------------
494 *
495 *==========================================================================*/
496void smp_send_stop(void)
497{
498 smp_call_function(stop_this_cpu, NULL, 0);
499}
500
501/*==========================================================================*
502 * Name: stop_this_cpu
503 *
504 * Description: This routine halt CPU.
505 *
506 * Born on Date: 2002.02.05
507 *
508 * Arguments: NONE
509 *
510 * Returns: void (cannot fail)
511 *
512 * Modification log:
513 * Date Who Description
514 * ---------- --- --------------------------------------------------------
515 *
516 *==========================================================================*/
517static void stop_this_cpu(void *dummy)
518{
519 int cpu_id = smp_processor_id();
520
521 /*
522 * Remove this CPU:
523 */
524 set_cpu_online(cpu_id, false);
525
526 /*
527 * PSW IE = 1;
528 * IMASK = 0;
529 * goto SLEEP
530 */
531 local_irq_disable();
532 outl(0, M32R_ICU_IMASK_PORTL);
533 inl(M32R_ICU_IMASK_PORTL); /* dummy read */
534 local_irq_enable();
535
536 for ( ; ; );
537}
538
539void arch_send_call_function_ipi_mask(const struct cpumask *mask)
540{
541 send_IPI_mask(mask, CALL_FUNCTION_IPI, 0);
542}
543
544void arch_send_call_function_single_ipi(int cpu)
545{
546 send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI, 0);
547}
548
549/*==========================================================================*
550 * Name: smp_call_function_interrupt
551 *
552 * Description: This routine executes on CPU which received
553 * 'CALL_FUNCTION_IPI'.
554 *
555 * Born on Date: 2002.02.05
556 *
557 * Arguments: NONE
558 *
559 * Returns: void (cannot fail)
560 *
561 * Modification log:
562 * Date Who Description
563 * ---------- --- --------------------------------------------------------
564 *
565 *==========================================================================*/
566void smp_call_function_interrupt(void)
567{
568 irq_enter();
569 generic_smp_call_function_interrupt();
570 irq_exit();
571}
572
573void smp_call_function_single_interrupt(void)
574{
575 irq_enter();
576 generic_smp_call_function_single_interrupt();
577 irq_exit();
578}
579
580/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
581/* Timer Routines */
582/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
583
584/*==========================================================================*
585 * Name: smp_send_timer
586 *
587 * Description: This routine sends a 'LOCAL_TIMER_IPI' to all other CPUs
588 * in the system.
589 *
590 * Born on Date: 2002.02.05
591 *
592 * Arguments: NONE
593 *
594 * Returns: void (cannot fail)
595 *
596 * Modification log:
597 * Date Who Description
598 * ---------- --- --------------------------------------------------------
599 *
600 *==========================================================================*/
601void smp_send_timer(void)
602{
603 send_IPI_allbutself(LOCAL_TIMER_IPI, 1);
604}
605
606/*==========================================================================*
607 * Name: smp_send_timer
608 *
609 * Description: This routine executes on CPU which received
610 * 'LOCAL_TIMER_IPI'.
611 *
612 * Born on Date: 2002.02.05
613 *
614 * Arguments: *regs - a pointer to the saved regster info
615 *
616 * Returns: void (cannot fail)
617 *
618 * Modification log:
619 * Date Who Description
620 * ---------- --- --------------------------------------------------------
621 *
622 *==========================================================================*/
623void smp_ipi_timer_interrupt(struct pt_regs *regs)
624{
625 struct pt_regs *old_regs;
626 old_regs = set_irq_regs(regs);
627 irq_enter();
628 smp_local_timer_interrupt();
629 irq_exit();
630 set_irq_regs(old_regs);
631}
632
633/*==========================================================================*
634 * Name: smp_local_timer_interrupt
635 *
636 * Description: Local timer interrupt handler. It does both profiling and
637 * process statistics/rescheduling.
638 * We do profiling in every local tick, statistics/rescheduling
639 * happen only every 'profiling multiplier' ticks. The default
640 * multiplier is 1 and it can be changed by writing the new
641 * multiplier value into /proc/profile.
642 *
643 * Born on Date: 2002.02.05
644 *
645 * Arguments: *regs - a pointer to the saved regster info
646 *
647 * Returns: void (cannot fail)
648 *
649 * Original: arch/i386/kernel/apic.c
650 *
651 * Modification log:
652 * Date Who Description
653 * ---------- --- --------------------------------------------------------
654 * 2003-06-24 hy use per_cpu structure.
655 *==========================================================================*/
656void smp_local_timer_interrupt(void)
657{
658 int user = user_mode(get_irq_regs());
659 int cpu_id = smp_processor_id();
660
661 /*
662 * The profiling function is SMP safe. (nothing can mess
663 * around with "current", and the profiling counters are
664 * updated with atomic operations). This is especially
665 * useful with a profiling multiplier != 1
666 */
667
668 profile_tick(CPU_PROFILING);
669
670 if (--per_cpu(prof_counter, cpu_id) <= 0) {
671 /*
672 * The multiplier may have changed since the last time we got
673 * to this point as a result of the user writing to
674 * /proc/profile. In this case we need to adjust the APIC
675 * timer accordingly.
676 *
677 * Interrupts are already masked off at this point.
678 */
679 per_cpu(prof_counter, cpu_id)
680 = per_cpu(prof_multiplier, cpu_id);
681 if (per_cpu(prof_counter, cpu_id)
682 != per_cpu(prof_old_multiplier, cpu_id))
683 {
684 per_cpu(prof_old_multiplier, cpu_id)
685 = per_cpu(prof_counter, cpu_id);
686 }
687
688 update_process_times(user);
689 }
690}
691
692/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
693/* Send IPI Routines */
694/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
695
696/*==========================================================================*
697 * Name: send_IPI_allbutself
698 *
699 * Description: This routine sends a IPI to all other CPUs in the system.
700 *
701 * Born on Date: 2002.02.05
702 *
703 * Arguments: ipi_num - Number of IPI
704 * try - 0 : Send IPI certainly.
705 * !0 : The following IPI is not sent when Target CPU
706 * has not received the before IPI.
707 *
708 * Returns: void (cannot fail)
709 *
710 * Modification log:
711 * Date Who Description
712 * ---------- --- --------------------------------------------------------
713 *
714 *==========================================================================*/
715static void send_IPI_allbutself(int ipi_num, int try)
716{
717 cpumask_t cpumask;
718
719 cpumask_copy(&cpumask, cpu_online_mask);
720 cpumask_clear_cpu(smp_processor_id(), &cpumask);
721
722 send_IPI_mask(&cpumask, ipi_num, try);
723}
724
725/*==========================================================================*
726 * Name: send_IPI_mask
727 *
728 * Description: This routine sends a IPI to CPUs in the system.
729 *
730 * Born on Date: 2002.02.05
731 *
732 * Arguments: cpu_mask - Bitmap of target CPUs logical ID
733 * ipi_num - Number of IPI
734 * try - 0 : Send IPI certainly.
735 * !0 : The following IPI is not sent when Target CPU
736 * has not received the before IPI.
737 *
738 * Returns: void (cannot fail)
739 *
740 * Modification log:
741 * Date Who Description
742 * ---------- --- --------------------------------------------------------
743 *
744 *==========================================================================*/
745static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)
746{
747 cpumask_t physid_mask, tmp;
748 int cpu_id, phys_id;
749 int num_cpus = num_online_cpus();
750
751 if (num_cpus <= 1) /* NO MP */
752 return;
753
754 cpumask_and(&tmp, cpumask, cpu_online_mask);
755 BUG_ON(!cpumask_equal(cpumask, &tmp));
756
757 cpumask_clear(&physid_mask);
758 for_each_cpu(cpu_id, cpumask) {
759 if ((phys_id = cpu_to_physid(cpu_id)) != -1)
760 cpumask_set_cpu(phys_id, &physid_mask);
761 }
762
763 send_IPI_mask_phys(&physid_mask, ipi_num, try);
764}
765
766/*==========================================================================*
767 * Name: send_IPI_mask_phys
768 *
769 * Description: This routine sends a IPI to other CPUs in the system.
770 *
771 * Born on Date: 2002.02.05
772 *
773 * Arguments: cpu_mask - Bitmap of target CPUs physical ID
774 * ipi_num - Number of IPI
775 * try - 0 : Send IPI certainly.
776 * !0 : The following IPI is not sent when Target CPU
777 * has not received the before IPI.
778 *
779 * Returns: IPICRi regster value.
780 *
781 * Modification log:
782 * Date Who Description
783 * ---------- --- --------------------------------------------------------
784 *
785 *==========================================================================*/
786unsigned long send_IPI_mask_phys(const cpumask_t *physid_mask, int ipi_num,
787 int try)
788{
789 spinlock_t *ipilock;
790 volatile unsigned long *ipicr_addr;
791 unsigned long ipicr_val;
792 unsigned long my_physid_mask;
793 unsigned long mask = cpumask_bits(physid_mask)[0];
794
795
796 if (mask & ~physids_coerce(phys_cpu_present_map))
797 BUG();
798 if (ipi_num >= NR_IPIS || ipi_num < 0)
799 BUG();
800
801 mask <<= IPI_SHIFT;
802 ipilock = &ipi_lock[ipi_num];
803 ipicr_addr = (volatile unsigned long *)(M32R_ICU_IPICR_ADDR
804 + (ipi_num << 2));
805 my_physid_mask = ~(1 << smp_processor_id());
806
807 /*
808 * lock ipi_lock[i]
809 * check IPICRi == 0
810 * write IPICRi (send IPIi)
811 * unlock ipi_lock[i]
812 */
813 spin_lock(ipilock);
814 __asm__ __volatile__ (
815 ";; CHECK IPICRi == 0 \n\t"
816 ".fillinsn \n"
817 "1: \n\t"
818 "ld %0, @%1 \n\t"
819 "and %0, %4 \n\t"
820 "beqz %0, 2f \n\t"
821 "bnez %3, 3f \n\t"
822 "bra 1b \n\t"
823 ";; WRITE IPICRi (send IPIi) \n\t"
824 ".fillinsn \n"
825 "2: \n\t"
826 "st %2, @%1 \n\t"
827 ".fillinsn \n"
828 "3: \n\t"
829 : "=&r"(ipicr_val)
830 : "r"(ipicr_addr), "r"(mask), "r"(try), "r"(my_physid_mask)
831 : "memory"
832 );
833 spin_unlock(ipilock);
834
835 return ipicr_val;
836}