Skip to content

Commit 2a63bbc

Browse files
Pradeep Kumar ChitrapuKalle Valo
authored andcommitted
ath11k: add thermal cooling device support
Thermal cooling device support is added to control the temperature by throttling the data transmission for the given duration. Throttling is done by suspending all data tx queues by given percentage of time. The thermal device allows user to configure duty cycle. Throttling can be disabled by setting the duty cycle to 0. The cooling device can be found under /sys/class/thermal/cooling_deviceX/. Corresponding soft link to this device can be found under phy folder. /sys/class/ieee80211/phy*/device/cooling_device. To set duty cycle as 40%, echo 40 >/sys/class/ieee80211/phy*/device/cooling_device/cur_state Signed-off-by: Pradeep Kumar Chitrapu <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent f9680c7 commit 2a63bbc

File tree

7 files changed

+303
-1
lines changed

7 files changed

+303
-1
lines changed

drivers/net/wireless/ath/ath11k/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ath11k-y += core.o \
2020
ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o debugfs_sta.o
2121
ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
2222
ath11k-$(CONFIG_ATH11K_TRACING) += trace.o
23+
ath11k-$(CONFIG_THERMAL) += thermal.o
2324

2425
# for tracing framework to find trace.h
2526
CFLAGS_trace.o := -I$(src)

drivers/net/wireless/ath/ath11k/core.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,19 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab)
392392
goto err_mac_unregister;
393393
}
394394

395+
ret = ath11k_thermal_register(ab);
396+
if (ret) {
397+
ath11k_err(ab, "could not register thermal device: %d\n",
398+
ret);
399+
goto err_dp_pdev_free;
400+
}
401+
395402
return 0;
396403

404+
err_dp_pdev_free:
405+
ath11k_dp_pdev_free(ab);
397406
err_mac_unregister:
398407
ath11k_mac_unregister(ab);
399-
400408
err_pdev_debug:
401409
ath11k_debug_pdev_destroy(ab);
402410

@@ -405,6 +413,7 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab)
405413

406414
static void ath11k_core_pdev_destroy(struct ath11k_base *ab)
407415
{
416+
ath11k_thermal_unregister(ab);
408417
ath11k_mac_unregister(ab);
409418
ath11k_ahb_ext_irq_disable(ab);
410419
ath11k_dp_pdev_free(ab);
@@ -569,6 +578,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
569578
int ret;
570579

571580
mutex_lock(&ab->core_lock);
581+
ath11k_thermal_unregister(ab);
572582
ath11k_ahb_ext_irq_disable(ab);
573583
ath11k_dp_pdev_free(ab);
574584
ath11k_ahb_stop(ab);

drivers/net/wireless/ath/ath11k/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "hw.h"
2121
#include "hal_rx.h"
2222
#include "reg.h"
23+
#include "thermal.h"
2324

2425
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
2526

@@ -526,6 +527,7 @@ struct ath11k {
526527
struct ath11k_debug debug;
527528
#endif
528529
bool dfs_block_radar_events;
530+
struct ath11k_thermal thermal;
529531
};
530532

531533
struct ath11k_band_cap {
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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 "core.h"
10+
#include "debug.h"
11+
12+
static int
13+
ath11k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
14+
unsigned long *state)
15+
{
16+
*state = ATH11K_THERMAL_THROTTLE_MAX;
17+
18+
return 0;
19+
}
20+
21+
static int
22+
ath11k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
23+
unsigned long *state)
24+
{
25+
struct ath11k *ar = cdev->devdata;
26+
27+
mutex_lock(&ar->conf_mutex);
28+
*state = ar->thermal.throttle_state;
29+
mutex_unlock(&ar->conf_mutex);
30+
31+
return 0;
32+
}
33+
34+
static int
35+
ath11k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
36+
unsigned long throttle_state)
37+
{
38+
struct ath11k *ar = cdev->devdata;
39+
int ret;
40+
41+
if (throttle_state > ATH11K_THERMAL_THROTTLE_MAX) {
42+
ath11k_warn(ar->ab, "throttle state %ld is exceeding the limit %d\n",
43+
throttle_state, ATH11K_THERMAL_THROTTLE_MAX);
44+
return -EINVAL;
45+
}
46+
mutex_lock(&ar->conf_mutex);
47+
ret = ath11k_thermal_set_throttling(ar, throttle_state);
48+
if (ret == 0)
49+
ar->thermal.throttle_state = throttle_state;
50+
mutex_unlock(&ar->conf_mutex);
51+
return ret;
52+
}
53+
54+
static struct thermal_cooling_device_ops ath11k_thermal_ops = {
55+
.get_max_state = ath11k_thermal_get_max_throttle_state,
56+
.get_cur_state = ath11k_thermal_get_cur_throttle_state,
57+
.set_cur_state = ath11k_thermal_set_cur_throttle_state,
58+
};
59+
60+
int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state)
61+
{
62+
struct ath11k_base *sc = ar->ab;
63+
struct thermal_mitigation_params param;
64+
int ret = 0;
65+
66+
lockdep_assert_held(&ar->conf_mutex);
67+
68+
if (ar->state != ATH11K_STATE_ON)
69+
return 0;
70+
71+
memset(&param, 0, sizeof(param));
72+
param.pdev_id = ar->pdev->pdev_id;
73+
param.enable = throttle_state ? 1 : 0;
74+
param.dc = ATH11K_THERMAL_DEFAULT_DUTY_CYCLE;
75+
param.dc_per_event = 0xFFFFFFFF;
76+
77+
param.levelconf[0].tmplwm = ATH11K_THERMAL_TEMP_LOW_MARK;
78+
param.levelconf[0].tmphwm = ATH11K_THERMAL_TEMP_HIGH_MARK;
79+
param.levelconf[0].dcoffpercent = throttle_state;
80+
param.levelconf[0].priority = 0; /* disable all data tx queues */
81+
82+
ret = ath11k_wmi_send_thermal_mitigation_param_cmd(ar, &param);
83+
if (ret) {
84+
ath11k_warn(sc, "failed to send thermal mitigation duty cycle %u ret %d\n",
85+
throttle_state, ret);
86+
}
87+
88+
return ret;
89+
}
90+
91+
int ath11k_thermal_register(struct ath11k_base *sc)
92+
{
93+
struct thermal_cooling_device *cdev;
94+
struct ath11k *ar;
95+
struct ath11k_pdev *pdev;
96+
int i, ret;
97+
98+
for (i = 0; i < sc->num_radios; i++) {
99+
pdev = &sc->pdevs[i];
100+
ar = pdev->ar;
101+
if (!ar)
102+
continue;
103+
104+
cdev = thermal_cooling_device_register("ath11k_thermal", ar,
105+
&ath11k_thermal_ops);
106+
107+
if (IS_ERR(cdev)) {
108+
ath11k_err(sc, "failed to setup thermal device result: %ld\n",
109+
PTR_ERR(cdev));
110+
return -EINVAL;
111+
}
112+
113+
ret = sysfs_create_link(&ar->hw->wiphy->dev.kobj, &cdev->device.kobj,
114+
"cooling_device");
115+
if (ret) {
116+
ath11k_err(sc, "failed to create cooling device symlink\n");
117+
goto err_thermal_destroy;
118+
}
119+
120+
ar->thermal.cdev = cdev;
121+
}
122+
123+
return 0;
124+
125+
err_thermal_destroy:
126+
ath11k_thermal_unregister(sc);
127+
return ret;
128+
}
129+
130+
void ath11k_thermal_unregister(struct ath11k_base *sc)
131+
{
132+
struct ath11k *ar;
133+
struct ath11k_pdev *pdev;
134+
int i;
135+
136+
for (i = 0; i < sc->num_radios; i++) {
137+
pdev = &sc->pdevs[i];
138+
ar = pdev->ar;
139+
if (!ar)
140+
continue;
141+
142+
sysfs_remove_link(&ar->hw->wiphy->dev.kobj, "cooling_device");
143+
thermal_cooling_device_unregister(ar->thermal.cdev);
144+
}
145+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
2+
/*
3+
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
4+
*/
5+
6+
#ifndef _ATH11K_THERMAL_
7+
#define _ATH11K_THERMAL_
8+
9+
#define ATH11K_THERMAL_TEMP_LOW_MARK -100
10+
#define ATH11K_THERMAL_TEMP_HIGH_MARK 150
11+
#define ATH11K_THERMAL_THROTTLE_MAX 100
12+
#define ATH11K_THERMAL_DEFAULT_DUTY_CYCLE 100
13+
14+
struct ath11k_thermal {
15+
struct thermal_cooling_device *cdev;
16+
17+
/* protected by conf_mutex */
18+
u32 throttle_state;
19+
};
20+
21+
#if IS_REACHABLE(CONFIG_THERMAL)
22+
int ath11k_thermal_register(struct ath11k_base *sc);
23+
void ath11k_thermal_unregister(struct ath11k_base *sc);
24+
int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state);
25+
#else
26+
static inline int ath11k_thermal_register(struct ath11k_base *sc)
27+
{
28+
return 0;
29+
}
30+
31+
static inline void ath11k_thermal_unregister(struct ath11k *ar)
32+
{
33+
}
34+
35+
static inline int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state)
36+
{
37+
}
38+
39+
#endif
40+
#endif /* _ATH11K_THERMAL_ */

drivers/net/wireless/ath/ath11k/wmi.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2442,6 +2442,70 @@ ath11k_wmi_send_init_country_cmd(struct ath11k *ar,
24422442
return ret;
24432443
}
24442444

2445+
int
2446+
ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar,
2447+
struct thermal_mitigation_params *param)
2448+
{
2449+
struct ath11k_pdev_wmi *wmi = ar->wmi;
2450+
struct wmi_therm_throt_config_request_cmd *cmd;
2451+
struct wmi_therm_throt_level_config_info *lvl_conf;
2452+
struct wmi_tlv *tlv;
2453+
struct sk_buff *skb;
2454+
int i, ret, len;
2455+
2456+
len = sizeof(*cmd) + TLV_HDR_SIZE +
2457+
THERMAL_LEVELS * sizeof(struct wmi_therm_throt_level_config_info);
2458+
2459+
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
2460+
if (!skb)
2461+
return -ENOMEM;
2462+
2463+
cmd = (struct wmi_therm_throt_config_request_cmd *)skb->data;
2464+
2465+
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_THERM_THROT_CONFIG_REQUEST) |
2466+
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
2467+
2468+
cmd->pdev_id = ar->pdev->pdev_id;
2469+
cmd->enable = param->enable;
2470+
cmd->dc = param->dc;
2471+
cmd->dc_per_event = param->dc_per_event;
2472+
cmd->therm_throt_levels = THERMAL_LEVELS;
2473+
2474+
tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));
2475+
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
2476+
FIELD_PREP(WMI_TLV_LEN,
2477+
(THERMAL_LEVELS *
2478+
sizeof(struct wmi_therm_throt_level_config_info)));
2479+
2480+
lvl_conf = (struct wmi_therm_throt_level_config_info *)(skb->data +
2481+
sizeof(*cmd) +
2482+
TLV_HDR_SIZE);
2483+
for (i = 0; i < THERMAL_LEVELS; i++) {
2484+
lvl_conf->tlv_header =
2485+
FIELD_PREP(WMI_TLV_TAG, WMI_TAG_THERM_THROT_LEVEL_CONFIG_INFO) |
2486+
FIELD_PREP(WMI_TLV_LEN, sizeof(*lvl_conf) - TLV_HDR_SIZE);
2487+
2488+
lvl_conf->temp_lwm = param->levelconf[i].tmplwm;
2489+
lvl_conf->temp_hwm = param->levelconf[i].tmphwm;
2490+
lvl_conf->dc_off_percent = param->levelconf[i].dcoffpercent;
2491+
lvl_conf->prio = param->levelconf[i].priority;
2492+
lvl_conf++;
2493+
}
2494+
2495+
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_THERM_THROT_SET_CONF_CMDID);
2496+
if (ret) {
2497+
ath11k_warn(ar->ab, "failed to send THERM_THROT_SET_CONF cmd\n");
2498+
dev_kfree_skb(skb);
2499+
}
2500+
2501+
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
2502+
"WMI vdev set thermal throt pdev_id %d enable %d dc %d dc_per_event %x levels %d\n",
2503+
ar->pdev->pdev_id, param->enable, param->dc,
2504+
param->dc_per_event, THERMAL_LEVELS);
2505+
2506+
return ret;
2507+
}
2508+
24452509
int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter)
24462510
{
24472511
struct ath11k_pdev_wmi *wmi = ar->wmi;

drivers/net/wireless/ath/ath11k/wmi.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ enum wmi_tlv_cmd_id {
442442
WMI_DBGLOG_TIME_STAMP_SYNC_CMDID,
443443
WMI_SET_MULTIPLE_MCAST_FILTER_CMDID,
444444
WMI_READ_DATA_FROM_FLASH_CMDID,
445+
WMI_THERM_THROT_SET_CONF_CMDID,
446+
WMI_RUNTIME_DPD_RECAL_CMDID,
447+
WMI_GET_TPC_POWER_CMDID,
448+
WMI_IDLE_TRIGGER_MONITOR_CMDID,
445449
WMI_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_GRP_GPIO),
446450
WMI_GPIO_OUTPUT_CMDID,
447451
WMI_TXBF_CMDID,
@@ -3605,6 +3609,39 @@ struct wmi_init_country_cmd {
36053609
} cc_info;
36063610
} __packed;
36073611

3612+
#define THERMAL_LEVELS 1
3613+
struct tt_level_config {
3614+
u32 tmplwm;
3615+
u32 tmphwm;
3616+
u32 dcoffpercent;
3617+
u32 priority;
3618+
};
3619+
3620+
struct thermal_mitigation_params {
3621+
u32 pdev_id;
3622+
u32 enable;
3623+
u32 dc;
3624+
u32 dc_per_event;
3625+
struct tt_level_config levelconf[THERMAL_LEVELS];
3626+
};
3627+
3628+
struct wmi_therm_throt_config_request_cmd {
3629+
u32 tlv_header;
3630+
u32 pdev_id;
3631+
u32 enable;
3632+
u32 dc;
3633+
u32 dc_per_event;
3634+
u32 therm_throt_levels;
3635+
} __packed;
3636+
3637+
struct wmi_therm_throt_level_config_info {
3638+
u32 tlv_header;
3639+
u32 temp_lwm;
3640+
u32 temp_hwm;
3641+
u32 dc_off_percent;
3642+
u32 prio;
3643+
} __packed;
3644+
36083645
struct wmi_pdev_pktlog_filter_info {
36093646
u32 tlv_header;
36103647
struct wmi_mac_addr peer_macaddr;
@@ -4740,6 +4777,9 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
47404777
int
47414778
ath11k_wmi_send_init_country_cmd(struct ath11k *ar,
47424779
struct wmi_init_country_params init_cc_param);
4780+
int
4781+
ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar,
4782+
struct thermal_mitigation_params *param);
47434783
int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter);
47444784
int ath11k_wmi_pdev_pktlog_disable(struct ath11k *ar);
47454785
int ath11k_wmi_pdev_peer_pktlog_filter(struct ath11k *ar, u8 *addr, u8 enable);

0 commit comments

Comments
 (0)