mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
![Rafael J. Wysocki](/assets/img/avatar_default.png)
Some devices, like the I2C controller on SH7372, are not necessary for providing power to their children or forwarding wakeup signals (and generally interrupts) from them. They are only needed by their children when there's some data to transfer, so they may be suspended for the majority of time and resumed on demand, when the children have data to send or receive. For this purpose, however, their power.ignore_children flags have to be set, or the PM core wouldn't allow them to be suspended while their children were active. Unfortunately, in some situations it may take too much time to resume such devices so that they can assist their children in transferring data. For example, if such a device belongs to a PM domain which goes to the "power off" state when that device is suspended, it may take too much time to restore power to the domain in response to the request from one of the device's children. In that case, if the parent's resume time is critical, the domain should stay in the "power on" state, although it still may be desirable to power manage the parent itself (e.g. by manipulating its clock). In general, device PM QoS may be used to address this problem. Namely, if the device's children added PM QoS latency constraints for it, they would be able to prevent it from being put into an overly deep low-power state. However, in some cases the devices needing to be serviced are not the immediate children of a "children-ignoring" device, but its grandchildren or even less direct descendants. In those cases, the entity wanting to add a PM QoS request for a given device's ancestor that ignores its children will have to find it in the first place, so introduce a new helper function that may be used to achieve that. This function, dev_pm_qos_add_ancestor_request(), will search for the first ancestor of the given device whose power.ignore_children flag is set and will add a device PM QoS latency request for that ancestor on behalf of the caller. The request added this way may be removed with the help of dev_pm_qos_remove_request() in the future, like any other device PM QoS latency request. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
160 lines
5.3 KiB
C
160 lines
5.3 KiB
C
#ifndef _LINUX_PM_QOS_H
|
|
#define _LINUX_PM_QOS_H
|
|
/* interface for the pm_qos_power infrastructure of the linux kernel.
|
|
*
|
|
* Mark Gross <mgross@linux.intel.com>
|
|
*/
|
|
#include <linux/plist.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/device.h>
|
|
|
|
#define PM_QOS_RESERVED 0
|
|
#define PM_QOS_CPU_DMA_LATENCY 1
|
|
#define PM_QOS_NETWORK_LATENCY 2
|
|
#define PM_QOS_NETWORK_THROUGHPUT 3
|
|
|
|
#define PM_QOS_NUM_CLASSES 4
|
|
#define PM_QOS_DEFAULT_VALUE -1
|
|
|
|
#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
|
|
#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
|
|
#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
|
|
#define PM_QOS_DEV_LAT_DEFAULT_VALUE 0
|
|
|
|
struct pm_qos_request {
|
|
struct plist_node node;
|
|
int pm_qos_class;
|
|
};
|
|
|
|
struct dev_pm_qos_request {
|
|
struct plist_node node;
|
|
struct device *dev;
|
|
};
|
|
|
|
enum pm_qos_type {
|
|
PM_QOS_UNITIALIZED,
|
|
PM_QOS_MAX, /* return the largest value */
|
|
PM_QOS_MIN /* return the smallest value */
|
|
};
|
|
|
|
/*
|
|
* Note: The lockless read path depends on the CPU accessing
|
|
* target_value atomically. Atomic access is only guaranteed on all CPU
|
|
* types linux supports for 32 bit quantites
|
|
*/
|
|
struct pm_qos_constraints {
|
|
struct plist_head list;
|
|
s32 target_value; /* Do not change to 64 bit */
|
|
s32 default_value;
|
|
enum pm_qos_type type;
|
|
struct blocking_notifier_head *notifiers;
|
|
};
|
|
|
|
/* Action requested to pm_qos_update_target */
|
|
enum pm_qos_req_action {
|
|
PM_QOS_ADD_REQ, /* Add a new request */
|
|
PM_QOS_UPDATE_REQ, /* Update an existing request */
|
|
PM_QOS_REMOVE_REQ /* Remove an existing request */
|
|
};
|
|
|
|
static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req)
|
|
{
|
|
return req->dev != 0;
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
|
|
enum pm_qos_req_action action, int value);
|
|
void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class,
|
|
s32 value);
|
|
void pm_qos_update_request(struct pm_qos_request *req,
|
|
s32 new_value);
|
|
void pm_qos_remove_request(struct pm_qos_request *req);
|
|
|
|
int pm_qos_request(int pm_qos_class);
|
|
int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
|
|
int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
|
|
int pm_qos_request_active(struct pm_qos_request *req);
|
|
s32 pm_qos_read_value(struct pm_qos_constraints *c);
|
|
|
|
s32 dev_pm_qos_read_value(struct device *dev);
|
|
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
|
|
s32 value);
|
|
int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
|
|
int dev_pm_qos_remove_request(struct dev_pm_qos_request *req);
|
|
int dev_pm_qos_add_notifier(struct device *dev,
|
|
struct notifier_block *notifier);
|
|
int dev_pm_qos_remove_notifier(struct device *dev,
|
|
struct notifier_block *notifier);
|
|
int dev_pm_qos_add_global_notifier(struct notifier_block *notifier);
|
|
int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier);
|
|
void dev_pm_qos_constraints_init(struct device *dev);
|
|
void dev_pm_qos_constraints_destroy(struct device *dev);
|
|
int dev_pm_qos_add_ancestor_request(struct device *dev,
|
|
struct dev_pm_qos_request *req, s32 value);
|
|
#else
|
|
static inline int pm_qos_update_target(struct pm_qos_constraints *c,
|
|
struct plist_node *node,
|
|
enum pm_qos_req_action action,
|
|
int value)
|
|
{ return 0; }
|
|
static inline void pm_qos_add_request(struct pm_qos_request *req,
|
|
int pm_qos_class, s32 value)
|
|
{ return; }
|
|
static inline void pm_qos_update_request(struct pm_qos_request *req,
|
|
s32 new_value)
|
|
{ return; }
|
|
static inline void pm_qos_remove_request(struct pm_qos_request *req)
|
|
{ return; }
|
|
|
|
static inline int pm_qos_request(int pm_qos_class)
|
|
{ return 0; }
|
|
static inline int pm_qos_add_notifier(int pm_qos_class,
|
|
struct notifier_block *notifier)
|
|
{ return 0; }
|
|
static inline int pm_qos_remove_notifier(int pm_qos_class,
|
|
struct notifier_block *notifier)
|
|
{ return 0; }
|
|
static inline int pm_qos_request_active(struct pm_qos_request *req)
|
|
{ return 0; }
|
|
static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
|
|
{ return 0; }
|
|
|
|
static inline s32 dev_pm_qos_read_value(struct device *dev)
|
|
{ return 0; }
|
|
static inline int dev_pm_qos_add_request(struct device *dev,
|
|
struct dev_pm_qos_request *req,
|
|
s32 value)
|
|
{ return 0; }
|
|
static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
|
|
s32 new_value)
|
|
{ return 0; }
|
|
static inline int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
|
|
{ return 0; }
|
|
static inline int dev_pm_qos_add_notifier(struct device *dev,
|
|
struct notifier_block *notifier)
|
|
{ return 0; }
|
|
static inline int dev_pm_qos_remove_notifier(struct device *dev,
|
|
struct notifier_block *notifier)
|
|
{ return 0; }
|
|
static inline int dev_pm_qos_add_global_notifier(
|
|
struct notifier_block *notifier)
|
|
{ return 0; }
|
|
static inline int dev_pm_qos_remove_global_notifier(
|
|
struct notifier_block *notifier)
|
|
{ return 0; }
|
|
static inline void dev_pm_qos_constraints_init(struct device *dev)
|
|
{
|
|
dev->power.power_state = PMSG_ON;
|
|
}
|
|
static inline void dev_pm_qos_constraints_destroy(struct device *dev)
|
|
{
|
|
dev->power.power_state = PMSG_INVALID;
|
|
}
|
|
static inline int dev_pm_qos_add_ancestor_request(struct device *dev,
|
|
struct dev_pm_qos_request *req, s32 value)
|
|
{ return 0; }
|
|
#endif
|
|
|
|
#endif
|