From patchwork Tue Mar 31 01:52:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AceLan Kao X-Patchwork-Id: 1264480 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=uP1MrxqI; dkim-atps=neutral Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48rslK6s6fz9sSL; Tue, 31 Mar 2020 12:52:13 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1jJ64W-0005YR-VA; Tue, 31 Mar 2020 01:52:08 +0000 Received: from mail-pf1-f194.google.com ([209.85.210.194]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1jJ64U-0005Y3-Vj for kernel-team@lists.ubuntu.com; Tue, 31 Mar 2020 01:52:07 +0000 Received: by mail-pf1-f194.google.com with SMTP id 23so9579250pfj.1 for ; Mon, 30 Mar 2020 18:52:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=JfVHWpWPYPGyBNtkcc4zQKLzqWT2pGdtJO8IXdBF/A8=; b=uP1MrxqIygXN7BvCXTaheWaVG57BsMydBz5UIdXciSxN8nZOuK2PpvckP6W93arS9l +QF9XH93WYDUZfH6UGk0TMOhbRu0fs4nXu7tmre5jMVYOxTaMm3bRne0Cp1KkWfp6TnV e0tx5KzDf26uE0PmJsK1KNKA1+J9Y0wupEd8S3rs0H/03s/Q25PH3KCcceMwA/Z++0jm BHuDWBuKdEnuOAjccI7VRz9pzsrjS350aIWSA8K/uKKuKt34Tt+6UFqeCK+nU83vgRnA nKSlTliiAjwrvDfCLGvl4wdmMBn9vL6hbr7VRRnFpHSl5yiaJGQXXhRhT+OidDd8OCNq vnXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=JfVHWpWPYPGyBNtkcc4zQKLzqWT2pGdtJO8IXdBF/A8=; b=pEadI/qfERoldmAAZfYaeNnb16KA+8xfrbqahqIkojdJ96RxSGHXcYyee1RQ3vsxbJ C3qCylS5kYcjomrq633wCdngkxLsluApmLYWgFASYOaqkTAHn7Si46WFUkduzTCKy5le 5cowelgFE1t8e+4BdW+kOJsDLmEDW4Xqz0Di4IEBgdMr7kwJ0ee3xHWu1yPcSylUj7x6 Dc+Xu3Zd5wX7WJ6TK4+OnsCfI2wNh+PTYH/1dUkhQLXKFPYduY8Xkl+V7x+ReMPiDMGi cSZ8HppWhzxLHbVRo8rat1Ae89hg8l5TYh9yNKrQ1KjCpiR6MsBY7TUdmy0BpKVYMcN2 uJIg== X-Gm-Message-State: ANhLgQ1OW1kI75YLNlI6aUzaE9qP8AhXoWcxAkEGK6n5njPM1Qq75yTi kQ8yk90ZcjIqq9hDwvr2Qd1pGt3s3fw= X-Google-Smtp-Source: ADFU+vsEOtRtkPzsmzoF0lWEywEVdpWZzUvMkGYmQOgd0nCPX5bI+6nlp04zJ1HP8ERv+QyaTZp6fw== X-Received: by 2002:a63:4707:: with SMTP id u7mr15597984pga.221.1585619525015; Mon, 30 Mar 2020 18:52:05 -0700 (PDT) Received: from localhost (220-135-95-34.HINET-IP.hinet.net. [220.135.95.34]) by smtp.gmail.com with ESMTPSA id l22sm651977pjq.15.2020.03.30.18.52.04 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 30 Mar 2020 18:52:04 -0700 (PDT) From: AceLan Kao To: kernel-team@lists.ubuntu.com Subject: [PATCH 1/1][SRU][B][OEM-B] PM / runtime: Rework pm_runtime_force_suspend/resume() Date: Tue, 31 Mar 2020 09:52:00 +0800 Message-Id: <20200331015200.1476-2-acelan.kao@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200331015200.1476-1-acelan.kao@canonical.com> References: <20200331015200.1476-1-acelan.kao@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: "Rafael J. Wysocki" BugLink: https://bugs.launchpad.net/bugs/1869642 One of the limitations of pm_runtime_force_suspend/resume() is that if a parent driver wants to use these functions, all of its child drivers generally have to do that too because of the parent usage counter manipulations necessary to get the correct state of the parent during system-wide transitions to the working state (system resume). However, that limitation turns out to be artificial, so remove it. Namely, pm_runtime_force_suspend() only needs to update the children counter of its parent (if there's is a parent) when the device can stay in suspend after the subsequent system resume transition, as that counter is correct already otherwise. Now, if the parent's children counter is not updated, it is not necessary to increment the parent's usage counter in that case any more, as long as the children counters of devices are checked along with their usage counters in order to decide whether or not the devices may be left in suspend after the subsequent system resume transition. Accordingly, modify pm_runtime_force_suspend() to only call pm_runtime_set_suspended() for devices whose usage and children counters are at the "no references" level (the runtime PM status of the device needs to be updated to "suspended" anyway in case this function is called once again for the same device during the transition under way), drop the parent usage counter incrementation from it and update pm_runtime_force_resume() to compensate for these changes. Signed-off-by: Rafael J. Wysocki Reviewed-by: Ulf Hansson (cherry picked from commit 4918e1f87c5fb7fc8f73a7d8fb118beeb94e05f7) Signed-off-by: AceLan Kao Acked-by: Kleber Sacilotto de Souza Acked-by: Andrea Righi --- drivers/base/power/runtime.c | 74 +++++++++++++++++------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 6e89b51ea3d9..84832f1a75bf 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1613,17 +1613,28 @@ void pm_runtime_drop_link(struct device *dev) spin_unlock_irq(&dev->power.lock); } +static bool pm_runtime_need_not_resume(struct device *dev) +{ + return atomic_read(&dev->power.usage_count) <= 1 && + atomic_read(&dev->power.child_count) == 0; +} + /** * pm_runtime_force_suspend - Force a device into suspend state if needed. * @dev: Device to suspend. * * Disable runtime PM so we safely can check the device's runtime PM status and - * if it is active, invoke it's .runtime_suspend callback to bring it into - * suspend state. Keep runtime PM disabled to preserve the state unless we - * encounter errors. + * if it is active, invoke its ->runtime_suspend callback to suspend it and + * change its runtime PM status field to RPM_SUSPENDED. Also, if the device's + * usage and children counters don't indicate that the device was in use before + * the system-wide transition under way, decrement its parent's children counter + * (if there is a parent). Keep runtime PM disabled to preserve the state + * unless we encounter errors. * * Typically this function may be invoked from a system suspend callback to make - * sure the device is put into low power state. + * sure the device is put into low power state and it should only be used during + * system-wide PM transitions to sleep states. It assumes that the analogous + * pm_runtime_force_resume() will be used to resume the device. */ int pm_runtime_force_suspend(struct device *dev) { @@ -1646,17 +1657,18 @@ int pm_runtime_force_suspend(struct device *dev) goto err; /* - * Increase the runtime PM usage count for the device's parent, in case - * when we find the device being used when system suspend was invoked. - * This informs pm_runtime_force_resume() to resume the parent - * immediately, which is needed to be able to resume its children, - * when not deferring the resume to be managed via runtime PM. + * If the device can stay in suspend after the system-wide transition + * to the working state that will follow, drop the children counter of + * its parent, but set its status to RPM_SUSPENDED anyway in case this + * function will be called again for it in the meantime. */ - if (dev->parent && atomic_read(&dev->power.usage_count) > 1) - pm_runtime_get_noresume(dev->parent); + if (pm_runtime_need_not_resume(dev)) + pm_runtime_set_suspended(dev); + else + __update_runtime_status(dev, RPM_SUSPENDED); - pm_runtime_set_suspended(dev); return 0; + err: pm_runtime_enable(dev); return ret; @@ -1669,13 +1681,9 @@ EXPORT_SYMBOL_GPL(pm_runtime_force_suspend); * * Prior invoking this function we expect the user to have brought the device * into low power state by a call to pm_runtime_force_suspend(). Here we reverse - * those actions and brings the device into full power, if it is expected to be - * used on system resume. To distinguish that, we check whether the runtime PM - * usage count is greater than 1 (the PM core increases the usage count in the - * system PM prepare phase), as that indicates a real user (such as a subsystem, - * driver, userspace, etc.) is using it. If that is the case, the device is - * expected to be used on system resume as well, so then we resume it. In the - * other case, we defer the resume to be managed via runtime PM. + * those actions and bring the device into full power, if it is expected to be + * used on system resume. In the other case, we defer the resume to be managed + * via runtime PM. * * Typically this function may be invoked from a system resume callback. */ @@ -1684,32 +1692,18 @@ int pm_runtime_force_resume(struct device *dev) int (*callback)(struct device *); int ret = 0; - callback = RPM_GET_CALLBACK(dev, runtime_resume); - - if (!callback) { - ret = -ENOSYS; - goto out; - } - - if (!pm_runtime_status_suspended(dev)) + if (!pm_runtime_status_suspended(dev) || pm_runtime_need_not_resume(dev)) goto out; /* - * Decrease the parent's runtime PM usage count, if we increased it - * during system suspend in pm_runtime_force_suspend(). - */ - if (atomic_read(&dev->power.usage_count) > 1) { - if (dev->parent) - pm_runtime_put_noidle(dev->parent); - } else { - goto out; - } + * The value of the parent's children counter is correct already, so + * just update the status of the device. + */ + __update_runtime_status(dev, RPM_ACTIVE); - ret = pm_runtime_set_active(dev); - if (ret) - goto out; + callback = RPM_GET_CALLBACK(dev, runtime_resume); - ret = callback(dev); + ret = callback ? callback(dev) : -ENOSYS; if (ret) { pm_runtime_set_suspended(dev); goto out;