Browse Source

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
sumedh baikady 6 years ago
parent
commit
faadbb6cd0
4 changed files with 156 additions and 5 deletions
  1. 2 1
      dp/inc/cdp_txrx_ops.h
  2. 135 3
      dp/wifi3.0/dp_peer.c
  3. 4 1
      dp/wifi3.0/dp_rx_err.c
  4. 15 0
      dp/wifi3.0/dp_types.h

+ 2 - 1
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 */
 };
 

+ 135 - 3
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;

+ 4 - 1
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);
 	}

+ 15 - 0
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