Commit 4c585a57 authored by Leonard Crestez's avatar Leonard Crestez Committed by Kleber Sacilotto de Souza

crypto: mxs-dcp - Fix wait logic on chan threads

BugLink: https://bugs.launchpad.net/bugs/1798770

commit d80771c0 upstream.

When compiling with CONFIG_DEBUG_ATOMIC_SLEEP=y the mxs-dcp driver
prints warnings such as:

WARNING: CPU: 0 PID: 120 at kernel/sched/core.c:7736 __might_sleep+0x98/0x9c
do not call blocking ops when !TASK_RUNNING; state=1 set at [<8081978c>] dcp_chan_thread_sha+0x3c/0x2ec

The problem is that blocking ops will manipulate current->state
themselves so it is not allowed to call them between
set_current_state(TASK_INTERRUPTIBLE) and schedule().

Fix this by converting the per-chan mutex to a spinlock (it only
protects tiny list ops anyway) and rearranging the wait logic so that
callbacks are called current->state as TASK_RUNNING. Those callbacks
will indeed call blocking ops themselves so this is required.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarLeonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarStefan Bader <stefan.bader@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 2b6501be
...@@ -63,7 +63,7 @@ struct dcp { ...@@ -63,7 +63,7 @@ struct dcp {
struct dcp_coherent_block *coh; struct dcp_coherent_block *coh;
struct completion completion[DCP_MAX_CHANS]; struct completion completion[DCP_MAX_CHANS];
struct mutex mutex[DCP_MAX_CHANS]; spinlock_t lock[DCP_MAX_CHANS];
struct task_struct *thread[DCP_MAX_CHANS]; struct task_struct *thread[DCP_MAX_CHANS];
struct crypto_queue queue[DCP_MAX_CHANS]; struct crypto_queue queue[DCP_MAX_CHANS];
}; };
...@@ -349,13 +349,20 @@ static int dcp_chan_thread_aes(void *data) ...@@ -349,13 +349,20 @@ static int dcp_chan_thread_aes(void *data)
int ret; int ret;
do { while (!kthread_should_stop()) {
__set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
mutex_lock(&sdcp->mutex[chan]); spin_lock(&sdcp->lock[chan]);
backlog = crypto_get_backlog(&sdcp->queue[chan]); backlog = crypto_get_backlog(&sdcp->queue[chan]);
arq = crypto_dequeue_request(&sdcp->queue[chan]); arq = crypto_dequeue_request(&sdcp->queue[chan]);
mutex_unlock(&sdcp->mutex[chan]); spin_unlock(&sdcp->lock[chan]);
if (!backlog && !arq) {
schedule();
continue;
}
set_current_state(TASK_RUNNING);
if (backlog) if (backlog)
backlog->complete(backlog, -EINPROGRESS); backlog->complete(backlog, -EINPROGRESS);
...@@ -363,11 +370,8 @@ static int dcp_chan_thread_aes(void *data) ...@@ -363,11 +370,8 @@ static int dcp_chan_thread_aes(void *data)
if (arq) { if (arq) {
ret = mxs_dcp_aes_block_crypt(arq); ret = mxs_dcp_aes_block_crypt(arq);
arq->complete(arq, ret); arq->complete(arq, ret);
continue;
} }
}
schedule();
} while (!kthread_should_stop());
return 0; return 0;
} }
...@@ -407,9 +411,9 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb) ...@@ -407,9 +411,9 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb)
rctx->ecb = ecb; rctx->ecb = ecb;
actx->chan = DCP_CHAN_CRYPTO; actx->chan = DCP_CHAN_CRYPTO;
mutex_lock(&sdcp->mutex[actx->chan]); spin_lock(&sdcp->lock[actx->chan]);
ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
mutex_unlock(&sdcp->mutex[actx->chan]); spin_unlock(&sdcp->lock[actx->chan]);
wake_up_process(sdcp->thread[actx->chan]); wake_up_process(sdcp->thread[actx->chan]);
...@@ -645,13 +649,20 @@ static int dcp_chan_thread_sha(void *data) ...@@ -645,13 +649,20 @@ static int dcp_chan_thread_sha(void *data)
struct ahash_request *req; struct ahash_request *req;
int ret, fini; int ret, fini;
do { while (!kthread_should_stop()) {
__set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
mutex_lock(&sdcp->mutex[chan]); spin_lock(&sdcp->lock[chan]);
backlog = crypto_get_backlog(&sdcp->queue[chan]); backlog = crypto_get_backlog(&sdcp->queue[chan]);
arq = crypto_dequeue_request(&sdcp->queue[chan]); arq = crypto_dequeue_request(&sdcp->queue[chan]);
mutex_unlock(&sdcp->mutex[chan]); spin_unlock(&sdcp->lock[chan]);
if (!backlog && !arq) {
schedule();
continue;
}
set_current_state(TASK_RUNNING);
if (backlog) if (backlog)
backlog->complete(backlog, -EINPROGRESS); backlog->complete(backlog, -EINPROGRESS);
...@@ -663,12 +674,8 @@ static int dcp_chan_thread_sha(void *data) ...@@ -663,12 +674,8 @@ static int dcp_chan_thread_sha(void *data)
ret = dcp_sha_req_to_buf(arq); ret = dcp_sha_req_to_buf(arq);
fini = rctx->fini; fini = rctx->fini;
arq->complete(arq, ret); arq->complete(arq, ret);
if (!fini)
continue;
} }
}
schedule();
} while (!kthread_should_stop());
return 0; return 0;
} }
...@@ -726,9 +733,9 @@ static int dcp_sha_update_fx(struct ahash_request *req, int fini) ...@@ -726,9 +733,9 @@ static int dcp_sha_update_fx(struct ahash_request *req, int fini)
rctx->init = 1; rctx->init = 1;
} }
mutex_lock(&sdcp->mutex[actx->chan]); spin_lock(&sdcp->lock[actx->chan]);
ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
mutex_unlock(&sdcp->mutex[actx->chan]); spin_unlock(&sdcp->lock[actx->chan]);
wake_up_process(sdcp->thread[actx->chan]); wake_up_process(sdcp->thread[actx->chan]);
mutex_unlock(&actx->mutex); mutex_unlock(&actx->mutex);
...@@ -984,7 +991,7 @@ static int mxs_dcp_probe(struct platform_device *pdev) ...@@ -984,7 +991,7 @@ static int mxs_dcp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sdcp); platform_set_drvdata(pdev, sdcp);
for (i = 0; i < DCP_MAX_CHANS; i++) { for (i = 0; i < DCP_MAX_CHANS; i++) {
mutex_init(&sdcp->mutex[i]); spin_lock_init(&sdcp->lock[i]);
init_completion(&sdcp->completion[i]); init_completion(&sdcp->completion[i]);
crypto_init_queue(&sdcp->queue[i], 50); crypto_init_queue(&sdcp->queue[i], 50);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment