From mboxrd@z Thu Jan 1 00:00:00 1970 From: Johannes Berg Subject: [PATCH 02/12] powermac: support G5 CPU hotplug Date: Wed, 07 Feb 2007 13:45:38 +0100 Message-ID: <20070207124610.392302000@sipsolutions.net> References: <20070207124536.963531000@sipsolutions.net> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Return-path: Content-Disposition: inline; filename=powermac-g5-cpu-offline.patch List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-pm-bounces@lists.osdl.org Errors-To: linux-pm-bounces@lists.osdl.org To: linuxppc-dev@ozlabs.org Cc: linux-pm@lists.osdl.org List-Id: linux-pm@vger.kernel.org This patch allows "hotplugging" of CPUs on G5 machines. CPUs that are disabled are put into an idle loop with interrupts hard-disabled, to wake them up again we kick them just like when bringing them up. Signed-off-by: Johannes Berg Cc: Benjamin Herrenschmidt --- Except for the in-irq count hack I'm happy with this. I still haven't found where the in-hard-irq count is set to 1 in the down path during suspend or resume and other platforms do similar things so I'm inclined to leave this. --- linux-2.6-git.orig/arch/powerpc/platforms/powermac/smp.c 2007-02-07 02:= 55:05.657884289 +0100 +++ linux-2.6-git/arch/powerpc/platforms/powermac/smp.c 2007-02-07 02:55:27= .352884289 +0100 @@ -898,7 +898,7 @@ void smp_core99_cpu_die(unsigned int cpu cpu_dead[cpu] =3D 0; } = -#endif +#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 */ = /* Core99 Macs (dual G4s and G5s) */ struct smp_ops_t core99_smp_ops =3D { @@ -908,8 +908,16 @@ struct smp_ops_t core99_smp_ops =3D { .setup_cpu =3D smp_core99_setup_cpu, .give_timebase =3D smp_core99_give_timebase, .take_timebase =3D smp_core99_take_timebase, -#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) +#if defined(CONFIG_HOTPLUG_CPU) +# if defined(CONFIG_PPC32) .cpu_disable =3D smp_core99_cpu_disable, .cpu_die =3D smp_core99_cpu_die, +# endif +# if defined(CONFIG_PPC64) + .cpu_disable =3D generic_cpu_disable, + .cpu_die =3D generic_cpu_die, + /* intentionally do *NOT* assign cpu_enable, + * the generic code will use kick_cpu then! */ +# endif #endif }; --- linux-2.6-git.orig/arch/powerpc/platforms/powermac/setup.c 2007-02-07 0= 2:55:23.435884289 +0100 +++ linux-2.6-git/arch/powerpc/platforms/powermac/setup.c 2007-02-07 02:55:= 27.388884289 +0100 @@ -490,6 +490,9 @@ static int pmac_late_init(void) #ifdef CONFIG_SOFTWARE_SUSPEND pm_set_ops(&pmac_pm_ops); #endif /* CONFIG_SOFTWARE_SUSPEND */ + /* this is udbg (which is __init) and we can later use it during + * cpu hotplug (in smp_core99_kick_cpu) */ + ppc_md.progress =3D NULL; return 0; } = @@ -716,6 +719,39 @@ static int pmac_pci_probe_mode(struct pc return PCI_PROBE_NORMAL; return PCI_PROBE_DEVTREE; } + +#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 ... */ + hard_irq_disable(); + + printk(KERN_INFO "CPU#%d offline\n", smp_processor_id()); + __get_cpu_var(cpu_state) =3D 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(); + + while (1) { + ppc64_runlatch_off(); + if (ppc_md.power_save) { + ppc_md.power_save(); + } else { + HMT_low(); + HMT_very_low(); + } + } +} +#endif + #endif = static void __init pmac_init_irq(void) @@ -769,6 +805,6 @@ define_machine(powermac) { .phys_mem_access_prot =3D pci_phys_mem_access_prot, #endif #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) - .cpu_die =3D generic_mach_cpu_die, + .cpu_die =3D pmac_cpu_die, #endif }; --- linux-2.6-git.orig/arch/powerpc/kernel/smp.c 2007-02-07 02:55:06.111884= 289 +0100 +++ linux-2.6-git/arch/powerpc/kernel/smp.c 2007-02-07 02:55:27.439884289 += 0100 @@ -558,6 +558,11 @@ int __devinit start_secondary(void *unus = local_irq_enable(); = + /* it seems to be possible that we died from within + * an interrupt ... reset the in-irq counts */ + task_thread_info(paca[cpu].__current)->preempt_count &=3D + ~(SOFTIRQ_MASK|HARDIRQ_MASK); + cpu_idle(); return 0; } --