From patchwork Wed Aug 5 16:32:45 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lina Iyer X-Patchwork-Id: 6951841 X-Patchwork-Delegate: agross@codeaurora.org Return-Path: X-Original-To: patchwork-linux-arm-msm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 832229F39D for ; Wed, 5 Aug 2015 16:35:11 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8B1282050E for ; Wed, 5 Aug 2015 16:35:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8DD3C204AB for ; Wed, 5 Aug 2015 16:35:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753329AbbHEQeJ (ORCPT ); Wed, 5 Aug 2015 12:34:09 -0400 Received: from mail-pa0-f52.google.com ([209.85.220.52]:35724 "EHLO mail-pa0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753306AbbHEQdS (ORCPT ); Wed, 5 Aug 2015 12:33:18 -0400 Received: by pabxd6 with SMTP id xd6so22267806pab.2 for ; Wed, 05 Aug 2015 09:33:18 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=t5JJYEagOkXACCQC/HooRSLVAzzmqo50GfXtAt7aZM8=; b=Tl05YhR0VD7Ky9HWBkBHSfkrKyIRKBm2GFpJTwWVOnyXJVkk50NQAkCJrtg+wWXjHd e8v+Pm86WuKy5vdAMTbDhn9uISXAePIpUJ4zpnpIDhq2QXoO6C7Wc3Kb2gWcZqgQMuEt LLENv3uYJEUF3PpEuOKrhjLPejWt9PzC/C+VEipPy9TC43nbdiyZ87Bs6fmsH/cdcyt7 30X0IUONBazcVKl2DdH/EfWHtHM8kBP7BznLnv3nFG8ubDbbFPx57n8K3Z0WtkIwCisy dAFjfNZoUF2oyQfjlLA7G9nGCTZwgkbrljKfL/BRpsV2GHnLEG0b2fjdO7GruMb0QdxZ L0YQ== X-Gm-Message-State: ALoCoQnpPJM7PdmzfsTOMb9inaBC4HgwXI/uADIeRiquhluCsYYI3ptJTJxtyVe9IphwbgXYuHMt X-Received: by 10.66.255.67 with SMTP id ao3mr21096772pad.60.1438792398098; Wed, 05 Aug 2015 09:33:18 -0700 (PDT) Received: from ubuntu.localdomain (i-global254.qualcomm.com. [199.106.103.254]) by smtp.gmail.com with ESMTPSA id oq10sm3434036pdb.75.2015.08.05.09.33.16 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 05 Aug 2015 09:33:17 -0700 (PDT) From: Lina Iyer To: linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org Cc: agross@codeaurora.org, msivasub@codeaurora.org, sboyd@codeaurora.org, robh@kernel.org, Lina Iyer Subject: [PATCH RFC 09/10] drivers: qcom: spm: Use hwspinlock to serialize entry into SCM Date: Wed, 5 Aug 2015 10:32:45 -0600 Message-Id: <1438792366-2737-10-git-send-email-lina.iyer@linaro.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1438792366-2737-1-git-send-email-lina.iyer@linaro.org> References: <438731339-58317-1-git-send-email-lina.iyer@linaro.org> <1438792366-2737-1-git-send-email-lina.iyer@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Spam-Status: No, score=-7.0 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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 When the last CPU enters idle, the state of L2 is determined and the power controller for the L2 is programmed to power down. The power controllers' state machine is only triggered when all the CPUs have executed their WFI instruction. Multiple CPUs may enter SCM to power down at the same time. Linux identifies the last man down and determines the state of the cluster, but an FIQ could have kept another CPU busy. The last CPU to enter SCM may not be the last CPU as determined by Linux. So the state of the cluster would not be correctly relayed to the SCM. To ensure that the last CPU in Linux is the same in SCM, serialize the entry into SCM. Linux is responsible for flushing non-secure L2, while SCM flushes only the secure lines of L2. Invalidation for secure and non-secure L2 is done by the SCM when the first CPU resumes from idle. An example of the last man race - Say there are two cores powering down - CoreA and CoreB CoreA enters idle is not the last core and about to call into SCM CoreB enters idle and is the last core, determines L2 should be flushed CoreB receives an FIQ and gets busy handling the FIQ CoreA has an pending IRQ, bails out of SCM and cpuidle CoreB is still busy CoreA enters cpuidle again and now is the last core CoreA determines L2 should *not* be flushed and calls SCM CoreB finishes FIQ, enters SCM with a stale L2 state (L2 to be flushed) SCM records L2 as flushed and invalidates L2 when a core comes up. To avoid this race, serialize all entry from Linux to SCM for cpuidle. A hwspinlock is locked by Linux and released by the SCM when the context switches to Secure. This way, the last man view of both Linux and SCM, match with that of the L2 power controller configuration. A raw hwspinlock would not use s/w spinlocks around the hwspinlock. Since there is no possiblity of preemption in cpuidle, it is safe to use the raw variant of the hwspinlock. Signed-off-by: Lina Iyer --- drivers/soc/qcom/Kconfig | 1 + drivers/soc/qcom/spm.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index b6c2e5d..cb50efb 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -18,6 +18,7 @@ config QCOM_PM select PM_GENERIC_DOMAINS select PM_GENERIC_DOMAINS_SLEEP select PM_GENERIC_DOMAINS_OF + select HWSPINLOCK_QCOM help QCOM Platform specific power driver to manage cores and L2 low power modes. It interface with various system drivers to put the cores in diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index b6d75db..bd09514 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -38,6 +40,7 @@ #define SPM_CTL_INDEX 0x7f #define SPM_CTL_INDEX_SHIFT 4 #define SPM_CTL_EN BIT(0) +#define QCOM_PC_HWLOCK 7 enum pm_sleep_mode { PM_SLEEP_MODE_STBY, @@ -139,6 +142,7 @@ static int l2_flush_flag; typedef int (*idle_fn)(int); static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops); +static struct hwspinlock *remote_lock; static inline void spm_register_write(struct spm_driver_data *drv, enum spm_reg reg, u32 val) @@ -198,6 +202,24 @@ static int qcom_pm_collapse(unsigned long int unused) if (l2_flush_flag == QCOM_SCM_CPU_PWR_DOWN_L2_OFF) flush_cache_all(); + /* + * Wait and acquire the hwspin lock to synchronize + * the entry into SCM. The view of the last core in Linux + * should be same for SCM so the l2_flush_flag is correct. + * + * * IMPORTANT * + * 1. SCM unlocks this lock. + * 2. We do not want to call api that would spinlock before + * acquiring the hwspin lock. It will not be unlocked. + * So call raw variant + * 3. Every core needs to acquire this lock and the entry into + * SCM would be serialized after this point. + */ + if (remote_lock) { + while (hwspin_trylock_raw(remote_lock)) + ; + } + qcom_scm_cpu_power_down(l2_flush_flag); /* @@ -439,6 +461,10 @@ static int spm_dev_probe(struct platform_device *pdev) else per_cpu(cpu_spm_drv, index) = drv; + /* Initialize hwspinlock, to serialize entry into secure */ + if (!remote_lock && of_match_node(cache_spm_table, pdev->dev.of_node)) + remote_lock = hwspin_lock_request_specific(QCOM_PC_HWLOCK); + dev_dbg(&pdev->dev, "SPM device probed.\n"); return 0; }