[linux-pm] [RFC PATCH 5/5] ACPI: thermal: processor: Use the generic cpufreq infrastructure
amit daniel kachhap
amit.daniel at samsung.com
Mon May 19 02:09:13 PDT 2014
On Fri, May 16, 2014 at 12:36 AM, Eduardo Valentin <edubezval at gmail.com> wrote:
> Hello Amit,
>
> On Thu, May 08, 2014 at 08:08:00PM +0530, Amit Daniel Kachhap wrote:
>> This patch upgrades the ACPI cpufreq cooling portions to use the generic
>> cpufreq cooling infrastructure. There should not be any functionality
>> related changes as the same behaviour is provided by the generic
>> cpufreq APIs with the notifier mechanism.
>>
>
> This is a very good move as we are converging towards a more and more
> common infrastructure. How did you test this code?
Thanks.
Actually with linaro acpi kernel I was able to enable acpi processor
in my arndale(exynos5250) board. After that in some hacky way I
enabled acpi __TMP method to read its tmu temperatures and able to
test thermal cpufreq scaling. Ofcourse i am not able to test
cputhrottling as it is not supported.
>
>> Signed-off-by: Amit Daniel Kachhap <amit.daniel at samsung.com>
>> ---
>> drivers/acpi/processor_driver.c | 6 +-
>> drivers/acpi/processor_thermal.c | 210 +++++++++++++++++---------------------
>> 2 files changed, 99 insertions(+), 117 deletions(-)
>>
>> diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
>> index 7f70f31..10aba4a 100644
>> --- a/drivers/acpi/processor_driver.c
>> +++ b/drivers/acpi/processor_driver.c
>> @@ -36,6 +36,7 @@
>> #include <linux/cpuidle.h>
>> #include <linux/slab.h>
>> #include <linux/acpi.h>
>> +#include <linux/cpu_cooling.h>
>>
>> #include <acpi/processor.h>
>>
>> @@ -178,8 +179,7 @@ static int __acpi_processor_start(struct acpi_device *device)
>> if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
>> acpi_processor_power_init(pr);
>>
>> - pr->cdev = thermal_cooling_device_register("Processor", device,
>> - &processor_cooling_ops);
>> + pr->cdev = acpi_processor_cooling_register(device);
>> if (IS_ERR(pr->cdev)) {
>> result = PTR_ERR(pr->cdev);
>> goto err_power_exit;
>> @@ -250,7 +250,7 @@ static int acpi_processor_stop(struct device *dev)
>> if (pr->cdev) {
>> sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
>> sysfs_remove_link(&pr->cdev->device.kobj, "device");
>> - thermal_cooling_device_unregister(pr->cdev);
>> + cpufreq_cooling_unregister(pr->cdev);
>> pr->cdev = NULL;
>> }
>> return 0;
>> diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
>> index e003663..c442a58 100644
>> --- a/drivers/acpi/processor_thermal.c
>> +++ b/drivers/acpi/processor_thermal.c
>> @@ -31,6 +31,7 @@
>> #include <linux/init.h>
>> #include <linux/cpufreq.h>
>> #include <linux/acpi.h>
>> +#include <linux/cpu_cooling.h>
>> #include <acpi/processor.h>
>> #include <asm/uaccess.h>
>>
>> @@ -53,28 +54,11 @@ ACPI_MODULE_NAME("processor_thermal");
>>
>> static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
>> static unsigned int acpi_thermal_cpufreq_is_init = 0;
>> +static struct notifier_block cpufreq_cooling_notifier_block;
>>
>> #define reduction_pctg(cpu) \
>> per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu))
>>
>> -/*
>> - * Emulate "per package data" using per cpu data (which should really be
>> - * provided elsewhere)
>> - *
>> - * Note we can lose a CPU on cpu hotunplug, in this case we forget the state
>> - * temporarily. Fortunately that's not a big issue here (I hope)
>> - */
>> -static int phys_package_first_cpu(int cpu)
>> -{
>> - int i;
>> - int id = topology_physical_package_id(cpu);
>> -
>> - for_each_online_cpu(i)
>> - if (topology_physical_package_id(i) == id)
>> - return i;
>> - return 0;
>> -}
>> -
>> static int cpu_has_cpufreq(unsigned int cpu)
>> {
>> struct cpufreq_policy policy;
>> @@ -83,30 +67,6 @@ static int cpu_has_cpufreq(unsigned int cpu)
>> return 1;
>> }
>>
>> -static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
>> - unsigned long event, void *data)
>> -{
>> - struct cpufreq_policy *policy = data;
>> - unsigned long max_freq = 0;
>> -
>> - if (event != CPUFREQ_ADJUST)
>> - goto out;
>> -
>> - max_freq = (
>> - policy->cpuinfo.max_freq *
>> - (100 - reduction_pctg(policy->cpu) * 20)
>> - ) / 100;
>> -
>> - cpufreq_verify_within_limits(policy, 0, max_freq);
>> -
>> - out:
>> - return 0;
>> -}
>> -
>> -static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
>> - .notifier_call = acpi_thermal_cpufreq_notifier,
>> -};
>> -
>> static int cpufreq_get_max_state(unsigned int cpu)
>> {
>> if (!cpu_has_cpufreq(cpu))
>> @@ -123,34 +83,32 @@ static int cpufreq_get_cur_state(unsigned int cpu)
>> return reduction_pctg(cpu);
>> }
>>
>> -static int cpufreq_set_cur_state(unsigned int cpu, int state)
>> +static int acpi_processor_freq_level(unsigned int cpu, int state)
>> {
>> - int i;
>> + struct cpufreq_policy policy;
>> + unsigned long max_freq = 0;
>> + int level = 0;
>>
>> - if (!cpu_has_cpufreq(cpu))
>> + if (!acpi_thermal_cpufreq_is_init || cpufreq_get_policy(&policy, cpu))
>> return 0;
>>
>> reduction_pctg(cpu) = state;
>> + max_freq = (
>> + policy.cpuinfo.max_freq *
>> + (100 - reduction_pctg(cpu) * 20)
>> + ) / 100;
>>
>> - /*
>> - * Update all the CPUs in the same package because they all
>> - * contribute to the temperature and often share the same
>> - * frequency.
>> - */
>> - for_each_online_cpu(i) {
>> - if (topology_physical_package_id(i) ==
>> - topology_physical_package_id(cpu))
>> - cpufreq_update_policy(i);
>> - }
>> - return 0;
>> + level = cpufreq_cooling_get_level(phys_package_first_cpu(cpu),
>> + max_freq, GET_LEVEL_FLOOR);
>> + return level;
>> }
>>
>> void acpi_thermal_cpufreq_init(void)
>> {
>> int i;
>>
>> - i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block,
>> - CPUFREQ_POLICY_NOTIFIER);
>> + i = cpufreq_cooling_register_notifier(&cpufreq_cooling_notifier_block,
>> + CPU_COOLING_STATE_NOTIFIER);
>> if (!i)
>> acpi_thermal_cpufreq_is_init = 1;
>> }
>> @@ -158,9 +116,9 @@ void acpi_thermal_cpufreq_init(void)
>> void acpi_thermal_cpufreq_exit(void)
>> {
>> if (acpi_thermal_cpufreq_is_init)
>> - cpufreq_unregister_notifier
>> - (&acpi_thermal_cpufreq_notifier_block,
>> - CPUFREQ_POLICY_NOTIFIER);
>> + cpufreq_cooling_unregister_notifier(
>> + &cpufreq_cooling_notifier_block,
>> + CPU_COOLING_STATE_NOTIFIER);
>>
>> acpi_thermal_cpufreq_is_init = 0;
>> }
>> @@ -176,13 +134,31 @@ static int cpufreq_get_cur_state(unsigned int cpu)
>> return 0;
>> }
>>
>> -static int cpufreq_set_cur_state(unsigned int cpu, int state)
>> +static int acpi_processor_freq_level(unsigned int cpu, int state)
>> {
>> return 0;
>> }
>>
>> #endif
>>
>> +/*
>> + * Emulate "per package data" using per cpu data (which should really be
>> + * provided elsewhere)
>> + *
>> + * Note we can lose a CPU on cpu hotunplug, in this case we forget the state
>> + * temporarily. Fortunately that's not a big issue here (I hope)
>> + */
>> +static int phys_package_first_cpu(int cpu)
>> +{
>> + int i;
>> + int id = topology_physical_package_id(cpu);
>> +
>> + for_each_online_cpu(i)
>> + if (topology_physical_package_id(i) == id)
>> + return i;
>> + return 0;
>> +}
>> +
>> /* thermal cooling device callbacks */
>> static int acpi_processor_max_state(struct acpi_processor *pr)
>> {
>> @@ -198,57 +174,22 @@ static int acpi_processor_max_state(struct acpi_processor *pr)
>>
>> return max_state;
>> }
>> -static int
>> -processor_get_max_state(struct thermal_cooling_device *cdev,
>> - unsigned long *state)
>> -{
>> - struct acpi_device *device = cdev->devdata;
>> - struct acpi_processor *pr;
>> -
>> - if (!device)
>> - return -EINVAL;
>> -
>> - pr = acpi_driver_data(device);
>> - if (!pr)
>> - return -EINVAL;
>>
>> - *state = acpi_processor_max_state(pr);
>> - return 0;
>> -}
>> -
>> -static int
>> -processor_get_cur_state(struct thermal_cooling_device *cdev,
>> - unsigned long *cur_state)
>> +static int acpi_processor_cur_state(struct acpi_processor *pr)
>> {
>> - struct acpi_device *device = cdev->devdata;
>> - struct acpi_processor *pr;
>> -
>> - if (!device)
>> - return -EINVAL;
>> -
>> - pr = acpi_driver_data(device);
>> - if (!pr)
>> - return -EINVAL;
>> -
>> - *cur_state = cpufreq_get_cur_state(pr->id);
>> + int cur_state = 0;
>> + cur_state = cpufreq_get_cur_state(pr->id);
>> if (pr->flags.throttling)
>> - *cur_state += pr->throttling.state;
>> - return 0;
>> + cur_state += pr->throttling.state;
>> + return cur_state;
>> }
>>
>> -static int
>> -processor_set_cur_state(struct thermal_cooling_device *cdev,
>> - unsigned long state)
>> +static int acpi_processor_set_cur_state(struct acpi_processor *pr,
>> + struct cpufreq_cooling_status *cooling, unsigned long event)
>> {
>> - struct acpi_device *device = cdev->devdata;
>> - struct acpi_processor *pr;
>> - int result = 0;
>> - int max_pstate;
>> -
>> - if (!device)
>> - return -EINVAL;
>> + int result = 0, level = 0;
>> + int max_pstate, state = cooling->new_state;
>>
>> - pr = acpi_driver_data(device);
>> if (!pr)
>> return -EINVAL;
>>
>> @@ -257,20 +198,61 @@ processor_set_cur_state(struct thermal_cooling_device *cdev,
>> if (state > acpi_processor_max_state(pr))
>> return -EINVAL;
>>
>> - if (state <= max_pstate) {
>> + if (state <= max_pstate && event == CPU_COOLING_SET_STATE_PRE) {
>> if (pr->flags.throttling && pr->throttling.state)
>> result = acpi_processor_set_throttling(pr, 0, false);
>> - cpufreq_set_cur_state(pr->id, state);
>> - } else {
>> - cpufreq_set_cur_state(pr->id, max_pstate);
>> + } else if (state > max_pstate && event == CPU_COOLING_SET_STATE_POST) {
>> result = acpi_processor_set_throttling(pr,
>> state - max_pstate, false);
>> }
>> +
>> + level = acpi_processor_freq_level(pr->id, state);
>> + cooling->new_state = level;
>> +
>> return result;
>> }
>>
>> -const struct thermal_cooling_device_ops processor_cooling_ops = {
>> - .get_max_state = processor_get_max_state,
>> - .get_cur_state = processor_get_cur_state,
>> - .set_cur_state = processor_set_cur_state,
>> +static int acpi_cpufreq_cooling_notifier(struct notifier_block *nb,
>> + unsigned long event, void *data)
>> +{
>> + struct cpufreq_cooling_status *cooling = data;
>> + struct acpi_device *device = cooling->devdata;
>> + struct acpi_processor *pr = acpi_driver_data(device);
>> + switch (event) {
>> + case CPU_COOLING_SET_STATE_PRE:
>> + case CPU_COOLING_SET_STATE_POST:
>> + acpi_processor_set_cur_state(pr, cooling, event);
>> + break;
>> + case CPU_COOLING_GET_MAX_STATE:
>> + cooling->max_state = acpi_processor_max_state(pr);
>> + break;
>> + case CPU_COOLING_GET_CUR_STATE:
>> + cooling->cur_state = acpi_processor_cur_state(pr);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + return 0;
>> +}
>> +
>> +static struct notifier_block cpufreq_cooling_notifier_block = {
>> + .notifier_call = acpi_cpufreq_cooling_notifier,
>> };
>> +
>> +struct thermal_cooling_device *
>> +acpi_processor_cooling_register(struct acpi_device *device)
>> +{
>> + struct thermal_cooling_device *cdev;
>> + struct acpi_processor *pr = acpi_driver_data(device);
>> + int cpu = phys_package_first_cpu(pr->id);
>> + int i;
>> + int id = topology_physical_package_id(cpu);
>> + struct cpumask cpus;
>> +
>> + for_each_online_cpu(i)
>> + if (topology_physical_package_id(i) == id)
>> + cpumask_set_cpu(i, &cpus);
>> +
>> + cdev = cpufreq_cooling_register(&cpus, (void *)device);
>> + return cdev;
>> +}
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
More information about the linux-arm-kernel
mailing list