root/drivers/net/wireless/ath/ath10k/thermal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath10k_thermal_get_max_throttle_state
  2. ath10k_thermal_get_cur_throttle_state
  3. ath10k_thermal_set_cur_throttle_state
  4. ath10k_thermal_show_temp
  5. ath10k_thermal_event_temperature
  6. ath10k_thermal_set_throttling
  7. ath10k_thermal_register
  8. ath10k_thermal_unregister

   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 
  15 static int
  16 ath10k_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 
  24 static int
  25 ath10k_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 
  37 static int
  38 ath10k_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 
  55 static 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 
  61 static 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);
 103 out:
 104         mutex_unlock(&ar->conf_mutex);
 105         return ret;
 106 }
 107 
 108 void 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 
 116 static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath10k_thermal_show_temp,
 117                           NULL, 0);
 118 
 119 static struct attribute *ath10k_hwmon_attrs[] = {
 120         &sensor_dev_attr_temp1_input.dev_attr.attr,
 121         NULL,
 122 };
 123 ATTRIBUTE_GROUPS(ath10k_hwmon);
 124 
 125 void 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 
 154 int 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 
 205 err_remove_link:
 206         sysfs_remove_link(&ar->dev->kobj, "cooling_device");
 207 err_cooling_destroy:
 208         thermal_cooling_device_unregister(cdev);
 209         return ret;
 210 }
 211 
 212 void 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 }

/* [<][>][^][v][top][bottom][index][help] */