aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-05-02 16:33:51 -0400
committerPaul Mackerras <paulus@samba.org>2007-05-07 06:31:13 -0400
commitd9333afd6a714760c13f76ba275a32ec7bd979c1 (patch)
treeb75cb98ff938edca5aa5254b209d58037e8ec89c
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>
-rw-r--r--arch/powerpc/kernel/idle_power4.S21
-rw-r--r--arch/powerpc/platforms/powermac/setup.c52
-rw-r--r--arch/powerpc/platforms/powermac/smp.c12
-rw-r--r--include/asm-powerpc/machdep.h1
4 files changed, 82 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index ba3195478600..5328709eeedc 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -53,3 +53,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
53 isync 53 isync
54 b 1b 54 b 1b
55 55
56_GLOBAL(power4_cpu_offline_powersave)
57 /* Go to NAP now */
58 mfmsr r7
59 rldicl r0,r7,48,1
60 rotldi r0,r0,16
61 mtmsrd r0,1 /* hard-disable interrupts */
62 li r0,1
63 li r6,0
64 stb r0,PACAHARDIRQEN(r13) /* we'll hard-enable shortly */
65 stb r6,PACASOFTIRQEN(r13) /* soft-disable irqs */
66BEGIN_FTR_SECTION
67 DSSALL
68 sync
69END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
70 ori r7,r7,MSR_EE
71 oris r7,r7,MSR_POW@h
72 sync
73 isync
74 mtmsrd r7
75 isync
76 blr
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;
444static int pmac_late_init(void) 444static int pmac_late_init(void)
445{ 445{
446 initializing = 0; 446 initializing = 0;
447 /* this is udbg (which is __init) and we can later use it during
448 * cpu hotplug (in smp_core99_kick_cpu) */
449 ppc_md.progress = NULL;
447 return 0; 450 return 0;
448} 451}
449 452
@@ -661,7 +664,52 @@ static int pmac_pci_probe_mode(struct pci_bus *bus)
661 return PCI_PROBE_NORMAL; 664 return PCI_PROBE_NORMAL;
662 return PCI_PROBE_DEVTREE; 665 return PCI_PROBE_DEVTREE;
663} 666}
664#endif 667
668#ifdef CONFIG_HOTPLUG_CPU
669/* access per cpu vars from generic smp.c */
670DECLARE_PER_CPU(int, cpu_state);
671
672static void pmac_cpu_die(void)
673{
674 /*
675 * turn off as much as possible, we'll be
676 * kicked out as this will only be invoked
677 * on core99 platforms for now ...
678 */
679
680 printk(KERN_INFO "CPU#%d offline\n", smp_processor_id());
681 __get_cpu_var(cpu_state) = CPU_DEAD;
682 smp_wmb();
683
684 /*
685 * during the path that leads here preemption is disabled,
686 * reenable it now so that when coming up preempt count is
687 * zero correctly
688 */
689 preempt_enable();
690
691 /*
692 * hard-disable interrupts for the non-NAP case, the NAP code
693 * needs to re-enable interrupts (but soft-disables them)
694 */
695 hard_irq_disable();
696
697 while (1) {
698 /* let's not take timer interrupts too often ... */
699 set_dec(0x7fffffff);
700
701 /* should always be true at this point */
702 if (cpu_has_feature(CPU_FTR_CAN_NAP))
703 power4_cpu_offline_powersave();
704 else {
705 HMT_low();
706 HMT_very_low();
707 }
708 }
709}
710#endif /* CONFIG_HOTPLUG_CPU */
711
712#endif /* CONFIG_PPC64 */
665 713
666define_machine(powermac) { 714define_machine(powermac) {
667 .name = "PowerMac", 715 .name = "PowerMac",
@@ -698,6 +746,6 @@ define_machine(powermac) {
698 .phys_mem_access_prot = pci_phys_mem_access_prot, 746 .phys_mem_access_prot = pci_phys_mem_access_prot,
699#endif 747#endif
700#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) 748#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
701 .cpu_die = generic_mach_cpu_die, 749 .cpu_die = pmac_cpu_die,
702#endif 750#endif
703}; 751};
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 6f32c4eca6e5..330354113186 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -900,7 +900,7 @@ void smp_core99_cpu_die(unsigned int cpu)
900 cpu_dead[cpu] = 0; 900 cpu_dead[cpu] = 0;
901} 901}
902 902
903#endif 903#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 */
904 904
905/* Core99 Macs (dual G4s and G5s) */ 905/* Core99 Macs (dual G4s and G5s) */
906struct smp_ops_t core99_smp_ops = { 906struct smp_ops_t core99_smp_ops = {
@@ -910,8 +910,16 @@ struct smp_ops_t core99_smp_ops = {
910 .setup_cpu = smp_core99_setup_cpu, 910 .setup_cpu = smp_core99_setup_cpu,
911 .give_timebase = smp_core99_give_timebase, 911 .give_timebase = smp_core99_give_timebase,
912 .take_timebase = smp_core99_take_timebase, 912 .take_timebase = smp_core99_take_timebase,
913#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) 913#if defined(CONFIG_HOTPLUG_CPU)
914# if defined(CONFIG_PPC32)
914 .cpu_disable = smp_core99_cpu_disable, 915 .cpu_disable = smp_core99_cpu_disable,
915 .cpu_die = smp_core99_cpu_die, 916 .cpu_die = smp_core99_cpu_die,
917# endif
918# if defined(CONFIG_PPC64)
919 .cpu_disable = generic_cpu_disable,
920 .cpu_die = generic_cpu_die,
921 /* intentionally do *NOT* assign cpu_enable,
922 * the generic code will use kick_cpu then! */
923# endif
916#endif 924#endif
917}; 925};
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index b204926ce913..bbd17d0e170d 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -248,6 +248,7 @@ struct machdep_calls {
248}; 248};
249 249
250extern void power4_idle(void); 250extern void power4_idle(void);
251extern void power4_cpu_offline_powersave(void);
251extern void ppc6xx_idle(void); 252extern void ppc6xx_idle(void);
252 253
253/* 254/*