LCOV - code coverage report
Current view: top level - kernel/power - qos.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 37 123 30.1 %
Date: 2023-04-06 08:38:28 Functions: 3 12 25.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * Power Management Quality of Service (PM QoS) support base.
       4             :  *
       5             :  * Copyright (C) 2020 Intel Corporation
       6             :  *
       7             :  * Authors:
       8             :  *      Mark Gross <mgross@linux.intel.com>
       9             :  *      Rafael J. Wysocki <rafael.j.wysocki@intel.com>
      10             :  *
      11             :  * Provided here is an interface for specifying PM QoS dependencies.  It allows
      12             :  * entities depending on QoS constraints to register their requests which are
      13             :  * aggregated as appropriate to produce effective constraints (target values)
      14             :  * that can be monitored by entities needing to respect them, either by polling
      15             :  * or through a built-in notification mechanism.
      16             :  *
      17             :  * In addition to the basic functionality, more specific interfaces for managing
      18             :  * global CPU latency QoS requests and frequency QoS requests are provided.
      19             :  */
      20             : 
      21             : /*#define DEBUG*/
      22             : 
      23             : #include <linux/pm_qos.h>
      24             : #include <linux/sched.h>
      25             : #include <linux/spinlock.h>
      26             : #include <linux/slab.h>
      27             : #include <linux/time.h>
      28             : #include <linux/fs.h>
      29             : #include <linux/device.h>
      30             : #include <linux/miscdevice.h>
      31             : #include <linux/string.h>
      32             : #include <linux/platform_device.h>
      33             : #include <linux/init.h>
      34             : #include <linux/kernel.h>
      35             : #include <linux/debugfs.h>
      36             : #include <linux/seq_file.h>
      37             : 
      38             : #include <linux/uaccess.h>
      39             : #include <linux/export.h>
      40             : #include <trace/events/power.h>
      41             : 
      42             : /*
      43             :  * locking rule: all changes to constraints or notifiers lists
      44             :  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
      45             :  * held, taken with _irqsave.  One lock to rule them all
      46             :  */
      47             : static DEFINE_SPINLOCK(pm_qos_lock);
      48             : 
      49             : /**
      50             :  * pm_qos_read_value - Return the current effective constraint value.
      51             :  * @c: List of PM QoS constraint requests.
      52             :  */
      53           0 : s32 pm_qos_read_value(struct pm_qos_constraints *c)
      54             : {
      55           0 :         return READ_ONCE(c->target_value);
      56             : }
      57             : 
      58           2 : static int pm_qos_get_value(struct pm_qos_constraints *c)
      59             : {
      60           4 :         if (plist_head_empty(&c->list))
      61           1 :                 return c->no_constraint_value;
      62             : 
      63           1 :         switch (c->type) {
      64             :         case PM_QOS_MIN:
      65           2 :                 return plist_first(&c->list)->prio;
      66             : 
      67             :         case PM_QOS_MAX:
      68           0 :                 return plist_last(&c->list)->prio;
      69             : 
      70             :         default:
      71           0 :                 WARN(1, "Unknown PM QoS type in %s\n", __func__);
      72           0 :                 return PM_QOS_DEFAULT_VALUE;
      73             :         }
      74             : }
      75             : 
      76             : static void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
      77             : {
      78           1 :         WRITE_ONCE(c->target_value, value);
      79             : }
      80             : 
      81             : /**
      82             :  * pm_qos_update_target - Update a list of PM QoS constraint requests.
      83             :  * @c: List of PM QoS requests.
      84             :  * @node: Target list entry.
      85             :  * @action: Action to carry out (add, update or remove).
      86             :  * @value: New request value for the target list entry.
      87             :  *
      88             :  * Update the given list of PM QoS constraint requests, @c, by carrying an
      89             :  * @action involving the @node list entry and @value on it.
      90             :  *
      91             :  * The recognized values of @action are PM_QOS_ADD_REQ (store @value in @node
      92             :  * and add it to the list), PM_QOS_UPDATE_REQ (remove @node from the list, store
      93             :  * @value in it and add it to the list again), and PM_QOS_REMOVE_REQ (remove
      94             :  * @node from the list, ignore @value).
      95             :  *
      96             :  * Return: 1 if the aggregate constraint value has changed, 0  otherwise.
      97             :  */
      98           1 : int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
      99             :                          enum pm_qos_req_action action, int value)
     100             : {
     101             :         int prev_value, curr_value, new_value;
     102             :         unsigned long flags;
     103             : 
     104           1 :         spin_lock_irqsave(&pm_qos_lock, flags);
     105             : 
     106           1 :         prev_value = pm_qos_get_value(c);
     107           1 :         if (value == PM_QOS_DEFAULT_VALUE)
     108           0 :                 new_value = c->default_value;
     109             :         else
     110             :                 new_value = value;
     111             : 
     112           1 :         switch (action) {
     113             :         case PM_QOS_REMOVE_REQ:
     114           0 :                 plist_del(node, &c->list);
     115           0 :                 break;
     116             :         case PM_QOS_UPDATE_REQ:
     117             :                 /*
     118             :                  * To change the list, atomically remove, reinit with new value
     119             :                  * and add, then see if the aggregate has changed.
     120             :                  */
     121           0 :                 plist_del(node, &c->list);
     122             :                 fallthrough;
     123             :         case PM_QOS_ADD_REQ:
     124           1 :                 plist_node_init(node, new_value);
     125           1 :                 plist_add(node, &c->list);
     126           1 :                 break;
     127             :         default:
     128             :                 /* no action */
     129             :                 ;
     130             :         }
     131             : 
     132           1 :         curr_value = pm_qos_get_value(c);
     133           1 :         pm_qos_set_value(c, curr_value);
     134             : 
     135           1 :         spin_unlock_irqrestore(&pm_qos_lock, flags);
     136             : 
     137           1 :         trace_pm_qos_update_target(action, prev_value, curr_value);
     138             : 
     139           1 :         if (prev_value == curr_value)
     140             :                 return 0;
     141             : 
     142           0 :         if (c->notifiers)
     143           0 :                 blocking_notifier_call_chain(c->notifiers, curr_value, NULL);
     144             : 
     145             :         return 1;
     146             : }
     147             : 
     148             : /**
     149             :  * pm_qos_flags_remove_req - Remove device PM QoS flags request.
     150             :  * @pqf: Device PM QoS flags set to remove the request from.
     151             :  * @req: Request to remove from the set.
     152             :  */
     153             : static void pm_qos_flags_remove_req(struct pm_qos_flags *pqf,
     154             :                                     struct pm_qos_flags_request *req)
     155             : {
     156           0 :         s32 val = 0;
     157             : 
     158           0 :         list_del(&req->node);
     159           0 :         list_for_each_entry(req, &pqf->list, node)
     160           0 :                 val |= req->flags;
     161             : 
     162           0 :         pqf->effective_flags = val;
     163             : }
     164             : 
     165             : /**
     166             :  * pm_qos_update_flags - Update a set of PM QoS flags.
     167             :  * @pqf: Set of PM QoS flags to update.
     168             :  * @req: Request to add to the set, to modify, or to remove from the set.
     169             :  * @action: Action to take on the set.
     170             :  * @val: Value of the request to add or modify.
     171             :  *
     172             :  * Return: 1 if the aggregate constraint value has changed, 0 otherwise.
     173             :  */
     174           0 : bool pm_qos_update_flags(struct pm_qos_flags *pqf,
     175             :                          struct pm_qos_flags_request *req,
     176             :                          enum pm_qos_req_action action, s32 val)
     177             : {
     178             :         unsigned long irqflags;
     179             :         s32 prev_value, curr_value;
     180             : 
     181           0 :         spin_lock_irqsave(&pm_qos_lock, irqflags);
     182             : 
     183           0 :         prev_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
     184             : 
     185           0 :         switch (action) {
     186             :         case PM_QOS_REMOVE_REQ:
     187             :                 pm_qos_flags_remove_req(pqf, req);
     188             :                 break;
     189             :         case PM_QOS_UPDATE_REQ:
     190             :                 pm_qos_flags_remove_req(pqf, req);
     191             :                 fallthrough;
     192             :         case PM_QOS_ADD_REQ:
     193           0 :                 req->flags = val;
     194           0 :                 INIT_LIST_HEAD(&req->node);
     195           0 :                 list_add_tail(&req->node, &pqf->list);
     196           0 :                 pqf->effective_flags |= val;
     197           0 :                 break;
     198             :         default:
     199             :                 /* no action */
     200             :                 ;
     201             :         }
     202             : 
     203           0 :         curr_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
     204             : 
     205           0 :         spin_unlock_irqrestore(&pm_qos_lock, irqflags);
     206             : 
     207           0 :         trace_pm_qos_update_flags(action, prev_value, curr_value);
     208             : 
     209           0 :         return prev_value != curr_value;
     210             : }
     211             : 
     212             : #ifdef CONFIG_CPU_IDLE
     213             : /* Definitions related to the CPU latency QoS. */
     214             : 
     215             : static struct pm_qos_constraints cpu_latency_constraints = {
     216             :         .list = PLIST_HEAD_INIT(cpu_latency_constraints.list),
     217             :         .target_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
     218             :         .default_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
     219             :         .no_constraint_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
     220             :         .type = PM_QOS_MIN,
     221             : };
     222             : 
     223             : /**
     224             :  * cpu_latency_qos_limit - Return current system-wide CPU latency QoS limit.
     225             :  */
     226             : s32 cpu_latency_qos_limit(void)
     227             : {
     228             :         return pm_qos_read_value(&cpu_latency_constraints);
     229             : }
     230             : 
     231             : /**
     232             :  * cpu_latency_qos_request_active - Check the given PM QoS request.
     233             :  * @req: PM QoS request to check.
     234             :  *
     235             :  * Return: 'true' if @req has been added to the CPU latency QoS list, 'false'
     236             :  * otherwise.
     237             :  */
     238             : bool cpu_latency_qos_request_active(struct pm_qos_request *req)
     239             : {
     240             :         return req->qos == &cpu_latency_constraints;
     241             : }
     242             : EXPORT_SYMBOL_GPL(cpu_latency_qos_request_active);
     243             : 
     244             : static void cpu_latency_qos_apply(struct pm_qos_request *req,
     245             :                                   enum pm_qos_req_action action, s32 value)
     246             : {
     247             :         int ret = pm_qos_update_target(req->qos, &req->node, action, value);
     248             :         if (ret > 0)
     249             :                 wake_up_all_idle_cpus();
     250             : }
     251             : 
     252             : /**
     253             :  * cpu_latency_qos_add_request - Add new CPU latency QoS request.
     254             :  * @req: Pointer to a preallocated handle.
     255             :  * @value: Requested constraint value.
     256             :  *
     257             :  * Use @value to initialize the request handle pointed to by @req, insert it as
     258             :  * a new entry to the CPU latency QoS list and recompute the effective QoS
     259             :  * constraint for that list.
     260             :  *
     261             :  * Callers need to save the handle for later use in updates and removal of the
     262             :  * QoS request represented by it.
     263             :  */
     264             : void cpu_latency_qos_add_request(struct pm_qos_request *req, s32 value)
     265             : {
     266             :         if (!req)
     267             :                 return;
     268             : 
     269             :         if (cpu_latency_qos_request_active(req)) {
     270             :                 WARN(1, KERN_ERR "%s called for already added request\n", __func__);
     271             :                 return;
     272             :         }
     273             : 
     274             :         trace_pm_qos_add_request(value);
     275             : 
     276             :         req->qos = &cpu_latency_constraints;
     277             :         cpu_latency_qos_apply(req, PM_QOS_ADD_REQ, value);
     278             : }
     279             : EXPORT_SYMBOL_GPL(cpu_latency_qos_add_request);
     280             : 
     281             : /**
     282             :  * cpu_latency_qos_update_request - Modify existing CPU latency QoS request.
     283             :  * @req : QoS request to update.
     284             :  * @new_value: New requested constraint value.
     285             :  *
     286             :  * Use @new_value to update the QoS request represented by @req in the CPU
     287             :  * latency QoS list along with updating the effective constraint value for that
     288             :  * list.
     289             :  */
     290             : void cpu_latency_qos_update_request(struct pm_qos_request *req, s32 new_value)
     291             : {
     292             :         if (!req)
     293             :                 return;
     294             : 
     295             :         if (!cpu_latency_qos_request_active(req)) {
     296             :                 WARN(1, KERN_ERR "%s called for unknown object\n", __func__);
     297             :                 return;
     298             :         }
     299             : 
     300             :         trace_pm_qos_update_request(new_value);
     301             : 
     302             :         if (new_value == req->node.prio)
     303             :                 return;
     304             : 
     305             :         cpu_latency_qos_apply(req, PM_QOS_UPDATE_REQ, new_value);
     306             : }
     307             : EXPORT_SYMBOL_GPL(cpu_latency_qos_update_request);
     308             : 
     309             : /**
     310             :  * cpu_latency_qos_remove_request - Remove existing CPU latency QoS request.
     311             :  * @req: QoS request to remove.
     312             :  *
     313             :  * Remove the CPU latency QoS request represented by @req from the CPU latency
     314             :  * QoS list along with updating the effective constraint value for that list.
     315             :  */
     316             : void cpu_latency_qos_remove_request(struct pm_qos_request *req)
     317             : {
     318             :         if (!req)
     319             :                 return;
     320             : 
     321             :         if (!cpu_latency_qos_request_active(req)) {
     322             :                 WARN(1, KERN_ERR "%s called for unknown object\n", __func__);
     323             :                 return;
     324             :         }
     325             : 
     326             :         trace_pm_qos_remove_request(PM_QOS_DEFAULT_VALUE);
     327             : 
     328             :         cpu_latency_qos_apply(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
     329             :         memset(req, 0, sizeof(*req));
     330             : }
     331             : EXPORT_SYMBOL_GPL(cpu_latency_qos_remove_request);
     332             : 
     333             : /* User space interface to the CPU latency QoS via misc device. */
     334             : 
     335             : static int cpu_latency_qos_open(struct inode *inode, struct file *filp)
     336             : {
     337             :         struct pm_qos_request *req;
     338             : 
     339             :         req = kzalloc(sizeof(*req), GFP_KERNEL);
     340             :         if (!req)
     341             :                 return -ENOMEM;
     342             : 
     343             :         cpu_latency_qos_add_request(req, PM_QOS_DEFAULT_VALUE);
     344             :         filp->private_data = req;
     345             : 
     346             :         return 0;
     347             : }
     348             : 
     349             : static int cpu_latency_qos_release(struct inode *inode, struct file *filp)
     350             : {
     351             :         struct pm_qos_request *req = filp->private_data;
     352             : 
     353             :         filp->private_data = NULL;
     354             : 
     355             :         cpu_latency_qos_remove_request(req);
     356             :         kfree(req);
     357             : 
     358             :         return 0;
     359             : }
     360             : 
     361             : static ssize_t cpu_latency_qos_read(struct file *filp, char __user *buf,
     362             :                                     size_t count, loff_t *f_pos)
     363             : {
     364             :         struct pm_qos_request *req = filp->private_data;
     365             :         unsigned long flags;
     366             :         s32 value;
     367             : 
     368             :         if (!req || !cpu_latency_qos_request_active(req))
     369             :                 return -EINVAL;
     370             : 
     371             :         spin_lock_irqsave(&pm_qos_lock, flags);
     372             :         value = pm_qos_get_value(&cpu_latency_constraints);
     373             :         spin_unlock_irqrestore(&pm_qos_lock, flags);
     374             : 
     375             :         return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
     376             : }
     377             : 
     378             : static ssize_t cpu_latency_qos_write(struct file *filp, const char __user *buf,
     379             :                                      size_t count, loff_t *f_pos)
     380             : {
     381             :         s32 value;
     382             : 
     383             :         if (count == sizeof(s32)) {
     384             :                 if (copy_from_user(&value, buf, sizeof(s32)))
     385             :                         return -EFAULT;
     386             :         } else {
     387             :                 int ret;
     388             : 
     389             :                 ret = kstrtos32_from_user(buf, count, 16, &value);
     390             :                 if (ret)
     391             :                         return ret;
     392             :         }
     393             : 
     394             :         cpu_latency_qos_update_request(filp->private_data, value);
     395             : 
     396             :         return count;
     397             : }
     398             : 
     399             : static const struct file_operations cpu_latency_qos_fops = {
     400             :         .write = cpu_latency_qos_write,
     401             :         .read = cpu_latency_qos_read,
     402             :         .open = cpu_latency_qos_open,
     403             :         .release = cpu_latency_qos_release,
     404             :         .llseek = noop_llseek,
     405             : };
     406             : 
     407             : static struct miscdevice cpu_latency_qos_miscdev = {
     408             :         .minor = MISC_DYNAMIC_MINOR,
     409             :         .name = "cpu_dma_latency",
     410             :         .fops = &cpu_latency_qos_fops,
     411             : };
     412             : 
     413             : static int __init cpu_latency_qos_init(void)
     414             : {
     415             :         int ret;
     416             : 
     417             :         ret = misc_register(&cpu_latency_qos_miscdev);
     418             :         if (ret < 0)
     419             :                 pr_err("%s: %s setup failed\n", __func__,
     420             :                        cpu_latency_qos_miscdev.name);
     421             : 
     422             :         return ret;
     423             : }
     424             : late_initcall(cpu_latency_qos_init);
     425             : #endif /* CONFIG_CPU_IDLE */
     426             : 
     427             : /* Definitions related to the frequency QoS below. */
     428             : 
     429             : /**
     430             :  * freq_constraints_init - Initialize frequency QoS constraints.
     431             :  * @qos: Frequency QoS constraints to initialize.
     432             :  */
     433           1 : void freq_constraints_init(struct freq_constraints *qos)
     434             : {
     435             :         struct pm_qos_constraints *c;
     436             : 
     437           1 :         c = &qos->min_freq;
     438           2 :         plist_head_init(&c->list);
     439           1 :         c->target_value = FREQ_QOS_MIN_DEFAULT_VALUE;
     440           1 :         c->default_value = FREQ_QOS_MIN_DEFAULT_VALUE;
     441           1 :         c->no_constraint_value = FREQ_QOS_MIN_DEFAULT_VALUE;
     442           1 :         c->type = PM_QOS_MAX;
     443           1 :         c->notifiers = &qos->min_freq_notifiers;
     444           1 :         BLOCKING_INIT_NOTIFIER_HEAD(c->notifiers);
     445             : 
     446           1 :         c = &qos->max_freq;
     447           2 :         plist_head_init(&c->list);
     448           1 :         c->target_value = FREQ_QOS_MAX_DEFAULT_VALUE;
     449           1 :         c->default_value = FREQ_QOS_MAX_DEFAULT_VALUE;
     450           1 :         c->no_constraint_value = FREQ_QOS_MAX_DEFAULT_VALUE;
     451           1 :         c->type = PM_QOS_MIN;
     452           1 :         c->notifiers = &qos->max_freq_notifiers;
     453           1 :         BLOCKING_INIT_NOTIFIER_HEAD(c->notifiers);
     454           1 : }
     455             : 
     456             : /**
     457             :  * freq_qos_read_value - Get frequency QoS constraint for a given list.
     458             :  * @qos: Constraints to evaluate.
     459             :  * @type: QoS request type.
     460             :  */
     461           0 : s32 freq_qos_read_value(struct freq_constraints *qos,
     462             :                         enum freq_qos_req_type type)
     463             : {
     464             :         s32 ret;
     465             : 
     466           0 :         switch (type) {
     467             :         case FREQ_QOS_MIN:
     468           0 :                 ret = IS_ERR_OR_NULL(qos) ?
     469           0 :                         FREQ_QOS_MIN_DEFAULT_VALUE :
     470           0 :                         pm_qos_read_value(&qos->min_freq);
     471             :                 break;
     472             :         case FREQ_QOS_MAX:
     473           0 :                 ret = IS_ERR_OR_NULL(qos) ?
     474           0 :                         FREQ_QOS_MAX_DEFAULT_VALUE :
     475           0 :                         pm_qos_read_value(&qos->max_freq);
     476             :                 break;
     477             :         default:
     478           0 :                 WARN_ON(1);
     479           0 :                 ret = 0;
     480             :         }
     481             : 
     482           0 :         return ret;
     483             : }
     484             : 
     485             : /**
     486             :  * freq_qos_apply - Add/modify/remove frequency QoS request.
     487             :  * @req: Constraint request to apply.
     488             :  * @action: Action to perform (add/update/remove).
     489             :  * @value: Value to assign to the QoS request.
     490             :  *
     491             :  * This is only meant to be called from inside pm_qos, not drivers.
     492             :  */
     493           0 : int freq_qos_apply(struct freq_qos_request *req,
     494             :                           enum pm_qos_req_action action, s32 value)
     495             : {
     496             :         int ret;
     497             : 
     498           0 :         switch(req->type) {
     499             :         case FREQ_QOS_MIN:
     500           0 :                 ret = pm_qos_update_target(&req->qos->min_freq, &req->pnode,
     501             :                                            action, value);
     502           0 :                 break;
     503             :         case FREQ_QOS_MAX:
     504           0 :                 ret = pm_qos_update_target(&req->qos->max_freq, &req->pnode,
     505             :                                            action, value);
     506           0 :                 break;
     507             :         default:
     508             :                 ret = -EINVAL;
     509             :         }
     510             : 
     511           0 :         return ret;
     512             : }
     513             : 
     514             : /**
     515             :  * freq_qos_add_request - Insert new frequency QoS request into a given list.
     516             :  * @qos: Constraints to update.
     517             :  * @req: Preallocated request object.
     518             :  * @type: Request type.
     519             :  * @value: Request value.
     520             :  *
     521             :  * Insert a new entry into the @qos list of requests, recompute the effective
     522             :  * QoS constraint value for that list and initialize the @req object.  The
     523             :  * caller needs to save that object for later use in updates and removal.
     524             :  *
     525             :  * Return 1 if the effective constraint value has changed, 0 if the effective
     526             :  * constraint value has not changed, or a negative error code on failures.
     527             :  */
     528           0 : int freq_qos_add_request(struct freq_constraints *qos,
     529             :                          struct freq_qos_request *req,
     530             :                          enum freq_qos_req_type type, s32 value)
     531             : {
     532             :         int ret;
     533             : 
     534           0 :         if (IS_ERR_OR_NULL(qos) || !req || value < 0)
     535             :                 return -EINVAL;
     536             : 
     537           0 :         if (WARN(freq_qos_request_active(req),
     538             :                  "%s() called for active request\n", __func__))
     539             :                 return -EINVAL;
     540             : 
     541           0 :         req->qos = qos;
     542           0 :         req->type = type;
     543           0 :         ret = freq_qos_apply(req, PM_QOS_ADD_REQ, value);
     544           0 :         if (ret < 0) {
     545           0 :                 req->qos = NULL;
     546           0 :                 req->type = 0;
     547             :         }
     548             : 
     549             :         return ret;
     550             : }
     551             : EXPORT_SYMBOL_GPL(freq_qos_add_request);
     552             : 
     553             : /**
     554             :  * freq_qos_update_request - Modify existing frequency QoS request.
     555             :  * @req: Request to modify.
     556             :  * @new_value: New request value.
     557             :  *
     558             :  * Update an existing frequency QoS request along with the effective constraint
     559             :  * value for the list of requests it belongs to.
     560             :  *
     561             :  * Return 1 if the effective constraint value has changed, 0 if the effective
     562             :  * constraint value has not changed, or a negative error code on failures.
     563             :  */
     564           0 : int freq_qos_update_request(struct freq_qos_request *req, s32 new_value)
     565             : {
     566           0 :         if (!req || new_value < 0)
     567             :                 return -EINVAL;
     568             : 
     569           0 :         if (WARN(!freq_qos_request_active(req),
     570             :                  "%s() called for unknown object\n", __func__))
     571             :                 return -EINVAL;
     572             : 
     573           0 :         if (req->pnode.prio == new_value)
     574             :                 return 0;
     575             : 
     576           0 :         return freq_qos_apply(req, PM_QOS_UPDATE_REQ, new_value);
     577             : }
     578             : EXPORT_SYMBOL_GPL(freq_qos_update_request);
     579             : 
     580             : /**
     581             :  * freq_qos_remove_request - Remove frequency QoS request from its list.
     582             :  * @req: Request to remove.
     583             :  *
     584             :  * Remove the given frequency QoS request from the list of constraints it
     585             :  * belongs to and recompute the effective constraint value for that list.
     586             :  *
     587             :  * Return 1 if the effective constraint value has changed, 0 if the effective
     588             :  * constraint value has not changed, or a negative error code on failures.
     589             :  */
     590           0 : int freq_qos_remove_request(struct freq_qos_request *req)
     591             : {
     592             :         int ret;
     593             : 
     594           0 :         if (!req)
     595             :                 return -EINVAL;
     596             : 
     597           0 :         if (WARN(!freq_qos_request_active(req),
     598             :                  "%s() called for unknown object\n", __func__))
     599             :                 return -EINVAL;
     600             : 
     601           0 :         ret = freq_qos_apply(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
     602           0 :         req->qos = NULL;
     603           0 :         req->type = 0;
     604             : 
     605           0 :         return ret;
     606             : }
     607             : EXPORT_SYMBOL_GPL(freq_qos_remove_request);
     608             : 
     609             : /**
     610             :  * freq_qos_add_notifier - Add frequency QoS change notifier.
     611             :  * @qos: List of requests to add the notifier to.
     612             :  * @type: Request type.
     613             :  * @notifier: Notifier block to add.
     614             :  */
     615           0 : int freq_qos_add_notifier(struct freq_constraints *qos,
     616             :                           enum freq_qos_req_type type,
     617             :                           struct notifier_block *notifier)
     618             : {
     619             :         int ret;
     620             : 
     621           0 :         if (IS_ERR_OR_NULL(qos) || !notifier)
     622             :                 return -EINVAL;
     623             : 
     624           0 :         switch (type) {
     625             :         case FREQ_QOS_MIN:
     626           0 :                 ret = blocking_notifier_chain_register(qos->min_freq.notifiers,
     627             :                                                        notifier);
     628           0 :                 break;
     629             :         case FREQ_QOS_MAX:
     630           0 :                 ret = blocking_notifier_chain_register(qos->max_freq.notifiers,
     631             :                                                        notifier);
     632           0 :                 break;
     633             :         default:
     634           0 :                 WARN_ON(1);
     635           0 :                 ret = -EINVAL;
     636             :         }
     637             : 
     638             :         return ret;
     639             : }
     640             : EXPORT_SYMBOL_GPL(freq_qos_add_notifier);
     641             : 
     642             : /**
     643             :  * freq_qos_remove_notifier - Remove frequency QoS change notifier.
     644             :  * @qos: List of requests to remove the notifier from.
     645             :  * @type: Request type.
     646             :  * @notifier: Notifier block to remove.
     647             :  */
     648           0 : int freq_qos_remove_notifier(struct freq_constraints *qos,
     649             :                              enum freq_qos_req_type type,
     650             :                              struct notifier_block *notifier)
     651             : {
     652             :         int ret;
     653             : 
     654           0 :         if (IS_ERR_OR_NULL(qos) || !notifier)
     655             :                 return -EINVAL;
     656             : 
     657           0 :         switch (type) {
     658             :         case FREQ_QOS_MIN:
     659           0 :                 ret = blocking_notifier_chain_unregister(qos->min_freq.notifiers,
     660             :                                                          notifier);
     661           0 :                 break;
     662             :         case FREQ_QOS_MAX:
     663           0 :                 ret = blocking_notifier_chain_unregister(qos->max_freq.notifiers,
     664             :                                                          notifier);
     665           0 :                 break;
     666             :         default:
     667           0 :                 WARN_ON(1);
     668           0 :                 ret = -EINVAL;
     669             :         }
     670             : 
     671             :         return ret;
     672             : }
     673             : EXPORT_SYMBOL_GPL(freq_qos_remove_notifier);

Generated by: LCOV version 1.14