From: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org> To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>, Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>, Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org>, Catalin Marinas <catalin.marinas-5wv7dgnIgG8@public.gmane.org>, Charles Garcia Tobin <Charles.Garcia-Tobin-5wv7dgnIgG8@public.gmane.org>, Nicolas Pitre <nico-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>, Grant Likely <grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Peter De Schrijver <pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>, Santosh Shilimkar <santosh.shilimkar-l0cyMroinI0@public.gmane.org>, Daniel Lezcano <daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Amit Kucheria <amit.kucheria-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Vincent Guittot <vincent.guittot-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Antti Miettinen <ananaza-X3B1VOXEql0@public.gmane.org>, Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>, Kevin Hilman <khilman-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Sebastian Capella <sebcape-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>, Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>, Paul Walmsley <paul-DWxLp4Yu+b8AvxtiuMwx3w@public.gmane.org>, Chander Kashyap <k.chander-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>, Geoff Subject: [PATCH v7 5/8] arm64: add PSCI CPU_SUSPEND based cpu_suspend support Date: Wed, 13 Aug 2014 16:52:04 +0100 [thread overview] Message-ID: <1407945127-27554-6-git-send-email-lorenzo.pieralisi@arm.com> (raw) In-Reply-To: <1407945127-27554-1-git-send-email-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org> This patch implements the cpu_suspend cpu operations method through the PSCI CPU SUSPEND API. The PSCI implementation translates the idle state index passed by the cpu_suspend core call into a valid PSCI state according to the PSCI states initialized at boot through the cpu_init_idle() CPU operations hook. The PSCI CPU suspend operation hook checks if the PSCI state is a standby state. If it is, it calls the PSCI suspend implementation straight away, without saving any context. If the state is a power down state the kernel calls the __cpu_suspend API (that saves the CPU context) and passed the PSCI suspend finisher as a parameter so that PSCI can be called by the __cpu_suspend implementation after saving and flushing the context as last function before power down. For power down states, entry point is set to cpu_resume physical address, that represents the default kernel execution address following a CPU reset. Reviewed-by: Ashwin Chaugule <ashwin.chaugule-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org> --- arch/arm64/kernel/psci.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 5539547..8258a77 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -21,6 +21,7 @@ #include <linux/reboot.h> #include <linux/pm.h> #include <linux/delay.h> +#include <linux/slab.h> #include <uapi/linux/psci.h> #include <asm/compiler.h> @@ -28,6 +29,7 @@ #include <asm/errno.h> #include <asm/psci.h> #include <asm/smp_plat.h> +#include <asm/suspend.h> #include <asm/system_misc.h> #define PSCI_POWER_STATE_TYPE_STANDBY 0 @@ -65,6 +67,8 @@ enum psci_function { PSCI_FN_MAX, }; +static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state); + static u32 psci_function_id[PSCI_FN_MAX]; static int psci_to_linux_errno(int errno) @@ -93,6 +97,18 @@ static u32 psci_power_state_pack(struct psci_power_state state) & PSCI_0_2_POWER_STATE_AFFL_MASK); } +static void psci_power_state_unpack(u32 power_state, + struct psci_power_state *state) +{ + state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >> + PSCI_0_2_POWER_STATE_ID_SHIFT; + state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >> + PSCI_0_2_POWER_STATE_TYPE_SHIFT; + state->affinity_level = + (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >> + PSCI_0_2_POWER_STATE_AFFL_SHIFT; +} + /* * The following two functions are invoked via the invoke_psci_fn pointer * and will not be inlined, allowing us to piggyback on the AAPCS. @@ -199,6 +215,59 @@ static int psci_migrate_info_type(void) return err; } +static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node, + unsigned int cpu) +{ + int i, ret, count = 0; + struct psci_power_state *psci_states; + struct device_node *state_node; + + /* + * If the PSCI cpu_suspend function hook has not been initialized + * idle states must not be enabled, so bail out + */ + if (!psci_ops.cpu_suspend) + return -EOPNOTSUPP; + + /* Count idle states */ + while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", + count))) + count++; + + if (!count) + return -ENODEV; + + psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); + if (!psci_states) + return -ENOMEM; + + for (i = 0; i < count; i++) { + u32 psci_power_state; + + state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); + + ret = of_property_read_u32(state_node, + "arm,psci-suspend-param", + &psci_power_state); + if (ret) { + pr_warn(" * %s missing arm,psci-suspend-param property\n", + state_node->full_name); + goto free_mem; + } + + pr_debug("psci-power-state %#x index %d\n", psci_power_state, + i); + psci_power_state_unpack(psci_power_state, &psci_states[i]); + } + /* Idle states parsed correctly, initialize per-cpu pointer */ + per_cpu(psci_power_state, cpu) = psci_states; + return 0; + +free_mem: + kfree(psci_states); + return ret; +} + static int get_set_conduit_method(struct device_node *np) { const char *method; @@ -436,8 +505,39 @@ static int cpu_psci_cpu_kill(unsigned int cpu) #endif #endif +static int psci_suspend_finisher(unsigned long index) +{ + struct psci_power_state *state = __get_cpu_var(psci_power_state); + + return psci_ops.cpu_suspend(state[index - 1], + virt_to_phys(cpu_resume)); +} + +static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) +{ + int ret; + struct psci_power_state *state = __get_cpu_var(psci_power_state); + /* + * idle state index 0 corresponds to wfi, should never be called + * from the cpu_suspend operations + */ + if (WARN_ON_ONCE(!index)) + return -EINVAL; + + if (state->type == PSCI_POWER_STATE_TYPE_STANDBY) + ret = psci_ops.cpu_suspend(state[index - 1], 0); + else + ret = __cpu_suspend(index, psci_suspend_finisher); + + return ret; +} + const struct cpu_operations cpu_psci_ops = { .name = "psci", +#ifdef CONFIG_CPU_IDLE + .cpu_init_idle = cpu_psci_cpu_init_idle, + .cpu_suspend = cpu_psci_cpu_suspend, +#endif #ifdef CONFIG_SMP .cpu_init = cpu_psci_cpu_init, .cpu_prepare = cpu_psci_cpu_prepare, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html
WARNING: multiple messages have this Message-ID (diff)
From: lorenzo.pieralisi@arm.com (Lorenzo Pieralisi) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH v7 5/8] arm64: add PSCI CPU_SUSPEND based cpu_suspend support Date: Wed, 13 Aug 2014 16:52:04 +0100 [thread overview] Message-ID: <1407945127-27554-6-git-send-email-lorenzo.pieralisi@arm.com> (raw) In-Reply-To: <1407945127-27554-1-git-send-email-lorenzo.pieralisi@arm.com> This patch implements the cpu_suspend cpu operations method through the PSCI CPU SUSPEND API. The PSCI implementation translates the idle state index passed by the cpu_suspend core call into a valid PSCI state according to the PSCI states initialized at boot through the cpu_init_idle() CPU operations hook. The PSCI CPU suspend operation hook checks if the PSCI state is a standby state. If it is, it calls the PSCI suspend implementation straight away, without saving any context. If the state is a power down state the kernel calls the __cpu_suspend API (that saves the CPU context) and passed the PSCI suspend finisher as a parameter so that PSCI can be called by the __cpu_suspend implementation after saving and flushing the context as last function before power down. For power down states, entry point is set to cpu_resume physical address, that represents the default kernel execution address following a CPU reset. Reviewed-by: Ashwin Chaugule <ashwin.chaugule@linaro.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> --- arch/arm64/kernel/psci.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 5539547..8258a77 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -21,6 +21,7 @@ #include <linux/reboot.h> #include <linux/pm.h> #include <linux/delay.h> +#include <linux/slab.h> #include <uapi/linux/psci.h> #include <asm/compiler.h> @@ -28,6 +29,7 @@ #include <asm/errno.h> #include <asm/psci.h> #include <asm/smp_plat.h> +#include <asm/suspend.h> #include <asm/system_misc.h> #define PSCI_POWER_STATE_TYPE_STANDBY 0 @@ -65,6 +67,8 @@ enum psci_function { PSCI_FN_MAX, }; +static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state); + static u32 psci_function_id[PSCI_FN_MAX]; static int psci_to_linux_errno(int errno) @@ -93,6 +97,18 @@ static u32 psci_power_state_pack(struct psci_power_state state) & PSCI_0_2_POWER_STATE_AFFL_MASK); } +static void psci_power_state_unpack(u32 power_state, + struct psci_power_state *state) +{ + state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >> + PSCI_0_2_POWER_STATE_ID_SHIFT; + state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >> + PSCI_0_2_POWER_STATE_TYPE_SHIFT; + state->affinity_level = + (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >> + PSCI_0_2_POWER_STATE_AFFL_SHIFT; +} + /* * The following two functions are invoked via the invoke_psci_fn pointer * and will not be inlined, allowing us to piggyback on the AAPCS. @@ -199,6 +215,59 @@ static int psci_migrate_info_type(void) return err; } +static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node, + unsigned int cpu) +{ + int i, ret, count = 0; + struct psci_power_state *psci_states; + struct device_node *state_node; + + /* + * If the PSCI cpu_suspend function hook has not been initialized + * idle states must not be enabled, so bail out + */ + if (!psci_ops.cpu_suspend) + return -EOPNOTSUPP; + + /* Count idle states */ + while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", + count))) + count++; + + if (!count) + return -ENODEV; + + psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); + if (!psci_states) + return -ENOMEM; + + for (i = 0; i < count; i++) { + u32 psci_power_state; + + state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); + + ret = of_property_read_u32(state_node, + "arm,psci-suspend-param", + &psci_power_state); + if (ret) { + pr_warn(" * %s missing arm,psci-suspend-param property\n", + state_node->full_name); + goto free_mem; + } + + pr_debug("psci-power-state %#x index %d\n", psci_power_state, + i); + psci_power_state_unpack(psci_power_state, &psci_states[i]); + } + /* Idle states parsed correctly, initialize per-cpu pointer */ + per_cpu(psci_power_state, cpu) = psci_states; + return 0; + +free_mem: + kfree(psci_states); + return ret; +} + static int get_set_conduit_method(struct device_node *np) { const char *method; @@ -436,8 +505,39 @@ static int cpu_psci_cpu_kill(unsigned int cpu) #endif #endif +static int psci_suspend_finisher(unsigned long index) +{ + struct psci_power_state *state = __get_cpu_var(psci_power_state); + + return psci_ops.cpu_suspend(state[index - 1], + virt_to_phys(cpu_resume)); +} + +static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) +{ + int ret; + struct psci_power_state *state = __get_cpu_var(psci_power_state); + /* + * idle state index 0 corresponds to wfi, should never be called + * from the cpu_suspend operations + */ + if (WARN_ON_ONCE(!index)) + return -EINVAL; + + if (state->type == PSCI_POWER_STATE_TYPE_STANDBY) + ret = psci_ops.cpu_suspend(state[index - 1], 0); + else + ret = __cpu_suspend(index, psci_suspend_finisher); + + return ret; +} + const struct cpu_operations cpu_psci_ops = { .name = "psci", +#ifdef CONFIG_CPU_IDLE + .cpu_init_idle = cpu_psci_cpu_init_idle, + .cpu_suspend = cpu_psci_cpu_suspend, +#endif #ifdef CONFIG_SMP .cpu_init = cpu_psci_cpu_init, .cpu_prepare = cpu_psci_cpu_prepare, -- 1.9.1
next prev parent reply other threads:[~2014-08-13 15:52 UTC|newest] Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top 2014-08-13 15:51 [PATCH v7 0/8] ARM generic idle states Lorenzo Pieralisi 2014-08-13 15:51 ` Lorenzo Pieralisi 2014-08-13 15:52 ` [PATCH v7 1/8] arm64: kernel: refactor the CPU suspend API for retention states Lorenzo Pieralisi 2014-08-13 15:52 ` Lorenzo Pieralisi 2014-08-18 7:47 ` Hanjun Guo 2014-08-18 7:47 ` Hanjun Guo 2014-08-18 14:20 ` Catalin Marinas 2014-08-18 14:20 ` Catalin Marinas 2014-08-13 15:52 ` [PATCH v7 2/8] Documentation: arm: define DT idle states bindings Lorenzo Pieralisi 2014-08-13 15:52 ` Lorenzo Pieralisi [not found] ` <1407945127-27554-3-git-send-email-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org> 2014-08-13 19:25 ` Lina Iyer 2014-08-13 19:25 ` Lina Iyer 2014-08-13 22:11 ` Lorenzo Pieralisi 2014-08-13 22:11 ` Lorenzo Pieralisi 2014-08-15 17:20 ` Lina Iyer 2014-08-15 17:20 ` Lina Iyer 2014-08-15 17:51 ` Lorenzo Pieralisi 2014-08-15 17:51 ` Lorenzo Pieralisi 2014-08-18 14:20 ` Catalin Marinas 2014-08-18 14:20 ` Catalin Marinas 2014-08-13 15:52 ` [PATCH v7 3/8] drivers: cpuidle: implement DT based idle states infrastructure Lorenzo Pieralisi 2014-08-13 15:52 ` Lorenzo Pieralisi 2014-08-13 16:31 ` Nicolas Pitre 2014-08-13 16:31 ` Nicolas Pitre 2014-08-13 17:04 ` Lorenzo Pieralisi 2014-08-13 17:04 ` Lorenzo Pieralisi 2014-08-13 17:29 ` Nicolas Pitre 2014-08-13 17:29 ` Nicolas Pitre 2014-08-14 11:29 ` Lorenzo Pieralisi 2014-08-14 11:29 ` Lorenzo Pieralisi 2014-08-14 15:47 ` Nicolas Pitre 2014-08-14 15:47 ` Nicolas Pitre 2014-08-14 16:02 ` Lorenzo Pieralisi 2014-08-14 16:02 ` Lorenzo Pieralisi 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 14:21 ` Catalin Marinas 2014-08-13 15:52 ` [PATCH v7 4/8] arm64: kernel: introduce cpu_init_idle CPU operation Lorenzo Pieralisi 2014-08-13 15:52 ` Lorenzo Pieralisi 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 14:21 ` Catalin Marinas [not found] ` <1407945127-27554-1-git-send-email-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org> 2014-08-13 15:52 ` Lorenzo Pieralisi [this message] 2014-08-13 15:52 ` [PATCH v7 5/8] arm64: add PSCI CPU_SUSPEND based cpu_suspend support Lorenzo Pieralisi 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 14:21 ` Catalin Marinas 2014-08-13 15:52 ` [PATCH v7 6/8] drivers: cpuidle: CPU idle ARM64 driver Lorenzo Pieralisi 2014-08-13 15:52 ` Lorenzo Pieralisi 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 22:30 ` Lorenzo Pieralisi 2014-08-18 22:30 ` Lorenzo Pieralisi 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 22:25 ` Lorenzo Pieralisi 2014-08-18 22:25 ` Lorenzo Pieralisi 2014-08-13 15:52 ` [PATCH v7 7/8] drivers: cpuidle: initialize big.LITTLE driver through DT Lorenzo Pieralisi 2014-08-13 15:52 ` Lorenzo Pieralisi 2014-08-18 14:21 ` Catalin Marinas 2014-08-18 14:21 ` Catalin Marinas 2014-08-13 15:52 ` [PATCH v7 8/8] drivers: cpuidle: initialize Exynos " Lorenzo Pieralisi 2014-08-13 15:52 ` Lorenzo Pieralisi 2014-08-15 21:12 ` Lina Iyer 2014-08-15 21:12 ` Lina Iyer 2014-08-15 21:40 ` Lorenzo Pieralisi 2014-08-15 21:40 ` Lorenzo Pieralisi 2014-08-15 21:45 ` Lina Iyer 2014-08-15 21:45 ` Lina Iyer 2014-08-15 21:52 ` Lorenzo Pieralisi 2014-08-15 21:52 ` Lorenzo Pieralisi 2014-08-18 14:22 ` Catalin Marinas 2014-08-18 14:22 ` Catalin Marinas
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1407945127-27554-6-git-send-email-lorenzo.pieralisi@arm.com \ --to=lorenzo.pieralisi-5wv7dgnigg8@public.gmane.org \ --cc=Charles.Garcia-Tobin-5wv7dgnIgG8@public.gmane.org \ --cc=amit.kucheria-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=ananaza-X3B1VOXEql0@public.gmane.org \ --cc=broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \ --cc=catalin.marinas-5wv7dgnIgG8@public.gmane.org \ --cc=daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \ --cc=grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=k.chander-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org \ --cc=khilman-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \ --cc=linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \ --cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \ --cc=nico-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=paul-DWxLp4Yu+b8AvxtiuMwx3w@public.gmane.org \ --cc=pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org \ --cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \ --cc=santosh.shilimkar-l0cyMroinI0@public.gmane.org \ --cc=sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \ --cc=sebcape-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \ --cc=sudeep.holla-5wv7dgnIgG8@public.gmane.org \ --cc=t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org \ --cc=vincent.guittot-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.