^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2019 Linaro Limited.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define pr_fmt(fmt) "cpuidle cooling: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/cpu_cooling.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/cpuidle.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/idle_inject.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/idr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * struct cpuidle_cooling_device - data for the idle cooling device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * @ii_dev: an atomic to keep track of the last task exiting the idle cycle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * @state: a normalized integer giving the state of the cooling device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct cpuidle_cooling_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct idle_inject_device *ii_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned long state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static DEFINE_IDA(cpuidle_ida);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * cpuidle_cooling_runtime - Running time computation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * @idle_duration_us: CPU idle time to inject in microseconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * @state: a percentile based number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * The running duration is computed from the idle injection duration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * which is fixed. If we reach 100% of idle injection ratio, that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * means the running duration is zero. If we have a 50% ratio
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * injection, that means we have equal duration for idle and for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * running duration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * The formula is deduced as follows:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * running = idle x ((100 / ratio) - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * For precision purpose for integer math, we use the following:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * running = (idle x 100) / ratio - idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * For example, if we have an injected duration of 50%, then we end up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * with 10ms of idle injection and 10ms of running duration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * Return: An unsigned int for a usec based runtime duration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static unsigned int cpuidle_cooling_runtime(unsigned int idle_duration_us,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned long state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (!state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return ((idle_duration_us * 100) / state) - idle_duration_us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * cpuidle_cooling_get_max_state - Get the maximum state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * @cdev : the thermal cooling device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * @state : a pointer to the state variable to be filled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * The function always returns 100 as the injection ratio. It is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * percentile based for consistency accross different platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * Return: The function can not fail, it is always zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static int cpuidle_cooling_get_max_state(struct thermal_cooling_device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) unsigned long *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Depending on the configuration or the hardware, the running
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * cycle and the idle cycle could be different. We want to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * unify that to an 0..100 interval, so the set state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * interface will be the same whatever the platform is.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * The state 100% will make the cluster 100% ... idle. A 0%
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * injection ratio means no idle injection at all and 50%
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * means for 10ms of idle injection, we have 10ms of running
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) *state = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * cpuidle_cooling_get_cur_state - Get the current cooling state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * @cdev: the thermal cooling device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * @state: a pointer to the state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * The function just copies the state value from the private thermal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * cooling device structure, the mapping is 1 <-> 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Return: The function can not fail, it is always zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static int cpuidle_cooling_get_cur_state(struct thermal_cooling_device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) unsigned long *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct cpuidle_cooling_device *idle_cdev = cdev->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) *state = idle_cdev->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * cpuidle_cooling_set_cur_state - Set the current cooling state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * @cdev: the thermal cooling device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * @state: the target state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * The function checks first if we are initiating the mitigation which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * in turn wakes up all the idle injection tasks belonging to the idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * cooling device. In any case, it updates the internal state for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * cooling device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * Return: The function can not fail, it is always zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static int cpuidle_cooling_set_cur_state(struct thermal_cooling_device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned long state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct cpuidle_cooling_device *idle_cdev = cdev->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct idle_inject_device *ii_dev = idle_cdev->ii_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) unsigned long current_state = idle_cdev->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) unsigned int runtime_us, idle_duration_us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) idle_cdev->state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) idle_inject_get_duration(ii_dev, &runtime_us, &idle_duration_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) runtime_us = cpuidle_cooling_runtime(idle_duration_us, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) idle_inject_set_duration(ii_dev, runtime_us, idle_duration_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (current_state == 0 && state > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) idle_inject_start(ii_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) } else if (current_state > 0 && !state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) idle_inject_stop(ii_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * cpuidle_cooling_ops - thermal cooling device ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static struct thermal_cooling_device_ops cpuidle_cooling_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .get_max_state = cpuidle_cooling_get_max_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .get_cur_state = cpuidle_cooling_get_cur_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .set_cur_state = cpuidle_cooling_set_cur_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * __cpuidle_cooling_register: register the cooling device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * @drv: a cpuidle driver structure pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * @np: a device node structure pointer used for the thermal binding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * This function is in charge of allocating the cpuidle cooling device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * structure, the idle injection, initialize them and register the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * cooling device to the thermal framework.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * Return: zero on success, a negative value returned by one of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * underlying subsystem in case of error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static int __cpuidle_cooling_register(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct cpuidle_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct idle_inject_device *ii_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) struct cpuidle_cooling_device *idle_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct thermal_cooling_device *cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) unsigned int idle_duration_us = TICK_USEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) unsigned int latency_us = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) char dev_name[THERMAL_NAME_LENGTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) int id, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (!idle_cdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) id = ida_simple_get(&cpuidle_ida, 0, 0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (id < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ret = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) goto out_kfree;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) ii_dev = idle_inject_register(drv->cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (!ii_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) goto out_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) of_property_read_u32(np, "duration-us", &idle_duration_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) of_property_read_u32(np, "exit-latency-us", &latency_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) idle_inject_set_duration(ii_dev, TICK_USEC, idle_duration_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) idle_inject_set_latency(ii_dev, latency_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) idle_cdev->ii_dev = ii_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) snprintf(dev_name, sizeof(dev_name), "thermal-idle-%d", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) cdev = thermal_of_cooling_device_register(np, dev_name, idle_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) &cpuidle_cooling_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (IS_ERR(cdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) ret = PTR_ERR(cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) goto out_unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) pr_debug("%s: Idle injection set with idle duration=%u, latency=%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) dev_name, idle_duration_us, latency_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) out_unregister:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) idle_inject_unregister(ii_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) out_id:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ida_simple_remove(&cpuidle_ida, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) out_kfree:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) kfree(idle_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * cpuidle_cooling_register - Idle cooling device initialization function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * @drv: a cpuidle driver structure pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * This function is in charge of creating a cooling device per cpuidle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * driver and register it to the thermal framework.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Return: zero on success, or negative value corresponding to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * error detected in the underlying subsystems.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) void cpuidle_cooling_register(struct cpuidle_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct device_node *cooling_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct device_node *cpu_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) int cpu, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) for_each_cpu(cpu, drv->cpumask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) cpu_node = of_cpu_device_node_get(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) cooling_node = of_get_child_by_name(cpu_node, "thermal-idle");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) of_node_put(cpu_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (!cooling_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) pr_debug("'thermal-idle' node not found for cpu%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ret = __cpuidle_cooling_register(cooling_node, drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) of_node_put(cooling_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) pr_err("Failed to register the cpuidle cooling device" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) "for cpu%d: %d\n", cpu, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }