linux/arch/powerpc/platforms/iseries/smp.c
<<
>>
Prefs
   1/*
   2 * SMP support for iSeries machines.
   3 *
   4 * Dave Engebretsen, Peter Bergner, and
   5 * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
   6 *
   7 * Plus various changes from other IBM teams...
   8 *
   9 *      This program is free software; you can redistribute it and/or
  10 *      modify it under the terms of the GNU General Public License
  11 *      as published by the Free Software Foundation; either version
  12 *      2 of the License, or (at your option) any later version.
  13 */
  14
  15#undef DEBUG
  16
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/sched.h>
  20#include <linux/smp.h>
  21#include <linux/interrupt.h>
  22#include <linux/kernel_stat.h>
  23#include <linux/delay.h>
  24#include <linux/init.h>
  25#include <linux/spinlock.h>
  26#include <linux/cache.h>
  27#include <linux/err.h>
  28#include <linux/sysdev.h>
  29#include <linux/cpu.h>
  30
  31#include <asm/ptrace.h>
  32#include <asm/atomic.h>
  33#include <asm/irq.h>
  34#include <asm/page.h>
  35#include <asm/pgtable.h>
  36#include <asm/io.h>
  37#include <asm/smp.h>
  38#include <asm/paca.h>
  39#include <asm/iseries/hv_call.h>
  40#include <asm/time.h>
  41#include <asm/machdep.h>
  42#include <asm/cputable.h>
  43#include <asm/system.h>
  44
  45#include "smp.h"
  46
  47static unsigned long iSeries_smp_message[NR_CPUS];
  48
  49void iSeries_smp_message_recv(void)
  50{
  51        int cpu = smp_processor_id();
  52        int msg;
  53
  54        if (num_online_cpus() < 2)
  55                return;
  56
  57        for (msg = 0; msg < 4; msg++)
  58                if (test_and_clear_bit(msg, &iSeries_smp_message[cpu]))
  59                        smp_message_recv(msg);
  60}
  61
  62static inline void smp_iSeries_do_message(int cpu, int msg)
  63{
  64        set_bit(msg, &iSeries_smp_message[cpu]);
  65        HvCall_sendIPI(&(paca[cpu]));
  66}
  67
  68static void smp_iSeries_message_pass(int target, int msg)
  69{
  70        int i;
  71
  72        if (target < NR_CPUS)
  73                smp_iSeries_do_message(target, msg);
  74        else {
  75                for_each_online_cpu(i) {
  76                        if ((target == MSG_ALL_BUT_SELF) &&
  77                                        (i == smp_processor_id()))
  78                                continue;
  79                        smp_iSeries_do_message(i, msg);
  80                }
  81        }
  82}
  83
  84static int smp_iSeries_probe(void)
  85{
  86        return cpumask_weight(cpu_possible_mask);
  87}
  88
  89static void smp_iSeries_kick_cpu(int nr)
  90{
  91        BUG_ON((nr < 0) || (nr >= NR_CPUS));
  92
  93        /* Verify that our partition has a processor nr */
  94        if (lppaca_of(nr).dyn_proc_status >= 2)
  95                return;
  96
  97        /* The processor is currently spinning, waiting
  98         * for the cpu_start field to become non-zero
  99         * After we set cpu_start, the processor will
 100         * continue on to secondary_start in iSeries_head.S
 101         */
 102        paca[nr].cpu_start = 1;
 103}
 104
 105static void __devinit smp_iSeries_setup_cpu(int nr)
 106{
 107}
 108
 109static struct smp_ops_t iSeries_smp_ops = {
 110        .message_pass = smp_iSeries_message_pass,
 111        .probe        = smp_iSeries_probe,
 112        .kick_cpu     = smp_iSeries_kick_cpu,
 113        .setup_cpu    = smp_iSeries_setup_cpu,
 114};
 115
 116/* This is called very early. */
 117void __init smp_init_iSeries(void)
 118{
 119        smp_ops = &iSeries_smp_ops;
 120}
 121