From patchwork Mon Jul 21 16:06:23 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Pieralisi X-Patchwork-Id: 4597291 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A44269F2B8 for ; Mon, 21 Jul 2014 16:09:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id ABFD32014A for ; Mon, 21 Jul 2014 16:09:32 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B1AC82013D for ; Mon, 21 Jul 2014 16:09:31 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X9G7J-0002tJ-K4; Mon, 21 Jul 2014 16:07:09 +0000 Received: from service87.mimecast.com ([91.220.42.44]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X9G7E-0002kL-Du for linux-arm-kernel@lists.infradead.org; Mon, 21 Jul 2014 16:07:06 +0000 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Mon, 21 Jul 2014 17:06:41 +0100 Received: from red-moon.cambridge.arm.com ([10.1.255.212]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 21 Jul 2014 17:06:38 +0100 From: Lorenzo Pieralisi To: linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org Subject: [PATCH v6 4/7] arm64: add PSCI CPU_SUSPEND based cpu_suspend support Date: Mon, 21 Jul 2014 17:06:23 +0100 Message-Id: <1405958786-17243-5-git-send-email-lorenzo.pieralisi@arm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1405958786-17243-1-git-send-email-lorenzo.pieralisi@arm.com> References: <1405958786-17243-1-git-send-email-lorenzo.pieralisi@arm.com> X-OriginalArrivalTime: 21 Jul 2014 16:06:38.0852 (UTC) FILETIME=[C0FCFC40:01CFA4FD] X-MC-Unique: 114072117064100701 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140721_090704_918419_7EDC0FF7 X-CRM114-Status: GOOD ( 14.07 ) X-Spam-Score: -0.7 (/) Cc: Mark Rutland , Catalin Marinas , Tomasz Figa , Chander Kashyap , Lorenzo Pieralisi , Vincent Guittot , Nicolas Pitre , Daniel Lezcano , Grant Likely , Charles Garcia Tobin , devicetree@vger.kernel.org, Kevin Hilman , Bartlomiej Zolnierkiewicz , Sebastian Capella , Rob Herring , Antti Miettinen , Paul Walmsley , Geoff Levand , Peter De Schrijver , Stephen Boyd , Amit Kucheria , Mark Brown , Santosh Shilimkar , Sudeep Holla X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Entry point is set to cpu_resume physical address, that represents the default kernel execution address following a CPU reset; for standby states the entry point address is useless and will therefore be ignored by the PSCI implementation. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ashwin Chaugule --- arch/arm64/kernel/psci.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index a623c44..bbdf41d 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #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,61 @@ static int psci_migrate_info_type(void) return err; } +static int 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) { + pr_warn("idle state psci_state allocation failed\n"); + 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 +507,23 @@ static int cpu_psci_cpu_kill(unsigned int cpu) #endif #endif +static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) +{ + 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; + + return psci_ops.cpu_suspend(state[index - 1], + virt_to_phys(cpu_resume)); +} + const struct cpu_operations cpu_psci_ops = { .name = "psci", + .cpu_init_idle = cpu_psci_cpu_init_idle, #ifdef CONFIG_SMP .cpu_init = cpu_psci_cpu_init, .cpu_prepare = cpu_psci_cpu_prepare, @@ -448,5 +534,8 @@ const struct cpu_operations cpu_psci_ops = { .cpu_kill = cpu_psci_cpu_kill, #endif #endif +#ifdef CONFIG_ARM64_CPU_SUSPEND + .cpu_suspend = cpu_psci_cpu_suspend, +#endif };