diff --git a/dp/wifi3.0/dp_rx_mon_status.c b/dp/wifi3.0/dp_rx_mon_status.c index cb7be933c0..2c58d11b86 100644 --- a/dp/wifi3.0/dp_rx_mon_status.c +++ b/dp/wifi3.0/dp_rx_mon_status.c @@ -311,6 +311,56 @@ static void dp_rx_stats_update(struct dp_pdev *pdev, struct dp_peer *peer, } #endif +/* + * dp_rx_get_fcs_ok_msdu() - get ppdu status buffer containing fcs_ok msdu + * @pdev: pdev object + * @ppdu_info: ppdu info object + * + * Return: nbuf + */ + +static inline qdf_nbuf_t +dp_rx_get_fcs_ok_msdu(struct dp_pdev *pdev, + struct hal_rx_ppdu_info *ppdu_info) +{ + uint16_t mpdu_fcs_ok; + qdf_nbuf_t status_nbuf = NULL; + unsigned long int fcs_ok_bitmap; + + /* If fcs_ok_bitmap is zero, no need to procees further */ + if (qdf_unlikely(!ppdu_info->com_info.mpdu_fcs_ok_bitmap)) + return NULL; + + /* Obtain fcs_ok passed index from bitmap + * this index is used to get fcs passed first msdu payload + */ + + fcs_ok_bitmap = ppdu_info->com_info.mpdu_fcs_ok_bitmap; + mpdu_fcs_ok = qdf_find_first_bit(&fcs_ok_bitmap, HAL_RX_MAX_MPDU); + + /* Get status buffer by indexing mpdu_fcs_ok index + * containing first msdu payload with fcs passed + * and clone the buffer + */ + status_nbuf = ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].nbuf; + /* Take ref of status nbuf as this nbuf is to be + * freeed by upper layer. + */ + qdf_nbuf_ref(status_nbuf); + + /* Free the ppdu status buffer queue */ + qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q); + + return status_nbuf; +} + +static inline void +dp_rx_handle_ppdu_status_buf(struct dp_pdev *pdev, + struct hal_rx_ppdu_info *ppdu_info, + qdf_nbuf_t status_nbuf) +{ + qdf_nbuf_queue_add(&pdev->rx_ppdu_buf_q, status_nbuf); +} /** * dp_rx_handle_mcopy_mode() - Allocate and deliver first MSDU payload * @soc: core txrx main context @@ -329,7 +379,7 @@ dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, struct ieee80211_frame *wh; uint32_t *nbuf_data; - if (!ppdu_info->msdu_info.first_msdu_payload) + if (!ppdu_info->fcs_ok_msdu_info.first_msdu_payload) return QDF_STATUS_SUCCESS; if (pdev->m_copy_id.rx_ppdu_id == ppdu_info->com_info.ppdu_id) @@ -337,11 +387,12 @@ dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, pdev->m_copy_id.rx_ppdu_id = ppdu_info->com_info.ppdu_id; - wh = (struct ieee80211_frame *)(ppdu_info->msdu_info.first_msdu_payload - + 4); - size = (ppdu_info->msdu_info.first_msdu_payload - + wh = (struct ieee80211_frame *) + (ppdu_info->fcs_ok_msdu_info.first_msdu_payload + 4); + + size = (ppdu_info->fcs_ok_msdu_info.first_msdu_payload - qdf_nbuf_data(nbuf)); - ppdu_info->msdu_info.first_msdu_payload = NULL; + ppdu_info->fcs_ok_msdu_info.first_msdu_payload = NULL; if (qdf_nbuf_pull_head(nbuf, size) == NULL) return QDF_STATUS_SUCCESS; @@ -357,7 +408,7 @@ dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, *nbuf_data = pdev->ppdu_info.com_info.ppdu_id; /* only retain RX MSDU payload in the skb */ qdf_nbuf_trim_tail(nbuf, qdf_nbuf_len(nbuf) - - ppdu_info->msdu_info.payload_len); + ppdu_info->fcs_ok_msdu_info.payload_len); dp_wdi_event_handler(WDI_EVENT_RX_DATA, soc, nbuf, HTT_INVALID_PEER, WDI_NO_VAL, pdev->pdev_id); return QDF_STATUS_E_ALREADY; @@ -371,6 +422,49 @@ dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, } #endif +#ifdef FEATURE_PERPKT_INFO +static inline void +dp_rx_process_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, + struct hal_rx_ppdu_info *ppdu_info, + uint32_t tlv_status, + qdf_nbuf_t status_nbuf) +{ + QDF_STATUS mcopy_status; + + if (qdf_unlikely(!ppdu_info->com_info.mpdu_cnt)) { + qdf_nbuf_free(status_nbuf); + return; + } + /* Add buffers to queue until we receive + * HAL_TLV_STATUS_PPDU_DONE + */ + dp_rx_handle_ppdu_status_buf(pdev, ppdu_info, status_nbuf); + + /* If tlv_status is PPDU_DONE, process rx_ppdu_buf_q + * and devliver fcs_ok msdu buffer + */ + if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) { + /* Get rx ppdu status buffer having fcs ok msdu */ + status_nbuf = dp_rx_get_fcs_ok_msdu(pdev, ppdu_info); + if (status_nbuf) { + mcopy_status = dp_rx_handle_mcopy_mode(soc, pdev, + ppdu_info, + status_nbuf); + if (mcopy_status == QDF_STATUS_SUCCESS) + qdf_nbuf_free(status_nbuf); + } + } +} +#else +static inline void +dp_rx_process_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev, + struct hal_rx_ppdu_info *ppdu_info, + uint32_t tlv_status, + qdf_nbuf_t status_nbuf) +{ +} +#endif + /** * dp_rx_handle_smart_mesh_mode() - Deliver header for smart mesh * @soc: Datapath SOC handle @@ -571,7 +665,6 @@ dp_rx_mon_status_process_tlv(struct dp_soc *soc, uint32_t mac_id, uint8_t *rx_tlv; uint8_t *rx_tlv_start; uint32_t tlv_status = HAL_TLV_STATUS_BUF_DONE; - QDF_STATUS m_copy_status = QDF_STATUS_SUCCESS; QDF_STATUS enh_log_status = QDF_STATUS_SUCCESS; struct cdp_pdev_mon_stats *rx_mon_stats; int smart_mesh_status; @@ -601,7 +694,8 @@ dp_rx_mon_status_process_tlv(struct dp_soc *soc, uint32_t mac_id, (rx_enh_capture_mode != CDP_RX_ENH_CAPTURE_DISABLED)) { do { tlv_status = hal_rx_status_get_tlv_info(rx_tlv, - ppdu_info, pdev->soc->hal_soc); + ppdu_info, pdev->soc->hal_soc, + status_nbuf); dp_rx_mon_update_dbg_ppdu_stats(ppdu_info, rx_mon_stats); @@ -643,11 +737,10 @@ dp_rx_mon_status_process_tlv(struct dp_soc *soc, uint32_t mac_id, pdev, ppdu_info, status_nbuf); if (smart_mesh_status) qdf_nbuf_free(status_nbuf); - } else if (pdev->mcopy_mode) { - m_copy_status = dp_rx_handle_mcopy_mode(soc, - pdev, ppdu_info, status_nbuf); - if (m_copy_status == QDF_STATUS_SUCCESS) - qdf_nbuf_free(status_nbuf); + } else if (qdf_unlikely(pdev->mcopy_mode)) { + dp_rx_process_mcopy_mode(soc, pdev, + ppdu_info, tlv_status, + status_nbuf); } else if (rx_enh_capture_mode != CDP_RX_ENH_CAPTURE_DISABLED) { if (!nbuf_used) qdf_nbuf_free(status_nbuf); @@ -1118,6 +1211,7 @@ dp_rx_pdev_mon_status_attach(struct dp_pdev *pdev, int ring_id) { return status; qdf_nbuf_queue_init(&pdev->rx_status_q); + qdf_nbuf_queue_init(&pdev->rx_ppdu_buf_q); pdev->mon_ppdu_status = DP_PPDU_STATUS_START; diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 0b9cad2af8..7db7248429 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1628,6 +1628,11 @@ struct dp_pdev { uint64_t tx_ppdu_proc; uint32_t *ppdu_tlv_buf; /* Buffer to hold HTT ppdu stats TLVs*/ + + /* nbuf queue to maintain rx ppdu status buffer + * belonging to one ppdu + */ + qdf_nbuf_queue_t rx_ppdu_buf_q; }; struct dp_peer; diff --git a/hal/wifi3.0/hal_api_mon.h b/hal/wifi3.0/hal_api_mon.h index c4ff12da3b..a12df71068 100644 --- a/hal/wifi3.0/hal_api_mon.h +++ b/hal/wifi3.0/hal_api_mon.h @@ -148,6 +148,13 @@ #define HAL_RX_GET_MSDU_AGGREGATION(rx_desc, rs) #endif +#define HAL_RX_MPDU_FCS_BITMAP_0_31_OFFSET 0x00000000FFFFFFFF +#define HAL_RX_MPDU_FCS_BITMAP_LSB 32 +#define HAL_RX_MPDU_FCS_BITMAP_32_63_OFFSET 0xFFFFFFFF00000000 + +/* Max MPDUs per status buffer */ +#define HAL_RX_MAX_MPDU 64 + enum { DP_PPDU_STATUS_START, DP_PPDU_STATUS_DONE, @@ -395,11 +402,21 @@ struct hal_rx_ppdu_common_info { uint32_t ppdu_timestamp; uint32_t mpdu_cnt_fcs_ok; uint32_t mpdu_cnt_fcs_err; + uint64_t mpdu_fcs_ok_bitmap; + uint32_t last_ppdu_id; + uint32_t mpdu_cnt; }; +/** + * struct hal_rx_msdu_payload_info - msdu payload info + * @first_msdu_payload: pointer to first msdu payload + * @payload_len: payload len + * @nbuf: status network buffer to which msdu belongs to + */ struct hal_rx_msdu_payload_info { uint8_t *first_msdu_payload; uint32_t payload_len; + qdf_nbuf_t nbuf; }; /** @@ -431,6 +448,7 @@ struct hal_rx_ppdu_info { struct mon_rx_status rx_status; struct mon_rx_user_status rx_user_status[HAL_MAX_UL_MU_USERS]; struct hal_rx_msdu_payload_info msdu_info; + struct hal_rx_msdu_payload_info fcs_ok_msdu_info; struct hal_rx_nac_info nac_info; /* status ring PPDU start and end state */ uint32_t rx_state; @@ -443,6 +461,8 @@ struct hal_rx_ppdu_info { /* MPDU FCS error */ bool fcs_err; struct hal_rx_ppdu_msdu_info rx_msdu_info[HAL_MAX_UL_MU_USERS]; + /* first msdu payload for all mpdus in ppdu */ + struct hal_rx_msdu_payload_info ppdu_msdu_info[HAL_RX_MAX_MPDU]; }; static inline uint32_t @@ -491,15 +511,19 @@ static inline void hal_rx_proc_phyrx_other_receive_info_tlv(struct hal_soc *hal_ * hal_rx_status_get_tlv_info() - process receive info TLV * @rx_tlv_hdr: pointer to TLV header * @ppdu_info: pointer to ppdu_info + * @hal_soc: HAL soc handle + * @nbuf: PPDU status netowrk buffer * * Return: HAL_TLV_STATUS_PPDU_NOT_DONE or HAL_TLV_STATUS_PPDU_DONE from tlv */ static inline uint32_t hal_rx_status_get_tlv_info(void *rx_tlv_hdr, void *ppdu_info, - struct hal_soc *hal_soc) + struct hal_soc *hal_soc, + qdf_nbuf_t nbuf) { return hal_soc->ops->hal_rx_status_get_tlv_info(rx_tlv_hdr, - ppdu_info, hal_soc); + ppdu_info, hal_soc, + nbuf); } static inline diff --git a/hal/wifi3.0/hal_generic_api.h b/hal/wifi3.0/hal_generic_api.h index 915fb80c93..c02df13e31 100644 --- a/hal/wifi3.0/hal_generic_api.h +++ b/hal/wifi3.0/hal_generic_api.h @@ -321,7 +321,7 @@ hal_rx_update_rssi_chain(struct hal_rx_ppdu_info *ppdu_info, */ static inline uint32_t hal_rx_status_get_tlv_info_generic(void *rx_tlv_hdr, void *ppduinfo, - void *halsoc) + void *halsoc, qdf_nbuf_t nbuf) { struct hal_soc *hal = (struct hal_soc *)halsoc; uint32_t tlv_tag, user_id, tlv_len, value; @@ -348,6 +348,9 @@ hal_rx_status_get_tlv_info_generic(void *rx_tlv_hdr, void *ppduinfo, switch (tlv_tag) { case WIFIRX_PPDU_START_E: + { + struct hal_rx_ppdu_common_info *com_info = &ppdu_info->com_info; + ppdu_info->com_info.ppdu_id = HAL_RX_GET(rx_tlv, RX_PPDU_START_0, PHY_PPDU_ID); @@ -361,7 +364,18 @@ hal_rx_status_get_tlv_info_generic(void *rx_tlv_hdr, void *ppduinfo, ppdu_info->rx_status.ppdu_timestamp = ppdu_info->com_info.ppdu_timestamp; ppdu_info->rx_state = HAL_RX_MON_PPDU_START; + + /* If last ppdu_id doesn't match new ppdu_id, + * 1. reset mpdu_cnt + * 2. update last_ppdu_id with new + */ + if (com_info->ppdu_id != com_info->last_ppdu_id) { + com_info->mpdu_cnt = 0; + com_info->last_ppdu_id = + com_info->ppdu_id; + } break; + } case WIFIRX_PPDU_START_USER_INFO_E: break; @@ -475,6 +489,20 @@ hal_rx_status_get_tlv_info_generic(void *rx_tlv_hdr, void *ppduinfo, else ppdu_info->rx_status.rs_flags &= (~IEEE80211_AMPDU_FLAG); + + ppdu_info->com_info.mpdu_fcs_ok_bitmap = + (((ppdu_info->com_info.mpdu_fcs_ok_bitmap | + HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_8, + FCS_OK_BITMAP_63_32)) << + HAL_RX_MPDU_FCS_BITMAP_LSB) & + HAL_RX_MPDU_FCS_BITMAP_32_63_OFFSET); + + ppdu_info->com_info.mpdu_fcs_ok_bitmap = + ((ppdu_info->com_info.mpdu_fcs_ok_bitmap | + HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_7, + FCS_OK_BITMAP_31_0)) & + HAL_RX_MPDU_FCS_BITMAP_0_31_OFFSET); + break; } @@ -1207,13 +1235,28 @@ hal_rx_status_get_tlv_info_generic(void *rx_tlv_hdr, void *ppduinfo, ppdu_info); break; case WIFIRX_HEADER_E: + { + struct hal_rx_ppdu_common_info *com_info = &ppdu_info->com_info; + uint16_t mpdu_cnt = com_info->mpdu_cnt; + + /* Update first_msdu_payload for every mpdu and increment + * com_info->mpdu_cnt for every WIFIRX_HEADER_E TLV + */ + ppdu_info->ppdu_msdu_info[mpdu_cnt].first_msdu_payload = + rx_tlv; + ppdu_info->ppdu_msdu_info[mpdu_cnt].payload_len = tlv_len; + ppdu_info->ppdu_msdu_info[mpdu_cnt].nbuf = nbuf; ppdu_info->msdu_info.first_msdu_payload = rx_tlv; ppdu_info->msdu_info.payload_len = tlv_len; ppdu_info->user_id = user_id; ppdu_info->hdr_len = tlv_len; ppdu_info->data = rx_tlv; ppdu_info->data += 4; + + /* for every RX_HEADER TLV increment mpdu_cnt */ + com_info->mpdu_cnt++; return HAL_TLV_STATUS_HEADER; + } case WIFIRX_MPDU_START_E: { uint8_t *rx_mpdu_start = diff --git a/hal/wifi3.0/hal_internal.h b/hal/wifi3.0/hal_internal.h index 0c2b4dad3a..c13416638d 100644 --- a/hal/wifi3.0/hal_internal.h +++ b/hal/wifi3.0/hal_internal.h @@ -338,7 +338,7 @@ struct hal_hw_txrx_ops { void (*hal_reo_status_get_header)(uint32_t *d, int b, void *h); uint32_t (*hal_rx_status_get_tlv_info)(void *rx_tlv_hdr, void *ppdu_info, - void *hal); + void *hal, qdf_nbuf_t nbuf); void (*hal_rx_wbm_err_info_get)(void *wbm_desc, void *wbm_er_info); void (*hal_rx_dump_mpdu_start_tlv)(void *mpdustart,