Path: blob/main/sys/contrib/dev/athk/ath12k/acpi.c
178701 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.4*/56#include "core.h"7#include "acpi.h"8#include "debug.h"910static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)11{12union acpi_object *obj;13acpi_handle root_handle;14int ret, i;1516root_handle = ACPI_HANDLE(ab->dev);17if (!root_handle) {18ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid acpi handler\n");19return -EOPNOTSUPP;20}2122obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,23NULL);2425if (!obj) {26ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_evaluate_dsm() failed\n");27return -ENOENT;28}2930if (obj->type == ACPI_TYPE_INTEGER) {31switch (func) {32case ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS:33ab->acpi.func_bit = obj->integer.value;34break;35case ATH12K_ACPI_DSM_FUNC_DISABLE_FLAG:36ab->acpi.bit_flag = obj->integer.value;37break;38}39} else if (obj->type == ACPI_TYPE_STRING) {40switch (func) {41case ATH12K_ACPI_DSM_FUNC_BDF_EXT:42if (obj->string.length <= ATH12K_ACPI_BDF_ANCHOR_STRING_LEN ||43obj->string.length > ATH12K_ACPI_BDF_MAX_LEN ||44memcmp(obj->string.pointer, ATH12K_ACPI_BDF_ANCHOR_STRING,45ATH12K_ACPI_BDF_ANCHOR_STRING_LEN)) {46ath12k_warn(ab, "invalid ACPI DSM BDF size: %d\n",47obj->string.length);48ret = -EINVAL;49goto out;50}5152memcpy(ab->acpi.bdf_string, obj->string.pointer,53obj->buffer.length);5455break;56}57} else if (obj->type == ACPI_TYPE_BUFFER) {58switch (func) {59case ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS:60if (obj->buffer.length < ATH12K_ACPI_DSM_FUNC_MIN_BITMAP_SIZE ||61obj->buffer.length > ATH12K_ACPI_DSM_FUNC_MAX_BITMAP_SIZE) {62ath12k_warn(ab, "invalid ACPI DSM func size: %d\n",63obj->buffer.length);64ret = -EINVAL;65goto out;66}6768ab->acpi.func_bit = 0;69for (i = 0; i < obj->buffer.length; i++)70ab->acpi.func_bit += obj->buffer.pointer[i] << (i * 8);7172break;73case ATH12K_ACPI_DSM_FUNC_TAS_CFG:74if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {75ath12k_warn(ab, "invalid ACPI DSM TAS config size: %d\n",76obj->buffer.length);77ret = -EINVAL;78goto out;79}8081memcpy(&ab->acpi.tas_cfg, obj->buffer.pointer,82obj->buffer.length);8384break;85case ATH12K_ACPI_DSM_FUNC_TAS_DATA:86if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {87ath12k_warn(ab, "invalid ACPI DSM TAS data size: %d\n",88obj->buffer.length);89ret = -EINVAL;90goto out;91}9293memcpy(&ab->acpi.tas_sar_power_table, obj->buffer.pointer,94obj->buffer.length);9596break;97case ATH12K_ACPI_DSM_FUNC_BIOS_SAR:98if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {99ath12k_warn(ab, "invalid ACPI BIOS SAR data size: %d\n",100obj->buffer.length);101ret = -EINVAL;102goto out;103}104105memcpy(&ab->acpi.bios_sar_data, obj->buffer.pointer,106obj->buffer.length);107108break;109case ATH12K_ACPI_DSM_FUNC_GEO_OFFSET:110if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {111ath12k_warn(ab, "invalid ACPI GEO OFFSET data size: %d\n",112obj->buffer.length);113ret = -EINVAL;114goto out;115}116117memcpy(&ab->acpi.geo_offset_data, obj->buffer.pointer,118obj->buffer.length);119120break;121case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:122if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {123ath12k_warn(ab, "invalid ACPI DSM CCA data size: %d\n",124obj->buffer.length);125ret = -EINVAL;126goto out;127}128129memcpy(&ab->acpi.cca_data, obj->buffer.pointer,130obj->buffer.length);131132break;133case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:134if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {135ath12k_warn(ab, "invalid ACPI DSM band edge data size: %d\n",136obj->buffer.length);137ret = -EINVAL;138goto out;139}140141memcpy(&ab->acpi.band_edge_power, obj->buffer.pointer,142obj->buffer.length);143144break;145}146} else {147ath12k_warn(ab, "ACPI DSM method returned an unsupported object type: %d\n",148obj->type);149ret = -EINVAL;150goto out;151}152153ret = 0;154155out:156ACPI_FREE(obj);157return ret;158}159160static int ath12k_acpi_set_power_limit(struct ath12k_base *ab)161{162const u8 *tas_sar_power_table = ab->acpi.tas_sar_power_table;163int ret;164165if (tas_sar_power_table[0] != ATH12K_ACPI_TAS_DATA_VERSION ||166tas_sar_power_table[1] != ATH12K_ACPI_TAS_DATA_ENABLE) {167ath12k_warn(ab, "latest ACPI TAS data is invalid\n");168return -EINVAL;169}170171ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,172tas_sar_power_table,173ATH12K_ACPI_DSM_TAS_DATA_SIZE);174if (ret) {175ath12k_warn(ab, "failed to send ACPI TAS data table: %d\n", ret);176return ret;177}178179return ret;180}181182static int ath12k_acpi_set_bios_sar_power(struct ath12k_base *ab)183{184int ret;185186if (ab->acpi.bios_sar_data[0] != ATH12K_ACPI_POWER_LIMIT_VERSION ||187ab->acpi.bios_sar_data[1] != ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {188ath12k_warn(ab, "invalid latest ACPI BIOS SAR data\n");189return -EINVAL;190}191192ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);193if (ret) {194ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);195return ret;196}197198return 0;199}200201static void ath12k_acpi_dsm_notify(acpi_handle handle, u32 event, void *data)202{203int ret;204struct ath12k_base *ab = data;205206if (event == ATH12K_ACPI_NOTIFY_EVENT) {207ath12k_warn(ab, "unknown acpi notify %u\n", event);208return;209}210211if (!ab->acpi.acpi_tas_enable) {212ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_tas_enable is false\n");213return;214}215216ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);217if (ret) {218ath12k_warn(ab, "failed to update ACPI TAS data table: %d\n", ret);219return;220}221222ret = ath12k_acpi_set_power_limit(ab);223if (ret) {224ath12k_warn(ab, "failed to set ACPI TAS power limit data: %d", ret);225return;226}227228if (!ab->acpi.acpi_bios_sar_enable)229return;230231ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);232if (ret) {233ath12k_warn(ab, "failed to update BIOS SAR: %d\n", ret);234return;235}236237ret = ath12k_acpi_set_bios_sar_power(ab);238if (ret) {239ath12k_warn(ab, "failed to set BIOS SAR power limit: %d\n", ret);240return;241}242}243244static int ath12k_acpi_set_bios_sar_params(struct ath12k_base *ab)245{246int ret;247248ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);249if (ret) {250ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);251return ret;252}253254ret = ath12k_wmi_set_bios_geo_cmd(ab, ab->acpi.geo_offset_data);255if (ret) {256ath12k_warn(ab, "failed to set ACPI BIOS GEO table: %d\n", ret);257return ret;258}259260return 0;261}262263static int ath12k_acpi_set_tas_params(struct ath12k_base *ab)264{265int ret;266267ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_CONFIG_TYPE,268ab->acpi.tas_cfg,269ATH12K_ACPI_DSM_TAS_CFG_SIZE);270if (ret) {271ath12k_warn(ab, "failed to send ACPI TAS config table parameter: %d\n",272ret);273return ret;274}275276ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,277ab->acpi.tas_sar_power_table,278ATH12K_ACPI_DSM_TAS_DATA_SIZE);279if (ret) {280ath12k_warn(ab, "failed to send ACPI TAS data table parameter: %d\n",281ret);282return ret;283}284285return 0;286}287288bool ath12k_acpi_get_disable_rfkill(struct ath12k_base *ab)289{290return ab->acpi.acpi_disable_rfkill;291}292293bool ath12k_acpi_get_disable_11be(struct ath12k_base *ab)294{295return ab->acpi.acpi_disable_11be;296}297298void ath12k_acpi_set_dsm_func(struct ath12k_base *ab)299{300int ret;301u8 *buf;302303if (!ab->hw_params->acpi_guid)304/* not supported with this hardware */305return;306307if (ab->acpi.acpi_tas_enable) {308ret = ath12k_acpi_set_tas_params(ab);309if (ret) {310ath12k_warn(ab, "failed to send ACPI TAS parameters: %d\n", ret);311return;312}313}314315if (ab->acpi.acpi_bios_sar_enable) {316ret = ath12k_acpi_set_bios_sar_params(ab);317if (ret) {318ath12k_warn(ab, "failed to send ACPI BIOS SAR: %d\n", ret);319return;320}321}322323if (ab->acpi.acpi_cca_enable) {324buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;325ret = ath12k_wmi_set_bios_cmd(ab,326WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE,327buf,328ATH12K_ACPI_CCA_THR_OFFSET_LEN);329if (ret) {330ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n",331ret);332return;333}334}335336if (ab->acpi.acpi_band_edge_enable) {337ret = ath12k_wmi_set_bios_cmd(ab,338WMI_BIOS_PARAM_TYPE_BANDEDGE,339ab->acpi.band_edge_power,340sizeof(ab->acpi.band_edge_power));341if (ret) {342ath12k_warn(ab,343"failed to set ACPI DSM band edge channel power: %d\n",344ret);345return;346}347}348}349350int ath12k_acpi_start(struct ath12k_base *ab)351{352acpi_status status;353int ret;354355ab->acpi.acpi_tas_enable = false;356ab->acpi.acpi_disable_11be = false;357ab->acpi.acpi_disable_rfkill = false;358ab->acpi.acpi_bios_sar_enable = false;359ab->acpi.acpi_cca_enable = false;360ab->acpi.acpi_band_edge_enable = false;361ab->acpi.acpi_enable_bdf = false;362ab->acpi.bdf_string[0] = '\0';363364if (!ab->hw_params->acpi_guid)365/* not supported with this hardware */366return 0;367368ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS);369if (ret) {370ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to get ACPI DSM data: %d\n", ret);371return ret;372}373374if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_DISABLE_FLAG)) {375ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_DISABLE_FLAG);376if (ret) {377ath12k_warn(ab, "failed to get ACPI DISABLE FLAG: %d\n", ret);378return ret;379}380381if (ATH12K_ACPI_CHEK_BIT_VALID(ab->acpi,382ATH12K_ACPI_DSM_DISABLE_11BE_BIT))383ab->acpi.acpi_disable_11be = true;384385if (!ATH12K_ACPI_CHEK_BIT_VALID(ab->acpi,386ATH12K_ACPI_DSM_DISABLE_RFKILL_BIT))387ab->acpi.acpi_disable_rfkill = true;388}389390if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BDF_EXT)) {391ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BDF_EXT);392if (ret || ab->acpi.bdf_string[0] == '\0') {393ath12k_warn(ab, "failed to get ACPI BDF EXT: %d\n", ret);394return ret;395}396397ab->acpi.acpi_enable_bdf = true;398}399400if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {401ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_CFG);402if (ret) {403ath12k_warn(ab, "failed to get ACPI TAS config table: %d\n", ret);404return ret;405}406}407408if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {409ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);410if (ret) {411ath12k_warn(ab, "failed to get ACPI TAS data table: %d\n", ret);412return ret;413}414415if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&416ab->acpi.tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&417ab->acpi.tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE)418ab->acpi.acpi_tas_enable = true;419}420421if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {422ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);423if (ret) {424ath12k_warn(ab, "failed to get ACPI bios sar data: %d\n", ret);425return ret;426}427}428429if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {430ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_GEO_OFFSET);431if (ret) {432ath12k_warn(ab, "failed to get ACPI geo offset data: %d\n", ret);433return ret;434}435436if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&437ab->acpi.bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&438ab->acpi.bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&439!ab->acpi.acpi_tas_enable)440ab->acpi.acpi_bios_sar_enable = true;441}442443if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_CCA)) {444ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_CCA);445if (ret) {446ath12k_warn(ab, "failed to get ACPI DSM CCA threshold configuration: %d\n",447ret);448return ret;449}450451if (ab->acpi.cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&452ab->acpi.cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==453ATH12K_ACPI_CCA_THR_ENABLE_FLAG)454ab->acpi.acpi_cca_enable = true;455}456457if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi,458ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {459ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);460if (ret) {461ath12k_warn(ab, "failed to get ACPI DSM band edge channel power: %d\n",462ret);463return ret;464}465466if (ab->acpi.band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&467ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG)468ab->acpi.acpi_band_edge_enable = true;469}470471status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),472ACPI_DEVICE_NOTIFY,473ath12k_acpi_dsm_notify, ab);474if (ACPI_FAILURE(status)) {475ath12k_warn(ab, "failed to install DSM notify callback: %d\n", status);476return -EIO;477}478479ab->acpi.started = true;480481return 0;482}483484int ath12k_acpi_check_bdf_variant_name(struct ath12k_base *ab)485{486size_t max_len = sizeof(ab->qmi.target.bdf_ext);487488if (!ab->acpi.acpi_enable_bdf)489return -ENODATA;490491if (strscpy(ab->qmi.target.bdf_ext, ab->acpi.bdf_string + 4, max_len) < 0)492ath12k_dbg(ab, ATH12K_DBG_BOOT,493"acpi bdf variant longer than the buffer (variant: %s)\n",494ab->acpi.bdf_string);495496return 0;497}498499void ath12k_acpi_stop(struct ath12k_base *ab)500{501if (!ab->acpi.started)502return;503504acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),505ACPI_DEVICE_NOTIFY,506ath12k_acpi_dsm_notify);507508memset(&ab->acpi, 0, sizeof(ab->acpi));509}510511512