1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * fair_share.c - A simple weight based Thermal governor 4 * 5 * Copyright (C) 2012 Intel Corp 6 * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> 7 * 8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 * 10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 */ 12 13 #include <linux/thermal.h> 14 #include "thermal_trace.h" 15 16 #include "thermal_core.h" 17 18 static int get_trip_level(struct thermal_zone_device *tz) 19 { 20 const struct thermal_trip_desc *level_td = NULL; 21 const struct thermal_trip_desc *td; 22 int trip_level = -1; 23 24 for_each_trip_desc(tz, td) { 25 if (td->threshold > tz->temperature) 26 continue; 27 28 trip_level++; 29 30 if (!level_td || td->threshold > level_td->threshold) 31 level_td = td; 32 } 33 34 /* Bail out if the temperature is not greater than any trips. */ 35 if (trip_level < 0) 36 return 0; 37 38 trace_thermal_zone_trip(tz, thermal_zone_trip_id(tz, &level_td->trip), 39 level_td->trip.type); 40 41 return trip_level; 42 } 43 44 /** 45 * fair_share_throttle - throttles devices associated with the given zone 46 * @tz: thermal_zone_device 47 * @td: trip point descriptor 48 * @trip_level: number of trips crossed by the zone temperature 49 * 50 * Throttling Logic: This uses three parameters to calculate the new 51 * throttle state of the cooling devices associated with the given zone. 52 * 53 * Parameters used for Throttling: 54 * P1. max_state: Maximum throttle state exposed by the cooling device. 55 * P2. weight[i]/total_weight: 56 * How 'effective' the 'i'th device is, in cooling the given zone. 57 * P3. trip_level/max_no_of_trips: 58 * This describes the extent to which the devices should be throttled. 59 * We do not want to throttle too much when we trip a lower temperature, 60 * whereas the throttling is at full swing if we trip critical levels. 61 * new_state of cooling device = P3 * P2 * P1 62 */ 63 static void fair_share_throttle(struct thermal_zone_device *tz, 64 const struct thermal_trip_desc *td, 65 int trip_level) 66 { 67 struct thermal_instance *instance; 68 int total_weight = 0; 69 int nr_instances = 0; 70 71 list_for_each_entry(instance, &td->thermal_instances, trip_node) { 72 total_weight += instance->weight; 73 nr_instances++; 74 } 75 76 list_for_each_entry(instance, &td->thermal_instances, trip_node) { 77 struct thermal_cooling_device *cdev = instance->cdev; 78 u64 dividend; 79 u32 divisor; 80 81 dividend = trip_level; 82 dividend *= cdev->max_state; 83 divisor = tz->num_trips; 84 if (total_weight) { 85 dividend *= instance->weight; 86 divisor *= total_weight; 87 } else { 88 divisor *= nr_instances; 89 } 90 instance->target = div_u64(dividend, divisor); 91 92 thermal_cdev_update_nocheck(cdev); 93 } 94 } 95 96 static void fair_share_manage(struct thermal_zone_device *tz) 97 { 98 int trip_level = get_trip_level(tz); 99 const struct thermal_trip_desc *td; 100 101 lockdep_assert_held(&tz->lock); 102 103 for_each_trip_desc(tz, td) { 104 const struct thermal_trip *trip = &td->trip; 105 106 if (trip->temperature == THERMAL_TEMP_INVALID || 107 trip->type == THERMAL_TRIP_CRITICAL || 108 trip->type == THERMAL_TRIP_HOT) 109 continue; 110 111 fair_share_throttle(tz, td, trip_level); 112 } 113 } 114 115 static struct thermal_governor thermal_gov_fair_share = { 116 .name = "fair_share", 117 .manage = fair_share_manage, 118 }; 119 THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share); 120