From: Anilkumar Kolli <[email protected]>
Add tx stats supoort for QCA988X.
Parse peer stats from pktlog packets and update the tx rate
information per STA.
This way user space can query about transmit rate with iw.
V2:
- Added patch ath10k: remove MAC80211_DEBUGFS dependency on ath10k_sta_statistics
- No other changes
Anilkumar Kolli (3):
ath10k: remove MAC80211_DEBUGFS dependency on ath10k_sta_statistics
ath10k: move pktlog_filter out of ath10k_debug
ath10k: add per peer tx stats support for 10.2.4
drivers/net/wireless/ath/ath10k/core.h | 4 +-
drivers/net/wireless/ath/ath10k/debug.c | 16 +++----
drivers/net/wireless/ath/ath10k/debug.h | 21 +++++++--
drivers/net/wireless/ath/ath10k/debugfs_sta.c | 27 -----------
drivers/net/wireless/ath/ath10k/htt.h | 17 +++++++
drivers/net/wireless/ath/ath10k/htt_rx.c | 60 +++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/mac.c | 40 ++++++++++++++++-
7 files changed, 143 insertions(+), 42 deletions(-)
--
1.7.9.5
From: Anilkumar Kolli <[email protected]>
10.2.4 firmware branch (used in QCA988X) does not support
HTT_10_4_T2H_MSG_TYPE_PEER_STATS and that's why ath10k does not provide
tranmission rate statistics to user space, instead it just shows
hardcoded 6 Mbit/s. But pktlog firmware facility provides per peer tx
statistics. The firmware sends one pktlog event for every four
PPDUs per peer, which include:
* successful number of packets and bytes transmitted
* number of packets and bytes dropped
* retried number of packets and bytes
* rate info per ppdu
Firmware supports WMI_SERVICE_PEER_STATS, pktlog is enabled through
ATH10K_FLAG_PEER_STATS, which is nowadays enabled by default in ath10k.
This patch does not impact throughput.
Tested on QCA9880 with firmware version 10.2.4.70.48. This should also
work with firmware branch 10.2.4-1.0-00029
Parse peer stats from pktlog packets and update the tx rate information
per STA. This way user space can query about transmit rate with iw:
$iw wlan0 station dump
Station 3c:a9:f4:72:bb:a4 (on wlan1)
inactive time: 8210 ms
rx bytes: 9166
rx packets: 44
tx bytes: 1105
tx packets: 9
tx retries: 0
tx failed: 1
rx drop misc: 3
signal: -75 [-75, -87, -88] dBm
signal avg: -75 [-75, -85, -88] dBm
tx bitrate: 39.0 MBit/s MCS 10
rx bitrate: 26.0 MBit/s MCS 3
rx duration: 23250 us
authorized: yes
authenticated: yes
associated: yes
preamble: short
WMM/WME: yes
MFP: no
TDLS peer: no
DTIM period: 2
beacon interval:100
short preamble: yes
short slot time:yes
connected time: 22 seconds
Signed-off-by: Anilkumar Kolli <[email protected]>
---
drivers/net/wireless/ath/ath10k/debug.h | 18 ++++++++-
drivers/net/wireless/ath/ath10k/htt.h | 17 +++++++++
drivers/net/wireless/ath/ath10k/htt_rx.c | 60 ++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/mac.c | 10 +++++
4 files changed, 104 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index dd82a61ed1c8..5e662994c49a 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -51,7 +51,8 @@ enum ath10k_pktlog_filter {
ATH10K_PKTLOG_RCFIND = 0x000000004,
ATH10K_PKTLOG_RCUPDATE = 0x000000008,
ATH10K_PKTLOG_DBG_PRINT = 0x000000010,
- ATH10K_PKTLOG_ANY = 0x00000001f,
+ ATH10K_PKTLOG_PEER_STATS = 0x000000040,
+ ATH10K_PKTLOG_ANY = 0x00000005f,
};
enum ath10k_dbg_aggr_mode {
@@ -60,6 +61,21 @@ enum ath10k_dbg_aggr_mode {
ATH10K_DBG_AGGR_MODE_MAX,
};
+/* Types of packet log events */
+enum ath_pktlog_type {
+ ATH_PKTLOG_TYPE_TX_CTRL = 1,
+ ATH_PKTLOG_TYPE_TX_STAT,
+};
+
+struct ath10k_pktlog_hdr {
+ __le16 flags;
+ __le16 missed_cnt;
+ __le16 log_type; /* Type of log information foll this header */
+ __le16 size; /* Size of variable length log information in bytes */
+ __le32 timestamp;
+ u8 payload[0];
+} __packed;
+
/* FIXME: How to calculate the buffer size sanely? */
#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 6305308422c4..89db96afea17 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1497,6 +1497,23 @@ struct htt_peer_tx_stats {
u8 payload[0];
} __packed;
+#define ATH10K_10_2_TX_STATS_OFFSET 136
+#define PEER_STATS_FOR_NO_OF_PPDUS 4
+
+struct ath10k_10_2_peer_tx_stats {
+ u8 ratecode[PEER_STATS_FOR_NO_OF_PPDUS];
+ u8 success_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
+ __le16 success_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
+ u8 retry_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
+ __le16 retry_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
+ u8 failed_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
+ __le16 failed_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
+ u8 flags[PEER_STATS_FOR_NO_OF_PPDUS];
+ __le32 tx_duration;
+ u8 tx_ppdu_cnt;
+ u8 peer_id;
+} __packed;
+
union htt_rx_pn_t {
/* WEP: 24-bit PN */
u32 pn24;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 7d295ee71534..50670d651cff 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2449,6 +2449,62 @@ static void ath10k_htt_fetch_peer_stats(struct ath10k *ar,
rcu_read_unlock();
}
+static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data)
+{
+ struct ath10k_pktlog_hdr *hdr = (struct ath10k_pktlog_hdr *)data;
+ struct ath10k_per_peer_tx_stats *p_tx_stats = &ar->peer_tx_stats;
+ struct ath10k_10_2_peer_tx_stats *tx_stats;
+ struct ieee80211_sta *sta;
+ struct ath10k_peer *peer;
+ u16 log_type = __le16_to_cpu(hdr->log_type);
+ u32 peer_id = 0, i;
+
+ if (log_type != ATH_PKTLOG_TYPE_TX_STAT)
+ return;
+
+ tx_stats = (struct ath10k_10_2_peer_tx_stats *)((hdr->payload) +
+ ATH10K_10_2_TX_STATS_OFFSET);
+
+ if (!tx_stats->tx_ppdu_cnt)
+ return;
+
+ peer_id = tx_stats->peer_id;
+
+ rcu_read_lock();
+ spin_lock_bh(&ar->data_lock);
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer) {
+ ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n",
+ peer_id);
+ goto out;
+ }
+
+ sta = peer->sta;
+ for (i = 0; i < tx_stats->tx_ppdu_cnt; i++) {
+ p_tx_stats->succ_bytes =
+ __le16_to_cpu(tx_stats->success_bytes[i]);
+ p_tx_stats->retry_bytes =
+ __le16_to_cpu(tx_stats->retry_bytes[i]);
+ p_tx_stats->failed_bytes =
+ __le16_to_cpu(tx_stats->failed_bytes[i]);
+ p_tx_stats->ratecode = tx_stats->ratecode[i];
+ p_tx_stats->flags = tx_stats->flags[i];
+ p_tx_stats->succ_pkts = tx_stats->success_pkts[i];
+ p_tx_stats->retry_pkts = tx_stats->retry_pkts[i];
+ p_tx_stats->failed_pkts = tx_stats->failed_pkts[i];
+
+ ath10k_update_per_peer_tx_stats(ar, sta, p_tx_stats);
+ }
+ spin_unlock_bh(&ar->data_lock);
+ rcu_read_unlock();
+
+ return;
+
+out:
+ spin_unlock_bh(&ar->data_lock);
+ rcu_read_unlock();
+}
+
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
@@ -2566,6 +2622,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
skb->len -
offsetof(struct htt_resp,
pktlog_msg.payload));
+
+ if (ath10k_peer_stats_enabled(ar))
+ ath10k_fetch_10_2_tx_stats(ar,
+ resp->pktlog_msg.payload);
break;
}
case HTT_T2H_MSG_TYPE_RX_FLUSH: {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 884543026f3a..7b4a1d21c187 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7546,6 +7546,16 @@ struct ath10k_mac_change_chanctx_arg {
arvif->vdev_id, ret);
}
+ if (ath10k_peer_stats_enabled(ar)) {
+ ar->pktlog_filter |= ATH10K_PKTLOG_PEER_STATS;
+ ret = ath10k_wmi_pdev_pktlog_enable(ar,
+ ar->pktlog_filter);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable pktlog %d\n", ret);
+ goto err_stop;
+ }
+ }
+
mutex_unlock(&ar->conf_mutex);
return 0;
--
1.7.9.5
From: Anilkumar Kolli <[email protected]>
Remove CONFIG_MAC80211_DEBUGFS dependency on ath10k_sta_statistics().
ath10k_sta_statistics() has per sta tx/rx stats and this should not
be dependent on MAC80211_DEBUGFS.
No changes in functionality.
Signed-off-by: Anilkumar Kolli <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 2 +-
drivers/net/wireless/ath/ath10k/debug.h | 3 ---
drivers/net/wireless/ath/ath10k/debugfs_sta.c | 27 ----------------------
drivers/net/wireless/ath/ath10k/mac.c | 30 ++++++++++++++++++++++++-
4 files changed, 30 insertions(+), 32 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 643041ef3271..15e386d091a4 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -364,11 +364,11 @@ struct ath10k_sta {
struct rate_info txrate;
struct work_struct update_wk;
+ u64 rx_duration;
#ifdef CONFIG_MAC80211_DEBUGFS
/* protected by conf_mutex */
bool aggr_mode;
- u64 rx_duration;
#endif
};
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 548ad5483a4a..dd82a61ed1c8 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -190,9 +190,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats);
-void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct station_info *sinfo);
#else
static inline
void ath10k_sta_update_rx_duration(struct ath10k *ar,
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index d59ac6b83340..ff96f70d2282 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -65,33 +65,6 @@ void ath10k_sta_update_rx_duration(struct ath10k *ar,
ath10k_sta_update_stats_rx_duration(ar, stats);
}
-void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct station_info *sinfo)
-{
- struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
- struct ath10k *ar = arsta->arvif->ar;
-
- if (!ath10k_peer_stats_enabled(ar))
- return;
-
- sinfo->rx_duration = arsta->rx_duration;
- sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
-
- if (!arsta->txrate.legacy && !arsta->txrate.nss)
- return;
-
- if (arsta->txrate.legacy) {
- sinfo->txrate.legacy = arsta->txrate.legacy;
- } else {
- sinfo->txrate.mcs = arsta->txrate.mcs;
- sinfo->txrate.nss = arsta->txrate.nss;
- sinfo->txrate.bw = arsta->txrate.bw;
- }
- sinfo->txrate.flags = arsta->txrate.flags;
- sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE;
-}
-
static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 06383e70e009..884543026f3a 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7630,6 +7630,34 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
peer->removed = true;
}
+static void ath10k_sta_statistics(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo)
+{
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+
+ if (!ath10k_peer_stats_enabled(ar))
+ return;
+
+ sinfo->rx_duration = arsta->rx_duration;
+ sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
+
+ if (!arsta->txrate.legacy && !arsta->txrate.nss)
+ return;
+
+ if (arsta->txrate.legacy) {
+ sinfo->txrate.legacy = arsta->txrate.legacy;
+ } else {
+ sinfo->txrate.mcs = arsta->txrate.mcs;
+ sinfo->txrate.nss = arsta->txrate.nss;
+ sinfo->txrate.bw = arsta->txrate.bw;
+ }
+ sinfo->txrate.flags = arsta->txrate.flags;
+ sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE;
+}
+
static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_mac_op_tx,
.wake_tx_queue = ath10k_mac_op_wake_tx_queue,
@@ -7671,6 +7699,7 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
.unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx,
.switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx,
.sta_pre_rcu_remove = ath10k_mac_op_sta_pre_rcu_remove,
+ .sta_statistics = ath10k_sta_statistics,
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
@@ -7681,7 +7710,6 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = ath10k_sta_add_debugfs,
- .sta_statistics = ath10k_sta_statistics,
#endif
};
--
1.7.9.5
[email protected] wrote:
> Remove CONFIG_MAC80211_DEBUGFS dependency on ath10k_sta_statistics().
> ath10k_sta_statistics() has per sta tx/rx stats and this should not
> be dependent on MAC80211_DEBUGFS.
>
> No changes in functionality.
>
> Signed-off-by: Anilkumar Kolli <[email protected]>
> Signed-off-by: Kalle Valo <[email protected]>
3 patches applied to ath-next branch of ath.git, thanks.
6a7f891178c2 ath10k: remove MAC80211_DEBUGFS dependency on ath10k_sta_statistics
7f9befbb555d ath10k: move pktlog_filter out of ath10k_debug
e8123bb74c4e ath10k: add per peer tx stats support for 10.2.4
--
https://patchwork.kernel.org/patch/10092915/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
From: Anilkumar Kolli <[email protected]>
Move pktlog_filter from struct ath10k_debug to struct ath10k
so that pktlog can be enabled even when debugfs is not
enabled, needed to enable peer tx stats for 10.2.4.
No changes in functionality.
Signed-off-by: Anilkumar Kolli <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 2 +-
drivers/net/wireless/ath/ath10k/debug.c | 16 ++++++++--------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 15e386d091a4..eac9737ee407 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -488,7 +488,6 @@ struct ath10k_debug {
/* protected by conf_mutex */
u64 fw_dbglog_mask;
u32 fw_dbglog_level;
- u32 pktlog_filter;
u32 reg_addr;
u32 nf_cal_period;
void *cal_data;
@@ -963,6 +962,7 @@ struct ath10k {
} spectral;
#endif
+ u32 pktlog_filter;
struct {
/* protected by conf_mutex */
struct ath10k_fw_components utf_mode_fw;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index df514507d3f1..e278300b4f14 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1950,14 +1950,14 @@ int ath10k_debug_start(struct ath10k *ar)
ret);
}
- if (ar->debug.pktlog_filter) {
+ if (ar->pktlog_filter) {
ret = ath10k_wmi_pdev_pktlog_enable(ar,
- ar->debug.pktlog_filter);
+ ar->pktlog_filter);
if (ret)
/* not serious */
ath10k_warn(ar,
"failed to enable pktlog filter %x: %d\n",
- ar->debug.pktlog_filter, ret);
+ ar->pktlog_filter, ret);
} else {
ret = ath10k_wmi_pdev_pktlog_disable(ar);
if (ret)
@@ -2097,12 +2097,12 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH10K_STATE_ON) {
- ar->debug.pktlog_filter = filter;
+ ar->pktlog_filter = filter;
ret = count;
goto out;
}
- if (filter == ar->debug.pktlog_filter) {
+ if (filter == ar->pktlog_filter) {
ret = count;
goto out;
}
@@ -2111,7 +2111,7 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
if (ret) {
ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
- ar->debug.pktlog_filter, ret);
+ ar->pktlog_filter, ret);
goto out;
}
} else {
@@ -2122,7 +2122,7 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
}
}
- ar->debug.pktlog_filter = filter;
+ ar->pktlog_filter = filter;
ret = count;
out:
@@ -2139,7 +2139,7 @@ static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
mutex_lock(&ar->conf_mutex);
len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
- ar->debug.pktlog_filter);
+ ar->pktlog_filter);
mutex_unlock(&ar->conf_mutex);
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
--
1.7.9.5