diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index ada8d7cceebb..3b49c29ee0b4 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -847,7 +847,8 @@ struct ol_if_ops { * 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); + uint8_t *peer_macaddr, uint8_t tid, void *vdev_handle, + uint8_t reason_code); /* TODO: Add any other control path calls required to OL_IF/WMA layer */ }; diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index 54e0d00ba7b1..56e0df9d231d 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -1580,6 +1580,10 @@ void dp_peer_rx_init(struct dp_pdev *pdev, struct dp_peer *peer) #endif } + peer->active_ba_session_cnt = 0; + peer->hw_buffer_size = 0; + peer->kill_256_sessions = 0; + /* Setup default (non-qos) rx tid queue */ dp_rx_tid_setup_wifi3(peer, DP_NON_QOS_TID, 1, 0); @@ -1656,6 +1660,56 @@ void dp_peer_cleanup(struct dp_vdev *vdev, struct dp_peer *peer) dp_peer_rx_cleanup(vdev, peer); } +/* dp_teardown_256_ba_session() - Teardown sessions using 256 + * window size when a request with + * 64 window size is received. + * This is done as a WAR since HW can + * have only one setting per peer (64 or 256). + * @peer: Datapath peer + * + * Return: void + */ +static void dp_teardown_256_ba_sessions(struct dp_peer *peer) +{ + uint8_t delba_rcode = 0; + int tid; + struct dp_rx_tid *rx_tid = NULL; + + for (tid = 0; tid < DP_MAX_TIDS; tid++) { + rx_tid = &peer->rx_tid[tid]; + qdf_spin_lock_bh(&rx_tid->tid_lock); + + if (rx_tid->ba_win_size <= 64) { + qdf_spin_unlock_bh(&rx_tid->tid_lock); + continue; + } else { + if (rx_tid->ba_status == DP_RX_BA_ACTIVE || + rx_tid->ba_status == DP_RX_BA_IN_PROGRESS) { + /* send delba */ + if (!rx_tid->delba_tx_status) { + rx_tid->delba_tx_retry++; + rx_tid->delba_tx_status = 1; + rx_tid->delba_rcode = + IEEE80211_REASON_QOS_SETUP_REQUIRED; + delba_rcode = rx_tid->delba_rcode; + + 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, + delba_rcode); + } else { + qdf_spin_unlock_bh(&rx_tid->tid_lock); + } + } else { + qdf_spin_unlock_bh(&rx_tid->tid_lock); + } + } + } +} + /* * dp_rx_addba_resp_tx_completion_wifi3() – Update Rx Tid State * @@ -1697,8 +1751,28 @@ int dp_addba_resp_tx_completion_wifi3(void *peer_handle, return QDF_STATUS_E_FAILURE; } + /* First Session */ + if (peer->active_ba_session_cnt == 0) { + if (rx_tid->ba_win_size > 64 && rx_tid->ba_win_size <= 256) + peer->hw_buffer_size = 256; + else + peer->hw_buffer_size = 64; + } + rx_tid->ba_status = DP_RX_BA_ACTIVE; + + peer->active_ba_session_cnt++; + qdf_spin_unlock_bh(&rx_tid->tid_lock); + + /* Kill any session having 256 buffer size + * when 64 buffer size request is received. + * Also, latch on to 64 as new buffer size. + */ + if (peer->kill_256_sessions) { + dp_teardown_256_ba_sessions(peer); + peer->kill_256_sessions = 0; + } return QDF_STATUS_SUCCESS; } @@ -1735,6 +1809,43 @@ void dp_addba_responsesetup_wifi3(void *peer_handle, uint8_t tid, qdf_spin_unlock_bh(&rx_tid->tid_lock); } +/* dp_check_ba_buffersize() - Check buffer size in request + * and latch onto this size based on + * size used in first active session. + * @peer: Datapath peer + * @tid: Tid + * @buffersize: Block ack window size + * + * Return: void + */ +static void dp_check_ba_buffersize(struct dp_peer *peer, + uint16_t tid, + uint16_t buffersize) +{ + struct dp_rx_tid *rx_tid = NULL; + + rx_tid = &peer->rx_tid[tid]; + + if (peer->active_ba_session_cnt == 0) { + rx_tid->ba_win_size = buffersize; + } else { + if (peer->hw_buffer_size == 64) { + if (buffersize <= 64) + rx_tid->ba_win_size = buffersize; + else + rx_tid->ba_win_size = peer->hw_buffer_size; + } else if (peer->hw_buffer_size == 256) { + if (buffersize > 64) { + rx_tid->ba_win_size = buffersize; + } else { + rx_tid->ba_win_size = buffersize; + peer->hw_buffer_size = 64; + peer->kill_256_sessions = 1; + } + } + } +} + /* * dp_addba_requestprocess_wifi3() - Process ADDBA request from peer * @@ -1769,6 +1880,7 @@ int dp_addba_requestprocess_wifi3(void *peer_handle, (rx_tid->ba_status == DP_RX_BA_IN_PROGRESS)) { dp_rx_tid_update_wifi3(peer, tid, 1, 0); rx_tid->ba_status = DP_RX_BA_INACTIVE; + peer->active_ba_session_cnt--; qdf_spin_unlock_bh(&rx_tid->tid_lock); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "%s: Rx Tid- %d hw qdesc is already setup", @@ -1776,7 +1888,14 @@ int dp_addba_requestprocess_wifi3(void *peer_handle, return QDF_STATUS_E_FAILURE; } - if (dp_rx_tid_setup_wifi3(peer, tid, buffersize, 0)) { + if (rx_tid->ba_status == DP_RX_BA_IN_PROGRESS) { + qdf_spin_unlock_bh(&rx_tid->tid_lock); + return QDF_STATUS_E_FAILURE; + } + + dp_check_ba_buffersize(peer, tid, buffersize); + + if (dp_rx_tid_setup_wifi3(peer, tid, buffersize, startseqnum)) { rx_tid->ba_status = DP_RX_BA_INACTIVE; qdf_spin_unlock_bh(&rx_tid->tid_lock); return QDF_STATUS_E_FAILURE; @@ -1830,7 +1949,8 @@ int dp_delba_process_wifi3(void *peer_handle, struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; qdf_spin_lock_bh(&rx_tid->tid_lock); - if (rx_tid->ba_status == DP_RX_BA_INACTIVE) { + if (rx_tid->ba_status == DP_RX_BA_INACTIVE || + rx_tid->ba_status == DP_RX_BA_IN_PROGRESS) { qdf_spin_unlock_bh(&rx_tid->tid_lock); return QDF_STATUS_E_FAILURE; } @@ -1838,10 +1958,12 @@ int dp_delba_process_wifi3(void *peer_handle, * replace with a new one without queue extenstion descript to save * memory */ + rx_tid->delba_rcode = reasoncode; rx_tid->num_of_delba_req++; dp_rx_tid_update_wifi3(peer, tid, 1, 0); rx_tid->ba_status = DP_RX_BA_INACTIVE; + peer->active_ba_session_cnt--; qdf_spin_unlock_bh(&rx_tid->tid_lock); return 0; } @@ -1880,7 +2002,8 @@ int dp_delba_tx_completion_wifi3(void *peer_handle, 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); + peer->mac_addr.raw, tid, peer->vdev->ctrl_vdev, + rx_tid->delba_rcode); } return QDF_STATUS_SUCCESS; } else { @@ -1888,6 +2011,15 @@ int dp_delba_tx_completion_wifi3(void *peer_handle, rx_tid->delba_tx_retry = 0; rx_tid->delba_tx_status = 0; } + if (rx_tid->ba_status == DP_RX_BA_ACTIVE) { + dp_rx_tid_update_wifi3(peer, tid, 1, 0); + rx_tid->ba_status = DP_RX_BA_INACTIVE; + peer->active_ba_session_cnt--; + } + if (rx_tid->ba_status == DP_RX_BA_IN_PROGRESS) { + dp_rx_tid_update_wifi3(peer, tid, 1, 0); + rx_tid->ba_status = DP_RX_BA_INACTIVE; + } qdf_spin_unlock_bh(&rx_tid->tid_lock); return QDF_STATUS_SUCCESS; diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 490b6ed664ac..2b81e644f4c6 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -520,12 +520,15 @@ dp_2k_jump_handle(struct dp_soc *soc, if (!rx_tid->delba_tx_status) { rx_tid->delba_tx_retry++; rx_tid->delba_tx_status = 1; + rx_tid->delba_rcode = + IEEE80211_REASON_QOS_SETUP_REQUIRED; 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); + peer->vdev->ctrl_vdev, + rx_tid->delba_rcode); } else { qdf_spin_unlock_bh(&rx_tid->tid_lock); } diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index a58557e9c06d..1e63c195191e 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -502,6 +502,9 @@ struct dp_rx_tid { uint32_t delba_tx_success_cnt; uint32_t delba_tx_fail_cnt; + /* Delba reason code for retries */ + uint8_t delba_rcode; + }; /* per interrupt context */ @@ -1490,6 +1493,18 @@ struct dp_peer { dp_ecm_policy wds_ecm; #endif bool delete_in_progress; + + /* Active Block ack sessions */ + uint16_t active_ba_session_cnt; + + /* Current HW buffersize setting */ + uint16_t hw_buffer_size; + + /* + * Flag to check if sessions with 256 buffersize + * should be terminated. + */ + uint8_t kill_256_sessions; }; #ifdef CONFIG_WIN