aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/*