Commit 36a8015f authored by Leonard Crestez's avatar Leonard Crestez Committed by Rafael J. Wysocki
Browse files

PM / QoS: Restore DEV_PM_QOS_MIN/MAX_FREQUENCY



Support for adding per-device frequency limits was removed in
commit 2aac8bdf ("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: default avatarLeonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: default avatarMatthias Kaehlcke <mka@chromium.org>
Tested-by: default avatarMatthias Kaehlcke <mka@chromium.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 342035f6
Loading
Loading
Loading
Loading
+67 −6
Original line number Diff line number Diff line
@@ -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) {
	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;
+12 −0
Original line number Diff line number Diff line
@@ -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,
+3 −1
Original line number Diff line number Diff line
@@ -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;