From df4a57cd3121e3879a5dea801c44b103c0ccb48a Mon Sep 17 00:00:00 2001 From: sumedh baikady Date: Sun, 8 Apr 2018 22:19:22 -0700 Subject: [PATCH] qcacmn: Handle 2k exception and rate limit delba Upon receiving 2k jump exception, send delba and track delba tx status and retries. Change-Id: Ida35256233869dfa390c40030c9296b9c48481ce Crs-fixed: 2239856 --- dp/inc/cdp_txrx_cmn.h | 30 +++++++++ dp/inc/cdp_txrx_ops.h | 22 +++++++ dp/wifi3.0/dp_internal.h | 13 +++- dp/wifi3.0/dp_main.c | 1 + dp/wifi3.0/dp_peer.c | 128 +++++++++++++++++++++++++++++++-------- dp/wifi3.0/dp_rx_err.c | 88 ++++++++++++++++++++++++++- dp/wifi3.0/dp_types.h | 17 ++++++ hal/wifi3.0/hal_reo.c | 8 ++- hal/wifi3.0/hal_rx.c | 8 ++- 9 files changed, 284 insertions(+), 31 deletions(-) diff --git a/dp/inc/cdp_txrx_cmn.h b/dp/inc/cdp_txrx_cmn.h index fdc1d368ff..5ae10ac376 100644 --- a/dp/inc/cdp_txrx_cmn.h +++ b/dp/inc/cdp_txrx_cmn.h @@ -1061,6 +1061,36 @@ static inline int cdp_delba_process(ol_txrx_soc_handle soc, tid, reasoncode); } +/** + * cdp_delba_tx_completion() - Handle delba tx completion + * to update stats and retry transmission if failed. + * @soc: soc handle + * @peer_handle: peer handle + * @tid: Tid number + * @status: Tx completion status + * + * Return: 0 on Success, 1 on failure + */ + +static inline int cdp_delba_tx_completion(ol_txrx_soc_handle soc, + void *peer_handle, + uint8_t tid, int status) +{ + if (!soc || !soc->ops) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance:", __func__); + QDF_BUG(0); + return 0; + } + + if (!soc->ops->cmn_drv_ops || + !soc->ops->cmn_drv_ops->delba_tx_completion) + return 0; + + return soc->ops->cmn_drv_ops->delba_tx_completion(peer_handle, + tid, status); +} + static inline void cdp_set_addbaresponse(ol_txrx_soc_handle soc, void *peer_handle, int tid, uint16_t statuscode) { diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 0305fbd82c..54bd78b4fc 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -271,6 +271,17 @@ struct cdp_cmn_ops { int (*delba_process)(void *peer_handle, int tid, uint16_t reasoncode); + /** + * delba_tx_completion() - Indicate delba tx status + * @peer_handle: Peer handle + * @tid: Tid number + * @status: Tx completion status + * + * Return: 0 on Success, 1 on failure + */ + int (*delba_tx_completion)(void *peer_handle, + uint8_t tid, int status); + void (*set_addba_response)(void *peer_handle, uint8_t tid, uint16_t statuscode); @@ -806,6 +817,17 @@ struct ol_if_ops { #endif int (*peer_sta_kickout)(void *ctrl_pdev, uint8_t *peer_macaddr); + /** + * send_delba() - Send delba to peer + * @pdev_handle: Dp pdev handle + * @ctrl_peer: Peer handle + * @peer_macaddr: Peer mac addr + * @tid: Tid number + * + * Return: 0 for success, non-zero for failure + */ + int (*send_delba)(void *pdev_handle, void *ctrl_peer, + uint8_t *peer_macaddr, uint8_t tid, void *vdev_handle); /* TODO: Add any other control path calls required to OL_IF/WMA layer */ }; diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 6a6b185ef5..f5b6c678bc 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -656,7 +656,18 @@ extern void dp_set_addba_response(void *peer_handle, uint8_t tid, uint16_t statuscode); extern int dp_delba_process_wifi3(void *peer_handle, int tid, uint16_t reasoncode); - +/* + * dp_delba_tx_completion_wifi3() - Handle delba tx completion + * + * @peer_handle: Peer handle + * @tid: Tid number + * @status: Tx completion status + * Indicate status of delba Tx to DP for stats update and retry + * delba if tx failed. + * + */ +int dp_delba_tx_completion_wifi3(void *peer_handle, uint8_t tid, + int status); extern int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, uint32_t ba_window_size, uint32_t start_seq); diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 8992fedd01..b033e3416d 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -7607,6 +7607,7 @@ static struct cdp_cmn_ops dp_ops_cmn = { .txrx_peer_flush_ast_table = dp_wds_flush_ast_table_wifi3, .txrx_peer_map_attach = dp_peer_map_attach_wifi3, .txrx_pdev_set_ctrl_pdev = dp_pdev_set_ctrl_pdev, + .delba_tx_completion = dp_delba_tx_completion_wifi3, }; static struct cdp_ctrl_ops dp_ops_ctrl = { diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index 5ef49d76cf..7000cdd9c1 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -900,15 +900,24 @@ void dp_rx_tid_stats_cb(struct dp_soc *soc, void *cb_ctxt, queue_status->late_recv_mpdu_cnt, queue_status->win_jump_2k, queue_status->hole_cnt); - DP_PRINT_STATS("Num of Addba Req = %d\n", rx_tid->num_of_addba_req); - DP_PRINT_STATS("Num of Addba Resp = %d\n", rx_tid->num_of_addba_resp); - DP_PRINT_STATS("Num of Addba Resp successful = %d\n", - rx_tid->num_addba_rsp_success); - DP_PRINT_STATS("Num of Addba Resp failed = %d\n", - rx_tid->num_addba_rsp_failed); - DP_PRINT_STATS("Num of Delba Req = %d\n", rx_tid->num_of_delba_req); - DP_PRINT_STATS("BA window size = %d\n", rx_tid->ba_win_size); - DP_PRINT_STATS("Pn size = %d\n", rx_tid->pn_size); + DP_PRINT_STATS("Addba Req : %d\n" + "Addba Resp : %d\n" + "Addba Resp success : %d\n" + "Addba Resp failed : %d\n" + "Delba Req received : %d\n" + "Delba Tx success : %d\n" + "Delba Tx Fail : %d\n" + "BA window size : %d\n" + "Pn size : %d\n", + rx_tid->num_of_addba_req, + rx_tid->num_of_addba_resp, + rx_tid->num_addba_rsp_success, + rx_tid->num_addba_rsp_failed, + rx_tid->num_of_delba_req, + rx_tid->delba_tx_success_cnt, + rx_tid->delba_tx_fail_cnt, + rx_tid->ba_win_size, + rx_tid->pn_size); } static inline struct dp_peer *dp_peer_find_add_id(struct dp_soc *soc, @@ -1239,11 +1248,16 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, if (rx_tid->hw_qdesc_vaddr_unaligned != NULL) return dp_rx_tid_update_wifi3(peer, tid, ba_window_size, start_seq); + rx_tid->delba_tx_status = 0; + rx_tid->ppdu_id_2k = 0; rx_tid->num_of_addba_req = 0; rx_tid->num_of_delba_req = 0; rx_tid->num_of_addba_resp = 0; rx_tid->num_addba_rsp_failed = 0; rx_tid->num_addba_rsp_success = 0; + rx_tid->delba_tx_success_cnt = 0; + rx_tid->delba_tx_fail_cnt = 0; + rx_tid->statuscode = 0; #ifdef notyet hw_qdesc_size = hal_get_reo_qdesc_size(soc->hal_soc, ba_window_size); #else @@ -1648,8 +1662,14 @@ int dp_addba_resp_tx_completion_wifi3(void *peer_handle, uint8_t tid, int status) { struct dp_peer *peer = (struct dp_peer *)peer_handle; - struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; + struct dp_rx_tid *rx_tid = NULL; + if (!peer || peer->delete_in_progress) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Peer is NULL!\n", __func__); + return QDF_STATUS_E_FAILURE; + } + rx_tid = &peer->rx_tid[tid]; qdf_spin_lock_bh(&rx_tid->tid_lock); if (status) { rx_tid->num_addba_rsp_failed++; @@ -1659,7 +1679,7 @@ int dp_addba_resp_tx_completion_wifi3(void *peer_handle, QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "%s: Rx Tid- %d addba rsp tx completion failed!", __func__, tid); - return 0; + return QDF_STATUS_SUCCESS; } rx_tid->num_addba_rsp_success++; @@ -1671,19 +1691,9 @@ int dp_addba_resp_tx_completion_wifi3(void *peer_handle, return QDF_STATUS_E_FAILURE; } - if (dp_rx_tid_update_wifi3(peer, tid, rx_tid->ba_win_size, - rx_tid->startseqnum)) { - qdf_spin_unlock_bh(&rx_tid->tid_lock); - return QDF_STATUS_E_FAILURE; - } - if (rx_tid->userstatuscode != IEEE80211_STATUS_SUCCESS) - rx_tid->statuscode = rx_tid->userstatuscode; - else - rx_tid->statuscode = IEEE80211_STATUS_SUCCESS; - rx_tid->ba_status = DP_RX_BA_ACTIVE; qdf_spin_unlock_bh(&rx_tid->tid_lock); - return 0; + return QDF_STATUS_SUCCESS; } /* @@ -1701,8 +1711,14 @@ void dp_addba_responsesetup_wifi3(void *peer_handle, uint8_t tid, uint16_t *buffersize, uint16_t *batimeout) { struct dp_peer *peer = (struct dp_peer *)peer_handle; - struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; + struct dp_rx_tid *rx_tid = NULL; + if (!peer || peer->delete_in_progress) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Peer is NULL!\n", __func__); + return; + } + rx_tid = &peer->rx_tid[tid]; qdf_spin_lock_bh(&rx_tid->tid_lock); rx_tid->num_of_addba_resp++; /* setup ADDBA response parameters */ @@ -1732,8 +1748,14 @@ int dp_addba_requestprocess_wifi3(void *peer_handle, uint16_t startseqnum) { struct dp_peer *peer = (struct dp_peer *)peer_handle; - struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; + struct dp_rx_tid *rx_tid = NULL; + if (!peer || peer->delete_in_progress) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Peer is NULL!\n", __func__); + return QDF_STATUS_E_FAILURE; + } + rx_tid = &peer->rx_tid[tid]; qdf_spin_lock_bh(&rx_tid->tid_lock); rx_tid->num_of_addba_req++; if ((rx_tid->ba_status == DP_RX_BA_ACTIVE && @@ -1748,7 +1770,7 @@ int dp_addba_requestprocess_wifi3(void *peer_handle, return QDF_STATUS_E_FAILURE; } - if (dp_rx_tid_setup_wifi3(peer, tid, 1, 0)) { + if (dp_rx_tid_setup_wifi3(peer, tid, buffersize, 0)) { rx_tid->ba_status = DP_RX_BA_INACTIVE; qdf_spin_unlock_bh(&rx_tid->tid_lock); return QDF_STATUS_E_FAILURE; @@ -1758,8 +1780,15 @@ int dp_addba_requestprocess_wifi3(void *peer_handle, rx_tid->ba_win_size = buffersize; rx_tid->dialogtoken = dialogtoken; rx_tid->startseqnum = startseqnum; + + if (rx_tid->userstatuscode != IEEE80211_STATUS_SUCCESS) + rx_tid->statuscode = rx_tid->userstatuscode; + else + rx_tid->statuscode = IEEE80211_STATUS_SUCCESS; + qdf_spin_unlock_bh(&rx_tid->tid_lock); - return 0; + + return QDF_STATUS_SUCCESS; } /* @@ -1811,6 +1840,53 @@ int dp_delba_process_wifi3(void *peer_handle, return 0; } +/* + * dp_rx_delba_tx_completion_wifi3() – Send Delba Request + * + * @peer: Datapath peer handle + * @tid: TID number + * @status: tx completion status + * Return: 0 on success, error code on failure + */ + +int dp_delba_tx_completion_wifi3(void *peer_handle, + uint8_t tid, int status) +{ + struct dp_peer *peer = (struct dp_peer *)peer_handle; + struct dp_rx_tid *rx_tid = NULL; + + if (!peer || peer->delete_in_progress) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Peer is NULL!", __func__); + return QDF_STATUS_E_FAILURE; + } + rx_tid = &peer->rx_tid[tid]; + qdf_spin_lock_bh(&rx_tid->tid_lock); + if (status) { + rx_tid->delba_tx_fail_cnt++; + if (rx_tid->delba_tx_retry >= DP_MAX_DELBA_RETRY) { + rx_tid->delba_tx_retry = 0; + rx_tid->delba_tx_status = 0; + qdf_spin_unlock_bh(&rx_tid->tid_lock); + } else { + rx_tid->delba_tx_retry++; + rx_tid->delba_tx_status = 1; + qdf_spin_unlock_bh(&rx_tid->tid_lock); + peer->vdev->pdev->soc->cdp_soc.ol_ops->send_delba( + peer->vdev->pdev->ctrl_pdev, peer->ctrl_peer, + peer->mac_addr.raw, tid, peer->vdev->ctrl_vdev); + } + return QDF_STATUS_SUCCESS; + } else { + rx_tid->delba_tx_success_cnt++; + rx_tid->delba_tx_retry = 0; + rx_tid->delba_tx_status = 0; + } + qdf_spin_unlock_bh(&rx_tid->tid_lock); + + return QDF_STATUS_SUCCESS; +} + void dp_rx_discard(struct dp_vdev *vdev, struct dp_peer *peer, unsigned tid, qdf_nbuf_t msdu_list) { diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 904397a5e4..2e0f03db27 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -468,6 +468,73 @@ dp_rx_chain_msdus(struct dp_soc *soc, qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr, return mpdu_done; } +/** + * dp_2k_jump_handle() - Function to handle 2k jump exception + * on WBM ring + * + * @soc: core DP main context + * @nbuf: buffer pointer + * @rx_tlv_hdr: start of rx tlv header + * @peer_id: peer id of first msdu + * @tid: Tid for which exception occurred + * + * This function handles 2k jump violations arising out + * of receiving aggregates in non BA case. This typically + * may happen if aggregates are received on a QOS enabled TID + * while Rx window size is still initialized to value of 2. Or + * it may also happen if negotiated window size is 1 but peer + * sends aggregates. + * + */ + +static void +dp_2k_jump_handle(struct dp_soc *soc, + qdf_nbuf_t nbuf, + uint8_t *rx_tlv_hdr, + uint16_t peer_id, + uint8_t tid) +{ + uint32_t ppdu_id; + struct dp_peer *peer = NULL; + struct dp_rx_tid *rx_tid = NULL; + + peer = dp_peer_find_by_id(soc, peer_id); + if (!peer || peer->delete_in_progress) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "peer not found"); + goto free_nbuf; + } + rx_tid = &peer->rx_tid[tid]; + if (qdf_unlikely(rx_tid == NULL)) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "rx_tid is NULL!!"); + goto free_nbuf; + } + qdf_spin_lock_bh(&rx_tid->tid_lock); + ppdu_id = hal_rx_attn_phy_ppdu_id_get(rx_tlv_hdr); + if (rx_tid->ppdu_id_2k != ppdu_id) { + rx_tid->ppdu_id_2k = ppdu_id; + qdf_spin_unlock_bh(&rx_tid->tid_lock); + goto free_nbuf; + } + if (!rx_tid->delba_tx_status) { + rx_tid->delba_tx_retry++; + rx_tid->delba_tx_status = 1; + qdf_spin_unlock_bh(&rx_tid->tid_lock); + soc->cdp_soc.ol_ops->send_delba(peer->vdev->pdev->ctrl_pdev, + peer->ctrl_peer, + peer->mac_addr.raw, + tid, + peer->vdev->ctrl_vdev); + } else { + qdf_spin_unlock_bh(&rx_tid->tid_lock); + } + +free_nbuf: + qdf_nbuf_free(nbuf); + return; +} + /** * dp_rx_null_q_desc_handle() - Function to handle NULL Queue * descriptor violation on either a @@ -1053,6 +1120,8 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) qdf_nbuf_t nbuf, next; struct hal_wbm_err_desc_info wbm_err_info = { 0 }; uint8_t pool_id; + uint16_t peer_id = 0xFFFF; + uint8_t tid = 0; /* Debug -- Remove later */ qdf_assert(soc && hal_ring); @@ -1190,10 +1259,25 @@ done: continue; /* TODO */ /* Add per error code accounting */ - + case HAL_REO_ERR_REGULAR_FRAME_2K_JUMP: + pool_id = wbm_err_info.pool_id; + QDF_TRACE(QDF_MODULE_ID_DP, + QDF_TRACE_LEVEL_ERROR, + "Got pkt with REO ERROR: %d", + wbm_err_info.reo_err_code); + if (hal_rx_msdu_end_first_msdu_get(rx_tlv_hdr)) { + peer_id = + hal_rx_mpdu_start_sw_peer_id_get(rx_tlv_hdr); + tid = + hal_rx_mpdu_start_tid_get(hal_soc, rx_tlv_hdr); + } + dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr, + peer_id, tid); + nbuf = next; + continue; default: QDF_TRACE(QDF_MODULE_ID_DP, - QDF_TRACE_LEVEL_DEBUG, + QDF_TRACE_LEVEL_ERROR, "REO error %d detected", wbm_err_info.reo_err_code); } diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index ea9e72b05a..7e9efad290 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -92,6 +92,9 @@ #define DP_MAX_INTERRUPT_CONTEXTS 8 +/* Maximum retries for Delba per tid per peer */ +#define DP_MAX_DELBA_RETRY 3 + #ifndef REMOVE_PKT_LOG enum rx_pktlog_mode { DP_RX_PKTLOG_DISABLED = 0, @@ -480,6 +483,20 @@ struct dp_rx_tid { uint16_t statuscode; /* user defined ADDBA response status code */ uint16_t userstatuscode; + + /* Store ppdu_id when 2k exception is received */ + uint32_t ppdu_id_2k; + + /* Delba Tx completion status */ + uint8_t delba_tx_status; + + /* Delba Tx retry count */ + uint8_t delba_tx_retry; + + /* Delba stats */ + uint32_t delba_tx_success_cnt; + uint32_t delba_tx_fail_cnt; + }; /* per interrupt context */ diff --git a/hal/wifi3.0/hal_reo.c b/hal/wifi3.0/hal_reo.c index f72eb4ca93..2aaf7c6e1c 100644 --- a/hal/wifi3.0/hal_reo.c +++ b/hal/wifi3.0/hal_reo.c @@ -496,7 +496,13 @@ inline int hal_reo_cmd_update_rx_queue(void *reo_ring, struct hal_soc *soc, if (p->ba_window_size < 1) p->ba_window_size = 1; - + /* + * WAR to get 2k exception in Non BA case. + * Setting window size to 2 to get 2k jump exception + * when we receive aggregates in Non BA case + */ + if (p->ba_window_size == 1) + p->ba_window_size++; HAL_DESC_SET_FIELD(reo_desc, REO_UPDATE_RX_REO_QUEUE_4, BA_WINDOW_SIZE, p->ba_window_size - 1); diff --git a/hal/wifi3.0/hal_rx.c b/hal/wifi3.0/hal_rx.c index a5ad0ef214..ccd12d3b64 100644 --- a/hal/wifi3.0/hal_rx.c +++ b/hal/wifi3.0/hal_rx.c @@ -105,7 +105,13 @@ void hal_reo_qdesc_setup(void *hal_soc, int tid, uint32_t ba_window_size, if (ba_window_size < 1) ba_window_size = 1; - + /* + * WAR to get 2k exception in Non BA case. + * Setting window size to 2 to get 2k jump exception + * when we receive aggregates in Non BA case + */ + if (ba_window_size == 1) + ba_window_size++; /* Set RTY bit for non-BA case. Duplicate detection is currently not * done by HW in non-BA case if RTY bit is not set. * TODO: This is a temporary War and should be removed once HW fix is