^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * fair_share.c - A simple weight based Thermal governor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2012 Intel Corp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <trace/events/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "thermal_core.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * get_trip_level: - obtains the current trip level for a zone
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * @tz: thermal zone device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static int get_trip_level(struct thermal_zone_device *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) int trip_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) enum thermal_trip_type trip_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) if (tz->trips == 0 || !tz->ops->get_trip_temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) for (count = 0; count < tz->trips; count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) tz->ops->get_trip_temp(tz, count, &trip_temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (tz->temperature < trip_temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * count > 0 only if temperature is greater than first trip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * point, in which case, trip_point = count - 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) tz->ops->get_trip_type(tz, count - 1, &trip_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) trace_thermal_zone_trip(tz, count - 1, trip_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static long get_target_state(struct thermal_zone_device *tz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct thermal_cooling_device *cdev, int percentage, int level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned long max_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) cdev->ops->get_max_state(cdev, &max_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return (long)(percentage * level * max_state) / (100 * tz->trips);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * fair_share_throttle - throttles devices associated with the given zone
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * @tz: thermal_zone_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * @trip: trip point index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * Throttling Logic: This uses three parameters to calculate the new
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * throttle state of the cooling devices associated with the given zone.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * Parameters used for Throttling:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * P1. max_state: Maximum throttle state exposed by the cooling device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * P2. percentage[i]/100:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * How 'effective' the 'i'th device is, in cooling the given zone.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * P3. cur_trip_level/max_no_of_trips:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * This describes the extent to which the devices should be throttled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * We do not want to throttle too much when we trip a lower temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * whereas the throttling is at full swing if we trip critical levels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * (Heavily assumes the trip points are in ascending order)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * new_state of cooling device = P3 * P2 * P1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct thermal_instance *instance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) int total_weight = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int total_instance = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int cur_trip_level = get_trip_level(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) mutex_lock(&tz->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (instance->trip != trip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) total_weight += instance->weight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) total_instance++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int percentage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct thermal_cooling_device *cdev = instance->cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (instance->trip != trip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (!total_weight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) percentage = 100 / total_instance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) percentage = (instance->weight * 100) / total_weight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) instance->target = get_target_state(tz, cdev, percentage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) cur_trip_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) mutex_lock(&instance->cdev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) instance->cdev->updated = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) mutex_unlock(&instance->cdev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) thermal_cdev_update(cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) mutex_unlock(&tz->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static struct thermal_governor thermal_gov_fair_share = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .name = "fair_share",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .throttle = fair_share_throttle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share);