hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/base/power/qos.c
....@@ -1,12 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
23 * Devices PM QoS constraints management
34 *
45 * Copyright (C) 2011 Texas Instruments, Inc.
5
- *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License version 2 as
8
- * published by the Free Software Foundation.
9
- *
106 *
117 * This module exposes the interface to kernel space for specifying
128 * per-device PM QoS dependencies. It provides infrastructure for registration
....@@ -22,7 +18,7 @@
2218 * per-device constraint data struct.
2319 *
2420 * Note about the per-device constraint data struct allocation:
25
- * . The per-device constraints data struct ptr is tored into the device
21
+ * . The per-device constraints data struct ptr is stored into the device
2622 * dev_pm_info.
2723 * . To minimize the data usage by the per-device constraints, the data struct
2824 * is only allocated at the first call to dev_pm_qos_add_request.
....@@ -94,33 +90,54 @@
9490 EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
9591
9692 /**
97
- * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
93
+ * __dev_pm_qos_resume_latency - Get resume latency constraint for a given device.
9894 * @dev: Device to get the PM QoS constraint value for.
9995 *
10096 * This routine must be called with dev->power.lock held.
10197 */
102
-s32 __dev_pm_qos_read_value(struct device *dev)
98
+s32 __dev_pm_qos_resume_latency(struct device *dev)
10399 {
104100 lockdep_assert_held(&dev->power.lock);
105101
106
- return dev_pm_qos_raw_read_value(dev);
102
+ return dev_pm_qos_raw_resume_latency(dev);
107103 }
108104
109105 /**
110106 * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
111107 * @dev: Device to get the PM QoS constraint value for.
108
+ * @type: QoS request type.
112109 */
113
-s32 dev_pm_qos_read_value(struct device *dev)
110
+s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
114111 {
112
+ struct dev_pm_qos *qos = dev->power.qos;
115113 unsigned long flags;
116114 s32 ret;
117115
118116 spin_lock_irqsave(&dev->power.lock, flags);
119
- ret = __dev_pm_qos_read_value(dev);
117
+
118
+ switch (type) {
119
+ case DEV_PM_QOS_RESUME_LATENCY:
120
+ ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
121
+ : pm_qos_read_value(&qos->resume_latency);
122
+ break;
123
+ case DEV_PM_QOS_MIN_FREQUENCY:
124
+ ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
125
+ : freq_qos_read_value(&qos->freq, FREQ_QOS_MIN);
126
+ break;
127
+ case DEV_PM_QOS_MAX_FREQUENCY:
128
+ ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
129
+ : freq_qos_read_value(&qos->freq, FREQ_QOS_MAX);
130
+ break;
131
+ default:
132
+ WARN_ON(1);
133
+ ret = 0;
134
+ }
135
+
120136 spin_unlock_irqrestore(&dev->power.lock, flags);
121137
122138 return ret;
123139 }
140
+EXPORT_SYMBOL_GPL(dev_pm_qos_read_value);
124141
125142 /**
126143 * apply_constraint - Add/modify/remove device PM QoS request.
....@@ -143,17 +160,19 @@
143160 value = 0;
144161
145162 ret = pm_qos_update_target(&qos->resume_latency,
146
- &req->data.pnode, action, value,
147
- true);
163
+ &req->data.pnode, action, value);
148164 break;
149165 case DEV_PM_QOS_LATENCY_TOLERANCE:
150166 ret = pm_qos_update_target(&qos->latency_tolerance,
151
- &req->data.pnode, action, value,
152
- true);
167
+ &req->data.pnode, action, value);
153168 if (ret) {
154169 value = pm_qos_read_value(&qos->latency_tolerance);
155170 req->dev->power.set_latency_tolerance(req->dev, value);
156171 }
172
+ break;
173
+ case DEV_PM_QOS_MIN_FREQUENCY:
174
+ case DEV_PM_QOS_MAX_FREQUENCY:
175
+ ret = freq_qos_apply(&req->data.freq, action, value);
157176 break;
158177 case DEV_PM_QOS_FLAGS:
159178 ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
....@@ -183,12 +202,11 @@
183202 if (!qos)
184203 return -ENOMEM;
185204
186
- n = kzalloc(sizeof(*n), GFP_KERNEL);
205
+ n = kzalloc(3 * sizeof(*n), GFP_KERNEL);
187206 if (!n) {
188207 kfree(qos);
189208 return -ENOMEM;
190209 }
191
- BLOCKING_INIT_NOTIFIER_HEAD(n);
192210
193211 c = &qos->resume_latency;
194212 plist_head_init(&c->list);
....@@ -197,6 +215,7 @@
197215 c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
198216 c->type = PM_QOS_MIN;
199217 c->notifiers = n;
218
+ BLOCKING_INIT_NOTIFIER_HEAD(n);
200219
201220 c = &qos->latency_tolerance;
202221 plist_head_init(&c->list);
....@@ -204,6 +223,8 @@
204223 c->default_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
205224 c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
206225 c->type = PM_QOS_MIN;
226
+
227
+ freq_constraints_init(&qos->freq);
207228
208229 INIT_LIST_HEAD(&qos->flags.list);
209230
....@@ -258,11 +279,27 @@
258279 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
259280 memset(req, 0, sizeof(*req));
260281 }
282
+
261283 c = &qos->latency_tolerance;
262284 plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
263285 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
264286 memset(req, 0, sizeof(*req));
265287 }
288
+
289
+ c = &qos->freq.min_freq;
290
+ plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
291
+ apply_constraint(req, PM_QOS_REMOVE_REQ,
292
+ PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
293
+ memset(req, 0, sizeof(*req));
294
+ }
295
+
296
+ c = &qos->freq.max_freq;
297
+ plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
298
+ apply_constraint(req, PM_QOS_REMOVE_REQ,
299
+ PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
300
+ memset(req, 0, sizeof(*req));
301
+ }
302
+
266303 f = &qos->flags;
267304 list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
268305 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
....@@ -308,11 +345,22 @@
308345 ret = dev_pm_qos_constraints_allocate(dev);
309346
310347 trace_dev_pm_qos_add_request(dev_name(dev), type, value);
311
- if (!ret) {
312
- req->dev = dev;
313
- req->type = type;
348
+ if (ret)
349
+ return ret;
350
+
351
+ req->dev = dev;
352
+ req->type = type;
353
+ if (req->type == DEV_PM_QOS_MIN_FREQUENCY)
354
+ ret = freq_qos_add_request(&dev->power.qos->freq,
355
+ &req->data.freq,
356
+ FREQ_QOS_MIN, value);
357
+ else if (req->type == DEV_PM_QOS_MAX_FREQUENCY)
358
+ ret = freq_qos_add_request(&dev->power.qos->freq,
359
+ &req->data.freq,
360
+ FREQ_QOS_MAX, value);
361
+ else
314362 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
315
- }
363
+
316364 return ret;
317365 }
318366
....@@ -375,6 +423,10 @@
375423 case DEV_PM_QOS_RESUME_LATENCY:
376424 case DEV_PM_QOS_LATENCY_TOLERANCE:
377425 curr_value = req->data.pnode.prio;
426
+ break;
427
+ case DEV_PM_QOS_MIN_FREQUENCY:
428
+ case DEV_PM_QOS_MAX_FREQUENCY:
429
+ curr_value = req->data.freq.pnode.prio;
378430 break;
379431 case DEV_PM_QOS_FLAGS:
380432 curr_value = req->data.flr.flags;
....@@ -473,6 +525,7 @@
473525 *
474526 * @dev: target device for the constraint
475527 * @notifier: notifier block managed by caller.
528
+ * @type: request type.
476529 *
477530 * Will register the notifier into a notification chain that gets called
478531 * upon changes to the target value for the device.
....@@ -480,7 +533,8 @@
480533 * If the device's constraints object doesn't exist when this routine is called,
481534 * it will be created (or error code will be returned if that fails).
482535 */
483
-int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
536
+int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
537
+ enum dev_pm_qos_req_type type)
484538 {
485539 int ret = 0;
486540
....@@ -491,10 +545,28 @@
491545 else if (!dev->power.qos)
492546 ret = dev_pm_qos_constraints_allocate(dev);
493547
494
- if (!ret)
548
+ if (ret)
549
+ goto unlock;
550
+
551
+ switch (type) {
552
+ case DEV_PM_QOS_RESUME_LATENCY:
495553 ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
496554 notifier);
555
+ break;
556
+ case DEV_PM_QOS_MIN_FREQUENCY:
557
+ ret = freq_qos_add_notifier(&dev->power.qos->freq,
558
+ FREQ_QOS_MIN, notifier);
559
+ break;
560
+ case DEV_PM_QOS_MAX_FREQUENCY:
561
+ ret = freq_qos_add_notifier(&dev->power.qos->freq,
562
+ FREQ_QOS_MAX, notifier);
563
+ break;
564
+ default:
565
+ WARN_ON(1);
566
+ ret = -EINVAL;
567
+ }
497568
569
+unlock:
498570 mutex_unlock(&dev_pm_qos_mtx);
499571 return ret;
500572 }
....@@ -506,24 +578,44 @@
506578 *
507579 * @dev: target device for the constraint
508580 * @notifier: notifier block to be removed.
581
+ * @type: request type.
509582 *
510583 * Will remove the notifier from the notification chain that gets called
511584 * upon changes to the target value.
512585 */
513586 int dev_pm_qos_remove_notifier(struct device *dev,
514
- struct notifier_block *notifier)
587
+ struct notifier_block *notifier,
588
+ enum dev_pm_qos_req_type type)
515589 {
516
- int retval = 0;
590
+ int ret = 0;
517591
518592 mutex_lock(&dev_pm_qos_mtx);
519593
520594 /* Silently return if the constraints object is not present. */
521
- if (!IS_ERR_OR_NULL(dev->power.qos))
522
- retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
523
- notifier);
595
+ if (IS_ERR_OR_NULL(dev->power.qos))
596
+ goto unlock;
524597
598
+ switch (type) {
599
+ case DEV_PM_QOS_RESUME_LATENCY:
600
+ ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
601
+ notifier);
602
+ break;
603
+ case DEV_PM_QOS_MIN_FREQUENCY:
604
+ ret = freq_qos_remove_notifier(&dev->power.qos->freq,
605
+ FREQ_QOS_MIN, notifier);
606
+ break;
607
+ case DEV_PM_QOS_MAX_FREQUENCY:
608
+ ret = freq_qos_remove_notifier(&dev->power.qos->freq,
609
+ FREQ_QOS_MAX, notifier);
610
+ break;
611
+ default:
612
+ WARN_ON(1);
613
+ ret = -EINVAL;
614
+ }
615
+
616
+unlock:
525617 mutex_unlock(&dev_pm_qos_mtx);
526
- return retval;
618
+ return ret;
527619 }
528620 EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
529621
....@@ -583,6 +675,9 @@
583675 req = dev->power.qos->flags_req;
584676 dev->power.qos->flags_req = NULL;
585677 break;
678
+ default:
679
+ WARN_ON(1);
680
+ return;
586681 }
587682 __dev_pm_qos_remove_request(req);
588683 kfree(req);