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.c (5426B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
      4 */
      5
      6#include <linux/device.h>
      7#include <linux/sysfs.h>
      8#include <linux/thermal.h>
      9#include <linux/hwmon.h>
     10#include <linux/hwmon-sysfs.h>
     11#include "core.h"
     12#include "debug.h"
     13#include "wmi-ops.h"
     14
     15static int
     16ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
     17				      unsigned long *state)
     18{
     19	*state = ATH10K_THERMAL_THROTTLE_MAX;
     20
     21	return 0;
     22}
     23
     24static int
     25ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
     26				      unsigned long *state)
     27{
     28	struct ath10k *ar = cdev->devdata;
     29
     30	mutex_lock(&ar->conf_mutex);
     31	*state = ar->thermal.throttle_state;
     32	mutex_unlock(&ar->conf_mutex);
     33
     34	return 0;
     35}
     36
     37static int
     38ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
     39				      unsigned long throttle_state)
     40{
     41	struct ath10k *ar = cdev->devdata;
     42
     43	if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {
     44		ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",
     45			    throttle_state, ATH10K_THERMAL_THROTTLE_MAX);
     46		return -EINVAL;
     47	}
     48	mutex_lock(&ar->conf_mutex);
     49	ar->thermal.throttle_state = throttle_state;
     50	ath10k_thermal_set_throttling(ar);
     51	mutex_unlock(&ar->conf_mutex);
     52	return 0;
     53}
     54
     55static const struct thermal_cooling_device_ops ath10k_thermal_ops = {
     56	.get_max_state = ath10k_thermal_get_max_throttle_state,
     57	.get_cur_state = ath10k_thermal_get_cur_throttle_state,
     58	.set_cur_state = ath10k_thermal_set_cur_throttle_state,
     59};
     60
     61static ssize_t ath10k_thermal_show_temp(struct device *dev,
     62					struct device_attribute *attr,
     63					char *buf)
     64{
     65	struct ath10k *ar = dev_get_drvdata(dev);
     66	int ret, temperature;
     67	unsigned long time_left;
     68
     69	mutex_lock(&ar->conf_mutex);
     70
     71	/* Can't get temperature when the card is off */
     72	if (ar->state != ATH10K_STATE_ON) {
     73		ret = -ENETDOWN;
     74		goto out;
     75	}
     76
     77	reinit_completion(&ar->thermal.wmi_sync);
     78	ret = ath10k_wmi_pdev_get_temperature(ar);
     79	if (ret) {
     80		ath10k_warn(ar, "failed to read temperature %d\n", ret);
     81		goto out;
     82	}
     83
     84	if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
     85		ret = -ESHUTDOWN;
     86		goto out;
     87	}
     88
     89	time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
     90						ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
     91	if (!time_left) {
     92		ath10k_warn(ar, "failed to synchronize thermal read\n");
     93		ret = -ETIMEDOUT;
     94		goto out;
     95	}
     96
     97	spin_lock_bh(&ar->data_lock);
     98	temperature = ar->thermal.temperature;
     99	spin_unlock_bh(&ar->data_lock);
    100
    101	/* display in millidegree celcius */
    102	ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
    103out:
    104	mutex_unlock(&ar->conf_mutex);
    105	return ret;
    106}
    107
    108void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
    109{
    110	spin_lock_bh(&ar->data_lock);
    111	ar->thermal.temperature = temperature;
    112	spin_unlock_bh(&ar->data_lock);
    113	complete(&ar->thermal.wmi_sync);
    114}
    115
    116static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath10k_thermal_show_temp,
    117			  NULL, 0);
    118
    119static struct attribute *ath10k_hwmon_attrs[] = {
    120	&sensor_dev_attr_temp1_input.dev_attr.attr,
    121	NULL,
    122};
    123ATTRIBUTE_GROUPS(ath10k_hwmon);
    124
    125void ath10k_thermal_set_throttling(struct ath10k *ar)
    126{
    127	u32 period, duration, enabled;
    128	int ret;
    129
    130	lockdep_assert_held(&ar->conf_mutex);
    131
    132	if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
    133		return;
    134
    135	if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
    136		return;
    137
    138	if (ar->state != ATH10K_STATE_ON)
    139		return;
    140
    141	period = ar->thermal.quiet_period;
    142	duration = (period * ar->thermal.throttle_state) / 100;
    143	enabled = duration ? 1 : 0;
    144
    145	ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
    146					     ATH10K_QUIET_START_OFFSET,
    147					     enabled);
    148	if (ret) {
    149		ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
    150			    period, duration, enabled, ret);
    151	}
    152}
    153
    154int ath10k_thermal_register(struct ath10k *ar)
    155{
    156	struct thermal_cooling_device *cdev;
    157	struct device *hwmon_dev;
    158	int ret;
    159
    160	if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
    161		return 0;
    162
    163	cdev = thermal_cooling_device_register("ath10k_thermal", ar,
    164					       &ath10k_thermal_ops);
    165
    166	if (IS_ERR(cdev)) {
    167		ath10k_err(ar, "failed to setup thermal device result: %ld\n",
    168			   PTR_ERR(cdev));
    169		return -EINVAL;
    170	}
    171
    172	ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
    173				"cooling_device");
    174	if (ret) {
    175		ath10k_err(ar, "failed to create cooling device symlink\n");
    176		goto err_cooling_destroy;
    177	}
    178
    179	ar->thermal.cdev = cdev;
    180	ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT;
    181
    182	/* Do not register hwmon device when temperature reading is not
    183	 * supported by firmware
    184	 */
    185	if (!(ar->wmi.ops->gen_pdev_get_temperature))
    186		return 0;
    187
    188	/* Avoid linking error on devm_hwmon_device_register_with_groups, I
    189	 * guess linux/hwmon.h is missing proper stubs.
    190	 */
    191	if (!IS_REACHABLE(CONFIG_HWMON))
    192		return 0;
    193
    194	hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
    195							   "ath10k_hwmon", ar,
    196							   ath10k_hwmon_groups);
    197	if (IS_ERR(hwmon_dev)) {
    198		ath10k_err(ar, "failed to register hwmon device: %ld\n",
    199			   PTR_ERR(hwmon_dev));
    200		ret = -EINVAL;
    201		goto err_remove_link;
    202	}
    203	return 0;
    204
    205err_remove_link:
    206	sysfs_remove_link(&ar->dev->kobj, "cooling_device");
    207err_cooling_destroy:
    208	thermal_cooling_device_unregister(cdev);
    209	return ret;
    210}
    211
    212void ath10k_thermal_unregister(struct ath10k *ar)
    213{
    214	if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
    215		return;
    216
    217	sysfs_remove_link(&ar->dev->kobj, "cooling_device");
    218	thermal_cooling_device_unregister(ar->thermal.cdev);
    219}