~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/m32r/kernel/smp.c

Version: ~ [ linux-5.3 ] ~ [ linux-5.2.14 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.72 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.143 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.192 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.192 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.73 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  */
 42 static DEFINE_SPINLOCK(flushcache_lock);
 43 static volatile unsigned long flushcache_cpumask = 0;
 44 
 45 /*
 46  * For flush_tlb_others()
 47  */
 48 static cpumask_t flush_cpumask;
 49 static struct mm_struct *flush_mm;
 50 static struct vm_area_struct *flush_vma;
 51 static volatile unsigned long flush_va;
 52 static DEFINE_SPINLOCK(tlbstate_lock);
 53 #define FLUSH_ALL 0xffffffff
 54 
 55 DECLARE_PER_CPU(int, prof_multiplier);
 56 DECLARE_PER_CPU(int, prof_old_multiplier);
 57 DECLARE_PER_CPU(int, prof_counter);
 58 
 59 extern spinlock_t ipi_lock[];
 60 
 61 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 62 /* Function Prototypes                                                       */
 63 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 64 
 65 void smp_reschedule_interrupt(void);
 66 void smp_flush_cache_all_interrupt(void);
 67 
 68 static void flush_tlb_all_ipi(void *);
 69 static void flush_tlb_others(cpumask_t, struct mm_struct *,
 70         struct vm_area_struct *, unsigned long);
 71 
 72 void smp_invalidate_interrupt(void);
 73 
 74 static void stop_this_cpu(void *);
 75 
 76 void smp_ipi_timer_interrupt(struct pt_regs *);
 77 void smp_local_timer_interrupt(void);
 78 
 79 static void send_IPI_allbutself(int, int);
 80 static 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  *==========================================================================*/
104 void 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  *==========================================================================*/
127 void 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  *==========================================================================*/
149 void 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 }
167 EXPORT_SYMBOL(smp_flush_cache_all);
168 
169 void 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  *==========================================================================*/
197 void 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  *==========================================================================*/
226 static 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  *==========================================================================*/
247 void 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  *==========================================================================*/
293 void 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  *==========================================================================*/
316 void 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  *==========================================================================*/
371 static 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  *==========================================================================*/
449 void 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  *==========================================================================*/
496 void 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  *==========================================================================*/
517 static 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 
539 void arch_send_call_function_ipi_mask(const struct cpumask *mask)
540 {
541         send_IPI_mask(mask, CALL_FUNCTION_IPI, 0);
542 }
543 
544 void 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  *==========================================================================*/
566 void smp_call_function_interrupt(void)
567 {
568         irq_enter();
569         generic_smp_call_function_interrupt();
570         irq_exit();
571 }
572 
573 void 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  *==========================================================================*/
601 void 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  *==========================================================================*/
623 void 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  *==========================================================================*/
656 void 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  *==========================================================================*/
715 static 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  *==========================================================================*/
745 static 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  *==========================================================================*/
786 unsigned 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 }
837 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp