162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  SMP related functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *    Copyright IBM Corp. 1999, 2012
662306a36Sopenharmony_ci *    Author(s): Denis Joseph Barrow,
762306a36Sopenharmony_ci *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  based on other smp stuff by
1062306a36Sopenharmony_ci *    (c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
1162306a36Sopenharmony_ci *    (c) 1998 Ingo Molnar
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The code outside of smp.c uses logical cpu numbers, only smp.c does
1462306a36Sopenharmony_ci * the translation of logical to physical cpu ids. All new code that
1562306a36Sopenharmony_ci * operates on physical cpu numbers needs to go into smp.c.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define KMSG_COMPONENT "cpu"
1962306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/workqueue.h>
2262306a36Sopenharmony_ci#include <linux/memblock.h>
2362306a36Sopenharmony_ci#include <linux/export.h>
2462306a36Sopenharmony_ci#include <linux/init.h>
2562306a36Sopenharmony_ci#include <linux/mm.h>
2662306a36Sopenharmony_ci#include <linux/err.h>
2762306a36Sopenharmony_ci#include <linux/spinlock.h>
2862306a36Sopenharmony_ci#include <linux/kernel_stat.h>
2962306a36Sopenharmony_ci#include <linux/delay.h>
3062306a36Sopenharmony_ci#include <linux/interrupt.h>
3162306a36Sopenharmony_ci#include <linux/irqflags.h>
3262306a36Sopenharmony_ci#include <linux/irq_work.h>
3362306a36Sopenharmony_ci#include <linux/cpu.h>
3462306a36Sopenharmony_ci#include <linux/slab.h>
3562306a36Sopenharmony_ci#include <linux/sched/hotplug.h>
3662306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
3762306a36Sopenharmony_ci#include <linux/crash_dump.h>
3862306a36Sopenharmony_ci#include <linux/kprobes.h>
3962306a36Sopenharmony_ci#include <asm/asm-offsets.h>
4062306a36Sopenharmony_ci#include <asm/pfault.h>
4162306a36Sopenharmony_ci#include <asm/diag.h>
4262306a36Sopenharmony_ci#include <asm/switch_to.h>
4362306a36Sopenharmony_ci#include <asm/facility.h>
4462306a36Sopenharmony_ci#include <asm/ipl.h>
4562306a36Sopenharmony_ci#include <asm/setup.h>
4662306a36Sopenharmony_ci#include <asm/irq.h>
4762306a36Sopenharmony_ci#include <asm/tlbflush.h>
4862306a36Sopenharmony_ci#include <asm/vtimer.h>
4962306a36Sopenharmony_ci#include <asm/abs_lowcore.h>
5062306a36Sopenharmony_ci#include <asm/sclp.h>
5162306a36Sopenharmony_ci#include <asm/debug.h>
5262306a36Sopenharmony_ci#include <asm/os_info.h>
5362306a36Sopenharmony_ci#include <asm/sigp.h>
5462306a36Sopenharmony_ci#include <asm/idle.h>
5562306a36Sopenharmony_ci#include <asm/nmi.h>
5662306a36Sopenharmony_ci#include <asm/stacktrace.h>
5762306a36Sopenharmony_ci#include <asm/topology.h>
5862306a36Sopenharmony_ci#include <asm/vdso.h>
5962306a36Sopenharmony_ci#include <asm/maccess.h>
6062306a36Sopenharmony_ci#include "entry.h"
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cienum {
6362306a36Sopenharmony_ci	ec_schedule = 0,
6462306a36Sopenharmony_ci	ec_call_function_single,
6562306a36Sopenharmony_ci	ec_stop_cpu,
6662306a36Sopenharmony_ci	ec_mcck_pending,
6762306a36Sopenharmony_ci	ec_irq_work,
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cienum {
7162306a36Sopenharmony_ci	CPU_STATE_STANDBY,
7262306a36Sopenharmony_ci	CPU_STATE_CONFIGURED,
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct cpu *, cpu_device);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct pcpu {
7862306a36Sopenharmony_ci	unsigned long ec_mask;		/* bit mask for ec_xxx functions */
7962306a36Sopenharmony_ci	unsigned long ec_clk;		/* sigp timestamp for ec_xxx */
8062306a36Sopenharmony_ci	signed char state;		/* physical cpu state */
8162306a36Sopenharmony_ci	signed char polarization;	/* physical polarization */
8262306a36Sopenharmony_ci	u16 address;			/* physical cpu address */
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic u8 boot_core_type;
8662306a36Sopenharmony_cistatic struct pcpu pcpu_devices[NR_CPUS];
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciunsigned int smp_cpu_mt_shift;
8962306a36Sopenharmony_ciEXPORT_SYMBOL(smp_cpu_mt_shift);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciunsigned int smp_cpu_mtid;
9262306a36Sopenharmony_ciEXPORT_SYMBOL(smp_cpu_mtid);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#ifdef CONFIG_CRASH_DUMP
9562306a36Sopenharmony_ci__vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS];
9662306a36Sopenharmony_ci#endif
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic unsigned int smp_max_threads __initdata = -1U;
9962306a36Sopenharmony_cicpumask_t cpu_setup_mask;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int __init early_nosmt(char *s)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	smp_max_threads = 1;
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ciearly_param("nosmt", early_nosmt);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic int __init early_smt(char *s)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	get_option(&s, &smp_max_threads);
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ciearly_param("smt", early_smt);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/*
11662306a36Sopenharmony_ci * The smp_cpu_state_mutex must be held when changing the state or polarization
11762306a36Sopenharmony_ci * member of a pcpu data structure within the pcpu_devices array.
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_ciDEFINE_MUTEX(smp_cpu_state_mutex);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*
12262306a36Sopenharmony_ci * Signal processor helper functions.
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_cistatic inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	int cc;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	while (1) {
12962306a36Sopenharmony_ci		cc = __pcpu_sigp(addr, order, parm, NULL);
13062306a36Sopenharmony_ci		if (cc != SIGP_CC_BUSY)
13162306a36Sopenharmony_ci			return cc;
13262306a36Sopenharmony_ci		cpu_relax();
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	int cc, retry;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	for (retry = 0; ; retry++) {
14162306a36Sopenharmony_ci		cc = __pcpu_sigp(pcpu->address, order, parm, NULL);
14262306a36Sopenharmony_ci		if (cc != SIGP_CC_BUSY)
14362306a36Sopenharmony_ci			break;
14462306a36Sopenharmony_ci		if (retry >= 3)
14562306a36Sopenharmony_ci			udelay(10);
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci	return cc;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic inline int pcpu_stopped(struct pcpu *pcpu)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	u32 status;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (__pcpu_sigp(pcpu->address, SIGP_SENSE,
15562306a36Sopenharmony_ci			0, &status) != SIGP_CC_STATUS_STORED)
15662306a36Sopenharmony_ci		return 0;
15762306a36Sopenharmony_ci	return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline int pcpu_running(struct pcpu *pcpu)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING,
16362306a36Sopenharmony_ci			0, NULL) != SIGP_CC_STATUS_STORED)
16462306a36Sopenharmony_ci		return 1;
16562306a36Sopenharmony_ci	/* Status stored condition code is equivalent to cpu not running. */
16662306a36Sopenharmony_ci	return 0;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/*
17062306a36Sopenharmony_ci * Find struct pcpu by cpu address.
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_cistatic struct pcpu *pcpu_find_address(const struct cpumask *mask, u16 address)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	int cpu;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	for_each_cpu(cpu, mask)
17762306a36Sopenharmony_ci		if (pcpu_devices[cpu].address == address)
17862306a36Sopenharmony_ci			return pcpu_devices + cpu;
17962306a36Sopenharmony_ci	return NULL;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	int order;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (test_and_set_bit(ec_bit, &pcpu->ec_mask))
18762306a36Sopenharmony_ci		return;
18862306a36Sopenharmony_ci	order = pcpu_running(pcpu) ? SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL;
18962306a36Sopenharmony_ci	pcpu->ec_clk = get_tod_clock_fast();
19062306a36Sopenharmony_ci	pcpu_sigp_retry(pcpu, order, 0);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	unsigned long async_stack, nodat_stack, mcck_stack;
19662306a36Sopenharmony_ci	struct lowcore *lc;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	lc = (struct lowcore *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
19962306a36Sopenharmony_ci	nodat_stack = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
20062306a36Sopenharmony_ci	async_stack = stack_alloc();
20162306a36Sopenharmony_ci	mcck_stack = stack_alloc();
20262306a36Sopenharmony_ci	if (!lc || !nodat_stack || !async_stack || !mcck_stack)
20362306a36Sopenharmony_ci		goto out;
20462306a36Sopenharmony_ci	memcpy(lc, &S390_lowcore, 512);
20562306a36Sopenharmony_ci	memset((char *) lc + 512, 0, sizeof(*lc) - 512);
20662306a36Sopenharmony_ci	lc->async_stack = async_stack + STACK_INIT_OFFSET;
20762306a36Sopenharmony_ci	lc->nodat_stack = nodat_stack + STACK_INIT_OFFSET;
20862306a36Sopenharmony_ci	lc->mcck_stack = mcck_stack + STACK_INIT_OFFSET;
20962306a36Sopenharmony_ci	lc->cpu_nr = cpu;
21062306a36Sopenharmony_ci	lc->spinlock_lockval = arch_spin_lockval(cpu);
21162306a36Sopenharmony_ci	lc->spinlock_index = 0;
21262306a36Sopenharmony_ci	lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW);
21362306a36Sopenharmony_ci	lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW);
21462306a36Sopenharmony_ci	lc->preempt_count = PREEMPT_DISABLED;
21562306a36Sopenharmony_ci	if (nmi_alloc_mcesa(&lc->mcesad))
21662306a36Sopenharmony_ci		goto out;
21762306a36Sopenharmony_ci	if (abs_lowcore_map(cpu, lc, true))
21862306a36Sopenharmony_ci		goto out_mcesa;
21962306a36Sopenharmony_ci	lowcore_ptr[cpu] = lc;
22062306a36Sopenharmony_ci	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, __pa(lc));
22162306a36Sopenharmony_ci	return 0;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciout_mcesa:
22462306a36Sopenharmony_ci	nmi_free_mcesa(&lc->mcesad);
22562306a36Sopenharmony_ciout:
22662306a36Sopenharmony_ci	stack_free(mcck_stack);
22762306a36Sopenharmony_ci	stack_free(async_stack);
22862306a36Sopenharmony_ci	free_pages(nodat_stack, THREAD_SIZE_ORDER);
22962306a36Sopenharmony_ci	free_pages((unsigned long) lc, LC_ORDER);
23062306a36Sopenharmony_ci	return -ENOMEM;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic void pcpu_free_lowcore(struct pcpu *pcpu)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	unsigned long async_stack, nodat_stack, mcck_stack;
23662306a36Sopenharmony_ci	struct lowcore *lc;
23762306a36Sopenharmony_ci	int cpu;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	cpu = pcpu - pcpu_devices;
24062306a36Sopenharmony_ci	lc = lowcore_ptr[cpu];
24162306a36Sopenharmony_ci	nodat_stack = lc->nodat_stack - STACK_INIT_OFFSET;
24262306a36Sopenharmony_ci	async_stack = lc->async_stack - STACK_INIT_OFFSET;
24362306a36Sopenharmony_ci	mcck_stack = lc->mcck_stack - STACK_INIT_OFFSET;
24462306a36Sopenharmony_ci	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
24562306a36Sopenharmony_ci	lowcore_ptr[cpu] = NULL;
24662306a36Sopenharmony_ci	abs_lowcore_unmap(cpu);
24762306a36Sopenharmony_ci	nmi_free_mcesa(&lc->mcesad);
24862306a36Sopenharmony_ci	stack_free(async_stack);
24962306a36Sopenharmony_ci	stack_free(mcck_stack);
25062306a36Sopenharmony_ci	free_pages(nodat_stack, THREAD_SIZE_ORDER);
25162306a36Sopenharmony_ci	free_pages((unsigned long) lc, LC_ORDER);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct lowcore *lc, *abs_lc;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	lc = lowcore_ptr[cpu];
25962306a36Sopenharmony_ci	cpumask_set_cpu(cpu, &init_mm.context.cpu_attach_mask);
26062306a36Sopenharmony_ci	cpumask_set_cpu(cpu, mm_cpumask(&init_mm));
26162306a36Sopenharmony_ci	lc->cpu_nr = cpu;
26262306a36Sopenharmony_ci	lc->restart_flags = RESTART_FLAG_CTLREGS;
26362306a36Sopenharmony_ci	lc->spinlock_lockval = arch_spin_lockval(cpu);
26462306a36Sopenharmony_ci	lc->spinlock_index = 0;
26562306a36Sopenharmony_ci	lc->percpu_offset = __per_cpu_offset[cpu];
26662306a36Sopenharmony_ci	lc->kernel_asce = S390_lowcore.kernel_asce;
26762306a36Sopenharmony_ci	lc->user_asce = s390_invalid_asce;
26862306a36Sopenharmony_ci	lc->machine_flags = S390_lowcore.machine_flags;
26962306a36Sopenharmony_ci	lc->user_timer = lc->system_timer =
27062306a36Sopenharmony_ci		lc->steal_timer = lc->avg_steal_timer = 0;
27162306a36Sopenharmony_ci	abs_lc = get_abs_lowcore();
27262306a36Sopenharmony_ci	memcpy(lc->cregs_save_area, abs_lc->cregs_save_area, sizeof(lc->cregs_save_area));
27362306a36Sopenharmony_ci	put_abs_lowcore(abs_lc);
27462306a36Sopenharmony_ci	lc->cregs_save_area[1] = lc->kernel_asce;
27562306a36Sopenharmony_ci	lc->cregs_save_area[7] = lc->user_asce;
27662306a36Sopenharmony_ci	save_access_regs((unsigned int *) lc->access_regs_save_area);
27762306a36Sopenharmony_ci	arch_spin_lock_setup(cpu);
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct lowcore *lc;
28362306a36Sopenharmony_ci	int cpu;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	cpu = pcpu - pcpu_devices;
28662306a36Sopenharmony_ci	lc = lowcore_ptr[cpu];
28762306a36Sopenharmony_ci	lc->kernel_stack = (unsigned long)task_stack_page(tsk) + STACK_INIT_OFFSET;
28862306a36Sopenharmony_ci	lc->current_task = (unsigned long)tsk;
28962306a36Sopenharmony_ci	lc->lpp = LPP_MAGIC;
29062306a36Sopenharmony_ci	lc->current_pid = tsk->pid;
29162306a36Sopenharmony_ci	lc->user_timer = tsk->thread.user_timer;
29262306a36Sopenharmony_ci	lc->guest_timer = tsk->thread.guest_timer;
29362306a36Sopenharmony_ci	lc->system_timer = tsk->thread.system_timer;
29462306a36Sopenharmony_ci	lc->hardirq_timer = tsk->thread.hardirq_timer;
29562306a36Sopenharmony_ci	lc->softirq_timer = tsk->thread.softirq_timer;
29662306a36Sopenharmony_ci	lc->steal_timer = 0;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct lowcore *lc;
30262306a36Sopenharmony_ci	int cpu;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	cpu = pcpu - pcpu_devices;
30562306a36Sopenharmony_ci	lc = lowcore_ptr[cpu];
30662306a36Sopenharmony_ci	lc->restart_stack = lc->kernel_stack;
30762306a36Sopenharmony_ci	lc->restart_fn = (unsigned long) func;
30862306a36Sopenharmony_ci	lc->restart_data = (unsigned long) data;
30962306a36Sopenharmony_ci	lc->restart_source = -1U;
31062306a36Sopenharmony_ci	pcpu_sigp_retry(pcpu, SIGP_RESTART, 0);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_citypedef void (pcpu_delegate_fn)(void *);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/*
31662306a36Sopenharmony_ci * Call function via PSW restart on pcpu and stop the current cpu.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistatic void __pcpu_delegate(pcpu_delegate_fn *func, void *data)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	func(data);	/* should not return */
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic void pcpu_delegate(struct pcpu *pcpu,
32462306a36Sopenharmony_ci			  pcpu_delegate_fn *func,
32562306a36Sopenharmony_ci			  void *data, unsigned long stack)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct lowcore *lc, *abs_lc;
32862306a36Sopenharmony_ci	unsigned int source_cpu;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	lc = lowcore_ptr[pcpu - pcpu_devices];
33162306a36Sopenharmony_ci	source_cpu = stap();
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (pcpu->address == source_cpu) {
33462306a36Sopenharmony_ci		call_on_stack(2, stack, void, __pcpu_delegate,
33562306a36Sopenharmony_ci			      pcpu_delegate_fn *, func, void *, data);
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci	/* Stop target cpu (if func returns this stops the current cpu). */
33862306a36Sopenharmony_ci	pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
33962306a36Sopenharmony_ci	pcpu_sigp_retry(pcpu, SIGP_CPU_RESET, 0);
34062306a36Sopenharmony_ci	/* Restart func on the target cpu and stop the current cpu. */
34162306a36Sopenharmony_ci	if (lc) {
34262306a36Sopenharmony_ci		lc->restart_stack = stack;
34362306a36Sopenharmony_ci		lc->restart_fn = (unsigned long)func;
34462306a36Sopenharmony_ci		lc->restart_data = (unsigned long)data;
34562306a36Sopenharmony_ci		lc->restart_source = source_cpu;
34662306a36Sopenharmony_ci	} else {
34762306a36Sopenharmony_ci		abs_lc = get_abs_lowcore();
34862306a36Sopenharmony_ci		abs_lc->restart_stack = stack;
34962306a36Sopenharmony_ci		abs_lc->restart_fn = (unsigned long)func;
35062306a36Sopenharmony_ci		abs_lc->restart_data = (unsigned long)data;
35162306a36Sopenharmony_ci		abs_lc->restart_source = source_cpu;
35262306a36Sopenharmony_ci		put_abs_lowcore(abs_lc);
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci	asm volatile(
35562306a36Sopenharmony_ci		"0:	sigp	0,%0,%2	# sigp restart to target cpu\n"
35662306a36Sopenharmony_ci		"	brc	2,0b	# busy, try again\n"
35762306a36Sopenharmony_ci		"1:	sigp	0,%1,%3	# sigp stop to current cpu\n"
35862306a36Sopenharmony_ci		"	brc	2,1b	# busy, try again\n"
35962306a36Sopenharmony_ci		: : "d" (pcpu->address), "d" (source_cpu),
36062306a36Sopenharmony_ci		    "K" (SIGP_RESTART), "K" (SIGP_STOP)
36162306a36Sopenharmony_ci		: "0", "1", "cc");
36262306a36Sopenharmony_ci	for (;;) ;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/*
36662306a36Sopenharmony_ci * Enable additional logical cpus for multi-threading.
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_cistatic int pcpu_set_smt(unsigned int mtid)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	int cc;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (smp_cpu_mtid == mtid)
37362306a36Sopenharmony_ci		return 0;
37462306a36Sopenharmony_ci	cc = __pcpu_sigp(0, SIGP_SET_MULTI_THREADING, mtid, NULL);
37562306a36Sopenharmony_ci	if (cc == 0) {
37662306a36Sopenharmony_ci		smp_cpu_mtid = mtid;
37762306a36Sopenharmony_ci		smp_cpu_mt_shift = 0;
37862306a36Sopenharmony_ci		while (smp_cpu_mtid >= (1U << smp_cpu_mt_shift))
37962306a36Sopenharmony_ci			smp_cpu_mt_shift++;
38062306a36Sopenharmony_ci		pcpu_devices[0].address = stap();
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci	return cc;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/*
38662306a36Sopenharmony_ci * Call function on an online CPU.
38762306a36Sopenharmony_ci */
38862306a36Sopenharmony_civoid smp_call_online_cpu(void (*func)(void *), void *data)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct pcpu *pcpu;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* Use the current cpu if it is online. */
39362306a36Sopenharmony_ci	pcpu = pcpu_find_address(cpu_online_mask, stap());
39462306a36Sopenharmony_ci	if (!pcpu)
39562306a36Sopenharmony_ci		/* Use the first online cpu. */
39662306a36Sopenharmony_ci		pcpu = pcpu_devices + cpumask_first(cpu_online_mask);
39762306a36Sopenharmony_ci	pcpu_delegate(pcpu, func, data, (unsigned long) restart_stack);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/*
40162306a36Sopenharmony_ci * Call function on the ipl CPU.
40262306a36Sopenharmony_ci */
40362306a36Sopenharmony_civoid smp_call_ipl_cpu(void (*func)(void *), void *data)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct lowcore *lc = lowcore_ptr[0];
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (pcpu_devices[0].address == stap())
40862306a36Sopenharmony_ci		lc = &S390_lowcore;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	pcpu_delegate(&pcpu_devices[0], func, data,
41162306a36Sopenharmony_ci		      lc->nodat_stack);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ciint smp_find_processor_id(u16 address)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	int cpu;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	for_each_present_cpu(cpu)
41962306a36Sopenharmony_ci		if (pcpu_devices[cpu].address == address)
42062306a36Sopenharmony_ci			return cpu;
42162306a36Sopenharmony_ci	return -1;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_civoid schedule_mcck_handler(void)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	pcpu_ec_call(pcpu_devices + smp_processor_id(), ec_mcck_pending);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cibool notrace arch_vcpu_is_preempted(int cpu)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	if (test_cpu_flag_of(CIF_ENABLED_WAIT, cpu))
43262306a36Sopenharmony_ci		return false;
43362306a36Sopenharmony_ci	if (pcpu_running(pcpu_devices + cpu))
43462306a36Sopenharmony_ci		return false;
43562306a36Sopenharmony_ci	return true;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ciEXPORT_SYMBOL(arch_vcpu_is_preempted);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_civoid notrace smp_yield_cpu(int cpu)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	if (!MACHINE_HAS_DIAG9C)
44262306a36Sopenharmony_ci		return;
44362306a36Sopenharmony_ci	diag_stat_inc_norecursion(DIAG_STAT_X09C);
44462306a36Sopenharmony_ci	asm volatile("diag %0,0,0x9c"
44562306a36Sopenharmony_ci		     : : "d" (pcpu_devices[cpu].address));
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(smp_yield_cpu);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci/*
45062306a36Sopenharmony_ci * Send cpus emergency shutdown signal. This gives the cpus the
45162306a36Sopenharmony_ci * opportunity to complete outstanding interrupts.
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_civoid notrace smp_emergency_stop(void)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
45662306a36Sopenharmony_ci	static cpumask_t cpumask;
45762306a36Sopenharmony_ci	u64 end;
45862306a36Sopenharmony_ci	int cpu;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	arch_spin_lock(&lock);
46162306a36Sopenharmony_ci	cpumask_copy(&cpumask, cpu_online_mask);
46262306a36Sopenharmony_ci	cpumask_clear_cpu(smp_processor_id(), &cpumask);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	end = get_tod_clock() + (1000000UL << 12);
46562306a36Sopenharmony_ci	for_each_cpu(cpu, &cpumask) {
46662306a36Sopenharmony_ci		struct pcpu *pcpu = pcpu_devices + cpu;
46762306a36Sopenharmony_ci		set_bit(ec_stop_cpu, &pcpu->ec_mask);
46862306a36Sopenharmony_ci		while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL,
46962306a36Sopenharmony_ci				   0, NULL) == SIGP_CC_BUSY &&
47062306a36Sopenharmony_ci		       get_tod_clock() < end)
47162306a36Sopenharmony_ci			cpu_relax();
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	while (get_tod_clock() < end) {
47462306a36Sopenharmony_ci		for_each_cpu(cpu, &cpumask)
47562306a36Sopenharmony_ci			if (pcpu_stopped(pcpu_devices + cpu))
47662306a36Sopenharmony_ci				cpumask_clear_cpu(cpu, &cpumask);
47762306a36Sopenharmony_ci		if (cpumask_empty(&cpumask))
47862306a36Sopenharmony_ci			break;
47962306a36Sopenharmony_ci		cpu_relax();
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci	arch_spin_unlock(&lock);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ciNOKPROBE_SYMBOL(smp_emergency_stop);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci/*
48662306a36Sopenharmony_ci * Stop all cpus but the current one.
48762306a36Sopenharmony_ci */
48862306a36Sopenharmony_civoid smp_send_stop(void)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	int cpu;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* Disable all interrupts/machine checks */
49362306a36Sopenharmony_ci	__load_psw_mask(PSW_KERNEL_BITS);
49462306a36Sopenharmony_ci	trace_hardirqs_off();
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	debug_set_critical();
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (oops_in_progress)
49962306a36Sopenharmony_ci		smp_emergency_stop();
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* stop all processors */
50262306a36Sopenharmony_ci	for_each_online_cpu(cpu) {
50362306a36Sopenharmony_ci		if (cpu == smp_processor_id())
50462306a36Sopenharmony_ci			continue;
50562306a36Sopenharmony_ci		pcpu_sigp_retry(pcpu_devices + cpu, SIGP_STOP, 0);
50662306a36Sopenharmony_ci		while (!pcpu_stopped(pcpu_devices + cpu))
50762306a36Sopenharmony_ci			cpu_relax();
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci/*
51262306a36Sopenharmony_ci * This is the main routine where commands issued by other
51362306a36Sopenharmony_ci * cpus are handled.
51462306a36Sopenharmony_ci */
51562306a36Sopenharmony_cistatic void smp_handle_ext_call(void)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	unsigned long bits;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* handle bit signal external calls */
52062306a36Sopenharmony_ci	bits = xchg(&pcpu_devices[smp_processor_id()].ec_mask, 0);
52162306a36Sopenharmony_ci	if (test_bit(ec_stop_cpu, &bits))
52262306a36Sopenharmony_ci		smp_stop_cpu();
52362306a36Sopenharmony_ci	if (test_bit(ec_schedule, &bits))
52462306a36Sopenharmony_ci		scheduler_ipi();
52562306a36Sopenharmony_ci	if (test_bit(ec_call_function_single, &bits))
52662306a36Sopenharmony_ci		generic_smp_call_function_single_interrupt();
52762306a36Sopenharmony_ci	if (test_bit(ec_mcck_pending, &bits))
52862306a36Sopenharmony_ci		s390_handle_mcck();
52962306a36Sopenharmony_ci	if (test_bit(ec_irq_work, &bits))
53062306a36Sopenharmony_ci		irq_work_run();
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic void do_ext_call_interrupt(struct ext_code ext_code,
53462306a36Sopenharmony_ci				  unsigned int param32, unsigned long param64)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	inc_irq_stat(ext_code.code == 0x1202 ? IRQEXT_EXC : IRQEXT_EMS);
53762306a36Sopenharmony_ci	smp_handle_ext_call();
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_civoid arch_send_call_function_ipi_mask(const struct cpumask *mask)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	int cpu;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	for_each_cpu(cpu, mask)
54562306a36Sopenharmony_ci		pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_civoid arch_send_call_function_single_ipi(int cpu)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single);
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci/*
55462306a36Sopenharmony_ci * this function sends a 'reschedule' IPI to another CPU.
55562306a36Sopenharmony_ci * it goes straight through and wastes no time serializing
55662306a36Sopenharmony_ci * anything. Worst case is that we lose a reschedule ...
55762306a36Sopenharmony_ci */
55862306a36Sopenharmony_civoid arch_smp_send_reschedule(int cpu)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	pcpu_ec_call(pcpu_devices + cpu, ec_schedule);
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci#ifdef CONFIG_IRQ_WORK
56462306a36Sopenharmony_civoid arch_irq_work_raise(void)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	pcpu_ec_call(pcpu_devices + smp_processor_id(), ec_irq_work);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci#endif
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/*
57162306a36Sopenharmony_ci * parameter area for the set/clear control bit callbacks
57262306a36Sopenharmony_ci */
57362306a36Sopenharmony_cistruct ec_creg_mask_parms {
57462306a36Sopenharmony_ci	unsigned long orval;
57562306a36Sopenharmony_ci	unsigned long andval;
57662306a36Sopenharmony_ci	int cr;
57762306a36Sopenharmony_ci};
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci/*
58062306a36Sopenharmony_ci * callback for setting/clearing control bits
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic void smp_ctl_bit_callback(void *info)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct ec_creg_mask_parms *pp = info;
58562306a36Sopenharmony_ci	unsigned long cregs[16];
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	__ctl_store(cregs, 0, 15);
58862306a36Sopenharmony_ci	cregs[pp->cr] = (cregs[pp->cr] & pp->andval) | pp->orval;
58962306a36Sopenharmony_ci	__ctl_load(cregs, 0, 15);
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ctl_lock);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_civoid smp_ctl_set_clear_bit(int cr, int bit, bool set)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct ec_creg_mask_parms parms = { .cr = cr, };
59762306a36Sopenharmony_ci	struct lowcore *abs_lc;
59862306a36Sopenharmony_ci	u64 ctlreg;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (set) {
60162306a36Sopenharmony_ci		parms.orval = 1UL << bit;
60262306a36Sopenharmony_ci		parms.andval = -1UL;
60362306a36Sopenharmony_ci	} else {
60462306a36Sopenharmony_ci		parms.orval = 0;
60562306a36Sopenharmony_ci		parms.andval = ~(1UL << bit);
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci	spin_lock(&ctl_lock);
60862306a36Sopenharmony_ci	abs_lc = get_abs_lowcore();
60962306a36Sopenharmony_ci	ctlreg = abs_lc->cregs_save_area[cr];
61062306a36Sopenharmony_ci	ctlreg = (ctlreg & parms.andval) | parms.orval;
61162306a36Sopenharmony_ci	abs_lc->cregs_save_area[cr] = ctlreg;
61262306a36Sopenharmony_ci	put_abs_lowcore(abs_lc);
61362306a36Sopenharmony_ci	on_each_cpu(smp_ctl_bit_callback, &parms, 1);
61462306a36Sopenharmony_ci	spin_unlock(&ctl_lock);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ciEXPORT_SYMBOL(smp_ctl_set_clear_bit);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci#ifdef CONFIG_CRASH_DUMP
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ciint smp_store_status(int cpu)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	struct lowcore *lc;
62362306a36Sopenharmony_ci	struct pcpu *pcpu;
62462306a36Sopenharmony_ci	unsigned long pa;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	pcpu = pcpu_devices + cpu;
62762306a36Sopenharmony_ci	lc = lowcore_ptr[cpu];
62862306a36Sopenharmony_ci	pa = __pa(&lc->floating_pt_save_area);
62962306a36Sopenharmony_ci	if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS,
63062306a36Sopenharmony_ci			      pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
63162306a36Sopenharmony_ci		return -EIO;
63262306a36Sopenharmony_ci	if (!MACHINE_HAS_VX && !MACHINE_HAS_GS)
63362306a36Sopenharmony_ci		return 0;
63462306a36Sopenharmony_ci	pa = lc->mcesad & MCESA_ORIGIN_MASK;
63562306a36Sopenharmony_ci	if (MACHINE_HAS_GS)
63662306a36Sopenharmony_ci		pa |= lc->mcesad & MCESA_LC_MASK;
63762306a36Sopenharmony_ci	if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
63862306a36Sopenharmony_ci			      pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
63962306a36Sopenharmony_ci		return -EIO;
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/*
64462306a36Sopenharmony_ci * Collect CPU state of the previous, crashed system.
64562306a36Sopenharmony_ci * There are four cases:
64662306a36Sopenharmony_ci * 1) standard zfcp/nvme dump
64762306a36Sopenharmony_ci *    condition: OLDMEM_BASE == NULL && is_ipl_type_dump() == true
64862306a36Sopenharmony_ci *    The state for all CPUs except the boot CPU needs to be collected
64962306a36Sopenharmony_ci *    with sigp stop-and-store-status. The boot CPU state is located in
65062306a36Sopenharmony_ci *    the absolute lowcore of the memory stored in the HSA. The zcore code
65162306a36Sopenharmony_ci *    will copy the boot CPU state from the HSA.
65262306a36Sopenharmony_ci * 2) stand-alone kdump for SCSI/NVMe (zfcp/nvme dump with swapped memory)
65362306a36Sopenharmony_ci *    condition: OLDMEM_BASE != NULL && is_ipl_type_dump() == true
65462306a36Sopenharmony_ci *    The state for all CPUs except the boot CPU needs to be collected
65562306a36Sopenharmony_ci *    with sigp stop-and-store-status. The firmware or the boot-loader
65662306a36Sopenharmony_ci *    stored the registers of the boot CPU in the absolute lowcore in the
65762306a36Sopenharmony_ci *    memory of the old system.
65862306a36Sopenharmony_ci * 3) kdump and the old kernel did not store the CPU state,
65962306a36Sopenharmony_ci *    or stand-alone kdump for DASD
66062306a36Sopenharmony_ci *    condition: OLDMEM_BASE != NULL && !is_kdump_kernel()
66162306a36Sopenharmony_ci *    The state for all CPUs except the boot CPU needs to be collected
66262306a36Sopenharmony_ci *    with sigp stop-and-store-status. The kexec code or the boot-loader
66362306a36Sopenharmony_ci *    stored the registers of the boot CPU in the memory of the old system.
66462306a36Sopenharmony_ci * 4) kdump and the old kernel stored the CPU state
66562306a36Sopenharmony_ci *    condition: OLDMEM_BASE != NULL && is_kdump_kernel()
66662306a36Sopenharmony_ci *    This case does not exist for s390 anymore, setup_arch explicitly
66762306a36Sopenharmony_ci *    deactivates the elfcorehdr= kernel parameter
66862306a36Sopenharmony_ci */
66962306a36Sopenharmony_cistatic bool dump_available(void)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	return oldmem_data.start || is_ipl_type_dump();
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_civoid __init smp_save_dump_ipl_cpu(void)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct save_area *sa;
67762306a36Sopenharmony_ci	void *regs;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (!dump_available())
68062306a36Sopenharmony_ci		return;
68162306a36Sopenharmony_ci	sa = save_area_alloc(true);
68262306a36Sopenharmony_ci	regs = memblock_alloc(512, 8);
68362306a36Sopenharmony_ci	if (!sa || !regs)
68462306a36Sopenharmony_ci		panic("could not allocate memory for boot CPU save area\n");
68562306a36Sopenharmony_ci	copy_oldmem_kernel(regs, __LC_FPREGS_SAVE_AREA, 512);
68662306a36Sopenharmony_ci	save_area_add_regs(sa, regs);
68762306a36Sopenharmony_ci	memblock_free(regs, 512);
68862306a36Sopenharmony_ci	if (MACHINE_HAS_VX)
68962306a36Sopenharmony_ci		save_area_add_vxrs(sa, boot_cpu_vector_save_area);
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_civoid __init smp_save_dump_secondary_cpus(void)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	int addr, boot_cpu_addr, max_cpu_addr;
69562306a36Sopenharmony_ci	struct save_area *sa;
69662306a36Sopenharmony_ci	void *page;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (!dump_available())
69962306a36Sopenharmony_ci		return;
70062306a36Sopenharmony_ci	/* Allocate a page as dumping area for the store status sigps */
70162306a36Sopenharmony_ci	page = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE);
70262306a36Sopenharmony_ci	if (!page)
70362306a36Sopenharmony_ci		panic("ERROR: Failed to allocate %lx bytes below %lx\n",
70462306a36Sopenharmony_ci		      PAGE_SIZE, 1UL << 31);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Set multi-threading state to the previous system. */
70762306a36Sopenharmony_ci	pcpu_set_smt(sclp.mtid_prev);
70862306a36Sopenharmony_ci	boot_cpu_addr = stap();
70962306a36Sopenharmony_ci	max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev;
71062306a36Sopenharmony_ci	for (addr = 0; addr <= max_cpu_addr; addr++) {
71162306a36Sopenharmony_ci		if (addr == boot_cpu_addr)
71262306a36Sopenharmony_ci			continue;
71362306a36Sopenharmony_ci		if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0) ==
71462306a36Sopenharmony_ci		    SIGP_CC_NOT_OPERATIONAL)
71562306a36Sopenharmony_ci			continue;
71662306a36Sopenharmony_ci		sa = save_area_alloc(false);
71762306a36Sopenharmony_ci		if (!sa)
71862306a36Sopenharmony_ci			panic("could not allocate memory for save area\n");
71962306a36Sopenharmony_ci		__pcpu_sigp_relax(addr, SIGP_STORE_STATUS_AT_ADDRESS, __pa(page));
72062306a36Sopenharmony_ci		save_area_add_regs(sa, page);
72162306a36Sopenharmony_ci		if (MACHINE_HAS_VX) {
72262306a36Sopenharmony_ci			__pcpu_sigp_relax(addr, SIGP_STORE_ADDITIONAL_STATUS, __pa(page));
72362306a36Sopenharmony_ci			save_area_add_vxrs(sa, page);
72462306a36Sopenharmony_ci		}
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci	memblock_free(page, PAGE_SIZE);
72762306a36Sopenharmony_ci	diag_amode31_ops.diag308_reset();
72862306a36Sopenharmony_ci	pcpu_set_smt(0);
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci#endif /* CONFIG_CRASH_DUMP */
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_civoid smp_cpu_set_polarization(int cpu, int val)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	pcpu_devices[cpu].polarization = val;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ciint smp_cpu_get_polarization(int cpu)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	return pcpu_devices[cpu].polarization;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ciint smp_cpu_get_cpu_address(int cpu)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	return pcpu_devices[cpu].address;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic void __ref smp_get_core_info(struct sclp_core_info *info, int early)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	static int use_sigp_detection;
75062306a36Sopenharmony_ci	int address;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	if (use_sigp_detection || sclp_get_core_info(info, early)) {
75362306a36Sopenharmony_ci		use_sigp_detection = 1;
75462306a36Sopenharmony_ci		for (address = 0;
75562306a36Sopenharmony_ci		     address < (SCLP_MAX_CORES << smp_cpu_mt_shift);
75662306a36Sopenharmony_ci		     address += (1U << smp_cpu_mt_shift)) {
75762306a36Sopenharmony_ci			if (__pcpu_sigp_relax(address, SIGP_SENSE, 0) ==
75862306a36Sopenharmony_ci			    SIGP_CC_NOT_OPERATIONAL)
75962306a36Sopenharmony_ci				continue;
76062306a36Sopenharmony_ci			info->core[info->configured].core_id =
76162306a36Sopenharmony_ci				address >> smp_cpu_mt_shift;
76262306a36Sopenharmony_ci			info->configured++;
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci		info->combined = info->configured;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic int smp_add_present_cpu(int cpu);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic int smp_add_core(struct sclp_core_entry *core, cpumask_t *avail,
77162306a36Sopenharmony_ci			bool configured, bool early)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct pcpu *pcpu;
77462306a36Sopenharmony_ci	int cpu, nr, i;
77562306a36Sopenharmony_ci	u16 address;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	nr = 0;
77862306a36Sopenharmony_ci	if (sclp.has_core_type && core->type != boot_core_type)
77962306a36Sopenharmony_ci		return nr;
78062306a36Sopenharmony_ci	cpu = cpumask_first(avail);
78162306a36Sopenharmony_ci	address = core->core_id << smp_cpu_mt_shift;
78262306a36Sopenharmony_ci	for (i = 0; (i <= smp_cpu_mtid) && (cpu < nr_cpu_ids); i++) {
78362306a36Sopenharmony_ci		if (pcpu_find_address(cpu_present_mask, address + i))
78462306a36Sopenharmony_ci			continue;
78562306a36Sopenharmony_ci		pcpu = pcpu_devices + cpu;
78662306a36Sopenharmony_ci		pcpu->address = address + i;
78762306a36Sopenharmony_ci		if (configured)
78862306a36Sopenharmony_ci			pcpu->state = CPU_STATE_CONFIGURED;
78962306a36Sopenharmony_ci		else
79062306a36Sopenharmony_ci			pcpu->state = CPU_STATE_STANDBY;
79162306a36Sopenharmony_ci		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
79262306a36Sopenharmony_ci		set_cpu_present(cpu, true);
79362306a36Sopenharmony_ci		if (!early && smp_add_present_cpu(cpu) != 0)
79462306a36Sopenharmony_ci			set_cpu_present(cpu, false);
79562306a36Sopenharmony_ci		else
79662306a36Sopenharmony_ci			nr++;
79762306a36Sopenharmony_ci		cpumask_clear_cpu(cpu, avail);
79862306a36Sopenharmony_ci		cpu = cpumask_next(cpu, avail);
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci	return nr;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic int __smp_rescan_cpus(struct sclp_core_info *info, bool early)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct sclp_core_entry *core;
80662306a36Sopenharmony_ci	static cpumask_t avail;
80762306a36Sopenharmony_ci	bool configured;
80862306a36Sopenharmony_ci	u16 core_id;
80962306a36Sopenharmony_ci	int nr, i;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	cpus_read_lock();
81262306a36Sopenharmony_ci	mutex_lock(&smp_cpu_state_mutex);
81362306a36Sopenharmony_ci	nr = 0;
81462306a36Sopenharmony_ci	cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
81562306a36Sopenharmony_ci	/*
81662306a36Sopenharmony_ci	 * Add IPL core first (which got logical CPU number 0) to make sure
81762306a36Sopenharmony_ci	 * that all SMT threads get subsequent logical CPU numbers.
81862306a36Sopenharmony_ci	 */
81962306a36Sopenharmony_ci	if (early) {
82062306a36Sopenharmony_ci		core_id = pcpu_devices[0].address >> smp_cpu_mt_shift;
82162306a36Sopenharmony_ci		for (i = 0; i < info->configured; i++) {
82262306a36Sopenharmony_ci			core = &info->core[i];
82362306a36Sopenharmony_ci			if (core->core_id == core_id) {
82462306a36Sopenharmony_ci				nr += smp_add_core(core, &avail, true, early);
82562306a36Sopenharmony_ci				break;
82662306a36Sopenharmony_ci			}
82762306a36Sopenharmony_ci		}
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci	for (i = 0; i < info->combined; i++) {
83062306a36Sopenharmony_ci		configured = i < info->configured;
83162306a36Sopenharmony_ci		nr += smp_add_core(&info->core[i], &avail, configured, early);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci	mutex_unlock(&smp_cpu_state_mutex);
83462306a36Sopenharmony_ci	cpus_read_unlock();
83562306a36Sopenharmony_ci	return nr;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_civoid __init smp_detect_cpus(void)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	unsigned int cpu, mtid, c_cpus, s_cpus;
84162306a36Sopenharmony_ci	struct sclp_core_info *info;
84262306a36Sopenharmony_ci	u16 address;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	/* Get CPU information */
84562306a36Sopenharmony_ci	info = memblock_alloc(sizeof(*info), 8);
84662306a36Sopenharmony_ci	if (!info)
84762306a36Sopenharmony_ci		panic("%s: Failed to allocate %zu bytes align=0x%x\n",
84862306a36Sopenharmony_ci		      __func__, sizeof(*info), 8);
84962306a36Sopenharmony_ci	smp_get_core_info(info, 1);
85062306a36Sopenharmony_ci	/* Find boot CPU type */
85162306a36Sopenharmony_ci	if (sclp.has_core_type) {
85262306a36Sopenharmony_ci		address = stap();
85362306a36Sopenharmony_ci		for (cpu = 0; cpu < info->combined; cpu++)
85462306a36Sopenharmony_ci			if (info->core[cpu].core_id == address) {
85562306a36Sopenharmony_ci				/* The boot cpu dictates the cpu type. */
85662306a36Sopenharmony_ci				boot_core_type = info->core[cpu].type;
85762306a36Sopenharmony_ci				break;
85862306a36Sopenharmony_ci			}
85962306a36Sopenharmony_ci		if (cpu >= info->combined)
86062306a36Sopenharmony_ci			panic("Could not find boot CPU type");
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* Set multi-threading state for the current system */
86462306a36Sopenharmony_ci	mtid = boot_core_type ? sclp.mtid : sclp.mtid_cp;
86562306a36Sopenharmony_ci	mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1;
86662306a36Sopenharmony_ci	pcpu_set_smt(mtid);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* Print number of CPUs */
86962306a36Sopenharmony_ci	c_cpus = s_cpus = 0;
87062306a36Sopenharmony_ci	for (cpu = 0; cpu < info->combined; cpu++) {
87162306a36Sopenharmony_ci		if (sclp.has_core_type &&
87262306a36Sopenharmony_ci		    info->core[cpu].type != boot_core_type)
87362306a36Sopenharmony_ci			continue;
87462306a36Sopenharmony_ci		if (cpu < info->configured)
87562306a36Sopenharmony_ci			c_cpus += smp_cpu_mtid + 1;
87662306a36Sopenharmony_ci		else
87762306a36Sopenharmony_ci			s_cpus += smp_cpu_mtid + 1;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci	pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	/* Add CPUs present at boot */
88262306a36Sopenharmony_ci	__smp_rescan_cpus(info, true);
88362306a36Sopenharmony_ci	memblock_free(info, sizeof(*info));
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci/*
88762306a36Sopenharmony_ci *	Activate a secondary processor.
88862306a36Sopenharmony_ci */
88962306a36Sopenharmony_cistatic void smp_start_secondary(void *cpuvoid)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	int cpu = raw_smp_processor_id();
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	S390_lowcore.last_update_clock = get_tod_clock();
89462306a36Sopenharmony_ci	S390_lowcore.restart_stack = (unsigned long)restart_stack;
89562306a36Sopenharmony_ci	S390_lowcore.restart_fn = (unsigned long)do_restart;
89662306a36Sopenharmony_ci	S390_lowcore.restart_data = 0;
89762306a36Sopenharmony_ci	S390_lowcore.restart_source = -1U;
89862306a36Sopenharmony_ci	S390_lowcore.restart_flags = 0;
89962306a36Sopenharmony_ci	restore_access_regs(S390_lowcore.access_regs_save_area);
90062306a36Sopenharmony_ci	cpu_init();
90162306a36Sopenharmony_ci	rcu_cpu_starting(cpu);
90262306a36Sopenharmony_ci	init_cpu_timer();
90362306a36Sopenharmony_ci	vtime_init();
90462306a36Sopenharmony_ci	vdso_getcpu_init();
90562306a36Sopenharmony_ci	pfault_init();
90662306a36Sopenharmony_ci	cpumask_set_cpu(cpu, &cpu_setup_mask);
90762306a36Sopenharmony_ci	update_cpu_masks();
90862306a36Sopenharmony_ci	notify_cpu_starting(cpu);
90962306a36Sopenharmony_ci	if (topology_cpu_dedicated(cpu))
91062306a36Sopenharmony_ci		set_cpu_flag(CIF_DEDICATED_CPU);
91162306a36Sopenharmony_ci	else
91262306a36Sopenharmony_ci		clear_cpu_flag(CIF_DEDICATED_CPU);
91362306a36Sopenharmony_ci	set_cpu_online(cpu, true);
91462306a36Sopenharmony_ci	inc_irq_stat(CPU_RST);
91562306a36Sopenharmony_ci	local_irq_enable();
91662306a36Sopenharmony_ci	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci/* Upping and downing of CPUs */
92062306a36Sopenharmony_ciint __cpu_up(unsigned int cpu, struct task_struct *tidle)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	struct pcpu *pcpu = pcpu_devices + cpu;
92362306a36Sopenharmony_ci	int rc;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	if (pcpu->state != CPU_STATE_CONFIGURED)
92662306a36Sopenharmony_ci		return -EIO;
92762306a36Sopenharmony_ci	if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
92862306a36Sopenharmony_ci	    SIGP_CC_ORDER_CODE_ACCEPTED)
92962306a36Sopenharmony_ci		return -EIO;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	rc = pcpu_alloc_lowcore(pcpu, cpu);
93262306a36Sopenharmony_ci	if (rc)
93362306a36Sopenharmony_ci		return rc;
93462306a36Sopenharmony_ci	/*
93562306a36Sopenharmony_ci	 * Make sure global control register contents do not change
93662306a36Sopenharmony_ci	 * until new CPU has initialized control registers.
93762306a36Sopenharmony_ci	 */
93862306a36Sopenharmony_ci	spin_lock(&ctl_lock);
93962306a36Sopenharmony_ci	pcpu_prepare_secondary(pcpu, cpu);
94062306a36Sopenharmony_ci	pcpu_attach_task(pcpu, tidle);
94162306a36Sopenharmony_ci	pcpu_start_fn(pcpu, smp_start_secondary, NULL);
94262306a36Sopenharmony_ci	/* Wait until cpu puts itself in the online & active maps */
94362306a36Sopenharmony_ci	while (!cpu_online(cpu))
94462306a36Sopenharmony_ci		cpu_relax();
94562306a36Sopenharmony_ci	spin_unlock(&ctl_lock);
94662306a36Sopenharmony_ci	return 0;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic unsigned int setup_possible_cpus __initdata;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic int __init _setup_possible_cpus(char *s)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	get_option(&s, &setup_possible_cpus);
95462306a36Sopenharmony_ci	return 0;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ciearly_param("possible_cpus", _setup_possible_cpus);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ciint __cpu_disable(void)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	unsigned long cregs[16];
96162306a36Sopenharmony_ci	int cpu;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	/* Handle possible pending IPIs */
96462306a36Sopenharmony_ci	smp_handle_ext_call();
96562306a36Sopenharmony_ci	cpu = smp_processor_id();
96662306a36Sopenharmony_ci	set_cpu_online(cpu, false);
96762306a36Sopenharmony_ci	cpumask_clear_cpu(cpu, &cpu_setup_mask);
96862306a36Sopenharmony_ci	update_cpu_masks();
96962306a36Sopenharmony_ci	/* Disable pseudo page faults on this cpu. */
97062306a36Sopenharmony_ci	pfault_fini();
97162306a36Sopenharmony_ci	/* Disable interrupt sources via control register. */
97262306a36Sopenharmony_ci	__ctl_store(cregs, 0, 15);
97362306a36Sopenharmony_ci	cregs[0]  &= ~0x0000ee70UL;	/* disable all external interrupts */
97462306a36Sopenharmony_ci	cregs[6]  &= ~0xff000000UL;	/* disable all I/O interrupts */
97562306a36Sopenharmony_ci	cregs[14] &= ~0x1f000000UL;	/* disable most machine checks */
97662306a36Sopenharmony_ci	__ctl_load(cregs, 0, 15);
97762306a36Sopenharmony_ci	clear_cpu_flag(CIF_NOHZ_DELAY);
97862306a36Sopenharmony_ci	return 0;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_civoid __cpu_die(unsigned int cpu)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct pcpu *pcpu;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* Wait until target cpu is down */
98662306a36Sopenharmony_ci	pcpu = pcpu_devices + cpu;
98762306a36Sopenharmony_ci	while (!pcpu_stopped(pcpu))
98862306a36Sopenharmony_ci		cpu_relax();
98962306a36Sopenharmony_ci	pcpu_free_lowcore(pcpu);
99062306a36Sopenharmony_ci	cpumask_clear_cpu(cpu, mm_cpumask(&init_mm));
99162306a36Sopenharmony_ci	cpumask_clear_cpu(cpu, &init_mm.context.cpu_attach_mask);
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_civoid __noreturn cpu_die(void)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	idle_task_exit();
99762306a36Sopenharmony_ci	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
99862306a36Sopenharmony_ci	for (;;) ;
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_civoid __init smp_fill_possible_mask(void)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	unsigned int possible, sclp_max, cpu;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	sclp_max = max(sclp.mtid, sclp.mtid_cp) + 1;
100662306a36Sopenharmony_ci	sclp_max = min(smp_max_threads, sclp_max);
100762306a36Sopenharmony_ci	sclp_max = (sclp.max_cores * sclp_max) ?: nr_cpu_ids;
100862306a36Sopenharmony_ci	possible = setup_possible_cpus ?: nr_cpu_ids;
100962306a36Sopenharmony_ci	possible = min(possible, sclp_max);
101062306a36Sopenharmony_ci	for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
101162306a36Sopenharmony_ci		set_cpu_possible(cpu, true);
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_civoid __init smp_prepare_cpus(unsigned int max_cpus)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	/* request the 0x1201 emergency signal external interrupt */
101762306a36Sopenharmony_ci	if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt))
101862306a36Sopenharmony_ci		panic("Couldn't request external interrupt 0x1201");
101962306a36Sopenharmony_ci	/* request the 0x1202 external call external interrupt */
102062306a36Sopenharmony_ci	if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
102162306a36Sopenharmony_ci		panic("Couldn't request external interrupt 0x1202");
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_civoid __init smp_prepare_boot_cpu(void)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	struct pcpu *pcpu = pcpu_devices;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	WARN_ON(!cpu_present(0) || !cpu_online(0));
102962306a36Sopenharmony_ci	pcpu->state = CPU_STATE_CONFIGURED;
103062306a36Sopenharmony_ci	S390_lowcore.percpu_offset = __per_cpu_offset[0];
103162306a36Sopenharmony_ci	smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN);
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_civoid __init smp_setup_processor_id(void)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	pcpu_devices[0].address = stap();
103762306a36Sopenharmony_ci	S390_lowcore.cpu_nr = 0;
103862306a36Sopenharmony_ci	S390_lowcore.spinlock_lockval = arch_spin_lockval(0);
103962306a36Sopenharmony_ci	S390_lowcore.spinlock_index = 0;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci/*
104362306a36Sopenharmony_ci * the frequency of the profiling timer can be changed
104462306a36Sopenharmony_ci * by writing a multiplier value into /proc/profile.
104562306a36Sopenharmony_ci *
104662306a36Sopenharmony_ci * usually you want to run this on all CPUs ;)
104762306a36Sopenharmony_ci */
104862306a36Sopenharmony_ciint setup_profiling_timer(unsigned int multiplier)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	return 0;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic ssize_t cpu_configure_show(struct device *dev,
105462306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
105562306a36Sopenharmony_ci{
105662306a36Sopenharmony_ci	ssize_t count;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	mutex_lock(&smp_cpu_state_mutex);
105962306a36Sopenharmony_ci	count = sprintf(buf, "%d\n", pcpu_devices[dev->id].state);
106062306a36Sopenharmony_ci	mutex_unlock(&smp_cpu_state_mutex);
106162306a36Sopenharmony_ci	return count;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic ssize_t cpu_configure_store(struct device *dev,
106562306a36Sopenharmony_ci				   struct device_attribute *attr,
106662306a36Sopenharmony_ci				   const char *buf, size_t count)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	struct pcpu *pcpu;
106962306a36Sopenharmony_ci	int cpu, val, rc, i;
107062306a36Sopenharmony_ci	char delim;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	if (sscanf(buf, "%d %c", &val, &delim) != 1)
107362306a36Sopenharmony_ci		return -EINVAL;
107462306a36Sopenharmony_ci	if (val != 0 && val != 1)
107562306a36Sopenharmony_ci		return -EINVAL;
107662306a36Sopenharmony_ci	cpus_read_lock();
107762306a36Sopenharmony_ci	mutex_lock(&smp_cpu_state_mutex);
107862306a36Sopenharmony_ci	rc = -EBUSY;
107962306a36Sopenharmony_ci	/* disallow configuration changes of online cpus and cpu 0 */
108062306a36Sopenharmony_ci	cpu = dev->id;
108162306a36Sopenharmony_ci	cpu = smp_get_base_cpu(cpu);
108262306a36Sopenharmony_ci	if (cpu == 0)
108362306a36Sopenharmony_ci		goto out;
108462306a36Sopenharmony_ci	for (i = 0; i <= smp_cpu_mtid; i++)
108562306a36Sopenharmony_ci		if (cpu_online(cpu + i))
108662306a36Sopenharmony_ci			goto out;
108762306a36Sopenharmony_ci	pcpu = pcpu_devices + cpu;
108862306a36Sopenharmony_ci	rc = 0;
108962306a36Sopenharmony_ci	switch (val) {
109062306a36Sopenharmony_ci	case 0:
109162306a36Sopenharmony_ci		if (pcpu->state != CPU_STATE_CONFIGURED)
109262306a36Sopenharmony_ci			break;
109362306a36Sopenharmony_ci		rc = sclp_core_deconfigure(pcpu->address >> smp_cpu_mt_shift);
109462306a36Sopenharmony_ci		if (rc)
109562306a36Sopenharmony_ci			break;
109662306a36Sopenharmony_ci		for (i = 0; i <= smp_cpu_mtid; i++) {
109762306a36Sopenharmony_ci			if (cpu + i >= nr_cpu_ids || !cpu_present(cpu + i))
109862306a36Sopenharmony_ci				continue;
109962306a36Sopenharmony_ci			pcpu[i].state = CPU_STATE_STANDBY;
110062306a36Sopenharmony_ci			smp_cpu_set_polarization(cpu + i,
110162306a36Sopenharmony_ci						 POLARIZATION_UNKNOWN);
110262306a36Sopenharmony_ci		}
110362306a36Sopenharmony_ci		topology_expect_change();
110462306a36Sopenharmony_ci		break;
110562306a36Sopenharmony_ci	case 1:
110662306a36Sopenharmony_ci		if (pcpu->state != CPU_STATE_STANDBY)
110762306a36Sopenharmony_ci			break;
110862306a36Sopenharmony_ci		rc = sclp_core_configure(pcpu->address >> smp_cpu_mt_shift);
110962306a36Sopenharmony_ci		if (rc)
111062306a36Sopenharmony_ci			break;
111162306a36Sopenharmony_ci		for (i = 0; i <= smp_cpu_mtid; i++) {
111262306a36Sopenharmony_ci			if (cpu + i >= nr_cpu_ids || !cpu_present(cpu + i))
111362306a36Sopenharmony_ci				continue;
111462306a36Sopenharmony_ci			pcpu[i].state = CPU_STATE_CONFIGURED;
111562306a36Sopenharmony_ci			smp_cpu_set_polarization(cpu + i,
111662306a36Sopenharmony_ci						 POLARIZATION_UNKNOWN);
111762306a36Sopenharmony_ci		}
111862306a36Sopenharmony_ci		topology_expect_change();
111962306a36Sopenharmony_ci		break;
112062306a36Sopenharmony_ci	default:
112162306a36Sopenharmony_ci		break;
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ciout:
112462306a36Sopenharmony_ci	mutex_unlock(&smp_cpu_state_mutex);
112562306a36Sopenharmony_ci	cpus_read_unlock();
112662306a36Sopenharmony_ci	return rc ? rc : count;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_cistatic DEVICE_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic ssize_t show_cpu_address(struct device *dev,
113162306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	return sprintf(buf, "%d\n", pcpu_devices[dev->id].address);
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_cistatic DEVICE_ATTR(address, 0444, show_cpu_address, NULL);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic struct attribute *cpu_common_attrs[] = {
113862306a36Sopenharmony_ci	&dev_attr_configure.attr,
113962306a36Sopenharmony_ci	&dev_attr_address.attr,
114062306a36Sopenharmony_ci	NULL,
114162306a36Sopenharmony_ci};
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic struct attribute_group cpu_common_attr_group = {
114462306a36Sopenharmony_ci	.attrs = cpu_common_attrs,
114562306a36Sopenharmony_ci};
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic struct attribute *cpu_online_attrs[] = {
114862306a36Sopenharmony_ci	&dev_attr_idle_count.attr,
114962306a36Sopenharmony_ci	&dev_attr_idle_time_us.attr,
115062306a36Sopenharmony_ci	NULL,
115162306a36Sopenharmony_ci};
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic struct attribute_group cpu_online_attr_group = {
115462306a36Sopenharmony_ci	.attrs = cpu_online_attrs,
115562306a36Sopenharmony_ci};
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic int smp_cpu_online(unsigned int cpu)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	struct device *s = &per_cpu(cpu_device, cpu)->dev;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	return sysfs_create_group(&s->kobj, &cpu_online_attr_group);
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic int smp_cpu_pre_down(unsigned int cpu)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	struct device *s = &per_cpu(cpu_device, cpu)->dev;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
116962306a36Sopenharmony_ci	return 0;
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic int smp_add_present_cpu(int cpu)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	struct device *s;
117562306a36Sopenharmony_ci	struct cpu *c;
117662306a36Sopenharmony_ci	int rc;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	c = kzalloc(sizeof(*c), GFP_KERNEL);
117962306a36Sopenharmony_ci	if (!c)
118062306a36Sopenharmony_ci		return -ENOMEM;
118162306a36Sopenharmony_ci	per_cpu(cpu_device, cpu) = c;
118262306a36Sopenharmony_ci	s = &c->dev;
118362306a36Sopenharmony_ci	c->hotpluggable = 1;
118462306a36Sopenharmony_ci	rc = register_cpu(c, cpu);
118562306a36Sopenharmony_ci	if (rc)
118662306a36Sopenharmony_ci		goto out;
118762306a36Sopenharmony_ci	rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group);
118862306a36Sopenharmony_ci	if (rc)
118962306a36Sopenharmony_ci		goto out_cpu;
119062306a36Sopenharmony_ci	rc = topology_cpu_init(c);
119162306a36Sopenharmony_ci	if (rc)
119262306a36Sopenharmony_ci		goto out_topology;
119362306a36Sopenharmony_ci	return 0;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ciout_topology:
119662306a36Sopenharmony_ci	sysfs_remove_group(&s->kobj, &cpu_common_attr_group);
119762306a36Sopenharmony_ciout_cpu:
119862306a36Sopenharmony_ci	unregister_cpu(c);
119962306a36Sopenharmony_ciout:
120062306a36Sopenharmony_ci	return rc;
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ciint __ref smp_rescan_cpus(void)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	struct sclp_core_info *info;
120662306a36Sopenharmony_ci	int nr;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	info = kzalloc(sizeof(*info), GFP_KERNEL);
120962306a36Sopenharmony_ci	if (!info)
121062306a36Sopenharmony_ci		return -ENOMEM;
121162306a36Sopenharmony_ci	smp_get_core_info(info, 0);
121262306a36Sopenharmony_ci	nr = __smp_rescan_cpus(info, false);
121362306a36Sopenharmony_ci	kfree(info);
121462306a36Sopenharmony_ci	if (nr)
121562306a36Sopenharmony_ci		topology_schedule_update();
121662306a36Sopenharmony_ci	return 0;
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic ssize_t __ref rescan_store(struct device *dev,
122062306a36Sopenharmony_ci				  struct device_attribute *attr,
122162306a36Sopenharmony_ci				  const char *buf,
122262306a36Sopenharmony_ci				  size_t count)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	int rc;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	rc = lock_device_hotplug_sysfs();
122762306a36Sopenharmony_ci	if (rc)
122862306a36Sopenharmony_ci		return rc;
122962306a36Sopenharmony_ci	rc = smp_rescan_cpus();
123062306a36Sopenharmony_ci	unlock_device_hotplug();
123162306a36Sopenharmony_ci	return rc ? rc : count;
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_cistatic DEVICE_ATTR_WO(rescan);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic int __init s390_smp_init(void)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct device *dev_root;
123862306a36Sopenharmony_ci	int cpu, rc = 0;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	dev_root = bus_get_dev_root(&cpu_subsys);
124162306a36Sopenharmony_ci	if (dev_root) {
124262306a36Sopenharmony_ci		rc = device_create_file(dev_root, &dev_attr_rescan);
124362306a36Sopenharmony_ci		put_device(dev_root);
124462306a36Sopenharmony_ci		if (rc)
124562306a36Sopenharmony_ci			return rc;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	for_each_present_cpu(cpu) {
124962306a36Sopenharmony_ci		rc = smp_add_present_cpu(cpu);
125062306a36Sopenharmony_ci		if (rc)
125162306a36Sopenharmony_ci			goto out;
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "s390/smp:online",
125562306a36Sopenharmony_ci			       smp_cpu_online, smp_cpu_pre_down);
125662306a36Sopenharmony_ci	rc = rc <= 0 ? rc : 0;
125762306a36Sopenharmony_ciout:
125862306a36Sopenharmony_ci	return rc;
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_cisubsys_initcall(s390_smp_init);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_cistatic __always_inline void set_new_lowcore(struct lowcore *lc)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	union register_pair dst, src;
126562306a36Sopenharmony_ci	u32 pfx;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	src.even = (unsigned long) &S390_lowcore;
126862306a36Sopenharmony_ci	src.odd  = sizeof(S390_lowcore);
126962306a36Sopenharmony_ci	dst.even = (unsigned long) lc;
127062306a36Sopenharmony_ci	dst.odd  = sizeof(*lc);
127162306a36Sopenharmony_ci	pfx = __pa(lc);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	asm volatile(
127462306a36Sopenharmony_ci		"	mvcl	%[dst],%[src]\n"
127562306a36Sopenharmony_ci		"	spx	%[pfx]\n"
127662306a36Sopenharmony_ci		: [dst] "+&d" (dst.pair), [src] "+&d" (src.pair)
127762306a36Sopenharmony_ci		: [pfx] "Q" (pfx)
127862306a36Sopenharmony_ci		: "memory", "cc");
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ciint __init smp_reinit_ipl_cpu(void)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	unsigned long async_stack, nodat_stack, mcck_stack;
128462306a36Sopenharmony_ci	struct lowcore *lc, *lc_ipl;
128562306a36Sopenharmony_ci	unsigned long flags, cr0;
128662306a36Sopenharmony_ci	u64 mcesad;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	lc_ipl = lowcore_ptr[0];
128962306a36Sopenharmony_ci	lc = (struct lowcore *)	__get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
129062306a36Sopenharmony_ci	nodat_stack = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
129162306a36Sopenharmony_ci	async_stack = stack_alloc();
129262306a36Sopenharmony_ci	mcck_stack = stack_alloc();
129362306a36Sopenharmony_ci	if (!lc || !nodat_stack || !async_stack || !mcck_stack || nmi_alloc_mcesa(&mcesad))
129462306a36Sopenharmony_ci		panic("Couldn't allocate memory");
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	local_irq_save(flags);
129762306a36Sopenharmony_ci	local_mcck_disable();
129862306a36Sopenharmony_ci	set_new_lowcore(lc);
129962306a36Sopenharmony_ci	S390_lowcore.nodat_stack = nodat_stack + STACK_INIT_OFFSET;
130062306a36Sopenharmony_ci	S390_lowcore.async_stack = async_stack + STACK_INIT_OFFSET;
130162306a36Sopenharmony_ci	S390_lowcore.mcck_stack = mcck_stack + STACK_INIT_OFFSET;
130262306a36Sopenharmony_ci	__ctl_store(cr0, 0, 0);
130362306a36Sopenharmony_ci	__ctl_clear_bit(0, 28); /* disable lowcore protection */
130462306a36Sopenharmony_ci	S390_lowcore.mcesad = mcesad;
130562306a36Sopenharmony_ci	__ctl_load(cr0, 0, 0);
130662306a36Sopenharmony_ci	if (abs_lowcore_map(0, lc, false))
130762306a36Sopenharmony_ci		panic("Couldn't remap absolute lowcore");
130862306a36Sopenharmony_ci	lowcore_ptr[0] = lc;
130962306a36Sopenharmony_ci	local_mcck_enable();
131062306a36Sopenharmony_ci	local_irq_restore(flags);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	memblock_free_late(__pa(lc_ipl->mcck_stack - STACK_INIT_OFFSET), THREAD_SIZE);
131362306a36Sopenharmony_ci	memblock_free_late(__pa(lc_ipl->async_stack - STACK_INIT_OFFSET), THREAD_SIZE);
131462306a36Sopenharmony_ci	memblock_free_late(__pa(lc_ipl->nodat_stack - STACK_INIT_OFFSET), THREAD_SIZE);
131562306a36Sopenharmony_ci	memblock_free_late(__pa(lc_ipl), sizeof(*lc_ipl));
131662306a36Sopenharmony_ci	return 0;
131762306a36Sopenharmony_ci}
1318