File Index
Files and directories
Sign in
FILE

acpi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/ath/ath12k/acpi.c C
  1// SPDX-License-Identifier: BSD-3-Clause-Clear
  2/*
  3 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
  4 * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
  5 */
  6
  7#include "core.h"
  8#include "acpi.h"
  9#include "debug.h"
 10
 11static 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, i;
 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		switch (func) {
 33		case ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS:
 34			ab->acpi.func_bit = obj->integer.value;
 35			break;
 36		case ATH12K_ACPI_DSM_FUNC_DISABLE_FLAG:
 37			ab->acpi.bit_flag = obj->integer.value;
 38			break;
 39		}
 40	} else if (obj->type == ACPI_TYPE_STRING) {
 41		switch (func) {
 42		case ATH12K_ACPI_DSM_FUNC_BDF_EXT:
 43			if (obj->string.length <= ATH12K_ACPI_BDF_ANCHOR_STRING_LEN ||
 44			    obj->string.length > ATH12K_ACPI_BDF_MAX_LEN ||
 45			    memcmp(obj->string.pointer, ATH12K_ACPI_BDF_ANCHOR_STRING,
 46				   ATH12K_ACPI_BDF_ANCHOR_STRING_LEN)) {
 47				ath12k_warn(ab, "invalid ACPI DSM BDF size: %d\n",
 48					    obj->string.length);
 49				ret = -EINVAL;
 50				goto out;
 51			}
 52
 53			memcpy(ab->acpi.bdf_string, obj->string.pointer,
 54			       obj->buffer.length);
 55
 56			break;
 57		}
 58	} else if (obj->type == ACPI_TYPE_BUFFER) {
 59		switch (func) {
 60		case ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS:
 61			if (obj->buffer.length < ATH12K_ACPI_DSM_FUNC_MIN_BITMAP_SIZE ||
 62			    obj->buffer.length > ATH12K_ACPI_DSM_FUNC_MAX_BITMAP_SIZE) {
 63				ath12k_warn(ab, "invalid ACPI DSM func size: %d\n",
 64					    obj->buffer.length);
 65				ret = -EINVAL;
 66				goto out;
 67			}
 68
 69			ab->acpi.func_bit = 0;
 70			for (i = 0; i < obj->buffer.length; i++)
 71				ab->acpi.func_bit += obj->buffer.pointer[i] << (i * 8);
 72
 73			break;
 74		case ATH12K_ACPI_DSM_FUNC_TAS_CFG:
 75			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
 76				ath12k_warn(ab, "invalid ACPI DSM TAS config size: %d\n",
 77					    obj->buffer.length);
 78				ret = -EINVAL;
 79				goto out;
 80			}
 81
 82			memcpy(&ab->acpi.tas_cfg, obj->buffer.pointer,
 83			       obj->buffer.length);
 84
 85			break;
 86		case ATH12K_ACPI_DSM_FUNC_TAS_DATA:
 87			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
 88				ath12k_warn(ab, "invalid ACPI DSM TAS data size: %d\n",
 89					    obj->buffer.length);
 90				ret = -EINVAL;
 91				goto out;
 92			}
 93
 94			memcpy(&ab->acpi.tas_sar_power_table, obj->buffer.pointer,
 95			       obj->buffer.length);
 96
 97			break;
 98		case ATH12K_ACPI_DSM_FUNC_BIOS_SAR:
 99			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
100				ath12k_warn(ab, "invalid ACPI BIOS SAR data size: %d\n",
101					    obj->buffer.length);
102				ret = -EINVAL;
103				goto out;
104			}
105
106			memcpy(&ab->acpi.bios_sar_data, obj->buffer.pointer,
107			       obj->buffer.length);
108
109			break;
110		case ATH12K_ACPI_DSM_FUNC_GEO_OFFSET:
111			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
112				ath12k_warn(ab, "invalid ACPI GEO OFFSET data size: %d\n",
113					    obj->buffer.length);
114				ret = -EINVAL;
115				goto out;
116			}
117
118			memcpy(&ab->acpi.geo_offset_data, obj->buffer.pointer,
119			       obj->buffer.length);
120
121			break;
122		case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
123			if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
124				ath12k_warn(ab, "invalid ACPI DSM CCA data size: %d\n",
125					    obj->buffer.length);
126				ret = -EINVAL;
127				goto out;
128			}
129
130			memcpy(&ab->acpi.cca_data, obj->buffer.pointer,
131			       obj->buffer.length);
132
133			break;
134		case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
135			if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
136				ath12k_warn(ab, "invalid ACPI DSM band edge data size: %d\n",
137					    obj->buffer.length);
138				ret = -EINVAL;
139				goto out;
140			}
141
142			memcpy(&ab->acpi.band_edge_power, obj->buffer.pointer,
143			       obj->buffer.length);
144
145			break;
146		}
147	} else {
148		ath12k_warn(ab, "ACPI DSM method returned an unsupported object type: %d\n",
149			    obj->type);
150		ret = -EINVAL;
151		goto out;
152	}
153
154	ret = 0;
155
156out:
157	ACPI_FREE(obj);
158	return ret;
159}
160
161static int ath12k_acpi_set_power_limit(struct ath12k_base *ab)
162{
163	const u8 *tas_sar_power_table = ab->acpi.tas_sar_power_table;
164	int ret;
165
166	if (tas_sar_power_table[0] != ATH12K_ACPI_TAS_DATA_VERSION ||
167	    tas_sar_power_table[1] != ATH12K_ACPI_TAS_DATA_ENABLE) {
168		ath12k_warn(ab, "latest ACPI TAS data is invalid\n");
169		return -EINVAL;
170	}
171
172	ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,
173				      tas_sar_power_table,
174				      ATH12K_ACPI_DSM_TAS_DATA_SIZE);
175	if (ret) {
176		ath12k_warn(ab, "failed to send ACPI TAS data table: %d\n", ret);
177		return ret;
178	}
179
180	return ret;
181}
182
183static int ath12k_acpi_set_bios_sar_power(struct ath12k_base *ab)
184{
185	int ret;
186
187	if (ab->acpi.bios_sar_data[0] != ATH12K_ACPI_POWER_LIMIT_VERSION ||
188	    ab->acpi.bios_sar_data[1] != ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
189		ath12k_warn(ab, "invalid latest ACPI BIOS SAR data\n");
190		return -EINVAL;
191	}
192
193	ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);
194	if (ret) {
195		ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);
196		return ret;
197	}
198
199	return 0;
200}
201
202static void ath12k_acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
203{
204	int ret;
205	struct ath12k_base *ab = data;
206
207	if (event == ATH12K_ACPI_NOTIFY_EVENT) {
208		ath12k_warn(ab, "unknown acpi notify %u\n", event);
209		return;
210	}
211
212	if (!ab->acpi.acpi_tas_enable) {
213		ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_tas_enable is false\n");
214		return;
215	}
216
217	ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);
218	if (ret) {
219		ath12k_warn(ab, "failed to update ACPI TAS data table: %d\n", ret);
220		return;
221	}
222
223	ret = ath12k_acpi_set_power_limit(ab);
224	if (ret) {
225		ath12k_warn(ab, "failed to set ACPI TAS power limit data: %d", ret);
226		return;
227	}
228
229	if (!ab->acpi.acpi_bios_sar_enable)
230		return;
231
232	ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);
233	if (ret) {
234		ath12k_warn(ab, "failed to update BIOS SAR: %d\n", ret);
235		return;
236	}
237
238	ret = ath12k_acpi_set_bios_sar_power(ab);
239	if (ret) {
240		ath12k_warn(ab, "failed to set BIOS SAR power limit: %d\n", ret);
241		return;
242	}
243}
244
245static int ath12k_acpi_set_bios_sar_params(struct ath12k_base *ab)
246{
247	int ret;
248
249	ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);
250	if (ret) {
251		ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);
252		return ret;
253	}
254
255	ret = ath12k_wmi_set_bios_geo_cmd(ab, ab->acpi.geo_offset_data);
256	if (ret) {
257		ath12k_warn(ab, "failed to set ACPI BIOS GEO table: %d\n", ret);
258		return ret;
259	}
260
261	return 0;
262}
263
264static int ath12k_acpi_set_tas_params(struct ath12k_base *ab)
265{
266	int ret;
267
268	ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_CONFIG_TYPE,
269				      ab->acpi.tas_cfg,
270				      ATH12K_ACPI_DSM_TAS_CFG_SIZE);
271	if (ret) {
272		ath12k_warn(ab, "failed to send ACPI TAS config table parameter: %d\n",
273			    ret);
274		return ret;
275	}
276
277	ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,
278				      ab->acpi.tas_sar_power_table,
279				      ATH12K_ACPI_DSM_TAS_DATA_SIZE);
280	if (ret) {
281		ath12k_warn(ab, "failed to send ACPI TAS data table parameter: %d\n",
282			    ret);
283		return ret;
284	}
285
286	return 0;
287}
288
289bool ath12k_acpi_get_disable_rfkill(struct ath12k_base *ab)
290{
291	return ab->acpi.acpi_disable_rfkill;
292}
293
294bool ath12k_acpi_get_disable_11be(struct ath12k_base *ab)
295{
296	return ab->acpi.acpi_disable_11be;
297}
298
299void ath12k_acpi_set_dsm_func(struct ath12k_base *ab)
300{
301	int ret;
302	u8 *buf;
303
304	if (!ab->hw_params->acpi_guid)
305		/* not supported with this hardware */
306		return;
307
308	if (ab->acpi.acpi_tas_enable) {
309		ret = ath12k_acpi_set_tas_params(ab);
310		if (ret) {
311			ath12k_warn(ab, "failed to send ACPI TAS parameters: %d\n", ret);
312			return;
313		}
314	}
315
316	if (ab->acpi.acpi_bios_sar_enable) {
317		ret = ath12k_acpi_set_bios_sar_params(ab);
318		if (ret) {
319			ath12k_warn(ab, "failed to send ACPI BIOS SAR: %d\n", ret);
320			return;
321		}
322	}
323
324	if (ab->acpi.acpi_cca_enable) {
325		buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
326		ret = ath12k_wmi_set_bios_cmd(ab,
327					      WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE,
328					      buf,
329					      ATH12K_ACPI_CCA_THR_OFFSET_LEN);
330		if (ret) {
331			ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n",
332				    ret);
333			return;
334		}
335	}
336
337	if (ab->acpi.acpi_band_edge_enable) {
338		ret = ath12k_wmi_set_bios_cmd(ab,
339					      WMI_BIOS_PARAM_TYPE_BANDEDGE,
340					      ab->acpi.band_edge_power,
341					      sizeof(ab->acpi.band_edge_power));
342		if (ret) {
343			ath12k_warn(ab,
344				    "failed to set ACPI DSM band edge channel power: %d\n",
345				    ret);
346			return;
347		}
348	}
349}
350
351int ath12k_acpi_start(struct ath12k_base *ab)
352{
353	acpi_status status;
354	int ret;
355
356	ab->acpi.acpi_tas_enable = false;
357	ab->acpi.acpi_disable_11be = false;
358	ab->acpi.acpi_disable_rfkill = false;
359	ab->acpi.acpi_bios_sar_enable = false;
360	ab->acpi.acpi_cca_enable = false;
361	ab->acpi.acpi_band_edge_enable = false;
362	ab->acpi.acpi_enable_bdf = false;
363	ab->acpi.bdf_string[0] = '\0';
364
365	if (!ab->hw_params->acpi_guid)
366		/* not supported with this hardware */
367		return 0;
368
369	ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS);
370	if (ret) {
371		ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to get ACPI DSM data: %d\n", ret);
372		return ret;
373	}
374
375	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_DISABLE_FLAG)) {
376		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_DISABLE_FLAG);
377		if (ret) {
378			ath12k_warn(ab, "failed to get ACPI DISABLE FLAG: %d\n", ret);
379			return ret;
380		}
381
382		if (ATH12K_ACPI_CHEK_BIT_VALID(ab->acpi,
383					       ATH12K_ACPI_DSM_DISABLE_11BE_BIT))
384			ab->acpi.acpi_disable_11be = true;
385
386		if (!ATH12K_ACPI_CHEK_BIT_VALID(ab->acpi,
387						ATH12K_ACPI_DSM_DISABLE_RFKILL_BIT))
388			ab->acpi.acpi_disable_rfkill = true;
389	}
390
391	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BDF_EXT)) {
392		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BDF_EXT);
393		if (ret || ab->acpi.bdf_string[0] == '\0') {
394			ath12k_warn(ab, "failed to get ACPI BDF EXT: %d\n", ret);
395			return ret;
396		}
397
398		ab->acpi.acpi_enable_bdf = true;
399	}
400
401	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
402		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_CFG);
403		if (ret) {
404			ath12k_warn(ab, "failed to get ACPI TAS config table: %d\n", ret);
405			return ret;
406		}
407	}
408
409	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
410		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);
411		if (ret) {
412			ath12k_warn(ab, "failed to get ACPI TAS data table: %d\n", ret);
413			return ret;
414		}
415
416		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
417		    ab->acpi.tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
418		    ab->acpi.tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE)
419			ab->acpi.acpi_tas_enable = true;
420	}
421
422	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
423		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);
424		if (ret) {
425			ath12k_warn(ab, "failed to get ACPI bios sar data: %d\n", ret);
426			return ret;
427		}
428	}
429
430	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
431		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_GEO_OFFSET);
432		if (ret) {
433			ath12k_warn(ab, "failed to get ACPI geo offset data: %d\n", ret);
434			return ret;
435		}
436
437		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
438		    ab->acpi.bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
439		    ab->acpi.bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
440		    !ab->acpi.acpi_tas_enable)
441			ab->acpi.acpi_bios_sar_enable = true;
442	}
443
444	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_CCA)) {
445		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
446		if (ret) {
447			ath12k_warn(ab, "failed to get ACPI DSM CCA threshold configuration: %d\n",
448				    ret);
449			return ret;
450		}
451
452		if (ab->acpi.cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
453		    ab->acpi.cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
454		    ATH12K_ACPI_CCA_THR_ENABLE_FLAG)
455			ab->acpi.acpi_cca_enable = true;
456	}
457
458	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi,
459				       ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
460		ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
461		if (ret) {
462			ath12k_warn(ab, "failed to get ACPI DSM band edge channel power: %d\n",
463				    ret);
464			return ret;
465		}
466
467		if (ab->acpi.band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
468		    ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG)
469			ab->acpi.acpi_band_edge_enable = true;
470	}
471
472	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
473					     ACPI_DEVICE_NOTIFY,
474					     ath12k_acpi_dsm_notify, ab);
475	if (ACPI_FAILURE(status)) {
476		ath12k_warn(ab, "failed to install DSM notify callback: %d\n", status);
477		return -EIO;
478	}
479
480	ab->acpi.started = true;
481
482	return 0;
483}
484
485int ath12k_acpi_check_bdf_variant_name(struct ath12k_base *ab)
486{
487	size_t max_len = sizeof(ab->qmi.target.bdf_ext);
488
489	if (!ab->acpi.acpi_enable_bdf)
490		return -ENODATA;
491
492	if (strscpy(ab->qmi.target.bdf_ext, ab->acpi.bdf_string + 4, max_len) < 0)
493		ath12k_dbg(ab, ATH12K_DBG_BOOT,
494			   "acpi bdf variant longer than the buffer (variant: %s)\n",
495			   ab->acpi.bdf_string);
496
497	return 0;
498}
499
500void ath12k_acpi_stop(struct ath12k_base *ab)
501{
502	if (!ab->acpi.started)
503		return;
504
505	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
506				   ACPI_DEVICE_NOTIFY,
507				   ath12k_acpi_dsm_notify);
508
509	memset(&ab->acpi, 0, sizeof(ab->acpi));
510}
~/ Read-only file preview.