Skip to content

Commit

Permalink
[POWERPC] powermac: Support G5 CPU hotplug
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and Paul Mackerras committed May 7, 2007
1 parent ac18c67 commit d9333af
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 4 deletions.
21 changes: 21 additions & 0 deletions arch/powerpc/kernel/idle_power4.S
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
isync
b 1b

_GLOBAL(power4_cpu_offline_powersave)
/* Go to NAP now */
mfmsr r7
rldicl r0,r7,48,1
rotldi r0,r0,16
mtmsrd r0,1 /* hard-disable interrupts */
li r0,1
li r6,0
stb r0,PACAHARDIRQEN(r13) /* we'll hard-enable shortly */
stb r6,PACASOFTIRQEN(r13) /* soft-disable irqs */
BEGIN_FTR_SECTION
DSSALL
sync
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
ori r7,r7,MSR_EE
oris r7,r7,MSR_POW@h
sync
isync
mtmsrd r7
isync
blr
52 changes: 50 additions & 2 deletions arch/powerpc/platforms/powermac/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
};
12 changes: 10 additions & 2 deletions arch/powerpc/platforms/powermac/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ void smp_core99_cpu_die(unsigned int cpu)
cpu_dead[cpu] = 0;
}

#endif
#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 */

/* Core99 Macs (dual G4s and G5s) */
struct smp_ops_t core99_smp_ops = {
Expand All @@ -910,8 +910,16 @@ struct smp_ops_t core99_smp_ops = {
.setup_cpu = smp_core99_setup_cpu,
.give_timebase = smp_core99_give_timebase,
.take_timebase = smp_core99_take_timebase,
#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
#if defined(CONFIG_HOTPLUG_CPU)
# if defined(CONFIG_PPC32)
.cpu_disable = smp_core99_cpu_disable,
.cpu_die = smp_core99_cpu_die,
# endif
# if defined(CONFIG_PPC64)
.cpu_disable = generic_cpu_disable,
.cpu_die = generic_cpu_die,
/* intentionally do *NOT* assign cpu_enable,
* the generic code will use kick_cpu then! */
# endif
#endif
};
1 change: 1 addition & 0 deletions include/asm-powerpc/machdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ struct machdep_calls {
};

extern void power4_idle(void);
extern void power4_cpu_offline_powersave(void);
extern void ppc6xx_idle(void);

/*
Expand Down

0 comments on commit d9333af

Please sign in to comment.