From 32a205ef78661de621fa5d2dbed56d0e3f4230a2 Mon Sep 17 00:00:00 2001 From: Park Chungwoo Date: Fri, 18 Mar 2016 13:13:32 +0900 Subject: [PATCH] thermal: Apply gpu cooling related code. Change-Id: I594bd9293c7f5c72a5fb51a6e9bd7531b159faa6 Signed-off-by: Park Chungwoo Signed-off-by: Hyeonseong Gil --- drivers/thermal/Kconfig | 9 + drivers/thermal/Makefile | 2 + drivers/thermal/gpu_cooling.c | 462 +++++++++++++++++++++++++++ drivers/thermal/samsung/exynos_tmu.c | 99 +++++- include/linux/gpu_cooling.h | 89 ++++++ 5 files changed, 657 insertions(+), 4 deletions(-) create mode 100644 drivers/thermal/gpu_cooling.c create mode 100755 include/linux/gpu_cooling.h diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 07002df4f83a..f45874eb85b2 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -180,6 +180,15 @@ config DEVFREQ_THERMAL If you want this support, you should say Y here. +config GPU_THERMAL + bool "generic gpu cooling support" + depends on THERMAL_OF + help + This implements the generic gpu cooling mechanism through frequency + reduction. + + If you want this support, you should say Y here. + config THERMAL_EMULATION bool "Thermal emulation mode support" help diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 195cd08fbc30..2cf1a1fe0a06 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -27,6 +27,8 @@ thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o # devfreq cooling thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o +thermal_sys-$(CONFIG_GPU_THERMAL) += gpu_cooling.o + # platform thermal drivers obj-y += broadcom/ obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o diff --git a/drivers/thermal/gpu_cooling.c b/drivers/thermal/gpu_cooling.c new file mode 100644 index 000000000000..852c4ab01d40 --- /dev/null +++ b/drivers/thermal/gpu_cooling.c @@ -0,0 +1,462 @@ +/* + * linux/drivers/thermal/gpu_cooling.c + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) + * Copyright (C) 2012 Amit Daniel + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct gpufreq_cooling_device - data for cooling device with gpufreq + * @id: unique integer value corresponding to each gpufreq_cooling_device + * registered. + * @cool_dev: thermal_cooling_device pointer to keep track of the + * registered cooling device. + * @gpufreq_state: integer value representing the current state of gpufreq + * cooling devices. + * @gpufreq_val: integer value representing the absolute value of the clipped + * frequency. + * @allowed_gpus: all the gpus involved for this gpufreq_cooling_device. + * + * This structure is required for keeping information of each + * gpufreq_cooling_device registered. In order to prevent corruption of this a + * mutex lock cooling_gpu_lock is used. + */ +struct gpufreq_cooling_device { + int id; + struct thermal_cooling_device *cool_dev; + unsigned int gpufreq_state; + unsigned int gpufreq_val; +}; +static DEFINE_IDR(gpufreq_idr); +static DEFINE_MUTEX(cooling_gpu_lock); +static BLOCKING_NOTIFIER_HEAD(gpu_notifier); + +static unsigned int gpufreq_dev_count; + +extern struct cpufreq_frequency_table gpu_freq_table[]; + +/** + * get_idr - function to get a unique id. + * @idr: struct idr * handle used to create a id. + * @id: int * value generated by this function. + * + * This function will populate @id with an unique + * id, using the idr API. + * + * Return: 0 on success, an error code on failure. + */ +static int get_idr(struct idr *idr, int *id) +{ + int ret; + + mutex_lock(&cooling_gpu_lock); + ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL); + mutex_unlock(&cooling_gpu_lock); + if (unlikely(ret < 0)) + return ret; + *id = ret; + + return 0; +} + +/** + * release_idr - function to free the unique id. + * @idr: struct idr * handle used for creating the id. + * @id: int value representing the unique id. + */ +static void release_idr(struct idr *idr, int id) +{ + mutex_lock(&cooling_gpu_lock); + idr_remove(idr, id); + mutex_unlock(&cooling_gpu_lock); +} + +/* Below code defines functions to be used for gpufreq as cooling device */ + +enum gpufreq_cooling_property { + GET_LEVEL, + GET_FREQ, + GET_MAXL, +}; + +/** + * get_property - fetch a property of interest for a give gpu. + * @gpu: gpu for which the property is required + * @input: query parameter + * @output: query return + * @property: type of query (frequency, level, max level) + * + * This is the common function to + * 1. get maximum gpu cooling states + * 2. translate frequency to cooling state + * 3. translate cooling state to frequency + * Note that the code may be not in good shape + * but it is written in this way in order to: + * a) reduce duplicate code as most of the code can be shared. + * b) make sure the logic is consistent when translating between + * cooling states and frequencies. + * + * Return: 0 on success, -EINVAL when invalid parameters are passed. + */ +static int get_property(unsigned int gpu, unsigned long input, + unsigned int *output, + enum gpufreq_cooling_property property) +{ + int i; + unsigned long max_level = 0, level = 0; + unsigned int freq = CPUFREQ_ENTRY_INVALID; + int descend = -1; + struct cpufreq_frequency_table *pos, *table = + gpu_freq_table; + + if (!output) + return -EINVAL; + + if (!table) + return -EINVAL; + + cpufreq_for_each_valid_entry(pos, table) { + /* ignore duplicate entry */ + if (freq == pos->frequency) + continue; + + /* get the frequency order */ + if (freq != CPUFREQ_ENTRY_INVALID && descend == -1) + descend = freq > pos->frequency; + + freq = pos->frequency; + max_level++; + } + + /* No valid cpu frequency entry */ + if (max_level == 0) + return -EINVAL; + + /* max_level is an index, not a counter */ + max_level--; + + /* get max level */ + if (property == GET_MAXL) { + *output = (unsigned int)max_level; + return 0; + } + + if (property == GET_FREQ) + level = descend ? input : (max_level - input); + + i = 0; + cpufreq_for_each_valid_entry(pos, table) { + /* ignore duplicate entry */ + if (freq == pos->frequency) + continue; + + /* now we have a valid frequency entry */ + freq = pos->frequency; + + if (property == GET_LEVEL && (unsigned int)input == freq) { + /* get level by frequency */ + *output = descend ? i : (max_level - i); + return 0; + } + if (property == GET_FREQ && level == i) { + /* get frequency by level */ + *output = freq; + return 0; + } + i++; + } + + return -EINVAL; +} + +/** + * gpufreq_cooling_get_level - for a give gpu, return the cooling level. + * @gpu: gpu for which the level is required + * @freq: the frequency of interest + * + * This function will match the cooling level corresponding to the + * requested @freq and return it. + * + * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID + * otherwise. + */ +unsigned long gpufreq_cooling_get_level(unsigned int gpu, unsigned int freq) +{ + unsigned int val; + + if (get_property(gpu, (unsigned long)freq, &val, GET_LEVEL)) + return THERMAL_CSTATE_INVALID; + + return (unsigned long)val; +} +EXPORT_SYMBOL_GPL(gpufreq_cooling_get_level); + +/** + * gpufreq_apply_cooling - function to apply frequency clipping. + * @gpufreq_device: gpufreq_cooling_device pointer containing frequency + * clipping data. + * @cooling_state: value of the cooling state. + * + * Function used to make sure the gpufreq layer is aware of current thermal + * limits. The limits are applied by updating the gpufreq policy. + * + * Return: 0 on success, an error code otherwise (-EINVAL in case wrong + * cooling state). + */ +static int gpufreq_apply_cooling(struct gpufreq_cooling_device *gpufreq_device, + unsigned long cooling_state) +{ + /* Check if the old cooling action is same as new cooling action */ + if (gpufreq_device->gpufreq_state == cooling_state) + return 0; + + gpufreq_device->gpufreq_state = cooling_state; + + blocking_notifier_call_chain(&gpu_notifier, GPU_THROTTLING, &cooling_state); + + return 0; +} + +/* gpufreq cooling device callback functions are defined below */ + +/** + * gpufreq_get_max_state - callback function to get the max cooling state. + * @cdev: thermal cooling device pointer. + * @state: fill this variable with the max cooling state. + * + * Callback for the thermal cooling device to return the gpufreq + * max cooling state. + * + * Return: 0 on success, an error code otherwise. + */ +static int gpufreq_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + unsigned int count = 0; + int ret; + + ret = get_property(0, 0, &count, GET_MAXL); + + if (count > 0) + *state = count; + + return ret; +} + +/** + * gpufreq_get_cur_state - callback function to get the current cooling state. + * @cdev: thermal cooling device pointer. + * @state: fill this variable with the current cooling state. + * + * Callback for the thermal cooling device to return the gpufreq + * current cooling state. + * + * Return: 0 on success, an error code otherwise. + */ +static int gpufreq_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct gpufreq_cooling_device *gpufreq_device = cdev->devdata; + + *state = gpufreq_device->gpufreq_state; + + return 0; +} + +/** + * gpufreq_set_cur_state - callback function to set the current cooling state. + * @cdev: thermal cooling device pointer. + * @state: set this variable to the current cooling state. + * + * Callback for the thermal cooling device to change the gpufreq + * current cooling state. + * + * Return: 0 on success, an error code otherwise. + */ +static int gpufreq_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct gpufreq_cooling_device *gpufreq_device = cdev->devdata; + + return gpufreq_apply_cooling(gpufreq_device, state); +} + +static enum tmu_noti_state_t gpu_tstate = GPU_COLD; + +static int gpufreq_set_cur_temp(struct thermal_cooling_device *cdev, + bool suspended, int temp) +{ + enum tmu_noti_state_t tstate; + + if (suspended || temp < EXYNOS_COLD_TEMP) + tstate = GPU_COLD; + else + tstate = GPU_NORMAL; + + if (gpu_tstate == tstate) + return 0; + + gpu_tstate = tstate; + + blocking_notifier_call_chain(&gpu_notifier, tstate, &tstate); + + return 0; +} + +/* Bind gpufreq callbacks to thermal cooling device ops */ +static struct thermal_cooling_device_ops const gpufreq_cooling_ops = { + .get_max_state = gpufreq_get_max_state, + .get_cur_state = gpufreq_get_cur_state, + .set_cur_state = gpufreq_set_cur_state, + .set_cur_temp = gpufreq_set_cur_temp, +}; + + +int exynos_gpu_add_notifier(struct notifier_block *n) +{ + return blocking_notifier_chain_register(&gpu_notifier, n); +} + +/** + * __gpufreq_cooling_register - helper function to create gpufreq cooling device + * @np: a valid struct device_node to the cooling device device tree node + * @clip_gpus: gpumask of gpus where the frequency constraints will happen. + * + * This interface function registers the gpufreq cooling device with the name + * "thermal-gpufreq-%x". This api can support multiple instances of gpufreq + * cooling devices. It also gives the opportunity to link the cooling device + * with a device tree node, in order to bind it via the thermal DT code. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +static struct thermal_cooling_device * +__gpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_gpus) +{ + struct thermal_cooling_device *cool_dev; + struct gpufreq_cooling_device *gpufreq_dev = NULL; + char dev_name[THERMAL_NAME_LENGTH]; + int ret = 0; + + gpufreq_dev = kzalloc(sizeof(struct gpufreq_cooling_device), + GFP_KERNEL); + if (!gpufreq_dev) + return ERR_PTR(-ENOMEM); + + ret = get_idr(&gpufreq_idr, &gpufreq_dev->id); + if (ret) { + kfree(gpufreq_dev); + return ERR_PTR(-EINVAL); + } + + snprintf(dev_name, sizeof(dev_name), "thermal-gpufreq-%d", + gpufreq_dev->id); + + cool_dev = thermal_of_cooling_device_register(np, dev_name, gpufreq_dev, + &gpufreq_cooling_ops); + if (IS_ERR(cool_dev)) { + release_idr(&gpufreq_idr, gpufreq_dev->id); + kfree(gpufreq_dev); + return cool_dev; + } + gpufreq_dev->cool_dev = cool_dev; + gpufreq_dev->gpufreq_state = 0; + mutex_lock(&cooling_gpu_lock); + + gpufreq_dev_count++; + + mutex_unlock(&cooling_gpu_lock); + + return cool_dev; +} + +/** + * gpufreq_cooling_register - function to create gpufreq cooling device. + * @clip_gpus: cpumask of gpus where the frequency constraints will happen. + * + * This interface function registers the gpufreq cooling device with the name + * "thermal-gpufreq-%x". This api can support multiple instances of gpufreq + * cooling devices. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +struct thermal_cooling_device * +gpufreq_cooling_register(const struct cpumask *clip_gpus) +{ + return __gpufreq_cooling_register(NULL, clip_gpus); +} +EXPORT_SYMBOL_GPL(gpufreq_cooling_register); + +/** + * of_gpufreq_cooling_register - function to create gpufreq cooling device. + * @np: a valid struct device_node to the cooling device device tree node + * @clip_gpus: cpumask of gpus where the frequency constraints will happen. + * + * This interface function registers the gpufreq cooling device with the name + * "thermal-gpufreq-%x". This api can support multiple instances of gpufreq + * cooling devices. Using this API, the gpufreq cooling device will be + * linked to the device tree node provided. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +struct thermal_cooling_device * +of_gpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_gpus) +{ + if (!np) + return ERR_PTR(-EINVAL); + + return __gpufreq_cooling_register(np, clip_gpus); +} +EXPORT_SYMBOL_GPL(of_gpufreq_cooling_register); + +/** + * gpufreq_cooling_unregister - function to remove gpufreq cooling device. + * @cdev: thermal cooling device pointer. + * + * This interface function unregisters the "thermal-gpufreq-%x" cooling device. + */ +void gpufreq_cooling_unregister(struct thermal_cooling_device *cdev) +{ + struct gpufreq_cooling_device *gpufreq_dev; + + if (!cdev) + return; + + gpufreq_dev = cdev->devdata; + mutex_lock(&cooling_gpu_lock); + gpufreq_dev_count--; + mutex_unlock(&cooling_gpu_lock); + + thermal_cooling_device_unregister(gpufreq_dev->cool_dev); + release_idr(&gpufreq_idr, gpufreq_dev->id); + kfree(gpufreq_dev); +} +EXPORT_SYMBOL_GPL(gpufreq_cooling_unregister); diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 764a475642f9..c3496d6a99f0 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include "exynos_tmu.h" @@ -106,6 +108,8 @@ static DEFINE_MUTEX (thermal_suspend_lock); /* list of multiple instance for each thermal sensor */ static LIST_HEAD(dtm_dev_list); +struct cpufreq_frequency_table gpu_freq_table[10]; + /** * struct exynos_tmu_data : A structure to hold the private data of the TMU driver @@ -702,6 +706,46 @@ static int exynos_map_dt_data(struct platform_device *pdev) return 0; } +#ifdef CONFIG_GPU_THERMAL +static int gpu_cooling_table_init(struct platform_device *pdev) +{ + struct cpufreq_frequency_table *table_ptr; + unsigned int table_size; + u32 gpu_idx_num = 0; + int ret = 0, i = 0; + + /* gpu cooling frequency table parse */ + ret = of_property_read_u32(pdev->dev.of_node, "gpu_idx_num", + &gpu_idx_num); + if (ret < 0) + dev_err(&pdev->dev, "gpu_idx_num happend error value\n"); + + if (gpu_idx_num) { + table_ptr = kzalloc(sizeof(struct cpufreq_frequency_table) + * gpu_idx_num, GFP_KERNEL); + if (!table_ptr) { + dev_err(&pdev->dev, "failed to allocate for gpu_table\n"); + return -ENODEV; + } + table_size = sizeof(struct cpufreq_frequency_table) / + sizeof(unsigned int); + ret = of_property_read_u32_array(pdev->dev.of_node, "gpu_cooling_table", + (unsigned int *)table_ptr, table_size * gpu_idx_num); + + for (i = 0; i < gpu_idx_num; i++) { + gpu_freq_table[i].flags = table_ptr[i].flags; + gpu_freq_table[i].driver_data = table_ptr[i].driver_data; + gpu_freq_table[i].frequency = table_ptr[i].frequency; + dev_info(&pdev->dev, "[GPU TMU] index : %d, frequency : %d \n", + gpu_freq_table[i].driver_data, gpu_freq_table[i].frequency); + } + kfree(table_ptr); + } + return ret; +} +#else +static int gpu_cooling_table_init(struct platform_device *pdev) {return 0;} +#endif struct pm_qos_request thermal_cpu_hotplug_request; static int exynos_throttle_cpu_hotplug(void *p, int temp) @@ -789,6 +833,41 @@ static int exynos_cpufreq_cooling_register(struct exynos_tmu_data *data) return ret; } +#ifdef CONFIG_GPU_THERMAL +static int exynos_gpufreq_cooling_register(struct exynos_tmu_data *data) +{ + struct device_node *np, *child = NULL, *gchild, *ggchild; + struct device_node *cool_np; + struct of_phandle_args cooling_spec; + int ret, i; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return -ENODEV; + + /* Regist gpufreq cooling device */ + for (i = 0; i <= data->id; i++) { + child = of_get_next_child(np, child); + if (i == data->id) + break; + } + gchild = of_get_child_by_name(child, "cooling-maps"); + ggchild = of_get_next_child(gchild, NULL); + ret = of_parse_phandle_with_args(ggchild, "cooling-device", "#cooling-cells", + 0, &cooling_spec); + if (ret < 0) { + pr_err("exynos_tmu do not get cooling spec \n"); + } + cool_np = cooling_spec.np; + + data->cool_dev = of_gpufreq_cooling_register(cool_np, NULL); + + return ret; +} +#else +static int exynos_gpufreq_cooling_register(struct exynos_tmu_data *data) {return 0;} +#endif + static int exynos_tmu_probe(struct platform_device *pdev) { struct exynos_tmu_data *data; @@ -809,10 +888,22 @@ static int exynos_tmu_probe(struct platform_device *pdev) if (ret) goto err_sensor; - ret = exynos_cpufreq_cooling_register(data); - if (ret) { - dev_err(&pdev->dev, "Failed cooling register \n"); - goto err_sensor; + if (data->id == 0 || data->id == 1) { + ret = exynos_cpufreq_cooling_register(data); + if (ret) { + dev_err(&pdev->dev, "Failed cooling register \n"); + goto err_sensor; + } + } else if (data->id == 2) { + ret = gpu_cooling_table_init(pdev); + if (ret) + goto err_sensor; + + ret = exynos_gpufreq_cooling_register(data); + if (ret) { + dev_err(&pdev->dev, "Failed cooling register \n"); + goto err_sensor; + } } INIT_WORK(&data->irq_work, exynos_tmu_work); diff --git a/include/linux/gpu_cooling.h b/include/linux/gpu_cooling.h new file mode 100755 index 000000000000..1a2435d9b34e --- /dev/null +++ b/include/linux/gpu_cooling.h @@ -0,0 +1,89 @@ +/* + * linux/include/linux/gpu_cooling.h + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) + * Copyright (C) 2012 Amit Daniel + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#ifndef __GPU_COOLING_H__ +#define __GPU_COOLING_H__ + +#include +#include +#include + +#ifdef CONFIG_GPU_THERMAL + +/** + * gpufreq_cooling_register - function to create gpufreq cooling device. + * @clip_gpus: cpumask of gpus where the frequency constraints will happen + */ +struct thermal_cooling_device * +gpufreq_cooling_register(const struct cpumask *clip_gpus); + +/** + * of_gpufreq_cooling_register - create gpufreq cooling device based on DT. + * @np: a valid struct device_node to the cooling device device tree node. + * @clip_gpus: cpumask of gpus where the frequency constraints will happen + */ +#ifdef CONFIG_THERMAL_OF +struct thermal_cooling_device * +of_gpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_gpus); +#else +static inline struct thermal_cooling_device * +of_gpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_gpus) +{ + return NULL; +} +#endif + +/** + * gpufreq_cooling_unregister - function to remove gpufreq cooling device. + * @cdev: thermal cooling device pointer. + */ +void gpufreq_cooling_unregister(struct thermal_cooling_device *cdev); + +unsigned long gpufreq_cooling_get_level(unsigned int gpu, unsigned int freq); +#else /* !CONFIG_GPU_THERMAL */ +static inline struct thermal_cooling_device * +gpufreq_cooling_register(const struct cpumask *clip_gpus) +{ + return NULL; +} +static inline struct thermal_cooling_device * +of_gpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_gpus) +{ + return NULL; +} +static inline +void gpufreq_cooling_unregister(struct thermal_cooling_device *cdev) +{ + return; +} +static inline +unsigned long gpufreq_cooling_get_level(unsigned int gpu, unsigned int freq) +{ + return THERMAL_CSTATE_INVALID; +} +#endif /* CONFIG_GPU_THERMAL */ + +#endif /* __GPU_COOLING_H__ */ -- 2.20.1