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: 6952111 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.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9BD229F39D for ; Wed, 5 Aug 2015 16:38:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 99F1720155 for ; Wed, 5 Aug 2015 16:38:05 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A35AF2012B for ; Wed, 5 Aug 2015 16:38:04 +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 1ZN1fX-0007HI-Sg; Wed, 05 Aug 2015 16:35:55 +0000 Received: from casper.infradead.org ([2001:770:15f::2]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZN1dP-0004XW-KM for linux-arm-kernel@bombadil.infradead.org; Wed, 05 Aug 2015 16:33:43 +0000 Received: from mail-pa0-f48.google.com ([209.85.220.48]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZN1dN-00060m-1N for linux-arm-kernel@lists.infradead.org; Wed, 05 Aug 2015 16:33:42 +0000 Received: by pacrr5 with SMTP id rr5so4924267pac.3 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=anq12YoJHWTrOEJ7AvKAqsGzZbtGrGV1fmT0yeYkmzlqGvaswkUICVkHIIOR2rsSYe fct9f9arII1i72YdXw8nWrbJeHCiZlY4SGAjYuR+UPsmjpD5UCgLqz6NCUkVjNsihxDh wSW+oAKNgQKFPZFpxEydy4AQp9vmdlHbNmFBX3+QHuQ5mO3Vob+zDTDdDKOhK1kbVcE/ MNcTMn+Q5XdpDyP6IluT4e0o02+Z4c3rQ7LsWWX8elBA87r3BEhTCKuxzi4eOBQcRl3q 3EoXsy2JKMGFaF1SbRMjpqGjLXZmH9Ia06AFMg8b43pT39/4JjnE2NjdrZFMykclS6kt jPlQ== X-Gm-Message-State: ALoCoQk/zcsTYdoE+Jma2Y5EFc1Zs1Fpd92dFBYtSK6f4vC9iivcDaTNyBvflTrsS1ykRGZe4e3k 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 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> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150805_173341_242981_69875F43 X-CRM114-Status: GOOD ( 26.56 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: msivasub@codeaurora.org, robh@kernel.org, sboyd@codeaurora.org, Lina Iyer , agross@codeaurora.org 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=-4.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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; }