wlan-ap-Telecominfraproject/feeds/ipq95xx/mac80211/patches/qca/678-ath12k-add-mac-ops-to-get-tx-power.patch
John Crispin 144c5d00f4 ipq95xx/mac80211: update to ATH12.3-CS
Signed-off-by: John Crispin <john@phrozen.org>
2024-02-28 18:56:21 +01:00

664 lines
19 KiB
Diff

From 2758579734a12c00eb40a6e455efd04e59e44721 Mon Sep 17 00:00:00 2001
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
Date: Tue, 28 Dec 2021 13:14:06 +0530
Subject: [PATCH] ath12k: add mac ops to get tx power
Currently, driver does not support get_txpower mac ops because of which
cfg80211 returns vif->bss_conf.txpower to user space. bss_conf.txpower
gets its value from ieee80211_channel->max_reg_power. However, the
final txpower is dependent on few other parameters apart from max
regulatory supported power.
Add get_txpower to get the Tx power from FW and return it accordingly.
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Signed-off-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -229,6 +229,57 @@ bool ath12k_core_hw_group_start_ready(st
return (ag->num_started == ag->num_chip);
}
+void ath12k_fw_stats_pdevs_free(struct list_head *head)
+{
+ struct ath12k_fw_stats_pdev *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+static void ath12k_fw_stats_vdevs_free(struct list_head *head)
+{
+ struct ath12k_fw_stats_vdev *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+void ath12k_fw_stats_bcn_free(struct list_head *head)
+{
+ struct ath12k_fw_stats_bcn *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+void ath12k_fw_stats_init(struct ath12k *ar)
+{
+ INIT_LIST_HEAD(&ar->fw_stats.vdevs);
+ INIT_LIST_HEAD(&ar->fw_stats.pdevs);
+ INIT_LIST_HEAD(&ar->fw_stats.bcn);
+ init_completion(&ar->fw_stats_complete);
+}
+
+void ath12k_fw_stats_reset(struct ath12k *ar)
+{
+ ath12k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
+ ath12k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
+}
+
+void ath12k_fw_stats_free(struct ath12k_fw_stats *stats)
+{
+ ath12k_fw_stats_pdevs_free(&stats->pdevs);
+ ath12k_fw_stats_vdevs_free(&stats->vdevs);
+ ath12k_fw_stats_bcn_free(&stats->bcn);
+}
+
int ath12k_core_suspend(struct ath12k_base *ab)
{
int ret;
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -665,9 +665,6 @@ struct ath12k_debug {
struct dentry *debugfs_pdev;
struct ath12k_dbg_htt_stats htt_stats;
u32 extd_tx_stats;
- struct ath12k_fw_stats fw_stats;
- struct completion fw_stats_complete;
- bool fw_stats_done;
u32 extd_rx_stats;
u32 pktlog_filter;
u32 pktlog_mode;
@@ -866,6 +863,12 @@ struct ath12k {
struct completion mlo_setup_done;
u32 mlo_setup_status;
+
+ struct ath12k_fw_stats fw_stats;
+ struct completion fw_stats_complete;
+ bool fw_stats_done;
+
+ unsigned long last_tx_power_update;
};
struct ath12k_band_cap {
@@ -1315,6 +1318,11 @@ void ath12k_core_put_hw_group(struct ath
const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
const char *filename);
+void ath12k_fw_stats_init(struct ath12k *ar);
+void ath12k_fw_stats_pdevs_free(struct list_head *head);
+void ath12k_fw_stats_bcn_free(struct list_head *head);
+void ath12k_fw_stats_reset(struct ath12k *ar);
+void ath12k_fw_stats_free(struct ath12k_fw_stats *stats);
static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state)
{
--- a/drivers/net/wireless/ath/ath12k/debugfs.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs.c
@@ -53,86 +53,28 @@ static const char *htt_bp_lmac_ring[HTT_
"MONITOR_DEST_RING",
};
-static void ath12k_fw_stats_pdevs_free(struct list_head *head)
-{
- struct ath12k_fw_stats_pdev *i, *tmp;
-
- list_for_each_entry_safe(i, tmp, head, list) {
- list_del(&i->list);
- kfree(i);
- }
-}
-
-static void ath12k_fw_stats_vdevs_free(struct list_head *head)
-{
- struct ath12k_fw_stats_vdev *i, *tmp;
-
- list_for_each_entry_safe(i, tmp, head, list) {
- list_del(&i->list);
- kfree(i);
- }
-}
-
-static void ath12k_fw_stats_bcn_free(struct list_head *head)
-{
- struct ath12k_fw_stats_bcn *i, *tmp;
-
- list_for_each_entry_safe(i, tmp, head, list) {
- list_del(&i->list);
- kfree(i);
- }
-}
-
static void ath12k_debugfs_fw_stats_reset(struct ath12k *ar)
{
spin_lock_bh(&ar->data_lock);
- ar->debug.fw_stats_done = false;
- ath12k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
- ath12k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
+ ar->fw_stats_done = false;
+ ath12k_fw_stats_reset(ar);
spin_unlock_bh(&ar->data_lock);
}
-void ath12k_debugfs_fw_stats_process(struct ath12k_base *ab, struct sk_buff *skb)
+void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
+ struct ath12k_fw_stats *stats)
{
- struct ath12k_fw_stats stats = {};
- struct ath12k *ar;
+ struct ath12k_base *ab = ar->ab;
struct ath12k_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 = ath12k_wmi_pull_fw_stats(ab, skb, &stats);
- if (ret) {
- ath12k_warn(ab, "failed to pull fw stats: %d\n", ret);
- goto free;
- }
-
- rcu_read_lock();
- ar = ath12k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
- if (!ar) {
- rcu_read_unlock();
- ath12k_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(&stats.vdevs)) {
+ int i;
+ if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {
+ if (list_empty(&stats->vdevs)) {
ath12k_warn(ab, "empty vdev stats");
- goto complete;
+ return;
}
/* FW sends all the active VDEV stats irrespective of PDEV,
* hence limit until the count of all VDEVs started
@@ -145,43 +87,34 @@ void ath12k_debugfs_fw_stats_process(str
is_end = ((++num_vdev) == total_vdevs_started);
- list_splice_tail_init(&stats.vdevs,
- &ar->debug.fw_stats.vdevs);
+ list_splice_tail_init(&stats->vdevs,
+ &ar->fw_stats.vdevs);
if (is_end) {
- ar->debug.fw_stats_done = true;
+ ar->fw_stats_done = true;
num_vdev = 0;
}
- goto complete;
+ return;
}
- if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
- if (list_empty(&stats.bcn)) {
+ if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
+ if (list_empty(&stats->bcn)) {
ath12k_warn(ab, "empty bcn stats");
- goto complete;
+ return;
}
/* Mark end until we reached the count of all started VDEVs
* within the PDEV
*/
is_end = ((++num_bcn) == ar->num_started_vdevs);
- list_splice_tail_init(&stats.bcn,
- &ar->debug.fw_stats.bcn);
+ list_splice_tail_init(&stats->bcn,
+ &ar->fw_stats.bcn);
if (is_end) {
- ar->debug.fw_stats_done = true;
+ ar->fw_stats_done = true;
num_bcn = 0;
}
}
-complete:
- complete(&ar->debug.fw_stats_complete);
- rcu_read_unlock();
- spin_unlock_bh(&ar->data_lock);
-
-free:
- ath12k_fw_stats_pdevs_free(&stats.pdevs);
- ath12k_fw_stats_vdevs_free(&stats.vdevs);
- ath12k_fw_stats_bcn_free(&stats.bcn);
}
static int ath12k_debugfs_fw_stats_request(struct ath12k *ar,
@@ -202,7 +135,7 @@ static int ath12k_debugfs_fw_stats_reque
ath12k_debugfs_fw_stats_reset(ar);
- reinit_completion(&ar->debug.fw_stats_complete);
+ reinit_completion(&ar->fw_stats_complete);
ret = ath12k_wmi_send_stats_request_cmd(ar, req_param);
@@ -213,7 +146,7 @@ static int ath12k_debugfs_fw_stats_reque
}
time_left =
- wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+ wait_for_completion_timeout(&ar->fw_stats_complete,
1 * HZ);
if (!time_left)
return -ETIMEDOUT;
@@ -223,7 +156,7 @@ static int ath12k_debugfs_fw_stats_reque
break;
spin_lock_bh(&ar->data_lock);
- if (ar->debug.fw_stats_done) {
+ if (ar->fw_stats_done) {
spin_unlock_bh(&ar->data_lock);
break;
}
@@ -263,7 +196,7 @@ static int ath12k_open_pdev_stats(struct
goto err_free;
}
- ath12k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+ ath12k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id,
buf);
file->private_data = buf;
@@ -335,7 +268,7 @@ static int ath12k_open_vdev_stats(struct
goto err_free;
}
- ath12k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+ ath12k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id,
buf);
file->private_data = buf;
@@ -413,14 +346,14 @@ static int ath12k_open_bcn_stats(struct
}
}
- ath12k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+ ath12k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id,
buf);
/* since beacon stats request is looped for all active VDEVs, saved fw
* stats is not freed for each request until done for all active VDEVs
*/
spin_lock_bh(&ar->data_lock);
- ath12k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
+ ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn);
spin_unlock_bh(&ar->data_lock);
file->private_data = buf;
@@ -474,12 +407,12 @@ static ssize_t ath12k_write_enable_vdev_
mutex_lock(&ar->conf_mutex);
- if (enable == ar->debug.fw_stats.en_vdev_stats_ol) {
+ if (enable == ar->fw_stats.en_vdev_stats_ol) {
ret = count;
goto out;
}
- ar->debug.fw_stats.en_vdev_stats_ol = enable;
+ ar->fw_stats.en_vdev_stats_ol = enable;
ret = count;
out:
@@ -498,7 +431,7 @@ static ssize_t ath12k_read_enable_vdev_s
mutex_lock(&ar->conf_mutex);
len = scnprintf(buf, sizeof(buf) - len, "%u\n",
- ar->debug.fw_stats.en_vdev_stats_ol);
+ ar->fw_stats.en_vdev_stats_ol);
mutex_unlock(&ar->conf_mutex);
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
@@ -1301,7 +1234,7 @@ void ath12k_debugfs_fw_stats_init(struct
struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
ar->debug.debugfs_pdev);
- ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
+ ar->fw_stats.debugfs_fwstats = fwstats_dir;
/* all stats debugfs files created are under "fw_stats" directory
* created per PDEV
@@ -1315,11 +1248,6 @@ void ath12k_debugfs_fw_stats_init(struct
debugfs_create_file("en_vdev_stats_ol", 0600, fwstats_dir, ar,
&fops_vdev_stats_offload);
- INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
- INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
- INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
-
- init_completion(&ar->debug.fw_stats_complete);
}
int ath12k_pktlog_rx_filter_setting(struct ath12k *ar,
--- a/drivers/net/wireless/ath/ath12k/debugfs.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs.h
@@ -208,7 +208,8 @@ int ath12k_debugfs_register(struct ath12
void ath12k_debugfs_unregister(struct ath12k *ar);
int ath12k_debugfs_create(void);
void ath12k_debugfs_destroy(void);
-void ath12k_debugfs_fw_stats_process(struct ath12k_base *ab, struct sk_buff *skb);
+void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
+ struct ath12k_fw_stats *stats);
void ath12k_debugfs_fw_stats_init(struct ath12k *ar);
@@ -283,8 +284,8 @@ static inline void ath12k_debugfs_unregi
{
}
-static inline void ath12k_debugfs_fw_stats_process(struct ath12k_base *ab,
- struct sk_buff *skb)
+static inline void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
+ struct ath11k_fw_stats *stats)
{
}
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -8166,6 +8166,7 @@ static int ath12k_mac_radio_start(struct
ar->num_created_vdevs = 0;
ar->num_peers = 0;
ar->allocated_vdev_map = 0;
+ ar->chan_tx_pwr = ATH12K_PDEV_TX_POWER_INVALID;
spin_lock_bh(&ar->data_lock);
ar->awgn_intf_handling_in_prog = false;
@@ -8594,7 +8595,7 @@ static int ath12k_mac_vdev_create(struct
/* Send vdev stats offload commands to firmware before first vdev
* creation. ie., when num_created_vdevs = 0
*/
- if (ar->debug.fw_stats.en_vdev_stats_ol && !ar->num_created_vdevs) {
+ if (ar->fw_stats.en_vdev_stats_ol && !ar->num_created_vdevs) {
ret = ath12k_dp_tx_htt_h2t_vdev_stats_ol_req(ar, 0);
if (ret) {
ath12k_warn(ar->ab, "failed to request vdev stats offload: %d\n", ret);
@@ -9254,6 +9255,7 @@ static int ath12k_mac_op_add_chanctx(str
ar->rx_channel = ctx->def.chan;
spin_unlock_bh(&ar->data_lock);
+ ar->chan_tx_pwr = ATH12K_PDEV_TX_POWER_INVALID;
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -9285,6 +9287,7 @@ static void ath12k_mac_op_remove_chanctx
ar->rx_channel = NULL;
spin_unlock_bh(&ar->data_lock);
+ ar->chan_tx_pwr = ATH12K_PDEV_TX_POWER_INVALID;
mutex_unlock(&ar->conf_mutex);
}
@@ -9870,6 +9873,7 @@ static void ath12k_mac_update_rx_channel
ar->rx_channel = NULL;
}
rcu_read_unlock();
+ ar->chan_tx_pwr = ATH12K_PDEV_TX_POWER_INVALID;
}
static void
@@ -12213,6 +12217,127 @@ static void ath12k_mac_op_sta_statistics
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
}
+static int ath12k_fw_stats_request(struct ath12k *ar,
+ struct stats_request_params *req_param)
+{
+ struct ath12k_base *ab = ar->ab;
+ unsigned long time_left;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ spin_lock_bh(&ar->data_lock);
+ ar->fw_stats_done = false;
+ ath12k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
+ spin_unlock_bh(&ar->data_lock);
+
+ reinit_completion(&ar->fw_stats_complete);
+
+ ret = ath12k_wmi_send_stats_request_cmd(ar, req_param);
+ if (ret) {
+ ath12k_warn(ab, "could not request fw stats (%d)\n",
+ ret);
+ return ret;
+ }
+
+ time_left =
+ wait_for_completion_timeout(&ar->fw_stats_complete,
+ 1 * HZ);
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int ath12k_mac_op_get_txpower(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ int *dbm)
+{
+ struct ath12k_hw *ah = hw->priv;
+ struct stats_request_params req_param;
+ struct ath12k_fw_stats_pdev *pdev;
+ struct ath12k *ar;
+ struct ath12k_base *ab;
+ int ret;
+
+ /* Final Tx power is minimum of Target Power, CTL power, Regulatory
+ * Power, PSD EIRP Power. We just know the Regulatory power from the
+ * regulatory rules obtained. FW knows all these power and sets the min
+ * of these. Hence, we request the FW pdev stats in which FW reports
+ * the minimum of all vdev's channel Tx power.
+ */
+ mutex_lock(&ah->conf_mutex);
+
+ ar = ath12k_get_ar_by_vif(hw, vif, 0);
+ if (!ar) {
+ goto err_fallback;
+ }
+
+ ab = ar->ab;
+ if (ar->state != ATH12K_STATE_ON) {
+ goto err_fallback;
+ }
+
+ mutex_lock(&ar->conf_mutex);
+ if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) {
+ mutex_unlock(&ar->conf_mutex);
+ mutex_unlock(&ah->conf_mutex);
+ *dbm = 0;
+ return 0;
+ }
+
+ /* Limit the requests to Firmware for fetching the tx power */
+ if (ar->chan_tx_pwr != ATH12K_PDEV_TX_POWER_INVALID &&
+ time_before(jiffies, msecs_to_jiffies(ATH12K_PDEV_TX_POWER_REFRESH_TIME_MSECS) +
+ ar->last_tx_power_update))
+ goto get_tx_power;
+
+ req_param.pdev_id = ar->pdev->pdev_id;
+ req_param.vdev_id = 0;
+ req_param.stats_id = WMI_REQUEST_PDEV_STAT;
+
+ ret = ath12k_fw_stats_request(ar, &req_param);
+ if (ret) {
+ ath12k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
+ mutex_unlock(&ar->conf_mutex);
+ goto err_fallback;
+ }
+
+ spin_lock_bh(&ar->data_lock);
+ pdev = list_first_entry_or_null(&ar->fw_stats.pdevs,
+ struct ath12k_fw_stats_pdev,
+ list);
+ if (!pdev) {
+ spin_unlock_bh(&ar->data_lock);
+ mutex_unlock(&ar->conf_mutex);
+ goto err_fallback;
+ }
+
+ /* tx power is set as 2 units per dBm in FW. */
+ ar->chan_tx_pwr = pdev->chan_tx_power/2;
+ ar->last_tx_power_update = jiffies;
+
+ spin_unlock_bh(&ar->data_lock);
+
+get_tx_power:
+ *dbm = ar->chan_tx_pwr;
+
+ mutex_unlock(&ar->conf_mutex);
+ mutex_unlock(&ah->conf_mutex);
+
+ ath12k_dbg(ab, ATH12K_DBG_MAC, "txpower reported %d dBm\n", *dbm);
+ return 0;
+
+err_fallback:
+ mutex_unlock(&ah->conf_mutex);
+ /* We didn't get txpower from FW. Hence, relying on vif->bss_conf.txpower */
+ *dbm = vif->bss_conf.txpower;
+ ath12k_dbg(NULL, ATH12K_DBG_MAC, "txpower from firmware NaN, reported %d dBm\n",
+ *dbm);
+ return 0;
+}
+
static const struct ieee80211_ops ath12k_ops = {
.tx = ath12k_mac_op_tx,
.start = ath12k_mac_op_start,
@@ -12254,6 +12379,7 @@ static const struct ieee80211_ops ath12k
#ifdef CPTCFG_ATH12K_DEBUGFS
.sta_add_debugfs = ath12k_debugfs_sta_op_add,
#endif
+ .get_txpower = ath12k_mac_op_get_txpower,
};
static void ath12k_mac_update_ch_list(struct ath12k *ar,
@@ -12978,6 +13104,11 @@ static int ath12k_mac_hw_register(struct
goto err_unregister_hw;
}
+ /* fw stats init is separately required since fw pdev stats is also used
+ * in get_txpower mac ops hence it is handled separately from debugfs
+ */
+ ath12k_fw_stats_init(ar);
+
ret = ath12k_debugfs_register(ar);
if (ret) {
ath12k_err(ar->ab, "debugfs registration failed: %d\n", ret);
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6867,7 +6867,7 @@ void ath12k_wmi_fw_stats_fill(struct ath
spin_lock_bh(&ar->data_lock);
if (stats_id == WMI_REQUEST_PDEV_STAT) {
- pdev = list_first_entry_or_null(&fw_stats->pdevs,
+ pdev = list_first_entry_or_null(&ar->fw_stats.pdevs,
struct ath12k_fw_stats_pdev, list);
if (!pdev) {
ath12k_warn(ar->ab, "failed to get pdev stats\n");
@@ -7929,7 +7929,52 @@ static void ath12k_peer_assoc_conf_event
static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb)
{
- ath12k_debugfs_fw_stats_process(ab, skb);
+ struct ath12k_fw_stats stats = {};
+ struct ath12k *ar;
+ int ret;
+
+ INIT_LIST_HEAD(&stats.pdevs);
+ INIT_LIST_HEAD(&stats.vdevs);
+ INIT_LIST_HEAD(&stats.bcn);
+
+ ret = ath12k_wmi_pull_fw_stats(ab, skb, &stats);
+ if (ret) {
+ ath12k_warn(ab, "failed to pull fw stats: %d\n", ret);
+ goto free;
+ }
+
+ rcu_read_lock();
+ ar = ath12k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
+ if (!ar) {
+ rcu_read_unlock();
+ ath12k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
+ stats.pdev_id, ret);
+ goto free;
+ }
+
+ spin_lock_bh(&ar->data_lock);
+
+ /* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via
+ * debugfs fw stats. Therfore, processing it separately.
+ */
+ if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
+ list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs);
+ ar->fw_stats_done = true;
+ goto complete;
+ }
+
+ /* WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT are currently requested
+ * only via debugfs fw stats. Hence, processing these two in debugfs context
+ */
+ ath12k_debugfs_fw_stats_process(ar, &stats);
+
+complete:
+ complete(&ar->fw_stats_complete);
+ rcu_read_unlock();
+ spin_unlock_bh(&ar->data_lock);
+
+free:
+ ath12k_fw_stats_free(&stats);
}
/* PDEV_CTL_FAILSAFE_CHECK_EVENT is received from FW when the frequency scanned
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -128,6 +128,9 @@ struct ath12k_generic_iter {
#define ATH12K_OBSS_PD_SRG_EN BIT(30)
#define ATH12K_OBSS_PD_NON_SRG_EN BIT(31)
+#define ATH12K_PDEV_TX_POWER_INVALID (-1)
+#define ATH12K_PDEV_TX_POWER_REFRESH_TIME_MSECS 5000 /* msecs */
+
extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
void ath12k_mac_ap_ps_recalc(struct ath12k *ar);