Path: blob/master/drivers/acpi/processor_thermal.c
15109 views
/*1* processor_thermal.c - Passive cooling submodule of the ACPI processor driver2*3* Copyright (C) 2001, 2002 Andy Grover <[email protected]>4* Copyright (C) 2001, 2002 Paul Diefenbaugh <[email protected]>5* Copyright (C) 2004 Dominik Brodowski <[email protected]>6* Copyright (C) 2004 Anil S Keshavamurthy <[email protected]>7* - Added processor hotplug support8*9* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~10*11* This program is free software; you can redistribute it and/or modify12* it under the terms of the GNU General Public License as published by13* the Free Software Foundation; either version 2 of the License, or (at14* your option) any later version.15*16* This program is distributed in the hope that it will be useful, but17* WITHOUT ANY WARRANTY; without even the implied warranty of18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU19* General Public License for more details.20*21* You should have received a copy of the GNU General Public License along22* with this program; if not, write to the Free Software Foundation, Inc.,23* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.24*25* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~26*/2728#include <linux/kernel.h>29#include <linux/module.h>30#include <linux/init.h>31#include <linux/cpufreq.h>32#include <linux/sysdev.h>3334#include <asm/uaccess.h>3536#include <acpi/acpi_bus.h>37#include <acpi/processor.h>38#include <acpi/acpi_drivers.h>3940#define PREFIX "ACPI: "4142#define ACPI_PROCESSOR_CLASS "processor"43#define _COMPONENT ACPI_PROCESSOR_COMPONENT44ACPI_MODULE_NAME("processor_thermal");4546#ifdef CONFIG_CPU_FREQ4748/* If a passive cooling situation is detected, primarily CPUfreq is used, as it49* offers (in most cases) voltage scaling in addition to frequency scaling, and50* thus a cubic (instead of linear) reduction of energy. Also, we allow for51* _any_ cpufreq driver and not only the acpi-cpufreq driver.52*/5354#define CPUFREQ_THERMAL_MIN_STEP 055#define CPUFREQ_THERMAL_MAX_STEP 35657static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);58static unsigned int acpi_thermal_cpufreq_is_init = 0;5960static int cpu_has_cpufreq(unsigned int cpu)61{62struct cpufreq_policy policy;63if (!acpi_thermal_cpufreq_is_init || cpufreq_get_policy(&policy, cpu))64return 0;65return 1;66}6768static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,69unsigned long event, void *data)70{71struct cpufreq_policy *policy = data;72unsigned long max_freq = 0;7374if (event != CPUFREQ_ADJUST)75goto out;7677max_freq = (78policy->cpuinfo.max_freq *79(100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20)80) / 100;8182cpufreq_verify_within_limits(policy, 0, max_freq);8384out:85return 0;86}8788static struct notifier_block acpi_thermal_cpufreq_notifier_block = {89.notifier_call = acpi_thermal_cpufreq_notifier,90};9192static int cpufreq_get_max_state(unsigned int cpu)93{94if (!cpu_has_cpufreq(cpu))95return 0;9697return CPUFREQ_THERMAL_MAX_STEP;98}99100static int cpufreq_get_cur_state(unsigned int cpu)101{102if (!cpu_has_cpufreq(cpu))103return 0;104105return per_cpu(cpufreq_thermal_reduction_pctg, cpu);106}107108static int cpufreq_set_cur_state(unsigned int cpu, int state)109{110if (!cpu_has_cpufreq(cpu))111return 0;112113per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state;114cpufreq_update_policy(cpu);115return 0;116}117118void acpi_thermal_cpufreq_init(void)119{120int i;121122for (i = 0; i < nr_cpu_ids; i++)123if (cpu_present(i))124per_cpu(cpufreq_thermal_reduction_pctg, i) = 0;125126i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block,127CPUFREQ_POLICY_NOTIFIER);128if (!i)129acpi_thermal_cpufreq_is_init = 1;130}131132void acpi_thermal_cpufreq_exit(void)133{134if (acpi_thermal_cpufreq_is_init)135cpufreq_unregister_notifier136(&acpi_thermal_cpufreq_notifier_block,137CPUFREQ_POLICY_NOTIFIER);138139acpi_thermal_cpufreq_is_init = 0;140}141142#else /* ! CONFIG_CPU_FREQ */143static int cpufreq_get_max_state(unsigned int cpu)144{145return 0;146}147148static int cpufreq_get_cur_state(unsigned int cpu)149{150return 0;151}152153static int cpufreq_set_cur_state(unsigned int cpu, int state)154{155return 0;156}157158#endif159160int acpi_processor_get_limit_info(struct acpi_processor *pr)161{162163if (!pr)164return -EINVAL;165166if (pr->flags.throttling)167pr->flags.limit = 1;168169return 0;170}171172/* thermal coolign device callbacks */173static int acpi_processor_max_state(struct acpi_processor *pr)174{175int max_state = 0;176177/*178* There exists four states according to179* cpufreq_thermal_reduction_ptg. 0, 1, 2, 3180*/181max_state += cpufreq_get_max_state(pr->id);182if (pr->flags.throttling)183max_state += (pr->throttling.state_count -1);184185return max_state;186}187static int188processor_get_max_state(struct thermal_cooling_device *cdev,189unsigned long *state)190{191struct acpi_device *device = cdev->devdata;192struct acpi_processor *pr = acpi_driver_data(device);193194if (!device || !pr)195return -EINVAL;196197*state = acpi_processor_max_state(pr);198return 0;199}200201static int202processor_get_cur_state(struct thermal_cooling_device *cdev,203unsigned long *cur_state)204{205struct acpi_device *device = cdev->devdata;206struct acpi_processor *pr = acpi_driver_data(device);207208if (!device || !pr)209return -EINVAL;210211*cur_state = cpufreq_get_cur_state(pr->id);212if (pr->flags.throttling)213*cur_state += pr->throttling.state;214return 0;215}216217static int218processor_set_cur_state(struct thermal_cooling_device *cdev,219unsigned long state)220{221struct acpi_device *device = cdev->devdata;222struct acpi_processor *pr = acpi_driver_data(device);223int result = 0;224int max_pstate;225226if (!device || !pr)227return -EINVAL;228229max_pstate = cpufreq_get_max_state(pr->id);230231if (state > acpi_processor_max_state(pr))232return -EINVAL;233234if (state <= max_pstate) {235if (pr->flags.throttling && pr->throttling.state)236result = acpi_processor_set_throttling(pr, 0, false);237cpufreq_set_cur_state(pr->id, state);238} else {239cpufreq_set_cur_state(pr->id, max_pstate);240result = acpi_processor_set_throttling(pr,241state - max_pstate, false);242}243return result;244}245246struct thermal_cooling_device_ops processor_cooling_ops = {247.get_max_state = processor_get_max_state,248.get_cur_state = processor_get_cur_state,249.set_cur_state = processor_set_cur_state,250};251252253