Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756212AbZLDCtF (ORCPT ); Thu, 3 Dec 2009 21:49:05 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1756143AbZLDCtC (ORCPT ); Thu, 3 Dec 2009 21:49:02 -0500 Received: from gate.crashing.org ([63.228.1.57]:37854 "EHLO gate.crashing.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756076AbZLDCsK (ORCPT ); Thu, 3 Dec 2009 21:48:10 -0500 Subject: Re: [v10 PATCH 8/9]: pSeries: implement pSeries processor idle module From: Benjamin Herrenschmidt To: arun@linux.vnet.ibm.com Cc: Peter Zijlstra , Ingo Molnar , Vaidyanathan Srinivasan , Dipankar Sarma , Balbir Singh , Venkatesh Pallipadi , linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, linux-arch@vger.kernel.org, linux-acpi@vger.kernel.org In-Reply-To: <20091202100255.GI27251@linux.vnet.ibm.com> References: <20091202095427.GA27251@linux.vnet.ibm.com> <20091202100255.GI27251@linux.vnet.ibm.com> Content-Type: text/plain; charset="UTF-8" Date: Fri, 04 Dec 2009 13:47:38 +1100 Message-ID: <1259894858.2076.1251.camel@pasglop> Mime-Version: 1.0 X-Mailer: Evolution 2.28.1 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9555 Lines: 305 On Wed, 2009-12-02 at 15:32 +0530, Arun R Bharadwaj wrote: > * Arun R Bharadwaj [2009-12-02 15:24:27]: > > This patch creates arch/powerpc/platforms/pseries/processor_idle.c, > which implements the cpuidle infrastructure for pseries. > It implements a pseries_cpuidle_loop() which would be the main idle loop > called from cpu_idle(). It makes decision of entering either > dedicated_snooze_loop or dedicated_cede_loop for dedicated lpar and > shared_cede_loop for shared lpar processor based on the > decision taken by the cpuidle governor. So unless I'm mistaken, you removed our powerpc "generic" idle loop that calls into ppc_md.power_save(), and replaced it by some pseries specific idle loops... Now what about all the other powerpc platforms ? native 970 (aka G5) ? 6xx ? Cell ? Or are you still calling ppc_md.power_save somewhere that I missed ? Cheers, Ben. > Signed-off-by: Arun R Bharadwaj > --- > arch/powerpc/include/asm/system.h | 6 > arch/powerpc/kernel/sysfs.c | 2 > arch/powerpc/platforms/pseries/Makefile | 1 > arch/powerpc/platforms/pseries/processor_idle.c | 196 ++++++++++++++++++++++++ > arch/powerpc/platforms/pseries/pseries.h | 6 > 5 files changed, 211 insertions(+) > > Index: linux.trees.git/arch/powerpc/platforms/pseries/Makefile > =================================================================== > --- linux.trees.git.orig/arch/powerpc/platforms/pseries/Makefile > +++ linux.trees.git/arch/powerpc/platforms/pseries/Makefile > @@ -26,3 +26,4 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst > obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o > obj-$(CONFIG_CMM) += cmm.o > obj-$(CONFIG_DTL) += dtl.o > +obj-$(CONFIG_CPU_IDLE) += processor_idle.o > Index: linux.trees.git/arch/powerpc/platforms/pseries/pseries.h > =================================================================== > --- linux.trees.git.orig/arch/powerpc/platforms/pseries/pseries.h > +++ linux.trees.git/arch/powerpc/platforms/pseries/pseries.h > @@ -10,6 +10,8 @@ > #ifndef _PSERIES_PSERIES_H > #define _PSERIES_PSERIES_H > > +#include > + > extern void __init fw_feature_init(const char *hypertas, unsigned long len); > > struct pt_regs; > @@ -40,4 +42,8 @@ extern unsigned long rtas_poweron_auto; > > extern void find_udbg_vterm(void); > > +DECLARE_PER_CPU(unsigned long, smt_snooze_delay); > + > +extern struct cpuidle_driver pseries_idle_driver; > + > #endif /* _PSERIES_PSERIES_H */ > Index: linux.trees.git/arch/powerpc/platforms/pseries/processor_idle.c > =================================================================== > --- /dev/null > +++ linux.trees.git/arch/powerpc/platforms/pseries/processor_idle.c > @@ -0,0 +1,196 @@ > +/* > + * processor_idle - idle state cpuidle driver. > + * Adapted from drivers/acpi/processor_idle.c > + * > + * Arun R Bharadwaj > + * > + * Copyright (C) 2009 IBM Corporation. > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or (at > + * your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, write to the Free Software Foundation, Inc., > + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "plpar_wrappers.h" > +#include "pseries.h" > + > +MODULE_AUTHOR("Arun R Bharadwaj"); > +MODULE_DESCRIPTION("pSeries Idle State Driver"); > +MODULE_LICENSE("GPL"); > + > +struct cpuidle_driver pseries_idle_driver = { > + .name = "pseries_idle", > + .owner = THIS_MODULE, > +}; > + > +DEFINE_PER_CPU(struct cpuidle_device, pseries_dev); > + > +#define IDLE_STATE_COUNT 2 > + > +/* pSeries Idle state Flags */ > +#define PSERIES_DEDICATED_SNOOZE (0x01) > +#define PSERIES_DEDICATED_CEDE (0x02) > +#define PSERIES_SHARED_CEDE (0x03) > + > +static int pseries_idle_init(struct cpuidle_device *dev) > +{ > + return cpuidle_register_device(dev); > +} > + > +static void shared_cede_loop(void) > +{ > + get_lppaca()->idle = 1; > + cede_processor(); > + get_lppaca()->idle = 0; > +} > + > +static void dedicated_snooze_loop(void) > +{ > + local_irq_enable(); > + set_thread_flag(TIF_POLLING_NRFLAG); > + while (!need_resched()) { > + ppc64_runlatch_off(); > + HMT_low(); > + HMT_very_low(); > + } > + HMT_medium(); > + clear_thread_flag(TIF_POLLING_NRFLAG); > + smp_mb(); > + local_irq_disable(); > +} > + > +static void dedicated_cede_loop(void) > +{ > + ppc64_runlatch_off(); > + HMT_medium(); > + cede_processor(); > +} > + > +static void pseries_cpuidle_loop(struct cpuidle_device *dev, > + struct cpuidle_state *st) > +{ > + unsigned long in_purr, out_purr; > + > + get_lppaca()->idle = 1; > + get_lppaca()->donate_dedicated_cpu = 1; > + in_purr = mfspr(SPRN_PURR); > + > + if (st->flags & PSERIES_SHARED_CEDE) > + shared_cede_loop(); > + else if (st->flags & PSERIES_DEDICATED_SNOOZE) > + dedicated_snooze_loop(); > + else > + dedicated_cede_loop(); > + > + out_purr = mfspr(SPRN_PURR); > + get_lppaca()->wait_state_cycles += out_purr - in_purr; > + get_lppaca()->donate_dedicated_cpu = 0; > + get_lppaca()->idle = 0; > +} > + > +static int pseries_setup_cpuidle(struct cpuidle_device *dev, int cpu) > +{ > + int i; > + struct cpuidle_state *state; > + > + dev->cpu = cpu; > + > + if (get_lppaca()->shared_proc) { > + state = &dev->states[0]; > + snprintf(state->name, CPUIDLE_NAME_LEN, "IDLE"); > + state->enter = pseries_cpuidle_loop; > + strncpy(state->desc, "shared_cede", CPUIDLE_DESC_LEN); > + state->flags = PSERIES_SHARED_CEDE; > + state->exit_latency = 0; > + state->target_residency = 0; > + return 0; > + } > + > + for (i = 0; i < IDLE_STATE_COUNT; i++) { > + state = &dev->states[i]; > + > + snprintf(state->name, CPUIDLE_NAME_LEN, "CEDE%d", i); > + state->enter = pseries_cpuidle_loop; > + > + switch (i) { > + case 0: > + strncpy(state->desc, "snooze", CPUIDLE_DESC_LEN); > + state->flags = PSERIES_DEDICATED_SNOOZE; > + state->exit_latency = 0; > + state->target_residency = 0; > + break; > + > + case 1: > + strncpy(state->desc, "cede", CPUIDLE_DESC_LEN); > + state->flags = PSERIES_DEDICATED_CEDE; > + state->exit_latency = 1; > + state->target_residency = > + __get_cpu_var(smt_snooze_delay); > + break; > + } > + } > + dev->state_count = IDLE_STATE_COUNT; > + > + return 0; > +} > + > +void update_smt_snooze_delay(int snooze) > +{ > + int cpu; > + for_each_online_cpu(cpu) > + per_cpu(pseries_dev, cpu).states[0].target_residency = snooze; > +} > + > +static int __init pseries_processor_idle_init(void) > +{ > + int cpu; > + int result; > + > + result = cpuidle_register_driver(&pseries_idle_driver); > + > + if (result < 0) > + return result; > + > + printk(KERN_DEBUG "pSeries idle driver registered\n"); > + > + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) { > + printk(KERN_DEBUG "Using default idle\n"); > + return 0; > + } > + > + for_each_online_cpu(cpu) { > + pseries_setup_cpuidle(&per_cpu(pseries_dev, cpu), cpu); > + pseries_idle_init(&per_cpu(pseries_dev, cpu)); > + } > + > + printk(KERN_DEBUG "Using cpuidle idle loop\n"); > + > + return 0; > +} > + > +device_initcall(pseries_processor_idle_init); > Index: linux.trees.git/arch/powerpc/include/asm/system.h > =================================================================== > --- linux.trees.git.orig/arch/powerpc/include/asm/system.h > +++ linux.trees.git/arch/powerpc/include/asm/system.h > @@ -549,5 +549,11 @@ extern struct dentry *powerpc_debugfs_ro > > void cpu_idle_wait(void); > > +#ifdef CONFIG_CPU_IDLE > +extern void update_smt_snooze_delay(int snooze); > +#else > +static inline void update_smt_snooze_delay(int snooze) {} > +#endif > + > #endif /* __KERNEL__ */ > #endif /* _ASM_POWERPC_SYSTEM_H */ > Index: linux.trees.git/arch/powerpc/kernel/sysfs.c > =================================================================== > --- linux.trees.git.orig/arch/powerpc/kernel/sysfs.c > +++ linux.trees.git/arch/powerpc/kernel/sysfs.c > @@ -18,6 +18,7 @@ > #include > #include > #include > +#include > > #include "cacheinfo.h" > > @@ -51,6 +52,7 @@ static ssize_t store_smt_snooze_delay(st > return -EINVAL; > > per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze; > + update_smt_snooze_delay(snooze); > > return count; > } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/