Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31139971 authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds
Browse files

[PATCH] ppc32: support hotplug cpu on powermacs



This allows cpus to be off-lined on 32-bit SMP powermacs.  When a cpu
is off-lined, it is put into sleep mode with interrupts disabled.  It
can be on-lined again by asserting its soft-reset pin, which is
connected to a GPIO pin.

With this I can off-line the second cpu in my dual G4 powermac, which
means that I can then suspend the machine (the suspend/resume code
refuses to suspend if more than one cpu is online, and making it cope
with multiple cpus is surprisingly messy).

Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent bb0bb3b6
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -265,6 +265,15 @@ config PPC601_SYNC_FIX

	  If in doubt, say Y here.

config HOTPLUG_CPU
	bool "Support for enabling/disabling CPUs"
	depends on SMP && HOTPLUG && EXPERIMENTAL && PPC_PMAC
	---help---
	  Say Y here to be able to disable and re-enable individual
	  CPUs at runtime on SMP machines.

	  Say N if you are unsure.

source arch/ppc/platforms/4xx/Kconfig
source arch/ppc/platforms/85xx/Kconfig

+13 −15
Original line number Diff line number Diff line
@@ -1023,23 +1023,21 @@ __secondary_start_gemini:
        andc    r4,r4,r3
        mtspr   SPRN_HID0,r4
        sync
        bl      gemini_prom_init
        b       __secondary_start
#endif /* CONFIG_GEMINI */
	.globl	__secondary_start_psurge
__secondary_start_psurge:
	li	r24,1			/* cpu # */
	b	__secondary_start_psurge99
	.globl	__secondary_start_psurge2
__secondary_start_psurge2:
	li	r24,2			/* cpu # */
	b	__secondary_start_psurge99
	.globl	__secondary_start_psurge3
__secondary_start_psurge3:
	li	r24,3			/* cpu # */
	b	__secondary_start_psurge99
__secondary_start_psurge99:
	/* we come in here with IR=0 and DR=1, and DBAT 0

	.globl	__secondary_start_pmac_0
__secondary_start_pmac_0:
	/* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
	li	r24,0
	b	1f
	li	r24,1
	b	1f
	li	r24,2
	b	1f
	li	r24,3
1:
	/* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0
	   set to map the 0xf0000000 - 0xffffffff region */
	mfmsr	r0
	rlwinm	r0,r0,0,28,26		/* clear DR (0x10) */
+5 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/cpu.h>

#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -35,6 +36,7 @@
void default_idle(void)
{
	void (*powersave)(void);
	int cpu = smp_processor_id();

	powersave = ppc_md.power_save;

@@ -44,7 +46,7 @@ void default_idle(void)
#ifdef CONFIG_SMP
		else {
			set_thread_flag(TIF_POLLING_NRFLAG);
			while (!need_resched())
			while (!need_resched() && !cpu_is_offline(cpu))
				barrier();
			clear_thread_flag(TIF_POLLING_NRFLAG);
		}
@@ -52,6 +54,8 @@ void default_idle(void)
	}
	if (need_resched())
		schedule();
	if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
		cpu_die();
}

/*
+30 −14
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ cpumask_t cpu_online_map;
cpumask_t cpu_possible_map;
int smp_hw_index[NR_CPUS];
struct thread_info *secondary_ti;
static struct task_struct *idle_tasks[NR_CPUS];

EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(cpu_possible_map);
@@ -286,7 +287,8 @@ static void __devinit smp_store_cpu_info(int id)

void __init smp_prepare_cpus(unsigned int max_cpus)
{
	int num_cpus, i;
	int num_cpus, i, cpu;
	struct task_struct *p;

	/* Fixup boot cpu */
        smp_store_cpu_info(smp_processor_id());
@@ -308,6 +310,17 @@ void __init smp_prepare_cpus(unsigned int max_cpus)

	if (smp_ops->space_timers)
		smp_ops->space_timers(num_cpus);

	for_each_cpu(cpu) {
		if (cpu == smp_processor_id())
			continue;
		/* create a process for the processor */
		p = fork_idle(cpu);
		if (IS_ERR(p))
			panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
		p->thread_info->cpu = cpu;
		idle_tasks[cpu] = p;
	}
}

void __devinit smp_prepare_boot_cpu(void)
@@ -334,12 +347,17 @@ int __devinit start_secondary(void *unused)
	set_dec(tb_ticks_per_jiffy);
	cpu_callin_map[cpu] = 1;

	printk("CPU %i done callin...\n", cpu);
	printk("CPU %d done callin...\n", cpu);
	smp_ops->setup_cpu(cpu);
	printk("CPU %i done setup...\n", cpu);
	local_irq_enable();
	printk("CPU %d done setup...\n", cpu);
	smp_ops->take_timebase();
	printk("CPU %i done timebase take...\n", cpu);
	printk("CPU %d done timebase take...\n", cpu);

	spin_lock(&call_lock);
	cpu_set(cpu, cpu_online_map);
	spin_unlock(&call_lock);

	local_irq_enable();

	cpu_idle();
	return 0;
@@ -347,17 +365,11 @@ int __devinit start_secondary(void *unused)

int __cpu_up(unsigned int cpu)
{
	struct task_struct *p;
	char buf[32];
	int c;

	/* create a process for the processor */
	/* only regs.msr is actually used, and 0 is OK for it */
	p = fork_idle(cpu);
	if (IS_ERR(p))
		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
	secondary_ti = p->thread_info;
	p->thread_info->cpu = cpu;
	secondary_ti = idle_tasks[cpu]->thread_info;
	mb();

	/*
	 * There was a cache flush loop here to flush the cache
@@ -389,7 +401,11 @@ int __cpu_up(unsigned int cpu)
	printk("Processor %d found.\n", cpu);

	smp_ops->give_timebase();
	cpu_set(cpu, cpu_online_map);

	/* Wait until cpu puts itself in the online map */
	while (!cpu_online(cpu))
		cpu_relax();

	return 0;
}

+2 −0
Original line number Diff line number Diff line
@@ -161,6 +161,8 @@ _GLOBAL(low_sleep_handler)
	addi r3,r3,sleep_storage@l
	stw r5,0(r3)

	.globl	low_cpu_die
low_cpu_die:
	/* Flush & disable all caches */
	bl	flush_disable_caches

Loading