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

int340x_thermal_zone.c (8111B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * int340x_thermal_zone.c
      4 * Copyright (c) 2015, Intel Corporation.
      5 */
      6#include <linux/kernel.h>
      7#include <linux/module.h>
      8#include <linux/init.h>
      9#include <linux/acpi.h>
     10#include <linux/thermal.h>
     11#include <linux/units.h>
     12#include "int340x_thermal_zone.h"
     13
     14static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
     15					 int *temp)
     16{
     17	struct int34x_thermal_zone *d = zone->devdata;
     18	unsigned long long tmp;
     19	acpi_status status;
     20
     21	if (d->override_ops && d->override_ops->get_temp)
     22		return d->override_ops->get_temp(zone, temp);
     23
     24	status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);
     25	if (ACPI_FAILURE(status))
     26		return -EIO;
     27
     28	if (d->lpat_table) {
     29		int conv_temp;
     30
     31		conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);
     32		if (conv_temp < 0)
     33			return conv_temp;
     34
     35		*temp = (unsigned long)conv_temp * 10;
     36	} else
     37		/* _TMP returns the temperature in tenths of degrees Kelvin */
     38		*temp = deci_kelvin_to_millicelsius(tmp);
     39
     40	return 0;
     41}
     42
     43static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
     44					 int trip, int *temp)
     45{
     46	struct int34x_thermal_zone *d = zone->devdata;
     47	int i;
     48
     49	if (d->override_ops && d->override_ops->get_trip_temp)
     50		return d->override_ops->get_trip_temp(zone, trip, temp);
     51
     52	if (trip < d->aux_trip_nr)
     53		*temp = d->aux_trips[trip];
     54	else if (trip == d->crt_trip_id)
     55		*temp = d->crt_temp;
     56	else if (trip == d->psv_trip_id)
     57		*temp = d->psv_temp;
     58	else if (trip == d->hot_trip_id)
     59		*temp = d->hot_temp;
     60	else {
     61		for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
     62			if (d->act_trips[i].valid &&
     63			    d->act_trips[i].id == trip) {
     64				*temp = d->act_trips[i].temp;
     65				break;
     66			}
     67		}
     68		if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
     69			return -EINVAL;
     70	}
     71
     72	return 0;
     73}
     74
     75static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
     76					 int trip,
     77					 enum thermal_trip_type *type)
     78{
     79	struct int34x_thermal_zone *d = zone->devdata;
     80	int i;
     81
     82	if (d->override_ops && d->override_ops->get_trip_type)
     83		return d->override_ops->get_trip_type(zone, trip, type);
     84
     85	if (trip < d->aux_trip_nr)
     86		*type = THERMAL_TRIP_PASSIVE;
     87	else if (trip == d->crt_trip_id)
     88		*type = THERMAL_TRIP_CRITICAL;
     89	else if (trip == d->hot_trip_id)
     90		*type = THERMAL_TRIP_HOT;
     91	else if (trip == d->psv_trip_id)
     92		*type = THERMAL_TRIP_PASSIVE;
     93	else {
     94		for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
     95			if (d->act_trips[i].valid &&
     96			    d->act_trips[i].id == trip) {
     97				*type = THERMAL_TRIP_ACTIVE;
     98				break;
     99			}
    100		}
    101		if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
    102			return -EINVAL;
    103	}
    104
    105	return 0;
    106}
    107
    108static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
    109				      int trip, int temp)
    110{
    111	struct int34x_thermal_zone *d = zone->devdata;
    112	acpi_status status;
    113	char name[10];
    114
    115	if (d->override_ops && d->override_ops->set_trip_temp)
    116		return d->override_ops->set_trip_temp(zone, trip, temp);
    117
    118	snprintf(name, sizeof(name), "PAT%d", trip);
    119	status = acpi_execute_simple_method(d->adev->handle, name,
    120			millicelsius_to_deci_kelvin(temp));
    121	if (ACPI_FAILURE(status))
    122		return -EIO;
    123
    124	d->aux_trips[trip] = temp;
    125
    126	return 0;
    127}
    128
    129
    130static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone,
    131		int trip, int *temp)
    132{
    133	struct int34x_thermal_zone *d = zone->devdata;
    134	acpi_status status;
    135	unsigned long long hyst;
    136
    137	if (d->override_ops && d->override_ops->get_trip_hyst)
    138		return d->override_ops->get_trip_hyst(zone, trip, temp);
    139
    140	status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst);
    141	if (ACPI_FAILURE(status))
    142		*temp = 0;
    143	else
    144		*temp = hyst * 100;
    145
    146	return 0;
    147}
    148
    149static void int340x_thermal_critical(struct thermal_zone_device *zone)
    150{
    151	dev_dbg(&zone->device, "%s: critical temperature reached\n", zone->type);
    152}
    153
    154static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
    155	.get_temp       = int340x_thermal_get_zone_temp,
    156	.get_trip_temp	= int340x_thermal_get_trip_temp,
    157	.get_trip_type	= int340x_thermal_get_trip_type,
    158	.set_trip_temp	= int340x_thermal_set_trip_temp,
    159	.get_trip_hyst =  int340x_thermal_get_trip_hyst,
    160	.critical	= int340x_thermal_critical,
    161};
    162
    163static int int340x_thermal_get_trip_config(acpi_handle handle, char *name,
    164				      int *temp)
    165{
    166	unsigned long long r;
    167	acpi_status status;
    168
    169	status = acpi_evaluate_integer(handle, name, NULL, &r);
    170	if (ACPI_FAILURE(status))
    171		return -EIO;
    172
    173	*temp = deci_kelvin_to_millicelsius(r);
    174
    175	return 0;
    176}
    177
    178int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone)
    179{
    180	int trip_cnt = int34x_zone->aux_trip_nr;
    181	int i;
    182
    183	int34x_zone->crt_trip_id = -1;
    184	if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT",
    185					     &int34x_zone->crt_temp))
    186		int34x_zone->crt_trip_id = trip_cnt++;
    187
    188	int34x_zone->hot_trip_id = -1;
    189	if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_HOT",
    190					     &int34x_zone->hot_temp))
    191		int34x_zone->hot_trip_id = trip_cnt++;
    192
    193	int34x_zone->psv_trip_id = -1;
    194	if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_PSV",
    195					     &int34x_zone->psv_temp))
    196		int34x_zone->psv_trip_id = trip_cnt++;
    197
    198	for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
    199		char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
    200
    201		if (int340x_thermal_get_trip_config(int34x_zone->adev->handle,
    202					name,
    203					&int34x_zone->act_trips[i].temp))
    204			break;
    205
    206		int34x_zone->act_trips[i].id = trip_cnt++;
    207		int34x_zone->act_trips[i].valid = true;
    208	}
    209
    210	return trip_cnt;
    211}
    212EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
    213
    214static struct thermal_zone_params int340x_thermal_params = {
    215	.governor_name = "user_space",
    216	.no_hwmon = true,
    217};
    218
    219struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
    220				struct thermal_zone_device_ops *override_ops)
    221{
    222	struct int34x_thermal_zone *int34x_thermal_zone;
    223	acpi_status status;
    224	unsigned long long trip_cnt;
    225	int trip_mask = 0;
    226	int ret;
    227
    228	int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone),
    229				      GFP_KERNEL);
    230	if (!int34x_thermal_zone)
    231		return ERR_PTR(-ENOMEM);
    232
    233	int34x_thermal_zone->adev = adev;
    234	int34x_thermal_zone->override_ops = override_ops;
    235
    236	status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
    237	if (ACPI_FAILURE(status))
    238		trip_cnt = 0;
    239	else {
    240		int i;
    241
    242		int34x_thermal_zone->aux_trips =
    243			kcalloc(trip_cnt,
    244				sizeof(*int34x_thermal_zone->aux_trips),
    245				GFP_KERNEL);
    246		if (!int34x_thermal_zone->aux_trips) {
    247			ret = -ENOMEM;
    248			goto err_trip_alloc;
    249		}
    250		trip_mask = BIT(trip_cnt) - 1;
    251		int34x_thermal_zone->aux_trip_nr = trip_cnt;
    252		for (i = 0; i < trip_cnt; ++i)
    253			int34x_thermal_zone->aux_trips[i] = THERMAL_TEMP_INVALID;
    254	}
    255
    256	trip_cnt = int340x_thermal_read_trips(int34x_thermal_zone);
    257
    258	int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table(
    259								adev->handle);
    260
    261	int34x_thermal_zone->zone = thermal_zone_device_register(
    262						acpi_device_bid(adev),
    263						trip_cnt,
    264						trip_mask, int34x_thermal_zone,
    265						&int340x_thermal_zone_ops,
    266						&int340x_thermal_params,
    267						0, 0);
    268	if (IS_ERR(int34x_thermal_zone->zone)) {
    269		ret = PTR_ERR(int34x_thermal_zone->zone);
    270		goto err_thermal_zone;
    271	}
    272	ret = thermal_zone_device_enable(int34x_thermal_zone->zone);
    273	if (ret)
    274		goto err_enable;
    275
    276	return int34x_thermal_zone;
    277
    278err_enable:
    279	thermal_zone_device_unregister(int34x_thermal_zone->zone);
    280err_thermal_zone:
    281	acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
    282	kfree(int34x_thermal_zone->aux_trips);
    283err_trip_alloc:
    284	kfree(int34x_thermal_zone);
    285	return ERR_PTR(ret);
    286}
    287EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);
    288
    289void int340x_thermal_zone_remove(struct int34x_thermal_zone
    290				 *int34x_thermal_zone)
    291{
    292	thermal_zone_device_unregister(int34x_thermal_zone->zone);
    293	acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
    294	kfree(int34x_thermal_zone->aux_trips);
    295	kfree(int34x_thermal_zone);
    296}
    297EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
    298
    299MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
    300MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
    301MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
    302MODULE_LICENSE("GPL v2");