All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] Add Qualcomm crypto driver
@ 2014-04-03 16:17 Stanimir Varbanov
  2014-04-03 16:17 ` [PATCH 1/9] crypto: qce: Add core driver implementation Stanimir Varbanov
                   ` (8 more replies)
  0 siblings, 9 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:17 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Rob Landley, Herbert Xu, David S. Miller, Grant Likely
  Cc: Stanimir Varbanov, devicetree, linux-doc, linux-kernel,
	linux-crypto, linux-arm-msm

Hi,

The following patch set implements support for Qualcomm
crypto hardware accelerator driver. It registers itself
to the crypto subsystem and adds the following operations
for encryption/decription - AES with ECB CBC CTR XTS modes,
DES with ECB CBC modes, and 3DES ECB CBC modes.
For hashing and MAC it adds support for sha1 sha256,
hmac(sha1) hmac(sha256).

The version of the driver is reworked by me and it is based
on Codeaurora's qcrypto driver. The proposed version has many
coding style fixes, re-factored files, separated by
functionality. I wanted to make the driver more readable and
easier for review, hope I done well. I'll appreciate any review
comments which will help me to make this code clear and ready
for mainline kernel.

regards,
Stan

Stanimir Varbanov (9):
  crypto: qce: Add core driver implementation
  crypto: qce: Add register defines
  crypto: qce: Add dma and sg helpers
  crypto: qce: Add ablkcipher algorithms
  crypto: qce: Adds sha and hmac transforms
  crypto: qce: Adds infrastructure to setup the crypto block
  crypto: qce: Adds Makefile to build the driver
  crypto: qce: Build Qualcomm qce driver
  ARM: DT: qcom: Add Qualcomm crypto driver binding document

 .../devicetree/bindings/crypto/qcom-qce.txt        |  25 +
 drivers/crypto/Kconfig                             |  10 +
 drivers/crypto/Makefile                            |   1 +
 drivers/crypto/qce/Makefile                        |   6 +
 drivers/crypto/qce/ablkcipher.c                    | 397 ++++++++++++++
 drivers/crypto/qce/cipher.h                        |  62 +++
 drivers/crypto/qce/common.c                        | 424 +++++++++++++++
 drivers/crypto/qce/common.h                        | 111 ++++
 drivers/crypto/qce/core.c                          | 333 ++++++++++++
 drivers/crypto/qce/core.h                          |  69 +++
 drivers/crypto/qce/dma.c                           | 201 +++++++
 drivers/crypto/qce/dma.h                           |  57 ++
 drivers/crypto/qce/regs-v5.h                       | 327 +++++++++++
 drivers/crypto/qce/sha.c                           | 595 +++++++++++++++++++++
 drivers/crypto/qce/sha.h                           |  74 +++
 15 files changed, 2692 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/qcom-qce.txt
 create mode 100644 drivers/crypto/qce/Makefile
 create mode 100644 drivers/crypto/qce/ablkcipher.c
 create mode 100644 drivers/crypto/qce/cipher.h
 create mode 100644 drivers/crypto/qce/common.c
 create mode 100644 drivers/crypto/qce/common.h
 create mode 100644 drivers/crypto/qce/core.c
 create mode 100644 drivers/crypto/qce/core.h
 create mode 100644 drivers/crypto/qce/dma.c
 create mode 100644 drivers/crypto/qce/dma.h
 create mode 100644 drivers/crypto/qce/regs-v5.h
 create mode 100644 drivers/crypto/qce/sha.c
 create mode 100644 drivers/crypto/qce/sha.h

-- 
1.8.4.4

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 1/9] crypto: qce: Add core driver implementation
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
@ 2014-04-03 16:17 ` Stanimir Varbanov
  2014-04-03 18:19   ` Josh Cartwright
  2014-04-03 23:38   ` Courtney Cavin
  2014-04-03 16:17 ` [PATCH 2/9] crypto: qce: Add register defines Stanimir Varbanov
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:17 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, Grant Likely, Rob Herring
  Cc: Stanimir Varbanov, linux-kernel, linux-crypto, devicetree, linux-arm-msm

This adds core driver files. The core part is implementing a
platform driver probe and remove callbaks, the probe enables
clocks, checks crypto version, initialize and request dma
channels, create done tasklet and work queue and finally
register the algorithms into crypto subsystem.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/qce/core.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/qce/core.h |  69 ++++++++++
 2 files changed, 402 insertions(+)
 create mode 100644 drivers/crypto/qce/core.c
 create mode 100644 drivers/crypto/qce/core.h

diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
new file mode 100644
index 000000000000..240b9983e9b9
--- /dev/null
+++ b/drivers/crypto/qce/core.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+
+#include "dma.h"
+#include "core.h"
+#include "common.h"
+#include "cipher.h"
+#include "sha.h"
+#include "regs-v5.h"
+
+#define QCE_MAJOR_VERSION5	0x05
+#define QCE_QUEUE_LENGTH	50
+
+static int qce_async_request_queue(struct qce_device *qce,
+				   struct crypto_async_request *req)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&qce->lock, flags);
+	ret = crypto_enqueue_request(&qce->queue, req);
+	spin_unlock_irqrestore(&qce->lock, flags);
+
+	queue_work(qce->queue_wq, &qce->queue_work);
+
+	return ret;
+}
+
+static void qce_async_request_done(struct qce_device *qce, int ret)
+{
+	qce->result = ret;
+	tasklet_schedule(&qce->done_tasklet);
+}
+
+static struct qce_algo_ops qce_ops[] = {
+	{
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.register_alg = qce_ablkcipher_register,
+	},
+	{
+		.type = CRYPTO_ALG_TYPE_AHASH,
+		.register_alg = qce_ahash_register,
+	},
+};
+
+static void qce_unregister_algs(struct qce_device *qce)
+{
+	struct qce_alg_template *tmpl, *n;
+
+	list_for_each_entry_safe(tmpl, n, &qce->alg_list, entry) {
+		if (tmpl->crypto_alg_type == CRYPTO_ALG_TYPE_AHASH)
+			crypto_unregister_ahash(&tmpl->alg.ahash);
+		else
+			crypto_unregister_alg(&tmpl->alg.crypto);
+
+		list_del(&tmpl->entry);
+		kfree(tmpl);
+	}
+}
+
+static int qce_register_algs(struct qce_device *qce)
+{
+	struct qce_algo_ops *ops;
+	int i, rc = -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(qce_ops); i++) {
+		ops = &qce_ops[i];
+		ops->async_req_queue = qce_async_request_queue;
+		ops->async_req_done = qce_async_request_done;
+		rc = ops->register_alg(qce, ops);
+		if (rc)
+			break;
+	}
+
+	if (rc)
+		qce_unregister_algs(qce);
+
+	return rc;
+}
+
+static int qce_handle_request(struct crypto_async_request *async_req)
+{
+	int ret = -EINVAL, i;
+	struct qce_algo_ops *ops;
+	u32 type = crypto_tfm_alg_type(async_req->tfm);
+
+	for (i = 0; i < ARRAY_SIZE(qce_ops); i++) {
+		ops = &qce_ops[i];
+		if (type != ops->type)
+			continue;
+		ret = ops->async_req_handle(async_req);
+		break;
+	}
+
+	return ret;
+}
+
+static void qce_reqqueue_handler(struct work_struct *work)
+{
+	struct qce_device *qce =
+			container_of(work, struct qce_device, queue_work);
+	struct crypto_async_request *async_req = NULL, *backlog = NULL;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&qce->lock, flags);
+	if (!qce->req) {
+		backlog = crypto_get_backlog(&qce->queue);
+		async_req = crypto_dequeue_request(&qce->queue);
+		qce->req = async_req;
+	}
+	spin_unlock_irqrestore(&qce->lock, flags);
+
+	if (!async_req)
+		return;
+
+	if (backlog)
+		backlog->complete(backlog, -EINPROGRESS);
+
+	ret = qce_handle_request(async_req);
+	if (ret) {
+		spin_lock_irqsave(&qce->lock, flags);
+		qce->req = NULL;
+		spin_unlock_irqrestore(&qce->lock, flags);
+
+		async_req->complete(async_req, ret);
+	}
+}
+
+static void qce_tasklet_req_done(unsigned long data)
+{
+	struct qce_device *qce = (struct qce_device *)data;
+	struct crypto_async_request *areq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qce->lock, flags);
+	areq = qce->req;
+	qce->req = NULL;
+	spin_unlock_irqrestore(&qce->lock, flags);
+
+	if (areq)
+		areq->complete(areq, qce->result);
+
+	queue_work(qce->queue_wq, &qce->queue_work);
+}
+
+static int qce_get_version(struct qce_device *qce)
+{
+	u32 major, minor, step;
+	u32 val;
+
+	val = readl(qce->base + REG_VERSION);
+	major = (val & CORE_MAJOR_REV_MASK) >> CORE_MAJOR_REV;
+	minor = (val & CORE_MINOR_REV_MASK) >> CORE_MINOR_REV;
+	step = (val & CORE_STEP_REV_MASK) >> CORE_STEP_REV;
+
+	/*
+	 * the driver does not support v5 with minor 0 because it has special
+	 * alignment requirements.
+	 */
+	if (major < QCE_MAJOR_VERSION5 && minor == 0)
+		return -ENODEV;
+
+	qce->burst_size = QCE_BAM_BURST_SIZE;
+	qce->pipe_pair_index = 1;
+
+	dev_info(qce->dev, "Crypto device found, version %d.%d.%d\n",
+		 major, minor, step);
+
+	return 0;
+}
+
+static int qce_clks_get(struct qce_device *qce)
+{
+	struct clk *clk;
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < QCE_CLKS_NUM; i++) {
+		clk = devm_clk_get(qce->dev, clk_names[i]);
+		if (IS_ERR(clk)) {
+			rc = PTR_ERR(clk);
+			break;
+		}
+		qce->clks[i] = clk;
+	}
+
+	return rc;
+}
+
+static int qce_clks_enable(struct qce_device *qce, int enable)
+{
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < QCE_CLKS_NUM; i++) {
+		if (enable)
+			rc = clk_prepare_enable(qce->clks[i]);
+		else
+			clk_disable_unprepare(qce->clks[i]);
+
+		if (rc)
+			break;
+	}
+
+	if (rc)
+		do
+			clk_disable_unprepare(qce->clks[i]);
+		while (--i >= 0);
+
+	return rc;
+}
+
+static int qce_crypto_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct qce_device *qce;
+	struct resource *res;
+	int rc;
+
+	qce = devm_kzalloc(dev, sizeof(*qce), GFP_KERNEL);
+	if (!qce)
+		return -ENOMEM;
+
+	qce->dev = dev;
+	platform_set_drvdata(pdev, qce);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	qce->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(qce->base))
+		return PTR_ERR(qce->base);
+
+	rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+	if (rc < 0)
+		return rc;
+
+	rc = qce_clks_get(qce);
+	if (rc)
+		return rc;
+
+	rc = qce_clks_enable(qce, 1);
+	if (rc)
+		return rc;
+
+	rc = qce_dma_request(qce->dev, &qce->dma);
+	if (rc)
+		goto error_clks;
+
+	rc = qce_get_version(qce);
+	if (rc)
+		goto error_clks;
+
+	INIT_LIST_HEAD(&qce->alg_list);
+	spin_lock_init(&qce->lock);
+	tasklet_init(&qce->done_tasklet, qce_tasklet_req_done,
+		     (unsigned long)qce);
+
+	qce->queue_wq = alloc_workqueue("qce_wq", WQ_HIGHPRI | WQ_UNBOUND, 1);
+	if (!qce->queue_wq) {
+		rc = -ENOMEM;
+		goto error_dma;
+	}
+
+	INIT_WORK(&qce->queue_work, qce_reqqueue_handler);
+
+	crypto_init_queue(&qce->queue, QCE_QUEUE_LENGTH);
+
+	rc = qce_register_algs(qce);
+	if (rc)
+		goto error_dma;
+
+	return 0;
+error_dma:
+	qce_dma_release(&qce->dma);
+error_clks:
+	qce_clks_enable(qce, 0);
+	return rc;
+}
+
+static int qce_crypto_remove(struct platform_device *pdev)
+{
+	struct qce_device *qce = platform_get_drvdata(pdev);
+
+	cancel_work_sync(&qce->queue_work);
+	destroy_workqueue(qce->queue_wq);
+	tasklet_kill(&qce->done_tasklet);
+	qce_unregister_algs(qce);
+	qce_dma_release(&qce->dma);
+	qce_clks_enable(qce, 0);
+
+	return 0;
+}
+
+static const struct of_device_id qce_crypto_of_match[] = {
+	{ .compatible = "qcom,crypto-v5.1", },
+	{}
+};
+
+static struct platform_driver qce_crypto_driver = {
+	.probe = qce_crypto_probe,
+	.remove = qce_crypto_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = KBUILD_MODNAME,
+		.of_match_table = qce_crypto_of_match,
+	},
+};
+module_platform_driver(qce_crypto_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm crypto engine driver");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
+MODULE_AUTHOR("The Linux Foundation");
diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h
new file mode 100644
index 000000000000..bd6b648276b2
--- /dev/null
+++ b/drivers/crypto/qce/core.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CORE_H_
+#define _CORE_H_
+
+static const char * const clk_names[] = {
+	"core",		/* GCC_CE_CLK */
+	"iface",	/* GCC_CE_AHB_CLK */
+	"bus",		/* GCC_CE_AXI_CLK */
+};
+
+#define QCE_CLKS_NUM	ARRAY_SIZE(clk_names)
+
+/*
+ * Crypto engine device structure
+ *
+ * @alg_list: list of registered algorithms
+ * @queue: request queue
+ * @lock: the lock protects queue and req
+ * @done_tasklet: done tasklet object
+ * @queue_wq: queue workqueue
+ * @queue_work: queue work
+ * @req: current active request
+ * @result: result of transform
+ * @base: virtual IO base
+ * @dev: pointer to device
+ * @clks: array of device clocks
+ * @dma: pointer to dma data
+ * @burst_size: the crypto burst size
+ * @pipe_pair_index: which pipe pair the device using
+ */
+struct qce_device {
+	struct list_head alg_list;
+	struct crypto_queue queue;
+	spinlock_t lock;
+	struct tasklet_struct done_tasklet;
+	struct workqueue_struct *queue_wq;
+	struct work_struct queue_work;
+	struct crypto_async_request *req;
+	int result;
+	void __iomem *base;
+	struct device *dev;
+	struct clk *clks[QCE_CLKS_NUM];
+	struct qce_dma_data dma;
+	int burst_size;
+	unsigned int pipe_pair_index;
+};
+
+struct qce_algo_ops {
+	u32 type;
+	int (*register_alg)(struct qce_device *qce, struct qce_algo_ops *ops);
+	int (*async_req_queue)(struct qce_device *qce,
+			       struct crypto_async_request *req);
+	void (*async_req_done)(struct qce_device *qce, int ret);
+	int (*async_req_handle)(struct crypto_async_request *async_req);
+};
+
+#endif /* _CORE_H_ */
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 2/9] crypto: qce: Add register defines
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
  2014-04-03 16:17 ` [PATCH 1/9] crypto: qce: Add core driver implementation Stanimir Varbanov
@ 2014-04-03 16:17 ` Stanimir Varbanov
  2014-04-03 16:24   ` Kumar Gala
  2014-04-04  9:23   ` Srinivas Kandagatla
  2014-04-03 16:18 ` [PATCH 3/9] crypto: qce: Add dma and sg helpers Stanimir Varbanov
                   ` (6 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:17 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Stanimir Varbanov, linux-kernel, linux-crypto, linux-arm-msm

Here are all register addresses and bit/masks used by the driver.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/qce/regs-v5.h | 327 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 327 insertions(+)
 create mode 100644 drivers/crypto/qce/regs-v5.h

diff --git a/drivers/crypto/qce/regs-v5.h b/drivers/crypto/qce/regs-v5.h
new file mode 100644
index 000000000000..b64683b4707e
--- /dev/null
+++ b/drivers/crypto/qce/regs-v5.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _REGS_V5_H_
+#define _REGS_V5_H_
+
+#define REG_VERSION			0x000
+#define REG_STATUS			0x100
+#define REG_STATUS2			0x104
+#define REG_ENGINES_AVAIL		0x108
+#define REG_FIFO_SIZES			0x10c
+#define REG_SEG_SIZE			0x110
+#define REG_GOPROC			0x120
+#define REG_ENCR_SEG_CFG		0x200
+#define REG_ENCR_SEG_SIZE		0x204
+#define REG_ENCR_SEG_START		0x208
+#define REG_CNTR0_IV0			0x20c
+#define REG_CNTR1_IV1			0x210
+#define REG_CNTR2_IV2			0x214
+#define REG_CNTR3_IV3			0x218
+#define REG_CNTR_MASK			0x21C
+#define REG_ENCR_CCM_INT_CNTR0		0x220
+#define REG_ENCR_CCM_INT_CNTR1		0x224
+#define REG_ENCR_CCM_INT_CNTR2		0x228
+#define REG_ENCR_CCM_INT_CNTR3		0x22c
+#define REG_ENCR_XTS_DU_SIZE		0x230
+#define REG_AUTH_SEG_CFG		0x300
+#define REG_AUTH_SEG_SIZE		0x304
+#define REG_AUTH_SEG_START		0x308
+#define REG_AUTH_IV0			0x310
+#define REG_AUTH_IV1			0x314
+#define REG_AUTH_IV2			0x318
+#define REG_AUTH_IV3			0x31c
+#define REG_AUTH_IV4			0x320
+#define REG_AUTH_IV5			0x324
+#define REG_AUTH_IV6			0x328
+#define REG_AUTH_IV7			0x32c
+#define REG_AUTH_IV8			0x330
+#define REG_AUTH_IV9			0x334
+#define REG_AUTH_IV10			0x338
+#define REG_AUTH_IV11			0x33c
+#define REG_AUTH_IV12			0x340
+#define REG_AUTH_IV13			0x344
+#define REG_AUTH_IV14			0x348
+#define REG_AUTH_IV15			0x34c
+#define REG_AUTH_INFO_NONCE0		0x350
+#define REG_AUTH_INFO_NONCE1		0x354
+#define REG_AUTH_INFO_NONCE2		0x358
+#define REG_AUTH_INFO_NONCE3		0x35c
+#define REG_AUTH_BYTECNT0		0x390
+#define REG_AUTH_BYTECNT1		0x394
+#define REG_AUTH_BYTECNT2		0x398
+#define REG_AUTH_BYTECNT3		0x39c
+#define REG_AUTH_EXP_MAC0		0x3a0
+#define REG_AUTH_EXP_MAC1		0x3a4
+#define REG_AUTH_EXP_MAC2		0x3a8
+#define REG_AUTH_EXP_MAC3		0x3ac
+#define REG_AUTH_EXP_MAC4		0x3b0
+#define REG_AUTH_EXP_MAC5		0x3b4
+#define REG_AUTH_EXP_MAC6		0x3b8
+#define REG_AUTH_EXP_MAC7		0x3bc
+#define REG_CONFIG			0x400
+#define REG_GOPROC_QC_KEY		0x1000
+#define REG_GOPROC_OEM_KEY		0x2000
+#define REG_ENCR_KEY0			0x3000
+#define REG_ENCR_KEY1			0x3004
+#define REG_ENCR_KEY2			0x3008
+#define REG_ENCR_KEY3			0x300c
+#define REG_ENCR_KEY4			0x3010
+#define REG_ENCR_KEY5			0x3014
+#define REG_ENCR_KEY6			0x3018
+#define REG_ENCR_KEY7			0x301c
+#define REG_ENCR_XTS_KEY0		0x3020
+#define REG_ENCR_XTS_KEY1		0x3024
+#define REG_ENCR_XTS_KEY2		0x3028
+#define REG_ENCR_XTS_KEY3		0x302c
+#define REG_ENCR_XTS_KEY4		0x3030
+#define REG_ENCR_XTS_KEY5		0x3034
+#define REG_ENCR_XTS_KEY6		0x3038
+#define REG_ENCR_XTS_KEY7		0x303c
+#define REG_AUTH_KEY0			0x3040
+#define REG_AUTH_KEY1			0x3044
+#define REG_AUTH_KEY2			0x3048
+#define REG_AUTH_KEY3			0x304c
+#define REG_AUTH_KEY4			0x3050
+#define REG_AUTH_KEY5			0x3054
+#define REG_AUTH_KEY6			0x3058
+#define REG_AUTH_KEY7			0x305c
+#define REG_AUTH_KEY8			0x3060
+#define REG_AUTH_KEY9			0x3064
+#define REG_AUTH_KEY10			0x3068
+#define REG_AUTH_KEY11			0x306c
+#define REG_AUTH_KEY12			0x3070
+#define REG_AUTH_KEY13			0x3074
+#define REG_AUTH_KEY14			0x3078
+#define REG_AUTH_KEY15			0x307c
+
+/* Register bits - REG_VERSION */
+#define CORE_STEP_REV			0  /* bit 15-0 */
+#define CORE_STEP_REV_MASK		(0xffff << CORE_STEP_REV)
+#define CORE_MINOR_REV			16 /* bit 23-16 */
+#define CORE_MINOR_REV_MASK		(0xff << CORE_MINOR_REV)
+#define CORE_MAJOR_REV			24 /* bit 31-24 */
+#define CORE_MAJOR_REV_MASK		(0xff << CORE_MAJOR_REV)
+
+/* Register bits - REG_STATUS */
+#define MAC_FAILED			31
+#define DOUT_SIZE_AVAIL			26 /* bit 30-26 */
+#define DOUT_SIZE_AVAIL_MASK		(0x1f << DOUT_SIZE_AVAIL)
+#define DIN_SIZE_AVAIL			21 /* bit 21-25 */
+#define DIN_SIZE_AVAIL_MASK		(0x1f << DIN_SIZE_AVAIL)
+#define HSD_ERR				20
+#define ACCESS_VIOL			19
+#define PIPE_ACTIVE_ERR			18
+#define CFG_CHNG_ERR			17
+#define DOUT_ERR			16
+#define DIN_ERR				15
+#define AXI_ERR				14
+#define CRYPTO_STATE			10 /* bit 13-10 */
+#define CRYPTO_STATE_MASK		(0xf << CRYPTO_STATE)
+#define ENCR_BUSY			9
+#define AUTH_BUSY			8
+#define DOUT_INTR			7
+#define DIN_INTR			6
+#define OP_DONE_INTR			5
+#define ERR_INTR			4
+#define DOUT_RDY			3
+#define DIN_RDY				2
+#define OPERATION_DONE			1
+#define SW_ERR				0
+
+/* Register bits - REG_STATUS2 */
+#define AXI_EXTRA			1
+#define LOCKED				2
+
+/* Register bits - REG_CONFIG */
+#define REQ_SIZE			17 /* bit 20-17 */
+#define REQ_SIZE_MASK			(0xf << REQ_SIZE)
+#define REQ_SIZE_ENUM_1_BEAT		0
+#define REQ_SIZE_ENUM_2_BEAT		1
+#define REQ_SIZE_ENUM_3_BEAT		2
+#define REQ_SIZE_ENUM_4_BEAT		3
+#define REQ_SIZE_ENUM_5_BEAT		4
+#define REQ_SIZE_ENUM_6_BEAT		5
+#define REQ_SIZE_ENUM_7_BEAT		6
+#define REQ_SIZE_ENUM_8_BEAT		7
+#define REQ_SIZE_ENUM_9_BEAT		8
+#define REQ_SIZE_ENUM_10_BEAT		9
+#define REQ_SIZE_ENUM_11_BEAT		10
+#define REQ_SIZE_ENUM_12_BEAT		11
+#define REQ_SIZE_ENUM_13_BEAT		12
+#define REQ_SIZE_ENUM_14_BEAT		13
+#define REQ_SIZE_ENUM_15_BEAT		14
+#define REQ_SIZE_ENUM_16_BEAT		15
+
+#define MAX_QUEUED_REQ			14 /* bit 16-14 */
+#define MAX_QUEUED_REQ_MASK		(0x7 << MAX_QUEUED_REQ)
+#define ENUM_1_QUEUED_REQS		0
+#define ENUM_2_QUEUED_REQS		1
+#define ENUM_3_QUEUED_REQS		2
+
+#define IRQ_ENABLES			10 /* bit 13-10 */
+#define IRQ_ENABLES_MASK		(0xf << IRQ_ENABLES)
+
+#define LITTLE_ENDIAN_MODE		9
+#define LITTLE_ENDIAN_MASK		(1 << LITTLE_ENDIAN_MODE)
+#define PIPE_SET_SELECT			5 /* bit 8-5 */
+#define PIPE_SET_SELECT_MASK		(0xf << PIPE_SET_SELECT)
+
+#define HIGH_SPD_EN_N			4
+#define MASK_DOUT_INTR			3
+#define MASK_DIN_INTR			2
+#define MASK_OP_DONE_INTR		1
+#define MASK_ERR_INTR			0
+
+/* Register bits - REG_AUTH_SEG_CFG */
+#define COMP_EXP_MAC			24
+#define COMP_EXP_MAC_DISABLED		0
+#define COMP_EXP_MAC_ENABLED		1
+
+#define F9_DIRECTION			23
+#define F9_DIRECTION_UPLINK		0
+#define F9_DIRECTION_DOWNLINK		1
+
+#define AUTH_NONCE_NUM_WORDS		20 /* bit 22-20 */
+#define AUTH_NONCE_NUM_WORDS_MASK	(0x7 << AUTH_NONCE_NUM_WORDS)
+
+#define USE_PIPE_KEY_AUTH		19
+#define USE_HW_KEY_AUTH			18
+#define AUTH_FIRST			17
+#define AUTH_LAST			16
+
+#define AUTH_POS			14 /* bit 15-14 */
+#define AUTH_POS_MASK			(0x3 << AUTH_POS)
+#define AUTH_POS_BEFORE			0
+#define AUTH_POS_AFTER			1
+
+#define AUTH_SIZE			9 /* bits 13-9 */
+#define AUTH_SIZE_MASK			(0x1f << AUTH_SIZE)
+#define AUTH_SIZE_SHA1			0
+#define AUTH_SIZE_SHA256		1
+#define AUTH_SIZE_ENUM_1_BYTES		0
+#define AUTH_SIZE_ENUM_2_BYTES		1
+#define AUTH_SIZE_ENUM_3_BYTES		2
+#define AUTH_SIZE_ENUM_4_BYTES		3
+#define AUTH_SIZE_ENUM_5_BYTES		4
+#define AUTH_SIZE_ENUM_6_BYTES		5
+#define AUTH_SIZE_ENUM_7_BYTES		6
+#define AUTH_SIZE_ENUM_8_BYTES		7
+#define AUTH_SIZE_ENUM_9_BYTES		8
+#define AUTH_SIZE_ENUM_10_BYTES		9
+#define AUTH_SIZE_ENUM_11_BYTES		10
+#define AUTH_SIZE_ENUM_12_BYTES		11
+#define AUTH_SIZE_ENUM_13_BYTES		12
+#define AUTH_SIZE_ENUM_14_BYTES		13
+#define AUTH_SIZE_ENUM_15_BYTES		14
+#define AUTH_SIZE_ENUM_16_BYTES		15
+
+#define AUTH_MODE			6 /* bit 8-6 */
+#define AUTH_MODE_MASK			(0x7 << AUTH_MODE)
+#define AUTH_MODE_HASH			0
+#define AUTH_MODE_HMAC			1
+#define AUTH_MODE_CCM			0
+#define AUTH_MODE_CMAC			1
+
+#define AUTH_KEY_SIZE			3 /* bit 5-3 */
+#define AUTH_KEY_SIZE_MASK		(0x7 << AUTH_KEY_SIZE)
+#define AUTH_KEY_SZ_AES128		0
+#define AUTH_KEY_SZ_AES256		2
+
+#define AUTH_ALG			0 /* bit 2-0*/
+#define AUTH_ALG_MASK			7
+#define AUTH_ALG_NONE			0
+#define AUTH_ALG_SHA			1
+#define AUTH_ALG_AES			2
+#define AUTH_ALG_KASUMI			3
+#define AUTH_ALG_SNOW3G			4
+#define AUTH_ALG_ZUC			5
+
+/* Register bits - REG_ENCR_XTS_DU_SIZE */
+#define ENCR_XTS_DU_SIZE		0 /* bit 19-0 */
+#define ENCR_XTS_DU_SIZE_MASK		0xfffff
+
+/* Register bits - REG_ENCR_SEG_CFG */
+#define F8_KEYSTREAM_ENABLE		17 /* bit */
+#define F8_KEYSTREAM_DISABLED		0
+#define F8_KEYSTREAM_ENABLED		1
+
+#define F8_DIRECTION			16 /* bit */
+#define F8_DIRECTION_UPLINK		0
+#define F8_DIRECTION_DOWNLINK		1
+
+#define USE_PIPE_KEY_ENCR		15 /* bit */
+#define USE_PIPE_KEY_ENCR_ENABLED	1
+#define USE_KEY_REGISTERS		0
+
+#define USE_HW_KEY_ENCR			14
+#define USE_KEY_REG			0
+#define USE_HW_KEY			1
+
+#define LAST_CCM			13
+#define LAST_CCM_XFR			1
+#define INTERM_CCM_XFR			0
+
+#define CNTR_ALG			11 /* bit 12-11 */
+#define CNTR_ALG_MASK			(3 << CNTR_ALG)
+#define CNTR_ALG_NIST			0
+
+#define ENCODE				10
+
+#define ENCR_MODE			6 /* bit 9-6 */
+#define ENCR_MODE_MASK			(0xf << ENCR_MODE)
+#define ENCR_MODE_ECB			0
+#define ENCR_MODE_CBC			1
+#define ENCR_MODE_CTR			2
+#define ENCR_MODE_XTS			3
+#define ENCR_MODE_CCM			4
+
+#define ENCR_KEY_SZ			3 /* bit 5-3 */
+#define ENCR_KEY_SZ_MASK		(7 << ENCR_KEY_SZ)
+#define ENCR_KEY_SZ_DES			0
+#define ENCR_KEY_SZ_3DES		1
+#define ENCR_KEY_SZ_AES128		0
+#define ENCR_KEY_SZ_AES256		2
+
+#define ENCR_ALG			0 /* bit 2-0 */
+#define ENCR_ALG_MASK			(7 << ENCR_ALG)
+#define ENCR_ALG_NONE			0
+#define ENCR_ALG_DES			1
+#define ENCR_ALG_AES			2
+#define ENCR_ALG_KASUMI			4
+#define ENCR_ALG_SNOW_3G		5
+#define ENCR_ALG_ZUC			6
+
+/* Register bits - REG_GOPROC */
+#define GO				0
+#define CLR_CNTXT			1
+#define RESULTS_DUMP			2
+
+/* Register bits - REG_ENGINES_AVAIL */
+#define ENCR_AES_SEL			0
+#define DES_SEL				1
+#define ENCR_SNOW3G_SEL			2
+#define ENCR_KASUMI_SEL			3
+#define SHA_SEL				4
+#define SHA512_SEL			5
+#define AUTH_AES_SEL			6
+#define AUTH_SNOW3G_SEL			7
+#define AUTH_KASUMI_SEL			8
+#define BAM_PIPE_SETS			9  /* bit 12-9 */
+#define AXI_WR_BEATS			13 /* bit 18-13 */
+#define AXI_RD_BEATS			19 /* bit 24-19 */
+#define ENCR_ZUC_SEL			26
+#define AUTH_ZUC_SEL			27
+#define ZUC_ENABLE			28
+
+#endif /* _REGS_V5_H_ */
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 3/9] crypto: qce: Add dma and sg helpers
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
  2014-04-03 16:17 ` [PATCH 1/9] crypto: qce: Add core driver implementation Stanimir Varbanov
  2014-04-03 16:17 ` [PATCH 2/9] crypto: qce: Add register defines Stanimir Varbanov
@ 2014-04-03 16:18 ` Stanimir Varbanov
  2014-04-03 18:25   ` Josh Cartwright
  2014-04-03 23:15   ` Courtney Cavin
  2014-04-03 16:18 ` [PATCH 4/9] crypto: qce: Add ablkcipher algorithms Stanimir Varbanov
                   ` (5 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:18 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Stanimir Varbanov, linux-kernel, linux-crypto, linux-arm-msm

This adds dmaengine and sg-list helper functions used by
other parts of the crypto driver.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/qce/dma.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/qce/dma.h |  57 ++++++++++++++
 2 files changed, 258 insertions(+)
 create mode 100644 drivers/crypto/qce/dma.c
 create mode 100644 drivers/crypto/qce/dma.h

diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
new file mode 100644
index 000000000000..1bad958db2f9
--- /dev/null
+++ b/drivers/crypto/qce/dma.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+
+#include "dma.h"
+#include "core.h"
+#include "common.h"
+
+int qce_dma_request(struct device *dev, struct qce_dma_data *dma)
+{
+	unsigned int memsize;
+	void *va;
+	int ret;
+
+	dma->txchan = dma_request_slave_channel_reason(dev, "tx");
+	if (IS_ERR(dma->txchan)) {
+		ret = PTR_ERR(dma->txchan);
+		return ret;
+	}
+
+	dma->rxchan = dma_request_slave_channel_reason(dev, "rx");
+	if (IS_ERR(dma->rxchan)) {
+		ret = PTR_ERR(dma->rxchan);
+		goto error_rx;
+	}
+
+	memsize = QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ;
+	va = kzalloc(memsize, GFP_KERNEL);
+	if (!va) {
+		ret = -ENOMEM;
+		goto error_nomem;
+	}
+
+	dma->result_buf = va;
+	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
+
+	return 0;
+error_nomem:
+	if (!IS_ERR(dma->rxchan))
+		dma_release_channel(dma->rxchan);
+error_rx:
+	if (!IS_ERR(dma->txchan))
+		dma_release_channel(dma->txchan);
+	return ret;
+}
+
+void qce_dma_release(struct qce_dma_data *dma)
+{
+	dma_release_channel(dma->txchan);
+	dma_release_channel(dma->rxchan);
+	kfree(dma->result_buf);
+}
+
+int qce_mapsg(struct device *dev, struct scatterlist *sg, unsigned int nents,
+	      enum dma_data_direction dir, bool chained)
+{
+	int err;
+
+	if (chained) {
+		while (sg) {
+			err = dma_map_sg(dev, sg, 1, dir);
+			if (!err)
+				goto error;
+			sg = scatterwalk_sg_next(sg);
+		}
+	} else {
+		err = dma_map_sg(dev, sg, nents, dir);
+		if (!err)
+			goto error;
+	}
+
+	return nents;
+error:
+	return -EFAULT;
+}
+
+void qce_unmapsg(struct device *dev, struct scatterlist *sg, int nents,
+		 enum dma_data_direction dir, bool chained)
+{
+	if (chained)
+		while (sg) {
+			dma_unmap_sg(dev, sg, 1, dir);
+			sg = scatterwalk_sg_next(sg);
+		}
+	else
+		dma_unmap_sg(dev, sg, nents, dir);
+}
+
+int qce_countsg(struct scatterlist *sglist, int nbytes, bool *chained)
+{
+	struct scatterlist *sg = sglist;
+	int sg_nents = 0;
+
+	if (chained)
+		*chained = false;
+
+	while (nbytes > 0 && sg) {
+		sg_nents++;
+		nbytes -= sg->length;
+		if (!sg_is_last(sg) && (sg + 1)->length == 0 && chained)
+			*chained = true;
+		sg = scatterwalk_sg_next(sg);
+	}
+
+	return sg_nents;
+}
+
+struct scatterlist *
+qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl)
+{
+	struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
+
+	while (sg) {
+		if (!sg_page(sg))
+			break;
+		sg = sg_next(sg);
+	}
+
+	if (!sg)
+		goto error;
+
+	while (new_sgl && sg) {
+		sg_set_page(sg, sg_page(new_sgl), new_sgl->length,
+			    new_sgl->offset);
+		sg_last = sg;
+		sg = sg_next(sg);
+		new_sgl = sg_next(new_sgl);
+	}
+
+	if (new_sgl)
+		goto error;
+
+	return sg_last;
+error:
+	return ERR_PTR(-EINVAL);
+}
+
+static int qce_dma_prep_sg(struct dma_chan *chan, struct scatterlist *sg,
+			   int nents, unsigned long flags,
+			   enum dma_transfer_direction dir,
+			   dma_async_tx_callback cb, void *cb_param)
+{
+	struct dma_async_tx_descriptor *desc;
+
+	if (!sg || !nents)
+		return -EINVAL;
+
+	desc = dmaengine_prep_slave_sg(chan, sg, nents, dir, flags);
+	if (!desc)
+		return -EINVAL;
+
+	desc->callback = cb;
+	desc->callback_param = cb_param;
+	dmaengine_submit(desc);
+	return 0;
+}
+
+int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *rx_sg,
+		     int rx_nents, struct scatterlist *tx_sg, int tx_nents,
+		     dma_async_tx_callback cb, void *cb_param)
+{
+	struct dma_chan *rxchan = dma->rxchan;
+	struct dma_chan *txchan = dma->txchan;
+	unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+	int rc;
+
+	rc = qce_dma_prep_sg(rxchan, rx_sg, rx_nents, flags, DMA_MEM_TO_DEV,
+			     NULL, NULL);
+	if (rc)
+		return rc;
+
+	rc = qce_dma_prep_sg(txchan, tx_sg, tx_nents, flags, DMA_DEV_TO_MEM,
+			     cb, cb_param);
+
+	return rc;
+}
+
+void qce_dma_issue_pending(struct qce_dma_data *dma)
+{
+	dma_async_issue_pending(dma->rxchan);
+	dma_async_issue_pending(dma->txchan);
+}
+
+void qce_dma_terminate_all(struct qce_dma_data *dma)
+{
+	dmaengine_terminate_all(dma->rxchan);
+	dmaengine_terminate_all(dma->txchan);
+}
diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
new file mode 100644
index 000000000000..932b02fd8f25
--- /dev/null
+++ b/drivers/crypto/qce/dma.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DMA_H_
+#define _DMA_H_
+
+#define QCE_AUTHIV_REGS_CNT		16
+#define QCE_AUTH_BYTECOUNT_REGS_CNT	4
+#define QCE_CNTRIV_REGS_CNT		4
+
+/* result dump format */
+struct qce_result_dump {
+	u32 auth_iv[QCE_AUTHIV_REGS_CNT];
+	u32 auth_byte_count[QCE_AUTH_BYTECOUNT_REGS_CNT];
+	u32 encr_cntr_iv[QCE_CNTRIV_REGS_CNT];
+	u32 status;
+	u32 status2;
+};
+
+#define QCE_IGNORE_BUF_SZ	(2 * QCE_BAM_BURST_SIZE)
+#define QCE_RESULT_BUF_SZ	\
+		ALIGN(sizeof(struct qce_result_dump), QCE_BAM_BURST_SIZE)
+
+struct qce_dma_data {
+	struct dma_chan *txchan;
+	struct dma_chan *rxchan;
+	struct qce_result_dump *result_buf;
+	void *ignore_buf;
+};
+
+int qce_dma_request(struct device *dev, struct qce_dma_data *dma);
+void qce_dma_release(struct qce_dma_data *dma);
+int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *sg_in,
+		     int in_ents, struct scatterlist *sg_out, int out_ents,
+		     dma_async_tx_callback cb, void *cb_param);
+int qce_countsg(struct scatterlist *sg_list, int nbytes, bool *chained);
+void qce_unmapsg(struct device *dev, struct scatterlist *sg, int nents,
+		     enum dma_data_direction dir, bool chained);
+int qce_mapsg(struct device *dev, struct scatterlist *sg,
+		  unsigned int nents, enum dma_data_direction dir,
+		  bool chained);
+struct scatterlist *qce_sgtable_add(struct sg_table *sgt,
+				     struct scatterlist *sg_add);
+void qce_dma_issue_pending(struct qce_dma_data *dma);
+void qce_dma_terminate_all(struct qce_dma_data *dma);
+
+#endif /* _DMA_H_ */
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 4/9] crypto: qce: Add ablkcipher algorithms
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
                   ` (2 preceding siblings ...)
  2014-04-03 16:18 ` [PATCH 3/9] crypto: qce: Add dma and sg helpers Stanimir Varbanov
@ 2014-04-03 16:18 ` Stanimir Varbanov
  2014-04-03 16:18 ` [PATCH 5/9] crypto: qce: Adds sha and hmac transforms Stanimir Varbanov
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:18 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Stanimir Varbanov, linux-kernel, linux-crypto, linux-arm-msm

Here is the implementation of AES, DES and 3DES crypto API
callbacks, the crypto register alg function, the async request
handler and its dma done callback function.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/qce/ablkcipher.c | 397 ++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/qce/cipher.h     |  62 +++++++
 2 files changed, 459 insertions(+)
 create mode 100644 drivers/crypto/qce/ablkcipher.c
 create mode 100644 drivers/crypto/qce/cipher.h

diff --git a/drivers/crypto/qce/ablkcipher.c b/drivers/crypto/qce/ablkcipher.c
new file mode 100644
index 000000000000..364162187c8c
--- /dev/null
+++ b/drivers/crypto/qce/ablkcipher.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/des.h>
+
+#include "dma.h"
+#include "core.h"
+#include "common.h"
+#include "cipher.h"
+
+static void qce_ablkcipher_dma_done(void *data)
+{
+	struct crypto_async_request *async_req = data;
+	struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
+	struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct qce_cipher_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+	struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
+	struct qce_device *qce = tmpl->qce;
+	struct qce_result_dump *result = qce->dma.result_buf;
+	enum dma_data_direction dir_src, dir_dst;
+	u32 status;
+	int error;
+
+	dir_src = (req->src == req->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+	dir_dst = (req->src == req->dst) ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
+
+	qce_dma_terminate_all(&qce->dma);
+
+	if (req->src != req->dst)
+		qce_unmapsg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src,
+			    rctx->dst_chained);
+	qce_unmapsg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst,
+		    rctx->dst_chained);
+
+	sg_free_table(&rctx->dst_tbl);
+
+	error = qce_check_status(qce, &status);
+	if (error < 0)
+		dev_err(qce->dev, "ablkcipher operation error (%x)\n", status);
+
+	if (IS_ECB(rctx->flags))
+		goto done;
+
+	memcpy(ctx->iv, result->encr_cntr_iv, rctx->ivsize);
+
+done:
+	tmpl->async_req_done(tmpl->qce, error);
+}
+
+static int
+qce_ablkcipher_async_req_handle(struct crypto_async_request *async_req)
+{
+	struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
+	struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
+	struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
+	struct qce_device *qce = tmpl->qce;
+	enum dma_data_direction dir_src, dir_dst;
+	struct scatterlist *sg;
+	bool diff_dst;
+	gfp_t gfp;
+	int rc;
+
+	rctx->iv = req->info;
+	rctx->ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+	rctx->cryptlen = req->nbytes;
+
+	diff_dst = (req->src != req->dst) ? true : false;
+
+	dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
+	dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
+
+	rctx->src_nents = qce_countsg(req->src, req->nbytes,
+				      &rctx->src_chained);
+	if (diff_dst) {
+		rctx->dst_nents = qce_countsg(req->dst, req->nbytes,
+					      &rctx->dst_chained);
+	} else {
+		rctx->dst_nents = rctx->src_nents;
+		rctx->dst_chained = rctx->src_chained;
+	}
+
+	rctx->dst_nents += 1;
+
+	gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+						GFP_KERNEL : GFP_ATOMIC;
+
+	rc = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
+	if (rc)
+		return rc;
+
+	sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
+
+	sg = qce_sgtable_add(&rctx->dst_tbl, req->dst);
+	if (IS_ERR(sg)) {
+		rc = PTR_ERR(sg);
+		goto error_free;
+	}
+
+	sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg);
+	if (IS_ERR(sg)) {
+		rc = PTR_ERR(sg);
+		goto error_free;
+	}
+
+	sg_mark_end(sg);
+	rctx->dst_sg = rctx->dst_tbl.sgl;
+
+	rc = qce_mapsg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst,
+		       rctx->dst_chained);
+	if (rc < 0)
+		goto error_free;
+
+	if (diff_dst) {
+		rc = qce_mapsg(qce->dev, req->src, rctx->src_nents, dir_src,
+			       rctx->src_chained);
+		if (rc < 0)
+			goto error_unmap_dst;
+		rctx->src_sg = req->src;
+	} else {
+		rctx->src_sg = rctx->dst_sg;
+	}
+
+	rc = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, rctx->src_nents,
+			      rctx->dst_sg, rctx->dst_nents,
+			      qce_ablkcipher_dma_done, async_req);
+	if (rc)
+		goto error_unmap_src;
+
+	qce_dma_issue_pending(&qce->dma);
+
+	rc = qce_start(async_req, tmpl->crypto_alg_type, req->nbytes, 0);
+	if (rc)
+		goto error_terminate;
+
+	return 0;
+
+error_terminate:
+	qce_dma_terminate_all(&qce->dma);
+error_unmap_src:
+	if (diff_dst)
+		qce_unmapsg(qce->dev, req->src, rctx->src_nents, dir_src,
+			    rctx->src_chained);
+error_unmap_dst:
+	qce_unmapsg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst,
+		    rctx->dst_chained);
+error_free:
+	sg_free_table(&rctx->dst_tbl);
+	return rc;
+}
+
+static int qce_ablkcipher_setkey(struct crypto_ablkcipher *ablk, const u8 *key,
+				 unsigned int keylen)
+{
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk);
+	struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qce_alg_template *tmpl = to_cipher_tmpl(&ablk->base);
+	u32 flags = tmpl->alg_flags;
+	int ret = 0;
+
+	if (!key || !keylen)
+		return -EINVAL;
+
+	if (IS_AES(flags)) {
+		switch (keylen) {
+		case AES_KEYSIZE_128:
+		case AES_KEYSIZE_256:
+			break;
+		default:
+			goto badkey;
+		}
+	} else if (IS_DES(flags)) {
+		u32 tmp[DES_EXPKEY_WORDS];
+
+		if (keylen != QCE_DES_KEY_SIZE)
+			goto badkey;
+
+		ret = des_ekey(tmp, key);
+		if (!ret && crypto_ablkcipher_get_flags(ablk) &
+		    CRYPTO_TFM_REQ_WEAK_KEY)
+			goto weakkey;
+	} else if (IS_3DES(flags)) {
+		if (keylen != DES3_EDE_KEY_SIZE)
+			goto badkey;
+	}
+
+	ctx->enc_keylen = keylen;
+	memcpy(ctx->enc_key, key, keylen);
+	return 0;
+badkey:
+	crypto_ablkcipher_set_flags(ablk, CRYPTO_TFM_RES_BAD_KEY_LEN);
+	return -EINVAL;
+weakkey:
+	crypto_ablkcipher_set_flags(ablk, CRYPTO_TFM_RES_WEAK_KEY);
+	return -EINVAL;
+}
+
+static int qce_ablkcipher_encrypt(struct ablkcipher_request *req)
+{
+	struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct qce_alg_template *tmpl = to_cipher_tmpl(req->base.tfm);
+
+	rctx->flags = QCE_ENCRYPT | tmpl->alg_flags;
+	return tmpl->async_req_queue(tmpl->qce, &req->base);
+}
+
+static int qce_ablkcipher_decrypt(struct ablkcipher_request *req)
+{
+	struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct qce_alg_template *tmpl = to_cipher_tmpl(req->base.tfm);
+
+	rctx->flags = QCE_DECRYPT | tmpl->alg_flags;
+	return tmpl->async_req_queue(tmpl->qce, &req->base);
+}
+
+static int qce_ablkcipher_init(struct crypto_tfm *tfm)
+{
+	struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	memset(ctx, 0, sizeof(*ctx));
+	get_random_bytes(ctx->iv, QCE_MAX_IV_SIZE);
+	tfm->crt_ablkcipher.reqsize = sizeof(struct qce_cipher_reqctx);
+	return 0;
+}
+
+static void qce_ablkcipher_exit(struct crypto_tfm *tfm)
+{
+}
+
+struct qce_ablkcipher_def {
+	u32 flags;
+	const char *name;
+	const char *drv_name;
+	unsigned int blocksize;
+	unsigned int ivsize;
+	unsigned int min_keysize;
+	unsigned int max_keysize;
+};
+
+static const struct qce_ablkcipher_def ablkcipher_def[] = {
+	{
+		.flags		= QCE_ALG_AES | QCE_MODE_ECB,
+		.name		= "ecb(aes)",
+		.drv_name	= "ecb-aes-qce",
+		.blocksize	= AES_BLOCK_SIZE,
+		.ivsize		= AES_BLOCK_SIZE,
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+	},
+	{
+		.flags		= QCE_ALG_AES | QCE_MODE_CBC,
+		.name		= "cbc(aes)",
+		.drv_name	= "cbc-aes-qce",
+		.blocksize	= AES_BLOCK_SIZE,
+		.ivsize		= AES_BLOCK_SIZE,
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+	},
+	{
+		.flags		= QCE_ALG_AES | QCE_MODE_CTR,
+		.name		= "ctr(aes)",
+		.drv_name	= "ctr-aes-qce",
+		.blocksize	= AES_BLOCK_SIZE,
+		.ivsize		= AES_BLOCK_SIZE,
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+	},
+	{
+		.flags		= QCE_ALG_AES | QCE_MODE_XTS,
+		.name		= "xts(aes)",
+		.drv_name	= "xts-aes-qce",
+		.blocksize	= AES_BLOCK_SIZE,
+		.ivsize		= AES_BLOCK_SIZE,
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+	},
+	{
+		.flags		= QCE_ALG_DES | QCE_MODE_ECB,
+		.name		= "ecb(des)",
+		.drv_name	= "ecb-des-qce",
+		.blocksize	= DES_BLOCK_SIZE,
+		.ivsize		= 0,
+		.min_keysize	= QCE_DES_KEY_SIZE,
+		.max_keysize	= QCE_DES_KEY_SIZE,
+	},
+	{
+		.flags		= QCE_ALG_DES | QCE_MODE_CBC,
+		.name		= "cbc(des)",
+		.drv_name	= "cbc-des-qce",
+		.blocksize	= DES_BLOCK_SIZE,
+		.ivsize		= DES_BLOCK_SIZE,
+		.min_keysize	= QCE_DES_KEY_SIZE,
+		.max_keysize	= QCE_DES_KEY_SIZE,
+	},
+	{
+		.flags		= QCE_ALG_3DES | QCE_MODE_ECB,
+		.name		= "ecb(des3_ede)",
+		.drv_name	= "ecb-3des-qce",
+		.blocksize	= DES3_EDE_BLOCK_SIZE,
+		.ivsize		= 0,
+		.min_keysize	= DES3_EDE_KEY_SIZE,
+		.max_keysize	= DES3_EDE_KEY_SIZE,
+	},
+	{
+		.flags		= QCE_ALG_3DES | QCE_MODE_CBC,
+		.name		= "cbc(des3_ede)",
+		.drv_name	= "cbc-3des-qce",
+		.blocksize	= DES3_EDE_BLOCK_SIZE,
+		.ivsize		= DES3_EDE_BLOCK_SIZE,
+		.min_keysize	= DES3_EDE_KEY_SIZE,
+		.max_keysize	= DES3_EDE_KEY_SIZE,
+	},
+};
+
+static int qce_ablk_register_one(const struct qce_ablkcipher_def *def,
+				 struct qce_device *qce,
+				 struct qce_algo_ops *ops)
+{
+	struct qce_alg_template *tmpl;
+	struct crypto_alg *alg;
+	struct list_head *alg_list = &qce->alg_list;
+	int rc;
+
+	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
+	if (!tmpl)
+		return -ENOMEM;
+
+	alg = &tmpl->alg.crypto;
+
+	snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
+	snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+		 def->drv_name);
+
+	alg->cra_blocksize = def->blocksize;
+	alg->cra_ablkcipher.ivsize = def->ivsize;
+	alg->cra_ablkcipher.min_keysize = def->min_keysize;
+	alg->cra_ablkcipher.max_keysize = def->max_keysize;
+	alg->cra_ablkcipher.setkey = qce_ablkcipher_setkey;
+	alg->cra_ablkcipher.encrypt = qce_ablkcipher_encrypt;
+	alg->cra_ablkcipher.decrypt = qce_ablkcipher_decrypt;
+
+	alg->cra_priority = 300;
+	alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+	alg->cra_ctxsize = sizeof(struct qce_cipher_ctx);
+	alg->cra_alignmask = 0;
+	alg->cra_type = &crypto_ablkcipher_type;
+	alg->cra_module = THIS_MODULE;
+	alg->cra_init = qce_ablkcipher_init;
+	alg->cra_exit = qce_ablkcipher_exit;
+	INIT_LIST_HEAD(&alg->cra_list);
+
+	INIT_LIST_HEAD(&tmpl->entry);
+	tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_ABLKCIPHER;
+	tmpl->alg_flags = def->flags;
+	tmpl->qce = qce;
+	tmpl->async_req_queue = ops->async_req_queue;
+	tmpl->async_req_done = ops->async_req_done;
+	ops->async_req_handle = qce_ablkcipher_async_req_handle;
+
+	rc = crypto_register_alg(alg);
+	if (rc) {
+		dev_err(qce->dev, "%s registration failed\n", alg->cra_name);
+		kfree(tmpl);
+		return rc;
+	}
+
+	list_add_tail(&tmpl->entry, alg_list);
+	dev_info(qce->dev, "%s is registered\n", alg->cra_name);
+	return 0;
+}
+
+int qce_ablkcipher_register(struct qce_device *qce, struct qce_algo_ops *ops)
+{
+	int rc, i;
+
+	for (i = 0; i < ARRAY_SIZE(ablkcipher_def); i++) {
+		rc = qce_ablk_register_one(&ablkcipher_def[i], qce, ops);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h
new file mode 100644
index 000000000000..df6d31b4a241
--- /dev/null
+++ b/drivers/crypto/qce/cipher.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CIPHER_H_
+#define _CIPHER_H_
+
+struct qce_cipher_ctx {
+	u8 iv[QCE_MAX_IV_SIZE];
+	u8 enc_key[QCE_MAX_KEY_SIZE];
+	unsigned int enc_keylen;
+};
+
+/*
+ * @flags: operation flags
+ * @iv: pointer to the IV
+ * @ivsize: IV size
+ * @src_nents: source entries
+ * @dst_nents: destination entries
+ * @src_chained: is source chained
+ * @dst_chained: is destination chained
+ * @result_sg: scatterlist used for result buffer
+ * @dst_tbl: destination sg table
+ * @dst_sg: destination sg pointer table beginning;
+ * @src_tbl: source sg table
+ * @src_sg: source sg pointer table beginning;
+ * @cryptlen: crypto length
+ */
+struct qce_cipher_reqctx {
+	u32 flags;
+	u8 *iv;
+	unsigned int ivsize;
+	int src_nents;
+	int dst_nents;
+	bool src_chained;
+	bool dst_chained;
+	struct scatterlist result_sg;
+	struct sg_table dst_tbl;
+	struct scatterlist *dst_sg;
+	struct sg_table src_tbl;
+	struct scatterlist *src_sg;
+	unsigned int cryptlen;
+};
+
+static inline struct qce_alg_template *to_cipher_tmpl(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *alg = tfm->__crt_alg;
+	return container_of(alg, struct qce_alg_template, alg.crypto);
+}
+
+int qce_ablkcipher_register(struct qce_device *qce, struct qce_algo_ops *ops);
+
+#endif /* _CIPHER_H_ */
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 5/9] crypto: qce: Adds sha and hmac transforms
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
                   ` (3 preceding siblings ...)
  2014-04-03 16:18 ` [PATCH 4/9] crypto: qce: Add ablkcipher algorithms Stanimir Varbanov
@ 2014-04-03 16:18 ` Stanimir Varbanov
  2014-04-09  0:09   ` Stephen Boyd
  2014-04-03 16:18 ` [PATCH 6/9] crypto: qce: Adds infrastructure to setup the crypto block Stanimir Varbanov
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:18 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Stanimir Varbanov, linux-kernel, linux-crypto, linux-arm-msm

Here is the implementation and registration of ahash crypto type.
It includes sha1, sha256, hmac(sha1) and hmac(sha256).

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/qce/sha.c | 595 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/qce/sha.h |  74 ++++++
 2 files changed, 669 insertions(+)
 create mode 100644 drivers/crypto/qce/sha.c
 create mode 100644 drivers/crypto/qce/sha.h

diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
new file mode 100644
index 000000000000..d63818360c92
--- /dev/null
+++ b/drivers/crypto/qce/sha.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha.h>
+
+#include "dma.h"
+#include "core.h"
+#include "common.h"
+#include "sha.h"
+
+/* crypto hw padding constant for first operation */
+#define SHA_PADDING		64
+#define SHA_PADDING_MASK	(SHA_PADDING - 1)
+
+static const __be32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
+	SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0
+};
+
+static const __be32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
+	SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
+	SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7
+};
+
+static void qce_ahash_dma_done(void *data)
+{
+	struct crypto_async_request *async_req = data;
+	struct ahash_request *req = ahash_request_cast(async_req);
+	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
+	struct qce_device *qce = tmpl->qce;
+	struct qce_result_dump *result = qce->dma.result_buf;
+	unsigned int digestsize = crypto_ahash_digestsize(ahash);
+	int error;
+	u32 status;
+
+	qce_dma_terminate_all(&qce->dma);
+
+	qce_unmapsg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE,
+		     rctx->src_chained);
+	qce_unmapsg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE, 0);
+
+	memcpy(rctx->digest, result->auth_iv, digestsize);
+	if (req->result)
+		memcpy(req->result, result->auth_iv, digestsize);
+
+	rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]);
+	rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]);
+
+	error = qce_check_status(qce, &status);
+	if (error < 0)
+		dev_err(qce->dev, "ahash operation error (%x)\n", status);
+
+	req->src = rctx->src;
+	req->nbytes = rctx->nbytes;
+
+	rctx->last_blk = false;
+	rctx->first_blk = false;
+
+	tmpl->async_req_done(tmpl->qce, error);
+}
+
+static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
+{
+	struct ahash_request *req = ahash_request_cast(async_req);
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct qce_sha_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
+	struct qce_device *qce = tmpl->qce;
+	u32 flags = rctx->flags;
+	int rc;
+
+	if (IS_SHA(flags)) {
+		rctx->authkey = NULL;
+		rctx->authklen = 0;
+	} else if (IS_SHA_HMAC(flags)) {
+		rctx->authkey = ctx->authkey;
+		rctx->authklen = QCE_SHA_HMAC_KEY_SIZE;
+	} else if (IS_CMAC(flags)) {
+		rctx->authkey = ctx->authkey;
+		rctx->authklen = AES_KEYSIZE_128;
+	} else {
+		dev_err(qce->dev, "unsupported ahash algorithm\n");
+		return -EINVAL;
+	}
+
+	rctx->src_nents = qce_countsg(req->src, req->nbytes,
+				      &rctx->src_chained);
+	rc = qce_mapsg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE,
+		       rctx->src_chained);
+	if (rc < 0)
+		return rc;
+
+	sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
+
+	rc = qce_mapsg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE, 0);
+	if (rc < 0)
+		goto error_unmap_src;
+
+	rc = qce_dma_prep_sgs(&qce->dma, req->src, rctx->src_nents,
+			      &rctx->result_sg, 1,
+			      qce_ahash_dma_done, async_req);
+	if (rc)
+		goto error_unmap_src;
+
+	qce_dma_issue_pending(&qce->dma);
+
+	rc = qce_start(async_req, tmpl->crypto_alg_type, 0, 0);
+	if (rc)
+		goto error_terminate;
+
+	return 0;
+
+error_terminate:
+	qce_dma_terminate_all(&qce->dma);
+	qce_unmapsg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE, 0);
+error_unmap_src:
+	qce_unmapsg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE,
+		     rctx->src_chained);
+	return rc;
+}
+
+static int qce_ahash_init(struct ahash_request *req)
+{
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
+	const __be32 *std_iv = tmpl->std_iv;
+
+	memset(rctx, 0, sizeof(*rctx));
+	rctx->first_blk = true;
+	rctx->last_blk = false;
+	rctx->flags = tmpl->alg_flags;
+	memcpy(rctx->digest, std_iv, sizeof(rctx->digest));
+
+	return 0;
+}
+
+static int qce_ahash_export(struct ahash_request *req, void *out)
+{
+	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	u32 flags = rctx->flags;
+	unsigned int digestsize = crypto_ahash_digestsize(ahash);
+	unsigned int blocksize;
+	int ret = 0;
+
+	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash));
+
+	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
+		struct sha1_state *out_state = out;
+
+		out_state->count = rctx->count;
+		qce_cpu_to_be32p_array(out_state->state, rctx->digest,
+				       digestsize);
+		memcpy(out_state->buffer, rctx->trailing_buf, blocksize);
+
+	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) {
+		struct sha256_state *out_state = out;
+
+		out_state->count = rctx->count;
+		qce_cpu_to_be32p_array(out_state->state, rctx->digest,
+				       digestsize);
+		memcpy(out_state->buf, rctx->trailing_buf, blocksize);
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int qce_import_common(struct ahash_request *req, u64 in_count,
+				 u32 *state, u8 *buffer, bool hmac)
+{
+	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	u64 count = in_count;
+	unsigned int digestsize = crypto_ahash_digestsize(ahash);
+	unsigned int blocksize;
+
+	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash));
+	rctx->count = in_count;
+	memcpy(rctx->trailing_buf, buffer, blocksize);
+
+	if (in_count <= blocksize) {
+		rctx->first_blk = 1;
+	} else {
+		rctx->first_blk = 0;
+		/*
+		 * For HMAC, there is a hardware padding done when first block
+		 * is set. Therefore the byte_count must be incremened by 64
+		 * after the first block operation.
+		 */
+		if (hmac)
+			count += SHA_PADDING;
+	}
+
+	rctx->byte_count[0] = (u32)(count & ~SHA_PADDING_MASK);
+	rctx->byte_count[1] = (u32)(count >> 32);
+	qce_cpu_to_be32p_array((__be32 *)rctx->digest, (const u8 *)state,
+			       digestsize);
+	rctx->trailing_buf_len = (unsigned int)(in_count & (blocksize - 1));
+
+	return 0;
+}
+
+static int qce_ahash_import(struct ahash_request *req, const void *in)
+{
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	u32 flags = rctx->flags;
+	bool hmac = IS_SHA_HMAC(flags);
+	int ret;
+
+	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
+		struct sha1_state *state = (struct sha1_state *)in;
+
+		ret = qce_import_common(req, state->count, state->state,
+					state->buffer, hmac);
+	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) {
+		struct sha256_state *state = (struct sha256_state *)in;
+
+		ret = qce_import_common(req, state->count, state->state,
+					state->buf, hmac);
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int qce_ahash_update(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
+	unsigned int total, len;
+	int nents;
+	struct scatterlist *sg_last;
+	u8 *buf;
+	u32 pad_len;
+	u32 trailing_buf_len;
+	u32 nbytes;
+	u32 offset;
+	u32 bytes;
+	u8 *staging;
+	bool chained;
+	unsigned int blocksize;
+
+	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+	rctx->count += req->nbytes;
+
+	/* check for trailing buffer from previous updates and append it */
+	total = req->nbytes + rctx->trailing_buf_len;
+	len = req->nbytes;
+
+	if (total <= blocksize) {
+		buf = &rctx->trailing_buf[rctx->trailing_buf_len];
+		nents = qce_countsg(req->src, len, &chained);
+		bytes = sg_copy_to_buffer(req->src, nents, buf, len);
+		if (bytes != len) {
+			rctx->count -= req->nbytes;
+			return -EINVAL;
+		}
+
+		rctx->trailing_buf_len = total;
+		return 0;
+	}
+
+	/* save the original req structure fields */
+	rctx->src = req->src;
+	rctx->nbytes = req->nbytes;
+
+	staging = rctx->staging_buf;
+	staging = PTR_ALIGN(staging, dma_get_cache_alignment());
+	memcpy(staging, rctx->trailing_buf, rctx->trailing_buf_len);
+	buf = rctx->trailing_buf;
+
+	/* get new trailing buffer */
+	pad_len = ALIGN(total, blocksize) - total;
+	trailing_buf_len = blocksize - pad_len;
+	offset = req->nbytes - trailing_buf_len;
+
+	if (offset != req->nbytes)
+		scatterwalk_map_and_copy(buf, req->src, offset,
+					 trailing_buf_len, 0);
+
+	nbytes = total - trailing_buf_len;
+
+	len = rctx->trailing_buf_len;
+	sg_last = req->src;
+
+	while (len < nbytes) {
+		if ((len + sg_last->length) > nbytes)
+			break;
+		len += sg_last->length;
+		sg_last = scatterwalk_sg_next(sg_last);
+	}
+
+	sg_mark_end(sg_last);
+
+	if (rctx->trailing_buf_len) {
+		sg_init_table(rctx->sg, 2);
+		sg_set_buf(&rctx->sg[0], staging, rctx->trailing_buf_len);
+		scatterwalk_sg_chain(rctx->sg, 2, req->src);
+		req->src = rctx->sg;
+	}
+
+	req->nbytes = nbytes;
+	rctx->trailing_buf_len = trailing_buf_len;
+
+	return tmpl->async_req_queue(tmpl->qce, &req->base);
+}
+
+static int qce_ahash_final(struct ahash_request *req)
+{
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
+	u8 *staging;
+
+	rctx->last_blk = true;
+
+	/* save the original req structure fields */
+	rctx->src = req->src;
+	rctx->nbytes = req->nbytes;
+
+	staging = rctx->staging_buf;
+	staging = PTR_ALIGN(staging, dma_get_cache_alignment());
+	memcpy(staging, rctx->trailing_buf, rctx->trailing_buf_len);
+	sg_init_one(rctx->sg, staging, rctx->trailing_buf_len);
+
+	req->src = rctx->sg;
+	req->nbytes = rctx->trailing_buf_len;
+
+	return tmpl->async_req_queue(tmpl->qce, &req->base);
+}
+
+static int qce_ahash_digest(struct ahash_request *req)
+{
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
+	int ret;
+
+	ret = qce_ahash_init(req);
+	if (ret)
+		return ret;
+
+	/* save the original req structure fields */
+	rctx->src = req->src;
+	rctx->nbytes = req->nbytes;
+	rctx->first_blk = true;
+	rctx->last_blk = true;
+
+	return tmpl->async_req_queue(tmpl->qce, &req->base);
+}
+
+struct qce_ahash_result {
+	struct completion completion;
+	int error;
+};
+
+static void qce_setkey_complete(struct crypto_async_request *req, int error)
+{
+	struct qce_ahash_result *result = req->data;
+
+	if (error == -EINPROGRESS)
+		return;
+
+	result->error = error;
+	complete(&result->completion);
+}
+
+static int qce_ahash_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
+				 unsigned int keylen)
+{
+	unsigned int digestsize = crypto_ahash_digestsize(tfm);
+	struct qce_sha_ctx *ctx = crypto_tfm_ctx(&tfm->base);
+	struct qce_ahash_result result;
+	struct ahash_request *req;
+	struct scatterlist sg;
+	unsigned int blocksize;
+	struct crypto_ahash *ahash_tfm;
+	u8 *buf;
+	int ret;
+	const char *alg_name;
+
+	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+	memset(ctx->authkey, 0, blocksize);
+
+	if (keylen <= blocksize) {
+		memcpy(ctx->authkey, key, keylen);
+		ret = 0;
+		goto done;
+	}
+
+	if (digestsize == SHA1_DIGEST_SIZE)
+		alg_name = "sha1";
+	else
+		alg_name = "sha256";
+
+	ahash_tfm = crypto_alloc_ahash(alg_name, CRYPTO_ALG_TYPE_AHASH,
+				       CRYPTO_ALG_TYPE_AHASH_MASK);
+	if (IS_ERR(ahash_tfm))
+		return PTR_ERR(ahash_tfm);
+
+	req = ahash_request_alloc(ahash_tfm, GFP_KERNEL);
+	if (!req) {
+		ret = -ENOMEM;
+		goto err_free_ahash;
+	}
+
+	init_completion(&result.completion);
+	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				   qce_setkey_complete, &result);
+	crypto_ahash_clear_flags(ahash_tfm, ~0);
+
+	buf = kzalloc(keylen + QCE_MAX_ALIGN_SIZE, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_free_req;
+	}
+
+	memcpy(buf, key, keylen);
+	sg_init_one(&sg, buf, keylen);
+	ahash_request_set_crypt(req, &sg, ctx->authkey, keylen);
+
+	ret = crypto_ahash_digest(req);
+	if (ret == -EINPROGRESS || ret == -EBUSY) {
+		ret = wait_for_completion_interruptible(&result.completion);
+		if (!ret)
+			ret = result.error;
+	}
+
+	if (ret)
+		crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+	kfree(buf);
+err_free_req:
+	ahash_request_free(req);
+err_free_ahash:
+	crypto_free_ahash(ahash_tfm);
+done:
+	return ret;
+}
+
+static int qce_ahash_cra_init(struct crypto_tfm *tfm)
+{
+	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+	struct qce_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_ahash_set_reqsize(ahash, sizeof(struct qce_sha_reqctx));
+	memset(ctx, 0, sizeof(*ctx));
+	return 0;
+}
+
+static void qce_ahash_cra_exit(struct crypto_tfm *tfm)
+{
+}
+
+struct qce_ahash_def {
+	u32 flags;
+	const char *name;
+	const char *drv_name;
+	unsigned int digestsize;
+	unsigned int blocksize;
+	unsigned int statesize;
+	const __be32 *std_iv;
+};
+
+static const struct qce_ahash_def ahash_def[] = {
+	{
+		.flags		= QCE_HASH_SHA1,
+		.name		= "sha1",
+		.drv_name	= "sha1-qce",
+		.digestsize	= SHA1_DIGEST_SIZE,
+		.blocksize	= SHA1_BLOCK_SIZE,
+		.statesize	= sizeof(struct sha1_state),
+		.std_iv		= std_iv_sha1,
+	},
+	{
+		.flags		= QCE_HASH_SHA256,
+		.name		= "sha256",
+		.drv_name	= "sha256-qce",
+		.digestsize	= SHA256_DIGEST_SIZE,
+		.blocksize	= SHA256_BLOCK_SIZE,
+		.statesize	= sizeof(struct sha256_state),
+		.std_iv		= std_iv_sha256,
+	},
+	{
+		.flags		= QCE_HASH_SHA1_HMAC,
+		.name		= "hmac(sha1)",
+		.drv_name	= "hmac-sha1-qce",
+		.digestsize	= SHA1_DIGEST_SIZE,
+		.blocksize	= SHA1_BLOCK_SIZE,
+		.statesize	= sizeof(struct sha1_state),
+		.std_iv		= std_iv_sha1,
+	},
+	{
+		.flags		= QCE_HASH_SHA256_HMAC,
+		.name		= "hmac(sha256)",
+		.drv_name	= "hmac-sha256-qce",
+		.digestsize	= SHA256_DIGEST_SIZE,
+		.blocksize	= SHA256_BLOCK_SIZE,
+		.statesize	= sizeof(struct sha256_state),
+		.std_iv		= std_iv_sha256,
+	},
+};
+
+static int qce_ahash_register_one(const struct qce_ahash_def *def,
+				  struct qce_device *qce,
+				  struct qce_algo_ops *ops)
+{
+	struct qce_alg_template *tmpl;
+	struct ahash_alg *alg;
+	struct crypto_alg *base;
+	struct list_head *alg_list = &qce->alg_list;
+	int rc;
+
+	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
+	if (!tmpl)
+		return -ENOMEM;
+
+	tmpl->std_iv = def->std_iv;
+
+	alg = &tmpl->alg.ahash;
+	alg->init = qce_ahash_init;
+	alg->update = qce_ahash_update;
+	alg->final = qce_ahash_final;
+	alg->digest = qce_ahash_digest;
+	alg->export = qce_ahash_export;
+	alg->import = qce_ahash_import;
+	if (IS_SHA_HMAC(def->flags))
+		alg->setkey = qce_ahash_hmac_setkey;
+	alg->halg.digestsize = def->digestsize;
+	alg->halg.statesize = def->statesize;
+
+	base = &alg->halg.base;
+	base->cra_blocksize = def->blocksize;
+	base->cra_priority = 300;
+	base->cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC;
+	base->cra_ctxsize = sizeof(struct qce_sha_ctx);
+	base->cra_alignmask = 0;
+	base->cra_type = &crypto_ahash_type;
+	base->cra_module = THIS_MODULE;
+	base->cra_init = qce_ahash_cra_init;
+	base->cra_exit = qce_ahash_cra_exit;
+	INIT_LIST_HEAD(&base->cra_list);
+
+	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
+	snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+		 def->drv_name);
+
+	INIT_LIST_HEAD(&tmpl->entry);
+	tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AHASH;
+	tmpl->alg_flags = def->flags;
+	tmpl->qce = qce;
+	tmpl->async_req_queue = ops->async_req_queue;
+	tmpl->async_req_done = ops->async_req_done;
+	ops->async_req_handle = qce_ahash_async_req_handle;
+
+	rc = crypto_register_ahash(alg);
+	if (rc) {
+		dev_err(qce->dev, "%s registration failed\n", base->cra_name);
+		kfree(tmpl);
+		return rc;
+	}
+
+	list_add_tail(&tmpl->entry, alg_list);
+	dev_info(qce->dev, "%s is registered\n", base->cra_name);
+	return 0;
+}
+
+int qce_ahash_register(struct qce_device *qce, struct qce_algo_ops *ops)
+{
+	int rc, i;
+
+	for (i = 0; i < ARRAY_SIZE(ahash_def); i++) {
+		rc = qce_ahash_register_one(&ahash_def[i], qce, ops);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
diff --git a/drivers/crypto/qce/sha.h b/drivers/crypto/qce/sha.h
new file mode 100644
index 000000000000..4a99a8f0de82
--- /dev/null
+++ b/drivers/crypto/qce/sha.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SHA_H_
+#define _SHA_H_
+
+struct qce_sha_ctx {
+	u8 authkey[SHA256_BLOCK_SIZE];
+};
+
+#define STAGING_BUF_SZ	\
+	(SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE + QCE_MAX_ALIGN_SIZE)
+
+/*
+ * @flags: operation flags
+ * @src: request sg
+ * @src_chained: is source scatterlist chained
+ * @src_nents: source number of entries
+ * @nbytes: request number of bytes
+ * @byte_count: byte count
+ * @count: save count in states during update, import and export
+ * @first_blk: is it the first block
+ * @last_blk: is it the last block
+ * @trailing_buf: used during update, import and export
+ * @trailing_buf_len: lenght of the trailing buffer
+ * @staging_buf: buffer for internal use
+ * @digest: calculated digest
+ * @sg: used to chain sg lists
+ * @authkey: pointer to auth key in sha ctx
+ * @authklen: auth key length
+ * @result_sg: scatterlist used for result buffer
+ */
+struct qce_sha_reqctx {
+	u32 flags;
+	struct scatterlist *src;
+	bool src_chained;
+	int src_nents;
+	unsigned int nbytes;
+	u32 byte_count[2];
+	u64 count;
+	bool first_blk;
+	bool last_blk;
+	u8 trailing_buf[SHA256_BLOCK_SIZE];
+	unsigned int trailing_buf_len;
+	u8 staging_buf[STAGING_BUF_SZ];
+	u8 digest[SHA256_DIGEST_SIZE];
+	struct scatterlist sg[2];
+	u8 *authkey;
+	unsigned int authklen;
+	struct scatterlist result_sg;
+};
+
+int qce_ahash_register(struct qce_device *qce, struct qce_algo_ops *ops);
+
+static inline struct qce_alg_template *to_ahash_tmpl(struct crypto_tfm *tfm)
+{
+	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+	struct ahash_alg *alg = container_of(crypto_hash_alg_common(ahash),
+					     struct ahash_alg, halg);
+
+	return container_of(alg, struct qce_alg_template, alg.ahash);
+}
+
+#endif /* _SHA_H_ */
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 6/9] crypto: qce: Adds infrastructure to setup the crypto block
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
                   ` (4 preceding siblings ...)
  2014-04-03 16:18 ` [PATCH 5/9] crypto: qce: Adds sha and hmac transforms Stanimir Varbanov
@ 2014-04-03 16:18 ` Stanimir Varbanov
  2014-04-03 16:18 ` [PATCH 7/9] crypto: qce: Adds Makefile to build the driver Stanimir Varbanov
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:18 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Stanimir Varbanov, linux-kernel, linux-crypto, linux-arm-msm

Here are functions used to setup/prepare hardware registers for
all algorithms supported by the crypto block. It also exports
few helper functions needed by algorithms:
	- to check hardware status
	- to start crypto hardware
	- to translate data stream to big endian form

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/qce/common.c | 424 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/qce/common.h | 111 ++++++++++++
 2 files changed, 535 insertions(+)
 create mode 100644 drivers/crypto/qce/common.c
 create mode 100644 drivers/crypto/qce/common.h

diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c
new file mode 100644
index 000000000000..d9f32d6fc23b
--- /dev/null
+++ b/drivers/crypto/qce/common.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha.h>
+
+#include "dma.h"
+#include "core.h"
+#include "common.h"
+#include "regs-v5.h"
+#include "sha.h"
+#include "cipher.h"
+
+#define QCE_SECTOR_SIZE		512
+
+static inline u32 qce_read(struct qce_device *qce, u32 offset)
+{
+	return readl(qce->base + offset);
+}
+
+static inline void qce_write(struct qce_device *qce, u32 offset, u32 val)
+{
+	writel(val, qce->base + offset);
+}
+
+static inline void qce_write_array(struct qce_device *qce, u32 offset,
+				   const u32 *val, unsigned int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		qce_write(qce, offset + i * sizeof(u32), val[i]);
+}
+
+static inline void
+qce_clear_array(struct qce_device *qce, u32 offset, unsigned int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		qce_write(qce, offset + i * sizeof(u32), 0);
+}
+
+static u32 qce_encr_cfg(u32 flags, u32 aes_key_size)
+{
+	u32 cfg = 0;
+
+	if (IS_AES(flags)) {
+		if (aes_key_size == AES_KEYSIZE_128)
+			cfg |= ENCR_KEY_SZ_AES128 << ENCR_KEY_SZ;
+		else if (aes_key_size == AES_KEYSIZE_256)
+			cfg |= ENCR_KEY_SZ_AES256 << ENCR_KEY_SZ;
+	}
+
+	if (IS_AES(flags))
+		cfg |= ENCR_ALG_AES << ENCR_ALG;
+	else if (IS_DES(flags) || IS_3DES(flags))
+		cfg |= ENCR_ALG_DES << ENCR_ALG;
+
+	if (IS_DES(flags))
+		cfg |= ENCR_KEY_SZ_DES << ENCR_KEY_SZ;
+
+	if (IS_3DES(flags))
+		cfg |= ENCR_KEY_SZ_3DES << ENCR_KEY_SZ;
+
+	switch (flags & QCE_MODE_MASK) {
+	case QCE_MODE_ECB:
+		cfg |= ENCR_MODE_ECB << ENCR_MODE;
+		break;
+	case QCE_MODE_CBC:
+		cfg |= ENCR_MODE_CBC << ENCR_MODE;
+		break;
+	case QCE_MODE_CTR:
+		cfg |= ENCR_MODE_CTR << ENCR_MODE;
+		break;
+	case QCE_MODE_XTS:
+		cfg |= ENCR_MODE_XTS << ENCR_MODE;
+		break;
+	case QCE_MODE_CCM:
+		cfg |= ENCR_MODE_CCM << ENCR_MODE;
+		cfg |= LAST_CCM_XFR << LAST_CCM;
+		break;
+	default:
+		return ~0;
+	}
+
+	return cfg;
+}
+
+static u32 qce_auth_cfg(u32 flags, u32 key_size)
+{
+	u32 cfg = 0;
+
+	if (IS_AES(flags) && (IS_CCM(flags) || IS_CMAC(flags)))
+		cfg |= AUTH_ALG_AES << AUTH_ALG;
+	else
+		cfg |= AUTH_ALG_SHA << AUTH_ALG;
+
+	if (IS_CCM(flags) || IS_CMAC(flags)) {
+		if (key_size == AES_KEYSIZE_128)
+			cfg |= AUTH_KEY_SZ_AES128 << AUTH_KEY_SIZE;
+		else if (key_size == AES_KEYSIZE_256)
+			cfg |= AUTH_KEY_SZ_AES256 << AUTH_KEY_SIZE;
+	}
+
+	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags))
+		cfg |= AUTH_SIZE_SHA1 << AUTH_SIZE;
+	else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags))
+		cfg |= AUTH_SIZE_SHA256 << AUTH_SIZE;
+	else if (IS_CMAC(flags))
+		cfg |= AUTH_SIZE_ENUM_16_BYTES << AUTH_SIZE;
+
+	if (IS_SHA1(flags) || IS_SHA256(flags))
+		cfg |= AUTH_MODE_HASH << AUTH_MODE;
+	else if (IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags) ||
+		 IS_CBC(flags) || IS_CTR(flags))
+		cfg |= AUTH_MODE_HMAC << AUTH_MODE;
+	else if (IS_AES(flags) && IS_CCM(flags))
+		cfg |= AUTH_MODE_CCM << AUTH_MODE;
+	else if (IS_AES(flags) && IS_CMAC(flags))
+		cfg |= AUTH_MODE_CMAC << AUTH_MODE;
+
+	if (IS_SHA(flags) || IS_SHA_HMAC(flags))
+		cfg |= AUTH_POS_BEFORE << AUTH_POS;
+
+	if (IS_CCM(flags))
+		cfg |= QCE_MAX_NONCE_WORDS << AUTH_NONCE_NUM_WORDS;
+
+	if (IS_CBC(flags) || IS_CTR(flags) || IS_CCM(flags) ||
+	    IS_CMAC(flags))
+		cfg |= BIT(AUTH_LAST) | BIT(AUTH_FIRST);
+
+	return cfg;
+}
+
+static u32 qce_config_reg(struct qce_device *qce, int little)
+{
+	u32 beats = (qce->burst_size >> 3) - 1;
+	u32 pipe_pair = qce->pipe_pair_index;
+	u32 config;
+
+	config = beats << REQ_SIZE | BIT(MASK_DOUT_INTR) | BIT(MASK_DIN_INTR) |
+		 BIT(MASK_OP_DONE_INTR) | BIT(MASK_ERR_INTR) |
+		 pipe_pair << PIPE_SET_SELECT;
+	config &= ~HIGH_SPD_EN_N;
+
+	if (little)
+		config |= LITTLE_ENDIAN_MASK;
+
+	return config;
+}
+
+void qce_cpu_to_be32p_array(__be32 *dst, const u8 *src, unsigned int len)
+{
+	__be32 *d = dst;
+	const u8 *s = src;
+	unsigned int n;
+
+	n = len / sizeof(u32);
+	for (; n > 0; n--) {
+		*d = cpu_to_be32p((const __u32 *) s);
+		s += sizeof(__u32);
+		d++;
+	}
+}
+
+static void qce_xts_swapiv(u32 *dst, u8 *src, unsigned int ivsize)
+{
+	u8 swap[QCE_AES_IV_LENGTH];
+	u32 i, j;
+
+	if (ivsize > QCE_AES_IV_LENGTH)
+		return;
+
+	memset(swap, 0, QCE_AES_IV_LENGTH);
+
+	for (i = (QCE_AES_IV_LENGTH - ivsize), j = ivsize - 1;
+	     i < QCE_AES_IV_LENGTH; i++, j--)
+		swap[i] = src[j];
+
+	qce_cpu_to_be32p_array(dst, swap, QCE_AES_IV_LENGTH);
+}
+
+static void qce_xtskey(struct qce_device *qce, const u8 *enckey,
+		       unsigned int enckeylen, unsigned int cryptlen)
+{
+	u32 xtskey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
+	unsigned int xtsklen = enckeylen / (2 * sizeof(u32));
+	unsigned int xtsdusize;
+
+	qce_cpu_to_be32p_array(xtskey, enckey + enckeylen / 2, enckeylen / 2);
+	qce_write_array(qce, REG_ENCR_XTS_KEY0, xtskey, xtsklen);
+
+	/* xts du size 512B */
+	xtsdusize = min_t(u32, QCE_SECTOR_SIZE, cryptlen);
+	qce_write(qce, REG_ENCR_XTS_DU_SIZE, xtsdusize);
+}
+
+static void qce_setup_config(struct qce_device *qce)
+{
+	u32 config;
+
+	/* get big endianness */
+	config = qce_config_reg(qce, 0);
+
+	/* clear status */
+	qce_write(qce, REG_STATUS, 0);
+	qce_write(qce, REG_CONFIG, config);
+}
+
+static inline void qce_crypto_go(struct qce_device *qce)
+{
+	/* issue GO to crypto */
+	qce_write(qce, REG_GOPROC, BIT(GO) | BIT(RESULTS_DUMP));
+}
+
+static int qce_setup_regs_ahash(struct crypto_async_request *async_req,
+				u32 totallen, u32 offset)
+{
+	struct ahash_request *req = ahash_request_cast(async_req);
+	struct crypto_ahash *ahash = __crypto_ahash_cast(req->base.tfm);
+	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
+	struct qce_device *qce = tmpl->qce;
+	unsigned int digestsize = crypto_ahash_digestsize(ahash);
+	u32 auth[SHA256_DIGEST_SIZE / sizeof(u32)] = {0};
+	u32 mackey[QCE_SHA_HMAC_KEY_SIZE / sizeof(u32)] = {0};
+	u32 auth_cfg = 0, config;
+	unsigned int iv_words;
+
+	qce_setup_config(qce);
+
+	if (IS_CMAC(rctx->flags)) {
+		qce_write(qce, REG_AUTH_SEG_CFG, 0);
+		qce_write(qce, REG_ENCR_SEG_CFG, 0);
+		qce_write(qce, REG_ENCR_SEG_SIZE, 0);
+		qce_clear_array(qce, REG_AUTH_IV0, 16);
+		qce_clear_array(qce, REG_AUTH_KEY0, 16);
+		qce_clear_array(qce, REG_AUTH_BYTECNT0, 4);
+
+		auth_cfg = qce_auth_cfg(rctx->flags, rctx->authklen);
+	}
+
+	if (IS_SHA_HMAC(rctx->flags) || IS_CMAC(rctx->flags)) {
+		u32 authkey_words = rctx->authklen / sizeof(u32);
+
+		qce_cpu_to_be32p_array(mackey, rctx->authkey, rctx->authklen);
+		qce_write_array(qce, REG_AUTH_KEY0, mackey, authkey_words);
+	}
+
+	if (IS_CMAC(rctx->flags))
+		goto go_proc;
+
+	/* if not the last, the size has to be on the block boundary */
+	if (rctx->last_blk == false && (req->nbytes % SHA256_BLOCK_SIZE))
+		return -EINVAL;
+
+	/* write 20/32 bytes, 5/8 words into auth_iv for SHA1/SHA256 */
+	if (rctx->first_blk)
+		memcpy(auth, rctx->digest, digestsize);
+	else
+		qce_cpu_to_be32p_array(auth, rctx->digest, digestsize);
+
+	iv_words = (IS_SHA1(rctx->flags) || IS_SHA1_HMAC(rctx->flags)) ? 5 : 8;
+	qce_write_array(qce, REG_AUTH_IV0, auth, iv_words);
+
+	/* write AUTH_BYTECNT 0/1, start with 0 */
+	qce_write_array(qce, REG_AUTH_BYTECNT0, rctx->byte_count, 2);
+
+	auth_cfg = qce_auth_cfg(rctx->flags, 0);
+
+	/* set/reset last bit in AUTH_SEG_CFG register */
+	if (rctx->last_blk)
+		auth_cfg |= BIT(AUTH_LAST);
+	else
+		auth_cfg &= ~BIT(AUTH_LAST);
+
+	if (rctx->first_blk)
+		auth_cfg |= BIT(AUTH_FIRST);
+	else
+		auth_cfg &= ~BIT(AUTH_FIRST);
+
+go_proc:
+	/* get little endianness */
+	config = qce_config_reg(qce, 1);
+
+	qce_write(qce, REG_AUTH_SEG_CFG, auth_cfg);
+	qce_write(qce, REG_AUTH_SEG_SIZE, req->nbytes);
+	qce_write(qce, REG_AUTH_SEG_START, 0);
+	qce_write(qce, REG_ENCR_SEG_CFG, 0);
+	qce_write(qce, REG_SEG_SIZE, req->nbytes);
+	qce_write(qce, REG_CONFIG, config);
+
+	qce_crypto_go(qce);
+
+	return 0;
+}
+
+static int qce_setup_regs_ablkcipher(struct crypto_async_request *async_req,
+				     u32 totallen, u32 offset)
+{
+	struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
+	struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct qce_cipher_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+	struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
+	struct qce_device *qce = tmpl->qce;
+	u32 enckey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
+	u32 enciv[QCE_MAX_IV_SIZE / sizeof(u32)] = {0};
+	unsigned int enckey_words, enciv_words;
+	unsigned int keylen;
+	u32 encr_cfg = 0, auth_cfg = 0, config;
+	unsigned int ivsize = rctx->ivsize;
+	u32 flags = rctx->flags;
+
+	qce_setup_config(qce);
+
+	if (IS_XTS(flags))
+		keylen = ctx->enc_keylen / 2;
+	else
+		keylen = ctx->enc_keylen;
+
+	qce_cpu_to_be32p_array(enckey, ctx->enc_key, keylen);
+	enckey_words = keylen / sizeof(u32);
+
+	qce_write(qce, REG_AUTH_SEG_CFG, auth_cfg);
+
+	encr_cfg = qce_encr_cfg(flags, keylen);
+
+	if (IS_DES(flags)) {
+		enciv_words = 2;
+		enckey_words = 2;
+	} else if (IS_3DES(flags)) {
+		enciv_words = 2;
+		enckey_words = 6;
+	} else if (IS_AES(flags)) {
+		if (IS_XTS(flags))
+			qce_xtskey(qce, ctx->enc_key, ctx->enc_keylen,
+				   rctx->cryptlen);
+		enciv_words = 4;
+	} else {
+		return -EINVAL;
+	}
+
+	qce_write_array(qce, REG_ENCR_KEY0, enckey, enckey_words);
+
+	if (!IS_ECB(flags)) {
+		if (IS_XTS(flags))
+			qce_xts_swapiv(enciv, rctx->iv, ivsize);
+		else
+			qce_cpu_to_be32p_array(enciv, rctx->iv, ivsize);
+
+		qce_write_array(qce, REG_CNTR0_IV0, enciv, enciv_words);
+	}
+
+	if (IS_ENCRYPT(flags))
+		encr_cfg |= BIT(ENCODE);
+
+	qce_write(qce, REG_ENCR_SEG_CFG, encr_cfg);
+	qce_write(qce, REG_ENCR_SEG_SIZE, rctx->cryptlen);
+
+	/* get little endianness */
+	config = qce_config_reg(qce, 1);
+
+	qce_write(qce, REG_ENCR_SEG_START, offset & 0xffff);
+	qce_write(qce, REG_CNTR_MASK, 0xffffffff);
+	qce_write(qce, REG_SEG_SIZE, totallen);
+	qce_write(qce, REG_CONFIG, config);
+
+	qce_crypto_go(qce);
+
+	return 0;
+}
+
+int qce_start(struct crypto_async_request *async_req, u32 type, u32 totallen,
+	      u32 offset)
+{
+	int rc;
+
+	switch (type) {
+	case CRYPTO_ALG_TYPE_ABLKCIPHER:
+		rc = qce_setup_regs_ablkcipher(async_req, totallen, offset);
+		break;
+	case CRYPTO_ALG_TYPE_AHASH:
+		rc = qce_setup_regs_ahash(async_req, totallen, offset);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+#define STATUS_ERRORS	(BIT(SW_ERR) | BIT(AXI_ERR) | BIT(HSD_ERR))
+
+int qce_check_status(struct qce_device *qce, u32 *status)
+{
+	int rc = 0;
+
+	*status = qce_read(qce, REG_STATUS);
+
+	/*
+	 * Don't use result dump status. The operation may not be complete.
+	 * Instead, use the status we just read from device. In case, we need to
+	 * use result_status from result dump the result_status needs to be byte
+	 * swapped, since we set the device to little endian.
+	 */
+	if (*status & STATUS_ERRORS || !(*status & BIT(OPERATION_DONE)))
+		rc = -ENXIO;
+
+	return rc;
+}
diff --git a/drivers/crypto/qce/common.h b/drivers/crypto/qce/common.h
new file mode 100644
index 000000000000..69ab21d02c6e
--- /dev/null
+++ b/drivers/crypto/qce/common.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <linux/crypto.h>
+#include <linux/types.h>
+#include <crypto/aes.h>
+#include <crypto/des.h>
+#include <crypto/hash.h>
+
+/* key size in bytes */
+#define QCE_SHA_HMAC_KEY_SIZE		64
+#define QCE_DES_KEY_SIZE		DES_KEY_SIZE
+#define QCE_MAX_CIPHER_KEY_SIZE		AES_KEYSIZE_256
+#define QCE_MAX_KEY_SIZE		64
+
+/* IV length in bytes */
+#define QCE_AES_IV_LENGTH		AES_BLOCK_SIZE
+/* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
+#define QCE_MAX_IV_SIZE			AES_BLOCK_SIZE
+
+/* maximum nonce bytes  */
+#define QCE_MAX_NONCE			16
+#define QCE_MAX_NONCE_WORDS		(QCE_MAX_NONCE / sizeof(u32))
+
+/* burst size alignment requirement */
+#define QCE_MAX_ALIGN_SIZE		64
+
+/* maximum data transfer block size between BAM and CE */
+#define QCE_BAM_BURST_SIZE		64
+
+/* cipher algorithms */
+#define QCE_ALG_DES			BIT(0)
+#define QCE_ALG_3DES			BIT(1)
+#define QCE_ALG_AES			BIT(2)
+
+/* hash and hmac algorithms */
+#define QCE_HASH_SHA1			BIT(3)
+#define QCE_HASH_SHA256			BIT(4)
+#define QCE_HASH_SHA1_HMAC		BIT(5)
+#define QCE_HASH_SHA256_HMAC		BIT(6)
+#define QCE_HASH_AES_CMAC		BIT(7)
+
+/* cipher modes */
+#define QCE_MODE_CBC			BIT(8)
+#define QCE_MODE_ECB			BIT(9)
+#define QCE_MODE_CTR			BIT(10)
+#define QCE_MODE_XTS			BIT(11)
+#define QCE_MODE_CCM			BIT(12)
+#define QCE_MODE_MASK			0x1f00
+
+/* cipher encryption/decryption operations */
+#define QCE_ENCRYPT			BIT(13)
+#define QCE_DECRYPT			BIT(14)
+
+#define IS_DES(flags)			(flags & QCE_ALG_DES)
+#define IS_3DES(flags)			(flags & QCE_ALG_3DES)
+#define IS_AES(flags)			(flags & QCE_ALG_AES)
+
+#define IS_SHA1(flags)			(flags & QCE_HASH_SHA1)
+#define IS_SHA256(flags)		(flags & QCE_HASH_SHA256)
+#define IS_SHA1_HMAC(flags)		(flags & QCE_HASH_SHA1_HMAC)
+#define IS_SHA256_HMAC(flags)		(flags & QCE_HASH_SHA256_HMAC)
+#define IS_CMAC(flags)			(flags & QCE_HASH_AES_CMAC)
+#define IS_SHA(flags)			(IS_SHA1(flags) || IS_SHA256(flags))
+#define IS_SHA_HMAC(flags)		\
+		(IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags))
+
+#define IS_CBC(mode)			(mode & QCE_MODE_CBC)
+#define IS_ECB(mode)			(mode & QCE_MODE_ECB)
+#define IS_CTR(mode)			(mode & QCE_MODE_CTR)
+#define IS_XTS(mode)			(mode & QCE_MODE_XTS)
+#define IS_CCM(mode)			(mode & QCE_MODE_CCM)
+
+#define IS_ENCRYPT(dir)			(dir & QCE_ENCRYPT)
+#define IS_DECRYPT(dir)			(dir & QCE_DECRYPT)
+
+struct qce_alg_template {
+	struct list_head entry;
+	u32 crypto_alg_type;
+	u32 alg_flags;
+	const __be32 *std_iv;
+	union {
+		struct crypto_alg crypto;
+		struct ahash_alg ahash;
+	} alg;
+	struct qce_device *qce;
+
+	int (*async_req_queue)(struct qce_device *qce,
+			       struct crypto_async_request *req);
+	void (*async_req_done)(struct qce_device *qce, int ret);
+};
+
+void qce_cpu_to_be32p_array(__be32 *dst, const u8 *src, unsigned int len);
+int qce_check_status(struct qce_device *qce, u32 *status);
+int qce_start(struct crypto_async_request *async_req, u32 type, u32 totallen,
+	      u32 offset);
+
+#endif /* _COMMON_H_ */
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 7/9] crypto: qce: Adds Makefile to build the driver
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
                   ` (5 preceding siblings ...)
  2014-04-03 16:18 ` [PATCH 6/9] crypto: qce: Adds infrastructure to setup the crypto block Stanimir Varbanov
@ 2014-04-03 16:18 ` Stanimir Varbanov
  2014-04-03 16:18 ` [PATCH 8/9] crypto: qce: Build Qualcomm qce driver Stanimir Varbanov
  2014-04-03 16:18 ` [PATCH 9/9] ARM: DT: qcom: Add Qualcomm crypto driver binding document Stanimir Varbanov
  8 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:18 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Stanimir Varbanov, linux-kernel, linux-crypto, linux-arm-msm

Adds Makefile needed to build the driver.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/qce/Makefile | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 drivers/crypto/qce/Makefile

diff --git a/drivers/crypto/qce/Makefile b/drivers/crypto/qce/Makefile
new file mode 100644
index 000000000000..348dc3173afa
--- /dev/null
+++ b/drivers/crypto/qce/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypto.o
+qcrypto-objs := core.o \
+		common.o \
+		dma.o \
+		sha.o \
+		ablkcipher.o
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 8/9] crypto: qce: Build Qualcomm qce driver
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
                   ` (6 preceding siblings ...)
  2014-04-03 16:18 ` [PATCH 7/9] crypto: qce: Adds Makefile to build the driver Stanimir Varbanov
@ 2014-04-03 16:18 ` Stanimir Varbanov
  2014-04-03 16:18 ` [PATCH 9/9] ARM: DT: qcom: Add Qualcomm crypto driver binding document Stanimir Varbanov
  8 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:18 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Stanimir Varbanov, linux-crypto, linux-kernel, linux-arm-msm

Modify crypto Kconfig and Makefile in order to build the qce
driver.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 drivers/crypto/Kconfig  | 10 ++++++++++
 drivers/crypto/Makefile |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 03ccdb0ccf9e..0f8ec047b9e2 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -418,4 +418,14 @@ config CRYPTO_DEV_MXS_DCP
 	  To compile this driver as a module, choose M here: the module
 	  will be called mxs-dcp.
 
+config CRYPTO_DEV_QCE
+	tristate "Qualcomm crypto engine accelerator"
+	select CRYPTO_DES
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This driver supports Qualcomm crypto engine accelerator
+	  hardware. To compile this driver as a module, choose M here. The
+	  module will be called qcrypto.
+
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 482f090d16d0..320937bf201e 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
 obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
 obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
+obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 9/9] ARM: DT: qcom: Add Qualcomm crypto driver binding document
  2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
                   ` (7 preceding siblings ...)
  2014-04-03 16:18 ` [PATCH 8/9] crypto: qce: Build Qualcomm qce driver Stanimir Varbanov
@ 2014-04-03 16:18 ` Stanimir Varbanov
  8 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:18 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Rob Landley
  Cc: Stanimir Varbanov, devicetree, linux-doc, linux-kernel, linux-arm-msm

Here is Qualcomm crypto driver device tree binding documentation
to used as a reference example.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 .../devicetree/bindings/crypto/qcom-qce.txt        | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/qcom-qce.txt

diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.txt b/Documentation/devicetree/bindings/crypto/qcom-qce.txt
new file mode 100644
index 000000000000..7ec67c90d2d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/qcom-qce.txt
@@ -0,0 +1,25 @@
+Qualcomm crypto engine driver
+
+Required properties:
+
+- compatible  : should be "qcom,crypto-v5.1"
+- reg         : specifies base physical address and size of the registers map
+- clocks      : phandle to clock-controller plus clock-specifier pair
+- clock-names : "iface" clocks register interface
+		"bus" clocks data transfer interface
+		"core" clocks reset of the crypto block
+- dmas        : DMA specifiers for tx and rx dma channels. For more see
+		Documentation/devicetree/bindings/dma/dma.txt
+- dma-names   : DMA request names should be "rx" and "tx"
+
+Example:
+	crypto@fd45a000 {
+		compatible = "qcom,crypto-v5.1";
+		reg = <0xfd45a000 0x6000>;
+		clocks = <&gcc GCC_CE2_AHB_CLK>,
+			 <&gcc GCC_CE2_AXI_CLK>,
+			 <&gcc GCC_CE2_CLK>;
+		clock-names = "iface", "bus", "core";
+		dmas = <&cryptobam 2>, <&cryptobam 3>;
+		dma-names = "rx", "tx";
+	};
-- 
1.8.4.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/9] crypto: qce: Add register defines
  2014-04-03 16:17 ` [PATCH 2/9] crypto: qce: Add register defines Stanimir Varbanov
@ 2014-04-03 16:24   ` Kumar Gala
  2014-04-03 16:33     ` Stanimir Varbanov
  2014-04-04  9:23   ` Srinivas Kandagatla
  1 sibling, 1 reply; 31+ messages in thread
From: Kumar Gala @ 2014-04-03 16:24 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm


On Apr 3, 2014, at 11:17 AM, Stanimir Varbanov <svarbanov@mm-sol.com> wrote:

> Here are all register addresses and bit/masks used by the driver.
> 
> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
> ---
> drivers/crypto/qce/regs-v5.h | 327 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 327 insertions(+)
> create mode 100644 drivers/crypto/qce/regs-v5.h

This should be part of the first patch in the series, you shouldn’t have any patch that doesn’t build.

- k

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/9] crypto: qce: Add register defines
  2014-04-03 16:24   ` Kumar Gala
@ 2014-04-03 16:33     ` Stanimir Varbanov
  2014-04-03 16:42       ` Kumar Gala
  0 siblings, 1 reply; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-03 16:33 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

Hi,

On 04/03/2014 07:24 PM, Kumar Gala wrote:
> 
> On Apr 3, 2014, at 11:17 AM, Stanimir Varbanov <svarbanov@mm-sol.com> wrote:
> 
>> Here are all register addresses and bit/masks used by the driver.
>>
>> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
>> ---
>> drivers/crypto/qce/regs-v5.h | 327 +++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 327 insertions(+)
>> create mode 100644 drivers/crypto/qce/regs-v5.h
> 
> This should be part of the first patch in the series, you shouldn’t have any patch that doesn’t build.

Correct, I thought I mentioned in the cover letter that the series is
splitted by files to easier the review. I planned to squash all in one
patch after review is done.

regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/9] crypto: qce: Add register defines
  2014-04-03 16:33     ` Stanimir Varbanov
@ 2014-04-03 16:42       ` Kumar Gala
  0 siblings, 0 replies; 31+ messages in thread
From: Kumar Gala @ 2014-04-03 16:42 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm


On Apr 3, 2014, at 11:33 AM, Stanimir Varbanov <svarbanov@mm-sol.com> wrote:

> Hi,
> 
> On 04/03/2014 07:24 PM, Kumar Gala wrote:
>> 
>> On Apr 3, 2014, at 11:17 AM, Stanimir Varbanov <svarbanov@mm-sol.com> wrote:
>> 
>>> Here are all register addresses and bit/masks used by the driver.
>>> 
>>> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
>>> ---
>>> drivers/crypto/qce/regs-v5.h | 327 +++++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 327 insertions(+)
>>> create mode 100644 drivers/crypto/qce/regs-v5.h
>> 
>> This should be part of the first patch in the series, you shouldn’t have any patch that doesn’t build.
> 
> Correct, I thought I mentioned in the cover letter that the series is
> splitted by files to easier the review. I planned to squash all in one
> patch after review is done.

skipped the cover letter ;).  Normally I think we’d tag this with a [RFC] than on the subject line.

- k

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/9] crypto: qce: Add core driver implementation
  2014-04-03 16:17 ` [PATCH 1/9] crypto: qce: Add core driver implementation Stanimir Varbanov
@ 2014-04-03 18:19   ` Josh Cartwright
  2014-04-04 15:54     ` Stanimir Varbanov
  2014-04-03 23:38   ` Courtney Cavin
  1 sibling, 1 reply; 31+ messages in thread
From: Josh Cartwright @ 2014-04-03 18:19 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, Grant Likely, Rob Herring,
	linux-kernel, linux-crypto, devicetree, linux-arm-msm

Hey Stanimir-

Just a few comments/questions from a quick scan of your patchset:

On Thu, Apr 03, 2014 at 07:17:58PM +0300, Stanimir Varbanov wrote:
[..]
> +++ b/drivers/crypto/qce/core.c
[..]
> +
> +static struct qce_algo_ops qce_ops[] = {
> +	{
> +		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
> +		.register_alg = qce_ablkcipher_register,
> +	},
> +	{
> +		.type = CRYPTO_ALG_TYPE_AHASH,
> +		.register_alg = qce_ahash_register,
> +	},
> +};
> +
> +static void qce_unregister_algs(struct qce_device *qce)
> +{
> +	struct qce_alg_template *tmpl, *n;
> +
> +	list_for_each_entry_safe(tmpl, n, &qce->alg_list, entry) {
> +		if (tmpl->crypto_alg_type == CRYPTO_ALG_TYPE_AHASH)
> +			crypto_unregister_ahash(&tmpl->alg.ahash);
> +		else
> +			crypto_unregister_alg(&tmpl->alg.crypto);

Why no 'unregister_alg' member in qce_algo_ops?

> +
> +		list_del(&tmpl->entry);
> +		kfree(tmpl);
> +	}
> +}
> +
> +static int qce_register_algs(struct qce_device *qce)
> +{
> +	struct qce_algo_ops *ops;
> +	int i, rc = -ENODEV;
> +
> +	for (i = 0; i < ARRAY_SIZE(qce_ops); i++) {
> +		ops = &qce_ops[i];
> +		ops->async_req_queue = qce_async_request_queue;
> +		ops->async_req_done = qce_async_request_done;

Why not set these statically?

> +		rc = ops->register_alg(qce, ops);
> +		if (rc)
> +			break;
> +	}
> +
> +	if (rc)
> +		qce_unregister_algs(qce);
> +
> +	return rc;
> +}
[..]
> +static int qce_get_version(struct qce_device *qce)
> +{
> +	u32 major, minor, step;
> +	u32 val;
> +
> +	val = readl(qce->base + REG_VERSION);
> +	major = (val & CORE_MAJOR_REV_MASK) >> CORE_MAJOR_REV;
> +	minor = (val & CORE_MINOR_REV_MASK) >> CORE_MINOR_REV;
> +	step = (val & CORE_STEP_REV_MASK) >> CORE_STEP_REV;
> +
> +	/*
> +	 * the driver does not support v5 with minor 0 because it has special
> +	 * alignment requirements.
> +	 */
> +	if (major < QCE_MAJOR_VERSION5 && minor == 0)
> +		return -ENODEV;
> +
> +	qce->burst_size = QCE_BAM_BURST_SIZE;
> +	qce->pipe_pair_index = 1;
> +
> +	dev_info(qce->dev, "Crypto device found, version %d.%d.%d\n",
> +		 major, minor, step);

I'd suggest dev_dbg().  Kernel boot is chatty enough.

[..]
> +static int qce_clks_enable(struct qce_device *qce, int enable)
> +{
> +	int rc = 0;
> +	int i;
> +
> +	for (i = 0; i < QCE_CLKS_NUM; i++) {
> +		if (enable)
> +			rc = clk_prepare_enable(qce->clks[i]);
> +		else
> +			clk_disable_unprepare(qce->clks[i]);
> +
> +		if (rc)
> +			break;
> +	}
> +
> +	if (rc)
> +		do
> +			clk_disable_unprepare(qce->clks[i]);
> +		while (--i >= 0);
> +
> +	return rc;
> +}

See my below comment about lumping clocks together.

[..]
> +static int qce_crypto_remove(struct platform_device *pdev)
> +{
> +	struct qce_device *qce = platform_get_drvdata(pdev);
> +
> +	cancel_work_sync(&qce->queue_work);
> +	destroy_workqueue(qce->queue_wq);
> +	tasklet_kill(&qce->done_tasklet);
> +	qce_unregister_algs(qce);
> +	qce_dma_release(&qce->dma);
> +	qce_clks_enable(qce, 0);

qce_clks_enable(qce, 0) is really confusing....I'd suggest creating
separate qce_clks_enable() and qce_clks_disable() functions.

[..]
> +static const struct of_device_id qce_crypto_of_match[] = {
> +	{ .compatible = "qcom,crypto-v5.1", },
> +	{}
> +};

MODULE_DEVICE_TABLE()?

[..]
> +++ b/drivers/crypto/qce/core.h
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef _CORE_H_
> +#define _CORE_H_
> +
> +static const char * const clk_names[] = {
> +	"core",		/* GCC_CE_CLK */
> +	"iface",	/* GCC_CE_AHB_CLK */
> +	"bus",		/* GCC_CE_AXI_CLK */
> +};

You probably don't want this in a header file, as now each compilation
unit will have a copy :(.

Lumping all the clocks together assumes that you will only ever have all
clocks enabled, or all clocks disabled, are you sure that's what you
want?

[..]
> +struct qce_algo_ops {
> +	u32 type;
> +	int (*register_alg)(struct qce_device *qce, struct qce_algo_ops *ops);
> +	int (*async_req_queue)(struct qce_device *qce,
> +			       struct crypto_async_request *req);
> +	void (*async_req_done)(struct qce_device *qce, int ret);

What is the relationship between qce_algo_ops and the qce_alg_template
(which has these same two identically named callbacks)?

> +	int (*async_req_handle)(struct crypto_async_request *async_req);
> +};
> +
> +#endif /* _CORE_H_ */

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] crypto: qce: Add dma and sg helpers
  2014-04-03 16:18 ` [PATCH 3/9] crypto: qce: Add dma and sg helpers Stanimir Varbanov
@ 2014-04-03 18:25   ` Josh Cartwright
  2014-04-04  8:49     ` Stanimir Varbanov
  2014-04-03 23:15   ` Courtney Cavin
  1 sibling, 1 reply; 31+ messages in thread
From: Josh Cartwright @ 2014-04-03 18:25 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

Nitworthy comments :).

On Thu, Apr 03, 2014 at 07:18:00PM +0300, Stanimir Varbanov wrote:
[..]
> +++ b/drivers/crypto/qce/dma.c
[..]
> +int qce_dma_request(struct device *dev, struct qce_dma_data *dma)
> +{
> +	unsigned int memsize;
> +	void *va;
> +	int ret;
> +
> +	dma->txchan = dma_request_slave_channel_reason(dev, "tx");
> +	if (IS_ERR(dma->txchan)) {
> +		ret = PTR_ERR(dma->txchan);
> +		return ret;
> +	}
> +
> +	dma->rxchan = dma_request_slave_channel_reason(dev, "rx");
> +	if (IS_ERR(dma->rxchan)) {
> +		ret = PTR_ERR(dma->rxchan);
> +		goto error_rx;
> +	}
> +
> +	memsize = QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ;
> +	va = kzalloc(memsize, GFP_KERNEL);
> +	if (!va) {
> +		ret = -ENOMEM;
> +		goto error_nomem;
> +	}
> +
> +	dma->result_buf = va;
> +	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
> +
> +	return 0;
> +error_nomem:
> +	if (!IS_ERR(dma->rxchan))

How could this condition ever be false?

> +		dma_release_channel(dma->rxchan);
> +error_rx:
> +	if (!IS_ERR(dma->txchan))

Same here.

> +		dma_release_channel(dma->txchan);
> +	return ret;
> +}

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] crypto: qce: Add dma and sg helpers
  2014-04-03 16:18 ` [PATCH 3/9] crypto: qce: Add dma and sg helpers Stanimir Varbanov
  2014-04-03 18:25   ` Josh Cartwright
@ 2014-04-03 23:15   ` Courtney Cavin
  2014-04-04 13:07     ` Stanimir Varbanov
  1 sibling, 1 reply; 31+ messages in thread
From: Courtney Cavin @ 2014-04-03 23:15 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

On Thu, Apr 03, 2014 at 06:18:00PM +0200, Stanimir Varbanov wrote:
> This adds dmaengine and sg-list helper functions used by
> other parts of the crypto driver.
> 
> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
> ---
>  drivers/crypto/qce/dma.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/crypto/qce/dma.h |  57 ++++++++++++++
>  2 files changed, 258 insertions(+)
>  create mode 100644 drivers/crypto/qce/dma.c
>  create mode 100644 drivers/crypto/qce/dma.h

More nitpicking, because everyone loves that....

> 
> diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
> new file mode 100644
> index 000000000000..1bad958db2f9
> --- /dev/null
> +++ b/drivers/crypto/qce/dma.c
> @@ -0,0 +1,201 @@
[...]
> +int qce_dma_request(struct device *dev, struct qce_dma_data *dma)
> +{
> +	unsigned int memsize;
> +	void *va;
> +	int ret;
> +
> +	dma->txchan = dma_request_slave_channel_reason(dev, "tx");
> +	if (IS_ERR(dma->txchan)) {
> +		ret = PTR_ERR(dma->txchan);
> +		return ret;

You can just return PTR_ERR(dma->txchan) here, no need to set 'ret'.

> +	}
> +
> +	dma->rxchan = dma_request_slave_channel_reason(dev, "rx");
> +	if (IS_ERR(dma->rxchan)) {
> +		ret = PTR_ERR(dma->rxchan);
> +		goto error_rx;
> +	}
> +
> +	memsize = QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ;
> +	va = kzalloc(memsize, GFP_KERNEL);

'memsize' is only used here.  Just pass 'QCE_RESULT_BUF_SZ +
QCE_IGNORE_BUF_SZ' directly to kzalloc().

Additionally, is there some particular reason why we need to zero this
memory?

> +	if (!va) {
> +		ret = -ENOMEM;
> +		goto error_nomem;
> +	}
> +
> +	dma->result_buf = va;

Is there some requirement that we don't set dma->result_buf on error?
If not, we can discard the 'va' variable as well.

> +	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
> +
> +	return 0;
> +error_nomem:
> +	if (!IS_ERR(dma->rxchan))
> +		dma_release_channel(dma->rxchan);
> +error_rx:
> +	if (!IS_ERR(dma->txchan))
> +		dma_release_channel(dma->txchan);
> +	return ret;
> +}
> +
> +void qce_dma_release(struct qce_dma_data *dma)
> +{
> +	dma_release_channel(dma->txchan);
> +	dma_release_channel(dma->rxchan);
> +	kfree(dma->result_buf);
> +}
> +
> +int qce_mapsg(struct device *dev, struct scatterlist *sg, unsigned int nents,
> +	      enum dma_data_direction dir, bool chained)
> +{
> +	int err;
> +
> +	if (chained) {
> +		while (sg) {
> +			err = dma_map_sg(dev, sg, 1, dir);
> +			if (!err)
> +				goto error;
> +			sg = scatterwalk_sg_next(sg);
> +		}
> +	} else {
> +		err = dma_map_sg(dev, sg, nents, dir);
> +		if (!err)
> +			goto error;
> +	}
> +
> +	return nents;
> +error:
> +	return -EFAULT;

No need for this label, as there's no cleanup.  Just return
-EFAULT directly on error.

> +}
[...]
> +struct scatterlist *
> +qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl)
> +{
> +	struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
> +
> +	while (sg) {
> +		if (!sg_page(sg))
> +			break;
> +		sg = sg_next(sg);
> +	}
> +
> +	if (!sg)
> +		goto error;
> +
> +	while (new_sgl && sg) {
> +		sg_set_page(sg, sg_page(new_sgl), new_sgl->length,
> +			    new_sgl->offset);
> +		sg_last = sg;
> +		sg = sg_next(sg);
> +		new_sgl = sg_next(new_sgl);
> +	}
> +
> +	if (new_sgl)
> +		goto error;
> +
> +	return sg_last;
> +error:
> +	return ERR_PTR(-EINVAL);

No need for this label, as there's no cleanup.  Just return
ERR_PTR(-EINVAL) directly on error.

> +}
> +
> +static int qce_dma_prep_sg(struct dma_chan *chan, struct scatterlist *sg,
> +			   int nents, unsigned long flags,
> +			   enum dma_transfer_direction dir,
> +			   dma_async_tx_callback cb, void *cb_param)
> +{
> +	struct dma_async_tx_descriptor *desc;
> +
> +	if (!sg || !nents)
> +		return -EINVAL;
> +
> +	desc = dmaengine_prep_slave_sg(chan, sg, nents, dir, flags);
> +	if (!desc)
> +		return -EINVAL;
> +
> +	desc->callback = cb;
> +	desc->callback_param = cb_param;
> +	dmaengine_submit(desc);

Do we not care if there is an error here?

dma_cookie_t cookie;
...
cookie = dmaengine_submit(desc);
return dma_submit_error(cookie);

> +	return 0;
> +}
[...]
> diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
> new file mode 100644
> index 000000000000..932b02fd8f25
> --- /dev/null
> +++ b/drivers/crypto/qce/dma.h
> @@ -0,0 +1,57 @@
> +/*
> + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef _DMA_H_
> +#define _DMA_H_
> +
> +#define QCE_AUTHIV_REGS_CNT		16
> +#define QCE_AUTH_BYTECOUNT_REGS_CNT	4
> +#define QCE_CNTRIV_REGS_CNT		4
> +
> +/* result dump format */
> +struct qce_result_dump {
> +	u32 auth_iv[QCE_AUTHIV_REGS_CNT];
> +	u32 auth_byte_count[QCE_AUTH_BYTECOUNT_REGS_CNT];
> +	u32 encr_cntr_iv[QCE_CNTRIV_REGS_CNT];
> +	u32 status;
> +	u32 status2;
> +};
> +
> +#define QCE_IGNORE_BUF_SZ	(2 * QCE_BAM_BURST_SIZE)

QCE_BAM_BURST_SIZE is defined in common.h in 6/9.  Either that file
needs to be included from this one, or the definition needs to be moved.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/9] crypto: qce: Add core driver implementation
  2014-04-03 16:17 ` [PATCH 1/9] crypto: qce: Add core driver implementation Stanimir Varbanov
  2014-04-03 18:19   ` Josh Cartwright
@ 2014-04-03 23:38   ` Courtney Cavin
  2014-04-08 16:26     ` Stanimir Varbanov
  1 sibling, 1 reply; 31+ messages in thread
From: Courtney Cavin @ 2014-04-03 23:38 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, Grant Likely, Rob Herring,
	linux-kernel, linux-crypto, devicetree, linux-arm-msm

On Thu, Apr 03, 2014 at 06:17:58PM +0200, Stanimir Varbanov wrote:
> This adds core driver files. The core part is implementing a
> platform driver probe and remove callbaks, the probe enables
> clocks, checks crypto version, initialize and request dma
> channels, create done tasklet and work queue and finally
> register the algorithms into crypto subsystem.
> 
> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
> ---
>  drivers/crypto/qce/core.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/crypto/qce/core.h |  69 ++++++++++
>  2 files changed, 402 insertions(+)
>  create mode 100644 drivers/crypto/qce/core.c
>  create mode 100644 drivers/crypto/qce/core.h
> 
> diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
[...]
> +static struct qce_algo_ops qce_ops[] = {
> +	{
> +		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
> +		.register_alg = qce_ablkcipher_register,
> +	},
> +	{
> +		.type = CRYPTO_ALG_TYPE_AHASH,
> +		.register_alg = qce_ahash_register,
> +	},
> +};
> +
> +static void qce_unregister_algs(struct qce_device *qce)
> +{
> +	struct qce_alg_template *tmpl, *n;
> +
> +	list_for_each_entry_safe(tmpl, n, &qce->alg_list, entry) {
> +		if (tmpl->crypto_alg_type == CRYPTO_ALG_TYPE_AHASH)
> +			crypto_unregister_ahash(&tmpl->alg.ahash);
> +		else
> +			crypto_unregister_alg(&tmpl->alg.crypto);
> +
> +		list_del(&tmpl->entry);
> +		kfree(tmpl);

I find this whole memory/list management to be very disorganised.
ops->register_alg() is supposed to allocate this item--more precisely,
multiple items--using something that must be able to be kfree'd
directly, register it with the crypto core, and put it on this list
manually.  Here we unregister/remove/free this in the core.  Josh's
recommendation of a unregister_alg callback might help, but it all
remains a bit unclear with register_alg/unregister_alg managing X
algorithms per call. 

Additionally, above you have qce_ops, which clearly defines the
operations for specific algorithms types/groups, which in later patches
are shown to be seperated out into independent implementations.

>From what I can tell, this seems to be a framework with built-in yet
independent crypto implementations which call the crypto API directly.

It would be more logical to me if this was seperated out into a
"library/core" API, with the individual implementations as platform
drivers of their own.  Then they can register with the core, managing
memory how they please.

What am I missing?

> +	}
> +}
> +
> +static int qce_register_algs(struct qce_device *qce)
> +{
> +	struct qce_algo_ops *ops;
> +	int i, rc = -ENODEV;
> +
> +	for (i = 0; i < ARRAY_SIZE(qce_ops); i++) {
> +		ops = &qce_ops[i];
> +		ops->async_req_queue = qce_async_request_queue;
> +		ops->async_req_done = qce_async_request_done;
> +		rc = ops->register_alg(qce, ops);
> +		if (rc)
> +			break;
> +	}
> +
> +	if (rc)
> +		qce_unregister_algs(qce);
> +
> +	return rc;
> +}

-Courtney

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] crypto: qce: Add dma and sg helpers
  2014-04-03 18:25   ` Josh Cartwright
@ 2014-04-04  8:49     ` Stanimir Varbanov
  0 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-04  8:49 UTC (permalink / raw)
  To: Josh Cartwright
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

On 04/03/2014 09:25 PM, Josh Cartwright wrote:
> Nitworthy comments :).
> 
> On Thu, Apr 03, 2014 at 07:18:00PM +0300, Stanimir Varbanov wrote:
> [..]
>> +++ b/drivers/crypto/qce/dma.c
> [..]
>> +int qce_dma_request(struct device *dev, struct qce_dma_data *dma)
>> +{
>> +	unsigned int memsize;
>> +	void *va;
>> +	int ret;
>> +
>> +	dma->txchan = dma_request_slave_channel_reason(dev, "tx");
>> +	if (IS_ERR(dma->txchan)) {
>> +		ret = PTR_ERR(dma->txchan);
>> +		return ret;
>> +	}
>> +
>> +	dma->rxchan = dma_request_slave_channel_reason(dev, "rx");
>> +	if (IS_ERR(dma->rxchan)) {
>> +		ret = PTR_ERR(dma->rxchan);
>> +		goto error_rx;
>> +	}
>> +
>> +	memsize = QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ;
>> +	va = kzalloc(memsize, GFP_KERNEL);
>> +	if (!va) {
>> +		ret = -ENOMEM;
>> +		goto error_nomem;
>> +	}
>> +
>> +	dma->result_buf = va;
>> +	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
>> +
>> +	return 0;
>> +error_nomem:
>> +	if (!IS_ERR(dma->rxchan))
> 
> How could this condition ever be false?

Good catch. This is a leftover after error path restructuring. Will fix
it on next version.

-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/9] crypto: qce: Add register defines
  2014-04-03 16:17 ` [PATCH 2/9] crypto: qce: Add register defines Stanimir Varbanov
  2014-04-03 16:24   ` Kumar Gala
@ 2014-04-04  9:23   ` Srinivas Kandagatla
  2014-04-04 22:14     ` Stanimir Vabanov
  1 sibling, 1 reply; 31+ messages in thread
From: Srinivas Kandagatla @ 2014-04-04  9:23 UTC (permalink / raw)
  To: Stanimir Varbanov, Herbert Xu, David S. Miller
  Cc: linux-kernel, linux-crypto, linux-arm-msm


Minor nitpicks.

On 03/04/14 17:17, Stanimir Varbanov wrote:
> +#define REQ_SIZE			17 /* bit 20-17 */

I would have defined macros like this with _SHIFT at the end, something 
like this:

#define REQ_SIZE_SHIFT 		17

> +#define REQ_SIZE_MASK			(0xf << REQ_SIZE)
You could possibly use GENMASK macro for this, its much readable, in 
*some cases* it could reduce few more lines in header too.

#define REQ_SIZE_MASK		GENMASK(20, 17)


My comments are equally applicable to most macros in this header file.

--
srini
Linaro Qualcomm Landing Team.
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] crypto: qce: Add dma and sg helpers
  2014-04-03 23:15   ` Courtney Cavin
@ 2014-04-04 13:07     ` Stanimir Varbanov
  2014-04-07 22:42       ` Courtney Cavin
  0 siblings, 1 reply; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-04 13:07 UTC (permalink / raw)
  To: Courtney Cavin
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

Hi Courtney,

Thanks for the comments!

On 04/04/2014 02:15 AM, Courtney Cavin wrote:
> On Thu, Apr 03, 2014 at 06:18:00PM +0200, Stanimir Varbanov wrote:
>> This adds dmaengine and sg-list helper functions used by
>> other parts of the crypto driver.
>>
>> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
>> ---
>>  drivers/crypto/qce/dma.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/crypto/qce/dma.h |  57 ++++++++++++++
>>  2 files changed, 258 insertions(+)
>>  create mode 100644 drivers/crypto/qce/dma.c
>>  create mode 100644 drivers/crypto/qce/dma.h
> 
> More nitpicking, because everyone loves that....
> 
>>
>> diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
>> new file mode 100644
>> index 000000000000..1bad958db2f9
>> --- /dev/null
>> +++ b/drivers/crypto/qce/dma.c
>> @@ -0,0 +1,201 @@
> [...]
>> +int qce_dma_request(struct device *dev, struct qce_dma_data *dma)
>> +{
>> +	unsigned int memsize;
>> +	void *va;
>> +	int ret;
>> +
>> +	dma->txchan = dma_request_slave_channel_reason(dev, "tx");
>> +	if (IS_ERR(dma->txchan)) {
>> +		ret = PTR_ERR(dma->txchan);
>> +		return ret;
> 
> You can just return PTR_ERR(dma->txchan) here, no need to set 'ret'.

I think the idea was to have only one exit point from the function,
never mind I will return from here.

> 
>> +	}
>> +
>> +	dma->rxchan = dma_request_slave_channel_reason(dev, "rx");
>> +	if (IS_ERR(dma->rxchan)) {
>> +		ret = PTR_ERR(dma->rxchan);
>> +		goto error_rx;
>> +	}
>> +
>> +	memsize = QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ;
>> +	va = kzalloc(memsize, GFP_KERNEL);
> 
> 'memsize' is only used here.  Just pass 'QCE_RESULT_BUF_SZ +
> QCE_IGNORE_BUF_SZ' directly to kzalloc().
> 

The only reason to have "memsize" variable is to avoid carry over the
new line. The compiler is smart enough to delete this variable. But this
is a minor issue and I tend to agree with you.

> Additionally, is there some particular reason why we need to zero this
> memory?

IMO, it makes sense when debugging some issue related to dma to this
memory.

> 
>> +	if (!va) {
>> +		ret = -ENOMEM;
>> +		goto error_nomem;
>> +	}
>> +
>> +	dma->result_buf = va;
> 
> Is there some requirement that we don't set dma->result_buf on error?
> If not, we can discard the 'va' variable as well.

No, there is no such requirement, the error is fatal and driver will
refuse to .probe.

> 
>> +	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
>> +
>> +	return 0;
>> +error_nomem:
>> +	if (!IS_ERR(dma->rxchan))
>> +		dma_release_channel(dma->rxchan);
>> +error_rx:
>> +	if (!IS_ERR(dma->txchan))
>> +		dma_release_channel(dma->txchan);
>> +	return ret;
>> +}
>> +
>> +void qce_dma_release(struct qce_dma_data *dma)
>> +{
>> +	dma_release_channel(dma->txchan);
>> +	dma_release_channel(dma->rxchan);
>> +	kfree(dma->result_buf);
>> +}
>> +
>> +int qce_mapsg(struct device *dev, struct scatterlist *sg, unsigned int nents,
>> +	      enum dma_data_direction dir, bool chained)
>> +{
>> +	int err;
>> +
>> +	if (chained) {
>> +		while (sg) {
>> +			err = dma_map_sg(dev, sg, 1, dir);
>> +			if (!err)
>> +				goto error;
>> +			sg = scatterwalk_sg_next(sg);
>> +		}
>> +	} else {
>> +		err = dma_map_sg(dev, sg, nents, dir);
>> +		if (!err)
>> +			goto error;
>> +	}
>> +
>> +	return nents;
>> +error:
>> +	return -EFAULT;
> 
> No need for this label, as there's no cleanup.  Just return
> -EFAULT directly on error.

Sure, will do.

> 
>> +}
> [...]
>> +struct scatterlist *
>> +qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl)
>> +{
>> +	struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
>> +
>> +	while (sg) {
>> +		if (!sg_page(sg))
>> +			break;
>> +		sg = sg_next(sg);
>> +	}
>> +
>> +	if (!sg)
>> +		goto error;
>> +
>> +	while (new_sgl && sg) {
>> +		sg_set_page(sg, sg_page(new_sgl), new_sgl->length,
>> +			    new_sgl->offset);
>> +		sg_last = sg;
>> +		sg = sg_next(sg);
>> +		new_sgl = sg_next(new_sgl);
>> +	}
>> +
>> +	if (new_sgl)
>> +		goto error;
>> +
>> +	return sg_last;
>> +error:
>> +	return ERR_PTR(-EINVAL);
> 
> No need for this label, as there's no cleanup.  Just return
> ERR_PTR(-EINVAL) directly on error.

Sure, will fix it.

> 
>> +}
>> +
>> +static int qce_dma_prep_sg(struct dma_chan *chan, struct scatterlist *sg,
>> +			   int nents, unsigned long flags,
>> +			   enum dma_transfer_direction dir,
>> +			   dma_async_tx_callback cb, void *cb_param)
>> +{
>> +	struct dma_async_tx_descriptor *desc;
>> +
>> +	if (!sg || !nents)
>> +		return -EINVAL;
>> +
>> +	desc = dmaengine_prep_slave_sg(chan, sg, nents, dir, flags);
>> +	if (!desc)
>> +		return -EINVAL;
>> +
>> +	desc->callback = cb;
>> +	desc->callback_param = cb_param;
>> +	dmaengine_submit(desc);
> 
> Do we not care if there is an error here?
> 
> dma_cookie_t cookie;
> ...
> cookie = dmaengine_submit(desc);
> return dma_submit_error(cookie);
> 

Good catch, we should care. Will check the error. Thanks.

>> +	return 0;
>> +}
> [...]
>> diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
>> new file mode 100644
>> index 000000000000..932b02fd8f25
>> --- /dev/null
>> +++ b/drivers/crypto/qce/dma.h
>> @@ -0,0 +1,57 @@
>> +/*
>> + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef _DMA_H_
>> +#define _DMA_H_
>> +
>> +#define QCE_AUTHIV_REGS_CNT		16
>> +#define QCE_AUTH_BYTECOUNT_REGS_CNT	4
>> +#define QCE_CNTRIV_REGS_CNT		4
>> +
>> +/* result dump format */
>> +struct qce_result_dump {
>> +	u32 auth_iv[QCE_AUTHIV_REGS_CNT];
>> +	u32 auth_byte_count[QCE_AUTH_BYTECOUNT_REGS_CNT];
>> +	u32 encr_cntr_iv[QCE_CNTRIV_REGS_CNT];
>> +	u32 status;
>> +	u32 status2;
>> +};
>> +
>> +#define QCE_IGNORE_BUF_SZ	(2 * QCE_BAM_BURST_SIZE)
> 
> QCE_BAM_BURST_SIZE is defined in common.h in 6/9.  Either that file
> needs to be included from this one, or the definition needs to be moved.

I decided to not include any files in driver private headers. Thus I
include the private header files in relevant c files in order.

-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/9] crypto: qce: Add core driver implementation
  2014-04-03 18:19   ` Josh Cartwright
@ 2014-04-04 15:54     ` Stanimir Varbanov
  0 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-04 15:54 UTC (permalink / raw)
  To: Josh Cartwright
  Cc: Herbert Xu, David S. Miller, Grant Likely, Rob Herring,
	linux-kernel, linux-crypto, devicetree, linux-arm-msm

Hi Josh,

Thanks for the comments!

On 04/03/2014 09:19 PM, Josh Cartwright wrote:
> Hey Stanimir-
> 
> Just a few comments/questions from a quick scan of your patchset:
> 
> On Thu, Apr 03, 2014 at 07:17:58PM +0300, Stanimir Varbanov wrote:
> [..]
>> +++ b/drivers/crypto/qce/core.c
> [..]
>> +
>> +static struct qce_algo_ops qce_ops[] = {
>> +	{
>> +		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
>> +		.register_alg = qce_ablkcipher_register,
>> +	},
>> +	{
>> +		.type = CRYPTO_ALG_TYPE_AHASH,
>> +		.register_alg = qce_ahash_register,
>> +	},
>> +};
>> +
>> +static void qce_unregister_algs(struct qce_device *qce)
>> +{
>> +	struct qce_alg_template *tmpl, *n;
>> +
>> +	list_for_each_entry_safe(tmpl, n, &qce->alg_list, entry) {
>> +		if (tmpl->crypto_alg_type == CRYPTO_ALG_TYPE_AHASH)
>> +			crypto_unregister_ahash(&tmpl->alg.ahash);
>> +		else
>> +			crypto_unregister_alg(&tmpl->alg.crypto);
> 
> Why no 'unregister_alg' member in qce_algo_ops?

Because we have a common unregister function :). We have common
unregster function because in my opinion there is no need to copy the
same piece of code on every algorithm file (ablkcipher.c, sha.c and one
or two more could be added in the future). Something more, I'm not the
inventor of this asymmetric calling convention in driver internals, it
is widely spread in crypto drivers. So, I'm just have been inspired by
this idea, and giving that I personally do not like the monotonic and
linear  coding thus it was easy to me to borrow it.

> 
>> +
>> +		list_del(&tmpl->entry);
>> +		kfree(tmpl);
>> +	}
>> +}
>> +
>> +static int qce_register_algs(struct qce_device *qce)
>> +{
>> +	struct qce_algo_ops *ops;
>> +	int i, rc = -ENODEV;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(qce_ops); i++) {
>> +		ops = &qce_ops[i];
>> +		ops->async_req_queue = qce_async_request_queue;
>> +		ops->async_req_done = qce_async_request_done;
> 
> Why not set these statically?

To save few lines of code. If this breaks readability I could move those
function pointers to the qce_ops[].

> 
>> +		rc = ops->register_alg(qce, ops);
>> +		if (rc)
>> +			break;
>> +	}
>> +
>> +	if (rc)
>> +		qce_unregister_algs(qce);
>> +
>> +	return rc;
>> +}
> [..]
>> +static int qce_get_version(struct qce_device *qce)
>> +{
>> +	u32 major, minor, step;
>> +	u32 val;
>> +
>> +	val = readl(qce->base + REG_VERSION);
>> +	major = (val & CORE_MAJOR_REV_MASK) >> CORE_MAJOR_REV;
>> +	minor = (val & CORE_MINOR_REV_MASK) >> CORE_MINOR_REV;
>> +	step = (val & CORE_STEP_REV_MASK) >> CORE_STEP_REV;
>> +
>> +	/*
>> +	 * the driver does not support v5 with minor 0 because it has special
>> +	 * alignment requirements.
>> +	 */
>> +	if (major < QCE_MAJOR_VERSION5 && minor == 0)
>> +		return -ENODEV;
>> +
>> +	qce->burst_size = QCE_BAM_BURST_SIZE;
>> +	qce->pipe_pair_index = 1;
>> +
>> +	dev_info(qce->dev, "Crypto device found, version %d.%d.%d\n",
>> +		 major, minor, step);
> 
> I'd suggest dev_dbg().  Kernel boot is chatty enough.

OK.

> 
> [..]
>> +static int qce_clks_enable(struct qce_device *qce, int enable)
>> +{
>> +	int rc = 0;
>> +	int i;
>> +
>> +	for (i = 0; i < QCE_CLKS_NUM; i++) {
>> +		if (enable)
>> +			rc = clk_prepare_enable(qce->clks[i]);
>> +		else
>> +			clk_disable_unprepare(qce->clks[i]);
>> +
>> +		if (rc)
>> +			break;
>> +	}
>> +
>> +	if (rc)
>> +		do
>> +			clk_disable_unprepare(qce->clks[i]);
>> +		while (--i >= 0);
>> +
>> +	return rc;
>> +}
> 
> See my below comment about lumping clocks together.
> 
> [..]
>> +static int qce_crypto_remove(struct platform_device *pdev)
>> +{
>> +	struct qce_device *qce = platform_get_drvdata(pdev);
>> +
>> +	cancel_work_sync(&qce->queue_work);
>> +	destroy_workqueue(qce->queue_wq);
>> +	tasklet_kill(&qce->done_tasklet);
>> +	qce_unregister_algs(qce);
>> +	qce_dma_release(&qce->dma);
>> +	qce_clks_enable(qce, 0);
> 
> qce_clks_enable(qce, 0) is really confusing....I'd suggest creating
> separate qce_clks_enable() and qce_clks_disable() functions.
> 

OK will do.

> [..]
>> +static const struct of_device_id qce_crypto_of_match[] = {
>> +	{ .compatible = "qcom,crypto-v5.1", },
>> +	{}
>> +};
> 
> MODULE_DEVICE_TABLE()?

Good catch. Thanks.

> 
> [..]
>> +++ b/drivers/crypto/qce/core.h
>> @@ -0,0 +1,69 @@
>> +/*
>> + * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef _CORE_H_
>> +#define _CORE_H_
>> +
>> +static const char * const clk_names[] = {
>> +	"core",		/* GCC_CE_CLK */
>> +	"iface",	/* GCC_CE_AHB_CLK */
>> +	"bus",		/* GCC_CE_AXI_CLK */
>> +};
> 
> You probably don't want this in a header file, as now each compilation
> unit will have a copy :(.

It is my fault, I just forgot to move this array in the core.c.

> 
> Lumping all the clocks together assumes that you will only ever have all
> clocks enabled, or all clocks disabled, are you sure that's what you
> want?

At least until now all clocks are needed. When adding power management
this code should be revised.

> 
> [..]
>> +struct qce_algo_ops {
>> +	u32 type;
>> +	int (*register_alg)(struct qce_device *qce, struct qce_algo_ops *ops);
>> +	int (*async_req_queue)(struct qce_device *qce,
>> +			       struct crypto_async_request *req);
>> +	void (*async_req_done)(struct qce_device *qce, int ret);
> 
> What is the relationship between qce_algo_ops and the qce_alg_template
> (which has these same two identically named callbacks)?

This is a way of passing function pointers from core.c to the
ablkcipher.c and sha.c (where they are needed to queue up new crypto
async requests and finish the requests with done counterpart). This
avoids prototyping those core.c functions and calling them directly.

-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/9] crypto: qce: Add register defines
  2014-04-04  9:23   ` Srinivas Kandagatla
@ 2014-04-04 22:14     ` Stanimir Vabanov
  0 siblings, 0 replies; 31+ messages in thread
From: Stanimir Vabanov @ 2014-04-04 22:14 UTC (permalink / raw)
  To: Srinivas Kandagatla, Herbert Xu, David S. Miller
  Cc: linux-kernel, linux-crypto, linux-arm-msm

Hi Srini,

Thanks for the comments.

On 04/04/2014 12:23 PM, Srinivas Kandagatla wrote:
> 
> Minor nitpicks.
> 
> On 03/04/14 17:17, Stanimir Varbanov wrote:
>> +#define REQ_SIZE            17 /* bit 20-17 */
> 
> I would have defined macros like this with _SHIFT at the end, something
> like this:
> 
> #define REQ_SIZE_SHIFT         17

sure, I will add _SHIFT suffix to all places where it is applicable.

> 
>> +#define REQ_SIZE_MASK            (0xf << REQ_SIZE)
> You could possibly use GENMASK macro for this, its much readable, in
> *some cases* it could reduce few more lines in header too.
> 
> #define REQ_SIZE_MASK        GENMASK(20, 17)
> 
> 
> My comments are equally applicable to most macros in this header file.

yes, right will do. Thanks.

regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] crypto: qce: Add dma and sg helpers
  2014-04-04 13:07     ` Stanimir Varbanov
@ 2014-04-07 22:42       ` Courtney Cavin
  2014-04-08 12:08         ` Stanimir Varbanov
  0 siblings, 1 reply; 31+ messages in thread
From: Courtney Cavin @ 2014-04-07 22:42 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

On Fri, Apr 04, 2014 at 03:07:13PM +0200, Stanimir Varbanov wrote:
> >> diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
> >> new file mode 100644
> >> index 000000000000..932b02fd8f25
> >> --- /dev/null
> >> +++ b/drivers/crypto/qce/dma.h
> >> @@ -0,0 +1,57 @@
> >> +/*
> >> + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 and
> >> + * only version 2 as published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + */
> >> +
> >> +#ifndef _DMA_H_
> >> +#define _DMA_H_
> >> +
> >> +#define QCE_AUTHIV_REGS_CNT		16
> >> +#define QCE_AUTH_BYTECOUNT_REGS_CNT	4
> >> +#define QCE_CNTRIV_REGS_CNT		4
> >> +
> >> +/* result dump format */
> >> +struct qce_result_dump {
> >> +	u32 auth_iv[QCE_AUTHIV_REGS_CNT];
> >> +	u32 auth_byte_count[QCE_AUTH_BYTECOUNT_REGS_CNT];
> >> +	u32 encr_cntr_iv[QCE_CNTRIV_REGS_CNT];
> >> +	u32 status;
> >> +	u32 status2;
> >> +};
> >> +
> >> +#define QCE_IGNORE_BUF_SZ	(2 * QCE_BAM_BURST_SIZE)
> > 
> > QCE_BAM_BURST_SIZE is defined in common.h in 6/9.  Either that file
> > needs to be included from this one, or the definition needs to be moved.
> 
> I decided to not include any files in driver private headers. Thus I
> include the private header files in relevant c files in order.

Actually, that is exactly what I was trying to indicate as undesirable.
Please modify this so that each individual header file doesn't require
you to include another file for usage.

-Courtney

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] crypto: qce: Add dma and sg helpers
  2014-04-07 22:42       ` Courtney Cavin
@ 2014-04-08 12:08         ` Stanimir Varbanov
  0 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-08 12:08 UTC (permalink / raw)
  To: Courtney Cavin
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

Hi

On 04/08/2014 01:42 AM, Courtney Cavin wrote:
> On Fri, Apr 04, 2014 at 03:07:13PM +0200, Stanimir Varbanov wrote:
>>>> diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
>>>> new file mode 100644
>>>> index 000000000000..932b02fd8f25
>>>> --- /dev/null
>>>> +++ b/drivers/crypto/qce/dma.h
>>>> @@ -0,0 +1,57 @@
>>>> +/*
>>>> + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 and
>>>> + * only version 2 as published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + */
>>>> +
>>>> +#ifndef _DMA_H_
>>>> +#define _DMA_H_
>>>> +
>>>> +#define QCE_AUTHIV_REGS_CNT		16
>>>> +#define QCE_AUTH_BYTECOUNT_REGS_CNT	4
>>>> +#define QCE_CNTRIV_REGS_CNT		4
>>>> +
>>>> +/* result dump format */
>>>> +struct qce_result_dump {
>>>> +	u32 auth_iv[QCE_AUTHIV_REGS_CNT];
>>>> +	u32 auth_byte_count[QCE_AUTH_BYTECOUNT_REGS_CNT];
>>>> +	u32 encr_cntr_iv[QCE_CNTRIV_REGS_CNT];
>>>> +	u32 status;
>>>> +	u32 status2;
>>>> +};
>>>> +
>>>> +#define QCE_IGNORE_BUF_SZ	(2 * QCE_BAM_BURST_SIZE)
>>>
>>> QCE_BAM_BURST_SIZE is defined in common.h in 6/9.  Either that file
>>> needs to be included from this one, or the definition needs to be moved.
>>
>> I decided to not include any files in driver private headers. Thus I
>> include the private header files in relevant c files in order.
> 
> Actually, that is exactly what I was trying to indicate as undesirable.
> Please modify this so that each individual header file doesn't require
> you to include another file for usage.

OK, queued for version 2.

-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/9] crypto: qce: Add core driver implementation
  2014-04-03 23:38   ` Courtney Cavin
@ 2014-04-08 16:26     ` Stanimir Varbanov
  2014-04-08 22:00       ` Courtney Cavin
  0 siblings, 1 reply; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-08 16:26 UTC (permalink / raw)
  To: Courtney Cavin
  Cc: Herbert Xu, David S. Miller, Grant Likely, Rob Herring,
	linux-kernel, linux-crypto, devicetree, linux-arm-msm

Hi Courtney,

Thanks for the review!

On 04/04/2014 02:38 AM, Courtney Cavin wrote:
> On Thu, Apr 03, 2014 at 06:17:58PM +0200, Stanimir Varbanov wrote:
>> This adds core driver files. The core part is implementing a
>> platform driver probe and remove callbaks, the probe enables
>> clocks, checks crypto version, initialize and request dma
>> channels, create done tasklet and work queue and finally
>> register the algorithms into crypto subsystem.
>>
>> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
>> ---
>>  drivers/crypto/qce/core.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/crypto/qce/core.h |  69 ++++++++++
>>  2 files changed, 402 insertions(+)
>>  create mode 100644 drivers/crypto/qce/core.c
>>  create mode 100644 drivers/crypto/qce/core.h
>>
>> diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
> [...]
>> +static struct qce_algo_ops qce_ops[] = {
>> +	{
>> +		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
>> +		.register_alg = qce_ablkcipher_register,
>> +	},
>> +	{
>> +		.type = CRYPTO_ALG_TYPE_AHASH,
>> +		.register_alg = qce_ahash_register,
>> +	},
>> +};
>> +
>> +static void qce_unregister_algs(struct qce_device *qce)
>> +{
>> +	struct qce_alg_template *tmpl, *n;
>> +
>> +	list_for_each_entry_safe(tmpl, n, &qce->alg_list, entry) {
>> +		if (tmpl->crypto_alg_type == CRYPTO_ALG_TYPE_AHASH)
>> +			crypto_unregister_ahash(&tmpl->alg.ahash);
>> +		else
>> +			crypto_unregister_alg(&tmpl->alg.crypto);
>> +
>> +		list_del(&tmpl->entry);
>> +		kfree(tmpl);
> 
> I find this whole memory/list management to be very disorganised.
> ops->register_alg() is supposed to allocate this item--more precisely,
> multiple items--using something that must be able to be kfree'd
> directly, register it with the crypto core, and put it on this list
> manually.  Here we unregister/remove/free this in the core.  Josh's
> recommendation of a unregister_alg callback might help, but it all
> remains a bit unclear with register_alg/unregister_alg managing X
> algorithms per call. 
> 
> Additionally, above you have qce_ops, which clearly defines the
> operations for specific algorithms types/groups, which in later patches
> are shown to be seperated out into independent implementations.
> 
> From what I can tell, this seems to be a framework with built-in yet
> independent crypto implementations which call the crypto API directly.
> 
> It would be more logical to me if this was seperated out into a
> "library/core" API, with the individual implementations as platform
> drivers of their own.  Then they can register with the core, managing
> memory how they please.
> 
> What am I missing?
> 

No, you have not miss nothing.

OK I see your point. I made few changes in the core, killed the alg_list
and its manipulation function and added a .unregister_algs operation.
Now every type of algorithm will handle all core crypto api functions
itself. Also I'm using devm_kzalloc() in .register_algs when allocating
memory for qce_alg_template structures to avoid kfree(). The callbacks
async_req_queue/done are now embedded in qce_device structure and they
are invoked directly from algorithm implementations. Thus I have
separated the interfaces: functions implemented in core part of the
driver and struct qce_algo_ops having the function pointers implemented
by every type of algorithm.

If you don't have some objections I can send out a version 2.

-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/9] crypto: qce: Add core driver implementation
  2014-04-08 16:26     ` Stanimir Varbanov
@ 2014-04-08 22:00       ` Courtney Cavin
  2014-04-14  8:19         ` Stanimir Varbanov
  0 siblings, 1 reply; 31+ messages in thread
From: Courtney Cavin @ 2014-04-08 22:00 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, Grant Likely, Rob Herring,
	linux-kernel, linux-crypto, devicetree, linux-arm-msm

On Tue, Apr 08, 2014 at 06:26:44PM +0200, Stanimir Varbanov wrote:
> On 04/04/2014 02:38 AM, Courtney Cavin wrote:
> > On Thu, Apr 03, 2014 at 06:17:58PM +0200, Stanimir Varbanov wrote:
> >> This adds core driver files. The core part is implementing a
> >> platform driver probe and remove callbaks, the probe enables
> >> clocks, checks crypto version, initialize and request dma
> >> channels, create done tasklet and work queue and finally
> >> register the algorithms into crypto subsystem.
> >>
> >> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
> >> ---
> >>  drivers/crypto/qce/core.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++
> >>  drivers/crypto/qce/core.h |  69 ++++++++++
> >>  2 files changed, 402 insertions(+)
> >>  create mode 100644 drivers/crypto/qce/core.c
> >>  create mode 100644 drivers/crypto/qce/core.h
> >>
> >> diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
> > [...]
> >> +static struct qce_algo_ops qce_ops[] = {
> >> +	{
> >> +		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
> >> +		.register_alg = qce_ablkcipher_register,
> >> +	},
> >> +	{
> >> +		.type = CRYPTO_ALG_TYPE_AHASH,
> >> +		.register_alg = qce_ahash_register,
> >> +	},
> >> +};
> >> +
> >> +static void qce_unregister_algs(struct qce_device *qce)
> >> +{
> >> +	struct qce_alg_template *tmpl, *n;
> >> +
> >> +	list_for_each_entry_safe(tmpl, n, &qce->alg_list, entry) {
> >> +		if (tmpl->crypto_alg_type == CRYPTO_ALG_TYPE_AHASH)
> >> +			crypto_unregister_ahash(&tmpl->alg.ahash);
> >> +		else
> >> +			crypto_unregister_alg(&tmpl->alg.crypto);
> >> +
> >> +		list_del(&tmpl->entry);
> >> +		kfree(tmpl);
> > 
> > I find this whole memory/list management to be very disorganised.
> > ops->register_alg() is supposed to allocate this item--more precisely,
> > multiple items--using something that must be able to be kfree'd
> > directly, register it with the crypto core, and put it on this list
> > manually.  Here we unregister/remove/free this in the core.  Josh's
> > recommendation of a unregister_alg callback might help, but it all
> > remains a bit unclear with register_alg/unregister_alg managing X
> > algorithms per call. 
> > 
> > Additionally, above you have qce_ops, which clearly defines the
> > operations for specific algorithms types/groups, which in later patches
> > are shown to be seperated out into independent implementations.
> > 
> > From what I can tell, this seems to be a framework with built-in yet
> > independent crypto implementations which call the crypto API directly.
> > 
> > It would be more logical to me if this was seperated out into a
> > "library/core" API, with the individual implementations as platform
> > drivers of their own.  Then they can register with the core, managing
> > memory how they please.
> > 
> > What am I missing?
> > 
> 
> No, you have not miss nothing.
> 
> OK I see your point. I made few changes in the core, killed the alg_list
> and its manipulation function and added a .unregister_algs operation.
> Now every type of algorithm will handle all core crypto api functions
> itself. Also I'm using devm_kzalloc() in .register_algs when allocating
> memory for qce_alg_template structures to avoid kfree(). The callbacks
> async_req_queue/done are now embedded in qce_device structure and they
> are invoked directly from algorithm implementations. Thus I have
> separated the interfaces: functions implemented in core part of the
> driver and struct qce_algo_ops having the function pointers implemented
> by every type of algorithm.
> 
> If you don't have some objections I can send out a version 2.


Well, I'd have to see the code to understand clearly what you are
describing here, but the mention of devm_kzalloc() concerns me.  The
only device which I currently see to which this allocation could be
associated is the single platform_device in the core.  Associating the
memory with the core gets rid of the explicit call to kfree() by the
core, but doesn't rearrange the way the memory is actually managed.

If you have changed it so that each algorithm "block" has its own
device, then this would seem more reasonable, but I don't see that in
the explanation you provided.

-Courtney

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/9] crypto: qce: Adds sha and hmac transforms
  2014-04-03 16:18 ` [PATCH 5/9] crypto: qce: Adds sha and hmac transforms Stanimir Varbanov
@ 2014-04-09  0:09   ` Stephen Boyd
  2014-04-10 14:40     ` Stanimir Varbanov
  0 siblings, 1 reply; 31+ messages in thread
From: Stephen Boyd @ 2014-04-09  0:09 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

On 04/03, Stanimir Varbanov wrote:
> +static void qce_ahash_dma_done(void *data)
> +{
> +	struct crypto_async_request *async_req = data;
> +	struct ahash_request *req = ahash_request_cast(async_req);
> +	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
> +	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
> +	struct qce_device *qce = tmpl->qce;
> +	struct qce_result_dump *result = qce->dma.result_buf;
> +	unsigned int digestsize = crypto_ahash_digestsize(ahash);
> +	int error;
> +	u32 status;
> +
> +	qce_dma_terminate_all(&qce->dma);
> +
> +	qce_unmapsg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE,
> +		     rctx->src_chained);
> +	qce_unmapsg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE, 0);
> +
> +	memcpy(rctx->digest, result->auth_iv, digestsize);
> +	if (req->result)
> +		memcpy(req->result, result->auth_iv, digestsize);
> +
> +	rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]);
> +	rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]);

Does rctx->byte_count need to be marked __be32?

> +
> +	error = qce_check_status(qce, &status);
> +	if (error < 0)
> +		dev_err(qce->dev, "ahash operation error (%x)\n", status);
> +
> +	req->src = rctx->src;
> +	req->nbytes = rctx->nbytes;
> +
> +	rctx->last_blk = false;
> +	rctx->first_blk = false;
> +
> +	tmpl->async_req_done(tmpl->qce, error);
> +}
> +
[...]
> +static int qce_import_common(struct ahash_request *req, u64 in_count,
> +				 u32 *state, u8 *buffer, bool hmac)
> +{
> +	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
> +	u64 count = in_count;
> +	unsigned int digestsize = crypto_ahash_digestsize(ahash);
> +	unsigned int blocksize;
> +
> +	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash));
> +	rctx->count = in_count;
> +	memcpy(rctx->trailing_buf, buffer, blocksize);
> +
> +	if (in_count <= blocksize) {
> +		rctx->first_blk = 1;
> +	} else {
> +		rctx->first_blk = 0;
> +		/*
> +		 * For HMAC, there is a hardware padding done when first block
> +		 * is set. Therefore the byte_count must be incremened by 64
> +		 * after the first block operation.
> +		 */
> +		if (hmac)
> +			count += SHA_PADDING;
> +	}
> +
> +	rctx->byte_count[0] = (u32)(count & ~SHA_PADDING_MASK);
> +	rctx->byte_count[1] = (u32)(count >> 32);
> +	qce_cpu_to_be32p_array((__be32 *)rctx->digest, (const u8 *)state,
> +			       digestsize);
> +	rctx->trailing_buf_len = (unsigned int)(in_count & (blocksize - 1));

Is this a way to say

	(unsigned int)clamp_t(u64, in_count, blocksize - 1)

?

> +
> +	return 0;
> +}
> +
> +static int qce_ahash_import(struct ahash_request *req, const void *in)
> +{
> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
> +	u32 flags = rctx->flags;
> +	bool hmac = IS_SHA_HMAC(flags);
> +	int ret;
> +
> +	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
> +		struct sha1_state *state = (struct sha1_state *)in;

Unnecessary cast from void *.

> +
> +		ret = qce_import_common(req, state->count, state->state,
> +					state->buffer, hmac);
> +	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) {
> +		struct sha256_state *state = (struct sha256_state *)in;

Ditto.

> +
> +		ret = qce_import_common(req, state->count, state->state,
> +					state->buf, hmac);
> +	} else {
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int qce_ahash_update(struct ahash_request *req)
> +{
> +	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
> +	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
> +	unsigned int total, len;
> +	int nents;
> +	struct scatterlist *sg_last;
> +	u8 *buf;

> +	u32 pad_len;
> +	u32 trailing_buf_len;
> +	u32 nbytes;
> +	u32 offset;
> +	u32 bytes;

size_t for these?

> +	u8 *staging;
> +	bool chained;
> +	unsigned int blocksize;
> +
> +	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
> +	rctx->count += req->nbytes;
> +
> +	/* check for trailing buffer from previous updates and append it */
> +	total = req->nbytes + rctx->trailing_buf_len;
> +	len = req->nbytes;
[...]
> +
> +struct qce_ahash_def {
> +	u32 flags;

unsigned long?

> +	const char *name;
> +	const char *drv_name;
> +	unsigned int digestsize;
> +	unsigned int blocksize;
> +	unsigned int statesize;
> +	const __be32 *std_iv;
> +};
[..]
> +
> +/*

Nit: This isn't kernel doc notation

> + * @flags: operation flags
> + * @src: request sg
> + * @src_chained: is source scatterlist chained
> + * @src_nents: source number of entries
> + * @nbytes: request number of bytes
> + * @byte_count: byte count
> + * @count: save count in states during update, import and export
> + * @first_blk: is it the first block
> + * @last_blk: is it the last block
> + * @trailing_buf: used during update, import and export
> + * @trailing_buf_len: lenght of the trailing buffer
> + * @staging_buf: buffer for internal use
> + * @digest: calculated digest
> + * @sg: used to chain sg lists
> + * @authkey: pointer to auth key in sha ctx
> + * @authklen: auth key length
> + * @result_sg: scatterlist used for result buffer
> + */
> +struct qce_sha_reqctx {
> +	u32 flags;

unsigned long?

> +	struct scatterlist *src;
> +	bool src_chained;
> +	int src_nents;
> +	unsigned int nbytes;
> +	u32 byte_count[2];
> +	u64 count;
> +	bool first_blk;

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/9] crypto: qce: Adds sha and hmac transforms
  2014-04-09  0:09   ` Stephen Boyd
@ 2014-04-10 14:40     ` Stanimir Varbanov
  2014-04-11 20:12       ` Stephen Boyd
  0 siblings, 1 reply; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-10 14:40 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

Hi Stephen,

thanks for the comments.

On 04/09/2014 03:09 AM, Stephen Boyd wrote:
> On 04/03, Stanimir Varbanov wrote:
>> +static void qce_ahash_dma_done(void *data)
>> +{
>> +	struct crypto_async_request *async_req = data;
>> +	struct ahash_request *req = ahash_request_cast(async_req);
>> +	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
>> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
>> +	struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
>> +	struct qce_device *qce = tmpl->qce;
>> +	struct qce_result_dump *result = qce->dma.result_buf;
>> +	unsigned int digestsize = crypto_ahash_digestsize(ahash);
>> +	int error;
>> +	u32 status;
>> +
>> +	qce_dma_terminate_all(&qce->dma);
>> +
>> +	qce_unmapsg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE,
>> +		     rctx->src_chained);
>> +	qce_unmapsg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE, 0);
>> +
>> +	memcpy(rctx->digest, result->auth_iv, digestsize);
>> +	if (req->result)
>> +		memcpy(req->result, result->auth_iv, digestsize);
>> +
>> +	rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]);
>> +	rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]);
> 
> Does rctx->byte_count need to be marked __be32?

yes, makes sense.

> 
>> +
>> +	error = qce_check_status(qce, &status);
>> +	if (error < 0)
>> +		dev_err(qce->dev, "ahash operation error (%x)\n", status);
>> +
>> +	req->src = rctx->src;
>> +	req->nbytes = rctx->nbytes;
>> +
>> +	rctx->last_blk = false;
>> +	rctx->first_blk = false;
>> +
>> +	tmpl->async_req_done(tmpl->qce, error);
>> +}
>> +
> [...]
>> +static int qce_import_common(struct ahash_request *req, u64 in_count,
>> +				 u32 *state, u8 *buffer, bool hmac)
>> +{
>> +	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
>> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
>> +	u64 count = in_count;
>> +	unsigned int digestsize = crypto_ahash_digestsize(ahash);
>> +	unsigned int blocksize;
>> +
>> +	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash));
>> +	rctx->count = in_count;
>> +	memcpy(rctx->trailing_buf, buffer, blocksize);
>> +
>> +	if (in_count <= blocksize) {
>> +		rctx->first_blk = 1;
>> +	} else {
>> +		rctx->first_blk = 0;
>> +		/*
>> +		 * For HMAC, there is a hardware padding done when first block
>> +		 * is set. Therefore the byte_count must be incremened by 64
>> +		 * after the first block operation.
>> +		 */
>> +		if (hmac)
>> +			count += SHA_PADDING;
>> +	}
>> +
>> +	rctx->byte_count[0] = (u32)(count & ~SHA_PADDING_MASK);
>> +	rctx->byte_count[1] = (u32)(count >> 32);
>> +	qce_cpu_to_be32p_array((__be32 *)rctx->digest, (const u8 *)state,
>> +			       digestsize);
>> +	rctx->trailing_buf_len = (unsigned int)(in_count & (blocksize - 1));
> 
> Is this a way to say
> 
> 	(unsigned int)clamp_t(u64, in_count, blocksize - 1)
> 
> ?

In fact no, I think it should be:

trailing_buf_len = in_count % blocksize.

> 
>> +
>> +	return 0;
>> +}
>> +
>> +static int qce_ahash_import(struct ahash_request *req, const void *in)
>> +{
>> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
>> +	u32 flags = rctx->flags;
>> +	bool hmac = IS_SHA_HMAC(flags);
>> +	int ret;
>> +
>> +	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
>> +		struct sha1_state *state = (struct sha1_state *)in;
> 
> Unnecessary cast from void *.

Nope, "in" is "const void *". Cast is needed to avoid compiler warnings.

> 
>> +
>> +		ret = qce_import_common(req, state->count, state->state,
>> +					state->buffer, hmac);
>> +	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) {
>> +		struct sha256_state *state = (struct sha256_state *)in;
> 
> Ditto.
> 
>> +
>> +		ret = qce_import_common(req, state->count, state->state,
>> +					state->buf, hmac);
>> +	} else {
>> +		ret = -EINVAL;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qce_ahash_update(struct ahash_request *req)
>> +{
>> +	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
>> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
>> +	struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
>> +	unsigned int total, len;
>> +	int nents;
>> +	struct scatterlist *sg_last;
>> +	u8 *buf;
> 
>> +	u32 pad_len;
>> +	u32 trailing_buf_len;
>> +	u32 nbytes;
>> +	u32 offset;
>> +	u32 bytes;
> 
> size_t for these?

Hm, probably yes, I thought to revise this function cause it looks more
complicated than it should be.

> 
>> +	u8 *staging;
>> +	bool chained;
>> +	unsigned int blocksize;
>> +
>> +	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
>> +	rctx->count += req->nbytes;
>> +
>> +	/* check for trailing buffer from previous updates and append it */
>> +	total = req->nbytes + rctx->trailing_buf_len;
>> +	len = req->nbytes;
> [...]
>> +
>> +struct qce_ahash_def {
>> +	u32 flags;
> 
> unsigned long?

sure, will do.

> 
>> +	const char *name;
>> +	const char *drv_name;
>> +	unsigned int digestsize;
>> +	unsigned int blocksize;
>> +	unsigned int statesize;
>> +	const __be32 *std_iv;
>> +};
> [..]
>> +
>> +/*
> 
> Nit: This isn't kernel doc notation

OK. Will change to kernel doc in next version.

> 
>> + * @flags: operation flags
>> + * @src: request sg
>> + * @src_chained: is source scatterlist chained
>> + * @src_nents: source number of entries
>> + * @nbytes: request number of bytes
>> + * @byte_count: byte count
>> + * @count: save count in states during update, import and export
>> + * @first_blk: is it the first block
>> + * @last_blk: is it the last block
>> + * @trailing_buf: used during update, import and export
>> + * @trailing_buf_len: lenght of the trailing buffer
>> + * @staging_buf: buffer for internal use
>> + * @digest: calculated digest
>> + * @sg: used to chain sg lists
>> + * @authkey: pointer to auth key in sha ctx
>> + * @authklen: auth key length
>> + * @result_sg: scatterlist used for result buffer
>> + */
>> +struct qce_sha_reqctx {
>> +	u32 flags;
> 
> unsigned long?

sure, will do.

> 
>> +	struct scatterlist *src;
>> +	bool src_chained;
>> +	int src_nents;
>> +	unsigned int nbytes;
>> +	u32 byte_count[2];
>> +	u64 count;
>> +	bool first_blk;
> 


-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/9] crypto: qce: Adds sha and hmac transforms
  2014-04-10 14:40     ` Stanimir Varbanov
@ 2014-04-11 20:12       ` Stephen Boyd
  2014-04-14  8:23         ` Stanimir Varbanov
  0 siblings, 1 reply; 31+ messages in thread
From: Stephen Boyd @ 2014-04-11 20:12 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

On 04/10, Stanimir Varbanov wrote:
> On 04/09/2014 03:09 AM, Stephen Boyd wrote:
> > On 04/03, Stanimir Varbanov wrote:
> > 
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int qce_ahash_import(struct ahash_request *req, const void *in)
> >> +{
> >> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
> >> +	u32 flags = rctx->flags;
> >> +	bool hmac = IS_SHA_HMAC(flags);
> >> +	int ret;
> >> +
> >> +	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
> >> +		struct sha1_state *state = (struct sha1_state *)in;
> > 
> > Unnecessary cast from void *.
> 
> Nope, "in" is "const void *". Cast is needed to avoid compiler warnings.
> 

Ouch. Why are we casting away const? It should be possible to
make qce_import_common() take const state and buffer arguments?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/9] crypto: qce: Add core driver implementation
  2014-04-08 22:00       ` Courtney Cavin
@ 2014-04-14  8:19         ` Stanimir Varbanov
  0 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-14  8:19 UTC (permalink / raw)
  To: Courtney Cavin
  Cc: Herbert Xu, David S. Miller, Grant Likely, Rob Herring,
	linux-kernel, linux-crypto, devicetree, linux-arm-msm

Hi Courtney,

On 04/09/2014 01:00 AM, Courtney Cavin wrote:
> On Tue, Apr 08, 2014 at 06:26:44PM +0200, Stanimir Varbanov wrote:
>> On 04/04/2014 02:38 AM, Courtney Cavin wrote:
>>> On Thu, Apr 03, 2014 at 06:17:58PM +0200, Stanimir Varbanov wrote:
>>>> This adds core driver files. The core part is implementing a
>>>> platform driver probe and remove callbaks, the probe enables
>>>> clocks, checks crypto version, initialize and request dma
>>>> channels, create done tasklet and work queue and finally
>>>> register the algorithms into crypto subsystem.
>>>>
>>>> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
>>>> ---
>>>>  drivers/crypto/qce/core.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/crypto/qce/core.h |  69 ++++++++++
>>>>  2 files changed, 402 insertions(+)
>>>>  create mode 100644 drivers/crypto/qce/core.c
>>>>  create mode 100644 drivers/crypto/qce/core.h
>>>>
>>>> diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
>>> [...]
>>>> +static struct qce_algo_ops qce_ops[] = {
>>>> +	{
>>>> +		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
>>>> +		.register_alg = qce_ablkcipher_register,
>>>> +	},
>>>> +	{
>>>> +		.type = CRYPTO_ALG_TYPE_AHASH,
>>>> +		.register_alg = qce_ahash_register,
>>>> +	},
>>>> +};
>>>> +
>>>> +static void qce_unregister_algs(struct qce_device *qce)
>>>> +{
>>>> +	struct qce_alg_template *tmpl, *n;
>>>> +
>>>> +	list_for_each_entry_safe(tmpl, n, &qce->alg_list, entry) {
>>>> +		if (tmpl->crypto_alg_type == CRYPTO_ALG_TYPE_AHASH)
>>>> +			crypto_unregister_ahash(&tmpl->alg.ahash);
>>>> +		else
>>>> +			crypto_unregister_alg(&tmpl->alg.crypto);
>>>> +
>>>> +		list_del(&tmpl->entry);
>>>> +		kfree(tmpl);
>>>
>>> I find this whole memory/list management to be very disorganised.
>>> ops->register_alg() is supposed to allocate this item--more precisely,
>>> multiple items--using something that must be able to be kfree'd
>>> directly, register it with the crypto core, and put it on this list
>>> manually.  Here we unregister/remove/free this in the core.  Josh's
>>> recommendation of a unregister_alg callback might help, but it all
>>> remains a bit unclear with register_alg/unregister_alg managing X
>>> algorithms per call. 
>>>
>>> Additionally, above you have qce_ops, which clearly defines the
>>> operations for specific algorithms types/groups, which in later patches
>>> are shown to be seperated out into independent implementations.
>>>
>>> From what I can tell, this seems to be a framework with built-in yet
>>> independent crypto implementations which call the crypto API directly.
>>>
>>> It would be more logical to me if this was seperated out into a
>>> "library/core" API, with the individual implementations as platform
>>> drivers of their own.  Then they can register with the core, managing
>>> memory how they please.
>>>
>>> What am I missing?
>>>
>>
>> No, you have not miss nothing.
>>
>> OK I see your point. I made few changes in the core, killed the alg_list
>> and its manipulation function and added a .unregister_algs operation.
>> Now every type of algorithm will handle all core crypto api functions
>> itself. Also I'm using devm_kzalloc() in .register_algs when allocating
>> memory for qce_alg_template structures to avoid kfree(). The callbacks
>> async_req_queue/done are now embedded in qce_device structure and they
>> are invoked directly from algorithm implementations. Thus I have
>> separated the interfaces: functions implemented in core part of the
>> driver and struct qce_algo_ops having the function pointers implemented
>> by every type of algorithm.
>>
>> If you don't have some objections I can send out a version 2.
> 
> 
> Well, I'd have to see the code to understand clearly what you are
> describing here, but the mention of devm_kzalloc() concerns me.  The
> only device which I currently see to which this allocation could be
> associated is the single platform_device in the core.  Associating the
> memory with the core gets rid of the explicit call to kfree() by the
> core, but doesn't rearrange the way the memory is actually managed.

OK, no worries. I have no strong opinion and will use kzalloc() then.

> 
> If you have changed it so that each algorithm "block" has its own
> device, then this would seem more reasonable, but I don't see that in
> the explanation you provided.

No, that is not possible. The platform driver must be one because the
register space is common. The hardware accesses must be serialised from
core part of the driver.

-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/9] crypto: qce: Adds sha and hmac transforms
  2014-04-11 20:12       ` Stephen Boyd
@ 2014-04-14  8:23         ` Stanimir Varbanov
  0 siblings, 0 replies; 31+ messages in thread
From: Stanimir Varbanov @ 2014-04-14  8:23 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Herbert Xu, David S. Miller, linux-kernel, linux-crypto, linux-arm-msm

Hi Stephen,

On 04/11/2014 11:12 PM, Stephen Boyd wrote:
> On 04/10, Stanimir Varbanov wrote:
>> On 04/09/2014 03:09 AM, Stephen Boyd wrote:
>>> On 04/03, Stanimir Varbanov wrote:
>>>
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int qce_ahash_import(struct ahash_request *req, const void *in)
>>>> +{
>>>> +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req);
>>>> +	u32 flags = rctx->flags;
>>>> +	bool hmac = IS_SHA_HMAC(flags);
>>>> +	int ret;
>>>> +
>>>> +	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) {
>>>> +		struct sha1_state *state = (struct sha1_state *)in;
>>>
>>> Unnecessary cast from void *.
>>
>> Nope, "in" is "const void *". Cast is needed to avoid compiler warnings.
>>
> 
> Ouch. Why are we casting away const? It should be possible to
> make qce_import_common() take const state and buffer arguments?
> 

Sure, that's possible. Thanks!


-- 
regards,
Stan

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2014-04-14  8:23 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-03 16:17 [PATCH 0/9] Add Qualcomm crypto driver Stanimir Varbanov
2014-04-03 16:17 ` [PATCH 1/9] crypto: qce: Add core driver implementation Stanimir Varbanov
2014-04-03 18:19   ` Josh Cartwright
2014-04-04 15:54     ` Stanimir Varbanov
2014-04-03 23:38   ` Courtney Cavin
2014-04-08 16:26     ` Stanimir Varbanov
2014-04-08 22:00       ` Courtney Cavin
2014-04-14  8:19         ` Stanimir Varbanov
2014-04-03 16:17 ` [PATCH 2/9] crypto: qce: Add register defines Stanimir Varbanov
2014-04-03 16:24   ` Kumar Gala
2014-04-03 16:33     ` Stanimir Varbanov
2014-04-03 16:42       ` Kumar Gala
2014-04-04  9:23   ` Srinivas Kandagatla
2014-04-04 22:14     ` Stanimir Vabanov
2014-04-03 16:18 ` [PATCH 3/9] crypto: qce: Add dma and sg helpers Stanimir Varbanov
2014-04-03 18:25   ` Josh Cartwright
2014-04-04  8:49     ` Stanimir Varbanov
2014-04-03 23:15   ` Courtney Cavin
2014-04-04 13:07     ` Stanimir Varbanov
2014-04-07 22:42       ` Courtney Cavin
2014-04-08 12:08         ` Stanimir Varbanov
2014-04-03 16:18 ` [PATCH 4/9] crypto: qce: Add ablkcipher algorithms Stanimir Varbanov
2014-04-03 16:18 ` [PATCH 5/9] crypto: qce: Adds sha and hmac transforms Stanimir Varbanov
2014-04-09  0:09   ` Stephen Boyd
2014-04-10 14:40     ` Stanimir Varbanov
2014-04-11 20:12       ` Stephen Boyd
2014-04-14  8:23         ` Stanimir Varbanov
2014-04-03 16:18 ` [PATCH 6/9] crypto: qce: Adds infrastructure to setup the crypto block Stanimir Varbanov
2014-04-03 16:18 ` [PATCH 7/9] crypto: qce: Adds Makefile to build the driver Stanimir Varbanov
2014-04-03 16:18 ` [PATCH 8/9] crypto: qce: Build Qualcomm qce driver Stanimir Varbanov
2014-04-03 16:18 ` [PATCH 9/9] ARM: DT: qcom: Add Qualcomm crypto driver binding document Stanimir Varbanov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.