// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
*/
#include "debugfs.h"
#include "core.h"
#include "debug.h"
#include "wmi.h"
#include "hal_rx.h"
#include "dp_tx.h"
#include "debugfs_htt_stats.h"
#include "peer.h"
static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
"REO2SW1_RING",
"REO2SW2_RING",
"REO2SW3_RING",
"REO2SW4_RING",
"WBM2REO_LINK_RING",
"REO2TCL_RING",
"REO2FW_RING",
"RELEASE_RING",
"PPE_RELEASE_RING",
"TCL2TQM_RING",
"TQM_RELEASE_RING",
"REO_RELEASE_RING",
"WBM2SW0_RELEASE_RING",
"WBM2SW1_RELEASE_RING",
"WBM2SW2_RELEASE_RING",
"WBM2SW3_RELEASE_RING",
"REO_CMD_RING",
"REO_STATUS_RING",
};
static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
"FW2RXDMA_BUF_RING",
"FW2RXDMA_STATUS_RING",
"FW2RXDMA_LINK_RING",
"SW2RXDMA_BUF_RING",
"WBM2RXDMA_LINK_RING",
"RXDMA2FW_RING",
"RXDMA2SW_RING",
"RXDMA2RELEASE_RING",
"RXDMA2REO_RING",
"MONITOR_STATUS_RING",
"MONITOR_BUF_RING",
"MONITOR_DESC_RING",
"MONITOR_DEST_RING",
};
static void ath11k_fw_stats_pdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_pdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath11k_fw_stats_vdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_vdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath11k_fw_stats_bcn_free(struct list_head *head)
{
struct ath11k_fw_stats_bcn *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)
{
spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false;
ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
spin_unlock_bh(&ar->data_lock);
}
void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
{
struct ath11k_fw_stats stats = {};
struct ath11k *ar;
struct ath11k_pdev *pdev;
bool is_end;
static unsigned int num_vdev, num_bcn;
size_t total_vdevs_started = 0;
int i, ret;
INIT_LIST_HEAD(&stats.pdevs);
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.bcn);
ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
if (ret) {
ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
goto free;
}
rcu_read_lock();
ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
if (!ar) {
rcu_read_unlock();
ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
stats.pdev_id, ret);
goto free;
}
spin_lock_bh(&ar->data_lock);
if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
ar->debug.fw_stats_done = true;
goto complete;
}
if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
if (list_empty(