aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnilkumar Kolli <akolli@qti.qualcomm.com>2017-12-05 08:31:25 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2017-12-14 10:26:41 -0500
commite8123bb74c4ef05027e64124f214b8f01dd13352 (patch)
tree6783e6042525185b1f392f9be30f9556bee9cd94
parent7f9befbb555d27df98ae51d46d06e454a1f531c0 (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.h18
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h17
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c60
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c10
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
57enum ath10k_dbg_aggr_mode { 58enum 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 */
65enum ath_pktlog_type {
66 ATH_PKTLOG_TYPE_TX_CTRL = 1,
67 ATH_PKTLOG_TYPE_TX_STAT,
68};
69
70struct 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
1503struct 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
1500union htt_rx_pn_t { 1517union 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
2456static 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
2507out:
2508 spin_unlock_bh(&ar->data_lock);
2509 rcu_read_unlock();
2510}
2511
2456bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) 2512bool 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