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: Bartosz Markowski <bartosz.markowski@tieto.com> [kvalo@qca.qualcomm.com: remove ifdef, change error handling, change info messages to dbg] Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
d291d8e059
commit
209b2a68de
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user