Message ID | 8c0ead9cc598f9eb7d15bd4878108b545368dd6e.1560163748.git.viresh.kumar@linaro.org (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | cpufreq: Use QoS layer to manage freq-constraints | expand |
On Mon, Jun 10, 2019 at 04:21:34PM +0530, Viresh Kumar wrote: > This patch introduces the min-frequency and max-frequency device > constraints, which will be used by the cpufreq core to begin with. > > Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Again, I'm mostly ignorant about QoS, in the context of the existing code (particularly looking at DEV_PM_QOS_RESUME_LATENCY) this looks reasonable to me. FWIW: Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
On Mon, 10 Jun 2019 at 12:52, Viresh Kumar <viresh.kumar@linaro.org> wrote: > > This patch introduces the min-frequency and max-frequency device > constraints, which will be used by the cpufreq core to begin with. > > Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Kind regards Uffe > --- > drivers/base/power/qos.c | 103 +++++++++++++++++++++++++++++++++------ > include/linux/pm_qos.h | 18 +++++++ > 2 files changed, 107 insertions(+), 14 deletions(-) > > diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c > index 7bb88174371f..e977aef437a5 100644 > --- a/drivers/base/power/qos.c > +++ b/drivers/base/power/qos.c > @@ -151,6 +151,14 @@ 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: > + ret = pm_qos_update_target(&qos->min_frequency, > + &req->data.pnode, action, value); > + break; > + case DEV_PM_QOS_MAX_FREQUENCY: > + ret = pm_qos_update_target(&qos->max_frequency, > + &req->data.pnode, action, value); > + break; > case DEV_PM_QOS_FLAGS: > ret = pm_qos_update_flags(&qos->flags, &req->data.flr, > action, value); > @@ -179,12 +187,11 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) > if (!qos) > return -ENOMEM; > > - n = kzalloc(sizeof(*n), GFP_KERNEL); > + n = kzalloc(3 * sizeof(*n), GFP_KERNEL); > if (!n) { > kfree(qos); > return -ENOMEM; > } > - BLOCKING_INIT_NOTIFIER_HEAD(n); > > c = &qos->resume_latency; > plist_head_init(&c->list); > @@ -193,6 +200,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) > c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; > c->type = PM_QOS_MIN; > c->notifiers = n; > + BLOCKING_INIT_NOTIFIER_HEAD(n); > > c = &qos->latency_tolerance; > plist_head_init(&c->list); > @@ -201,6 +209,24 @@ 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; > > + c = &qos->min_frequency; > + plist_head_init(&c->list); > + c->target_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE; > + c->default_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE; > + c->no_constraint_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE; > + c->type = PM_QOS_MAX; > + c->notifiers = ++n; > + BLOCKING_INIT_NOTIFIER_HEAD(n); > + > + c = &qos->max_frequency; > + plist_head_init(&c->list); > + c->target_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; > + c->default_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; > + c->no_constraint_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; > + c->type = PM_QOS_MIN; > + c->notifiers = ++n; > + BLOCKING_INIT_NOTIFIER_HEAD(n); > + > INIT_LIST_HEAD(&qos->flags.list); > > spin_lock_irq(&dev->power.lock); > @@ -254,11 +280,25 @@ void dev_pm_qos_constraints_destroy(struct device *dev) > apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); > memset(req, 0, sizeof(*req)); > } > + > c = &qos->latency_tolerance; > plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { > apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); > memset(req, 0, sizeof(*req)); > } > + > + c = &qos->min_frequency; > + plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { > + apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE); > + memset(req, 0, sizeof(*req)); > + } > + > + c = &qos->max_frequency; > + plist_for_each_entry_safe(req, tmp, &c->list, data.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); > @@ -370,6 +410,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, > switch(req->type) { > case DEV_PM_QOS_RESUME_LATENCY: > case DEV_PM_QOS_LATENCY_TOLERANCE: > + case DEV_PM_QOS_MIN_FREQUENCY: > + case DEV_PM_QOS_MAX_FREQUENCY: > curr_value = req->data.pnode.prio; > break; > case DEV_PM_QOS_FLAGS: > @@ -482,9 +524,6 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier, > { > int ret = 0; > > - if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY)) > - return -EINVAL; > - > mutex_lock(&dev_pm_qos_mtx); > > if (IS_ERR(dev->power.qos)) > @@ -492,10 +531,28 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier, > else if (!dev->power.qos) > ret = dev_pm_qos_constraints_allocate(dev); > > - if (!ret) > + if (ret) > + goto unlock; > + > + switch (type) { > + case DEV_PM_QOS_RESUME_LATENCY: > ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers, > notifier); > + break; > + case DEV_PM_QOS_MIN_FREQUENCY: > + ret = blocking_notifier_chain_register(dev->power.qos->min_frequency.notifiers, > + notifier); > + break; > + case DEV_PM_QOS_MAX_FREQUENCY: > + ret = blocking_notifier_chain_register(dev->power.qos->max_frequency.notifiers, > + notifier); > + break; > + default: > + WARN_ON(1); > + ret = -EINVAL; > + } > > +unlock: > mutex_unlock(&dev_pm_qos_mtx); > return ret; > } > @@ -516,20 +573,35 @@ int dev_pm_qos_remove_notifier(struct device *dev, > struct notifier_block *notifier, > enum dev_pm_qos_req_type type) > { > - int retval = 0; > - > - if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY)) > - return -EINVAL; > + int ret = 0; > > mutex_lock(&dev_pm_qos_mtx); > > /* Silently return if the constraints object is not present. */ > - if (!IS_ERR_OR_NULL(dev->power.qos)) > - retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers, > - notifier); > + if (IS_ERR_OR_NULL(dev->power.qos)) > + goto unlock; > > + switch (type) { > + case DEV_PM_QOS_RESUME_LATENCY: > + ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers, > + notifier); > + break; > + case DEV_PM_QOS_MIN_FREQUENCY: > + ret = blocking_notifier_chain_unregister(dev->power.qos->min_frequency.notifiers, > + notifier); > + break; > + case DEV_PM_QOS_MAX_FREQUENCY: > + ret = blocking_notifier_chain_unregister(dev->power.qos->max_frequency.notifiers, > + notifier); > + break; > + default: > + WARN_ON(1); > + ret = -EINVAL; > + } > + > +unlock: > mutex_unlock(&dev_pm_qos_mtx); > - return retval; > + return ret; > } > EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier); > > @@ -589,6 +661,9 @@ static void __dev_pm_qos_drop_user_request(struct device *dev, > req = dev->power.qos->flags_req; > dev->power.qos->flags_req = NULL; > break; > + default: > + WARN_ON(1); > + return; > } > __dev_pm_qos_remove_request(req); > kfree(req); > diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h > index 55814d48c39c..3f994283a5ae 100644 > --- a/include/linux/pm_qos.h > +++ b/include/linux/pm_qos.h > @@ -40,6 +40,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 (-1) > #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) > > #define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) > @@ -58,6 +60,8 @@ struct pm_qos_flags_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, > }; > > @@ -99,10 +103,14 @@ struct pm_qos_flags { > struct dev_pm_qos { > struct pm_qos_constraints resume_latency; > struct pm_qos_constraints latency_tolerance; > + struct pm_qos_constraints min_frequency; > + struct pm_qos_constraints max_frequency; > struct pm_qos_flags flags; > struct dev_pm_qos_request *resume_latency_req; > struct dev_pm_qos_request *latency_tolerance_req; > struct dev_pm_qos_request *flags_req; > + struct dev_pm_qos_request *min_frequency_req; > + struct dev_pm_qos_request *max_frequency_req; > }; > > /* Action requested to pm_qos_update_target */ > @@ -185,6 +193,12 @@ static inline s32 dev_pm_qos_raw_read_value(struct device *dev, > case DEV_PM_QOS_RESUME_LATENCY: > return IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT > : pm_qos_read_value(&qos->resume_latency); > + case DEV_PM_QOS_MIN_FREQUENCY: > + return IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE > + : pm_qos_read_value(&qos->min_frequency); > + case DEV_PM_QOS_MAX_FREQUENCY: > + return IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE > + : pm_qos_read_value(&qos->max_frequency); > default: > WARN_ON(1); > return 0; > @@ -256,6 +270,10 @@ static inline s32 dev_pm_qos_raw_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; > -- > 2.21.0.rc0.269.g1a574e7a288b >
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 7bb88174371f..e977aef437a5 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -151,6 +151,14 @@ 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: + ret = pm_qos_update_target(&qos->min_frequency, + &req->data.pnode, action, value); + break; + case DEV_PM_QOS_MAX_FREQUENCY: + ret = pm_qos_update_target(&qos->max_frequency, + &req->data.pnode, action, value); + break; case DEV_PM_QOS_FLAGS: ret = pm_qos_update_flags(&qos->flags, &req->data.flr, action, value); @@ -179,12 +187,11 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) if (!qos) return -ENOMEM; - n = kzalloc(sizeof(*n), GFP_KERNEL); + n = kzalloc(3 * sizeof(*n), GFP_KERNEL); if (!n) { kfree(qos); return -ENOMEM; } - BLOCKING_INIT_NOTIFIER_HEAD(n); c = &qos->resume_latency; plist_head_init(&c->list); @@ -193,6 +200,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; c->type = PM_QOS_MIN; c->notifiers = n; + BLOCKING_INIT_NOTIFIER_HEAD(n); c = &qos->latency_tolerance; plist_head_init(&c->list); @@ -201,6 +209,24 @@ 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; + c = &qos->min_frequency; + plist_head_init(&c->list); + c->target_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE; + c->default_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE; + c->no_constraint_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE; + c->type = PM_QOS_MAX; + c->notifiers = ++n; + BLOCKING_INIT_NOTIFIER_HEAD(n); + + c = &qos->max_frequency; + plist_head_init(&c->list); + c->target_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; + c->default_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; + c->no_constraint_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; + c->type = PM_QOS_MIN; + c->notifiers = ++n; + BLOCKING_INIT_NOTIFIER_HEAD(n); + INIT_LIST_HEAD(&qos->flags.list); spin_lock_irq(&dev->power.lock); @@ -254,11 +280,25 @@ void dev_pm_qos_constraints_destroy(struct device *dev) apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); memset(req, 0, sizeof(*req)); } + c = &qos->latency_tolerance; plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); memset(req, 0, sizeof(*req)); } + + c = &qos->min_frequency; + plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { + apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE); + memset(req, 0, sizeof(*req)); + } + + c = &qos->max_frequency; + plist_for_each_entry_safe(req, tmp, &c->list, data.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); @@ -370,6 +410,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, switch(req->type) { case DEV_PM_QOS_RESUME_LATENCY: case DEV_PM_QOS_LATENCY_TOLERANCE: + case DEV_PM_QOS_MIN_FREQUENCY: + case DEV_PM_QOS_MAX_FREQUENCY: curr_value = req->data.pnode.prio; break; case DEV_PM_QOS_FLAGS: @@ -482,9 +524,6 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier, { int ret = 0; - if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY)) - return -EINVAL; - mutex_lock(&dev_pm_qos_mtx); if (IS_ERR(dev->power.qos)) @@ -492,10 +531,28 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier, else if (!dev->power.qos) ret = dev_pm_qos_constraints_allocate(dev); - if (!ret) + if (ret) + goto unlock; + + switch (type) { + case DEV_PM_QOS_RESUME_LATENCY: ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers, notifier); + break; + case DEV_PM_QOS_MIN_FREQUENCY: + ret = blocking_notifier_chain_register(dev->power.qos->min_frequency.notifiers, + notifier); + break; + case DEV_PM_QOS_MAX_FREQUENCY: + ret = blocking_notifier_chain_register(dev->power.qos->max_frequency.notifiers, + notifier); + break; + default: + WARN_ON(1); + ret = -EINVAL; + } +unlock: mutex_unlock(&dev_pm_qos_mtx); return ret; } @@ -516,20 +573,35 @@ int dev_pm_qos_remove_notifier(struct device *dev, struct notifier_block *notifier, enum dev_pm_qos_req_type type) { - int retval = 0; - - if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY)) - return -EINVAL; + int ret = 0; mutex_lock(&dev_pm_qos_mtx); /* Silently return if the constraints object is not present. */ - if (!IS_ERR_OR_NULL(dev->power.qos)) - retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers, - notifier); + if (IS_ERR_OR_NULL(dev->power.qos)) + goto unlock; + switch (type) { + case DEV_PM_QOS_RESUME_LATENCY: + ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers, + notifier); + break; + case DEV_PM_QOS_MIN_FREQUENCY: + ret = blocking_notifier_chain_unregister(dev->power.qos->min_frequency.notifiers, + notifier); + break; + case DEV_PM_QOS_MAX_FREQUENCY: + ret = blocking_notifier_chain_unregister(dev->power.qos->max_frequency.notifiers, + notifier); + break; + default: + WARN_ON(1); + ret = -EINVAL; + } + +unlock: mutex_unlock(&dev_pm_qos_mtx); - return retval; + return ret; } EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier); @@ -589,6 +661,9 @@ static void __dev_pm_qos_drop_user_request(struct device *dev, req = dev->power.qos->flags_req; dev->power.qos->flags_req = NULL; break; + default: + WARN_ON(1); + return; } __dev_pm_qos_remove_request(req); kfree(req); diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 55814d48c39c..3f994283a5ae 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -40,6 +40,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 (-1) #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) #define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) @@ -58,6 +60,8 @@ struct pm_qos_flags_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, }; @@ -99,10 +103,14 @@ struct pm_qos_flags { struct dev_pm_qos { struct pm_qos_constraints resume_latency; struct pm_qos_constraints latency_tolerance; + struct pm_qos_constraints min_frequency; + struct pm_qos_constraints max_frequency; struct pm_qos_flags flags; struct dev_pm_qos_request *resume_latency_req; struct dev_pm_qos_request *latency_tolerance_req; struct dev_pm_qos_request *flags_req; + struct dev_pm_qos_request *min_frequency_req; + struct dev_pm_qos_request *max_frequency_req; }; /* Action requested to pm_qos_update_target */ @@ -185,6 +193,12 @@ static inline s32 dev_pm_qos_raw_read_value(struct device *dev, case DEV_PM_QOS_RESUME_LATENCY: return IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT : pm_qos_read_value(&qos->resume_latency); + case DEV_PM_QOS_MIN_FREQUENCY: + return IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE + : pm_qos_read_value(&qos->min_frequency); + case DEV_PM_QOS_MAX_FREQUENCY: + return IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE + : pm_qos_read_value(&qos->max_frequency); default: WARN_ON(1); return 0; @@ -256,6 +270,10 @@ static inline s32 dev_pm_qos_raw_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;
This patch introduces the min-frequency and max-frequency device constraints, which will be used by the cpufreq core to begin with. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> --- drivers/base/power/qos.c | 103 +++++++++++++++++++++++++++++++++------ include/linux/pm_qos.h | 18 +++++++ 2 files changed, 107 insertions(+), 14 deletions(-)