thermal.c (5573B)
1// SPDX-License-Identifier: BSD-3-Clause-Clear 2/* 3 * Copyright (c) 2020 The Linux Foundation. All rights reserved. 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 14static int 15ath11k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, 16 unsigned long *state) 17{ 18 *state = ATH11K_THERMAL_THROTTLE_MAX; 19 20 return 0; 21} 22 23static int 24ath11k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, 25 unsigned long *state) 26{ 27 struct ath11k *ar = cdev->devdata; 28 29 mutex_lock(&ar->conf_mutex); 30 *state = ar->thermal.throttle_state; 31 mutex_unlock(&ar->conf_mutex); 32 33 return 0; 34} 35 36static int 37ath11k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, 38 unsigned long throttle_state) 39{ 40 struct ath11k *ar = cdev->devdata; 41 int ret; 42 43 if (throttle_state > ATH11K_THERMAL_THROTTLE_MAX) { 44 ath11k_warn(ar->ab, "throttle state %ld is exceeding the limit %d\n", 45 throttle_state, ATH11K_THERMAL_THROTTLE_MAX); 46 return -EINVAL; 47 } 48 mutex_lock(&ar->conf_mutex); 49 ret = ath11k_thermal_set_throttling(ar, throttle_state); 50 if (ret == 0) 51 ar->thermal.throttle_state = throttle_state; 52 mutex_unlock(&ar->conf_mutex); 53 return ret; 54} 55 56static const struct thermal_cooling_device_ops ath11k_thermal_ops = { 57 .get_max_state = ath11k_thermal_get_max_throttle_state, 58 .get_cur_state = ath11k_thermal_get_cur_throttle_state, 59 .set_cur_state = ath11k_thermal_set_cur_throttle_state, 60}; 61 62static ssize_t ath11k_thermal_show_temp(struct device *dev, 63 struct device_attribute *attr, 64 char *buf) 65{ 66 struct ath11k *ar = dev_get_drvdata(dev); 67 int ret, temperature; 68 unsigned long time_left; 69 70 mutex_lock(&ar->conf_mutex); 71 72 /* Can't get temperature when the card is off */ 73 if (ar->state != ATH11K_STATE_ON) { 74 ret = -ENETDOWN; 75 goto out; 76 } 77 78 reinit_completion(&ar->thermal.wmi_sync); 79 ret = ath11k_wmi_send_pdev_temperature_cmd(ar); 80 if (ret) { 81 ath11k_warn(ar->ab, "failed to read temperature %d\n", ret); 82 goto out; 83 } 84 85 if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) { 86 ret = -ESHUTDOWN; 87 goto out; 88 } 89 90 time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync, 91 ATH11K_THERMAL_SYNC_TIMEOUT_HZ); 92 if (!time_left) { 93 ath11k_warn(ar->ab, "failed to synchronize thermal read\n"); 94 ret = -ETIMEDOUT; 95 goto out; 96 } 97 98 spin_lock_bh(&ar->data_lock); 99 temperature = ar->thermal.temperature; 100 spin_unlock_bh(&ar->data_lock); 101 102 /* display in millidegree celcius */ 103 ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); 104out: 105 mutex_unlock(&ar->conf_mutex); 106 return ret; 107} 108 109void ath11k_thermal_event_temperature(struct ath11k *ar, int temperature) 110{ 111 spin_lock_bh(&ar->data_lock); 112 ar->thermal.temperature = temperature; 113 spin_unlock_bh(&ar->data_lock); 114 complete(&ar->thermal.wmi_sync); 115} 116 117static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath11k_thermal_show_temp, 118 NULL, 0); 119 120static struct attribute *ath11k_hwmon_attrs[] = { 121 &sensor_dev_attr_temp1_input.dev_attr.attr, 122 NULL, 123}; 124ATTRIBUTE_GROUPS(ath11k_hwmon); 125 126int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state) 127{ 128 struct ath11k_base *sc = ar->ab; 129 struct thermal_mitigation_params param; 130 int ret = 0; 131 132 lockdep_assert_held(&ar->conf_mutex); 133 134 if (ar->state != ATH11K_STATE_ON) 135 return 0; 136 137 memset(¶m, 0, sizeof(param)); 138 param.pdev_id = ar->pdev->pdev_id; 139 param.enable = throttle_state ? 1 : 0; 140 param.dc = ATH11K_THERMAL_DEFAULT_DUTY_CYCLE; 141 param.dc_per_event = 0xFFFFFFFF; 142 143 param.levelconf[0].tmplwm = ATH11K_THERMAL_TEMP_LOW_MARK; 144 param.levelconf[0].tmphwm = ATH11K_THERMAL_TEMP_HIGH_MARK; 145 param.levelconf[0].dcoffpercent = throttle_state; 146 param.levelconf[0].priority = 0; /* disable all data tx queues */ 147 148 ret = ath11k_wmi_send_thermal_mitigation_param_cmd(ar, ¶m); 149 if (ret) { 150 ath11k_warn(sc, "failed to send thermal mitigation duty cycle %u ret %d\n", 151 throttle_state, ret); 152 } 153 154 return ret; 155} 156 157int ath11k_thermal_register(struct ath11k_base *sc) 158{ 159 struct thermal_cooling_device *cdev; 160 struct device *hwmon_dev; 161 struct ath11k *ar; 162 struct ath11k_pdev *pdev; 163 int i, ret; 164 165 for (i = 0; i < sc->num_radios; i++) { 166 pdev = &sc->pdevs[i]; 167 ar = pdev->ar; 168 if (!ar) 169 continue; 170 171 cdev = thermal_cooling_device_register("ath11k_thermal", ar, 172 &ath11k_thermal_ops); 173 174 if (IS_ERR(cdev)) { 175 ath11k_err(sc, "failed to setup thermal device result: %ld\n", 176 PTR_ERR(cdev)); 177 ret = -EINVAL; 178 goto err_thermal_destroy; 179 } 180 181 ar->thermal.cdev = cdev; 182 183 ret = sysfs_create_link(&ar->hw->wiphy->dev.kobj, &cdev->device.kobj, 184 "cooling_device"); 185 if (ret) { 186 ath11k_err(sc, "failed to create cooling device symlink\n"); 187 goto err_thermal_destroy; 188 } 189 190 if (!IS_REACHABLE(CONFIG_HWMON)) 191 return 0; 192 193 hwmon_dev = devm_hwmon_device_register_with_groups(&ar->hw->wiphy->dev, 194 "ath11k_hwmon", ar, 195 ath11k_hwmon_groups); 196 if (IS_ERR(hwmon_dev)) { 197 ath11k_err(ar->ab, "failed to register hwmon device: %ld\n", 198 PTR_ERR(hwmon_dev)); 199 ret = -EINVAL; 200 goto err_thermal_destroy; 201 } 202 } 203 204 return 0; 205 206err_thermal_destroy: 207 ath11k_thermal_unregister(sc); 208 return ret; 209} 210 211void ath11k_thermal_unregister(struct ath11k_base *sc) 212{ 213 struct ath11k *ar; 214 struct ath11k_pdev *pdev; 215 int i; 216 217 for (i = 0; i < sc->num_radios; i++) { 218 pdev = &sc->pdevs[i]; 219 ar = pdev->ar; 220 if (!ar) 221 continue; 222 223 sysfs_remove_link(&ar->hw->wiphy->dev.kobj, "cooling_device"); 224 thermal_cooling_device_unregister(ar->thermal.cdev); 225 } 226}