summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2011-01-13 17:31:53 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:43:04 -0800
commit249124f8f007b9de4ea6f3723003fb48ce347349 (patch)
treef41209c80f990940326cc83558fb12b6604264c3 /drivers/misc
parent41e361ff01e39494a8b4dce6664a428b22f1dfc3 (diff)
misc: tegra-cryptodev: asynchronous callbacks for encrypt/decrypt
the tegra-aes driver was changed to being an actual asynchronous cipher driver. the client now has to pass a callback which will be called by tegra-aes when the operation is complete. Original-Change-Id: I1cbc1d30722afef2c3edafbbebb3529e94e1d364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/16047 Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Rebase-Id: R8e755c720837307ee3061e654f74a929d561c1da
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/tegra-cryptodev.c52
1 files changed, 49 insertions, 3 deletions
diff --git a/drivers/misc/tegra-cryptodev.c b/drivers/misc/tegra-cryptodev.c
index a18f59e858fe..453e40ef0945 100644
--- a/drivers/misc/tegra-cryptodev.c
+++ b/drivers/misc/tegra-cryptodev.c
@@ -44,6 +44,11 @@ struct tegra_crypto_ctx {
int use_ssk;
};
+struct tegra_crypto_completion {
+ struct completion restart;
+ int req_err;
+};
+
static int alloc_bufs(unsigned long *buf[NBUFS])
{
int i;
@@ -134,6 +139,16 @@ static int tegra_crypto_dev_release(struct inode *inode, struct file *filp)
return 0;
}
+static void tegra_crypt_complete(struct crypto_async_request *req, int err)
+{
+ struct tegra_crypto_completion *done = req->data;
+
+ if (err != -EINPROGRESS) {
+ done->req_err = err;
+ complete(&done->restart);
+ }
+}
+
static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_req *crypt_req)
{
struct crypto_ablkcipher *tfm;
@@ -143,6 +158,7 @@ static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_re
unsigned long *xbuf[NBUFS];
int ret = 0, size = 0;
unsigned long total = 0;
+ struct tegra_crypto_completion tcrypt_complete;
if (crypt_req->op & TEGRA_CRYPTO_ECB) {
req = ablkcipher_request_alloc(ctx->ecb_tfm, GFP_KERNEL);
@@ -176,6 +192,11 @@ static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_re
goto process_req_out;
}
+ init_completion(&tcrypt_complete.restart);
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ tegra_crypt_complete, &tcrypt_complete);
+
total = crypt_req->plaintext_sz;
while (total > 0) {
size = min(total, PAGE_SIZE);
@@ -187,13 +208,28 @@ static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_re
}
sg_init_one(&in_sg, xbuf[0], size);
sg_init_one(&out_sg, xbuf[1], size);
+
ablkcipher_request_set_crypt(req, &in_sg,
&out_sg, size, crypt_req->iv);
- req->base.complete = NULL;
+
+ INIT_COMPLETION(tcrypt_complete.restart);
+ tcrypt_complete.req_err = 0;
ret = crypt_req->encrypt ?
crypto_ablkcipher_encrypt(req) :
crypto_ablkcipher_decrypt(req);
- if (ret < 0) {
+
+ if ((ret == -EINPROGRESS) || (ret == -EBUSY)) {
+ /* crypto driver is asynchronous */
+ ret = wait_for_completion_interruptible(&tcrypt_complete.restart);
+
+ if (ret < 0)
+ goto process_req_buf_out;
+
+ if (tcrypt_complete.req_err < 0) {
+ ret = tcrypt_complete.req_err;
+ goto process_req_buf_out;
+ }
+ } else if (ret < 0) {
pr_debug("%scrypt failed (%d)\n",
crypt_req->encrypt ? "en" : "de", ret);
goto process_req_buf_out;
@@ -223,7 +259,7 @@ static long tegra_crypto_dev_ioctl(struct file *filp,
struct tegra_crypto_ctx *ctx = filp->private_data;
struct tegra_crypt_req crypt_req;
struct tegra_rng_req rng_req;
- char rng[TEGRA_CRYPTO_RNG_SIZE];
+ char *rng;
int ret = 0;
switch (ioctl_num) {
@@ -253,6 +289,13 @@ static long tegra_crypto_dev_ioctl(struct file *filp,
if (copy_from_user(&rng_req, (void __user *)arg, sizeof(rng_req)))
return -EFAULT;
+ rng = kzalloc(rng_req.nbytes, GFP_KERNEL);
+ if (!rng) {
+ pr_err("mem alloc for rng fail");
+ ret = -ENODATA;
+ goto rng_out;
+ }
+
ret = crypto_rng_get_bytes(ctx->rng, rng,
rng_req.nbytes);
@@ -266,6 +309,9 @@ static long tegra_crypto_dev_ioctl(struct file *filp,
(const void *)rng, rng_req.nbytes);
ret = (ret < 0) ? -ENODATA : 0;
rng_out:
+ if (rng)
+ kfree(rng);
+
break;