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: Maharaja Kennadyrajan <mkenna@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Maharaja Kennadyrajan 2018-03-14 12:14:08 +02:00 committed by Kalle Valo
parent caee728ab7
commit bc64d05220
6 changed files with 518 additions and 15 deletions

View File

@ -325,6 +325,27 @@ struct ath10k_tpc_stats {
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 {
u32 phy_errors;
u32 pulses_total;
@ -530,6 +551,7 @@ struct ath10k_debug {
/* used for tpc-dump storage, protected by data-lock */
struct ath10k_tpc_stats *tpc_stats;
struct ath10k_tpc_stats_final *tpc_stats_final;
struct completion tpc_complete;

View File

@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar,
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,
unsigned int j, char *buf, size_t *len)
{
@ -2185,6 +2198,95 @@ static const struct file_operations fops_sta_tid_stats_mask = {
.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)
{
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
@ -2305,6 +2407,11 @@ int ath10k_debug_register(struct ath10k *ar)
ar->debug.debugfs_phy,
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;
}

View File

@ -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_tpc_stats_process(struct ath10k *ar,
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);
#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,
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,
int len)
{

View File

@ -201,6 +201,9 @@ struct wmi_ops {
(struct ath10k *ar,
enum wmi_bss_survey_req_type type);
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);
@ -1445,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value)
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

View File

@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications 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
* purpose with or without fee is hereby granted, provided that the above
@ -196,6 +197,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
/* 10.X WMI cmd track */
@ -362,6 +364,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
/* 10.2.4 WMI cmd track */
@ -528,6 +531,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid =
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
/* 10.4 WMI cmd track */
@ -1480,6 +1484,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
@ -4313,19 +4318,11 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar,
}
}
void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
u32 num_tx_chain)
{
u32 i, j, pream_idx, num_tx_chain;
u8 rate_code[WMI_TPC_RATE_MAX], rate_idx;
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
struct wmi_pdev_tpc_config_event *ev;
struct ath10k_tpc_stats *tpc_stats;
ev = (struct wmi_pdev_tpc_config_event *)skb->data;
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
if (!tpc_stats)
return;
u32 i, j, pream_idx;
u8 rate_idx;
/* Create the rate code table based on the chains supported */
rate_idx = 0;
@ -4349,8 +4346,6 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
pream_table[pream_idx] = rate_idx;
pream_idx++;
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
/* Fill HT20 rate code */
for (i = 0; i < num_tx_chain; i++) {
for (j = 0; j < 8; j++) {
@ -4374,7 +4369,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
pream_idx++;
/* Fill VHT20 rate code */
for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) {
for (i = 0; i < num_tx_chain; i++) {
for (j = 0; j < 10; j++) {
rate_code[rate_idx] =
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
@ -4418,6 +4413,26 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END;
}
void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
{
u32 num_tx_chain;
u8 rate_code[WMI_TPC_RATE_MAX];
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
struct wmi_pdev_tpc_config_event *ev;
struct ath10k_tpc_stats *tpc_stats;
ev = (struct wmi_pdev_tpc_config_event *)skb->data;
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
if (!tpc_stats)
return;
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
num_tx_chain);
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
@ -4457,6 +4472,246 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
__le32_to_cpu(ev->rate_max));
}
static u8
ath10k_wmi_tpc_final_get_rate(struct ath10k *ar,
struct wmi_pdev_tpc_final_table_event *ev,
u32 rate_idx, u32 num_chains,
u32 rate_code, u8 type, u32 pream_idx)
{
u8 tpc, num_streams, preamble, ch, stm_idx;
s8 pow_agcdd, pow_agstbc, pow_agtxbf;
int pream;
num_streams = ATH10K_HW_NSS(rate_code);
preamble = ATH10K_HW_PREAMBLE(rate_code);
ch = num_chains - 1;
stm_idx = num_streams - 1;
pream = -1;
if (__le32_to_cpu(ev->chan_freq) <= 2483) {
switch (pream_idx) {
case WMI_TPC_PREAM_2GHZ_CCK:
pream = 0;
break;
case WMI_TPC_PREAM_2GHZ_OFDM:
pream = 1;
break;
case WMI_TPC_PREAM_2GHZ_HT20:
case WMI_TPC_PREAM_2GHZ_VHT20:
pream = 2;
break;
case WMI_TPC_PREAM_2GHZ_HT40:
case WMI_TPC_PREAM_2GHZ_VHT40:
pream = 3;
break;
case WMI_TPC_PREAM_2GHZ_VHT80:
pream = 4;
break;
default:
pream = -1;
break;
}
}
if (__le32_to_cpu(ev->chan_freq) >= 5180) {
switch (pream_idx) {
case WMI_TPC_PREAM_5GHZ_OFDM:
pream = 0;
break;
case WMI_TPC_PREAM_5GHZ_HT20:
case WMI_TPC_PREAM_5GHZ_VHT20:
pream = 1;
break;
case WMI_TPC_PREAM_5GHZ_HT40:
case WMI_TPC_PREAM_5GHZ_VHT40:
pream = 2;
break;
case WMI_TPC_PREAM_5GHZ_VHT80:
pream = 3;
break;
case WMI_TPC_PREAM_5GHZ_HTCUP:
pream = 4;
break;
default:
pream = -1;
break;
}
}
if (pream == 4)
tpc = min_t(u8, ev->rates_array[rate_idx],
ev->max_reg_allow_pow[ch]);
else
tpc = min_t(u8, min_t(u8, ev->rates_array[rate_idx],
ev->max_reg_allow_pow[ch]),
ev->ctl_power_table[0][pream][stm_idx]);
if (__le32_to_cpu(ev->num_tx_chain) <= 1)
goto out;
if (preamble == WMI_RATE_PREAMBLE_CCK)
goto out;
if (num_chains <= num_streams)
goto out;
switch (type) {
case WMI_TPC_TABLE_TYPE_STBC:
pow_agstbc = ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx];
if (pream == 4)
tpc = min_t(u8, tpc, pow_agstbc);
else
tpc = min_t(u8, min_t(u8, tpc, pow_agstbc),
ev->ctl_power_table[0][pream][stm_idx]);
break;
case WMI_TPC_TABLE_TYPE_TXBF:
pow_agtxbf = ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx];
if (pream == 4)
tpc = min_t(u8, tpc, pow_agtxbf);
else
tpc = min_t(u8, min_t(u8, tpc, pow_agtxbf),
ev->ctl_power_table[1][pream][stm_idx]);
break;
case WMI_TPC_TABLE_TYPE_CDD:
pow_agcdd = ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx];
if (pream == 4)
tpc = min_t(u8, tpc, pow_agcdd);
else
tpc = min_t(u8, min_t(u8, tpc, pow_agcdd),
ev->ctl_power_table[0][pream][stm_idx]);
break;
default:
ath10k_warn(ar, "unknown wmi tpc final table type: %d\n", type);
tpc = 0;
break;
}
out:
return tpc;
}
static void
ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar,
struct wmi_pdev_tpc_final_table_event *ev,
struct ath10k_tpc_stats_final *tpc_stats,
u8 *rate_code, u16 *pream_table, u8 type)
{
u32 i, j, pream_idx, flags;
u8 tpc[WMI_TPC_TX_N_CHAIN];
char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
char buff[WMI_TPC_BUF_SIZE];
flags = __le32_to_cpu(ev->flags);
switch (type) {
case WMI_TPC_TABLE_TYPE_CDD:
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n");
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
return;
}
break;
case WMI_TPC_TABLE_TYPE_STBC:
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n");
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
return;
}
break;
case WMI_TPC_TABLE_TYPE_TXBF:
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n");
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
return;
}
break;
default:
ath10k_dbg(ar, ATH10K_DBG_WMI,
"invalid table type in wmi tpc event: %d\n", type);
return;
}
pream_idx = 0;
for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
memset(tpc_value, 0, sizeof(tpc_value));
memset(buff, 0, sizeof(buff));
if (i == pream_table[pream_idx])
pream_idx++;
for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
if (j >= __le32_to_cpu(ev->num_tx_chain))
break;
tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
rate_code[i],
type, pream_idx);
snprintf(buff, sizeof(buff), "%8d ", tpc[j]);
strncat(tpc_value, buff, strlen(buff));
}
tpc_stats->tpc_table_final[type].pream_idx[i] = pream_idx;
tpc_stats->tpc_table_final[type].rate_code[i] = rate_code[i];
memcpy(tpc_stats->tpc_table_final[type].tpc_value[i],
tpc_value, sizeof(tpc_value));
}
}
void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb)
{
u32 num_tx_chain;
u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
struct wmi_pdev_tpc_final_table_event *ev;
struct ath10k_tpc_stats_final *tpc_stats;
ev = (struct wmi_pdev_tpc_final_table_event *)skb->data;
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
if (!tpc_stats)
return;
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
num_tx_chain);
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
tpc_stats->ctl = __le32_to_cpu(ev->ctl);
tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain);
tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain);
tpc_stats->twice_antenna_reduction =
__le32_to_cpu(ev->twice_antenna_reduction);
tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
rate_code, pream_table,
WMI_TPC_TABLE_TYPE_CDD);
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
rate_code, pream_table,
WMI_TPC_TABLE_TYPE_STBC);
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
rate_code, pream_table,
WMI_TPC_TABLE_TYPE_TXBF);
ath10k_debug_tpc_stats_final_process(ar, tpc_stats);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event tpc final table channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n",
__le32_to_cpu(ev->chan_freq),
__le32_to_cpu(ev->phy_mode),
__le32_to_cpu(ev->ctl),
__le32_to_cpu(ev->reg_domain),
a_sle32_to_cpu(ev->twice_antenna_gain),
__le32_to_cpu(ev->twice_antenna_reduction),
__le32_to_cpu(ev->power_limit),
__le32_to_cpu(ev->twice_max_rd_power) / 2,
__le32_to_cpu(ev->num_tx_chain),
__le32_to_cpu(ev->rate_max));
}
static void
ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
{
@ -5549,6 +5804,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_4_TDLS_PEER_EVENTID:
ath10k_wmi_handle_tdls_peer_event(ar, skb);
break;
case WMI_10_4_PDEV_TPC_TABLE_EVENTID:
ath10k_wmi_event_tpc_final_table(ar, skb);
break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@ -7989,6 +8247,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
return peer_qos;
}
static struct sk_buff *
ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
{
struct wmi_pdev_get_tpc_table_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return ERR_PTR(-ENOMEM);
cmd = (struct wmi_pdev_get_tpc_table_cmd *)skb->data;
cmd->param = __cpu_to_le32(param);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev get tpc table param:%d\n", param);
return skb;
}
static struct sk_buff *
ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
const struct wmi_tdls_peer_update_cmd_arg *arg,
@ -8430,6 +8706,8 @@ static const struct wmi_ops wmi_10_4_ops = {
.ext_resource_config = ath10k_wmi_10_4_ext_resource_config,
.gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state,
.gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update,
.gen_pdev_get_tpc_table_cmdid =
ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid,
/* shared with 10.2 */
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev,

View File

@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications 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
* purpose with or without fee is hereby granted, provided that the above
@ -197,6 +198,9 @@ enum wmi_service {
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_SERVICE_MGMT_TX_WMI,
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 */
WMI_SERVICE_MAX,
@ -339,6 +343,9 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
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)
@ -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_EXPLICIT_MODE_ONLY);
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:
return NULL;
}
@ -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);
SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
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
@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd {
#define WMI_TPC_CONFIG_PARAM 1
#define WMI_TPC_RATE_MAX 160
#define WMI_TPC_FINAL_RATE_MAX 240
#define WMI_TPC_TX_N_CHAIN 4
#define WMI_TPC_PREAM_TABLE_MAX 10
#define WMI_TPC_FLAG 3
#define WMI_TPC_BUF_SIZE 10
#define WMI_TPC_BEAMFORMING 2
enum wmi_tpc_table_type {
WMI_TPC_TABLE_TYPE_CDD = 0,
@ -4039,6 +4057,51 @@ enum wmi_tp_scale {
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 {
/* number of channels */
__le32 num_chan;
@ -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,
enum wmi_vdev_subtype subtype);
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_ */