From patchwork Tue Mar 18 10:20:26 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Pieralisi X-Patchwork-Id: 26470 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-yh0-f72.google.com (mail-yh0-f72.google.com [209.85.213.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id ABCE1203C3 for ; Tue, 18 Mar 2014 10:19:20 +0000 (UTC) Received: by mail-yh0-f72.google.com with SMTP id f10sf17688592yha.3 for ; Tue, 18 Mar 2014 03:19:20 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe:content-type :content-transfer-encoding; bh=+NbpER23Sl52WqjLwz3JpqLp7y+nlsgm4z5ojkBOeeU=; b=IVXLNqWFlkLTePv3EXTNRrX/azUDX3OuP2T5ej4OuBTcB3EwFMywydrYZO/FlmXDUd i2w7G20ltZXrP6PE34RYVWkXTNNTACXr1yjGpGeFvKXdVhVelgHL1pb/L/plV+xafPyW dBDb+xfAZd5Z3Z0fq4UhRobNseexpvNT93WYO35VJrnmr34dgsPcze8zxWzfqE0Q9Bl3 hfOS6SWPTGmt2uQv4nQSbDYca+XS5paGyyubNDgPT9zd+J3YQxkyge5JDt4OHt3mUOja Evsn6YI9Xr8oObEir5HJpC2ikdCn9GkEFBuf04QFT0oQplTOkgnh3LZPBRpnbVNF/wqF x82g== X-Gm-Message-State: ALoCoQkbWwhmws4j5/OBt4SW+FZ4e5mVlUVerXeUBoystcCnsHJ5inGChGqT2V6hiOSX9J1bKB84 X-Received: by 10.58.111.202 with SMTP id ik10mr1777632veb.4.1395137960459; Tue, 18 Mar 2014 03:19:20 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.21.213 with SMTP id 79ls1269883qgl.35.gmail; Tue, 18 Mar 2014 03:19:20 -0700 (PDT) X-Received: by 10.52.108.228 with SMTP id hn4mr681449vdb.43.1395137960384; Tue, 18 Mar 2014 03:19:20 -0700 (PDT) Received: from mail-ve0-f171.google.com (mail-ve0-f171.google.com [209.85.128.171]) by mx.google.com with ESMTPS id gs7si2527956vdc.56.2014.03.18.03.19.20 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 18 Mar 2014 03:19:20 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.171; Received: by mail-ve0-f171.google.com with SMTP id cz12so6764774veb.16 for ; Tue, 18 Mar 2014 03:19:20 -0700 (PDT) X-Received: by 10.58.178.238 with SMTP id db14mr3644074vec.25.1395137960298; Tue, 18 Mar 2014 03:19:20 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.78.9 with SMTP id i9csp193368vck; Tue, 18 Mar 2014 03:19:19 -0700 (PDT) X-Received: by 10.68.202.230 with SMTP id kl6mr31695404pbc.55.1395137959289; Tue, 18 Mar 2014 03:19:19 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id yp10si12139647pab.134.2014.03.18.03.19.18; Tue, 18 Mar 2014 03:19:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753467AbaCRKTR (ORCPT + 9 others); Tue, 18 Mar 2014 06:19:17 -0400 Received: from service87.mimecast.com ([91.220.42.44]:54211 "EHLO service87.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753958AbaCRKTO (ORCPT ); Tue, 18 Mar 2014 06:19:14 -0400 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Tue, 18 Mar 2014 10:19:12 +0000 Received: from red-moon.cambridge.arm.com ([10.1.255.212]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 18 Mar 2014 10:19:22 +0000 From: Lorenzo Pieralisi To: linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: devicetree@vger.kernel.org, Lorenzo Pieralisi , Mark Rutland , Sudeep Holla , Catalin Marinas , Charles Garcia Tobin , Nicolas Pitre , Rob Herring , Grant Likely , Peter De Schrijver , Santosh Shilimkar , Daniel Lezcano , Amit Kucheria , Vincent Guittot , Antti Miettinen , Stephen Boyd , Kevin Hilman , Sebastian Capella , Tomasz Figa Subject: [PATCH RFC 2/4] arm64: add PSCI CPU_SUSPEND based cpu_suspend support Date: Tue, 18 Mar 2014 10:20:26 +0000 Message-Id: <1395138028-19630-3-git-send-email-lorenzo.pieralisi@arm.com> X-Mailer: git-send-email 1.8.4 In-Reply-To: <1395138028-19630-1-git-send-email-lorenzo.pieralisi@arm.com> References: <1395138028-19630-1-git-send-email-lorenzo.pieralisi@arm.com> X-OriginalArrivalTime: 18 Mar 2014 10:19:22.0562 (UTC) FILETIME=[87F4B220:01CF4293] X-MC-Unique: 114031810191205201 Sender: devicetree-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: devicetree@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: lorenzo.pieralisi@arm.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , 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 by the PSCI protocol backend. Entry point is set to cpu_resume physical address, that represents the default kernel execution address following a CPU reset. Idle state index 0 is initialized to power state standby WFI so that if called by the idle driver it provides the default behaviour. Signed-off-by: Lorenzo Pieralisi --- arch/arm64/include/asm/psci.h | 6 +++ arch/arm64/kernel/idle_states.c | 1 + arch/arm64/kernel/psci.c | 84 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h index e5312ea..b8ec598 100644 --- a/arch/arm64/include/asm/psci.h +++ b/arch/arm64/include/asm/psci.h @@ -14,6 +14,12 @@ #ifndef __ASM_PSCI_H #define __ASM_PSCI_H +struct idle_state; + int psci_init(void); +int __init psci_register_idle_states(struct cpumask *cpumask, + struct idle_state *idle_states, + unsigned int count); + #endif /* __ASM_PSCI_H */ diff --git a/arch/arm64/kernel/idle_states.c b/arch/arm64/kernel/idle_states.c index 0386cff..eb1e912 100644 --- a/arch/arm64/kernel/idle_states.c +++ b/arch/arm64/kernel/idle_states.c @@ -31,6 +31,7 @@ struct protocol_init { }; static const struct protocol_init protocols[] __initconst = { + {"arm,psci", psci_register_idle_states}, {} }; diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 4f97db3..fe01589 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -18,12 +18,15 @@ #include #include #include +#include #include #include #include +#include #include #include +#include #define PSCI_POWER_STATE_TYPE_STANDBY 0 #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 @@ -54,6 +57,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]; #define PSCI_RET_SUCCESS 0 @@ -94,6 +99,17 @@ static u32 psci_power_state_pack(struct psci_power_state state) << PSCI_POWER_STATE_AFFL_SHIFT); } +static void psci_power_state_unpack(u32 power_state, + struct psci_power_state *state) +{ + state->id = (power_state >> PSCI_POWER_STATE_ID_SHIFT) + & PSCI_POWER_STATE_ID_MASK; + state->type = (power_state >> PSCI_POWER_STATE_TYPE_SHIFT) + & PSCI_POWER_STATE_TYPE_MASK; + state->affinity_level = (power_state >> PSCI_POWER_STATE_AFFL_SHIFT) + & PSCI_POWER_STATE_AFFL_MASK; +} + /* * The following two functions are invoked via the invoke_psci_fn pointer * and will not be inlined, allowing us to piggyback on the AAPCS. @@ -176,6 +192,59 @@ static const struct of_device_id psci_of_match[] __initconst = { {}, }; +int __init psci_register_idle_states(struct cpumask *cpumask, + struct idle_state *idle_states, + unsigned int count) +{ + int cpu, i; + struct psci_power_state *psci_states; + const struct cpu_operations *cpu_ops_ptr; + + if (!idle_states) + return -EINVAL; + /* + * This is belt-and-braces: make sure that if the idle + * specified protocol is psci, the cpu_ops have been + * initialized to psci operations. Anything else is + * a recipe for mayhem. + */ + for_each_cpu(cpu, cpumask) { + cpu_ops_ptr = cpu_ops[cpu]; + if (WARN_ON(!cpu_ops_ptr || strcmp(cpu_ops_ptr->name, "psci"))) + return -EOPNOTSUPP; + } + + psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); + + if (!psci_states) { + pr_warn("psci idle state allocation failed\n"); + return -ENOMEM; + } + + for_each_cpu(cpu, cpumask) { + if (per_cpu(psci_power_state, cpu)) { + pr_warn("idle states already initialized on cpu %u\n", + cpu); + continue; + } + per_cpu(psci_power_state, cpu) = psci_states; + } + + /* + * Index 0 is always considered as standby wfi + */ + psci_states[0].type = PSCI_POWER_STATE_TYPE_STANDBY; + + for (i = 1; i < count; i++) { + pr_debug("psci-power-state %#x index %u\n", + idle_states[i].state->param, i); + psci_power_state_unpack(idle_states[i].state->param, + &psci_states[i]); + } + + return 0; +} + int __init psci_init(void) { struct device_node *np; @@ -282,6 +351,18 @@ static void cpu_psci_cpu_die(unsigned int cpu) } #endif +#ifdef CONFIG_ARM64_CPU_SUSPEND +static int cpu_psci_cpu_suspend(unsigned long index) +{ + struct psci_power_state *state = __get_cpu_var(psci_power_state); + + if (!state) + return -EOPNOTSUPP; + + return psci_ops.cpu_suspend(state[index], virt_to_phys(cpu_resume)); +} +#endif + const struct cpu_operations cpu_psci_ops = { .name = "psci", .cpu_init = cpu_psci_cpu_init, @@ -291,6 +372,9 @@ const struct cpu_operations cpu_psci_ops = { .cpu_disable = cpu_psci_cpu_disable, .cpu_die = cpu_psci_cpu_die, #endif +#ifdef CONFIG_ARM64_CPU_SUSPEND + .cpu_suspend = cpu_psci_cpu_suspend, +#endif }; #endif