linux/drivers/base
Rafael J. Wysocki 17218e0092 PM / genpd: Stop/start devices without pm_runtime_force_suspend/resume()
There are problems with calling pm_runtime_force_suspend/resume()
to "stop" and "start" devices in genpd_finish_suspend() and
genpd_resume_noirq() (and in analogous hibernation-specific genpd
callbacks) after commit 122a22377a (PM / Domains: Stop/start
devices during system PM suspend/resume in genpd) as those routines
do much more than just "stopping" and "starting" devices (which was
the stated purpose of that commit) unnecessarily and may not play
well with system-wide PM driver callbacks.

First, consider the pm_runtime_force_suspend() in
genpd_finish_suspend().  If the current runtime PM status of the
device is "suspended", that function most likely does the right thing
by ignoring the device, because it should have been "stopped" already
and whatever needed to be done to deactivate it shoud have been done.
In turn, if the runtime PM status of the device is "active",
genpd_runtime_suspend() is called for it (indirectly) and (1) runs
the ->runtime_suspend callback provided by the device's driver
(assuming no bus type with ->runtime_suspend of its own), (2) "stops"
the device and (3) checks if the domain can be powered down, and then
(4) the device's runtime PM status is changed to "suspended".  Out of
the four actions above (1) is not necessary and it may be outright
harmful, (3) is pointless and (4) is questionable.  The only
operation that needs to be carried out here is (2).

The reason why (1) is not necessary is because the system-wide
PM callbacks provided by the device driver for the transition in
question have been run and they should have taken care of the
driver's part of device suspend already.  Moreover, it may be
harmful, because the ->runtime_suspend callback may want to
access the device which is partially suspended at that point
and may not be responsive.  Also, system-wide PM callbacks may
have been run already (in the previous phases of the system
transition under way) for the device's parent or for its supplier
devices (if any) and the device may not be accessible because of
that.

There also is no reason to do (3), because genpd_finish_suspend()
will repeat it anyway, and (4) potentially causes confusion to ensue
during the subsequent system transition to the working state.

Consider pm_runtime_force_resume() in genpd_resume_noirq() now.
It runs genpd_runtime_resume() for all devices with runtime PM
status set to "suspended", which includes all of the devices
whose runtime PM status was changed by pm_runtime_force_suspend()
before and may include some devices already suspended when the
pm_runtime_force_suspend() was running, which may be confusing.  The
genpd_runtime_resume() first tries to power up the domain, which
(again) is pointless, because genpd_resume_noirq() has done that
already.  Then, it "starts" the device and runs the ->runtime_resume
callback (from the driver, say) for it.  If all is well, the device
is left with the runtime PM status set to "active".

Unfortunately, running the driver's ->runtime_resume callback
before its system-wide PM callbacks and possibly before some
system-wide PM callbacks of the parent device's driver (let
alone supplier drivers) is asking for trouble, especially if
the device had been suspended before pm_runtime_force_suspend()
ran previously or if the callbacks in question expect to be run
back-to-back with their suspend-side counterparts.  It also should
not be necessary, because the system-wide PM driver callbacks that
will be invoked for the device subsequently should take care of
resuming it just fine.

[Running the driver's ->runtime_resume callback in the "noirq"
phase of the transition to the working state may be problematic
even for devices whose drivers do use pm_runtime_force_resume()
in (or as) their system-wide PM callbacks if they have suppliers
other than their parents, because it may cause the supplier to
be resumed after the consumer in some cases.]

Because of the above, modify genpd as follows:

 1. Change genpd_finish_suspend() to only "stop" devices with
    runtime PM status set to "active" (without invoking runtime PM
    callbacks for them, changing their runtime PM status and so on).

    That doesn't change the handling of devices whose drivers use
    pm_runtime_force_suspend/resume() in (or as) their system-wide
    PM callbacks and addresses the issues described above for the
    other devices.

 2. Change genpd_resume_noirq() to only "start" devices with
    runtime PM status set to "active" (without invoking runtime PM
    callbacks for them, changing their runtime PM status and so on).

    Again, that doesn't change the handling of devices whose drivers
    use pm_runtime_force_suspend/resume() in (or as) their system-wide
    PM callbacks and addresses the described issues for the other
    devices.  Devices with runtime PM status set to "suspended"
    are not started with the assumption that they will be resumed
    later, either by pm_runtime_force_resume() or via runtime PM.

 3. Change genpd_restore_noirq() to follow genpd_resume_noirq().

    That causes devices already suspended before hibernation to be
    left alone (which also is the case without the change) and
    avoids running the ->runtime_resume driver callback too early
    for the other devices.

 4. Change genpd_freeze_noirq() and genpd_thaw_noirq() in accordance
    with the above modifications.

Fixes: 122a22377a (PM / Domains: Stop/start devices during system PM suspend/resume in genpd)
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
2018-01-15 01:33:37 +01:00
..
power PM / genpd: Stop/start devices without pm_runtime_force_suspend/resume() 2018-01-15 01:33:37 +01:00
regmap regmap: Updates for v4.15 2017-11-13 09:45:34 -08:00
test Driver core patches for 4.15-rc1 2017-11-16 08:55:30 -08:00
arch_topology.c Driver core patches for 4.15-rc1 2017-11-16 08:55:30 -08:00
attribute_container.c attribute_container: Fix typo 2016-08-31 15:13:56 +02:00
base.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
bus.c driver core: bus: Fix a potential double free 2017-08-31 18:57:30 +02:00
cacheinfo.c Merge branch 'x86-cache-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip 2016-12-22 09:25:45 -08:00
class.c driver core: remove class_attrs from struct class 2017-06-09 10:41:00 +02:00
component.c Merge 4.5-rc4 into driver-core-next 2016-02-14 14:29:55 -08:00
container.c
core.c Driver core patches for 4.15-rc1 2017-11-16 08:55:30 -08:00
cpu.c Power management updates for v4.15-rc1 2017-11-13 19:43:50 -08:00
dd.c Driver core patches for 4.15-rc1 2017-11-16 08:55:30 -08:00
devcoredump.c driver core: devcoredump: convert to use class_groups 2016-11-29 21:12:12 +01:00
devres.c devres: add devm_alloc_percpu() 2016-11-15 22:34:25 -05:00
devtmpfs.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
dma-coherent.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
dma-contiguous.c cma: Store a name in the cma structure 2017-04-18 20:41:12 +02:00
dma-mapping.c dma-coherent: remove the DMA_MEMORY_MAP and DMA_MEMORY_IO flags 2017-09-01 11:59:17 +02:00
driver.c driver core: add missing blank line after declaration 2015-03-25 14:36:30 +01:00
firmware_class.c Revert "firmware: add sanity check on shutdown/suspend" 2017-09-10 21:19:06 -07:00
firmware.c
hypervisor.c
init.c drivers: of/base: move of_init to driver_init 2015-05-26 19:55:56 -07:00
isa.c isa: Prevent NULL dereference in isa_bus driver callbacks 2017-11-28 16:40:58 +01:00
Kconfig firmware: cleanup FIRMWARE_IN_KERNEL message 2017-11-28 16:47:46 +01:00
Makefile License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
map.c drivers: base: map: Use kmalloc_array instead of kmalloc 2015-03-25 14:35:08 +01:00
memory.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
module.c base: make module_create_drivers_dir race-free 2016-06-15 19:21:31 -07:00
node.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
pinctrl.c driver core: fix automatic pinctrl management 2017-06-13 11:07:32 +02:00
platform-msi.c irqchip/MSI: Use irq_domain_update_bus_token instead of an open coded access 2017-06-22 18:29:17 +02:00
platform.c drivers: flag buses which demand DMA configuration 2017-10-19 16:34:52 +02:00
property.c device property: Make fwnode_handle_get() return the fwnode 2017-11-09 00:17:22 +01:00
soc.c base: soc: Allow early registration of a single SoC device 2017-03-29 21:43:26 +02:00
syscore.c
topology.c base: topology: constify attribute_group structures. 2017-08-28 17:49:22 +02:00
transport_class.c