2005-04-17 02:20:36 +04:00
/*
* processor_throttling . c - Throttling submodule of the ACPI processor driver
*
* Copyright ( C ) 2001 , 2002 Andy Grover < andrew . grover @ intel . com >
* Copyright ( C ) 2001 , 2002 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
* Copyright ( C ) 2004 Dominik Brodowski < linux @ brodo . de >
* Copyright ( C ) 2004 Anil S Keshavamurthy < anil . s . keshavamurthy @ intel . com >
* - Added processor hotplug support
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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>
2007-11-29 11:22:43 +03:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <linux/cpufreq.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <asm/io.h>
# include <asm/uaccess.h>
# include <acpi/acpi_bus.h>
2008-11-08 02:57:45 +03:00
# include <acpi/acpi_drivers.h>
2005-04-17 02:20:36 +04:00
# include <acpi/processor.h>
# define ACPI_PROCESSOR_CLASS "processor"
# define _COMPONENT ACPI_PROCESSOR_COMPONENT
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " processor_throttling " ) ;
2005-04-17 02:20:36 +04:00
2008-01-28 08:54:46 +03:00
struct throttling_tstate {
unsigned int cpu ; /* cpu nr */
int target_state ; /* target T-state */
} ;
# define THROTTLING_PRECHANGE (1)
# define THROTTLING_POSTCHANGE (2)
2007-06-02 08:15:25 +04:00
static int acpi_processor_get_throttling ( struct acpi_processor * pr ) ;
int acpi_processor_set_throttling ( struct acpi_processor * pr , int state ) ;
2007-05-26 18:49:58 +04:00
2008-01-28 08:53:42 +03:00
static int acpi_processor_update_tsd_coord ( void )
{
int count , count_target ;
int retval = 0 ;
unsigned int i , j ;
2009-01-01 05:08:47 +03:00
cpumask_var_t covered_cpus ;
2008-01-28 08:53:42 +03:00
struct acpi_processor * pr , * match_pr ;
struct acpi_tsd_package * pdomain , * match_pdomain ;
struct acpi_processor_throttling * pthrottling , * match_pthrottling ;
2009-01-01 05:08:47 +03:00
if ( ! alloc_cpumask_var ( & covered_cpus , GFP_KERNEL ) )
return - ENOMEM ;
2008-01-28 08:53:42 +03:00
/*
* Now that we have _TSD data from all CPUs , lets setup T - state
2008-01-28 08:55:56 +03:00
* coordination between all CPUs .
2008-01-28 08:53:42 +03:00
*/
for_each_possible_cpu ( i ) {
2008-06-10 03:22:23 +04:00
pr = per_cpu ( processors , i ) ;
2008-01-28 08:53:42 +03:00
if ( ! pr )
continue ;
/* Basic validity check for domain info */
pthrottling = & ( pr - > throttling ) ;
/*
* If tsd package for one cpu is invalid , the coordination
* among all CPUs is thought as invalid .
* Maybe it is ugly .
*/
if ( ! pthrottling - > tsd_valid_flag ) {
retval = - EINVAL ;
break ;
}
}
if ( retval )
goto err_ret ;
2009-01-01 05:08:47 +03:00
cpumask_clear ( covered_cpus ) ;
2008-01-28 08:53:42 +03:00
for_each_possible_cpu ( i ) {
2008-06-10 03:22:23 +04:00
pr = per_cpu ( processors , i ) ;
2008-01-28 08:53:42 +03:00
if ( ! pr )
continue ;
2009-01-01 05:08:47 +03:00
if ( cpumask_test_cpu ( i , covered_cpus ) )
2008-01-28 08:53:42 +03:00
continue ;
pthrottling = & pr - > throttling ;
pdomain = & ( pthrottling - > domain_info ) ;
2009-01-01 05:08:47 +03:00
cpumask_set_cpu ( i , pthrottling - > shared_cpu_map ) ;
cpumask_set_cpu ( i , covered_cpus ) ;
2008-01-28 08:53:42 +03:00
/*
* If the number of processor in the TSD domain is 1 , it is
* unnecessary to parse the coordination for this CPU .
*/
if ( pdomain - > num_processors < = 1 )
continue ;
/* Validate the Domain info */
count_target = pdomain - > num_processors ;
count = 1 ;
for_each_possible_cpu ( j ) {
if ( i = = j )
continue ;
2008-06-10 03:22:23 +04:00
match_pr = per_cpu ( processors , j ) ;
2008-01-28 08:53:42 +03:00
if ( ! match_pr )
continue ;
match_pthrottling = & ( match_pr - > throttling ) ;
match_pdomain = & ( match_pthrottling - > domain_info ) ;
if ( match_pdomain - > domain ! = pdomain - > domain )
continue ;
/* Here i and j are in the same domain.
* If two TSD packages have the same domain , they
* should have the same num_porcessors and
* coordination type . Otherwise it will be regarded
* as illegal .
*/
if ( match_pdomain - > num_processors ! = count_target ) {
retval = - EINVAL ;
goto err_ret ;
}
if ( pdomain - > coord_type ! = match_pdomain - > coord_type ) {
retval = - EINVAL ;
goto err_ret ;
}
2009-01-01 05:08:47 +03:00
cpumask_set_cpu ( j , covered_cpus ) ;
cpumask_set_cpu ( j , pthrottling - > shared_cpu_map ) ;
2008-01-28 08:53:42 +03:00
count + + ;
}
for_each_possible_cpu ( j ) {
if ( i = = j )
continue ;
2008-06-10 03:22:23 +04:00
match_pr = per_cpu ( processors , j ) ;
2008-01-28 08:53:42 +03:00
if ( ! match_pr )
continue ;
match_pthrottling = & ( match_pr - > throttling ) ;
match_pdomain = & ( match_pthrottling - > domain_info ) ;
if ( match_pdomain - > domain ! = pdomain - > domain )
continue ;
/*
* If some CPUS have the same domain , they
* will have the same shared_cpu_map .
*/
2009-01-01 05:08:47 +03:00
cpumask_copy ( match_pthrottling - > shared_cpu_map ,
pthrottling - > shared_cpu_map ) ;
2008-01-28 08:53:42 +03:00
}
}
err_ret :
2009-01-01 05:08:47 +03:00
free_cpumask_var ( covered_cpus ) ;
2008-01-28 08:53:42 +03:00
for_each_possible_cpu ( i ) {
2008-06-10 03:22:23 +04:00
pr = per_cpu ( processors , i ) ;
2008-01-28 08:53:42 +03:00
if ( ! pr )
continue ;
/*
* Assume no coordination on any error parsing domain info .
* The coordination type will be forced as SW_ALL .
*/
if ( retval ) {
pthrottling = & ( pr - > throttling ) ;
2009-01-01 05:08:47 +03:00
cpumask_clear ( pthrottling - > shared_cpu_map ) ;
cpumask_set_cpu ( i , pthrottling - > shared_cpu_map ) ;
2008-01-28 08:53:42 +03:00
pthrottling - > shared_type = DOMAIN_COORD_TYPE_SW_ALL ;
}
}
return retval ;
}
/*
* Update the T - state coordination after the _TSD
* data for all cpus is obtained .
*/
void acpi_processor_throttling_init ( void )
{
if ( acpi_processor_update_tsd_coord ( ) )
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Assume no T-state coordination \n " ) ) ;
return ;
}
2008-01-28 08:54:46 +03:00
static int acpi_processor_throttling_notifier ( unsigned long event , void * data )
{
struct throttling_tstate * p_tstate = data ;
struct acpi_processor * pr ;
unsigned int cpu ;
int target_state ;
struct acpi_processor_limit * p_limit ;
struct acpi_processor_throttling * p_throttling ;
cpu = p_tstate - > cpu ;
2008-06-10 03:22:23 +04:00
pr = per_cpu ( processors , cpu ) ;
2008-01-28 08:54:46 +03:00
if ( ! pr ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Invalid pr pointer \n " ) ) ;
return 0 ;
}
if ( ! pr - > flags . throttling ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Throttling control is "
" unsupported on CPU %d \n " , cpu ) ) ;
return 0 ;
}
target_state = p_tstate - > target_state ;
p_throttling = & ( pr - > throttling ) ;
switch ( event ) {
case THROTTLING_PRECHANGE :
/*
* Prechange event is used to choose one proper t - state ,
* which meets the limits of thermal , user and _TPC .
*/
p_limit = & pr - > limit ;
if ( p_limit - > thermal . tx > target_state )
target_state = p_limit - > thermal . tx ;
if ( p_limit - > user . tx > target_state )
target_state = p_limit - > user . tx ;
if ( pr - > throttling_platform_limit > target_state )
target_state = pr - > throttling_platform_limit ;
if ( target_state > = p_throttling - > state_count ) {
printk ( KERN_WARNING
" Exceed the limit of T-state \n " ) ;
target_state = p_throttling - > state_count - 1 ;
}
p_tstate - > target_state = target_state ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " PreChange Event: "
" target T-state of CPU %d is T%d \n " ,
cpu , target_state ) ) ;
break ;
case THROTTLING_POSTCHANGE :
/*
* Postchange event is only used to update the
* T - state flag of acpi_processor_throttling .
*/
p_throttling - > state = target_state ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " PostChange Event: "
" CPU %d is switched to T%d \n " ,
cpu , target_state ) ) ;
break ;
default :
printk ( KERN_WARNING
" Unsupported Throttling notifier event \n " ) ;
break ;
}
return 0 ;
}
2007-07-25 08:57:46 +04:00
/*
* _TPC - Throttling Present Capabilities
*/
2007-05-26 18:49:58 +04:00
static int acpi_processor_get_platform_limit ( struct acpi_processor * pr )
{
acpi_status status = 0 ;
2008-10-10 10:22:59 +04:00
unsigned long long tpc = 0 ;
2007-05-26 18:49:58 +04:00
2007-06-02 08:15:25 +04:00
if ( ! pr )
2007-05-26 18:49:58 +04:00
return - EINVAL ;
status = acpi_evaluate_integer ( pr - > handle , " _TPC " , NULL , & tpc ) ;
2007-07-25 08:57:46 +04:00
if ( ACPI_FAILURE ( status ) ) {
if ( status ! = AE_NOT_FOUND ) {
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _TPC " ) ) ;
}
2007-05-26 18:49:58 +04:00
return - ENODEV ;
}
pr - > throttling_platform_limit = ( int ) tpc ;
return 0 ;
}
int acpi_processor_tstate_has_changed ( struct acpi_processor * pr )
{
2007-11-15 11:59:30 +03:00
int result = 0 ;
int throttling_limit ;
int current_state ;
struct acpi_processor_limit * limit ;
int target_state ;
result = acpi_processor_get_platform_limit ( pr ) ;
if ( result ) {
/* Throttling Limit is unsupported */
return result ;
}
throttling_limit = pr - > throttling_platform_limit ;
if ( throttling_limit > = pr - > throttling . state_count ) {
/* Uncorrect Throttling Limit */
return - EINVAL ;
}
current_state = pr - > throttling . state ;
if ( current_state > throttling_limit ) {
/*
* The current state can meet the requirement of
* _TPC limit . But it is reasonable that OSPM changes
* t - states from high to low for better performance .
* Of course the limit condition of thermal
* and user should be considered .
*/
limit = & pr - > limit ;
target_state = throttling_limit ;
if ( limit - > thermal . tx > target_state )
target_state = limit - > thermal . tx ;
if ( limit - > user . tx > target_state )
target_state = limit - > user . tx ;
} else if ( current_state = = throttling_limit ) {
/*
* Unnecessary to change the throttling state
*/
return 0 ;
} else {
/*
* If the current state is lower than the limit of _TPC , it
* will be forced to switch to the throttling state defined
* by throttling_platfor_limit .
* Because the previous state meets with the limit condition
* of thermal and user , it is unnecessary to check it again .
*/
target_state = throttling_limit ;
}
return acpi_processor_set_throttling ( pr , target_state ) ;
2007-05-26 18:49:58 +04:00
}
2007-07-25 08:57:46 +04:00
/*
* _PTC - Processor Throttling Control ( and status ) register location
*/
2007-05-26 18:49:58 +04:00
static int acpi_processor_get_throttling_control ( struct acpi_processor * pr )
{
int result = 0 ;
acpi_status status = 0 ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
union acpi_object * ptc = NULL ;
union acpi_object obj = { 0 } ;
2007-11-15 12:05:05 +03:00
struct acpi_processor_throttling * throttling ;
2007-05-26 18:49:58 +04:00
status = acpi_evaluate_object ( pr - > handle , " _PTC " , NULL , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
2007-07-25 08:57:46 +04:00
if ( status ! = AE_NOT_FOUND ) {
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _PTC " ) ) ;
}
2007-05-26 18:49:58 +04:00
return - ENODEV ;
}
ptc = ( union acpi_object * ) buffer . pointer ;
if ( ! ptc | | ( ptc - > type ! = ACPI_TYPE_PACKAGE )
| | ( ptc - > package . count ! = 2 ) ) {
printk ( KERN_ERR PREFIX " Invalid _PTC data \n " ) ;
result = - EFAULT ;
goto end ;
}
/*
* control_register
*/
obj = ptc - > package . elements [ 0 ] ;
if ( ( obj . type ! = ACPI_TYPE_BUFFER )
| | ( obj . buffer . length < sizeof ( struct acpi_ptc_register ) )
| | ( obj . buffer . pointer = = NULL ) ) {
2007-06-02 08:15:25 +04:00
printk ( KERN_ERR PREFIX
" Invalid _PTC data (control_register) \n " ) ;
2007-05-26 18:49:58 +04:00
result = - EFAULT ;
goto end ;
}
memcpy ( & pr - > throttling . control_register , obj . buffer . pointer ,
sizeof ( struct acpi_ptc_register ) ) ;
/*
* status_register
*/
obj = ptc - > package . elements [ 1 ] ;
if ( ( obj . type ! = ACPI_TYPE_BUFFER )
| | ( obj . buffer . length < sizeof ( struct acpi_ptc_register ) )
| | ( obj . buffer . pointer = = NULL ) ) {
printk ( KERN_ERR PREFIX " Invalid _PTC data (status_register) \n " ) ;
result = - EFAULT ;
goto end ;
}
memcpy ( & pr - > throttling . status_register , obj . buffer . pointer ,
2007-06-02 08:15:25 +04:00
sizeof ( struct acpi_ptc_register ) ) ;
2007-05-26 18:49:58 +04:00
2007-11-15 12:05:05 +03:00
throttling = & pr - > throttling ;
if ( ( throttling - > control_register . bit_width +
throttling - > control_register . bit_offset ) > 32 ) {
printk ( KERN_ERR PREFIX " Invalid _PTC control register \n " ) ;
result = - EFAULT ;
goto end ;
}
if ( ( throttling - > status_register . bit_width +
throttling - > status_register . bit_offset ) > 32 ) {
printk ( KERN_ERR PREFIX " Invalid _PTC status register \n " ) ;
result = - EFAULT ;
goto end ;
}
2007-06-02 08:15:25 +04:00
end :
2007-05-26 18:49:58 +04:00
kfree ( buffer . pointer ) ;
return result ;
}
2007-07-25 08:57:46 +04:00
/*
* _TSS - Throttling Supported States
*/
2007-05-26 18:49:58 +04:00
static int acpi_processor_get_throttling_states ( struct acpi_processor * pr )
{
int result = 0 ;
acpi_status status = AE_OK ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
struct acpi_buffer format = { sizeof ( " NNNNN " ) , " NNNNN " } ;
struct acpi_buffer state = { 0 , NULL } ;
union acpi_object * tss = NULL ;
int i ;
status = acpi_evaluate_object ( pr - > handle , " _TSS " , NULL , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
2007-07-25 08:57:46 +04:00
if ( status ! = AE_NOT_FOUND ) {
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _TSS " ) ) ;
}
2007-05-26 18:49:58 +04:00
return - ENODEV ;
}
tss = buffer . pointer ;
if ( ! tss | | ( tss - > type ! = ACPI_TYPE_PACKAGE ) ) {
printk ( KERN_ERR PREFIX " Invalid _TSS data \n " ) ;
result = - EFAULT ;
goto end ;
}
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Found %d throttling states \n " ,
tss - > package . count ) ) ;
pr - > throttling . state_count = tss - > package . count ;
pr - > throttling . states_tss =
kmalloc ( sizeof ( struct acpi_processor_tx_tss ) * tss - > package . count ,
GFP_KERNEL ) ;
if ( ! pr - > throttling . states_tss ) {
result = - ENOMEM ;
goto end ;
}
for ( i = 0 ; i < pr - > throttling . state_count ; i + + ) {
2007-06-02 08:15:25 +04:00
struct acpi_processor_tx_tss * tx =
( struct acpi_processor_tx_tss * ) & ( pr - > throttling .
states_tss [ i ] ) ;
2007-05-26 18:49:58 +04:00
state . length = sizeof ( struct acpi_processor_tx_tss ) ;
state . pointer = tx ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Extracting state %d \n " , i ) ) ;
status = acpi_extract_package ( & ( tss - > package . elements [ i ] ) ,
& format , & state ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_EXCEPTION ( ( AE_INFO , status , " Invalid _TSS data " ) ) ;
result = - EFAULT ;
kfree ( pr - > throttling . states_tss ) ;
goto end ;
}
if ( ! tx - > freqpercentage ) {
printk ( KERN_ERR PREFIX
2007-06-02 08:15:25 +04:00
" Invalid _TSS data: freq is zero \n " ) ;
2007-05-26 18:49:58 +04:00
result = - EFAULT ;
kfree ( pr - > throttling . states_tss ) ;
goto end ;
}
}
end :
kfree ( buffer . pointer ) ;
return result ;
}
2007-07-25 08:57:46 +04:00
/*
* _TSD - T - State Dependencies
*/
2007-06-02 08:15:25 +04:00
static int acpi_processor_get_tsd ( struct acpi_processor * pr )
2007-05-26 18:49:58 +04:00
{
int result = 0 ;
acpi_status status = AE_OK ;
2007-06-02 08:15:25 +04:00
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
struct acpi_buffer format = { sizeof ( " NNNNN " ) , " NNNNN " } ;
struct acpi_buffer state = { 0 , NULL } ;
union acpi_object * tsd = NULL ;
2007-05-26 18:49:58 +04:00
struct acpi_tsd_package * pdomain ;
2008-01-28 08:53:42 +03:00
struct acpi_processor_throttling * pthrottling ;
pthrottling = & pr - > throttling ;
pthrottling - > tsd_valid_flag = 0 ;
2007-05-26 18:49:58 +04:00
status = acpi_evaluate_object ( pr - > handle , " _TSD " , NULL , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
2007-07-25 08:57:46 +04:00
if ( status ! = AE_NOT_FOUND ) {
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _TSD " ) ) ;
}
2007-05-26 18:49:58 +04:00
return - ENODEV ;
}
tsd = buffer . pointer ;
if ( ! tsd | | ( tsd - > type ! = ACPI_TYPE_PACKAGE ) ) {
2008-09-28 10:51:56 +04:00
printk ( KERN_ERR PREFIX " Invalid _TSD data \n " ) ;
2007-05-26 18:49:58 +04:00
result = - EFAULT ;
goto end ;
}
if ( tsd - > package . count ! = 1 ) {
2008-09-28 10:51:56 +04:00
printk ( KERN_ERR PREFIX " Invalid _TSD data \n " ) ;
2007-05-26 18:49:58 +04:00
result = - EFAULT ;
goto end ;
}
pdomain = & ( pr - > throttling . domain_info ) ;
state . length = sizeof ( struct acpi_tsd_package ) ;
state . pointer = pdomain ;
status = acpi_extract_package ( & ( tsd - > package . elements [ 0 ] ) ,
2007-06-02 08:15:25 +04:00
& format , & state ) ;
2007-05-26 18:49:58 +04:00
if ( ACPI_FAILURE ( status ) ) {
2008-09-28 10:51:56 +04:00
printk ( KERN_ERR PREFIX " Invalid _TSD data \n " ) ;
2007-05-26 18:49:58 +04:00
result = - EFAULT ;
goto end ;
}
if ( pdomain - > num_entries ! = ACPI_TSD_REV0_ENTRIES ) {
2008-09-28 10:51:56 +04:00
printk ( KERN_ERR PREFIX " Unknown _TSD:num_entries \n " ) ;
2007-05-26 18:49:58 +04:00
result = - EFAULT ;
goto end ;
}
if ( pdomain - > revision ! = ACPI_TSD_REV0_REVISION ) {
2008-09-28 10:51:56 +04:00
printk ( KERN_ERR PREFIX " Unknown _TSD:revision \n " ) ;
2007-05-26 18:49:58 +04:00
result = - EFAULT ;
goto end ;
}
2008-01-28 08:53:42 +03:00
pthrottling = & pr - > throttling ;
pthrottling - > tsd_valid_flag = 1 ;
pthrottling - > shared_type = pdomain - > coord_type ;
2009-01-01 05:08:47 +03:00
cpumask_set_cpu ( pr - > id , pthrottling - > shared_cpu_map ) ;
2008-01-28 08:53:42 +03:00
/*
* If the coordination type is not defined in ACPI spec ,
* the tsd_valid_flag will be clear and coordination type
* will be forecd as DOMAIN_COORD_TYPE_SW_ALL .
*/
if ( pdomain - > coord_type ! = DOMAIN_COORD_TYPE_SW_ALL & &
pdomain - > coord_type ! = DOMAIN_COORD_TYPE_SW_ANY & &
pdomain - > coord_type ! = DOMAIN_COORD_TYPE_HW_ALL ) {
pthrottling - > tsd_valid_flag = 0 ;
pthrottling - > shared_type = DOMAIN_COORD_TYPE_SW_ALL ;
}
2007-06-02 08:15:25 +04:00
end :
2007-05-26 18:49:58 +04:00
kfree ( buffer . pointer ) ;
return result ;
}
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Throttling Control
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-05-26 18:49:58 +04:00
static int acpi_processor_get_throttling_fadt ( struct acpi_processor * pr )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int state = 0 ;
u32 value = 0 ;
u32 duty_mask = 0 ;
u32 duty_value = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! pr )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ! pr - > flags . throttling )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
pr - > throttling . state = 0 ;
duty_mask = pr - > throttling . state_count - 1 ;
duty_mask < < = pr - > throttling . duty_offset ;
local_irq_disable ( ) ;
value = inl ( pr - > throttling . address ) ;
/*
* Compute the current throttling state when throttling is enabled
* ( bit 4 is on ) .
*/
if ( value & 0x10 ) {
duty_value = value & duty_mask ;
duty_value > > = pr - > throttling . duty_offset ;
if ( duty_value )
2005-08-05 08:44:28 +04:00
state = pr - > throttling . state_count - duty_value ;
2005-04-17 02:20:36 +04:00
}
pr - > throttling . state = state ;
local_irq_enable ( ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" Throttling state is T%d (%d%% throttling applied) \n " ,
state , pr - > throttling . states [ state ] . performance ) ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-11-15 12:06:36 +03:00
# ifdef CONFIG_X86
static int acpi_throttling_rdmsr ( struct acpi_processor * pr ,
acpi_integer * value )
{
struct cpuinfo_x86 * c ;
u64 msr_high , msr_low ;
unsigned int cpu ;
u64 msr = 0 ;
int ret = - 1 ;
cpu = pr - > id ;
c = & cpu_data ( cpu ) ;
if ( ( c - > x86_vendor ! = X86_VENDOR_INTEL ) | |
! cpu_has ( c , X86_FEATURE_ACPI ) ) {
printk ( KERN_ERR PREFIX
" HARDWARE addr space,NOT supported yet \n " ) ;
} else {
msr_low = 0 ;
msr_high = 0 ;
2007-11-29 11:22:43 +03:00
rdmsr_safe ( MSR_IA32_THERM_CONTROL ,
2007-11-15 12:06:36 +03:00
( u32 * ) & msr_low , ( u32 * ) & msr_high ) ;
msr = ( msr_high < < 32 ) | msr_low ;
* value = ( acpi_integer ) msr ;
ret = 0 ;
}
return ret ;
}
static int acpi_throttling_wrmsr ( struct acpi_processor * pr , acpi_integer value )
{
struct cpuinfo_x86 * c ;
unsigned int cpu ;
int ret = - 1 ;
u64 msr ;
cpu = pr - > id ;
c = & cpu_data ( cpu ) ;
if ( ( c - > x86_vendor ! = X86_VENDOR_INTEL ) | |
! cpu_has ( c , X86_FEATURE_ACPI ) ) {
printk ( KERN_ERR PREFIX
" HARDWARE addr space,NOT supported yet \n " ) ;
} else {
msr = value ;
2007-11-29 11:22:43 +03:00
wrmsr_safe ( MSR_IA32_THERM_CONTROL ,
2007-11-15 12:06:36 +03:00
msr & 0xffffffff , msr > > 32 ) ;
ret = 0 ;
}
return ret ;
}
# else
static int acpi_throttling_rdmsr ( struct acpi_processor * pr ,
acpi_integer * value )
{
printk ( KERN_ERR PREFIX
" HARDWARE addr space,NOT supported yet \n " ) ;
return - 1 ;
}
static int acpi_throttling_wrmsr ( struct acpi_processor * pr , acpi_integer value )
{
printk ( KERN_ERR PREFIX
" HARDWARE addr space,NOT supported yet \n " ) ;
return - 1 ;
}
# endif
2007-11-15 12:03:46 +03:00
static int acpi_read_throttling_status ( struct acpi_processor * pr ,
acpi_integer * value )
2007-05-26 18:49:58 +04:00
{
2007-11-15 12:05:05 +03:00
u32 bit_width , bit_offset ;
2007-11-15 12:03:46 +03:00
u64 ptc_value ;
2007-11-15 12:05:05 +03:00
u64 ptc_mask ;
2007-11-15 12:03:46 +03:00
struct acpi_processor_throttling * throttling ;
int ret = - 1 ;
throttling = & pr - > throttling ;
2007-05-26 18:49:58 +04:00
switch ( throttling - > status_register . space_id ) {
case ACPI_ADR_SPACE_SYSTEM_IO :
2007-11-15 12:03:46 +03:00
ptc_value = 0 ;
2007-11-15 12:05:05 +03:00
bit_width = throttling - > status_register . bit_width ;
bit_offset = throttling - > status_register . bit_offset ;
2007-06-02 08:15:25 +04:00
acpi_os_read_port ( ( acpi_io_address ) throttling - > status_register .
2007-11-15 12:03:46 +03:00
address , ( u32 * ) & ptc_value ,
2007-11-15 12:05:05 +03:00
( u32 ) ( bit_width + bit_offset ) ) ;
ptc_mask = ( 1 < < bit_width ) - 1 ;
* value = ( acpi_integer ) ( ( ptc_value > > bit_offset ) & ptc_mask ) ;
2007-11-15 12:03:46 +03:00
ret = 0 ;
2007-05-26 18:49:58 +04:00
break ;
case ACPI_ADR_SPACE_FIXED_HARDWARE :
2007-11-15 12:06:36 +03:00
ret = acpi_throttling_rdmsr ( pr , value ) ;
2007-05-26 18:49:58 +04:00
break ;
default :
printk ( KERN_ERR PREFIX " Unknown addr space %d \n " ,
2007-06-02 08:15:25 +04:00
( u32 ) ( throttling - > status_register . space_id ) ) ;
2007-05-26 18:49:58 +04:00
}
2007-11-15 12:03:46 +03:00
return ret ;
2007-05-26 18:49:58 +04:00
}
2007-11-15 12:03:46 +03:00
static int acpi_write_throttling_state ( struct acpi_processor * pr ,
acpi_integer value )
2007-05-26 18:49:58 +04:00
{
2007-11-15 12:05:05 +03:00
u32 bit_width , bit_offset ;
2007-11-15 12:03:46 +03:00
u64 ptc_value ;
2007-11-15 12:05:05 +03:00
u64 ptc_mask ;
2007-11-15 12:03:46 +03:00
struct acpi_processor_throttling * throttling ;
2007-05-26 18:49:58 +04:00
int ret = - 1 ;
2007-11-15 12:03:46 +03:00
throttling = & pr - > throttling ;
2007-05-26 18:49:58 +04:00
switch ( throttling - > control_register . space_id ) {
case ACPI_ADR_SPACE_SYSTEM_IO :
2007-11-15 12:05:05 +03:00
bit_width = throttling - > control_register . bit_width ;
bit_offset = throttling - > control_register . bit_offset ;
ptc_mask = ( 1 < < bit_width ) - 1 ;
ptc_value = value & ptc_mask ;
2007-06-02 08:15:25 +04:00
acpi_os_write_port ( ( acpi_io_address ) throttling - >
2007-11-15 12:05:05 +03:00
control_register . address ,
( u32 ) ( ptc_value < < bit_offset ) ,
( u32 ) ( bit_width + bit_offset ) ) ;
2007-05-26 18:49:58 +04:00
ret = 0 ;
break ;
case ACPI_ADR_SPACE_FIXED_HARDWARE :
2007-11-15 12:06:36 +03:00
ret = acpi_throttling_wrmsr ( pr , value ) ;
2007-05-26 18:49:58 +04:00
break ;
default :
printk ( KERN_ERR PREFIX " Unknown addr space %d \n " ,
2007-06-02 08:15:25 +04:00
( u32 ) ( throttling - > control_register . space_id ) ) ;
2007-05-26 18:49:58 +04:00
}
return ret ;
}
2007-11-15 12:03:46 +03:00
static int acpi_get_throttling_state ( struct acpi_processor * pr ,
acpi_integer value )
2007-05-26 18:49:58 +04:00
{
int i ;
for ( i = 0 ; i < pr - > throttling . state_count ; i + + ) {
2007-06-02 08:15:25 +04:00
struct acpi_processor_tx_tss * tx =
( struct acpi_processor_tx_tss * ) & ( pr - > throttling .
states_tss [ i ] ) ;
if ( tx - > control = = value )
2007-05-26 18:49:58 +04:00
break ;
}
2007-06-02 08:15:25 +04:00
if ( i > pr - > throttling . state_count )
i = - 1 ;
2007-05-26 18:49:58 +04:00
return i ;
}
2007-11-15 12:03:46 +03:00
static int acpi_get_throttling_value ( struct acpi_processor * pr ,
int state , acpi_integer * value )
2007-05-26 18:49:58 +04:00
{
2007-11-15 12:03:46 +03:00
int ret = - 1 ;
2007-06-02 08:15:25 +04:00
if ( state > = 0 & & state < = pr - > throttling . state_count ) {
struct acpi_processor_tx_tss * tx =
( struct acpi_processor_tx_tss * ) & ( pr - > throttling .
states_tss [ state ] ) ;
2007-11-15 12:03:46 +03:00
* value = tx - > control ;
ret = 0 ;
2007-05-26 18:49:58 +04:00
}
2007-11-15 12:03:46 +03:00
return ret ;
2007-05-26 18:49:58 +04:00
}
static int acpi_processor_get_throttling_ptc ( struct acpi_processor * pr )
{
int state = 0 ;
2007-11-15 12:03:46 +03:00
int ret ;
acpi_integer value ;
2007-05-26 18:49:58 +04:00
if ( ! pr )
return - EINVAL ;
if ( ! pr - > flags . throttling )
return - ENODEV ;
pr - > throttling . state = 0 ;
2007-11-29 11:22:43 +03:00
2007-11-15 12:03:46 +03:00
value = 0 ;
ret = acpi_read_throttling_status ( pr , & value ) ;
if ( ret > = 0 ) {
2007-06-02 08:15:25 +04:00
state = acpi_get_throttling_state ( pr , value ) ;
2007-05-26 18:49:58 +04:00
pr - > throttling . state = state ;
}
return 0 ;
}
static int acpi_processor_get_throttling ( struct acpi_processor * pr )
{
2009-01-01 05:08:47 +03:00
cpumask_var_t saved_mask ;
2007-11-29 11:22:43 +03:00
int ret ;
2008-01-28 08:53:30 +03:00
if ( ! pr )
return - EINVAL ;
if ( ! pr - > flags . throttling )
return - ENODEV ;
2009-01-01 05:08:47 +03:00
if ( ! alloc_cpumask_var ( & saved_mask , GFP_KERNEL ) )
return - ENOMEM ;
2007-11-29 11:22:43 +03:00
/*
* Migrate task to the cpu pointed by pr .
*/
2009-01-01 05:08:47 +03:00
cpumask_copy ( saved_mask , & current - > cpus_allowed ) ;
/* FIXME: use work_on_cpu() */
set_cpus_allowed_ptr ( current , cpumask_of ( pr - > id ) ) ;
2007-11-29 11:22:43 +03:00
ret = pr - > throttling . acpi_processor_get_throttling ( pr ) ;
/* restore the previous state */
2009-01-01 05:08:47 +03:00
set_cpus_allowed_ptr ( current , saved_mask ) ;
free_cpumask_var ( saved_mask ) ;
2007-11-29 11:22:43 +03:00
return ret ;
2007-05-26 18:49:58 +04:00
}
2007-11-15 12:02:03 +03:00
static int acpi_processor_get_fadt_info ( struct acpi_processor * pr )
{
int i , step ;
if ( ! pr - > throttling . address ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " No throttling register \n " ) ) ;
return - EINVAL ;
} else if ( ! pr - > throttling . duty_width ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " No throttling states \n " ) ) ;
return - EINVAL ;
}
/* TBD: Support duty_cycle values that span bit 4. */
else if ( ( pr - > throttling . duty_offset + pr - > throttling . duty_width ) > 4 ) {
printk ( KERN_WARNING PREFIX " duty_cycle spans bit 4 \n " ) ;
return - EINVAL ;
}
pr - > throttling . state_count = 1 < < acpi_gbl_FADT . duty_width ;
/*
* Compute state values . Note that throttling displays a linear power
* performance relationship ( at 50 % performance the CPU will consume
* 50 % power ) . Values are in 1 / 10 th of a percent to preserve accuracy .
*/
step = ( 1000 / pr - > throttling . state_count ) ;
for ( i = 0 ; i < pr - > throttling . state_count ; i + + ) {
pr - > throttling . states [ i ] . performance = 1000 - step * i ;
pr - > throttling . states [ i ] . power = 1000 - step * i ;
}
return 0 ;
}
2007-07-03 08:53:12 +04:00
static int acpi_processor_set_throttling_fadt ( struct acpi_processor * pr ,
int state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
u32 value = 0 ;
u32 duty_mask = 0 ;
u32 duty_value = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! pr )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( state < 0 ) | | ( state > ( pr - > throttling . state_count - 1 ) ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ! pr - > flags . throttling )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( state = = pr - > throttling . state )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2007-05-26 18:49:58 +04:00
if ( state < pr - > throttling_platform_limit )
return - EPERM ;
2005-04-17 02:20:36 +04:00
/*
* Calculate the duty_value and duty_mask .
*/
if ( state ) {
duty_value = pr - > throttling . state_count - state ;
duty_value < < = pr - > throttling . duty_offset ;
/* Used to clear all duty_value bits */
duty_mask = pr - > throttling . state_count - 1 ;
2007-02-02 19:48:22 +03:00
duty_mask < < = acpi_gbl_FADT . duty_offset ;
2005-04-17 02:20:36 +04:00
duty_mask = ~ duty_mask ;
}
local_irq_disable ( ) ;
/*
* Disable throttling by writing a 0 to bit 4. Note that we must
* turn it off before you can change the duty_value .
*/
value = inl ( pr - > throttling . address ) ;
if ( value & 0x10 ) {
value & = 0xFFFFFFEF ;
outl ( value , pr - > throttling . address ) ;
}
/*
* Write the new duty_value and then enable throttling . Note
* that a state value of 0 leaves throttling disabled .
*/
if ( state ) {
value & = duty_mask ;
value | = duty_value ;
outl ( value , pr - > throttling . address ) ;
value | = 0x00000010 ;
outl ( value , pr - > throttling . address ) ;
}
pr - > throttling . state = state ;
local_irq_enable ( ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" Throttling state set to T%d (%d%%) \n " , state ,
( pr - > throttling . states [ state ] . performance ? pr - >
throttling . states [ state ] . performance / 10 : 0 ) ) ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-07-03 08:53:12 +04:00
static int acpi_processor_set_throttling_ptc ( struct acpi_processor * pr ,
int state )
2007-05-26 18:49:58 +04:00
{
2007-11-15 12:03:46 +03:00
int ret ;
acpi_integer value ;
2007-05-26 18:49:58 +04:00
if ( ! pr )
return - EINVAL ;
if ( ( state < 0 ) | | ( state > ( pr - > throttling . state_count - 1 ) ) )
return - EINVAL ;
if ( ! pr - > flags . throttling )
return - ENODEV ;
if ( state = = pr - > throttling . state )
return 0 ;
if ( state < pr - > throttling_platform_limit )
return - EPERM ;
2007-11-15 12:03:46 +03:00
value = 0 ;
ret = acpi_get_throttling_value ( pr , state , & value ) ;
if ( ret > = 0 ) {
acpi_write_throttling_state ( pr , value ) ;
2007-05-26 18:49:58 +04:00
pr - > throttling . state = state ;
}
return 0 ;
}
int acpi_processor_set_throttling ( struct acpi_processor * pr , int state )
{
2009-01-01 05:08:47 +03:00
cpumask_var_t saved_mask ;
2008-02-02 11:56:18 +03:00
int ret = 0 ;
2008-01-28 08:55:56 +03:00
unsigned int i ;
struct acpi_processor * match_pr ;
struct acpi_processor_throttling * p_throttling ;
struct throttling_tstate t_state ;
2009-01-01 05:08:47 +03:00
cpumask_var_t online_throttling_cpus ;
2008-01-28 08:53:30 +03:00
if ( ! pr )
return - EINVAL ;
if ( ! pr - > flags . throttling )
return - ENODEV ;
if ( ( state < 0 ) | | ( state > ( pr - > throttling . state_count - 1 ) ) )
return - EINVAL ;
2009-01-01 05:08:47 +03:00
if ( ! alloc_cpumask_var ( & saved_mask , GFP_KERNEL ) )
return - ENOMEM ;
if ( ! alloc_cpumask_var ( & online_throttling_cpus , GFP_KERNEL ) ) {
free_cpumask_var ( saved_mask ) ;
return - ENOMEM ;
}
cpumask_copy ( saved_mask , & current - > cpus_allowed ) ;
2008-01-28 08:55:56 +03:00
t_state . target_state = state ;
p_throttling = & ( pr - > throttling ) ;
2009-01-01 05:08:47 +03:00
cpumask_and ( online_throttling_cpus , cpu_online_mask ,
p_throttling - > shared_cpu_map ) ;
2007-11-29 11:22:43 +03:00
/*
2008-01-28 08:55:56 +03:00
* The throttling notifier will be called for every
* affected cpu in order to get one proper T - state .
* The notifier event is THROTTLING_PRECHANGE .
2007-11-29 11:22:43 +03:00
*/
2009-01-01 05:08:47 +03:00
for_each_cpu ( i , online_throttling_cpus ) {
2008-01-28 08:55:56 +03:00
t_state . cpu = i ;
acpi_processor_throttling_notifier ( THROTTLING_PRECHANGE ,
& t_state ) ;
}
/*
* The function of acpi_processor_set_throttling will be called
* to switch T - state . If the coordination type is SW_ALL or HW_ALL ,
* it is necessary to call it for every affected cpu . Otherwise
* it can be called only for the cpu pointed by pr .
*/
if ( p_throttling - > shared_type = = DOMAIN_COORD_TYPE_SW_ANY ) {
2009-01-01 05:08:47 +03:00
/* FIXME: use work_on_cpu() */
set_cpus_allowed_ptr ( current , cpumask_of ( pr - > id ) ) ;
2008-01-28 08:55:56 +03:00
ret = p_throttling - > acpi_processor_set_throttling ( pr ,
t_state . target_state ) ;
} else {
/*
* When the T - state coordination is SW_ALL or HW_ALL ,
* it is necessary to set T - state for every affected
* cpus .
*/
2009-01-01 05:08:47 +03:00
for_each_cpu ( i , online_throttling_cpus ) {
2008-06-10 03:22:23 +04:00
match_pr = per_cpu ( processors , i ) ;
2008-01-28 08:55:56 +03:00
/*
* If the pointer is invalid , we will report the
* error message and continue .
*/
if ( ! match_pr ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Invalid Pointer for CPU %d \n " , i ) ) ;
continue ;
}
/*
* If the throttling control is unsupported on CPU i ,
* we will report the error message and continue .
*/
if ( ! match_pr - > flags . throttling ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Throttling Controll is unsupported "
" on CPU %d \n " , i ) ) ;
continue ;
}
t_state . cpu = i ;
2009-01-01 05:08:47 +03:00
/* FIXME: use work_on_cpu() */
set_cpus_allowed_ptr ( current , cpumask_of ( i ) ) ;
2008-01-28 08:55:56 +03:00
ret = match_pr - > throttling .
acpi_processor_set_throttling (
match_pr , t_state . target_state ) ;
}
}
/*
* After the set_throttling is called , the
* throttling notifier is called for every
* affected cpu to update the T - states .
* The notifier event is THROTTLING_POSTCHANGE
*/
2009-01-01 05:08:47 +03:00
for_each_cpu ( i , online_throttling_cpus ) {
2008-01-28 08:55:56 +03:00
t_state . cpu = i ;
acpi_processor_throttling_notifier ( THROTTLING_POSTCHANGE ,
& t_state ) ;
}
2007-11-29 11:22:43 +03:00
/* restore the previous state */
2009-01-01 05:08:47 +03:00
/* FIXME: use work_on_cpu() */
set_cpus_allowed_ptr ( current , saved_mask ) ;
free_cpumask_var ( online_throttling_cpus ) ;
free_cpumask_var ( saved_mask ) ;
2007-11-29 11:22:43 +03:00
return ret ;
2007-05-26 18:49:58 +04:00
}
2005-08-05 08:44:28 +04:00
int acpi_processor_get_throttling_info ( struct acpi_processor * pr )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
2008-01-28 08:53:42 +03:00
struct acpi_processor_throttling * pthrottling ;
2005-04-17 02:20:36 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" pblk_address[0x%08x] duty_offset[%d] duty_width[%d] \n " ,
pr - > throttling . address ,
pr - > throttling . duty_offset ,
pr - > throttling . duty_width ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! pr )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2007-07-25 08:57:46 +04:00
/*
* Evaluate _PTC , _TSS and _TPC
* They must all be present or none of them can be used .
*/
if ( acpi_processor_get_throttling_control ( pr ) | |
acpi_processor_get_throttling_states ( pr ) | |
acpi_processor_get_platform_limit ( pr ) )
{
2007-06-02 08:15:25 +04:00
pr - > throttling . acpi_processor_get_throttling =
& acpi_processor_get_throttling_fadt ;
pr - > throttling . acpi_processor_set_throttling =
& acpi_processor_set_throttling_fadt ;
2008-01-15 08:47:47 +03:00
if ( acpi_processor_get_fadt_info ( pr ) )
return 0 ;
2007-05-26 18:49:58 +04:00
} else {
2007-06-02 08:15:25 +04:00
pr - > throttling . acpi_processor_get_throttling =
& acpi_processor_get_throttling_ptc ;
pr - > throttling . acpi_processor_set_throttling =
& acpi_processor_set_throttling_ptc ;
2007-05-26 18:49:58 +04:00
}
2005-04-17 02:20:36 +04:00
2008-01-28 08:53:42 +03:00
/*
* If TSD package for one CPU can ' t be parsed successfully , it means
* that this CPU will have no coordination with other CPUs .
*/
if ( acpi_processor_get_tsd ( pr ) ) {
pthrottling = & pr - > throttling ;
pthrottling - > tsd_valid_flag = 0 ;
2009-01-01 05:08:47 +03:00
cpumask_set_cpu ( pr - > id , pthrottling - > shared_cpu_map ) ;
2008-01-28 08:53:42 +03:00
pthrottling - > shared_type = DOMAIN_COORD_TYPE_SW_ALL ;
}
2007-07-25 08:57:46 +04:00
2005-04-17 02:20:36 +04:00
/*
* PIIX4 Errata : We don ' t support throttling on the original PIIX4 .
* This shouldn ' t be an issue as few ( if any ) mobile systems ever
* used this part .
*/
if ( errata . piix4 . throttle ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" Throttling not supported on PIIX4 A- or B-step \n " ) ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Found %d throttling states \n " ,
2005-08-05 08:44:28 +04:00
pr - > throttling . state_count ) ) ;
2005-04-17 02:20:36 +04:00
pr - > flags . throttling = 1 ;
/*
* Disable throttling ( if enabled ) . We ' ll let subsequent policy ( e . g .
* thermal ) decide to lower performance if it so chooses , but for now
* we ' ll crank up the speed .
*/
result = acpi_processor_get_throttling ( pr ) ;
if ( result )
goto end ;
if ( pr - > throttling . state ) {
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Disabling throttling (was T%d) \n " ,
pr - > throttling . state ) ) ;
2005-04-17 02:20:36 +04:00
result = acpi_processor_set_throttling ( pr , 0 ) ;
if ( result )
goto end ;
}
2005-08-05 08:44:28 +04:00
end :
2005-04-17 02:20:36 +04:00
if ( result )
pr - > flags . throttling = 0 ;
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
/* proc interface */
2005-08-05 08:44:28 +04:00
static int acpi_processor_throttling_seq_show ( struct seq_file * seq ,
void * offset )
2005-04-17 02:20:36 +04:00
{
2006-10-01 02:28:50 +04:00
struct acpi_processor * pr = seq - > private ;
2005-08-05 08:44:28 +04:00
int i = 0 ;
int result = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! pr )
goto end ;
if ( ! ( pr - > throttling . state_count > 0 ) ) {
seq_puts ( seq , " <not supported> \n " ) ;
goto end ;
}
result = acpi_processor_get_throttling ( pr ) ;
if ( result ) {
2005-08-05 08:44:28 +04:00
seq_puts ( seq ,
" Could not determine current throttling state. \n " ) ;
2005-04-17 02:20:36 +04:00
goto end ;
}
seq_printf ( seq , " state count: %d \n "
2007-05-26 18:49:58 +04:00
" active state: T%d \n "
2007-06-02 08:15:25 +04:00
" state available: T%d to T%d \n " ,
2007-05-26 18:49:58 +04:00
pr - > throttling . state_count , pr - > throttling . state ,
2007-06-02 08:15:25 +04:00
pr - > throttling_platform_limit ,
pr - > throttling . state_count - 1 ) ;
2005-04-17 02:20:36 +04:00
seq_puts ( seq , " states: \n " ) ;
2007-07-23 20:39:28 +04:00
if ( pr - > throttling . acpi_processor_get_throttling = =
acpi_processor_get_throttling_fadt ) {
2007-05-26 18:49:58 +04:00
for ( i = 0 ; i < pr - > throttling . state_count ; i + + )
seq_printf ( seq , " %cT%d: %02d%% \n " ,
2007-06-02 08:15:25 +04:00
( i = = pr - > throttling . state ? ' * ' : ' ' ) , i ,
( pr - > throttling . states [ i ] . performance ? pr - >
throttling . states [ i ] . performance / 10 : 0 ) ) ;
2007-07-23 20:39:28 +04:00
} else {
2007-05-26 18:49:58 +04:00
for ( i = 0 ; i < pr - > throttling . state_count ; i + + )
seq_printf ( seq , " %cT%d: %02d%% \n " ,
2007-06-02 08:15:25 +04:00
( i = = pr - > throttling . state ? ' * ' : ' ' ) , i ,
( int ) pr - > throttling . states_tss [ i ] .
freqpercentage ) ;
2007-07-23 20:39:28 +04:00
}
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_processor_throttling_open_fs ( struct inode * inode ,
struct file * file )
2005-04-17 02:20:36 +04:00
{
return single_open ( file , acpi_processor_throttling_seq_show ,
2005-08-05 08:44:28 +04:00
PDE ( inode ) - > data ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-02 08:15:25 +04:00
static ssize_t acpi_processor_write_throttling ( struct file * file ,
2006-01-07 21:19:00 +03:00
const char __user * buffer ,
size_t count , loff_t * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
2006-10-01 02:28:50 +04:00
struct seq_file * m = file - > private_data ;
struct acpi_processor * pr = m - > private ;
ACPI: fix processor throttling set error
http://bugzilla.kernel.org/show_bug.cgi?id=9704
When echo some invalid values to /proc/acpi/processor/*/throttling,
there isn't any error info returned, on the contray, it sets
throttling value to some T* successfully, obviously, this is incorrect,
a correct way should be to let it fail and return error info.
This patch fixed the aforementioned issue, it also enables
/proc/acpi/processor/*/throttling to accept such values as 't0' and 'T0',
it also strictly limits /proc/acpi/processor/*/throttling only to accept
"*", "t*" and "T*", "*" is the throttling state value the processor can
support, current, it is 0 - 7.
Before applying this patch, the test result is below:
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "1xxxxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# cd /
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T100" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "2xxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T2
state available: T0 to T7
states:
T0: 100%
T1: 87%
*T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "7777" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost /]# echo "7xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost /]#
After applying this patch, the test result is below:
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# vi drivers/acpi/processor_throttling.c
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "t7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "7000" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo -n > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo $?
0
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo t0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo T0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo Tt0 > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo T > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-14 08:54:37 +04:00
char state_string [ 5 ] = " " ;
char * charp = NULL ;
size_t state_val = 0 ;
char tmpbuf [ 5 ] = " " ;
2005-04-17 02:20:36 +04:00
if ( ! pr | | ( count > sizeof ( state_string ) - 1 ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( state_string , buffer , count ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
state_string [ count ] = ' \0 ' ;
ACPI: fix processor throttling set error
http://bugzilla.kernel.org/show_bug.cgi?id=9704
When echo some invalid values to /proc/acpi/processor/*/throttling,
there isn't any error info returned, on the contray, it sets
throttling value to some T* successfully, obviously, this is incorrect,
a correct way should be to let it fail and return error info.
This patch fixed the aforementioned issue, it also enables
/proc/acpi/processor/*/throttling to accept such values as 't0' and 'T0',
it also strictly limits /proc/acpi/processor/*/throttling only to accept
"*", "t*" and "T*", "*" is the throttling state value the processor can
support, current, it is 0 - 7.
Before applying this patch, the test result is below:
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "1xxxxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# cd /
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T100" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "2xxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T2
state available: T0 to T7
states:
T0: 100%
T1: 87%
*T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "7777" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost /]# echo "7xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost /]#
After applying this patch, the test result is below:
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# vi drivers/acpi/processor_throttling.c
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "t7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "7000" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo -n > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo $?
0
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo t0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo T0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo Tt0 > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo T > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-14 08:54:37 +04:00
if ( ( count > 0 ) & & ( state_string [ count - 1 ] = = ' \n ' ) )
state_string [ count - 1 ] = ' \0 ' ;
2005-04-17 02:20:36 +04:00
ACPI: fix processor throttling set error
http://bugzilla.kernel.org/show_bug.cgi?id=9704
When echo some invalid values to /proc/acpi/processor/*/throttling,
there isn't any error info returned, on the contray, it sets
throttling value to some T* successfully, obviously, this is incorrect,
a correct way should be to let it fail and return error info.
This patch fixed the aforementioned issue, it also enables
/proc/acpi/processor/*/throttling to accept such values as 't0' and 'T0',
it also strictly limits /proc/acpi/processor/*/throttling only to accept
"*", "t*" and "T*", "*" is the throttling state value the processor can
support, current, it is 0 - 7.
Before applying this patch, the test result is below:
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "1xxxxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# cd /
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T100" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "2xxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T2
state available: T0 to T7
states:
T0: 100%
T1: 87%
*T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "7777" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost /]# echo "7xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost /]#
After applying this patch, the test result is below:
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# vi drivers/acpi/processor_throttling.c
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "t7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "7000" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo -n > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo $?
0
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo t0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo T0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo Tt0 > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo T > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-14 08:54:37 +04:00
charp = state_string ;
if ( ( state_string [ 0 ] = = ' t ' ) | | ( state_string [ 0 ] = = ' T ' ) )
charp + + ;
state_val = simple_strtoul ( charp , NULL , 0 ) ;
if ( state_val > = pr - > throttling . state_count )
return - EINVAL ;
2008-06-17 20:43:41 +04:00
snprintf ( tmpbuf , 5 , " %zu " , state_val ) ;
ACPI: fix processor throttling set error
http://bugzilla.kernel.org/show_bug.cgi?id=9704
When echo some invalid values to /proc/acpi/processor/*/throttling,
there isn't any error info returned, on the contray, it sets
throttling value to some T* successfully, obviously, this is incorrect,
a correct way should be to let it fail and return error info.
This patch fixed the aforementioned issue, it also enables
/proc/acpi/processor/*/throttling to accept such values as 't0' and 'T0',
it also strictly limits /proc/acpi/processor/*/throttling only to accept
"*", "t*" and "T*", "*" is the throttling state value the processor can
support, current, it is 0 - 7.
Before applying this patch, the test result is below:
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "1xxxxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T1
state available: T0 to T7
states:
T0: 100%
*T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost acpi]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost acpi]# cd /
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "T100" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "2xxxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T2
state available: T0 to T7
states:
T0: 100%
T1: 87%
*T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost /]# echo "7777" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost /]# echo "7xxx" > /proc/acpi/processor/CPU0/throttling
[root@localhost /]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost /]#
After applying this patch, the test result is below:
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "T0" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T0
state available: T0 to T7
states:
*T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# vi drivers/acpi/processor_throttling.c
[root@localhost linux-2.6.24-rc6]# echo "T8" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "t7" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo "t70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "7000" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "70" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo "xxx" > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo -n > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo $?
0
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo -n "" > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# cat /proc/acpi/processor/CPU0/throttling
state count: 8
active state: T7
state available: T0 to T7
states:
T0: 100%
T1: 87%
T2: 75%
T3: 62%
T4: 50%
T5: 37%
T6: 25%
*T7: 12%
[root@localhost linux-2.6.24-rc6]# echo t0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo T0 > /proc/acpi/processor/CPU0/throttling
[root@localhost linux-2.6.24-rc6]# echo Tt0 > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]# echo T > /proc/acpi/processor/CPU0/throttling
-bash: echo: write error: Invalid argument
[root@localhost linux-2.6.24-rc6]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-14 08:54:37 +04:00
if ( strcmp ( tmpbuf , charp ) ! = 0 )
return - EINVAL ;
result = acpi_processor_set_throttling ( pr , state_val ) ;
2005-04-17 02:20:36 +04:00
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
struct file_operations acpi_processor_throttling_fops = {
2008-04-29 12:02:27 +04:00
. owner = THIS_MODULE ,
2005-08-05 08:44:28 +04:00
. open = acpi_processor_throttling_open_fs ,
. read = seq_read ,
2006-01-07 00:47:00 +03:00
. write = acpi_processor_write_throttling ,
2005-08-05 08:44:28 +04:00
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;