summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c1
-rw-r--r--drivers/net/wireless/ath/ath12k/thermal.c107
-rw-r--r--drivers/net/wireless/ath/ath12k/thermal.h14
3 files changed, 121 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 99e6cc6d6d7f..9ce759626f18 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -14806,6 +14806,7 @@ static void ath12k_mac_setup(struct ath12k *ar)
init_completion(&ar->completed_11d_scan);
init_completion(&ar->regd_update_completed);
init_completion(&ar->thermal.wmi_sync);
+ mutex_init(&ar->thermal.lock);
ar->thermal.temperature = 0;
ar->thermal.hwmon_dev = NULL;
diff --git a/drivers/net/wireless/ath/ath12k/thermal.c b/drivers/net/wireless/ath/ath12k/thermal.c
index 6f70c11c1098..97fc49c40ac1 100644
--- a/drivers/net/wireless/ath/ath12k/thermal.c
+++ b/drivers/net/wireless/ath/ath12k/thermal.c
@@ -76,6 +76,73 @@ void ath12k_thermal_init_configs(struct ath12k *ar)
ar->thermal.tt_level_configs = &tt_level_configs[cfg_idx][0];
}
+static int
+ath12k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = ATH12K_THERMAL_THROTTLE_MAX;
+
+ return 0;
+}
+
+static int
+ath12k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct ath12k *ar = cdev->devdata;
+
+ mutex_lock(&ar->thermal.lock);
+ *state = ar->thermal.throttle_state;
+ mutex_unlock(&ar->thermal.lock);
+
+ return 0;
+}
+
+int ath12k_thermal_set_throttling(struct ath12k *ar, u32 throttle_state)
+{
+ struct ath12k_wmi_thermal_mitigation_arg param = {};
+ struct ath12k_wmi_tt_level_config_param cfg = {};
+ int ret;
+
+ param.num_levels = 1;
+ cfg.dcoffpercent = throttle_state;
+ param.levelconf = &cfg;
+
+ ret = ath12k_wmi_send_thermal_mitigation_cmd(ar, &param);
+ if (ret)
+ ath12k_warn(ar->ab, "failed to send thermal mitigation cmd: %d\n",
+ ret);
+
+ return ret;
+}
+
+static int
+ath12k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long throttle_state)
+{
+ struct ath12k *ar = cdev->devdata;
+
+ if (throttle_state > ATH12K_THERMAL_THROTTLE_MAX)
+ return -EINVAL;
+
+ scoped_guard(mutex, &ar->thermal.lock) {
+ if (ar->thermal.throttle_state == throttle_state)
+ return 0;
+ ar->thermal.throttle_state = throttle_state;
+ }
+
+ if (throttle_state == 0)
+ return ath12k_thermal_throttling_config_default(ar);
+
+ return ath12k_thermal_set_throttling(ar, throttle_state);
+}
+
+static const struct thermal_cooling_device_ops ath12k_thermal_ops = {
+ .get_max_state = ath12k_thermal_get_max_throttle_state,
+ .get_cur_state = ath12k_thermal_get_cur_throttle_state,
+ .set_cur_state = ath12k_thermal_set_cur_throttle_state,
+};
+
static ssize_t ath12k_thermal_temp_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -132,6 +199,7 @@ ATTRIBUTE_GROUPS(ath12k_hwmon);
static int ath12k_thermal_setup_radio(struct ath12k_base *ab, int i)
{
+ char pdev_name[20];
struct ath12k *ar;
int ret;
@@ -139,6 +207,28 @@ static int ath12k_thermal_setup_radio(struct ath12k_base *ab, int i)
if (!ar)
return 0;
+ ar->thermal.cdev =
+ thermal_cooling_device_register("ath12k_thermal", ar,
+ &ath12k_thermal_ops);
+ if (IS_ERR(ar->thermal.cdev)) {
+ ret = PTR_ERR(ar->thermal.cdev);
+ ar->thermal.cdev = NULL;
+ ath12k_err(ar->ab, "failed to register cooling device: %d\n",
+ ret);
+ return ret;
+ }
+
+ scnprintf(pdev_name, sizeof(pdev_name), "cooling_device%u",
+ ar->hw_link_id);
+
+ ret = sysfs_create_link(&ar->ah->hw->wiphy->dev.kobj,
+ &ar->thermal.cdev->device.kobj, pdev_name);
+ if (ret) {
+ ath12k_err(ab, "failed to create cooling device symlink: %d\n",
+ ret);
+ goto unregister_cdev;
+ }
+
ar->thermal.hwmon_dev =
hwmon_device_register_with_groups(&ar->ah->hw->wiphy->dev,
"ath12k_hwmon", ar,
@@ -148,14 +238,22 @@ static int ath12k_thermal_setup_radio(struct ath12k_base *ab, int i)
ar->thermal.hwmon_dev = NULL;
ath12k_err(ar->ab, "failed to register hwmon device: %d\n",
ret);
- return ret;
+ goto remove_sysfs;
}
return 0;
+
+remove_sysfs:
+ sysfs_remove_link(&ar->ah->hw->wiphy->dev.kobj, pdev_name);
+unregister_cdev:
+ thermal_cooling_device_unregister(ar->thermal.cdev);
+ ar->thermal.cdev = NULL;
+ return ret;
}
static void ath12k_thermal_cleanup_radio(struct ath12k_base *ab, int i)
{
+ char pdev_name[20];
struct ath12k *ar;
ar = ab->pdevs[i].ar;
@@ -164,6 +262,13 @@ static void ath12k_thermal_cleanup_radio(struct ath12k_base *ab, int i)
hwmon_device_unregister(ar->thermal.hwmon_dev);
ar->thermal.hwmon_dev = NULL;
+
+ scnprintf(pdev_name, sizeof(pdev_name), "cooling_device%u",
+ ar->hw_link_id);
+ sysfs_remove_link(&ar->ah->hw->wiphy->dev.kobj, pdev_name);
+
+ thermal_cooling_device_unregister(ar->thermal.cdev);
+ ar->thermal.cdev = NULL;
}
int ath12k_thermal_register(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/thermal.h b/drivers/net/wireless/ath/ath12k/thermal.h
index 33231bb3683c..30e7b0880e05 100644
--- a/drivers/net/wireless/ath/ath12k/thermal.h
+++ b/drivers/net/wireless/ath/ath12k/thermal.h
@@ -7,9 +7,12 @@
#ifndef _ATH12K_THERMAL_
#define _ATH12K_THERMAL_
+#include <linux/mutex.h>
+
#define ATH12K_THERMAL_SYNC_TIMEOUT_HZ (5 * HZ)
#define ATH12K_THERMAL_DEFAULT_DUTY_CYCLE 100
+#define ATH12K_THERMAL_THROTTLE_MAX 100
enum ath12k_thermal_cfg_idx {
/* Internal Power Amplifier Device */
@@ -26,6 +29,10 @@ struct ath12k_thermal {
int temperature;
struct device *hwmon_dev;
const struct ath12k_wmi_tt_level_config_param *tt_level_configs;
+ struct thermal_cooling_device *cdev;
+ /* Serialize thermal operations and hwmon reads */
+ struct mutex lock;
+ u32 throttle_state;
};
#if IS_REACHABLE(CONFIG_THERMAL)
@@ -34,6 +41,7 @@ void ath12k_thermal_unregister(struct ath12k_base *ab);
void ath12k_thermal_event_temperature(struct ath12k *ar, int temperature);
int ath12k_thermal_throttling_config_default(struct ath12k *ar);
void ath12k_thermal_init_configs(struct ath12k *ar);
+int ath12k_thermal_set_throttling(struct ath12k *ar, u32 throttle_state);
#else
static inline int ath12k_thermal_register(struct ath12k_base *ab)
{
@@ -57,5 +65,11 @@ static inline int ath12k_thermal_throttling_config_default(struct ath12k *ar)
static inline void ath12k_thermal_init_configs(struct ath12k *ar)
{
}
+
+static inline int ath12k_thermal_set_throttling(struct ath12k *ar,
+ u32 throttle_state)
+{
+ return 0;
+}
#endif
#endif /* _ATH12K_THERMAL_ */