|
@@ -188,7 +188,6 @@ wlan_mgmt_rx_reo_algo_calculate_wait_count(
|
|
return QDF_STATUS_E_NULL_VALUE;
|
|
return QDF_STATUS_E_NULL_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
- qdf_assert_always(num_mlo_links >= 1);
|
|
|
|
qdf_assert_always(num_mlo_links <= MGMT_RX_REO_MAX_LINKS);
|
|
qdf_assert_always(num_mlo_links <= MGMT_RX_REO_MAX_LINKS);
|
|
|
|
|
|
/* Get the MLO link ID of incoming frame */
|
|
/* 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_old_frame);
|
|
qdf_assert_always(wait_count_new_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);
|
|
qdf_assert_always(num_mlo_links <= MGMT_RX_REO_MAX_LINKS);
|
|
|
|
|
|
for (link_id = 0; link_id < num_mlo_links; link_id++) {
|
|
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;
|
|
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
|
|
QDF_STATUS
|
|
wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
|
|
wlan_mgmt_rx_reo_algo_entry(struct wlan_objmgr_pdev *pdev,
|
|
struct mgmt_rx_reo_frame_descriptor *desc,
|
|
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;
|
|
struct mgmt_rx_reo_context *reo_ctx;
|
|
QDF_STATUS status;
|
|
QDF_STATUS status;
|
|
|
|
+ int8_t num_mlo_links;
|
|
|
|
|
|
if (!is_queued)
|
|
if (!is_queued)
|
|
return QDF_STATUS_E_NULL_VALUE;
|
|
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();
|
|
reo_ctx = mgmt_rx_reo_get_context();
|
|
if (!reo_ctx) {
|
|
if (!reo_ctx) {
|
|
mgmt_rx_reo_err("REO context is NULL");
|
|
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 */
|
|
/* Update the Host snapshot */
|
|
status = wlan_mgmt_rx_reo_update_host_snapshot(
|
|
status = wlan_mgmt_rx_reo_update_host_snapshot(
|
|
pdev,
|
|
pdev,
|
|
desc->rx_params->reo_params);
|
|
desc->rx_params->reo_params);
|
|
if (QDF_IS_STATUS_ERROR(status)) {
|
|
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;
|
|
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(
|
|
status = wlan_mgmt_rx_reo_algo_calculate_wait_count(
|
|
pdev,
|
|
pdev,
|
|
desc->rx_params->reo_params,
|
|
desc->rx_params->reo_params,
|
|
- reo_ctx->num_mlo_links,
|
|
|
|
|
|
+ num_mlo_links,
|
|
&desc->wait_count);
|
|
&desc->wait_count);
|
|
if (QDF_IS_STATUS_ERROR(status)) {
|
|
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;
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
/* Update the REO list */
|
|
/* 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)) {
|
|
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;
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ qdf_spin_unlock(&reo_ctx->reo_algo_entry_lock);
|
|
|
|
+
|
|
/* Finally, release the entries for which pending frame is received */
|
|
/* Finally, release the entries for which pending frame is received */
|
|
return mgmt_rx_reo_list_release_entries(&reo_ctx->reo_list);
|
|
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;
|
|
reo_context->ts_last_delivered_frame.valid = false;
|
|
|
|
|
|
|
|
+ qdf_spinlock_create(&reo_context->reo_algo_entry_lock);
|
|
|
|
+
|
|
return QDF_STATUS_SUCCESS;
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1324,6 +1439,8 @@ mgmt_rx_reo_deinit_context(void)
|
|
return QDF_STATUS_E_NULL_VALUE;
|
|
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);
|
|
status = mgmt_rx_reo_list_deinit(&reo_context->reo_list);
|
|
if (QDF_IS_STATUS_ERROR(status)) {
|
|
if (QDF_IS_STATUS_ERROR(status)) {
|
|
mgmt_rx_reo_err("Failed to de-initialize mgmt Rx reo list");
|
|
mgmt_rx_reo_err("Failed to de-initialize mgmt Rx reo list");
|