From patchwork Fri Apr 24 16:46:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11508607 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8523A81 for ; Fri, 24 Apr 2020 16:47:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6D24420728 for ; Fri, 24 Apr 2020 16:47:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="QsUZIst0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728119AbgDXQrT (ORCPT ); Fri, 24 Apr 2020 12:47:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726793AbgDXQrT (ORCPT ); Fri, 24 Apr 2020 12:47:19 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6E96AC09B047 for ; Fri, 24 Apr 2020 09:47:19 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id g6so4868998pgs.9 for ; Fri, 24 Apr 2020 09:47:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=8LMkNBqXB+CeQceWfD+1N1s9IOWokLMqWssX/DZezGQ=; b=QsUZIst0n7NitTwTbPskwHB/A9M3npMfgM+TRceAN2YLnBjo7TiuFLgIDIAlNhloZQ Hhw57EsdqXMyumDsh1p+qtH9Zn5ICKQGQ58SLXj71jnWAYQwMA/6Pufm5DvprHi4Cef4 rH4sHfsgJYbQ0P7x2TuhVvmMmpEyWPlY6KftQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=8LMkNBqXB+CeQceWfD+1N1s9IOWokLMqWssX/DZezGQ=; b=Q161pK9PaqwacDpdTdKr+4EhcvSU+v95iBdXc60eD64+SjLQ5zABn1TGB5I4NyUIsY vuL6MfuSNGGEIq3Fm4F5UD9tvm4pmpsk4tH+rEHQdWvA6K/ezE5Ct9zjNgH1R4xLgMl2 HwmcUEcYcY/BggzPr80J19+E9fKSfoxcAjTLd/fJ8gkk7Qc5McbyDj79M3p60cb0FLKj qFzJkoKYnLU7uyxUFOhXfNe6sHajvU9YSZsd1jwUWMQ2rkpVEFyM7GXCbi4rOyHtgwUJ 8k3m1iAygbI6lavP7vV99Hs0TGSRJxlQ0JCBr55kqznHcJ6QQ1gCDIY5SzvdY7ol2WU4 2ZYQ== X-Gm-Message-State: AGi0PuYKeFvfyGbKoskBaLcCoVyjN+2QKJ0l6UIqDOtRvzsqhkqFAFYQ rKDTYpc3GehzHT6Ec/K1cDV3Rw== X-Google-Smtp-Source: APiQypJWdVuaFCmqhM/KqVMwq1a10HxnD754ZLgp0ghuRAORQk+vl0gQ1jCPIlxmNdNeTKvaSlm4aw== X-Received: by 2002:a63:f30a:: with SMTP id l10mr10233893pgh.372.1587746838702; Fri, 24 Apr 2020 09:47:18 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id r28sm6319205pfg.186.2020.04.24.09.47.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Apr 2020 09:47:17 -0700 (PDT) From: Douglas Anderson To: Greg Kroah-Hartman , rafael.j.wysocki@intel.com, Andy Gross , Bjorn Andersson Cc: evgreen@chromium.org, mka@chromium.org, mkshah@codeaurora.org, swboyd@chromium.org, Douglas Anderson , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 1/5] soc: qcom: rpmh-rsc: Correctly ignore CPU_CLUSTER_PM notifications Date: Fri, 24 Apr 2020 09:46:53 -0700 Message-Id: <20200424094610.v5.1.Ic7096b3b9b7828cdd41cd5469a6dee5eb6abf549@changeid> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog MIME-Version: 1.0 Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Our switch statement doesn't have entries for CPU_CLUSTER_PM_ENTER, CPU_CLUSTER_PM_ENTER_FAILED, and CPU_CLUSTER_PM_EXIT and doesn't have a default. This means that we'll try to do a flush in those cases but we won't necessarily be the last CPU down. That's not so ideal since our (lack of) locking assumes we're on the last CPU. Luckily this isn't as big a problem as you'd think since (at least on the SoC I tested) we don't get these notifications except on full system suspend. ...and on full system suspend we get them on the last CPU down. That means that the worst problem we hit is flushing twice. Still, it's good to make it correct. Fixes: 985427f997b6 ("soc: qcom: rpmh: Invoke rpmh_flush() for dirty caches") Reported-by: Stephen Boyd Signed-off-by: Douglas Anderson Reviewed-by: Maulik Shah Reviewed-by: Stephen Boyd --- Changes in v5: - Corrently => Correctly Changes in v4: - ("...Corrently ignore CPU_CLUSTER_PM notifications") split out for v4. Changes in v3: None Changes in v2: None drivers/soc/qcom/rpmh-rsc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index a9e15699f55f..3571a99fc839 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -806,6 +806,8 @@ static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb, case CPU_PM_EXIT: cpumask_clear_cpu(smp_processor_id(), &drv->cpus_entered_pm); goto exit; + default: + return NOTIFY_DONE; } ret = rpmh_rsc_ctrlr_is_busy(drv); From patchwork Fri Apr 24 16:46:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11508635 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AF74C81 for ; Fri, 24 Apr 2020 16:47:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 97E2A20774 for ; Fri, 24 Apr 2020 16:47:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="L/h+pXon" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728577AbgDXQrW (ORCPT ); Fri, 24 Apr 2020 12:47:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727021AbgDXQrV (ORCPT ); Fri, 24 Apr 2020 12:47:21 -0400 Received: from mail-pg1-x544.google.com (mail-pg1-x544.google.com [IPv6:2607:f8b0:4864:20::544]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2C48DC09B046 for ; Fri, 24 Apr 2020 09:47:21 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id r4so4875614pgg.4 for ; Fri, 24 Apr 2020 09:47:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=E3KjD6DEHWViNkrcMMSN/omOCLanYpgnv+lBLaBhKo0=; b=L/h+pXonieUaKE73C74m7aMrsu8HHy+pR/uPK4uZDzSdlYpkfZZFlHeFh8cuAkVGnR 9LMNHSbA35LlAXdwElE2wq/ptphsPvR5QFW+Fy5fz9fznaea8oujzZldCqIkd1UBld40 xChpGFiZVBUmj51foycCY7G4sC9kIwiEVfO/g= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=E3KjD6DEHWViNkrcMMSN/omOCLanYpgnv+lBLaBhKo0=; b=r6iNUh59sOYpReUZKK1w/rWRvXrYgomDL6FoA9gLcrg+LySTKfi0Y+uKrppyNYDWRI 59Bh+ch83f6pFaVQn68VQnAQ41mWZms1Yd/X9zfFP0j/0Y2ZA7NCNVnXlMV76lo1g2lF Z7O8emAHLHcdJU5Iq24iErRbKCReTFiHeg98KXDRU9iNR/HFJ7/9LkdJSVsR+ESQKYdU yxWENx+6+Q4pP5YZjyGIE7bLKZdWL8bcoXFFOKk9Fi958yjZ4tqgUHhlJvYT4E2T7aGU qAohAEOM5NYxhHshZwy/CsM6FCHgRn3oxrnY9rUL3W4luGkQW5ONNFkV6S4MzfkHFxKp oX/g== X-Gm-Message-State: AGi0PuZR/DGfOF+XEnfXSnlrtSF0O3gCH6ohlE+Eh2OEqOnY9VNrsEAM JmAyFd7zP5m47+Aztp+oeIeJ7A== X-Google-Smtp-Source: APiQypJS5Vu2StLAphXoyH18FEjHXWpUyRYfnNWIgp88nn9o0an/t8A9h4S6g8LYSa3anEqvIzef7A== X-Received: by 2002:a63:f50c:: with SMTP id w12mr9858798pgh.253.1587746840689; Fri, 24 Apr 2020 09:47:20 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id r28sm6319205pfg.186.2020.04.24.09.47.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Apr 2020 09:47:19 -0700 (PDT) From: Douglas Anderson To: Greg Kroah-Hartman , rafael.j.wysocki@intel.com, Andy Gross , Bjorn Andersson Cc: evgreen@chromium.org, mka@chromium.org, mkshah@codeaurora.org, swboyd@chromium.org, Douglas Anderson , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 2/5] soc: qcom: rpmh-rsc: We aren't notified of our own failure w/ NOTIFY_BAD Date: Fri, 24 Apr 2020 09:46:54 -0700 Message-Id: <20200424094610.v5.2.I1927d1bca2569a27b2d04986baf285027f0818a2@changeid> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog In-Reply-To: <20200424094610.v5.1.Ic7096b3b9b7828cdd41cd5469a6dee5eb6abf549@changeid> References: <20200424094610.v5.1.Ic7096b3b9b7828cdd41cd5469a6dee5eb6abf549@changeid> MIME-Version: 1.0 Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org When a PM Notifier returns NOTIFY_BAD it doesn't get called with CPU_PM_ENTER_FAILED. It only get called for CPU_PM_ENTER_FAILED if someone else (further down the notifier chain) returns NOTIFY_BAD. Handle this case by taking our CPU out of the list of ones that have entered PM. Without this it's possible we could detect that the last CPU went down (and we would flush) even if some CPU was alive. That's not good since our flushing routines currently assume they're running on the last CPU for mutual exclusion. Fixes: 985427f997b6 ("soc: qcom: rpmh: Invoke rpmh_flush() for dirty caches") Signed-off-by: Douglas Anderson Reviewed-by: Maulik Shah Reviewed-by: Stephen Boyd --- Changes in v5: None Changes in v4: - ("...We aren't notified of our own failure...") split out for v4. Changes in v3: None Changes in v2: None drivers/soc/qcom/rpmh-rsc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 3571a99fc839..e540e49fd61c 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -823,6 +823,10 @@ static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb, ret = NOTIFY_OK; exit: + if (ret == NOTIFY_BAD) + /* We won't be called w/ CPU_PM_ENTER_FAILED */ + cpumask_clear_cpu(smp_processor_id(), &drv->cpus_entered_pm); + spin_unlock(&drv->pm_lock); return ret; } From patchwork Fri Apr 24 16:46:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11508623 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 93DE015AB for ; Fri, 24 Apr 2020 16:47:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6FCA421556 for ; Fri, 24 Apr 2020 16:47:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="anMh/gpG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728664AbgDXQr1 (ORCPT ); Fri, 24 Apr 2020 12:47:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36450 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728575AbgDXQrZ (ORCPT ); Fri, 24 Apr 2020 12:47:25 -0400 Received: from mail-pg1-x541.google.com (mail-pg1-x541.google.com [IPv6:2607:f8b0:4864:20::541]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3A1D2C09B047 for ; Fri, 24 Apr 2020 09:47:24 -0700 (PDT) Received: by mail-pg1-x541.google.com with SMTP id o10so4875978pgb.6 for ; Fri, 24 Apr 2020 09:47:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DlbMzsVP92mS9LVkheQwBLWwhs/wCWhGqHUKlJRd3Zk=; b=anMh/gpGlng+/GdOk/KtuufXhSHvjb3Xg5RwpWu7kDoaxfwXo9Xy56LEKeO0T1L9IS vyvNhjwKfOJMnUIZ+Z43SmvH4ZCdSWdGrrn8X8JxOmgNmwgq1w2yvT3MuxUb+R+ww7d/ CnKwgyJAKfLMnwRkrQw3WdnqRLShJktUFlZ9E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DlbMzsVP92mS9LVkheQwBLWwhs/wCWhGqHUKlJRd3Zk=; b=FbAA6MAOQ3aeUbapE3tpIvHHHDb8QqxE8Nfdbpp0MYqOGfRnrn7iRzBopPu7bGO4lO QfpLnWDMTnepv4DQnm7DxgTRgX+R8ESbY45HY1D0FXs1usvT2PCk7aF1t9iXcyfrq7iO BnvSt67b6tvgLM1SjcJm+vJSGh3iBrON22SPS8poH1YhgrFEIbPmvvaKsgVLLeNh3YqC 6rHgV3Q58pC1D314KyeY+Qm2DH0ZKVT1PEtjTwFR87iHYlIy2OklHTSp4bUBZHIkaZ2w ETqMWP/NFyyw0+W878u0UI/P7RAtUykPBE79IKscA+SJCRRfxEcNAxZvnK7n8NSoIc+x SiMg== X-Gm-Message-State: AGi0Pubi4mBQtdhaSbChnY397+8Idf1JwNNj53/w4TOOrq9PhKdPhuEB iz0wl9aV+uXzVM1e7pe7Ox4p4Q== X-Google-Smtp-Source: APiQypJUUh7XgEeHmPzFV4AOAw9Zj6I2wSwm0lMRTnEKKVKtUnmkIn5IDTPw2TroFmgey8viuUmaAw== X-Received: by 2002:aa7:850f:: with SMTP id v15mr10264519pfn.204.1587746843519; Fri, 24 Apr 2020 09:47:23 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id r28sm6319205pfg.186.2020.04.24.09.47.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Apr 2020 09:47:22 -0700 (PDT) From: Douglas Anderson To: Greg Kroah-Hartman , rafael.j.wysocki@intel.com, Andy Gross , Bjorn Andersson Cc: evgreen@chromium.org, mka@chromium.org, mkshah@codeaurora.org, swboyd@chromium.org, Douglas Anderson , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 4/5] soc: qcom: rpmh-rsc: Simplify locking by eliminating the per-TCS lock Date: Fri, 24 Apr 2020 09:46:56 -0700 Message-Id: <20200424094610.v5.4.Ib8dccfdb10bf6b1fb1d600ca1c21d9c0db1ef746@changeid> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog In-Reply-To: <20200424094610.v5.1.Ic7096b3b9b7828cdd41cd5469a6dee5eb6abf549@changeid> References: <20200424094610.v5.1.Ic7096b3b9b7828cdd41cd5469a6dee5eb6abf549@changeid> MIME-Version: 1.0 Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org The rpmh-rsc code had both a driver-level lock (sometimes referred to in comments as drv->lock) and a lock per-TCS. The idea was supposed to be that there would be times where you could get by with just locking a TCS lock and therefor other RPMH users wouldn't be blocked. The above didn't work out so well. Looking at tcs_write() the bigger drv->lock was held for most of the function anyway. Only the __tcs_buffer_write() and __tcs_set_trigger() calls were called without holding the drv->lock. It actually turns out that in tcs_write() we don't need to hold the drv->lock for those function calls anyway even if the per-TCS lock isn't there anymore. From the newly added comments in the code, this is because: - We marked "tcs_in_use" under lock. - Once "tcs_in_use" has been marked nobody else could be writing to these registers until the interrupt goes off. - The interrupt can't go off until we trigger w/ the last line of __tcs_set_trigger(). Thus, from a tcs_write() point of view, the per-TCS lock was useless. Looking at rpmh_rsc_write_ctrl_data(), only the per-TCS lock was held. It turns out, though, that this function already needs to be called with the equivalent of the drv->lock held anyway (we either need to hold drv->lock as we will in a future patch or we need to know no other CPUs could be running as happens today). Specifically rpmh_rsc_write_ctrl_data() might be writing to a TCS that has been borrowed for writing an active transation but it never checks this. Let's eliminate this extra overhead and avoid possible AB BA locking headaches. Suggested-by: Maulik Shah Signed-off-by: Douglas Anderson Reviewed-by: Stephen Boyd --- Changes in v5: - without it the => without holding the - Copy why tcs_write() could release drv->lock early to commit msg. - goto err => goto unlock - Verbosify comment, saying trigger meant end of __tcs_set_trigger(). Changes in v4: None Changes in v3: - ("soc: qcom: rpmh-rsc: Simplify locking...") new for v3. Changes in v2: None drivers/soc/qcom/rpmh-internal.h | 13 ++------ drivers/soc/qcom/rpmh-rsc.c | 55 +++++++++++++++----------------- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index dba8510c0669..1f2857b3f38e 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -28,7 +28,6 @@ struct rsc_drv; * @offset: Start of the TCS group relative to the TCSes in the RSC. * @num_tcs: Number of TCSes in this type. * @ncpt: Number of commands in each TCS. - * @lock: Lock for synchronizing this TCS writes. * @req: Requests that are sent from the TCS; only used for ACTIVE_ONLY * transfers (could be on a wake/sleep TCS if we are borrowing for * an ACTIVE_ONLY transfer). @@ -48,7 +47,6 @@ struct tcs_group { u32 offset; int num_tcs; int ncpt; - spinlock_t lock; const struct tcs_request *req[MAX_TCS_PER_TYPE]; DECLARE_BITMAP(slots, MAX_TCS_SLOTS); }; @@ -103,14 +101,9 @@ struct rpmh_ctrlr { * @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY * transfers, but might show a sleep/wake TCS in use if * it was borrowed for an active_only transfer. You - * must hold both the lock in this struct and the - * tcs_lock for the TCS in order to mark a TCS as - * in-use, but you only need the lock in this structure - * (aka the drv->lock) to mark one freed. - * @lock: Synchronize state of the controller. If you will be - * grabbing this lock and a tcs_lock at the same time, - * grab the tcs_lock first so we always have a - * consistent lock ordering. + * must hold the lock in this struct (AKA drv->lock) in + * order to update this. + * @lock: Synchronize state of the controller. * @pm_lock: Synchronize during PM notifications. * Used when solver mode is not present. * @client: Handle to the DRV's client. diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index e540e49fd61c..8ed39464d9d8 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -179,11 +179,7 @@ static void write_tcs_reg_sync(struct rsc_drv *drv, int reg, int tcs_id, * * Returns true if nobody has claimed this TCS (by setting tcs_in_use). * - * Context: Must be called with the drv->lock held or the tcs_lock for the TCS - * being tested. If only the tcs_lock is held then it is possible that - * this function will return that a tcs is still busy when it has been - * recently been freed but it will never return free when a TCS is - * actually in use. + * Context: Must be called with the drv->lock held. * * Return: true if the given TCS is free. */ @@ -242,8 +238,6 @@ void rpmh_rsc_invalidate(struct rsc_drv *drv) * This is normally pretty straightforward except if we are trying to send * an ACTIVE_ONLY message but don't have any active_only TCSes. * - * Called without drv->lock held and with no tcs_lock locks held. - * * Return: A pointer to a tcs_group or an ERR_PTR. */ static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv, @@ -581,24 +575,19 @@ static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg) if (IS_ERR(tcs)) return PTR_ERR(tcs); - spin_lock_irqsave(&tcs->lock, flags); - spin_lock(&drv->lock); + spin_lock_irqsave(&drv->lock, flags); /* * The h/w does not like if we send a request to the same address, * when one is already in-flight or being processed. */ ret = check_for_req_inflight(drv, tcs, msg); - if (ret) { - spin_unlock(&drv->lock); - goto done_write; - } + if (ret) + goto unlock; - tcs_id = find_free_tcs(tcs); - if (tcs_id < 0) { - ret = tcs_id; - spin_unlock(&drv->lock); - goto done_write; - } + ret = find_free_tcs(tcs); + if (ret < 0) + goto unlock; + tcs_id = ret; tcs->req[tcs_id - tcs->offset] = msg; set_bit(tcs_id, drv->tcs_in_use); @@ -612,13 +601,22 @@ static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg) write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0); enable_tcs_irq(drv, tcs_id, true); } - spin_unlock(&drv->lock); + spin_unlock_irqrestore(&drv->lock, flags); + /* + * These two can be done after the lock is released because: + * - We marked "tcs_in_use" under lock. + * - Once "tcs_in_use" has been marked nobody else could be writing + * to these registers until the interrupt goes off. + * - The interrupt can't go off until we trigger w/ the last line + * of __tcs_set_trigger() below. + */ __tcs_buffer_write(drv, tcs_id, 0, msg); __tcs_set_trigger(drv, tcs_id, true); -done_write: - spin_unlock_irqrestore(&tcs->lock, flags); + return 0; +unlock: + spin_unlock_irqrestore(&drv->lock, flags); return ret; } @@ -673,8 +671,6 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) * Only for use on sleep/wake TCSes since those are the only ones we maintain * tcs->slots for. * - * Must be called with the tcs_lock for the group held. - * * Return: -ENOMEM if there was no room, else 0. */ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg, @@ -709,25 +705,25 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg, * This should only be called for for sleep/wake state, never active-only * state. * + * The caller must ensure that no other RPMH actions are happening and the + * controller is idle when this function is called since it runs lockless. + * * Return: 0 if no error; else -error. */ int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg) { struct tcs_group *tcs; int tcs_id = 0, cmd_id = 0; - unsigned long flags; int ret; tcs = get_tcs_for_msg(drv, msg); if (IS_ERR(tcs)) return PTR_ERR(tcs); - spin_lock_irqsave(&tcs->lock, flags); /* find the TCS id and the command in the TCS to write to */ ret = find_slots(tcs, msg, &tcs_id, &cmd_id); if (!ret) __tcs_buffer_write(drv, tcs_id, cmd_id, msg); - spin_unlock_irqrestore(&tcs->lock, flags); return ret; } @@ -756,8 +752,8 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv) * should be checked for not busy, because we used wake TCSes for * active requests in this case. * - * Since this is called from the last cpu, need not take drv or tcs - * lock before checking tcs_is_free(). + * Since this is called from the last cpu, need not take drv->lock + * before checking tcs_is_free(). */ if (!tcs->num_tcs) tcs = &drv->tcs[WAKE_TCS]; @@ -885,7 +881,6 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev, tcs->type = tcs_cfg[i].type; tcs->num_tcs = tcs_cfg[i].n; tcs->ncpt = ncpt; - spin_lock_init(&tcs->lock); if (!tcs->num_tcs || tcs->type == CONTROL_TCS) continue; From patchwork Fri Apr 24 16:46:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11508619 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7BEF681 for ; Fri, 24 Apr 2020 16:47:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 59CB821582 for ; Fri, 24 Apr 2020 16:47:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="he8pSS7r" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728677AbgDXQrc (ORCPT ); Fri, 24 Apr 2020 12:47:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36458 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728665AbgDXQr1 (ORCPT ); Fri, 24 Apr 2020 12:47:27 -0400 Received: from mail-pg1-x52e.google.com (mail-pg1-x52e.google.com [IPv6:2607:f8b0:4864:20::52e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A2E8C09B046 for ; Fri, 24 Apr 2020 09:47:26 -0700 (PDT) Received: by mail-pg1-x52e.google.com with SMTP id h69so4876840pgc.8 for ; Fri, 24 Apr 2020 09:47:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=orKCNE4hRiBbNhpBcDazavN/nPK49l5HFeijFppdj2o=; b=he8pSS7rqGTjqgq5T+kxHJLZTqgs8701cwiLsQgHIRl3XRlyaZ+rEL9+70LqYUpG+j oRqOf+X6JAYuwVMreSIewoNV4Rrvho1lYN6C8SAQxceTHJMlIZhVeTX2bYNlnkSFDGUl W2ZrPVX3LhJH/XPiXayxShqjS82bIxZTxyGK8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=orKCNE4hRiBbNhpBcDazavN/nPK49l5HFeijFppdj2o=; b=pVJ5PwWQbI5UIPTL8zCzVPc/LhnZdlt9XT7UXWSXsP7MnfQy9a3TlwohnSMNv4D1bi EUF+hOXjRhE/muQUpy9H22xi1F38LA5/ayqNDyImTLWTTau0wPp9VI1esY2SMGJK8V1w E1qaHEW0uLS9hCmPdBRHry0L7u4nZxgKQo6yowQDbq4Sd+R1+0nbDf5nhYPPRxMdNt66 2hXm3wM2mEMSZf7CoSeWPneRs2tsgQd2rjKYO5v5Y5Q7dvMlzhrjD5B9wD3b9UJsyKVA Pc2oY5hhWKY6ooeoMXSoBCRKrgx2qZLeHouDEigGBturadAepBdNIYHtyk0UuQCsHXUe OzCw== X-Gm-Message-State: AGi0PuY5rKJjf1oaCmry02w+/0luu9Jjp0PSpElBIuWP+8A/HmtnK9vn 28/DSMYXz9sCutsH6+fhNZeLQQ== X-Google-Smtp-Source: APiQypIBcmde6jMoK5r2yFBiCpm25INdDDEU8FKHwOh++xVDofqBRE0jczQuE+z6QY//Bj0ifYEYPg== X-Received: by 2002:a63:f211:: with SMTP id v17mr9485956pgh.83.1587746845266; Fri, 24 Apr 2020 09:47:25 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id r28sm6319205pfg.186.2020.04.24.09.47.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Apr 2020 09:47:24 -0700 (PDT) From: Douglas Anderson To: Greg Kroah-Hartman , rafael.j.wysocki@intel.com, Andy Gross , Bjorn Andersson Cc: evgreen@chromium.org, mka@chromium.org, mkshah@codeaurora.org, swboyd@chromium.org, Douglas Anderson , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 5/5] soc: qcom: rpmh-rsc: Remove the pm_lock Date: Fri, 24 Apr 2020 09:46:57 -0700 Message-Id: <20200424094610.v5.5.I295cb72bc5334a2af80313cbe97cb5c9dcb1442c@changeid> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog In-Reply-To: <20200424094610.v5.1.Ic7096b3b9b7828cdd41cd5469a6dee5eb6abf549@changeid> References: <20200424094610.v5.1.Ic7096b3b9b7828cdd41cd5469a6dee5eb6abf549@changeid> MIME-Version: 1.0 Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org It has been postulated that the pm_lock is bad for performance because a CPU currently running rpmh_flush() could block other CPUs from coming out of idle. Similarly CPUs coming out of / going into idle all need to contend with each other for the spinlock just to update the variable tracking who's in PM. Let's optimize this a bit. Specifically: - Use a count rather than a bitmask. This is faster to access and also means we can use the atomic_inc_return() function to really detect who the last one to enter PM was. - Accept that it's OK if we race and are doing the flush (because we think we're last) while another CPU is coming out of idle. As long as we block that CPU if/when it tries to do an active-only transfer we're OK. Signed-off-by: Douglas Anderson Reviewed-by: Stephen Boyd --- Changes in v5: None Changes in v4: - Rebased atop split-out fixes. Changes in v3: - Rebased atop patch to get rid of per-TCS lock. - Removed bogus comment in rpmh_flush(). - thelock => the lock. - Do one last double-check to try to avoid returning NOTIFY_BAD. Changes in v2: - Always grab drv->lock first to ensure lock ordering. - Grab the cache_lock in rpmh_flush(). - Comments about why num_online_cpus() is OK. - Return NOTIFY_DONE for things we don't care about. - Use trylock to avoid spinning in CPU_PM code. - !rpmh_flush() should have been rpmh_flush(), so we were alwys failing. - Account for CPU_PM_ENTER_FAILED not being called if we return NOTIFY_BAD. drivers/soc/qcom/rpmh-internal.h | 11 +++-- drivers/soc/qcom/rpmh-rsc.c | 72 ++++++++++++++++++++------------ drivers/soc/qcom/rpmh.c | 25 +++++++---- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index 1f2857b3f38e..ef60e790a750 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -95,7 +95,7 @@ struct rpmh_ctrlr { * @num_tcs: Number of TCSes in this DRV. * @rsc_pm: CPU PM notifier for controller. * Used when solver mode is not present. - * @cpus_entered_pm: CPU mask for cpus in idle power collapse. + * @cpus_in_pm: Number of CPUs not in idle power collapse. * Used when solver mode is not present. * @tcs: TCS groups. * @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY @@ -103,9 +103,9 @@ struct rpmh_ctrlr { * it was borrowed for an active_only transfer. You * must hold the lock in this struct (AKA drv->lock) in * order to update this. - * @lock: Synchronize state of the controller. - * @pm_lock: Synchronize during PM notifications. - * Used when solver mode is not present. + * @lock: Synchronize state of the controller. If RPMH's cache + * lock will also be held, the order is: drv->lock then + * cache_lock. * @client: Handle to the DRV's client. */ struct rsc_drv { @@ -114,11 +114,10 @@ struct rsc_drv { int id; int num_tcs; struct notifier_block rsc_pm; - struct cpumask cpus_entered_pm; + atomic_t cpus_in_pm; struct tcs_group tcs[TCS_TYPE_NR]; DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR); spinlock_t lock; - spinlock_t pm_lock; struct rpmh_ctrlr client; }; diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 8ed39464d9d8..571aa1012f23 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -737,6 +737,8 @@ int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg) * SLEEP and WAKE sets. If AMCs are busy, controller can not enter * power collapse, so deny from the last cpu's pm notification. * + * Context: Must be called with the drv->lock held. + * * Return: * * False - AMCs are idle * * True - AMCs are busy @@ -751,9 +753,6 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv) * dedicated TCS for active state use, then re-purposed wake TCSes * should be checked for not busy, because we used wake TCSes for * active requests in this case. - * - * Since this is called from the last cpu, need not take drv->lock - * before checking tcs_is_free(). */ if (!tcs->num_tcs) tcs = &drv->tcs[WAKE_TCS]; @@ -788,42 +787,62 @@ static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb, { struct rsc_drv *drv = container_of(nfb, struct rsc_drv, rsc_pm); int ret = NOTIFY_OK; - - spin_lock(&drv->pm_lock); + int cpus_in_pm; switch (action) { case CPU_PM_ENTER: - cpumask_set_cpu(smp_processor_id(), &drv->cpus_entered_pm); - - if (!cpumask_equal(&drv->cpus_entered_pm, cpu_online_mask)) - goto exit; + cpus_in_pm = atomic_inc_return(&drv->cpus_in_pm); + /* + * NOTE: comments for num_online_cpus() point out that it's + * only a snapshot so we need to be careful. It should be OK + * for us to use, though. It's important for us not to miss + * if we're the last CPU going down so it would only be a + * problem if a CPU went offline right after we did the check + * AND that CPU was not idle AND that CPU was the last non-idle + * CPU. That can't happen. CPUs would have to come out of idle + * before the CPU could go offline. + */ + if (cpus_in_pm < num_online_cpus()) + return NOTIFY_OK; break; case CPU_PM_ENTER_FAILED: case CPU_PM_EXIT: - cpumask_clear_cpu(smp_processor_id(), &drv->cpus_entered_pm); - goto exit; + atomic_dec(&drv->cpus_in_pm); + return NOTIFY_OK; default: return NOTIFY_DONE; } - ret = rpmh_rsc_ctrlr_is_busy(drv); - if (ret) { - ret = NOTIFY_BAD; - goto exit; + /* + * It's likely we're on the last CPU. Grab the drv->lock and write + * out the sleep/wake commands to RPMH hardware. Grabbing the lock + * means that if we race with another CPU coming up we are still + * guaranteed to be safe. If another CPU came up just after we checked + * and has grabbed the lock or started an active transfer then we'll + * notice we're busy and abort. If another CPU comes up after we start + * flushing it will be blocked from starting an active transfer until + * we're done flushing. If another CPU starts an active transfer after + * we release the lock we're still OK because we're no longer the last + * CPU. + */ + if (spin_trylock(&drv->lock)) { + if (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client)) + ret = NOTIFY_BAD; + spin_unlock(&drv->lock); + } else { + /* Another CPU must be up */ + return NOTIFY_OK; } - ret = rpmh_flush(&drv->client); - if (ret) - ret = NOTIFY_BAD; - else - ret = NOTIFY_OK; - -exit: - if (ret == NOTIFY_BAD) - /* We won't be called w/ CPU_PM_ENTER_FAILED */ - cpumask_clear_cpu(smp_processor_id(), &drv->cpus_entered_pm); + if (ret == NOTIFY_BAD) { + /* Double-check if we're here because someone else is up */ + if (cpus_in_pm < num_online_cpus()) + ret = NOTIFY_OK; + else + /* We won't be called w/ CPU_PM_ENTER_FAILED */ + atomic_dec(&drv->cpus_in_pm); + } - spin_unlock(&drv->pm_lock); return ret; } @@ -966,7 +985,6 @@ static int rpmh_rsc_probe(struct platform_device *pdev) solver_config = solver_config >> DRV_HW_SOLVER_SHIFT; if (!solver_config) { drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback; - spin_lock_init(&drv->pm_lock); cpu_pm_register_notifier(&drv->rsc_pm); } diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index d1626a1328d7..f2b5b46ccd1f 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -435,9 +435,6 @@ static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state, * * @ctrlr: Controller making request to flush cached data * - * This function is called from sleep code on the last CPU - * (thus no spinlock needed). - * * Return: * * 0 - Success * * Error code - Otherwise @@ -445,13 +442,21 @@ static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state, int rpmh_flush(struct rpmh_ctrlr *ctrlr) { struct cache_req *p; - int ret; + int ret = 0; lockdep_assert_irqs_disabled(); + /* + * Currently rpmh_flush() is only called when we think we're running + * on the last processor. If the lock is busy it means another + * processor is up and it's better to abort than spin. + */ + if (!spin_trylock(&ctrlr->cache_lock)) + return -EBUSY; + if (!ctrlr->dirty) { pr_debug("Skipping flush, TCS has latest data.\n"); - return 0; + goto exit; } /* Invalidate the TCSes first to avoid stale data */ @@ -460,7 +465,7 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr) /* First flush the cached batch requests */ ret = flush_batch(ctrlr); if (ret) - return ret; + goto exit; list_for_each_entry(p, &ctrlr->cache, list) { if (!is_req_valid(p)) { @@ -471,16 +476,18 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr) ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr, p->sleep_val); if (ret) - return ret; + goto exit; ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr, p->wake_val); if (ret) - return ret; + goto exit; } ctrlr->dirty = false; - return 0; +exit: + spin_unlock(&ctrlr->cache_lock); + return ret; } /**