2019-05-27 08:55:15 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2012-09-18 11:05:01 +05:30
/*
* fair_share . c - A simple weight based Thermal governor
*
* Copyright ( C ) 2012 Intel Corp
* Copyright ( C ) 2012 Durgadoss R < durgadoss . r @ intel . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/thermal.h>
2023-03-07 14:37:25 +01:00
# include "thermal_trace.h"
2012-09-18 11:05:01 +05:30
# include "thermal_core.h"
static int get_trip_level ( struct thermal_zone_device * tz )
{
2024-04-10 18:58:56 +02:00
const struct thermal_trip_desc * level_td = NULL ;
2024-04-02 20:56:43 +02:00
const struct thermal_trip_desc * td ;
2024-01-15 18:55:13 +01:00
int trip_level = - 1 ;
2012-09-18 11:05:01 +05:30
2024-04-02 20:56:43 +02:00
for_each_trip_desc ( tz , td ) {
2024-04-10 18:58:56 +02:00
if ( td - > threshold > tz - > temperature )
2024-01-15 18:55:13 +01:00
continue ;
2023-10-12 20:29:43 +02:00
2024-01-15 18:55:13 +01:00
trip_level + + ;
2024-04-10 18:58:56 +02:00
if ( ! level_td | | td - > threshold > level_td - > threshold )
level_td = td ;
2012-09-18 11:05:01 +05:30
}
2014-07-29 11:50:50 +01:00
2023-10-12 20:29:43 +02:00
/* Bail out if the temperature is not greater than any trips. */
2024-01-15 18:55:13 +01:00
if ( trip_level < 0 )
2023-10-12 20:29:43 +02:00
return 0 ;
2024-04-10 18:58:56 +02:00
trace_thermal_zone_trip ( tz , thermal_zone_trip_id ( tz , & level_td - > trip ) ,
level_td - > trip . type ) ;
2014-07-29 11:50:50 +01:00
2023-10-12 20:29:43 +02:00
return trip_level ;
2012-09-18 11:05:01 +05:30
}
/**
2015-02-18 16:04:23 +00:00
* fair_share_throttle - throttles devices associated with the given zone
2019-11-20 21:15:12 +05:30
* @ tz : thermal_zone_device
2023-10-12 20:34:50 +02:00
* @ trip : trip point
2024-04-10 18:57:38 +02:00
* @ trip_level : number of trips crossed by the zone temperature
2012-09-18 11:05:01 +05:30
*
* 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 .
2024-04-10 19:00:10 +02:00
* P2 . weight [ i ] / total_weight :
2012-09-18 11:05:01 +05:30
* How ' effective ' the ' i ' th device is , in cooling the given zone .
2024-04-10 18:57:38 +02:00
* P3 . trip_level / max_no_of_trips :
2012-09-18 11:05:01 +05:30
* 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 .
* new_state of cooling device = P3 * P2 * P1
*/
2024-04-10 18:57:38 +02:00
static void fair_share_throttle ( struct thermal_zone_device * tz ,
const struct thermal_trip * trip ,
int trip_level )
2012-09-18 11:05:01 +05:30
{
struct thermal_instance * instance ;
2015-02-18 16:04:25 +00:00
int total_weight = 0 ;
2024-04-10 19:00:10 +02:00
int nr_instances = 0 ;
2021-04-22 16:36:22 +01:00
2015-02-18 16:04:22 +00:00
list_for_each_entry ( instance , & tz - > thermal_instances , tz_node ) {
2015-02-18 16:04:25 +00:00
if ( instance - > trip ! = trip )
continue ;
total_weight + = instance - > weight ;
2024-04-10 19:00:10 +02:00
nr_instances + + ;
2015-02-18 16:04:25 +00:00
}
list_for_each_entry ( instance , & tz - > thermal_instances , tz_node ) {
2015-02-18 16:04:22 +00:00
struct thermal_cooling_device * cdev = instance - > cdev ;
2024-04-10 19:00:10 +02:00
u64 dividend ;
u32 divisor ;
2012-09-18 11:05:01 +05:30
2015-02-18 16:04:22 +00:00
if ( instance - > trip ! = trip )
2012-09-18 11:05:01 +05:30
continue ;
2024-04-10 19:00:10 +02:00
dividend = trip_level ;
dividend * = cdev - > max_state ;
divisor = tz - > num_trips ;
if ( total_weight ) {
dividend * = instance - > weight ;
divisor * = total_weight ;
} else {
divisor * = nr_instances ;
}
instance - > target = div_u64 ( dividend , divisor ) ;
2012-09-18 11:05:01 +05:30
2021-04-22 16:36:23 +01:00
mutex_lock ( & cdev - > lock ) ;
__thermal_cdev_update ( cdev ) ;
mutex_unlock ( & cdev - > lock ) ;
2012-09-18 11:05:01 +05:30
}
2024-04-10 18:57:38 +02:00
}
static void fair_share_manage ( struct thermal_zone_device * tz )
{
int trip_level = get_trip_level ( tz ) ;
const struct thermal_trip_desc * td ;
lockdep_assert_held ( & tz - > lock ) ;
for_each_trip_desc ( tz , td ) {
const struct thermal_trip * trip = & td - > trip ;
2021-04-22 16:36:22 +01:00
2024-04-10 18:57:38 +02:00
if ( trip - > temperature = = THERMAL_TEMP_INVALID | |
trip - > type = = THERMAL_TRIP_CRITICAL | |
trip - > type = = THERMAL_TRIP_HOT )
continue ;
fair_share_throttle ( tz , trip , trip_level ) ;
}
2012-09-18 11:05:01 +05:30
}
2012-09-27 16:57:53 +05:30
static struct thermal_governor thermal_gov_fair_share = {
2024-04-10 18:57:38 +02:00
. name = " fair_share " ,
. manage = fair_share_manage ,
2012-09-18 11:05:01 +05:30
} ;
2019-06-12 22:13:25 +02:00
THERMAL_GOVERNOR_DECLARE ( thermal_gov_fair_share ) ;