Commit b66213cdb002b08b29603d488c451dfe25e2ca20

Authored by Jean Pihet
Committed by Rafael J. Wysocki
1 parent 91ff4cb803

PM QoS: Add global notification mechanism for device constraints

Add a global notification chain that gets called upon changes to the
aggregated constraint value for any device.
The notification callbacks are passing the full constraint request data
in order for the callees to have access to it. The current use is for the
platform low-level code to access the target device of the constraint.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

Showing 3 changed files with 87 additions and 15 deletions Side-by-side Diff

drivers/base/power/qos.c
... ... @@ -17,6 +17,12 @@
17 17 *
18 18 * This QoS design is best effort based. Dependents register their QoS needs.
19 19 * Watchers register to keep track of the current QoS needs of the system.
  20 + * Watchers can register different types of notification callbacks:
  21 + * . a per-device notification callback using the dev_pm_qos_*_notifier API.
  22 + * The notification chain data is stored in the per-device constraint
  23 + * data struct.
  24 + * . a system-wide notification callback using the dev_pm_qos_*_global_notifier
  25 + * API. The notification chain data is stored in a static variable.
20 26 *
21 27 * Note about the per-device constraint data struct allocation:
22 28 * . The per-device constraints data struct ptr is tored into the device
23 29  
... ... @@ -45,8 +51,38 @@
45 51  
46 52  
47 53 static DEFINE_MUTEX(dev_pm_qos_mtx);
  54 +static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
48 55  
49 56 /*
  57 + * apply_constraint
  58 + * @req: constraint request to apply
  59 + * @action: action to perform add/update/remove, of type enum pm_qos_req_action
  60 + * @value: defines the qos request
  61 + *
  62 + * Internal function to update the constraints list using the PM QoS core
  63 + * code and if needed call the per-device and the global notification
  64 + * callbacks
  65 + */
  66 +static int apply_constraint(struct dev_pm_qos_request *req,
  67 + enum pm_qos_req_action action, int value)
  68 +{
  69 + int ret, curr_value;
  70 +
  71 + ret = pm_qos_update_target(req->dev->power.constraints,
  72 + &req->node, action, value);
  73 +
  74 + if (ret) {
  75 + /* Call the global callbacks if needed */
  76 + curr_value = pm_qos_read_value(req->dev->power.constraints);
  77 + blocking_notifier_call_chain(&dev_pm_notifiers,
  78 + (unsigned long)curr_value,
  79 + req);
  80 + }
  81 +
  82 + return ret;
  83 +}
  84 +
  85 +/*
50 86 * dev_pm_qos_constraints_allocate
51 87 * @dev: device to allocate data for
52 88 *
53 89  
... ... @@ -111,12 +147,11 @@
111 147 &dev->power.constraints->list,
112 148 node) {
113 149 /*
114   - * Update constraints list and call the per-device
  150 + * Update constraints list and call the notification
115 151 * callbacks if needed
116 152 */
117   - pm_qos_update_target(req->dev->power.constraints,
118   - &req->node, PM_QOS_REMOVE_REQ,
119   - PM_QOS_DEFAULT_VALUE);
  153 + apply_constraint(req, PM_QOS_REMOVE_REQ,
  154 + PM_QOS_DEFAULT_VALUE);
120 155 memset(req, 0, sizeof(*req));
121 156 }
122 157  
... ... @@ -147,7 +182,7 @@
147 182 * removed from the system
148 183 */
149 184 int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
150   - s32 value)
  185 + s32 value)
151 186 {
152 187 int ret = 0;
153 188  
... ... @@ -178,8 +213,7 @@
178 213 ret = dev_pm_qos_constraints_allocate(dev);
179 214  
180 215 if (!ret)
181   - ret = pm_qos_update_target(dev->power.constraints, &req->node,
182   - PM_QOS_ADD_REQ, value);
  216 + ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
183 217  
184 218 out:
185 219 mutex_unlock(&dev_pm_qos_mtx);
... ... @@ -220,10 +254,8 @@
220 254  
221 255 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) {
222 256 if (new_value != req->node.prio)
223   - ret = pm_qos_update_target(req->dev->power.constraints,
224   - &req->node,
225   - PM_QOS_UPDATE_REQ,
226   - new_value);
  257 + ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
  258 + new_value);
227 259 } else {
228 260 /* Return if the device has been removed */
229 261 ret = -ENODEV;
... ... @@ -262,9 +294,8 @@
262 294 mutex_lock(&dev_pm_qos_mtx);
263 295  
264 296 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) {
265   - ret = pm_qos_update_target(req->dev->power.constraints,
266   - &req->node, PM_QOS_REMOVE_REQ,
267   - PM_QOS_DEFAULT_VALUE);
  297 + ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
  298 + PM_QOS_DEFAULT_VALUE);
268 299 memset(req, 0, sizeof(*req));
269 300 } else {
270 301 /* Return if the device has been removed */
... ... @@ -336,4 +367,34 @@
336 367 return retval;
337 368 }
338 369 EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
  370 +
  371 +/**
  372 + * dev_pm_qos_add_global_notifier - sets notification entry for changes to
  373 + * target value of the PM QoS constraints for any device
  374 + *
  375 + * @notifier: notifier block managed by caller.
  376 + *
  377 + * Will register the notifier into a notification chain that gets called
  378 + * upon changes to the target value for any device.
  379 + */
  380 +int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
  381 +{
  382 + return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
  383 +}
  384 +EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
  385 +
  386 +/**
  387 + * dev_pm_qos_remove_global_notifier - deletes notification for changes to
  388 + * target value of PM QoS constraints for any device
  389 + *
  390 + * @notifier: notifier block to be removed.
  391 + *
  392 + * Will remove the notifier from the notification chain that gets called
  393 + * upon changes to the target value for any device.
  394 + */
  395 +int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
  396 +{
  397 + return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
  398 +}
  399 +EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
include/linux/pm_qos.h
... ... @@ -75,6 +75,7 @@
75 75 int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
76 76 int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
77 77 int pm_qos_request_active(struct pm_qos_request *req);
  78 +s32 pm_qos_read_value(struct pm_qos_constraints *c);
78 79  
79 80 int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
80 81 s32 value);
... ... @@ -84,6 +85,8 @@
84 85 struct notifier_block *notifier);
85 86 int dev_pm_qos_remove_notifier(struct device *dev,
86 87 struct notifier_block *notifier);
  88 +int dev_pm_qos_add_global_notifier(struct notifier_block *notifier);
  89 +int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier);
87 90 void dev_pm_qos_constraints_init(struct device *dev);
88 91 void dev_pm_qos_constraints_destroy(struct device *dev);
89 92 #else
... ... @@ -111,6 +114,8 @@
111 114 { return 0; }
112 115 static inline int pm_qos_request_active(struct pm_qos_request *req)
113 116 { return 0; }
  117 +static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
  118 + { return 0; }
114 119  
115 120 static inline int dev_pm_qos_add_request(struct device *dev,
116 121 struct dev_pm_qos_request *req,
... ... @@ -126,6 +131,12 @@
126 131 { return 0; }
127 132 static inline int dev_pm_qos_remove_notifier(struct device *dev,
128 133 struct notifier_block *notifier)
  134 + { return 0; }
  135 +static inline int dev_pm_qos_add_global_notifier(
  136 + struct notifier_block *notifier)
  137 + { return 0; }
  138 +static inline int dev_pm_qos_remove_global_notifier(
  139 + struct notifier_block *notifier)
129 140 { return 0; }
130 141 static inline void dev_pm_qos_constraints_init(struct device *dev)
131 142 { return; }
... ... @@ -140,7 +140,7 @@
140 140 }
141 141 }
142 142  
143   -static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
  143 +s32 pm_qos_read_value(struct pm_qos_constraints *c)
144 144 {
145 145 return c->target_value;
146 146 }