diff options
-rw-r--r-- | arch/powerpc/kernel/idle_power4.S | 21 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 52 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/smp.c | 12 | ||||
-rw-r--r-- | include/asm-powerpc/machdep.h | 1 |
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 */ | ||
66 | BEGIN_FTR_SECTION | ||
67 | DSSALL | ||
68 | sync | ||
69 | END_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; | |||
444 | static int pmac_late_init(void) | 444 | static 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 */ | ||
670 | DECLARE_PER_CPU(int, cpu_state); | ||
671 | |||
672 | static 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 | ||
666 | define_machine(powermac) { | 714 | define_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) */ |
906 | struct smp_ops_t core99_smp_ops = { | 906 | struct 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 | ||
250 | extern void power4_idle(void); | 250 | extern void power4_idle(void); |
251 | extern void power4_cpu_offline_powersave(void); | ||
251 | extern void ppc6xx_idle(void); | 252 | extern void ppc6xx_idle(void); |
252 | 253 | ||
253 | /* | 254 | /* |