Branch data Line data Source code
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 : 0 : ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
17 : : unsigned long *state)
18 : : {
19 : 0 : *state = ATH10K_THERMAL_THROTTLE_MAX;
20 : :
21 : 0 : return 0;
22 : : }
23 : :
24 : : static int
25 : 0 : ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
26 : : unsigned long *state)
27 : : {
28 : 0 : struct ath10k *ar = cdev->devdata;
29 : :
30 : 0 : mutex_lock(&ar->conf_mutex);
31 : 0 : *state = ar->thermal.throttle_state;
32 : 0 : mutex_unlock(&ar->conf_mutex);
33 : :
34 : 0 : return 0;
35 : : }
36 : :
37 : : static int
38 : 0 : ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
39 : : unsigned long throttle_state)
40 : : {
41 : 0 : struct ath10k *ar = cdev->devdata;
42 : :
43 [ # # ]: 0 : if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {
44 : 0 : ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",
45 : : throttle_state, ATH10K_THERMAL_THROTTLE_MAX);
46 : 0 : return -EINVAL;
47 : : }
48 : 0 : mutex_lock(&ar->conf_mutex);
49 : 0 : ar->thermal.throttle_state = throttle_state;
50 : 0 : ath10k_thermal_set_throttling(ar);
51 : 0 : mutex_unlock(&ar->conf_mutex);
52 : 0 : 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 : 0 : static ssize_t ath10k_thermal_show_temp(struct device *dev,
62 : : struct device_attribute *attr,
63 : : char *buf)
64 : : {
65 : 0 : struct ath10k *ar = dev_get_drvdata(dev);
66 : 0 : int ret, temperature;
67 : 0 : unsigned long time_left;
68 : :
69 : 0 : mutex_lock(&ar->conf_mutex);
70 : :
71 : : /* Can't get temperature when the card is off */
72 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
73 : 0 : ret = -ENETDOWN;
74 : 0 : goto out;
75 : : }
76 : :
77 : 0 : reinit_completion(&ar->thermal.wmi_sync);
78 : 0 : ret = ath10k_wmi_pdev_get_temperature(ar);
79 [ # # ]: 0 : if (ret) {
80 : 0 : ath10k_warn(ar, "failed to read temperature %d\n", ret);
81 : 0 : goto out;
82 : : }
83 : :
84 [ # # ]: 0 : if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
85 : 0 : ret = -ESHUTDOWN;
86 : 0 : goto out;
87 : : }
88 : :
89 : 0 : time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
90 : : ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
91 [ # # ]: 0 : if (!time_left) {
92 : 0 : ath10k_warn(ar, "failed to synchronize thermal read\n");
93 : 0 : ret = -ETIMEDOUT;
94 : 0 : goto out;
95 : : }
96 : :
97 : 0 : spin_lock_bh(&ar->data_lock);
98 : 0 : temperature = ar->thermal.temperature;
99 : 0 : spin_unlock_bh(&ar->data_lock);
100 : :
101 : : /* display in millidegree celcius */
102 : 0 : ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
103 : 0 : out:
104 : 0 : mutex_unlock(&ar->conf_mutex);
105 : 0 : return ret;
106 : : }
107 : :
108 : 0 : void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
109 : : {
110 : 0 : spin_lock_bh(&ar->data_lock);
111 : 0 : ar->thermal.temperature = temperature;
112 : 0 : spin_unlock_bh(&ar->data_lock);
113 : 0 : complete(&ar->thermal.wmi_sync);
114 : 0 : }
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 : 0 : void ath10k_thermal_set_throttling(struct ath10k *ar)
126 : : {
127 : 0 : u32 period, duration, enabled;
128 : 0 : int ret;
129 : :
130 : 0 : lockdep_assert_held(&ar->conf_mutex);
131 : :
132 [ # # ]: 0 : if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
133 : : return;
134 : :
135 [ # # ]: 0 : if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
136 : : return;
137 : :
138 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON)
139 : : return;
140 : :
141 : 0 : period = ar->thermal.quiet_period;
142 : 0 : duration = (period * ar->thermal.throttle_state) / 100;
143 : 0 : enabled = duration ? 1 : 0;
144 : :
145 : 0 : ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
146 : : ATH10K_QUIET_START_OFFSET,
147 : : enabled);
148 [ # # ]: 0 : if (ret) {
149 : 0 : 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 : 0 : int ath10k_thermal_register(struct ath10k *ar)
155 : : {
156 : 0 : struct thermal_cooling_device *cdev;
157 : 0 : struct device *hwmon_dev;
158 : 0 : int ret;
159 : :
160 [ # # ]: 0 : if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
161 : : return 0;
162 : :
163 : 0 : cdev = thermal_cooling_device_register("ath10k_thermal", ar,
164 : : &ath10k_thermal_ops);
165 : :
166 [ # # ]: 0 : if (IS_ERR(cdev)) {
167 : 0 : ath10k_err(ar, "failed to setup thermal device result: %ld\n",
168 : : PTR_ERR(cdev));
169 : 0 : return -EINVAL;
170 : : }
171 : :
172 : 0 : ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
173 : : "cooling_device");
174 [ # # ]: 0 : if (ret) {
175 : 0 : ath10k_err(ar, "failed to create cooling device symlink\n");
176 : 0 : goto err_cooling_destroy;
177 : : }
178 : :
179 : 0 : ar->thermal.cdev = cdev;
180 : 0 : 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 [ # # ]: 0 : 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 : 0 : if (!IS_REACHABLE(CONFIG_HWMON))
192 : : return 0;
193 : :
194 : 0 : hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
195 : : "ath10k_hwmon", ar,
196 : : ath10k_hwmon_groups);
197 [ # # ]: 0 : if (IS_ERR(hwmon_dev)) {
198 : 0 : ath10k_err(ar, "failed to register hwmon device: %ld\n",
199 : : PTR_ERR(hwmon_dev));
200 : 0 : ret = -EINVAL;
201 : 0 : goto err_remove_link;
202 : : }
203 : : return 0;
204 : :
205 : : err_remove_link:
206 : 0 : sysfs_remove_link(&ar->dev->kobj, "cooling_device");
207 : 0 : err_cooling_destroy:
208 : 0 : thermal_cooling_device_unregister(cdev);
209 : 0 : return ret;
210 : : }
211 : :
212 : 0 : void ath10k_thermal_unregister(struct ath10k *ar)
213 : : {
214 [ # # ]: 0 : if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
215 : : return;
216 : :
217 : 0 : sysfs_remove_link(&ar->dev->kobj, "cooling_device");
218 : 0 : thermal_cooling_device_unregister(ar->thermal.cdev);
219 : : }
|