10015d9a2SAmit Kucheria // SPDX-License-Identifier: GPL-2.0-only 20015d9a2SAmit Kucheria /* 30015d9a2SAmit Kucheria * fair_share.c - A simple weight based Thermal governor 40015d9a2SAmit Kucheria * 50015d9a2SAmit Kucheria * Copyright (C) 2012 Intel Corp 60015d9a2SAmit Kucheria * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> 70015d9a2SAmit Kucheria * 80015d9a2SAmit Kucheria * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90015d9a2SAmit Kucheria * 100015d9a2SAmit Kucheria * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 110015d9a2SAmit Kucheria */ 120015d9a2SAmit Kucheria 130015d9a2SAmit Kucheria #include <linux/thermal.h> 140015d9a2SAmit Kucheria #include <trace/events/thermal.h> 150015d9a2SAmit Kucheria 160015d9a2SAmit Kucheria #include "thermal_core.h" 170015d9a2SAmit Kucheria 180015d9a2SAmit Kucheria /** 190015d9a2SAmit Kucheria * get_trip_level: - obtains the current trip level for a zone 200015d9a2SAmit Kucheria * @tz: thermal zone device 210015d9a2SAmit Kucheria */ 220015d9a2SAmit Kucheria static int get_trip_level(struct thermal_zone_device *tz) 230015d9a2SAmit Kucheria { 240015d9a2SAmit Kucheria int count = 0; 250015d9a2SAmit Kucheria int trip_temp; 260015d9a2SAmit Kucheria enum thermal_trip_type trip_type; 270015d9a2SAmit Kucheria 28e5bfcd30SDaniel Lezcano if (tz->num_trips == 0 || !tz->ops->get_trip_temp) 290015d9a2SAmit Kucheria return 0; 300015d9a2SAmit Kucheria 31e5bfcd30SDaniel Lezcano for (count = 0; count < tz->num_trips; count++) { 320015d9a2SAmit Kucheria tz->ops->get_trip_temp(tz, count, &trip_temp); 330015d9a2SAmit Kucheria if (tz->temperature < trip_temp) 340015d9a2SAmit Kucheria break; 350015d9a2SAmit Kucheria } 360015d9a2SAmit Kucheria 370015d9a2SAmit Kucheria /* 380015d9a2SAmit Kucheria * count > 0 only if temperature is greater than first trip 390015d9a2SAmit Kucheria * point, in which case, trip_point = count - 1 400015d9a2SAmit Kucheria */ 410015d9a2SAmit Kucheria if (count > 0) { 420015d9a2SAmit Kucheria tz->ops->get_trip_type(tz, count - 1, &trip_type); 430015d9a2SAmit Kucheria trace_thermal_zone_trip(tz, count - 1, trip_type); 440015d9a2SAmit Kucheria } 450015d9a2SAmit Kucheria 460015d9a2SAmit Kucheria return count; 470015d9a2SAmit Kucheria } 480015d9a2SAmit Kucheria 490015d9a2SAmit Kucheria static long get_target_state(struct thermal_zone_device *tz, 500015d9a2SAmit Kucheria struct thermal_cooling_device *cdev, int percentage, int level) 510015d9a2SAmit Kucheria { 52*c408b3d1SViresh Kumar return (long)(percentage * level * cdev->max_state) / (100 * tz->num_trips); 530015d9a2SAmit Kucheria } 540015d9a2SAmit Kucheria 550015d9a2SAmit Kucheria /** 560015d9a2SAmit Kucheria * fair_share_throttle - throttles devices associated with the given zone 570015d9a2SAmit Kucheria * @tz: thermal_zone_device 580015d9a2SAmit Kucheria * @trip: trip point index 590015d9a2SAmit Kucheria * 600015d9a2SAmit Kucheria * Throttling Logic: This uses three parameters to calculate the new 610015d9a2SAmit Kucheria * throttle state of the cooling devices associated with the given zone. 620015d9a2SAmit Kucheria * 630015d9a2SAmit Kucheria * Parameters used for Throttling: 640015d9a2SAmit Kucheria * P1. max_state: Maximum throttle state exposed by the cooling device. 650015d9a2SAmit Kucheria * P2. percentage[i]/100: 660015d9a2SAmit Kucheria * How 'effective' the 'i'th device is, in cooling the given zone. 670015d9a2SAmit Kucheria * P3. cur_trip_level/max_no_of_trips: 680015d9a2SAmit Kucheria * This describes the extent to which the devices should be throttled. 690015d9a2SAmit Kucheria * We do not want to throttle too much when we trip a lower temperature, 700015d9a2SAmit Kucheria * whereas the throttling is at full swing if we trip critical levels. 710015d9a2SAmit Kucheria * (Heavily assumes the trip points are in ascending order) 720015d9a2SAmit Kucheria * new_state of cooling device = P3 * P2 * P1 730015d9a2SAmit Kucheria */ 740015d9a2SAmit Kucheria static int fair_share_throttle(struct thermal_zone_device *tz, int trip) 750015d9a2SAmit Kucheria { 760015d9a2SAmit Kucheria struct thermal_instance *instance; 770015d9a2SAmit Kucheria int total_weight = 0; 780015d9a2SAmit Kucheria int total_instance = 0; 790015d9a2SAmit Kucheria int cur_trip_level = get_trip_level(tz); 800015d9a2SAmit Kucheria 81670a5e35SDaniel Lezcano lockdep_assert_held(&tz->lock); 82fef05776SLukasz Luba 830015d9a2SAmit Kucheria list_for_each_entry(instance, &tz->thermal_instances, tz_node) { 840015d9a2SAmit Kucheria if (instance->trip != trip) 850015d9a2SAmit Kucheria continue; 860015d9a2SAmit Kucheria 870015d9a2SAmit Kucheria total_weight += instance->weight; 880015d9a2SAmit Kucheria total_instance++; 890015d9a2SAmit Kucheria } 900015d9a2SAmit Kucheria 910015d9a2SAmit Kucheria list_for_each_entry(instance, &tz->thermal_instances, tz_node) { 920015d9a2SAmit Kucheria int percentage; 930015d9a2SAmit Kucheria struct thermal_cooling_device *cdev = instance->cdev; 940015d9a2SAmit Kucheria 950015d9a2SAmit Kucheria if (instance->trip != trip) 960015d9a2SAmit Kucheria continue; 970015d9a2SAmit Kucheria 980015d9a2SAmit Kucheria if (!total_weight) 990015d9a2SAmit Kucheria percentage = 100 / total_instance; 1000015d9a2SAmit Kucheria else 1010015d9a2SAmit Kucheria percentage = (instance->weight * 100) / total_weight; 1020015d9a2SAmit Kucheria 1030015d9a2SAmit Kucheria instance->target = get_target_state(tz, cdev, percentage, 1040015d9a2SAmit Kucheria cur_trip_level); 1050015d9a2SAmit Kucheria 1061a933698SLukasz Luba mutex_lock(&cdev->lock); 1071a933698SLukasz Luba __thermal_cdev_update(cdev); 1081a933698SLukasz Luba mutex_unlock(&cdev->lock); 1090015d9a2SAmit Kucheria } 110fef05776SLukasz Luba 1110015d9a2SAmit Kucheria return 0; 1120015d9a2SAmit Kucheria } 1130015d9a2SAmit Kucheria 1140015d9a2SAmit Kucheria static struct thermal_governor thermal_gov_fair_share = { 1150015d9a2SAmit Kucheria .name = "fair_share", 1160015d9a2SAmit Kucheria .throttle = fair_share_throttle, 1170015d9a2SAmit Kucheria }; 1180015d9a2SAmit Kucheria THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share); 119