pm runtime and system suspend resume

chao xie xiechao.linux at
Tue Jun 19 21:54:42 EDT 2012

>> hi
>> PM_RUNTIME provide a way for device driver do runtime PM. so for some
>> devices, they have some surrounded logic. For example, the device may
>> get clock from outside, or it need PHY support(USB is a example).
>> To get these dependency out of device driver, i define a struct
>> dev_pm_domain, and make dev.pm_domain point to it. So in the device
>> driver, when the hardware should be enabled, we can call
>> pm_runtime_get_sync while when the hardware is idle or does not work,
>> we can call pm_runtime_put_sync.
>> It seems work well, but i have question about the suspend/resume of
>> device. When the whole system will go to deep idle, and it will
>> suspend the devices. for the function do device suspend
>> __device_suspend,
> What source file is that function in?

The function is located at drivers/base/power/main.c

>>  it will call pm_runtime_get_noresume(dev). As i
>> think it will make the device not do runtime suspend any more. Is that
>> correct?
> It sounds wrong.  Why would a suspend routine do that?

I do knot know, but the code is there.

>> There is the question, how device driver handle the logic surrounds
>> it? I want to add pm_runtime_put_sync in dev->driver->pm->suspend
>> function, and pm_runtime_get_sync in dev->driver->pm->resume.
> You must not do that.  If you do, your driver will hang.

why it will hang?

>> Because
>> __device_suspend increase the usage_count, pm_runtime_put_sync will
>> not do real work.
>> So is that right that i directly call pm_runtime_suspend in
>> dev->driver->pm->suspend and pm_runtime_resume in
>> dev->driver->pm->resume?
> No, it works the other way around.  pm_runtime_suspend calls
> dev->driver->pm->suspend, and pm_runtime_resume calls
> dev->driver->pm->resume.

I have checked the pm_runtime_suspend implementation. It will call
__pm_runtime_suspend without RPM_GET_PUT. It means that it will
directly call rpm_suspend. in this function, the pm_ops call sequence
if (dev->pm_domain)
               callback = dev->pm_domain->ops.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;
       else if (dev->bus && dev->bus->pm)
               callback = dev->bus->pm->runtime_suspend;
               callback = NULL;

       if (!callback && dev->driver && dev->driver->pm)
               callback = dev->driver->pm->runtime_suspend;

It means that if dev->pm_domain is not NULL, it will not call
dev->driver->pm operations.

Finally the real question is who will deal with the dev->pm_domain?
when system go to sleep.
The driver will use pm_runtime_get/put to deal with dev->pm_domain
when it want to work or is in idle. Then when system go to sleep, the
driver need care about dev->pm_domain too.
Usally, dev->pm_domain is a easy way to handle the difference SOCs
with same device IP. For example, USB. Many vendor may have same usb
IP but difference phy and clock configuration. putting these stuff
into dev->pm_domain can make driver be shared by different SOCs.

> Alan Stern

More information about the linux-arm-kernel mailing list