2005-04-17 02:20:36 +04:00
/*
2006-10-03 23:29:15 +04:00
* acpi - cpufreq . c - ACPI Processor P - States Driver ( $ Revision : 1.4 $ )
2005-04-17 02:20:36 +04:00
*
* Copyright ( C ) 2001 , 2002 Andy Grover < andrew . grover @ intel . com >
* Copyright ( C ) 2001 , 2002 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
* Copyright ( C ) 2002 - 2004 Dominik Brodowski < linux @ brodo . de >
2006-10-03 23:29:15 +04:00
* Copyright ( C ) 2006 Denis Sadykov < denis . m . sadykov @ intel . com >
2005-04-17 02:20:36 +04:00
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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 ; either version 2 of the License , or ( at
* your option ) any later version .
*
* 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 <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
2006-10-03 23:29:15 +04:00
# include <linux/smp.h>
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <linux/cpufreq.h>
2005-08-25 23:59:00 +04:00
# include <linux/compiler.h>
2006-09-02 01:02:24 +04:00
# include <linux/dmi.h>
2008-11-24 03:49:58 +03:00
# include <linux/ftrace.h>
2005-04-17 02:20:36 +04:00
# include <linux/acpi.h>
# include <acpi/processor.h>
2006-10-03 23:29:15 +04:00
# include <asm/io.h>
2006-10-03 23:33:14 +04:00
# include <asm/msr.h>
2006-10-03 23:29:15 +04:00
# include <asm/processor.h>
# include <asm/cpufeature.h>
# include <asm/delay.h>
# include <asm/uaccess.h>
2005-04-17 02:20:36 +04:00
# define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
MODULE_AUTHOR ( " Paul Diefenbaugh, Dominik Brodowski " ) ;
MODULE_DESCRIPTION ( " ACPI Processor P-States Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2006-10-03 23:33:14 +04:00
enum {
UNDEFINED_CAPABLE = 0 ,
SYSTEM_INTEL_MSR_CAPABLE ,
SYSTEM_IO_CAPABLE ,
} ;
# define INTEL_MSR_RANGE (0xffff)
2006-10-03 23:38:45 +04:00
# define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1)
2006-10-03 23:33:14 +04:00
2006-10-03 23:29:15 +04:00
struct acpi_cpufreq_data {
2006-10-03 23:35:23 +04:00
struct acpi_processor_performance * acpi_data ;
struct cpufreq_frequency_table * freq_table ;
2006-10-03 23:38:45 +04:00
unsigned int max_freq ;
2006-10-03 23:35:23 +04:00
unsigned int resume ;
unsigned int cpu_feature ;
2005-04-17 02:20:36 +04:00
} ;
2008-01-30 15:33:12 +03:00
static DEFINE_PER_CPU ( struct acpi_cpufreq_data * , drv_data ) ;
2007-08-08 02:40:30 +04:00
/* acpi_perf_data is a pointer to percpu data. */
static struct acpi_processor_performance * acpi_perf_data ;
2005-04-17 02:20:36 +04:00
static struct cpufreq_driver acpi_cpufreq_driver ;
2005-08-25 23:59:00 +04:00
static unsigned int acpi_pstate_strict ;
2006-10-03 23:33:14 +04:00
static int check_est_cpu ( unsigned int cpuid )
{
2007-10-19 22:35:04 +04:00
struct cpuinfo_x86 * cpu = & cpu_data ( cpuid ) ;
2006-10-03 23:33:14 +04:00
if ( cpu - > x86_vendor ! = X86_VENDOR_INTEL | |
2006-10-03 23:35:23 +04:00
! cpu_has ( cpu , X86_FEATURE_EST ) )
2006-10-03 23:33:14 +04:00
return 0 ;
return 1 ;
}
static unsigned extract_io ( u32 value , struct acpi_cpufreq_data * data )
2006-10-03 23:29:15 +04:00
{
2006-10-03 23:35:23 +04:00
struct acpi_processor_performance * perf ;
int i ;
2006-10-03 23:29:15 +04:00
perf = data - > acpi_data ;
2006-10-18 08:41:48 +04:00
for ( i = 0 ; i < perf - > state_count ; i + + ) {
2006-10-03 23:29:15 +04:00
if ( value = = perf - > states [ i ] . status )
return data - > freq_table [ i ] . frequency ;
}
return 0 ;
}
2006-10-03 23:33:14 +04:00
static unsigned extract_msr ( u32 msr , struct acpi_cpufreq_data * data )
{
int i ;
2006-10-03 23:37:42 +04:00
struct acpi_processor_performance * perf ;
2006-10-03 23:33:14 +04:00
msr & = INTEL_MSR_RANGE ;
2006-10-03 23:37:42 +04:00
perf = data - > acpi_data ;
2006-10-18 08:41:48 +04:00
for ( i = 0 ; data - > freq_table [ i ] . frequency ! = CPUFREQ_TABLE_END ; i + + ) {
2006-10-03 23:37:42 +04:00
if ( msr = = perf - > states [ data - > freq_table [ i ] . index ] . status )
2006-10-03 23:33:14 +04:00
return data - > freq_table [ i ] . frequency ;
}
return data - > freq_table [ 0 ] . frequency ;
}
static unsigned extract_freq ( u32 val , struct acpi_cpufreq_data * data )
{
switch ( data - > cpu_feature ) {
2006-10-03 23:35:23 +04:00
case SYSTEM_INTEL_MSR_CAPABLE :
2006-10-03 23:33:14 +04:00
return extract_msr ( val , data ) ;
2006-10-03 23:35:23 +04:00
case SYSTEM_IO_CAPABLE :
2006-10-03 23:33:14 +04:00
return extract_io ( val , data ) ;
2006-10-03 23:35:23 +04:00
default :
2006-10-03 23:33:14 +04:00
return 0 ;
}
}
struct msr_addr {
u32 reg ;
} ;
2006-10-03 23:29:15 +04:00
struct io_addr {
u16 port ;
u8 bit_width ;
} ;
2006-10-03 23:33:14 +04:00
typedef union {
struct msr_addr msr ;
struct io_addr io ;
} drv_addr_union ;
2006-10-03 23:29:15 +04:00
struct drv_cmd {
2006-10-03 23:33:14 +04:00
unsigned int type ;
2009-01-04 16:18:08 +03:00
cpumask_var_t mask ;
2006-10-03 23:33:14 +04:00
drv_addr_union addr ;
2006-10-03 23:29:15 +04:00
u32 val ;
} ;
2009-01-17 02:31:15 +03:00
static long do_drv_read ( void * _cmd )
2005-04-17 02:20:36 +04:00
{
2009-01-17 02:31:15 +03:00
struct drv_cmd * cmd = _cmd ;
2006-10-03 23:33:14 +04:00
u32 h ;
switch ( cmd - > type ) {
2006-10-03 23:35:23 +04:00
case SYSTEM_INTEL_MSR_CAPABLE :
2006-10-03 23:33:14 +04:00
rdmsr ( cmd - > addr . msr . reg , cmd - > val , h ) ;
break ;
2006-10-03 23:35:23 +04:00
case SYSTEM_IO_CAPABLE :
2006-12-13 21:41:16 +03:00
acpi_os_read_port ( ( acpi_io_address ) cmd - > addr . io . port ,
& cmd - > val ,
( u32 ) cmd - > addr . io . bit_width ) ;
2006-10-03 23:33:14 +04:00
break ;
2006-10-03 23:35:23 +04:00
default :
2006-10-03 23:33:14 +04:00
break ;
}
2009-01-17 02:31:15 +03:00
return 0 ;
2006-10-03 23:29:15 +04:00
}
2005-04-17 02:20:36 +04:00
2009-01-17 02:31:15 +03:00
static long do_drv_write ( void * _cmd )
2006-10-03 23:29:15 +04:00
{
2009-01-17 02:31:15 +03:00
struct drv_cmd * cmd = _cmd ;
2007-05-24 02:42:13 +04:00
u32 lo , hi ;
2006-10-03 23:33:14 +04:00
switch ( cmd - > type ) {
2006-10-03 23:35:23 +04:00
case SYSTEM_INTEL_MSR_CAPABLE :
2007-05-24 02:42:13 +04:00
rdmsr ( cmd - > addr . msr . reg , lo , hi ) ;
lo = ( lo & ~ INTEL_MSR_RANGE ) | ( cmd - > val & INTEL_MSR_RANGE ) ;
wrmsr ( cmd - > addr . msr . reg , lo , hi ) ;
2006-10-03 23:33:14 +04:00
break ;
2006-10-03 23:35:23 +04:00
case SYSTEM_IO_CAPABLE :
2006-12-13 21:41:16 +03:00
acpi_os_write_port ( ( acpi_io_address ) cmd - > addr . io . port ,
cmd - > val ,
( u32 ) cmd - > addr . io . bit_width ) ;
2006-10-03 23:33:14 +04:00
break ;
2006-10-03 23:35:23 +04:00
default :
2006-10-03 23:33:14 +04:00
break ;
}
2009-01-17 02:31:15 +03:00
return 0 ;
2006-10-03 23:29:15 +04:00
}
2005-04-17 02:20:36 +04:00
2006-10-18 08:41:48 +04:00
static void drv_read ( struct drv_cmd * cmd )
2006-10-03 23:29:15 +04:00
{
cmd - > val = 0 ;
2009-01-17 02:31:15 +03:00
work_on_cpu ( cpumask_any ( cmd - > mask ) , do_drv_read , cmd ) ;
2006-10-03 23:29:15 +04:00
}
static void drv_write ( struct drv_cmd * cmd )
{
2006-10-03 23:35:23 +04:00
unsigned int i ;
2006-10-03 23:29:15 +04:00
2009-01-04 16:18:08 +03:00
for_each_cpu ( i , cmd - > mask ) {
2009-01-17 02:31:15 +03:00
work_on_cpu ( i , do_drv_write , cmd ) ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 23:29:15 +04:00
}
2005-04-17 02:20:36 +04:00
2009-01-04 16:18:08 +03:00
static u32 get_cur_val ( const struct cpumask * mask )
2006-10-03 23:29:15 +04:00
{
2006-10-03 23:35:23 +04:00
struct acpi_processor_performance * perf ;
struct drv_cmd cmd ;
2005-04-17 02:20:36 +04:00
2009-01-04 16:18:08 +03:00
if ( unlikely ( cpumask_empty ( mask ) ) )
2006-10-03 23:29:15 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2009-01-04 16:18:08 +03:00
switch ( per_cpu ( drv_data , cpumask_first ( mask ) ) - > cpu_feature ) {
2006-10-03 23:33:14 +04:00
case SYSTEM_INTEL_MSR_CAPABLE :
cmd . type = SYSTEM_INTEL_MSR_CAPABLE ;
cmd . addr . msr . reg = MSR_IA32_PERF_STATUS ;
break ;
case SYSTEM_IO_CAPABLE :
cmd . type = SYSTEM_IO_CAPABLE ;
2009-01-04 16:18:08 +03:00
perf = per_cpu ( drv_data , cpumask_first ( mask ) ) - > acpi_data ;
2006-10-03 23:33:14 +04:00
cmd . addr . io . port = perf - > control_register . address ;
cmd . addr . io . bit_width = perf - > control_register . bit_width ;
break ;
default :
return 0 ;
}
2006-10-03 23:29:15 +04:00
drv_read ( & cmd ) ;
2005-04-17 02:20:36 +04:00
2006-10-03 23:29:15 +04:00
dprintk ( " get_cur_val = %u \n " , cmd . val ) ;
return cmd . val ;
}
2005-04-17 02:20:36 +04:00
2009-01-04 16:18:10 +03:00
struct perf_cur {
union {
struct {
u32 lo ;
u32 hi ;
} split ;
u64 whole ;
} aperf_cur , mperf_cur ;
} ;
static long read_measured_perf_ctrs ( void * _cur )
{
struct perf_cur * cur = _cur ;
rdmsr ( MSR_IA32_APERF , cur - > aperf_cur . split . lo , cur - > aperf_cur . split . hi ) ;
rdmsr ( MSR_IA32_MPERF , cur - > mperf_cur . split . lo , cur - > mperf_cur . split . hi ) ;
wrmsr ( MSR_IA32_APERF , 0 , 0 ) ;
wrmsr ( MSR_IA32_MPERF , 0 , 0 ) ;
return 0 ;
}
2006-10-03 23:38:45 +04:00
/*
* Return the measured active ( C0 ) frequency on this CPU since last call
* to this function .
* Input : cpu number
* Return : Average CPU frequency in terms of max frequency ( zero on error )
*
* We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
* over a period of time , while CPU is in C0 state .
* IA32_MPERF counts at the rate of max advertised frequency
* IA32_APERF counts at the rate of actual CPU frequency
* Only IA32_APERF / IA32_MPERF ratio is architecturally defined and
* no meaning should be associated with absolute values of these MSRs .
*/
2008-08-04 22:59:07 +04:00
static unsigned int get_measured_perf ( struct cpufreq_policy * policy ,
unsigned int cpu )
2006-10-03 23:38:45 +04:00
{
2009-01-04 16:18:10 +03:00
struct perf_cur cur ;
2006-10-03 23:38:45 +04:00
unsigned int perf_percent ;
unsigned int retval ;
2009-01-04 16:18:10 +03:00
if ( ! work_on_cpu ( cpu , read_measured_perf_ctrs , & cur ) )
2006-10-03 23:38:45 +04:00
return 0 ;
# ifdef __i386__
/*
* We dont want to do 64 bit divide with 32 bit kernel
* Get an approximate value . Return failure in case we cannot get
* an approximate value .
*/
2009-01-04 16:18:10 +03:00
if ( unlikely ( cur . aperf_cur . split . hi | | cur . mperf_cur . split . hi ) ) {
2006-10-03 23:38:45 +04:00
int shift_count ;
u32 h ;
2009-01-04 16:18:10 +03:00
h = max_t ( u32 , cur . aperf_cur . split . hi , cur . mperf_cur . split . hi ) ;
2006-10-03 23:38:45 +04:00
shift_count = fls ( h ) ;
2009-01-04 16:18:10 +03:00
cur . aperf_cur . whole > > = shift_count ;
cur . mperf_cur . whole > > = shift_count ;
2006-10-03 23:38:45 +04:00
}
2009-01-04 16:18:10 +03:00
if ( ( ( unsigned long ) ( - 1 ) / 100 ) < cur . aperf_cur . split . lo ) {
2006-10-03 23:38:45 +04:00
int shift_count = 7 ;
2009-01-04 16:18:10 +03:00
cur . aperf_cur . split . lo > > = shift_count ;
cur . mperf_cur . split . lo > > = shift_count ;
2006-10-03 23:38:45 +04:00
}
2009-01-04 16:18:10 +03:00
if ( cur . aperf_cur . split . lo & & cur . mperf_cur . split . lo )
perf_percent = ( cur . aperf_cur . split . lo * 100 ) /
cur . mperf_cur . split . lo ;
2006-10-18 08:41:48 +04:00
else
2006-10-03 23:38:45 +04:00
perf_percent = 0 ;
# else
2009-01-04 16:18:10 +03:00
if ( unlikely ( ( ( unsigned long ) ( - 1 ) / 100 ) < cur . aperf_cur . whole ) ) {
2006-10-03 23:38:45 +04:00
int shift_count = 7 ;
2009-01-04 16:18:10 +03:00
cur . aperf_cur . whole > > = shift_count ;
cur . mperf_cur . whole > > = shift_count ;
2006-10-03 23:38:45 +04:00
}
2009-01-04 16:18:10 +03:00
if ( cur . aperf_cur . whole & & cur . mperf_cur . whole )
perf_percent = ( cur . aperf_cur . whole * 100 ) /
cur . mperf_cur . whole ;
2006-10-18 08:41:48 +04:00
else
2006-10-03 23:38:45 +04:00
perf_percent = 0 ;
# endif
2008-08-04 22:59:07 +04:00
retval = per_cpu ( drv_data , policy - > cpu ) - > max_freq * perf_percent / 100 ;
2006-10-03 23:38:45 +04:00
return retval ;
}
2006-10-03 23:29:15 +04:00
static unsigned int get_cur_freq_on_cpu ( unsigned int cpu )
{
2008-01-30 15:33:12 +03:00
struct acpi_cpufreq_data * data = per_cpu ( drv_data , cpu ) ;
2006-10-03 23:35:23 +04:00
unsigned int freq ;
2008-04-28 23:13:43 +04:00
unsigned int cached_freq ;
2006-10-03 23:29:15 +04:00
dprintk ( " get_cur_freq_on_cpu (%d) \n " , cpu ) ;
if ( unlikely ( data = = NULL | |
2006-10-03 23:35:23 +04:00
data - > acpi_data = = NULL | | data - > freq_table = = NULL ) ) {
2006-10-03 23:29:15 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-04-28 23:13:43 +04:00
cached_freq = data - > freq_table [ data - > acpi_data - > state ] . frequency ;
2009-01-04 16:18:10 +03:00
freq = extract_freq ( get_cur_val ( cpumask_of ( cpu ) ) , data ) ;
2008-04-28 23:13:43 +04:00
if ( freq ! = cached_freq ) {
/*
* The dreaded BIOS frequency change behind our back .
* Force set the frequency on next target call .
*/
data - > resume = 1 ;
}
2006-10-03 23:29:15 +04:00
dprintk ( " cur freq = %u \n " , freq ) ;
2005-04-17 02:20:36 +04:00
2006-10-03 23:29:15 +04:00
return freq ;
2005-04-17 02:20:36 +04:00
}
2009-01-17 02:31:15 +03:00
static unsigned int check_freqs ( const struct cpumask * mask , unsigned int freq ,
2006-10-03 23:35:23 +04:00
struct acpi_cpufreq_data * data )
2006-10-03 23:29:15 +04:00
{
2006-10-03 23:35:23 +04:00
unsigned int cur_freq ;
unsigned int i ;
2005-04-17 02:20:36 +04:00
2006-10-18 08:41:48 +04:00
for ( i = 0 ; i < 100 ; i + + ) {
2006-10-03 23:29:15 +04:00
cur_freq = extract_freq ( get_cur_val ( mask ) , data ) ;
if ( cur_freq = = freq )
return 1 ;
udelay ( 10 ) ;
}
return 0 ;
}
static int acpi_cpufreq_target ( struct cpufreq_policy * policy ,
2006-10-03 23:35:23 +04:00
unsigned int target_freq , unsigned int relation )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:33:12 +03:00
struct acpi_cpufreq_data * data = per_cpu ( drv_data , policy - > cpu ) ;
2006-10-03 23:35:23 +04:00
struct acpi_processor_performance * perf ;
struct cpufreq_freqs freqs ;
struct drv_cmd cmd ;
2006-12-19 23:58:55 +03:00
unsigned int next_state = 0 ; /* Index into freq_table */
unsigned int next_perf_state = 0 ; /* Index into perf table */
2006-10-03 23:35:23 +04:00
unsigned int i ;
int result = 0 ;
2008-11-24 03:49:58 +03:00
struct power_trace it ;
2006-10-03 23:29:15 +04:00
dprintk ( " acpi_cpufreq_target %d (%d) \n " , target_freq , policy - > cpu ) ;
if ( unlikely ( data = = NULL | |
2006-10-18 08:41:48 +04:00
data - > acpi_data = = NULL | | data - > freq_table = = NULL ) ) {
2006-10-03 23:29:15 +04:00
return - ENODEV ;
}
2005-04-17 02:20:36 +04:00
2009-01-04 16:18:08 +03:00
if ( unlikely ( ! alloc_cpumask_var ( & cmd . mask , GFP_KERNEL ) ) )
return - ENOMEM ;
2006-10-03 23:29:15 +04:00
perf = data - > acpi_data ;
2005-04-17 02:20:36 +04:00
result = cpufreq_frequency_table_target ( policy ,
2006-10-03 23:35:23 +04:00
data - > freq_table ,
target_freq ,
relation , & next_state ) ;
2009-01-04 16:18:08 +03:00
if ( unlikely ( result ) ) {
result = - ENODEV ;
goto out ;
}
2005-04-17 02:20:36 +04:00
2006-10-03 23:29:15 +04:00
next_perf_state = data - > freq_table [ next_state ] . index ;
2006-10-03 23:36:30 +04:00
if ( perf - > state = = next_perf_state ) {
2006-10-03 23:29:15 +04:00
if ( unlikely ( data - > resume ) ) {
2006-10-03 23:35:23 +04:00
dprintk ( " Called after resume, resetting to P%d \n " ,
next_perf_state ) ;
2006-10-03 23:29:15 +04:00
data - > resume = 0 ;
} else {
2006-10-03 23:35:23 +04:00
dprintk ( " Already at target state (P%d) \n " ,
next_perf_state ) ;
2009-01-04 16:18:08 +03:00
goto out ;
2006-10-03 23:29:15 +04:00
}
2005-12-14 23:05:00 +03:00
}
2008-11-24 03:49:58 +03:00
trace_power_mark ( & it , POWER_PSTATE , next_perf_state ) ;
2006-10-03 23:35:23 +04:00
switch ( data - > cpu_feature ) {
case SYSTEM_INTEL_MSR_CAPABLE :
cmd . type = SYSTEM_INTEL_MSR_CAPABLE ;
cmd . addr . msr . reg = MSR_IA32_PERF_CTL ;
2007-05-24 02:42:13 +04:00
cmd . val = ( u32 ) perf - > states [ next_perf_state ] . control ;
2006-10-03 23:35:23 +04:00
break ;
case SYSTEM_IO_CAPABLE :
cmd . type = SYSTEM_IO_CAPABLE ;
cmd . addr . io . port = perf - > control_register . address ;
cmd . addr . io . bit_width = perf - > control_register . bit_width ;
cmd . val = ( u32 ) perf - > states [ next_perf_state ] . control ;
break ;
default :
2009-01-04 16:18:08 +03:00
result = - ENODEV ;
goto out ;
2006-10-03 23:35:23 +04:00
}
2005-12-14 23:05:00 +03:00
2009-01-04 16:18:08 +03:00
/* cpufreq holds the hotplug lock, so we are safe from here on */
2006-10-03 23:29:15 +04:00
if ( policy - > shared_type ! = CPUFREQ_SHARED_TYPE_ANY )
2009-01-04 16:18:08 +03:00
cpumask_and ( cmd . mask , cpu_online_mask , policy - > cpus ) ;
2006-10-03 23:29:15 +04:00
else
2009-01-04 16:18:08 +03:00
cpumask_copy ( cmd . mask , cpumask_of ( policy - > cpu ) ) ;
2005-12-14 23:05:00 +03:00
2006-12-19 23:58:55 +03:00
freqs . old = perf - > states [ perf - > state ] . core_frequency * 1000 ;
freqs . new = data - > freq_table [ next_state ] . frequency ;
2009-01-04 16:18:08 +03:00
for_each_cpu ( i , cmd . mask ) {
2006-10-03 23:29:15 +04:00
freqs . cpu = i ;
cpufreq_notify_transition ( & freqs , CPUFREQ_PRECHANGE ) ;
2005-12-14 23:05:00 +03:00
}
2005-04-17 02:20:36 +04:00
2006-10-03 23:29:15 +04:00
drv_write ( & cmd ) ;
2005-12-14 23:05:00 +03:00
2006-10-03 23:29:15 +04:00
if ( acpi_pstate_strict ) {
2009-01-04 16:18:08 +03:00
if ( ! check_freqs ( cmd . mask , freqs . new , data ) ) {
2006-10-03 23:29:15 +04:00
dprintk ( " acpi_cpufreq_target failed (%d) \n " ,
2006-10-03 23:35:23 +04:00
policy - > cpu ) ;
2009-01-04 16:18:08 +03:00
result = - EAGAIN ;
goto out ;
2005-12-14 23:05:00 +03:00
}
}
2009-01-04 16:18:08 +03:00
for_each_cpu ( i , cmd . mask ) {
2006-10-03 23:29:15 +04:00
freqs . cpu = i ;
cpufreq_notify_transition ( & freqs , CPUFREQ_POSTCHANGE ) ;
}
perf - > state = next_perf_state ;
2009-01-04 16:18:08 +03:00
out :
free_cpumask_var ( cmd . mask ) ;
2006-10-03 23:29:15 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 23:35:23 +04:00
static int acpi_cpufreq_verify ( struct cpufreq_policy * policy )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:33:12 +03:00
struct acpi_cpufreq_data * data = per_cpu ( drv_data , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
dprintk ( " acpi_cpufreq_verify \n " ) ;
2006-10-03 23:29:15 +04:00
return cpufreq_frequency_table_verify ( policy , data - > freq_table ) ;
2005-04-17 02:20:36 +04:00
}
static unsigned long
2006-10-03 23:35:23 +04:00
acpi_cpufreq_guess_freq ( struct acpi_cpufreq_data * data , unsigned int cpu )
2005-04-17 02:20:36 +04:00
{
2006-10-03 23:35:23 +04:00
struct acpi_processor_performance * perf = data - > acpi_data ;
2005-12-14 23:05:00 +03:00
2005-04-17 02:20:36 +04:00
if ( cpu_khz ) {
/* search the closest match to cpu_khz */
unsigned int i ;
unsigned long freq ;
2005-12-14 23:05:00 +03:00
unsigned long freqn = perf - > states [ 0 ] . core_frequency * 1000 ;
2005-04-17 02:20:36 +04:00
2006-10-18 08:41:48 +04:00
for ( i = 0 ; i < ( perf - > state_count - 1 ) ; i + + ) {
2005-04-17 02:20:36 +04:00
freq = freqn ;
2006-10-18 08:41:48 +04:00
freqn = perf - > states [ i + 1 ] . core_frequency * 1000 ;
2005-04-17 02:20:36 +04:00
if ( ( 2 * cpu_khz ) > ( freqn + freq ) ) {
2005-12-14 23:05:00 +03:00
perf - > state = i ;
2006-10-03 23:35:23 +04:00
return freq ;
2005-04-17 02:20:36 +04:00
}
}
2006-10-18 08:41:48 +04:00
perf - > state = perf - > state_count - 1 ;
2006-10-03 23:35:23 +04:00
return freqn ;
2005-12-14 23:05:00 +03:00
} else {
2005-04-17 02:20:36 +04:00
/* assume CPU is at P0... */
2005-12-14 23:05:00 +03:00
perf - > state = 0 ;
return perf - > states [ 0 ] . core_frequency * 1000 ;
}
2005-04-17 02:20:36 +04:00
}
2009-01-01 05:08:47 +03:00
static void free_acpi_perf_data ( void )
{
unsigned int i ;
/* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */
for_each_possible_cpu ( i )
free_cpumask_var ( per_cpu_ptr ( acpi_perf_data , i )
- > shared_cpu_map ) ;
free_percpu ( acpi_perf_data ) ;
}
2005-12-14 23:05:00 +03:00
/*
* acpi_cpufreq_early_init - initialize ACPI P - States library
*
* Initialize the ACPI P - States library ( drivers / acpi / processor_perflib . c )
* in order to determine correct frequency and voltage pairings . We can
* do _PDC and _PSD and find out the processor dependency for the
* actual init that will happen later . . .
*/
2007-08-08 02:40:30 +04:00
static int __init acpi_cpufreq_early_init ( void )
2005-12-14 23:05:00 +03:00
{
2009-01-01 05:08:47 +03:00
unsigned int i ;
2005-12-14 23:05:00 +03:00
dprintk ( " acpi_cpufreq_early_init \n " ) ;
2007-08-08 02:40:30 +04:00
acpi_perf_data = alloc_percpu ( struct acpi_processor_performance ) ;
if ( ! acpi_perf_data ) {
dprintk ( " Memory allocation error for acpi_perf_data. \n " ) ;
return - ENOMEM ;
2005-12-14 23:05:00 +03:00
}
2009-01-01 05:08:47 +03:00
for_each_possible_cpu ( i ) {
2009-01-01 05:08:47 +03:00
if ( ! alloc_cpumask_var_node (
& per_cpu_ptr ( acpi_perf_data , i ) - > shared_cpu_map ,
GFP_KERNEL , cpu_to_node ( i ) ) ) {
2009-01-01 05:08:47 +03:00
/* Freeing a NULL pointer is OK: alloc_percpu zeroes. */
free_acpi_perf_data ( ) ;
return - ENOMEM ;
}
}
2005-12-14 23:05:00 +03:00
/* Do initialization in ACPI core */
2006-10-03 23:29:15 +04:00
acpi_processor_preregister_performance ( acpi_perf_data ) ;
return 0 ;
2005-12-14 23:05:00 +03:00
}
2006-10-21 09:37:39 +04:00
# ifdef CONFIG_SMP
2006-09-02 01:02:24 +04:00
/*
* Some BIOSes do SW_ANY coordination internally , either set it up in hw
* or do it in BIOS firmware and won ' t inform about it to OS . If not
* detected , this has a side effect of making CPU run at a different speed
* than OS intended it to run at . Detect it and handle it cleanly .
*/
static int bios_with_sw_any_bug ;
2007-10-03 23:15:40 +04:00
static int sw_any_bug_found ( const struct dmi_system_id * d )
2006-09-02 01:02:24 +04:00
{
bios_with_sw_any_bug = 1 ;
return 0 ;
}
2007-10-03 23:15:40 +04:00
static const struct dmi_system_id sw_any_bug_dmi_table [ ] = {
2006-09-02 01:02:24 +04:00
{
. callback = sw_any_bug_found ,
. ident = " Supermicro Server X6DLP " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Supermicro " ) ,
DMI_MATCH ( DMI_BIOS_VERSION , " 080010 " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " X6DLP " ) ,
} ,
} ,
{ }
} ;
2006-10-21 09:37:39 +04:00
# endif
2006-09-02 01:02:24 +04:00
2006-10-03 23:35:23 +04:00
static int acpi_cpufreq_cpu_init ( struct cpufreq_policy * policy )
2005-04-17 02:20:36 +04:00
{
2006-10-03 23:35:23 +04:00
unsigned int i ;
unsigned int valid_states = 0 ;
unsigned int cpu = policy - > cpu ;
struct acpi_cpufreq_data * data ;
unsigned int result = 0 ;
2007-10-19 22:35:04 +04:00
struct cpuinfo_x86 * c = & cpu_data ( policy - > cpu ) ;
2006-10-03 23:35:23 +04:00
struct acpi_processor_performance * perf ;
2005-04-17 02:20:36 +04:00
dprintk ( " acpi_cpufreq_cpu_init \n " ) ;
2006-10-03 23:29:15 +04:00
data = kzalloc ( sizeof ( struct acpi_cpufreq_data ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! data )
2006-10-03 23:35:23 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2007-08-08 02:40:30 +04:00
data - > acpi_data = percpu_ptr ( acpi_perf_data , cpu ) ;
2008-01-30 15:33:12 +03:00
per_cpu ( drv_data , cpu ) = data ;
2005-04-17 02:20:36 +04:00
2006-10-18 08:41:48 +04:00
if ( cpu_has ( c , X86_FEATURE_CONSTANT_TSC ) )
2006-10-03 23:29:15 +04:00
acpi_cpufreq_driver . flags | = CPUFREQ_CONST_LOOPS ;
2005-04-17 02:20:36 +04:00
2006-10-03 23:29:15 +04:00
result = acpi_processor_register_performance ( data - > acpi_data , cpu ) ;
2005-04-17 02:20:36 +04:00
if ( result )
goto err_free ;
2005-12-14 23:05:00 +03:00
perf = data - > acpi_data ;
policy - > shared_type = perf - > shared_type ;
2006-10-18 08:41:48 +04:00
2006-06-26 08:34:43 +04:00
/*
2006-10-18 08:41:48 +04:00
* Will let policy - > cpus know about dependency only when software
2006-06-26 08:34:43 +04:00
* coordination is required .
*/
if ( policy - > shared_type = = CPUFREQ_SHARED_TYPE_ALL | |
2006-09-02 01:02:24 +04:00
policy - > shared_type = = CPUFREQ_SHARED_TYPE_ANY ) {
2009-01-04 16:18:06 +03:00
cpumask_copy ( policy - > cpus , perf - > shared_cpu_map ) ;
2006-09-02 01:02:24 +04:00
}
2009-01-04 16:18:06 +03:00
cpumask_copy ( policy - > related_cpus , perf - > shared_cpu_map ) ;
2006-09-02 01:02:24 +04:00
# ifdef CONFIG_SMP
dmi_check_system ( sw_any_bug_dmi_table ) ;
2009-01-04 16:18:06 +03:00
if ( bios_with_sw_any_bug & & cpumask_weight ( policy - > cpus ) = = 1 ) {
2006-09-02 01:02:24 +04:00
policy - > shared_type = CPUFREQ_SHARED_TYPE_ALL ;
2009-01-04 16:18:06 +03:00
cpumask_copy ( policy - > cpus , cpu_core_mask ( cpu ) ) ;
2006-09-02 01:02:24 +04:00
}
# endif
2005-12-14 23:05:00 +03:00
2005-04-17 02:20:36 +04:00
/* capability check */
2005-12-14 23:05:00 +03:00
if ( perf - > state_count < = 1 ) {
2005-04-17 02:20:36 +04:00
dprintk ( " No P-States \n " ) ;
result = - ENODEV ;
goto err_unreg ;
}
2005-12-14 23:05:00 +03:00
2006-10-03 23:29:15 +04:00
if ( perf - > control_register . space_id ! = perf - > status_register . space_id ) {
result = - ENODEV ;
goto err_unreg ;
}
switch ( perf - > control_register . space_id ) {
2006-10-03 23:35:23 +04:00
case ACPI_ADR_SPACE_SYSTEM_IO :
2006-10-03 23:29:15 +04:00
dprintk ( " SYSTEM IO addr space \n " ) ;
2006-10-03 23:33:14 +04:00
data - > cpu_feature = SYSTEM_IO_CAPABLE ;
break ;
2006-10-03 23:35:23 +04:00
case ACPI_ADR_SPACE_FIXED_HARDWARE :
2006-10-03 23:33:14 +04:00
dprintk ( " HARDWARE addr space \n " ) ;
if ( ! check_est_cpu ( cpu ) ) {
result = - ENODEV ;
goto err_unreg ;
}
data - > cpu_feature = SYSTEM_INTEL_MSR_CAPABLE ;
2006-10-03 23:29:15 +04:00
break ;
2006-10-03 23:35:23 +04:00
default :
2006-10-03 23:29:15 +04:00
dprintk ( " Unknown addr space %d \n " ,
2006-10-03 23:35:23 +04:00
( u32 ) ( perf - > control_register . space_id ) ) ;
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
goto err_unreg ;
}
2006-10-18 08:41:48 +04:00
data - > freq_table = kmalloc ( sizeof ( struct cpufreq_frequency_table ) *
( perf - > state_count + 1 ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! data - > freq_table ) {
result = - ENOMEM ;
goto err_unreg ;
}
/* detect transition latency */
policy - > cpuinfo . transition_latency = 0 ;
2006-10-18 08:41:48 +04:00
for ( i = 0 ; i < perf - > state_count ; i + + ) {
2006-10-03 23:35:23 +04:00
if ( ( perf - > states [ i ] . transition_latency * 1000 ) >
policy - > cpuinfo . transition_latency )
policy - > cpuinfo . transition_latency =
perf - > states [ i ] . transition_latency * 1000 ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 23:38:45 +04:00
data - > max_freq = perf - > states [ 0 ] . core_frequency * 1000 ;
2005-04-17 02:20:36 +04:00
/* table init */
2006-10-18 08:41:48 +04:00
for ( i = 0 ; i < perf - > state_count ; i + + ) {
2007-06-14 05:24:02 +04:00
if ( i > 0 & & perf - > states [ i ] . core_frequency > =
data - > freq_table [ valid_states - 1 ] . frequency / 1000 )
2006-10-03 23:29:15 +04:00
continue ;
data - > freq_table [ valid_states ] . index = i ;
data - > freq_table [ valid_states ] . frequency =
2006-10-03 23:35:23 +04:00
perf - > states [ i ] . core_frequency * 1000 ;
2006-10-03 23:29:15 +04:00
valid_states + + ;
2005-04-17 02:20:36 +04:00
}
2006-11-14 04:47:44 +03:00
data - > freq_table [ valid_states ] . frequency = CPUFREQ_TABLE_END ;
2006-12-19 23:58:55 +03:00
perf - > state = 0 ;
2005-04-17 02:20:36 +04:00
result = cpufreq_frequency_table_cpuinfo ( policy , data - > freq_table ) ;
2006-10-18 08:41:48 +04:00
if ( result )
2005-04-17 02:20:36 +04:00
goto err_freqfree ;
2006-12-15 21:52:45 +03:00
switch ( perf - > control_register . space_id ) {
2006-10-03 23:35:23 +04:00
case ACPI_ADR_SPACE_SYSTEM_IO :
2006-10-03 23:33:14 +04:00
/* Current speed is unknown and not detectable by IO port */
policy - > cur = acpi_cpufreq_guess_freq ( data , policy - > cpu ) ;
break ;
2006-10-03 23:35:23 +04:00
case ACPI_ADR_SPACE_FIXED_HARDWARE :
2006-10-03 23:36:30 +04:00
acpi_cpufreq_driver . get = get_cur_freq_on_cpu ;
2006-12-15 21:52:45 +03:00
policy - > cur = get_cur_freq_on_cpu ( cpu ) ;
2006-10-03 23:33:14 +04:00
break ;
2006-10-03 23:35:23 +04:00
default :
2006-10-03 23:33:14 +04:00
break ;
}
2005-04-17 02:20:36 +04:00
/* notify BIOS that we exist */
acpi_processor_notify_smm ( THIS_MODULE ) ;
2006-10-03 23:38:45 +04:00
/* Check for APERF/MPERF support in hardware */
if ( c - > x86_vendor = = X86_VENDOR_INTEL & & c - > cpuid_level > = 6 ) {
unsigned int ecx ;
ecx = cpuid_ecx ( 6 ) ;
2006-10-18 08:41:48 +04:00
if ( ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY )
2006-10-03 23:38:45 +04:00
acpi_cpufreq_driver . getavg = get_measured_perf ;
}
2006-10-03 23:29:15 +04:00
dprintk ( " CPU%u - ACPI performance management activated. \n " , cpu ) ;
2005-12-14 23:05:00 +03:00
for ( i = 0 ; i < perf - > state_count ; i + + )
2005-04-17 02:20:36 +04:00
dprintk ( " %cP%d: %d MHz, %d mW, %d uS \n " ,
2006-10-03 23:35:23 +04:00
( i = = perf - > state ? ' * ' : ' ' ) , i ,
2005-12-14 23:05:00 +03:00
( u32 ) perf - > states [ i ] . core_frequency ,
( u32 ) perf - > states [ i ] . power ,
( u32 ) perf - > states [ i ] . transition_latency ) ;
2005-04-17 02:20:36 +04:00
cpufreq_frequency_table_get_attr ( data - > freq_table , policy - > cpu ) ;
2006-10-03 23:35:23 +04:00
2005-05-18 21:49:00 +04:00
/*
* the first call to - > target ( ) should result in us actually
* writing something to the appropriate registers .
*/
data - > resume = 1 ;
2006-10-03 23:35:23 +04:00
2006-10-03 23:29:15 +04:00
return result ;
2005-04-17 02:20:36 +04:00
2006-10-18 08:41:48 +04:00
err_freqfree :
2005-04-17 02:20:36 +04:00
kfree ( data - > freq_table ) ;
2006-10-18 08:41:48 +04:00
err_unreg :
2005-12-14 23:05:00 +03:00
acpi_processor_unregister_performance ( perf , cpu ) ;
2006-10-18 08:41:48 +04:00
err_free :
2005-04-17 02:20:36 +04:00
kfree ( data ) ;
2008-01-30 15:33:12 +03:00
per_cpu ( drv_data , cpu ) = NULL ;
2005-04-17 02:20:36 +04:00
2006-10-03 23:35:23 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 23:35:23 +04:00
static int acpi_cpufreq_cpu_exit ( struct cpufreq_policy * policy )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:33:12 +03:00
struct acpi_cpufreq_data * data = per_cpu ( drv_data , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
dprintk ( " acpi_cpufreq_cpu_exit \n " ) ;
if ( data ) {
cpufreq_frequency_table_put_attr ( policy - > cpu ) ;
2008-01-30 15:33:12 +03:00
per_cpu ( drv_data , policy - > cpu ) = NULL ;
2006-10-03 23:35:23 +04:00
acpi_processor_unregister_performance ( data - > acpi_data ,
policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
kfree ( data ) ;
}
2006-10-03 23:35:23 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 23:35:23 +04:00
static int acpi_cpufreq_resume ( struct cpufreq_policy * policy )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:33:12 +03:00
struct acpi_cpufreq_data * data = per_cpu ( drv_data , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
dprintk ( " acpi_cpufreq_resume \n " ) ;
data - > resume = 1 ;
2006-10-03 23:35:23 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 23:35:23 +04:00
static struct freq_attr * acpi_cpufreq_attr [ ] = {
2005-04-17 02:20:36 +04:00
& cpufreq_freq_attr_scaling_available_freqs ,
NULL ,
} ;
static struct cpufreq_driver acpi_cpufreq_driver = {
2006-10-03 23:35:23 +04:00
. verify = acpi_cpufreq_verify ,
. target = acpi_cpufreq_target ,
. init = acpi_cpufreq_cpu_init ,
. exit = acpi_cpufreq_cpu_exit ,
. resume = acpi_cpufreq_resume ,
. name = " acpi-cpufreq " ,
. owner = THIS_MODULE ,
. attr = acpi_cpufreq_attr ,
2005-04-17 02:20:36 +04:00
} ;
2006-10-03 23:35:23 +04:00
static int __init acpi_cpufreq_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-08-08 02:40:30 +04:00
int ret ;
2008-09-25 06:04:31 +04:00
if ( acpi_disabled )
return 0 ;
2005-04-17 02:20:36 +04:00
dprintk ( " acpi_cpufreq_init \n " ) ;
2007-08-08 02:40:30 +04:00
ret = acpi_cpufreq_early_init ( ) ;
if ( ret )
return ret ;
2005-12-14 23:05:00 +03:00
2008-07-14 06:59:44 +04:00
ret = cpufreq_register_driver ( & acpi_cpufreq_driver ) ;
if ( ret )
2009-01-01 05:08:47 +03:00
free_acpi_perf_data ( ) ;
2008-07-14 06:59:44 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 23:35:23 +04:00
static void __exit acpi_cpufreq_exit ( void )
2005-04-17 02:20:36 +04:00
{
dprintk ( " acpi_cpufreq_exit \n " ) ;
cpufreq_unregister_driver ( & acpi_cpufreq_driver ) ;
2007-08-08 02:40:30 +04:00
free_percpu ( acpi_perf_data ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-25 23:59:00 +04:00
module_param ( acpi_pstate_strict , uint , 0644 ) ;
2006-10-03 23:35:23 +04:00
MODULE_PARM_DESC ( acpi_pstate_strict ,
2006-10-18 08:41:48 +04:00
" value 0 or non-zero. non-zero -> strict ACPI checks are "
" performed during frequency changes. " ) ;
2005-04-17 02:20:36 +04:00
late_initcall ( acpi_cpufreq_init ) ;
module_exit ( acpi_cpufreq_exit ) ;
MODULE_ALIAS ( " acpi " ) ;