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