aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k
diff options
context:
space:
mode:
authorAnilkumar Kolli <akolli@qti.qualcomm.com>2016-11-23 09:58:10 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2016-11-23 14:40:02 -0500
commitcec17c382140a17ad54853a4b57a84588f090806 (patch)
treee55f453a49817441976d84c080f0eea453c0d62e /drivers/net/wireless/ath/ath10k
parent3fea18d079e2f1f50bc2a37db826c9e6e8a4003e (diff)
ath10k: add per peer htt tx stats support for 10.4
Per peer tx stats are part of 'HTT_10_4_T2H_MSG_TYPE_PEER_STATS' event, Firmware sends one HTT event for every four PPDUs. HTT payload has success pkts/bytes, failed pkts/bytes, retry pkts/bytes and rate info per ppdu. Peer stats are enabled through 'WMI_SERVICE_PEER_STATS', which are nowadays enabled by default. Parse peer stats and update the tx rate information per STA. tx rate, Peer stats are tested on QCA4019 with Firmware version 10.4-3.2.1-00028. Signed-off-by: Anilkumar Kolli <akolli@qti.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k')
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h17
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h25
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c125
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h10
5 files changed, 178 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 018fc22d6056..6f2608a501e2 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -337,6 +337,7 @@ struct ath10k_sta {
337 u32 nss; 337 u32 nss;
338 u32 smps; 338 u32 smps;
339 u16 peer_id; 339 u16 peer_id;
340 struct rate_info txrate;
340 341
341 struct work_struct update_wk; 342 struct work_struct update_wk;
342 343
@@ -692,6 +693,21 @@ struct ath10k_fw_components {
692 struct ath10k_fw_file fw_file; 693 struct ath10k_fw_file fw_file;
693}; 694};
694 695
696struct ath10k_per_peer_tx_stats {
697 u32 succ_bytes;
698 u32 retry_bytes;
699 u32 failed_bytes;
700 u8 ratecode;
701 u8 flags;
702 u16 peer_id;
703 u16 succ_pkts;
704 u16 retry_pkts;
705 u16 failed_pkts;
706 u16 duration;
707 u32 reserved1;
708 u32 reserved2;
709};
710
695struct ath10k { 711struct ath10k {
696 struct ath_common ath_common; 712 struct ath_common ath_common;
697 struct ieee80211_hw *hw; 713 struct ieee80211_hw *hw;
@@ -905,6 +921,7 @@ struct ath10k {
905 921
906 struct ath10k_thermal thermal; 922 struct ath10k_thermal thermal;
907 struct ath10k_wow wow; 923 struct ath10k_wow wow;
924 struct ath10k_per_peer_tx_stats peer_tx_stats;
908 925
909 /* NAPI */ 926 /* NAPI */
910 struct net_device napi_dev; 927 struct net_device napi_dev;
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 130cd9502021..cd160b16db1e 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -137,6 +137,8 @@ static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = {
137 HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, 137 HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
138 [HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] = 138 [HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] =
139 HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND, 139 HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
140 [HTT_10_4_T2H_MSG_TYPE_PEER_STATS] =
141 HTT_T2H_MSG_TYPE_PEER_STATS,
140}; 142};
141 143
142int ath10k_htt_connect(struct ath10k_htt *htt) 144int ath10k_htt_connect(struct ath10k_htt *htt)
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 0d2ed09f202b..164eb3a10566 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -419,6 +419,7 @@ enum htt_10_4_t2h_msg_type {
419 HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18, 419 HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18,
420 /* 0x19 to 0x2f are reserved */ 420 /* 0x19 to 0x2f are reserved */
421 HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND = 0x30, 421 HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND = 0x30,
422 HTT_10_4_T2H_MSG_TYPE_PEER_STATS = 0x31,
422 /* keep this last */ 423 /* keep this last */
423 HTT_10_4_T2H_NUM_MSGS 424 HTT_10_4_T2H_NUM_MSGS
424}; 425};
@@ -453,6 +454,7 @@ enum htt_t2h_msg_type {
453 HTT_T2H_MSG_TYPE_TX_FETCH_IND, 454 HTT_T2H_MSG_TYPE_TX_FETCH_IND,
454 HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM, 455 HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
455 HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND, 456 HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
457 HTT_T2H_MSG_TYPE_PEER_STATS,
456 /* keep this last */ 458 /* keep this last */
457 HTT_T2H_NUM_MSGS 459 HTT_T2H_NUM_MSGS
458}; 460};
@@ -1470,6 +1472,28 @@ struct htt_channel_change {
1470 __le32 phymode; 1472 __le32 phymode;
1471} __packed; 1473} __packed;
1472 1474
1475struct htt_per_peer_tx_stats_ind {
1476 __le32 succ_bytes;
1477 __le32 retry_bytes;
1478 __le32 failed_bytes;
1479 u8 ratecode;
1480 u8 flags;
1481 __le16 peer_id;
1482 __le16 succ_pkts;
1483 __le16 retry_pkts;
1484 __le16 failed_pkts;
1485 __le16 tx_duration;
1486 __le32 reserved1;
1487 __le32 reserved2;
1488} __packed;
1489
1490struct htt_peer_tx_stats {
1491 u8 num_ppdu;
1492 u8 ppdu_len;
1493 u8 version;
1494 u8 payload[0];
1495} __packed;
1496
1473union htt_rx_pn_t { 1497union htt_rx_pn_t {
1474 /* WEP: 24-bit PN */ 1498 /* WEP: 24-bit PN */
1475 u32 pn24; 1499 u32 pn24;
@@ -1521,6 +1545,7 @@ struct htt_resp {
1521 struct htt_tx_fetch_confirm tx_fetch_confirm; 1545 struct htt_tx_fetch_confirm tx_fetch_confirm;
1522 struct htt_tx_mode_switch_ind tx_mode_switch_ind; 1546 struct htt_tx_mode_switch_ind tx_mode_switch_ind;
1523 struct htt_channel_change chan_change; 1547 struct htt_channel_change chan_change;
1548 struct htt_peer_tx_stats peer_tx_stats;
1524 }; 1549 };
1525} __packed; 1550} __packed;
1526 1551
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 285b235268d7..86d082cf4eef 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2194,6 +2194,128 @@ void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
2194 dev_kfree_skb_any(skb); 2194 dev_kfree_skb_any(skb);
2195} 2195}
2196 2196
2197static inline bool is_valid_legacy_rate(u8 rate)
2198{
2199 static const u8 legacy_rates[] = {1, 2, 5, 11, 6, 9, 12,
2200 18, 24, 36, 48, 54};
2201 int i;
2202
2203 for (i = 0; i < ARRAY_SIZE(legacy_rates); i++) {
2204 if (rate == legacy_rates[i])
2205 return true;
2206 }
2207
2208 return false;
2209}
2210
2211static void
2212ath10k_update_per_peer_tx_stats(struct ath10k *ar,
2213 struct ieee80211_sta *sta,
2214 struct ath10k_per_peer_tx_stats *peer_stats)
2215{
2216 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
2217 u8 rate = 0, sgi;
2218 struct rate_info txrate;
2219
2220 lockdep_assert_held(&ar->data_lock);
2221
2222 txrate.flags = ATH10K_HW_PREAMBLE(peer_stats->ratecode);
2223 txrate.bw = ATH10K_HW_BW(peer_stats->flags);
2224 txrate.nss = ATH10K_HW_NSS(peer_stats->ratecode);
2225 txrate.mcs = ATH10K_HW_MCS_RATE(peer_stats->ratecode);
2226 sgi = ATH10K_HW_GI(peer_stats->flags);
2227
2228 if (((txrate.flags == WMI_RATE_PREAMBLE_HT) ||
2229 (txrate.flags == WMI_RATE_PREAMBLE_VHT)) && txrate.mcs > 9) {
2230 ath10k_warn(ar, "Invalid mcs %hhd peer stats", txrate.mcs);
2231 return;
2232 }
2233
2234 if (txrate.flags == WMI_RATE_PREAMBLE_CCK ||
2235 txrate.flags == WMI_RATE_PREAMBLE_OFDM) {
2236 rate = ATH10K_HW_LEGACY_RATE(peer_stats->ratecode);
2237
2238 if (!is_valid_legacy_rate(rate)) {
2239 ath10k_warn(ar, "Invalid legacy rate %hhd peer stats",
2240 rate);
2241 return;
2242 }
2243
2244 /* This is hacky, FW sends CCK rate 5.5Mbps as 6 */
2245 rate *= 10;
2246 if (rate == 60 && txrate.flags == WMI_RATE_PREAMBLE_CCK)
2247 rate = rate - 5;
2248 arsta->txrate.legacy = rate * 10;
2249 } else if (txrate.flags == WMI_RATE_PREAMBLE_HT) {
2250 arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
2251 arsta->txrate.mcs = txrate.mcs;
2252 } else {
2253 arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
2254 arsta->txrate.mcs = txrate.mcs;
2255 }
2256
2257 if (sgi)
2258 arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2259
2260 arsta->txrate.nss = txrate.nss;
2261 arsta->txrate.bw = txrate.bw + RATE_INFO_BW_20;
2262}
2263
2264static void ath10k_htt_fetch_peer_stats(struct ath10k *ar,
2265 struct sk_buff *skb)
2266{
2267 struct htt_resp *resp = (struct htt_resp *)skb->data;
2268 struct ath10k_per_peer_tx_stats *p_tx_stats = &ar->peer_tx_stats;
2269 struct htt_per_peer_tx_stats_ind *tx_stats;
2270 struct ieee80211_sta *sta;
2271 struct ath10k_peer *peer;
2272 int peer_id, i;
2273 u8 ppdu_len, num_ppdu;
2274
2275 num_ppdu = resp->peer_tx_stats.num_ppdu;
2276 ppdu_len = resp->peer_tx_stats.ppdu_len * sizeof(__le32);
2277
2278 if (skb->len < sizeof(struct htt_resp_hdr) + num_ppdu * ppdu_len) {
2279 ath10k_warn(ar, "Invalid peer stats buf length %d\n", skb->len);
2280 return;
2281 }
2282
2283 tx_stats = (struct htt_per_peer_tx_stats_ind *)
2284 (resp->peer_tx_stats.payload);
2285 peer_id = __le16_to_cpu(tx_stats->peer_id);
2286
2287 rcu_read_lock();
2288 spin_lock_bh(&ar->data_lock);
2289 peer = ath10k_peer_find_by_id(ar, peer_id);
2290 if (!peer) {
2291 ath10k_warn(ar, "Invalid peer id %d peer stats buffer\n",
2292 peer_id);
2293 goto out;
2294 }
2295
2296 sta = peer->sta;
2297 for (i = 0; i < num_ppdu; i++) {
2298 tx_stats = (struct htt_per_peer_tx_stats_ind *)
2299 (resp->peer_tx_stats.payload + i * ppdu_len);
2300
2301 p_tx_stats->succ_bytes = __le32_to_cpu(tx_stats->succ_bytes);
2302 p_tx_stats->retry_bytes = __le32_to_cpu(tx_stats->retry_bytes);
2303 p_tx_stats->failed_bytes =
2304 __le32_to_cpu(tx_stats->failed_bytes);
2305 p_tx_stats->ratecode = tx_stats->ratecode;
2306 p_tx_stats->flags = tx_stats->flags;
2307 p_tx_stats->succ_pkts = __le16_to_cpu(tx_stats->succ_pkts);
2308 p_tx_stats->retry_pkts = __le16_to_cpu(tx_stats->retry_pkts);
2309 p_tx_stats->failed_pkts = __le16_to_cpu(tx_stats->failed_pkts);
2310
2311 ath10k_update_per_peer_tx_stats(ar, sta, p_tx_stats);
2312 }
2313
2314out:
2315 spin_unlock_bh(&ar->data_lock);
2316 rcu_read_unlock();
2317}
2318
2197bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) 2319bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
2198{ 2320{
2199 struct ath10k_htt *htt = &ar->htt; 2321 struct ath10k_htt *htt = &ar->htt;
@@ -2354,6 +2476,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
2354 case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND: 2476 case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND:
2355 ath10k_htt_rx_tx_mode_switch_ind(ar, skb); 2477 ath10k_htt_rx_tx_mode_switch_ind(ar, skb);
2356 break; 2478 break;
2479 case HTT_T2H_MSG_TYPE_PEER_STATS:
2480 ath10k_htt_fetch_peer_stats(ar, skb);
2481 break;
2357 case HTT_T2H_MSG_TYPE_EN_STATS: 2482 case HTT_T2H_MSG_TYPE_EN_STATS:
2358 default: 2483 default:
2359 ath10k_warn(ar, "htt event (%d) not handled\n", 2484 ath10k_warn(ar, "htt event (%d) not handled\n",
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 3a73b5cc1551..5d3dff95b2e5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4603,9 +4603,17 @@ enum wmi_rate_preamble {
4603 4603
4604#define ATH10K_HW_NSS(rate) (1 + (((rate) >> 4) & 0x3)) 4604#define ATH10K_HW_NSS(rate) (1 + (((rate) >> 4) & 0x3))
4605#define ATH10K_HW_PREAMBLE(rate) (((rate) >> 6) & 0x3) 4605#define ATH10K_HW_PREAMBLE(rate) (((rate) >> 6) & 0x3)
4606#define ATH10K_HW_RATECODE(rate, nss, preamble) \ 4606#define ATH10K_HW_MCS_RATE(rate) ((rate) & 0xf)
4607#define ATH10K_HW_LEGACY_RATE(rate) ((rate) & 0x3f)
4608#define ATH10K_HW_BW(flags) (((flags) >> 3) & 0x3)
4609#define ATH10K_HW_GI(flags) (((flags) >> 5) & 0x1)
4610#define ATH10K_HW_RATECODE(rate, nss, preamble) \
4607 (((preamble) << 6) | ((nss) << 4) | (rate)) 4611 (((preamble) << 6) | ((nss) << 4) | (rate))
4608 4612
4613#define VHT_MCS_NUM 10
4614#define VHT_BW_NUM 4
4615#define VHT_NSS_NUM 4
4616
4609/* Value to disable fixed rate setting */ 4617/* Value to disable fixed rate setting */
4610#define WMI_FIXED_RATE_NONE (0xff) 4618#define WMI_FIXED_RATE_NONE (0xff)
4611 4619