Merge branch 'for-linus' of git://git.linaro.org/people/rmk/linux-arm
[pandora-kernel.git] / arch / arm / kernel / smp.c
index 4619177..47ab905 100644 (file)
@@ -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);