diff --git a/drivers/crypto/tegra-hv-vse-safety.c b/drivers/crypto/tegra-hv-vse-safety.c index eeb37524..54e5b79a 100644 --- a/drivers/crypto/tegra-hv-vse-safety.c +++ b/drivers/crypto/tegra-hv-vse-safety.c @@ -664,10 +664,15 @@ static int read_and_validate_valid_msg( int read_size = -1, err = 0; size_t size_ivc_msg = sizeof(struct tegra_virtual_se_ivc_msg_t); - irq_state = &(se_dev->crypto_to_ivc_map[node_id].wait_interrupt); + mutex_lock(&(g_crypto_to_ivc_map[node_id].irq_state_lock)); + irq_state = &(g_crypto_to_ivc_map[node_id].wait_interrupt); + mutex_unlock(&(g_crypto_to_ivc_map[node_id].irq_state_lock)); + if (!tegra_hv_ivc_can_read(pivck)) { + mutex_lock(&(g_crypto_to_ivc_map[node_id].irq_state_lock)); *irq_state = INTERMEDIATE_REQ_INTERRUPT; - dev_err(se_dev->dev, "%s(): no valid message, await interrupt.\n", __func__); + mutex_unlock(&(g_crypto_to_ivc_map[node_id].irq_state_lock)); + dev_info(se_dev->dev, "%s(): no valid message, await interrupt.\n", __func__); return -EAGAIN; } @@ -801,7 +806,7 @@ static int tegra_hv_vse_safety_send_ivc_wait( int err; bool is_dummy = false; u64 time_left; - enum ivc_irq_state *irq_state; + enum ivc_irq_state *irq_state, local_irq_state; mutex_lock(&g_crypto_to_ivc_map[node_id].se_ivc_lock); @@ -830,8 +835,11 @@ static int tegra_hv_vse_safety_send_ivc_wait( goto exit; } + mutex_lock(&(g_crypto_to_ivc_map[node_id].irq_state_lock)); irq_state = &(se_dev->crypto_to_ivc_map[node_id].wait_interrupt); - if (*irq_state == NO_INTERRUPT) { + local_irq_state = *irq_state; + mutex_unlock(&(g_crypto_to_ivc_map[node_id].irq_state_lock)); + if (local_irq_state == NO_INTERRUPT) { err = read_and_validate_dummy_msg(se_dev, pivck, node_id, &is_dummy); if (err != 0) { dev_err(se_dev->dev, "Failed to read and validate dummy message.\n"); @@ -843,9 +851,9 @@ static int tegra_hv_vse_safety_send_ivc_wait( dev_err(se_dev->dev, "Failed to read & validate valid message.\n"); goto exit; } - if (*irq_state == INTERMEDIATE_REQ_INTERRUPT) { + if (err == -EAGAIN) { err = 0; - pr_debug("%s(): wait_interrupt = %u", __func__, *irq_state); + pr_debug("%s(): wait_interrupt = %u", __func__, local_irq_state); time_left = wait_for_completion_timeout(&priv->alg_complete, TEGRA_HV_VSE_TIMEOUT); if (time_left == 0) { @@ -854,7 +862,7 @@ static int tegra_hv_vse_safety_send_ivc_wait( goto exit; } } - pr_debug("%s(): wait_interrupt = %u", __func__, *irq_state); + pr_debug("%s(): wait_interrupt = %u", __func__, local_irq_state); } else { dev_err(se_dev->dev, "%s(): Invalid resonse sequence, expected dummy message.\n", @@ -4629,10 +4637,9 @@ static int tegra_vse_kthread(void *data) int ret; bool is_dummy = false; size_t size_ivc_msg = sizeof(struct tegra_virtual_se_ivc_msg_t); - enum ivc_irq_state *irq_state; + enum ivc_irq_state *irq_state, local_irq_state; se_dev = g_virtual_se_dev[g_crypto_to_ivc_map[node_id].se_engine]; - irq_state = &(se_dev->crypto_to_ivc_map[node_id].wait_interrupt); ivc_msg = devm_kzalloc(se_dev->dev, size_ivc_msg, GFP_KERNEL); if (!ivc_msg) @@ -4671,9 +4678,13 @@ static int tegra_vse_kthread(void *data) continue; } - while (tegra_hv_ivc_can_read(pivck)) { - pr_debug("%s(): wait_interrupt = %u", __func__, *irq_state); - if (*irq_state == INTERMEDIATE_REQ_INTERRUPT) { + mutex_lock(&(se_dev->crypto_to_ivc_map[node_id].irq_state_lock)); + irq_state = &(se_dev->crypto_to_ivc_map[node_id].wait_interrupt); + local_irq_state = *irq_state; + mutex_unlock(&(se_dev->crypto_to_ivc_map[node_id].irq_state_lock)); + while (tegra_hv_ivc_can_read(pivck) && local_irq_state != NO_INTERRUPT) { + pr_debug("%s(): wait_interrupt = %u", __func__, local_irq_state); + if (local_irq_state == INTERMEDIATE_REQ_INTERRUPT) { err = read_and_validate_valid_msg(se_dev, pivck, node_id, &is_dummy, true); if (err != 0) { @@ -4681,11 +4692,15 @@ static int tegra_vse_kthread(void *data) "%s(): Unable to read validate message", __func__); } + mutex_lock(&(se_dev->crypto_to_ivc_map[node_id].irq_state_lock)); *irq_state = NO_INTERRUPT; + local_irq_state = *irq_state; + mutex_unlock(&(se_dev->crypto_to_ivc_map[node_id].irq_state_lock)); pr_debug("%s():%d wait_interrupt = %u\n", - __func__, __LINE__, *irq_state); + __func__, __LINE__, local_irq_state); break; - } else if (*irq_state == FIRST_REQ_INTERRUPT) { + + } else if (local_irq_state == FIRST_REQ_INTERRUPT) { err = read_and_validate_dummy_msg(se_dev, pivck, node_id, &is_dummy); if (err != 0) { @@ -4695,7 +4710,12 @@ static int tegra_vse_kthread(void *data) continue; } if (is_dummy == true) { + mutex_lock( + &(se_dev->crypto_to_ivc_map[node_id].irq_state_lock)); *irq_state = INTERMEDIATE_REQ_INTERRUPT; + local_irq_state = *irq_state; + mutex_unlock( + &(se_dev->crypto_to_ivc_map[node_id].irq_state_lock)); pr_debug("%s():%d Dummy message read. Read valid message.", __func__, __LINE__); continue; @@ -4703,6 +4723,9 @@ static int tegra_vse_kthread(void *data) dev_err(se_dev->dev, "Invalid response sequence"); break; } + } else { + dev_err(se_dev->dev, "Invalid irq state - %u", local_irq_state); + return -EINVAL; } } } @@ -4988,6 +5011,7 @@ static int tegra_hv_vse_safety_probe(struct platform_device *pdev) tegra_hv_ivc_channel_reset(crypto_dev->ivck); init_completion(&crypto_dev->tegra_vse_complete); mutex_init(&crypto_dev->se_ivc_lock); + mutex_init(&crypto_dev->irq_state_lock); crypto_dev->tegra_vse_task = kthread_run(tegra_vse_kthread, &crypto_dev->node_id, "tegra_vse_kthread-%u", node_id); @@ -5124,7 +5148,8 @@ static void tegra_hv_vse_safety_shutdown(struct platform_device *pdev) if (g_crypto_to_ivc_map[cnt].se_engine == se_dev->engine_id && g_crypto_to_ivc_map[cnt].ivck != NULL) { /* Wait for SE server to be free*/ - while (mutex_is_locked(&g_crypto_to_ivc_map[cnt].se_ivc_lock)) + while (mutex_is_locked(&g_crypto_to_ivc_map[cnt].se_ivc_lock) + || mutex_is_locked(&g_crypto_to_ivc_map[cnt].irq_state_lock)) usleep_range(8, 10); } } diff --git a/drivers/crypto/tegra-hv-vse.h b/drivers/crypto/tegra-hv-vse.h index e5838db8..d1e01621 100644 --- a/drivers/crypto/tegra-hv-vse.h +++ b/drivers/crypto/tegra-hv-vse.h @@ -46,6 +46,7 @@ struct crypto_dev_to_ivc_map { * 2: awaiting actual message, wait for interrupt */ enum ivc_irq_state wait_interrupt; + struct mutex irq_state_lock; }; struct tegra_virtual_se_dev {