From ea84c95dbfe8c8bca95f7db77971483626dfd19a Mon Sep 17 00:00:00 2001 From: Arun Swain Date: Tue, 4 Aug 2020 23:18:31 -0700 Subject: [PATCH] tegra: platform: dce: Fix race condition on fgpa Resolve race condition where DCE Firmware could potentially send an IVC signal before even CPU driver starts listening for it. This fix makes sure that the driver need not wait if it has been signalled already by Firmware. Jira TDS-6381 Change-Id: I3d6dd1f93ce36f9e44b7157f70c0aad099f2d561 Signed-off-by: Arun Swain Reviewed-on: https://git-master.nvidia.com/r/c/linux-t23x/+/2394468 Tested-by: Santosh Galma Tested-by: mobile promotions Reviewed-by: Santosh Galma Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Mahesh Kumar Reviewed-by: mobile promotions GVS: Gerrit_Virtual_Submit --- drivers/platform/tegra/dce/dce-ipc.c | 15 +++++---------- drivers/platform/tegra/dce/dce-worker.c | 16 +++++++++------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/platform/tegra/dce/dce-ipc.c b/drivers/platform/tegra/dce/dce-ipc.c index d2aedc69..2f7e1bc4 100644 --- a/drivers/platform/tegra/dce/dce-ipc.c +++ b/drivers/platform/tegra/dce/dce-ipc.c @@ -174,7 +174,7 @@ static void dce_ipc_signal_target(struct ivc *ivc) ch->signal.notify(ch->d, &ch->signal.to_d); } -static int dce_ipc_wait(struct tegra_dce *d, u32 w_type, u32 ch_type) +static int _dce_ipc_wait(struct tegra_dce *d, u32 w_type, u32 ch_type) { int ret = 0; struct dce_ipc_channel *ch; @@ -191,8 +191,6 @@ static int dce_ipc_wait(struct tegra_dce *d, u32 w_type, u32 ch_type) goto out; } - dce_mutex_lock(&ch->lock); - ch->w_type = w_type; dce_mutex_unlock(&ch->lock); @@ -207,7 +205,6 @@ static int dce_ipc_wait(struct tegra_dce *d, u32 w_type, u32 ch_type) ch->w_type = DCE_IPC_WAIT_TYPE_INVALID; out: - dce_mutex_unlock(&ch->lock); return ret; } @@ -429,11 +426,7 @@ void dce_ipc_channel_reset(struct tegra_dce *d, u32 ch_type) ch->flags &= ~DCE_IPC_CHANNEL_SYNCED; - dce_mutex_unlock(&ch->lock); - - dce_ipc_wait(ch->d, DCE_IPC_WAIT_TYPE_SYNC, ch_type); - - dce_mutex_lock(&ch->lock); + _dce_ipc_wait(ch->d, DCE_IPC_WAIT_TYPE_SYNC, ch_type); ch->flags |= DCE_IPC_CHANNEL_SYNCED; @@ -651,7 +644,9 @@ int dce_ipc_send_message_sync(struct tegra_dce *d, u32 ch_type, goto done; } - ret = dce_ipc_wait(ch->d, DCE_IPC_WAIT_TYPE_RPC, ch_type); + dce_mutex_lock(&ch->lock); + ret = _dce_ipc_wait(ch->d, DCE_IPC_WAIT_TYPE_RPC, ch_type); + dce_mutex_unlock(&ch->lock); if (ret) { dce_err(ch->d, "Error in waiting for ack"); goto done; diff --git a/drivers/platform/tegra/dce/dce-worker.c b/drivers/platform/tegra/dce/dce-worker.c index fce4b480..1235ab3d 100644 --- a/drivers/platform/tegra/dce/dce-worker.c +++ b/drivers/platform/tegra/dce/dce-worker.c @@ -53,8 +53,12 @@ void dce_worker_thread_wait(struct tegra_dce *d, enum dce_worker_state new_state; struct dce_worker_info *w = &d->wrk_info; + dce_mutex_lock(&w->lock); + if (w->state_changed == true) { + w->state_changed = false; dce_warn(d, "Unexpected state_changed value"); + dce_mutex_unlock(&w->lock); return; } @@ -81,13 +85,14 @@ void dce_worker_thread_wait(struct tegra_dce *d, return; } - dce_mutex_lock(&w->lock); w->c_state = new_state; dce_mutex_unlock(&w->lock); if (new_state == STATE_DCE_WORKER_BOOT_WAIT) timeout_val_ms = 1000; + dce_mutex_unlock(&w->lock); + ret = DCE_COND_WAIT_INTERRUPTIBLE(&w->cond, dce_worker_wakeup_cond(d), timeout_val_ms); @@ -119,18 +124,16 @@ void dce_worker_thread_wakeup(struct tegra_dce *d, struct dce_worker_info *w = &d->wrk_info; enum dce_worker_state new_state = w->c_state; - if (w->state_changed == true) { + dce_mutex_lock(&w->lock); + + if (w->state_changed == true) dce_warn(d, "Unexpected state_changed value"); - dce_mutex_unlock(&w->lock); - return; - } switch (event) { case EVENT_ID_DCE_IPC_SIGNAL_RECEIVED: if (w->c_state != STATE_DCE_WORKER_WFI) { dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]", event, w->c_state); - return; } new_state = STATE_DCE_WORKER_IDLE; break; @@ -160,7 +163,6 @@ void dce_worker_thread_wakeup(struct tegra_dce *d, return; } - dce_mutex_lock(&w->lock); w->c_state = new_state; w->state_changed = true; dce_mutex_unlock(&w->lock);