Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 2019 Linaro Limited.
0004  *
0005  *  Author: Daniel Lezcano <daniel.lezcano@linaro.org>
0006  *
0007  */
0008 #define pr_fmt(fmt) "cpuidle cooling: " fmt
0009 
0010 #include <linux/cpu_cooling.h>
0011 #include <linux/cpuidle.h>
0012 #include <linux/device.h>
0013 #include <linux/err.h>
0014 #include <linux/idle_inject.h>
0015 #include <linux/of_device.h>
0016 #include <linux/slab.h>
0017 #include <linux/thermal.h>
0018 
0019 /**
0020  * struct cpuidle_cooling_device - data for the idle cooling device
0021  * @ii_dev: an atomic to keep track of the last task exiting the idle cycle
0022  * @state: a normalized integer giving the state of the cooling device
0023  */
0024 struct cpuidle_cooling_device {
0025     struct idle_inject_device *ii_dev;
0026     unsigned long state;
0027 };
0028 
0029 /**
0030  * cpuidle_cooling_runtime - Running time computation
0031  * @idle_duration_us: CPU idle time to inject in microseconds
0032  * @state: a percentile based number
0033  *
0034  * The running duration is computed from the idle injection duration
0035  * which is fixed. If we reach 100% of idle injection ratio, that
0036  * means the running duration is zero. If we have a 50% ratio
0037  * injection, that means we have equal duration for idle and for
0038  * running duration.
0039  *
0040  * The formula is deduced as follows:
0041  *
0042  *  running = idle x ((100 / ratio) - 1)
0043  *
0044  * For precision purpose for integer math, we use the following:
0045  *
0046  *  running = (idle x 100) / ratio - idle
0047  *
0048  * For example, if we have an injected duration of 50%, then we end up
0049  * with 10ms of idle injection and 10ms of running duration.
0050  *
0051  * Return: An unsigned int for a usec based runtime duration.
0052  */
0053 static unsigned int cpuidle_cooling_runtime(unsigned int idle_duration_us,
0054                         unsigned long state)
0055 {
0056     if (!state)
0057         return 0;
0058 
0059     return ((idle_duration_us * 100) / state) - idle_duration_us;
0060 }
0061 
0062 /**
0063  * cpuidle_cooling_get_max_state - Get the maximum state
0064  * @cdev  : the thermal cooling device
0065  * @state : a pointer to the state variable to be filled
0066  *
0067  * The function always returns 100 as the injection ratio. It is
0068  * percentile based for consistency accross different platforms.
0069  *
0070  * Return: The function can not fail, it is always zero
0071  */
0072 static int cpuidle_cooling_get_max_state(struct thermal_cooling_device *cdev,
0073                      unsigned long *state)
0074 {
0075     /*
0076      * Depending on the configuration or the hardware, the running
0077      * cycle and the idle cycle could be different. We want to
0078      * unify that to an 0..100 interval, so the set state
0079      * interface will be the same whatever the platform is.
0080      *
0081      * The state 100% will make the cluster 100% ... idle. A 0%
0082      * injection ratio means no idle injection at all and 50%
0083      * means for 10ms of idle injection, we have 10ms of running
0084      * time.
0085      */
0086     *state = 100;
0087 
0088     return 0;
0089 }
0090 
0091 /**
0092  * cpuidle_cooling_get_cur_state - Get the current cooling state
0093  * @cdev: the thermal cooling device
0094  * @state: a pointer to the state
0095  *
0096  * The function just copies  the state value from the private thermal
0097  * cooling device structure, the mapping is 1 <-> 1.
0098  *
0099  * Return: The function can not fail, it is always zero
0100  */
0101 static int cpuidle_cooling_get_cur_state(struct thermal_cooling_device *cdev,
0102                      unsigned long *state)
0103 {
0104     struct cpuidle_cooling_device *idle_cdev = cdev->devdata;
0105 
0106     *state = idle_cdev->state;
0107 
0108     return 0;
0109 }
0110 
0111 /**
0112  * cpuidle_cooling_set_cur_state - Set the current cooling state
0113  * @cdev: the thermal cooling device
0114  * @state: the target state
0115  *
0116  * The function checks first if we are initiating the mitigation which
0117  * in turn wakes up all the idle injection tasks belonging to the idle
0118  * cooling device. In any case, it updates the internal state for the
0119  * cooling device.
0120  *
0121  * Return: The function can not fail, it is always zero
0122  */
0123 static int cpuidle_cooling_set_cur_state(struct thermal_cooling_device *cdev,
0124                      unsigned long state)
0125 {
0126     struct cpuidle_cooling_device *idle_cdev = cdev->devdata;
0127     struct idle_inject_device *ii_dev = idle_cdev->ii_dev;
0128     unsigned long current_state = idle_cdev->state;
0129     unsigned int runtime_us, idle_duration_us;
0130 
0131     idle_cdev->state = state;
0132 
0133     idle_inject_get_duration(ii_dev, &runtime_us, &idle_duration_us);
0134 
0135     runtime_us = cpuidle_cooling_runtime(idle_duration_us, state);
0136 
0137     idle_inject_set_duration(ii_dev, runtime_us, idle_duration_us);
0138 
0139     if (current_state == 0 && state > 0) {
0140         idle_inject_start(ii_dev);
0141     } else if (current_state > 0 && !state)  {
0142         idle_inject_stop(ii_dev);
0143     }
0144 
0145     return 0;
0146 }
0147 
0148 /**
0149  * cpuidle_cooling_ops - thermal cooling device ops
0150  */
0151 static struct thermal_cooling_device_ops cpuidle_cooling_ops = {
0152     .get_max_state = cpuidle_cooling_get_max_state,
0153     .get_cur_state = cpuidle_cooling_get_cur_state,
0154     .set_cur_state = cpuidle_cooling_set_cur_state,
0155 };
0156 
0157 /**
0158  * __cpuidle_cooling_register: register the cooling device
0159  * @drv: a cpuidle driver structure pointer
0160  * @np: a device node structure pointer used for the thermal binding
0161  *
0162  * This function is in charge of allocating the cpuidle cooling device
0163  * structure, the idle injection, initialize them and register the
0164  * cooling device to the thermal framework.
0165  *
0166  * Return: zero on success, a negative value returned by one of the
0167  * underlying subsystem in case of error
0168  */
0169 static int __cpuidle_cooling_register(struct device_node *np,
0170                       struct cpuidle_driver *drv)
0171 {
0172     struct idle_inject_device *ii_dev;
0173     struct cpuidle_cooling_device *idle_cdev;
0174     struct thermal_cooling_device *cdev;
0175     struct device *dev;
0176     unsigned int idle_duration_us = TICK_USEC;
0177     unsigned int latency_us = UINT_MAX;
0178     char *name;
0179     int ret;
0180 
0181     idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL);
0182     if (!idle_cdev) {
0183         ret = -ENOMEM;
0184         goto out;
0185     }
0186 
0187     ii_dev = idle_inject_register(drv->cpumask);
0188     if (!ii_dev) {
0189         ret = -EINVAL;
0190         goto out_kfree;
0191     }
0192 
0193     of_property_read_u32(np, "duration-us", &idle_duration_us);
0194     of_property_read_u32(np, "exit-latency-us", &latency_us);
0195 
0196     idle_inject_set_duration(ii_dev, TICK_USEC, idle_duration_us);
0197     idle_inject_set_latency(ii_dev, latency_us);
0198 
0199     idle_cdev->ii_dev = ii_dev;
0200 
0201     dev = get_cpu_device(cpumask_first(drv->cpumask));
0202 
0203     name = kasprintf(GFP_KERNEL, "idle-%s", dev_name(dev));
0204     if (!name) {
0205         ret = -ENOMEM;
0206         goto out_unregister;
0207     }
0208 
0209     cdev = thermal_of_cooling_device_register(np, name, idle_cdev,
0210                           &cpuidle_cooling_ops);
0211     if (IS_ERR(cdev)) {
0212         ret = PTR_ERR(cdev);
0213         goto out_kfree_name;
0214     }
0215 
0216     pr_debug("%s: Idle injection set with idle duration=%u, latency=%u\n",
0217          name, idle_duration_us, latency_us);
0218 
0219     kfree(name);
0220 
0221     return 0;
0222 
0223 out_kfree_name:
0224     kfree(name);
0225 out_unregister:
0226     idle_inject_unregister(ii_dev);
0227 out_kfree:
0228     kfree(idle_cdev);
0229 out:
0230     return ret;
0231 }
0232 
0233 /**
0234  * cpuidle_cooling_register - Idle cooling device initialization function
0235  * @drv: a cpuidle driver structure pointer
0236  *
0237  * This function is in charge of creating a cooling device per cpuidle
0238  * driver and register it to the thermal framework.
0239  *
0240  * Return: zero on success, or negative value corresponding to the
0241  * error detected in the underlying subsystems.
0242  */
0243 void cpuidle_cooling_register(struct cpuidle_driver *drv)
0244 {
0245     struct device_node *cooling_node;
0246     struct device_node *cpu_node;
0247     int cpu, ret;
0248 
0249     for_each_cpu(cpu, drv->cpumask) {
0250 
0251         cpu_node = of_cpu_device_node_get(cpu);
0252 
0253         cooling_node = of_get_child_by_name(cpu_node, "thermal-idle");
0254 
0255         of_node_put(cpu_node);
0256 
0257         if (!cooling_node) {
0258             pr_debug("'thermal-idle' node not found for cpu%d\n", cpu);
0259             continue;
0260         }
0261 
0262         ret = __cpuidle_cooling_register(cooling_node, drv);
0263 
0264         of_node_put(cooling_node);
0265 
0266         if (ret) {
0267             pr_err("Failed to register the cpuidle cooling device" \
0268                    "for cpu%d: %d\n", cpu, ret);
0269             break;
0270         }
0271     }
0272 }