xref: /linux/drivers/net/wireless/ath/ath12k/acpi.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
5  */
6 
7 #include "core.h"
8 #include "acpi.h"
9 #include "debug.h"
10 
ath12k_acpi_dsm_get_data(struct ath12k_base * ab,int func)11 static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
12 {
13 	union acpi_object *obj;
14 	acpi_handle root_handle;
15 	int ret;
16 
17 	root_handle = ACPI_HANDLE(ab->dev);
18 	if (!root_handle) {
19 		ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid acpi handler\n");
20 		return -EOPNOTSUPP;
21 	}
22 
23 	obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,
24 				NULL);
25 
26 	if (!obj) {
27 		ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_evaluate_dsm() failed\n");
28 		return -ENOENT;
29 	}
30 
31 	if (obj->type == ACPI_TYPE_INTEGER) {
32 		ab->acpi.func_bit = obj->integer.value;
33 	} else if (obj->type == ACPI_TYPE_BUFFER) {
34 		switch (func) {
35 		case ATH12K_ACPI_DSM_FUNC_TAS_CFG:
36 			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
37 				ath12k_warn(ab, "invalid ACPI DSM TAS config size: %d\n",
38 					    obj->buffer.length);
39 				ret = -EINVAL;
40 				goto out;
41 			}
42 
43 			memcpy(&ab->acpi.tas_cfg, obj->buffer.pointer,
44 			       obj->buffer.length);
45 
46 			break;
47 		case ATH12K_ACPI_DSM_FUNC_TAS_DATA:
48 			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
49 				ath12k_warn(ab, "invalid ACPI DSM TAS data size: %d\n",
50 					    obj->buffer.length);
51 				ret = -EINVAL;
52 				goto out;
53 			}
54 
55 			memcpy(&ab->acpi.tas_sar_power_table, obj->buffer.pointer,
56 			       obj->buffer.length);
57 
58 			break;
59 		case ATH12K_ACPI_DSM_FUNC_BIOS_SAR:
60 			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
61 				ath12k_warn(ab, "invalid ACPI BIOS SAR data size: %d\n",
62 					    obj->buffer.length);
63 				ret = -EINVAL;
64 				goto out;
65 			}
66 
67 			memcpy(&ab->acpi.bios_sar_data, obj->buffer.pointer,
68 			       obj->buffer.length);
69 
70 			break;
71 		case ATH12K_ACPI_DSM_FUNC_GEO_OFFSET:
72 			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
73 				ath12k_warn(ab, "invalid ACPI GEO OFFSET data size: %d\n",
74 					    obj->buffer.length);
75 				ret = -EINVAL;
76 				goto out;
77 			}
78 
79 			memcpy(&ab->acpi.geo_offset_data, obj->buffer.pointer,
80 			       obj->buffer.length);
81 
82 			break;
83 		case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
84 			if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
85 				ath12k_warn(ab, "invalid ACPI DSM CCA data size: %d\n",
86 					    obj->buffer.length);
87 				ret = -EINVAL;
88 				goto out;
89 			}
90 
91 			memcpy(&ab->acpi.cca_data, obj->buffer.pointer,
92 			       obj->buffer.length);
93 
94 			break;
95 		case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
96 			if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
97 				ath12k_warn(ab, "invalid ACPI DSM band edge data size: %d\n",
98 					    obj->buffer.length);
99 				ret = -EINVAL;
100 				goto out;
101 			}
102 
103 			memcpy(&ab->acpi.band_edge_power, obj->buffer.pointer,
104 			       obj->buffer.length);
105 
106 			break;
107 		}
108 	} else {
109 		ath12k_warn(ab, "ACPI DSM method returned an unsupported object type: %d\n",
110 			    obj->type);
111 		ret = -EINVAL;
112 		goto out;
113 	}
114 
115 	ret = 0;
116 
117 out:
118 	ACPI_FREE(obj);
119 	return ret;
120 }
121 
ath12k_acpi_set_power_limit(struct ath12k_base * ab)122 static int ath12k_acpi_set_power_limit(struct ath12k_base *ab)
123 {
124 	const u8 *tas_sar_power_table = ab->acpi.tas_sar_power_table;
125 	int ret;
126 
127 	if (tas_sar_power_table[0] != ATH12K_ACPI_TAS_DATA_VERSION ||
128 	    tas_sar_power_table[1] != ATH12K_ACPI_TAS_DATA_ENABLE) {
129 		ath12k_warn(ab, "latest ACPI TAS data is invalid\n");
130 		return -EINVAL;
131 	}
132 
133 	ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,
134 				      tas_sar_power_table,
135 				      ATH12K_ACPI_DSM_TAS_DATA_SIZE);
136 	if (ret) {
137 		ath12k_warn(ab, "failed to send ACPI TAS data table: %d\n", ret);
138 		return ret;
139 	}
140 
141 	return ret;
142 }
143 
ath12k_acpi_set_bios_sar_power(struct ath12k_base * ab)144 static int ath12k_acpi_set_bios_sar_power(struct ath12k_base *ab)
145 {
146 	int ret;
147 
148 	if (ab->acpi.bios_sar_data[0] != ATH12K_ACPI_POWER_LIMIT_VERSION ||
149 	    ab->acpi.bios_sar_data[1] != ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
150 		ath12k_warn(ab, "invalid latest ACPI BIOS SAR data\n");
151 		return -EINVAL;
152 	}
153 
154 	ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);
155 	if (ret) {
156 		ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);
157 		return ret;
158 	}
159 
160 	return 0;
161 }
162 
ath12k_acpi_dsm_notify(acpi_handle handle,u32 event,void * data)163 static void ath12k_acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
164 {
165 	int ret;
166 	struct ath12k_base *ab = data;
167 
168 	if (event == ATH12K_ACPI_NOTIFY_EVENT) {
169 		ath12k_warn(ab, "unknown acpi notify %u\n", event);
170 		return;
171 	}
172 
173 	if (!ab->acpi.acpi_tas_enable) {
174 		ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_tas_enable is false\n");
175 		return;
176 	}
177 
178 	ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);
179 	if (ret) {
180 		ath12k_warn(ab, "failed to update ACPI TAS data table: %d\n", ret);
181 		return;
182 	}
183 
184 	ret = ath12k_acpi_set_power_limit(ab);
185 	if (ret) {
186 		ath12k_warn(ab, "failed to set ACPI TAS power limit data: %d", ret);
187 		return;
188 	}
189 
190 	if (!ab->acpi.acpi_bios_sar_enable)
191 		return;
192 
193 	ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);
194 	if (ret) {
195 		ath12k_warn(ab, "failed to update BIOS SAR: %d\n", ret);
196 		return;
197 	}
198 
199 	ret = ath12k_acpi_set_bios_sar_power(ab);
200 	if (ret) {
201 		ath12k_warn(ab, "failed to set BIOS SAR power limit: %d\n", ret);
202 		return;
203 	}
204 }
205 
ath12k_acpi_set_bios_sar_params(struct ath12k_base * ab)206 static int ath12k_acpi_set_bios_sar_params(struct ath12k_base *ab)
207 {
208 	int ret;
209 
210 	ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);
211 	if (ret) {
212 		ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);
213 		return ret;
214 	}
215 
216 	ret = ath12k_wmi_set_bios_geo_cmd(ab, ab->acpi.geo_offset_data);
217 	if (ret) {
218 		ath12k_warn(ab, "failed to set ACPI BIOS GEO table: %d\n", ret);
219 		return ret;
220 	}
221 
222 	return 0;
223 }
224 
ath12k_acpi_set_tas_params(struct ath12k_base * ab)225 static int ath12k_acpi_set_tas_params(struct ath12k_base *ab)
226 {
227 	int ret;
228 
229 	ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_CONFIG_TYPE,
230 				      ab->acpi.tas_cfg,
231 				      ATH12K_ACPI_DSM_TAS_CFG_SIZE);
232 	if (ret) {
233 		ath12k_warn(ab, "failed to send ACPI TAS config table parameter: %d\n",
234 			    ret);
235 		return ret;
236 	}
237 
238 	ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,
239 				      ab->acpi.tas_sar_power_table,
240 				      ATH12K_ACPI_DSM_TAS_DATA_SIZE);
241 	if (ret) {
242 		ath12k_warn(ab, "failed to send ACPI TAS data table parameter: %d\n",
243 			    ret);
244 		return ret;
245 	}
246 
247 	return 0;
248 }
249 
ath12k_acpi_start(struct ath12k_base * ab)250 int ath12k_acpi_start(struct ath12k_base *ab)
251 {
252 	acpi_status status;
253 	u8 *buf;
254 	int ret;
255 
256 	if (!ab->hw_params->acpi_guid)
257 		/* not supported with this hardware */
258 		return 0;
259 
260 	ab->acpi.acpi_tas_enable = false;
261 
262 	ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS);
263 	if (ret) {
264 		ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to get ACPI DSM data: %d\n", ret);
265 		return ret;
266 	}
267 
268 	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
269 		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_CFG);
270 		if (ret) {
271 			ath12k_warn(ab, "failed to get ACPI TAS config table: %d\n", ret);
272 			return ret;
273 		}
274 	}
275 
276 	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
277 		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);
278 		if (ret) {
279 			ath12k_warn(ab, "failed to get ACPI TAS data table: %d\n", ret);
280 			return ret;
281 		}
282 
283 		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
284 		    ab->acpi.tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
285 		    ab->acpi.tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE)
286 			ab->acpi.acpi_tas_enable = true;
287 	}
288 
289 	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
290 		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);
291 		if (ret) {
292 			ath12k_warn(ab, "failed to get ACPI bios sar data: %d\n", ret);
293 			return ret;
294 		}
295 	}
296 
297 	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
298 		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_GEO_OFFSET);
299 		if (ret) {
300 			ath12k_warn(ab, "failed to get ACPI geo offset data: %d\n", ret);
301 			return ret;
302 		}
303 
304 		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
305 		    ab->acpi.bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
306 		    ab->acpi.bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
307 		    !ab->acpi.acpi_tas_enable)
308 			ab->acpi.acpi_bios_sar_enable = true;
309 	}
310 
311 	if (ab->acpi.acpi_tas_enable) {
312 		ret = ath12k_acpi_set_tas_params(ab);
313 		if (ret) {
314 			ath12k_warn(ab, "failed to send ACPI parameters: %d\n", ret);
315 			return ret;
316 		}
317 	}
318 
319 	if (ab->acpi.acpi_bios_sar_enable) {
320 		ret = ath12k_acpi_set_bios_sar_params(ab);
321 		if (ret)
322 			return ret;
323 	}
324 
325 	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_CCA)) {
326 		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
327 		if (ret) {
328 			ath12k_warn(ab, "failed to get ACPI DSM CCA threshold configuration: %d\n",
329 				    ret);
330 			return ret;
331 		}
332 
333 		if (ab->acpi.cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
334 		    ab->acpi.cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
335 		    ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
336 			buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
337 			ret = ath12k_wmi_set_bios_cmd(ab,
338 						      WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE,
339 						      buf,
340 						      ATH12K_ACPI_CCA_THR_OFFSET_LEN);
341 			if (ret) {
342 				ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n",
343 					    ret);
344 				return ret;
345 			}
346 		}
347 	}
348 
349 	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi,
350 				       ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
351 		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
352 		if (ret) {
353 			ath12k_warn(ab, "failed to get ACPI DSM band edge channel power: %d\n",
354 				    ret);
355 			return ret;
356 		}
357 
358 		if (ab->acpi.band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
359 		    ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
360 			ret = ath12k_wmi_set_bios_cmd(ab,
361 						      WMI_BIOS_PARAM_TYPE_BANDEDGE,
362 						      ab->acpi.band_edge_power,
363 						      sizeof(ab->acpi.band_edge_power));
364 			if (ret) {
365 				ath12k_warn(ab,
366 					    "failed to set ACPI DSM band edge channel power: %d\n",
367 					    ret);
368 				return ret;
369 			}
370 		}
371 	}
372 
373 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
374 					     ACPI_DEVICE_NOTIFY,
375 					     ath12k_acpi_dsm_notify, ab);
376 	if (ACPI_FAILURE(status)) {
377 		ath12k_warn(ab, "failed to install DSM notify callback: %d\n", status);
378 		return -EIO;
379 	}
380 
381 	ab->acpi.started = true;
382 
383 	return 0;
384 }
385 
ath12k_acpi_stop(struct ath12k_base * ab)386 void ath12k_acpi_stop(struct ath12k_base *ab)
387 {
388 	if (!ab->acpi.started)
389 		return;
390 
391 	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
392 				   ACPI_DEVICE_NOTIFY,
393 				   ath12k_acpi_dsm_notify);
394 
395 	memset(&ab->acpi, 0, sizeof(ab->acpi));
396 }
397