summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/powermac/setup.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-05-03 06:33:51 +1000
committerPaul Mackerras <paulus@samba.org>2007-05-07 20:31:13 +1000
commitd9333afd6a714760c13f76ba275a32ec7bd979c1 (patch)
treeb75cb98ff938edca5aa5254b209d58037e8ec89c /arch/powerpc/platforms/powermac/setup.c
parentac18c673e7fa71f62ce613edfe6634edb99f968b (diff)
[POWERPC] powermac: Support G5 CPU hotplug
This allows "hotplugging" of CPUs on G5 machines. CPUs that are disabled are put into an idle loop with the decrementer frequency set to minimum. To wake them up again we kick them just like when bringing them up. To stop those CPUs from messing with any global state we stop them from entering the timer interrupt. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/powermac/setup.c')
-rw-r--r--arch/powerpc/platforms/powermac/setup.c52
1 files changed, 50 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 5ae57e17d2ba..e365bff74d83 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -444,6 +444,9 @@ static int initializing = 1;
static int pmac_late_init(void)
{
initializing = 0;
+ /* this is udbg (which is __init) and we can later use it during
+ * cpu hotplug (in smp_core99_kick_cpu) */
+ ppc_md.progress = NULL;
return 0;
}
@@ -661,7 +664,52 @@ static int pmac_pci_probe_mode(struct pci_bus *bus)
return PCI_PROBE_NORMAL;
return PCI_PROBE_DEVTREE;
}
-#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+/* access per cpu vars from generic smp.c */
+DECLARE_PER_CPU(int, cpu_state);
+
+static void pmac_cpu_die(void)
+{
+ /*
+ * turn off as much as possible, we'll be
+ * kicked out as this will only be invoked
+ * on core99 platforms for now ...
+ */
+
+ printk(KERN_INFO "CPU#%d offline\n", smp_processor_id());
+ __get_cpu_var(cpu_state) = CPU_DEAD;
+ smp_wmb();
+
+ /*
+ * during the path that leads here preemption is disabled,
+ * reenable it now so that when coming up preempt count is
+ * zero correctly
+ */
+ preempt_enable();
+
+ /*
+ * hard-disable interrupts for the non-NAP case, the NAP code
+ * needs to re-enable interrupts (but soft-disables them)
+ */
+ hard_irq_disable();
+
+ while (1) {
+ /* let's not take timer interrupts too often ... */
+ set_dec(0x7fffffff);
+
+ /* should always be true at this point */
+ if (cpu_has_feature(CPU_FTR_CAN_NAP))
+ power4_cpu_offline_powersave();
+ else {
+ HMT_low();
+ HMT_very_low();
+ }
+ }
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#endif /* CONFIG_PPC64 */
define_machine(powermac) {
.name = "PowerMac",
@@ -698,6 +746,6 @@ define_machine(powermac) {
.phys_mem_access_prot = pci_phys_mem_access_prot,
#endif
#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
- .cpu_die = generic_mach_cpu_die,
+ .cpu_die = pmac_cpu_die,
#endif
};