xref: /openbmc/linux/kernel/power/qos.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e8db0be1SJean Pihet /*
3fe52de36SRafael J. Wysocki  * Power Management Quality of Service (PM QoS) support base.
4e8db0be1SJean Pihet  *
5fe52de36SRafael J. Wysocki  * Copyright (C) 2020 Intel Corporation
6e8db0be1SJean Pihet  *
7fe52de36SRafael J. Wysocki  * Authors:
8e8db0be1SJean Pihet  *	Mark Gross <mgross@linux.intel.com>
9fe52de36SRafael J. Wysocki  *	Rafael J. Wysocki <rafael.j.wysocki@intel.com>
10fe52de36SRafael J. Wysocki  *
11fe52de36SRafael J. Wysocki  * Provided here is an interface for specifying PM QoS dependencies.  It allows
12fe52de36SRafael J. Wysocki  * entities depending on QoS constraints to register their requests which are
13fe52de36SRafael J. Wysocki  * aggregated as appropriate to produce effective constraints (target values)
14fe52de36SRafael J. Wysocki  * that can be monitored by entities needing to respect them, either by polling
15fe52de36SRafael J. Wysocki  * or through a built-in notification mechanism.
16fe52de36SRafael J. Wysocki  *
17fe52de36SRafael J. Wysocki  * In addition to the basic functionality, more specific interfaces for managing
18fe52de36SRafael J. Wysocki  * global CPU latency QoS requests and frequency QoS requests are provided.
19e8db0be1SJean Pihet  */
20e8db0be1SJean Pihet 
21e8db0be1SJean Pihet /*#define DEBUG*/
22e8db0be1SJean Pihet 
23e8db0be1SJean Pihet #include <linux/pm_qos.h>
24e8db0be1SJean Pihet #include <linux/sched.h>
25e8db0be1SJean Pihet #include <linux/spinlock.h>
26e8db0be1SJean Pihet #include <linux/slab.h>
27e8db0be1SJean Pihet #include <linux/time.h>
28e8db0be1SJean Pihet #include <linux/fs.h>
29e8db0be1SJean Pihet #include <linux/device.h>
30e8db0be1SJean Pihet #include <linux/miscdevice.h>
31e8db0be1SJean Pihet #include <linux/string.h>
32e8db0be1SJean Pihet #include <linux/platform_device.h>
33e8db0be1SJean Pihet #include <linux/init.h>
34e8db0be1SJean Pihet #include <linux/kernel.h>
35f5f4eda4SNishanth Menon #include <linux/debugfs.h>
36f5f4eda4SNishanth Menon #include <linux/seq_file.h>
37e8db0be1SJean Pihet 
38e8db0be1SJean Pihet #include <linux/uaccess.h>
396e5fdeedSPaul Gortmaker #include <linux/export.h>
40247e9ee0SSahara #include <trace/events/power.h>
41e8db0be1SJean Pihet 
42e8db0be1SJean Pihet /*
43cc749986SJean Pihet  * locking rule: all changes to constraints or notifiers lists
44e8db0be1SJean Pihet  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
45e8db0be1SJean Pihet  * held, taken with _irqsave.  One lock to rule them all
46e8db0be1SJean Pihet  */
47e8db0be1SJean Pihet static DEFINE_SPINLOCK(pm_qos_lock);
48e8db0be1SJean Pihet 
49dcd70ca1SRafael J. Wysocki /**
50dcd70ca1SRafael J. Wysocki  * pm_qos_read_value - Return the current effective constraint value.
51dcd70ca1SRafael J. Wysocki  * @c: List of PM QoS constraint requests.
52dcd70ca1SRafael J. Wysocki  */
pm_qos_read_value(struct pm_qos_constraints * c)53dcd70ca1SRafael J. Wysocki s32 pm_qos_read_value(struct pm_qos_constraints *c)
54dcd70ca1SRafael J. Wysocki {
55a534e924SQian Cai 	return READ_ONCE(c->target_value);
56dcd70ca1SRafael J. Wysocki }
57dcd70ca1SRafael J. Wysocki 
pm_qos_get_value(struct pm_qos_constraints * c)58dcd70ca1SRafael J. Wysocki static int pm_qos_get_value(struct pm_qos_constraints *c)
59e8db0be1SJean Pihet {
60abe98ec2SJean Pihet 	if (plist_head_empty(&c->list))
61327adaedSRafael J. Wysocki 		return c->no_constraint_value;
62e8db0be1SJean Pihet 
63abe98ec2SJean Pihet 	switch (c->type) {
64e8db0be1SJean Pihet 	case PM_QOS_MIN:
65abe98ec2SJean Pihet 		return plist_first(&c->list)->prio;
66e8db0be1SJean Pihet 
67e8db0be1SJean Pihet 	case PM_QOS_MAX:
68abe98ec2SJean Pihet 		return plist_last(&c->list)->prio;
69e8db0be1SJean Pihet 
70e8db0be1SJean Pihet 	default:
71dcd70ca1SRafael J. Wysocki 		WARN(1, "Unknown PM QoS type in %s\n", __func__);
72c6a57bffSLuis Gonzalez Fernandez 		return PM_QOS_DEFAULT_VALUE;
73e8db0be1SJean Pihet 	}
74e8db0be1SJean Pihet }
75e8db0be1SJean Pihet 
pm_qos_set_value(struct pm_qos_constraints * c,s32 value)76dcd70ca1SRafael J. Wysocki static void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
77e8db0be1SJean Pihet {
78a534e924SQian Cai 	WRITE_ONCE(c->target_value, value);
79e8db0be1SJean Pihet }
80e8db0be1SJean Pihet 
81abe98ec2SJean Pihet /**
827b35370bSRafael J. Wysocki  * pm_qos_update_target - Update a list of PM QoS constraint requests.
837b35370bSRafael J. Wysocki  * @c: List of PM QoS requests.
847b35370bSRafael J. Wysocki  * @node: Target list entry.
857b35370bSRafael J. Wysocki  * @action: Action to carry out (add, update or remove).
867b35370bSRafael J. Wysocki  * @value: New request value for the target list entry.
87abe98ec2SJean Pihet  *
887b35370bSRafael J. Wysocki  * Update the given list of PM QoS constraint requests, @c, by carrying an
897b35370bSRafael J. Wysocki  * @action involving the @node list entry and @value on it.
907b35370bSRafael J. Wysocki  *
917b35370bSRafael J. Wysocki  * The recognized values of @action are PM_QOS_ADD_REQ (store @value in @node
927b35370bSRafael J. Wysocki  * and add it to the list), PM_QOS_UPDATE_REQ (remove @node from the list, store
937b35370bSRafael J. Wysocki  * @value in it and add it to the list again), and PM_QOS_REMOVE_REQ (remove
947b35370bSRafael J. Wysocki  * @node from the list, ignore @value).
957b35370bSRafael J. Wysocki  *
967b35370bSRafael J. Wysocki  * Return: 1 if the aggregate constraint value has changed, 0  otherwise.
97abe98ec2SJean Pihet  */
pm_qos_update_target(struct pm_qos_constraints * c,struct plist_node * node,enum pm_qos_req_action action,int value)98abe98ec2SJean Pihet int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
99abe98ec2SJean Pihet 			 enum pm_qos_req_action action, int value)
100e8db0be1SJean Pihet {
101abe98ec2SJean Pihet 	int prev_value, curr_value, new_value;
1027b35370bSRafael J. Wysocki 	unsigned long flags;
103e8db0be1SJean Pihet 
104e8db0be1SJean Pihet 	spin_lock_irqsave(&pm_qos_lock, flags);
1057b35370bSRafael J. Wysocki 
106abe98ec2SJean Pihet 	prev_value = pm_qos_get_value(c);
107abe98ec2SJean Pihet 	if (value == PM_QOS_DEFAULT_VALUE)
108abe98ec2SJean Pihet 		new_value = c->default_value;
109abe98ec2SJean Pihet 	else
110abe98ec2SJean Pihet 		new_value = value;
111abe98ec2SJean Pihet 
112abe98ec2SJean Pihet 	switch (action) {
113abe98ec2SJean Pihet 	case PM_QOS_REMOVE_REQ:
114abe98ec2SJean Pihet 		plist_del(node, &c->list);
115abe98ec2SJean Pihet 		break;
116abe98ec2SJean Pihet 	case PM_QOS_UPDATE_REQ:
117e8db0be1SJean Pihet 		/*
1187b35370bSRafael J. Wysocki 		 * To change the list, atomically remove, reinit with new value
1197b35370bSRafael J. Wysocki 		 * and add, then see if the aggregate has changed.
120e8db0be1SJean Pihet 		 */
121abe98ec2SJean Pihet 		plist_del(node, &c->list);
122df561f66SGustavo A. R. Silva 		fallthrough;
123abe98ec2SJean Pihet 	case PM_QOS_ADD_REQ:
124abe98ec2SJean Pihet 		plist_node_init(node, new_value);
125abe98ec2SJean Pihet 		plist_add(node, &c->list);
126abe98ec2SJean Pihet 		break;
127abe98ec2SJean Pihet 	default:
128abe98ec2SJean Pihet 		/* no action */
129abe98ec2SJean Pihet 		;
130e8db0be1SJean Pihet 	}
131abe98ec2SJean Pihet 
132abe98ec2SJean Pihet 	curr_value = pm_qos_get_value(c);
133abe98ec2SJean Pihet 	pm_qos_set_value(c, curr_value);
134abe98ec2SJean Pihet 
135e8db0be1SJean Pihet 	spin_unlock_irqrestore(&pm_qos_lock, flags);
136e8db0be1SJean Pihet 
137247e9ee0SSahara 	trace_pm_qos_update_target(action, prev_value, curr_value);
1387b35370bSRafael J. Wysocki 
1397b35370bSRafael J. Wysocki 	if (prev_value == curr_value)
1407b35370bSRafael J. Wysocki 		return 0;
1417b35370bSRafael J. Wysocki 
1422d984ad1SRafael J. Wysocki 	if (c->notifiers)
1437b35370bSRafael J. Wysocki 		blocking_notifier_call_chain(c->notifiers, curr_value, NULL);
1447b35370bSRafael J. Wysocki 
1457b35370bSRafael J. Wysocki 	return 1;
146e8db0be1SJean Pihet }
147e8db0be1SJean Pihet 
148e8db0be1SJean Pihet /**
1495efbe427SRafael J. Wysocki  * pm_qos_flags_remove_req - Remove device PM QoS flags request.
1505efbe427SRafael J. Wysocki  * @pqf: Device PM QoS flags set to remove the request from.
1515efbe427SRafael J. Wysocki  * @req: Request to remove from the set.
1525efbe427SRafael J. Wysocki  */
pm_qos_flags_remove_req(struct pm_qos_flags * pqf,struct pm_qos_flags_request * req)1535efbe427SRafael J. Wysocki static void pm_qos_flags_remove_req(struct pm_qos_flags *pqf,
1545efbe427SRafael J. Wysocki 				    struct pm_qos_flags_request *req)
1555efbe427SRafael J. Wysocki {
1565efbe427SRafael J. Wysocki 	s32 val = 0;
1575efbe427SRafael J. Wysocki 
1585efbe427SRafael J. Wysocki 	list_del(&req->node);
1595efbe427SRafael J. Wysocki 	list_for_each_entry(req, &pqf->list, node)
1605efbe427SRafael J. Wysocki 		val |= req->flags;
1615efbe427SRafael J. Wysocki 
1625efbe427SRafael J. Wysocki 	pqf->effective_flags = val;
1635efbe427SRafael J. Wysocki }
1645efbe427SRafael J. Wysocki 
1655efbe427SRafael J. Wysocki /**
1665efbe427SRafael J. Wysocki  * pm_qos_update_flags - Update a set of PM QoS flags.
1677b35370bSRafael J. Wysocki  * @pqf: Set of PM QoS flags to update.
1685efbe427SRafael J. Wysocki  * @req: Request to add to the set, to modify, or to remove from the set.
1695efbe427SRafael J. Wysocki  * @action: Action to take on the set.
1705efbe427SRafael J. Wysocki  * @val: Value of the request to add or modify.
1715efbe427SRafael J. Wysocki  *
1727b35370bSRafael J. Wysocki  * Return: 1 if the aggregate constraint value has changed, 0 otherwise.
1735efbe427SRafael J. Wysocki  */
pm_qos_update_flags(struct pm_qos_flags * pqf,struct pm_qos_flags_request * req,enum pm_qos_req_action action,s32 val)1745efbe427SRafael J. Wysocki bool pm_qos_update_flags(struct pm_qos_flags *pqf,
1755efbe427SRafael J. Wysocki 			 struct pm_qos_flags_request *req,
1765efbe427SRafael J. Wysocki 			 enum pm_qos_req_action action, s32 val)
1775efbe427SRafael J. Wysocki {
1785efbe427SRafael J. Wysocki 	unsigned long irqflags;
1795efbe427SRafael J. Wysocki 	s32 prev_value, curr_value;
1805efbe427SRafael J. Wysocki 
1815efbe427SRafael J. Wysocki 	spin_lock_irqsave(&pm_qos_lock, irqflags);
1825efbe427SRafael J. Wysocki 
1835efbe427SRafael J. Wysocki 	prev_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
1845efbe427SRafael J. Wysocki 
1855efbe427SRafael J. Wysocki 	switch (action) {
1865efbe427SRafael J. Wysocki 	case PM_QOS_REMOVE_REQ:
1875efbe427SRafael J. Wysocki 		pm_qos_flags_remove_req(pqf, req);
1885efbe427SRafael J. Wysocki 		break;
1895efbe427SRafael J. Wysocki 	case PM_QOS_UPDATE_REQ:
1905efbe427SRafael J. Wysocki 		pm_qos_flags_remove_req(pqf, req);
191df561f66SGustavo A. R. Silva 		fallthrough;
1925efbe427SRafael J. Wysocki 	case PM_QOS_ADD_REQ:
1935efbe427SRafael J. Wysocki 		req->flags = val;
1945efbe427SRafael J. Wysocki 		INIT_LIST_HEAD(&req->node);
1955efbe427SRafael J. Wysocki 		list_add_tail(&req->node, &pqf->list);
1965efbe427SRafael J. Wysocki 		pqf->effective_flags |= val;
1975efbe427SRafael J. Wysocki 		break;
1985efbe427SRafael J. Wysocki 	default:
1995efbe427SRafael J. Wysocki 		/* no action */
2005efbe427SRafael J. Wysocki 		;
2015efbe427SRafael J. Wysocki 	}
2025efbe427SRafael J. Wysocki 
2035efbe427SRafael J. Wysocki 	curr_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
2045efbe427SRafael J. Wysocki 
2055efbe427SRafael J. Wysocki 	spin_unlock_irqrestore(&pm_qos_lock, irqflags);
2065efbe427SRafael J. Wysocki 
207247e9ee0SSahara 	trace_pm_qos_update_flags(action, prev_value, curr_value);
2087b35370bSRafael J. Wysocki 
2095efbe427SRafael J. Wysocki 	return prev_value != curr_value;
2105efbe427SRafael J. Wysocki }
2115efbe427SRafael J. Wysocki 
212814d51f8SRafael J. Wysocki #ifdef CONFIG_CPU_IDLE
2132552d352SRafael J. Wysocki /* Definitions related to the CPU latency QoS. */
2142552d352SRafael J. Wysocki 
2152552d352SRafael J. Wysocki static struct pm_qos_constraints cpu_latency_constraints = {
2162552d352SRafael J. Wysocki 	.list = PLIST_HEAD_INIT(cpu_latency_constraints.list),
2172552d352SRafael J. Wysocki 	.target_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
2182552d352SRafael J. Wysocki 	.default_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
2192552d352SRafael J. Wysocki 	.no_constraint_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
2202552d352SRafael J. Wysocki 	.type = PM_QOS_MIN,
2212552d352SRafael J. Wysocki };
2222552d352SRafael J. Wysocki 
cpu_latency_qos_value_invalid(s32 value)223*5f55836aSClive Lin static inline bool cpu_latency_qos_value_invalid(s32 value)
224*5f55836aSClive Lin {
225*5f55836aSClive Lin 	return value < 0 && value != PM_QOS_DEFAULT_VALUE;
226*5f55836aSClive Lin }
227*5f55836aSClive Lin 
2285efbe427SRafael J. Wysocki /**
22967b06ba0SRafael J. Wysocki  * cpu_latency_qos_limit - Return current system-wide CPU latency QoS limit.
230e8db0be1SJean Pihet  */
cpu_latency_qos_limit(void)23167b06ba0SRafael J. Wysocki s32 cpu_latency_qos_limit(void)
232e8db0be1SJean Pihet {
2332552d352SRafael J. Wysocki 	return pm_qos_read_value(&cpu_latency_constraints);
234e8db0be1SJean Pihet }
235e8db0be1SJean Pihet 
23667b06ba0SRafael J. Wysocki /**
23767b06ba0SRafael J. Wysocki  * cpu_latency_qos_request_active - Check the given PM QoS request.
23867b06ba0SRafael J. Wysocki  * @req: PM QoS request to check.
23967b06ba0SRafael J. Wysocki  *
24067b06ba0SRafael J. Wysocki  * Return: 'true' if @req has been added to the CPU latency QoS list, 'false'
24167b06ba0SRafael J. Wysocki  * otherwise.
24267b06ba0SRafael J. Wysocki  */
cpu_latency_qos_request_active(struct pm_qos_request * req)24367b06ba0SRafael J. Wysocki bool cpu_latency_qos_request_active(struct pm_qos_request *req)
244e8db0be1SJean Pihet {
2452552d352SRafael J. Wysocki 	return req->qos == &cpu_latency_constraints;
246e8db0be1SJean Pihet }
24767b06ba0SRafael J. Wysocki EXPORT_SYMBOL_GPL(cpu_latency_qos_request_active);
248e8db0be1SJean Pihet 
cpu_latency_qos_apply(struct pm_qos_request * req,enum pm_qos_req_action action,s32 value)249333eed7dSRafael J. Wysocki static void cpu_latency_qos_apply(struct pm_qos_request *req,
2503a4a0042SRafael J. Wysocki 				  enum pm_qos_req_action action, s32 value)
2513a4a0042SRafael J. Wysocki {
2523a4a0042SRafael J. Wysocki 	int ret = pm_qos_update_target(req->qos, &req->node, action, value);
2533a4a0042SRafael J. Wysocki 	if (ret > 0)
2543a4a0042SRafael J. Wysocki 		wake_up_all_idle_cpus();
2553a4a0042SRafael J. Wysocki }
2563a4a0042SRafael J. Wysocki 
257e8db0be1SJean Pihet /**
25867b06ba0SRafael J. Wysocki  * cpu_latency_qos_add_request - Add new CPU latency QoS request.
25967b06ba0SRafael J. Wysocki  * @req: Pointer to a preallocated handle.
26067b06ba0SRafael J. Wysocki  * @value: Requested constraint value.
261e8db0be1SJean Pihet  *
26267b06ba0SRafael J. Wysocki  * Use @value to initialize the request handle pointed to by @req, insert it as
26367b06ba0SRafael J. Wysocki  * a new entry to the CPU latency QoS list and recompute the effective QoS
26467b06ba0SRafael J. Wysocki  * constraint for that list.
26567b06ba0SRafael J. Wysocki  *
26667b06ba0SRafael J. Wysocki  * Callers need to save the handle for later use in updates and removal of the
26767b06ba0SRafael J. Wysocki  * QoS request represented by it.
268e8db0be1SJean Pihet  */
cpu_latency_qos_add_request(struct pm_qos_request * req,s32 value)26967b06ba0SRafael J. Wysocki void cpu_latency_qos_add_request(struct pm_qos_request *req, s32 value)
270e8db0be1SJean Pihet {
271*5f55836aSClive Lin 	if (!req || cpu_latency_qos_value_invalid(value))
272abe98ec2SJean Pihet 		return;
273e8db0be1SJean Pihet 
27467b06ba0SRafael J. Wysocki 	if (cpu_latency_qos_request_active(req)) {
27567b06ba0SRafael J. Wysocki 		WARN(1, KERN_ERR "%s called for already added request\n", __func__);
276e8db0be1SJean Pihet 		return;
277e8db0be1SJean Pihet 	}
27802c92a37SRafael J. Wysocki 
279333eed7dSRafael J. Wysocki 	trace_pm_qos_add_request(value);
28002c92a37SRafael J. Wysocki 
2812552d352SRafael J. Wysocki 	req->qos = &cpu_latency_constraints;
282333eed7dSRafael J. Wysocki 	cpu_latency_qos_apply(req, PM_QOS_ADD_REQ, value);
283e8db0be1SJean Pihet }
28467b06ba0SRafael J. Wysocki EXPORT_SYMBOL_GPL(cpu_latency_qos_add_request);
285e8db0be1SJean Pihet 
286e8db0be1SJean Pihet /**
28767b06ba0SRafael J. Wysocki  * cpu_latency_qos_update_request - Modify existing CPU latency QoS request.
28867b06ba0SRafael J. Wysocki  * @req : QoS request to update.
28967b06ba0SRafael J. Wysocki  * @new_value: New requested constraint value.
290e8db0be1SJean Pihet  *
29167b06ba0SRafael J. Wysocki  * Use @new_value to update the QoS request represented by @req in the CPU
29267b06ba0SRafael J. Wysocki  * latency QoS list along with updating the effective constraint value for that
29367b06ba0SRafael J. Wysocki  * list.
294e8db0be1SJean Pihet  */
cpu_latency_qos_update_request(struct pm_qos_request * req,s32 new_value)29567b06ba0SRafael J. Wysocki void cpu_latency_qos_update_request(struct pm_qos_request *req, s32 new_value)
296e8db0be1SJean Pihet {
297*5f55836aSClive Lin 	if (!req || cpu_latency_qos_value_invalid(new_value))
298e8db0be1SJean Pihet 		return;
299e8db0be1SJean Pihet 
30067b06ba0SRafael J. Wysocki 	if (!cpu_latency_qos_request_active(req)) {
30167b06ba0SRafael J. Wysocki 		WARN(1, KERN_ERR "%s called for unknown object\n", __func__);
302e8db0be1SJean Pihet 		return;
303e8db0be1SJean Pihet 	}
304e8db0be1SJean Pihet 
305333eed7dSRafael J. Wysocki 	trace_pm_qos_update_request(new_value);
30602c92a37SRafael J. Wysocki 
30702c92a37SRafael J. Wysocki 	if (new_value == req->node.prio)
30802c92a37SRafael J. Wysocki 		return;
30902c92a37SRafael J. Wysocki 
310333eed7dSRafael J. Wysocki 	cpu_latency_qos_apply(req, PM_QOS_UPDATE_REQ, new_value);
311e8db0be1SJean Pihet }
31267b06ba0SRafael J. Wysocki EXPORT_SYMBOL_GPL(cpu_latency_qos_update_request);
313e8db0be1SJean Pihet 
314e8db0be1SJean Pihet /**
31567b06ba0SRafael J. Wysocki  * cpu_latency_qos_remove_request - Remove existing CPU latency QoS request.
31667b06ba0SRafael J. Wysocki  * @req: QoS request to remove.
317e8db0be1SJean Pihet  *
31867b06ba0SRafael J. Wysocki  * Remove the CPU latency QoS request represented by @req from the CPU latency
31967b06ba0SRafael J. Wysocki  * QoS list along with updating the effective constraint value for that list.
320e8db0be1SJean Pihet  */
cpu_latency_qos_remove_request(struct pm_qos_request * req)32167b06ba0SRafael J. Wysocki void cpu_latency_qos_remove_request(struct pm_qos_request *req)
322e8db0be1SJean Pihet {
32367b06ba0SRafael J. Wysocki 	if (!req)
324e8db0be1SJean Pihet 		return;
325e8db0be1SJean Pihet 
32667b06ba0SRafael J. Wysocki 	if (!cpu_latency_qos_request_active(req)) {
32767b06ba0SRafael J. Wysocki 		WARN(1, KERN_ERR "%s called for unknown object\n", __func__);
328e8db0be1SJean Pihet 		return;
329e8db0be1SJean Pihet 	}
330e8db0be1SJean Pihet 
331333eed7dSRafael J. Wysocki 	trace_pm_qos_remove_request(PM_QOS_DEFAULT_VALUE);
33202c92a37SRafael J. Wysocki 
333333eed7dSRafael J. Wysocki 	cpu_latency_qos_apply(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
334cc749986SJean Pihet 	memset(req, 0, sizeof(*req));
335e8db0be1SJean Pihet }
33667b06ba0SRafael J. Wysocki EXPORT_SYMBOL_GPL(cpu_latency_qos_remove_request);
337e8db0be1SJean Pihet 
3382552d352SRafael J. Wysocki /* User space interface to the CPU latency QoS via misc device. */
33963cffc05SRafael J. Wysocki 
cpu_latency_qos_open(struct inode * inode,struct file * filp)3402552d352SRafael J. Wysocki static int cpu_latency_qos_open(struct inode *inode, struct file *filp)
341e8db0be1SJean Pihet {
34263cffc05SRafael J. Wysocki 	struct pm_qos_request *req;
343e8db0be1SJean Pihet 
34463cffc05SRafael J. Wysocki 	req = kzalloc(sizeof(*req), GFP_KERNEL);
345e8db0be1SJean Pihet 	if (!req)
346e8db0be1SJean Pihet 		return -ENOMEM;
347e8db0be1SJean Pihet 
34867b06ba0SRafael J. Wysocki 	cpu_latency_qos_add_request(req, PM_QOS_DEFAULT_VALUE);
349e8db0be1SJean Pihet 	filp->private_data = req;
350e8db0be1SJean Pihet 
351e8db0be1SJean Pihet 	return 0;
352e8db0be1SJean Pihet }
353e8db0be1SJean Pihet 
cpu_latency_qos_release(struct inode * inode,struct file * filp)3542552d352SRafael J. Wysocki static int cpu_latency_qos_release(struct inode *inode, struct file *filp)
355e8db0be1SJean Pihet {
356299a2298SRafael J. Wysocki 	struct pm_qos_request *req = filp->private_data;
357e8db0be1SJean Pihet 
358299a2298SRafael J. Wysocki 	filp->private_data = NULL;
359299a2298SRafael J. Wysocki 
36067b06ba0SRafael J. Wysocki 	cpu_latency_qos_remove_request(req);
361e8db0be1SJean Pihet 	kfree(req);
362e8db0be1SJean Pihet 
363e8db0be1SJean Pihet 	return 0;
364e8db0be1SJean Pihet }
365e8db0be1SJean Pihet 
cpu_latency_qos_read(struct file * filp,char __user * buf,size_t count,loff_t * f_pos)3662552d352SRafael J. Wysocki static ssize_t cpu_latency_qos_read(struct file *filp, char __user *buf,
367e8db0be1SJean Pihet 				    size_t count, loff_t *f_pos)
368e8db0be1SJean Pihet {
369cc749986SJean Pihet 	struct pm_qos_request *req = filp->private_data;
370299a2298SRafael J. Wysocki 	unsigned long flags;
371299a2298SRafael J. Wysocki 	s32 value;
372e8db0be1SJean Pihet 
37367b06ba0SRafael J. Wysocki 	if (!req || !cpu_latency_qos_request_active(req))
374e8db0be1SJean Pihet 		return -EINVAL;
375e8db0be1SJean Pihet 
376e8db0be1SJean Pihet 	spin_lock_irqsave(&pm_qos_lock, flags);
3772552d352SRafael J. Wysocki 	value = pm_qos_get_value(&cpu_latency_constraints);
378e8db0be1SJean Pihet 	spin_unlock_irqrestore(&pm_qos_lock, flags);
379e8db0be1SJean Pihet 
380e8db0be1SJean Pihet 	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
381e8db0be1SJean Pihet }
382e8db0be1SJean Pihet 
cpu_latency_qos_write(struct file * filp,const char __user * buf,size_t count,loff_t * f_pos)3832552d352SRafael J. Wysocki static ssize_t cpu_latency_qos_write(struct file *filp, const char __user *buf,
384e8db0be1SJean Pihet 				     size_t count, loff_t *f_pos)
385e8db0be1SJean Pihet {
386e8db0be1SJean Pihet 	s32 value;
387e8db0be1SJean Pihet 
388e8db0be1SJean Pihet 	if (count == sizeof(s32)) {
389e8db0be1SJean Pihet 		if (copy_from_user(&value, buf, sizeof(s32)))
390e8db0be1SJean Pihet 			return -EFAULT;
391d4f7ecf7SAndy Shevchenko 	} else {
392e8db0be1SJean Pihet 		int ret;
393e8db0be1SJean Pihet 
394d4f7ecf7SAndy Shevchenko 		ret = kstrtos32_from_user(buf, count, 16, &value);
395d4f7ecf7SAndy Shevchenko 		if (ret)
396d4f7ecf7SAndy Shevchenko 			return ret;
397e8db0be1SJean Pihet 	}
398e8db0be1SJean Pihet 
39967b06ba0SRafael J. Wysocki 	cpu_latency_qos_update_request(filp->private_data, value);
400e8db0be1SJean Pihet 
401e8db0be1SJean Pihet 	return count;
402e8db0be1SJean Pihet }
403e8db0be1SJean Pihet 
4042552d352SRafael J. Wysocki static const struct file_operations cpu_latency_qos_fops = {
4052552d352SRafael J. Wysocki 	.write = cpu_latency_qos_write,
4062552d352SRafael J. Wysocki 	.read = cpu_latency_qos_read,
4072552d352SRafael J. Wysocki 	.open = cpu_latency_qos_open,
4082552d352SRafael J. Wysocki 	.release = cpu_latency_qos_release,
409299a2298SRafael J. Wysocki 	.llseek = noop_llseek,
410299a2298SRafael J. Wysocki };
411299a2298SRafael J. Wysocki 
41202c92a37SRafael J. Wysocki static struct miscdevice cpu_latency_qos_miscdev = {
41302c92a37SRafael J. Wysocki 	.minor = MISC_DYNAMIC_MINOR,
41402c92a37SRafael J. Wysocki 	.name = "cpu_dma_latency",
4152552d352SRafael J. Wysocki 	.fops = &cpu_latency_qos_fops,
41602c92a37SRafael J. Wysocki };
417299a2298SRafael J. Wysocki 
cpu_latency_qos_init(void)4182552d352SRafael J. Wysocki static int __init cpu_latency_qos_init(void)
419e8db0be1SJean Pihet {
42063cffc05SRafael J. Wysocki 	int ret;
421e8db0be1SJean Pihet 
42202c92a37SRafael J. Wysocki 	ret = misc_register(&cpu_latency_qos_miscdev);
42363cffc05SRafael J. Wysocki 	if (ret < 0)
42463cffc05SRafael J. Wysocki 		pr_err("%s: %s setup failed\n", __func__,
42502c92a37SRafael J. Wysocki 		       cpu_latency_qos_miscdev.name);
426e8db0be1SJean Pihet 
427e8db0be1SJean Pihet 	return ret;
428e8db0be1SJean Pihet }
4292552d352SRafael J. Wysocki late_initcall(cpu_latency_qos_init);
430814d51f8SRafael J. Wysocki #endif /* CONFIG_CPU_IDLE */
43177751a46SRafael J. Wysocki 
43277751a46SRafael J. Wysocki /* Definitions related to the frequency QoS below. */
43377751a46SRafael J. Wysocki 
freq_qos_value_invalid(s32 value)4343a8395b5SChungkai Yang static inline bool freq_qos_value_invalid(s32 value)
4353a8395b5SChungkai Yang {
4363a8395b5SChungkai Yang 	return value < 0 && value != PM_QOS_DEFAULT_VALUE;
4373a8395b5SChungkai Yang }
4383a8395b5SChungkai Yang 
43977751a46SRafael J. Wysocki /**
44077751a46SRafael J. Wysocki  * freq_constraints_init - Initialize frequency QoS constraints.
44177751a46SRafael J. Wysocki  * @qos: Frequency QoS constraints to initialize.
44277751a46SRafael J. Wysocki  */
freq_constraints_init(struct freq_constraints * qos)44377751a46SRafael J. Wysocki void freq_constraints_init(struct freq_constraints *qos)
44477751a46SRafael J. Wysocki {
44577751a46SRafael J. Wysocki 	struct pm_qos_constraints *c;
44677751a46SRafael J. Wysocki 
44777751a46SRafael J. Wysocki 	c = &qos->min_freq;
44877751a46SRafael J. Wysocki 	plist_head_init(&c->list);
44977751a46SRafael J. Wysocki 	c->target_value = FREQ_QOS_MIN_DEFAULT_VALUE;
45077751a46SRafael J. Wysocki 	c->default_value = FREQ_QOS_MIN_DEFAULT_VALUE;
45177751a46SRafael J. Wysocki 	c->no_constraint_value = FREQ_QOS_MIN_DEFAULT_VALUE;
45277751a46SRafael J. Wysocki 	c->type = PM_QOS_MAX;
45377751a46SRafael J. Wysocki 	c->notifiers = &qos->min_freq_notifiers;
45477751a46SRafael J. Wysocki 	BLOCKING_INIT_NOTIFIER_HEAD(c->notifiers);
45577751a46SRafael J. Wysocki 
45677751a46SRafael J. Wysocki 	c = &qos->max_freq;
45777751a46SRafael J. Wysocki 	plist_head_init(&c->list);
45877751a46SRafael J. Wysocki 	c->target_value = FREQ_QOS_MAX_DEFAULT_VALUE;
45977751a46SRafael J. Wysocki 	c->default_value = FREQ_QOS_MAX_DEFAULT_VALUE;
46077751a46SRafael J. Wysocki 	c->no_constraint_value = FREQ_QOS_MAX_DEFAULT_VALUE;
46177751a46SRafael J. Wysocki 	c->type = PM_QOS_MIN;
46277751a46SRafael J. Wysocki 	c->notifiers = &qos->max_freq_notifiers;
46377751a46SRafael J. Wysocki 	BLOCKING_INIT_NOTIFIER_HEAD(c->notifiers);
46477751a46SRafael J. Wysocki }
46577751a46SRafael J. Wysocki 
46677751a46SRafael J. Wysocki /**
46777751a46SRafael J. Wysocki  * freq_qos_read_value - Get frequency QoS constraint for a given list.
46877751a46SRafael J. Wysocki  * @qos: Constraints to evaluate.
46977751a46SRafael J. Wysocki  * @type: QoS request type.
47077751a46SRafael J. Wysocki  */
freq_qos_read_value(struct freq_constraints * qos,enum freq_qos_req_type type)47177751a46SRafael J. Wysocki s32 freq_qos_read_value(struct freq_constraints *qos,
47277751a46SRafael J. Wysocki 			enum freq_qos_req_type type)
47377751a46SRafael J. Wysocki {
47477751a46SRafael J. Wysocki 	s32 ret;
47577751a46SRafael J. Wysocki 
47677751a46SRafael J. Wysocki 	switch (type) {
47777751a46SRafael J. Wysocki 	case FREQ_QOS_MIN:
47877751a46SRafael J. Wysocki 		ret = IS_ERR_OR_NULL(qos) ?
47977751a46SRafael J. Wysocki 			FREQ_QOS_MIN_DEFAULT_VALUE :
48077751a46SRafael J. Wysocki 			pm_qos_read_value(&qos->min_freq);
48177751a46SRafael J. Wysocki 		break;
48277751a46SRafael J. Wysocki 	case FREQ_QOS_MAX:
48377751a46SRafael J. Wysocki 		ret = IS_ERR_OR_NULL(qos) ?
48477751a46SRafael J. Wysocki 			FREQ_QOS_MAX_DEFAULT_VALUE :
48577751a46SRafael J. Wysocki 			pm_qos_read_value(&qos->max_freq);
48677751a46SRafael J. Wysocki 		break;
48777751a46SRafael J. Wysocki 	default:
48877751a46SRafael J. Wysocki 		WARN_ON(1);
48977751a46SRafael J. Wysocki 		ret = 0;
49077751a46SRafael J. Wysocki 	}
49177751a46SRafael J. Wysocki 
49277751a46SRafael J. Wysocki 	return ret;
49377751a46SRafael J. Wysocki }
49477751a46SRafael J. Wysocki 
49577751a46SRafael J. Wysocki /**
49677751a46SRafael J. Wysocki  * freq_qos_apply - Add/modify/remove frequency QoS request.
49777751a46SRafael J. Wysocki  * @req: Constraint request to apply.
49877751a46SRafael J. Wysocki  * @action: Action to perform (add/update/remove).
49977751a46SRafael J. Wysocki  * @value: Value to assign to the QoS request.
50036a8015fSLeonard Crestez  *
50136a8015fSLeonard Crestez  * This is only meant to be called from inside pm_qos, not drivers.
50277751a46SRafael J. Wysocki  */
freq_qos_apply(struct freq_qos_request * req,enum pm_qos_req_action action,s32 value)50336a8015fSLeonard Crestez int freq_qos_apply(struct freq_qos_request *req,
50477751a46SRafael J. Wysocki 			  enum pm_qos_req_action action, s32 value)
50577751a46SRafael J. Wysocki {
50677751a46SRafael J. Wysocki 	int ret;
50777751a46SRafael J. Wysocki 
50877751a46SRafael J. Wysocki 	switch(req->type) {
50977751a46SRafael J. Wysocki 	case FREQ_QOS_MIN:
51077751a46SRafael J. Wysocki 		ret = pm_qos_update_target(&req->qos->min_freq, &req->pnode,
51177751a46SRafael J. Wysocki 					   action, value);
51277751a46SRafael J. Wysocki 		break;
51377751a46SRafael J. Wysocki 	case FREQ_QOS_MAX:
51477751a46SRafael J. Wysocki 		ret = pm_qos_update_target(&req->qos->max_freq, &req->pnode,
51577751a46SRafael J. Wysocki 					   action, value);
51677751a46SRafael J. Wysocki 		break;
51777751a46SRafael J. Wysocki 	default:
51877751a46SRafael J. Wysocki 		ret = -EINVAL;
51977751a46SRafael J. Wysocki 	}
52077751a46SRafael J. Wysocki 
52177751a46SRafael J. Wysocki 	return ret;
52277751a46SRafael J. Wysocki }
52377751a46SRafael J. Wysocki 
52477751a46SRafael J. Wysocki /**
52577751a46SRafael J. Wysocki  * freq_qos_add_request - Insert new frequency QoS request into a given list.
52677751a46SRafael J. Wysocki  * @qos: Constraints to update.
52777751a46SRafael J. Wysocki  * @req: Preallocated request object.
52877751a46SRafael J. Wysocki  * @type: Request type.
52977751a46SRafael J. Wysocki  * @value: Request value.
53077751a46SRafael J. Wysocki  *
53177751a46SRafael J. Wysocki  * Insert a new entry into the @qos list of requests, recompute the effective
53277751a46SRafael J. Wysocki  * QoS constraint value for that list and initialize the @req object.  The
53377751a46SRafael J. Wysocki  * caller needs to save that object for later use in updates and removal.
53477751a46SRafael J. Wysocki  *
53577751a46SRafael J. Wysocki  * Return 1 if the effective constraint value has changed, 0 if the effective
53677751a46SRafael J. Wysocki  * constraint value has not changed, or a negative error code on failures.
53777751a46SRafael J. Wysocki  */
freq_qos_add_request(struct freq_constraints * qos,struct freq_qos_request * req,enum freq_qos_req_type type,s32 value)53877751a46SRafael J. Wysocki int freq_qos_add_request(struct freq_constraints *qos,
53977751a46SRafael J. Wysocki 			 struct freq_qos_request *req,
54077751a46SRafael J. Wysocki 			 enum freq_qos_req_type type, s32 value)
54177751a46SRafael J. Wysocki {
54277751a46SRafael J. Wysocki 	int ret;
54377751a46SRafael J. Wysocki 
5443a8395b5SChungkai Yang 	if (IS_ERR_OR_NULL(qos) || !req || freq_qos_value_invalid(value))
54577751a46SRafael J. Wysocki 		return -EINVAL;
54677751a46SRafael J. Wysocki 
54777751a46SRafael J. Wysocki 	if (WARN(freq_qos_request_active(req),
54877751a46SRafael J. Wysocki 		 "%s() called for active request\n", __func__))
54977751a46SRafael J. Wysocki 		return -EINVAL;
55077751a46SRafael J. Wysocki 
55177751a46SRafael J. Wysocki 	req->qos = qos;
55277751a46SRafael J. Wysocki 	req->type = type;
55377751a46SRafael J. Wysocki 	ret = freq_qos_apply(req, PM_QOS_ADD_REQ, value);
55477751a46SRafael J. Wysocki 	if (ret < 0) {
55577751a46SRafael J. Wysocki 		req->qos = NULL;
55677751a46SRafael J. Wysocki 		req->type = 0;
55777751a46SRafael J. Wysocki 	}
55877751a46SRafael J. Wysocki 
55977751a46SRafael J. Wysocki 	return ret;
56077751a46SRafael J. Wysocki }
56177751a46SRafael J. Wysocki EXPORT_SYMBOL_GPL(freq_qos_add_request);
56277751a46SRafael J. Wysocki 
56377751a46SRafael J. Wysocki /**
56477751a46SRafael J. Wysocki  * freq_qos_update_request - Modify existing frequency QoS request.
56577751a46SRafael J. Wysocki  * @req: Request to modify.
56677751a46SRafael J. Wysocki  * @new_value: New request value.
56777751a46SRafael J. Wysocki  *
56877751a46SRafael J. Wysocki  * Update an existing frequency QoS request along with the effective constraint
56977751a46SRafael J. Wysocki  * value for the list of requests it belongs to.
57077751a46SRafael J. Wysocki  *
57177751a46SRafael J. Wysocki  * Return 1 if the effective constraint value has changed, 0 if the effective
57277751a46SRafael J. Wysocki  * constraint value has not changed, or a negative error code on failures.
57377751a46SRafael J. Wysocki  */
freq_qos_update_request(struct freq_qos_request * req,s32 new_value)57477751a46SRafael J. Wysocki int freq_qos_update_request(struct freq_qos_request *req, s32 new_value)
57577751a46SRafael J. Wysocki {
5763a8395b5SChungkai Yang 	if (!req || freq_qos_value_invalid(new_value))
57777751a46SRafael J. Wysocki 		return -EINVAL;
57877751a46SRafael J. Wysocki 
57977751a46SRafael J. Wysocki 	if (WARN(!freq_qos_request_active(req),
58077751a46SRafael J. Wysocki 		 "%s() called for unknown object\n", __func__))
58177751a46SRafael J. Wysocki 		return -EINVAL;
58277751a46SRafael J. Wysocki 
58377751a46SRafael J. Wysocki 	if (req->pnode.prio == new_value)
58477751a46SRafael J. Wysocki 		return 0;
58577751a46SRafael J. Wysocki 
58677751a46SRafael J. Wysocki 	return freq_qos_apply(req, PM_QOS_UPDATE_REQ, new_value);
58777751a46SRafael J. Wysocki }
58877751a46SRafael J. Wysocki EXPORT_SYMBOL_GPL(freq_qos_update_request);
58977751a46SRafael J. Wysocki 
59077751a46SRafael J. Wysocki /**
59177751a46SRafael J. Wysocki  * freq_qos_remove_request - Remove frequency QoS request from its list.
59277751a46SRafael J. Wysocki  * @req: Request to remove.
59377751a46SRafael J. Wysocki  *
59477751a46SRafael J. Wysocki  * Remove the given frequency QoS request from the list of constraints it
59577751a46SRafael J. Wysocki  * belongs to and recompute the effective constraint value for that list.
59677751a46SRafael J. Wysocki  *
59777751a46SRafael J. Wysocki  * Return 1 if the effective constraint value has changed, 0 if the effective
59877751a46SRafael J. Wysocki  * constraint value has not changed, or a negative error code on failures.
59977751a46SRafael J. Wysocki  */
freq_qos_remove_request(struct freq_qos_request * req)60077751a46SRafael J. Wysocki int freq_qos_remove_request(struct freq_qos_request *req)
60177751a46SRafael J. Wysocki {
60205ff1ba4SRafael J. Wysocki 	int ret;
60305ff1ba4SRafael J. Wysocki 
60477751a46SRafael J. Wysocki 	if (!req)
60577751a46SRafael J. Wysocki 		return -EINVAL;
60677751a46SRafael J. Wysocki 
60777751a46SRafael J. Wysocki 	if (WARN(!freq_qos_request_active(req),
60877751a46SRafael J. Wysocki 		 "%s() called for unknown object\n", __func__))
60977751a46SRafael J. Wysocki 		return -EINVAL;
61077751a46SRafael J. Wysocki 
61105ff1ba4SRafael J. Wysocki 	ret = freq_qos_apply(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
61205ff1ba4SRafael J. Wysocki 	req->qos = NULL;
61305ff1ba4SRafael J. Wysocki 	req->type = 0;
61405ff1ba4SRafael J. Wysocki 
61505ff1ba4SRafael J. Wysocki 	return ret;
61677751a46SRafael J. Wysocki }
61777751a46SRafael J. Wysocki EXPORT_SYMBOL_GPL(freq_qos_remove_request);
61877751a46SRafael J. Wysocki 
61977751a46SRafael J. Wysocki /**
62077751a46SRafael J. Wysocki  * freq_qos_add_notifier - Add frequency QoS change notifier.
62177751a46SRafael J. Wysocki  * @qos: List of requests to add the notifier to.
62277751a46SRafael J. Wysocki  * @type: Request type.
62377751a46SRafael J. Wysocki  * @notifier: Notifier block to add.
62477751a46SRafael J. Wysocki  */
freq_qos_add_notifier(struct freq_constraints * qos,enum freq_qos_req_type type,struct notifier_block * notifier)62577751a46SRafael J. Wysocki int freq_qos_add_notifier(struct freq_constraints *qos,
62677751a46SRafael J. Wysocki 			  enum freq_qos_req_type type,
62777751a46SRafael J. Wysocki 			  struct notifier_block *notifier)
62877751a46SRafael J. Wysocki {
62977751a46SRafael J. Wysocki 	int ret;
63077751a46SRafael J. Wysocki 
63177751a46SRafael J. Wysocki 	if (IS_ERR_OR_NULL(qos) || !notifier)
63277751a46SRafael J. Wysocki 		return -EINVAL;
63377751a46SRafael J. Wysocki 
63477751a46SRafael J. Wysocki 	switch (type) {
63577751a46SRafael J. Wysocki 	case FREQ_QOS_MIN:
63677751a46SRafael J. Wysocki 		ret = blocking_notifier_chain_register(qos->min_freq.notifiers,
63777751a46SRafael J. Wysocki 						       notifier);
63877751a46SRafael J. Wysocki 		break;
63977751a46SRafael J. Wysocki 	case FREQ_QOS_MAX:
64077751a46SRafael J. Wysocki 		ret = blocking_notifier_chain_register(qos->max_freq.notifiers,
64177751a46SRafael J. Wysocki 						       notifier);
64277751a46SRafael J. Wysocki 		break;
64377751a46SRafael J. Wysocki 	default:
64477751a46SRafael J. Wysocki 		WARN_ON(1);
64577751a46SRafael J. Wysocki 		ret = -EINVAL;
64677751a46SRafael J. Wysocki 	}
64777751a46SRafael J. Wysocki 
64877751a46SRafael J. Wysocki 	return ret;
64977751a46SRafael J. Wysocki }
65077751a46SRafael J. Wysocki EXPORT_SYMBOL_GPL(freq_qos_add_notifier);
65177751a46SRafael J. Wysocki 
65277751a46SRafael J. Wysocki /**
65377751a46SRafael J. Wysocki  * freq_qos_remove_notifier - Remove frequency QoS change notifier.
65477751a46SRafael J. Wysocki  * @qos: List of requests to remove the notifier from.
65577751a46SRafael J. Wysocki  * @type: Request type.
65677751a46SRafael J. Wysocki  * @notifier: Notifier block to remove.
65777751a46SRafael J. Wysocki  */
freq_qos_remove_notifier(struct freq_constraints * qos,enum freq_qos_req_type type,struct notifier_block * notifier)65877751a46SRafael J. Wysocki int freq_qos_remove_notifier(struct freq_constraints *qos,
65977751a46SRafael J. Wysocki 			     enum freq_qos_req_type type,
66077751a46SRafael J. Wysocki 			     struct notifier_block *notifier)
66177751a46SRafael J. Wysocki {
66277751a46SRafael J. Wysocki 	int ret;
66377751a46SRafael J. Wysocki 
66477751a46SRafael J. Wysocki 	if (IS_ERR_OR_NULL(qos) || !notifier)
66577751a46SRafael J. Wysocki 		return -EINVAL;
66677751a46SRafael J. Wysocki 
66777751a46SRafael J. Wysocki 	switch (type) {
66877751a46SRafael J. Wysocki 	case FREQ_QOS_MIN:
66977751a46SRafael J. Wysocki 		ret = blocking_notifier_chain_unregister(qos->min_freq.notifiers,
67077751a46SRafael J. Wysocki 							 notifier);
67177751a46SRafael J. Wysocki 		break;
67277751a46SRafael J. Wysocki 	case FREQ_QOS_MAX:
67377751a46SRafael J. Wysocki 		ret = blocking_notifier_chain_unregister(qos->max_freq.notifiers,
67477751a46SRafael J. Wysocki 							 notifier);
67577751a46SRafael J. Wysocki 		break;
67677751a46SRafael J. Wysocki 	default:
67777751a46SRafael J. Wysocki 		WARN_ON(1);
67877751a46SRafael J. Wysocki 		ret = -EINVAL;
67977751a46SRafael J. Wysocki 	}
68077751a46SRafael J. Wysocki 
68177751a46SRafael J. Wysocki 	return ret;
68277751a46SRafael J. Wysocki }
68377751a46SRafael J. Wysocki EXPORT_SYMBOL_GPL(freq_qos_remove_notifier);
684