Commit 209b2a68 authored by Bartosz Markowski's avatar Bartosz Markowski Committed by Kalle Valo

ath10k: add platform regulatory domain support

This overrides whatever regulatory the device
EEPROM contains and uses what the platform says
instead - in this implementation the ACPI driver.

In case the hint is not programmed or corrupted (0xffff)
the device falls back to the eeprom programmed settings.
Signed-off-by: default avatarBartosz Markowski <bartosz.markowski@tieto.com>
[kvalo@qca.qualcomm.com: remove ifdef, change error handling, change info messages to dbg]
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent d291d8e0
......@@ -713,6 +713,7 @@ struct ath10k {
u32 phy_capability;
u32 hw_min_tx_power;
u32 hw_max_tx_power;
u32 hw_eeprom_rd;
u32 ht_cap_info;
u32 vht_cap_info;
u32 num_rf_chains;
......
......@@ -19,6 +19,7 @@
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <linux/acpi.h>
#include "hif.h"
#include "core.h"
......@@ -3179,7 +3180,8 @@ static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif,
ath10k_mac_vif_tx_unlock(arvif, pause_id);
break;
default:
ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n",
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"received unknown tx pause action %d on vdev %i, ignoring\n",
action, arvif->vdev_id);
break;
}
......@@ -7789,6 +7791,109 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id)
return arvif_iter.arvif;
}
#define WRD_METHOD "WRDD"
#define WRDD_WIFI (0x07)
static u32 ath10k_mac_wrdd_get_mcc(struct ath10k *ar, union acpi_object *wrdd)
{
union acpi_object *mcc_pkg;
union acpi_object *domain_type;
union acpi_object *mcc_value;
u32 i;
if (wrdd->type != ACPI_TYPE_PACKAGE ||
wrdd->package.count < 2 ||
wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
wrdd->package.elements[0].integer.value != 0) {
ath10k_warn(ar, "ignoring malformed/unsupported wrdd structure\n");
return 0;
}
for (i = 1; i < wrdd->package.count; ++i) {
mcc_pkg = &wrdd->package.elements[i];
if (mcc_pkg->type != ACPI_TYPE_PACKAGE)
continue;
if (mcc_pkg->package.count < 2)
continue;
if (mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
continue;
domain_type = &mcc_pkg->package.elements[0];
if (domain_type->integer.value != WRDD_WIFI)
continue;
mcc_value = &mcc_pkg->package.elements[1];
return mcc_value->integer.value;
}
return 0;
}
static int ath10k_mac_get_wrdd_regulatory(struct ath10k *ar, u16 *rd)
{
struct pci_dev __maybe_unused *pdev = to_pci_dev(ar->dev);
acpi_handle root_handle;
acpi_handle handle;
struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_status status;
u32 alpha2_code;
char alpha2[3];
root_handle = ACPI_HANDLE(&pdev->dev);
if (!root_handle)
return -EOPNOTSUPP;
status = acpi_get_handle(root_handle, (acpi_string)WRD_METHOD, &handle);
if (ACPI_FAILURE(status)) {
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"failed to get wrd method %d\n", status);
return -EIO;
}
status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
if (ACPI_FAILURE(status)) {
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"failed to call wrdc %d\n", status);
return -EIO;
}
alpha2_code = ath10k_mac_wrdd_get_mcc(ar, wrdd.pointer);
kfree(wrdd.pointer);
if (!alpha2_code)
return -EIO;
alpha2[0] = (alpha2_code >> 8) & 0xff;
alpha2[1] = (alpha2_code >> 0) & 0xff;
alpha2[2] = '\0';
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"regulatory hint from WRDD (alpha2-code): %s\n", alpha2);
*rd = ath_regd_find_country_by_name(alpha2);
if (*rd == 0xffff)
return -EIO;
*rd |= COUNTRY_ERD_FLAG;
return 0;
}
static int ath10k_mac_init_rd(struct ath10k *ar)
{
int ret;
u16 rd;
ret = ath10k_mac_get_wrdd_regulatory(ar, &rd);
if (ret) {
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"fallback to eeprom programmed regulatory settings\n");
rd = ar->hw_eeprom_rd;
}
ar->ath_common.regulatory.current_rd = rd;
return 0;
}
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
......@@ -8012,6 +8117,12 @@ int ath10k_mac_register(struct ath10k *ar)
ar->running_fw->fw_file.fw_features))
ar->ops->wake_tx_queue = NULL;
ret = ath10k_mac_init_rd(ar);
if (ret) {
ath10k_err(ar, "failed to derive regdom: %d\n", ret);
goto err_dfs_detector_exit;
}
ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
ath10k_reg_notifier);
if (ret) {
......
......@@ -4676,7 +4676,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
ar->fw_version_build = (__le32_to_cpu(arg.sw_ver1) & 0x0000ffff);
ar->phy_capability = __le32_to_cpu(arg.phy_capab);
ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd);
ar->hw_eeprom_rd = __le32_to_cpu(arg.eeprom_rd);
ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
arg.service_map, arg.service_map_len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment