From patchwork Sat Feb 12 22:14:41 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Wysocki X-Patchwork-Id: 552411 Received: from smtp1.linux-foundation.org (smtp1.linux-foundation.org [140.211.169.13]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p1CMKBme024465 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Sat, 12 Feb 2011 22:20:39 GMT Received: from daredevil.linux-foundation.org (localhost [127.0.0.1]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p1CMI8fn030005; Sat, 12 Feb 2011 14:18:09 -0800 Received: from ogre.sisk.pl (ogre.sisk.pl [217.79.144.158]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p1CMFKis029725 for ; Sat, 12 Feb 2011 14:15:22 -0800 Received: from localhost (localhost.localdomain [127.0.0.1]) by ogre.sisk.pl (Postfix) with ESMTP id 6B9FC1A194D; Sat, 12 Feb 2011 23:11:47 +0100 (CET) Received: from ogre.sisk.pl ([127.0.0.1]) by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 22975-08; Sat, 12 Feb 2011 23:11:23 +0100 (CET) Received: from ferrari.rjw.lan (220-bem-13.acn.waw.pl [82.210.184.220]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ogre.sisk.pl (Postfix) with ESMTP id D36A01A512D; Sat, 12 Feb 2011 23:11:22 +0100 (CET) From: "Rafael J. Wysocki" To: "Linux-pm mailing list" Date: Sat, 12 Feb 2011 23:14:41 +0100 User-Agent: KMail/1.13.5 (Linux/2.6.38-rc4+; KDE/4.4.4; x86_64; ; ) References: <201101300107.19389.rjw@sisk.pl> <201102011939.49793.rjw@sisk.pl> <201102122312.26545.rjw@sisk.pl> In-Reply-To: <201102122312.26545.rjw@sisk.pl> MIME-Version: 1.0 Message-Id: <201102122314.41407.rjw@sisk.pl> X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux Received-SPF: pass (localhost is always allowed.) X-Spam-Status: No, hits=-3.942 required=5 tests=AWL, BAYES_00, OSDL_HEADER_SUBJECT_BRACKETED X-Spam-Checker-Version: SpamAssassin 3.2.4-osdl_revision__1.47__ X-MIMEDefang-Filter: lf$Revision: 1.188 $ X-Scanned-By: MIMEDefang 2.63 on 140.211.169.21 Cc: Mark Brown , LKML , Grant Likely Subject: [linux-pm] [RFC][PATCH 2/2] PM: Make system-wide PM and runtime PM handle subsystems consistently X-BeenThere: linux-pm@lists.linux-foundation.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux power management List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-pm-bounces@lists.linux-foundation.org Errors-To: linux-pm-bounces@lists.linux-foundation.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sat, 12 Feb 2011 22:20:39 +0000 (UTC) Index: linux-2.6/drivers/base/power/main.c =================================================================== --- linux-2.6.orig/drivers/base/power/main.c +++ linux-2.6/drivers/base/power/main.c @@ -433,21 +433,17 @@ static int device_resume_noirq(struct de error = pm_noirq_op(dev, dev->bus->pm, state); if (error) goto End; - } - - if (dev->type && dev->type->pm) { + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "EARLY type "); error = pm_noirq_op(dev, dev->type->pm, state); if (error) goto End; - } - - if (dev->class && dev->class->pm) { + } else if (dev->class && dev->class->pm) { pm_dev_dbg(dev, state, "EARLY class "); error = pm_noirq_op(dev, dev->class->pm, state); } -End: + End: TRACE_RESUME(error); return error; } @@ -532,21 +528,18 @@ static int device_resume(struct device * if (dev->bus->pm) { pm_dev_dbg(dev, state, ""); error = pm_op(dev, dev->bus->pm, state); + goto End; } else if (dev->bus->resume) { pm_dev_dbg(dev, state, "legacy "); error = legacy_resume(dev, dev->bus->resume); - } - if (error) goto End; + } } - if (dev->type) { - if (dev->type->pm) { - pm_dev_dbg(dev, state, "type "); - error = pm_op(dev, dev->type->pm, state); - } - if (error) - goto End; + if (dev->type && dev->type->pm) { + pm_dev_dbg(dev, state, "type "); + error = pm_op(dev, dev->type->pm, state); + goto End; } if (dev->class) { @@ -558,6 +551,7 @@ static int device_resume(struct device * error = legacy_resume(dev, dev->class->resume); } } + End: device_unlock(dev); complete_all(&dev->power.completion); @@ -644,19 +638,18 @@ static void device_complete(struct devic dev->pwr_domain->ops.complete(dev); } - if (dev->class && dev->class->pm && dev->class->pm->complete) { - pm_dev_dbg(dev, state, "completing class "); - dev->class->pm->complete(dev); - } - - if (dev->type && dev->type->pm && dev->type->pm->complete) { - pm_dev_dbg(dev, state, "completing type "); - dev->type->pm->complete(dev); - } - - if (dev->bus && dev->bus->pm && dev->bus->pm->complete) { + if (dev->bus && dev->bus->pm) { pm_dev_dbg(dev, state, "completing "); - dev->bus->pm->complete(dev); + if (dev->bus->pm->complete) + dev->bus->pm->complete(dev); + } else if (dev->type && dev->type->pm) { + pm_dev_dbg(dev, state, "completing type "); + if (dev->type->pm->complete) + dev->type->pm->complete(dev); + } else if (dev->class && dev->class->pm) { + pm_dev_dbg(dev, state, "completing class "); + if (dev->class->pm->complete) + dev->class->pm->complete(dev); } device_unlock(dev); @@ -741,27 +734,23 @@ static pm_message_t resume_event(pm_mess */ static int device_suspend_noirq(struct device *dev, pm_message_t state) { - int error = 0; + int error; - if (dev->class && dev->class->pm) { - pm_dev_dbg(dev, state, "LATE class "); - error = pm_noirq_op(dev, dev->class->pm, state); + if (dev->bus && dev->bus->pm) { + pm_dev_dbg(dev, state, "LATE "); + error = pm_noirq_op(dev, dev->bus->pm, state); if (error) - goto End; - } - - if (dev->type && dev->type->pm) { + return error; + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "LATE type "); error = pm_noirq_op(dev, dev->type->pm, state); if (error) - goto End; - } - - if (dev->bus && dev->bus->pm) { - pm_dev_dbg(dev, state, "LATE "); - error = pm_noirq_op(dev, dev->bus->pm, state); + return error; + } else if (dev->class && dev->class->pm) { + pm_dev_dbg(dev, state, "LATE class "); + error = pm_noirq_op(dev, dev->class->pm, state); if (error) - goto End; + return error; } if (dev->pwr_domain) { @@ -769,8 +758,7 @@ static int device_suspend_noirq(struct d pm_noirq_op(dev, &dev->pwr_domain->ops, state); } -End: - return error; + return 0; } /** @@ -857,40 +845,36 @@ static int __device_suspend(struct devic goto End; } - if (dev->class) { - if (dev->class->pm) { - pm_dev_dbg(dev, state, "class "); - error = pm_op(dev, dev->class->pm, state); - } else if (dev->class->suspend) { - pm_dev_dbg(dev, state, "legacy class "); - error = legacy_suspend(dev, state, dev->class->suspend); - } - if (error) - goto End; - } - - if (dev->type) { - if (dev->type->pm) { - pm_dev_dbg(dev, state, "type "); - error = pm_op(dev, dev->type->pm, state); - } - if (error) - goto End; - } - if (dev->bus) { if (dev->bus->pm) { pm_dev_dbg(dev, state, ""); error = pm_op(dev, dev->bus->pm, state); + goto Domain; } else if (dev->bus->suspend) { pm_dev_dbg(dev, state, "legacy "); error = legacy_suspend(dev, state, dev->bus->suspend); + goto Domain; } - if (error) - goto End; } - if (dev->pwr_domain) { + if (dev->type && dev->type->pm) { + pm_dev_dbg(dev, state, "type "); + error = pm_op(dev, dev->type->pm, state); + goto Domain; + } + + if (dev->class) { + if (dev->class->pm) { + pm_dev_dbg(dev, state, "class "); + error = pm_op(dev, dev->class->pm, state); + } else if (dev->class->suspend) { + pm_dev_dbg(dev, state, "legacy class "); + error = legacy_suspend(dev, state, dev->class->suspend); + } + } + + Domain: + if (!error && dev->pwr_domain) { pm_dev_dbg(dev, state, "power domain "); pm_op(dev, &dev->pwr_domain->ops, state); } @@ -985,25 +969,24 @@ static int device_prepare(struct device device_lock(dev); - if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) { + if (dev->bus && dev->bus->pm) { pm_dev_dbg(dev, state, "preparing "); - error = dev->bus->pm->prepare(dev); + if (dev->bus->pm->prepare) + error = dev->bus->pm->prepare(dev); suspend_report_result(dev->bus->pm->prepare, error); if (error) goto End; - } - - if (dev->type && dev->type->pm && dev->type->pm->prepare) { + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "preparing type "); - error = dev->type->pm->prepare(dev); + if (dev->type->pm->prepare) + error = dev->type->pm->prepare(dev); suspend_report_result(dev->type->pm->prepare, error); if (error) goto End; - } - - if (dev->class && dev->class->pm && dev->class->pm->prepare) { + } else if (dev->class && dev->class->pm) { pm_dev_dbg(dev, state, "preparing class "); - error = dev->class->pm->prepare(dev); + if (dev->class->pm->prepare) + error = dev->class->pm->prepare(dev); suspend_report_result(dev->class->pm->prepare, error); if (error) goto End; Index: linux-2.6/drivers/base/power/runtime.c =================================================================== --- linux-2.6.orig/drivers/base/power/runtime.c +++ linux-2.6/drivers/base/power/runtime.c @@ -214,9 +214,9 @@ static int rpm_idle(struct device *dev, dev->power.idle_notification = true; - if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) + if (dev->bus && dev->bus->pm) callback = dev->bus->pm->runtime_idle; - else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_idle; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_idle; @@ -382,9 +382,9 @@ static int rpm_suspend(struct device *de __update_runtime_status(dev, RPM_SUSPENDING); - if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) + if (dev->bus && dev->bus->pm) callback = dev->bus->pm->runtime_suspend; - else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend) + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_suspend; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_suspend; @@ -584,9 +584,9 @@ static int rpm_resume(struct device *dev if (dev->pwr_domain) rpm_callback(dev->pwr_domain->ops.runtime_resume, dev); - if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) + if (dev->bus && dev->bus->pm) callback = dev->bus->pm->runtime_resume; - else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume) + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_resume; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_resume; Index: linux-2.6/Documentation/power/devices.txt =================================================================== --- linux-2.6.orig/Documentation/power/devices.txt +++ linux-2.6/Documentation/power/devices.txt @@ -249,23 +249,17 @@ various phases always run after tasks ha unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have been disabled (except for those marked with the IRQ_WAKEUP flag). -Most phases use bus, type, and class callbacks (that is, methods defined in -dev->bus->pm, dev->type->pm, and dev->class->pm). The prepare and complete -phases are exceptions; they use only bus callbacks. When multiple callbacks -are used in a phase, they are invoked in the order: during -power-down transitions and in the opposite order during power-up transitions. -For example, during the suspend phase the PM core invokes - - dev->class->pm.suspend(dev); - dev->type->pm.suspend(dev); - dev->bus->pm.suspend(dev); - -before moving on to the next device, whereas during the resume phase the core -invokes - - dev->bus->pm.resume(dev); - dev->type->pm.resume(dev); - dev->class->pm.resume(dev); +All phases use bus, type, or class callbacks (that is, methods defined in +dev->bus->pm, dev->type->pm, or dev->class->pm). These callbacks are mutually +exclusive, so if the bus provides a struct dev_pm_ops object pointed to by its +pm field (i.e. both dev->bus and dev->bus->pm are defined), the callbacks +included in that object (i.e. dev->bus->pm) will be used. In turn, if the +device type provides a struct dev_pm_ops object pointed to by its pm field +(i.e. both dev->type and dev->type->pm are defined), the PM core will used the +callbacks from that object (i.e. dev->type->pm). Finally, if the pm fields of +both the bus and device type objects are NULL (or those objects do not exist), +the callbacks provided by the class (that is, the callbacks from dev->class->pm) +will be used. These callbacks may in turn invoke device- or driver-specific methods stored in dev->driver->pm, but they don't have to.