smp.c 15.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 *  linux/arch/arm/kernel/smp.c
 *
 *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
R
Russell King 已提交
10
#include <linux/module.h>
L
Linus Torvalds 已提交
11 12 13 14 15 16 17 18 19
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/cache.h>
#include <linux/profile.h>
#include <linux/errno.h>
#include <linux/mm.h>
A
Alexey Dobriyan 已提交
20
#include <linux/err.h>
L
Linus Torvalds 已提交
21 22
#include <linux/cpu.h>
#include <linux/seq_file.h>
R
Russell King 已提交
23
#include <linux/irq.h>
24 25
#include <linux/percpu.h>
#include <linux/clockchips.h>
26
#include <linux/completion.h>
27
#include <linux/cpufreq.h>
L
Linus Torvalds 已提交
28

A
Arun Sharma 已提交
29
#include <linux/atomic.h>
30
#include <asm/smp.h>
L
Linus Torvalds 已提交
31 32
#include <asm/cacheflush.h>
#include <asm/cpu.h>
33
#include <asm/cputype.h>
34
#include <asm/exception.h>
35
#include <asm/idmap.h>
36
#include <asm/topology.h>
37 38 39
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
L
Linus Torvalds 已提交
40
#include <asm/processor.h>
41
#include <asm/sections.h>
L
Linus Torvalds 已提交
42 43
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
44
#include <asm/smp_plat.h>
45
#include <asm/virt.h>
46
#include <asm/mach/arch.h>
47
#include <asm/mpu.h>
L
Linus Torvalds 已提交
48

49 50 51 52 53 54 55
/*
 * as from 2.5, kernels no longer have an init_tasks structure
 * so we need some other way of telling a new secondary core
 * where to place its SVC stack
 */
struct secondary_data secondary_data;

56 57 58 59
/*
 * control for which core is the next to come out of the secondary
 * boot "holding pen"
 */
60
volatile int pen_release = -1;
61

L
Linus Torvalds 已提交
62
enum ipi_msg_type {
63 64
	IPI_WAKEUP,
	IPI_TIMER,
L
Linus Torvalds 已提交
65 66
	IPI_RESCHEDULE,
	IPI_CALL_FUNC,
67
	IPI_CALL_FUNC_SINGLE,
L
Linus Torvalds 已提交
68 69 70
	IPI_CPU_STOP,
};

71 72
static DECLARE_COMPLETION(cpu_running);

73 74 75 76 77 78 79 80
static struct smp_operations smp_ops;

void __init smp_set_ops(struct smp_operations *ops)
{
	if (ops)
		smp_ops = *ops;
};

81 82 83 84 85 86 87
static unsigned long get_arch_pgd(pgd_t *pgd)
{
	phys_addr_t pgdir = virt_to_phys(pgd);
	BUG_ON(pgdir & ARCH_PGD_MASK);
	return pgdir >> ARCH_PGD_SHIFT;
}

88
int __cpu_up(unsigned int cpu, struct task_struct *idle)
L
Linus Torvalds 已提交
89 90 91
{
	int ret;

92 93 94 95
	/*
	 * We need to tell the secondary core where to find
	 * its stack and the page tables.
	 */
A
Al Viro 已提交
96
	secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
97 98 99 100
#ifdef CONFIG_ARM_MPU
	secondary_data.mpu_rgn_szr = mpu_rgn_info.rgns[MPU_RAM_REGION].drsr;
#endif

101
#ifdef CONFIG_MMU
102 103
	secondary_data.pgdir = get_arch_pgd(idmap_pgd);
	secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
104
#endif
105 106
	__cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
	outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
107

L
Linus Torvalds 已提交
108 109 110 111
	/*
	 * Now bring the CPU into our world.
	 */
	ret = boot_secondary(cpu, idle);
112 113 114 115 116
	if (ret == 0) {
		/*
		 * CPU was successfully started, wait for it
		 * to come online or time out.
		 */
117 118
		wait_for_completion_timeout(&cpu_running,
						 msecs_to_jiffies(1000));
119

120 121
		if (!cpu_online(cpu)) {
			pr_crit("CPU%u: failed to come online\n", cpu);
122
			ret = -EIO;
123 124 125
		}
	} else {
		pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
126 127 128
	}


129
	memset(&secondary_data, 0, sizeof(secondary_data));
L
Linus Torvalds 已提交
130 131 132
	return ret;
}

133
/* platform specific SMP operations */
134
void __init smp_init_cpus(void)
135 136 137 138 139
{
	if (smp_ops.smp_init_cpus)
		smp_ops.smp_init_cpus();
}

140
int boot_secondary(unsigned int cpu, struct task_struct *idle)
141 142 143 144 145 146
{
	if (smp_ops.smp_boot_secondary)
		return smp_ops.smp_boot_secondary(cpu, idle);
	return -ENOSYS;
}

147 148 149 150 151 152 153 154 155 156
int platform_can_cpu_hotplug(void)
{
#ifdef CONFIG_HOTPLUG_CPU
	if (smp_ops.cpu_kill)
		return 1;
#endif

	return 0;
}

157
#ifdef CONFIG_HOTPLUG_CPU
158
static int platform_cpu_kill(unsigned int cpu)
159 160 161 162 163 164
{
	if (smp_ops.cpu_kill)
		return smp_ops.cpu_kill(cpu);
	return 1;
}

165
static int platform_cpu_disable(unsigned int cpu)
166 167 168 169 170 171 172 173 174 175 176
{
	if (smp_ops.cpu_disable)
		return smp_ops.cpu_disable(cpu);

	/*
	 * By default, allow disabling all CPUs except the first one,
	 * since this is special on a lot of platforms, e.g. because
	 * of clock tick interrupts.
	 */
	return cpu == 0 ? -EPERM : 0;
}
177 178 179
/*
 * __cpu_disable runs on the processor to be shutdown.
 */
180
int __cpu_disable(void)
181 182 183 184
{
	unsigned int cpu = smp_processor_id();
	int ret;

185
	ret = platform_cpu_disable(cpu);
186 187 188 189 190 191 192
	if (ret)
		return ret;

	/*
	 * Take this CPU offline.  Once we clear this, we can't return,
	 * and we must not schedule until we're ready to give up the cpu.
	 */
193
	set_cpu_online(cpu, false);
194 195 196 197 198 199 200 201 202

	/*
	 * OK - migrate IRQs away from this CPU
	 */
	migrate_irqs();

	/*
	 * Flush user cache and TLB mappings, and then remove this CPU
	 * from the vm mask set of all processes.
203 204 205
	 *
	 * Caches are flushed to the Level of Unification Inner Shareable
	 * to write-back dirty lines to unified caches shared by all CPUs.
206
	 */
207
	flush_cache_louis();
208 209
	local_flush_tlb_all();

210
	clear_tasks_mm_cpumask(cpu);
211 212 213 214

	return 0;
}

215 216
static DECLARE_COMPLETION(cpu_died);

217 218 219 220
/*
 * called on the thread which is asking for a CPU to be shutdown -
 * waits until shutdown has completed, or it is timed out.
 */
221
void __cpu_die(unsigned int cpu)
222
{
223 224 225 226 227 228
	if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
		pr_err("CPU%u: cpu didn't die\n", cpu);
		return;
	}
	printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);

229 230 231 232 233 234 235
	/*
	 * platform_cpu_kill() is generally expected to do the powering off
	 * and/or cutting of clocks to the dying CPU.  Optionally, this may
	 * be done by the CPU which is dying in preference to supporting
	 * this call, but that means there is _no_ synchronisation between
	 * the requesting CPU and the dying CPU actually losing power.
	 */
236 237 238 239 240 241 242 243 244 245 246 247
	if (!platform_cpu_kill(cpu))
		printk("CPU%u: unable to kill\n", cpu);
}

/*
 * Called from the idle thread for the CPU which has been shutdown.
 *
 * Note that we disable IRQs here, but do not re-enable them
 * before returning to the caller. This is also the behaviour
 * of the other hotplug-cpu capable cores, so presumably coming
 * out of idle fixes this.
 */
248
void __ref cpu_die(void)
249 250 251 252 253
{
	unsigned int cpu = smp_processor_id();

	idle_task_exit();

254 255
	local_irq_disable();

256 257 258 259 260 261 262 263 264 265 266 267 268
	/*
	 * Flush the data out of the L1 cache for this CPU.  This must be
	 * before the completion to ensure that data is safely written out
	 * before platform_cpu_kill() gets called - which may disable
	 * *this* CPU and power down its cache.
	 */
	flush_cache_louis();

	/*
	 * Tell __cpu_die() that this CPU is now safe to dispose of.  Once
	 * this returns, power and/or clocks can be removed at any point
	 * from this CPU and its cache by platform_cpu_kill().
	 */
269
	complete(&cpu_died);
270

271
	/*
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
	 * Ensure that the cache lines associated with that completion are
	 * written out.  This covers the case where _this_ CPU is doing the
	 * powering down, to ensure that the completion is visible to the
	 * CPU waiting for this one.
	 */
	flush_cache_louis();

	/*
	 * The actual CPU shutdown procedure is at least platform (if not
	 * CPU) specific.  This may remove power, or it may simply spin.
	 *
	 * Platforms are generally expected *NOT* to return from this call,
	 * although there are some which do because they have no way to
	 * power down the CPU.  These platforms are the _only_ reason we
	 * have a return path which uses the fragment of assembly below.
	 *
	 * The return path should not be used for platforms which can
	 * power off the CPU.
290
	 */
291 292
	if (smp_ops.cpu_die)
		smp_ops.cpu_die(cpu);
293 294 295 296 297 298 299

	/*
	 * Do not return to the idle loop - jump back to the secondary
	 * cpu initialisation.  There's some initialisation which needs
	 * to be repeated to undo the effects of taking the CPU offline.
	 */
	__asm__("mov	sp, %0\n"
300
	"	mov	fp, #0\n"
301 302
	"	b	secondary_start_kernel"
		:
A
Al Viro 已提交
303
		: "r" (task_stack_page(current) + THREAD_SIZE - 8));
304 305 306
}
#endif /* CONFIG_HOTPLUG_CPU */

307 308 309 310
/*
 * Called by both boot and secondaries to move global data into
 * per-processor storage.
 */
311
static void smp_store_cpu_info(unsigned int cpuid)
312 313 314 315
{
	struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);

	cpu_info->loops_per_jiffy = loops_per_jiffy;
316
	cpu_info->cpuid = read_cpuid_id();
317 318

	store_cpu_topology(cpuid);
319 320
}

321 322 323 324
/*
 * This is the secondary CPU boot entry.  We're using this CPUs
 * idle thread stack, but a set of temporary page tables.
 */
325
asmlinkage void secondary_start_kernel(void)
326 327
{
	struct mm_struct *mm = &init_mm;
328 329 330 331 332 333 334
	unsigned int cpu;

	/*
	 * The identity mapping is uncached (strongly ordered), so
	 * switch away from it before attempting any exclusive accesses.
	 */
	cpu_switch_mm(mm->pgd, mm);
335
	local_flush_bp_all();
336 337
	enter_lazy_tlb(mm, current);
	local_flush_tlb_all();
338 339 340 341 342

	/*
	 * All kernel threads share the same mm context; grab a
	 * reference and switch to it.
	 */
343
	cpu = smp_processor_id();
344 345
	atomic_inc(&mm->mm_count);
	current->active_mm = mm;
346
	cpumask_set_cpu(cpu, mm_cpumask(mm));
347

348 349
	cpu_init();

350 351
	printk("CPU%u: Booted secondary processor\n", cpu);

352
	preempt_disable();
353
	trace_hardirqs_off();
354 355 356 357

	/*
	 * Give the platform a chance to do its own initialisation.
	 */
358 359
	if (smp_ops.smp_secondary_init)
		smp_ops.smp_secondary_init(cpu);
360

361
	notify_cpu_starting(cpu);
362

363 364 365 366 367
	calibrate_delay();

	smp_store_cpu_info(cpu);

	/*
368 369
	 * OK, now it's safe to let the boot CPU continue.  Wait for
	 * the CPU migration code to notice that the CPU is online
370
	 * before we continue - which happens after __cpu_up returns.
371
	 */
372
	set_cpu_online(cpu, true);
373
	complete(&cpu_running);
374 375 376 377

	local_irq_enable();
	local_fiq_enable();

378 379 380
	/*
	 * OK, it's off to the idle thread for us
	 */
T
Thomas Gleixner 已提交
381
	cpu_startup_entry(CPUHP_ONLINE);
382 383
}

L
Linus Torvalds 已提交
384 385
void __init smp_cpus_done(unsigned int max_cpus)
{
386 387
	printk(KERN_INFO "SMP: Total of %d processors activated.\n",
	       num_online_cpus());
388 389

	hyp_mode_check();
L
Linus Torvalds 已提交
390 391 392 393
}

void __init smp_prepare_boot_cpu(void)
{
394
	set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
L
Linus Torvalds 已提交
395 396
}

397
void __init smp_prepare_cpus(unsigned int max_cpus)
L
Linus Torvalds 已提交
398
{
399
	unsigned int ncores = num_possible_cpus();
L
Linus Torvalds 已提交
400

401 402
	init_cpu_topology();

403
	smp_store_cpu_info(smp_processor_id());
L
Linus Torvalds 已提交
404 405

	/*
406
	 * are we trying to boot more cores than exist?
L
Linus Torvalds 已提交
407
	 */
408 409
	if (max_cpus > ncores)
		max_cpus = ncores;
410 411 412 413
	if (ncores > 1 && max_cpus) {
		/*
		 * Initialise the present map, which describes the set of CPUs
		 * actually populated at the present time. A platform should
414 415
		 * re-initialize the map in the platforms smp_prepare_cpus()
		 * if present != possible (e.g. physical hotplug).
416
		 */
417
		init_cpu_present(cpu_possible_mask);
418

419 420 421 422
		/*
		 * Initialise the SCU if there are more than one CPU
		 * and let them know where to start.
		 */
423 424
		if (smp_ops.smp_prepare_cpus)
			smp_ops.smp_prepare_cpus(max_cpus);
425
	}
L
Linus Torvalds 已提交
426 427
}

428 429 430 431
static void (*smp_cross_call)(const struct cpumask *, unsigned int);

void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
{
432 433
	if (!smp_cross_call)
		smp_cross_call = fn;
434 435
}

436
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
L
Linus Torvalds 已提交
437
{
R
Russell King 已提交
438
	smp_cross_call(mask, IPI_CALL_FUNC);
L
Linus Torvalds 已提交
439 440
}

441 442 443 444 445
void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
{
	smp_cross_call(mask, IPI_WAKEUP);
}

446
void arch_send_call_function_single_ipi(int cpu)
447
{
R
Russell King 已提交
448
	smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
449 450
}

451
static const char *ipi_types[NR_IPI] = {
452 453
#define S(x,s)	[x] = s
	S(IPI_WAKEUP, "CPU wakeup interrupts"),
454 455 456 457 458 459 460
	S(IPI_TIMER, "Timer broadcast interrupts"),
	S(IPI_RESCHEDULE, "Rescheduling interrupts"),
	S(IPI_CALL_FUNC, "Function call interrupts"),
	S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
	S(IPI_CPU_STOP, "CPU stop interrupts"),
};

461
void show_ipi_list(struct seq_file *p, int prec)
L
Linus Torvalds 已提交
462
{
463
	unsigned int cpu, i;
L
Linus Torvalds 已提交
464

465 466
	for (i = 0; i < NR_IPI; i++) {
		seq_printf(p, "%*s%u: ", prec - 1, "IPI", i);
L
Linus Torvalds 已提交
467

468
		for_each_online_cpu(cpu)
469 470
			seq_printf(p, "%10u ",
				   __get_irq_stat(cpu, ipi_irqs[i]));
L
Linus Torvalds 已提交
471

472 473
		seq_printf(p, " %s\n", ipi_types[i]);
	}
L
Linus Torvalds 已提交
474 475
}

476
u64 smp_irq_stat_cpu(unsigned int cpu)
477
{
478 479
	u64 sum = 0;
	int i;
480

481 482
	for (i = 0; i < NR_IPI; i++)
		sum += __get_irq_stat(cpu, ipi_irqs[i]);
483

484
	return sum;
485 486
}

487
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
488
void tick_broadcast(const struct cpumask *mask)
489
{
R
Russell King 已提交
490
	smp_cross_call(mask, IPI_TIMER);
491
}
492
#endif
493

494
static DEFINE_RAW_SPINLOCK(stop_lock);
L
Linus Torvalds 已提交
495 496 497 498 499 500

/*
 * ipi_cpu_stop - handle IPI from smp_send_stop()
 */
static void ipi_cpu_stop(unsigned int cpu)
{
501 502
	if (system_state == SYSTEM_BOOTING ||
	    system_state == SYSTEM_RUNNING) {
503
		raw_spin_lock(&stop_lock);
504 505
		printk(KERN_CRIT "CPU%u: stopping\n", cpu);
		dump_stack();
506
		raw_spin_unlock(&stop_lock);
507
	}
L
Linus Torvalds 已提交
508

509
	set_cpu_online(cpu, false);
L
Linus Torvalds 已提交
510 511 512 513 514 515 516 517 518 519 520

	local_fiq_disable();
	local_irq_disable();

	while (1)
		cpu_relax();
}

/*
 * Main handler for inter-processor interrupts
 */
R
Russell King 已提交
521
asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
522 523 524 525 526
{
	handle_IPI(ipinr, regs);
}

void handle_IPI(int ipinr, struct pt_regs *regs)
L
Linus Torvalds 已提交
527 528
{
	unsigned int cpu = smp_processor_id();
R
Russell King 已提交
529
	struct pt_regs *old_regs = set_irq_regs(regs);
L
Linus Torvalds 已提交
530

531 532
	if (ipinr < NR_IPI)
		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
L
Linus Torvalds 已提交
533

534
	switch (ipinr) {
535 536 537
	case IPI_WAKEUP:
		break;

538
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
539
	case IPI_TIMER:
540
		irq_enter();
541
		tick_receive_broadcast();
542
		irq_exit();
543
		break;
544
#endif
L
Linus Torvalds 已提交
545

546
	case IPI_RESCHEDULE:
547
		scheduler_ipi();
548
		break;
L
Linus Torvalds 已提交
549

550
	case IPI_CALL_FUNC:
551
		irq_enter();
552
		generic_smp_call_function_interrupt();
553
		irq_exit();
554
		break;
555

556
	case IPI_CALL_FUNC_SINGLE:
557
		irq_enter();
558
		generic_smp_call_function_single_interrupt();
559
		irq_exit();
560
		break;
L
Linus Torvalds 已提交
561

562
	case IPI_CPU_STOP:
563
		irq_enter();
564
		ipi_cpu_stop(cpu);
565
		irq_exit();
566
		break;
L
Linus Torvalds 已提交
567

568 569 570 571
	default:
		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
		       cpu, ipinr);
		break;
L
Linus Torvalds 已提交
572
	}
R
Russell King 已提交
573
	set_irq_regs(old_regs);
L
Linus Torvalds 已提交
574 575 576 577
}

void smp_send_reschedule(int cpu)
{
R
Russell King 已提交
578
	smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
L
Linus Torvalds 已提交
579 580 581 582
}

void smp_send_stop(void)
{
583
	unsigned long timeout;
584
	struct cpumask mask;
L
Linus Torvalds 已提交
585

586 587
	cpumask_copy(&mask, cpu_online_mask);
	cpumask_clear_cpu(smp_processor_id(), &mask);
588 589
	if (!cpumask_empty(&mask))
		smp_cross_call(&mask, IPI_CPU_STOP);
590

591 592 593 594
	/* Wait up to one second for other CPUs to stop */
	timeout = USEC_PER_SEC;
	while (num_online_cpus() > 1 && timeout--)
		udelay(1);
595

596 597
	if (num_online_cpus() > 1)
		pr_warning("SMP: failed to stop secondary CPUs\n");
598 599 600
}

/*
L
Linus Torvalds 已提交
601
 * not supported here
602
 */
603
int setup_profiling_timer(unsigned int multiplier)
604
{
L
Linus Torvalds 已提交
605
	return -EINVAL;
606
}
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659

#ifdef CONFIG_CPU_FREQ

static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
static unsigned long global_l_p_j_ref;
static unsigned long global_l_p_j_ref_freq;

static int cpufreq_callback(struct notifier_block *nb,
					unsigned long val, void *data)
{
	struct cpufreq_freqs *freq = data;
	int cpu = freq->cpu;

	if (freq->flags & CPUFREQ_CONST_LOOPS)
		return NOTIFY_OK;

	if (!per_cpu(l_p_j_ref, cpu)) {
		per_cpu(l_p_j_ref, cpu) =
			per_cpu(cpu_data, cpu).loops_per_jiffy;
		per_cpu(l_p_j_ref_freq, cpu) = freq->old;
		if (!global_l_p_j_ref) {
			global_l_p_j_ref = loops_per_jiffy;
			global_l_p_j_ref_freq = freq->old;
		}
	}

	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
		loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
						global_l_p_j_ref_freq,
						freq->new);
		per_cpu(cpu_data, cpu).loops_per_jiffy =
			cpufreq_scale(per_cpu(l_p_j_ref, cpu),
					per_cpu(l_p_j_ref_freq, cpu),
					freq->new);
	}
	return NOTIFY_OK;
}

static struct notifier_block cpufreq_notifier = {
	.notifier_call  = cpufreq_callback,
};

static int __init register_cpufreq_notifier(void)
{
	return cpufreq_register_notifier(&cpufreq_notifier,
						CPUFREQ_TRANSITION_NOTIFIER);
}
core_initcall(register_cpufreq_notifier);

#endif