2012-09-18 09:35:01 +04:00
/*
* fair_share . c - A simple weight based Thermal governor
*
* Copyright ( C ) 2012 Intel Corp
* Copyright ( C ) 2012 Durgadoss R < durgadoss . r @ intel . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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 ; version 2 of the License .
*
* 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/thermal.h>
2014-07-29 14:50:50 +04:00
# include <trace/events/thermal.h>
2012-09-18 09:35:01 +04:00
# include "thermal_core.h"
/**
* get_trip_level : - obtains the current trip level for a zone
* @ tz : thermal zone device
*/
static int get_trip_level ( struct thermal_zone_device * tz )
{
int count = 0 ;
2015-07-24 09:12:54 +03:00
int trip_temp ;
2014-07-29 14:50:50 +04:00
enum thermal_trip_type trip_type ;
2012-09-18 09:35:01 +04:00
if ( tz - > trips = = 0 | | ! tz - > ops - > get_trip_temp )
return 0 ;
for ( count = 0 ; count < tz - > trips ; count + + ) {
tz - > ops - > get_trip_temp ( tz , count , & trip_temp ) ;
if ( tz - > temperature < trip_temp )
break ;
}
2014-07-29 14:50:50 +04:00
/*
* count > 0 only if temperature is greater than first trip
* point , in which case , trip_point = count - 1
*/
if ( count > 0 ) {
tz - > ops - > get_trip_type ( tz , count - 1 , & trip_type ) ;
trace_thermal_zone_trip ( tz , count - 1 , trip_type ) ;
}
2012-09-18 09:35:01 +04:00
return count ;
}
static long get_target_state ( struct thermal_zone_device * tz ,
2015-02-18 19:04:25 +03:00
struct thermal_cooling_device * cdev , int percentage , int level )
2012-09-18 09:35:01 +04:00
{
unsigned long max_state ;
cdev - > ops - > get_max_state ( cdev , & max_state ) ;
2015-02-18 19:04:25 +03:00
return ( long ) ( percentage * level * max_state ) / ( 100 * tz - > trips ) ;
2012-09-18 09:35:01 +04:00
}
/**
2015-02-18 19:04:23 +03:00
* fair_share_throttle - throttles devices associated with the given zone
2012-09-18 09:35:01 +04:00
* @ tz - thermal_zone_device
*
* Throttling Logic : This uses three parameters to calculate the new
* throttle state of the cooling devices associated with the given zone .
*
* Parameters used for Throttling :
* P1 . max_state : Maximum throttle state exposed by the cooling device .
2015-02-18 19:04:25 +03:00
* P2 . percentage [ i ] / 100 :
2012-09-18 09:35:01 +04:00
* How ' effective ' the ' i ' th device is , in cooling the given zone .
* P3 . cur_trip_level / max_no_of_trips :
* This describes the extent to which the devices should be throttled .
* We do not want to throttle too much when we trip a lower temperature ,
* whereas the throttling is at full swing if we trip critical levels .
* ( Heavily assumes the trip points are in ascending order )
* new_state of cooling device = P3 * P2 * P1
*/
2012-09-27 15:27:53 +04:00
static int fair_share_throttle ( struct thermal_zone_device * tz , int trip )
2012-09-18 09:35:01 +04:00
{
struct thermal_instance * instance ;
2015-02-18 19:04:25 +03:00
int total_weight = 0 ;
int total_instance = 0 ;
2012-09-18 09:35:01 +04:00
int cur_trip_level = get_trip_level ( tz ) ;
2015-02-18 19:04:22 +03:00
list_for_each_entry ( instance , & tz - > thermal_instances , tz_node ) {
2015-02-18 19:04:25 +03:00
if ( instance - > trip ! = trip )
continue ;
total_weight + = instance - > weight ;
total_instance + + ;
}
list_for_each_entry ( instance , & tz - > thermal_instances , tz_node ) {
int percentage ;
2015-02-18 19:04:22 +03:00
struct thermal_cooling_device * cdev = instance - > cdev ;
2012-09-18 09:35:01 +04:00
2015-02-18 19:04:22 +03:00
if ( instance - > trip ! = trip )
2012-09-18 09:35:01 +04:00
continue ;
2015-02-18 19:04:25 +03:00
if ( ! total_weight )
percentage = 100 / total_instance ;
else
percentage = ( instance - > weight * 100 ) / total_weight ;
instance - > target = get_target_state ( tz , cdev , percentage ,
cur_trip_level ) ;
2012-09-18 09:35:01 +04:00
instance - > cdev - > updated = false ;
thermal_cdev_update ( cdev ) ;
}
return 0 ;
}
2012-09-27 15:27:53 +04:00
static struct thermal_governor thermal_gov_fair_share = {
2012-09-18 09:35:01 +04:00
. name = " fair_share " ,
. throttle = fair_share_throttle ,
} ;
2013-03-26 12:38:29 +04:00
int thermal_gov_fair_share_register ( void )
2012-09-18 09:35:01 +04:00
{
return thermal_register_governor ( & thermal_gov_fair_share ) ;
}
2013-03-26 12:38:29 +04:00
void thermal_gov_fair_share_unregister ( void )
2012-09-18 09:35:01 +04:00
{
thermal_unregister_governor ( & thermal_gov_fair_share ) ;
}