Skip to content

Commit

Permalink
wifi: iwlwifi: mvm: Add debugfs to get TAS status
Browse files Browse the repository at this point in the history
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: Abhishek Naik <abhishek.naik@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230320122330.8efc8c41efae.I94e1a6efb9c33e2cdbcf4bf3ed2384005397dee9@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
Abhishek Naik authored and Johannes Berg committed Mar 22, 2023
1 parent cf85123 commit 9457077
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 2 deletions.
96 changes: 96 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ enum iwl_debug_cmds {
* &struct iwl_buf_alloc_cmd
*/
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:
* sends command to fw once dump collection completed
Expand Down Expand Up @@ -421,4 +427,94 @@ struct iwl_dbg_dump_complete_cmd {
__le32 tp_data;
} __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__ */
190 changes: 189 additions & 1 deletion drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
// 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) 2016-2017 Intel Deutschland GmbH
*/
#include <linux/vmalloc.h>
#include <linux/err.h>
#include <linux/ieee80211.h>
#include <linux/netdevice.h>
#include <linux/dmi.h>

#include "mvm.h"
#include "sta.h"
#include "iwl-io.h"
#include "debugfs.h"
#include "iwl-modparams.h"
#include "fw/error-dump.h"
#include "fw/api/phy-ctxt.h"

static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
char __user *user_buf,
Expand Down Expand Up @@ -714,6 +716,190 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf,
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,
char __user *user_buf,
size_t count, loff_t *ppos)
Expand Down Expand Up @@ -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(fw_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_nmi, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
Expand Down Expand Up @@ -1894,6 +2081,7 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)

if (mvm->fw->phy_integration_ver)
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
MVM_DEBUGFS_ADD_FILE(sar_geo_profile, mvm->debugfs_dir, 0400);
#endif
Expand Down
10 changes: 10 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/mvm/fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
int i;
Expand Down Expand Up @@ -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)
{
return DSM_VALUE_RFI_DISABLE;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct ieee80211_vif *vif,
bool forbidden);

bool iwl_mvm_is_vendor_in_approved_list(void);
#endif /* __IWL_MVM_H__ */

0 comments on commit 9457077

Please sign in to comment.