@ -13,6 +13,7 @@
# include <linux/notifier.h>
# include <linux/clockchips.h>
# include <linux/of.h>
# include <linux/slab.h>
# include <asm/machdep.h>
# include <asm/firmware.h>
@ -158,70 +159,83 @@ static int powernv_add_idle_states(void)
struct device_node * power_mgt ;
int nr_idle_states = 1 ; /* Snooze */
int dt_idle_states ;
const __be32 * idle_state_flags ;
const __be32 * idle_state_latency ;
u32 len_flags , flags , latency_ns ;
int i ;
u32 * latency_ns , * residency_ns , * flags ;
int i , rc ;
/* Currently we have snooze statically defined */
power_mgt = of_find_node_by_path ( " /ibm,opal/power-mgt " ) ;
if ( ! power_mgt ) {
pr_warn ( " opal: PowerMgmt Node not found \n " ) ;
return nr_idle_states ;
goto out ;
}
idle_state_flags = of_get_property ( power_mgt , " ibm,cpu-idle-state-flags " , & len_flags ) ;
if ( ! idle_state_flags ) {
pr_warn ( " DT-PowerMgmt: missing ibm,cpu-idle-state-flags \n " ) ;
return nr_idle_states ;
/* Read values of any property to determine the num of idle states */
dt_idle_states = of_property_count_u32_elems ( power_mgt , " ibm,cpu-idle-state-flags " ) ;
if ( dt_idle_states < 0 ) {
pr_warn ( " cpuidle-powernv: no idle states found in the DT \n " ) ;
goto out ;
}
idle_state_latency = of_get_property ( power_mgt ,
" ibm,cpu-idle-state-latencies-ns " , NULL ) ;
if ( ! idle_state_latency ) {
pr_warn ( " DT-PowerMgmt: missing ibm,cpu-idle-state-latencies-ns \n " ) ;
return nr_idle_state s;
flags = kzalloc ( sizeof ( * flags ) * dt_idle_states , GFP_KERNEL ) ;
if ( of_property_read_u32_array ( power_mgt ,
" ibm,cpu-idle-state-flags " , flags , dt_idle_states ) ) {
pr_warn ( " cpuidle-powernv : missing ibm,cpu-idle-state-flags in DT \n " ) ;
goto out_free_flag s;
}
dt_idle_states = len_flags / sizeof ( u32 ) ;
latency_ns = kzalloc ( sizeof ( * latency_ns ) * dt_idle_states , GFP_KERNEL ) ;
rc = of_property_read_u32_array ( power_mgt ,
" ibm,cpu-idle-state-latencies-ns " , latency_ns , dt_idle_states ) ;
if ( rc ) {
pr_warn ( " cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT \n " ) ;
goto out_free_latency ;
}
for ( i = 0 ; i < dt_idle_states ; i + + ) {
residency_ns = kzalloc ( sizeof ( * residency_ns ) * dt_idle_states , GFP_KERNEL ) ;
rc = of_property_read_u32_array ( power_mgt ,
" ibm,cpu-idle-state-residency-ns " , residency_ns , dt_idle_states ) ;
flags = be32_to_cpu ( idle_state_flags [ i ] ) ;
for ( i = 0 ; i < dt_idle_states ; i + + ) {
/* Cpuidle accepts exit_latency in us and we estimate
* target residency to be 10 x exit_latency
/*
* Cpuidle accepts exit_latency and target_residency in us .
* Use default target_residency values if f / w does not expose it .
*/
latency_ns = be32_to_cpu ( idle_state_latency [ i ] ) ;
if ( flags & OPAL_PM_NAP_ENABLED ) {
if ( flags [ i ] & OPAL_PM_NAP_ENABLED ) {
/* Add NAP state */
strcpy ( powernv_states [ nr_idle_states ] . name , " Nap " ) ;
strcpy ( powernv_states [ nr_idle_states ] . desc , " Nap " ) ;
powernv_states [ nr_idle_states ] . flags = 0 ;
powernv_states [ nr_idle_states ] . exit_latency =
( ( unsigned int ) latency_ns ) / 1000 ;
powernv_states [ nr_idle_states ] . target_residency =
( ( unsigned int ) latency_ns / 100 ) ;
powernv_states [ nr_idle_states ] . target_residency = 100 ;
powernv_states [ nr_idle_states ] . enter = & nap_loop ;
nr_idle_states + + ;
}
if ( flags & OPAL_PM_SLEEP_ENABLED | |
flags & OPAL_PM_SLEEP_ENABLED_ER1 ) {
} else if ( flags [ i ] & OPAL_PM_SLEEP_ENABLED | |
flags [ i ] & OPAL_PM_SLEEP_ENABLED_ER1 ) {
/* Add FASTSLEEP state */
strcpy ( powernv_states [ nr_idle_states ] . name , " FastSleep " ) ;
strcpy ( powernv_states [ nr_idle_states ] . desc , " FastSleep " ) ;
powernv_states [ nr_idle_states ] . flags = CPUIDLE_FLAG_TIMER_STOP ;
powernv_states [ nr_idle_states ] . exit_latency =
( ( unsigned int ) latency_ns ) / 1000 ;
powernv_states [ nr_idle_states ] . target_residency =
( ( unsigned int ) latency_ns / 100 ) ;
powernv_states [ nr_idle_states ] . target_residency = 300000 ;
powernv_states [ nr_idle_states ] . enter = & fastsleep_loop ;
nr_idle_states + + ;
}
powernv_states [ nr_idle_states ] . exit_latency =
( ( unsigned int ) latency_ns [ i ] ) / 1000 ;
if ( ! rc ) {
powernv_states [ nr_idle_states ] . target_residency =
( ( unsigned int ) residency_ns [ i ] ) / 1000 ;
}
nr_idle_states + + ;
}
kfree ( residency_ns ) ;
out_free_latency :
kfree ( latency_ns ) ;
out_free_flags :
kfree ( flags ) ;
out :
return nr_idle_states ;
}