diff options
Diffstat (limited to 'arch/arm/kernel/smp.c')
| -rw-r--r-- | arch/arm/kernel/smp.c | 45 | 
1 files changed, 38 insertions, 7 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 79078edbb9b..4231034b812 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -211,6 +211,13 @@ void __cpuinit __cpu_die(unsigned int cpu)  	}  	printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); +	/* +	 * 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. +	 */  	if (!platform_cpu_kill(cpu))  		printk("CPU%u: unable to kill\n", cpu);  } @@ -230,14 +237,41 @@ void __ref cpu_die(void)  	idle_task_exit();  	local_irq_disable(); -	mb(); -	/* Tell __cpu_die() that this CPU is now safe to dispose of */ +	/* +	 * 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(). +	 */  	RCU_NONIDLE(complete(&cpu_died));  	/* -	 * actual CPU shutdown procedure is at least platform (if not -	 * CPU) specific. +	 * 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.  	 */  	if (smp_ops.cpu_die)  		smp_ops.cpu_die(cpu); @@ -673,9 +707,6 @@ static int cpufreq_callback(struct notifier_block *nb,  	if (freq->flags & CPUFREQ_CONST_LOOPS)  		return NOTIFY_OK; -	if (arm_delay_ops.const_clock) -		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;  |