diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/mac.c | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/thermal.c | 107 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/thermal.h | 14 |
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, ¶m); + 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_ */ |
