diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index ea03668493c7..9799c8bf65e1 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -903,6 +903,8 @@ struct cdp_tx_completion_ppdu_user { * @num_users: Number of users * @num_mpdu: Number of MPDUs in PPDU * @num_msdu: Number of MSDUs in PPDU + * @frame_type: frame SU or MU + * @frame_ctrl: frame control of 80211 header * @channel: Channel informartion * @ack_rssi: RSSI value of last ack packet (units=dB above noise floor) * @tx_duration: PPDU airtime @@ -918,6 +920,7 @@ struct cdp_tx_completion_ppdu { uint32_t num_mpdu:9, num_msdu:16; uint16_t frame_type; + uint16_t frame_ctrl; uint16_t channel; uint16_t phy_mode; uint32_t ack_rssi; diff --git a/dp/wifi3.0/dp_htt.c b/dp/wifi3.0/dp_htt.c index f4a82d78a551..0e51bde40ec5 100644 --- a/dp/wifi3.0/dp_htt.c +++ b/dp/wifi3.0/dp_htt.c @@ -47,6 +47,33 @@ do { \ } while (0) #define HTT_MGMT_CTRL_TLV_RESERVERD_LEN 12 +/** + * Bitmap of HTT PPDU TLV types for Default mode + */ +#define HTT_PPDU_DEFAULT_TLV_BITMAP \ + (1 << HTT_PPDU_STATS_COMMON_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \ + (1 << HTT_PPDU_STATS_USR_RATE_TLV) | \ + (1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) + +/** + * Bitmap of HTT PPDU TLV types for Sniffer mode + */ +#define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP \ + (1 << HTT_PPDU_STATS_COMMON_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \ + (1 << HTT_PPDU_STATS_USR_RATE_TLV) | \ + (1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV) | \ + (1 << HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV) | \ + (1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV) + +#define HTT_FRAMECTRL_DATATYPE 0x08 +#define HTT_PPDU_DESC_MAX_DEPTH 16 /* * dp_tx_stats_update() - Update per-peer statistics @@ -1538,24 +1565,26 @@ void htt_t2h_stats_handler(void *context) } /* - * dp_get_ppdu_info_user_index: Find place holder for the received - * ppdu stats info + * dp_get_ppdu_info_user_index: Find and allocate a per-user descriptor for a PPDU, + * if a new peer id arrives in a PPDU * pdev: DP pdev handle + * @peer_id : peer unique identifier + * @ppdu_info: per ppdu tlv structure * * return:user index to be populated */ #ifdef FEATURE_PERPKT_INFO static uint8_t dp_get_ppdu_info_user_index(struct dp_pdev *pdev, - uint16_t peer_id) + uint16_t peer_id, + struct ppdu_info *ppdu_info) { uint8_t user_index = 0; struct cdp_tx_completion_ppdu *ppdu_desc; struct cdp_tx_completion_ppdu_user *ppdu_user_desc; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); - while ((user_index + 1) <= pdev->tx_ppdu_info.last_user) { + while ((user_index + 1) <= ppdu_info->last_user) { ppdu_user_desc = &ppdu_desc->user[user_index]; if (ppdu_user_desc->peer_id != peer_id) { user_index++; @@ -1569,33 +1598,30 @@ static uint8_t dp_get_ppdu_info_user_index(struct dp_pdev *pdev, } } - pdev->tx_ppdu_info.last_user++; + ppdu_info->last_user++; /* Max users possible is 8 so last user should not exceed 8 */ - qdf_assert_always(pdev->tx_ppdu_info.last_user <= CDP_MU_MAX_USERS); - return pdev->tx_ppdu_info.last_user - 1; + qdf_assert_always(ppdu_info->last_user <= CDP_MU_MAX_USERS); + return ppdu_info->last_user - 1; } /* * dp_process_ppdu_stats_common_tlv: Process htt_ppdu_stats_common_tlv * pdev: DP pdev handle * @tag_buf: buffer containing the tlv htt_ppdu_stats_common_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_common_tlv(struct dp_pdev *pdev, - uint32_t *tag_buf) + uint32_t *tag_buf, struct ppdu_info *ppdu_info) { uint16_t frame_type; uint16_t freq; struct dp_soc *soc = NULL; - struct cdp_tx_completion_ppdu *ppdu_desc; - htt_ppdu_stats_common_tlv *dp_stats_buf = - (htt_ppdu_stats_common_tlv *)tag_buf; + struct cdp_tx_completion_ppdu *ppdu_desc = NULL; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); - ppdu_desc->ppdu_id = dp_stats_buf->ppdu_id; tag_buf += 2; ppdu_desc->num_users = HTT_PPDU_STATS_COMMON_TLV_NUM_USERS_GET(*tag_buf); @@ -1633,11 +1659,13 @@ static void dp_process_ppdu_stats_common_tlv(struct dp_pdev *pdev, /* * dp_process_ppdu_stats_user_common_tlv: Process ppdu_stats_user_common * @tag_buf: buffer containing the tlv htt_ppdu_stats_user_common_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_user_common_tlv( - struct dp_pdev *pdev, uint32_t *tag_buf) + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { uint16_t peer_id; struct dp_peer *peer; @@ -1645,8 +1673,7 @@ static void dp_process_ppdu_stats_user_common_tlv( struct cdp_tx_completion_ppdu_user *ppdu_user_desc; uint8_t curr_user_index = 0; - ppdu_desc = - (struct cdp_tx_completion_ppdu *) qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; peer_id = HTT_PPDU_STATS_USER_COMMON_TLV_SW_PEER_ID_GET(*tag_buf); @@ -1655,7 +1682,7 @@ static void dp_process_ppdu_stats_user_common_tlv( if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; @@ -1677,6 +1704,7 @@ static void dp_process_ppdu_stats_user_common_tlv( HTT_PPDU_STATS_USER_COMMON_TLV_QOS_CTRL_GET(*tag_buf); ppdu_user_desc->frame_ctrl = HTT_PPDU_STATS_USER_COMMON_TLV_FRAME_CTRL_GET(*tag_buf); + ppdu_desc->frame_ctrl = ppdu_user_desc->frame_ctrl; } @@ -1684,11 +1712,13 @@ static void dp_process_ppdu_stats_user_common_tlv( * dp_process_ppdu_stats_user_rate_tlv() - Process htt_ppdu_stats_user_rate_tlv * @pdev: DP pdev handle * @tag_buf: T2H message buffer carrying the user rate TLV + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev, - uint32_t *tag_buf) + uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { uint16_t peer_id; struct dp_peer *peer; @@ -1696,8 +1726,7 @@ static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev, struct cdp_tx_completion_ppdu_user *ppdu_user_desc; uint8_t curr_user_index = 0; - ppdu_desc = - (struct cdp_tx_completion_ppdu *) qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; peer_id = HTT_PPDU_STATS_USER_RATE_TLV_SW_PEER_ID_GET(*tag_buf); @@ -1706,7 +1735,7 @@ static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev, if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; @@ -1754,11 +1783,13 @@ static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev, * htt_ppdu_stats_enq_mpdu_bitmap_64_tlv * pdev: DP PDEV handle * @tag_buf: buffer containing the tlv htt_ppdu_stats_enq_mpdu_bitmap_64_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv( - struct dp_pdev *pdev, uint32_t *tag_buf) + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { htt_ppdu_stats_enq_mpdu_bitmap_64_tlv *dp_stats_buf = (htt_ppdu_stats_enq_mpdu_bitmap_64_tlv *)tag_buf; @@ -1769,8 +1800,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv( uint16_t peer_id; struct dp_peer *peer; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; @@ -1782,7 +1812,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv( if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; @@ -1797,11 +1827,13 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv( * htt_ppdu_stats_enq_mpdu_bitmap_256_tlv * soc: DP SOC handle * @tag_buf: buffer containing the tlv htt_ppdu_stats_enq_mpdu_bitmap_256_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv( - struct dp_pdev *pdev, uint32_t *tag_buf) + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { htt_ppdu_stats_enq_mpdu_bitmap_256_tlv *dp_stats_buf = (htt_ppdu_stats_enq_mpdu_bitmap_256_tlv *)tag_buf; @@ -1812,8 +1844,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv( uint16_t peer_id; struct dp_peer *peer; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; @@ -1825,7 +1856,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv( if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; @@ -1840,11 +1871,13 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv( * htt_ppdu_stats_user_cmpltn_common_tlv * soc: DP SOC handle * @tag_buf: buffer containing the tlv htt_ppdu_stats_user_cmpltn_common_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_user_cmpltn_common_tlv( - struct dp_pdev *pdev, uint32_t *tag_buf) + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { uint16_t peer_id; struct dp_peer *peer; @@ -1854,8 +1887,7 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv( htt_ppdu_stats_user_cmpltn_common_tlv *dp_stats_buf = (htt_ppdu_stats_user_cmpltn_common_tlv *)tag_buf; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; peer_id = @@ -1865,7 +1897,7 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv( if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; @@ -1897,6 +1929,7 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv( ppdu_user_desc->is_ampdu = HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_IS_AMPDU_GET(*tag_buf); + ppdu_info->is_ampdu = ppdu_user_desc->is_ampdu; } @@ -1905,11 +1938,13 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv( * htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv * pdev: DP PDEV handle * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv( - struct dp_pdev *pdev, uint32_t *tag_buf) + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv *dp_stats_buf = (htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv *)tag_buf; @@ -1919,8 +1954,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv( uint16_t peer_id; struct dp_peer *peer; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; @@ -1932,7 +1966,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv( if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; @@ -1947,11 +1981,13 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv( * htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv * pdev: DP PDEV handle * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv( - struct dp_pdev *pdev, uint32_t *tag_buf) + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv *dp_stats_buf = (htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv *)tag_buf; @@ -1961,8 +1997,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv( uint16_t peer_id; struct dp_peer *peer; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; @@ -1974,7 +2009,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv( if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; @@ -1989,11 +2024,13 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv( * htt_ppdu_stats_user_compltn_ack_ba_status_tlv * pdev: DP PDE handle * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ack_ba_status_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ static void dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv( - struct dp_pdev *pdev, uint32_t *tag_buf) + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { uint16_t peer_id; struct dp_peer *peer; @@ -2001,29 +2038,31 @@ static void dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv( struct cdp_tx_completion_ppdu_user *ppdu_user_desc; uint8_t curr_user_index = 0; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf += 2; peer_id = HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_SW_PEER_ID_GET(*tag_buf); + peer = dp_peer_find_by_id(pdev->soc, peer_id); if (!peer) return; - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; ppdu_user_desc->peer_id = peer_id; tag_buf++; + ppdu_user_desc->tid = + HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_TID_NUM_GET(*tag_buf); ppdu_user_desc->num_mpdu = - HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MPDU_GET(*tag_buf); + HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MPDU_GET(*tag_buf); ppdu_user_desc->num_msdu = - HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MSDU_GET(*tag_buf); + HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MSDU_GET(*tag_buf); ppdu_user_desc->success_msdus = ppdu_user_desc->num_msdu; @@ -2037,11 +2076,13 @@ static void dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv( * htt_ppdu_stats_user_common_array_tlv * pdev: DP PDEV handle * @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ack_ba_status_tlv + * @ppdu_info: per ppdu tlv structure * * return:void */ -static void dp_process_ppdu_stats_user_common_array_tlv(struct dp_pdev *pdev, - uint32_t *tag_buf) +static void dp_process_ppdu_stats_user_common_array_tlv( + struct dp_pdev *pdev, uint32_t *tag_buf, + struct ppdu_info *ppdu_info) { uint32_t peer_id; struct dp_peer *peer; @@ -2050,8 +2091,7 @@ static void dp_process_ppdu_stats_user_common_array_tlv(struct dp_pdev *pdev, uint8_t curr_user_index = 0; struct htt_tx_ppdu_stats_info *dp_stats_buf; - ppdu_desc = - (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf); + ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf); tag_buf++; dp_stats_buf = (struct htt_tx_ppdu_stats_info *)tag_buf; @@ -2067,7 +2107,7 @@ static void dp_process_ppdu_stats_user_common_array_tlv(struct dp_pdev *pdev, return; } - curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id); + curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info); ppdu_user_desc = &ppdu_desc->user[curr_user_index]; @@ -2167,94 +2207,275 @@ static void dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv( /** * dp_process_ppdu_tag(): Function to process the PPDU TLVs - * @soc: DP Physical device (radio) handle + * @pdev: DP pdev handle * @tag_buf: TLV buffer + * @tlv_len: length of tlv + * @ppdu_info: per ppdu tlv structure * * return: void */ static void dp_process_ppdu_tag(struct dp_pdev *pdev, uint32_t *tag_buf, - uint32_t tlv_len) + uint32_t tlv_len, struct ppdu_info *ppdu_info) { uint32_t tlv_type = HTT_STATS_TLV_TAG_GET(*tag_buf); + switch (tlv_type) { case HTT_PPDU_STATS_COMMON_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_common_tlv)); - dp_process_ppdu_stats_common_tlv(pdev, tag_buf); + dp_process_ppdu_stats_common_tlv(pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_COMMON_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_user_common_tlv)); - dp_process_ppdu_stats_user_common_tlv(pdev, tag_buf); + dp_process_ppdu_stats_user_common_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_RATE_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_user_rate_tlv)); - dp_process_ppdu_stats_user_rate_tlv(pdev, tag_buf); + dp_process_ppdu_stats_user_rate_tlv(pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_enq_mpdu_bitmap_64_tlv)); - dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv(pdev, tag_buf); + dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_256_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_enq_mpdu_bitmap_256_tlv)); - dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv(pdev, tag_buf); + dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_user_cmpltn_common_tlv)); - dp_process_ppdu_stats_user_cmpltn_common_tlv(pdev, tag_buf); + dp_process_ppdu_stats_user_cmpltn_common_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv)); - dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv(pdev, - tag_buf); + dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv)); - dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv(pdev, - tag_buf); + dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_user_compltn_ack_ba_status_tlv)); - dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv(pdev, - tag_buf); + dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_COMMON_ARRAY_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_usr_common_array_tlv_v)); - dp_process_ppdu_stats_user_common_array_tlv(pdev, - tag_buf); + dp_process_ppdu_stats_user_common_array_tlv( + pdev, tag_buf, ppdu_info); break; case HTT_PPDU_STATS_USR_COMPLTN_FLUSH_TLV: qdf_assert_always(tlv_len == sizeof(htt_ppdu_stats_flush_tlv)); - dp_process_ppdu_stats_user_compltn_flush_tlv(pdev, - tag_buf); + dp_process_ppdu_stats_user_compltn_flush_tlv( + pdev, tag_buf); break; case HTT_PPDU_STATS_TX_MGMTCTRL_PAYLOAD_TLV: - dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv(pdev, - tag_buf, tlv_len); + dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv( + pdev, tag_buf, tlv_len); break; default: break; } } -static QDF_STATUS dp_htt_process_tlv(struct dp_pdev *pdev, +/** + * dp_ppdu_desc_deliver(): Function to deliver Tx PPDU status descriptor + * to upper layer + * @pdev: DP pdev handle + * @ppdu_info: per PPDU TLV descriptor + * + * return: void + */ +static +void dp_ppdu_desc_deliver(struct dp_pdev *pdev, + struct ppdu_info *ppdu_info) +{ + struct cdp_tx_completion_ppdu *ppdu_desc = NULL; + struct dp_peer *peer = NULL; + qdf_nbuf_t nbuf; + uint16_t i; + + ppdu_desc = (struct cdp_tx_completion_ppdu *) + qdf_nbuf_data(ppdu_info->nbuf); + + ppdu_desc->num_users = ppdu_info->last_user; + ppdu_desc->ppdu_id = ppdu_info->ppdu_id; + + for (i = 0; i < ppdu_desc->num_users; i++) { + + + ppdu_desc->num_mpdu += ppdu_desc->user[i].num_mpdu; + ppdu_desc->num_msdu += ppdu_desc->user[i].num_msdu; + + if (ppdu_desc->user[i].tid < CDP_DATA_TID_MAX) { + 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; + + dp_tx_stats_update(pdev->soc, peer, + &ppdu_desc->user[i], + ppdu_desc->ack_rssi); + } + } + + /* + * Remove from the list + */ + TAILQ_REMOVE(&pdev->ppdu_info_list, ppdu_info, ppdu_info_list_elem); + nbuf = ppdu_info->nbuf; + pdev->list_depth--; + qdf_mem_free(ppdu_info); + + qdf_assert_always(nbuf); + + ppdu_desc = (struct cdp_tx_completion_ppdu *) + qdf_nbuf_data(nbuf); + + /** + * Deliver PPDU stats only for valid (acked) data frames if + * sniffer mode is not enabled. + * If sniffer mode is enabled, PPDU stats for all frames + * including mgmt/control frames should be delivered to upper layer + */ + if (pdev->tx_sniffer_enable || pdev->mcopy_mode) { + dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC, pdev->soc, + nbuf, HTT_INVALID_PEER, + WDI_NO_VAL, pdev->pdev_id); + } else { + if (ppdu_desc->num_mpdu != 0 && ppdu_desc->num_users != 0 && + ppdu_desc->frame_ctrl & HTT_FRAMECTRL_DATATYPE) { + + dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC, + pdev->soc, nbuf, HTT_INVALID_PEER, + WDI_NO_VAL, pdev->pdev_id); + } else + qdf_nbuf_free(nbuf); + } + return; +} + +/** + * dp_get_ppdu_desc(): Function to allocate new PPDU status + * desc for new ppdu id + * @pdev: DP pdev handle + * @ppdu_id: PPDU unique identifier + * @tlv_type: TLV type received + * + * return: ppdu_info per ppdu tlv structure + */ +static +struct ppdu_info *dp_get_ppdu_desc(struct dp_pdev *pdev, uint32_t ppdu_id, + uint8_t tlv_type) +{ + struct ppdu_info *ppdu_info = NULL; + + /* + * Find ppdu_id node exists or not + */ + TAILQ_FOREACH(ppdu_info, &pdev->ppdu_info_list, ppdu_info_list_elem) { + + if (ppdu_info && (ppdu_info->ppdu_id == ppdu_id)) { + break; + } + } + + if (ppdu_info) { + /** + * if we get tlv_type that is already been processed for ppdu, + * that means we got a new ppdu with same ppdu id. + * Hence Flush the older ppdu + */ + if (ppdu_info->tlv_bitmap & (1 << tlv_type)) + dp_ppdu_desc_deliver(pdev, ppdu_info); + else + return ppdu_info; + } + + /** + * Flush the head ppdu descriptor if ppdu desc list reaches max + * threshold + */ + if (pdev->list_depth > HTT_PPDU_DESC_MAX_DEPTH) { + ppdu_info = TAILQ_FIRST(&pdev->ppdu_info_list); + dp_ppdu_desc_deliver(pdev, ppdu_info); + } + + /* + * Allocate new ppdu_info node + */ + ppdu_info = qdf_mem_malloc(sizeof(struct ppdu_info)); + if (!ppdu_info) + return NULL; + + ppdu_info->nbuf = qdf_nbuf_alloc(pdev->soc->osdev, + sizeof(struct cdp_tx_completion_ppdu), 0, 4, + TRUE); + if (!ppdu_info->nbuf) { + qdf_mem_free(ppdu_info); + return NULL; + } + + qdf_mem_zero(qdf_nbuf_data(ppdu_info->nbuf), + sizeof(struct cdp_tx_completion_ppdu)); + + if (qdf_nbuf_put_tail(ppdu_info->nbuf, + sizeof(struct cdp_tx_completion_ppdu)) == NULL) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "No tailroom for HTT PPDU"); + qdf_nbuf_free(ppdu_info->nbuf); + ppdu_info->nbuf = NULL; + ppdu_info->last_user = 0; + qdf_mem_free(ppdu_info); + return NULL; + } + + /** + * No lock is needed because all PPDU TLVs are processed in + * same context and this list is updated in same context + */ + TAILQ_INSERT_TAIL(&pdev->ppdu_info_list, ppdu_info, + ppdu_info_list_elem); + pdev->list_depth++; + return ppdu_info; +} + +/** + * dp_htt_process_tlv(): Function to process each PPDU TLVs + * @pdev: DP pdev handle + * @htt_t2h_msg: HTT target to host message + * + * return: ppdu_info per ppdu tlv structure + */ + +static struct ppdu_info *dp_htt_process_tlv(struct dp_pdev *pdev, qdf_nbuf_t htt_t2h_msg) { uint32_t length; uint32_t ppdu_id; uint8_t tlv_type; - uint32_t tlv_length; + uint32_t tlv_length, tlv_bitmap_expected; uint8_t *tlv_buf; - QDF_STATUS status = QDF_STATUS_E_PENDING; + struct ppdu_info *ppdu_info = NULL; uint32_t *msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg); @@ -2263,6 +2484,7 @@ static QDF_STATUS dp_htt_process_tlv(struct dp_pdev *pdev, msg_word = msg_word + 1; ppdu_id = HTT_T2H_PPDU_STATS_PPDU_ID_GET(*msg_word); + msg_word = msg_word + 3; while (length > 0) { tlv_buf = (uint8_t *)msg_word; @@ -2274,22 +2496,56 @@ static QDF_STATUS dp_htt_process_tlv(struct dp_pdev *pdev, if (tlv_length == 0) break; - if (tlv_type == HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) - status = QDF_STATUS_SUCCESS; - - if ((tlv_type == HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) && - (pdev->last_ppdu_id != ppdu_id)) - status = QDF_STATUS_SUCCESS; - tlv_length += HTT_TLV_HDR_LEN; - dp_process_ppdu_tag(pdev, msg_word, tlv_length); + /** + * Not allocating separate ppdu descriptor for MGMT Payload + * TLV as this is sent as separate WDI indication and it + * doesn't contain any ppdu information + */ + if (tlv_type == HTT_PPDU_STATS_TX_MGMTCTRL_PAYLOAD_TLV) { + dp_process_ppdu_tag(pdev, msg_word, tlv_length, NULL); + msg_word = (uint32_t *)((uint8_t *)tlv_buf + tlv_length); + length -= (tlv_length); + continue; + } + + ppdu_info = dp_get_ppdu_desc(pdev, ppdu_id, tlv_type); + if (!ppdu_info) + return NULL; + ppdu_info->ppdu_id = ppdu_id; + ppdu_info->tlv_bitmap |= (1 << tlv_type); + + dp_process_ppdu_tag(pdev, msg_word, tlv_length, ppdu_info); + + /** + * Increment pdev level tlv count to monitor + * missing TLVs + */ + pdev->tlv_count++; + ppdu_info->last_tlv_cnt = pdev->tlv_count; msg_word = (uint32_t *)((uint8_t *)tlv_buf + tlv_length); length -= (tlv_length); } + pdev->last_ppdu_id = ppdu_id; - return status; + + tlv_bitmap_expected = HTT_PPDU_DEFAULT_TLV_BITMAP; + + if (pdev->tx_sniffer_enable || pdev->mcopy_mode) { + if (ppdu_info->is_ampdu) + tlv_bitmap_expected = HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP; + } + + /** + * Once all the TLVs for a given PPDU has been processed, + * return PPDU status to be delivered to higher layer + */ + if (ppdu_info->tlv_bitmap == tlv_bitmap_expected) + return ppdu_info; + + return NULL; } #endif /* FEATURE_PERPKT_INFO */ @@ -2307,78 +2563,15 @@ static void dp_txrx_ppdu_stats_handler(struct dp_soc *soc, uint8_t pdev_id, qdf_nbuf_t htt_t2h_msg) { struct dp_pdev *pdev = soc->pdev_list[pdev_id]; - struct dp_peer *peer; - struct cdp_tx_completion_ppdu *ppdu_desc; - int status; - int i; + struct ppdu_info *ppdu_info = NULL; if (!pdev->enhanced_stats_en && !pdev->tx_sniffer_enable && !pdev->mcopy_mode) return; - if (!pdev->tx_ppdu_info.buf) { - /* - * Todo: For MU/OFDMA, we need to account for multiple user - * descriptors in a PPDU, in skb size. - * The allocation has to be moved to ppdu_cmn tlv processing - */ - pdev->tx_ppdu_info.buf = qdf_nbuf_alloc(soc->osdev, - sizeof(struct cdp_tx_completion_ppdu), 0, 4, - TRUE); - - if (!pdev->tx_ppdu_info.buf) { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Nbuf Allocation failed for HTT PPDU"); - return; - } - - qdf_mem_zero(qdf_nbuf_data(pdev->tx_ppdu_info.buf), - sizeof(struct cdp_tx_completion_ppdu)); - - if (qdf_nbuf_put_tail(pdev->tx_ppdu_info.buf, - sizeof(struct cdp_tx_completion_ppdu)) == NULL) { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "No tailroom for HTT PPDU"); - qdf_nbuf_free(pdev->tx_ppdu_info.buf); - pdev->tx_ppdu_info.buf = NULL; - pdev->tx_ppdu_info.last_user = 0; - return; - } - - } - - status = dp_htt_process_tlv(pdev, htt_t2h_msg); - - if (status == QDF_STATUS_SUCCESS) { - ppdu_desc = (struct cdp_tx_completion_ppdu *) - qdf_nbuf_data(pdev->tx_ppdu_info.buf); - - ppdu_desc->num_users = pdev->tx_ppdu_info.last_user; - - for (i = 0; i < ppdu_desc->num_users; i++) { - peer = dp_peer_find_by_id(soc, - ppdu_desc->user[i].peer_id); - if (!peer) - continue; - - ppdu_desc->num_mpdu += ppdu_desc->user[i].num_mpdu; - ppdu_desc->num_msdu += ppdu_desc->user[i].num_msdu; - - if (ppdu_desc->user[i].tid < CDP_DATA_TID_MAX) { - dp_tx_stats_update(soc, peer, - &ppdu_desc->user[i], - ppdu_desc->ack_rssi); - } - } - - dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC, soc, - pdev->tx_ppdu_info.buf, HTT_INVALID_PEER, - WDI_NO_VAL, pdev_id); - - pdev->tx_ppdu_info.buf = NULL; - pdev->tx_ppdu_info.last_user = 0; - } - + ppdu_info = dp_htt_process_tlv(pdev, htt_t2h_msg); + if (ppdu_info) + dp_ppdu_desc_deliver(pdev, ppdu_info); } #else static void dp_txrx_ppdu_stats_handler(struct dp_soc *soc, diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index d5f415518d77..860a735bfb97 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -2614,6 +2614,13 @@ static struct cdp_pdev *dp_pdev_attach_wifi3(struct cdp_soc_t *txrx_soc, /* set the reo destination during initialization */ pdev->reo_dest = pdev->pdev_id + 1; + /* + * initialize ppdu tlv list + */ + TAILQ_INIT(&pdev->ppdu_info_list); + pdev->tlv_count = 0; + pdev->list_depth = 0; + return (struct cdp_pdev *)pdev; fail1: diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 893e71a1988d..90a0eea98c58 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -938,6 +938,29 @@ struct dp_neighbour_peer { TAILQ_ENTRY(dp_neighbour_peer) neighbour_peer_list_elem; }; +/** + * struct ppdu_info - PPDU Status info descriptor + * @ppdu_id - Unique ppduid assigned by firmware for every tx packet + * @max_ppdu_id - wrap around for ppdu id + * @last_tlv_cnt - Keep track for missing ppdu tlvs + * @last_user - last ppdu processed for user + * @is_ampdu - set if Ampdu aggregate + * @nbuf - ppdu descriptor payload + * @ppdu_desc - ppdu descriptor + * @ppdu_info_list_elem - linked list of ppdu tlvs + */ +struct ppdu_info { + uint32_t ppdu_id; + uint32_t max_ppdu_id; + uint16_t tlv_bitmap; + uint16_t last_tlv_cnt; + uint16_t last_user:8, + is_ampdu:1; + qdf_nbuf_t nbuf; + struct cdp_tx_completion_ppdu *ppdu_desc; + TAILQ_ENTRY(ppdu_info) ppdu_info_list_elem; +}; + /* PDEV level structure for data path */ struct dp_pdev { /* PDEV handle from OSIF layer TBD: see if we really need osif_pdev */ @@ -1133,6 +1156,10 @@ struct dp_pdev { #ifdef ATH_SUPPORT_NAC_RSSI bool nac_rssi_filtering; #endif + /* list of ppdu tlvs */ + TAILQ_HEAD(, ppdu_info) ppdu_info_list; + uint32_t tlv_count; + uint32_t list_depth; }; struct dp_peer;