smp.c 26.0 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
M
Martin Schwidefsky 已提交
2
 *  SMP related functions
L
Linus Torvalds 已提交
3
 *
4
 *    Copyright IBM Corp. 1999, 2012
M
Martin Schwidefsky 已提交
5 6 7
 *    Author(s): Denis Joseph Barrow,
 *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
 *		 Heiko Carstens <heiko.carstens@de.ibm.com>,
L
Linus Torvalds 已提交
8
 *
9
 *  based on other smp stuff by
L
Linus Torvalds 已提交
10 11 12
 *    (c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
 *    (c) 1998 Ingo Molnar
 *
M
Martin Schwidefsky 已提交
13 14 15
 * 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.
L
Linus Torvalds 已提交
16 17
 */

18 19 20
#define KMSG_COMPONENT "cpu"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

21
#include <linux/workqueue.h>
L
Linus Torvalds 已提交
22 23 24
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
A
Alexey Dobriyan 已提交
25
#include <linux/err.h>
L
Linus Torvalds 已提交
26 27 28 29
#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
30
#include <linux/irqflags.h>
L
Linus Torvalds 已提交
31
#include <linux/cpu.h>
32
#include <linux/slab.h>
M
Michael Holzheu 已提交
33
#include <linux/crash_dump.h>
34
#include <asm/asm-offsets.h>
35 36
#include <asm/switch_to.h>
#include <asm/facility.h>
M
Michael Holzheu 已提交
37
#include <asm/ipl.h>
38
#include <asm/setup.h>
L
Linus Torvalds 已提交
39 40
#include <asm/irq.h>
#include <asm/tlbflush.h>
41
#include <asm/vtimer.h>
M
Michael Holzheu 已提交
42
#include <asm/lowcore.h>
43
#include <asm/sclp.h>
44
#include <asm/vdso.h>
45
#include <asm/debug.h>
46
#include <asm/os_info.h>
47
#include <asm/sigp.h>
48
#include "entry.h"
L
Linus Torvalds 已提交
49

M
Martin Schwidefsky 已提交
50 51 52 53 54 55
enum {
	ec_schedule = 0,
	ec_call_function,
	ec_call_function_single,
	ec_stop_cpu,
};
56

M
Martin Schwidefsky 已提交
57
enum {
58 59 60 61
	CPU_STATE_STANDBY,
	CPU_STATE_CONFIGURED,
};

M
Martin Schwidefsky 已提交
62 63 64 65 66 67 68
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 */
69
	int polarization;		/* physical polarization */
M
Martin Schwidefsky 已提交
70 71 72 73 74 75 76
	u16 address;			/* physical cpu address */
};

static u8 boot_cpu_type;
static u16 boot_cpu_address;
static struct pcpu pcpu_devices[NR_CPUS];

77 78 79 80
/*
 * The smp_cpu_state_mutex must be held when changing the state or polarization
 * member of a pcpu data structure within the pcpu_devices arreay.
 */
81
DEFINE_MUTEX(smp_cpu_state_mutex);
82

M
Martin Schwidefsky 已提交
83 84 85 86 87 88 89
/*
 * 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;
90

M
Martin Schwidefsky 已提交
91 92 93 94 95 96 97 98 99
	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;
}
L
Linus Torvalds 已提交
100

M
Martin Schwidefsky 已提交
101
static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
102
{
M
Martin Schwidefsky 已提交
103
	int cc;
104

M
Martin Schwidefsky 已提交
105
	while (1) {
106
		cc = __pcpu_sigp(addr, order, parm, NULL);
107
		if (cc != SIGP_CC_BUSY)
M
Martin Schwidefsky 已提交
108 109
			return cc;
		cpu_relax();
110 111 112
	}
}

M
Martin Schwidefsky 已提交
113
static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
H
Heiko Carstens 已提交
114
{
M
Martin Schwidefsky 已提交
115 116 117
	int cc, retry;

	for (retry = 0; ; retry++) {
118
		cc = __pcpu_sigp(pcpu->address, order, parm, NULL);
119
		if (cc != SIGP_CC_BUSY)
M
Martin Schwidefsky 已提交
120 121 122 123 124 125 126 127 128
			break;
		if (retry >= 3)
			udelay(10);
	}
	return cc;
}

static inline int pcpu_stopped(struct pcpu *pcpu)
{
129
	u32 uninitialized_var(status);
130

131
	if (__pcpu_sigp(pcpu->address, SIGP_SENSE,
132
			0, &status) != SIGP_CC_STATUS_STORED)
M
Martin Schwidefsky 已提交
133
		return 0;
134
	return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
M
Martin Schwidefsky 已提交
135 136 137
}

static inline int pcpu_running(struct pcpu *pcpu)
H
Heiko Carstens 已提交
138
{
139
	if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING,
140
			0, NULL) != SIGP_CC_STATUS_STORED)
M
Martin Schwidefsky 已提交
141
		return 1;
142 143
	/* Status stored condition code is equivalent to cpu not running. */
	return 0;
H
Heiko Carstens 已提交
144 145
}

146
/*
M
Martin Schwidefsky 已提交
147
 * Find struct pcpu by cpu address.
148
 */
M
Martin Schwidefsky 已提交
149
static struct pcpu *pcpu_find_address(const struct cpumask *mask, int address)
150 151 152
{
	int cpu;

M
Martin Schwidefsky 已提交
153 154 155 156 157 158 159 160 161 162 163 164
	for_each_cpu(cpu, mask)
		if (pcpu_devices[cpu].address == address)
			return pcpu_devices + cpu;
	return NULL;
}

static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
{
	int order;

	set_bit(ec_bit, &pcpu->ec_mask);
	order = pcpu_running(pcpu) ?
165
		SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL;
M
Martin Schwidefsky 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179
	pcpu_sigp_retry(pcpu, order, 0);
}

static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
{
	struct _lowcore *lc;

	if (pcpu != &pcpu_devices[0]) {
		pcpu->lowcore =	(struct _lowcore *)
			__get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
		pcpu->async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
		pcpu->panic_stack = __get_free_page(GFP_KERNEL);
		if (!pcpu->lowcore || !pcpu->panic_stack || !pcpu->async_stack)
			goto out;
180
	}
M
Martin Schwidefsky 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
	lc = pcpu->lowcore;
	memcpy(lc, &S390_lowcore, 512);
	memset((char *) lc + 512, 0, sizeof(*lc) - 512);
	lc->async_stack = pcpu->async_stack + ASYNC_SIZE;
	lc->panic_stack = pcpu->panic_stack + PAGE_SIZE;
	lc->cpu_nr = cpu;
#ifndef CONFIG_64BIT
	if (MACHINE_HAS_IEEE) {
		lc->extended_save_area_addr = get_zeroed_page(GFP_KERNEL);
		if (!lc->extended_save_area_addr)
			goto out;
	}
#else
	if (vdso_alloc_per_cpu(lc))
		goto out;
#endif
	lowcore_ptr[cpu] = lc;
198
	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc);
M
Martin Schwidefsky 已提交
199 200 201 202 203 204 205 206
	return 0;
out:
	if (pcpu != &pcpu_devices[0]) {
		free_page(pcpu->panic_stack);
		free_pages(pcpu->async_stack, ASYNC_ORDER);
		free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
	}
	return -ENOMEM;
207 208
}

209 210
#ifdef CONFIG_HOTPLUG_CPU

M
Martin Schwidefsky 已提交
211
static void pcpu_free_lowcore(struct pcpu *pcpu)
212
{
213
	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
M
Martin Schwidefsky 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
	lowcore_ptr[pcpu - pcpu_devices] = NULL;
#ifndef CONFIG_64BIT
	if (MACHINE_HAS_IEEE) {
		struct _lowcore *lc = pcpu->lowcore;

		free_page((unsigned long) lc->extended_save_area_addr);
		lc->extended_save_area_addr = 0;
	}
#else
	vdso_free_per_cpu(pcpu->lowcore);
#endif
	if (pcpu != &pcpu_devices[0]) {
		free_page(pcpu->panic_stack);
		free_pages(pcpu->async_stack, ASYNC_ORDER);
		free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
	}
}

232 233
#endif /* CONFIG_HOTPLUG_CPU */

M
Martin Schwidefsky 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
{
	struct _lowcore *lc = pcpu->lowcore;

	atomic_inc(&init_mm.context.attach_count);
	lc->cpu_nr = cpu;
	lc->percpu_offset = __per_cpu_offset[cpu];
	lc->kernel_asce = S390_lowcore.kernel_asce;
	lc->machine_flags = S390_lowcore.machine_flags;
	lc->ftrace_func = S390_lowcore.ftrace_func;
	lc->user_timer = lc->system_timer = lc->steal_timer = 0;
	__ctl_store(lc->cregs_save_area, 0, 15);
	save_access_regs((unsigned int *) lc->access_regs_save_area);
	memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
	       MAX_FACILITY_BIT/8);
}

static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
{
	struct _lowcore *lc = pcpu->lowcore;
	struct thread_info *ti = task_thread_info(tsk);

	lc->kernel_stack = (unsigned long) task_stack_page(tsk) + THREAD_SIZE;
	lc->thread_info = (unsigned long) task_thread_info(tsk);
	lc->current_task = (unsigned long) tsk;
	lc->user_timer = ti->user_timer;
	lc->system_timer = ti->system_timer;
	lc->steal_timer = 0;
}

static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
{
	struct _lowcore *lc = pcpu->lowcore;

	lc->restart_stack = lc->kernel_stack;
	lc->restart_fn = (unsigned long) func;
	lc->restart_data = (unsigned long) data;
	lc->restart_source = -1UL;
272
	pcpu_sigp_retry(pcpu, SIGP_RESTART, 0);
M
Martin Schwidefsky 已提交
273 274 275 276 277 278 279 280
}

/*
 * Call function via PSW restart on pcpu and stop the current cpu.
 */
static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
			  void *data, unsigned long stack)
{
281
	struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
282
	unsigned long source_cpu = stap();
M
Martin Schwidefsky 已提交
283 284

	__load_psw_mask(psw_kernel_bits);
285
	if (pcpu->address == source_cpu)
M
Martin Schwidefsky 已提交
286 287
		func(data);	/* should not return */
	/* Stop target cpu (if func returns this stops the current cpu). */
288
	pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
M
Martin Schwidefsky 已提交
289
	/* Restart func on the target cpu and stop the current cpu. */
290 291 292 293
	mem_assign_absolute(lc->restart_stack, stack);
	mem_assign_absolute(lc->restart_fn, (unsigned long) func);
	mem_assign_absolute(lc->restart_data, (unsigned long) data);
	mem_assign_absolute(lc->restart_source, source_cpu);
M
Martin Schwidefsky 已提交
294
	asm volatile(
295
		"0:	sigp	0,%0,%2	# sigp restart to target cpu\n"
M
Martin Schwidefsky 已提交
296
		"	brc	2,0b	# busy, try again\n"
297
		"1:	sigp	0,%1,%3	# sigp stop to current cpu\n"
M
Martin Schwidefsky 已提交
298
		"	brc	2,1b	# busy, try again\n"
299
		: : "d" (pcpu->address), "d" (source_cpu),
300 301
		    "K" (SIGP_RESTART), "K" (SIGP_STOP)
		: "0", "1", "cc");
M
Martin Schwidefsky 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
	for (;;) ;
}

/*
 * Call function on an online CPU.
 */
void smp_call_online_cpu(void (*func)(void *), void *data)
{
	struct pcpu *pcpu;

	/* Use the current cpu if it is online. */
	pcpu = pcpu_find_address(cpu_online_mask, stap());
	if (!pcpu)
		/* Use the first online cpu. */
		pcpu = pcpu_devices + cpumask_first(cpu_online_mask);
	pcpu_delegate(pcpu, func, data, (unsigned long) restart_stack);
}

/*
 * Call function on the ipl CPU.
 */
void smp_call_ipl_cpu(void (*func)(void *), void *data)
{
325 326
	pcpu_delegate(&pcpu_devices[0], func, data,
		      pcpu_devices->panic_stack + PAGE_SIZE);
M
Martin Schwidefsky 已提交
327 328 329 330 331 332 333 334 335 336
}

int smp_find_processor_id(u16 address)
{
	int cpu;

	for_each_present_cpu(cpu)
		if (pcpu_devices[cpu].address == address)
			return cpu;
	return -1;
337 338
}

M
Martin Schwidefsky 已提交
339
int smp_vcpu_scheduled(int cpu)
340
{
M
Martin Schwidefsky 已提交
341 342 343 344 345 346 347
	return pcpu_running(pcpu_devices + cpu);
}

void smp_yield(void)
{
	if (MACHINE_HAS_DIAG44)
		asm volatile("diag 0,0,0x44");
348 349
}

M
Martin Schwidefsky 已提交
350
void smp_yield_cpu(int cpu)
351
{
M
Martin Schwidefsky 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	if (MACHINE_HAS_DIAG9C)
		asm volatile("diag %0,0,0x9c"
			     : : "d" (pcpu_devices[cpu].address));
	else if (MACHINE_HAS_DIAG44)
		asm volatile("diag 0,0,0x44");
}

/*
 * Send cpus emergency shutdown signal. This gives the cpus the
 * opportunity to complete outstanding interrupts.
 */
void smp_emergency_stop(cpumask_t *cpumask)
{
	u64 end;
	int cpu;

	end = get_clock() + (1000000UL << 12);
	for_each_cpu(cpu, cpumask) {
		struct pcpu *pcpu = pcpu_devices + cpu;
		set_bit(ec_stop_cpu, &pcpu->ec_mask);
372 373
		while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL,
				   0, NULL) == SIGP_CC_BUSY &&
M
Martin Schwidefsky 已提交
374 375 376 377 378 379 380 381 382
		       get_clock() < end)
			cpu_relax();
	}
	while (get_clock() < end) {
		for_each_cpu(cpu, cpumask)
			if (pcpu_stopped(pcpu_devices + cpu))
				cpumask_clear_cpu(cpu, cpumask);
		if (cpumask_empty(cpumask))
			break;
383
		cpu_relax();
M
Martin Schwidefsky 已提交
384
	}
385 386
}

M
Martin Schwidefsky 已提交
387 388 389
/*
 * Stop all cpus but the current one.
 */
390
void smp_send_stop(void)
L
Linus Torvalds 已提交
391
{
392 393
	cpumask_t cpumask;
	int cpu;
L
Linus Torvalds 已提交
394

395
	/* Disable all interrupts/machine checks */
396
	__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
397
	trace_hardirqs_off();
L
Linus Torvalds 已提交
398

399
	debug_set_critical();
400 401 402
	cpumask_copy(&cpumask, cpu_online_mask);
	cpumask_clear_cpu(smp_processor_id(), &cpumask);

M
Martin Schwidefsky 已提交
403 404
	if (oops_in_progress)
		smp_emergency_stop(&cpumask);
L
Linus Torvalds 已提交
405

406 407
	/* stop all processors */
	for_each_cpu(cpu, &cpumask) {
M
Martin Schwidefsky 已提交
408
		struct pcpu *pcpu = pcpu_devices + cpu;
409
		pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
M
Martin Schwidefsky 已提交
410
		while (!pcpu_stopped(pcpu))
H
Heiko Carstens 已提交
411 412 413 414
			cpu_relax();
	}
}

M
Martin Schwidefsky 已提交
415 416 417 418 419
/*
 * Stop the current cpu.
 */
void smp_stop_cpu(void)
{
420
	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
M
Martin Schwidefsky 已提交
421 422 423
	for (;;) ;
}

L
Linus Torvalds 已提交
424 425 426 427
/*
 * This is the main routine where commands issued by other
 * cpus are handled.
 */
428
static void do_ext_call_interrupt(struct ext_code ext_code,
429
				  unsigned int param32, unsigned long param64)
L
Linus Torvalds 已提交
430
{
431
	unsigned long bits;
M
Martin Schwidefsky 已提交
432
	int cpu;
L
Linus Torvalds 已提交
433

M
Martin Schwidefsky 已提交
434
	cpu = smp_processor_id();
435
	if (ext_code.code == 0x1202)
M
Martin Schwidefsky 已提交
436
		kstat_cpu(cpu).irqs[EXTINT_EXC]++;
437
	else
M
Martin Schwidefsky 已提交
438
		kstat_cpu(cpu).irqs[EXTINT_EMS]++;
439 440 441
	/*
	 * handle bit signal external calls
	 */
M
Martin Schwidefsky 已提交
442
	bits = xchg(&pcpu_devices[cpu].ec_mask, 0);
L
Linus Torvalds 已提交
443

444 445 446
	if (test_bit(ec_stop_cpu, &bits))
		smp_stop_cpu();

447 448 449
	if (test_bit(ec_schedule, &bits))
		scheduler_ipi();

450
	if (test_bit(ec_call_function, &bits))
451 452 453 454
		generic_smp_call_function_interrupt();

	if (test_bit(ec_call_function_single, &bits))
		generic_smp_call_function_single_interrupt();
455

L
Linus Torvalds 已提交
456 457
}

458
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
459 460 461
{
	int cpu;

462
	for_each_cpu(cpu, mask)
M
Martin Schwidefsky 已提交
463
		pcpu_ec_call(pcpu_devices + cpu, ec_call_function);
464 465 466 467
}

void arch_send_call_function_single_ipi(int cpu)
{
M
Martin Schwidefsky 已提交
468
	pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single);
469 470
}

471
#ifndef CONFIG_64BIT
L
Linus Torvalds 已提交
472 473 474
/*
 * this function sends a 'purge tlb' signal to another CPU.
 */
475
static void smp_ptlb_callback(void *info)
L
Linus Torvalds 已提交
476
{
M
Martin Schwidefsky 已提交
477
	__tlb_flush_local();
L
Linus Torvalds 已提交
478 479 480 481
}

void smp_ptlb_all(void)
{
482
	on_each_cpu(smp_ptlb_callback, NULL, 1);
L
Linus Torvalds 已提交
483 484
}
EXPORT_SYMBOL(smp_ptlb_all);
485
#endif /* ! CONFIG_64BIT */
L
Linus Torvalds 已提交
486 487 488 489 490 491 492 493

/*
 * this function sends a 'reschedule' IPI to another CPU.
 * it goes straight through and wastes no time serializing
 * anything. Worst case is that we lose a reschedule ...
 */
void smp_send_reschedule(int cpu)
{
M
Martin Schwidefsky 已提交
494
	pcpu_ec_call(pcpu_devices + cpu, ec_schedule);
L
Linus Torvalds 已提交
495 496 497 498 499
}

/*
 * parameter area for the set/clear control bit callbacks
 */
500
struct ec_creg_mask_parms {
M
Martin Schwidefsky 已提交
501 502 503
	unsigned long orval;
	unsigned long andval;
	int cr;
504
};
L
Linus Torvalds 已提交
505 506 507 508

/*
 * callback for setting/clearing control bits
 */
509 510
static void smp_ctl_bit_callback(void *info)
{
511
	struct ec_creg_mask_parms *pp = info;
L
Linus Torvalds 已提交
512
	unsigned long cregs[16];
513

514
	__ctl_store(cregs, 0, 15);
M
Martin Schwidefsky 已提交
515
	cregs[pp->cr] = (cregs[pp->cr] & pp->andval) | pp->orval;
516
	__ctl_load(cregs, 0, 15);
L
Linus Torvalds 已提交
517 518 519 520 521
}

/*
 * Set a bit in a control register of all cpus
 */
522 523
void smp_ctl_set_bit(int cr, int bit)
{
M
Martin Schwidefsky 已提交
524
	struct ec_creg_mask_parms parms = { 1UL << bit, -1UL, cr };
L
Linus Torvalds 已提交
525

526
	on_each_cpu(smp_ctl_bit_callback, &parms, 1);
L
Linus Torvalds 已提交
527
}
528
EXPORT_SYMBOL(smp_ctl_set_bit);
L
Linus Torvalds 已提交
529 530 531 532

/*
 * Clear a bit in a control register of all cpus
 */
533 534
void smp_ctl_clear_bit(int cr, int bit)
{
M
Martin Schwidefsky 已提交
535
	struct ec_creg_mask_parms parms = { 0, ~(1UL << bit), cr };
L
Linus Torvalds 已提交
536

537
	on_each_cpu(smp_ctl_bit_callback, &parms, 1);
L
Linus Torvalds 已提交
538
}
539
EXPORT_SYMBOL(smp_ctl_clear_bit);
L
Linus Torvalds 已提交
540

M
Michael Holzheu 已提交
541
#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_CRASH_DUMP)
M
Michael Holzheu 已提交
542

M
Martin Schwidefsky 已提交
543 544 545 546
struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
EXPORT_SYMBOL_GPL(zfcpdump_save_areas);

static void __init smp_get_save_area(int cpu, u16 address)
M
Michael Holzheu 已提交
547
{
M
Martin Schwidefsky 已提交
548 549 550
	void *lc = pcpu_devices[0].lowcore;
	struct save_area *save_area;

M
Michael Holzheu 已提交
551
	if (is_kdump_kernel())
M
Michael Holzheu 已提交
552
		return;
M
Martin Schwidefsky 已提交
553 554 555
	if (!OLDMEM_BASE && (address == boot_cpu_address ||
			     ipl_info.type != IPL_TYPE_FCP_DUMP))
		return;
556
	if (cpu >= NR_CPUS) {
M
Martin Schwidefsky 已提交
557 558
		pr_warning("CPU %i exceeds the maximum %i and is excluded "
			   "from the dump\n", cpu, NR_CPUS - 1);
559
		return;
M
Michael Holzheu 已提交
560
	}
M
Martin Schwidefsky 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573
	save_area = kmalloc(sizeof(struct save_area), GFP_KERNEL);
	if (!save_area)
		panic("could not allocate memory for save area\n");
	zfcpdump_save_areas[cpu] = save_area;
#ifdef CONFIG_CRASH_DUMP
	if (address == boot_cpu_address) {
		/* Copy the registers of the boot cpu. */
		copy_oldmem_page(1, (void *) save_area, sizeof(*save_area),
				 SAVE_AREA_BASE - PAGE_SIZE, 0);
		return;
	}
#endif
	/* Get the registers of a non-boot cpu. */
574
	__pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
M
Martin Schwidefsky 已提交
575
	memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area));
M
Michael Holzheu 已提交
576 577
}

M
Martin Schwidefsky 已提交
578
int smp_store_status(int cpu)
579
{
M
Martin Schwidefsky 已提交
580
	struct pcpu *pcpu;
581

M
Martin Schwidefsky 已提交
582
	pcpu = pcpu_devices + cpu;
583 584
	if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS,
			      0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED)
M
Martin Schwidefsky 已提交
585
		return -EIO;
586 587 588
	return 0;
}

M
Martin Schwidefsky 已提交
589
#else /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */
590

M
Martin Schwidefsky 已提交
591
static inline void smp_get_save_area(int cpu, u16 address) { }
592

M
Martin Schwidefsky 已提交
593
#endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */
594

595 596 597 598 599 600 601 602 603 604
void smp_cpu_set_polarization(int cpu, int val)
{
	pcpu_devices[cpu].polarization = val;
}

int smp_cpu_get_polarization(int cpu)
{
	return pcpu_devices[cpu].polarization;
}

M
Martin Schwidefsky 已提交
605
static struct sclp_cpu_info *smp_get_cpu_info(void)
606
{
M
Martin Schwidefsky 已提交
607
	static int use_sigp_detection;
608
	struct sclp_cpu_info *info;
M
Martin Schwidefsky 已提交
609 610 611 612 613 614
	int address;

	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (info && (use_sigp_detection || sclp_get_cpu_info(info))) {
		use_sigp_detection = 1;
		for (address = 0; address <= MAX_CPU_ADDRESS; address++) {
615 616
			if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) ==
			    SIGP_CC_NOT_OPERATIONAL)
M
Martin Schwidefsky 已提交
617 618 619 620 621
				continue;
			info->cpu[info->configured].address = address;
			info->configured++;
		}
		info->combined = info->configured;
622
	}
M
Martin Schwidefsky 已提交
623
	return info;
624 625
}

M
Martin Schwidefsky 已提交
626 627 628 629
static int __devinit smp_add_present_cpu(int cpu);

static int __devinit __smp_rescan_cpus(struct sclp_cpu_info *info,
				       int sysfs_add)
630
{
M
Martin Schwidefsky 已提交
631
	struct pcpu *pcpu;
632
	cpumask_t avail;
M
Martin Schwidefsky 已提交
633
	int cpu, nr, i;
634

M
Martin Schwidefsky 已提交
635
	nr = 0;
636
	cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
M
Martin Schwidefsky 已提交
637 638 639 640 641 642 643 644 645 646
	cpu = cpumask_first(&avail);
	for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) {
		if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type)
			continue;
		if (pcpu_find_address(cpu_present_mask, info->cpu[i].address))
			continue;
		pcpu = pcpu_devices + cpu;
		pcpu->address = info->cpu[i].address;
		pcpu->state = (cpu >= info->configured) ?
			CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
647
		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
M
Martin Schwidefsky 已提交
648 649 650 651 652 653 654 655
		set_cpu_present(cpu, true);
		if (sysfs_add && smp_add_present_cpu(cpu) != 0)
			set_cpu_present(cpu, false);
		else
			nr++;
		cpu = cpumask_next(cpu, &avail);
	}
	return nr;
L
Linus Torvalds 已提交
656 657
}

658 659 660 661 662
static void __init smp_detect_cpus(void)
{
	unsigned int cpu, c_cpus, s_cpus;
	struct sclp_cpu_info *info;

M
Martin Schwidefsky 已提交
663
	info = smp_get_cpu_info();
664 665 666 667
	if (!info)
		panic("smp_detect_cpus failed to allocate memory\n");
	if (info->has_cpu_type) {
		for (cpu = 0; cpu < info->combined; cpu++) {
M
Martin Schwidefsky 已提交
668 669 670 671 672
			if (info->cpu[cpu].address != boot_cpu_address)
				continue;
			/* The boot cpu dictates the cpu type. */
			boot_cpu_type = info->cpu[cpu].type;
			break;
673 674
		}
	}
M
Martin Schwidefsky 已提交
675
	c_cpus = s_cpus = 0;
676
	for (cpu = 0; cpu < info->combined; cpu++) {
M
Martin Schwidefsky 已提交
677
		if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type)
678
			continue;
M
Martin Schwidefsky 已提交
679 680 681 682
		if (cpu < info->configured) {
			smp_get_save_area(c_cpus, info->cpu[cpu].address);
			c_cpus++;
		} else
683 684
			s_cpus++;
	}
685
	pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus);
686
	get_online_cpus();
M
Martin Schwidefsky 已提交
687
	__smp_rescan_cpus(info, 0);
688
	put_online_cpus();
M
Martin Schwidefsky 已提交
689
	kfree(info);
690 691
}

L
Linus Torvalds 已提交
692
/*
693
 *	Activate a secondary processor.
L
Linus Torvalds 已提交
694
 */
M
Martin Schwidefsky 已提交
695
static void __cpuinit smp_start_secondary(void *cpuvoid)
L
Linus Torvalds 已提交
696
{
M
Martin Schwidefsky 已提交
697 698 699 700 701 702 703 704
	S390_lowcore.last_update_clock = get_clock();
	S390_lowcore.restart_stack = (unsigned long) restart_stack;
	S390_lowcore.restart_fn = (unsigned long) do_restart;
	S390_lowcore.restart_data = 0;
	S390_lowcore.restart_source = -1UL;
	restore_access_regs(S390_lowcore.access_regs_save_area);
	__ctl_load(S390_lowcore.cregs_save_area, 0, 15);
	__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
705
	cpu_init();
706
	preempt_disable();
707 708
	init_cpu_timer();
	init_cpu_vtimer();
H
Heiko Carstens 已提交
709
	pfault_init();
710
	notify_cpu_starting(smp_processor_id());
711
	set_cpu_online(smp_processor_id(), true);
L
Linus Torvalds 已提交
712
	local_irq_enable();
713 714
	/* cpu_idle will call schedule for us */
	cpu_idle();
L
Linus Torvalds 已提交
715 716 717
}

/* Upping and downing of CPUs */
718
int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
L
Linus Torvalds 已提交
719
{
M
Martin Schwidefsky 已提交
720 721
	struct pcpu *pcpu;
	int rc;
L
Linus Torvalds 已提交
722

M
Martin Schwidefsky 已提交
723 724
	pcpu = pcpu_devices + cpu;
	if (pcpu->state != CPU_STATE_CONFIGURED)
725
		return -EIO;
726 727
	if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
	    SIGP_CC_ORDER_CODE_ACCEPTED)
728
		return -EIO;
729

M
Martin Schwidefsky 已提交
730 731 732 733
	rc = pcpu_alloc_lowcore(pcpu, cpu);
	if (rc)
		return rc;
	pcpu_prepare_secondary(pcpu, cpu);
734
	pcpu_attach_task(pcpu, tidle);
M
Martin Schwidefsky 已提交
735
	pcpu_start_fn(pcpu, smp_start_secondary, NULL);
L
Linus Torvalds 已提交
736 737 738 739 740
	while (!cpu_online(cpu))
		cpu_relax();
	return 0;
}

741
static int __init setup_possible_cpus(char *s)
742
{
M
Martin Schwidefsky 已提交
743
	int max, cpu;
744

M
Martin Schwidefsky 已提交
745 746
	if (kstrtoint(s, 0, &max) < 0)
		return 0;
747
	init_cpu_possible(cpumask_of(0));
M
Martin Schwidefsky 已提交
748
	for (cpu = 1; cpu < max && cpu < nr_cpu_ids; cpu++)
749
		set_cpu_possible(cpu, true);
750 751 752 753
	return 0;
}
early_param("possible_cpus", setup_possible_cpus);

754 755
#ifdef CONFIG_HOTPLUG_CPU

756
int __cpu_disable(void)
L
Linus Torvalds 已提交
757
{
M
Martin Schwidefsky 已提交
758
	unsigned long cregs[16];
L
Linus Torvalds 已提交
759

M
Martin Schwidefsky 已提交
760 761
	set_cpu_online(smp_processor_id(), false);
	/* Disable pseudo page faults on this cpu. */
H
Heiko Carstens 已提交
762
	pfault_fini();
M
Martin Schwidefsky 已提交
763 764 765 766 767 768
	/* Disable interrupt sources via control register. */
	__ctl_store(cregs, 0, 15);
	cregs[0]  &= ~0x0000ee70UL;	/* disable all external interrupts */
	cregs[6]  &= ~0xff000000UL;	/* disable all I/O interrupts */
	cregs[14] &= ~0x1f000000UL;	/* disable most machine checks */
	__ctl_load(cregs, 0, 15);
L
Linus Torvalds 已提交
769 770 771
	return 0;
}

772
void __cpu_die(unsigned int cpu)
L
Linus Torvalds 已提交
773
{
M
Martin Schwidefsky 已提交
774 775
	struct pcpu *pcpu;

L
Linus Torvalds 已提交
776
	/* Wait until target cpu is down */
M
Martin Schwidefsky 已提交
777 778
	pcpu = pcpu_devices + cpu;
	while (!pcpu_stopped(pcpu))
L
Linus Torvalds 已提交
779
		cpu_relax();
M
Martin Schwidefsky 已提交
780
	pcpu_free_lowcore(pcpu);
781
	atomic_dec(&init_mm.context.attach_count);
L
Linus Torvalds 已提交
782 783
}

784
void __noreturn cpu_die(void)
L
Linus Torvalds 已提交
785 786
{
	idle_task_exit();
787
	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
M
Martin Schwidefsky 已提交
788
	for (;;) ;
L
Linus Torvalds 已提交
789 790
}

791 792
#endif /* CONFIG_HOTPLUG_CPU */

L
Linus Torvalds 已提交
793 794
void __init smp_prepare_cpus(unsigned int max_cpus)
{
795 796 797
	/* request the 0x1201 emergency signal external interrupt */
	if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
		panic("Couldn't request external interrupt 0x1201");
798 799 800
	/* request the 0x1202 external call external interrupt */
	if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
		panic("Couldn't request external interrupt 0x1202");
M
Martin Schwidefsky 已提交
801
	smp_detect_cpus();
L
Linus Torvalds 已提交
802 803
}

H
Heiko Carstens 已提交
804
void __init smp_prepare_boot_cpu(void)
L
Linus Torvalds 已提交
805
{
M
Martin Schwidefsky 已提交
806 807 808 809 810 811 812 813
	struct pcpu *pcpu = pcpu_devices;

	boot_cpu_address = stap();
	pcpu->state = CPU_STATE_CONFIGURED;
	pcpu->address = boot_cpu_address;
	pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
	pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE;
	pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE;
L
Linus Torvalds 已提交
814
	S390_lowcore.percpu_offset = __per_cpu_offset[0];
815
	smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN);
M
Martin Schwidefsky 已提交
816 817
	set_cpu_present(0, true);
	set_cpu_online(0, true);
L
Linus Torvalds 已提交
818 819
}

H
Heiko Carstens 已提交
820
void __init smp_cpus_done(unsigned int max_cpus)
L
Linus Torvalds 已提交
821 822 823
{
}

824 825 826 827 828
void __init smp_setup_processor_id(void)
{
	S390_lowcore.cpu_nr = 0;
}

L
Linus Torvalds 已提交
829 830 831 832 833 834 835 836
/*
 * the frequency of the profiling timer can be changed
 * by writing a multiplier value into /proc/profile.
 *
 * usually you want to run this on all CPUs ;)
 */
int setup_profiling_timer(unsigned int multiplier)
{
837
	return 0;
L
Linus Torvalds 已提交
838 839
}

840
#ifdef CONFIG_HOTPLUG_CPU
841
static ssize_t cpu_configure_show(struct device *dev,
M
Martin Schwidefsky 已提交
842
				  struct device_attribute *attr, char *buf)
843 844 845 846
{
	ssize_t count;

	mutex_lock(&smp_cpu_state_mutex);
M
Martin Schwidefsky 已提交
847
	count = sprintf(buf, "%d\n", pcpu_devices[dev->id].state);
848 849 850 851
	mutex_unlock(&smp_cpu_state_mutex);
	return count;
}

852
static ssize_t cpu_configure_store(struct device *dev,
M
Martin Schwidefsky 已提交
853 854
				   struct device_attribute *attr,
				   const char *buf, size_t count)
855
{
M
Martin Schwidefsky 已提交
856 857
	struct pcpu *pcpu;
	int cpu, val, rc;
858 859 860 861 862 863
	char delim;

	if (sscanf(buf, "%d %c", &val, &delim) != 1)
		return -EINVAL;
	if (val != 0 && val != 1)
		return -EINVAL;
864
	get_online_cpus();
H
Heiko Carstens 已提交
865
	mutex_lock(&smp_cpu_state_mutex);
866
	rc = -EBUSY;
867
	/* disallow configuration changes of online cpus and cpu 0 */
M
Martin Schwidefsky 已提交
868
	cpu = dev->id;
869
	if (cpu_online(cpu) || cpu == 0)
870
		goto out;
M
Martin Schwidefsky 已提交
871
	pcpu = pcpu_devices + cpu;
872 873 874
	rc = 0;
	switch (val) {
	case 0:
M
Martin Schwidefsky 已提交
875 876 877 878 879 880
		if (pcpu->state != CPU_STATE_CONFIGURED)
			break;
		rc = sclp_cpu_deconfigure(pcpu->address);
		if (rc)
			break;
		pcpu->state = CPU_STATE_STANDBY;
881
		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
M
Martin Schwidefsky 已提交
882
		topology_expect_change();
883 884
		break;
	case 1:
M
Martin Schwidefsky 已提交
885 886 887 888 889 890
		if (pcpu->state != CPU_STATE_STANDBY)
			break;
		rc = sclp_cpu_configure(pcpu->address);
		if (rc)
			break;
		pcpu->state = CPU_STATE_CONFIGURED;
891
		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
M
Martin Schwidefsky 已提交
892
		topology_expect_change();
893 894 895 896 897 898
		break;
	default:
		break;
	}
out:
	mutex_unlock(&smp_cpu_state_mutex);
H
Heiko Carstens 已提交
899
	put_online_cpus();
900 901
	return rc ? rc : count;
}
902
static DEVICE_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
903 904
#endif /* CONFIG_HOTPLUG_CPU */

905 906
static ssize_t show_cpu_address(struct device *dev,
				struct device_attribute *attr, char *buf)
907
{
M
Martin Schwidefsky 已提交
908
	return sprintf(buf, "%d\n", pcpu_devices[dev->id].address);
909
}
910
static DEVICE_ATTR(address, 0444, show_cpu_address, NULL);
911 912 913

static struct attribute *cpu_common_attrs[] = {
#ifdef CONFIG_HOTPLUG_CPU
914
	&dev_attr_configure.attr,
915
#endif
916
	&dev_attr_address.attr,
917 918 919 920 921 922
	NULL,
};

static struct attribute_group cpu_common_attr_group = {
	.attrs = cpu_common_attrs,
};
L
Linus Torvalds 已提交
923

924 925
static ssize_t show_idle_count(struct device *dev,
				struct device_attribute *attr, char *buf)
926
{
M
Martin Schwidefsky 已提交
927
	struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
928
	unsigned long long idle_count;
929
	unsigned int sequence;
930

M
Martin Schwidefsky 已提交
931 932 933
	do {
		sequence = ACCESS_ONCE(idle->sequence);
		idle_count = ACCESS_ONCE(idle->idle_count);
934
		if (ACCESS_ONCE(idle->clock_idle_enter))
M
Martin Schwidefsky 已提交
935 936
			idle_count++;
	} while ((sequence & 1) || (idle->sequence != sequence));
937 938
	return sprintf(buf, "%llu\n", idle_count);
}
939
static DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
940

941 942
static ssize_t show_idle_time(struct device *dev,
				struct device_attribute *attr, char *buf)
943
{
M
Martin Schwidefsky 已提交
944 945
	struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
	unsigned long long now, idle_time, idle_enter, idle_exit;
946
	unsigned int sequence;
947

M
Martin Schwidefsky 已提交
948 949 950 951
	do {
		now = get_clock();
		sequence = ACCESS_ONCE(idle->sequence);
		idle_time = ACCESS_ONCE(idle->idle_time);
952 953
		idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
		idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
M
Martin Schwidefsky 已提交
954 955
	} while ((sequence & 1) || (idle->sequence != sequence));
	idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
956
	return sprintf(buf, "%llu\n", idle_time >> 12);
957
}
958
static DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
959

960
static struct attribute *cpu_online_attrs[] = {
961 962
	&dev_attr_idle_count.attr,
	&dev_attr_idle_time_us.attr,
963 964 965
	NULL,
};

966 967
static struct attribute_group cpu_online_attr_group = {
	.attrs = cpu_online_attrs,
968 969
};

970 971 972 973
static int __cpuinit smp_cpu_notify(struct notifier_block *self,
				    unsigned long action, void *hcpu)
{
	unsigned int cpu = (unsigned int)(long)hcpu;
M
Martin Schwidefsky 已提交
974
	struct cpu *c = &pcpu_devices[cpu].cpu;
975
	struct device *s = &c->dev;
976
	int err = 0;
977

978
	switch (action & ~CPU_TASKS_FROZEN) {
979
	case CPU_ONLINE:
980
		err = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
981 982
		break;
	case CPU_DEAD:
983
		sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
984 985
		break;
	}
986
	return notifier_from_errno(err);
987 988
}

989
static int __devinit smp_add_present_cpu(int cpu)
990
{
M
Martin Schwidefsky 已提交
991
	struct cpu *c = &pcpu_devices[cpu].cpu;
992
	struct device *s = &c->dev;
993 994 995 996 997 998 999 1000 1001
	int rc;

	c->hotpluggable = 1;
	rc = register_cpu(c, cpu);
	if (rc)
		goto out;
	rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group);
	if (rc)
		goto out_cpu;
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
	if (cpu_online(cpu)) {
		rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
		if (rc)
			goto out_online;
	}
	rc = topology_cpu_init(c);
	if (rc)
		goto out_topology;
	return 0;

out_topology:
	if (cpu_online(cpu))
		sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
out_online:
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
	sysfs_remove_group(&s->kobj, &cpu_common_attr_group);
out_cpu:
#ifdef CONFIG_HOTPLUG_CPU
	unregister_cpu(c);
#endif
out:
	return rc;
}

#ifdef CONFIG_HOTPLUG_CPU
1026

1027
int __ref smp_rescan_cpus(void)
1028
{
M
Martin Schwidefsky 已提交
1029 1030
	struct sclp_cpu_info *info;
	int nr;
1031

M
Martin Schwidefsky 已提交
1032 1033 1034
	info = smp_get_cpu_info();
	if (!info)
		return -ENOMEM;
1035
	get_online_cpus();
H
Heiko Carstens 已提交
1036
	mutex_lock(&smp_cpu_state_mutex);
M
Martin Schwidefsky 已提交
1037
	nr = __smp_rescan_cpus(info, 1);
1038
	mutex_unlock(&smp_cpu_state_mutex);
H
Heiko Carstens 已提交
1039
	put_online_cpus();
M
Martin Schwidefsky 已提交
1040 1041
	kfree(info);
	if (nr)
H
Heiko Carstens 已提交
1042
		topology_schedule_update();
M
Martin Schwidefsky 已提交
1043
	return 0;
1044 1045
}

1046 1047
static ssize_t __ref rescan_store(struct device *dev,
				  struct device_attribute *attr,
1048
				  const char *buf,
1049 1050 1051 1052 1053
				  size_t count)
{
	int rc;

	rc = smp_rescan_cpus();
1054 1055
	return rc ? rc : count;
}
1056
static DEVICE_ATTR(rescan, 0200, NULL, rescan_store);
1057 1058
#endif /* CONFIG_HOTPLUG_CPU */

1059
static int __init s390_smp_init(void)
L
Linus Torvalds 已提交
1060
{
1061
	int cpu, rc;
1062

1063
	hotcpu_notifier(smp_cpu_notify, 0);
1064
#ifdef CONFIG_HOTPLUG_CPU
1065
	rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan);
1066 1067 1068 1069 1070
	if (rc)
		return rc;
#endif
	for_each_present_cpu(cpu) {
		rc = smp_add_present_cpu(cpu);
1071 1072
		if (rc)
			return rc;
L
Linus Torvalds 已提交
1073 1074 1075
	}
	return 0;
}
1076
subsys_initcall(s390_smp_init);