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 * @trip: trip point 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 *trip, 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, &tz->thermal_instances, tz_node) { 72 if (instance->trip != trip) 73 continue; 74 75 total_weight += instance->weight; 76 nr_instances++; 77 } 78 79 list_for_each_entry(instance, &tz->thermal_instances, tz_node) { 80 struct thermal_cooling_device *cdev = instance->cdev; 81 u64 dividend; 82 u32 divisor; 83 84 if (instance->trip != trip) 85 continue; 86 87 dividend = trip_level; 88 dividend *= cdev->max_state; 89 divisor = tz->num_trips; 90 if (total_weight) { 91 dividend *= instance->weight; 92 divisor *= total_weight; 93 } else { 94 divisor *= nr_instances; 95 } 96 instance->target = div_u64(dividend, divisor); 97 98 mutex_lock(&cdev->lock); 99 __thermal_cdev_update(cdev); 100 mutex_unlock(&cdev->lock); 101 } 102 } 103 104 static void fair_share_manage(struct thermal_zone_device *tz) 105 { 106 int trip_level = get_trip_level(tz); 107 const struct thermal_trip_desc *td; 108 109 lockdep_assert_held(&tz->lock); 110 111 for_each_trip_desc(tz, td) { 112 const struct thermal_trip *trip = &td->trip; 113 114 if (trip->temperature == THERMAL_TEMP_INVALID || 115 trip->type == THERMAL_TRIP_CRITICAL || 116 trip->type == THERMAL_TRIP_HOT) 117 continue; 118 119 fair_share_throttle(tz, trip, trip_level); 120 } 121 } 122 123 static struct thermal_governor thermal_gov_fair_share = { 124 .name = "fair_share", 125 .manage = fair_share_manage, 126 }; 127 THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share); 128