PM: Introduce core framework for run-time PM of I/O devices (rev. 14)
Subsystems (9)
PATCH 1/1 PM: Introduce core framework for run-time PM of I/O devices (rev. 14)
Hi,
Below is the rev. 14 of the runtime PM patch. Hopefully it addresses all of the remaining reservations.
Thanks,
Rafael
---
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 14)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
--- Documentation/power/runtime_pm.txt | 386 ++++++++++++++ drivers/base/dd.c | 21 drivers/base/power/Makefile | 1 drivers/base/power/main.c | 20 drivers/base/power/power.h | 31 - drivers/base/power/runtime.c | 969 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 101 +++ include/linux/pm_runtime.h | 115 ++++ kernel/power/Kconfig | 14 kernel/power/main.c | 17 10 files changed, 1664 insertions(+), 11 deletions(-)
kernel/power/Kconfig +14 -0
@@ -208,3 +208,17 @@ config APM_EMULATION random kernel OOPSes or reboots that don't seem to be related to anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). + +config PM_RUNTIME + bool "Run-time PM core functionality" + depends on PM + ---help--- + Enable functionality allowing I/O devices to be put into energy-saving + (low power) states at run time (or autosuspended) after a specified + period of inactivity and woken up in response to a hardware-generated + wake-up event or a driver's request. + + Hardware support is generally required for this functionality to work + and the bus type drivers of the buses the devices are on are + responsible for the actual handling of the autosuspend requests and + wake-up events.
kernel/power/main.c +17 -0
@@ -11,6 +11,7 @@#include <linux/kobject.h> #include <linux/string.h> #include <linux/resume-trace.h> +#include <linux/workqueue.h> #include "power.h"
@@ -217,8 +218,24 @@ static struct attribute_group attr_group .attrs = g, }; +#ifdef CONFIG_PM_RUNTIME +struct workqueue_struct *pm_wq; + +static int __init pm_start_workqueue (void ) +{ + pm_wq =create_freezeable_workqueue ("pm" ); + +return pm_wq ?0 : -ENOMEM ; +} +#else +static inline int pm_start_workqueue (void ) {return 0 ; } +#endif +static int __init pm_init (void ) { +int error =pm_start_workqueue (); +if (error) +return error; power_kobj =kobject_create_and_add ("power" ,NULL );if (!power_kobj)return -ENOMEM ;
include/linux/pm.h +98 -3
130 lines not on this page · raw message
drivers/base/power/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/power/runtime.c new file +969 -0
969 lines not on this page · raw message
include/linux/pm_runtime.h new file +115 -0
115 lines not on this page · raw message
drivers/base/power/main.c +19 -1
@@ -21,6 +21,7 @@#include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/resume-trace.h> #include <linux/rwsem.h> #include <linux/interrupt.h>
@@ -49,6 +50,16 @@ static DEFINE_MUTEX(dpm_list_mtx);static bool transition_started;/** +* device_pm_init - Initialize the PM-related part of a device object +* @dev: Device object being initialized. +*/ +void device_pm_init (struct device *dev) +{ + dev->power.status =DPM_ON ; +pm_runtime_init (dev); +} + +/** * device_pm_lock - lock the list of active devices used by the PM core */ void device_pm_lock (void )
@@ -105,6 +116,7 @@ void device_pm_remove(struct device *devmutex_lock (&dpm_list_mtx);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); +pm_runtime_remove (dev); }/**
@@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t stmutex_unlock (&dpm_list_mtx);device_complete (dev, state); +pm_runtime_enable (dev);mutex_lock (&dpm_list_mtx); }
@@ -757,11 +770,16 @@ static int dpm_prepare(pm_message_t stat dev->power.status =DPM_PREPARING ;mutex_unlock (&dpm_list_mtx); - error =device_prepare (dev, state); +if (pm_runtime_disable (dev) &&device_may_wakeup (dev)) +/* Wake-up requested during system sleep transition. */ + error = -EBUSY ; +else + error =device_prepare (dev, state);mutex_lock (&dpm_list_mtx);if (error) { dev->power.status =DPM_ON ; +pm_runtime_enable (dev);if (error == -EAGAIN ) {put_device (dev); error =0 ;
drivers/base/dd.c +21 -0
@@ -23,6 +23,7 @@#include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h"
@@ -202,7 +203,17 @@ int driver_probe_device(struct device_drpr_debug ("bus: '%s': %s: matched device %s with driver %s\n" , drv->bus->name, __func__,dev_name (dev), drv->name); +/* +* Wait for run-time PM calls to complete and prevent new suspend calls +* until the probe is done. +*/ +pm_runtime_disable (dev); +pm_runtime_get_noresume (dev); +pm_runtime_enable (dev); ret =really_probe (dev, drv); +pm_runtime_put_noidle (dev); +if (!ret) +pm_runtime_idle (dev);return ret; }
@@ -306,6 +317,14 @@ static void __device_release_driver(stru drv = dev->driver;if (drv) { +/* +* Wait for run-time PM calls to complete and prevent new +* suspend calls until the remove is done. +*/ +pm_runtime_disable (dev); +pm_runtime_get_noresume (dev); +pm_runtime_enable (dev); +driver_sysfs_remove (dev);if (dev->bus)
@@ -324,6 +343,8 @@ static void __device_release_driver(strublocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_UNBOUND_DRIVER , dev); + +pm_runtime_put_noidle (dev); } }
drivers/base/power/power.h +24 -7
@@ -1,7 +1,14 @@ -static inline void device_pm_init (struct device *dev) -{ - dev->power.status =DPM_ON ; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init (struct device *dev); +extern void pm_runtime_remove (struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init (struct device *dev) {} +static inline void pm_runtime_remove (struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } +extern void device_pm_init (struct device *dev);extern void device_pm_add (struct device *);extern void device_pm_remove (struct device *);extern void device_pm_move_before (struct device *,struct device *);extern void device_pm_move_after (struct device *,struct device *);extern void device_pm_move_last (struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init (struct device *dev) +{ +pm_runtime_init (dev); +} + +static inline void device_pm_remove (struct device *dev) +{ +pm_runtime_remove (dev); +}static inline void device_pm_add (struct device *dev) {} -static inline void device_pm_remove (struct device *dev) {}static inline void device_pm_move_before (struct device *deva,struct device *devb) {}static inline void device_pm_move_after (struct device *deva,struct device *devb) {}static inline void device_pm_move_last (struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM
Documentation/power/runtime_pm.txt new file +386 -0
386 lines not on this page · raw message
PATCH 1/1 PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
Hi,
One more update. This one should address your comments from this thread
http://lkml.org/lkml/2009/8/8/113
Thanks,
Rafael
---
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
--- Documentation/power/runtime_pm.txt | 386 ++++++++++++++ drivers/base/dd.c | 11 drivers/base/power/Makefile | 1 drivers/base/power/main.c | 22 drivers/base/power/power.h | 31 - drivers/base/power/runtime.c | 1011 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 101 +++ include/linux/pm_runtime.h | 114 ++++ kernel/power/Kconfig | 14 kernel/power/main.c | 17 10 files changed, 1697 insertions(+), 11 deletions(-)
kernel/power/Kconfig +14 -0
@@ -208,3 +208,17 @@ config APM_EMULATION random kernel OOPSes or reboots that don't seem to be related to anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). + +config PM_RUNTIME + bool "Run-time PM core functionality" + depends on PM + ---help--- + Enable functionality allowing I/O devices to be put into energy-saving + (low power) states at run time (or autosuspended) after a specified + period of inactivity and woken up in response to a hardware-generated + wake-up event or a driver's request. + + Hardware support is generally required for this functionality to work + and the bus type drivers of the buses the devices are on are + responsible for the actual handling of the autosuspend requests and + wake-up events.
kernel/power/main.c +17 -0
@@ -11,6 +11,7 @@#include <linux/kobject.h> #include <linux/string.h> #include <linux/resume-trace.h> +#include <linux/workqueue.h> #include "power.h"
@@ -217,8 +218,24 @@ static struct attribute_group attr_group .attrs = g, }; +#ifdef CONFIG_PM_RUNTIME +struct workqueue_struct *pm_wq; + +static int __init pm_start_workqueue (void ) +{ + pm_wq =create_freezeable_workqueue ("pm" ); + +return pm_wq ?0 : -ENOMEM ; +} +#else +static inline int pm_start_workqueue (void ) {return 0 ; } +#endif +static int __init pm_init (void ) { +int error =pm_start_workqueue (); +if (error) +return error; power_kobj =kobject_create_and_add ("power" ,NULL );if (!power_kobj)return -ENOMEM ;
include/linux/pm.h +98 -3
130 lines not on this page · raw message
drivers/base/power/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/power/runtime.c new file +1011 -0
1,011 lines not on this page · raw message
include/linux/pm_runtime.h new file +114 -0
114 lines not on this page · raw message
drivers/base/power/main.c +21 -1
@@ -21,6 +21,7 @@#include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/resume-trace.h> #include <linux/rwsem.h> #include <linux/interrupt.h>
@@ -49,6 +50,16 @@ static DEFINE_MUTEX(dpm_list_mtx);static bool transition_started;/** +* device_pm_init - Initialize the PM-related part of a device object +* @dev: Device object being initialized. +*/ +void device_pm_init (struct device *dev) +{ + dev->power.status =DPM_ON ; +pm_runtime_init (dev); +} + +/** * device_pm_lock - lock the list of active devices used by the PM core */ void device_pm_lock (void )
@@ -105,6 +116,7 @@ void device_pm_remove(struct device *devmutex_lock (&dpm_list_mtx);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); +pm_runtime_remove (dev); }/**
@@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t stmutex_unlock (&dpm_list_mtx);device_complete (dev, state); +pm_runtime_put_noidle (dev);mutex_lock (&dpm_list_mtx); }
@@ -757,7 +770,14 @@ static int dpm_prepare(pm_message_t stat dev->power.status =DPM_PREPARING ;mutex_unlock (&dpm_list_mtx); - error =device_prepare (dev, state); +pm_runtime_get_noresume (dev); +if (pm_runtime_barrier (dev) &&device_may_wakeup (dev)) { +/* Wake-up requested during system sleep transition. */ +pm_runtime_put_noidle (dev); + error = -EBUSY ; + }else { + error =device_prepare (dev, state); + }mutex_lock (&dpm_list_mtx);if (error) {
drivers/base/dd.c +11 -0
@@ -23,6 +23,7 @@#include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h"
@@ -202,7 +203,12 @@ int driver_probe_device(struct device_drpr_debug ("bus: '%s': %s: matched device %s with driver %s\n" , drv->bus->name, __func__,dev_name (dev), drv->name); +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); ret =really_probe (dev, drv); +pm_runtime_put_noidle (dev); +if (!ret) +pm_runtime_idle (dev);return ret; }
@@ -306,6 +312,9 @@ static void __device_release_driver(stru drv = dev->driver;if (drv) { +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); +driver_sysfs_remove (dev);if (dev->bus)
@@ -324,6 +333,8 @@ static void __device_release_driver(strublocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_UNBOUND_DRIVER , dev); + +pm_runtime_put_noidle (dev); } }
drivers/base/power/power.h +24 -7
@@ -1,7 +1,14 @@ -static inline void device_pm_init (struct device *dev) -{ - dev->power.status =DPM_ON ; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init (struct device *dev); +extern void pm_runtime_remove (struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init (struct device *dev) {} +static inline void pm_runtime_remove (struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } +extern void device_pm_init (struct device *dev);extern void device_pm_add (struct device *);extern void device_pm_remove (struct device *);extern void device_pm_move_before (struct device *,struct device *);extern void device_pm_move_after (struct device *,struct device *);extern void device_pm_move_last (struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init (struct device *dev) +{ +pm_runtime_init (dev); +} + +static inline void device_pm_remove (struct device *dev) +{ +pm_runtime_remove (dev); +}static inline void device_pm_add (struct device *dev) {} -static inline void device_pm_remove (struct device *dev) {}static inline void device_pm_move_before (struct device *deva,struct device *devb) {}static inline void device_pm_move_after (struct device *deva,struct device *devb) {}static inline void device_pm_move_last (struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM
Documentation/power/runtime_pm.txt new file +386 -0
386 lines not on this page · raw message
Re: [PATCH update] PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
Hi Rafael,
Quoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 15)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
Looking good! I have a few nitpicks below, but from a functional perspective it's all good. I've tested v15 with platform device drivers for I2C, UIO and framebuffer. Before adding my "Acked-by" I also want to test the V4L capture driver, but I need to wait a few days until I can get my hands on such a hardware platform.
Thanks for folding in and fixing up the debug patch. I was able to drop most remaining patches thanks to feedback from Alan. So the only needed patch apart from this one (and the ones in your linux-next branch) is the one in this micro-series: "PM: Runtime PM v15 for Platform Devices 20090812".
Quoted 2 lines
include/linux/pm.h +0
-0
[..]
Quoted 11 lines
struct
dev_pm_info{
pm_message_t power_state;
- unsigned can_wakeup:1;
- unsigned should_wakeup:1;
+ unsigned int can_wakeup:1;
+ unsigned int should_wakeup:1;
enumdpm_statestatus; /* Owned by the PM core */include/linux/pm.h +1
-1-#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM_SLEEP struct
list_headentry;
#endif
Quoted 8 lines
+#ifdef
CONFIG_PM_RUNTIME
+ structtimer_listsuspend_timer;
+ unsigned longtimer_expires;
+ structwork_structwork;
+wait_queue_head_twait_queue;
+spinlock_tlock;
+atomic_tusage_count;
+atomic_tchild_count;
I suppose child_count has to be atomic?
Quoted 2 lines
drivers/base/power/runtime.c new file +0
-0
[...]
Quoted 2 lines
+int
__pm_runtime_suspend(struct device *dev, bool from_wq)
+__releases(&dev->power.lock)__acquires(&dev->power.lock)
[...]
drivers/base/power/runtime.c line 202
Quoted 10 lines
+ if (
dev->bus&&dev->bus->pm&&dev->bus->pm->runtime_suspend) {
+spin_unlock_irq(&dev->power.lock);drivers/base/power/runtime.c new file +8
-0+ + retval = dev->bus->pm->runtime_suspend(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + }
Nit: { and } above do not follow the regular coding style.
Quoted 2 lines
+int
__pm_runtime_resume(struct device *dev, bool from_wq)
+__releases(&dev->power.lock)__acquires(&dev->power.lock)
[...]
drivers/base/power/runtime.c line 369
Quoted 10 lines
+ if (
dev->bus&&dev->bus->pm&&dev->bus->pm->runtime_resume) {
+spin_unlock_irq(&dev->power.lock);drivers/base/power/runtime.c new file +8
-0+ + retval = dev->bus->pm->runtime_resume(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + }
Same minor issue here.
Apart from that all is fine. Thank you.
/ magnus
Re: [PATCH update] PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
In reply to Rafael J. WysockiHi Rafael,
Quoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 15)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
Looking good! I have a few nitpicks below, but from a functional perspective it's all good. I've tested v15 with platform device drivers for I2C, UIO and framebuffer. Before adding my "Acked-by" I also want to test the V4L capture driver, but I need to wait a few days until I can get my hands on such a hardware platform.
Thanks for folding in and fixing up the debug patch. I was able to drop most remaining patches thanks to feedback from Alan. So the only needed patch apart from this one (and the ones in your linux-next branch) is the one in this micro-series: "PM: Runtime PM v15 for Platform Devices 20090812".
Quoted 2 lines
include/linux/pm.h +0
-0
[..]
Quoted 11 lines
struct
dev_pm_info{
pm_message_t power_state;
- unsigned can_wakeup:1;
- unsigned should_wakeup:1;
+ unsigned int can_wakeup:1;
+ unsigned int should_wakeup:1;
enumdpm_statestatus; /* Owned by the PM core */include/linux/pm.h +1
-1-#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM_SLEEP struct
list_headentry;
#endif
Quoted 8 lines
+#ifdef
CONFIG_PM_RUNTIME
+ structtimer_listsuspend_timer;
+ unsigned longtimer_expires;
+ structwork_structwork;
+wait_queue_head_twait_queue;
+spinlock_tlock;
+atomic_tusage_count;
+atomic_tchild_count;
I suppose child_count has to be atomic?
Quoted 2 lines
drivers/base/power/runtime.c new file +0
-0
[...]
Quoted 2 lines
+int
__pm_runtime_suspend(struct device *dev, bool from_wq)
+__releases(&dev->power.lock)__acquires(&dev->power.lock)
[...]
drivers/base/power/runtime.c line 202
Quoted 10 lines
+ if (
dev->bus&&dev->bus->pm&&dev->bus->pm->runtime_suspend) {
+spin_unlock_irq(&dev->power.lock);drivers/base/power/runtime.c new file +8
-0+ + retval = dev->bus->pm->runtime_suspend(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + }
Nit: { and } above do not follow the regular coding style.
Quoted 2 lines
+int
__pm_runtime_resume(struct device *dev, bool from_wq)
+__releases(&dev->power.lock)__acquires(&dev->power.lock)
[...]
drivers/base/power/runtime.c line 369
Quoted 10 lines
+ if (
dev->bus&&dev->bus->pm&&dev->bus->pm->runtime_resume) {
+spin_unlock_irq(&dev->power.lock);drivers/base/power/runtime.c new file +8
-0+ + retval = dev->bus->pm->runtime_resume(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + }
Same minor issue here.
Apart from that all is fine. Thank you.
/ magnus
Alan Stern
maintainerRe: [PATCH update] PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
Quoted 6 lines · Magnus Damm
Quoted 2 lines
drivers/base/power/runtime.c new file +0
-0[...]
Quoted 2 lines
+int
__pm_runtime_suspend(struct device *dev, bool from_wq)
+__releases(&dev->power.lock)__acquires(&dev->power.lock)[...]
Quoted 12 lines
drivers/base/power/runtime.c line 202
Quoted 10 lines
+ if (
dev->bus&&dev->bus->pm&&dev->bus->pm->runtime_suspend) {
+spin_unlock_irq(&dev->power.lock);drivers/base/power/runtime.c new file +8
-0+ + retval = dev->bus->pm->runtime_suspend(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + }Nit: { and } above do not follow the regular coding style.
As a matter of fact they do. From Documentation/CodingStyle:
Do not unnecessarily use braces where a single statement will do.
if (condition)
action();
This does not apply if one branch of a conditional statement is a single statement. Use braces in both branches.
if (condition) {
do_this();
do_that();
} else {
otherwise();
}Alan Stern
Alan Stern
maintainerRe: [PATCH update] PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
In reply to Magnus DammQuoted 6 lines · Magnus Damm
Quoted 2 lines
drivers/base/power/runtime.c new file +0
-0[...]
Quoted 2 lines
+int
__pm_runtime_suspend(struct device *dev, bool from_wq)
+__releases(&dev->power.lock)__acquires(&dev->power.lock)[...]
Quoted 12 lines
drivers/base/power/runtime.c line 202
Quoted 10 lines
+ if (
dev->bus&&dev->bus->pm&&dev->bus->pm->runtime_suspend) {
+spin_unlock_irq(&dev->power.lock);drivers/base/power/runtime.c new file +8
-0+ + retval = dev->bus->pm->runtime_suspend(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + }Nit: { and } above do not follow the regular coding style.
As a matter of fact they do. From Documentation/CodingStyle:
Do not unnecessarily use braces where a single statement will do.
if (condition)
action();
This does not apply if one branch of a conditional statement is a single statement. Use braces in both branches.
if (condition) {
do_this();
do_that();
} else {
otherwise();
}Alan Stern
Re: [PATCH update] PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
In reply to Magnus DammQuoted 1 line · Magnus Damm
Hi Rafael,
Hi,
Quoted 44 lines · Rafael J. Wysocki
Quoted 9 lines
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 15)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>Looking good! I have a few nitpicks below, but from a functional perspective it's all good. I've tested v15 with platform device drivers for I2C, UIO and framebuffer. Before adding my "Acked-by" I also want to test the V4L capture driver, but I need to wait a few days until I can get my hands on such a hardware platform.
Thanks for folding in and fixing up the debug patch. I was able to drop most remaining patches thanks to feedback from Alan. So the only needed patch apart from this one (and the ones in your linux-next branch) is the one in this micro-series: "PM: Runtime PM v15 for Platform Devices 20090812".
Quoted 2 lines
include/linux/pm.h +0
-0[..]
Quoted 13 lines
struct dev_pm_info { pm_message_t power_state;include/linux/pm.h +5
-3- unsigned can_wakeup:1; - unsigned should_wakeup:1; + unsigned int can_wakeup:1; + unsigned int should_wakeup:1;enum dpm_state status;/* Owned by the PM core */ -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM_SLEEP struct list_head entry;#endif +#ifdef CONFIG_PM_RUNTIME +struct timer_list suspend_timer;
Quoted 8 lines
include/linux/pm.h enum dpm_state { · line 425
Quoted 6 lines
include/linux/pm.h +6
-0+unsigned long timer_expires; +struct work_struct work; +wait_queue_head_t wait_queue; +spinlock_t lock; +atomic_t usage_count; +atomic_t child_count;I suppose
child_counthas to be atomic?
I'd say so, it's modified in a few places without locking.
Quoted 6 lines
Quoted 2 lines
drivers/base/power/runtime.c new file +0
-0[...]
Quoted 2 lines
drivers/base/power/runtime.c new file +2
-0+int __pm_runtime_suspend(struct device *dev, bool from_wq) + __releases(&dev->power.lock) __acquires(&dev->power.lock)[...]
Quoted 12 lines
drivers/base/power/runtime.c line 202
Quoted 10 lines
drivers/base/power/runtime.c new file +10
-0+if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { +spin_unlock_irq (&dev->power.lock); + + retval = dev->bus->pm->runtime_suspend (dev); + +spin_lock_irq (&dev->power.lock); + dev->power.runtime_error = retval; + }else { + retval = -ENOSYS ; + }Nit: { and } above do not follow the regular coding style.
Well, you've got a very good answer to this from Alan. ;-)
Thanks,
Rafael
Re: [PATCH update] PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
In reply to Magnus DammQuoted 1 line · Magnus Damm
Hi Rafael,
Hi,
Quoted 44 lines · Rafael J. Wysocki
Quoted 9 lines
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 15)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>Looking good! I have a few nitpicks below, but from a functional perspective it's all good. I've tested v15 with platform device drivers for I2C, UIO and framebuffer. Before adding my "Acked-by" I also want to test the V4L capture driver, but I need to wait a few days until I can get my hands on such a hardware platform.
Thanks for folding in and fixing up the debug patch. I was able to drop most remaining patches thanks to feedback from Alan. So the only needed patch apart from this one (and the ones in your linux-next branch) is the one in this micro-series: "PM: Runtime PM v15 for Platform Devices 20090812".
Quoted 2 lines
include/linux/pm.h +0
-0[..]
Quoted 13 lines
struct dev_pm_info { pm_message_t power_state;include/linux/pm.h +5
-3- unsigned can_wakeup:1; - unsigned should_wakeup:1; + unsigned int can_wakeup:1; + unsigned int should_wakeup:1;enum dpm_state status;/* Owned by the PM core */ -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM_SLEEP struct list_head entry;#endif +#ifdef CONFIG_PM_RUNTIME +struct timer_list suspend_timer;
Quoted 8 lines
include/linux/pm.h enum dpm_state { · line 425
Quoted 6 lines
include/linux/pm.h +6
-0+unsigned long timer_expires; +struct work_struct work; +wait_queue_head_t wait_queue; +spinlock_t lock; +atomic_t usage_count; +atomic_t child_count;I suppose
child_counthas to be atomic?
I'd say so, it's modified in a few places without locking.
Quoted 6 lines
Quoted 2 lines
drivers/base/power/runtime.c new file +0
-0[...]
Quoted 2 lines
drivers/base/power/runtime.c new file +2
-0+int __pm_runtime_suspend(struct device *dev, bool from_wq) + __releases(&dev->power.lock) __acquires(&dev->power.lock)[...]
Quoted 12 lines
drivers/base/power/runtime.c line 202
Quoted 10 lines
drivers/base/power/runtime.c new file +10
-0+if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { +spin_unlock_irq (&dev->power.lock); + + retval = dev->bus->pm->runtime_suspend (dev); + +spin_lock_irq (&dev->power.lock); + dev->power.runtime_error = retval; + }else { + retval = -ENOSYS ; + }Nit: { and } above do not follow the regular coding style.
Well, you've got a very good answer to this from Alan. ;-)
Thanks,
Rafael
RFC 1/1 PCI: Runtime power management
In reply to Rafael J. WysockiI got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
--- drivers/pci/pci-acpi.c | 55 +++++++++++++++++++++++++ drivers/pci/pci-driver.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.c | 87 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 3 + include/linux/pci.h | 3 + 5 files changed, 248 insertions(+), 0 deletions(-)
drivers/pci/pci-acpi.c +55 -0
@@ -12,6 +12,7 @@#include <linux/pci.h> #include <linux/module.h> #include <linux/pci-aspm.h> +#include <linux/pm_runtime.h> #include <acpi/acpi.h> #include <acpi/acpi_bus.h>
@@ -120,14 +121,62 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)return error; } +static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; + +if (!handle) +return -ENODEV ; + + status =acpi_bus_get_device (handle, &acpi_dev); +if (ACPI_FAILURE (status)) +return -ENODEV ; + +if (enable) { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE_RUN ); +acpi_enable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + }else { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE ); +acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +} + +static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, .can_wakeup = acpi_pci_can_wakeup, .sleep_wake = acpi_pci_sleep_wake, + .runtime_wake = acpi_pci_runtime_wake, }; +static void pci_device_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pm_runtime_resume (dev); +} + +static void pci_root_bridge_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; +struct pci_dev *pci_dev =to_pci_dev (dev); + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pci_bus_pme_event (pci_dev); +} +/* ACPI bus type */ static int acpi_pci_find_device (struct device *dev,acpi_handle *handle) {
@@ -140,6 +189,9 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) *handle =acpi_get_child (DEVICE_ACPI_HANDLE (dev->parent), addr);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_device_notify, dev);return 0 ; }
@@ -158,6 +210,9 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) *handle =acpi_get_pci_rootbridge_handle (seg, bus);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_root_bridge_notify, dev);return 0 ; }
drivers/pci/pci-driver.c +100 -0
124 lines not on this page · raw message
drivers/pci/pci.c +87 -0
111 lines not on this page · raw message
drivers/pci/pci.h +3 -0
@@ -34,6 +34,8 @@ extern int pci_mmap_fits(struct pci_dev *pdev, int resno,* * @sleep_wake: enables/disables the system wake up capability of given device * +* @runtime_wake: enables/disables the runtime wakeup capability of given device +* * If given platform is generally capable of power managing PCI devices, all of * these callbacks are mandatory. */
@@ -43,6 +45,7 @@ struct pci_platform_pm_ops {pci_power_t (*choose_state)(struct pci_dev *dev);bool (*can_wakeup)(struct pci_dev *dev);int (*sleep_wake)(struct pci_dev *dev,bool enable); +int (*runtime_wake)(struct pci_dev *dev,bool enable); };extern int pci_set_platform_pm (struct pci_platform_pm_ops *ops);
include/linux/pci.h +3 -0
@@ -734,10 +734,13 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);bool pci_pme_capable (struct pci_dev *dev,pci_power_t state);void pci_pme_active (struct pci_dev *dev,bool enable);int pci_enable_wake (struct pci_dev *dev,pci_power_t state,bool enable); +int pci_enable_runtime_wake (struct pci_dev *dev,bool enable);int pci_wake_from_d3 (struct pci_dev *dev,bool enable);pci_power_t pci_target_state (struct pci_dev *dev);int pci_prepare_to_sleep (struct pci_dev *dev);int pci_back_from_sleep (struct pci_dev *dev); +int pci_dev_pme_event (struct pci_dev *dev); +int pci_bus_pme_event (struct pci_dev *dev);/* Functions for PCI Hotplug drivers to use */ int pci_bus_find_capability (struct pci_bus *bus,unsigned int devfn,int cap);
Signature · 1 line
Matthew Garrett | [email protected]
RFC 1/1 PCI: Runtime power management
In reply to Rafael J. WysockiI got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
--- drivers/pci/pci-acpi.c | 55 +++++++++++++++++++++++++ drivers/pci/pci-driver.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.c | 87 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 3 + include/linux/pci.h | 3 + 5 files changed, 248 insertions(+), 0 deletions(-)
drivers/pci/pci-acpi.c +55 -0
@@ -12,6 +12,7 @@#include <linux/pci.h> #include <linux/module.h> #include <linux/pci-aspm.h> +#include <linux/pm_runtime.h> #include <acpi/acpi.h> #include <acpi/acpi_bus.h>
@@ -120,14 +121,62 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)return error; } +static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; + +if (!handle) +return -ENODEV ; + + status =acpi_bus_get_device (handle, &acpi_dev); +if (ACPI_FAILURE (status)) +return -ENODEV ; + +if (enable) { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE_RUN ); +acpi_enable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + }else { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE ); +acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +} + +static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, .can_wakeup = acpi_pci_can_wakeup, .sleep_wake = acpi_pci_sleep_wake, + .runtime_wake = acpi_pci_runtime_wake, }; +static void pci_device_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pm_runtime_resume (dev); +} + +static void pci_root_bridge_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; +struct pci_dev *pci_dev =to_pci_dev (dev); + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pci_bus_pme_event (pci_dev); +} +/* ACPI bus type */ static int acpi_pci_find_device (struct device *dev,acpi_handle *handle) {
@@ -140,6 +189,9 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) *handle =acpi_get_child (DEVICE_ACPI_HANDLE (dev->parent), addr);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_device_notify, dev);return 0 ; }
@@ -158,6 +210,9 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) *handle =acpi_get_pci_rootbridge_handle (seg, bus);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_root_bridge_notify, dev);return 0 ; }
drivers/pci/pci-driver.c +100 -0
124 lines not on this page · raw message
drivers/pci/pci.c +87 -0
111 lines not on this page · raw message
drivers/pci/pci.h +3 -0
@@ -34,6 +34,8 @@ extern int pci_mmap_fits(struct pci_dev *pdev, int resno,* * @sleep_wake: enables/disables the system wake up capability of given device * +* @runtime_wake: enables/disables the runtime wakeup capability of given device +* * If given platform is generally capable of power managing PCI devices, all of * these callbacks are mandatory. */
@@ -43,6 +45,7 @@ struct pci_platform_pm_ops {pci_power_t (*choose_state)(struct pci_dev *dev);bool (*can_wakeup)(struct pci_dev *dev);int (*sleep_wake)(struct pci_dev *dev,bool enable); +int (*runtime_wake)(struct pci_dev *dev,bool enable); };extern int pci_set_platform_pm (struct pci_platform_pm_ops *ops);
include/linux/pci.h +3 -0
@@ -734,10 +734,13 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);bool pci_pme_capable (struct pci_dev *dev,pci_power_t state);void pci_pme_active (struct pci_dev *dev,bool enable);int pci_enable_wake (struct pci_dev *dev,pci_power_t state,bool enable); +int pci_enable_runtime_wake (struct pci_dev *dev,bool enable);int pci_wake_from_d3 (struct pci_dev *dev,bool enable);pci_power_t pci_target_state (struct pci_dev *dev);int pci_prepare_to_sleep (struct pci_dev *dev);int pci_back_from_sleep (struct pci_dev *dev); +int pci_dev_pme_event (struct pci_dev *dev); +int pci_bus_pme_event (struct pci_dev *dev);/* Functions for PCI Hotplug drivers to use */ int pci_bus_find_capability (struct pci_bus *bus,unsigned int devfn,int cap);
Signature · 1 line
Matthew Garrett | [email protected]
RFC 1/1 usb: Add support for runtime power management of the hcd
The PCI runtime power management code means that we can implement support for powering down PCI host controllers. This patchset adds core support code along with a new hcd flag (HCD_RUNTIME_PM) that allows hosts to opt in if they support this functionality. Successfully tested with Intel EHCI and UHCI, though the UHCI code may need to pay more attention to vendor-specific features.
The power savings from this are measurable but not huge - it still seems like a decent optimisation. The main problem is that BIOS bugs on some Dell laptops will kill USB if this is used, so we either default to off or add some quirks to handle that case (I have some ideas in that respect).
--- drivers/usb/core/hcd-pci.c | 13 +++++++++++++ drivers/usb/core/hcd.c | 9 +++++++++ drivers/usb/core/hcd.h | 1 + drivers/usb/host/ehci-pci.c | 2 +- drivers/usb/host/uhci-hcd.c | 2 +- 5 files changed, 25 insertions(+), 2 deletions(-)
drivers/usb/core/hcd-pci.c +13 -0
@@ -363,6 +363,18 @@ static int hcd_pci_restore(struct device *dev)return resume_common (dev, true); } +static int hcd_pci_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct usb_hcd *hcd =pci_get_drvdata (pci_dev); +struct usb_device *rhdev = hcd->self.root_hub; + +if (!(hcd->driver->flags &HCD_RUNTIME_PM )) +return -EINVAL ; + +return 0 ; +} +struct dev_pm_ops usb_hcd_pci_pm_ops = { .suspend = hcd_pci_suspend, .suspend_noirq = hcd_pci_suspend_noirq,
@@ -376,6 +388,7 @@ struct dev_pm_ops usb_hcd_pci_pm_ops = { .poweroff_noirq = hcd_pci_suspend_noirq, .restore_noirq = hcd_pci_resume_noirq, .restore = hcd_pci_restore, + .runtime_suspend = hcd_pci_runtime_suspend, };EXPORT_SYMBOL_GPL (usb_hcd_pci_pm_ops);
drivers/usb/core/hcd.c +9 -0
@@ -38,6 +38,7 @@#include <asm/unaligned.h> #include <linux/platform_device.h> #include <linux/workqueue.h> +#include <linux/pm_runtime.h> #include <linux/usb.h>
@@ -1747,6 +1748,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)if (status ==0 ) {usb_set_device_state (rhdev,USB_STATE_SUSPENDED ); hcd->state =HC_STATE_SUSPENDED ; +pm_runtime_put (hcd->self.controller); }else { hcd->state = old_state; dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
@@ -1768,6 +1770,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)if (hcd->state ==HC_STATE_RUNNING )return 0 ; +pm_runtime_get_sync (hcd->self.controller); hcd->state =HC_STATE_RESUMING ; status = hcd->driver->bus_resume (hcd);if (status ==0 ) {
@@ -1781,6 +1784,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) hcd->state = old_state;dev_dbg (&rhdev->dev,"bus %s fail, err %d\n" ,"resume" , status); +pm_runtime_put (hcd->self.controller);if (status != -ESHUTDOWN )usb_hc_died (hcd); }
@@ -1968,6 +1972,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,INIT_WORK (&hcd->wakeup_work, hcd_resume_work);#endif +pm_runtime_enable (dev); +pm_runtime_get (dev); + hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc :"USB Host Controller" ;
@@ -1979,6 +1986,8 @@ static void hcd_release (struct kref *kref) { struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); +pm_runtime_put_sync (hcd->self.controller); +kfree (hcd); }
drivers/usb/core/hcd.h +1 -0
@@ -171,6 +171,7 @@ struct hc_driver {int flags;#define HCD_MEMORY 0x0001/* HC regs use memory (else I/O) */ #define HCD_LOCAL_MEM 0x0002/* HC needs local memory */ +#define HCD_RUNTIME_PM 0x0004/* HC supports handling runtime PM */ #define HCD_USB11 0x0010/* USB 1.1 */ #define HCD_USB2 0x0020/* USB 2.0 */ #define HCD_USB3 0x0040/* USB 3.0 */
drivers/usb/host/ehci-pci.c +1 -1
@@ -368,7 +368,7 @@ static const struct hc_driver ehci_pci_hc_driver = {* generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_RUNTIME_PM,/* * basic lifecycle operations
drivers/usb/host/uhci-hcd.c +1 -1
@@ -900,7 +900,7 @@ static const struct hc_driver uhci_driver = {/* Generic hardware linkage */ .irq = uhci_irq, - .flags = HCD_USB11, + .flags = HCD_USB11 | HCD_RUNTIME_PM,/* Basic lifecycle operations */ .reset = uhci_init,
Signature · 1 line
Matthew Garrett | [email protected]
RFC 1/1 usb: Add support for runtime power management of the hcd
In reply to Matthew GarrettThe PCI runtime power management code means that we can implement support for powering down PCI host controllers. This patchset adds core support code along with a new hcd flag (HCD_RUNTIME_PM) that allows hosts to opt in if they support this functionality. Successfully tested with Intel EHCI and UHCI, though the UHCI code may need to pay more attention to vendor-specific features.
The power savings from this are measurable but not huge - it still seems like a decent optimisation. The main problem is that BIOS bugs on some Dell laptops will kill USB if this is used, so we either default to off or add some quirks to handle that case (I have some ideas in that respect).
--- drivers/usb/core/hcd-pci.c | 13 +++++++++++++ drivers/usb/core/hcd.c | 9 +++++++++ drivers/usb/core/hcd.h | 1 + drivers/usb/host/ehci-pci.c | 2 +- drivers/usb/host/uhci-hcd.c | 2 +- 5 files changed, 25 insertions(+), 2 deletions(-)
drivers/usb/core/hcd-pci.c +13 -0
@@ -363,6 +363,18 @@ static int hcd_pci_restore(struct device *dev)return resume_common (dev, true); } +static int hcd_pci_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct usb_hcd *hcd =pci_get_drvdata (pci_dev); +struct usb_device *rhdev = hcd->self.root_hub; + +if (!(hcd->driver->flags &HCD_RUNTIME_PM )) +return -EINVAL ; + +return 0 ; +} +struct dev_pm_ops usb_hcd_pci_pm_ops = { .suspend = hcd_pci_suspend, .suspend_noirq = hcd_pci_suspend_noirq,
@@ -376,6 +388,7 @@ struct dev_pm_ops usb_hcd_pci_pm_ops = { .poweroff_noirq = hcd_pci_suspend_noirq, .restore_noirq = hcd_pci_resume_noirq, .restore = hcd_pci_restore, + .runtime_suspend = hcd_pci_runtime_suspend, };EXPORT_SYMBOL_GPL (usb_hcd_pci_pm_ops);
drivers/usb/core/hcd.c +9 -0
@@ -38,6 +38,7 @@#include <asm/unaligned.h> #include <linux/platform_device.h> #include <linux/workqueue.h> +#include <linux/pm_runtime.h> #include <linux/usb.h>
@@ -1747,6 +1748,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)if (status ==0 ) {usb_set_device_state (rhdev,USB_STATE_SUSPENDED ); hcd->state =HC_STATE_SUSPENDED ; +pm_runtime_put (hcd->self.controller); }else { hcd->state = old_state; dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
@@ -1768,6 +1770,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)if (hcd->state ==HC_STATE_RUNNING )return 0 ; +pm_runtime_get_sync (hcd->self.controller); hcd->state =HC_STATE_RESUMING ; status = hcd->driver->bus_resume (hcd);if (status ==0 ) {
@@ -1781,6 +1784,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) hcd->state = old_state;dev_dbg (&rhdev->dev,"bus %s fail, err %d\n" ,"resume" , status); +pm_runtime_put (hcd->self.controller);if (status != -ESHUTDOWN )usb_hc_died (hcd); }
@@ -1968,6 +1972,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,INIT_WORK (&hcd->wakeup_work, hcd_resume_work);#endif +pm_runtime_enable (dev); +pm_runtime_get (dev); + hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc :"USB Host Controller" ;
@@ -1979,6 +1986,8 @@ static void hcd_release (struct kref *kref) { struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); +pm_runtime_put_sync (hcd->self.controller); +kfree (hcd); }
drivers/usb/core/hcd.h +1 -0
@@ -171,6 +171,7 @@ struct hc_driver {int flags;#define HCD_MEMORY 0x0001/* HC regs use memory (else I/O) */ #define HCD_LOCAL_MEM 0x0002/* HC needs local memory */ +#define HCD_RUNTIME_PM 0x0004/* HC supports handling runtime PM */ #define HCD_USB11 0x0010/* USB 1.1 */ #define HCD_USB2 0x0020/* USB 2.0 */ #define HCD_USB3 0x0040/* USB 3.0 */
drivers/usb/host/ehci-pci.c +1 -1
@@ -368,7 +368,7 @@ static const struct hc_driver ehci_pci_hc_driver = {* generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_RUNTIME_PM,/* * basic lifecycle operations
drivers/usb/host/uhci-hcd.c +1 -1
@@ -900,7 +900,7 @@ static const struct hc_driver uhci_driver = {/* Generic hardware linkage */ .irq = uhci_irq, - .flags = HCD_USB11, + .flags = HCD_USB11 | HCD_RUNTIME_PM,/* Basic lifecycle operations */ .reset = uhci_init,
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] usb: Add support for runtime power management of the hcd
Am Donnerstag, 13. August 2009 02:35:44 schrieb Matthew Garrett:
Quoted 1 line
The power savings from this are measurable but not huge - it still seems
How large?
Quoted 4 lines
like a decent optimisation. The main problem is that BIOS bugs on some Dell laptops will kill USB if this is used, so we either default to off or add some quirks to handle that case (I have some ideas in that respect).
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct · line 1975
Quoted 5 lines
drivers/usb/core/hcd.c +1
-0@@ -1968,6 +1972,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,INIT_WORK (&hcd->wakeup_work, hcd_resume_work);#endif +pm_runtime_enable (dev);
So you don't get a reference from that?
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, · line 1976
Quoted 1 line
drivers/usb/core/hcd.c +1
-0+pm_runtime_get (dev);
What happens if you get a runtime suspend request in between? Is this a flaw of the API?
Regards
Oliver
Re: [RFC] usb: Add support for runtime power management of the hcd
Quoted 5 lines · Oliver Neukum
Am Donnerstag, 13. August 2009 02:35:44 schrieb Matthew Garrett:
Quoted 1 line
The power savings from this are measurable but not huge - it still seems
How large?
About 0.2W on an ich9 system.
Quoted 7 lines
Quoted 4 lines
like a decent optimisation. The main problem is that BIOS bugs on some Dell laptops will kill USB if this is used, so we either default to off or add some quirks to handle that case (I have some ideas in that respect).
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
They range from pragmatic to ugly. We could blacklist all Dells, though I'm trying to find out if there's a BIOS date that guarantees the system is fixed. Alternatively, it's a single-line bug in the DSDT - we could implement some kind of fixup in the ACPI parsing code. I find the latter interesting but possibly too hideous to live :)
Quoted 7 lines
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct · line 1975
Quoted 5 lines
drivers/usb/core/hcd.c +1
-0@@ -1968,6 +1972,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,INIT_WORK (&hcd->wakeup_work, hcd_resume_work);#endif +pm_runtime_enable (dev);So you don't get a reference from that?
No, but...
Quoted 4 lines
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, · line 1976
Quoted 1 line
drivers/usb/core/hcd.c +1
-0+pm_runtime_get (dev);What happens if you get a runtime suspend request in between? Is this a flaw of the API?
I suspect that just swapping the order of those two lines would be fine.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] usb: Add support for runtime power management of the hcd
In reply to Oliver NeukumQuoted 5 lines · Oliver Neukum
Am Donnerstag, 13. August 2009 02:35:44 schrieb Matthew Garrett:
Quoted 1 line
The power savings from this are measurable but not huge - it still seems
How large?
About 0.2W on an ich9 system.
Quoted 7 lines
Quoted 4 lines
like a decent optimisation. The main problem is that BIOS bugs on some Dell laptops will kill USB if this is used, so we either default to off or add some quirks to handle that case (I have some ideas in that respect).
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
They range from pragmatic to ugly. We could blacklist all Dells, though I'm trying to find out if there's a BIOS date that guarantees the system is fixed. Alternatively, it's a single-line bug in the DSDT - we could implement some kind of fixup in the ACPI parsing code. I find the latter interesting but possibly too hideous to live :)
Quoted 7 lines
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct · line 1975
Quoted 5 lines
drivers/usb/core/hcd.c +1
-0@@ -1968,6 +1972,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,INIT_WORK (&hcd->wakeup_work, hcd_resume_work);#endif +pm_runtime_enable (dev);So you don't get a reference from that?
No, but...
Quoted 4 lines
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, · line 1976
Quoted 1 line
drivers/usb/core/hcd.c +1
-0+pm_runtime_get (dev);What happens if you get a runtime suspend request in between? Is this a flaw of the API?
I suspect that just swapping the order of those two lines would be fine.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] usb: Add support for runtime power management of the hcd
Am Donnerstag, 13. August 2009 14:30:34 schrieb Matthew Garrett:
Quoted 8 lines
Quoted 2 lines
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
They range from pragmatic to ugly. We could blacklist all Dells, though I'm trying to find out if there's a BIOS date that guarantees the system is fixed. Alternatively, it's a single-line bug in the DSDT - we could implement some kind of fixup in the ACPI parsing code. I find the latter interesting but possibly too hideous to live :)
Is there any indication only those BIOSes are affected?
Regards
Oliver
Re: [RFC] usb: Add support for runtime power management of the hcd
Quoted 11 lines · Oliver Neukum
Am Donnerstag, 13. August 2009 14:30:34 schrieb Matthew Garrett:
Quoted 8 lines
Quoted 2 lines
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
They range from pragmatic to ugly. We could blacklist all Dells, though I'm trying to find out if there's a BIOS date that guarantees the system is fixed. Alternatively, it's a single-line bug in the DSDT - we could implement some kind of fixup in the ACPI parsing code. I find the latter interesting but possibly too hideous to live :)
Is there any indication only those BIOSes are affected?
Based on what I've looked at, other BIOSes either indicate that they don't support this or should work properly. Real life may disagree.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] usb: Add support for runtime power management of the hcd
In reply to Oliver NeukumQuoted 11 lines · Oliver Neukum
Am Donnerstag, 13. August 2009 14:30:34 schrieb Matthew Garrett:
Quoted 8 lines
Quoted 2 lines
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
They range from pragmatic to ugly. We could blacklist all Dells, though I'm trying to find out if there's a BIOS date that guarantees the system is fixed. Alternatively, it's a single-line bug in the DSDT - we could implement some kind of fixup in the ACPI parsing code. I find the latter interesting but possibly too hideous to live :)
Is there any indication only those BIOSes are affected?
Based on what I've looked at, other BIOSes either indicate that they don't support this or should work properly. Real life may disagree.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [RFC] usb: Add support for runtime power management of the hcd
In reply to Matthew GarrettAm Donnerstag, 13. August 2009 14:30:34 schrieb Matthew Garrett:
Quoted 8 lines
Quoted 2 lines
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
They range from pragmatic to ugly. We could blacklist all Dells, though I'm trying to find out if there's a BIOS date that guarantees the system is fixed. Alternatively, it's a single-line bug in the DSDT - we could implement some kind of fixup in the ACPI parsing code. I find the latter interesting but possibly too hideous to live :)
Is there any indication only those BIOSes are affected?
Regards
Oliver
Re: [RFC] usb: Add support for runtime power management of the hcd
In reply to Matthew GarrettAm Donnerstag, 13. August 2009 02:35:44 schrieb Matthew Garrett:
Quoted 1 line
The power savings from this are measurable but not huge - it still seems
How large?
Quoted 4 lines
like a decent optimisation. The main problem is that BIOS bugs on some Dell laptops will kill USB if this is used, so we either default to off or add some quirks to handle that case (I have some ideas in that respect).
Your earlier failures don't look promising regarding BIOSes. What do you have in mind?
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct · line 1975
Quoted 5 lines
drivers/usb/core/hcd.c +1
-0@@ -1968,6 +1972,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,INIT_WORK (&hcd->wakeup_work, hcd_resume_work);#endif +pm_runtime_enable (dev);
So you don't get a reference from that?
drivers/usb/core/hcd.c struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, · line 1976
Quoted 1 line
drivers/usb/core/hcd.c +1
-0+pm_runtime_get (dev);
What happens if you get a runtime suspend request in between? Is this a flaw of the API?
Regards
Oliver
Alan Stern
maintainerRe: [RFC] usb: Add support for runtime power management of the hcd
In reply to Matthew GarrettQuoted 7 lines · Matthew Garrett
drivers/usb/core/hcd-pci.c +1
-0@@ -363,6 +363,18 @@ static int hcd_pci_restore(struct device *dev)return resume_common (dev, true); } +static int hcd_pci_runtime_suspend (struct device *dev)
drivers/usb/core/hcd-pci.c static int hcd_pci_restore(struct device *dev) · line 376
Quoted 10 lines
drivers/usb/core/hcd-pci.c +10
-0+{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct usb_hcd *hcd =pci_get_drvdata (pci_dev); +struct usb_device *rhdev = hcd->self.root_hub; + +if (!(hcd->driver->flags &HCD_RUNTIME_PM )) +return -EINVAL ; + +return 0 ; +}
You have to call the HCD's pci_suspend method! Not to mention calling synchronize_irq and all the other stuff in hcd_pci_suspend and hcd_pci_suspend_noirq.
Ditto for resuming.
Alan Stern
Alan Stern
maintainerRe: [RFC] usb: Add support for runtime power management of the hcd
In reply to Matthew GarrettQuoted 7 lines · Matthew Garrett
drivers/usb/core/hcd-pci.c +1
-0@@ -363,6 +363,18 @@ static int hcd_pci_restore(struct device *dev)return resume_common (dev, true); } +static int hcd_pci_runtime_suspend (struct device *dev)
drivers/usb/core/hcd-pci.c static int hcd_pci_restore(struct device *dev) · line 376
Quoted 10 lines
drivers/usb/core/hcd-pci.c +10
-0+{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct usb_hcd *hcd =pci_get_drvdata (pci_dev); +struct usb_device *rhdev = hcd->self.root_hub; + +if (!(hcd->driver->flags &HCD_RUNTIME_PM )) +return -EINVAL ; + +return 0 ; +}
You have to call the HCD's pci_suspend method! Not to mention calling synchronize_irq and all the other stuff in hcd_pci_suspend and hcd_pci_suspend_noirq.
Ditto for resuming.
Alan Stern
Re: [RFC] usb: Add support for runtime power management of the hcd
Quoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.
The bus level code does this, assuming that the driver-level code doesn't return an error.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [RFC] usb: Add support for runtime power management of the hcd
In reply to Alan SternQuoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.
The bus level code does this, assuming that the driver-level code doesn't return an error.
Signature · 1 line
Matthew Garrett | [email protected]
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
In reply to Matthew Garrettdrivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 923
Quoted 12 lines · Matthew Garrett
drivers/pci/pci-driver.c +9
-0+#ifdef CONFIG_PM_RUNTIME + +static int pci_pm_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error; + +device_set_wakeup_enable (dev,1 );
This is a userspace policy parameter. Kernel code should not alter it. Instead you should test device_may_wakeup.
Quoted 25 lines
drivers/pci/pci-driver.c +25
-0+ error =pci_enable_runtime_wake (pci_dev, true); + +if (error) +return -EBUSY ; + +if (pm && pm->runtime_suspend) + error = pm->runtime_suspend (dev); + +if (error) + goto out; + + error =pci_pm_suspend (dev); + +if (error) + goto resume; + +disable_irq (pci_dev->irq); + error =pci_pm_suspend_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) + goto resume_noirq; + +return 0 ; +
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 958
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+resume_noirq: +disable_irq (pci_dev->irq); +pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); +resume: +pci_pm_resume (dev); +out: +pci_enable_runtime_wake (pci_dev, false); +return error; +}
The goto statements and unwinding code don't match up.
Quoted 21 lines
drivers/pci/pci-driver.c +21
-0+static int pci_pm_runtime_resume (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error =0 ; + +disable_irq (pci_dev->irq); + error =pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) +return error; + + error =pci_pm_resume (dev); + +if (error) +return error; + +if (pm->runtime_resume) + error = pm->runtime_resume (dev); +
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 990
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+if (error) +return error; + + error =pci_enable_runtime_wake (pci_dev, false); + +if (error) +return error; + +return 0 ; +}
Log an error message when something goes wrong?
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 1000
Quoted 9 lines
drivers/pci/pci-driver.c +9
-0+static void pci_pm_runtime_idle (struct device *dev) +{ +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; + +if (pm && pm->runtime_idle) + pm->runtime_idle (dev); + +pm_schedule_suspend (dev,0 ); +}
This misses the point. The whole idea of runtime_idle is to tell you that the device is idle and might be ready to be suspended. If you're going to call pm_schedule_suspend anyway, there's no reason to invoke pm->runtime_idle.
Alan Stern
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
In reply to Matthew Garrettdrivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 923
Quoted 12 lines · Matthew Garrett
drivers/pci/pci-driver.c +9
-0+#ifdef CONFIG_PM_RUNTIME + +static int pci_pm_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error; + +device_set_wakeup_enable (dev,1 );
This is a userspace policy parameter. Kernel code should not alter it. Instead you should test device_may_wakeup.
Quoted 25 lines
drivers/pci/pci-driver.c +25
-0+ error =pci_enable_runtime_wake (pci_dev, true); + +if (error) +return -EBUSY ; + +if (pm && pm->runtime_suspend) + error = pm->runtime_suspend (dev); + +if (error) + goto out; + + error =pci_pm_suspend (dev); + +if (error) + goto resume; + +disable_irq (pci_dev->irq); + error =pci_pm_suspend_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) + goto resume_noirq; + +return 0 ; +
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 958
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+resume_noirq: +disable_irq (pci_dev->irq); +pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); +resume: +pci_pm_resume (dev); +out: +pci_enable_runtime_wake (pci_dev, false); +return error; +}
The goto statements and unwinding code don't match up.
Quoted 21 lines
drivers/pci/pci-driver.c +21
-0+static int pci_pm_runtime_resume (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error =0 ; + +disable_irq (pci_dev->irq); + error =pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) +return error; + + error =pci_pm_resume (dev); + +if (error) +return error; + +if (pm->runtime_resume) + error = pm->runtime_resume (dev); +
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 990
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+if (error) +return error; + + error =pci_enable_runtime_wake (pci_dev, false); + +if (error) +return error; + +return 0 ; +}
Log an error message when something goes wrong?
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 1000
Quoted 9 lines
drivers/pci/pci-driver.c +9
-0+static void pci_pm_runtime_idle (struct device *dev) +{ +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; + +if (pm && pm->runtime_idle) + pm->runtime_idle (dev); + +pm_schedule_suspend (dev,0 ); +}
This misses the point. The whole idea of runtime_idle is to tell you that the device is idle and might be ready to be suspended. If you're going to call pm_schedule_suspend anyway, there's no reason to invoke pm->runtime_idle.
Alan Stern
Re: [RFC] PCI: Runtime power management
Quoted 5 lines · Alan Stern
Quoted 2 lines · Matthew Garrett
drivers/pci/pci-driver.c +0
-0
Quoted 12 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 923
Quoted 9 lines
drivers/pci/pci-driver.c +9
-0+#ifdef CONFIG_PM_RUNTIME + +static int pci_pm_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error; + +device_set_wakeup_enable (dev,1 );This is a userspace policy parameter. Kernel code should not alter it. Instead you should test
device_may_wakeup.
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 9 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 958
Quoted 7 lines
drivers/pci/pci-driver.c +7
-0+enable_irq (pci_dev->irq); +resume: +pci_pm_resume (dev); +out: +pci_enable_runtime_wake (pci_dev, false); +return error; +}The goto statements and unwinding code don't match up.
I'll look at that.
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 990
Quoted 5 lines
drivers/pci/pci-driver.c +5
-0+if (error) +return error; + +return 0 ; +}Log an error message when something goes wrong?
Seems fair.
Quoted 6 lines
Quoted 6 lines
drivers/pci/pci-driver.c +6
-0+static void pci_pm_runtime_idle (struct device *dev) +{ +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; + +if (pm && pm->runtime_idle) + pm->runtime_idle (dev);
Quoted 8 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 1000
Quoted 3 lines
drivers/pci/pci-driver.c +3
-0+ +pm_schedule_suspend (dev,0 ); +}This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.
My understanding of the API was that pm_device_put() invokes runtime_idle if the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [RFC] PCI: Runtime power management
In reply to Alan SternQuoted 5 lines · Alan Stern
Quoted 2 lines · Matthew Garrett
drivers/pci/pci-driver.c +0
-0
Quoted 12 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 923
Quoted 9 lines
drivers/pci/pci-driver.c +9
-0+#ifdef CONFIG_PM_RUNTIME + +static int pci_pm_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error; + +device_set_wakeup_enable (dev,1 );This is a userspace policy parameter. Kernel code should not alter it. Instead you should test
device_may_wakeup.
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 9 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 958
Quoted 7 lines
drivers/pci/pci-driver.c +7
-0+enable_irq (pci_dev->irq); +resume: +pci_pm_resume (dev); +out: +pci_enable_runtime_wake (pci_dev, false); +return error; +}The goto statements and unwinding code don't match up.
I'll look at that.
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 990
Quoted 5 lines
drivers/pci/pci-driver.c +5
-0+if (error) +return error; + +return 0 ; +}Log an error message when something goes wrong?
Seems fair.
Quoted 6 lines
Quoted 6 lines
drivers/pci/pci-driver.c +6
-0+static void pci_pm_runtime_idle (struct device *dev) +{ +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; + +if (pm && pm->runtime_idle) + pm->runtime_idle (dev);
Quoted 8 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 1000
Quoted 3 lines
drivers/pci/pci-driver.c +3
-0+ +pm_schedule_suspend (dev,0 ); +}This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.
My understanding of the API was that pm_device_put() invokes runtime_idle if the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [RFC] PCI: Runtime power management
Quoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing device_may_wakeup().
Quoted 11 lines
Quoted 4 lines
This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.My understanding of the API was that
pm_device_put()invokesruntime_idleif the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.From the API docs:
"The action performed by a bus type's ->runtime_idle() callback is totally dependent on the bus type in question, but the expected and recommended action is to check if the device can be suspended (i.e. if all of the conditions necessary for suspending the device are satisfied) and to queue up a suspend request for the device in that case."
Though perhaps the device level runtime_idle shouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
In reply to Matthew GarrettQuoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing device_may_wakeup().
Quoted 11 lines
Quoted 4 lines
This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.My understanding of the API was that
pm_device_put()invokesruntime_idleif the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.From the API docs:
"The action performed by a bus type's ->runtime_idle() callback is totally dependent on the bus type in question, but the expected and recommended action is to check if the device can be suspended (i.e. if all of the conditions necessary for suspending the device are satisfied) and to queue up a suspend request for the device in that case."
Though perhaps the device level runtime_idle shouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.
Signature · 1 line
Matthew Garrett | [email protected]
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
Quoted 8 lines · Matthew Garrett
Quoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.The bus level code does this, assuming that the driver-level code doesn't return an error.
So it does; my mistake.
Quoted 9 lines · Matthew Garrett
Quoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 4 lines
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing
device_may_wakeup().
You are suggesting separate flag sets for system-wide wakeup and runtime wakeup? I don't disagree, but implementing them will be problematical.
That's because it's not always possible to change a device's wakeup setting while it is suspended. Thus if a device was runtime suspended with wakeup enabled, and then we want to do a system sleep and change the device's wakeup setting to disabled, we would have to wake the device back up in order to do it.
Quoted 18 lines
Quoted 9 lines
Quoted 4 lines
This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.My understanding of the API was that
pm_device_put()invokesruntime_idleif the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.From the API docs:
"The action performed by a bus type's ->runtime_idle() callback is totally dependent on the bus type in question, but the expected and recommended action is to check if the device can be suspended (i.e. if all of the conditions necessary for suspending the device are satisfied) and to queue up a suspend request for the device in that case."
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.
If you want to get the device-level runtime_idle involved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.
However changing the return type wouldn't hurt anything, and it would allow the pm_schedule_suspend call to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.
Alan Stern
Alan Stern
maintainerRe: [linux-pm] [RFC] PCI: Runtime power management
In reply to Matthew GarrettQuoted 8 lines · Matthew Garrett
Quoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.The bus level code does this, assuming that the driver-level code doesn't return an error.
So it does; my mistake.
Quoted 9 lines · Matthew Garrett
Quoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 4 lines
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing
device_may_wakeup().
You are suggesting separate flag sets for system-wide wakeup and runtime wakeup? I don't disagree, but implementing them will be problematical.
That's because it's not always possible to change a device's wakeup setting while it is suspended. Thus if a device was runtime suspended with wakeup enabled, and then we want to do a system sleep and change the device's wakeup setting to disabled, we would have to wake the device back up in order to do it.
Quoted 18 lines
Quoted 9 lines
Quoted 4 lines
This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.My understanding of the API was that
pm_device_put()invokesruntime_idleif the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.From the API docs:
"The action performed by a bus type's ->runtime_idle() callback is totally dependent on the bus type in question, but the expected and recommended action is to check if the device can be suspended (i.e. if all of the conditions necessary for suspending the device are satisfied) and to queue up a suspend request for the device in that case."
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.
If you want to get the device-level runtime_idle involved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.
However changing the return type wouldn't hurt anything, and it would allow the pm_schedule_suspend call to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.
Alan Stern
Re: [linux-pm] [RFC] PCI: Runtime power management
Quoted 64 lines · Alan Stern
Quoted 8 lines · Matthew Garrett
Quoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.The bus level code does this, assuming that the driver-level code doesn't return an error.
So it does; my mistake.
Quoted 9 lines · Matthew Garrett
Quoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 4 lines
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing
device_may_wakeup().You are suggesting separate flag sets for system-wide wakeup and runtime wakeup? I don't disagree, but implementing them will be problematical.
That's because it's not always possible to change a device's wakeup setting while it is suspended. Thus if a device was runtime suspended with wakeup enabled, and then we want to do a system sleep and change the device's wakeup setting to disabled, we would have to wake the device back up in order to do it.
Quoted 18 lines
Quoted 9 lines
Quoted 4 lines
This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.My understanding of the API was that
pm_device_put()invokesruntime_idleif the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.From the API docs:
"The action performed by a bus type's ->runtime_idle() callback is totally dependent on the bus type in question, but the expected and recommended action is to check if the device can be suspended (i.e. if all of the conditions necessary for suspending the device are satisfied) and to queue up a suspend request for the device in that case."
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.
Quoted 8 lines
If you want to get the device-level
runtime_idleinvolved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.However changing the return type wouldn't hurt anything, and it would allow the
pm_schedule_suspendcall to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.
Well, I'm not against that, but what should pm_runtime_idle() do with the result returned by it? Just pass it to the caller?
Rafael
Re: [linux-pm] [RFC] PCI: Runtime power management
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · Alan Stern
Quoted 1 line · Matthew Garrett
On Thu, Aug 13, 2009 at 11:22:44AM -0400, Alan Stern wrote:
...
Quoted 10 lines
Quoted 10 lines
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.If you want to get the device-level
runtime_idleinvolved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.
Quoted 6 lines
Quoted 3 lines
However changing the return type wouldn't hurt anything, and it would allow the
pm_schedule_suspendcall to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.Well, I'm not against that, but what should
pm_runtime_idle()do with the result returned by it? Just pass it to the caller?
Hm, perhaps its better to ignore it, though.
Rafael
Alan Stern
maintainerRe: [linux-pm] [RFC] PCI: Runtime power management
Quoted 16 lines · Rafael J. Wysocki
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · Alan Stern
Quoted 1 line · Matthew Garrett
On Thu, Aug 13, 2009 at 11:22:44AM -0400, Alan Stern wrote:
...
Quoted 10 lines
Quoted 10 lines
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.If you want to get the device-level
runtime_idleinvolved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
However changing the return type wouldn't hurt anything, and it would allow the
pm_schedule_suspendcall to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.Well, I'm not against that, but what should
pm_runtime_idle()do with the result returned by it? Just pass it to the caller?Hm, perhaps its better to ignore it, though.
That's what I was going to say. The return value is intended for use by bus-level code when calling a driver-level routine.
Alan Stern
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 16 lines · Rafael J. Wysocki
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · Alan Stern
Quoted 1 line · Matthew Garrett
On Thu, Aug 13, 2009 at 11:22:44AM -0400, Alan Stern wrote:
...
Quoted 10 lines
Quoted 10 lines
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.If you want to get the device-level
runtime_idleinvolved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
However changing the return type wouldn't hurt anything, and it would allow the
pm_schedule_suspendcall to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.Well, I'm not against that, but what should
pm_runtime_idle()do with the result returned by it? Just pass it to the caller?Hm, perhaps its better to ignore it, though.
That's what I was going to say. The return value is intended for use by bus-level code when calling a driver-level routine.
Alan Stern
Re: [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · Alan Stern
Quoted 1 line · Matthew Garrett
On Thu, Aug 13, 2009 at 11:22:44AM -0400, Alan Stern wrote:
...
Quoted 10 lines
Quoted 10 lines
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.If you want to get the device-level
runtime_idleinvolved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.
Quoted 6 lines
Quoted 3 lines
However changing the return type wouldn't hurt anything, and it would allow the
pm_schedule_suspendcall to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.Well, I'm not against that, but what should
pm_runtime_idle()do with the result returned by it? Just pass it to the caller?
Hm, perhaps its better to ignore it, though.
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Alan SternQuoted 64 lines · Alan Stern
Quoted 8 lines · Matthew Garrett
Quoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.The bus level code does this, assuming that the driver-level code doesn't return an error.
So it does; my mistake.
Quoted 9 lines · Matthew Garrett
Quoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 4 lines
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing
device_may_wakeup().You are suggesting separate flag sets for system-wide wakeup and runtime wakeup? I don't disagree, but implementing them will be problematical.
That's because it's not always possible to change a device's wakeup setting while it is suspended. Thus if a device was runtime suspended with wakeup enabled, and then we want to do a system sleep and change the device's wakeup setting to disabled, we would have to wake the device back up in order to do it.
Quoted 18 lines
Quoted 9 lines
Quoted 4 lines
This misses the point. The whole idea of
runtime_idleis to tell you that the device is idle and might be ready to be suspended. If you're going to callpm_schedule_suspendanyway, there's no reason to invokepm->runtime_idle.My understanding of the API was that
pm_device_put()invokesruntime_idleif the refcount hits 0. The bus layer has no idea of the refcount, and calling suspend directly from the driver would defeat the point of the system-wide recounting.From the API docs:
"The action performed by a bus type's ->runtime_idle() callback is totally dependent on the bus type in question, but the expected and recommended action is to check if the device can be suspended (i.e. if all of the conditions necessary for suspending the device are satisfied) and to queue up a suspend request for the device in that case."
Quoted 4 lines
Though perhaps the device level
runtime_idleshouldn't be void - that way the bus can ask the driver whether its suspend conditions have been satisfied? Right now there doesn't seem to be any way for the bus to ask that.
Quoted 8 lines
If you want to get the device-level
runtime_idleinvolved, you can make _it_ responsible for scheduling the suspend. Then the bus-level code simply has to check whether everything is okay at the bus level, and if it is, call the device-level routine.However changing the return type wouldn't hurt anything, and it would allow the
pm_schedule_suspendcall to be centralized in the bus code. You could ask Rafael about it, or just send him a patch.
Well, I'm not against that, but what should pm_runtime_idle() do with the result returned by it? Just pass it to the caller?
Rafael
Re: [linux-pm] [RFC] PCI: Runtime power management
In reply to Alan SternQuoted 34 lines · Alan Stern
Quoted 8 lines · Matthew Garrett
Quoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.The bus level code does this, assuming that the driver-level code doesn't return an error.
So it does; my mistake.
Quoted 9 lines · Matthew Garrett
Quoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 4 lines
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing
device_may_wakeup().You are suggesting separate flag sets for system-wide wakeup and runtime wakeup? I don't disagree, but implementing them will be problematical.
Quoted 5 lines
That's because it's not always possible to change a device's wakeup setting while it is suspended. Thus if a device was runtime suspended with wakeup enabled, and then we want to do a system sleep and change the device's wakeup setting to disabled, we would have to wake the device back up in order to do it.
Well, sometimes the user may want a device to be power managed at run time and not to be able to wake up the system from sleep states. For example, I'd like the USB controller in my box to be suspended at run time whenever it's not used, but surely I wouldn't like it to do system-wide wakeup, because it does that when I move the mouse which is a cordless one. Simply turning the mouse on causes the system to wake up. :-)
So, I don't think we have a choice here. If the user forbids the device to wake up the system from sleep states, we have to do what he wants, even if that means the devices has to be resumed before putting the system into a sleep state.
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like runtime_forbidden, that the user space will be able to set through sysfs?
If the user space does that, we can't power manage the device at run time, so it can't do runtime wakeup as well. Otherwise, the device is power manageable at run time, which implies runtime wakeup if supported.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
Quoted 6 lines · Rafael J. Wysocki
Well, sometimes the user may want a device to be power managed at run time and not to be able to wake up the system from sleep states. For example, I'd like the USB controller in my box to be suspended at run time whenever it's not used, but surely I wouldn't like it to do system-wide wakeup, because it does that when I move the mouse which is a cordless one. Simply turning the mouse on causes the system to wake up. :-)
Right, so clearly my code is broken right now.
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?
I think even having a runtime_wakeup flag (which defaults to on) would be sufficient. If the worst case is scenario is that we have to resume devices in order to apply the correct policy when going into a systemwide suspend state, I think that's acceptable.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 6 lines · Rafael J. Wysocki
Well, sometimes the user may want a device to be power managed at run time and not to be able to wake up the system from sleep states. For example, I'd like the USB controller in my box to be suspended at run time whenever it's not used, but surely I wouldn't like it to do system-wide wakeup, because it does that when I move the mouse which is a cordless one. Simply turning the mouse on causes the system to wake up. :-)
Right, so clearly my code is broken right now.
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?
I think even having a runtime_wakeup flag (which defaults to on) would be sufficient. If the worst case is scenario is that we have to resume devices in order to apply the correct policy when going into a systemwide suspend state, I think that's acceptable.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
Quoted 9 lines · Matthew Garrett
Quoted 6 lines · Rafael J. Wysocki
Well, sometimes the user may want a device to be power managed at run time and not to be able to wake up the system from sleep states. For example, I'd like the USB controller in my box to be suspended at run time whenever it's not used, but surely I wouldn't like it to do system-wide wakeup, because it does that when I move the mouse which is a cordless one. Simply turning the mouse on causes the system to wake up. :-)
Quoted 8 lines
Right, so clearly my code is broken right now.
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?I think even having a
runtime_wakeupflag (which defaults to on) would be sufficient.
Perhaps it would, but then unsetting runtime_wakeup would effectively disable runtime PM for devices that need it to be power managed at run time (probably all input devices). Also there may be situations in which user space may really want to disable runtime PM for some devices (think of broken hardware for one example).
Quoted 3 lines
If the worst case is scenario is that we have to resume devices in order to apply the correct policy when going into a systemwide suspend state, I think that's acceptable.
I agree.
Thanks,
Rafael
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
Quoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?
Quoted 8 lines
Quoted 2 lines
I think even having a
runtime_wakeupflag (which defaults to on) would be sufficient.Perhaps it would, but then unsetting
runtime_wakeupwould effectively disable runtime PM for devices that need it to be power managed at run time (probably all input devices). Also there may be situations in which user space may really want to disable runtime PM for some devices (think of broken hardware for one example).
It sounds like there are really three choices here, and the decision should largely be left up to the user:
1. don't use runtime PM,
2. allow runtime PM but disable remote wakeup,
3. allow runtime PM with remote wakeup enabled.
Now, a driver may say "I can't do my job without remote wakeup". Such a driver would refuse to do runtime_suspend in case 2. But otherwise we should follow the preference of the user.
The only remaining question is how to expose this in sysfs in a way that won't be confusing and that won't be confused with the "wakeup" attribute. One possibility is to use the "level" attribute introduced in USB; possible levels are "on" (no runtime PM) and "auto" (runtime PM allowed). Then a new "runtime_wakeup" attribute could contain nothing (if wakeup is not available), "enabled", or "disabled".
Alan Stern
Alan Stern
maintainerRe: [linux-pm] [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?
Quoted 8 lines
Quoted 2 lines
I think even having a
runtime_wakeupflag (which defaults to on) would be sufficient.Perhaps it would, but then unsetting
runtime_wakeupwould effectively disable runtime PM for devices that need it to be power managed at run time (probably all input devices). Also there may be situations in which user space may really want to disable runtime PM for some devices (think of broken hardware for one example).
It sounds like there are really three choices here, and the decision should largely be left up to the user:
1. don't use runtime PM,
2. allow runtime PM but disable remote wakeup,
3. allow runtime PM with remote wakeup enabled.
Now, a driver may say "I can't do my job without remote wakeup". Such a driver would refuse to do runtime_suspend in case 2. But otherwise we should follow the preference of the user.
The only remaining question is how to expose this in sysfs in a way that won't be confusing and that won't be confused with the "wakeup" attribute. One possibility is to use the "level" attribute introduced in USB; possible levels are "on" (no runtime PM) and "auto" (runtime PM allowed). Then a new "runtime_wakeup" attribute could contain nothing (if wakeup is not available), "enabled", or "disabled".
Alan Stern
Re: [linux-pm] [RFC] PCI: Runtime power management
Quoted 28 lines · Alan Stern
Quoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?Quoted 8 lines
Quoted 2 lines
I think even having a
runtime_wakeupflag (which defaults to on) would be sufficient.Perhaps it would, but then unsetting
runtime_wakeupwould effectively disable runtime PM for devices that need it to be power managed at run time (probably all input devices). Also there may be situations in which user space may really want to disable runtime PM for some devices (think of broken hardware for one example).It sounds like there are really three choices here, and the decision should largely be left up to the user:
1. don't use runtime PM,
2. allow runtime PM but disable remote wakeup,
3. allow runtime PM with remote wakeup enabled.
Now, a driver may say "I can't do my job without remote wakeup". Such a driver would refuse to do
runtime_suspendin case 2. But otherwise we should follow the preference of the user.
Quoted 6 lines
The only remaining question is how to expose this in sysfs in a way that won't be confusing and that won't be confused with the "wakeup" attribute. One possibility is to use the "level" attribute introduced in USB; possible levels are "on" (no runtime PM) and "auto" (runtime PM allowed). Then a new "
runtime_wakeup" attribute could contain nothing (if wakeup is not available), "enabled", or "disabled".
That seems to require two flags.
runtime_forbidden - if unset, the driver decides whether or not to use runtime
PM; that could be exposed through sysfs as 'runtime' under the 'power' subdirectory with the following values:
* 'disabled' - runtime_forbidden is set by the user space
* 'on' - runtime_forbidden is unset, runtime PM is used (disable_depth == 0)
* 'off' - runtime_forbidden is unset, runtime PM is not used
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is unset.
runtime_wakeup - if set, the device is allowed to do remote wakeup at run time
That could be represented as 'runtime_wakeup' under 'power' with the following values:
* no value (empty file) is 'runtime' is 'disabled'
* 'enabled'
* 'disabled'
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is set.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
Quoted 8 lines · Rafael J. Wysocki
runtime_wakeup- if set, the device is allowed to do remote wakeup at run time
That could be represented as 'runtime_wakeup' under 'power' with the following values:
* no value (empty file) is 'runtime' is 'disabled'
* 'enabled'
* 'disabled'
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is set.
Why would you ever want runtime_wakeup to be false unless runtime_forbidden is true? Surely the point of runtime power management is to be transparent to the user, in which case remote wakeup is required?
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 8 lines · Rafael J. Wysocki
runtime_wakeup- if set, the device is allowed to do remote wakeup at run time
That could be represented as 'runtime_wakeup' under 'power' with the following values:
* no value (empty file) is 'runtime' is 'disabled'
* 'enabled'
* 'disabled'
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is set.
Why would you ever want runtime_wakeup to be false unless runtime_forbidden is true? Surely the point of runtime power management is to be transparent to the user, in which case remote wakeup is required?
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
Quoted 11 lines · Matthew Garrett
Quoted 8 lines · Rafael J. Wysocki
runtime_wakeup- if set, the device is allowed to do remote wakeup at run time
That could be represented as 'runtime_wakeup' under 'power' with the following values:
* no value (empty file) is 'runtime' is 'disabled'
* 'enabled'
* 'disabled'
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is set.
Quoted 4 lines
Why would you ever want
runtime_wakeupto be false unlessruntime_forbiddenis true? Surely the point of runtime power management is to be transparent to the user, in which case remote wakeup is required?
Well, this was exactly my point previously. :-)
Still, although for the majority of devices 'runtime_wakeup' disabled would mean no runtime PM at all IMO, there may be devices that actually work without remote wakeup, although they support it in general.
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
Quoted 2 lines · Rafael J. Wysocki
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
I think in that case we'd probably just want the interface to be downed? Some of this is going to require device-specific policy, I think - for the network case we probably want something in between IF_RUNNING and IF_DOWN (IF_CARRIER, perhaps) that indicates that we want the PHY to be powered. Pushing this out to sysfs would mean we'd have a consistent interface but varying semantics, and I'm not convinced that's an especially helpful interface.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 2 lines · Rafael J. Wysocki
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
I think in that case we'd probably just want the interface to be downed? Some of this is going to require device-specific policy, I think - for the network case we probably want something in between IF_RUNNING and IF_DOWN (IF_CARRIER, perhaps) that indicates that we want the PHY to be powered. Pushing this out to sysfs would mean we'd have a consistent interface but varying semantics, and I'm not convinced that's an especially helpful interface.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
Quoted 5 lines · Matthew Garrett
Quoted 2 lines · Rafael J. Wysocki
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
Quoted 7 lines
I think in that case we'd probably just want the interface to be downed? Some of this is going to require device-specific policy, I think - for the network case we probably want something in between
IF_RUNNINGandIF_DOWN(IF_CARRIER, perhaps) that indicates that we want the PHY to be powered. Pushing this out to sysfs would mean we'd have a consistent interface but varying semantics, and I'm not convinced that's an especially helpful interface.
I'm not disagreeing with that.
At this point I'd like to know the Alan's opinion. I would gladly use the 'runtime_forbidden' flag only, but if we overlook something now, it's going to be difficult to fix later.
Thanks,
Rafael
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
Quoted 14 lines · Rafael J. Wysocki
Quoted 5 lines · Matthew Garrett
Quoted 2 lines · Rafael J. Wysocki
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
Quoted 7 lines
I think in that case we'd probably just want the interface to be downed? Some of this is going to require device-specific policy, I think - for the network case we probably want something in between
IF_RUNNINGandIF_DOWN(IF_CARRIER, perhaps) that indicates that we want the PHY to be powered. Pushing this out to sysfs would mean we'd have a consistent interface but varying semantics, and I'm not convinced that's an especially helpful interface.
Quoted 5 lines
I'm not disagreeing with that.
At this point I'd like to know the Alan's opinion. I would gladly use the '
runtime_forbidden' flag only, but if we overlook something now, it's going to be difficult to fix later.
The notion of "remote wakeup" is more or less the same for all devices, and it can effectively be abstracted into the core. Other notions, like IF_CARRIER, are more device-dependent. They must be handled at the bus or driver level, not in the core.
The real question is whether we should export a "may_runtime_wakeup" flag. If we don't then we prevent the use of a degraded power-management mode in devices with broken wakeup support. Perhaps that's okay, I don't know.
Which reminds me... In addition to these flags controlling what settings should be enabled, maybe we should add a flag to record whether or not remote wakeup was turned on when the device was last suspended. Although the core wouldn't use it, such a flag might be very convenient for drivers.
Alan Stern
Alan Stern
maintainerRe: [linux-pm] [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 14 lines · Rafael J. Wysocki
Quoted 5 lines · Matthew Garrett
Quoted 2 lines · Rafael J. Wysocki
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
Quoted 7 lines
I think in that case we'd probably just want the interface to be downed? Some of this is going to require device-specific policy, I think - for the network case we probably want something in between
IF_RUNNINGandIF_DOWN(IF_CARRIER, perhaps) that indicates that we want the PHY to be powered. Pushing this out to sysfs would mean we'd have a consistent interface but varying semantics, and I'm not convinced that's an especially helpful interface.
Quoted 5 lines
I'm not disagreeing with that.
At this point I'd like to know the Alan's opinion. I would gladly use the '
runtime_forbidden' flag only, but if we overlook something now, it's going to be difficult to fix later.
The notion of "remote wakeup" is more or less the same for all devices, and it can effectively be abstracted into the core. Other notions, like IF_CARRIER, are more device-dependent. They must be handled at the bus or driver level, not in the core.
The real question is whether we should export a "may_runtime_wakeup" flag. If we don't then we prevent the use of a degraded power-management mode in devices with broken wakeup support. Perhaps that's okay, I don't know.
Which reminds me... In addition to these flags controlling what settings should be enabled, maybe we should add a flag to record whether or not remote wakeup was turned on when the device was last suspended. Although the core wouldn't use it, such a flag might be very convenient for drivers.
Alan Stern
Re: [RFC] PCI: Runtime power management
In reply to Matthew GarrettQuoted 5 lines · Matthew Garrett
Quoted 2 lines · Rafael J. Wysocki
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
Quoted 7 lines
I think in that case we'd probably just want the interface to be downed? Some of this is going to require device-specific policy, I think - for the network case we probably want something in between
IF_RUNNINGandIF_DOWN(IF_CARRIER, perhaps) that indicates that we want the PHY to be powered. Pushing this out to sysfs would mean we'd have a consistent interface but varying semantics, and I'm not convinced that's an especially helpful interface.
I'm not disagreeing with that.
At this point I'd like to know the Alan's opinion. I would gladly use the 'runtime_forbidden' flag only, but if we overlook something now, it's going to be difficult to fix later.
Thanks,
Rafael
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Why would you ever want
runtime_wakeupto be false unlessruntime_forbiddenis true? Surely the point of runtime power management is to be transparent to the user, in which case remote wakeup is required?
Matthew, what makes you think remote wakeup is required? Lots of power-manageable devices don't support it at all (consider disk drives or display screens).
Quoted 5 lines
Well, this was exactly my point previously. :-)
Still, although for the majority of devices '
runtime_wakeup' disabled would mean no runtime PM at all IMO, there may be devices that actually work without remote wakeup, although they support it in general.
That last part is quite true. For example, we might suspend the device whenever no process has opened the device file. It would be a degraded form of power management, but better than nothing.
Quoted 2 lines
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
Or if the device's support for remote wakeup is broken.
Alan Stern
Alan Stern
maintainerRe: [linux-pm] [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Why would you ever want
runtime_wakeupto be false unlessruntime_forbiddenis true? Surely the point of runtime power management is to be transparent to the user, in which case remote wakeup is required?
Matthew, what makes you think remote wakeup is required? Lots of power-manageable devices don't support it at all (consider disk drives or display screens).
Quoted 5 lines
Well, this was exactly my point previously. :-)
Still, although for the majority of devices '
runtime_wakeup' disabled would mean no runtime PM at all IMO, there may be devices that actually work without remote wakeup, although they support it in general.
That last part is quite true. For example, we might suspend the device whenever no process has opened the device file. It would be a degraded form of power management, but better than nothing.
Quoted 2 lines
I can even imagine a scenario where this setting might be useful, like when we don't want a network adapter to be woken up from the outside.
Or if the device's support for remote wakeup is broken.
Alan Stern
Re: [RFC] PCI: Runtime power management
Quoted 10 lines · Alan Stern
Quoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Why would you ever want
runtime_wakeupto be false unlessruntime_forbiddenis true? Surely the point of runtime power management is to be transparent to the user, in which case remote wakeup is required?Matthew, what makes you think remote wakeup is required? Lots of power-manageable devices don't support it at all (consider disk drives or display screens).
Sorry, I meant in cases where remote wakeup is a sensible concept. For things like storage there's obviously no reason to require it, but for something like USB the absence of remote wakeup would effectively break the driver for most users.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [linux-pm] [RFC] PCI: Runtime power management
In reply to Alan SternQuoted 10 lines · Alan Stern
Quoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Why would you ever want
runtime_wakeupto be false unlessruntime_forbiddenis true? Surely the point of runtime power management is to be transparent to the user, in which case remote wakeup is required?Matthew, what makes you think remote wakeup is required? Lots of power-manageable devices don't support it at all (consider disk drives or display screens).
Sorry, I meant in cases where remote wakeup is a sensible concept. For things like storage there's obviously no reason to require it, but for something like USB the absence of remote wakeup would effectively break the driver for most users.
Signature · 1 line
Matthew Garrett | [email protected]
Alan Stern
maintainerRe: [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 9 lines · Rafael J. Wysocki
Quoted 6 lines
The only remaining question is how to expose this in sysfs in a way that won't be confusing and that won't be confused with the "wakeup" attribute. One possibility is to use the "level" attribute introduced in USB; possible levels are "on" (no runtime PM) and "auto" (runtime PM allowed). Then a new "
runtime_wakeup" attribute could contain nothing (if wakeup is not available), "enabled", or "disabled".That seems to require two flags.
Quoted 8 lines
runtime_forbidden- if unset, the driver decides whether or not to use runtime
PM; that could be exposed through sysfs as 'runtime' under the 'power' subdirectory with the following values:
* 'disabled' -runtime_forbiddenis set by the user space
* 'on' -runtime_forbiddenis unset, runtime PM is used (disable_depth== 0)
* 'off' -runtime_forbiddenis unset, runtime PM is not used
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is unset.
Too confusing. The difference between "disabled" and "off" is so subtle that even I don't understand it!
All we need for this is a simple on/off switch. Or to be consistent with the terms that are already exposed to userspace for USB devices:
"auto"/"on", where "auto" means the system automatically changes power levels (runtime PM is enabled) and "on" means the device is always on (runtime PM is disabled).
And I don't like the "runtime_forbidden" name either. It's long and it's a negative, making it harder to understand. ("off" means that the device is permanently on!) What's wrong with "level", as in "power/level"? That seems very intuitive.
Quoted 8 lines
runtime_wakeup- if set, the device is allowed to do remote wakeup at run time
That could be represented as 'runtime_wakeup' under 'power' with the following values:
* no value (empty file) is 'runtime' is 'disabled'
* 'enabled'
* 'disabled'
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is set.
This is okay except for your definition of empty file. This makes it dependent on the power/level setting. The two should be independent. Thus, empty file should mean that the device doesn't support remote wakeup, in which case writes are ignored.
This scheme, like yours, requires two new bitflags. We could call them something like "may_runtime_suspend" and "may_runtime_wakeup".
Alan Stern
Alan Stern
maintainerRe: [linux-pm] [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 9 lines · Rafael J. Wysocki
Quoted 6 lines
The only remaining question is how to expose this in sysfs in a way that won't be confusing and that won't be confused with the "wakeup" attribute. One possibility is to use the "level" attribute introduced in USB; possible levels are "on" (no runtime PM) and "auto" (runtime PM allowed). Then a new "
runtime_wakeup" attribute could contain nothing (if wakeup is not available), "enabled", or "disabled".That seems to require two flags.
Quoted 8 lines
runtime_forbidden- if unset, the driver decides whether or not to use runtime
PM; that could be exposed through sysfs as 'runtime' under the 'power' subdirectory with the following values:
* 'disabled' -runtime_forbiddenis set by the user space
* 'on' -runtime_forbiddenis unset, runtime PM is used (disable_depth== 0)
* 'off' -runtime_forbiddenis unset, runtime PM is not used
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is unset.
Too confusing. The difference between "disabled" and "off" is so subtle that even I don't understand it!
All we need for this is a simple on/off switch. Or to be consistent with the terms that are already exposed to userspace for USB devices:
"auto"/"on", where "auto" means the system automatically changes power levels (runtime PM is enabled) and "on" means the device is always on (runtime PM is disabled).
And I don't like the "runtime_forbidden" name either. It's long and it's a negative, making it harder to understand. ("off" means that the device is permanently on!) What's wrong with "level", as in "power/level"? That seems very intuitive.
Quoted 8 lines
runtime_wakeup- if set, the device is allowed to do remote wakeup at run time
That could be represented as 'runtime_wakeup' under 'power' with the following values:
* no value (empty file) is 'runtime' is 'disabled'
* 'enabled'
* 'disabled'
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is set.
This is okay except for your definition of empty file. This makes it dependent on the power/level setting. The two should be independent. Thus, empty file should mean that the device doesn't support remote wakeup, in which case writes are ignored.
This scheme, like yours, requires two new bitflags. We could call them something like "may_runtime_suspend" and "may_runtime_wakeup".
Alan Stern
Re: [RFC] PCI: Runtime power management
In reply to Alan SternQuoted 28 lines · Alan Stern
Quoted 4 lines · Rafael J. Wysocki
Quoted 4 lines
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?Quoted 8 lines
Quoted 2 lines
I think even having a
runtime_wakeupflag (which defaults to on) would be sufficient.Perhaps it would, but then unsetting
runtime_wakeupwould effectively disable runtime PM for devices that need it to be power managed at run time (probably all input devices). Also there may be situations in which user space may really want to disable runtime PM for some devices (think of broken hardware for one example).It sounds like there are really three choices here, and the decision should largely be left up to the user:
1. don't use runtime PM,
2. allow runtime PM but disable remote wakeup,
3. allow runtime PM with remote wakeup enabled.
Now, a driver may say "I can't do my job without remote wakeup". Such a driver would refuse to do
runtime_suspendin case 2. But otherwise we should follow the preference of the user.
Quoted 6 lines
The only remaining question is how to expose this in sysfs in a way that won't be confusing and that won't be confused with the "wakeup" attribute. One possibility is to use the "level" attribute introduced in USB; possible levels are "on" (no runtime PM) and "auto" (runtime PM allowed). Then a new "
runtime_wakeup" attribute could contain nothing (if wakeup is not available), "enabled", or "disabled".
That seems to require two flags.
runtime_forbidden - if unset, the driver decides whether or not to use runtime
PM; that could be exposed through sysfs as 'runtime' under the 'power' subdirectory with the following values:
* 'disabled' - runtime_forbidden is set by the user space
* 'on' - runtime_forbidden is unset, runtime PM is used (disable_depth == 0)
* 'off' - runtime_forbidden is unset, runtime PM is not used
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is unset.
runtime_wakeup - if set, the device is allowed to do remote wakeup at run time
That could be represented as 'runtime_wakeup' under 'power' with the following values:
* no value (empty file) is 'runtime' is 'disabled'
* 'enabled'
* 'disabled'
To set/unset the user space writes 'enabled'/'disabled' to it, respectively. The default is set.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Matthew GarrettQuoted 9 lines · Matthew Garrett
Quoted 6 lines · Rafael J. Wysocki
Well, sometimes the user may want a device to be power managed at run time and not to be able to wake up the system from sleep states. For example, I'd like the USB controller in my box to be suspended at run time whenever it's not used, but surely I wouldn't like it to do system-wide wakeup, because it does that when I move the mouse which is a cordless one. Simply turning the mouse on causes the system to wake up. :-)
Quoted 8 lines
Right, so clearly my code is broken right now.
Quoted 3 lines
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like
runtime_forbidden, that the user space will be able to set through sysfs?I think even having a
runtime_wakeupflag (which defaults to on) would be sufficient.
Perhaps it would, but then unsetting runtime_wakeup would effectively disable runtime PM for devices that need it to be power managed at run time (probably all input devices). Also there may be situations in which user space may really want to disable runtime PM for some devices (think of broken hardware for one example).
Quoted 3 lines
If the worst case is scenario is that we have to resume devices in order to apply the correct policy when going into a systemwide suspend state, I think that's acceptable.
I agree.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Alan SternQuoted 34 lines · Alan Stern
Quoted 8 lines · Matthew Garrett
Quoted 3 lines · Alan Stern
You have to call the HCD's
pci_suspendmethod! Not to mention callingsynchronize_irqand all the other stuff inhcd_pci_suspendandhcd_pci_suspend_noirq.The bus level code does this, assuming that the driver-level code doesn't return an error.
So it does; my mistake.
Quoted 9 lines · Matthew Garrett
Quoted 6 lines · Matthew Garrett
Ugh. I'd really prefer us to assume that drivers are able to cope unless proven otherwise. Userspace policy makes sense where we don't have any idea whether something will work or not, but I'd really expect that most PCI drivers will either cope (in which case they'll have enabling code) or won't (in which case they won't). Why would we want userspace to influence this?
Quoted 4 lines
Though, thinking about it, you're right that setting this does override user policy. I think we need an additional flag to indicate that the device supports runtime wakeup and test that as well when doing
device_may_wakeup().You are suggesting separate flag sets for system-wide wakeup and runtime wakeup? I don't disagree, but implementing them will be problematical.
Quoted 5 lines
That's because it's not always possible to change a device's wakeup setting while it is suspended. Thus if a device was runtime suspended with wakeup enabled, and then we want to do a system sleep and change the device's wakeup setting to disabled, we would have to wake the device back up in order to do it.
Well, sometimes the user may want a device to be power managed at run time and not to be able to wake up the system from sleep states. For example, I'd like the USB controller in my box to be suspended at run time whenever it's not used, but surely I wouldn't like it to do system-wide wakeup, because it does that when I move the mouse which is a cordless one. Simply turning the mouse on causes the system to wake up. :-)
So, I don't think we have a choice here. If the user forbids the device to wake up the system from sleep states, we have to do what he wants, even if that means the devices has to be resumed before putting the system into a sleep state.
Why don't we add a flag indicating whether or not the device is allowed to be power managed at run time, something like runtime_forbidden, that the user space will be able to set through sysfs?
If the user space does that, we can't power manage the device at run time, so it can't do runtime wakeup as well. Otherwise, the device is power manageable at run time, which implies runtime wakeup if supported.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Matthew GarrettQuoted 8 lines · On Thu, 13 Aug 2009 01:29:25 +0100 Matthew Garrett <[email protected]> wrote:
I got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
Quoted 6 lines
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
PCI bits look pretty good to me, though Rafael should take a look too. Card readers and firewire could benefit from similar treatment, maybe that would get us to .5W territory on some machines.
Signature · 1 line
Jesse Barnes, Intel Open Source Technology Center
Re: [RFC] PCI: Runtime power management
In reply to Matthew GarrettQuoted 8 lines · On Thu, 13 Aug 2009 01:29:25 +0100 Matthew Garrett <[email protected]> wrote:
I got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
Quoted 6 lines
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
PCI bits look pretty good to me, though Rafael should take a look too. Card readers and firewire could benefit from similar treatment, maybe that would get us to .5W territory on some machines.
Signature · 1 line
Jesse Barnes, Intel Open Source Technology Center
Re: [RFC] PCI: Runtime power management
Quoted 11 lines · Jesse Barnes
Quoted 8 lines · On Thu, 13 Aug 2009 01:29:25 +0100 Matthew Garrett <[email protected]> wrote:
I got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
Quoted 8 lines
Quoted 6 lines
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
PCI bits look pretty good to me, though Rafael should take a look too.
I'm going to do that shortly.
Quoted 1 line
Card readers and firewire could benefit from similar treatment,
As well us network adapters.
Quoted 1 line
maybe that would get us to .5W territory on some machines.
Hopefully. :-)
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Jesse BarnesQuoted 11 lines · Jesse Barnes
Quoted 8 lines · On Thu, 13 Aug 2009 01:29:25 +0100 Matthew Garrett <[email protected]> wrote:
I got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
Quoted 8 lines
Quoted 6 lines
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
PCI bits look pretty good to me, though Rafael should take a look too.
I'm going to do that shortly.
Quoted 1 line
Card readers and firewire could benefit from similar treatment,
As well us network adapters.
Quoted 1 line
maybe that would get us to .5W territory on some machines.
Hopefully. :-)
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Matthew GarrettHi,
First of all, thanks a lot for looking into this!
Quoted 8 lines · Matthew Garrett
I got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
Quoted 6 lines
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
Do you have any prototypes for that? I started working on it some time ago, but then I focused on the core runtime PM framework.
Quoted 21 lines
--- drivers/pci/pci-acpi.c | 55 +++++++++++++++++++++++++ drivers/pci/pci-driver.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.c | 87 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 3 + include/linux/pci.h | 3 + 5 files changed, 248 insertions(+), 0 deletions(-)drivers/pci/pci-acpi.c +1
-0@@ -12,6 +12,7 @@#include <linux/pci.h> #include <linux/module.h> #include <linux/pci-aspm.h> +#include <linux/pm_runtime.h> #include <acpi/acpi.h> #include <acpi/acpi_bus.h>
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 129
Quoted 9 lines
drivers/pci/pci-acpi.c +6
-0@@ -120,14 +121,62 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)return error; } +static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; +
Hm, I'd move that into ACPI as
int acp_runtime_wake_enable(acpi_handle handle, bool enable)
in which form it could also be useful to non-PCI devices.
Quoted 12 lines
drivers/pci/pci-acpi.c +12
-0+if (!handle) +return -ENODEV ; + + status =acpi_bus_get_device (handle, &acpi_dev); +if (ACPI_FAILURE (status)) +return -ENODEV ; + +if (enable) { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE_RUN ); + acpi_enable_gpe(acpi_dev->wakeup.gpe_device,
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 151
Quoted 10 lines
drivers/pci/pci-acpi.c +10
-0+ acpi_dev->wakeup.gpe_number); + }else { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE ); +acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +}
Ah, that's the part I've always been missing!
How exactly do we figure out which GPE is a wake-up one for given device? IOW, how are the wakeup.gpe_device and wakeup.gpe_number fields populated?
Quoted 85 lines
drivers/pci/pci-acpi.c +26
-0+ +static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, .can_wakeup = acpi_pci_can_wakeup, .sleep_wake = acpi_pci_sleep_wake, + .runtime_wake = acpi_pci_runtime_wake, }; +static void pci_device_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pm_runtime_resume (dev); +} + +static void pci_root_bridge_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; +struct pci_dev *pci_dev =to_pci_dev (dev); + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pci_bus_pme_event (pci_dev); +} +/* ACPI bus type */ static int acpi_pci_find_device (struct device *dev,acpi_handle *handle) {@@ -140,6 +189,9 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) *handle =acpi_get_child (DEVICE_ACPI_HANDLE (dev->parent), addr);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_device_notify, dev);return 0 ; }@@ -158,6 +210,9 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) *handle =acpi_get_pci_rootbridge_handle (seg, bus);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_root_bridge_notify, dev);return 0 ; }drivers/pci/pci-driver.c +13
-0@@ -11,12 +11,14 @@#include <linux/pci.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/device.h> #include <linux/mempolicy.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/sched.h> #include <linux/cpu.h> +#include <linux/pm_runtime.h> #include "pci.h" /* @@ -910,6 +912,101 @@ static int pci_pm_restore(struct device *dev)#endif /* !CONFIG_HIBERNATION */ +#ifdef CONFIG_PM_RUNTIME + +static int pci_pm_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error; + +device_set_wakeup_enable (dev,1 ); + error =pci_enable_runtime_wake (pci_dev, true); +
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+if (error) +return -EBUSY ; + +if (pm && pm->runtime_suspend) + error = pm->runtime_suspend (dev); + +if (error) + goto out; + + error =pci_pm_suspend (dev);
This has a chance to be confusing IMO. pci_pm_suspend() calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 940
Quoted 5 lines
drivers/pci/pci-driver.c +5
-0+ +if (error) + goto resume; + +disable_irq (pci_dev->irq);
I don't really think it's necessary to disable the interrupt here. We prevent drivers from receiving interrupts while pci_pm_suspend_noirq() is being run during system-wide power transitions to protect them from receiving "alien" interrupts they might be unable to handle, but in the runtime case I think the driver should take care of protecting itself from that.
The generic part of pci_pm_suspend_noirq() doesn't do things that require interrupts to be disabled. The driver's ->suspend_noirq() may do such things in principle, but then I'd prefer it not to be called directly from here.
IMO pci_pm_runtime_suspend() should work like a combination of pci_pm_suspend() and pci_pm_suspend_noirq(), except that instead of executing two driver callbacks it will only call one ->runtime_suspend() callback without disabling the device interrupt.
If the driver has to disable its interrupt in ->runtime_suspend(), it should do that by itself.
Of course, analogous comment apply to pci_pm_runtime_resume() below.
Quoted 50 lines
drivers/pci/pci-driver.c +50
-0+ error =pci_pm_suspend_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) + goto resume_noirq; + +return 0 ; + +resume_noirq: +disable_irq (pci_dev->irq); +pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); +resume: +pci_pm_resume (dev); +out: +pci_enable_runtime_wake (pci_dev, false); +return error; +} + +static int pci_pm_runtime_resume (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error =0 ; + +disable_irq (pci_dev->irq); + error =pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) +return error; + + error =pci_pm_resume (dev); + +if (error) +return error; + +if (pm->runtime_resume) + error = pm->runtime_resume (dev); + +if (error) +return error; + + error =pci_enable_runtime_wake (pci_dev, false); + +if (error) +return error; + +return 0 ; +}
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 1000
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+ +static void pci_pm_runtime_idle (struct device *dev) +{ +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; + +if (pm && pm->runtime_idle) + pm->runtime_idle (dev); + +pm_schedule_suspend (dev,0 ); +}
That has already been discussed.
Quoted 65 lines
drivers/pci/pci-driver.c +12
-0+ +#else /* !CONFIG_PM_RUNTIME */ + +#define pci_pm_runtime_suspend NULL +#define pci_pm_runtime_resume NULL +#define pci_pm_runtime_idle NULL + +#endif +struct dev_pm_ops pci_dev_pm_ops = { .prepare = pci_pm_prepare, .complete = pci_pm_complete,@@ -925,6 +1022,9 @@ struct dev_pm_ops pci_dev_pm_ops = { .thaw_noirq = pci_pm_thaw_noirq, .poweroff_noirq = pci_pm_poweroff_noirq, .restore_noirq = pci_pm_restore_noirq, + .runtime_suspend = pci_pm_runtime_suspend, + .runtime_resume = pci_pm_runtime_resume, + .runtime_idle = pci_pm_runtime_idle, };#define PCI_PM_OPS_PTR (&pci_dev_pm_ops)drivers/pci/pci.c +21
-0@@ -18,6 +18,7 @@#include <linux/log2.h> #include <linux/pci-aspm.h> #include <linux/pm_wakeup.h> +#include <linux/pm_runtime.h> #include <linux/interrupt.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include <linux/device.h> @@ -428,6 +429,12 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) pci_platform_pm->sleep_wake(dev, enable) : -ENODEV; } +static inline int platform_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +return pci_platform_pm ? + pci_platform_pm->runtime_wake (dev, enable) : -ENODEV ; +} +/** * pci_raw_set_power_state - Use PCI PM registers to set the power state of * given PCI device @@ -1239,6 +1246,38 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) }/** +* pci_enable_runtime_wake - enable PCI device as runtime wakeup event source +* @dev: PCI device affected +* @enable: True to enable event generation; false to disable +* +* This enables the device as a runtime wakeup event source, or disables it. +* This typically requires platform support. +* +* RETURN VALUE: +* 0 is returned on success +* -EINVAL is returned if device is not supposed to wake up the system +* -ENODEV is returned if platform cannot support runtime PM on the device +*/ +int pci_enable_runtime_wake (struct pci_dev *dev,bool enable) +{
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1272
Quoted 10 lines
drivers/pci/pci.c +10
-0+int error =0 ; +bool pme_done = false; + +if (!enable &&platform_pci_can_wakeup (dev)) + error =platform_pci_runtime_wake (dev, false); + +if (!enable ||pci_pme_capable (dev, PCI_D3hot)) { +pci_pme_active (dev, enable); + pme_done = true; + }
I don't really follow your intention here. The condition means that PME is going to be enabled unless 'enable' is set and the device is not capable of generating PMEs. However, if 'enable' is unset, we're still going to try to enable the PME, even if the device can't generate it. Shouldn't that be
if (enable && pci_pme_capable(dev, PCI_D3hot)) ?
Also, that assumes the device is going to be put into D3_hot, but do we know that for sure?
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1278
Quoted 6 lines
drivers/pci/pci.c +6
-0+ +if (enable &&platform_pci_can_wakeup (dev)) + error =platform_pci_runtime_wake (dev, true); + +return pme_done ?0 : error; +}
I have no comments to the part below.
Quoted 88 lines
drivers/pci/pci.c +49
-0+/** * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold * @dev: PCI device to prepare * @enable: True to enable wake-up event generation; false to disable @@ -1346,6 +1385,54 @@ int pci_back_from_sleep(struct pci_dev *dev) }/** +* pci_dev_pme_event - check if a device has a pending pme +* +* @dev: Device to handle. +*/ + +int pci_dev_pme_event (struct pci_dev *dev) +{ +u16 pmcsr; + +if (!dev->pm_cap) +return -ENODEV ; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); + +if (pmcsr &PCI_PM_CTRL_PME_STATUS ) { +pci_write_config_word (dev, dev->pm_cap +PCI_PM_CTRL , pmcsr); +pm_runtime_get (&dev->dev); +return 0 ; + } + +return -ENODEV ; +} + +/** +* pci_bus_pme_event - search for subordinate devices with a pending +* pme and handle them +* +* @dev: Parent device to handle +*/ +int pci_bus_pme_event (struct pci_dev *dev) +{ +struct pci_bus *bus; +struct pci_dev *pdev; + +if (pci_is_root_bus (dev->bus)) + bus = dev->bus; +else if (dev->subordinate) + bus = dev->subordinate; +else +return -ENODEV ; + +list_for_each_entry (pdev, &bus->devices, bus_list) +pci_dev_pme_event (pdev); + +return 0 ; +} + +/** * pci_pm_init - Initialize PM functions of given PCI device * @dev: PCI device to handle. */ drivers/pci/pci.h +3
-0@@ -34,6 +34,8 @@ extern int pci_mmap_fits(struct pci_dev *pdev, int resno,* * @sleep_wake: enables/disables the system wake up capability of given device * +* @runtime_wake: enables/disables the runtime wakeup capability of given device +* * If given platform is generally capable of power managing PCI devices, all of * these callbacks are mandatory. */ @@ -43,6 +45,7 @@ struct pci_platform_pm_ops {pci_power_t (*choose_state)(struct pci_dev *dev);bool (*can_wakeup)(struct pci_dev *dev);int (*sleep_wake)(struct pci_dev *dev,bool enable); +int (*runtime_wake)(struct pci_dev *dev,bool enable); };extern int pci_set_platform_pm (struct pci_platform_pm_ops *ops);include/linux/pci.h +0
-0@@ -734,10 +734,13 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);bool pci_pme_capable (struct pci_dev *dev,pci_power_t state);void pci_pme_active (struct pci_dev *dev,bool enable);int pci_enable_wake (struct pci_dev *dev,pci_power_t state,bool enable);
include/linux/pci.h pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); · line 746
Quoted 10 lines
include/linux/pci.h +3
-0+int pci_enable_runtime_wake (struct pci_dev *dev,bool enable);int pci_wake_from_d3 (struct pci_dev *dev,bool enable);pci_power_t pci_target_state (struct pci_dev *dev);int pci_prepare_to_sleep (struct pci_dev *dev);int pci_back_from_sleep (struct pci_dev *dev); +int pci_dev_pme_event (struct pci_dev *dev); +int pci_bus_pme_event (struct pci_dev *dev);/* Functions for PCI Hotplug drivers to use */ int pci_bus_find_capability (struct pci_bus *bus,unsigned int devfn,int cap);
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
Quoted 2 lines · Rafael J. Wysocki
Do you have any prototypes for that? I started working on it some time ago, but then I focused on the core runtime PM framework.
The native PCIe PME code? There's some in the final patchset at
http://bugzilla.kernel.org/show_bug.cgi?id=6892 but I haven't had time to look into merging that into the current kernel. I also don't have anything to test against, which makes life more awkward.
Quoted 9 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 129
Quoted 6 lines
drivers/pci/pci-acpi.c +6
-0+static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; +Hm, I'd move that into ACPI as
Quoted 3 lines
int
acp_runtime_wake_enable(acpi_handle handle, bool enable)in which form it could also be useful to non-PCI devices.
Hm. Yeah, that's not too bad an idea.
Quoted 10 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 151
Quoted 5 lines
drivers/pci/pci-acpi.c +5
-0+acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +}Ah, that's the part I've always been missing!
How exactly do we figure out which GPE is a wake-up one for given device? IOW, how are the wakeup.gpe_device and wakeup.gpe_number fields populated?
There's a field in the ACPI device definition in the DSDT that defines the needed GPE and which runlevels it can resume from.
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 1 line
drivers/pci/pci-driver.c +1
-0+ error =pci_pm_suspend (dev);This has a chance to be confusing IMO.
pci_pm_suspend()calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().
Yes, that was how I'd planned it. An alternative would be for runtime_suspend to return a negative value if there's an error, 0 if the bus code should continue or a positive value if the runtime_suspend() call handles all of it and the bus code should just return immediately?
Quoted 7 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ disable_irq(pci_dev->irq);I don't really think it's necessary to disable the interrupt here. We prevent drivers from receiving interrupts while
pci_pm_suspend_noirq()is being run during system-wide power transitions to protect them from receiving "alien" interrupts they might be unable to handle, but in the runtime case I think the driver should take care of protecting itself from that.
That sounds fine. I didn't want to take a risk in that respect, but if we should be safe here I can just drop that.
Quoted 10 lines
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1272
Quoted 4 lines
drivers/pci/pci.c +4
-0+if (!enable ||pci_pme_capable (dev, PCI_D3hot)) { +pci_pme_active (dev, enable); + pme_done = true; + }I don't really follow your intention here. The condition means that PME is going to be enabled unless 'enable' is set and the device is not capable of generating PMEs. However, if 'enable' is unset, we're still going to try to enable the PME, even if the device can't generate it. Shouldn't that be
Hmm. That was copied from pci_enable_wake() just above, but it does seem a little bit odd. I suspect that that needs some clarification as well.
Quoted 2 lines
Also, that assumes the device is going to be put into
D3_hot, but do we know that for sure?
I'd be surprised if there's any hardware that supports wakeups from D2 but not D3hot, so I just kept the code simple for now.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 2 lines · Rafael J. Wysocki
Do you have any prototypes for that? I started working on it some time ago, but then I focused on the core runtime PM framework.
The native PCIe PME code? There's some in the final patchset at
http://bugzilla.kernel.org/show_bug.cgi?id=6892 but I haven't had time to look into merging that into the current kernel. I also don't have anything to test against, which makes life more awkward.
Quoted 9 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 129
Quoted 6 lines
drivers/pci/pci-acpi.c +6
-0+static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; +Hm, I'd move that into ACPI as
Quoted 3 lines
int
acp_runtime_wake_enable(acpi_handle handle, bool enable)in which form it could also be useful to non-PCI devices.
Hm. Yeah, that's not too bad an idea.
Quoted 10 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 151
Quoted 5 lines
drivers/pci/pci-acpi.c +5
-0+acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +}Ah, that's the part I've always been missing!
How exactly do we figure out which GPE is a wake-up one for given device? IOW, how are the wakeup.gpe_device and wakeup.gpe_number fields populated?
There's a field in the ACPI device definition in the DSDT that defines the needed GPE and which runlevels it can resume from.
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 1 line
drivers/pci/pci-driver.c +1
-0+ error =pci_pm_suspend (dev);This has a chance to be confusing IMO.
pci_pm_suspend()calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().
Yes, that was how I'd planned it. An alternative would be for runtime_suspend to return a negative value if there's an error, 0 if the bus code should continue or a positive value if the runtime_suspend() call handles all of it and the bus code should just return immediately?
Quoted 7 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ disable_irq(pci_dev->irq);I don't really think it's necessary to disable the interrupt here. We prevent drivers from receiving interrupts while
pci_pm_suspend_noirq()is being run during system-wide power transitions to protect them from receiving "alien" interrupts they might be unable to handle, but in the runtime case I think the driver should take care of protecting itself from that.
That sounds fine. I didn't want to take a risk in that respect, but if we should be safe here I can just drop that.
Quoted 10 lines
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1272
Quoted 4 lines
drivers/pci/pci.c +4
-0+if (!enable ||pci_pme_capable (dev, PCI_D3hot)) { +pci_pme_active (dev, enable); + pme_done = true; + }I don't really follow your intention here. The condition means that PME is going to be enabled unless 'enable' is set and the device is not capable of generating PMEs. However, if 'enable' is unset, we're still going to try to enable the PME, even if the device can't generate it. Shouldn't that be
Hmm. That was copied from pci_enable_wake() just above, but it does seem a little bit odd. I suspect that that needs some clarification as well.
Quoted 2 lines
Also, that assumes the device is going to be put into
D3_hot, but do we know that for sure?
I'd be surprised if there's any hardware that supports wakeups from D2 but not D3hot, so I just kept the code simple for now.
Signature · 1 line
Matthew Garrett | [email protected]
Re: [RFC] PCI: Runtime power management
Quoted 6 lines · Matthew Garrett
Quoted 2 lines · Rafael J. Wysocki
Do you have any prototypes for that? I started working on it some time ago, but then I focused on the core runtime PM framework.
The native PCIe PME code?
Yes.
Quoted 2 lines
There's some in the final patchset at
http://bugzilla.kernel.org/show_bug.cgi?id=6892
Well, I don't like that very much.
Quoted 2 lines
but I haven't had time to look into merging that into the current kernel. I also don't have anything to test against, which makes life more awkward.
One of my AMD-based boxes should be suitable for that.
Quoted 37 lines
Quoted 9 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 129
Quoted 6 lines
drivers/pci/pci-acpi.c +6
-0+static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; +Hm, I'd move that into ACPI as
Quoted 3 lines
int
acp_runtime_wake_enable(acpi_handle handle, bool enable)in which form it could also be useful to non-PCI devices.
Hm. Yeah, that's not too bad an idea.
Quoted 10 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 151
Quoted 5 lines
drivers/pci/pci-acpi.c +5
-0+acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +}Ah, that's the part I've always been missing!
How exactly do we figure out which GPE is a wake-up one for given device? IOW, how are the wakeup.gpe_device and wakeup.gpe_number fields populated?
There's a field in the ACPI device definition in the DSDT that defines the needed GPE and which runlevels it can resume from.
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 1 line
drivers/pci/pci-driver.c +1
-0+ error =pci_pm_suspend (dev);This has a chance to be confusing IMO.
pci_pm_suspend()calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().
Quoted 4 lines
Yes, that was how I'd planned it. An alternative would be for
runtime_suspendto return a negative value if there's an error, 0 if the bus code should continue or a positive value if theruntime_suspend()call handles all of it and the bus code should just return immediately?
I just don't think that the existing suspend-resume callbacks are suitable for runtime PM.
For example, in the majority of cases the existing suspend callbacks put devices into D3_hot (or into the deepest low power state allowed by the platform and hardware), but that means 10 ms latency, also for the resume part. Do we want that for runtime PM for all drivers?
Perhaps a more suitable model would be to put devices into D1 first, if available, and then put them into D2 and D3 after specific delays? Currently the core framework doesn't provide any tools for that, but it may be worth extending it for this purpose.
Also, I think it should be impossible to use the "legacy" callbacks for runtime PM. They surely are not designed with that in mind.
Quoted 10 lines
Quoted 7 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ disable_irq(pci_dev->irq);I don't really think it's necessary to disable the interrupt here. We prevent drivers from receiving interrupts while
pci_pm_suspend_noirq()is being run during system-wide power transitions to protect them from receiving "alien" interrupts they might be unable to handle, but in the runtime case I think the driver should take care of protecting itself from that.That sounds fine. I didn't want to take a risk in that respect, but if we should be safe here I can just drop that.
As far as the PCI PM core is concerned, we should.
Quoted 11 lines
Quoted 10 lines
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1272
Quoted 4 lines
drivers/pci/pci.c +4
-0+if (!enable ||pci_pme_capable (dev, PCI_D3hot)) { +pci_pme_active (dev, enable); + pme_done = true; + }I don't really follow your intention here. The condition means that PME is going to be enabled unless 'enable' is set and the device is not capable of generating PMEs. However, if 'enable' is unset, we're still going to try to enable the PME, even if the device can't generate it. Shouldn't that be
Quoted 2 lines
Hmm. That was copied from
pci_enable_wake()just above, but it does seem a little bit odd. I suspect that that needs some clarification as well.
Ah, OK. If 'enabled' is unset, we want to disable the PME for all states, so we call pci_pm_active(dev, false) unconditionally in that case. If 'enable' is set, we only want to enable the PME if it's supported in given state. Sorry for the noise.
Quoted 5 lines
Quoted 2 lines
Also, that assumes the device is going to be put into
D3_hot, but do we know that for sure?I'd be surprised if there's any hardware that supports wakeups from D2 but not D3hot, so I just kept the code simple for now.
OK
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line · Matthew Garrett
On Fri, Aug 14, 2009 at 11:22:27PM +0200, Rafael J. Wysocki wrote:
...
Quoted 21 lines
Quoted 8 lines
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 1 line
drivers/pci/pci-driver.c +1
-0+ error =pci_pm_suspend (dev);This has a chance to be confusing IMO.
pci_pm_suspend()calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().Quoted 4 lines
Yes, that was how I'd planned it. An alternative would be for
runtime_suspendto return a negative value if there's an error, 0 if the bus code should continue or a positive value if theruntime_suspend()call handles all of it and the bus code should just return immediately?I just don't think that the existing suspend-resume callbacks are suitable for runtime PM.
For example, in the majority of cases the existing suspend callbacks put devices into
D3_hot(or into the deepest low power state allowed by the platform and hardware), but that means 10 ms latency, also for the resume part. Do we want that for runtime PM for all drivers?
Quoted 7 lines
Perhaps a more suitable model would be to put devices into D1 first, if available, and then put them into D2 and D3 after specific delays? Currently the core framework doesn't provide any tools for that, but it may be worth extending it for this purpose.
Also, I think it should be impossible to use the "legacy" callbacks for runtime PM. They surely are not designed with that in mind.
To be more specific, let's go through pci_pm_suspend() and pci_pm_suspend_noirq() and see what parts of these are useful for runtime PM.
pci_legacy_suspend() shouldn't be used at run time IMO, as I said above.
For runtime PM we shouldn't even continue if pm is NULL. There's nothing like "default runtime PM", either the driver supports it, or not. We also should require the callback to be implemented and IMO that should be ->runtime_suspend().
Of course we need to invoke the callback and call pci_fixup_device() after that.
pci_legacy_suspend_late() shouldn't be used at run time.
Since I think we should require pm to be not NULL for runtime PM, the second block in pci_pm_suspend_noirq() is redundant in that case.
Now, I don't think we need the _noirq callback for runtime PM, because we've just executed the "regular" callback and I bet there are no devices requiring additional driver-specific operations after pci_fixup_device(). So ->runtime_suspend() should be sufficient.
The remaining part of pci_pm_suspend_noirq() is useful, so it can be executed by pci_pm_runtime_suspend() directly.
Thus we get
static int pci_pm_runtime_suspend(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error;
if (!pm || !pm->runtime_suspend)
return -ENOSYS;
pci_dev->state_saved = false;
error = pm->runtime_suspend(dev);
suspend_report_result(pm->runtime_suspend, error);
if (error)
return error;
pci_fixup_device(pci_fixup_suspend, pci_dev);
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
&& pci_dev->current_state != PCI_UNKNOWN) {
WARN_ONCE(pci_dev->current_state != prev,
"PCI PM: State of device not saved by %pF\n",
pm->runtime_suspend);
return 0;
}
if (!pci_dev->state_saved) {
pci_save_state(pci_dev);
if (!pci_is_bridge(pci_dev))
pci_prepare_to_sleep(pci_dev);
}
pci_pm_set_unknown_state(pci_dev);
return 0;
}Now, if the driver has a universal suspend routine, like for example r8169, it only needs to point .runtime_suspend to that one and it should work.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Rafael J. WysockiQuoted 2 lines · Rafael J. Wysocki
Quoted 1 line · Matthew Garrett
On Fri, Aug 14, 2009 at 11:22:27PM +0200, Rafael J. Wysocki wrote:
...
Quoted 21 lines
Quoted 8 lines
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 1 line
drivers/pci/pci-driver.c +1
-0+ error =pci_pm_suspend (dev);This has a chance to be confusing IMO.
pci_pm_suspend()calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().Quoted 4 lines
Yes, that was how I'd planned it. An alternative would be for
runtime_suspendto return a negative value if there's an error, 0 if the bus code should continue or a positive value if theruntime_suspend()call handles all of it and the bus code should just return immediately?I just don't think that the existing suspend-resume callbacks are suitable for runtime PM.
For example, in the majority of cases the existing suspend callbacks put devices into
D3_hot(or into the deepest low power state allowed by the platform and hardware), but that means 10 ms latency, also for the resume part. Do we want that for runtime PM for all drivers?
Quoted 7 lines
Perhaps a more suitable model would be to put devices into D1 first, if available, and then put them into D2 and D3 after specific delays? Currently the core framework doesn't provide any tools for that, but it may be worth extending it for this purpose.
Also, I think it should be impossible to use the "legacy" callbacks for runtime PM. They surely are not designed with that in mind.
To be more specific, let's go through pci_pm_suspend() and pci_pm_suspend_noirq() and see what parts of these are useful for runtime PM.
pci_legacy_suspend() shouldn't be used at run time IMO, as I said above.
For runtime PM we shouldn't even continue if pm is NULL. There's nothing like "default runtime PM", either the driver supports it, or not. We also should require the callback to be implemented and IMO that should be ->runtime_suspend().
Of course we need to invoke the callback and call pci_fixup_device() after that.
pci_legacy_suspend_late() shouldn't be used at run time.
Since I think we should require pm to be not NULL for runtime PM, the second block in pci_pm_suspend_noirq() is redundant in that case.
Now, I don't think we need the _noirq callback for runtime PM, because we've just executed the "regular" callback and I bet there are no devices requiring additional driver-specific operations after pci_fixup_device(). So ->runtime_suspend() should be sufficient.
The remaining part of pci_pm_suspend_noirq() is useful, so it can be executed by pci_pm_runtime_suspend() directly.
Thus we get
static int pci_pm_runtime_suspend(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error;
if (!pm || !pm->runtime_suspend)
return -ENOSYS;
pci_dev->state_saved = false;
error = pm->runtime_suspend(dev);
suspend_report_result(pm->runtime_suspend, error);
if (error)
return error;
pci_fixup_device(pci_fixup_suspend, pci_dev);
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
&& pci_dev->current_state != PCI_UNKNOWN) {
WARN_ONCE(pci_dev->current_state != prev,
"PCI PM: State of device not saved by %pF\n",
pm->runtime_suspend);
return 0;
}
if (!pci_dev->state_saved) {
pci_save_state(pci_dev);
if (!pci_is_bridge(pci_dev))
pci_prepare_to_sleep(pci_dev);
}
pci_pm_set_unknown_state(pci_dev);
return 0;
}Now, if the driver has a universal suspend routine, like for example r8169, it only needs to point .runtime_suspend to that one and it should work.
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Matthew GarrettQuoted 6 lines · Matthew Garrett
Quoted 2 lines · Rafael J. Wysocki
Do you have any prototypes for that? I started working on it some time ago, but then I focused on the core runtime PM framework.
The native PCIe PME code?
Yes.
Quoted 2 lines
There's some in the final patchset at
http://bugzilla.kernel.org/show_bug.cgi?id=6892
Well, I don't like that very much.
Quoted 2 lines
but I haven't had time to look into merging that into the current kernel. I also don't have anything to test against, which makes life more awkward.
One of my AMD-based boxes should be suitable for that.
Quoted 37 lines
Quoted 9 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 129
Quoted 6 lines
drivers/pci/pci-acpi.c +6
-0+static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; +Hm, I'd move that into ACPI as
Quoted 3 lines
int
acp_runtime_wake_enable(acpi_handle handle, bool enable)in which form it could also be useful to non-PCI devices.
Hm. Yeah, that's not too bad an idea.
Quoted 10 lines
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 151
Quoted 5 lines
drivers/pci/pci-acpi.c +5
-0+acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +}Ah, that's the part I've always been missing!
How exactly do we figure out which GPE is a wake-up one for given device? IOW, how are the wakeup.gpe_device and wakeup.gpe_number fields populated?
There's a field in the ACPI device definition in the DSDT that defines the needed GPE and which runlevels it can resume from.
Quoted 7 lines
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 1 line
drivers/pci/pci-driver.c +1
-0+ error =pci_pm_suspend (dev);This has a chance to be confusing IMO.
pci_pm_suspend()calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().
Quoted 4 lines
Yes, that was how I'd planned it. An alternative would be for
runtime_suspendto return a negative value if there's an error, 0 if the bus code should continue or a positive value if theruntime_suspend()call handles all of it and the bus code should just return immediately?
I just don't think that the existing suspend-resume callbacks are suitable for runtime PM.
For example, in the majority of cases the existing suspend callbacks put devices into D3_hot (or into the deepest low power state allowed by the platform and hardware), but that means 10 ms latency, also for the resume part. Do we want that for runtime PM for all drivers?
Perhaps a more suitable model would be to put devices into D1 first, if available, and then put them into D2 and D3 after specific delays? Currently the core framework doesn't provide any tools for that, but it may be worth extending it for this purpose.
Also, I think it should be impossible to use the "legacy" callbacks for runtime PM. They surely are not designed with that in mind.
Quoted 10 lines
Quoted 7 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ disable_irq(pci_dev->irq);I don't really think it's necessary to disable the interrupt here. We prevent drivers from receiving interrupts while
pci_pm_suspend_noirq()is being run during system-wide power transitions to protect them from receiving "alien" interrupts they might be unable to handle, but in the runtime case I think the driver should take care of protecting itself from that.That sounds fine. I didn't want to take a risk in that respect, but if we should be safe here I can just drop that.
As far as the PCI PM core is concerned, we should.
Quoted 11 lines
Quoted 10 lines
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1272
Quoted 4 lines
drivers/pci/pci.c +4
-0+if (!enable ||pci_pme_capable (dev, PCI_D3hot)) { +pci_pme_active (dev, enable); + pme_done = true; + }I don't really follow your intention here. The condition means that PME is going to be enabled unless 'enable' is set and the device is not capable of generating PMEs. However, if 'enable' is unset, we're still going to try to enable the PME, even if the device can't generate it. Shouldn't that be
Quoted 2 lines
Hmm. That was copied from
pci_enable_wake()just above, but it does seem a little bit odd. I suspect that that needs some clarification as well.
Ah, OK. If 'enabled' is unset, we want to disable the PME for all states, so we call pci_pm_active(dev, false) unconditionally in that case. If 'enable' is set, we only want to enable the PME if it's supported in given state. Sorry for the noise.
Quoted 5 lines
Quoted 2 lines
Also, that assumes the device is going to be put into
D3_hot, but do we know that for sure?I'd be surprised if there's any hardware that supports wakeups from D2 but not D3hot, so I just kept the code simple for now.
OK
Thanks,
Rafael
Re: [RFC] PCI: Runtime power management
In reply to Matthew GarrettHi,
First of all, thanks a lot for looking into this!
Quoted 8 lines · Matthew Garrett
I got a fixed BIOS from Dell and have been able to get this working now. It seems entirely happy with USB, but I'd like some sanity checks on whether I'm doing this correctly. There's certainly a couple of quirks related to setting the ACPI GPE type that would need a little bit of work in the ACPI layer, and it breaks ACPI-mediated PCI hotplug though that's easy enough to fix by just calling into the hotplug code from the core notifier.
Quoted 6 lines
This patch builds on top of Rafael's work on systemwide runtime power management. It supports suspending and resuming PCI devices at runtime, enabling platform wakeup events that allow the devices to automatically resume when appropriate. It currently requires platform support, but PCIe setups could be supported natively once native PCIe PME code has been added to the kernel.
Do you have any prototypes for that? I started working on it some time ago, but then I focused on the core runtime PM framework.
Quoted 21 lines
--- drivers/pci/pci-acpi.c | 55 +++++++++++++++++++++++++ drivers/pci/pci-driver.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.c | 87 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 3 + include/linux/pci.h | 3 + 5 files changed, 248 insertions(+), 0 deletions(-)drivers/pci/pci-acpi.c +1
-0@@ -12,6 +12,7 @@#include <linux/pci.h> #include <linux/module.h> #include <linux/pci-aspm.h> +#include <linux/pm_runtime.h> #include <acpi/acpi.h> #include <acpi/acpi_bus.h>
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 129
Quoted 9 lines
drivers/pci/pci-acpi.c +6
-0@@ -120,14 +121,62 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)return error; } +static int acpi_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +acpi_status status; +acpi_handle handle =DEVICE_ACPI_HANDLE (&dev->dev); +struct acpi_device *acpi_dev; +
Hm, I'd move that into ACPI as
int acp_runtime_wake_enable(acpi_handle handle, bool enable)
in which form it could also be useful to non-PCI devices.
Quoted 12 lines
drivers/pci/pci-acpi.c +12
-0+if (!handle) +return -ENODEV ; + + status =acpi_bus_get_device (handle, &acpi_dev); +if (ACPI_FAILURE (status)) +return -ENODEV ; + +if (enable) { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE_RUN ); + acpi_enable_gpe(acpi_dev->wakeup.gpe_device,
drivers/pci/pci-acpi.c static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) · line 151
Quoted 10 lines
drivers/pci/pci-acpi.c +10
-0+ acpi_dev->wakeup.gpe_number); + }else { +acpi_set_gpe_type (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number, +ACPI_GPE_TYPE_WAKE ); +acpi_disable_gpe (acpi_dev->wakeup.gpe_device, + acpi_dev->wakeup.gpe_number); + } +return 0 ; +}
Ah, that's the part I've always been missing!
How exactly do we figure out which GPE is a wake-up one for given device? IOW, how are the wakeup.gpe_device and wakeup.gpe_number fields populated?
Quoted 85 lines
drivers/pci/pci-acpi.c +26
-0+ +static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, .can_wakeup = acpi_pci_can_wakeup, .sleep_wake = acpi_pci_sleep_wake, + .runtime_wake = acpi_pci_runtime_wake, }; +static void pci_device_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pm_runtime_resume (dev); +} + +static void pci_root_bridge_notify (acpi_handle handle,u32 event,void *data) +{ +struct device *dev = data; +struct pci_dev *pci_dev =to_pci_dev (dev); + +if (event ==ACPI_NOTIFY_DEVICE_WAKE ) +pci_bus_pme_event (pci_dev); +} +/* ACPI bus type */ static int acpi_pci_find_device (struct device *dev,acpi_handle *handle) {@@ -140,6 +189,9 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) *handle =acpi_get_child (DEVICE_ACPI_HANDLE (dev->parent), addr);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_device_notify, dev);return 0 ; }@@ -158,6 +210,9 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) *handle =acpi_get_pci_rootbridge_handle (seg, bus);if (!*handle)return -ENODEV ; + +acpi_install_notify_handler (*handle,ACPI_SYSTEM_NOTIFY , + pci_root_bridge_notify, dev);return 0 ; }drivers/pci/pci-driver.c +13
-0@@ -11,12 +11,14 @@#include <linux/pci.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/device.h> #include <linux/mempolicy.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/sched.h> #include <linux/cpu.h> +#include <linux/pm_runtime.h> #include "pci.h" /* @@ -910,6 +912,101 @@ static int pci_pm_restore(struct device *dev)#endif /* !CONFIG_HIBERNATION */ +#ifdef CONFIG_PM_RUNTIME + +static int pci_pm_runtime_suspend (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error; + +device_set_wakeup_enable (dev,1 ); + error =pci_enable_runtime_wake (pci_dev, true); +
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 935
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+if (error) +return -EBUSY ; + +if (pm && pm->runtime_suspend) + error = pm->runtime_suspend (dev); + +if (error) + goto out; + + error =pci_pm_suspend (dev);
This has a chance to be confusing IMO. pci_pm_suspend() calls the driver's ->suspend() routine, which is specific to suspend to RAM. So, this means that drivers are supposed to implement ->runtime_suspend() only if they want to do something _in_ _addition_ to the things done by ->suspend() and ->suspend_noirq().
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 940
Quoted 5 lines
drivers/pci/pci-driver.c +5
-0+ +if (error) + goto resume; + +disable_irq (pci_dev->irq);
I don't really think it's necessary to disable the interrupt here. We prevent drivers from receiving interrupts while pci_pm_suspend_noirq() is being run during system-wide power transitions to protect them from receiving "alien" interrupts they might be unable to handle, but in the runtime case I think the driver should take care of protecting itself from that.
The generic part of pci_pm_suspend_noirq() doesn't do things that require interrupts to be disabled. The driver's ->suspend_noirq() may do such things in principle, but then I'd prefer it not to be called directly from here.
IMO pci_pm_runtime_suspend() should work like a combination of pci_pm_suspend() and pci_pm_suspend_noirq(), except that instead of executing two driver callbacks it will only call one ->runtime_suspend() callback without disabling the device interrupt.
If the driver has to disable its interrupt in ->runtime_suspend(), it should do that by itself.
Of course, analogous comment apply to pci_pm_runtime_resume() below.
Quoted 50 lines
drivers/pci/pci-driver.c +50
-0+ error =pci_pm_suspend_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) + goto resume_noirq; + +return 0 ; + +resume_noirq: +disable_irq (pci_dev->irq); +pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); +resume: +pci_pm_resume (dev); +out: +pci_enable_runtime_wake (pci_dev, false); +return error; +} + +static int pci_pm_runtime_resume (struct device *dev) +{ +struct pci_dev *pci_dev =to_pci_dev (dev); +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; +int error =0 ; + +disable_irq (pci_dev->irq); + error =pci_pm_resume_noirq (dev); +enable_irq (pci_dev->irq); + +if (error) +return error; + + error =pci_pm_resume (dev); + +if (error) +return error; + +if (pm->runtime_resume) + error = pm->runtime_resume (dev); + +if (error) +return error; + + error =pci_enable_runtime_wake (pci_dev, false); + +if (error) +return error; + +return 0 ; +}
drivers/pci/pci-driver.c static int pci_pm_restore(struct device *dev) · line 1000
Quoted 10 lines
drivers/pci/pci-driver.c +10
-0+ +static void pci_pm_runtime_idle (struct device *dev) +{ +struct dev_pm_ops *pm = dev->driver ? dev->driver->pm :NULL ; + +if (pm && pm->runtime_idle) + pm->runtime_idle (dev); + +pm_schedule_suspend (dev,0 ); +}
That has already been discussed.
Quoted 65 lines
drivers/pci/pci-driver.c +12
-0+ +#else /* !CONFIG_PM_RUNTIME */ + +#define pci_pm_runtime_suspend NULL +#define pci_pm_runtime_resume NULL +#define pci_pm_runtime_idle NULL + +#endif +struct dev_pm_ops pci_dev_pm_ops = { .prepare = pci_pm_prepare, .complete = pci_pm_complete,@@ -925,6 +1022,9 @@ struct dev_pm_ops pci_dev_pm_ops = { .thaw_noirq = pci_pm_thaw_noirq, .poweroff_noirq = pci_pm_poweroff_noirq, .restore_noirq = pci_pm_restore_noirq, + .runtime_suspend = pci_pm_runtime_suspend, + .runtime_resume = pci_pm_runtime_resume, + .runtime_idle = pci_pm_runtime_idle, };#define PCI_PM_OPS_PTR (&pci_dev_pm_ops)drivers/pci/pci.c +21
-0@@ -18,6 +18,7 @@#include <linux/log2.h> #include <linux/pci-aspm.h> #include <linux/pm_wakeup.h> +#include <linux/pm_runtime.h> #include <linux/interrupt.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include <linux/device.h> @@ -428,6 +429,12 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) pci_platform_pm->sleep_wake(dev, enable) : -ENODEV; } +static inline int platform_pci_runtime_wake (struct pci_dev *dev,bool enable) +{ +return pci_platform_pm ? + pci_platform_pm->runtime_wake (dev, enable) : -ENODEV ; +} +/** * pci_raw_set_power_state - Use PCI PM registers to set the power state of * given PCI device @@ -1239,6 +1246,38 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) }/** +* pci_enable_runtime_wake - enable PCI device as runtime wakeup event source +* @dev: PCI device affected +* @enable: True to enable event generation; false to disable +* +* This enables the device as a runtime wakeup event source, or disables it. +* This typically requires platform support. +* +* RETURN VALUE: +* 0 is returned on success +* -EINVAL is returned if device is not supposed to wake up the system +* -ENODEV is returned if platform cannot support runtime PM on the device +*/ +int pci_enable_runtime_wake (struct pci_dev *dev,bool enable) +{
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1272
Quoted 10 lines
drivers/pci/pci.c +10
-0+int error =0 ; +bool pme_done = false; + +if (!enable &&platform_pci_can_wakeup (dev)) + error =platform_pci_runtime_wake (dev, false); + +if (!enable ||pci_pme_capable (dev, PCI_D3hot)) { +pci_pme_active (dev, enable); + pme_done = true; + }
I don't really follow your intention here. The condition means that PME is going to be enabled unless 'enable' is set and the device is not capable of generating PMEs. However, if 'enable' is unset, we're still going to try to enable the PME, even if the device can't generate it. Shouldn't that be
if (enable && pci_pme_capable(dev, PCI_D3hot)) ?
Also, that assumes the device is going to be put into D3_hot, but do we know that for sure?
drivers/pci/pci.c int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) · line 1278
Quoted 6 lines
drivers/pci/pci.c +6
-0+ +if (enable &&platform_pci_can_wakeup (dev)) + error =platform_pci_runtime_wake (dev, true); + +return pme_done ?0 : error; +}
I have no comments to the part below.
Quoted 88 lines
drivers/pci/pci.c +49
-0+/** * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold * @dev: PCI device to prepare * @enable: True to enable wake-up event generation; false to disable @@ -1346,6 +1385,54 @@ int pci_back_from_sleep(struct pci_dev *dev) }/** +* pci_dev_pme_event - check if a device has a pending pme +* +* @dev: Device to handle. +*/ + +int pci_dev_pme_event (struct pci_dev *dev) +{ +u16 pmcsr; + +if (!dev->pm_cap) +return -ENODEV ; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); + +if (pmcsr &PCI_PM_CTRL_PME_STATUS ) { +pci_write_config_word (dev, dev->pm_cap +PCI_PM_CTRL , pmcsr); +pm_runtime_get (&dev->dev); +return 0 ; + } + +return -ENODEV ; +} + +/** +* pci_bus_pme_event - search for subordinate devices with a pending +* pme and handle them +* +* @dev: Parent device to handle +*/ +int pci_bus_pme_event (struct pci_dev *dev) +{ +struct pci_bus *bus; +struct pci_dev *pdev; + +if (pci_is_root_bus (dev->bus)) + bus = dev->bus; +else if (dev->subordinate) + bus = dev->subordinate; +else +return -ENODEV ; + +list_for_each_entry (pdev, &bus->devices, bus_list) +pci_dev_pme_event (pdev); + +return 0 ; +} + +/** * pci_pm_init - Initialize PM functions of given PCI device * @dev: PCI device to handle. */ drivers/pci/pci.h +3
-0@@ -34,6 +34,8 @@ extern int pci_mmap_fits(struct pci_dev *pdev, int resno,* * @sleep_wake: enables/disables the system wake up capability of given device * +* @runtime_wake: enables/disables the runtime wakeup capability of given device +* * If given platform is generally capable of power managing PCI devices, all of * these callbacks are mandatory. */ @@ -43,6 +45,7 @@ struct pci_platform_pm_ops {pci_power_t (*choose_state)(struct pci_dev *dev);bool (*can_wakeup)(struct pci_dev *dev);int (*sleep_wake)(struct pci_dev *dev,bool enable); +int (*runtime_wake)(struct pci_dev *dev,bool enable); };extern int pci_set_platform_pm (struct pci_platform_pm_ops *ops);include/linux/pci.h +0
-0@@ -734,10 +734,13 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);bool pci_pme_capable (struct pci_dev *dev,pci_power_t state);void pci_pme_active (struct pci_dev *dev,bool enable);int pci_enable_wake (struct pci_dev *dev,pci_power_t state,bool enable);
include/linux/pci.h pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); · line 746
Quoted 10 lines
include/linux/pci.h +3
-0+int pci_enable_runtime_wake (struct pci_dev *dev,bool enable);int pci_wake_from_d3 (struct pci_dev *dev,bool enable);pci_power_t pci_target_state (struct pci_dev *dev);int pci_prepare_to_sleep (struct pci_dev *dev);int pci_back_from_sleep (struct pci_dev *dev); +int pci_dev_pme_event (struct pci_dev *dev); +int pci_bus_pme_event (struct pci_dev *dev);/* Functions for PCI Hotplug drivers to use */ int pci_bus_find_capability (struct pci_bus *bus,unsigned int devfn,int cap);
Thanks,
Rafael
PATCH 1/1 PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
--- Documentation/power/runtime_pm.txt | 378 +++++++++++++ drivers/base/dd.c | 11 drivers/base/power/Makefile | 1 drivers/base/power/main.c | 22 drivers/base/power/power.h | 31 - drivers/base/power/runtime.c | 1011 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 101 +++ include/linux/pm_runtime.h | 114 ++++ kernel/power/Kconfig | 14 kernel/power/main.c | 17 10 files changed, 1689 insertions(+), 11 deletions(-)
kernel/power/Kconfig +14 -0
@@ -208,3 +208,17 @@ config APM_EMULATION random kernel OOPSes or reboots that don't seem to be related to anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). + +config PM_RUNTIME + bool "Run-time PM core functionality" + depends on PM + ---help--- + Enable functionality allowing I/O devices to be put into energy-saving + (low power) states at run time (or autosuspended) after a specified + period of inactivity and woken up in response to a hardware-generated + wake-up event or a driver's request. + + Hardware support is generally required for this functionality to work + and the bus type drivers of the buses the devices are on are + responsible for the actual handling of the autosuspend requests and + wake-up events.
kernel/power/main.c +17 -0
@@ -11,6 +11,7 @@#include <linux/kobject.h> #include <linux/string.h> #include <linux/resume-trace.h> +#include <linux/workqueue.h> #include "power.h"
@@ -217,8 +218,24 @@ static struct attribute_group attr_group .attrs = g, }; +#ifdef CONFIG_PM_RUNTIME +struct workqueue_struct *pm_wq; + +static int __init pm_start_workqueue (void ) +{ + pm_wq =create_freezeable_workqueue ("pm" ); + +return pm_wq ?0 : -ENOMEM ; +} +#else +static inline int pm_start_workqueue (void ) {return 0 ; } +#endif +static int __init pm_init (void ) { +int error =pm_start_workqueue (); +if (error) +return error; power_kobj =kobject_create_and_add ("power" ,NULL );if (!power_kobj)return -ENOMEM ;
include/linux/pm.h +98 -3
130 lines not on this page · raw message
drivers/base/power/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/power/runtime.c new file +1011 -0
1,011 lines not on this page · raw message
include/linux/pm_runtime.h new file +114 -0
114 lines not on this page · raw message
drivers/base/power/main.c +21 -1
@@ -21,6 +21,7 @@#include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/resume-trace.h> #include <linux/rwsem.h> #include <linux/interrupt.h>
@@ -49,6 +50,16 @@ static DEFINE_MUTEX(dpm_list_mtx);static bool transition_started;/** +* device_pm_init - Initialize the PM-related part of a device object +* @dev: Device object being initialized. +*/ +void device_pm_init (struct device *dev) +{ + dev->power.status =DPM_ON ; +pm_runtime_init (dev); +} + +/** * device_pm_lock - lock the list of active devices used by the PM core */ void device_pm_lock (void )
@@ -105,6 +116,7 @@ void device_pm_remove(struct device *devmutex_lock (&dpm_list_mtx);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); +pm_runtime_remove (dev); }/**
@@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t stmutex_unlock (&dpm_list_mtx);device_complete (dev, state); +pm_runtime_put_noidle (dev);mutex_lock (&dpm_list_mtx); }
@@ -757,7 +770,14 @@ static int dpm_prepare(pm_message_t stat dev->power.status =DPM_PREPARING ;mutex_unlock (&dpm_list_mtx); - error =device_prepare (dev, state); +pm_runtime_get_noresume (dev); +if (pm_runtime_barrier (dev) &&device_may_wakeup (dev)) { +/* Wake-up requested during system sleep transition. */ +pm_runtime_put_noidle (dev); + error = -EBUSY ; + }else { + error =device_prepare (dev, state); + }mutex_lock (&dpm_list_mtx);if (error) {
drivers/base/dd.c +11 -0
@@ -23,6 +23,7 @@#include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h"
@@ -202,7 +203,10 @@ int driver_probe_device(struct device_drpr_debug ("bus: '%s': %s: matched device %s with driver %s\n" , drv->bus->name, __func__,dev_name (dev), drv->name); +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); ret =really_probe (dev, drv); +pm_runtime_put_sync (dev);return ret; }
@@ -245,7 +249,9 @@ int device_attach(struct device *dev) ret =0 ; } }else { +pm_runtime_get_noresume (dev); ret =bus_for_each_drv (dev->bus,NULL , dev, __device_attach); +pm_runtime_put_sync (dev); }up (&dev->sem);return ret;
@@ -306,6 +312,9 @@ static void __device_release_driver(stru drv = dev->driver;if (drv) { +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); +driver_sysfs_remove (dev);if (dev->bus)
@@ -324,6 +333,8 @@ static void __device_release_driver(strublocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_UNBOUND_DRIVER , dev); + +pm_runtime_put_sync (dev); } }
drivers/base/power/power.h +24 -7
@@ -1,7 +1,14 @@ -static inline void device_pm_init (struct device *dev) -{ - dev->power.status =DPM_ON ; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init (struct device *dev); +extern void pm_runtime_remove (struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init (struct device *dev) {} +static inline void pm_runtime_remove (struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } +extern void device_pm_init (struct device *dev);extern void device_pm_add (struct device *);extern void device_pm_remove (struct device *);extern void device_pm_move_before (struct device *,struct device *);extern void device_pm_move_after (struct device *,struct device *);extern void device_pm_move_last (struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init (struct device *dev) +{ +pm_runtime_init (dev); +} + +static inline void device_pm_remove (struct device *dev) +{ +pm_runtime_remove (dev); +}static inline void device_pm_add (struct device *dev) {} -static inline void device_pm_remove (struct device *dev) {}static inline void device_pm_move_before (struct device *deva,struct device *devb) {}static inline void device_pm_move_after (struct device *deva,struct device *devb) {}static inline void device_pm_move_last (struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM
Documentation/power/runtime_pm.txt new file +378 -0
378 lines not on this page · raw message
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
Quoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
If there are no more outstanding issues with this, any chance of having this rolled in to a topic branch along with Magnus's platform bus support? It would be nice if these could spend some time in -next, especially as it seems there are no longer any glaring issues with the patch series.
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
In reply to Rafael J. WysockiQuoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
If there are no more outstanding issues with this, any chance of having this rolled in to a topic branch along with Magnus's platform bus support? It would be nice if these could spend some time in -next, especially as it seems there are no longer any glaring issues with the patch series.
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
Quoted 14 lines · Paul Mundt
Quoted 13 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Quoted 7 lines
Quoted 1 line
Signed-off-by Rafael J. Wysocki <[email protected]>If there are no more outstanding issues with this, any chance of having this rolled in to a topic branch along with Magnus's platform bus support? It would be nice if these could spend some time in -next, especially as it seems there are no longer any glaring issues with the patch series.
I completely agree and I hope there are no major issues with this patch any more.
If there are no objections, I'm going to put the patch into my linux-next branch shortly, from where it will go to the for-linus branch. I'm going to do that with the Magnus' patch too.
Thanks,
Rafael
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
In reply to Paul MundtQuoted 14 lines · Paul Mundt
Quoted 13 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Quoted 7 lines
Quoted 1 line
Signed-off-by Rafael J. Wysocki <[email protected]>If there are no more outstanding issues with this, any chance of having this rolled in to a topic branch along with Magnus's platform bus support? It would be nice if these could spend some time in -next, especially as it seems there are no longer any glaring issues with the patch series.
I completely agree and I hope there are no major issues with this patch any more.
If there are no objections, I'm going to put the patch into my linux-next branch shortly, from where it will go to the for-linus branch. I'm going to do that with the Magnus' patch too.
Thanks,
Rafael
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
In reply to Rafael J. WysockiQuoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
I've now tested v16 with my SuperH Mobile platform device Runtime PM implementation. All seems fine and my patches for patches for drivers such as i2c master, fbdev, v4l2 and uio behave as expected.
The patch "PM: Runtime PM v15 - Platform Device Bus Support" works well with v16 and does not need any update.
Cheers,
/ magnus
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
In reply to Rafael J. WysockiQuoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
I've now tested v16 with my SuperH Mobile platform device Runtime PM implementation. All seems fine and my patches for patches for drivers such as i2c master, fbdev, v4l2 and uio behave as expected.
The patch "PM: Runtime PM v15 - Platform Device Bus Support" works well with v16 and does not need any update.
Cheers,
/ magnus
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
Quoted 16 lines · Magnus Damm
Quoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
Quoted 8 lines
I've now tested v16 with my SuperH Mobile platform device Runtime PM implementation. All seems fine and my patches for patches for drivers such as i2c master, fbdev, v4l2 and uio behave as expected.
Acked-by Magnus Damm <[email protected]>The patch "PM: Runtime PM v15 - Platform Device Bus Support" works well with v16 and does not need any update.
Thanks for the ACK, but I have one more update to the patch. Namely, I've decided to change the return value of the ->runtime_idle() callback to int as a result of the recent discussion on the PCI runtime PM patch from Matthew.
I'll post the updated patch in a little while.
Thanks,
Rafael
Re: [PATCH update 2x] PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
In reply to Magnus DammQuoted 16 lines · Magnus Damm
Quoted 9 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct
dev_pm_info' and device run-time PM callbacks to 'structdev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.Quoted 5 lines
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
Signed-off-by Rafael J. Wysocki <[email protected]>
Quoted 8 lines
I've now tested v16 with my SuperH Mobile platform device Runtime PM implementation. All seems fine and my patches for patches for drivers such as i2c master, fbdev, v4l2 and uio behave as expected.
Acked-by Magnus Damm <[email protected]>The patch "PM: Runtime PM v15 - Platform Device Bus Support" works well with v16 and does not need any update.
Thanks for the ACK, but I have one more update to the patch. Namely, I've decided to change the return value of the ->runtime_idle() callback to int as a result of the recent discussion on the PCI runtime PM patch from Matthew.
I'll post the updated patch in a little while.
Thanks,
Rafael
PATCH 1/1 PM: Introduce core framework for run-time PM of I/O devices (rev. 17)
In reply to Rafael J. WysockiHi,
The only difference between this one and rev. 16 is that now the runtime_idle() callback is defined to return int, as suggested by Matthew in the "PCI: Runtime power management" thread.
Thanks,
Rafael
---
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 17)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
--- Documentation/power/runtime_pm.txt | 378 +++++++++++++ drivers/base/dd.c | 11 drivers/base/power/Makefile | 1 drivers/base/power/main.c | 22 drivers/base/power/power.h | 31 - drivers/base/power/runtime.c | 1011 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 101 +++ include/linux/pm_runtime.h | 114 ++++ kernel/power/Kconfig | 14 kernel/power/main.c | 17 10 files changed, 1689 insertions(+), 11 deletions(-)
kernel/power/Kconfig +14 -0
@@ -208,3 +208,17 @@ config APM_EMULATION random kernel OOPSes or reboots that don't seem to be related to anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). + +config PM_RUNTIME + bool "Run-time PM core functionality" + depends on PM + ---help--- + Enable functionality allowing I/O devices to be put into energy-saving + (low power) states at run time (or autosuspended) after a specified + period of inactivity and woken up in response to a hardware-generated + wake-up event or a driver's request. + + Hardware support is generally required for this functionality to work + and the bus type drivers of the buses the devices are on are + responsible for the actual handling of the autosuspend requests and + wake-up events.
kernel/power/main.c +17 -0
@@ -11,6 +11,7 @@#include <linux/kobject.h> #include <linux/string.h> #include <linux/resume-trace.h> +#include <linux/workqueue.h> #include "power.h"
@@ -217,8 +218,24 @@ static struct attribute_group attr_group .attrs = g, }; +#ifdef CONFIG_PM_RUNTIME +struct workqueue_struct *pm_wq; + +static int __init pm_start_workqueue (void ) +{ + pm_wq =create_freezeable_workqueue ("pm" ); + +return pm_wq ?0 : -ENOMEM ; +} +#else +static inline int pm_start_workqueue (void ) {return 0 ; } +#endif +static int __init pm_init (void ) { +int error =pm_start_workqueue (); +if (error) +return error; power_kobj =kobject_create_and_add ("power" ,NULL );if (!power_kobj)return -ENOMEM ;
include/linux/pm.h +98 -3
130 lines not on this page · raw message
drivers/base/power/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/power/runtime.c new file +1011 -0
1,011 lines not on this page · raw message
include/linux/pm_runtime.h new file +114 -0
114 lines not on this page · raw message
drivers/base/power/main.c +21 -1
@@ -21,6 +21,7 @@#include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/resume-trace.h> #include <linux/rwsem.h> #include <linux/interrupt.h>
@@ -49,6 +50,16 @@ static DEFINE_MUTEX(dpm_list_mtx);static bool transition_started;/** +* device_pm_init - Initialize the PM-related part of a device object +* @dev: Device object being initialized. +*/ +void device_pm_init (struct device *dev) +{ + dev->power.status =DPM_ON ; +pm_runtime_init (dev); +} + +/** * device_pm_lock - lock the list of active devices used by the PM core */ void device_pm_lock (void )
@@ -105,6 +116,7 @@ void device_pm_remove(struct device *devmutex_lock (&dpm_list_mtx);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); +pm_runtime_remove (dev); }/**
@@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t stmutex_unlock (&dpm_list_mtx);device_complete (dev, state); +pm_runtime_put_noidle (dev);mutex_lock (&dpm_list_mtx); }
@@ -757,7 +770,14 @@ static int dpm_prepare(pm_message_t stat dev->power.status =DPM_PREPARING ;mutex_unlock (&dpm_list_mtx); - error =device_prepare (dev, state); +pm_runtime_get_noresume (dev); +if (pm_runtime_barrier (dev) &&device_may_wakeup (dev)) { +/* Wake-up requested during system sleep transition. */ +pm_runtime_put_noidle (dev); + error = -EBUSY ; + }else { + error =device_prepare (dev, state); + }mutex_lock (&dpm_list_mtx);if (error) {
drivers/base/dd.c +11 -0
@@ -23,6 +23,7 @@#include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h"
@@ -202,7 +203,10 @@ int driver_probe_device(struct device_drpr_debug ("bus: '%s': %s: matched device %s with driver %s\n" , drv->bus->name, __func__,dev_name (dev), drv->name); +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); ret =really_probe (dev, drv); +pm_runtime_put_sync (dev);return ret; }
@@ -245,7 +249,9 @@ int device_attach(struct device *dev) ret =0 ; } }else { +pm_runtime_get_noresume (dev); ret =bus_for_each_drv (dev->bus,NULL , dev, __device_attach); +pm_runtime_put_sync (dev); }up (&dev->sem);return ret;
@@ -306,6 +312,9 @@ static void __device_release_driver(stru drv = dev->driver;if (drv) { +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); +driver_sysfs_remove (dev);if (dev->bus)
@@ -324,6 +333,8 @@ static void __device_release_driver(strublocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_UNBOUND_DRIVER , dev); + +pm_runtime_put_sync (dev); } }
drivers/base/power/power.h +24 -7
@@ -1,7 +1,14 @@ -static inline void device_pm_init (struct device *dev) -{ - dev->power.status =DPM_ON ; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init (struct device *dev); +extern void pm_runtime_remove (struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init (struct device *dev) {} +static inline void pm_runtime_remove (struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } +extern void device_pm_init (struct device *dev);extern void device_pm_add (struct device *);extern void device_pm_remove (struct device *);extern void device_pm_move_before (struct device *,struct device *);extern void device_pm_move_after (struct device *,struct device *);extern void device_pm_move_last (struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init (struct device *dev) +{ +pm_runtime_init (dev); +} + +static inline void device_pm_remove (struct device *dev) +{ +pm_runtime_remove (dev); +}static inline void device_pm_add (struct device *dev) {} -static inline void device_pm_remove (struct device *dev) {}static inline void device_pm_move_before (struct device *deva,struct device *devb) {}static inline void device_pm_move_after (struct device *deva,struct device *devb) {}static inline void device_pm_move_last (struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM
Documentation/power/runtime_pm.txt new file +378 -0
378 lines not on this page · raw message
PATCH 1/1 PM: Introduce core framework for run-time PM of I/O devices (rev. 17)
In reply to Rafael J. WysockiHi,
The only difference between this one and rev. 16 is that now the runtime_idle() callback is defined to return int, as suggested by Matthew in the "PCI: Runtime power management" thread.
Thanks,
Rafael
---
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 17)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
--- Documentation/power/runtime_pm.txt | 378 +++++++++++++ drivers/base/dd.c | 11 drivers/base/power/Makefile | 1 drivers/base/power/main.c | 22 drivers/base/power/power.h | 31 - drivers/base/power/runtime.c | 1011 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 101 +++ include/linux/pm_runtime.h | 114 ++++ kernel/power/Kconfig | 14 kernel/power/main.c | 17 10 files changed, 1689 insertions(+), 11 deletions(-)
kernel/power/Kconfig +14 -0
@@ -208,3 +208,17 @@ config APM_EMULATION random kernel OOPSes or reboots that don't seem to be related to anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). + +config PM_RUNTIME + bool "Run-time PM core functionality" + depends on PM + ---help--- + Enable functionality allowing I/O devices to be put into energy-saving + (low power) states at run time (or autosuspended) after a specified + period of inactivity and woken up in response to a hardware-generated + wake-up event or a driver's request. + + Hardware support is generally required for this functionality to work + and the bus type drivers of the buses the devices are on are + responsible for the actual handling of the autosuspend requests and + wake-up events.
kernel/power/main.c +17 -0
@@ -11,6 +11,7 @@#include <linux/kobject.h> #include <linux/string.h> #include <linux/resume-trace.h> +#include <linux/workqueue.h> #include "power.h"
@@ -217,8 +218,24 @@ static struct attribute_group attr_group .attrs = g, }; +#ifdef CONFIG_PM_RUNTIME +struct workqueue_struct *pm_wq; + +static int __init pm_start_workqueue (void ) +{ + pm_wq =create_freezeable_workqueue ("pm" ); + +return pm_wq ?0 : -ENOMEM ; +} +#else +static inline int pm_start_workqueue (void ) {return 0 ; } +#endif +static int __init pm_init (void ) { +int error =pm_start_workqueue (); +if (error) +return error; power_kobj =kobject_create_and_add ("power" ,NULL );if (!power_kobj)return -ENOMEM ;
include/linux/pm.h +98 -3
130 lines not on this page · raw message
drivers/base/power/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/power/runtime.c new file +1011 -0
1,011 lines not on this page · raw message
include/linux/pm_runtime.h new file +114 -0
114 lines not on this page · raw message
drivers/base/power/main.c +21 -1
@@ -21,6 +21,7 @@#include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/resume-trace.h> #include <linux/rwsem.h> #include <linux/interrupt.h>
@@ -49,6 +50,16 @@ static DEFINE_MUTEX(dpm_list_mtx);static bool transition_started;/** +* device_pm_init - Initialize the PM-related part of a device object +* @dev: Device object being initialized. +*/ +void device_pm_init (struct device *dev) +{ + dev->power.status =DPM_ON ; +pm_runtime_init (dev); +} + +/** * device_pm_lock - lock the list of active devices used by the PM core */ void device_pm_lock (void )
@@ -105,6 +116,7 @@ void device_pm_remove(struct device *devmutex_lock (&dpm_list_mtx);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); +pm_runtime_remove (dev); }/**
@@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t stmutex_unlock (&dpm_list_mtx);device_complete (dev, state); +pm_runtime_put_noidle (dev);mutex_lock (&dpm_list_mtx); }
@@ -757,7 +770,14 @@ static int dpm_prepare(pm_message_t stat dev->power.status =DPM_PREPARING ;mutex_unlock (&dpm_list_mtx); - error =device_prepare (dev, state); +pm_runtime_get_noresume (dev); +if (pm_runtime_barrier (dev) &&device_may_wakeup (dev)) { +/* Wake-up requested during system sleep transition. */ +pm_runtime_put_noidle (dev); + error = -EBUSY ; + }else { + error =device_prepare (dev, state); + }mutex_lock (&dpm_list_mtx);if (error) {
drivers/base/dd.c +11 -0
@@ -23,6 +23,7 @@#include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h"
@@ -202,7 +203,10 @@ int driver_probe_device(struct device_drpr_debug ("bus: '%s': %s: matched device %s with driver %s\n" , drv->bus->name, __func__,dev_name (dev), drv->name); +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); ret =really_probe (dev, drv); +pm_runtime_put_sync (dev);return ret; }
@@ -245,7 +249,9 @@ int device_attach(struct device *dev) ret =0 ; } }else { +pm_runtime_get_noresume (dev); ret =bus_for_each_drv (dev->bus,NULL , dev, __device_attach); +pm_runtime_put_sync (dev); }up (&dev->sem);return ret;
@@ -306,6 +312,9 @@ static void __device_release_driver(stru drv = dev->driver;if (drv) { +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); +driver_sysfs_remove (dev);if (dev->bus)
@@ -324,6 +333,8 @@ static void __device_release_driver(strublocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_UNBOUND_DRIVER , dev); + +pm_runtime_put_sync (dev); } }
drivers/base/power/power.h +24 -7
@@ -1,7 +1,14 @@ -static inline void device_pm_init (struct device *dev) -{ - dev->power.status =DPM_ON ; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init (struct device *dev); +extern void pm_runtime_remove (struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init (struct device *dev) {} +static inline void pm_runtime_remove (struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } +extern void device_pm_init (struct device *dev);extern void device_pm_add (struct device *);extern void device_pm_remove (struct device *);extern void device_pm_move_before (struct device *,struct device *);extern void device_pm_move_after (struct device *,struct device *);extern void device_pm_move_last (struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init (struct device *dev) +{ +pm_runtime_init (dev); +} + +static inline void device_pm_remove (struct device *dev) +{ +pm_runtime_remove (dev); +}static inline void device_pm_add (struct device *dev) {} -static inline void device_pm_remove (struct device *dev) {}static inline void device_pm_move_before (struct device *deva,struct device *devb) {}static inline void device_pm_move_after (struct device *deva,struct device *devb) {}static inline void device_pm_move_last (struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM
Documentation/power/runtime_pm.txt new file +378 -0
378 lines not on this page · raw message
PATCH 1/1 PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 16)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
--- Documentation/power/runtime_pm.txt | 378 +++++++++++++ drivers/base/dd.c | 11 drivers/base/power/Makefile | 1 drivers/base/power/main.c | 22 drivers/base/power/power.h | 31 - drivers/base/power/runtime.c | 1011 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 101 +++ include/linux/pm_runtime.h | 114 ++++ kernel/power/Kconfig | 14 kernel/power/main.c | 17 10 files changed, 1689 insertions(+), 11 deletions(-)
kernel/power/Kconfig +14 -0
@@ -208,3 +208,17 @@ config APM_EMULATION random kernel OOPSes or reboots that don't seem to be related to anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). + +config PM_RUNTIME + bool "Run-time PM core functionality" + depends on PM + ---help--- + Enable functionality allowing I/O devices to be put into energy-saving + (low power) states at run time (or autosuspended) after a specified + period of inactivity and woken up in response to a hardware-generated + wake-up event or a driver's request. + + Hardware support is generally required for this functionality to work + and the bus type drivers of the buses the devices are on are + responsible for the actual handling of the autosuspend requests and + wake-up events.
kernel/power/main.c +17 -0
@@ -11,6 +11,7 @@#include <linux/kobject.h> #include <linux/string.h> #include <linux/resume-trace.h> +#include <linux/workqueue.h> #include "power.h"
@@ -217,8 +218,24 @@ static struct attribute_group attr_group .attrs = g, }; +#ifdef CONFIG_PM_RUNTIME +struct workqueue_struct *pm_wq; + +static int __init pm_start_workqueue (void ) +{ + pm_wq =create_freezeable_workqueue ("pm" ); + +return pm_wq ?0 : -ENOMEM ; +} +#else +static inline int pm_start_workqueue (void ) {return 0 ; } +#endif +static int __init pm_init (void ) { +int error =pm_start_workqueue (); +if (error) +return error; power_kobj =kobject_create_and_add ("power" ,NULL );if (!power_kobj)return -ENOMEM ;
include/linux/pm.h +98 -3
130 lines not on this page · raw message
drivers/base/power/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/power/runtime.c new file +1011 -0
1,011 lines not on this page · raw message
include/linux/pm_runtime.h new file +114 -0
114 lines not on this page · raw message
drivers/base/power/main.c +21 -1
@@ -21,6 +21,7 @@#include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/resume-trace.h> #include <linux/rwsem.h> #include <linux/interrupt.h>
@@ -49,6 +50,16 @@ static DEFINE_MUTEX(dpm_list_mtx);static bool transition_started;/** +* device_pm_init - Initialize the PM-related part of a device object +* @dev: Device object being initialized. +*/ +void device_pm_init (struct device *dev) +{ + dev->power.status =DPM_ON ; +pm_runtime_init (dev); +} + +/** * device_pm_lock - lock the list of active devices used by the PM core */ void device_pm_lock (void )
@@ -105,6 +116,7 @@ void device_pm_remove(struct device *devmutex_lock (&dpm_list_mtx);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); +pm_runtime_remove (dev); }/**
@@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t stmutex_unlock (&dpm_list_mtx);device_complete (dev, state); +pm_runtime_put_noidle (dev);mutex_lock (&dpm_list_mtx); }
@@ -757,7 +770,14 @@ static int dpm_prepare(pm_message_t stat dev->power.status =DPM_PREPARING ;mutex_unlock (&dpm_list_mtx); - error =device_prepare (dev, state); +pm_runtime_get_noresume (dev); +if (pm_runtime_barrier (dev) &&device_may_wakeup (dev)) { +/* Wake-up requested during system sleep transition. */ +pm_runtime_put_noidle (dev); + error = -EBUSY ; + }else { + error =device_prepare (dev, state); + }mutex_lock (&dpm_list_mtx);if (error) {
drivers/base/dd.c +11 -0
@@ -23,6 +23,7 @@#include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h"
@@ -202,7 +203,10 @@ int driver_probe_device(struct device_drpr_debug ("bus: '%s': %s: matched device %s with driver %s\n" , drv->bus->name, __func__,dev_name (dev), drv->name); +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); ret =really_probe (dev, drv); +pm_runtime_put_sync (dev);return ret; }
@@ -245,7 +249,9 @@ int device_attach(struct device *dev) ret =0 ; } }else { +pm_runtime_get_noresume (dev); ret =bus_for_each_drv (dev->bus,NULL , dev, __device_attach); +pm_runtime_put_sync (dev); }up (&dev->sem);return ret;
@@ -306,6 +312,9 @@ static void __device_release_driver(stru drv = dev->driver;if (drv) { +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); +driver_sysfs_remove (dev);if (dev->bus)
@@ -324,6 +333,8 @@ static void __device_release_driver(strublocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_UNBOUND_DRIVER , dev); + +pm_runtime_put_sync (dev); } }
drivers/base/power/power.h +24 -7
@@ -1,7 +1,14 @@ -static inline void device_pm_init (struct device *dev) -{ - dev->power.status =DPM_ON ; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init (struct device *dev); +extern void pm_runtime_remove (struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init (struct device *dev) {} +static inline void pm_runtime_remove (struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } +extern void device_pm_init (struct device *dev);extern void device_pm_add (struct device *);extern void device_pm_remove (struct device *);extern void device_pm_move_before (struct device *,struct device *);extern void device_pm_move_after (struct device *,struct device *);extern void device_pm_move_last (struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init (struct device *dev) +{ +pm_runtime_init (dev); +} + +static inline void device_pm_remove (struct device *dev) +{ +pm_runtime_remove (dev); +}static inline void device_pm_add (struct device *dev) {} -static inline void device_pm_remove (struct device *dev) {}static inline void device_pm_move_before (struct device *deva,struct device *devb) {}static inline void device_pm_move_after (struct device *deva,struct device *devb) {}static inline void device_pm_move_last (struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM
Documentation/power/runtime_pm.txt new file +378 -0
378 lines not on this page · raw message
PATCH 1/1 PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
In reply to Rafael J. WysockiHi,
One more update. This one should address your comments from this thread
http://lkml.org/lkml/2009/8/8/113
Thanks,
Rafael
---
From: Rafael J. Wysocki <[email protected]>
Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 15)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things.
Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback.
--- Documentation/power/runtime_pm.txt | 386 ++++++++++++++ drivers/base/dd.c | 11 drivers/base/power/Makefile | 1 drivers/base/power/main.c | 22 drivers/base/power/power.h | 31 - drivers/base/power/runtime.c | 1011 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 101 +++ include/linux/pm_runtime.h | 114 ++++ kernel/power/Kconfig | 14 kernel/power/main.c | 17 10 files changed, 1697 insertions(+), 11 deletions(-)
kernel/power/Kconfig +14 -0
@@ -208,3 +208,17 @@ config APM_EMULATION random kernel OOPSes or reboots that don't seem to be related to anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). + +config PM_RUNTIME + bool "Run-time PM core functionality" + depends on PM + ---help--- + Enable functionality allowing I/O devices to be put into energy-saving + (low power) states at run time (or autosuspended) after a specified + period of inactivity and woken up in response to a hardware-generated + wake-up event or a driver's request. + + Hardware support is generally required for this functionality to work + and the bus type drivers of the buses the devices are on are + responsible for the actual handling of the autosuspend requests and + wake-up events.
kernel/power/main.c +17 -0
@@ -11,6 +11,7 @@#include <linux/kobject.h> #include <linux/string.h> #include <linux/resume-trace.h> +#include <linux/workqueue.h> #include "power.h"
@@ -217,8 +218,24 @@ static struct attribute_group attr_group .attrs = g, }; +#ifdef CONFIG_PM_RUNTIME +struct workqueue_struct *pm_wq; + +static int __init pm_start_workqueue (void ) +{ + pm_wq =create_freezeable_workqueue ("pm" ); + +return pm_wq ?0 : -ENOMEM ; +} +#else +static inline int pm_start_workqueue (void ) {return 0 ; } +#endif +static int __init pm_init (void ) { +int error =pm_start_workqueue (); +if (error) +return error; power_kobj =kobject_create_and_add ("power" ,NULL );if (!power_kobj)return -ENOMEM ;
include/linux/pm.h +98 -3
130 lines not on this page · raw message
drivers/base/power/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/power/runtime.c new file +1011 -0
1,011 lines not on this page · raw message
include/linux/pm_runtime.h new file +114 -0
114 lines not on this page · raw message
drivers/base/power/main.c +21 -1
@@ -21,6 +21,7 @@#include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/resume-trace.h> #include <linux/rwsem.h> #include <linux/interrupt.h>
@@ -49,6 +50,16 @@ static DEFINE_MUTEX(dpm_list_mtx);static bool transition_started;/** +* device_pm_init - Initialize the PM-related part of a device object +* @dev: Device object being initialized. +*/ +void device_pm_init (struct device *dev) +{ + dev->power.status =DPM_ON ; +pm_runtime_init (dev); +} + +/** * device_pm_lock - lock the list of active devices used by the PM core */ void device_pm_lock (void )
@@ -105,6 +116,7 @@ void device_pm_remove(struct device *devmutex_lock (&dpm_list_mtx);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); +pm_runtime_remove (dev); }/**
@@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t stmutex_unlock (&dpm_list_mtx);device_complete (dev, state); +pm_runtime_put_noidle (dev);mutex_lock (&dpm_list_mtx); }
@@ -757,7 +770,14 @@ static int dpm_prepare(pm_message_t stat dev->power.status =DPM_PREPARING ;mutex_unlock (&dpm_list_mtx); - error =device_prepare (dev, state); +pm_runtime_get_noresume (dev); +if (pm_runtime_barrier (dev) &&device_may_wakeup (dev)) { +/* Wake-up requested during system sleep transition. */ +pm_runtime_put_noidle (dev); + error = -EBUSY ; + }else { + error =device_prepare (dev, state); + }mutex_lock (&dpm_list_mtx);if (error) {
drivers/base/dd.c +11 -0
@@ -23,6 +23,7 @@#include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h"
@@ -202,7 +203,12 @@ int driver_probe_device(struct device_drpr_debug ("bus: '%s': %s: matched device %s with driver %s\n" , drv->bus->name, __func__,dev_name (dev), drv->name); +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); ret =really_probe (dev, drv); +pm_runtime_put_noidle (dev); +if (!ret) +pm_runtime_idle (dev);return ret; }
@@ -306,6 +312,9 @@ static void __device_release_driver(stru drv = dev->driver;if (drv) { +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); +driver_sysfs_remove (dev);if (dev->bus)
@@ -324,6 +333,8 @@ static void __device_release_driver(strublocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_UNBOUND_DRIVER , dev); + +pm_runtime_put_noidle (dev); } }
drivers/base/power/power.h +24 -7
@@ -1,7 +1,14 @@ -static inline void device_pm_init (struct device *dev) -{ - dev->power.status =DPM_ON ; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init (struct device *dev); +extern void pm_runtime_remove (struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init (struct device *dev) {} +static inline void pm_runtime_remove (struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } +extern void device_pm_init (struct device *dev);extern void device_pm_add (struct device *);extern void device_pm_remove (struct device *);extern void device_pm_move_before (struct device *,struct device *);extern void device_pm_move_after (struct device *,struct device *);extern void device_pm_move_last (struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init (struct device *dev) +{ +pm_runtime_init (dev); +} + +static inline void device_pm_remove (struct device *dev) +{ +pm_runtime_remove (dev); +}static inline void device_pm_add (struct device *dev) {} -static inline void device_pm_remove (struct device *dev) {}static inline void device_pm_move_before (struct device *deva,struct device *devb) {}static inline void device_pm_move_after (struct device *deva,struct device *devb) {}static inline void device_pm_move_last (struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM
Documentation/power/runtime_pm.txt new file +386 -0
386 lines not on this page · raw message