qcacmn: Fix OFDMA stats counter
user info with delayed ba stats are stored and stats are updated later
on receiving BAR.
Change-Id: I574dd94d5a7db2160953b5d5d302eff18f4f8648
diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h
index 90c17af..8dc063e 100644
--- a/dp/inc/cdp_txrx_cmn_struct.h
+++ b/dp/inc/cdp_txrx_cmn_struct.h
@@ -1152,6 +1152,57 @@
};
/**
+ * struct cdp_delayed_tx_completion_ppdu_user - Delayed Tx PPDU completion
+ * per-user information
+ * @frame_ctrl: frame control field in 802.11 header
+ * @qos_ctrl: QoS control field in 802.11 header
+ * @mpdu_tried: number of mpdus tried
+ * @ltf_size: ltf_size
+ * @stbc: stbc
+ * @he_re: he_re (range extension)
+ * @txbf: txbf
+ * @bw: Transmission bandwidth
+ * <enum 2 transmit_bw_20_MHz>
+ * <enum 3 transmit_bw_40_MHz>
+ * <enum 4 transmit_bw_80_MHz>
+ * <enum 5 transmit_bw_160_MHz>
+ * @nss: NSS 1,2, ...8
+ * @mcs: MCS index
+ * @preamble: preamble
+ * @gi: guard interval 800/400/1600/3200 ns
+ * @dcm: dcm
+ * @ldpc: ldpc
+ * @ru_start: RU start index
+ * @ru_tones: RU tones length
+ * @is_mcast: MCAST or UCAST
+ * @user_pos: user position
+ * @mu_group_id: mu group id
+ */
+struct cdp_delayed_tx_completion_ppdu_user {
+ uint32_t frame_ctrl:16,
+ qos_ctrl:16;
+ uint32_t mpdu_tried_ucast:16,
+ mpdu_tried_mcast:16;
+ uint32_t ltf_size:2,
+ stbc:1,
+ he_re:1,
+ txbf:4,
+ bw:4,
+ nss:4,
+ mcs:4,
+ preamble:4,
+ gi:4,
+ dcm:1,
+ ldpc:1,
+ delayed_ba:1;
+ uint16_t ru_start;
+ uint16_t ru_tones;
+ bool is_mcast;
+ uint32_t user_pos;
+ uint32_t mu_group_id;
+};
+
+/**
* struct cdp_tx_completion_ppdu_user - Tx PPDU completion per-user information
* @completion_status: completion status - OK/Filter/Abort/Timeout
* @tid: TID number
@@ -1354,6 +1405,7 @@
* @ppdu_id: PPDU Id
* @ppdu_seq_id: ppdu sequence id for sojourn stats
* @vdev_id: VAP Id
+ * @bar_num_users: BA response user count, based on completion common TLV
* @num_users: Number of users
* @num_mpdu: Number of MPDUs in PPDU
* @num_msdu: Number of MSDUs in PPDU
@@ -1365,6 +1417,7 @@
* @ppdu_start_timestamp: TSF at PPDU start
* @ppdu_end_timestamp: TSF at PPDU end
* @ack_timestamp: TSF at the reception of ACK
+ * @delayed_ba: Delayed ba flag
* @user: per-User stats (array of per-user structures)
* @mpdu_q: queue of mpdu in a ppdu
*/
@@ -1372,6 +1425,7 @@
uint32_t ppdu_id;
uint32_t ppdu_seq_id;
uint16_t vdev_id;
+ uint16_t bar_num_users;
uint32_t num_users;
uint8_t last_usr_index;
uint32_t num_mpdu:9,
@@ -1385,6 +1439,7 @@
uint32_t ppdu_start_timestamp;
uint32_t ppdu_end_timestamp;
uint32_t ack_timestamp;
+ bool delayed_ba;
struct cdp_tx_completion_ppdu_user user[CDP_MU_MAX_USERS];
qdf_nbuf_queue_t mpdu_q;
};
diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h
index e6eaca6..6cb31b7 100644
--- a/dp/inc/cdp_txrx_stats_struct.h
+++ b/dp/inc/cdp_txrx_stats_struct.h
@@ -127,6 +127,39 @@
(((nssb) & CDP_TXRX_RATECODE_NSS_MASK) << CDP_TXRX_RATECODE_NSS_LSB) | \
(((premb) & CDP_TXRX_RATECODE_PREM_MASK) << CDP_TXRX_RATECODE_PREM_LSB))
+/*
+ * cdp_tx_transmit_type: Transmit type index
+ * SU: SU Transmit type index
+ * MU_MIMO: MU_MIMO Transmit type index
+ * MU_OFDMA: MU_OFDMA Transmit type index
+ * MU_MIMO_OFDMA: MU MIMO OFDMA Transmit type index
+ */
+enum cdp_tx_transmit_type {
+ SU = 0,
+ MU_MIMO,
+ MU_OFDMA,
+ MU_MIMO_OFDMA,
+};
+
+/*
+ * cdp_ru_index: Different RU index
+ *
+ * RU_26_INDEX : 26-tone Resource Unit index
+ * RU_52_INDEX : 52-tone Resource Unit index
+ * RU_106_INDEX: 106-tone Resource Unit index
+ * RU_242_INDEX: 242-tone Resource Unit index
+ * RU_484_INDEX: 484-tone Resource Unit index
+ * RU_996_INDEX: 996-tone Resource Unit index
+ */
+enum cdp_ru_index {
+ RU_26_INDEX = 0,
+ RU_52_INDEX,
+ RU_106_INDEX,
+ RU_242_INDEX,
+ RU_484_INDEX,
+ RU_996_INDEX,
+};
+
/* Different Packet Types */
enum cdp_packet_type {
DOT11_A = 0,
@@ -383,6 +416,19 @@
uint32_t mcs_count[MAX_MCS];
};
+/* struct cdp_tx_pkt_info - tx packet info
+ * num_msdu - successful msdu
+ * num_mpdu - successful mpdu from compltn common
+ * mpdu_tried - mpdu tried
+ *
+ * tx packet info counter field for mpdu success/tried and msdu
+ */
+struct cdp_tx_pkt_info {
+ uint32_t num_msdu;
+ uint32_t num_mpdu;
+ uint32_t mpdu_tried;
+};
+
/* struct cdp_tx_stats - tx stats
* @cdp_pkt_info comp_pkt: Pkt Info for which completions were received
* @cdp_pkt_info ucast: Unicast Packet Count
@@ -452,11 +498,11 @@
* @failed_retry_count: packets failed due to retry above 802.11 retry limit
* @retry_count: packets successfully send after one or more retry
* @multiple_retry_count: packets successfully sent after more than one retry
- * @transmit_type: tx transmit type
+ * @transmit_type: pkt info for tx transmit type
* @mu_group_id: mumimo mu group id
* @ru_start: RU start index
* @ru_tones: RU tones size
- * @ru_loc: RU location 26/ 52/ 106/ 242/ 484 counter
+ * @ru_loc: pkt info for RU location 26/ 52/ 106/ 242/ 484 counter
* @num_ppdu_cookie_valid : Number of comp received with valid ppdu cookie
*/
struct cdp_tx_stats {
@@ -538,11 +584,12 @@
uint32_t multiple_retry_count;
uint32_t last_tx_rate_used;
- uint32_t transmit_type[MAX_TRANSMIT_TYPES];
+ struct cdp_tx_pkt_info transmit_type[MAX_TRANSMIT_TYPES];
uint32_t mu_group_id[MAX_MU_GROUP_ID];
uint32_t ru_start;
uint32_t ru_tones;
- uint32_t ru_loc[MAX_RU_LOCATIONS];
+ struct cdp_tx_pkt_info ru_loc[MAX_RU_LOCATIONS];
+
uint32_t num_ppdu_cookie_valid;
};
@@ -1248,6 +1295,7 @@
* @tx_comp_histogram: Number of Tx completions per interrupt
* @rx_ind_histogram: Number of Rx ring descriptors reaped per interrupt
* @ppdu_stats_counter: ppdu stats counter
+ * @cdp_delayed_ba_not_recev: counter for delayed ba not received
* @htt_tx_pdev_stats: htt pdev stats for tx
* @htt_rx_pdev_stats: htt pdev stats for rx
*/
@@ -1293,6 +1341,7 @@
struct cdp_hist_tx_comp tx_comp_histogram;
struct cdp_hist_rx_ind rx_ind_histogram;
uint64_t ppdu_stats_counter[CDP_PPDU_STATS_MAX_TAG];
+ uint32_t cdp_delayed_ba_not_recev;
struct cdp_htt_tx_pdev_stats htt_tx_pdev_stats;
struct cdp_htt_rx_pdev_stats htt_rx_pdev_stats;
diff --git a/dp/wifi3.0/dp_htt.c b/dp/wifi3.0/dp_htt.c
index 349aca1..cbb4ccd 100644
--- a/dp/wifi3.0/dp_htt.c
+++ b/dp/wifi3.0/dp_htt.c
@@ -67,6 +67,108 @@
#ifdef FEATURE_PERPKT_INFO
/*
+ * dp_peer_copy_delay_stats() - copy ppdu stats to peer delayed stats.
+ * @peer: Datapath peer handle
+ * @ppdu: PPDU Descriptor
+ *
+ * Return: None
+ *
+ * on Tx data frame, we may get delayed ba set
+ * in htt_ppdu_stats_user_common_tlv. which mean we get Block Ack(BA) after we
+ * request Block Ack Request(BAR). Successful msdu is received only after Block
+ * Ack. To populate peer stats we need successful msdu(data frame).
+ * So we hold the Tx data stats on delayed_ba for stats update.
+ */
+static inline void
+dp_peer_copy_delay_stats(struct dp_peer *peer,
+ struct cdp_tx_completion_ppdu_user *ppdu)
+{
+ struct dp_pdev *pdev;
+ struct dp_vdev *vdev;
+
+ if (peer->last_delayed_ba) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "BA not yet recv for prev delayed ppdu[%d]\n",
+ peer->last_delayed_ba_ppduid);
+ vdev = peer->vdev;
+ if (vdev) {
+ pdev = vdev->pdev;
+ pdev->stats.cdp_delayed_ba_not_recev++;
+ }
+ }
+
+ peer->delayed_ba_ppdu_stats.ltf_size = ppdu->ltf_size;
+ peer->delayed_ba_ppdu_stats.stbc = ppdu->stbc;
+ peer->delayed_ba_ppdu_stats.he_re = ppdu->he_re;
+ peer->delayed_ba_ppdu_stats.txbf = ppdu->txbf;
+ peer->delayed_ba_ppdu_stats.bw = ppdu->bw;
+ peer->delayed_ba_ppdu_stats.nss = ppdu->nss;
+ peer->delayed_ba_ppdu_stats.preamble = ppdu->preamble;
+ peer->delayed_ba_ppdu_stats.gi = ppdu->gi;
+ peer->delayed_ba_ppdu_stats.dcm = ppdu->dcm;
+ peer->delayed_ba_ppdu_stats.ldpc = ppdu->ldpc;
+ peer->delayed_ba_ppdu_stats.dcm = ppdu->dcm;
+ peer->delayed_ba_ppdu_stats.mpdu_tried_ucast = ppdu->mpdu_tried_ucast;
+ peer->delayed_ba_ppdu_stats.mpdu_tried_mcast = ppdu->mpdu_tried_mcast;
+ peer->delayed_ba_ppdu_stats.frame_ctrl = ppdu->frame_ctrl;
+ peer->delayed_ba_ppdu_stats.qos_ctrl = ppdu->qos_ctrl;
+ peer->delayed_ba_ppdu_stats.dcm = ppdu->dcm;
+
+ peer->delayed_ba_ppdu_stats.ru_start = ppdu->ru_start;
+ peer->delayed_ba_ppdu_stats.ru_tones = ppdu->ru_tones;
+ peer->delayed_ba_ppdu_stats.is_mcast = ppdu->is_mcast;
+
+ peer->delayed_ba_ppdu_stats.user_pos = ppdu->user_pos;
+ peer->delayed_ba_ppdu_stats.mu_group_id = ppdu->mu_group_id;
+
+ peer->last_delayed_ba = true;
+}
+
+/*
+ * dp_peer_copy_stats_to_bar() - copy delayed stats to ppdu stats.
+ * @peer: Datapath peer handle
+ * @ppdu: PPDU Descriptor
+ *
+ * Return: None
+ *
+ * For Tx BAR, PPDU stats TLV include Block Ack info. PPDU info
+ * from Tx BAR frame not required to populate peer stats.
+ * But we need successful MPDU and MSDU to update previous
+ * transmitted Tx data frame. Overwrite ppdu stats with the previous
+ * stored ppdu stats.
+ */
+static void
+dp_peer_copy_stats_to_bar(struct dp_peer *peer,
+ struct cdp_tx_completion_ppdu_user *ppdu)
+{
+ ppdu->ltf_size = peer->delayed_ba_ppdu_stats.ltf_size;
+ ppdu->stbc = peer->delayed_ba_ppdu_stats.stbc;
+ ppdu->he_re = peer->delayed_ba_ppdu_stats.he_re;
+ ppdu->txbf = peer->delayed_ba_ppdu_stats.txbf;
+ ppdu->bw = peer->delayed_ba_ppdu_stats.bw;
+ ppdu->nss = peer->delayed_ba_ppdu_stats.nss;
+ ppdu->preamble = peer->delayed_ba_ppdu_stats.preamble;
+ ppdu->gi = peer->delayed_ba_ppdu_stats.gi;
+ ppdu->dcm = peer->delayed_ba_ppdu_stats.dcm;
+ ppdu->ldpc = peer->delayed_ba_ppdu_stats.ldpc;
+ ppdu->dcm = peer->delayed_ba_ppdu_stats.dcm;
+ ppdu->mpdu_tried_ucast = peer->delayed_ba_ppdu_stats.mpdu_tried_ucast;
+ ppdu->mpdu_tried_mcast = peer->delayed_ba_ppdu_stats.mpdu_tried_mcast;
+ ppdu->frame_ctrl = peer->delayed_ba_ppdu_stats.frame_ctrl;
+ ppdu->qos_ctrl = peer->delayed_ba_ppdu_stats.qos_ctrl;
+ ppdu->dcm = peer->delayed_ba_ppdu_stats.dcm;
+
+ ppdu->ru_start = peer->delayed_ba_ppdu_stats.ru_start;
+ ppdu->ru_tones = peer->delayed_ba_ppdu_stats.ru_tones;
+ ppdu->is_mcast = peer->delayed_ba_ppdu_stats.is_mcast;
+
+ ppdu->user_pos = peer->delayed_ba_ppdu_stats.user_pos;
+ ppdu->mu_group_id = peer->delayed_ba_ppdu_stats.mu_group_id;
+
+ peer->last_delayed_ba = false;
+}
+
+/*
* dp_tx_rate_stats_update() - Update rate per-peer statistics
* @peer: Datapath peer handle
* @ppdu: PPDU Descriptor
@@ -139,10 +241,14 @@
struct dp_pdev *pdev = peer->vdev->pdev;
uint8_t preamble, mcs;
uint16_t num_msdu;
+ uint16_t num_mpdu;
+ uint16_t mpdu_tried;
preamble = ppdu->preamble;
mcs = ppdu->mcs;
num_msdu = ppdu->num_msdu;
+ num_mpdu = ppdu->mpdu_success;
+ mpdu_tried = ppdu->mpdu_tried_ucast + ppdu->mpdu_tried_mcast;
/* If the peer statistics are already processed as part of
* per-MSDU completion handler, do not process these again in per-PPDU
@@ -176,27 +282,63 @@
DP_STATS_UPD(peer, tx.ru_start, ppdu->ru_start);
switch (ppdu->ru_tones) {
case RU_26:
- DP_STATS_INC(peer, tx.ru_loc[0], num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_26_INDEX].num_msdu,
+ num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_26_INDEX].num_mpdu,
+ num_mpdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_26_INDEX].mpdu_tried,
+ mpdu_tried);
break;
case RU_52:
- DP_STATS_INC(peer, tx.ru_loc[1], num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_52_INDEX].num_msdu,
+ num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_52_INDEX].num_mpdu,
+ num_mpdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_52_INDEX].mpdu_tried,
+ mpdu_tried);
break;
case RU_106:
- DP_STATS_INC(peer, tx.ru_loc[2], num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_106_INDEX].num_msdu,
+ num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_106_INDEX].num_mpdu,
+ num_mpdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_106_INDEX].mpdu_tried,
+ mpdu_tried);
break;
case RU_242:
- DP_STATS_INC(peer, tx.ru_loc[3], num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_242_INDEX].num_msdu,
+ num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_242_INDEX].num_mpdu,
+ num_mpdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_242_INDEX].mpdu_tried,
+ mpdu_tried);
break;
case RU_484:
- DP_STATS_INC(peer, tx.ru_loc[4], num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_484_INDEX].num_msdu,
+ num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_484_INDEX].num_mpdu,
+ num_mpdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_484_INDEX].mpdu_tried,
+ mpdu_tried);
break;
case RU_996:
- DP_STATS_INC(peer, tx.ru_loc[5], num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_996_INDEX].num_msdu,
+ num_msdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_996_INDEX].num_mpdu,
+ num_mpdu);
+ DP_STATS_INC(peer, tx.ru_loc[RU_996_INDEX].mpdu_tried,
+ mpdu_tried);
break;
}
}
- DP_STATS_INC(peer, tx.transmit_type[ppdu->ppdu_type], num_msdu);
+ DP_STATS_INC(peer, tx.transmit_type[ppdu->ppdu_type].num_msdu,
+ num_msdu);
+ DP_STATS_INC(peer, tx.transmit_type[ppdu->ppdu_type].num_mpdu,
+ num_mpdu);
+ DP_STATS_INC(peer, tx.transmit_type[ppdu->ppdu_type].mpdu_tried,
+ mpdu_tried);
+
DP_STATS_INC_PKT(peer, tx.comp_pkt,
num_msdu, (ppdu->success_bytes +
ppdu->retry_bytes + ppdu->failed_bytes));
@@ -1948,6 +2090,7 @@
if (HTT_PPDU_STATS_USER_COMMON_TLV_DELAYED_BA_GET(*tag_buf)) {
ppdu_user_desc->delayed_ba = 1;
+ ppdu_desc->delayed_ba = 1;
}
if (HTT_PPDU_STATS_USER_COMMON_TLV_MCAST_GET(*tag_buf)) {
@@ -1968,11 +2111,8 @@
HTT_PPDU_STATS_USER_COMMON_TLV_FRAME_CTRL_GET(*tag_buf);
ppdu_desc->frame_ctrl = ppdu_user_desc->frame_ctrl;
- if (ppdu_user_desc->delayed_ba) {
+ if (ppdu_user_desc->delayed_ba)
ppdu_user_desc->mpdu_success = 0;
- ppdu_user_desc->mpdu_tried_mcast = 0;
- ppdu_user_desc->mpdu_tried_ucast = 0;
- }
tag_buf += 3;
@@ -2244,6 +2384,19 @@
HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_IS_AMPDU_GET(*tag_buf);
ppdu_info->is_ampdu = ppdu_user_desc->is_ampdu;
+ /*
+ * increase successful mpdu counter from
+ * htt_ppdu_stats_user_cmpltn_common_tlv
+ */
+ ppdu_info->mpdu_compltn_common_tlv += ppdu_user_desc->mpdu_success;
+
+ /*
+ * MU BAR may send request to n users but we may received ack only from
+ * m users. To have count of number of users respond back, we have a
+ * separate counter bar_num_users per PPDU that get increment for every
+ * htt_ppdu_stats_user_cmpltn_common_tlv
+ */
+ ppdu_desc->bar_num_users++;
}
/*
@@ -2372,6 +2525,8 @@
tag_buf += 2;
ppdu_user_desc->success_bytes = *tag_buf;
+ /* increase successful mpdu counter */
+ ppdu_info->mpdu_ack_ba_tlv += ppdu_user_desc->num_mpdu;
}
/*
@@ -2683,6 +2838,7 @@
uint32_t tlv_bitmap_expected;
uint32_t tlv_bitmap_default;
uint16_t i;
+ uint32_t num_users;
ppdu_desc = (struct cdp_tx_completion_ppdu *)
qdf_nbuf_data(ppdu_info->nbuf);
@@ -2699,7 +2855,15 @@
}
tlv_bitmap_default = tlv_bitmap_expected;
- for (i = 0; i < ppdu_desc->num_users; i++) {
+
+ if (ppdu_desc->frame_type == CDP_PPDU_FTYPE_BAR) {
+ num_users = ppdu_desc->bar_num_users;
+ ppdu_desc->num_users = ppdu_desc->bar_num_users;
+ } else {
+ num_users = ppdu_desc->num_users;
+ }
+
+ for (i = 0; i < num_users; i++) {
ppdu_desc->num_mpdu += ppdu_desc->user[i].num_mpdu;
ppdu_desc->num_msdu += ppdu_desc->user[i].num_msdu;
@@ -2717,17 +2881,31 @@
HTT_PPDU_STATS_USER_STATUS_OK)
tlv_bitmap_expected = tlv_bitmap_expected & 0xFF;
- if (ppdu_info->tlv_bitmap != tlv_bitmap_expected) {
+ /*
+ * different frame like DATA, BAR or CTRL has different
+ * tlv bitmap expected. Apart from ACK_BA_STATUS TLV, we
+ * receive other tlv in-order/sequential from fw.
+ * Since ACK_BA_STATUS TLV come from Hardware it is
+ * asynchronous So we need to depend on some tlv to confirm
+ * all tlv is received for a ppdu.
+ * So we depend on both HTT_PPDU_STATS_COMMON_TLV and
+ * ACK_BA_STATUS_TLV.
+ */
+ if (!(ppdu_info->tlv_bitmap &
+ (1 << HTT_PPDU_STATS_COMMON_TLV)) ||
+ !(ppdu_info->tlv_bitmap &
+ (1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV))) {
dp_peer_unref_del_find_by_id(peer);
continue;
}
+
/**
* Update tx stats for data frames having Qos as well as
* non-Qos data tid
*/
if ((ppdu_desc->user[i].tid < CDP_DATA_TID_MAX ||
(ppdu_desc->user[i].tid == CDP_DATA_NON_QOS_TID)) &&
- (ppdu_desc->frame_type == CDP_PPDU_FTYPE_DATA)) {
+ (ppdu_desc->frame_type != CDP_PPDU_FTYPE_CTRL)) {
dp_tx_stats_update(pdev->soc, peer,
&ppdu_desc->user[i],
@@ -2839,6 +3017,15 @@
(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV)))
return ppdu_info;
+ /**
+ * apart from ACK BA STATUS TLV rest all comes in order
+ * so if tlv type not ACK BA STATUS TLV we can deliver
+ * ppdu_info
+ */
+ if (tlv_type ==
+ HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV)
+ return ppdu_info;
+
dp_ppdu_desc_deliver(pdev, ppdu_info);
} else {
return ppdu_info;
@@ -2913,6 +3100,8 @@
uint8_t *tlv_buf;
struct ppdu_info *ppdu_info = NULL;
struct cdp_tx_completion_ppdu *ppdu_desc = NULL;
+ struct dp_peer *peer;
+ uint32_t i = 0;
uint32_t *msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg);
@@ -2977,13 +3166,6 @@
tlv_bitmap_expected = HTT_PPDU_DEFAULT_TLV_BITMAP;
- ppdu_desc = ppdu_info->ppdu_desc;
- if (ppdu_desc &&
- ppdu_desc->user[ppdu_desc->last_usr_index].completion_status !=
- HTT_PPDU_STATS_USER_STATUS_OK) {
- tlv_bitmap_expected = tlv_bitmap_expected & 0xFF;
- }
-
if (pdev->tx_sniffer_enable || pdev->mcopy_mode) {
if (ppdu_info->is_ampdu)
tlv_bitmap_expected =
@@ -2991,6 +3173,85 @@
ppdu_info->tlv_bitmap);
}
+ ppdu_desc = ppdu_info->ppdu_desc;
+
+ if (!ppdu_desc)
+ return NULL;
+
+ if (ppdu_desc->user[ppdu_desc->last_usr_index].completion_status !=
+ HTT_PPDU_STATS_USER_STATUS_OK) {
+ tlv_bitmap_expected = tlv_bitmap_expected & 0xFF;
+ }
+
+ if (ppdu_desc->frame_type == CDP_PPDU_FTYPE_DATA &&
+ (ppdu_info->tlv_bitmap & (1 << HTT_PPDU_STATS_COMMON_TLV)) &&
+ ppdu_desc->delayed_ba) {
+ for (i = 0; i < ppdu_desc->num_users; i++) {
+ uint32_t ppdu_id;
+
+ ppdu_id = ppdu_desc->ppdu_id;
+ peer = dp_peer_find_by_id(pdev->soc,
+ ppdu_desc->user[i].peer_id);
+ /**
+ * This check is to make sure peer is not deleted
+ * after processing the TLVs.
+ */
+ if (!peer)
+ continue;
+
+ /**
+ * save delayed ba user info
+ */
+ if (ppdu_desc->user[i].delayed_ba) {
+ dp_peer_copy_delay_stats(peer,
+ &ppdu_desc->user[i]);
+ peer->last_delayed_ba_ppduid = ppdu_id;
+ }
+ dp_peer_unref_del_find_by_id(peer);
+ }
+ }
+
+ /*
+ * when frame type is BAR and STATS_COMMON_TLV is set
+ * copy the store peer delayed info to BAR status
+ */
+ if (ppdu_desc->frame_type == CDP_PPDU_FTYPE_BAR &&
+ (ppdu_info->tlv_bitmap & (1 << HTT_PPDU_STATS_COMMON_TLV))) {
+ for (i = 0; i < ppdu_desc->bar_num_users; i++) {
+ peer = dp_peer_find_by_id(pdev->soc,
+ ppdu_desc->user[i].peer_id);
+ /**
+ * This check is to make sure peer is not deleted
+ * after processing the TLVs.
+ */
+ if (!peer)
+ continue;
+
+ if (peer->last_delayed_ba) {
+ dp_peer_copy_stats_to_bar(peer,
+ &ppdu_desc->user[i]);
+ }
+ dp_peer_unref_del_find_by_id(peer);
+ }
+ }
+
+ /*
+ * for frame type DATA and BAR, we update stats based on MSDU,
+ * successful msdu and mpdu are populate from ACK BA STATUS TLV
+ * which comes out of order. successful mpdu also populated from
+ * COMPLTN COMMON TLV which comes in order. for every ppdu_info
+ * we store successful mpdu from both tlv and compare before delivering
+ * to make sure we received ACK BA STATUS TLV.
+ */
+ if (ppdu_desc->frame_type != CDP_PPDU_FTYPE_CTRL) {
+ /*
+ * successful mpdu count should match with both tlv
+ */
+ if (ppdu_info->mpdu_compltn_common_tlv !=
+ ppdu_info->mpdu_ack_ba_tlv)
+ return NULL;
+ }
+
/**
* Once all the TLVs for a given PPDU has been processed,
* return PPDU status to be delivered to higher layer
diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h
index b42741a..21df93e 100644
--- a/dp/wifi3.0/dp_internal.h
+++ b/dp/wifi3.0/dp_internal.h
@@ -64,6 +64,21 @@
(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV)
/**
+ * Bitmap of HTT PPDU delayed ba TLV types for Default mode
+ */
+#define HTT_PPDU_DELAYED_BA_TLV_BITMAP \
+ (1 << HTT_PPDU_STATS_COMMON_TLV) | \
+ (1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
+ (1 << HTT_PPDU_STATS_USR_RATE_TLV)
+
+/**
+ * Bitmap of HTT PPDU TLV types for Delayed BA
+ */
+#define HTT_PPDU_STATUS_TLV_BITMAP \
+ (1 << HTT_PPDU_STATS_COMMON_TLV) | \
+ (1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV)
+
+/**
* Bitmap of HTT PPDU TLV types for Sniffer mode bitmap 64
*/
#define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP_64 \
@@ -739,6 +754,23 @@
extern void dp_peer_find_hash_add(struct dp_soc *soc, struct dp_peer *peer);
extern void dp_peer_find_hash_remove(struct dp_soc *soc, struct dp_peer *peer);
extern void dp_peer_find_hash_erase(struct dp_soc *soc);
+
+/*
+ * dp_peer_ppdu_delayed_ba_init() Initialize ppdu in peer
+ * @peer: Datapath peer
+ *
+ * return: void
+ */
+void dp_peer_ppdu_delayed_ba_init(struct dp_peer *peer);
+
+/*
+ * dp_peer_ppdu_delayed_ba_cleanup() free ppdu allocated in peer
+ * @peer: Datapath peer
+ *
+ * return: void
+ */
+void dp_peer_ppdu_delayed_ba_cleanup(struct dp_peer *peer);
+
extern void dp_peer_rx_init(struct dp_pdev *pdev, struct dp_peer *peer);
void dp_peer_tx_init(struct dp_pdev *pdev, struct dp_peer *peer);
extern void dp_peer_cleanup(struct dp_vdev *vdev, struct dp_peer *peer);
diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c
index 76777c9..26ca66c 100644
--- a/dp/wifi3.0/dp_main.c
+++ b/dp/wifi3.0/dp_main.c
@@ -5392,6 +5392,8 @@
dp_peer_rx_init(pdev, peer);
dp_peer_tx_init(pdev, peer);
+ dp_peer_ppdu_delayed_ba_init(peer);
+
return;
}
diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c
index d58b2a3..9692f71 100644
--- a/dp/wifi3.0/dp_peer.c
+++ b/dp/wifi3.0/dp_peer.c
@@ -2299,6 +2299,32 @@
qdf_spinlock_destroy(&peer->rx_tid[tid].tid_lock);
}
+#ifdef FEATURE_PERPKT_INFO
+/*
+ * dp_peer_ppdu_delayed_ba_init() Initialize ppdu in peer
+ * @peer: Datapath peer
+ *
+ * return: void
+ */
+void dp_peer_ppdu_delayed_ba_init(struct dp_peer *peer)
+{
+ qdf_mem_zero(&peer->delayed_ba_ppdu_stats,
+ sizeof(struct cdp_delayed_tx_completion_ppdu_user));
+ peer->last_delayed_ba = false;
+ peer->last_delayed_ba_ppduid = 0;
+}
+#else
+/*
+ * dp_peer_ppdu_delayed_ba_init() Initialize ppdu in peer
+ * @peer: Datapath peer
+ *
+ * return: void
+ */
+void dp_peer_ppdu_delayed_ba_init(struct dp_peer *peer)
+{
+}
+#endif
+
/*
* dp_peer_cleanup() – Cleanup peer information
* @vdev: Datapath vdev
diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c
index 2cc9f02..56a955a 100644
--- a/dp/wifi3.0/dp_stats.c
+++ b/dp/wifi3.0/dp_stats.c
@@ -4864,10 +4864,10 @@
DP_PRINT_STATS("Transmit Type :");
DP_PRINT_STATS("SU %d, MU_MIMO %d, MU_OFDMA %d, MU_MIMO_OFDMA %d",
- peer->stats.tx.transmit_type[0],
- peer->stats.tx.transmit_type[1],
- peer->stats.tx.transmit_type[2],
- peer->stats.tx.transmit_type[3]);
+ peer->stats.tx.transmit_type[SU].num_msdu,
+ peer->stats.tx.transmit_type[MU_MIMO].num_msdu,
+ peer->stats.tx.transmit_type[MU_OFDMA].num_msdu,
+ peer->stats.tx.transmit_type[MU_MIMO_OFDMA].num_msdu);
for (i = 0; i < MAX_MU_GROUP_ID;) {
index = 0;
@@ -4887,12 +4887,18 @@
DP_PRINT_STATS("Last Packet RU index [%d], Size [%d]",
peer->stats.tx.ru_start, peer->stats.tx.ru_tones);
DP_PRINT_STATS("RU Locations RU[26 52 106 242 484 996]:");
- DP_PRINT_STATS("RU_26: %d", peer->stats.tx.ru_loc[0]);
- DP_PRINT_STATS("RU 52: %d", peer->stats.tx.ru_loc[1]);
- DP_PRINT_STATS("RU 106: %d", peer->stats.tx.ru_loc[2]);
- DP_PRINT_STATS("RU 242: %d", peer->stats.tx.ru_loc[3]);
- DP_PRINT_STATS("RU 484: %d", peer->stats.tx.ru_loc[4]);
- DP_PRINT_STATS("RU 996: %d", peer->stats.tx.ru_loc[5]);
+ DP_PRINT_STATS("RU_26: %d",
+ peer->stats.tx.ru_loc[RU_26_INDEX].num_msdu);
+ DP_PRINT_STATS("RU 52: %d",
+ peer->stats.tx.ru_loc[RU_52_INDEX].num_msdu);
+ DP_PRINT_STATS("RU 106: %d",
+ peer->stats.tx.ru_loc[RU_106_INDEX].num_msdu);
+ DP_PRINT_STATS("RU 242: %d",
+ peer->stats.tx.ru_loc[RU_242_INDEX].num_msdu);
+ DP_PRINT_STATS("RU 484: %d",
+ peer->stats.tx.ru_loc[RU_484_INDEX].num_msdu);
+ DP_PRINT_STATS("RU 996: %d",
+ peer->stats.tx.ru_loc[RU_996_INDEX].num_msdu);
DP_PRINT_STATS("Aggregation:");
DP_PRINT_STATS("Number of Msdu's Part of Amsdu = %d",
@@ -5354,6 +5360,8 @@
DP_PRINT_STATS(" Tag[%d] = %llu", index,
pdev->stats.ppdu_stats_counter[index]);
}
+ DP_PRINT_STATS("BA not received for delayed_ba: %d",
+ pdev->stats.cdp_delayed_ba_not_recev);
DP_PRINT_STATS("tx_ppdu_proc: %llu\n",
pdev->tx_ppdu_proc);
diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h
index 8b1eb7f..2796253 100644
--- a/dp/wifi3.0/dp_types.h
+++ b/dp/wifi3.0/dp_types.h
@@ -1211,8 +1211,10 @@
* @is_ampdu - set if Ampdu aggregate
* @nbuf - ppdu descriptor payload
* @ppdu_desc - ppdu descriptor
- * @ppdu_info_list_elem - linked list of ppdu tlvs
+ * @ppdu_info_list_elem - linked list of ppdu tlvs
* @ppdu_info_queue_elem - Singly linked list (queue) of ppdu tlvs
+ * @mpdu_compltn_common_tlv - Successful MPDU counter from COMPLTN COMMON tlv
+ * @mpdu_ack_ba_tlv - Successful MPDU from ACK BA tlv
*/
struct ppdu_info {
uint32_t ppdu_id;
@@ -1234,6 +1236,8 @@
#else
TAILQ_ENTRY(ppdu_info) ppdu_info_list_elem;
#endif
+ uint16_t mpdu_compltn_common_tlv;
+ uint16_t mpdu_ack_ba_tlv;
};
/**
@@ -1960,6 +1964,14 @@
qdf_atomic_t flush_in_progress;
struct dp_peer_cached_bufq bufq_info;
#endif
+#ifdef FEATURE_PERPKT_INFO
+ /* delayed ba ppdu stats handling */
+ struct cdp_delayed_tx_completion_ppdu_user delayed_ba_ppdu_stats;
+ /* delayed ba flag */
+ bool last_delayed_ba;
+ /* delayed ba ppdu id */
+ uint32_t last_delayed_ba_ppduid;
+#endif
};
/*