[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