2005-04-17 02:20:36 +04:00
/*
* linux / drivers / cpufreq / freq_table . c
*
* Copyright ( C ) 2002 - 2003 Dominik Brodowski
2008-05-22 10:52:05 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/cpufreq.h>
2006-10-26 14:50:58 +04:00
# define dprintk(msg...) \
cpufreq_debug_printk ( CPUFREQ_DEBUG_CORE , " freq-table " , msg )
2005-04-17 02:20:36 +04:00
/*********************************************************************
* FREQUENCY TABLE HELPERS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int cpufreq_frequency_table_cpuinfo ( struct cpufreq_policy * policy ,
struct cpufreq_frequency_table * table )
{
unsigned int min_freq = ~ 0 ;
unsigned int max_freq = 0 ;
2006-05-31 01:58:41 +04:00
unsigned int i ;
2005-04-17 02:20:36 +04:00
2009-01-18 09:56:41 +03:00
for ( i = 0 ; ( table [ i ] . frequency ! = CPUFREQ_TABLE_END ) ; i + + ) {
2005-04-17 02:20:36 +04:00
unsigned int freq = table [ i ] . frequency ;
if ( freq = = CPUFREQ_ENTRY_INVALID ) {
dprintk ( " table entry %u is invalid, skipping \n " , i ) ;
continue ;
}
2006-10-26 14:50:58 +04:00
dprintk ( " table entry %u: %u kHz, %u index \n " ,
i , freq , table [ i ] . index ) ;
2005-04-17 02:20:36 +04:00
if ( freq < min_freq )
min_freq = freq ;
if ( freq > max_freq )
max_freq = freq ;
}
policy - > min = policy - > cpuinfo . min_freq = min_freq ;
policy - > max = policy - > cpuinfo . max_freq = max_freq ;
if ( policy - > min = = ~ 0 )
return - EINVAL ;
else
return 0 ;
}
EXPORT_SYMBOL_GPL ( cpufreq_frequency_table_cpuinfo ) ;
int cpufreq_frequency_table_verify ( struct cpufreq_policy * policy ,
struct cpufreq_frequency_table * table )
{
unsigned int next_larger = ~ 0 ;
2006-05-31 01:59:48 +04:00
unsigned int i ;
2005-04-17 02:20:36 +04:00
unsigned int count = 0 ;
2006-10-26 14:50:58 +04:00
dprintk ( " request for verification of policy (%u - %u kHz) for cpu %u \n " ,
policy - > min , policy - > max , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
if ( ! cpu_online ( policy - > cpu ) )
return - EINVAL ;
2006-10-26 14:50:58 +04:00
cpufreq_verify_within_limits ( policy , policy - > cpuinfo . min_freq ,
policy - > cpuinfo . max_freq ) ;
2005-04-17 02:20:36 +04:00
2009-01-18 09:56:41 +03:00
for ( i = 0 ; ( table [ i ] . frequency ! = CPUFREQ_TABLE_END ) ; i + + ) {
2005-04-17 02:20:36 +04:00
unsigned int freq = table [ i ] . frequency ;
if ( freq = = CPUFREQ_ENTRY_INVALID )
continue ;
if ( ( freq > = policy - > min ) & & ( freq < = policy - > max ) )
count + + ;
else if ( ( next_larger > freq ) & & ( freq > policy - > max ) )
next_larger = freq ;
}
if ( ! count )
policy - > max = next_larger ;
2006-10-26 14:50:58 +04:00
cpufreq_verify_within_limits ( policy , policy - > cpuinfo . min_freq ,
policy - > cpuinfo . max_freq ) ;
2005-04-17 02:20:36 +04:00
2006-10-26 14:50:58 +04:00
dprintk ( " verification lead to (%u - %u kHz) for cpu %u \n " ,
policy - > min , policy - > max , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( cpufreq_frequency_table_verify ) ;
int cpufreq_frequency_table_target ( struct cpufreq_policy * policy ,
struct cpufreq_frequency_table * table ,
unsigned int target_freq ,
unsigned int relation ,
unsigned int * index )
{
2006-05-31 02:09:31 +04:00
struct cpufreq_frequency_table optimal = {
. index = ~ 0 ,
. frequency = 0 ,
} ;
struct cpufreq_frequency_table suboptimal = {
. index = ~ 0 ,
. frequency = 0 ,
} ;
2005-04-17 02:20:36 +04:00
unsigned int i ;
2006-10-26 14:50:58 +04:00
dprintk ( " request for target %u kHz (relation: %u) for cpu %u \n " ,
target_freq , relation , policy - > cpu ) ;
2005-04-17 02:20:36 +04:00
switch ( relation ) {
case CPUFREQ_RELATION_H :
suboptimal . frequency = ~ 0 ;
break ;
case CPUFREQ_RELATION_L :
optimal . frequency = ~ 0 ;
break ;
}
if ( ! cpu_online ( policy - > cpu ) )
return - EINVAL ;
2009-01-18 09:56:41 +03:00
for ( i = 0 ; ( table [ i ] . frequency ! = CPUFREQ_TABLE_END ) ; i + + ) {
2005-04-17 02:20:36 +04:00
unsigned int freq = table [ i ] . frequency ;
if ( freq = = CPUFREQ_ENTRY_INVALID )
continue ;
if ( ( freq < policy - > min ) | | ( freq > policy - > max ) )
continue ;
2009-01-18 09:56:41 +03:00
switch ( relation ) {
2005-04-17 02:20:36 +04:00
case CPUFREQ_RELATION_H :
if ( freq < = target_freq ) {
if ( freq > = optimal . frequency ) {
optimal . frequency = freq ;
optimal . index = i ;
}
} else {
if ( freq < = suboptimal . frequency ) {
suboptimal . frequency = freq ;
suboptimal . index = i ;
}
}
break ;
case CPUFREQ_RELATION_L :
if ( freq > = target_freq ) {
if ( freq < = optimal . frequency ) {
optimal . frequency = freq ;
optimal . index = i ;
}
} else {
if ( freq > = suboptimal . frequency ) {
suboptimal . frequency = freq ;
suboptimal . index = i ;
}
}
break ;
}
}
if ( optimal . index > i ) {
if ( suboptimal . index > i )
return - EINVAL ;
* index = suboptimal . index ;
} else
* index = optimal . index ;
dprintk ( " target is %u (%u kHz, %u) \n " , * index , table [ * index ] . frequency ,
table [ * index ] . index ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( cpufreq_frequency_table_target ) ;
2008-03-26 01:06:53 +03:00
static DEFINE_PER_CPU ( struct cpufreq_frequency_table * , show_table ) ;
2005-04-17 02:20:36 +04:00
/**
2007-11-22 01:52:15 +03:00
* show_available_freqs - show available frequencies for the specified CPU
2005-04-17 02:20:36 +04:00
*/
2009-01-18 09:56:41 +03:00
static ssize_t show_available_freqs ( struct cpufreq_policy * policy , char * buf )
2005-04-17 02:20:36 +04:00
{
unsigned int i = 0 ;
unsigned int cpu = policy - > cpu ;
ssize_t count = 0 ;
struct cpufreq_frequency_table * table ;
2008-03-26 01:06:53 +03:00
if ( ! per_cpu ( show_table , cpu ) )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2008-03-26 01:06:53 +03:00
table = per_cpu ( show_table , cpu ) ;
2005-04-17 02:20:36 +04:00
2009-01-18 09:56:41 +03:00
for ( i = 0 ; ( table [ i ] . frequency ! = CPUFREQ_TABLE_END ) ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( table [ i ] . frequency = = CPUFREQ_ENTRY_INVALID )
continue ;
count + = sprintf ( & buf [ count ] , " %d " , table [ i ] . frequency ) ;
}
count + = sprintf ( & buf [ count ] , " \n " ) ;
return count ;
}
struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
2006-10-26 14:50:58 +04:00
. attr = { . name = " scaling_available_frequencies " ,
. mode = 0444 ,
} ,
2005-04-17 02:20:36 +04:00
. show = show_available_freqs ,
} ;
EXPORT_SYMBOL_GPL ( cpufreq_freq_attr_scaling_available_freqs ) ;
/*
* if you use these , you must assure that the frequency table is valid
* all the time between get_attr and put_attr !
*/
2006-02-28 08:43:23 +03:00
void cpufreq_frequency_table_get_attr ( struct cpufreq_frequency_table * table ,
2005-04-17 02:20:36 +04:00
unsigned int cpu )
{
dprintk ( " setting show_table for cpu %u to %p \n " , cpu , table ) ;
2008-03-26 01:06:53 +03:00
per_cpu ( show_table , cpu ) = table ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL_GPL ( cpufreq_frequency_table_get_attr ) ;
void cpufreq_frequency_table_put_attr ( unsigned int cpu )
{
dprintk ( " clearing show_table for cpu %u \n " , cpu ) ;
2008-03-26 01:06:53 +03:00
per_cpu ( show_table , cpu ) = NULL ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL_GPL ( cpufreq_frequency_table_put_attr ) ;
struct cpufreq_frequency_table * cpufreq_frequency_get_table ( unsigned int cpu )
{
2008-03-26 01:06:53 +03:00
return per_cpu ( show_table , cpu ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL_GPL ( cpufreq_frequency_get_table ) ;
2009-01-18 09:56:41 +03:00
MODULE_AUTHOR ( " Dominik Brodowski <linux@brodo.de> " ) ;
MODULE_DESCRIPTION ( " CPUfreq frequency table helpers " ) ;
MODULE_LICENSE ( " GPL " ) ;