PM / QoS: Restore DEV_PM_QOS_MIN/MAX_FREQUENCY
authorLeonard Crestez <leonard.crestez@nxp.com>
Tue, 26 Nov 2019 15:17:13 +0000 (17:17 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 29 Nov 2019 11:04:50 +0000 (12:04 +0100)
Support for adding per-device frequency limits was removed in
commit 2aac8bdf7a0f ("PM: QoS: Drop frequency QoS types from device PM QoS")
after cpufreq switched to use a new "freq_constraints" construct.

Restore support for per-device freq limits but base this upon
freq_constraints. This is primarily meant to be used by the devfreq
subsystem.

This removes the "static" marking on freq_qos_apply but does not export
it for modules.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Tested-by: Matthias Kaehlcke <mka@chromium.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/base/power/qos.c
include/linux/pm_qos.h
kernel/power/qos.c

index 350dcafd751f8e6c352f5e68945103da7cd84227..8e93167f1783a476e71d042e59d52d6acef4fe94 100644 (file)
@@ -115,10 +115,20 @@ s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
 
        spin_lock_irqsave(&dev->power.lock, flags);
 
-       if (type == DEV_PM_QOS_RESUME_LATENCY) {
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
                ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
                        : pm_qos_read_value(&qos->resume_latency);
-       } else {
+               break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
+                       : freq_qos_read_value(&qos->freq, FREQ_QOS_MIN);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
+                       : freq_qos_read_value(&qos->freq, FREQ_QOS_MAX);
+               break;
+       default:
                WARN_ON(1);
                ret = 0;
        }
@@ -159,6 +169,10 @@ static int apply_constraint(struct dev_pm_qos_request *req,
                        req->dev->power.set_latency_tolerance(req->dev, value);
                }
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_apply(&req->data.freq, action, value);
+               break;
        case DEV_PM_QOS_FLAGS:
                ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
                                          action, value);
@@ -209,6 +223,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
        c->type = PM_QOS_MIN;
 
+       freq_constraints_init(&qos->freq);
+
        INIT_LIST_HEAD(&qos->flags.list);
 
        spin_lock_irq(&dev->power.lock);
@@ -269,6 +285,20 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
                memset(req, 0, sizeof(*req));
        }
 
+       c = &qos->freq.min_freq;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ,
+                                PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
+       c = &qos->freq.max_freq;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ,
+                                PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
        f = &qos->flags;
        list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -314,11 +344,22 @@ static int __dev_pm_qos_add_request(struct device *dev,
                ret = dev_pm_qos_constraints_allocate(dev);
 
        trace_dev_pm_qos_add_request(dev_name(dev), type, value);
-       if (!ret) {
-               req->dev = dev;
-               req->type = type;
+       if (ret)
+               return ret;
+
+       req->dev = dev;
+       req->type = type;
+       if (req->type == DEV_PM_QOS_MIN_FREQUENCY)
+               ret = freq_qos_add_request(&dev->power.qos->freq,
+                                          &req->data.freq,
+                                          FREQ_QOS_MIN, value);
+       else if (req->type == DEV_PM_QOS_MAX_FREQUENCY)
+               ret = freq_qos_add_request(&dev->power.qos->freq,
+                                          &req->data.freq,
+                                          FREQ_QOS_MAX, value);
+       else
                ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
-       }
+
        return ret;
 }
 
@@ -382,6 +423,10 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
        case DEV_PM_QOS_LATENCY_TOLERANCE:
                curr_value = req->data.pnode.prio;
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               curr_value = req->data.freq.pnode.prio;
+               break;
        case DEV_PM_QOS_FLAGS:
                curr_value = req->data.flr.flags;
                break;
@@ -507,6 +552,14 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
                ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
                                                       notifier);
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = freq_qos_add_notifier(&dev->power.qos->freq,
+                                           FREQ_QOS_MIN, notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_add_notifier(&dev->power.qos->freq,
+                                           FREQ_QOS_MAX, notifier);
+               break;
        default:
                WARN_ON(1);
                ret = -EINVAL;
@@ -546,6 +599,14 @@ int dev_pm_qos_remove_notifier(struct device *dev,
                ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
                                                         notifier);
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = freq_qos_remove_notifier(&dev->power.qos->freq,
+                                              FREQ_QOS_MIN, notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_remove_notifier(&dev->power.qos->freq,
+                                              FREQ_QOS_MAX, notifier);
+               break;
        default:
                WARN_ON(1);
                ret = -EINVAL;
index 678fec6da5b96fbcdf4e5af7b7ccf47bc1a34cb7..19eafca5680e6d651c1ba94f5d52899a68661527 100644 (file)
@@ -34,6 +34,8 @@ enum pm_qos_flags_status {
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT    PM_QOS_LATENCY_ANY
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
+#define PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE     0
+#define PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE     FREQ_QOS_MAX_DEFAULT_VALUE
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
 
 #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
@@ -101,6 +103,8 @@ struct freq_qos_request {
 enum dev_pm_qos_req_type {
        DEV_PM_QOS_RESUME_LATENCY = 1,
        DEV_PM_QOS_LATENCY_TOLERANCE,
+       DEV_PM_QOS_MIN_FREQUENCY,
+       DEV_PM_QOS_MAX_FREQUENCY,
        DEV_PM_QOS_FLAGS,
 };
 
@@ -109,6 +113,7 @@ struct dev_pm_qos_request {
        union {
                struct plist_node pnode;
                struct pm_qos_flags_request flr;
+               struct freq_qos_request freq;
        } data;
        struct device *dev;
 };
@@ -116,6 +121,7 @@ struct dev_pm_qos_request {
 struct dev_pm_qos {
        struct pm_qos_constraints resume_latency;
        struct pm_qos_constraints latency_tolerance;
+       struct freq_constraints freq;
        struct pm_qos_flags flags;
        struct dev_pm_qos_request *resume_latency_req;
        struct dev_pm_qos_request *latency_tolerance_req;
@@ -214,6 +220,10 @@ static inline s32 dev_pm_qos_read_value(struct device *dev,
        switch (type) {
        case DEV_PM_QOS_RESUME_LATENCY:
                return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               return PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               return PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
        default:
                WARN_ON(1);
                return 0;
@@ -293,6 +303,8 @@ int freq_qos_add_request(struct freq_constraints *qos,
                         enum freq_qos_req_type type, s32 value);
 int freq_qos_update_request(struct freq_qos_request *req, s32 new_value);
 int freq_qos_remove_request(struct freq_qos_request *req);
+int freq_qos_apply(struct freq_qos_request *req,
+                  enum pm_qos_req_action action, s32 value);
 
 int freq_qos_add_notifier(struct freq_constraints *qos,
                          enum freq_qos_req_type type,
index a45cba7df0ae2f7a5f9e276c0a0a88e09d527a19..83edf8698118628fa72d890d8fd844eeade86366 100644 (file)
@@ -714,8 +714,10 @@ s32 freq_qos_read_value(struct freq_constraints *qos,
  * @req: Constraint request to apply.
  * @action: Action to perform (add/update/remove).
  * @value: Value to assign to the QoS request.
+ *
+ * This is only meant to be called from inside pm_qos, not drivers.
  */
-static int freq_qos_apply(struct freq_qos_request *req,
+int freq_qos_apply(struct freq_qos_request *req,
                          enum pm_qos_req_action action, s32 value)
 {
        int ret;