From patchwork Fri May 5 15:02:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abel Vesa X-Patchwork-Id: 679394 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF58BC7EE22 for ; Fri, 5 May 2023 15:03:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232361AbjEEPDB (ORCPT ); Fri, 5 May 2023 11:03:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44190 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232033AbjEEPC7 (ORCPT ); Fri, 5 May 2023 11:02:59 -0400 Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4CC7017FDB for ; Fri, 5 May 2023 08:02:58 -0700 (PDT) Received: by mail-wm1-x331.google.com with SMTP id 5b1f17b1804b1-3f1950f569eso13419455e9.2 for ; Fri, 05 May 2023 08:02:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1683298977; x=1685890977; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wnwRc6d0+9EWZZzimRgYOvHwHdEA2vECtr+bww8AbFg=; b=FibUsG3XI9Lq7wQ10qHYw/Bvt6sUQW4LEEw3nWXXvzewtyxloN0yZOkBzvfttujGim vFuP0GcJta/xmjbRYfKkiefgfPljvOLCmDY+0Tgsdsp19o9n5gEKo1Gj1zbWYg7Nf2tZ UCrzqRNmkJMrp7xnq9s9QSQ/LnF+qK7X/2Jh6eNcQxEdIEL/sVMzTsHZ57nTC/44lee1 p2eCF1D9kOyvOCrc0QSM1K23acPCaZeJAuKMf4omicQI9iSY8qLbrYMEfImx8ioyAKxe W1OfYq9B+1cLYhMFilkzud3FPlXJD9hk2esMl5kBpPXhYS0V/WTtByoTE7bcB+wBw1tJ mcBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683298977; x=1685890977; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wnwRc6d0+9EWZZzimRgYOvHwHdEA2vECtr+bww8AbFg=; b=O4BgMZuTM61x2d9IhDDaTROwZDKZxYhSRhhYAZbpabmKKQ0GG0ouzZjfFK0f+UPowz nNngUiluE1jk0T7bZ+tWGO1NZ+8p6u6NaCsXRcORtJVqiLijbcUE8gWpH9NaxNf5V5Ah xi+Vzkoh4qs/lvEKmoGWcy2jwVW4/ao15PvgEI75LsUn7oFoG35BvrnhOafJb4vnQhs4 jT1nKphDOuyiEf3SgVBgVKLlH5e9nYk1utBssBIf4+EU2mLNNLAA6TNh/FYAlm/8wdma 9MAkK49nToS6BQPdpGki7K29aYS3sH4k5CcZIj/hqi+5YGDTMCt3Yea7oofSQVYDFd+P 8AyA== X-Gm-Message-State: AC+VfDyXZMXyJllLRNC1si/7Z2VmWRJ/aYHMBh4+NjGe5Ebq+gt23q3R EfrIB3gCYaNIbNZMhk+2spCkgg== X-Google-Smtp-Source: ACHHUZ4orA7JAVJkHC48E6ikDofmVT5wSbQFY3BgobWZT+r3BuhvDX8LQwhPbFjsUaNlsygGnWg7Fg== X-Received: by 2002:a05:600c:2293:b0:3f3:1fa6:d2a8 with SMTP id 19-20020a05600c229300b003f31fa6d2a8mr1436996wmf.25.1683298976745; Fri, 05 May 2023 08:02:56 -0700 (PDT) Received: from hackbox.lan ([86.121.163.20]) by smtp.gmail.com with ESMTPSA id a6-20020a1cf006000000b003f0aefcc457sm8262189wmb.45.2023.05.05.08.02.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 May 2023 08:02:56 -0700 (PDT) From: Abel Vesa To: "Rafael J . Wysocki" , Kevin Hilman , Ulf Hansson , Pavel Machek , Len Brown , Greg Kroah-Hartman , Bjorn Andersson , Andy Gross , Konrad Dybcio , Mike Turquette , Stephen Boyd , Saravana Kannan , Matthias Kaehlcke Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, Doug Anderson Subject: [RFC PATCH v4 2/2] PM: domains: Skip disabling unused until sync state Date: Fri, 5 May 2023 18:02:41 +0300 Message-Id: <20230505150241.3469424-3-abel.vesa@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230505150241.3469424-1-abel.vesa@linaro.org> References: <20230505150241.3469424-1-abel.vesa@linaro.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org By storing the status of the domain at boot, specified by the provider, we can decide to skip powering 'off' the domain on the late initcall, strictly based on the status boot being 'on' or 'unknown', and then assume the provider will disable it from its sync state callback. Also, provide a generic genpd sync state callback for those providers that only need that when they state synced. Signed-off-by: Abel Vesa --- drivers/base/power/domain.c | 51 +++++++++++++++++++++++++++++++++++-- include/linux/pm_domain.h | 5 ++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 33a3945c023e..9cc0ce43b47b 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -125,6 +125,7 @@ static const struct genpd_lock_ops genpd_spin_ops = { #define genpd_unlock(p) p->lock_ops->unlock(p) #define genpd_status_on(genpd) (genpd->status == GENPD_STATE_ON) +#define genpd_boot_keep_on(genpd) (!(genpd->boot_status == GENPD_STATE_OFF)) #define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE) #define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) #define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP) @@ -654,6 +655,29 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) queue_work(pm_wq, &genpd->power_off_work); } +/** + * pm_genpd_power_off_unused_sync_state - Power off all domains for provider. + * @dev: Provider's device. + * + * Request power off for all unused domains of the provider. + * This should be used exclusively as sync state callback for genpd providers. + */ +void pm_genpd_power_off_unused_sync_state(struct device *dev) +{ + struct generic_pm_domain *genpd; + + mutex_lock(&gpd_list_lock); + + list_for_each_entry(genpd, &gpd_list, gpd_list_node) + if (genpd->provider->dev == dev && genpd_boot_keep_on(genpd)) { + genpd->boot_status = GENPD_STATE_OFF; + genpd_queue_power_off_work(genpd); + } + + mutex_unlock(&gpd_list_lock); +} +EXPORT_SYMBOL_GPL(pm_genpd_power_off_unused_sync_state); + /** * genpd_power_off - Remove power from a given PM domain. * @genpd: PM domain to power down. @@ -674,6 +698,12 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, unsigned int not_suspended = 0; int ret; + /* + * If the domain was left enabled at boot stage, + * abort power off until sync state is reached. + */ + if (genpd_boot_keep_on(genpd)) + return -EBUSY; /* * Do not try to power off the domain in the following situations: * (1) The domain is already in the "power off" state. @@ -763,6 +793,12 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth) struct gpd_link *link; int ret = 0; + /* + * Just in case this is the first power on request, mark the boot + * status of it as 'off'. + */ + genpd->boot_status = GENPD_STATE_OFF; + if (genpd_status_on(genpd)) return 0; @@ -1095,8 +1131,16 @@ static int __init genpd_power_off_unused(void) mutex_lock(&gpd_list_lock); + /* + * If the provider has registered a 'sync state' callback, + * assume that callback will power off its registered unused domains, + * otherwise we power them off from here. + */ list_for_each_entry(genpd, &gpd_list, gpd_list_node) - genpd_queue_power_off_work(genpd); + if (!dev_has_sync_state(&genpd->dev)) { + genpd->boot_status = GENPD_STATE_OFF; + genpd_queue_power_off_work(genpd); + } mutex_unlock(&gpd_list_lock); @@ -1124,6 +1168,9 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, { struct gpd_link *link; + if (genpd_boot_keep_on(genpd)) + return; + if (!genpd_status_on(genpd) || genpd_is_always_on(genpd)) return; @@ -2064,7 +2111,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd, genpd->gov = gov; INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); atomic_set(&genpd->sd_count, 0); - genpd->status = boot_status; + genpd->status = genpd->boot_status = boot_status; genpd->device_count = 0; genpd->provider = NULL; genpd->has_provider = false; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index c545e44ee52b..86bb531a319c 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -132,6 +132,7 @@ struct generic_pm_domain { const char *name; atomic_t sd_count; /* Number of subdomains with power "on" */ enum gpd_status status; /* Current state of the domain */ + enum gpd_status boot_status; /* Boot state of the domain */ unsigned int device_count; /* Number of devices */ unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ @@ -233,6 +234,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd, struct dev_power_governor *gov, enum gpd_status boot_status); int pm_genpd_remove(struct generic_pm_domain *genpd); +void pm_genpd_power_off_unused_sync_state(struct device *dev); int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state); int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb); int dev_pm_genpd_remove_notifier(struct device *dev); @@ -281,6 +283,9 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd) return -EOPNOTSUPP; } +static inline void pm_genpd_power_off_unused_sync_state(struct device *dev) +{ } + static inline int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) {