Name: Hotplug CPU Remove for PPC Author: Rusty Russell Status: Experimental Depends: Hotcpu/hotcpu-cpudown.patch.gz Hotcpu/wake_idle_cpu.patch.gz D: This introduces hotplug CPU capability for PPC. diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19474-linux-2.5.34/arch/ppc/kernel/idle.c .19474-linux-2.5.34.updated/arch/ppc/kernel/idle.c --- .19474-linux-2.5.34/arch/ppc/kernel/idle.c 2002-07-25 10:13:03.000000000 +1000 +++ .19474-linux-2.5.34.updated/arch/ppc/kernel/idle.c 2002-09-10 15:23:33.000000000 +1000 @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -95,14 +97,45 @@ void default_idle(void) #endif /* CONFIG_PPC_ISERIES */ } +DECLARE_PER_CPU(int, cpu_die); +static void die_cpu_die(void) +{ + preempt_disable(); + printk("Cpu %u Dust Dust Dust\n", smp_processor_id()); + /* Ack it */ + __get_cpu_var(cpu_die) = 2; + + /* Death loop */ + local_irq_disable(); + while (__get_cpu_var(cpu_die)) + mb(); + +#if 0 /* FIXME */ + /* Now, we missed any cache flush IPIs, so be safe. */ + local_flush_tlb(); +#endif + local_irq_enable(); + + /* Ack it by setting online bit */ + br_write_lock_irq(BR_CPU_LOCK); + set_bit(smp_processor_id(), cpu_online_map); + br_write_unlock_irq(BR_CPU_LOCK); + printk("Cpu %u arisen\n", smp_processor_id()); + preempt_enable(); +} + /* * SMP entry into the idle task - calls the same thing as the * non-smp versions. -- Cort */ int cpu_idle(void) { - for (;;) + for (;;) { default_idle(); + + if (unlikely(__get_cpu_var(cpu_die))) + die_cpu_die(); + } return 0; } diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .19474-linux-2.5.34/arch/ppc/kernel/smp.c .19474-linux-2.5.34.updated/arch/ppc/kernel/smp.c --- .19474-linux-2.5.34/arch/ppc/kernel/smp.c 2002-09-10 15:21:22.000000000 +1000 +++ .19474-linux-2.5.34.updated/arch/ppc/kernel/smp.c 2002-09-10 15:21:43.000000000 +1000 @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -389,6 +391,10 @@ int __cpu_up(unsigned int cpu) char buf[32]; int c; + /* FIXME: we don't take it fully down ATM. --RR */ + if (cpu_callin_map[cpu]) + goto up; + /* create a process for the processor */ /* only regs.msr is actually used, and 0 is OK for it */ memset(®s, 0, sizeof(struct pt_regs)); @@ -432,21 +438,43 @@ int __cpu_up(unsigned int cpu) printk("Processor %d found.\n", cpu); smp_ops->give_timebase(); + up: br_write_lock_irq(BR_CPU_LOCK); - set_bit(cpu, &cpu_online_map); + set_bit(cpu, cpu_online_map); br_write_unlock_irq(BR_CPU_LOCK); return 0; } -int __cpu_disable(unsigned int cpu) +int __cpu_disable(void) { return -ENOSYS; } -/* Since we fail __cpu_disable, this is never called. */ +DEFINE_PER_CPU(int, cpu_die); + void __cpu_die(unsigned int cpu) { - BUG(); + unsigned int i; + + printk("Killing cpu %u (%p)\n", cpu, &per_cpu(cpu_die, cpu)); + /* Final threads can take some time to actually clean up */ + while (!idle_cpu(cpu)) + yield(); + + per_cpu(cpu_die, cpu) = 1; + wmb(); + wake_idle_cpu(cpu); + printk("Waiting for cpu %u\n", cpu); + for (i = 0; i < 100; i++) { + rmb(); + if (per_cpu(cpu_die, cpu) == 2) { + printk("cpu %u says its dead\n", cpu); + return; + } + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + } + printk("cpu %u didn't die.... hmm...\n", cpu); } void smp_cpus_done(unsigned int max_cpus)