cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

thermal_helpers.c (6776B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  thermal_helpers.c - helper functions to handle thermal devices
      4 *
      5 *  Copyright (C) 2016 Eduardo Valentin <edubezval@gmail.com>
      6 *
      7 *  Highly based on original thermal_core.c
      8 *  Copyright (C) 2008 Intel Corp
      9 *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
     10 *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
     11 */
     12
     13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     14
     15#include <linux/device.h>
     16#include <linux/err.h>
     17#include <linux/export.h>
     18#include <linux/slab.h>
     19#include <linux/string.h>
     20#include <linux/sysfs.h>
     21
     22#include <trace/events/thermal.h>
     23
     24#include "thermal_core.h"
     25
     26int get_tz_trend(struct thermal_zone_device *tz, int trip)
     27{
     28	enum thermal_trend trend;
     29
     30	if (tz->emul_temperature || !tz->ops->get_trend ||
     31	    tz->ops->get_trend(tz, trip, &trend)) {
     32		if (tz->temperature > tz->last_temperature)
     33			trend = THERMAL_TREND_RAISING;
     34		else if (tz->temperature < tz->last_temperature)
     35			trend = THERMAL_TREND_DROPPING;
     36		else
     37			trend = THERMAL_TREND_STABLE;
     38	}
     39
     40	return trend;
     41}
     42EXPORT_SYMBOL(get_tz_trend);
     43
     44struct thermal_instance *
     45get_thermal_instance(struct thermal_zone_device *tz,
     46		     struct thermal_cooling_device *cdev, int trip)
     47{
     48	struct thermal_instance *pos = NULL;
     49	struct thermal_instance *target_instance = NULL;
     50
     51	mutex_lock(&tz->lock);
     52	mutex_lock(&cdev->lock);
     53
     54	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
     55		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
     56			target_instance = pos;
     57			break;
     58		}
     59	}
     60
     61	mutex_unlock(&cdev->lock);
     62	mutex_unlock(&tz->lock);
     63
     64	return target_instance;
     65}
     66EXPORT_SYMBOL(get_thermal_instance);
     67
     68/**
     69 * thermal_zone_get_temp() - returns the temperature of a thermal zone
     70 * @tz: a valid pointer to a struct thermal_zone_device
     71 * @temp: a valid pointer to where to store the resulting temperature.
     72 *
     73 * When a valid thermal zone reference is passed, it will fetch its
     74 * temperature and fill @temp.
     75 *
     76 * Return: On success returns 0, an error code otherwise
     77 */
     78int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
     79{
     80	int ret = -EINVAL;
     81	int count;
     82	int crit_temp = INT_MAX;
     83	enum thermal_trip_type type;
     84
     85	if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
     86		goto exit;
     87
     88	mutex_lock(&tz->lock);
     89
     90	ret = tz->ops->get_temp(tz, temp);
     91
     92	if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
     93		for (count = 0; count < tz->trips; count++) {
     94			ret = tz->ops->get_trip_type(tz, count, &type);
     95			if (!ret && type == THERMAL_TRIP_CRITICAL) {
     96				ret = tz->ops->get_trip_temp(tz, count,
     97						&crit_temp);
     98				break;
     99			}
    100		}
    101
    102		/*
    103		 * Only allow emulating a temperature when the real temperature
    104		 * is below the critical temperature so that the emulation code
    105		 * cannot hide critical conditions.
    106		 */
    107		if (!ret && *temp < crit_temp)
    108			*temp = tz->emul_temperature;
    109	}
    110
    111	mutex_unlock(&tz->lock);
    112exit:
    113	return ret;
    114}
    115EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
    116
    117/**
    118 * thermal_zone_set_trips - Computes the next trip points for the driver
    119 * @tz: a pointer to a thermal zone device structure
    120 *
    121 * The function computes the next temperature boundaries by browsing
    122 * the trip points. The result is the closer low and high trip points
    123 * to the current temperature. These values are passed to the backend
    124 * driver to let it set its own notification mechanism (usually an
    125 * interrupt).
    126 *
    127 * It does not return a value
    128 */
    129void thermal_zone_set_trips(struct thermal_zone_device *tz)
    130{
    131	int low = -INT_MAX;
    132	int high = INT_MAX;
    133	int trip_temp, hysteresis;
    134	int i, ret;
    135
    136	mutex_lock(&tz->lock);
    137
    138	if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
    139		goto exit;
    140
    141	for (i = 0; i < tz->trips; i++) {
    142		int trip_low;
    143
    144		tz->ops->get_trip_temp(tz, i, &trip_temp);
    145		tz->ops->get_trip_hyst(tz, i, &hysteresis);
    146
    147		trip_low = trip_temp - hysteresis;
    148
    149		if (trip_low < tz->temperature && trip_low > low)
    150			low = trip_low;
    151
    152		if (trip_temp > tz->temperature && trip_temp < high)
    153			high = trip_temp;
    154	}
    155
    156	/* No need to change trip points */
    157	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
    158		goto exit;
    159
    160	tz->prev_low_trip = low;
    161	tz->prev_high_trip = high;
    162
    163	dev_dbg(&tz->device,
    164		"new temperature boundaries: %d < x < %d\n", low, high);
    165
    166	/*
    167	 * Set a temperature window. When this window is left the driver
    168	 * must inform the thermal core via thermal_zone_device_update.
    169	 */
    170	ret = tz->ops->set_trips(tz, low, high);
    171	if (ret)
    172		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
    173
    174exit:
    175	mutex_unlock(&tz->lock);
    176}
    177
    178void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms)
    179{
    180	*delay_jiffies = msecs_to_jiffies(delay_ms);
    181	if (delay_ms > 1000)
    182		*delay_jiffies = round_jiffies(*delay_jiffies);
    183}
    184
    185static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
    186				       int target)
    187{
    188	if (cdev->ops->set_cur_state(cdev, target))
    189		return;
    190
    191	thermal_notify_cdev_state_update(cdev->id, target);
    192	thermal_cooling_device_stats_update(cdev, target);
    193}
    194
    195void __thermal_cdev_update(struct thermal_cooling_device *cdev)
    196{
    197	struct thermal_instance *instance;
    198	unsigned long target = 0;
    199
    200	/* Make sure cdev enters the deepest cooling state */
    201	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
    202		dev_dbg(&cdev->device, "zone%d->target=%lu\n",
    203			instance->tz->id, instance->target);
    204		if (instance->target == THERMAL_NO_TARGET)
    205			continue;
    206		if (instance->target > target)
    207			target = instance->target;
    208	}
    209
    210	thermal_cdev_set_cur_state(cdev, target);
    211
    212	trace_cdev_update(cdev, target);
    213	dev_dbg(&cdev->device, "set to state %lu\n", target);
    214}
    215
    216/**
    217 * thermal_cdev_update - update cooling device state if needed
    218 * @cdev:	pointer to struct thermal_cooling_device
    219 *
    220 * Update the cooling device state if there is a need.
    221 */
    222void thermal_cdev_update(struct thermal_cooling_device *cdev)
    223{
    224	mutex_lock(&cdev->lock);
    225	if (!cdev->updated) {
    226		__thermal_cdev_update(cdev);
    227		cdev->updated = true;
    228	}
    229	mutex_unlock(&cdev->lock);
    230}
    231EXPORT_SYMBOL(thermal_cdev_update);
    232
    233/**
    234 * thermal_zone_get_slope - return the slope attribute of the thermal zone
    235 * @tz: thermal zone device with the slope attribute
    236 *
    237 * Return: If the thermal zone device has a slope attribute, return it, else
    238 * return 1.
    239 */
    240int thermal_zone_get_slope(struct thermal_zone_device *tz)
    241{
    242	if (tz && tz->tzp)
    243		return tz->tzp->slope;
    244	return 1;
    245}
    246EXPORT_SYMBOL_GPL(thermal_zone_get_slope);
    247
    248/**
    249 * thermal_zone_get_offset - return the offset attribute of the thermal zone
    250 * @tz: thermal zone device with the offset attribute
    251 *
    252 * Return: If the thermal zone device has a offset attribute, return it, else
    253 * return 0.
    254 */
    255int thermal_zone_get_offset(struct thermal_zone_device *tz)
    256{
    257	if (tz && tz->tzp)
    258		return tz->tzp->offset;
    259	return 0;
    260}
    261EXPORT_SYMBOL_GPL(thermal_zone_get_offset);