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