Skip to content

Commit a41d103

Browse files
Pradeep Kumar ChitrapuKalle Valo
Pradeep Kumar Chitrapu
authored and
Kalle Valo
committed
ath11k: add thermal sensor device support
Temperature sensor generates electrical analog voltage from temperature of each chain. The analog voltage is converted to digital value through ADC. For reading temperature values fom user space, hw monitoring device is used. Whenever the user requests for current temperature, the driver sends WMI command and wait for response. For reading temperature, cat /sys/class/ieee80211/phy*/device/hwmon/hwmon2/temp1_input Signed-off-by: Pradeep Kumar Chitrapu <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent 2a63bbc commit a41d103

File tree

6 files changed

+188
-0
lines changed

6 files changed

+188
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ static void ath11k_core_restart(struct work_struct *work)
655655
complete(&ar->install_key_done);
656656
complete(&ar->vdev_setup_done);
657657
complete(&ar->bss_survey_done);
658+
complete(&ar->thermal.wmi_sync);
658659

659660
wake_up(&ar->dp.tx_empty_waitq);
660661
idr_for_each(&ar->txmgmt_idr,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5905,6 +5905,8 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
59055905
init_completion(&ar->bss_survey_done);
59065906
init_completion(&ar->scan.started);
59075907
init_completion(&ar->scan.completed);
5908+
init_completion(&ar->thermal.wmi_sync);
5909+
59085910
INIT_DELAYED_WORK(&ar->scan.timeout, ath11k_scan_timeout_work);
59095911
INIT_WORK(&ar->regd_update_work, ath11k_regd_update_work);
59105912

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

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <linux/device.h>
77
#include <linux/sysfs.h>
88
#include <linux/thermal.h>
9+
#include <linux/hwmon.h>
10+
#include <linux/hwmon-sysfs.h>
911
#include "core.h"
1012
#include "debug.h"
1113

@@ -57,6 +59,70 @@ static struct thermal_cooling_device_ops ath11k_thermal_ops = {
5759
.set_cur_state = ath11k_thermal_set_cur_throttle_state,
5860
};
5961

62+
static 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);
104+
out:
105+
mutex_unlock(&ar->conf_mutex);
106+
return ret;
107+
}
108+
109+
void 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+
117+
static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath11k_thermal_show_temp,
118+
NULL, 0);
119+
120+
static struct attribute *ath11k_hwmon_attrs[] = {
121+
&sensor_dev_attr_temp1_input.dev_attr.attr,
122+
NULL,
123+
};
124+
ATTRIBUTE_GROUPS(ath11k_hwmon);
125+
60126
int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state)
61127
{
62128
struct ath11k_base *sc = ar->ab;
@@ -91,6 +157,7 @@ int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state)
91157
int ath11k_thermal_register(struct ath11k_base *sc)
92158
{
93159
struct thermal_cooling_device *cdev;
160+
struct device *hwmon_dev;
94161
struct ath11k *ar;
95162
struct ath11k_pdev *pdev;
96163
int i, ret;
@@ -118,6 +185,18 @@ int ath11k_thermal_register(struct ath11k_base *sc)
118185
}
119186

120187
ar->thermal.cdev = cdev;
188+
if (!IS_REACHABLE(CONFIG_HWMON))
189+
return 0;
190+
191+
hwmon_dev = devm_hwmon_device_register_with_groups(&ar->hw->wiphy->dev,
192+
"ath11k_hwmon", ar,
193+
ath11k_hwmon_groups);
194+
if (IS_ERR(hwmon_dev)) {
195+
ath11k_err(ar->ab, "failed to register hwmon device: %ld\n",
196+
PTR_ERR(hwmon_dev));
197+
ret = -EINVAL;
198+
goto err_thermal_destroy;
199+
}
121200
}
122201

123202
return 0;

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,26 @@
1010
#define ATH11K_THERMAL_TEMP_HIGH_MARK 150
1111
#define ATH11K_THERMAL_THROTTLE_MAX 100
1212
#define ATH11K_THERMAL_DEFAULT_DUTY_CYCLE 100
13+
#define ATH11K_HWMON_NAME_LEN 15
14+
#define ATH11K_THERMAL_SYNC_TIMEOUT_HZ (5 * HZ)
1315

1416
struct ath11k_thermal {
1517
struct thermal_cooling_device *cdev;
18+
struct completion wmi_sync;
1619

1720
/* protected by conf_mutex */
1821
u32 throttle_state;
22+
/* temperature value in Celcius degree
23+
* protected by data_lock
24+
*/
25+
int temperature;
1926
};
2027

2128
#if IS_REACHABLE(CONFIG_THERMAL)
2229
int ath11k_thermal_register(struct ath11k_base *sc);
2330
void ath11k_thermal_unregister(struct ath11k_base *sc);
2431
int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state);
32+
void ath11k_thermal_event_temperature(struct ath11k *ar, int temperature);
2533
#else
2634
static inline int ath11k_thermal_register(struct ath11k_base *sc)
2735
{
@@ -36,5 +44,10 @@ static inline int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_
3644
{
3745
}
3846

47+
static inline void ath11k_thermal_event_temperature(struct ath11k *ar,
48+
int temperature)
49+
{
50+
}
51+
3952
#endif
4053
#endif /* _ATH11K_THERMAL_ */

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

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,34 @@ int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar,
14711471
return ret;
14721472
}
14731473

1474+
int ath11k_wmi_send_pdev_temperature_cmd(struct ath11k *ar)
1475+
{
1476+
struct ath11k_pdev_wmi *wmi = ar->wmi;
1477+
struct wmi_get_pdev_temperature_cmd *cmd;
1478+
struct sk_buff *skb;
1479+
int ret;
1480+
1481+
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
1482+
if (!skb)
1483+
return -ENOMEM;
1484+
1485+
cmd = (struct wmi_get_pdev_temperature_cmd *)skb->data;
1486+
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_GET_TEMPERATURE_CMD) |
1487+
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
1488+
cmd->pdev_id = ar->pdev->pdev_id;
1489+
1490+
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_GET_TEMPERATURE_CMDID);
1491+
if (ret) {
1492+
ath11k_warn(ar->ab, "failed to send WMI_PDEV_GET_TEMPERATURE cmd\n");
1493+
dev_kfree_skb(skb);
1494+
}
1495+
1496+
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
1497+
"WMI pdev get temperature for pdev_id %d\n", ar->pdev->pdev_id);
1498+
1499+
return ret;
1500+
}
1501+
14741502
int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
14751503
u32 vdev_id, u32 bcn_ctrl_op)
14761504
{
@@ -4232,6 +4260,31 @@ int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb,
42324260
return 0;
42334261
}
42344262

4263+
static int
4264+
ath11k_pull_pdev_temp_ev(struct ath11k_base *ab, u8 *evt_buf,
4265+
u32 len, const struct wmi_pdev_temperature_event *ev)
4266+
{
4267+
const void **tb;
4268+
int ret;
4269+
4270+
tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
4271+
if (IS_ERR(tb)) {
4272+
ret = PTR_ERR(tb);
4273+
ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
4274+
return ret;
4275+
}
4276+
4277+
ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT];
4278+
if (!ev) {
4279+
ath11k_warn(ab, "failed to fetch pdev temp ev");
4280+
kfree(tb);
4281+
return -EPROTO;
4282+
}
4283+
4284+
kfree(tb);
4285+
return 0;
4286+
}
4287+
42354288
size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head)
42364289
{
42374290
struct ath11k_fw_stats_vdev *i;
@@ -5578,6 +5631,30 @@ ath11k_wmi_pdev_dfs_radar_detected_event(struct ath11k_base *ab, struct sk_buff
55785631
kfree(tb);
55795632
}
55805633

5634+
static void
5635+
ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab,
5636+
struct sk_buff *skb)
5637+
{
5638+
struct ath11k *ar;
5639+
struct wmi_pdev_temperature_event ev = {0};
5640+
5641+
if (ath11k_pull_pdev_temp_ev(ab, skb->data, skb->len, &ev) != 0) {
5642+
ath11k_warn(ab, "failed to extract pdev temperature event");
5643+
return;
5644+
}
5645+
5646+
ath11k_dbg(ab, ATH11K_DBG_WMI,
5647+
"pdev temperature ev temp %d pdev_id %d\n", ev.temp, ev.pdev_id);
5648+
5649+
ar = ath11k_mac_get_ar_by_pdev_id(ab, ev.pdev_id);
5650+
if (!ar) {
5651+
ath11k_warn(ab, "invalid pdev id in pdev temperature ev %d", ev.pdev_id);
5652+
return;
5653+
}
5654+
5655+
ath11k_thermal_event_temperature(ar, ev.temp);
5656+
}
5657+
55815658
static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
55825659
{
55835660
struct wmi_cmd_hdr *cmd_hdr;
@@ -5655,6 +5732,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
56555732
case WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID:
56565733
ath11k_wmi_pdev_csa_switch_count_status_event(ab, skb);
56575734
break;
5735+
case WMI_PDEV_TEMPERATURE_EVENTID:
5736+
ath11k_wmi_pdev_temperature_event(ab, skb);
5737+
break;
56585738
/* add Unsupported events here */
56595739
case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
56605740
case WMI_VDEV_DELETE_RESP_EVENTID:

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,6 +3304,12 @@ struct wmi_request_stats_cmd {
33043304
u32 pdev_id;
33053305
} __packed;
33063306

3307+
struct wmi_get_pdev_temperature_cmd {
3308+
u32 tlv_header;
3309+
u32 param;
3310+
u32 pdev_id;
3311+
} __packed;
3312+
33073313
#define WMI_BEACON_TX_BUFFER_SIZE 512
33083314

33093315
struct wmi_bcn_tmpl_cmd {
@@ -4132,6 +4138,12 @@ struct wmi_pdev_radar_ev {
41324138
s32 sidx;
41334139
} __packed;
41344140

4141+
struct wmi_pdev_temperature_event {
4142+
/* temperature value in Celcius degree */
4143+
s32 temp;
4144+
u32 pdev_id;
4145+
} __packed;
4146+
41354147
#define WMI_RX_STATUS_OK 0x00
41364148
#define WMI_RX_STATUS_ERR_CRC 0x01
41374149
#define WMI_RX_STATUS_ERR_DECRYPT 0x08
@@ -4763,6 +4775,7 @@ int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar,
47634775
enum wmi_bss_chan_info_req_type type);
47644776
int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar,
47654777
struct stats_request_params *param);
4778+
int ath11k_wmi_send_pdev_temperature_cmd(struct ath11k *ar);
47664779
int ath11k_wmi_send_peer_flush_tids_cmd(struct ath11k *ar,
47674780
u8 peer_addr[ETH_ALEN],
47684781
struct peer_flush_params *param);

0 commit comments

Comments
 (0)