From faadbb6cd0aca110566560a28e195b8bdd77f6c4 Mon Sep 17 00:00:00 2001 From: sumedh baikady Date: Tue, 21 Aug 2018 21:13:42 -0700 Subject: [PATCH] qcacmn: Handle addba req with incompatible buffersize In HKv1 HW there is a buffersize setting per peer, hence once we set buffersize we have to stick to this for all subsequent requests for all tids. If buffersize in Addba request is more than first session's buffersize, we restrict buffersize to old value, else we send respond with new size and send delba to previous sessions not compatible with new buffersize Change-Id: Ia71d994ee06ca7b37d93273f5fa69547f816dd20 Crs-fixed: 2247816 --- dp/inc/cdp_txrx_ops.h | 3 +- dp/wifi3.0/dp_peer.c | 138 ++++++++++++++++++++++++++++++++++++++++- dp/wifi3.0/dp_rx_err.c | 5 +- dp/wifi3.0/dp_types.h | 15 +++++ 4 files changed, 156 insertions(+), 5 deletions(-) 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