diff options
author | Anilkumar Kolli <akolli@qti.qualcomm.com> | 2017-12-05 08:31:25 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2017-12-14 10:26:41 -0500 |
commit | e8123bb74c4ef05027e64124f214b8f01dd13352 (patch) | |
tree | 6783e6042525185b1f392f9be30f9556bee9cd94 | |
parent | 7f9befbb555d27df98ae51d46d06e454a1f531c0 (diff) |
ath10k: add per peer tx stats support for 10.2.4
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 <akolli@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_rx.c | 60 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 10 |
4 files changed, 104 insertions, 1 deletions
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 { | |||
51 | ATH10K_PKTLOG_RCFIND = 0x000000004, | 51 | ATH10K_PKTLOG_RCFIND = 0x000000004, |
52 | ATH10K_PKTLOG_RCUPDATE = 0x000000008, | 52 | ATH10K_PKTLOG_RCUPDATE = 0x000000008, |
53 | ATH10K_PKTLOG_DBG_PRINT = 0x000000010, | 53 | ATH10K_PKTLOG_DBG_PRINT = 0x000000010, |
54 | ATH10K_PKTLOG_ANY = 0x00000001f, | 54 | ATH10K_PKTLOG_PEER_STATS = 0x000000040, |
55 | ATH10K_PKTLOG_ANY = 0x00000005f, | ||
55 | }; | 56 | }; |
56 | 57 | ||
57 | enum ath10k_dbg_aggr_mode { | 58 | enum ath10k_dbg_aggr_mode { |
@@ -60,6 +61,21 @@ enum ath10k_dbg_aggr_mode { | |||
60 | ATH10K_DBG_AGGR_MODE_MAX, | 61 | ATH10K_DBG_AGGR_MODE_MAX, |
61 | }; | 62 | }; |
62 | 63 | ||
64 | /* Types of packet log events */ | ||
65 | enum ath_pktlog_type { | ||
66 | ATH_PKTLOG_TYPE_TX_CTRL = 1, | ||
67 | ATH_PKTLOG_TYPE_TX_STAT, | ||
68 | }; | ||
69 | |||
70 | struct ath10k_pktlog_hdr { | ||
71 | __le16 flags; | ||
72 | __le16 missed_cnt; | ||
73 | __le16 log_type; /* Type of log information foll this header */ | ||
74 | __le16 size; /* Size of variable length log information in bytes */ | ||
75 | __le32 timestamp; | ||
76 | u8 payload[0]; | ||
77 | } __packed; | ||
78 | |||
63 | /* FIXME: How to calculate the buffer size sanely? */ | 79 | /* FIXME: How to calculate the buffer size sanely? */ |
64 | #define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024) | 80 | #define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024) |
65 | 81 | ||
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 7d6143523634..7bd93d627f6b 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 { | |||
1497 | u8 payload[0]; | 1497 | u8 payload[0]; |
1498 | } __packed; | 1498 | } __packed; |
1499 | 1499 | ||
1500 | #define ATH10K_10_2_TX_STATS_OFFSET 136 | ||
1501 | #define PEER_STATS_FOR_NO_OF_PPDUS 4 | ||
1502 | |||
1503 | struct ath10k_10_2_peer_tx_stats { | ||
1504 | u8 ratecode[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1505 | u8 success_pkts[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1506 | __le16 success_bytes[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1507 | u8 retry_pkts[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1508 | __le16 retry_bytes[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1509 | u8 failed_pkts[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1510 | __le16 failed_bytes[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1511 | u8 flags[PEER_STATS_FOR_NO_OF_PPDUS]; | ||
1512 | __le32 tx_duration; | ||
1513 | u8 tx_ppdu_cnt; | ||
1514 | u8 peer_id; | ||
1515 | } __packed; | ||
1516 | |||
1500 | union htt_rx_pn_t { | 1517 | union htt_rx_pn_t { |
1501 | /* WEP: 24-bit PN */ | 1518 | /* WEP: 24-bit PN */ |
1502 | u32 pn24; | 1519 | u32 pn24; |
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 07f7960ab70c..620ed7dca836 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c | |||
@@ -2453,6 +2453,62 @@ out: | |||
2453 | rcu_read_unlock(); | 2453 | rcu_read_unlock(); |
2454 | } | 2454 | } |
2455 | 2455 | ||
2456 | static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data) | ||
2457 | { | ||
2458 | struct ath10k_pktlog_hdr *hdr = (struct ath10k_pktlog_hdr *)data; | ||
2459 | struct ath10k_per_peer_tx_stats *p_tx_stats = &ar->peer_tx_stats; | ||
2460 | struct ath10k_10_2_peer_tx_stats *tx_stats; | ||
2461 | struct ieee80211_sta *sta; | ||
2462 | struct ath10k_peer *peer; | ||
2463 | u16 log_type = __le16_to_cpu(hdr->log_type); | ||
2464 | u32 peer_id = 0, i; | ||
2465 | |||
2466 | if (log_type != ATH_PKTLOG_TYPE_TX_STAT) | ||
2467 | return; | ||
2468 | |||
2469 | tx_stats = (struct ath10k_10_2_peer_tx_stats *)((hdr->payload) + | ||
2470 | ATH10K_10_2_TX_STATS_OFFSET); | ||
2471 | |||
2472 | if (!tx_stats->tx_ppdu_cnt) | ||
2473 | return; | ||
2474 | |||
2475 | peer_id = tx_stats->peer_id; | ||
2476 | |||
2477 | rcu_read_lock(); | ||
2478 | spin_lock_bh(&ar->data_lock); | ||
2479 | peer = ath10k_peer_find_by_id(ar, peer_id); | ||
2480 | if (!peer) { | ||
2481 | ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n", | ||
2482 | peer_id); | ||
2483 | goto out; | ||
2484 | } | ||
2485 | |||
2486 | sta = peer->sta; | ||
2487 | for (i = 0; i < tx_stats->tx_ppdu_cnt; i++) { | ||
2488 | p_tx_stats->succ_bytes = | ||
2489 | __le16_to_cpu(tx_stats->success_bytes[i]); | ||
2490 | p_tx_stats->retry_bytes = | ||
2491 | __le16_to_cpu(tx_stats->retry_bytes[i]); | ||
2492 | p_tx_stats->failed_bytes = | ||
2493 | __le16_to_cpu(tx_stats->failed_bytes[i]); | ||
2494 | p_tx_stats->ratecode = tx_stats->ratecode[i]; | ||
2495 | p_tx_stats->flags = tx_stats->flags[i]; | ||
2496 | p_tx_stats->succ_pkts = tx_stats->success_pkts[i]; | ||
2497 | p_tx_stats->retry_pkts = tx_stats->retry_pkts[i]; | ||
2498 | p_tx_stats->failed_pkts = tx_stats->failed_pkts[i]; | ||
2499 | |||
2500 | ath10k_update_per_peer_tx_stats(ar, sta, p_tx_stats); | ||
2501 | } | ||
2502 | spin_unlock_bh(&ar->data_lock); | ||
2503 | rcu_read_unlock(); | ||
2504 | |||
2505 | return; | ||
2506 | |||
2507 | out: | ||
2508 | spin_unlock_bh(&ar->data_lock); | ||
2509 | rcu_read_unlock(); | ||
2510 | } | ||
2511 | |||
2456 | bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) | 2512 | bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) |
2457 | { | 2513 | { |
2458 | struct ath10k_htt *htt = &ar->htt; | 2514 | struct ath10k_htt *htt = &ar->htt; |
@@ -2570,6 +2626,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) | |||
2570 | skb->len - | 2626 | skb->len - |
2571 | offsetof(struct htt_resp, | 2627 | offsetof(struct htt_resp, |
2572 | pktlog_msg.payload)); | 2628 | pktlog_msg.payload)); |
2629 | |||
2630 | if (ath10k_peer_stats_enabled(ar)) | ||
2631 | ath10k_fetch_10_2_tx_stats(ar, | ||
2632 | resp->pktlog_msg.payload); | ||
2573 | break; | 2633 | break; |
2574 | } | 2634 | } |
2575 | case HTT_T2H_MSG_TYPE_RX_FLUSH: { | 2635 | 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 18b9b374f4f6..ef2ed409ad4f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -7546,6 +7546,16 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
7546 | arvif->vdev_id, ret); | 7546 | arvif->vdev_id, ret); |
7547 | } | 7547 | } |
7548 | 7548 | ||
7549 | if (ath10k_peer_stats_enabled(ar)) { | ||
7550 | ar->pktlog_filter |= ATH10K_PKTLOG_PEER_STATS; | ||
7551 | ret = ath10k_wmi_pdev_pktlog_enable(ar, | ||
7552 | ar->pktlog_filter); | ||
7553 | if (ret) { | ||
7554 | ath10k_warn(ar, "failed to enable pktlog %d\n", ret); | ||
7555 | goto err_stop; | ||
7556 | } | ||
7557 | } | ||
7558 | |||
7549 | mutex_unlock(&ar->conf_mutex); | 7559 | mutex_unlock(&ar->conf_mutex); |
7550 | return 0; | 7560 | return 0; |
7551 | 7561 | ||