Commit 9457077d authored by Abhishek Naik's avatar Abhishek Naik Committed by Johannes Berg

wifi: iwlwifi: mvm: Add debugfs to get TAS status

Add debugfs file in mvm to retrieve TAS status per LMAC,
TAS block list, current mcc, OEM name and OEM allowed list.
Signed-off-by: default avatarAbhishek Naik <abhishek.naik@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230320122330.8efc8c41efae.I94e1a6efb9c33e2cdbcf4bf3ed2384005397dee9@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent cf85123a
...@@ -42,6 +42,12 @@ enum iwl_debug_cmds { ...@@ -42,6 +42,12 @@ enum iwl_debug_cmds {
* &struct iwl_buf_alloc_cmd * &struct iwl_buf_alloc_cmd
*/ */
BUFFER_ALLOCATION = 0x8, BUFFER_ALLOCATION = 0x8,
/**
* @GET_TAS_STATUS:
* sends command to fw to get TAS status
* the response is &struct iwl_mvm_tas_status_resp
*/
GET_TAS_STATUS = 0xA,
/** /**
* @FW_DUMP_COMPLETE_CMD: * @FW_DUMP_COMPLETE_CMD:
* sends command to fw once dump collection completed * sends command to fw once dump collection completed
...@@ -421,4 +427,94 @@ struct iwl_dbg_dump_complete_cmd { ...@@ -421,4 +427,94 @@ struct iwl_dbg_dump_complete_cmd {
__le32 tp_data; __le32 tp_data;
} __packed; /* FW_DUMP_COMPLETE_CMD_API_S_VER_1 */ } __packed; /* FW_DUMP_COMPLETE_CMD_API_S_VER_1 */
#define TAS_LMAC_BAND_HB 0
#define TAS_LMAC_BAND_LB 1
#define TAS_LMAC_BAND_UHB 2
#define TAS_LMAC_BAND_INVALID 3
/**
* struct iwl_mvm_tas_status_per_mac - tas status per lmac
* @static_status: tas statically enabled or disabled per lmac - TRUE/FALSE
* @static_dis_reason: TAS static disable reason, uses
* &enum iwl_mvm_tas_statically_disabled_reason
* @dynamic_status: Current TAS status. uses
* &enum iwl_mvm_tas_dyna_status
* @near_disconnection: is TAS currently near disconnection per lmac? - TRUE/FALSE
* @max_reg_pwr_limit: Regulatory power limits in dBm
* @sar_limit: SAR limits per lmac in dBm
* @band: Band per lmac
* @reserved: reserved
*/
struct iwl_mvm_tas_status_per_mac {
u8 static_status;
u8 static_dis_reason;
u8 dynamic_status;
u8 near_disconnection;
__le16 max_reg_pwr_limit;
__le16 sar_limit;
u8 band;
u8 reserved[3];
} __packed; /*DEBUG_GET_TAS_STATUS_PER_MAC_S_VER_1*/
/**
* struct iwl_mvm_tas_status_resp - Response to GET_TAS_STATUS
* @tas_fw_version: TAS FW version
* @is_uhb_for_usa_enable: is UHB enabled in USA? - TRUE/FALSE
* @curr_mcc: current mcc
* @block_list: country block list
* @tas_status_mac: TAS status per lmac, uses
* &struct iwl_mvm_tas_status_per_mac
* @in_dual_radio: is TAS in dual radio? - TRUE/FALSE
* @reserved: reserved
*/
struct iwl_mvm_tas_status_resp {
u8 tas_fw_version;
u8 is_uhb_for_usa_enable;
__le16 curr_mcc;
__le16 block_list[16];
struct iwl_mvm_tas_status_per_mac tas_status_mac[2];
u8 in_dual_radio;
u8 reserved[3];
} __packed; /*DEBUG_GET_TAS_STATUS_RSP_API_S_VER_3*/
/**
* enum iwl_mvm_tas_dyna_status - TAS current running status
* @TAS_DYNA_INACTIVE: TAS status is inactive
* @TAS_DYNA_INACTIVE_MVM_MODE: TAS is disabled due because FW is in MVM mode
* or is in softap mode.
* @TAS_DYNA_INACTIVE_TRIGGER_MODE: TAS is disabled because FW is in
* multi user trigger mode
* @TAS_DYNA_INACTIVE_BLOCK_LISTED: TAS is disabled because current mcc
* is blocklisted mcc
* @TAS_DYNA_INACTIVE_UHB_NON_US: TAS is disabled because current band is UHB
* and current mcc is USA
* @TAS_DYNA_ACTIVE: TAS is currently active
* @TAS_DYNA_STATUS_MAX: TAS status max value
*/
enum iwl_mvm_tas_dyna_status {
TAS_DYNA_INACTIVE,
TAS_DYNA_INACTIVE_MVM_MODE,
TAS_DYNA_INACTIVE_TRIGGER_MODE,
TAS_DYNA_INACTIVE_BLOCK_LISTED,
TAS_DYNA_INACTIVE_UHB_NON_US,
TAS_DYNA_ACTIVE,
TAS_DYNA_STATUS_MAX,
}; /*_TAS_DYNA_STATUS_E*/
/**
* enum iwl_mvm_tas_statically_disabled_reason - TAS statically disabled reason
* @TAS_DISABLED_DUE_TO_BIOS: TAS is disabled because TAS is disabled in BIOS
* @TAS_DISABLED_DUE_TO_SAR_6DBM: TAS is disabled because SAR limit is less than 6 Dbm
* @TAS_DISABLED_REASON_INVALID: TAS disable reason is invalid
* @TAS_DISABLED_REASON_MAX: TAS disable reason max value
*/
enum iwl_mvm_tas_statically_disabled_reason {
TAS_DISABLED_DUE_TO_BIOS,
TAS_DISABLED_DUE_TO_SAR_6DBM,
TAS_DISABLED_REASON_INVALID,
TAS_DISABLED_REASON_MAX,
}; /*_TAS_STATICALLY_DISABLED_REASON_E*/
#endif /* __iwl_fw_api_debug_h__ */ #endif /* __iwl_fw_api_debug_h__ */
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* /*
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH
*/ */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/dmi.h>
#include "mvm.h" #include "mvm.h"
#include "sta.h" #include "sta.h"
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
#include "debugfs.h" #include "debugfs.h"
#include "iwl-modparams.h" #include "iwl-modparams.h"
#include "fw/error-dump.h" #include "fw/error-dump.h"
#include "fw/api/phy-ctxt.h"
static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
char __user *user_buf, char __user *user_buf,
...@@ -714,6 +716,190 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, ...@@ -714,6 +716,190 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf,
return ret; return ret;
} }
static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
struct iwl_mvm_tas_status_resp tas_rsp;
struct iwl_mvm_tas_status_resp *rsp = &tas_rsp;
static const size_t bufsz = 1024;
char *buff, *pos, *endpos;
const char * const tas_dis_reason[TAS_DISABLED_REASON_MAX] = {
[TAS_DISABLED_DUE_TO_BIOS] =
"Due To BIOS",
[TAS_DISABLED_DUE_TO_SAR_6DBM] =
"Due To SAR Limit Less Than 6 dBm",
[TAS_DISABLED_REASON_INVALID] =
"N/A",
};
const char * const tas_current_status[TAS_DYNA_STATUS_MAX] = {
[TAS_DYNA_INACTIVE] = "INACTIVE",
[TAS_DYNA_INACTIVE_MVM_MODE] =
"inactive due to mvm mode",
[TAS_DYNA_INACTIVE_TRIGGER_MODE] =
"inactive due to trigger mode",
[TAS_DYNA_INACTIVE_BLOCK_LISTED] =
"inactive due to block listed",
[TAS_DYNA_INACTIVE_UHB_NON_US] =
"inactive due to uhb non US",
[TAS_DYNA_ACTIVE] = "ACTIVE",
};
struct iwl_host_cmd hcmd = {
.id = WIDE_ID(DEBUG_GROUP, GET_TAS_STATUS),
.flags = CMD_WANT_SKB,
.len = { 0, },
.data = { NULL, },
};
int ret, i, tmp;
bool tas_enabled = false;
unsigned long dyn_status;
if (!iwl_mvm_firmware_running(mvm))
return -ENODEV;
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd(mvm, &hcmd);
mutex_unlock(&mvm->mutex);
if (ret < 0)
return ret;
buff = kzalloc(bufsz, GFP_KERNEL);
if (!buff)
return -ENOMEM;
pos = buff;
endpos = pos + bufsz;
rsp = (void *)hcmd.resp_pkt->data;
pos += scnprintf(pos, endpos - pos, "TAS Conclusion:\n");
for (i = 0; i < rsp->in_dual_radio + 1; i++) {
if (rsp->tas_status_mac[i].band != TAS_LMAC_BAND_INVALID &&
rsp->tas_status_mac[i].dynamic_status & BIT(TAS_DYNA_ACTIVE)) {
pos += scnprintf(pos, endpos - pos, "\tON for ");
switch (rsp->tas_status_mac[i].band) {
case TAS_LMAC_BAND_HB:
pos += scnprintf(pos, endpos - pos, "HB\n");
break;
case TAS_LMAC_BAND_LB:
pos += scnprintf(pos, endpos - pos, "LB\n");
break;
case TAS_LMAC_BAND_UHB:
pos += scnprintf(pos, endpos - pos, "UHB\n");
break;
case TAS_LMAC_BAND_INVALID:
pos += scnprintf(pos, endpos - pos,
"INVALID BAND\n");
break;
default:
pos += scnprintf(pos, endpos - pos,
"Unsupported band (%d)\n",
rsp->tas_status_mac[i].band);
goto out;
}
tas_enabled = true;
}
}
if (!tas_enabled)
pos += scnprintf(pos, endpos - pos, "\tOFF\n");
pos += scnprintf(pos, endpos - pos, "TAS Report\n");
pos += scnprintf(pos, endpos - pos, "TAS FW version: %d\n",
rsp->tas_fw_version);
pos += scnprintf(pos, endpos - pos, "Is UHB enabled for USA?: %s\n",
rsp->is_uhb_for_usa_enable ? "True" : "False");
pos += scnprintf(pos, endpos - pos, "Current MCC: 0x%x\n",
le16_to_cpu(rsp->curr_mcc));
pos += scnprintf(pos, endpos - pos, "Block list entries:");
for (i = 0; i < APCI_WTAS_BLACK_LIST_MAX; i++)
pos += scnprintf(pos, endpos - pos, " 0x%x",
le16_to_cpu(rsp->block_list[i]));
pos += scnprintf(pos, endpos - pos, "\nOEM name: %s\n",
dmi_get_system_info(DMI_SYS_VENDOR));
pos += scnprintf(pos, endpos - pos, "\tVendor In Approved List: %s\n",
iwl_mvm_is_vendor_in_approved_list() ? "YES" : "NO");
pos += scnprintf(pos, endpos - pos,
"\tDo TAS Support Dual Radio?: %s\n",
rsp->in_dual_radio ? "TRUE" : "FALSE");
for (i = 0; i < rsp->in_dual_radio + 1; i++) {
if (rsp->tas_status_mac[i].static_status == 0) {
pos += scnprintf(pos, endpos - pos,
"Static status: disabled\n");
pos += scnprintf(pos, endpos - pos,
"Static disabled reason: %s (0)\n",
tas_dis_reason[0]);
goto out;
}
pos += scnprintf(pos, endpos - pos, "TAS status for ");
switch (rsp->tas_status_mac[i].band) {
case TAS_LMAC_BAND_HB:
pos += scnprintf(pos, endpos - pos, "High band\n");
break;
case TAS_LMAC_BAND_LB:
pos += scnprintf(pos, endpos - pos, "Low band\n");
break;
case TAS_LMAC_BAND_UHB:
pos += scnprintf(pos, endpos - pos,
"Ultra high band\n");
break;
case TAS_LMAC_BAND_INVALID:
pos += scnprintf(pos, endpos - pos,
"INVALID band\n");
break;
default:
pos += scnprintf(pos, endpos - pos,
"Unsupported band (%d)\n",
rsp->tas_status_mac[i].band);
goto out;
}
pos += scnprintf(pos, endpos - pos, "Static status: %sabled\n",
rsp->tas_status_mac[i].static_status ?
"En" : "Dis");
pos += scnprintf(pos, endpos - pos,
"\tStatic Disabled Reason: ");
if (rsp->tas_status_mac[i].static_dis_reason < TAS_DISABLED_REASON_MAX)
pos += scnprintf(pos, endpos - pos, "%s (%d)\n",
tas_dis_reason[rsp->tas_status_mac[i].static_dis_reason],
rsp->tas_status_mac[i].static_dis_reason);
else
pos += scnprintf(pos, endpos - pos,
"unsupported value (%d)\n",
rsp->tas_status_mac[i].static_dis_reason);
pos += scnprintf(pos, endpos - pos, "Dynamic status:\n");
dyn_status = (rsp->tas_status_mac[i].dynamic_status);
for_each_set_bit(tmp, &dyn_status, sizeof(dyn_status)) {
if (tmp >= 0 && tmp < TAS_DYNA_STATUS_MAX)
pos += scnprintf(pos, endpos - pos,
"\t%s (%d)\n",
tas_current_status[tmp], tmp);
}
pos += scnprintf(pos, endpos - pos,
"Is near disconnection?: %s\n",
rsp->tas_status_mac[i].near_disconnection ?
"True" : "False");
tmp = le16_to_cpu(rsp->tas_status_mac[i].max_reg_pwr_limit);
pos += scnprintf(pos, endpos - pos,
"Max. regulatory pwr limit (dBm): %d.%03d\n",
tmp / 8, 125 * (tmp % 8));
tmp = le16_to_cpu(rsp->tas_status_mac[i].sar_limit);
pos += scnprintf(pos, endpos - pos,
"SAR limit (dBm): %d.%03d\n",
tmp / 8, 125 * (tmp % 8));
}
out:
ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
kfree(buff);
iwl_free_resp(&hcmd);
return ret;
}
static ssize_t iwl_dbgfs_phy_integration_ver_read(struct file *file, static ssize_t iwl_dbgfs_phy_integration_ver_read(struct file *file,
char __user *user_buf, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
...@@ -1685,6 +1871,7 @@ MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); ...@@ -1685,6 +1871,7 @@ MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
MVM_DEBUGFS_READ_FILE_OPS(fw_ver); MVM_DEBUGFS_READ_FILE_OPS(fw_ver);
MVM_DEBUGFS_READ_FILE_OPS(phy_integration_ver); MVM_DEBUGFS_READ_FILE_OPS(phy_integration_ver);
MVM_DEBUGFS_READ_FILE_OPS(tas_get_status);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
...@@ -1894,6 +2081,7 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) ...@@ -1894,6 +2081,7 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)
if (mvm->fw->phy_integration_ver) if (mvm->fw->phy_integration_ver)
MVM_DEBUGFS_ADD_FILE(phy_integration_ver, mvm->debugfs_dir, 0400); MVM_DEBUGFS_ADD_FILE(phy_integration_ver, mvm->debugfs_dir, 0400);
MVM_DEBUGFS_ADD_FILE(tas_get_status, mvm->debugfs_dir, 0400);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
MVM_DEBUGFS_ADD_FILE(sar_geo_profile, mvm->debugfs_dir, 0400); MVM_DEBUGFS_ADD_FILE(sar_geo_profile, mvm->debugfs_dir, 0400);
#endif #endif
......
...@@ -1092,6 +1092,11 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { ...@@ -1092,6 +1092,11 @@ static const struct dmi_system_id dmi_tas_approved_list[] = {
{} {}
}; };
bool iwl_mvm_is_vendor_in_approved_list(void)
{
return dmi_check_system(dmi_tas_approved_list);
}
static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc) static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc)
{ {
int i; int i;
...@@ -1371,6 +1376,11 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) ...@@ -1371,6 +1376,11 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
{ {
} }
bool iwl_mvm_is_vendor_in_approved_list(void)
{
return false;
}
static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
{ {
return DSM_VALUE_RFI_DISABLE; return DSM_VALUE_RFI_DISABLE;
......
...@@ -2343,5 +2343,5 @@ static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm) ...@@ -2343,5 +2343,5 @@ static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)
void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm, void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
bool forbidden); bool forbidden);
bool iwl_mvm_is_vendor_in_approved_list(void);
#endif /* __IWL_MVM_H__ */ #endif /* __IWL_MVM_H__ */
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