Loading drivers/thermal/cpu_cooling.c +135 −224 Original line number Diff line number Diff line Loading @@ -4,6 +4,8 @@ * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> * * Copyright (C) 2014 Viresh Kumar <viresh.kumar@linaro.org> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 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 Loading @@ -28,6 +30,20 @@ #include <linux/cpu.h> #include <linux/cpu_cooling.h> /* * Cooling state <-> CPUFreq frequency * * Cooling states are translated to frequencies throughout this driver and this * is the relation between them. * * Highest cooling state corresponds to lowest possible frequency. * * i.e. * level 0 --> 1st Max Freq * level 1 --> 2nd Max Freq * ... */ /** * struct cpufreq_cooling_device - data for cooling device with cpufreq * @id: unique integer value corresponding to each cpufreq_cooling_device Loading @@ -38,26 +54,27 @@ * cooling devices. * @cpufreq_val: integer value representing the absolute value of the clipped * frequency. * @max_level: maximum cooling level. One less than total number of valid * cpufreq frequencies. * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. * @node: list_head to link all cpufreq_cooling_device together. * * This structure is required for keeping information of each * cpufreq_cooling_device registered. In order to prevent corruption of this a * mutex lock cooling_cpufreq_lock is used. * This structure is required for keeping information of each registered * cpufreq_cooling_device. */ struct cpufreq_cooling_device { int id; struct thermal_cooling_device *cool_dev; unsigned int cpufreq_state; unsigned int cpufreq_val; unsigned int max_level; unsigned int *freq_table; /* In descending order */ struct cpumask allowed_cpus; struct list_head node; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); static unsigned int cpufreq_dev_count; static LIST_HEAD(cpufreq_dev_list); /** Loading Loading @@ -99,120 +116,30 @@ static void release_idr(struct idr *idr, int id) /* Below code defines functions to be used for cpufreq as cooling device */ /** * is_cpufreq_valid - function to check frequency transitioning capability. * @cpu: cpu for which check is needed. * * This function will check the current state of the system if * it is capable of changing the frequency for a given @cpu. * * Return: 0 if the system is not currently capable of changing * the frequency of given cpu. !0 in case the frequency is changeable. */ static int is_cpufreq_valid(int cpu) { struct cpufreq_policy policy; return !cpufreq_get_policy(&policy, cpu); } enum cpufreq_cooling_property { GET_LEVEL, GET_FREQ, GET_MAXL, }; /** * get_property - fetch a property of interest for a give cpu. * @cpu: cpu for which the property is required * @input: query parameter * @output: query return * @property: type of query (frequency, level, max level) * get_level: Find the level for a particular frequency * @cpufreq_dev: cpufreq_dev for which the property is required * @freq: Frequency * * This is the common function to * 1. get maximum cpu 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. * Return: level on success, THERMAL_CSTATE_INVALID on error. */ static int get_property(unsigned int cpu, unsigned long input, unsigned int *output, enum cpufreq_cooling_property property) static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev, unsigned int freq) { int i; unsigned long max_level = 0, level = 0; unsigned int freq = CPUFREQ_ENTRY_INVALID; int descend = -1; struct cpufreq_frequency_table *pos, *table = cpufreq_frequency_get_table(cpu); 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--; unsigned long 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; for (level = 0; level <= cpufreq_dev->max_level; level++) { if (freq == cpufreq_dev->freq_table[level]) return level; /* 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++; if (freq > cpufreq_dev->freq_table[level]) break; } return -EINVAL; return THERMAL_CSTATE_INVALID; } /** * cpufreq_cooling_get_level - for a give cpu, return the cooling level. * cpufreq_cooling_get_level - for a given cpu, return the cooling level. * @cpu: cpu for which the level is required * @freq: the frequency of interest * Loading @@ -224,77 +151,21 @@ static int get_property(unsigned int cpu, unsigned long input, */ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) { unsigned int val; if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL)) return THERMAL_CSTATE_INVALID; struct cpufreq_cooling_device *cpufreq_dev; return (unsigned long)val; mutex_lock(&cooling_cpufreq_lock); list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { mutex_unlock(&cooling_cpufreq_lock); return get_level(cpufreq_dev, freq); } EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); /** * get_cpu_frequency - get the absolute value of frequency from level. * @cpu: cpu for which frequency is fetched. * @level: cooling level * * This function matches cooling level with frequency. Based on a cooling level * of frequency, equals cooling state of cpu cooling device, it will return * the corresponding frequency. * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc * * Return: 0 on error, the corresponding frequency otherwise. */ static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) { int ret = 0; unsigned int freq; ret = get_property(cpu, level, &freq, GET_FREQ); if (ret) return 0; return freq; } /** * cpufreq_apply_cooling - function to apply frequency clipping. * @cpufreq_device: cpufreq_cooling_device pointer containing frequency * clipping data. * @cooling_state: value of the cooling state. * * Function used to make sure the cpufreq layer is aware of current thermal * limits. The limits are applied by updating the cpufreq policy. * * Return: 0 on success, an error code otherwise (-EINVAL in case wrong * cooling state). */ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, unsigned long cooling_state) { unsigned int cpuid, clip_freq; struct cpumask *mask = &cpufreq_device->allowed_cpus; unsigned int cpu = cpumask_any(mask); /* Check if the old cooling action is same as new cooling action */ if (cpufreq_device->cpufreq_state == cooling_state) return 0; clip_freq = get_cpu_frequency(cpu, cooling_state); if (!clip_freq) return -EINVAL; cpufreq_device->cpufreq_state = cooling_state; cpufreq_device->cpufreq_val = clip_freq; for_each_cpu(cpuid, mask) { if (is_cpufreq_valid(cpuid)) cpufreq_update_policy(cpuid); } mutex_unlock(&cooling_cpufreq_lock); return 0; pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu); return THERMAL_CSTATE_INVALID; } EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); /** * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. Loading Loading @@ -324,11 +195,6 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, &cpufreq_dev->allowed_cpus)) continue; if (!cpufreq_dev->cpufreq_val) cpufreq_dev->cpufreq_val = get_cpu_frequency( cpumask_any(&cpufreq_dev->allowed_cpus), cpufreq_dev->cpufreq_state); max_freq = cpufreq_dev->cpufreq_val; if (policy->max != max_freq) Loading @@ -355,19 +221,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpumask *mask = &cpufreq_device->allowed_cpus; unsigned int cpu; unsigned int count = 0; int ret; cpu = cpumask_any(mask); ret = get_property(cpu, 0, &count, GET_MAXL); if (count > 0) *state = count; return ret; *state = cpufreq_device->max_level; return 0; } /** Loading Loading @@ -404,8 +260,24 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); unsigned int clip_freq; /* Request state should be less than max_level */ if (WARN_ON(state > cpufreq_device->max_level)) return -EINVAL; /* Check if the old cooling action is same as new cooling action */ if (cpufreq_device->cpufreq_state == state) return 0; clip_freq = cpufreq_device->freq_table[state]; cpufreq_device->cpufreq_state = state; cpufreq_device->cpufreq_val = clip_freq; cpufreq_update_policy(cpu); return cpufreq_apply_cooling(cpufreq_device, state); return 0; } /* Bind cpufreq callbacks to thermal cooling device ops */ Loading @@ -420,10 +292,25 @@ static struct notifier_block thermal_cpufreq_notifier_block = { .notifier_call = cpufreq_thermal_notifier, }; static unsigned int find_next_max(struct cpufreq_frequency_table *table, unsigned int prev_max) { struct cpufreq_frequency_table *pos; unsigned int max = 0; cpufreq_for_each_valid_entry(pos, table) { if (pos->frequency > max && pos->frequency < prev_max) max = pos->frequency; } return max; } /** * __cpufreq_cooling_register - helper function to create cpufreq cooling device * @np: a valid struct device_node to the cooling device device tree node * @clip_cpus: cpumask of cpus where the frequency constraints will happen. * Normally this should be same as cpufreq policy->related_cpus. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq Loading @@ -438,37 +325,42 @@ __cpufreq_cooling_register(struct device_node *np, const struct cpumask *clip_cpus) { struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev = NULL; unsigned int min = 0, max = 0; struct cpufreq_cooling_device *cpufreq_dev; char dev_name[THERMAL_NAME_LENGTH]; int ret = 0, i; struct cpufreq_policy policy; struct cpufreq_frequency_table *pos, *table; unsigned int freq, i; int ret; /* Verify that all the clip cpus have same freq_min, freq_max limit */ for_each_cpu(i, clip_cpus) { /* continue if cpufreq policy not found and not return error */ if (!cpufreq_get_policy(&policy, i)) continue; if (min == 0 && max == 0) { min = policy.cpuinfo.min_freq; max = policy.cpuinfo.max_freq; } else { if (min != policy.cpuinfo.min_freq || max != policy.cpuinfo.max_freq) return ERR_PTR(-EINVAL); table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); if (!table) { pr_debug("%s: CPUFreq table not found\n", __func__); return ERR_PTR(-EPROBE_DEFER); } } cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), GFP_KERNEL); cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); if (!cpufreq_dev) return ERR_PTR(-ENOMEM); /* Find max levels */ cpufreq_for_each_valid_entry(pos, table) cpufreq_dev->max_level++; cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) * cpufreq_dev->max_level, GFP_KERNEL); if (!cpufreq_dev->freq_table) { cool_dev = ERR_PTR(-ENOMEM); goto free_cdev; } /* max_level is an index, not a counter */ cpufreq_dev->max_level--; cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); if (ret) { kfree(cpufreq_dev); return ERR_PTR(-EINVAL); cool_dev = ERR_PTR(ret); goto free_table; } snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", Loading @@ -476,24 +368,43 @@ __cpufreq_cooling_register(struct device_node *np, cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, &cpufreq_cooling_ops); if (IS_ERR(cool_dev)) { release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev); return cool_dev; if (IS_ERR(cool_dev)) goto remove_idr; /* Fill freq-table in descending order of frequencies */ for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { freq = find_next_max(table, freq); cpufreq_dev->freq_table[i] = freq; /* Warn for duplicate entries */ if (!freq) pr_warn("%s: table has duplicate entries\n", __func__); else pr_debug("%s: freq:%u KHz\n", __func__, freq); } cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0]; cpufreq_dev->cool_dev = cool_dev; cpufreq_dev->cpufreq_state = 0; mutex_lock(&cooling_cpufreq_lock); /* Register the notifier for first cpufreq cooling device */ if (cpufreq_dev_count == 0) if (list_empty(&cpufreq_dev_list)) cpufreq_register_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); cpufreq_dev_count++; list_add(&cpufreq_dev->node, &cpufreq_dev_list); mutex_unlock(&cooling_cpufreq_lock); return cool_dev; remove_idr: release_idr(&cpufreq_idr, cpufreq_dev->id); free_table: kfree(cpufreq_dev->freq_table); free_cdev: kfree(cpufreq_dev); return cool_dev; } Loading Loading @@ -555,16 +466,16 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) cpufreq_dev = cdev->devdata; mutex_lock(&cooling_cpufreq_lock); list_del(&cpufreq_dev->node); cpufreq_dev_count--; /* Unregister the notifier for the last cpufreq cooling device */ if (cpufreq_dev_count == 0) if (list_empty(&cpufreq_dev_list)) cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); mutex_unlock(&cooling_cpufreq_lock); thermal_cooling_device_unregister(cpufreq_dev->cool_dev); release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev->freq_table); kfree(cpufreq_dev); } EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); drivers/thermal/db8500_cpufreq_cooling.c +9 −11 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ */ #include <linux/cpu_cooling.h> #include <linux/cpufreq.h> #include <linux/err.h> #include <linux/module.h> #include <linux/of.h> Loading @@ -28,18 +27,17 @@ static int db8500_cpufreq_cooling_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; struct cpumask mask_val; /* make sure cpufreq driver has been initialized */ if (!cpufreq_frequency_get_table(0)) return -EPROBE_DEFER; cdev = cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(cdev)) { int ret = PTR_ERR(cdev); cpumask_set_cpu(0, &mask_val); cdev = cpufreq_cooling_register(&mask_val); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "Failed to register cooling device %d\n", ret); if (IS_ERR(cdev)) { dev_err(&pdev->dev, "Failed to register cooling device\n"); return PTR_ERR(cdev); return ret; } platform_set_drvdata(pdev, cdev); Loading drivers/thermal/imx_thermal.c +5 −10 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ #include <linux/clk.h> #include <linux/cpu_cooling.h> #include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/init.h> Loading Loading @@ -454,15 +453,10 @@ static int imx_thermal_probe(struct platform_device *pdev) const struct of_device_id *of_id = of_match_device(of_imx_thermal_match, &pdev->dev); struct imx_thermal_data *data; struct cpumask clip_cpus; struct regmap *map; int measure_freq; int ret; if (!cpufreq_get_current_driver()) { dev_dbg(&pdev->dev, "no cpufreq driver!"); return -EPROBE_DEFER; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; Loading Loading @@ -516,12 +510,13 @@ static int imx_thermal_probe(struct platform_device *pdev) regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); cpumask_set_cpu(0, &clip_cpus); data->cdev = cpufreq_cooling_register(&clip_cpus); data->cdev = cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(data->cdev)) { ret = PTR_ERR(data->cdev); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "failed to register cpufreq cooling device: %d\n", ret); "failed to register cpufreq cooling device: %d\n", ret); return ret; } Loading drivers/thermal/int340x_thermal/Makefile +1 −0 Original line number Diff line number Diff line obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o drivers/thermal/int340x_thermal/acpi_thermal_rel.c +4 −4 Original line number Diff line number Diff line Loading @@ -82,7 +82,7 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" }; if (!acpi_has_method(handle, "_TRT")) return 0; return -ENODEV; status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer); if (ACPI_FAILURE(status)) Loading Loading @@ -167,7 +167,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" }; if (!acpi_has_method(handle, "_ART")) return 0; return -ENODEV; status = acpi_evaluate_object(handle, "_ART", NULL, &buffer); if (ACPI_FAILURE(status)) Loading Loading @@ -321,8 +321,8 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd, unsigned long length = 0; int count = 0; char __user *arg = (void __user *)__arg; struct trt *trts; struct art *arts; struct trt *trts = NULL; struct art *arts = NULL; switch (cmd) { case ACPI_THERMAL_GET_TRT_COUNT: Loading Loading
drivers/thermal/cpu_cooling.c +135 −224 Original line number Diff line number Diff line Loading @@ -4,6 +4,8 @@ * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> * * Copyright (C) 2014 Viresh Kumar <viresh.kumar@linaro.org> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 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 Loading @@ -28,6 +30,20 @@ #include <linux/cpu.h> #include <linux/cpu_cooling.h> /* * Cooling state <-> CPUFreq frequency * * Cooling states are translated to frequencies throughout this driver and this * is the relation between them. * * Highest cooling state corresponds to lowest possible frequency. * * i.e. * level 0 --> 1st Max Freq * level 1 --> 2nd Max Freq * ... */ /** * struct cpufreq_cooling_device - data for cooling device with cpufreq * @id: unique integer value corresponding to each cpufreq_cooling_device Loading @@ -38,26 +54,27 @@ * cooling devices. * @cpufreq_val: integer value representing the absolute value of the clipped * frequency. * @max_level: maximum cooling level. One less than total number of valid * cpufreq frequencies. * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. * @node: list_head to link all cpufreq_cooling_device together. * * This structure is required for keeping information of each * cpufreq_cooling_device registered. In order to prevent corruption of this a * mutex lock cooling_cpufreq_lock is used. * This structure is required for keeping information of each registered * cpufreq_cooling_device. */ struct cpufreq_cooling_device { int id; struct thermal_cooling_device *cool_dev; unsigned int cpufreq_state; unsigned int cpufreq_val; unsigned int max_level; unsigned int *freq_table; /* In descending order */ struct cpumask allowed_cpus; struct list_head node; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); static unsigned int cpufreq_dev_count; static LIST_HEAD(cpufreq_dev_list); /** Loading Loading @@ -99,120 +116,30 @@ static void release_idr(struct idr *idr, int id) /* Below code defines functions to be used for cpufreq as cooling device */ /** * is_cpufreq_valid - function to check frequency transitioning capability. * @cpu: cpu for which check is needed. * * This function will check the current state of the system if * it is capable of changing the frequency for a given @cpu. * * Return: 0 if the system is not currently capable of changing * the frequency of given cpu. !0 in case the frequency is changeable. */ static int is_cpufreq_valid(int cpu) { struct cpufreq_policy policy; return !cpufreq_get_policy(&policy, cpu); } enum cpufreq_cooling_property { GET_LEVEL, GET_FREQ, GET_MAXL, }; /** * get_property - fetch a property of interest for a give cpu. * @cpu: cpu for which the property is required * @input: query parameter * @output: query return * @property: type of query (frequency, level, max level) * get_level: Find the level for a particular frequency * @cpufreq_dev: cpufreq_dev for which the property is required * @freq: Frequency * * This is the common function to * 1. get maximum cpu 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. * Return: level on success, THERMAL_CSTATE_INVALID on error. */ static int get_property(unsigned int cpu, unsigned long input, unsigned int *output, enum cpufreq_cooling_property property) static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev, unsigned int freq) { int i; unsigned long max_level = 0, level = 0; unsigned int freq = CPUFREQ_ENTRY_INVALID; int descend = -1; struct cpufreq_frequency_table *pos, *table = cpufreq_frequency_get_table(cpu); 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--; unsigned long 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; for (level = 0; level <= cpufreq_dev->max_level; level++) { if (freq == cpufreq_dev->freq_table[level]) return level; /* 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++; if (freq > cpufreq_dev->freq_table[level]) break; } return -EINVAL; return THERMAL_CSTATE_INVALID; } /** * cpufreq_cooling_get_level - for a give cpu, return the cooling level. * cpufreq_cooling_get_level - for a given cpu, return the cooling level. * @cpu: cpu for which the level is required * @freq: the frequency of interest * Loading @@ -224,77 +151,21 @@ static int get_property(unsigned int cpu, unsigned long input, */ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) { unsigned int val; if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL)) return THERMAL_CSTATE_INVALID; struct cpufreq_cooling_device *cpufreq_dev; return (unsigned long)val; mutex_lock(&cooling_cpufreq_lock); list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { mutex_unlock(&cooling_cpufreq_lock); return get_level(cpufreq_dev, freq); } EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); /** * get_cpu_frequency - get the absolute value of frequency from level. * @cpu: cpu for which frequency is fetched. * @level: cooling level * * This function matches cooling level with frequency. Based on a cooling level * of frequency, equals cooling state of cpu cooling device, it will return * the corresponding frequency. * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc * * Return: 0 on error, the corresponding frequency otherwise. */ static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) { int ret = 0; unsigned int freq; ret = get_property(cpu, level, &freq, GET_FREQ); if (ret) return 0; return freq; } /** * cpufreq_apply_cooling - function to apply frequency clipping. * @cpufreq_device: cpufreq_cooling_device pointer containing frequency * clipping data. * @cooling_state: value of the cooling state. * * Function used to make sure the cpufreq layer is aware of current thermal * limits. The limits are applied by updating the cpufreq policy. * * Return: 0 on success, an error code otherwise (-EINVAL in case wrong * cooling state). */ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, unsigned long cooling_state) { unsigned int cpuid, clip_freq; struct cpumask *mask = &cpufreq_device->allowed_cpus; unsigned int cpu = cpumask_any(mask); /* Check if the old cooling action is same as new cooling action */ if (cpufreq_device->cpufreq_state == cooling_state) return 0; clip_freq = get_cpu_frequency(cpu, cooling_state); if (!clip_freq) return -EINVAL; cpufreq_device->cpufreq_state = cooling_state; cpufreq_device->cpufreq_val = clip_freq; for_each_cpu(cpuid, mask) { if (is_cpufreq_valid(cpuid)) cpufreq_update_policy(cpuid); } mutex_unlock(&cooling_cpufreq_lock); return 0; pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu); return THERMAL_CSTATE_INVALID; } EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); /** * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. Loading Loading @@ -324,11 +195,6 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, &cpufreq_dev->allowed_cpus)) continue; if (!cpufreq_dev->cpufreq_val) cpufreq_dev->cpufreq_val = get_cpu_frequency( cpumask_any(&cpufreq_dev->allowed_cpus), cpufreq_dev->cpufreq_state); max_freq = cpufreq_dev->cpufreq_val; if (policy->max != max_freq) Loading @@ -355,19 +221,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; struct cpumask *mask = &cpufreq_device->allowed_cpus; unsigned int cpu; unsigned int count = 0; int ret; cpu = cpumask_any(mask); ret = get_property(cpu, 0, &count, GET_MAXL); if (count > 0) *state = count; return ret; *state = cpufreq_device->max_level; return 0; } /** Loading Loading @@ -404,8 +260,24 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); unsigned int clip_freq; /* Request state should be less than max_level */ if (WARN_ON(state > cpufreq_device->max_level)) return -EINVAL; /* Check if the old cooling action is same as new cooling action */ if (cpufreq_device->cpufreq_state == state) return 0; clip_freq = cpufreq_device->freq_table[state]; cpufreq_device->cpufreq_state = state; cpufreq_device->cpufreq_val = clip_freq; cpufreq_update_policy(cpu); return cpufreq_apply_cooling(cpufreq_device, state); return 0; } /* Bind cpufreq callbacks to thermal cooling device ops */ Loading @@ -420,10 +292,25 @@ static struct notifier_block thermal_cpufreq_notifier_block = { .notifier_call = cpufreq_thermal_notifier, }; static unsigned int find_next_max(struct cpufreq_frequency_table *table, unsigned int prev_max) { struct cpufreq_frequency_table *pos; unsigned int max = 0; cpufreq_for_each_valid_entry(pos, table) { if (pos->frequency > max && pos->frequency < prev_max) max = pos->frequency; } return max; } /** * __cpufreq_cooling_register - helper function to create cpufreq cooling device * @np: a valid struct device_node to the cooling device device tree node * @clip_cpus: cpumask of cpus where the frequency constraints will happen. * Normally this should be same as cpufreq policy->related_cpus. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq Loading @@ -438,37 +325,42 @@ __cpufreq_cooling_register(struct device_node *np, const struct cpumask *clip_cpus) { struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev = NULL; unsigned int min = 0, max = 0; struct cpufreq_cooling_device *cpufreq_dev; char dev_name[THERMAL_NAME_LENGTH]; int ret = 0, i; struct cpufreq_policy policy; struct cpufreq_frequency_table *pos, *table; unsigned int freq, i; int ret; /* Verify that all the clip cpus have same freq_min, freq_max limit */ for_each_cpu(i, clip_cpus) { /* continue if cpufreq policy not found and not return error */ if (!cpufreq_get_policy(&policy, i)) continue; if (min == 0 && max == 0) { min = policy.cpuinfo.min_freq; max = policy.cpuinfo.max_freq; } else { if (min != policy.cpuinfo.min_freq || max != policy.cpuinfo.max_freq) return ERR_PTR(-EINVAL); table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); if (!table) { pr_debug("%s: CPUFreq table not found\n", __func__); return ERR_PTR(-EPROBE_DEFER); } } cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), GFP_KERNEL); cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); if (!cpufreq_dev) return ERR_PTR(-ENOMEM); /* Find max levels */ cpufreq_for_each_valid_entry(pos, table) cpufreq_dev->max_level++; cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) * cpufreq_dev->max_level, GFP_KERNEL); if (!cpufreq_dev->freq_table) { cool_dev = ERR_PTR(-ENOMEM); goto free_cdev; } /* max_level is an index, not a counter */ cpufreq_dev->max_level--; cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); if (ret) { kfree(cpufreq_dev); return ERR_PTR(-EINVAL); cool_dev = ERR_PTR(ret); goto free_table; } snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", Loading @@ -476,24 +368,43 @@ __cpufreq_cooling_register(struct device_node *np, cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, &cpufreq_cooling_ops); if (IS_ERR(cool_dev)) { release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev); return cool_dev; if (IS_ERR(cool_dev)) goto remove_idr; /* Fill freq-table in descending order of frequencies */ for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { freq = find_next_max(table, freq); cpufreq_dev->freq_table[i] = freq; /* Warn for duplicate entries */ if (!freq) pr_warn("%s: table has duplicate entries\n", __func__); else pr_debug("%s: freq:%u KHz\n", __func__, freq); } cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0]; cpufreq_dev->cool_dev = cool_dev; cpufreq_dev->cpufreq_state = 0; mutex_lock(&cooling_cpufreq_lock); /* Register the notifier for first cpufreq cooling device */ if (cpufreq_dev_count == 0) if (list_empty(&cpufreq_dev_list)) cpufreq_register_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); cpufreq_dev_count++; list_add(&cpufreq_dev->node, &cpufreq_dev_list); mutex_unlock(&cooling_cpufreq_lock); return cool_dev; remove_idr: release_idr(&cpufreq_idr, cpufreq_dev->id); free_table: kfree(cpufreq_dev->freq_table); free_cdev: kfree(cpufreq_dev); return cool_dev; } Loading Loading @@ -555,16 +466,16 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) cpufreq_dev = cdev->devdata; mutex_lock(&cooling_cpufreq_lock); list_del(&cpufreq_dev->node); cpufreq_dev_count--; /* Unregister the notifier for the last cpufreq cooling device */ if (cpufreq_dev_count == 0) if (list_empty(&cpufreq_dev_list)) cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); mutex_unlock(&cooling_cpufreq_lock); thermal_cooling_device_unregister(cpufreq_dev->cool_dev); release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev->freq_table); kfree(cpufreq_dev); } EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);
drivers/thermal/db8500_cpufreq_cooling.c +9 −11 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ */ #include <linux/cpu_cooling.h> #include <linux/cpufreq.h> #include <linux/err.h> #include <linux/module.h> #include <linux/of.h> Loading @@ -28,18 +27,17 @@ static int db8500_cpufreq_cooling_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; struct cpumask mask_val; /* make sure cpufreq driver has been initialized */ if (!cpufreq_frequency_get_table(0)) return -EPROBE_DEFER; cdev = cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(cdev)) { int ret = PTR_ERR(cdev); cpumask_set_cpu(0, &mask_val); cdev = cpufreq_cooling_register(&mask_val); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "Failed to register cooling device %d\n", ret); if (IS_ERR(cdev)) { dev_err(&pdev->dev, "Failed to register cooling device\n"); return PTR_ERR(cdev); return ret; } platform_set_drvdata(pdev, cdev); Loading
drivers/thermal/imx_thermal.c +5 −10 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ #include <linux/clk.h> #include <linux/cpu_cooling.h> #include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/init.h> Loading Loading @@ -454,15 +453,10 @@ static int imx_thermal_probe(struct platform_device *pdev) const struct of_device_id *of_id = of_match_device(of_imx_thermal_match, &pdev->dev); struct imx_thermal_data *data; struct cpumask clip_cpus; struct regmap *map; int measure_freq; int ret; if (!cpufreq_get_current_driver()) { dev_dbg(&pdev->dev, "no cpufreq driver!"); return -EPROBE_DEFER; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; Loading Loading @@ -516,12 +510,13 @@ static int imx_thermal_probe(struct platform_device *pdev) regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); cpumask_set_cpu(0, &clip_cpus); data->cdev = cpufreq_cooling_register(&clip_cpus); data->cdev = cpufreq_cooling_register(cpu_present_mask); if (IS_ERR(data->cdev)) { ret = PTR_ERR(data->cdev); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "failed to register cpufreq cooling device: %d\n", ret); "failed to register cpufreq cooling device: %d\n", ret); return ret; } Loading
drivers/thermal/int340x_thermal/Makefile +1 −0 Original line number Diff line number Diff line obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o
drivers/thermal/int340x_thermal/acpi_thermal_rel.c +4 −4 Original line number Diff line number Diff line Loading @@ -82,7 +82,7 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" }; if (!acpi_has_method(handle, "_TRT")) return 0; return -ENODEV; status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer); if (ACPI_FAILURE(status)) Loading Loading @@ -167,7 +167,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" }; if (!acpi_has_method(handle, "_ART")) return 0; return -ENODEV; status = acpi_evaluate_object(handle, "_ART", NULL, &buffer); if (ACPI_FAILURE(status)) Loading Loading @@ -321,8 +321,8 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd, unsigned long length = 0; int count = 0; char __user *arg = (void __user *)__arg; struct trt *trts; struct art *arts; struct trt *trts = NULL; struct art *arts = NULL; switch (cmd) { case ACPI_THERMAL_GET_TRT_COUNT: Loading