Commit bc64d052 authored by Maharaja Kennadyrajan's avatar Maharaja Kennadyrajan Committed by Kalle Valo

ath10k: debugfs support to get final TPC stats for 10.4 variants

Export the final Transmit Power Control (TPC) value, which is the
minimum of control power and existing TPC value to user space via
a new debugfs file "tpc_stats_final" to help with debugging.
It works with the new wmi cmd and event introduced in 10.4 firmware
branch.

WMI command ID: WMI_PDEV_GET_TPC_TABLE_CMDID
WMI event ID: WMI_PDEV_TPC_TABLE_EVENTID

cat /sys/kernel/debug/ieee80211/phyX/ath10k/tpc_stats_final

$ cat /sys/kernel/debug/ieee80211/phyX/ath10k/tpc_stats_final

TPC config for channel 5180 mode 10

CTL             =  0x 0 Reg. Domain             = 58
Antenna Gain    =  0 Reg. Max Antenna Gain      =   0
Power Limit     = 60 Reg. Max Power             = 60
Num tx chains   =  2 Num supported rates        = 109

******************* CDD POWER TABLE ****************

No.  Preamble Rate_code tpc_value1 tpc_value2 tpc_value3
0    CCK      0x40        0          0
1    CCK      0x41        0          0
[...]
107  HTCUP    0x 0       46          46
108  HTCUP    0x 0       46          46

******************* STBC POWER TABLE ****************

No.  Preamble Rate_code tpc_value1 tpc_value2 tpc_value3
0    CCK      0x40        0          0
1    CCK      0x41        0          0
[...]
107  HTCUP    0x 0        46         46
108  HTCUP    0x 0        46         46

***********************************
TXBF not supported
**********************************

The existing tpc_stats debugfs file provides the dump
which is minimum of target power and regulatory domain.

cat /sys/kernel/debug/ieee80211/phyX/ath10k/tpc_stats

Hardware_used: QCA4019
Firmware version: firmware-5.bin_10.4-3.0-00209
Signed-off-by: default avatarMaharaja Kennadyrajan <mkenna@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent caee728a
...@@ -325,6 +325,27 @@ struct ath10k_tpc_stats { ...@@ -325,6 +325,27 @@ struct ath10k_tpc_stats {
struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG]; struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG];
}; };
struct ath10k_tpc_table_final {
u32 pream_idx[WMI_TPC_FINAL_RATE_MAX];
u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
char tpc_value[WMI_TPC_FINAL_RATE_MAX][WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
};
struct ath10k_tpc_stats_final {
u32 reg_domain;
u32 chan_freq;
u32 phy_mode;
u32 twice_antenna_reduction;
u32 twice_max_rd_power;
s32 twice_antenna_gain;
u32 power_limit;
u32 num_tx_chain;
u32 ctl;
u32 rate_max;
u8 flag[WMI_TPC_FLAG];
struct ath10k_tpc_table_final tpc_table_final[WMI_TPC_FLAG];
};
struct ath10k_dfs_stats { struct ath10k_dfs_stats {
u32 phy_errors; u32 phy_errors;
u32 pulses_total; u32 pulses_total;
...@@ -530,6 +551,7 @@ struct ath10k_debug { ...@@ -530,6 +551,7 @@ struct ath10k_debug {
/* used for tpc-dump storage, protected by data-lock */ /* used for tpc-dump storage, protected by data-lock */
struct ath10k_tpc_stats *tpc_stats; struct ath10k_tpc_stats *tpc_stats;
struct ath10k_tpc_stats_final *tpc_stats_final;
struct completion tpc_complete; struct completion tpc_complete;
......
...@@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar, ...@@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar,
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
} }
void
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
struct ath10k_tpc_stats_final *tpc_stats)
{
spin_lock_bh(&ar->data_lock);
kfree(ar->debug.tpc_stats_final);
ar->debug.tpc_stats_final = tpc_stats;
complete(&ar->debug.tpc_complete);
spin_unlock_bh(&ar->data_lock);
}
static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
unsigned int j, char *buf, size_t *len) unsigned int j, char *buf, size_t *len)
{ {
...@@ -2185,6 +2198,95 @@ static const struct file_operations fops_sta_tid_stats_mask = { ...@@ -2185,6 +2198,95 @@ static const struct file_operations fops_sta_tid_stats_mask = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar)
{
int ret;
unsigned long time_left;
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->debug.tpc_complete);
ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM);
if (ret) {
ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret);
return ret;
}
time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
1 * HZ);
if (time_left == 0)
return -ETIMEDOUT;
return 0;
}
static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file)
{
struct ath10k *ar = inode->i_private;
void *buf;
int ret;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH10K_STATE_ON) {
ret = -ENETDOWN;
goto err_unlock;
}
buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
if (!buf) {
ret = -ENOMEM;
goto err_unlock;
}
ret = ath10k_debug_tpc_stats_final_request(ar);
if (ret) {
ath10k_warn(ar, "failed to request tpc stats final: %d\n",
ret);
goto err_free;
}
ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
file->private_data = buf;
mutex_unlock(&ar->conf_mutex);
return 0;
err_free:
vfree(buf);
err_unlock:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static int ath10k_tpc_stats_final_release(struct inode *inode,
struct file *file)
{
vfree(file->private_data);
return 0;
}
static ssize_t ath10k_tpc_stats_final_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
const char *buf = file->private_data;
unsigned int len = strlen(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_tpc_stats_final = {
.open = ath10k_tpc_stats_final_open,
.release = ath10k_tpc_stats_final_release,
.read = ath10k_tpc_stats_final_read,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath10k_debug_create(struct ath10k *ar) int ath10k_debug_create(struct ath10k *ar)
{ {
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
...@@ -2305,6 +2407,11 @@ int ath10k_debug_register(struct ath10k *ar) ...@@ -2305,6 +2407,11 @@ int ath10k_debug_register(struct ath10k *ar)
ar->debug.debugfs_phy, ar->debug.debugfs_phy,
ar, &fops_sta_tid_stats_mask); ar, &fops_sta_tid_stats_mask);
if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map))
debugfs_create_file("tpc_stats_final", 0400,
ar->debug.debugfs_phy, ar,
&fops_tpc_stats_final);
return 0; return 0;
} }
......
...@@ -102,6 +102,9 @@ void ath10k_debug_unregister(struct ath10k *ar); ...@@ -102,6 +102,9 @@ void ath10k_debug_unregister(struct ath10k *ar);
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
void ath10k_debug_tpc_stats_process(struct ath10k *ar, void ath10k_debug_tpc_stats_process(struct ath10k *ar,
struct ath10k_tpc_stats *tpc_stats); struct ath10k_tpc_stats *tpc_stats);
void
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
struct ath10k_tpc_stats_final *tpc_stats);
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
...@@ -165,6 +168,13 @@ static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar, ...@@ -165,6 +168,13 @@ static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar,
kfree(tpc_stats); kfree(tpc_stats);
} }
static inline void
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
struct ath10k_tpc_stats_final *tpc_stats)
{
kfree(tpc_stats);
}
static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
int len) int len)
{ {
......
...@@ -201,6 +201,9 @@ struct wmi_ops { ...@@ -201,6 +201,9 @@ struct wmi_ops {
(struct ath10k *ar, (struct ath10k *ar,
enum wmi_bss_survey_req_type type); enum wmi_bss_survey_req_type type);
struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value); struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value);
struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar,
u32 param);
}; };
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
...@@ -1445,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value) ...@@ -1445,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value)
return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid); return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid);
} }
static inline int
ath10k_wmi_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
{
struct sk_buff *skb;
if (!ar->wmi.ops->gen_pdev_get_tpc_table_cmdid)
return -EOPNOTSUPP;
skb = ar->wmi.ops->gen_pdev_get_tpc_table_cmdid(ar, param);
if (IS_ERR(skb))
return PTR_ERR(skb);
return ath10k_wmi_cmd_send(ar, skb,
ar->wmi.cmd->pdev_get_tpc_table_cmdid);
}
#endif #endif
This diff is collapsed.
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -197,6 +198,9 @@ enum wmi_service { ...@@ -197,6 +198,9 @@ enum wmi_service {
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_SERVICE_MGMT_TX_WMI, WMI_SERVICE_MGMT_TX_WMI,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, WMI_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
WMI_SERVICE_HOST_DFS_CHECK_SUPPORT,
WMI_SERVICE_TPC_STATS_FINAL,
/* keep last */ /* keep last */
WMI_SERVICE_MAX, WMI_SERVICE_MAX,
...@@ -339,6 +343,9 @@ enum wmi_10_4_service { ...@@ -339,6 +343,9 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
WMI_10_4_SERVICE_TPC_STATS_FINAL,
}; };
static inline char *wmi_service_name(int service_id) static inline char *wmi_service_name(int service_id)
...@@ -448,6 +455,9 @@ static inline char *wmi_service_name(int service_id) ...@@ -448,6 +455,9 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE); SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE);
SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY); SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY);
SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH); SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH);
SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS);
SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
default: default:
return NULL; return NULL;
} }
...@@ -746,6 +756,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, ...@@ -746,6 +756,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len); WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len);
SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len); WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len);
SVCMAP(WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, len);
SVCMAP(WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len);
SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL,
WMI_SERVICE_TPC_STATS_FINAL, len);
} }
#undef SVCMAP #undef SVCMAP
...@@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd { ...@@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd {
#define WMI_TPC_CONFIG_PARAM 1 #define WMI_TPC_CONFIG_PARAM 1
#define WMI_TPC_RATE_MAX 160 #define WMI_TPC_RATE_MAX 160
#define WMI_TPC_FINAL_RATE_MAX 240
#define WMI_TPC_TX_N_CHAIN 4 #define WMI_TPC_TX_N_CHAIN 4
#define WMI_TPC_PREAM_TABLE_MAX 10 #define WMI_TPC_PREAM_TABLE_MAX 10
#define WMI_TPC_FLAG 3 #define WMI_TPC_FLAG 3
#define WMI_TPC_BUF_SIZE 10 #define WMI_TPC_BUF_SIZE 10
#define WMI_TPC_BEAMFORMING 2
enum wmi_tpc_table_type { enum wmi_tpc_table_type {
WMI_TPC_TABLE_TYPE_CDD = 0, WMI_TPC_TABLE_TYPE_CDD = 0,
...@@ -4039,6 +4057,51 @@ enum wmi_tp_scale { ...@@ -4039,6 +4057,51 @@ enum wmi_tp_scale {
WMI_TP_SCALE_SIZE = 5, /* max num of enum */ WMI_TP_SCALE_SIZE = 5, /* max num of enum */
}; };
struct wmi_pdev_tpc_final_table_event {
__le32 reg_domain;
__le32 chan_freq;
__le32 phy_mode;
__le32 twice_antenna_reduction;
__le32 twice_max_rd_power;
a_sle32 twice_antenna_gain;
__le32 power_limit;
__le32 rate_max;
__le32 num_tx_chain;
__le32 ctl;
__le32 flags;
s8 max_reg_allow_pow[WMI_TPC_TX_N_CHAIN];
s8 max_reg_allow_pow_agcdd[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
s8 max_reg_allow_pow_agstbc[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
s8 max_reg_allow_pow_agtxbf[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
u8 rates_array[WMI_TPC_FINAL_RATE_MAX];
u8 ctl_power_table[WMI_TPC_BEAMFORMING][WMI_TPC_TX_N_CHAIN]
[WMI_TPC_TX_N_CHAIN];
} __packed;
struct wmi_pdev_get_tpc_table_cmd {
__le32 param;
} __packed;
enum wmi_tpc_pream_2ghz {
WMI_TPC_PREAM_2GHZ_CCK = 0,
WMI_TPC_PREAM_2GHZ_OFDM,
WMI_TPC_PREAM_2GHZ_HT20,
WMI_TPC_PREAM_2GHZ_HT40,
WMI_TPC_PREAM_2GHZ_VHT20,
WMI_TPC_PREAM_2GHZ_VHT40,
WMI_TPC_PREAM_2GHZ_VHT80,
};
enum wmi_tpc_pream_5ghz {
WMI_TPC_PREAM_5GHZ_OFDM = 1,
WMI_TPC_PREAM_5GHZ_HT20,
WMI_TPC_PREAM_5GHZ_HT40,
WMI_TPC_PREAM_5GHZ_VHT20,
WMI_TPC_PREAM_5GHZ_VHT40,
WMI_TPC_PREAM_5GHZ_VHT80,
WMI_TPC_PREAM_5GHZ_HTCUP,
};
struct wmi_pdev_chanlist_update_event { struct wmi_pdev_chanlist_update_event {
/* number of channels */ /* number of channels */
__le32 num_chan; __le32 num_chan;
...@@ -6979,5 +7042,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, ...@@ -6979,5 +7042,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
enum wmi_vdev_subtype subtype); enum wmi_vdev_subtype subtype);
int ath10k_wmi_barrier(struct ath10k *ar); int ath10k_wmi_barrier(struct ath10k *ar);
void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
u32 num_tx_chain);
void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb);
#endif /* _WMI_H_ */ #endif /* _WMI_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