Commit 7b6b153a authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: add vdev stats processing

New qca6174 wmi-tlv firmware supports vdev stats.
This patch adds support for it in the debug
frontend.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 2c512059
...@@ -159,6 +159,25 @@ struct ath10k_fw_stats_peer { ...@@ -159,6 +159,25 @@ struct ath10k_fw_stats_peer {
u32 peer_rx_rate; /* 10x only */ u32 peer_rx_rate; /* 10x only */
}; };
struct ath10k_fw_stats_vdev {
struct list_head list;
u32 vdev_id;
u32 beacon_snr;
u32 data_snr;
u32 num_tx_frames[4];
u32 num_rx_frames;
u32 num_tx_frames_retries[4];
u32 num_tx_frames_failures[4];
u32 num_rts_fail;
u32 num_rts_success;
u32 num_rx_err;
u32 num_rx_discard;
u32 num_tx_not_acked;
u32 tx_rate_history[10];
u32 beacon_rssi_history[10];
};
struct ath10k_fw_stats_pdev { struct ath10k_fw_stats_pdev {
struct list_head list; struct list_head list;
...@@ -220,6 +239,7 @@ struct ath10k_fw_stats_pdev { ...@@ -220,6 +239,7 @@ struct ath10k_fw_stats_pdev {
struct ath10k_fw_stats { struct ath10k_fw_stats {
struct list_head pdevs; struct list_head pdevs;
struct list_head vdevs;
struct list_head peers; struct list_head peers;
}; };
......
...@@ -243,6 +243,16 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head) ...@@ -243,6 +243,16 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
} }
} }
static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head)
{
struct ath10k_fw_stats_vdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath10k_debug_fw_stats_peers_free(struct list_head *head) static void ath10k_debug_fw_stats_peers_free(struct list_head *head)
{ {
struct ath10k_fw_stats_peer *i, *tmp; struct ath10k_fw_stats_peer *i, *tmp;
...@@ -258,6 +268,7 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar) ...@@ -258,6 +268,7 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false; ar->debug.fw_stats_done = false;
ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers); ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
} }
...@@ -273,14 +284,27 @@ static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head) ...@@ -273,14 +284,27 @@ static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head)
return num; return num;
} }
static size_t ath10k_debug_fw_stats_num_vdevs(struct list_head *head)
{
struct ath10k_fw_stats_vdev *i;
size_t num = 0;
list_for_each_entry(i, head, list)
++num;
return num;
}
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)
{ {
struct ath10k_fw_stats stats = {}; struct ath10k_fw_stats stats = {};
bool is_start, is_started, is_end; bool is_start, is_started, is_end;
size_t num_peers; size_t num_peers;
size_t num_vdevs;
int ret; int ret;
INIT_LIST_HEAD(&stats.pdevs); INIT_LIST_HEAD(&stats.pdevs);
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.peers); INIT_LIST_HEAD(&stats.peers);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
...@@ -308,6 +332,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) ...@@ -308,6 +332,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
} }
num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers); num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers);
num_vdevs = ath10k_debug_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs);
is_start = (list_empty(&ar->debug.fw_stats.pdevs) && is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
!list_empty(&stats.pdevs)); !list_empty(&stats.pdevs));
is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
...@@ -330,7 +355,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) ...@@ -330,7 +355,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
goto free; goto free;
} }
if (num_vdevs >= BITS_PER_LONG) {
ath10k_warn(ar, "dropping fw vdev stats\n");
goto free;
}
list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
} }
complete(&ar->debug.fw_stats_complete); complete(&ar->debug.fw_stats_complete);
...@@ -340,6 +371,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) ...@@ -340,6 +371,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
* resources if that is not the case. * resources if that is not the case.
*/ */
ath10k_debug_fw_stats_pdevs_free(&stats.pdevs); ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
ath10k_debug_fw_stats_vdevs_free(&stats.vdevs);
ath10k_debug_fw_stats_peers_free(&stats.peers); ath10k_debug_fw_stats_peers_free(&stats.peers);
unlock: unlock:
...@@ -395,8 +427,11 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, ...@@ -395,8 +427,11 @@ static void ath10k_fw_stats_fill(struct ath10k *ar,
unsigned int len = 0; unsigned int len = 0;
unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE; unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE;
const struct ath10k_fw_stats_pdev *pdev; const struct ath10k_fw_stats_pdev *pdev;
const struct ath10k_fw_stats_vdev *vdev;
const struct ath10k_fw_stats_peer *peer; const struct ath10k_fw_stats_peer *peer;
size_t num_peers; size_t num_peers;
size_t num_vdevs;
int i;
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
...@@ -408,6 +443,7 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, ...@@ -408,6 +443,7 @@ static void ath10k_fw_stats_fill(struct ath10k *ar,
} }
num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers); num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers);
num_vdevs = ath10k_debug_fw_stats_num_vdevs(&fw_stats->vdevs);
len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n", len += scnprintf(buf + len, buf_len - len, "%30s\n",
...@@ -529,6 +565,65 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, ...@@ -529,6 +565,65 @@ static void ath10k_fw_stats_fill(struct ath10k *ar,
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
"ath10k VDEV stats", num_vdevs);
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
"=================");
list_for_each_entry(vdev, &fw_stats->vdevs, list) {
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"vdev id", vdev->vdev_id);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"beacon snr", vdev->beacon_snr);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"data snr", vdev->data_snr);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rx frames", vdev->num_rx_frames);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rts fail", vdev->num_rts_fail);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rts success", vdev->num_rts_success);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rx err", vdev->num_rx_err);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rx discard", vdev->num_rx_discard);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num tx not acked", vdev->num_tx_not_acked);
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"num tx frames", i,
vdev->num_tx_frames[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"num tx frames retries", i,
vdev->num_tx_frames_retries[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"num tx frames failures", i,
vdev->num_tx_frames_failures[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] 0x%08x\n",
"tx rate history", i,
vdev->tx_rate_history[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"beacon rssi history", i,
vdev->beacon_rssi_history[i]);
len += scnprintf(buf + len, buf_len - len, "\n");
}
len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
"ath10k PEER stats", num_peers); "ath10k PEER stats", num_peers);
...@@ -1900,6 +1995,7 @@ int ath10k_debug_create(struct ath10k *ar) ...@@ -1900,6 +1995,7 @@ int ath10k_debug_create(struct ath10k *ar)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.peers); INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
return 0; return 0;
......
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