* [RFC PATCH V3 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms @ 2013-08-19 4:27 Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 1/5] pseries/cpuidle: Remove dependency of pseries.h file Deepthi Dharwar ` (4 more replies) 0 siblings, 5 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-19 4:27 UTC (permalink / raw) To: benh, daniel.lezcano, kernel, scottwood, linux-pm, linuxppc-dev Cc: preeti, dongsheng.wang This patch series consolidates the backend cpuidle driver for pseries and powernv platforms and also enables the new drivers/cpuidle/cpuidle-powerpc.c to include other powerpc drivers with minimal code duplication. Current existing backend driver for pseries has been moved to drivers/cpuidle and has been extended to accommodate powernv idle power mgmt states. As seen in V1 of this patch series, having a separate powernv backend driver results in too much code duplication, which is less elegant and can pose maintenance problems going further. Using the cpuidle framework to exploit platform low power idle states management can take advantage of advanced heuristics, tunables and features provided by framework. The statistics and tracing infrastructure provided by the cpuidle framework also helps in enabling power management related tools and help tune the system and applications. Earlier in 3.3 kernel, pseries idle state management was modified to exploit the cpuidle framework and the end goal of this patch is to have powernv platform also to hook its idle states into cpuidle framework with minimal code duplication between both platforms. This result is a generic powerpc backend driver currently enabled for pseries and powernv platforms and which can be extended to accommodate other powerpc archs in the future. This series aims to maintain compatibility and functionality to existing pseries and powernv idle cpu management code. There are no new functions or idle states added as part of this series. This can be extended by adding more states to this existing framework. With this patch series, the powernv cpuidle functionalities are on-par with pSeries idle management. Other POWERPC platforms can use this patch series to exploit the CPUIDLE framework. This patch mainly focus on an integrated CPUIDLE backend driver for POWERPC. Minor cpuidle clean-ups including a generic hotplug cpuidle notifier, using cpuidle_register calls will be taken up going further. V1 -> http://lkml.org/lkml/2013/7/23/143 V2 -> https://lkml.org/lkml/2013/7/30/872 Changes from V2: =============== * This patch series does not include smt-snooze-delay fixes. This will be taken up later on. * Integrated POWERPC driver in drivers/cpuidle. Enabled for all of POWERPC platform. Currently has PSERIES and POWERNV support. No compile time flags in .c file. This will be one consolidated binary that does a run time detection based on platform and take decisions accordingly. Deepthi Dharwar (5): pseries/cpuidle: Remove dependency of pseries.h file pseries: Move plpar_wrapper.h to powerpc common include/asm location. powerpc/cpuidle: Generic powerpc backend cpuidle driver. powerpc/cpuidle: Enable powernv cpuidle support. powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework. arch/powerpc/include/asm/paca.h | 23 + arch/powerpc/include/asm/plpar_wrappers.h | 325 +++++++++++++++++++ arch/powerpc/include/asm/processor.h | 2 arch/powerpc/platforms/powernv/setup.c | 14 + arch/powerpc/platforms/pseries/Kconfig | 9 - arch/powerpc/platforms/pseries/Makefile | 1 arch/powerpc/platforms/pseries/cmm.c | 3 arch/powerpc/platforms/pseries/dtl.c | 3 arch/powerpc/platforms/pseries/hotplug-cpu.c | 3 arch/powerpc/platforms/pseries/hvconsole.c | 2 arch/powerpc/platforms/pseries/iommu.c | 3 arch/powerpc/platforms/pseries/kexec.c | 2 arch/powerpc/platforms/pseries/lpar.c | 2 arch/powerpc/platforms/pseries/plpar_wrappers.h | 324 ------------------- arch/powerpc/platforms/pseries/processor_idle.c | 362 --------------------- arch/powerpc/platforms/pseries/pseries.h | 3 arch/powerpc/platforms/pseries/setup.c | 2 arch/powerpc/platforms/pseries/smp.c | 2 drivers/cpuidle/Kconfig | 7 drivers/cpuidle/Makefile | 2 drivers/cpuidle/cpuidle-powerpc.c | 391 +++++++++++++++++++++++ 21 files changed, 772 insertions(+), 713 deletions(-) create mode 100644 arch/powerpc/include/asm/plpar_wrappers.h delete mode 100644 arch/powerpc/platforms/pseries/plpar_wrappers.h delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c create mode 100644 drivers/cpuidle/cpuidle-powerpc.c -- Deepthi ^ permalink raw reply [flat|nested] 16+ messages in thread
* [RFC PATCH V3 1/5] pseries/cpuidle: Remove dependency of pseries.h file 2013-08-19 4:27 [RFC PATCH V3 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms Deepthi Dharwar @ 2013-08-19 4:28 ` Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 2/5] pseries: Move plpar_wrapper.h to powerpc common include/asm location Deepthi Dharwar ` (3 subsequent siblings) 4 siblings, 0 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-19 4:28 UTC (permalink / raw) To: benh, daniel.lezcano, kernel, scottwood, linux-pm, linuxppc-dev Cc: preeti, dongsheng.wang As a part of pseries_idle cleanup to make the backend driver code common to both pseries and powernv. Remove non-essential smt_snooze_delay declaration in pseries.h header file and pseries.h file inclusion in pseries/processor_idle.c Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> --- arch/powerpc/platforms/pseries/processor_idle.c | 1 - arch/powerpc/platforms/pseries/pseries.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 4644efa0..ca70279 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -20,7 +20,6 @@ #include <asm/runlatch.h> #include "plpar_wrappers.h" -#include "pseries.h" struct cpuidle_driver pseries_idle_driver = { .name = "pseries_idle", diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index c2a3a25..d1b07e6 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -60,9 +60,6 @@ extern struct device_node *dlpar_configure_connector(u32); extern int dlpar_attach_node(struct device_node *); extern int dlpar_detach_node(struct device_node *); -/* Snooze Delay, pseries_idle */ -DECLARE_PER_CPU(long, smt_snooze_delay); - /* PCI root bridge prepare function override for pseries */ struct pci_host_bridge; int pseries_root_bridge_prepare(struct pci_host_bridge *bridge); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH V3 2/5] pseries: Move plpar_wrapper.h to powerpc common include/asm location. 2013-08-19 4:27 [RFC PATCH V3 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 1/5] pseries/cpuidle: Remove dependency of pseries.h file Deepthi Dharwar @ 2013-08-19 4:28 ` Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver Deepthi Dharwar ` (2 subsequent siblings) 4 siblings, 0 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-19 4:28 UTC (permalink / raw) To: benh, daniel.lezcano, kernel, scottwood, linux-pm, linuxppc-dev Cc: preeti, dongsheng.wang As a part of pseries_idle backend driver cleanup to make the code common to both pseries and powernv platforms, it is necessary to move the backend-driver code to drivers/cpuidle. As a pre-requisite for that, it is essential to move plpar_wrapper.h to include/asm. Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> --- arch/powerpc/include/asm/plpar_wrappers.h | 325 +++++++++++++++++++++++ arch/powerpc/platforms/pseries/cmm.c | 3 arch/powerpc/platforms/pseries/dtl.c | 3 arch/powerpc/platforms/pseries/hotplug-cpu.c | 3 arch/powerpc/platforms/pseries/hvconsole.c | 2 arch/powerpc/platforms/pseries/iommu.c | 3 arch/powerpc/platforms/pseries/kexec.c | 2 arch/powerpc/platforms/pseries/lpar.c | 2 arch/powerpc/platforms/pseries/plpar_wrappers.h | 324 ----------------------- arch/powerpc/platforms/pseries/processor_idle.c | 3 arch/powerpc/platforms/pseries/setup.c | 2 arch/powerpc/platforms/pseries/smp.c | 2 12 files changed, 336 insertions(+), 338 deletions(-) create mode 100644 arch/powerpc/include/asm/plpar_wrappers.h delete mode 100644 arch/powerpc/platforms/pseries/plpar_wrappers.h diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h new file mode 100644 index 0000000..e2f84d6 --- /dev/null +++ b/arch/powerpc/include/asm/plpar_wrappers.h @@ -0,0 +1,325 @@ +#ifndef _PSERIES_PLPAR_WRAPPERS_H +#define _PSERIES_PLPAR_WRAPPERS_H + +#include <linux/string.h> +#include <linux/irqflags.h> + +#include <asm/hvcall.h> +#include <asm/paca.h> +#include <asm/page.h> + +/* Get state of physical CPU from query_cpu_stopped */ +int smp_query_cpu_stopped(unsigned int pcpu); +#define QCSS_STOPPED 0 +#define QCSS_STOPPING 1 +#define QCSS_NOT_STOPPED 2 +#define QCSS_HARDWARE_ERROR -1 +#define QCSS_HARDWARE_BUSY -2 + +static inline long poll_pending(void) +{ + return plpar_hcall_norets(H_POLL_PENDING); +} + +static inline u8 get_cede_latency_hint(void) +{ + return get_lppaca()->cede_latency_hint; +} + +static inline void set_cede_latency_hint(u8 latency_hint) +{ + get_lppaca()->cede_latency_hint = latency_hint; +} + +static inline long cede_processor(void) +{ + return plpar_hcall_norets(H_CEDE); +} + +static inline long extended_cede_processor(unsigned long latency_hint) +{ + long rc; + u8 old_latency_hint = get_cede_latency_hint(); + + set_cede_latency_hint(latency_hint); + + rc = cede_processor(); +#ifdef CONFIG_TRACE_IRQFLAGS + /* Ensure that H_CEDE returns with IRQs on */ + if (WARN_ON(!(mfmsr() & MSR_EE))) + __hard_irq_enable(); +#endif + + set_cede_latency_hint(old_latency_hint); + + return rc; +} + +static inline long vpa_call(unsigned long flags, unsigned long cpu, + unsigned long vpa) +{ + flags = flags << H_VPA_FUNC_SHIFT; + + return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa); +} + +static inline long unregister_vpa(unsigned long cpu) +{ + return vpa_call(H_VPA_DEREG_VPA, cpu, 0); +} + +static inline long register_vpa(unsigned long cpu, unsigned long vpa) +{ + return vpa_call(H_VPA_REG_VPA, cpu, vpa); +} + +static inline long unregister_slb_shadow(unsigned long cpu) +{ + return vpa_call(H_VPA_DEREG_SLB, cpu, 0); +} + +static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa) +{ + return vpa_call(H_VPA_REG_SLB, cpu, vpa); +} + +static inline long unregister_dtl(unsigned long cpu) +{ + return vpa_call(H_VPA_DEREG_DTL, cpu, 0); +} + +static inline long register_dtl(unsigned long cpu, unsigned long vpa) +{ + return vpa_call(H_VPA_REG_DTL, cpu, vpa); +} + +static inline long plpar_page_set_loaned(unsigned long vpa) +{ + unsigned long cmo_page_sz = cmo_get_page_size(); + long rc = 0; + int i; + + for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz) + rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, vpa + i, 0); + + for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz) + plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, + vpa + i - cmo_page_sz, 0); + + return rc; +} + +static inline long plpar_page_set_active(unsigned long vpa) +{ + unsigned long cmo_page_sz = cmo_get_page_size(); + long rc = 0; + int i; + + for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz) + rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, vpa + i, 0); + + for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz) + plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, + vpa + i - cmo_page_sz, 0); + + return rc; +} + +extern void vpa_init(int cpu); + +static inline long plpar_pte_enter(unsigned long flags, + unsigned long hpte_group, unsigned long hpte_v, + unsigned long hpte_r, unsigned long *slot) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r); + + *slot = retbuf[0]; + + return rc; +} + +static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex, + unsigned long avpn, unsigned long *old_pteh_ret, + unsigned long *old_ptel_ret) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn); + + *old_pteh_ret = retbuf[0]; + *old_ptel_ret = retbuf[1]; + + return rc; +} + +/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */ +static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex, + unsigned long avpn, unsigned long *old_pteh_ret, + unsigned long *old_ptel_ret) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn); + + *old_pteh_ret = retbuf[0]; + *old_ptel_ret = retbuf[1]; + + return rc; +} + +static inline long plpar_pte_read(unsigned long flags, unsigned long ptex, + unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall(H_READ, retbuf, flags, ptex); + + *old_pteh_ret = retbuf[0]; + *old_ptel_ret = retbuf[1]; + + return rc; +} + +/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */ +static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex, + unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex); + + *old_pteh_ret = retbuf[0]; + *old_ptel_ret = retbuf[1]; + + return rc; +} + +/* + * plpar_pte_read_4_raw can be called in real mode. + * ptes must be 8*sizeof(unsigned long) + */ +static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex, + unsigned long *ptes) + +{ + long rc; + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; + + rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex); + + memcpy(ptes, retbuf, 8*sizeof(unsigned long)); + + return rc; +} + +static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex, + unsigned long avpn) +{ + return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn); +} + +static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba, + unsigned long *tce_ret) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba); + + *tce_ret = retbuf[0]; + + return rc; +} + +static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba, + unsigned long tceval) +{ + return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval); +} + +static inline long plpar_tce_put_indirect(unsigned long liobn, + unsigned long ioba, unsigned long page, unsigned long count) +{ + return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count); +} + +static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba, + unsigned long tceval, unsigned long count) +{ + return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count); +} + +static inline long plpar_get_term_char(unsigned long termno, + unsigned long *len_ret, char *buf_ret) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + unsigned long *lbuf = (unsigned long *)buf_ret; /* TODO: alignment? */ + + rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno); + + *len_ret = retbuf[0]; + lbuf[0] = retbuf[1]; + lbuf[1] = retbuf[2]; + + return rc; +} + +static inline long plpar_put_term_char(unsigned long termno, unsigned long len, + const char *buffer) +{ + unsigned long *lbuf = (unsigned long *)buffer; /* TODO: alignment? */ + return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0], + lbuf[1]); +} + +/* Set various resource mode parameters */ +static inline long plpar_set_mode(unsigned long mflags, unsigned long resource, + unsigned long value1, unsigned long value2) +{ + return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2); +} + +/* + * Enable relocation on exceptions on this partition + * + * Note: this call has a partition wide scope and can take a while to complete. + * If it returns H_LONG_BUSY_* it should be retried periodically until it + * returns H_SUCCESS. + */ +static inline long enable_reloc_on_exceptions(void) +{ + /* mflags = 3: Exceptions at 0xC000000000004000 */ + return plpar_set_mode(3, 3, 0, 0); +} + +/* + * Disable relocation on exceptions on this partition + * + * Note: this call has a partition wide scope and can take a while to complete. + * If it returns H_LONG_BUSY_* it should be retried periodically until it + * returns H_SUCCESS. + */ +static inline long disable_reloc_on_exceptions(void) +{ + return plpar_set_mode(0, 3, 0, 0); +} + +static inline long plapr_set_ciabr(unsigned long ciabr) +{ + return plpar_set_mode(0, 1, ciabr, 0); +} + +static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0) +{ + return plpar_set_mode(0, 2, dawr0, dawrx0); +} + +#endif /* _PSERIES_PLPAR_WRAPPERS_H */ diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index c638535..1e561be 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -40,8 +40,7 @@ #include <asm/pgalloc.h> #include <asm/uaccess.h> #include <linux/memory.h> - -#include "plpar_wrappers.h" +#include <asm/plpar_wrappers.h> #define CMM_DRIVER_VERSION "1.0.0" #define CMM_DEFAULT_DELAY 1 diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 0cc0ac0..f6cb051 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -29,8 +29,7 @@ #include <asm/firmware.h> #include <asm/lppaca.h> #include <asm/debug.h> - -#include "plpar_wrappers.h" +#include <asm/plpar_wrappers.h> struct dtl { struct dtl_entry *buf; diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 217ca5c..a8ef932 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -30,7 +30,8 @@ #include <asm/machdep.h> #include <asm/vdso_datapage.h> #include <asm/xics.h> -#include "plpar_wrappers.h" +#include <asm/plpar_wrappers.h> + #include "offline_states.h" /* This version can't take the spinlock, because it never returns */ diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c index b344f94..f3f108b 100644 --- a/arch/powerpc/platforms/pseries/hvconsole.c +++ b/arch/powerpc/platforms/pseries/hvconsole.c @@ -28,7 +28,7 @@ #include <linux/errno.h> #include <asm/hvcall.h> #include <asm/hvconsole.h> -#include "plpar_wrappers.h" +#include <asm/plpar_wrappers.h> /** * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 23fc1dc..4821933 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -48,8 +48,7 @@ #include <asm/ppc-pci.h> #include <asm/udbg.h> #include <asm/mmzone.h> - -#include "plpar_wrappers.h" +#include <asm/plpar_wrappers.h> static void tce_invalidate_pSeries_sw(struct iommu_table *tbl, diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 7d94bdc..13fa95b3 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -17,9 +17,9 @@ #include <asm/mpic.h> #include <asm/xics.h> #include <asm/smp.h> +#include <asm/plpar_wrappers.h> #include "pseries.h" -#include "plpar_wrappers.h" static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) { diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 8bad880..e1873bc 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -41,8 +41,8 @@ #include <asm/smp.h> #include <asm/trace.h> #include <asm/firmware.h> +#include <asm/plpar_wrappers.h> -#include "plpar_wrappers.h" #include "pseries.h" /* Flag bits for H_BULK_REMOVE */ diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h deleted file mode 100644 index f35787b..0000000 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ /dev/null @@ -1,324 +0,0 @@ -#ifndef _PSERIES_PLPAR_WRAPPERS_H -#define _PSERIES_PLPAR_WRAPPERS_H - -#include <linux/string.h> -#include <linux/irqflags.h> - -#include <asm/hvcall.h> -#include <asm/paca.h> -#include <asm/page.h> - -/* Get state of physical CPU from query_cpu_stopped */ -int smp_query_cpu_stopped(unsigned int pcpu); -#define QCSS_STOPPED 0 -#define QCSS_STOPPING 1 -#define QCSS_NOT_STOPPED 2 -#define QCSS_HARDWARE_ERROR -1 -#define QCSS_HARDWARE_BUSY -2 - -static inline long poll_pending(void) -{ - return plpar_hcall_norets(H_POLL_PENDING); -} - -static inline u8 get_cede_latency_hint(void) -{ - return get_lppaca()->cede_latency_hint; -} - -static inline void set_cede_latency_hint(u8 latency_hint) -{ - get_lppaca()->cede_latency_hint = latency_hint; -} - -static inline long cede_processor(void) -{ - return plpar_hcall_norets(H_CEDE); -} - -static inline long extended_cede_processor(unsigned long latency_hint) -{ - long rc; - u8 old_latency_hint = get_cede_latency_hint(); - - set_cede_latency_hint(latency_hint); - - rc = cede_processor(); -#ifdef CONFIG_TRACE_IRQFLAGS - /* Ensure that H_CEDE returns with IRQs on */ - if (WARN_ON(!(mfmsr() & MSR_EE))) - __hard_irq_enable(); -#endif - - set_cede_latency_hint(old_latency_hint); - - return rc; -} - -static inline long vpa_call(unsigned long flags, unsigned long cpu, - unsigned long vpa) -{ - flags = flags << H_VPA_FUNC_SHIFT; - - return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa); -} - -static inline long unregister_vpa(unsigned long cpu) -{ - return vpa_call(H_VPA_DEREG_VPA, cpu, 0); -} - -static inline long register_vpa(unsigned long cpu, unsigned long vpa) -{ - return vpa_call(H_VPA_REG_VPA, cpu, vpa); -} - -static inline long unregister_slb_shadow(unsigned long cpu) -{ - return vpa_call(H_VPA_DEREG_SLB, cpu, 0); -} - -static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa) -{ - return vpa_call(H_VPA_REG_SLB, cpu, vpa); -} - -static inline long unregister_dtl(unsigned long cpu) -{ - return vpa_call(H_VPA_DEREG_DTL, cpu, 0); -} - -static inline long register_dtl(unsigned long cpu, unsigned long vpa) -{ - return vpa_call(H_VPA_REG_DTL, cpu, vpa); -} - -static inline long plpar_page_set_loaned(unsigned long vpa) -{ - unsigned long cmo_page_sz = cmo_get_page_size(); - long rc = 0; - int i; - - for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz) - rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, vpa + i, 0); - - for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz) - plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, - vpa + i - cmo_page_sz, 0); - - return rc; -} - -static inline long plpar_page_set_active(unsigned long vpa) -{ - unsigned long cmo_page_sz = cmo_get_page_size(); - long rc = 0; - int i; - - for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz) - rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, vpa + i, 0); - - for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz) - plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, - vpa + i - cmo_page_sz, 0); - - return rc; -} - -extern void vpa_init(int cpu); - -static inline long plpar_pte_enter(unsigned long flags, - unsigned long hpte_group, unsigned long hpte_v, - unsigned long hpte_r, unsigned long *slot) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r); - - *slot = retbuf[0]; - - return rc; -} - -static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex, - unsigned long avpn, unsigned long *old_pteh_ret, - unsigned long *old_ptel_ret) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn); - - *old_pteh_ret = retbuf[0]; - *old_ptel_ret = retbuf[1]; - - return rc; -} - -/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */ -static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex, - unsigned long avpn, unsigned long *old_pteh_ret, - unsigned long *old_ptel_ret) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn); - - *old_pteh_ret = retbuf[0]; - *old_ptel_ret = retbuf[1]; - - return rc; -} - -static inline long plpar_pte_read(unsigned long flags, unsigned long ptex, - unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall(H_READ, retbuf, flags, ptex); - - *old_pteh_ret = retbuf[0]; - *old_ptel_ret = retbuf[1]; - - return rc; -} - -/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */ -static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex, - unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex); - - *old_pteh_ret = retbuf[0]; - *old_ptel_ret = retbuf[1]; - - return rc; -} - -/* - * plpar_pte_read_4_raw can be called in real mode. - * ptes must be 8*sizeof(unsigned long) - */ -static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex, - unsigned long *ptes) - -{ - long rc; - unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; - - rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex); - - memcpy(ptes, retbuf, 8*sizeof(unsigned long)); - - return rc; -} - -static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex, - unsigned long avpn) -{ - return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn); -} - -static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba, - unsigned long *tce_ret) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba); - - *tce_ret = retbuf[0]; - - return rc; -} - -static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba, - unsigned long tceval) -{ - return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval); -} - -static inline long plpar_tce_put_indirect(unsigned long liobn, - unsigned long ioba, unsigned long page, unsigned long count) -{ - return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count); -} - -static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba, - unsigned long tceval, unsigned long count) -{ - return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count); -} - -static inline long plpar_get_term_char(unsigned long termno, - unsigned long *len_ret, char *buf_ret) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - unsigned long *lbuf = (unsigned long *)buf_ret; /* TODO: alignment? */ - - rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno); - - *len_ret = retbuf[0]; - lbuf[0] = retbuf[1]; - lbuf[1] = retbuf[2]; - - return rc; -} - -static inline long plpar_put_term_char(unsigned long termno, unsigned long len, - const char *buffer) -{ - unsigned long *lbuf = (unsigned long *)buffer; /* TODO: alignment? */ - return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0], - lbuf[1]); -} - -/* Set various resource mode parameters */ -static inline long plpar_set_mode(unsigned long mflags, unsigned long resource, - unsigned long value1, unsigned long value2) -{ - return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2); -} - -/* - * Enable relocation on exceptions on this partition - * - * Note: this call has a partition wide scope and can take a while to complete. - * If it returns H_LONG_BUSY_* it should be retried periodically until it - * returns H_SUCCESS. - */ -static inline long enable_reloc_on_exceptions(void) -{ - /* mflags = 3: Exceptions at 0xC000000000004000 */ - return plpar_set_mode(3, 3, 0, 0); -} - -/* - * Disable relocation on exceptions on this partition - * - * Note: this call has a partition wide scope and can take a while to complete. - * If it returns H_LONG_BUSY_* it should be retried periodically until it - * returns H_SUCCESS. - */ -static inline long disable_reloc_on_exceptions(void) { - return plpar_set_mode(0, 3, 0, 0); -} - -static inline long plapr_set_ciabr(unsigned long ciabr) -{ - return plpar_set_mode(0, 1, ciabr, 0); -} - -static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0) -{ - return plpar_set_mode(0, 2, dawr0, dawrx0); -} - -#endif /* _PSERIES_PLPAR_WRAPPERS_H */ diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index ca70279..c905b99 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -18,8 +18,7 @@ #include <asm/machdep.h> #include <asm/firmware.h> #include <asm/runlatch.h> - -#include "plpar_wrappers.h" +#include <asm/plpar_wrappers.h> struct cpuidle_driver pseries_idle_driver = { .name = "pseries_idle", diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index c11c823..4291589 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -66,8 +66,8 @@ #include <asm/firmware.h> #include <asm/eeh.h> #include <asm/reg.h> +#include <asm/plpar_wrappers.h> -#include "plpar_wrappers.h" #include "pseries.h" int CMO_PrPSP = -1; diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 306643c..1c79af7 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -43,8 +43,8 @@ #include <asm/cputhreads.h> #include <asm/xics.h> #include <asm/dbell.h> +#include <asm/plpar_wrappers.h> -#include "plpar_wrappers.h" #include "pseries.h" #include "offline_states.h" ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-19 4:27 [RFC PATCH V3 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 1/5] pseries/cpuidle: Remove dependency of pseries.h file Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 2/5] pseries: Move plpar_wrapper.h to powerpc common include/asm location Deepthi Dharwar @ 2013-08-19 4:28 ` Deepthi Dharwar 2013-08-19 5:52 ` Wang Dongsheng-B40534 2013-08-19 4:28 ` [RFC PATCH V3 4/5] powerpc/cpuidle: Enable powernv cpuidle support Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 5/5] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework Deepthi Dharwar 4 siblings, 1 reply; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-19 4:28 UTC (permalink / raw) To: benh, daniel.lezcano, kernel, scottwood, linux-pm, linuxppc-dev Cc: preeti, dongsheng.wang This patch involves moving the current pseries_idle backend driver code from pseries/processor_idle.c to drivers/cpuidle/cpuidle-powerpc.c, and making the backend code generic enough to be able to extend this driver code for complete powerpc platform to exploit the cpuidle framework. It enables the support for pseries platform, such that going forward the same code with minimal efforts can be re-used for a common driver on powernv and can be further extended to support cpuidle idle state mgmt for the rest of the powerpc platforms. This removes a lot of code duplicacy, making the code elegant. Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> --- arch/powerpc/include/asm/paca.h | 23 + arch/powerpc/include/asm/processor.h | 2 arch/powerpc/platforms/pseries/Kconfig | 9 - arch/powerpc/platforms/pseries/Makefile | 1 arch/powerpc/platforms/pseries/processor_idle.c | 360 ----------------------- drivers/cpuidle/Kconfig | 7 drivers/cpuidle/Makefile | 2 drivers/cpuidle/cpuidle-powerpc.c | 361 +++++++++++++++++++++++ 8 files changed, 394 insertions(+), 371 deletions(-) delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c create mode 100644 drivers/cpuidle/cpuidle-powerpc.c diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 77c91e7..7bd83ff 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -175,6 +175,29 @@ extern void setup_paca(struct paca_struct *new_paca); extern void allocate_pacas(void); extern void free_unused_pacas(void); +#ifdef CONFIG_PPC_BOOK3S +#define get_lppaca_is_shared_proc() get_paca()->lppaca_ptr->shared_proc +static inline void set_lppaca_idle(u8 idle) +{ + get_paca()->lppaca_ptr->idle = idle; +} + +static inline void add_lppaca_wait_state(u64 cycles) +{ + get_paca()->lppaca_ptr->wait_state_cycles += cycles; +} + +static inline void set_lppaca_donate_dedicated_cpu(u8 value) +{ + get_paca()->lppaca_ptr->donate_dedicated_cpu = value; +} +#else +#define get_lppaca_is_shared_proc() -1 +static inline void set_lppaca_idle(u8 idle) { } +static inline void add_lppaca_wait_state(u64 cycles) { } +static inline void set_lppaca_donate_dedicated_cpu(u8 value) { } +#endif + #else /* CONFIG_PPC64 */ static inline void allocate_pacas(void) { }; diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index e378ccc..5f57c56 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -430,7 +430,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF}; extern int powersave_nap; /* set if nap mode can be used in idle loop */ extern void power7_nap(void); -#ifdef CONFIG_PSERIES_IDLE +#ifdef CONFIG_CPU_IDLE_POWERPC extern void update_smt_snooze_delay(int cpu, int residency); #else static inline void update_smt_snooze_delay(int cpu, int residency) {} diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 62b4f80..bb59bb0 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -119,12 +119,3 @@ config DTL which are accessible through a debugfs file. Say N if you are unsure. - -config PSERIES_IDLE - bool "Cpuidle driver for pSeries platforms" - depends on CPU_IDLE - depends on PPC_PSERIES - default y - help - Select this option to enable processor idle state management - through cpuidle subsystem. diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 8ae0103..4b22379 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o -obj-$(CONFIG_PSERIES_IDLE) += processor_idle.o ifeq ($(CONFIG_PPC_PSERIES),y) obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c deleted file mode 100644 index c905b99..0000000 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * processor_idle - idle state cpuidle driver. - * Adapted from drivers/idle/intel_idle.c and - * drivers/acpi/processor_idle.c - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/moduleparam.h> -#include <linux/cpuidle.h> -#include <linux/cpu.h> -#include <linux/notifier.h> - -#include <asm/paca.h> -#include <asm/reg.h> -#include <asm/machdep.h> -#include <asm/firmware.h> -#include <asm/runlatch.h> -#include <asm/plpar_wrappers.h> - -struct cpuidle_driver pseries_idle_driver = { - .name = "pseries_idle", - .owner = THIS_MODULE, -}; - -#define MAX_IDLE_STATE_COUNT 2 - -static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; -static struct cpuidle_device __percpu *pseries_cpuidle_devices; -static struct cpuidle_state *cpuidle_state_table; - -static inline void idle_loop_prolog(unsigned long *in_purr) -{ - *in_purr = mfspr(SPRN_PURR); - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - get_lppaca()->idle = 1; -} - -static inline void idle_loop_epilog(unsigned long in_purr) -{ - get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr; - get_lppaca()->idle = 0; -} - -static int snooze_loop(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - unsigned long in_purr; - int cpu = dev->cpu; - - idle_loop_prolog(&in_purr); - local_irq_enable(); - set_thread_flag(TIF_POLLING_NRFLAG); - - while ((!need_resched()) && cpu_online(cpu)) { - ppc64_runlatch_off(); - HMT_low(); - HMT_very_low(); - } - - HMT_medium(); - clear_thread_flag(TIF_POLLING_NRFLAG); - smp_mb(); - - idle_loop_epilog(in_purr); - - return index; -} - -static void check_and_cede_processor(void) -{ - /* - * Ensure our interrupt state is properly tracked, - * also checks if no interrupt has occurred while we - * were soft-disabled - */ - if (prep_irq_for_idle()) { - cede_processor(); -#ifdef CONFIG_TRACE_IRQFLAGS - /* Ensure that H_CEDE returns with IRQs on */ - if (WARN_ON(!(mfmsr() & MSR_EE))) - __hard_irq_enable(); -#endif - } -} - -static int dedicated_cede_loop(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - unsigned long in_purr; - - idle_loop_prolog(&in_purr); - get_lppaca()->donate_dedicated_cpu = 1; - - ppc64_runlatch_off(); - HMT_medium(); - check_and_cede_processor(); - - get_lppaca()->donate_dedicated_cpu = 0; - - idle_loop_epilog(in_purr); - - return index; -} - -static int shared_cede_loop(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - unsigned long in_purr; - - idle_loop_prolog(&in_purr); - - /* - * Yield the processor to the hypervisor. We return if - * an external interrupt occurs (which are driven prior - * to returning here) or if a prod occurs from another - * processor. When returning here, external interrupts - * are enabled. - */ - check_and_cede_processor(); - - idle_loop_epilog(in_purr); - - return index; -} - -/* - * States for dedicated partition case. - */ -static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = { - { /* Snooze */ - .name = "snooze", - .desc = "snooze", - .flags = CPUIDLE_FLAG_TIME_VALID, - .exit_latency = 0, - .target_residency = 0, - .enter = &snooze_loop }, - { /* CEDE */ - .name = "CEDE", - .desc = "CEDE", - .flags = CPUIDLE_FLAG_TIME_VALID, - .exit_latency = 10, - .target_residency = 100, - .enter = &dedicated_cede_loop }, -}; - -/* - * States for shared partition case. - */ -static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { - { /* Shared Cede */ - .name = "Shared Cede", - .desc = "Shared Cede", - .flags = CPUIDLE_FLAG_TIME_VALID, - .exit_latency = 0, - .target_residency = 0, - .enter = &shared_cede_loop }, -}; - -void update_smt_snooze_delay(int cpu, int residency) -{ - struct cpuidle_driver *drv = cpuidle_get_driver(); - struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); - - if (cpuidle_state_table != dedicated_states) - return; - - if (residency < 0) { - /* Disable the Nap state on that cpu */ - if (dev) - dev->states_usage[1].disable = 1; - } else - if (drv) - drv->states[1].target_residency = residency; -} - -static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n, - unsigned long action, void *hcpu) -{ - int hotcpu = (unsigned long)hcpu; - struct cpuidle_device *dev = - per_cpu_ptr(pseries_cpuidle_devices, hotcpu); - - if (dev && cpuidle_get_driver()) { - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - cpuidle_pause_and_lock(); - cpuidle_enable_device(dev); - cpuidle_resume_and_unlock(); - break; - - case CPU_DEAD: - case CPU_DEAD_FROZEN: - cpuidle_pause_and_lock(); - cpuidle_disable_device(dev); - cpuidle_resume_and_unlock(); - break; - - default: - return NOTIFY_DONE; - } - } - return NOTIFY_OK; -} - -static struct notifier_block setup_hotplug_notifier = { - .notifier_call = pseries_cpuidle_add_cpu_notifier, -}; - -/* - * pseries_cpuidle_driver_init() - */ -static int pseries_cpuidle_driver_init(void) -{ - int idle_state; - struct cpuidle_driver *drv = &pseries_idle_driver; - - drv->state_count = 0; - - for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) { - - if (idle_state > max_idle_state) - break; - - /* is the state not enabled? */ - if (cpuidle_state_table[idle_state].enter == NULL) - continue; - - drv->states[drv->state_count] = /* structure copy */ - cpuidle_state_table[idle_state]; - - drv->state_count += 1; - } - - return 0; -} - -/* pseries_idle_devices_uninit(void) - * unregister cpuidle devices and de-allocate memory - */ -static void pseries_idle_devices_uninit(void) -{ - int i; - struct cpuidle_device *dev; - - for_each_possible_cpu(i) { - dev = per_cpu_ptr(pseries_cpuidle_devices, i); - cpuidle_unregister_device(dev); - } - - free_percpu(pseries_cpuidle_devices); - return; -} - -/* pseries_idle_devices_init() - * allocate, initialize and register cpuidle device - */ -static int pseries_idle_devices_init(void) -{ - int i; - struct cpuidle_driver *drv = &pseries_idle_driver; - struct cpuidle_device *dev; - - pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device); - if (pseries_cpuidle_devices == NULL) - return -ENOMEM; - - for_each_possible_cpu(i) { - dev = per_cpu_ptr(pseries_cpuidle_devices, i); - dev->state_count = drv->state_count; - dev->cpu = i; - if (cpuidle_register_device(dev)) { - printk(KERN_DEBUG \ - "cpuidle_register_device %d failed!\n", i); - return -EIO; - } - } - - return 0; -} - -/* - * pseries_idle_probe() - * Choose state table for shared versus dedicated partition - */ -static int pseries_idle_probe(void) -{ - - if (!firmware_has_feature(FW_FEATURE_SPLPAR)) - return -ENODEV; - - if (cpuidle_disable != IDLE_NO_OVERRIDE) - return -ENODEV; - - if (max_idle_state == 0) { - printk(KERN_DEBUG "pseries processor idle disabled.\n"); - return -EPERM; - } - - if (get_lppaca()->shared_proc) - cpuidle_state_table = shared_states; - else - cpuidle_state_table = dedicated_states; - - return 0; -} - -static int __init pseries_processor_idle_init(void) -{ - int retval; - - retval = pseries_idle_probe(); - if (retval) - return retval; - - pseries_cpuidle_driver_init(); - retval = cpuidle_register_driver(&pseries_idle_driver); - if (retval) { - printk(KERN_DEBUG "Registration of pseries driver failed.\n"); - return retval; - } - - retval = pseries_idle_devices_init(); - if (retval) { - pseries_idle_devices_uninit(); - cpuidle_unregister_driver(&pseries_idle_driver); - return retval; - } - - register_cpu_notifier(&setup_hotplug_notifier); - printk(KERN_DEBUG "pseries_idle_driver registered\n"); - - return 0; -} - -static void __exit pseries_processor_idle_exit(void) -{ - - unregister_cpu_notifier(&setup_hotplug_notifier); - pseries_idle_devices_uninit(); - cpuidle_unregister_driver(&pseries_idle_driver); - - return; -} - -module_init(pseries_processor_idle_init); -module_exit(pseries_processor_idle_exit); - -MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>"); -MODULE_DESCRIPTION("Cpuidle driver for POWER"); -MODULE_LICENSE("GPL"); diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 0e2cd5c..99ee5d4 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ help Select this to enable cpuidle on Xilinx Zynq processors. +config CPU_IDLE_POWERPC + bool "CPU Idle driver for POWERPC platforms" + depends on PPC64 + default y + help + Select this option to enable processor idle state management + for POWERPC platform. endif config ARCH_NEEDS_CPU_IDLE_COUPLED diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 8767a7b..d12e205 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -8,3 +8,5 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o + +obj-$(CONFIG_CPU_IDLE_POWERPC) += cpuidle-powerpc.o diff --git a/drivers/cpuidle/cpuidle-powerpc.c b/drivers/cpuidle/cpuidle-powerpc.c new file mode 100644 index 0000000..5756085 --- /dev/null +++ b/drivers/cpuidle/cpuidle-powerpc.c @@ -0,0 +1,361 @@ +/* + * processor_idle - idle state cpuidle driver. + * Adapted from drivers/idle/intel_idle.c and + * drivers/acpi/processor_idle.c + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/cpuidle.h> +#include <linux/cpu.h> +#include <linux/notifier.h> + +#include <asm/paca.h> +#include <asm/reg.h> +#include <asm/machdep.h> +#include <asm/firmware.h> +#include <asm/runlatch.h> +#include <asm/plpar_wrappers.h> + +struct cpuidle_driver powerpc_idle_driver = { + .name = "powerpc_idle", + .owner = THIS_MODULE, +}; + +#define MAX_IDLE_STATE_COUNT 2 + +static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; +static struct cpuidle_device __percpu *powerpc_cpuidle_devices; +static struct cpuidle_state *cpuidle_state_table; + +static inline void idle_loop_prolog(unsigned long *in_purr) +{ + *in_purr = mfspr(SPRN_PURR); + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ + set_lppaca_idle(1); +} + +static inline void idle_loop_epilog(unsigned long in_purr) +{ + add_lppaca_wait_state(mfspr(SPRN_PURR) - in_purr); + set_lppaca_idle(0); +} + +static int snooze_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long in_purr; + + idle_loop_prolog(&in_purr); + 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(); + + idle_loop_epilog(in_purr); + + return index; +} + +static void check_and_cede_processor(void) +{ + /* + * Ensure our interrupt state is properly tracked, + * also checks if no interrupt has occurred while we + * were soft-disabled + */ + if (prep_irq_for_idle()) { + cede_processor(); +#ifdef CONFIG_TRACE_IRQFLAGS + /* Ensure that H_CEDE returns with IRQs on */ + if (WARN_ON(!(mfmsr() & MSR_EE))) + __hard_irq_enable(); +#endif + } +} + +static int dedicated_cede_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long in_purr; + + idle_loop_prolog(&in_purr); + set_lppaca_donate_dedicated_cpu(1); + + ppc64_runlatch_off(); + HMT_medium(); + check_and_cede_processor(); + + set_lppaca_donate_dedicated_cpu(0); + idle_loop_epilog(in_purr); + + return index; +} + +static int shared_cede_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long in_purr; + + idle_loop_prolog(&in_purr); + + /* + * Yield the processor to the hypervisor. We return if + * an external interrupt occurs (which are driven prior + * to returning here) or if a prod occurs from another + * processor. When returning here, external interrupts + * are enabled. + */ + check_and_cede_processor(); + + idle_loop_epilog(in_purr); + + return index; +} + +/* + * States for dedicated partition case. + */ +static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = { + { /* Snooze */ + .name = "snooze", + .desc = "snooze", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 0, + .target_residency = 0, + .enter = &snooze_loop }, + { /* CEDE */ + .name = "CEDE", + .desc = "CEDE", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 10, + .target_residency = 100, + .enter = &dedicated_cede_loop }, +}; + +/* + * States for shared partition case. + */ +static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { + { /* Shared Cede */ + .name = "Shared Cede", + .desc = "Shared Cede", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 0, + .target_residency = 0, + .enter = &shared_cede_loop }, +}; + +void update_smt_snooze_delay(int cpu, int residency) +{ + struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); + + if (cpuidle_state_table != dedicated_states) + return; + + if (residency < 0) { + /* Disable the Nap state on that cpu */ + if (dev) + dev->states_usage[1].disable = 1; + } else + if (drv) + drv->states[1].target_residency = residency; +} + +static int powerpc_cpuidle_add_cpu_notifier(struct notifier_block *n, + unsigned long action, void *hcpu) +{ + int hotcpu = (unsigned long)hcpu; + struct cpuidle_device *dev = + per_cpu_ptr(powerpc_cpuidle_devices, hotcpu); + + if (dev && cpuidle_get_driver()) { + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + cpuidle_pause_and_lock(); + cpuidle_enable_device(dev); + cpuidle_resume_and_unlock(); + break; + + case CPU_DEAD: + case CPU_DEAD_FROZEN: + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + cpuidle_resume_and_unlock(); + break; + + default: + return NOTIFY_DONE; + } + } + return NOTIFY_OK; +} + +static struct notifier_block setup_hotplug_notifier = { + .notifier_call = powerpc_cpuidle_add_cpu_notifier, +}; + +/* + * powerpc_cpuidle_driver_init() + */ +static int powerpc_cpuidle_driver_init(void) +{ + int idle_state; + struct cpuidle_driver *drv = &powerpc_idle_driver; + + drv->state_count = 0; + + for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) { + + if (idle_state > max_idle_state) + break; + + /* is the state not enabled? */ + if (cpuidle_state_table[idle_state].enter == NULL) + continue; + + drv->states[drv->state_count] = /* structure copy */ + cpuidle_state_table[idle_state]; + + drv->state_count += 1; + } + + return 0; +} + +/* powerpc_idle_devices_uninit(void) + * unregister cpuidle devices and de-allocate memory + */ +static void powerpc_idle_devices_uninit(void) +{ + int i; + struct cpuidle_device *dev; + + for_each_possible_cpu(i) { + dev = per_cpu_ptr(powerpc_cpuidle_devices, i); + cpuidle_unregister_device(dev); + } + + free_percpu(powerpc_cpuidle_devices); + return; +} + +/* powerpc_idle_devices_init() + * allocate, initialize and register cpuidle device + */ +static int powerpc_idle_devices_init(void) +{ + int i; + struct cpuidle_driver *drv = &powerpc_idle_driver; + struct cpuidle_device *dev; + + powerpc_cpuidle_devices = alloc_percpu(struct cpuidle_device); + if (powerpc_cpuidle_devices == NULL) + return -ENOMEM; + + for_each_possible_cpu(i) { + dev = per_cpu_ptr(powerpc_cpuidle_devices, i); + dev->state_count = drv->state_count; + dev->cpu = i; + if (cpuidle_register_device(dev)) { + printk(KERN_DEBUG \ + "cpuidle_register_device %d failed!\n", i); + return -EIO; + } + } + + return 0; +} + +/* + * powerpc_idle_probe() + * Choose state table for shared versus dedicated partition + */ +static int powerpc_idle_probe(void) +{ + + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) + return -ENODEV; + + if (cpuidle_disable != IDLE_NO_OVERRIDE) + return -ENODEV; + + if (max_idle_state == 0) { + printk(KERN_DEBUG "powerpc processor idle disabled.\n"); + return -EPERM; + } + + if (firmware_has_feature(FW_FEATURE_SPLPAR)) { + if (get_lppaca_is_shared_proc() == 1) + cpuidle_state_table = shared_states; + else if (get_lppaca_is_shared_proc() == 0) + cpuidle_state_table = dedicated_states; + } else + return -ENODEV; + + return 0; +} + +static int __init powerpc_processor_idle_init(void) +{ + int retval; + + retval = powerpc_idle_probe(); + if (retval) + return retval; + + powerpc_cpuidle_driver_init(); + retval = cpuidle_register_driver(&powerpc_idle_driver); + if (retval) { + printk(KERN_DEBUG "Registration of powerpc driver failed.\n"); + return retval; + } + + retval = powerpc_idle_devices_init(); + if (retval) { + powerpc_idle_devices_uninit(); + cpuidle_unregister_driver(&powerpc_idle_driver); + return retval; + } + + register_cpu_notifier(&setup_hotplug_notifier); + printk(KERN_DEBUG "powerpc_idle_driver registered\n"); + + return 0; +} + +static void __exit powerpc_processor_idle_exit(void) +{ + + unregister_cpu_notifier(&setup_hotplug_notifier); + powerpc_idle_devices_uninit(); + cpuidle_unregister_driver(&powerpc_idle_driver); + + return; +} + +module_init(powerpc_processor_idle_init); +module_exit(powerpc_processor_idle_exit); + +MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>"); +MODULE_DESCRIPTION("Cpuidle driver for powerpc"); +MODULE_LICENSE("GPL"); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* RE: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-19 4:28 ` [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver Deepthi Dharwar @ 2013-08-19 5:52 ` Wang Dongsheng-B40534 2013-08-19 10:18 ` Deepthi Dharwar 0 siblings, 1 reply; 16+ messages in thread From: Wang Dongsheng-B40534 @ 2013-08-19 5:52 UTC (permalink / raw) To: Deepthi Dharwar, benh@kernel.crashing.org, daniel.lezcano@linaro.org, kernel@vger.kernel.org, Wood Scott-B07421, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org Cc: preeti@linux.vnet.ibm.com SSB0aGluayB3ZSBzaG91bGQgbW92ZSB0aGUgc3RhdGVzIGFuZCBoYW5kbGUgZnVuY3Rpb24gdG8g YXJjaC9wb3dlci9wbGF0Zm9ybSoNClRoZSBzdGF0ZXMgYW5kIGhhbmRsZSBmdW5jdGlvbiBpcyBi ZWxvbmcgdG8gYmFja2VuZCBkcml2ZXIsIG5vdCBmb3IgdGhpcywgZGlmZmVyZW50IHBsYXRmb3Jt IGhhdmUgZGlmZmVyZW50IHN0YXRlLg0KRGlmZmVyZW50IHBsYXRmb3JtcyB0byBtYWtlIHRoZWly IG93biBkZWFsIHdpdGggdGhlc2Ugc3RhdGVzLg0KDQpJIHRoaW5rIHdlIGNhbm5vdCBwdXQgYWxs IHRoZSBzdGF0dXMgb2YgZGlmZmVyZW50IHBsYXRmb3JtcyBhbmQgaGFuZGxlciBpbiB0aGlzIGRy aXZlci4NCg0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9jcHVpZGxlL0tjb25maWcgYi9kcml2ZXJz L2NwdWlkbGUvS2NvbmZpZw0KPiBpbmRleCAwZTJjZDVjLi45OWVlNWQ0IDEwMDY0NA0KPiAtLS0g YS9kcml2ZXJzL2NwdWlkbGUvS2NvbmZpZw0KPiArKysgYi9kcml2ZXJzL2NwdWlkbGUvS2NvbmZp Zw0KPiBAQCAtNDIsNiArNDIsMTMgQEAgY29uZmlnIENQVV9JRExFX1pZTlENCj4gIAloZWxwDQo+ ICAJICBTZWxlY3QgdGhpcyB0byBlbmFibGUgY3B1aWRsZSBvbiBYaWxpbnggWnlucSBwcm9jZXNz b3JzLg0KPiANCj4gK2NvbmZpZyBDUFVfSURMRV9QT1dFUlBDDQo+ICsJYm9vbCAiQ1BVIElkbGUg ZHJpdmVyIGZvciBQT1dFUlBDIHBsYXRmb3JtcyINCj4gKwlkZXBlbmRzIG9uIFBQQzY0DQoNCldo eSBub3QgUFBDPw0KDQoNCj4gKwlkZWZhdWx0IHkNCj4gKyAgICAgICAgaGVscA0KPiArICAgICAg ICAgIFNlbGVjdCB0aGlzIG9wdGlvbiB0byBlbmFibGUgcHJvY2Vzc29yIGlkbGUgc3RhdGUgbWFu YWdlbWVudA0KPiArCSAgZm9yIFBPV0VSUEMgcGxhdGZvcm0uDQo+ICBlbmRpZg0KPiANCj4gIGNv bmZpZyBBUkNIX05FRURTX0NQVV9JRExFX0NPVVBMRUQNCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMv Y3B1aWRsZS9NYWtlZmlsZSBiL2RyaXZlcnMvY3B1aWRsZS9NYWtlZmlsZQ0KPiBpbmRleCA4NzY3 YTdiLi5kMTJlMjA1IDEwMDY0NA0KPiAtLS0gYS9kcml2ZXJzL2NwdWlkbGUvTWFrZWZpbGUNCj4g KysrIGIvZHJpdmVycy9jcHVpZGxlL01ha2VmaWxlDQo+IEBAIC04LDMgKzgsNSBAQCBvYmotJChD T05GSUdfQVJDSF9ORUVEU19DUFVfSURMRV9DT1VQTEVEKSArPSBjb3VwbGVkLm8NCj4gIG9iai0k KENPTkZJR19DUFVfSURMRV9DQUxYRURBKSArPSBjcHVpZGxlLWNhbHhlZGEubw0KPiAgb2JqLSQo Q09ORklHX0FSQ0hfS0lSS1dPT0QpICs9IGNwdWlkbGUta2lya3dvb2Qubw0KPiAgb2JqLSQoQ09O RklHX0NQVV9JRExFX1pZTlEpICs9IGNwdWlkbGUtenlucS5vDQo+ICsNCj4gK29iai0kKENPTkZJ R19DUFVfSURMRV9QT1dFUlBDKSArPSBjcHVpZGxlLXBvd2VycGMubw0KPiBkaWZmIC0tZ2l0IGEv ZHJpdmVycy9jcHVpZGxlL2NwdWlkbGUtcG93ZXJwYy5jIGIvZHJpdmVycy9jcHVpZGxlL2NwdWlk bGUtDQo+IHBvd2VycGMuYw0KPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiBpbmRleCAwMDAwMDAw Li41NzU2MDg1DQo+IC0tLSAvZGV2L251bGwNCj4gKysrIGIvZHJpdmVycy9jcHVpZGxlL2NwdWlk bGUtcG93ZXJwYy5jDQo+IEBAIC0wLDAgKzEsMzYxIEBADQo+ICsvKg0KPiArICogIHByb2Nlc3Nv cl9pZGxlIC0gaWRsZSBzdGF0ZSBjcHVpZGxlIGRyaXZlci4NCj4gKyAqICBBZGFwdGVkIGZyb20g ZHJpdmVycy9pZGxlL2ludGVsX2lkbGUuYyBhbmQNCj4gKyAqICBkcml2ZXJzL2FjcGkvcHJvY2Vz c29yX2lkbGUuYw0KPiArICoNCj4gKyAqLw0KPiArDQo+ICsjaW5jbHVkZSA8bGludXgva2VybmVs Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvaW5p dC5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZXBhcmFtLmg+DQo+ICsjaW5jbHVkZSA8bGlu dXgvY3B1aWRsZS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2NwdS5oPg0KPiArI2luY2x1ZGUgPGxp bnV4L25vdGlmaWVyLmg+DQo+ICsNCj4gKyNpbmNsdWRlIDxhc20vcGFjYS5oPg0KPiArI2luY2x1 ZGUgPGFzbS9yZWcuaD4NCj4gKyNpbmNsdWRlIDxhc20vbWFjaGRlcC5oPg0KPiArI2luY2x1ZGUg PGFzbS9maXJtd2FyZS5oPg0KPiArI2luY2x1ZGUgPGFzbS9ydW5sYXRjaC5oPg0KPiArI2luY2x1 ZGUgPGFzbS9wbHBhcl93cmFwcGVycy5oPg0KPiArDQo+ICtzdHJ1Y3QgY3B1aWRsZV9kcml2ZXIg cG93ZXJwY19pZGxlX2RyaXZlciA9IHsNCj4gKwkubmFtZSAgICAgICAgICAgICA9ICJwb3dlcnBj X2lkbGUiLA0KPiArCS5vd25lciAgICAgICAgICAgID0gVEhJU19NT0RVTEUsDQo+ICt9Ow0KPiAr DQo+ICsjZGVmaW5lIE1BWF9JRExFX1NUQVRFX0NPVU5UCTINCj4gKw0KPiArc3RhdGljIGludCBt YXhfaWRsZV9zdGF0ZSA9IE1BWF9JRExFX1NUQVRFX0NPVU5UIC0gMTsNCklmIHRoaXMgaXMgYSBn ZW5lcmljIGRyaXZlciwgZG8gbm90IGRlZmluZSBNQVhfSURMRV9TVEFURV9DT1VOVCwgYmVjYXVz ZSB3ZSBkb24ndCBrbm93IGhvdyBtYW55IHN0YXRlIG9uIG90aGVyIHBsYXRmb3Jtcy4NCg0KSG93 IGFib3V0IHVzaW5nIEFSUkFZX1NJWkUgdG8gZ2V0IHRoZSBtYXggaWRsZSBzdGF0ZT8NCg0KPiAr c3RhdGljIHN0cnVjdCBjcHVpZGxlX2RldmljZSBfX3BlcmNwdSAqcG93ZXJwY19jcHVpZGxlX2Rl dmljZXM7DQo+ICtzdGF0aWMgc3RydWN0IGNwdWlkbGVfc3RhdGUgKmNwdWlkbGVfc3RhdGVfdGFi bGU7DQo+ICsNClNob3VsZCBiZSByZW1vdmUgYWxsIGFib3V0ICpkZXZpY2UqLg0KSWYgdGhlIG5v dGlmaWVyIGhhbmRsZSB1c2luZyBkZXZpY2UsIHlvdSBjYW4gdXNlICJjcHVpZGxlX2RldmljZXMi KGluY2x1ZGUvbGludXgvY3B1aWRsZS5oKS4NCg0KPiArc3RhdGljIGlubGluZSB2b2lkIGlkbGVf bG9vcF9wcm9sb2codW5zaWduZWQgbG9uZyAqaW5fcHVycikNCj4gK3sNCj4gKwkqaW5fcHVyciA9 IG1mc3ByKFNQUk5fUFVSUik7DQo+ICsJLyoNCj4gKwkgKiBJbmRpY2F0ZSB0byB0aGUgSFYgdGhh dCB3ZSBhcmUgaWRsZS4gTm93IHdvdWxkIGJlDQo+ICsJICogYSBnb29kIHRpbWUgdG8gZmluZCBv dGhlciB3b3JrIHRvIGRpc3BhdGNoLg0KPiArCSAqLw0KPiArCXNldF9scHBhY2FfaWRsZSgxKTsN Cj4gK30NCj4gKw0KPiArc3RhdGljIGlubGluZSB2b2lkIGlkbGVfbG9vcF9lcGlsb2codW5zaWdu ZWQgbG9uZyBpbl9wdXJyKQ0KPiArew0KPiArCWFkZF9scHBhY2Ffd2FpdF9zdGF0ZShtZnNwcihT UFJOX1BVUlIpIC0gaW5fcHVycik7DQo+ICsJc2V0X2xwcGFjYV9pZGxlKDApOw0KPiArfQ0KPiAr DQo+ICtzdGF0aWMgaW50IHNub296ZV9sb29wKHN0cnVjdCBjcHVpZGxlX2RldmljZSAqZGV2LA0K PiArCQkJc3RydWN0IGNwdWlkbGVfZHJpdmVyICpkcnYsDQo+ICsJCQlpbnQgaW5kZXgpDQo+ICt7 DQo+ICsJdW5zaWduZWQgbG9uZyBpbl9wdXJyOw0KPiArDQo+ICsJaWRsZV9sb29wX3Byb2xvZygm aW5fcHVycik7DQo+ICsJbG9jYWxfaXJxX2VuYWJsZSgpOw0KPiArCXNldF90aHJlYWRfZmxhZyhU SUZfUE9MTElOR19OUkZMQUcpOw0KPiArDQo+ICsJd2hpbGUgKCFuZWVkX3Jlc2NoZWQoKSkgew0K PiArCQlwcGM2NF9ydW5sYXRjaF9vZmYoKTsNCj4gKwkJSE1UX2xvdygpOw0KPiArCQlITVRfdmVy eV9sb3coKTsNCj4gKwl9DQo+ICsNCj4gKwlITVRfbWVkaXVtKCk7DQo+ICsJY2xlYXJfdGhyZWFk X2ZsYWcoVElGX1BPTExJTkdfTlJGTEFHKTsNCj4gKwlzbXBfbWIoKTsNCj4gKw0KPiArCWlkbGVf bG9vcF9lcGlsb2coaW5fcHVycik7DQo+ICsNCj4gKwlyZXR1cm4gaW5kZXg7DQo+ICt9DQo+ICsN Cj4gK3N0YXRpYyB2b2lkIGNoZWNrX2FuZF9jZWRlX3Byb2Nlc3Nvcih2b2lkKQ0KPiArew0KPiAr CS8qDQo+ICsJICogRW5zdXJlIG91ciBpbnRlcnJ1cHQgc3RhdGUgaXMgcHJvcGVybHkgdHJhY2tl ZCwNCj4gKwkgKiBhbHNvIGNoZWNrcyBpZiBubyBpbnRlcnJ1cHQgaGFzIG9jY3VycmVkIHdoaWxl IHdlDQo+ICsJICogd2VyZSBzb2Z0LWRpc2FibGVkDQo+ICsJICovDQo+ICsJaWYgKHByZXBfaXJx X2Zvcl9pZGxlKCkpIHsNCj4gKwkJY2VkZV9wcm9jZXNzb3IoKTsNCj4gKyNpZmRlZiBDT05GSUdf VFJBQ0VfSVJRRkxBR1MNCj4gKwkJLyogRW5zdXJlIHRoYXQgSF9DRURFIHJldHVybnMgd2l0aCBJ UlFzIG9uICovDQo+ICsJCWlmIChXQVJOX09OKCEobWZtc3IoKSAmIE1TUl9FRSkpKQ0KPiArCQkJ X19oYXJkX2lycV9lbmFibGUoKTsNCj4gKyNlbmRpZg0KPiArCX0NCj4gK30NCj4gKw0KPiArc3Rh dGljIGludCBkZWRpY2F0ZWRfY2VkZV9sb29wKHN0cnVjdCBjcHVpZGxlX2RldmljZSAqZGV2LA0K PiArCQkJCXN0cnVjdCBjcHVpZGxlX2RyaXZlciAqZHJ2LA0KPiArCQkJCWludCBpbmRleCkNCj4g K3sNCj4gKwl1bnNpZ25lZCBsb25nIGluX3B1cnI7DQo+ICsNCj4gKwlpZGxlX2xvb3BfcHJvbG9n KCZpbl9wdXJyKTsNCj4gKwlzZXRfbHBwYWNhX2RvbmF0ZV9kZWRpY2F0ZWRfY3B1KDEpOw0KPiAr DQo+ICsJcHBjNjRfcnVubGF0Y2hfb2ZmKCk7DQo+ICsJSE1UX21lZGl1bSgpOw0KPiArCWNoZWNr X2FuZF9jZWRlX3Byb2Nlc3NvcigpOw0KPiArDQo+ICsJc2V0X2xwcGFjYV9kb25hdGVfZGVkaWNh dGVkX2NwdSgwKTsNCj4gKwlpZGxlX2xvb3BfZXBpbG9nKGluX3B1cnIpOw0KPiArDQo+ICsJcmV0 dXJuIGluZGV4Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IHNoYXJlZF9jZWRlX2xvb3Aoc3Ry dWN0IGNwdWlkbGVfZGV2aWNlICpkZXYsDQo+ICsJCQlzdHJ1Y3QgY3B1aWRsZV9kcml2ZXIgKmRy diwNCj4gKwkJCWludCBpbmRleCkNCj4gK3sNCj4gKwl1bnNpZ25lZCBsb25nIGluX3B1cnI7DQo+ ICsNCj4gKwlpZGxlX2xvb3BfcHJvbG9nKCZpbl9wdXJyKTsNCj4gKw0KPiArCS8qDQo+ICsJICog WWllbGQgdGhlIHByb2Nlc3NvciB0byB0aGUgaHlwZXJ2aXNvci4gIFdlIHJldHVybiBpZg0KPiAr CSAqIGFuIGV4dGVybmFsIGludGVycnVwdCBvY2N1cnMgKHdoaWNoIGFyZSBkcml2ZW4gcHJpb3IN Cj4gKwkgKiB0byByZXR1cm5pbmcgaGVyZSkgb3IgaWYgYSBwcm9kIG9jY3VycyBmcm9tIGFub3Ro ZXINCj4gKwkgKiBwcm9jZXNzb3IuIFdoZW4gcmV0dXJuaW5nIGhlcmUsIGV4dGVybmFsIGludGVy cnVwdHMNCj4gKwkgKiBhcmUgZW5hYmxlZC4NCj4gKwkgKi8NCj4gKwljaGVja19hbmRfY2VkZV9w cm9jZXNzb3IoKTsNCj4gKw0KPiArCWlkbGVfbG9vcF9lcGlsb2coaW5fcHVycik7DQo+ICsNCj4g KwlyZXR1cm4gaW5kZXg7DQo+ICt9DQo+ICsNCj4gKy8qDQo+ICsgKiBTdGF0ZXMgZm9yIGRlZGlj YXRlZCBwYXJ0aXRpb24gY2FzZS4NCj4gKyAqLw0KPiArc3RhdGljIHN0cnVjdCBjcHVpZGxlX3N0 YXRlIGRlZGljYXRlZF9zdGF0ZXNbTUFYX0lETEVfU1RBVEVfQ09VTlRdID0gew0KPiArCXsgLyog U25vb3plICovDQo+ICsJCS5uYW1lID0gInNub296ZSIsDQo+ICsJCS5kZXNjID0gInNub296ZSIs DQo+ICsJCS5mbGFncyA9IENQVUlETEVfRkxBR19USU1FX1ZBTElELA0KPiArCQkuZXhpdF9sYXRl bmN5ID0gMCwNCj4gKwkJLnRhcmdldF9yZXNpZGVuY3kgPSAwLA0KPiArCQkuZW50ZXIgPSAmc25v b3plX2xvb3AgfSwNCj4gKwl7IC8qIENFREUgKi8NCj4gKwkJLm5hbWUgPSAiQ0VERSIsDQo+ICsJ CS5kZXNjID0gIkNFREUiLA0KPiArCQkuZmxhZ3MgPSBDUFVJRExFX0ZMQUdfVElNRV9WQUxJRCwN Cj4gKwkJLmV4aXRfbGF0ZW5jeSA9IDEwLA0KPiArCQkudGFyZ2V0X3Jlc2lkZW5jeSA9IDEwMCwN Cj4gKwkJLmVudGVyID0gJmRlZGljYXRlZF9jZWRlX2xvb3AgfSwNCj4gK307DQo+ICsNCj4gKy8q DQo+ICsgKiBTdGF0ZXMgZm9yIHNoYXJlZCBwYXJ0aXRpb24gY2FzZS4NCj4gKyAqLw0KPiArc3Rh dGljIHN0cnVjdCBjcHVpZGxlX3N0YXRlIHNoYXJlZF9zdGF0ZXNbTUFYX0lETEVfU1RBVEVfQ09V TlRdID0gew0KPiArCXsgLyogU2hhcmVkIENlZGUgKi8NCj4gKwkJLm5hbWUgPSAiU2hhcmVkIENl ZGUiLA0KPiArCQkuZGVzYyA9ICJTaGFyZWQgQ2VkZSIsDQo+ICsJCS5mbGFncyA9IENQVUlETEVf RkxBR19USU1FX1ZBTElELA0KPiArCQkuZXhpdF9sYXRlbmN5ID0gMCwNCj4gKwkJLnRhcmdldF9y ZXNpZGVuY3kgPSAwLA0KPiArCQkuZW50ZXIgPSAmc2hhcmVkX2NlZGVfbG9vcCB9LA0KPiArfTsN Cj4gKw0KPiArdm9pZCB1cGRhdGVfc210X3Nub296ZV9kZWxheShpbnQgY3B1LCBpbnQgcmVzaWRl bmN5KQ0KPiArew0KPiArCXN0cnVjdCBjcHVpZGxlX2RyaXZlciAqZHJ2ID0gY3B1aWRsZV9nZXRf ZHJpdmVyKCk7DQo+ICsJc3RydWN0IGNwdWlkbGVfZGV2aWNlICpkZXYgPSBwZXJfY3B1KGNwdWlk bGVfZGV2aWNlcywgY3B1KTsNCj4gKw0KPiArCWlmIChjcHVpZGxlX3N0YXRlX3RhYmxlICE9IGRl ZGljYXRlZF9zdGF0ZXMpDQo+ICsJCXJldHVybjsNCj4gKw0KPiArCWlmIChyZXNpZGVuY3kgPCAw KSB7DQo+ICsJCS8qIERpc2FibGUgdGhlIE5hcCBzdGF0ZSBvbiB0aGF0IGNwdSAqLw0KPiArCQlp ZiAoZGV2KQ0KPiArCQkJZGV2LT5zdGF0ZXNfdXNhZ2VbMV0uZGlzYWJsZSA9IDE7DQo+ICsJfSBl bHNlDQo+ICsJCWlmIChkcnYpDQo+ICsJCQlkcnYtPnN0YXRlc1sxXS50YXJnZXRfcmVzaWRlbmN5 ID0gcmVzaWRlbmN5Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IHBvd2VycGNfY3B1aWRsZV9h ZGRfY3B1X25vdGlmaWVyKHN0cnVjdCBub3RpZmllcl9ibG9jayAqbiwNCj4gKwkJCXVuc2lnbmVk IGxvbmcgYWN0aW9uLCB2b2lkICpoY3B1KQ0KPiArew0KPiArCWludCBob3RjcHUgPSAodW5zaWdu ZWQgbG9uZyloY3B1Ow0KPiArCXN0cnVjdCBjcHVpZGxlX2RldmljZSAqZGV2ID0NCj4gKwkJCXBl cl9jcHVfcHRyKHBvd2VycGNfY3B1aWRsZV9kZXZpY2VzLCBob3RjcHUpOw0KPiArDQo+ICsJaWYg KGRldiAmJiBjcHVpZGxlX2dldF9kcml2ZXIoKSkgew0KPiArCQlzd2l0Y2ggKGFjdGlvbikgew0K PiArCQljYXNlIENQVV9PTkxJTkU6DQo+ICsJCWNhc2UgQ1BVX09OTElORV9GUk9aRU46DQo+ICsJ CQljcHVpZGxlX3BhdXNlX2FuZF9sb2NrKCk7DQo+ICsJCQljcHVpZGxlX2VuYWJsZV9kZXZpY2Uo ZGV2KTsNCj4gKwkJCWNwdWlkbGVfcmVzdW1lX2FuZF91bmxvY2soKTsNCj4gKwkJCWJyZWFrOw0K PiArDQo+ICsJCWNhc2UgQ1BVX0RFQUQ6DQo+ICsJCWNhc2UgQ1BVX0RFQURfRlJPWkVOOg0KPiAr CQkJY3B1aWRsZV9wYXVzZV9hbmRfbG9jaygpOw0KPiArCQkJY3B1aWRsZV9kaXNhYmxlX2Rldmlj ZShkZXYpOw0KPiArCQkJY3B1aWRsZV9yZXN1bWVfYW5kX3VubG9jaygpOw0KPiArCQkJYnJlYWs7 DQo+ICsNCj4gKwkJZGVmYXVsdDoNCj4gKwkJCXJldHVybiBOT1RJRllfRE9ORTsNCj4gKwkJfQ0K PiArCX0NCj4gKwlyZXR1cm4gTk9USUZZX09LOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgc3RydWN0 IG5vdGlmaWVyX2Jsb2NrIHNldHVwX2hvdHBsdWdfbm90aWZpZXIgPSB7DQo+ICsJLm5vdGlmaWVy X2NhbGwgPSBwb3dlcnBjX2NwdWlkbGVfYWRkX2NwdV9ub3RpZmllciwNCj4gK307DQo+ICsNCldl IHNob3VsZCBkaXNjdXNzIHRoaXMgd2l0aCBEYW5pZWwuDQoNCj4gKy8qDQo+ICsgKiBwb3dlcnBj X2NwdWlkbGVfZHJpdmVyX2luaXQoKQ0KPiArICovDQo+ICtzdGF0aWMgaW50IHBvd2VycGNfY3B1 aWRsZV9kcml2ZXJfaW5pdCh2b2lkKQ0KPiArew0KPiArCWludCBpZGxlX3N0YXRlOw0KPiArCXN0 cnVjdCBjcHVpZGxlX2RyaXZlciAqZHJ2ID0gJnBvd2VycGNfaWRsZV9kcml2ZXI7DQo+ICsNCj4g KwlkcnYtPnN0YXRlX2NvdW50ID0gMDsNCj4gKw0KPiArCWZvciAoaWRsZV9zdGF0ZSA9IDA7IGlk bGVfc3RhdGUgPCBNQVhfSURMRV9TVEFURV9DT1VOVDsNCj4gKytpZGxlX3N0YXRlKSB7DQo+ICsN Cj4gKwkJaWYgKGlkbGVfc3RhdGUgPiBtYXhfaWRsZV9zdGF0ZSkNCj4gKwkJCWJyZWFrOw0KPiAr DQo+ICsJCS8qIGlzIHRoZSBzdGF0ZSBub3QgZW5hYmxlZD8gKi8NCj4gKwkJaWYgKGNwdWlkbGVf c3RhdGVfdGFibGVbaWRsZV9zdGF0ZV0uZW50ZXIgPT0gTlVMTCkNCj4gKwkJCWNvbnRpbnVlOw0K PiArDQpEaWQgdGhlIHN0YXRlIGhhdmUgZGVwZW5kZW50Pw0KSWYgeWVzLCBtYXkgYmUgc2hvdWxk IGJyZWFrIG91dCB0aGUgbG9vcCwgbm90IGNvbnRpbnVlLg0KDQo+ICsJCWRydi0+c3RhdGVzW2Ry di0+c3RhdGVfY291bnRdID0JLyogc3RydWN0dXJlIGNvcHkgKi8NCj4gKwkJCWNwdWlkbGVfc3Rh dGVfdGFibGVbaWRsZV9zdGF0ZV07DQo+ICsNCj4gKwkJZHJ2LT5zdGF0ZV9jb3VudCArPSAxOw0K PiArCX0NCj4gKw0KPiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICsvKiBwb3dlcnBjX2lkbGVf ZGV2aWNlc191bmluaXQodm9pZCkNCj4gKyAqIHVucmVnaXN0ZXIgY3B1aWRsZSBkZXZpY2VzIGFu ZCBkZS1hbGxvY2F0ZSBtZW1vcnkNCj4gKyAqLw0KPiArc3RhdGljIHZvaWQgcG93ZXJwY19pZGxl X2RldmljZXNfdW5pbml0KHZvaWQpDQo+ICt7DQo+ICsJaW50IGk7DQo+ICsJc3RydWN0IGNwdWlk bGVfZGV2aWNlICpkZXY7DQo+ICsNCj4gKwlmb3JfZWFjaF9wb3NzaWJsZV9jcHUoaSkgew0KPiAr CQlkZXYgPSBwZXJfY3B1X3B0cihwb3dlcnBjX2NwdWlkbGVfZGV2aWNlcywgaSk7DQo+ICsJCWNw dWlkbGVfdW5yZWdpc3Rlcl9kZXZpY2UoZGV2KTsNCj4gKwl9DQo+ICsNCj4gKwlmcmVlX3BlcmNw dShwb3dlcnBjX2NwdWlkbGVfZGV2aWNlcyk7DQo+ICsJcmV0dXJuOw0KPiArfQ0KPiArDQo+ICsv KiBwb3dlcnBjX2lkbGVfZGV2aWNlc19pbml0KCkNCj4gKyAqIGFsbG9jYXRlLCBpbml0aWFsaXpl IGFuZCByZWdpc3RlciBjcHVpZGxlIGRldmljZQ0KPiArICovDQo+ICtzdGF0aWMgaW50IHBvd2Vy cGNfaWRsZV9kZXZpY2VzX2luaXQodm9pZCkNCj4gK3sNCj4gKwlpbnQgaTsNCj4gKwlzdHJ1Y3Qg Y3B1aWRsZV9kcml2ZXIgKmRydiA9ICZwb3dlcnBjX2lkbGVfZHJpdmVyOw0KPiArCXN0cnVjdCBj cHVpZGxlX2RldmljZSAqZGV2Ow0KPiArDQo+ICsJcG93ZXJwY19jcHVpZGxlX2RldmljZXMgPSBh bGxvY19wZXJjcHUoc3RydWN0IGNwdWlkbGVfZGV2aWNlKTsNCj4gKwlpZiAocG93ZXJwY19jcHVp ZGxlX2RldmljZXMgPT0gTlVMTCkNCj4gKwkJcmV0dXJuIC1FTk9NRU07DQo+ICsNCj4gKwlmb3Jf ZWFjaF9wb3NzaWJsZV9jcHUoaSkgew0KPiArCQlkZXYgPSBwZXJfY3B1X3B0cihwb3dlcnBjX2Nw dWlkbGVfZGV2aWNlcywgaSk7DQo+ICsJCWRldi0+c3RhdGVfY291bnQgPSBkcnYtPnN0YXRlX2Nv dW50Ow0KPiArCQlkZXYtPmNwdSA9IGk7DQo+ICsJCWlmIChjcHVpZGxlX3JlZ2lzdGVyX2Rldmlj ZShkZXYpKSB7DQoNClBsZWFzZSB1c2UgY3B1aWRsZV9yZWdpc3RlcigpLg0KDQo+ICsJCQlwcmlu dGsoS0VSTl9ERUJVRyBcDQo+ICsJCQkJImNwdWlkbGVfcmVnaXN0ZXJfZGV2aWNlICVkIGZhaWxl ZCFcbiIsIGkpOw0KPiArCQkJcmV0dXJuIC1FSU87DQo+ICsJCX0NCj4gKwl9DQo+ICsNCj4gKwly ZXR1cm4gMDsNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIHBvd2VycGNfaWRsZV9wcm9iZSgpDQo+ ICsgKiBDaG9vc2Ugc3RhdGUgdGFibGUgZm9yIHNoYXJlZCB2ZXJzdXMgZGVkaWNhdGVkIHBhcnRp dGlvbg0KPiArICovDQo+ICtzdGF0aWMgaW50IHBvd2VycGNfaWRsZV9wcm9iZSh2b2lkKQ0KPiAr ew0KPiArDQo+ICsJaWYgKCFmaXJtd2FyZV9oYXNfZmVhdHVyZShGV19GRUFUVVJFX1NQTFBBUikp DQo+ICsJCXJldHVybiAtRU5PREVWOw0KPiArDQo+ICsJaWYgKGNwdWlkbGVfZGlzYWJsZSAhPSBJ RExFX05PX09WRVJSSURFKQ0KPiArCQlyZXR1cm4gLUVOT0RFVjsNCj4gKw0KPiArCWlmIChtYXhf aWRsZV9zdGF0ZSA9PSAwKSB7DQo+ICsJCXByaW50ayhLRVJOX0RFQlVHICJwb3dlcnBjIHByb2Nl c3NvciBpZGxlIGRpc2FibGVkLlxuIik7DQo+ICsJCXJldHVybiAtRVBFUk07DQo+ICsJfQ0KPiAr DQo+ICsJaWYgKGZpcm13YXJlX2hhc19mZWF0dXJlKEZXX0ZFQVRVUkVfU1BMUEFSKSkgew0KPiAr CQlpZiAoZ2V0X2xwcGFjYV9pc19zaGFyZWRfcHJvYygpID09IDEpDQo+ICsJCQljcHVpZGxlX3N0 YXRlX3RhYmxlID0gc2hhcmVkX3N0YXRlczsNCj4gKwkJZWxzZSBpZiAoZ2V0X2xwcGFjYV9pc19z aGFyZWRfcHJvYygpID09IDApDQo+ICsJCQljcHVpZGxlX3N0YXRlX3RhYmxlID0gZGVkaWNhdGVk X3N0YXRlczsNCj4gKwl9IGVsc2UNCj4gKwkJcmV0dXJuIC1FTk9ERVY7DQo+ICsNCj4gKwlyZXR1 cm4gMDsNCj4gK30NCj4gKw0KPiArc3RhdGljIGludCBfX2luaXQgcG93ZXJwY19wcm9jZXNzb3Jf aWRsZV9pbml0KHZvaWQpDQo+ICt7DQo+ICsJaW50IHJldHZhbDsNCj4gKw0KPiArCXJldHZhbCA9 IHBvd2VycGNfaWRsZV9wcm9iZSgpOw0KPiArCWlmIChyZXR2YWwpDQo+ICsJCXJldHVybiByZXR2 YWw7DQo+ICsNCj4gKwlwb3dlcnBjX2NwdWlkbGVfZHJpdmVyX2luaXQoKTsNCj4gKwlyZXR2YWwg PSBjcHVpZGxlX3JlZ2lzdGVyX2RyaXZlcigmcG93ZXJwY19pZGxlX2RyaXZlcik7DQo+ICsJaWYg KHJldHZhbCkgew0KPiArCQlwcmludGsoS0VSTl9ERUJVRyAiUmVnaXN0cmF0aW9uIG9mIHBvd2Vy cGMgZHJpdmVyIGZhaWxlZC5cbiIpOw0KPiArCQlyZXR1cm4gcmV0dmFsOw0KPiArCX0NCj4gKw0K PiArCXJldHZhbCA9IHBvd2VycGNfaWRsZV9kZXZpY2VzX2luaXQoKTsNCj4gKwlpZiAocmV0dmFs KSB7DQo+ICsJCXBvd2VycGNfaWRsZV9kZXZpY2VzX3VuaW5pdCgpOw0KPiArCQljcHVpZGxlX3Vu cmVnaXN0ZXJfZHJpdmVyKCZwb3dlcnBjX2lkbGVfZHJpdmVyKTsNCj4gKwkJcmV0dXJuIHJldHZh bDsNCj4gKwl9DQo+ICsNCj4gKwlyZWdpc3Rlcl9jcHVfbm90aWZpZXIoJnNldHVwX2hvdHBsdWdf bm90aWZpZXIpOw0KPiArCXByaW50ayhLRVJOX0RFQlVHICJwb3dlcnBjX2lkbGVfZHJpdmVyIHJl Z2lzdGVyZWRcbiIpOw0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2 b2lkIF9fZXhpdCBwb3dlcnBjX3Byb2Nlc3Nvcl9pZGxlX2V4aXQodm9pZCkNCj4gK3sNCj4gKw0K PiArCXVucmVnaXN0ZXJfY3B1X25vdGlmaWVyKCZzZXR1cF9ob3RwbHVnX25vdGlmaWVyKTsNCj4g Kwlwb3dlcnBjX2lkbGVfZGV2aWNlc191bmluaXQoKTsNCj4gKwljcHVpZGxlX3VucmVnaXN0ZXJf ZHJpdmVyKCZwb3dlcnBjX2lkbGVfZHJpdmVyKTsNCj4gKw0KPiArCXJldHVybjsNCj4gK30NCj4g Kw0KRGlkIHlvdSB0ZXN0IG1vZHVsZSBtb2RlPyAqUmVtb3ZlKiB0aGUgbW9kdWxlIGNhbm5vdCB3 b3JrLg0KPiANCg0K ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-19 5:52 ` Wang Dongsheng-B40534 @ 2013-08-19 10:18 ` Deepthi Dharwar 2013-08-19 18:17 ` Scott Wood 0 siblings, 1 reply; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-19 10:18 UTC (permalink / raw) To: Wang Dongsheng-B40534 Cc: Wood Scott-B07421, daniel.lezcano@linaro.org, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org Hi Dongsheng, On 08/19/2013 11:22 AM, Wang Dongsheng-B40534 wrote: > I think we should move the states and handle function to arch/power/platform* > The states and handle function is belong to backend driver, not for this, different platform have different state. > Different platforms to make their own deal with these states. > > I think we cannot put all the status of different platforms and handler in this driver. The idea here is a single powerpc back-end driver, which does a runtime detection of the platform it is running and choose the right idle states table. This was one of outcome of V2 discussion. I feel there is no harm in keeping the state information in the same file. We do have x86, which has all its variants information in one file. One place will have all the idle consolidated information of all the platform variants. If community does feel, we need to have just the states information in arch specific file, we can do so. >> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig >> index 0e2cd5c..99ee5d4 100644 >> --- a/drivers/cpuidle/Kconfig >> +++ b/drivers/cpuidle/Kconfig >> @@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ >> help >> Select this to enable cpuidle on Xilinx Zynq processors. >> >> +config CPU_IDLE_POWERPC >> + bool "CPU Idle driver for POWERPC platforms" >> + depends on PPC64 > > Why not PPC? PPC64 seems to a good place to began the consolidation work. This patch-set has not been tested for PPC32 currently. > >> + default y >> + help >> + Select this option to enable processor idle state management >> + for POWERPC platform. >> endif >> >> config ARCH_NEEDS_CPU_IDLE_COUPLED >> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile >> index 8767a7b..d12e205 100644 >> --- a/drivers/cpuidle/Makefile >> +++ b/drivers/cpuidle/Makefile >> @@ -8,3 +8,5 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o >> obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o >> obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o >> obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o >> + >> +obj-$(CONFIG_CPU_IDLE_POWERPC) += cpuidle-powerpc.o >> diff --git a/drivers/cpuidle/cpuidle-powerpc.c b/drivers/cpuidle/cpuidle- >> powerpc.c >> new file mode 100644 >> index 0000000..5756085 >> --- /dev/null >> +++ b/drivers/cpuidle/cpuidle-powerpc.c >> @@ -0,0 +1,361 @@ >> +/* >> + * processor_idle - idle state cpuidle driver. >> + * Adapted from drivers/idle/intel_idle.c and >> + * drivers/acpi/processor_idle.c >> + * >> + */ >> + >> +#include <linux/kernel.h> >> +#include <linux/module.h> >> +#include <linux/init.h> >> +#include <linux/moduleparam.h> >> +#include <linux/cpuidle.h> >> +#include <linux/cpu.h> >> +#include <linux/notifier.h> >> + >> +#include <asm/paca.h> >> +#include <asm/reg.h> >> +#include <asm/machdep.h> >> +#include <asm/firmware.h> >> +#include <asm/runlatch.h> >> +#include <asm/plpar_wrappers.h> >> + >> +struct cpuidle_driver powerpc_idle_driver = { >> + .name = "powerpc_idle", >> + .owner = THIS_MODULE, >> +}; >> + >> +#define MAX_IDLE_STATE_COUNT 2 >> + >> +static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; > If this is a generic driver, do not define MAX_IDLE_STATE_COUNT, because we don't know how many state on other platforms. > > How about using ARRAY_SIZE to get the max idle state? > Yes, I do agree. We need a generic way to return the no of idle states. >> +static struct cpuidle_device __percpu *powerpc_cpuidle_devices; >> +static struct cpuidle_state *cpuidle_state_table; >> + > Should be remove all about *device*. > If the notifier handle using device, you can use "cpuidle_devices"(include/linux/cpuidle.h). The hotplug notifier has a dependency to the cpu device struct. Yes, I agree using this is way to go forward. As outlined in the cover cpuidle cleanups will be taken in subsequent versions. >> +static inline void idle_loop_prolog(unsigned long *in_purr) >> +{ >> + *in_purr = mfspr(SPRN_PURR); >> + /* >> + * Indicate to the HV that we are idle. Now would be >> + * a good time to find other work to dispatch. >> + */ >> + set_lppaca_idle(1); >> +} >> + >> +static inline void idle_loop_epilog(unsigned long in_purr) >> +{ >> + add_lppaca_wait_state(mfspr(SPRN_PURR) - in_purr); >> + set_lppaca_idle(0); >> +} >> + >> +static int snooze_loop(struct cpuidle_device *dev, >> + struct cpuidle_driver *drv, >> + int index) >> +{ >> + unsigned long in_purr; >> + >> + idle_loop_prolog(&in_purr); >> + 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(); >> + >> + idle_loop_epilog(in_purr); >> + >> + return index; >> +} >> + >> +static void check_and_cede_processor(void) >> +{ >> + /* >> + * Ensure our interrupt state is properly tracked, >> + * also checks if no interrupt has occurred while we >> + * were soft-disabled >> + */ >> + if (prep_irq_for_idle()) { >> + cede_processor(); >> +#ifdef CONFIG_TRACE_IRQFLAGS >> + /* Ensure that H_CEDE returns with IRQs on */ >> + if (WARN_ON(!(mfmsr() & MSR_EE))) >> + __hard_irq_enable(); >> +#endif >> + } >> +} >> + >> +static int dedicated_cede_loop(struct cpuidle_device *dev, >> + struct cpuidle_driver *drv, >> + int index) >> +{ >> + unsigned long in_purr; >> + >> + idle_loop_prolog(&in_purr); >> + set_lppaca_donate_dedicated_cpu(1); >> + >> + ppc64_runlatch_off(); >> + HMT_medium(); >> + check_and_cede_processor(); >> + >> + set_lppaca_donate_dedicated_cpu(0); >> + idle_loop_epilog(in_purr); >> + >> + return index; >> +} >> + >> +static int shared_cede_loop(struct cpuidle_device *dev, >> + struct cpuidle_driver *drv, >> + int index) >> +{ >> + unsigned long in_purr; >> + >> + idle_loop_prolog(&in_purr); >> + >> + /* >> + * Yield the processor to the hypervisor. We return if >> + * an external interrupt occurs (which are driven prior >> + * to returning here) or if a prod occurs from another >> + * processor. When returning here, external interrupts >> + * are enabled. >> + */ >> + check_and_cede_processor(); >> + >> + idle_loop_epilog(in_purr); >> + >> + return index; >> +} >> + >> +/* >> + * States for dedicated partition case. >> + */ >> +static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = { >> + { /* Snooze */ >> + .name = "snooze", >> + .desc = "snooze", >> + .flags = CPUIDLE_FLAG_TIME_VALID, >> + .exit_latency = 0, >> + .target_residency = 0, >> + .enter = &snooze_loop }, >> + { /* CEDE */ >> + .name = "CEDE", >> + .desc = "CEDE", >> + .flags = CPUIDLE_FLAG_TIME_VALID, >> + .exit_latency = 10, >> + .target_residency = 100, >> + .enter = &dedicated_cede_loop }, >> +}; >> + >> +/* >> + * States for shared partition case. >> + */ >> +static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { >> + { /* Shared Cede */ >> + .name = "Shared Cede", >> + .desc = "Shared Cede", >> + .flags = CPUIDLE_FLAG_TIME_VALID, >> + .exit_latency = 0, >> + .target_residency = 0, >> + .enter = &shared_cede_loop }, >> +}; >> + >> +void update_smt_snooze_delay(int cpu, int residency) >> +{ >> + struct cpuidle_driver *drv = cpuidle_get_driver(); >> + struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); >> + >> + if (cpuidle_state_table != dedicated_states) >> + return; >> + >> + if (residency < 0) { >> + /* Disable the Nap state on that cpu */ >> + if (dev) >> + dev->states_usage[1].disable = 1; >> + } else >> + if (drv) >> + drv->states[1].target_residency = residency; >> +} >> + >> +static int powerpc_cpuidle_add_cpu_notifier(struct notifier_block *n, >> + unsigned long action, void *hcpu) >> +{ >> + int hotcpu = (unsigned long)hcpu; >> + struct cpuidle_device *dev = >> + per_cpu_ptr(powerpc_cpuidle_devices, hotcpu); >> + >> + if (dev && cpuidle_get_driver()) { >> + switch (action) { >> + case CPU_ONLINE: >> + case CPU_ONLINE_FROZEN: >> + cpuidle_pause_and_lock(); >> + cpuidle_enable_device(dev); >> + cpuidle_resume_and_unlock(); >> + break; >> + >> + case CPU_DEAD: >> + case CPU_DEAD_FROZEN: >> + cpuidle_pause_and_lock(); >> + cpuidle_disable_device(dev); >> + cpuidle_resume_and_unlock(); >> + break; >> + >> + default: >> + return NOTIFY_DONE; >> + } >> + } >> + return NOTIFY_OK; >> +} >> + >> +static struct notifier_block setup_hotplug_notifier = { >> + .notifier_call = powerpc_cpuidle_add_cpu_notifier, >> +}; >> + > We should discuss this with Daniel. Yes, having a single cpuidle hotplug notifier across all archs removes a lot of code duplication. But this would involve changes across archs that is a huge feature by itself and extensive testing. This is not in the per-view of current patch series but will be taken up separately. >> +/* >> + * powerpc_cpuidle_driver_init() >> + */ >> +static int powerpc_cpuidle_driver_init(void) >> +{ >> + int idle_state; >> + struct cpuidle_driver *drv = &powerpc_idle_driver; >> + >> + drv->state_count = 0; >> + >> + for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; >> ++idle_state) { >> + >> + if (idle_state > max_idle_state) >> + break; >> + >> + /* is the state not enabled? */ >> + if (cpuidle_state_table[idle_state].enter == NULL) >> + continue; >> + > Did the state have dependent? > If yes, may be should break out the loop, not continue. Dependent in what way ? >> + drv->states[drv->state_count] = /* structure copy */ >> + cpuidle_state_table[idle_state]; >> + >> + drv->state_count += 1; >> + } >> + >> + return 0; >> +} >> + >> +/* powerpc_idle_devices_uninit(void) >> + * unregister cpuidle devices and de-allocate memory >> + */ >> +static void powerpc_idle_devices_uninit(void) >> +{ >> + int i; >> + struct cpuidle_device *dev; >> + >> + for_each_possible_cpu(i) { >> + dev = per_cpu_ptr(powerpc_cpuidle_devices, i); >> + cpuidle_unregister_device(dev); >> + } >> + >> + free_percpu(powerpc_cpuidle_devices); >> + return; >> +} >> + >> +/* powerpc_idle_devices_init() >> + * allocate, initialize and register cpuidle device >> + */ >> +static int powerpc_idle_devices_init(void) >> +{ >> + int i; >> + struct cpuidle_driver *drv = &powerpc_idle_driver; >> + struct cpuidle_device *dev; >> + >> + powerpc_cpuidle_devices = alloc_percpu(struct cpuidle_device); >> + if (powerpc_cpuidle_devices == NULL) >> + return -ENOMEM; >> + >> + for_each_possible_cpu(i) { >> + dev = per_cpu_ptr(powerpc_cpuidle_devices, i); >> + dev->state_count = drv->state_count; >> + dev->cpu = i; >> + if (cpuidle_register_device(dev)) { > > Please use cpuidle_register(). > >> + printk(KERN_DEBUG \ >> + "cpuidle_register_device %d failed!\n", i); >> + return -EIO; >> + } >> + } >> + >> + return 0; >> +} >> + >> +/* >> + * powerpc_idle_probe() >> + * Choose state table for shared versus dedicated partition >> + */ >> +static int powerpc_idle_probe(void) >> +{ >> + >> + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) >> + return -ENODEV; >> + >> + if (cpuidle_disable != IDLE_NO_OVERRIDE) >> + return -ENODEV; >> + >> + if (max_idle_state == 0) { >> + printk(KERN_DEBUG "powerpc processor idle disabled.\n"); >> + return -EPERM; >> + } >> + >> + if (firmware_has_feature(FW_FEATURE_SPLPAR)) { >> + if (get_lppaca_is_shared_proc() == 1) >> + cpuidle_state_table = shared_states; >> + else if (get_lppaca_is_shared_proc() == 0) >> + cpuidle_state_table = dedicated_states; >> + } else >> + return -ENODEV; >> + >> + return 0; >> +} >> + >> +static int __init powerpc_processor_idle_init(void) >> +{ >> + int retval; >> + >> + retval = powerpc_idle_probe(); >> + if (retval) >> + return retval; >> + >> + powerpc_cpuidle_driver_init(); >> + retval = cpuidle_register_driver(&powerpc_idle_driver); >> + if (retval) { >> + printk(KERN_DEBUG "Registration of powerpc driver failed.\n"); >> + return retval; >> + } >> + >> + retval = powerpc_idle_devices_init(); >> + if (retval) { >> + powerpc_idle_devices_uninit(); >> + cpuidle_unregister_driver(&powerpc_idle_driver); >> + return retval; >> + } >> + >> + register_cpu_notifier(&setup_hotplug_notifier); >> + printk(KERN_DEBUG "powerpc_idle_driver registered\n"); >> + >> + return 0; >> +} >> + >> +static void __exit powerpc_processor_idle_exit(void) >> +{ >> + >> + unregister_cpu_notifier(&setup_hotplug_notifier); >> + powerpc_idle_devices_uninit(); >> + cpuidle_unregister_driver(&powerpc_idle_driver); >> + >> + return; >> +} >> + > Did you test module mode? *Remove* the module cannot work. >> This is currently in-built module as there is a dependency in kernel/sysfs.c currently. Going forward we will look to have this as a module. This is just an RFC patch to see if we can go forward this line. Thanks so much for the review. I have duly noted down the issues that will be addressed in the coming versions. Regards, Deepthi > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-19 10:18 ` Deepthi Dharwar @ 2013-08-19 18:17 ` Scott Wood 2013-08-21 4:53 ` Deepthi Dharwar 0 siblings, 1 reply; 16+ messages in thread From: Scott Wood @ 2013-08-19 18:17 UTC (permalink / raw) To: Deepthi Dharwar Cc: Wood Scott-B07421, daniel.lezcano@linaro.org, Wang Dongsheng-B40534, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On Mon, 2013-08-19 at 15:48 +0530, Deepthi Dharwar wrote: > Hi Dongsheng, > > On 08/19/2013 11:22 AM, Wang Dongsheng-B40534 wrote: > > I think we should move the states and handle function to arch/power/platform* > > The states and handle function is belong to backend driver, not for this, different platform have different state. > > Different platforms to make their own deal with these states. > > > > I think we cannot put all the status of different platforms and handler in this driver. > > The idea here is a single powerpc back-end driver, which does a runtime > detection of the platform it is running and choose the right > idle states table. This was one of outcome of V2 discussion. I see a lot more in there than just detecting a platform and choosing a driver. > I feel there is no harm in keeping the state information in the same > file. We do have x86, which has all its variants information in one > file. One place will have all the idle consolidated information of > all the platform variants. If community does feel, we need to > have just the states information in arch specific file, we can do so. What actual functionality is common to all powerpc but not common to other arches? > >> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig > >> index 0e2cd5c..99ee5d4 100644 > >> --- a/drivers/cpuidle/Kconfig > >> +++ b/drivers/cpuidle/Kconfig > >> @@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ > >> help > >> Select this to enable cpuidle on Xilinx Zynq processors. > >> > >> +config CPU_IDLE_POWERPC > >> + bool "CPU Idle driver for POWERPC platforms" > >> + depends on PPC64 > > > > Why not PPC? > > PPC64 seems to a good place to began the consolidation work. This > patch-set has not been tested for PPC32 currently. PPC64 is a bad place to start if you want it to be generic, because it means you'll end up growing dependencies on other things that are PPC64 only. There are too many arbitrary 32/64 differences as is. -Scott ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-19 18:17 ` Scott Wood @ 2013-08-21 4:53 ` Deepthi Dharwar 2013-08-21 20:08 ` Scott Wood 0 siblings, 1 reply; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-21 4:53 UTC (permalink / raw) To: Scott Wood Cc: Wood Scott-B07421, daniel.lezcano@linaro.org, Wang Dongsheng-B40534, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On 08/19/2013 11:47 PM, Scott Wood wrote: > On Mon, 2013-08-19 at 15:48 +0530, Deepthi Dharwar wrote: >> Hi Dongsheng, >> >> On 08/19/2013 11:22 AM, Wang Dongsheng-B40534 wrote: >>> I think we should move the states and handle function to arch/power/platform* >>> The states and handle function is belong to backend driver, not for this, different platform have different state. >>> Different platforms to make their own deal with these states. >>> >>> I think we cannot put all the status of different platforms and handler in this driver. >> >> The idea here is a single powerpc back-end driver, which does a runtime >> detection of the platform it is running and choose the right >> idle states table. This was one of outcome of V2 discussion. > > I see a lot more in there than just detecting a platform and choosing a > driver. > >> I feel there is no harm in keeping the state information in the same >> file. We do have x86, which has all its variants information in one >> file. One place will have all the idle consolidated information of >> all the platform variants. If community does feel, we need to >> have just the states information in arch specific file, we can do so. > > What actual functionality is common to all powerpc but not common to > other arches? > >>>> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig >>>> index 0e2cd5c..99ee5d4 100644 >>>> --- a/drivers/cpuidle/Kconfig >>>> +++ b/drivers/cpuidle/Kconfig >>>> @@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ >>>> help >>>> Select this to enable cpuidle on Xilinx Zynq processors. >>>> >>>> +config CPU_IDLE_POWERPC >>>> + bool "CPU Idle driver for POWERPC platforms" >>>> + depends on PPC64 >>> >>> Why not PPC? >> >> PPC64 seems to a good place to began the consolidation work. This >> patch-set has not been tested for PPC32 currently. > > PPC64 is a bad place to start if you want it to be generic, because it > means you'll end up growing dependencies on other things that are PPC64 > only. There are too many arbitrary 32/64 differences as is. Hi Scott, >From my understanding, PPC64 includes BOOK3E and BOOK3S archs. PPC includes PPC32 and PPC64. It seemed logical to start consolidating at PPC64 as one does not want to get into 32/64 bit differences. >From your comments above, I just wanted to clarify if PPC or PPC64 is bad place to start. If PPC64 is bad place to start, then whats the way forward ? Can you please throw some more light on it. Thanks! Deepthi > -Scott > > > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-21 4:53 ` Deepthi Dharwar @ 2013-08-21 20:08 ` Scott Wood 2013-08-22 5:50 ` Deepthi Dharwar 0 siblings, 1 reply; 16+ messages in thread From: Scott Wood @ 2013-08-21 20:08 UTC (permalink / raw) To: Deepthi Dharwar Cc: Wood Scott-B07421, daniel.lezcano@linaro.org, Wang Dongsheng-B40534, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On Wed, 2013-08-21 at 10:23 +0530, Deepthi Dharwar wrote: > On 08/19/2013 11:47 PM, Scott Wood wrote: > > On Mon, 2013-08-19 at 15:48 +0530, Deepthi Dharwar wrote: > >> Hi Dongsheng, > >> > >> On 08/19/2013 11:22 AM, Wang Dongsheng-B40534 wrote: > >>> I think we should move the states and handle function to arch/power/platform* > >>> The states and handle function is belong to backend driver, not for this, different platform have different state. > >>> Different platforms to make their own deal with these states. > >>> > >>> I think we cannot put all the status of different platforms and handler in this driver. > >> > >> The idea here is a single powerpc back-end driver, which does a runtime > >> detection of the platform it is running and choose the right > >> idle states table. This was one of outcome of V2 discussion. > > > > I see a lot more in there than just detecting a platform and choosing a > > driver. > > > >> I feel there is no harm in keeping the state information in the same > >> file. We do have x86, which has all its variants information in one > >> file. One place will have all the idle consolidated information of > >> all the platform variants. If community does feel, we need to > >> have just the states information in arch specific file, we can do so. > > > > What actual functionality is common to all powerpc but not common to > > other arches? No answer? > >>>> +config CPU_IDLE_POWERPC > >>>> + bool "CPU Idle driver for POWERPC platforms" > >>>> + depends on PPC64 > >>> > >>> Why not PPC? > >> > >> PPC64 seems to a good place to began the consolidation work. This > >> patch-set has not been tested for PPC32 currently. > > > > PPC64 is a bad place to start if you want it to be generic, because it > > means you'll end up growing dependencies on other things that are PPC64 > > only. There are too many arbitrary 32/64 differences as is. > > Hi Scott, > > From my understanding, PPC64 includes BOOK3E and BOOK3S archs. > PPC includes PPC32 and PPC64. > > It seemed logical to start consolidating at PPC64 as > one does not want to get into 32/64 bit differences. I don't want to "get into" a file that claims to be generic PPC but is loaded with 64-bit dependencies. > From your comments above, I just wanted to clarify if PPC or PPC64 is > bad place to start. If PPC64 is bad place to start, then whats the way > forward ? Can you please throw some more light on it. The way forward is to give this file a more appropriate name based on the hardware that it actually targets -- and to refactor it so that the answer to that question is not complicated. -Scott ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-21 20:08 ` Scott Wood @ 2013-08-22 5:50 ` Deepthi Dharwar 2013-08-22 5:58 ` Benjamin Herrenschmidt 2013-08-22 21:24 ` Scott Wood 0 siblings, 2 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-22 5:50 UTC (permalink / raw) To: Scott Wood Cc: Wood Scott-B07421, Wang Dongsheng-B40534, daniel.lezcano@linaro.org, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On 08/22/2013 01:38 AM, Scott Wood wrote: > On Wed, 2013-08-21 at 10:23 +0530, Deepthi Dharwar wrote: >> On 08/19/2013 11:47 PM, Scott Wood wrote: >>> On Mon, 2013-08-19 at 15:48 +0530, Deepthi Dharwar wrote: >>>> Hi Dongsheng, >>>> >>>> On 08/19/2013 11:22 AM, Wang Dongsheng-B40534 wrote: >>>>> I think we should move the states and handle function to arch/power/platform* >>>>> The states and handle function is belong to backend driver, not for this, different platform have different state. >>>>> Different platforms to make their own deal with these states. >>>>> >>>>> I think we cannot put all the status of different platforms and handler in this driver. >>>> >>>> The idea here is a single powerpc back-end driver, which does a runtime >>>> detection of the platform it is running and choose the right >>>> idle states table. This was one of outcome of V2 discussion. >>> >>> I see a lot more in there than just detecting a platform and choosing a >>> driver. >>> >>>> I feel there is no harm in keeping the state information in the same >>>> file. We do have x86, which has all its variants information in one >>>> file. One place will have all the idle consolidated information of >>>> all the platform variants. If community does feel, we need to >>>> have just the states information in arch specific file, we can do so. >>> >>> What actual functionality is common to all powerpc but not common to >>> other arches? > The functionality here is idle states on powerpc like the snooze loop that is common. Also, the basic registration of the driver, hotplug notifier etc for powerpc. > >>>>>> +config CPU_IDLE_POWERPC >>>>>> + bool "CPU Idle driver for POWERPC platforms" >>>>>> + depends on PPC64 >>>>> >>>>> Why not PPC? >>>> >>>> PPC64 seems to a good place to began the consolidation work. This >>>> patch-set has not been tested for PPC32 currently. >>> >>> PPC64 is a bad place to start if you want it to be generic, because it >>> means you'll end up growing dependencies on other things that are PPC64 >>> only. There are too many arbitrary 32/64 differences as is. >> >> Hi Scott, >> >> From my understanding, PPC64 includes BOOK3E and BOOK3S archs. >> PPC includes PPC32 and PPC64. >> >> It seemed logical to start consolidating at PPC64 as >> one does not want to get into 32/64 bit differences. > > I don't want to "get into" a file that claims to be generic PPC but is > loaded with 64-bit dependencies. > >> From your comments above, I just wanted to clarify if PPC or PPC64 is >> bad place to start. If PPC64 is bad place to start, then whats the way >> forward ? Can you please throw some more light on it. > > The way forward is to give this file a more appropriate name based on > the hardware that it actually targets -- and to refactor it so that the > answer to that question is not complicated. Sure, thanks. Our idea was to have POWER archs idle states merged at the first go. Only that is what is enabled in the current version (V4 posted out) ( Code is enabled for PSERIES and POWERNV only) If needed, other POWERPC archs might benefit by extending the same driver, that is why it is named cpuidle-powerpc.c But if having cpuidle backend-driver separately for other powerpc arcs makes sense such that each one have their own state information etc then it makes sense to name the files as cpuidle-power.c, cpuilde-ppc32.c and so on. Regards, Deepthi > > -Scott > > > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-22 5:50 ` Deepthi Dharwar @ 2013-08-22 5:58 ` Benjamin Herrenschmidt 2013-08-22 6:41 ` Deepthi Dharwar 2013-08-22 21:24 ` Scott Wood 1 sibling, 1 reply; 16+ messages in thread From: Benjamin Herrenschmidt @ 2013-08-22 5:58 UTC (permalink / raw) To: Deepthi Dharwar Cc: Wood Scott-B07421, daniel.lezcano@linaro.org, Wang Dongsheng-B40534, preeti@linux.vnet.ibm.com, Scott Wood, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On Thu, 2013-08-22 at 11:20 +0530, Deepthi Dharwar wrote: > But if having cpuidle backend-driver separately for other powerpc arcs > makes sense such that each one have their own state information etc > then it makes sense to name the files as cpuidle-power.c, > cpuilde-ppc32.c and so on. If by "power" you mean IBM POWER machines/CPUs, then make it cpuidle-ibm-power or cpuidle-book3s64 maybe to clarify what families it affects. Cheers Ben. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-22 5:58 ` Benjamin Herrenschmidt @ 2013-08-22 6:41 ` Deepthi Dharwar 0 siblings, 0 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-22 6:41 UTC (permalink / raw) To: Benjamin Herrenschmidt Cc: Wood Scott-B07421, Wang Dongsheng-B40534, daniel.lezcano@linaro.org, Scott Wood, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On 08/22/2013 11:28 AM, Benjamin Herrenschmidt wrote: > On Thu, 2013-08-22 at 11:20 +0530, Deepthi Dharwar wrote: >> But if having cpuidle backend-driver separately for other powerpc arcs >> makes sense such that each one have their own state information etc >> then it makes sense to name the files as cpuidle-power.c, >> cpuilde-ppc32.c and so on. > > If by "power" you mean IBM POWER machines/CPUs, then make it > cpuidle-ibm-power or cpuidle-book3s64 maybe to clarify what families it > affects. Sure. Thanks :) Regards, Deepthi > Cheers > Ben. > > > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-22 5:50 ` Deepthi Dharwar 2013-08-22 5:58 ` Benjamin Herrenschmidt @ 2013-08-22 21:24 ` Scott Wood 2013-08-23 10:11 ` Deepthi Dharwar 1 sibling, 1 reply; 16+ messages in thread From: Scott Wood @ 2013-08-22 21:24 UTC (permalink / raw) To: Deepthi Dharwar Cc: Wood Scott-B07421, Wang Dongsheng-B40534, daniel.lezcano@linaro.org, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On Thu, 2013-08-22 at 11:20 +0530, Deepthi Dharwar wrote: > On 08/22/2013 01:38 AM, Scott Wood wrote: > > On Wed, 2013-08-21 at 10:23 +0530, Deepthi Dharwar wrote: > >> On 08/19/2013 11:47 PM, Scott Wood wrote: > >>> What actual functionality is common to all powerpc but not common to > >>> other arches? > > > > The functionality here is idle states on powerpc like the snooze loop > that is common. > Also, the basic registration of the driver, hotplug notifier etc for > powerpc. The snooze loop uses things like SPRN_PURR, get_lppaca(), and CTRL which aren't common to all PPC (they might be common to all book3s64). I also don't see any hook for the low power mode entry -- is "snooze" just a busy loop plus the de-emphasis stuff like HMT and CTRL[RUN]? I'm not familiar with the term "snooze" in this context. I don't think we'd use anything like that on our chips; we'd always at least "wait" or "doze" depending on the chip. It's not clear what is powerpc-specific about the notifier -- perhaps it should go in drivers/cpuidle/. > > The way forward is to give this file a more appropriate name based on > > the hardware that it actually targets -- and to refactor it so that the > > answer to that question is not complicated. > > Sure, thanks. > Our idea was to have POWER archs idle states merged at the first go. > Only that is what is enabled in the current version (V4 posted out) > ( Code is enabled for PSERIES and POWERNV only) > If needed, other POWERPC archs might benefit by extending the same > driver, that is why it is named cpuidle-powerpc.c > > But if having cpuidle backend-driver separately for other powerpc arcs > makes sense such that each one have their own state information etc > then it makes sense to name the files as cpuidle-power.c, > cpuilde-ppc32.c and so on. Thanks. -Scott ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver. 2013-08-22 21:24 ` Scott Wood @ 2013-08-23 10:11 ` Deepthi Dharwar 0 siblings, 0 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-23 10:11 UTC (permalink / raw) To: Scott Wood Cc: Wood Scott-B07421, daniel.lezcano@linaro.org, Wang Dongsheng-B40534, preeti@linux.vnet.ibm.com, linux-pm@lists.linux-foundation.org, linuxppc-dev@lists.ozlabs.org On 08/23/2013 02:54 AM, Scott Wood wrote: > On Thu, 2013-08-22 at 11:20 +0530, Deepthi Dharwar wrote: >> On 08/22/2013 01:38 AM, Scott Wood wrote: >>> On Wed, 2013-08-21 at 10:23 +0530, Deepthi Dharwar wrote: >>>> On 08/19/2013 11:47 PM, Scott Wood wrote: >>>>> What actual functionality is common to all powerpc but not common to >>>>> other arches? >>> >> >> The functionality here is idle states on powerpc like the snooze loop >> that is common. >> Also, the basic registration of the driver, hotplug notifier etc for >> powerpc. > > The snooze loop uses things like SPRN_PURR, get_lppaca(), and CTRL which > aren't common to all PPC (they might be common to all book3s64). I also > don't see any hook for the low power mode entry -- is "snooze" just a > busy loop plus the de-emphasis stuff like HMT and CTRL[RUN]? I'm not > familiar with the term "snooze" in this context. I don't think we'd use > anything like that on our chips; we'd always at least "wait" or "doze" > depending on the chip. > Duly noted. Lot of stuff are common across book3s64. So my later versions of this patchset does just that. (V5 posted out yesterday). The driver is common only to IBM-POWER platform. Other PPC variants can have their own driver. > It's not clear what is powerpc-specific about the notifier -- perhaps it > should go in drivers/cpuidle/. Currently all the arcs have their own hotplug notifier. Unifying this across all archs is a challenge that needs to be taken going forward. Thanks for the review. Regards, Deepthi >>> The way forward is to give this file a more appropriate name based on >>> the hardware that it actually targets -- and to refactor it so that the >>> answer to that question is not complicated. >> >> Sure, thanks. >> Our idea was to have POWER archs idle states merged at the first go. >> Only that is what is enabled in the current version (V4 posted out) >> ( Code is enabled for PSERIES and POWERNV only) >> If needed, other POWERPC archs might benefit by extending the same >> driver, that is why it is named cpuidle-powerpc.c >> >> But if having cpuidle backend-driver separately for other powerpc arcs >> makes sense such that each one have their own state information etc >> then it makes sense to name the files as cpuidle-power.c, >> cpuilde-ppc32.c and so on. > > Thanks. > > -Scott > > > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* [RFC PATCH V3 4/5] powerpc/cpuidle: Enable powernv cpuidle support. 2013-08-19 4:27 [RFC PATCH V3 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms Deepthi Dharwar ` (2 preceding siblings ...) 2013-08-19 4:28 ` [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver Deepthi Dharwar @ 2013-08-19 4:28 ` Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 5/5] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework Deepthi Dharwar 4 siblings, 0 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-19 4:28 UTC (permalink / raw) To: benh, daniel.lezcano, kernel, scottwood, linux-pm, linuxppc-dev Cc: preeti, dongsheng.wang The following patch extends the current powerpc backend idle driver to the powernv platform. Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> --- drivers/cpuidle/cpuidle-powerpc.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/cpuidle/cpuidle-powerpc.c b/drivers/cpuidle/cpuidle-powerpc.c index 5756085..e1cf599 100644 --- a/drivers/cpuidle/cpuidle-powerpc.c +++ b/drivers/cpuidle/cpuidle-powerpc.c @@ -53,7 +53,9 @@ static int snooze_loop(struct cpuidle_device *dev, { unsigned long in_purr; - idle_loop_prolog(&in_purr); + if (firmware_has_feature(FW_FEATURE_SPLPAR)) + idle_loop_prolog(&in_purr); + local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); @@ -67,7 +69,8 @@ static int snooze_loop(struct cpuidle_device *dev, clear_thread_flag(TIF_POLLING_NRFLAG); smp_mb(); - idle_loop_epilog(in_purr); + if (firmware_has_feature(FW_FEATURE_SPLPAR)) + idle_loop_epilog(in_purr); return index; } @@ -130,6 +133,15 @@ static int shared_cede_loop(struct cpuidle_device *dev, return index; } +static int nap_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + ppc64_runlatch_off(); + power7_idle(); + return index; +} + /* * States for dedicated partition case. */ @@ -163,6 +175,23 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { .enter = &shared_cede_loop }, }; +static struct cpuidle_state powernv_states[MAX_IDLE_STATE_COUNT] = { + { /* Snooze */ + .name = "snooze", + .desc = "snooze", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 0, + .target_residency = 0, + .enter = &snooze_loop }, + { /* NAP */ + .name = "NAP", + .desc = "NAP", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 10, + .target_residency = 100, + .enter = &nap_loop }, +}; + void update_smt_snooze_delay(int cpu, int residency) { struct cpuidle_driver *drv = cpuidle_get_driver(); @@ -282,7 +311,6 @@ static int powerpc_idle_devices_init(void) return -EIO; } } - return 0; } @@ -309,6 +337,8 @@ static int powerpc_idle_probe(void) cpuidle_state_table = shared_states; else if (get_lppaca_is_shared_proc() == 0) cpuidle_state_table = dedicated_states; + } else if (firmware_has_feature(FW_FEATURE_OPALv3)) { + cpuidle_state_table = powernv_states; } else return -ENODEV; ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH V3 5/5] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework. 2013-08-19 4:27 [RFC PATCH V3 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms Deepthi Dharwar ` (3 preceding siblings ...) 2013-08-19 4:28 ` [RFC PATCH V3 4/5] powerpc/cpuidle: Enable powernv cpuidle support Deepthi Dharwar @ 2013-08-19 4:28 ` Deepthi Dharwar 4 siblings, 0 replies; 16+ messages in thread From: Deepthi Dharwar @ 2013-08-19 4:28 UTC (permalink / raw) To: benh, daniel.lezcano, kernel, scottwood, linux-pm, linuxppc-dev Cc: preeti, dongsheng.wang This patch enables idle cpu on the powernv platform to hook on to the cpuidle framework, if available, else call on to default idle platform code. Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> --- arch/powerpc/platforms/powernv/setup.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 84438af..fc62f21 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -25,6 +25,7 @@ #include <linux/of.h> #include <linux/interrupt.h> #include <linux/bug.h> +#include <linux/cpuidle.h> #include <asm/machdep.h> #include <asm/firmware.h> @@ -175,6 +176,17 @@ static void __init pnv_setup_machdep_rtas(void) } #endif /* CONFIG_PPC_POWERNV_RTAS */ +void powernv_idle(void) +{ + /* Hook to cpuidle framework if available, else + * call on default platform idle code + */ + if (cpuidle_idle_call()) { + HMT_low(); + HMT_very_low(); + } +} + static int __init pnv_probe(void) { unsigned long root = of_get_flat_dt_root(); @@ -205,7 +217,7 @@ define_machine(powernv) { .show_cpuinfo = pnv_show_cpuinfo, .progress = pnv_progress, .machine_shutdown = pnv_shutdown, - .power_save = power7_idle, + .power_save = powernv_idle, .calibrate_decr = generic_calibrate_decr, #ifdef CONFIG_KEXEC .kexec_cpu_down = pnv_kexec_cpu_down, ^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2013-08-23 10:13 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-08-19 4:27 [RFC PATCH V3 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 1/5] pseries/cpuidle: Remove dependency of pseries.h file Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 2/5] pseries: Move plpar_wrapper.h to powerpc common include/asm location Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver Deepthi Dharwar 2013-08-19 5:52 ` Wang Dongsheng-B40534 2013-08-19 10:18 ` Deepthi Dharwar 2013-08-19 18:17 ` Scott Wood 2013-08-21 4:53 ` Deepthi Dharwar 2013-08-21 20:08 ` Scott Wood 2013-08-22 5:50 ` Deepthi Dharwar 2013-08-22 5:58 ` Benjamin Herrenschmidt 2013-08-22 6:41 ` Deepthi Dharwar 2013-08-22 21:24 ` Scott Wood 2013-08-23 10:11 ` Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 4/5] powerpc/cpuidle: Enable powernv cpuidle support Deepthi Dharwar 2013-08-19 4:28 ` [RFC PATCH V3 5/5] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework Deepthi Dharwar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).