From 0f08390fa419e0dbf856d5506204ae709c30518c Mon Sep 17 00:00:00 2001 From: Tiger Yu Date: Fri, 12 Jun 2020 09:14:22 +0800 Subject: [PATCH] qcacmn: Add memory barrier to avoid inconsistent reg write for valid flag Add memory barrier to avoid inconsistent reg write for valid flag. Change-Id: Ieb4ed80872961889f29de083a6b1dcdbe6a303d2 CRs-Fixed: 2699549 --- hal/wifi3.0/hal_internal.h | 2 ++ hal/wifi3.0/hal_srng.c | 20 +++++++++++++++++++- qdf/inc/qdf_util.h | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/hal/wifi3.0/hal_internal.h b/hal/wifi3.0/hal_internal.h index f58ae1e311..19f24ad65f 100644 --- a/hal/wifi3.0/hal_internal.h +++ b/hal/wifi3.0/hal_internal.h @@ -237,6 +237,7 @@ typedef struct hal_ring_handle *hal_ring_handle_t; * @dequeue_val: register value at the time of delayed write dequeue * @valid: whether this entry is valid or not * @enqueue_time: enqueue time (qdf_log_timestamp) + * @work_scheduled_time: work scheduled time (qdf_log_timestamp) * @dequeue_time: dequeue time (qdf_log_timestamp) */ struct hal_reg_write_q_elem { @@ -246,6 +247,7 @@ struct hal_reg_write_q_elem { uint32_t dequeue_val; uint8_t valid; qdf_time_t enqueue_time; + qdf_time_t work_scheduled_time; qdf_time_t dequeue_time; }; diff --git a/hal/wifi3.0/hal_srng.c b/hal/wifi3.0/hal_srng.c index 1e9b403075..8cb491954f 100644 --- a/hal/wifi3.0/hal_srng.c +++ b/hal/wifi3.0/hal_srng.c @@ -461,7 +461,10 @@ static void hal_reg_write_work(void *arg) uint32_t *addr; q_elem = &hal->reg_write_queue[(hal->read_idx)]; + q_elem->work_scheduled_time = qdf_get_log_timestamp(); + /* Make sure q_elem consistent in the memory for multi-cores */ + qdf_rmb(); if (!q_elem->valid) return; @@ -474,7 +477,11 @@ static void hal_reg_write_work(void *arg) return; } - while (q_elem->valid) { + while (true) { + qdf_rmb(); + if (!q_elem->valid) + break; + q_elem->dequeue_time = qdf_get_log_timestamp(); ring_id = q_elem->srng->ring_id; addr = q_elem->addr; @@ -569,6 +576,17 @@ static void hal_reg_write_enqueue(struct hal_soc *hal_soc, qdf_wmb(); q_elem->valid = true; + /* + * After all other fields in the q_elem has been updated + * in memory successfully, the valid flag needs to be updated + * in memory in time too. + * Else there is a chance that the dequeuing worker thread + * might read stale valid flag and the work will be bypassed + * for this round. And if there is no other work scheduled + * later, this hal register writing won't be updated any more. + */ + qdf_wmb(); + srng->reg_write_in_progress = true; qdf_atomic_inc(&hal_soc->active_work_cnt); diff --git a/qdf/inc/qdf_util.h b/qdf/inc/qdf_util.h index 0eea9b00bb..ff78ce357b 100644 --- a/qdf/inc/qdf_util.h +++ b/qdf/inc/qdf_util.h @@ -51,6 +51,11 @@ typedef __qdf_wait_queue_head_t qdf_wait_queue_head_t; */ #define qdf_wmb() __qdf_wmb() +/** + * qdf_rmb - read memory barrier. + */ +#define qdf_rmb() __qdf_rmb() + /** * qdf_mb - read + write memory barrier. */