162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Devices PM QoS constraints management
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This module exposes the interface to kernel space for specifying
862306a36Sopenharmony_ci * per-device PM QoS dependencies. It provides infrastructure for registration
962306a36Sopenharmony_ci * of:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Dependents on a QoS value : register requests
1262306a36Sopenharmony_ci * Watchers of QoS value : get notified when target QoS value changes
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * This QoS design is best effort based. Dependents register their QoS needs.
1562306a36Sopenharmony_ci * Watchers register to keep track of the current QoS needs of the system.
1662306a36Sopenharmony_ci * Watchers can register a per-device notification callback using the
1762306a36Sopenharmony_ci * dev_pm_qos_*_notifier API. The notification chain data is stored in the
1862306a36Sopenharmony_ci * per-device constraint data struct.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Note about the per-device constraint data struct allocation:
2162306a36Sopenharmony_ci * . The per-device constraints data struct ptr is stored into the device
2262306a36Sopenharmony_ci *    dev_pm_info.
2362306a36Sopenharmony_ci * . To minimize the data usage by the per-device constraints, the data struct
2462306a36Sopenharmony_ci *   is only allocated at the first call to dev_pm_qos_add_request.
2562306a36Sopenharmony_ci * . The data is later free'd when the device is removed from the system.
2662306a36Sopenharmony_ci *  . A global mutex protects the constraints users from the data being
2762306a36Sopenharmony_ci *     allocated and free'd.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/pm_qos.h>
3162306a36Sopenharmony_ci#include <linux/spinlock.h>
3262306a36Sopenharmony_ci#include <linux/slab.h>
3362306a36Sopenharmony_ci#include <linux/device.h>
3462306a36Sopenharmony_ci#include <linux/mutex.h>
3562306a36Sopenharmony_ci#include <linux/export.h>
3662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3762306a36Sopenharmony_ci#include <linux/err.h>
3862306a36Sopenharmony_ci#include <trace/events/power.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "power.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic DEFINE_MUTEX(dev_pm_qos_mtx);
4362306a36Sopenharmony_cistatic DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * __dev_pm_qos_flags - Check PM QoS flags for a given device.
4762306a36Sopenharmony_ci * @dev: Device to check the PM QoS flags for.
4862306a36Sopenharmony_ci * @mask: Flags to check against.
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * This routine must be called with dev->power.lock held.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cienum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct dev_pm_qos *qos = dev->power.qos;
5562306a36Sopenharmony_ci	struct pm_qos_flags *pqf;
5662306a36Sopenharmony_ci	s32 val;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	lockdep_assert_held(&dev->power.lock);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(qos))
6162306a36Sopenharmony_ci		return PM_QOS_FLAGS_UNDEFINED;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	pqf = &qos->flags;
6462306a36Sopenharmony_ci	if (list_empty(&pqf->list))
6562306a36Sopenharmony_ci		return PM_QOS_FLAGS_UNDEFINED;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	val = pqf->effective_flags & mask;
6862306a36Sopenharmony_ci	if (val)
6962306a36Sopenharmony_ci		return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return PM_QOS_FLAGS_NONE;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/**
7562306a36Sopenharmony_ci * dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
7662306a36Sopenharmony_ci * @dev: Device to check the PM QoS flags for.
7762306a36Sopenharmony_ci * @mask: Flags to check against.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_cienum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	unsigned long irqflags;
8262306a36Sopenharmony_ci	enum pm_qos_flags_status ret;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	spin_lock_irqsave(&dev->power.lock, irqflags);
8562306a36Sopenharmony_ci	ret = __dev_pm_qos_flags(dev, mask);
8662306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->power.lock, irqflags);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return ret;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_flags);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/**
9362306a36Sopenharmony_ci * __dev_pm_qos_resume_latency - Get resume latency constraint for a given device.
9462306a36Sopenharmony_ci * @dev: Device to get the PM QoS constraint value for.
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * This routine must be called with dev->power.lock held.
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_cis32 __dev_pm_qos_resume_latency(struct device *dev)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	lockdep_assert_held(&dev->power.lock);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return dev_pm_qos_raw_resume_latency(dev);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/**
10662306a36Sopenharmony_ci * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
10762306a36Sopenharmony_ci * @dev: Device to get the PM QoS constraint value for.
10862306a36Sopenharmony_ci * @type: QoS request type.
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_cis32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct dev_pm_qos *qos = dev->power.qos;
11362306a36Sopenharmony_ci	unsigned long flags;
11462306a36Sopenharmony_ci	s32 ret;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	spin_lock_irqsave(&dev->power.lock, flags);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	switch (type) {
11962306a36Sopenharmony_ci	case DEV_PM_QOS_RESUME_LATENCY:
12062306a36Sopenharmony_ci		ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
12162306a36Sopenharmony_ci			: pm_qos_read_value(&qos->resume_latency);
12262306a36Sopenharmony_ci		break;
12362306a36Sopenharmony_ci	case DEV_PM_QOS_MIN_FREQUENCY:
12462306a36Sopenharmony_ci		ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
12562306a36Sopenharmony_ci			: freq_qos_read_value(&qos->freq, FREQ_QOS_MIN);
12662306a36Sopenharmony_ci		break;
12762306a36Sopenharmony_ci	case DEV_PM_QOS_MAX_FREQUENCY:
12862306a36Sopenharmony_ci		ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
12962306a36Sopenharmony_ci			: freq_qos_read_value(&qos->freq, FREQ_QOS_MAX);
13062306a36Sopenharmony_ci		break;
13162306a36Sopenharmony_ci	default:
13262306a36Sopenharmony_ci		WARN_ON(1);
13362306a36Sopenharmony_ci		ret = 0;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->power.lock, flags);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return ret;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/**
14262306a36Sopenharmony_ci * apply_constraint - Add/modify/remove device PM QoS request.
14362306a36Sopenharmony_ci * @req: Constraint request to apply
14462306a36Sopenharmony_ci * @action: Action to perform (add/update/remove).
14562306a36Sopenharmony_ci * @value: Value to assign to the QoS request.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * Internal function to update the constraints list using the PM QoS core
14862306a36Sopenharmony_ci * code and if needed call the per-device callbacks.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistatic int apply_constraint(struct dev_pm_qos_request *req,
15162306a36Sopenharmony_ci			    enum pm_qos_req_action action, s32 value)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct dev_pm_qos *qos = req->dev->power.qos;
15462306a36Sopenharmony_ci	int ret;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	switch(req->type) {
15762306a36Sopenharmony_ci	case DEV_PM_QOS_RESUME_LATENCY:
15862306a36Sopenharmony_ci		if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
15962306a36Sopenharmony_ci			value = 0;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		ret = pm_qos_update_target(&qos->resume_latency,
16262306a36Sopenharmony_ci					   &req->data.pnode, action, value);
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	case DEV_PM_QOS_LATENCY_TOLERANCE:
16562306a36Sopenharmony_ci		ret = pm_qos_update_target(&qos->latency_tolerance,
16662306a36Sopenharmony_ci					   &req->data.pnode, action, value);
16762306a36Sopenharmony_ci		if (ret) {
16862306a36Sopenharmony_ci			value = pm_qos_read_value(&qos->latency_tolerance);
16962306a36Sopenharmony_ci			req->dev->power.set_latency_tolerance(req->dev, value);
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	case DEV_PM_QOS_MIN_FREQUENCY:
17362306a36Sopenharmony_ci	case DEV_PM_QOS_MAX_FREQUENCY:
17462306a36Sopenharmony_ci		ret = freq_qos_apply(&req->data.freq, action, value);
17562306a36Sopenharmony_ci		break;
17662306a36Sopenharmony_ci	case DEV_PM_QOS_FLAGS:
17762306a36Sopenharmony_ci		ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
17862306a36Sopenharmony_ci					  action, value);
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	default:
18162306a36Sopenharmony_ci		ret = -EINVAL;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return ret;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/*
18862306a36Sopenharmony_ci * dev_pm_qos_constraints_allocate
18962306a36Sopenharmony_ci * @dev: device to allocate data for
19062306a36Sopenharmony_ci *
19162306a36Sopenharmony_ci * Called at the first call to add_request, for constraint data allocation
19262306a36Sopenharmony_ci * Must be called with the dev_pm_qos_mtx mutex held
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_cistatic int dev_pm_qos_constraints_allocate(struct device *dev)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct dev_pm_qos *qos;
19762306a36Sopenharmony_ci	struct pm_qos_constraints *c;
19862306a36Sopenharmony_ci	struct blocking_notifier_head *n;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	qos = kzalloc(sizeof(*qos), GFP_KERNEL);
20162306a36Sopenharmony_ci	if (!qos)
20262306a36Sopenharmony_ci		return -ENOMEM;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	n = kzalloc(3 * sizeof(*n), GFP_KERNEL);
20562306a36Sopenharmony_ci	if (!n) {
20662306a36Sopenharmony_ci		kfree(qos);
20762306a36Sopenharmony_ci		return -ENOMEM;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	c = &qos->resume_latency;
21162306a36Sopenharmony_ci	plist_head_init(&c->list);
21262306a36Sopenharmony_ci	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
21362306a36Sopenharmony_ci	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
21462306a36Sopenharmony_ci	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
21562306a36Sopenharmony_ci	c->type = PM_QOS_MIN;
21662306a36Sopenharmony_ci	c->notifiers = n;
21762306a36Sopenharmony_ci	BLOCKING_INIT_NOTIFIER_HEAD(n);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	c = &qos->latency_tolerance;
22062306a36Sopenharmony_ci	plist_head_init(&c->list);
22162306a36Sopenharmony_ci	c->target_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
22262306a36Sopenharmony_ci	c->default_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
22362306a36Sopenharmony_ci	c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
22462306a36Sopenharmony_ci	c->type = PM_QOS_MIN;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	freq_constraints_init(&qos->freq);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	INIT_LIST_HEAD(&qos->flags.list);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	spin_lock_irq(&dev->power.lock);
23162306a36Sopenharmony_ci	dev->power.qos = qos;
23262306a36Sopenharmony_ci	spin_unlock_irq(&dev->power.lock);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return 0;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic void __dev_pm_qos_hide_latency_limit(struct device *dev);
23862306a36Sopenharmony_cistatic void __dev_pm_qos_hide_flags(struct device *dev);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/**
24162306a36Sopenharmony_ci * dev_pm_qos_constraints_destroy
24262306a36Sopenharmony_ci * @dev: target device
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * Called from the device PM subsystem on device removal under device_pm_lock().
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_civoid dev_pm_qos_constraints_destroy(struct device *dev)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct dev_pm_qos *qos;
24962306a36Sopenharmony_ci	struct dev_pm_qos_request *req, *tmp;
25062306a36Sopenharmony_ci	struct pm_qos_constraints *c;
25162306a36Sopenharmony_ci	struct pm_qos_flags *f;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_sysfs_mtx);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/*
25662306a36Sopenharmony_ci	 * If the device's PM QoS resume latency limit or PM QoS flags have been
25762306a36Sopenharmony_ci	 * exposed to user space, they have to be hidden at this point.
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci	pm_qos_sysfs_remove_resume_latency(dev);
26062306a36Sopenharmony_ci	pm_qos_sysfs_remove_flags(dev);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	__dev_pm_qos_hide_latency_limit(dev);
26562306a36Sopenharmony_ci	__dev_pm_qos_hide_flags(dev);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	qos = dev->power.qos;
26862306a36Sopenharmony_ci	if (!qos)
26962306a36Sopenharmony_ci		goto out;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Flush the constraints lists for the device. */
27262306a36Sopenharmony_ci	c = &qos->resume_latency;
27362306a36Sopenharmony_ci	plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
27462306a36Sopenharmony_ci		/*
27562306a36Sopenharmony_ci		 * Update constraints list and call the notification
27662306a36Sopenharmony_ci		 * callbacks if needed
27762306a36Sopenharmony_ci		 */
27862306a36Sopenharmony_ci		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
27962306a36Sopenharmony_ci		memset(req, 0, sizeof(*req));
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	c = &qos->latency_tolerance;
28362306a36Sopenharmony_ci	plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
28462306a36Sopenharmony_ci		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
28562306a36Sopenharmony_ci		memset(req, 0, sizeof(*req));
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	c = &qos->freq.min_freq;
28962306a36Sopenharmony_ci	plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
29062306a36Sopenharmony_ci		apply_constraint(req, PM_QOS_REMOVE_REQ,
29162306a36Sopenharmony_ci				 PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
29262306a36Sopenharmony_ci		memset(req, 0, sizeof(*req));
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	c = &qos->freq.max_freq;
29662306a36Sopenharmony_ci	plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
29762306a36Sopenharmony_ci		apply_constraint(req, PM_QOS_REMOVE_REQ,
29862306a36Sopenharmony_ci				 PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
29962306a36Sopenharmony_ci		memset(req, 0, sizeof(*req));
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	f = &qos->flags;
30362306a36Sopenharmony_ci	list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
30462306a36Sopenharmony_ci		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
30562306a36Sopenharmony_ci		memset(req, 0, sizeof(*req));
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	spin_lock_irq(&dev->power.lock);
30962306a36Sopenharmony_ci	dev->power.qos = ERR_PTR(-ENODEV);
31062306a36Sopenharmony_ci	spin_unlock_irq(&dev->power.lock);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	kfree(qos->resume_latency.notifiers);
31362306a36Sopenharmony_ci	kfree(qos);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci out:
31662306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_sysfs_mtx);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic bool dev_pm_qos_invalid_req_type(struct device *dev,
32262306a36Sopenharmony_ci					enum dev_pm_qos_req_type type)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	return type == DEV_PM_QOS_LATENCY_TOLERANCE &&
32562306a36Sopenharmony_ci	       !dev->power.set_latency_tolerance;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int __dev_pm_qos_add_request(struct device *dev,
32962306a36Sopenharmony_ci				    struct dev_pm_qos_request *req,
33062306a36Sopenharmony_ci				    enum dev_pm_qos_req_type type, s32 value)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	int ret = 0;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (!dev || !req || dev_pm_qos_invalid_req_type(dev, type))
33562306a36Sopenharmony_ci		return -EINVAL;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (WARN(dev_pm_qos_request_active(req),
33862306a36Sopenharmony_ci		 "%s() called for already added request\n", __func__))
33962306a36Sopenharmony_ci		return -EINVAL;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (IS_ERR(dev->power.qos))
34262306a36Sopenharmony_ci		ret = -ENODEV;
34362306a36Sopenharmony_ci	else if (!dev->power.qos)
34462306a36Sopenharmony_ci		ret = dev_pm_qos_constraints_allocate(dev);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	trace_dev_pm_qos_add_request(dev_name(dev), type, value);
34762306a36Sopenharmony_ci	if (ret)
34862306a36Sopenharmony_ci		return ret;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	req->dev = dev;
35162306a36Sopenharmony_ci	req->type = type;
35262306a36Sopenharmony_ci	if (req->type == DEV_PM_QOS_MIN_FREQUENCY)
35362306a36Sopenharmony_ci		ret = freq_qos_add_request(&dev->power.qos->freq,
35462306a36Sopenharmony_ci					   &req->data.freq,
35562306a36Sopenharmony_ci					   FREQ_QOS_MIN, value);
35662306a36Sopenharmony_ci	else if (req->type == DEV_PM_QOS_MAX_FREQUENCY)
35762306a36Sopenharmony_ci		ret = freq_qos_add_request(&dev->power.qos->freq,
35862306a36Sopenharmony_ci					   &req->data.freq,
35962306a36Sopenharmony_ci					   FREQ_QOS_MAX, value);
36062306a36Sopenharmony_ci	else
36162306a36Sopenharmony_ci		ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return ret;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci/**
36762306a36Sopenharmony_ci * dev_pm_qos_add_request - inserts new qos request into the list
36862306a36Sopenharmony_ci * @dev: target device for the constraint
36962306a36Sopenharmony_ci * @req: pointer to a preallocated handle
37062306a36Sopenharmony_ci * @type: type of the request
37162306a36Sopenharmony_ci * @value: defines the qos request
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * This function inserts a new entry in the device constraints list of
37462306a36Sopenharmony_ci * requested qos performance characteristics. It recomputes the aggregate
37562306a36Sopenharmony_ci * QoS expectations of parameters and initializes the dev_pm_qos_request
37662306a36Sopenharmony_ci * handle.  Caller needs to save this handle for later use in updates and
37762306a36Sopenharmony_ci * removal.
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * Returns 1 if the aggregated constraint value has changed,
38062306a36Sopenharmony_ci * 0 if the aggregated constraint value has not changed,
38162306a36Sopenharmony_ci * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
38262306a36Sopenharmony_ci * to allocate for data structures, -ENODEV if the device has just been removed
38362306a36Sopenharmony_ci * from the system.
38462306a36Sopenharmony_ci *
38562306a36Sopenharmony_ci * Callers should ensure that the target device is not RPM_SUSPENDED before
38662306a36Sopenharmony_ci * using this function for requests of type DEV_PM_QOS_FLAGS.
38762306a36Sopenharmony_ci */
38862306a36Sopenharmony_ciint dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
38962306a36Sopenharmony_ci			   enum dev_pm_qos_req_type type, s32 value)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	int ret;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
39462306a36Sopenharmony_ci	ret = __dev_pm_qos_add_request(dev, req, type, value);
39562306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
39662306a36Sopenharmony_ci	return ret;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/**
40162306a36Sopenharmony_ci * __dev_pm_qos_update_request - Modify an existing device PM QoS request.
40262306a36Sopenharmony_ci * @req : PM QoS request to modify.
40362306a36Sopenharmony_ci * @new_value: New value to request.
40462306a36Sopenharmony_ci */
40562306a36Sopenharmony_cistatic int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
40662306a36Sopenharmony_ci				       s32 new_value)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	s32 curr_value;
40962306a36Sopenharmony_ci	int ret = 0;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (!req) /*guard against callers passing in null */
41262306a36Sopenharmony_ci		return -EINVAL;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (WARN(!dev_pm_qos_request_active(req),
41562306a36Sopenharmony_ci		 "%s() called for unknown object\n", __func__))
41662306a36Sopenharmony_ci		return -EINVAL;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(req->dev->power.qos))
41962306a36Sopenharmony_ci		return -ENODEV;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	switch(req->type) {
42262306a36Sopenharmony_ci	case DEV_PM_QOS_RESUME_LATENCY:
42362306a36Sopenharmony_ci	case DEV_PM_QOS_LATENCY_TOLERANCE:
42462306a36Sopenharmony_ci		curr_value = req->data.pnode.prio;
42562306a36Sopenharmony_ci		break;
42662306a36Sopenharmony_ci	case DEV_PM_QOS_MIN_FREQUENCY:
42762306a36Sopenharmony_ci	case DEV_PM_QOS_MAX_FREQUENCY:
42862306a36Sopenharmony_ci		curr_value = req->data.freq.pnode.prio;
42962306a36Sopenharmony_ci		break;
43062306a36Sopenharmony_ci	case DEV_PM_QOS_FLAGS:
43162306a36Sopenharmony_ci		curr_value = req->data.flr.flags;
43262306a36Sopenharmony_ci		break;
43362306a36Sopenharmony_ci	default:
43462306a36Sopenharmony_ci		return -EINVAL;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	trace_dev_pm_qos_update_request(dev_name(req->dev), req->type,
43862306a36Sopenharmony_ci					new_value);
43962306a36Sopenharmony_ci	if (curr_value != new_value)
44062306a36Sopenharmony_ci		ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return ret;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci/**
44662306a36Sopenharmony_ci * dev_pm_qos_update_request - modifies an existing qos request
44762306a36Sopenharmony_ci * @req : handle to list element holding a dev_pm_qos request to use
44862306a36Sopenharmony_ci * @new_value: defines the qos request
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * Updates an existing dev PM qos request along with updating the
45162306a36Sopenharmony_ci * target value.
45262306a36Sopenharmony_ci *
45362306a36Sopenharmony_ci * Attempts are made to make this code callable on hot code paths.
45462306a36Sopenharmony_ci *
45562306a36Sopenharmony_ci * Returns 1 if the aggregated constraint value has changed,
45662306a36Sopenharmony_ci * 0 if the aggregated constraint value has not changed,
45762306a36Sopenharmony_ci * -EINVAL in case of wrong parameters, -ENODEV if the device has been
45862306a36Sopenharmony_ci * removed from the system
45962306a36Sopenharmony_ci *
46062306a36Sopenharmony_ci * Callers should ensure that the target device is not RPM_SUSPENDED before
46162306a36Sopenharmony_ci * using this function for requests of type DEV_PM_QOS_FLAGS.
46262306a36Sopenharmony_ci */
46362306a36Sopenharmony_ciint dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	int ret;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
46862306a36Sopenharmony_ci	ret = __dev_pm_qos_update_request(req, new_value);
46962306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
47062306a36Sopenharmony_ci	return ret;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	int ret;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (!req) /*guard against callers passing in null */
47962306a36Sopenharmony_ci		return -EINVAL;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (WARN(!dev_pm_qos_request_active(req),
48262306a36Sopenharmony_ci		 "%s() called for unknown object\n", __func__))
48362306a36Sopenharmony_ci		return -EINVAL;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(req->dev->power.qos))
48662306a36Sopenharmony_ci		return -ENODEV;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type,
48962306a36Sopenharmony_ci					PM_QOS_DEFAULT_VALUE);
49062306a36Sopenharmony_ci	ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
49162306a36Sopenharmony_ci	memset(req, 0, sizeof(*req));
49262306a36Sopenharmony_ci	return ret;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci/**
49662306a36Sopenharmony_ci * dev_pm_qos_remove_request - modifies an existing qos request
49762306a36Sopenharmony_ci * @req: handle to request list element
49862306a36Sopenharmony_ci *
49962306a36Sopenharmony_ci * Will remove pm qos request from the list of constraints and
50062306a36Sopenharmony_ci * recompute the current target value. Call this on slow code paths.
50162306a36Sopenharmony_ci *
50262306a36Sopenharmony_ci * Returns 1 if the aggregated constraint value has changed,
50362306a36Sopenharmony_ci * 0 if the aggregated constraint value has not changed,
50462306a36Sopenharmony_ci * -EINVAL in case of wrong parameters, -ENODEV if the device has been
50562306a36Sopenharmony_ci * removed from the system
50662306a36Sopenharmony_ci *
50762306a36Sopenharmony_ci * Callers should ensure that the target device is not RPM_SUSPENDED before
50862306a36Sopenharmony_ci * using this function for requests of type DEV_PM_QOS_FLAGS.
50962306a36Sopenharmony_ci */
51062306a36Sopenharmony_ciint dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	int ret;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
51562306a36Sopenharmony_ci	ret = __dev_pm_qos_remove_request(req);
51662306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
51762306a36Sopenharmony_ci	return ret;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci/**
52262306a36Sopenharmony_ci * dev_pm_qos_add_notifier - sets notification entry for changes to target value
52362306a36Sopenharmony_ci * of per-device PM QoS constraints
52462306a36Sopenharmony_ci *
52562306a36Sopenharmony_ci * @dev: target device for the constraint
52662306a36Sopenharmony_ci * @notifier: notifier block managed by caller.
52762306a36Sopenharmony_ci * @type: request type.
52862306a36Sopenharmony_ci *
52962306a36Sopenharmony_ci * Will register the notifier into a notification chain that gets called
53062306a36Sopenharmony_ci * upon changes to the target value for the device.
53162306a36Sopenharmony_ci *
53262306a36Sopenharmony_ci * If the device's constraints object doesn't exist when this routine is called,
53362306a36Sopenharmony_ci * it will be created (or error code will be returned if that fails).
53462306a36Sopenharmony_ci */
53562306a36Sopenharmony_ciint dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
53662306a36Sopenharmony_ci			    enum dev_pm_qos_req_type type)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	int ret = 0;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (IS_ERR(dev->power.qos))
54362306a36Sopenharmony_ci		ret = -ENODEV;
54462306a36Sopenharmony_ci	else if (!dev->power.qos)
54562306a36Sopenharmony_ci		ret = dev_pm_qos_constraints_allocate(dev);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (ret)
54862306a36Sopenharmony_ci		goto unlock;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	switch (type) {
55162306a36Sopenharmony_ci	case DEV_PM_QOS_RESUME_LATENCY:
55262306a36Sopenharmony_ci		ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
55362306a36Sopenharmony_ci						       notifier);
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	case DEV_PM_QOS_MIN_FREQUENCY:
55662306a36Sopenharmony_ci		ret = freq_qos_add_notifier(&dev->power.qos->freq,
55762306a36Sopenharmony_ci					    FREQ_QOS_MIN, notifier);
55862306a36Sopenharmony_ci		break;
55962306a36Sopenharmony_ci	case DEV_PM_QOS_MAX_FREQUENCY:
56062306a36Sopenharmony_ci		ret = freq_qos_add_notifier(&dev->power.qos->freq,
56162306a36Sopenharmony_ci					    FREQ_QOS_MAX, notifier);
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	default:
56462306a36Sopenharmony_ci		WARN_ON(1);
56562306a36Sopenharmony_ci		ret = -EINVAL;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ciunlock:
56962306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
57062306a36Sopenharmony_ci	return ret;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci/**
57562306a36Sopenharmony_ci * dev_pm_qos_remove_notifier - deletes notification for changes to target value
57662306a36Sopenharmony_ci * of per-device PM QoS constraints
57762306a36Sopenharmony_ci *
57862306a36Sopenharmony_ci * @dev: target device for the constraint
57962306a36Sopenharmony_ci * @notifier: notifier block to be removed.
58062306a36Sopenharmony_ci * @type: request type.
58162306a36Sopenharmony_ci *
58262306a36Sopenharmony_ci * Will remove the notifier from the notification chain that gets called
58362306a36Sopenharmony_ci * upon changes to the target value.
58462306a36Sopenharmony_ci */
58562306a36Sopenharmony_ciint dev_pm_qos_remove_notifier(struct device *dev,
58662306a36Sopenharmony_ci			       struct notifier_block *notifier,
58762306a36Sopenharmony_ci			       enum dev_pm_qos_req_type type)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	int ret = 0;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* Silently return if the constraints object is not present. */
59462306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dev->power.qos))
59562306a36Sopenharmony_ci		goto unlock;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	switch (type) {
59862306a36Sopenharmony_ci	case DEV_PM_QOS_RESUME_LATENCY:
59962306a36Sopenharmony_ci		ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
60062306a36Sopenharmony_ci							 notifier);
60162306a36Sopenharmony_ci		break;
60262306a36Sopenharmony_ci	case DEV_PM_QOS_MIN_FREQUENCY:
60362306a36Sopenharmony_ci		ret = freq_qos_remove_notifier(&dev->power.qos->freq,
60462306a36Sopenharmony_ci					       FREQ_QOS_MIN, notifier);
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci	case DEV_PM_QOS_MAX_FREQUENCY:
60762306a36Sopenharmony_ci		ret = freq_qos_remove_notifier(&dev->power.qos->freq,
60862306a36Sopenharmony_ci					       FREQ_QOS_MAX, notifier);
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci	default:
61162306a36Sopenharmony_ci		WARN_ON(1);
61262306a36Sopenharmony_ci		ret = -EINVAL;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ciunlock:
61662306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
61762306a36Sopenharmony_ci	return ret;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci/**
62262306a36Sopenharmony_ci * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
62362306a36Sopenharmony_ci * @dev: Device whose ancestor to add the request for.
62462306a36Sopenharmony_ci * @req: Pointer to the preallocated handle.
62562306a36Sopenharmony_ci * @type: Type of the request.
62662306a36Sopenharmony_ci * @value: Constraint latency value.
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_ciint dev_pm_qos_add_ancestor_request(struct device *dev,
62962306a36Sopenharmony_ci				    struct dev_pm_qos_request *req,
63062306a36Sopenharmony_ci				    enum dev_pm_qos_req_type type, s32 value)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct device *ancestor = dev->parent;
63362306a36Sopenharmony_ci	int ret = -ENODEV;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	switch (type) {
63662306a36Sopenharmony_ci	case DEV_PM_QOS_RESUME_LATENCY:
63762306a36Sopenharmony_ci		while (ancestor && !ancestor->power.ignore_children)
63862306a36Sopenharmony_ci			ancestor = ancestor->parent;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci		break;
64162306a36Sopenharmony_ci	case DEV_PM_QOS_LATENCY_TOLERANCE:
64262306a36Sopenharmony_ci		while (ancestor && !ancestor->power.set_latency_tolerance)
64362306a36Sopenharmony_ci			ancestor = ancestor->parent;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci	default:
64762306a36Sopenharmony_ci		ancestor = NULL;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci	if (ancestor)
65062306a36Sopenharmony_ci		ret = dev_pm_qos_add_request(ancestor, req, type, value);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (ret < 0)
65362306a36Sopenharmony_ci		req->dev = NULL;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	return ret;
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic void __dev_pm_qos_drop_user_request(struct device *dev,
66062306a36Sopenharmony_ci					   enum dev_pm_qos_req_type type)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct dev_pm_qos_request *req = NULL;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	switch(type) {
66562306a36Sopenharmony_ci	case DEV_PM_QOS_RESUME_LATENCY:
66662306a36Sopenharmony_ci		req = dev->power.qos->resume_latency_req;
66762306a36Sopenharmony_ci		dev->power.qos->resume_latency_req = NULL;
66862306a36Sopenharmony_ci		break;
66962306a36Sopenharmony_ci	case DEV_PM_QOS_LATENCY_TOLERANCE:
67062306a36Sopenharmony_ci		req = dev->power.qos->latency_tolerance_req;
67162306a36Sopenharmony_ci		dev->power.qos->latency_tolerance_req = NULL;
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci	case DEV_PM_QOS_FLAGS:
67462306a36Sopenharmony_ci		req = dev->power.qos->flags_req;
67562306a36Sopenharmony_ci		dev->power.qos->flags_req = NULL;
67662306a36Sopenharmony_ci		break;
67762306a36Sopenharmony_ci	default:
67862306a36Sopenharmony_ci		WARN_ON(1);
67962306a36Sopenharmony_ci		return;
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci	__dev_pm_qos_remove_request(req);
68262306a36Sopenharmony_ci	kfree(req);
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic void dev_pm_qos_drop_user_request(struct device *dev,
68662306a36Sopenharmony_ci					 enum dev_pm_qos_req_type type)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
68962306a36Sopenharmony_ci	__dev_pm_qos_drop_user_request(dev, type);
69062306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci/**
69462306a36Sopenharmony_ci * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
69562306a36Sopenharmony_ci * @dev: Device whose PM QoS latency limit is to be exposed to user space.
69662306a36Sopenharmony_ci * @value: Initial value of the latency limit.
69762306a36Sopenharmony_ci */
69862306a36Sopenharmony_ciint dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct dev_pm_qos_request *req;
70162306a36Sopenharmony_ci	int ret;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	if (!device_is_registered(dev) || value < 0)
70462306a36Sopenharmony_ci		return -EINVAL;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), GFP_KERNEL);
70762306a36Sopenharmony_ci	if (!req)
70862306a36Sopenharmony_ci		return -ENOMEM;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_RESUME_LATENCY, value);
71162306a36Sopenharmony_ci	if (ret < 0) {
71262306a36Sopenharmony_ci		kfree(req);
71362306a36Sopenharmony_ci		return ret;
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_sysfs_mtx);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dev->power.qos))
72162306a36Sopenharmony_ci		ret = -ENODEV;
72262306a36Sopenharmony_ci	else if (dev->power.qos->resume_latency_req)
72362306a36Sopenharmony_ci		ret = -EEXIST;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (ret < 0) {
72662306a36Sopenharmony_ci		__dev_pm_qos_remove_request(req);
72762306a36Sopenharmony_ci		kfree(req);
72862306a36Sopenharmony_ci		mutex_unlock(&dev_pm_qos_mtx);
72962306a36Sopenharmony_ci		goto out;
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci	dev->power.qos->resume_latency_req = req;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	ret = pm_qos_sysfs_add_resume_latency(dev);
73662306a36Sopenharmony_ci	if (ret)
73762306a36Sopenharmony_ci		dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci out:
74062306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_sysfs_mtx);
74162306a36Sopenharmony_ci	return ret;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic void __dev_pm_qos_hide_latency_limit(struct device *dev)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->resume_latency_req)
74862306a36Sopenharmony_ci		__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci/**
75262306a36Sopenharmony_ci * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
75362306a36Sopenharmony_ci * @dev: Device whose PM QoS latency limit is to be hidden from user space.
75462306a36Sopenharmony_ci */
75562306a36Sopenharmony_civoid dev_pm_qos_hide_latency_limit(struct device *dev)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_sysfs_mtx);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	pm_qos_sysfs_remove_resume_latency(dev);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
76262306a36Sopenharmony_ci	__dev_pm_qos_hide_latency_limit(dev);
76362306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_sysfs_mtx);
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci/**
77062306a36Sopenharmony_ci * dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space.
77162306a36Sopenharmony_ci * @dev: Device whose PM QoS flags are to be exposed to user space.
77262306a36Sopenharmony_ci * @val: Initial values of the flags.
77362306a36Sopenharmony_ci */
77462306a36Sopenharmony_ciint dev_pm_qos_expose_flags(struct device *dev, s32 val)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	struct dev_pm_qos_request *req;
77762306a36Sopenharmony_ci	int ret;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (!device_is_registered(dev))
78062306a36Sopenharmony_ci		return -EINVAL;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), GFP_KERNEL);
78362306a36Sopenharmony_ci	if (!req)
78462306a36Sopenharmony_ci		return -ENOMEM;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val);
78762306a36Sopenharmony_ci	if (ret < 0) {
78862306a36Sopenharmony_ci		kfree(req);
78962306a36Sopenharmony_ci		return ret;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
79362306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_sysfs_mtx);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dev->power.qos))
79862306a36Sopenharmony_ci		ret = -ENODEV;
79962306a36Sopenharmony_ci	else if (dev->power.qos->flags_req)
80062306a36Sopenharmony_ci		ret = -EEXIST;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (ret < 0) {
80362306a36Sopenharmony_ci		__dev_pm_qos_remove_request(req);
80462306a36Sopenharmony_ci		kfree(req);
80562306a36Sopenharmony_ci		mutex_unlock(&dev_pm_qos_mtx);
80662306a36Sopenharmony_ci		goto out;
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci	dev->power.qos->flags_req = req;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	ret = pm_qos_sysfs_add_flags(dev);
81362306a36Sopenharmony_ci	if (ret)
81462306a36Sopenharmony_ci		dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci out:
81762306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_sysfs_mtx);
81862306a36Sopenharmony_ci	pm_runtime_put(dev);
81962306a36Sopenharmony_ci	return ret;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic void __dev_pm_qos_hide_flags(struct device *dev)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)
82662306a36Sopenharmony_ci		__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci/**
83062306a36Sopenharmony_ci * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space.
83162306a36Sopenharmony_ci * @dev: Device whose PM QoS flags are to be hidden from user space.
83262306a36Sopenharmony_ci */
83362306a36Sopenharmony_civoid dev_pm_qos_hide_flags(struct device *dev)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
83662306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_sysfs_mtx);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	pm_qos_sysfs_remove_flags(dev);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
84162306a36Sopenharmony_ci	__dev_pm_qos_hide_flags(dev);
84262306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_sysfs_mtx);
84562306a36Sopenharmony_ci	pm_runtime_put(dev);
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci/**
85062306a36Sopenharmony_ci * dev_pm_qos_update_flags - Update PM QoS flags request owned by user space.
85162306a36Sopenharmony_ci * @dev: Device to update the PM QoS flags request for.
85262306a36Sopenharmony_ci * @mask: Flags to set/clear.
85362306a36Sopenharmony_ci * @set: Whether to set or clear the flags (true means set).
85462306a36Sopenharmony_ci */
85562306a36Sopenharmony_ciint dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	s32 value;
85862306a36Sopenharmony_ci	int ret;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
86162306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dev->power.qos) || !dev->power.qos->flags_req) {
86462306a36Sopenharmony_ci		ret = -EINVAL;
86562306a36Sopenharmony_ci		goto out;
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	value = dev_pm_qos_requested_flags(dev);
86962306a36Sopenharmony_ci	if (set)
87062306a36Sopenharmony_ci		value |= mask;
87162306a36Sopenharmony_ci	else
87262306a36Sopenharmony_ci		value &= ~mask;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci out:
87762306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
87862306a36Sopenharmony_ci	pm_runtime_put(dev);
87962306a36Sopenharmony_ci	return ret;
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci/**
88362306a36Sopenharmony_ci * dev_pm_qos_get_user_latency_tolerance - Get user space latency tolerance.
88462306a36Sopenharmony_ci * @dev: Device to obtain the user space latency tolerance for.
88562306a36Sopenharmony_ci */
88662306a36Sopenharmony_cis32 dev_pm_qos_get_user_latency_tolerance(struct device *dev)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	s32 ret;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
89162306a36Sopenharmony_ci	ret = IS_ERR_OR_NULL(dev->power.qos)
89262306a36Sopenharmony_ci		|| !dev->power.qos->latency_tolerance_req ?
89362306a36Sopenharmony_ci			PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
89462306a36Sopenharmony_ci			dev->power.qos->latency_tolerance_req->data.pnode.prio;
89562306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
89662306a36Sopenharmony_ci	return ret;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci/**
90062306a36Sopenharmony_ci * dev_pm_qos_update_user_latency_tolerance - Update user space latency tolerance.
90162306a36Sopenharmony_ci * @dev: Device to update the user space latency tolerance for.
90262306a36Sopenharmony_ci * @val: New user space latency tolerance for @dev (negative values disable).
90362306a36Sopenharmony_ci */
90462306a36Sopenharmony_ciint dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	int ret;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_mtx);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dev->power.qos)
91162306a36Sopenharmony_ci	    || !dev->power.qos->latency_tolerance_req) {
91262306a36Sopenharmony_ci		struct dev_pm_qos_request *req;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		if (val < 0) {
91562306a36Sopenharmony_ci			if (val == PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT)
91662306a36Sopenharmony_ci				ret = 0;
91762306a36Sopenharmony_ci			else
91862306a36Sopenharmony_ci				ret = -EINVAL;
91962306a36Sopenharmony_ci			goto out;
92062306a36Sopenharmony_ci		}
92162306a36Sopenharmony_ci		req = kzalloc(sizeof(*req), GFP_KERNEL);
92262306a36Sopenharmony_ci		if (!req) {
92362306a36Sopenharmony_ci			ret = -ENOMEM;
92462306a36Sopenharmony_ci			goto out;
92562306a36Sopenharmony_ci		}
92662306a36Sopenharmony_ci		ret = __dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY_TOLERANCE, val);
92762306a36Sopenharmony_ci		if (ret < 0) {
92862306a36Sopenharmony_ci			kfree(req);
92962306a36Sopenharmony_ci			goto out;
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci		dev->power.qos->latency_tolerance_req = req;
93262306a36Sopenharmony_ci	} else {
93362306a36Sopenharmony_ci		if (val < 0) {
93462306a36Sopenharmony_ci			__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY_TOLERANCE);
93562306a36Sopenharmony_ci			ret = 0;
93662306a36Sopenharmony_ci		} else {
93762306a36Sopenharmony_ci			ret = __dev_pm_qos_update_request(dev->power.qos->latency_tolerance_req, val);
93862306a36Sopenharmony_ci		}
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci out:
94262306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_mtx);
94362306a36Sopenharmony_ci	return ret;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_update_user_latency_tolerance);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci/**
94862306a36Sopenharmony_ci * dev_pm_qos_expose_latency_tolerance - Expose latency tolerance to userspace
94962306a36Sopenharmony_ci * @dev: Device whose latency tolerance to expose
95062306a36Sopenharmony_ci */
95162306a36Sopenharmony_ciint dev_pm_qos_expose_latency_tolerance(struct device *dev)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	int ret;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!dev->power.set_latency_tolerance)
95662306a36Sopenharmony_ci		return -EINVAL;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_sysfs_mtx);
95962306a36Sopenharmony_ci	ret = pm_qos_sysfs_add_latency_tolerance(dev);
96062306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_sysfs_mtx);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	return ret;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_tolerance);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci/**
96762306a36Sopenharmony_ci * dev_pm_qos_hide_latency_tolerance - Hide latency tolerance from userspace
96862306a36Sopenharmony_ci * @dev: Device whose latency tolerance to hide
96962306a36Sopenharmony_ci */
97062306a36Sopenharmony_civoid dev_pm_qos_hide_latency_tolerance(struct device *dev)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	mutex_lock(&dev_pm_qos_sysfs_mtx);
97362306a36Sopenharmony_ci	pm_qos_sysfs_remove_latency_tolerance(dev);
97462306a36Sopenharmony_ci	mutex_unlock(&dev_pm_qos_sysfs_mtx);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	/* Remove the request from user space now */
97762306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
97862306a36Sopenharmony_ci	dev_pm_qos_update_user_latency_tolerance(dev,
97962306a36Sopenharmony_ci		PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT);
98062306a36Sopenharmony_ci	pm_runtime_put(dev);
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_tolerance);
983