소스 검색

qcacmn: Add lock to protect reo algorithm entry

Add spin lock protect the critical section in reorder
algorithm entry.

CRs-Fixed: 3048994
Change-Id: I9bc6b30b2102dd14f0e5e2ba593e9a6bbbb72714
Edayilliam Jayadev 3 년 전
부모
커밋
8498476787
2개의 변경된 파일129개의 추가작업 그리고 8개의 파일을 삭제
  1. 125 8
      umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo.c
  2. 4 0
      umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo_i.h

+ 125 - 8
umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo.c

@@ -188,7 +188,6 @@ wlan_mgmt_rx_reo_algo_calculate_wait_count(
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	qdf_assert_always(num_mlo_links >= 1);
 	qdf_assert_always(num_mlo_links <= MGMT_RX_REO_MAX_LINKS);
 
 	/* Get the MLO link ID of incoming frame */
@@ -888,7 +887,6 @@ mgmt_rx_reo_update_wait_count(
 	qdf_assert_always(wait_count_old_frame);
 	qdf_assert_always(wait_count_new_frame);
 
-	qdf_assert_always(num_mlo_links >= 1);
 	qdf_assert_always(num_mlo_links <= MGMT_RX_REO_MAX_LINKS);
 
 	for (link_id = 0; link_id < num_mlo_links; link_id++) {
@@ -1156,6 +1154,24 @@ wlan_mgmt_rx_reo_update_host_snapshot(struct wlan_objmgr_pdev *pdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * mgmt_rx_reo_get_num_mlo_links() - Get number of MLO HW links from the reo
+ * context object
+ * @reo_context: Pointer to reo context object
+
+ * Return: On success returns number of MLO HW links. On failure returns -1.
+ */
+static int8_t
+mgmt_rx_reo_get_num_mlo_links(struct mgmt_rx_reo_context *reo_context)
+{
+	if (!reo_context) {
+		mgmt_rx_reo_err("Mgmt reo context is null");
+		return MGMT_RX_REO_INVALID_NUM_LINKS;
+	}
+
+	return reo_context->num_mlo_links;
+}
+
 QDF_STATUS
 wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
 			    struct mgmt_rx_reo_frame_descriptor *desc,
@@ -1163,6 +1179,7 @@ wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
 {
 	struct mgmt_rx_reo_context *reo_ctx;
 	QDF_STATUS status;
+	int8_t num_mlo_links;
 
 	if (!is_queued)
 		return QDF_STATUS_E_NULL_VALUE;
@@ -1177,15 +1194,108 @@ wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
 	reo_ctx = mgmt_rx_reo_get_context();
 	if (!reo_ctx) {
 		mgmt_rx_reo_err("REO context is NULL");
-		return QDF_STATUS_E_FAILURE;
+		return QDF_STATUS_E_NULL_VALUE;
 	}
 
+	num_mlo_links = mgmt_rx_reo_get_num_mlo_links(reo_ctx);
+	qdf_assert_always(num_mlo_links > 0);
+	qdf_assert_always(num_mlo_links <= MGMT_RX_REO_MAX_LINKS);
+
+	/**
+	 * Critical Section = Host snapshot update + Calculation of wait
+	 * counts + Update reorder list. Following section describes the
+	 * motivation for making this a critical section.
+	 * Lets take an example of 2 links (Link A & B) and each has received
+	 * a management frame A1 and B1 such that MLO global time stamp of A1 <
+	 * MLO global time stamp of B1. Host is concurrently executing
+	 * "wlan_mgmt_rx_reo_algo_entry" for A1 and B1 in 2 different CPUs.
+	 *
+	 * A lock less version of this API("wlan_mgmt_rx_reo_algo_entry_v1") is
+	 * as follows.
+	 *
+	 * wlan_mgmt_rx_reo_algo_entry()
+	 * {
+	 *     Host snapshot update
+	 *     Calculation of wait counts
+	 *     Update reorder list
+	 *     Release to upper layer
+	 * }
+	 *
+	 * We may run into race conditions under the following sequence of
+	 * operations.
+	 *
+	 * 1. Host snapshot update for link A in context of frame A1
+	 * 2. Host snapshot update for link B in context of frame B1
+	 * 3. Calculation of wait count for frame B1
+	 *        link A wait count =  0
+	 *        link B wait count =  0
+	 * 4. Update reorder list with frame B1
+	 * 5. Release B1 to upper layer
+	 * 6. Calculation of wait count for frame A1
+	 *        link A wait count =  0
+	 *        link B wait count =  0
+	 * 7. Update reorder list with frame A1
+	 * 8. Release A1 to upper layer
+	 *
+	 * This leads to incorrect behaviour as B1 goes to upper layer before
+	 * A1.
+	 *
+	 * To prevent this lets make Host snapshot update + Calculate wait count
+	 * a critical section by adding locks. The updated version of the API
+	 * ("wlan_mgmt_rx_reo_algo_entry_v2") is as follows.
+	 *
+	 * wlan_mgmt_rx_reo_algo_entry()
+	 * {
+	 *     LOCK
+	 *         Host snapshot update
+	 *         Calculation of wait counts
+	 *     UNLOCK
+	 *     Update reorder list
+	 *     Release to upper layer
+	 * }
+	 *
+	 * With this API also We may run into race conditions under the
+	 * following sequence of operations.
+	 *
+	 * 1. Host snapshot update for link A in context of frame A1 +
+	 *    Calculation of wait count for frame A1
+	 *        link A wait count =  0
+	 *        link B wait count =  0
+	 * 2. Host snapshot update for link B in context of frame B1 +
+	 *    Calculation of wait count for frame B1
+	 *        link A wait count =  0
+	 *        link B wait count =  0
+	 * 4. Update reorder list with frame B1
+	 * 5. Release B1 to upper layer
+	 * 7. Update reorder list with frame A1
+	 * 8. Release A1 to upper layer
+	 *
+	 * This also leads to incorrect behaviour as B1 goes to upper layer
+	 * before A1.
+	 *
+	 * To prevent this, let's make Host snapshot update + Calculate wait
+	 * count + Update reorder list a critical section by adding locks.
+	 * The updated version of the API ("wlan_mgmt_rx_reo_algo_entry_final")
+	 * is as follows.
+	 *
+	 * wlan_mgmt_rx_reo_algo_entry()
+	 * {
+	 *     LOCK
+	 *         Host snapshot update
+	 *         Calculation of wait counts
+	 *         Update reorder list
+	 *     UNLOCK
+	 *     Release to upper layer
+	 * }
+	 */
+	qdf_spin_lock(&reo_ctx->reo_algo_entry_lock);
+
 	/* Update the Host snapshot */
 	status = wlan_mgmt_rx_reo_update_host_snapshot(
 						pdev,
 						desc->rx_params->reo_params);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		mgmt_rx_reo_err("Unable to update Host snapshot");
+		qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -1193,20 +1303,23 @@ wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
 	status = wlan_mgmt_rx_reo_algo_calculate_wait_count(
 						pdev,
 						desc->rx_params->reo_params,
-						reo_ctx->num_mlo_links,
+						num_mlo_links,
 						&desc->wait_count);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		mgmt_rx_reo_err("Wait count calculation failed");
+		qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
 		return QDF_STATUS_E_FAILURE;
 	}
 
 	/* Update the REO list */
-	status = mgmt_rx_reo_update_list(&reo_ctx->reo_list, desc, is_queued);
+	status = mgmt_rx_reo_update_list(&reo_ctx->reo_list, num_mlo_links,
+					 desc, is_queued);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		mgmt_rx_reo_err("REO list updation failed");
+		qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
+
 	/* Finally, release the entries for which pending frame is received */
 	return mgmt_rx_reo_list_release_entries(&reo_ctx->reo_list);
 }
@@ -1232,6 +1345,8 @@ mgmt_rx_reo_init_context(void)
 
 	reo_context->ts_last_delivered_frame.valid = false;
 
+	qdf_spinlock_create(&reo_context->reo_algo_entry_lock);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -1324,6 +1439,8 @@ mgmt_rx_reo_deinit_context(void)
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
+	qdf_spinlock_destroy(&reo_context->reo_algo_entry_lock);
+
 	status = mgmt_rx_reo_list_deinit(&reo_context->reo_list);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mgmt_rx_reo_err("Failed to de-initialize mgmt Rx reo list");

+ 4 - 0
umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_rx_reo_i.h

@@ -42,6 +42,7 @@
  * Remove this once the actual one is implemented.
  */
 #define MGMT_RX_REO_MAX_LINKS (16)
+#define MGMT_RX_REO_INVALID_NUM_LINKS (-1)
 /* Reason to release an entry from the reorder list */
 #define MGMT_RX_REO_LIST_ENTRY_RELEASE_REASON_ZERO_WAIT_COUNT           (BIT(0))
 #define MGMT_RX_REO_LIST_ENTRY_RELEASE_REASON_AGED_OUT                  (BIT(1))
@@ -193,11 +194,14 @@ struct mgmt_rx_reo_list_entry {
  * @ts_last_delivered_frame: Stores the global time stamp for the last frame
  * delivered to the upper layer
  * @num_mlo_links: Number of MLO links on the system
+ * @reo_algo_entry_lock: Spin lock to protect reo algorithm entry critical
+ * section execution
  */
 struct mgmt_rx_reo_context {
 	struct mgmt_rx_reo_list reo_list;
 	struct mgmt_rx_reo_global_ts_info ts_last_delivered_frame;
 	uint8_t num_mlo_links;
+	qdf_spinlock_t reo_algo_entry_lock;
 };
 
 /**