/*
* SMP related functions
*
* Copyright IBM Corp. 1999,2012
* Author(s): Denis Joseph Barrow,
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
* Heiko Carstens <heiko.carstens@de.ibm.com>,
*
* based on other smp stuff by
* (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
* (c) 1998 Ingo Molnar
*
* The code outside of smp.c uses logical cpu numbers, only smp.c does
* the translation of logical to physical cpu ids. All new code that
* operates on physical cpu numbers needs to go into smp.c.
*/
#define KMSG_COMPONENT "cpu"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irqflags.h>
#include <linux/cpu.h>
#include <linux/slab.h>
#include <linux/crash_dump.h>
#include <asm/asm-offsets.h>
#include <asm/switch_to.h>
#include <asm/facility.h>
#include <asm/ipl.h>
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/tlbflush.h>
#include <asm/timer.h>
#include <asm/lowcore.h>
#include <asm/sclp.h>
#include <asm/vdso.h>
#include <asm/debug.h>
#include <asm/os_info.h>
#include "entry.h"
enum {
sigp_sense = 1,
sigp_external_call = 2,
sigp_emergency_signal = 3,
sigp_start = 4,
sigp_stop = 5,
sigp_restart = 6,
sigp_stop_and_store_status = 9,
sigp_initial_cpu_reset = 11,
sigp_cpu_reset = 12,
sigp_set_prefix = 13,
sigp_store_status_at_address = 14,
sigp_store_extended_status_at_address = 15,
sigp_set_architecture = 18,
sigp_conditional_emergency_signal = 19,
sigp_sense_running = 21,
};
enum {
sigp_order_code_accepted = 0,
sigp_status_stored = 1,
sigp_busy = 2,
sigp_not_operational = 3,
};
enum {
ec_schedule = 0,
ec_call_function,
ec_call_function_single,
ec_stop_cpu,
};
enum {
CPU_STATE_STANDBY,
CPU_STATE_CONFIGURED,
};
struct pcpu {
struct cpu cpu;
struct _lowcore *lowcore; /* lowcore page(s) for the cpu */
unsigned long async_stack; /* async stack for the cpu */
unsigned long panic_stack; /* panic stack for the cpu */
unsigned long ec_mask; /* bit mask for ec_xxx functions */
int state; /* physical cpu state */
u32 status; /* last status received via sigp */
u16 address; /* physical cpu address */
};
static u8 boot_cpu_type;
static u16 boot_cpu_address;
static struct pcpu pcpu_devices[NR_CPUS];
DEFINE_MUTEX(smp_cpu_state_mutex);
/*
* Signal processor helper functions.
*/
static inline int __pcpu_sigp(u16 addr, u8 order, u32 parm, u32 *status)
{
register unsigned int reg1 asm ("1") = parm;
int cc;
asm volatile(
" sigp %1,%2,0(%3)\n"
" ipm %0\n"
" srl %0,28\n"
: "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc");
if (status && cc == 1)
*status = reg1;
return cc;
}
static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
{
int cc;
while (1) {
cc = __pcpu_sigp(addr, order, parm, status);
if (cc != sigp_busy)
return cc;
cpu_relax();
}
}
static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
{
int cc, retry;
for (retry = 0; ; retry++) {
cc = __pcpu_sigp(pcpu->address, order, parm,