提交 9a07a796 编写于 作者: L Linus Torvalds

Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6

Pull crypto update from Herbert Xu:
 "API:

   - Crypto self tests can now be disabled at boot/run time.
   - Add async support to algif_aead.

  Algorithms:

   - A large number of fixes to MPI from Nicolai Stange.
   - Performance improvement for HMAC DRBG.

  Drivers:

   - Use generic crypto engine in omap-des.
   - Merge ppc4xx-rng and crypto4xx drivers.
   - Fix lockups in sun4i-ss driver by disabling IRQs.
   - Add DMA engine support to ccp.
   - Reenable talitos hash algorithms.
   - Add support for Hisilicon SoC RNG.
   - Add basic crypto driver for the MXC SCC.

  Others:

   - Do not allocate crypto hash tfm in NORECLAIM context in ecryptfs"

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (77 commits)
  crypto: qat - change the adf_ctl_stop_devices to void
  crypto: caam - fix caam_jr_alloc() ret code
  crypto: vmx - comply with ABIs that specify vrsave as reserved.
  crypto: testmgr - Add a flag allowing the self-tests to be disabled at runtime.
  crypto: ccp - constify ccp_actions structure
  crypto: marvell/cesa - Use dma_pool_zalloc
  crypto: qat - make adf_vf_isr.c dependant on IOV config
  crypto: qat - Fix typo in comments
  lib: asn1_decoder - add MODULE_LICENSE("GPL")
  crypto: omap-sham - Use dma_request_chan() for requesting DMA channel
  crypto: omap-des - Use dma_request_chan() for requesting DMA channel
  crypto: omap-aes - Use dma_request_chan() for requesting DMA channel
  crypto: omap-des - Integrate with the crypto engine framework
  crypto: s5p-sss - fix incorrect usage of scatterlists api
  crypto: s5p-sss - Fix missed interrupts when working with 8 kB blocks
  crypto: s5p-sss - Use common BIT macro
  crypto: mxc-scc - fix unwinding in mxc_scc_crypto_register()
  crypto: mxc-scc - signedness bugs in mxc_scc_ablkcipher_req_init()
  crypto: talitos - fix ahash algorithms registration
  crypto: ccp - Ensure all dependencies are specified
  ...
......@@ -1936,9 +1936,9 @@ static int test_skcipher(void)
}
req = skcipher_request_alloc(skcipher, GFP_KERNEL);
if (IS_ERR(req)) {
pr_info("could not allocate request queue\n");
ret = PTR_ERR(req);
if (!req) {
pr_info("could not allocate skcipher request\n");
ret = -ENOMEM;
goto out;
}
......
Freescale Security Controller (SCC)
Required properties:
- compatible : Should be "fsl,imx25-scc".
- reg : Should contain register location and length.
- interrupts : Should contain interrupt numbers for SCM IRQ and SMN IRQ.
- interrupt-names : Should specify the names "scm" and "smn" for the
SCM IRQ and SMN IRQ.
- clocks: Should contain the clock driving the SCC core.
- clock-names: Should be set to "ipg".
Example:
scc: crypto@53fac000 {
compatible = "fsl,imx25-scc";
reg = <0x53fac000 0x4000>;
clocks = <&clks 111>;
clock-names = "ipg";
interrupts = <49>, <50>;
interrupt-names = "scm", "smn";
};
......@@ -23,10 +23,8 @@ Required properties:
- "samsung,exynos4210-secss" for Exynos4210, Exynos4212, Exynos4412, Exynos5250,
Exynos5260 and Exynos5420 SoCs.
- reg : Offset and length of the register set for the module
- interrupts : interrupt specifiers of SSS module interrupts, should contain
following entries:
- first : feed control interrupt (required for all variants),
- second : hash interrupt (required only for samsung,s5pv210-secss).
- interrupts : interrupt specifiers of SSS module interrupts (one feed
control interrupt).
- clocks : list of clock phandle and specifier pairs for all clocks listed in
clock-names property.
......
Hisilicon Random Number Generator
Required properties:
- compatible : Should be "hisilicon,hip04-rng" or "hisilicon,hip05-rng"
- reg : Offset and length of the register set of this block
Example:
rng@d1010000 {
compatible = "hisilicon,hip05-rng";
reg = <0xd1010000 0x100>;
};
......@@ -838,6 +838,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
It will be ignored when crashkernel=X,high is not used
or memory reserved is below 4G.
cryptomgr.notests
[KNL] Disable crypto self-tests
cs89x0_dma= [HW,NET]
Format: <dma>
......
......@@ -627,6 +627,7 @@ F: include/linux/altera_jtaguart.h
AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER
M: Tom Lendacky <thomas.lendacky@amd.com>
M: Gary Hook <gary.hook@amd.com>
L: linux-crypto@vger.kernel.org
S: Supported
F: drivers/crypto/ccp/
......
......@@ -420,6 +420,15 @@
interrupts = <41>;
};
scc: crypto@53fac000 {
compatible = "fsl,imx25-scc";
reg = <0x53fac000 0x4000>;
clocks = <&clks 111>;
clock-names = "ipg";
interrupts = <49>, <50>;
interrupt-names = "scm", "smn";
};
esdhc1: esdhc@53fb4000 {
compatible = "fsl,imx25-esdhc";
reg = <0x53fb4000 0x4000>;
......
......@@ -13,7 +13,7 @@
* any later version.
*/
#include <crypto/aead.h>
#include <crypto/internal/aead.h>
#include <crypto/scatterwalk.h>
#include <crypto/if_alg.h>
#include <linux/init.h>
......@@ -29,15 +29,24 @@ struct aead_sg_list {
struct scatterlist sg[ALG_MAX_PAGES];
};
struct aead_async_rsgl {
struct af_alg_sgl sgl;
struct list_head list;
};
struct aead_async_req {
struct scatterlist *tsgl;
struct aead_async_rsgl first_rsgl;
struct list_head list;
struct kiocb *iocb;
unsigned int tsgls;
char iv[];
};
struct aead_ctx {
struct aead_sg_list tsgl;
/*
* RSGL_MAX_ENTRIES is an artificial limit where user space at maximum
* can cause the kernel to allocate RSGL_MAX_ENTRIES * ALG_MAX_PAGES
* pages
*/
#define RSGL_MAX_ENTRIES ALG_MAX_PAGES
struct af_alg_sgl rsgl[RSGL_MAX_ENTRIES];
struct aead_async_rsgl first_rsgl;
struct list_head list;
void *iv;
......@@ -75,6 +84,17 @@ static inline bool aead_sufficient_data(struct aead_ctx *ctx)
return ctx->used >= ctx->aead_assoclen + as;
}
static void aead_reset_ctx(struct aead_ctx *ctx)
{
struct aead_sg_list *sgl = &ctx->tsgl;
sg_init_table(sgl->sg, ALG_MAX_PAGES);
sgl->cur = 0;
ctx->used = 0;
ctx->more = 0;
ctx->merge = 0;
}
static void aead_put_sgl(struct sock *sk)
{
struct alg_sock *ask = alg_sk(sk);
......@@ -90,11 +110,7 @@ static void aead_put_sgl(struct sock *sk)
put_page(sg_page(sg + i));
sg_assign_page(sg + i, NULL);
}
sg_init_table(sg, ALG_MAX_PAGES);
sgl->cur = 0;
ctx->used = 0;
ctx->more = 0;
ctx->merge = 0;
aead_reset_ctx(ctx);
}
static void aead_wmem_wakeup(struct sock *sk)
......@@ -349,23 +365,188 @@ static ssize_t aead_sendpage(struct socket *sock, struct page *page,
return err ?: size;
}
static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags)
#define GET_ASYM_REQ(req, tfm) (struct aead_async_req *) \
((char *)req + sizeof(struct aead_request) + \
crypto_aead_reqsize(tfm))
#define GET_REQ_SIZE(tfm) sizeof(struct aead_async_req) + \
crypto_aead_reqsize(tfm) + crypto_aead_ivsize(tfm) + \
sizeof(struct aead_request)
static void aead_async_cb(struct crypto_async_request *_req, int err)
{
struct sock *sk = _req->data;
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
struct crypto_aead *tfm = crypto_aead_reqtfm(&ctx->aead_req);
struct aead_request *req = aead_request_cast(_req);
struct aead_async_req *areq = GET_ASYM_REQ(req, tfm);
struct scatterlist *sg = areq->tsgl;
struct aead_async_rsgl *rsgl;
struct kiocb *iocb = areq->iocb;
unsigned int i, reqlen = GET_REQ_SIZE(tfm);
list_for_each_entry(rsgl, &areq->list, list) {
af_alg_free_sg(&rsgl->sgl);
if (rsgl != &areq->first_rsgl)
sock_kfree_s(sk, rsgl, sizeof(*rsgl));
}
for (i = 0; i < areq->tsgls; i++)
put_page(sg_page(sg + i));
sock_kfree_s(sk, areq->tsgl, sizeof(*areq->tsgl) * areq->tsgls);
sock_kfree_s(sk, req, reqlen);
__sock_put(sk);
iocb->ki_complete(iocb, err, err);
}
static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
int flags)
{
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
struct crypto_aead *tfm = crypto_aead_reqtfm(&ctx->aead_req);
struct aead_async_req *areq;
struct aead_request *req = NULL;
struct aead_sg_list *sgl = &ctx->tsgl;
struct aead_async_rsgl *last_rsgl = NULL, *rsgl;
unsigned int as = crypto_aead_authsize(tfm);
unsigned int i, reqlen = GET_REQ_SIZE(tfm);
int err = -ENOMEM;
unsigned long used;
size_t outlen;
size_t usedpages = 0;
lock_sock(sk);
if (ctx->more) {
err = aead_wait_for_data(sk, flags);
if (err)
goto unlock;
}
used = ctx->used;
outlen = used;
if (!aead_sufficient_data(ctx))
goto unlock;
req = sock_kmalloc(sk, reqlen, GFP_KERNEL);
if (unlikely(!req))
goto unlock;
areq = GET_ASYM_REQ(req, tfm);
memset(&areq->first_rsgl, '\0', sizeof(areq->first_rsgl));
INIT_LIST_HEAD(&areq->list);
areq->iocb = msg->msg_iocb;
memcpy(areq->iv, ctx->iv, crypto_aead_ivsize(tfm));
aead_request_set_tfm(req, tfm);
aead_request_set_ad(req, ctx->aead_assoclen);
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
aead_async_cb, sk);
used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
/* take over all tx sgls from ctx */
areq->tsgl = sock_kmalloc(sk, sizeof(*areq->tsgl) * sgl->cur,
GFP_KERNEL);
if (unlikely(!areq->tsgl))
goto free;
sg_init_table(areq->tsgl, sgl->cur);
for (i = 0; i < sgl->cur; i++)
sg_set_page(&areq->tsgl[i], sg_page(&sgl->sg[i]),
sgl->sg[i].length, sgl->sg[i].offset);
areq->tsgls = sgl->cur;
/* create rx sgls */
while (iov_iter_count(&msg->msg_iter)) {
size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
(outlen - usedpages));
if (list_empty(&areq->list)) {
rsgl = &areq->first_rsgl;
} else {
rsgl = sock_kmalloc(sk, sizeof(*rsgl), GFP_KERNEL);
if (unlikely(!rsgl)) {
err = -ENOMEM;
goto free;
}
}
rsgl->sgl.npages = 0;
list_add_tail(&rsgl->list, &areq->list);
/* make one iovec available as scatterlist */
err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen);
if (err < 0)
goto free;
usedpages += err;
/* chain the new scatterlist with previous one */
if (last_rsgl)
af_alg_link_sg(&last_rsgl->sgl, &rsgl->sgl);
last_rsgl = rsgl;
/* we do not need more iovecs as we have sufficient memory */
if (outlen <= usedpages)
break;
iov_iter_advance(&msg->msg_iter, err);
}
err = -EINVAL;
/* ensure output buffer is sufficiently large */
if (usedpages < outlen)
goto free;
aead_request_set_crypt(req, areq->tsgl, areq->first_rsgl.sgl.sg, used,
areq->iv);
err = ctx->enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
if (err) {
if (err == -EINPROGRESS) {
sock_hold(sk);
err = -EIOCBQUEUED;
aead_reset_ctx(ctx);
goto unlock;
} else if (err == -EBADMSG) {
aead_put_sgl(sk);
}
goto free;
}
aead_put_sgl(sk);
free:
list_for_each_entry(rsgl, &areq->list, list) {
af_alg_free_sg(&rsgl->sgl);
if (rsgl != &areq->first_rsgl)
sock_kfree_s(sk, rsgl, sizeof(*rsgl));
}
if (areq->tsgl)
sock_kfree_s(sk, areq->tsgl, sizeof(*areq->tsgl) * areq->tsgls);
if (req)
sock_kfree_s(sk, req, reqlen);
unlock:
aead_wmem_wakeup(sk);
release_sock(sk);
return err ? err : outlen;
}
static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
{
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
struct aead_sg_list *sgl = &ctx->tsgl;
unsigned int i = 0;
struct aead_async_rsgl *last_rsgl = NULL;
struct aead_async_rsgl *rsgl, *tmp;
int err = -EINVAL;
unsigned long used = 0;
size_t outlen = 0;
size_t usedpages = 0;
unsigned int cnt = 0;
/* Limit number of IOV blocks to be accessed below */
if (msg->msg_iter.nr_segs > RSGL_MAX_ENTRIES)
return -ENOMSG;
lock_sock(sk);
......@@ -417,21 +598,33 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
(outlen - usedpages));
if (list_empty(&ctx->list)) {
rsgl = &ctx->first_rsgl;
} else {
rsgl = sock_kmalloc(sk, sizeof(*rsgl), GFP_KERNEL);
if (unlikely(!rsgl)) {
err = -ENOMEM;
goto unlock;
}
}
rsgl->sgl.npages = 0;
list_add_tail(&rsgl->list, &ctx->list);
/* make one iovec available as scatterlist */
err = af_alg_make_sg(&ctx->rsgl[cnt], &msg->msg_iter,
seglen);
err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen);
if (err < 0)
goto unlock;
usedpages += err;
/* chain the new scatterlist with previous one */
if (cnt)
af_alg_link_sg(&ctx->rsgl[cnt-1], &ctx->rsgl[cnt]);
if (last_rsgl)
af_alg_link_sg(&last_rsgl->sgl, &rsgl->sgl);
last_rsgl = rsgl;
/* we do not need more iovecs as we have sufficient memory */
if (outlen <= usedpages)
break;
iov_iter_advance(&msg->msg_iter, err);
cnt++;
}
err = -EINVAL;
......@@ -440,8 +633,7 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
goto unlock;
sg_mark_end(sgl->sg + sgl->cur - 1);
aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->rsgl[0].sg,
aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->first_rsgl.sgl.sg,
used, ctx->iv);
aead_request_set_ad(&ctx->aead_req, ctx->aead_assoclen);
......@@ -454,23 +646,35 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
/* EBADMSG implies a valid cipher operation took place */
if (err == -EBADMSG)
aead_put_sgl(sk);
goto unlock;
}
aead_put_sgl(sk);
err = 0;
unlock:
for (i = 0; i < cnt; i++)
af_alg_free_sg(&ctx->rsgl[i]);
list_for_each_entry_safe(rsgl, tmp, &ctx->list, list) {
af_alg_free_sg(&rsgl->sgl);
if (rsgl != &ctx->first_rsgl)
sock_kfree_s(sk, rsgl, sizeof(*rsgl));
list_del(&rsgl->list);
}
INIT_LIST_HEAD(&ctx->list);
aead_wmem_wakeup(sk);
release_sock(sk);
return err ? err : outlen;
}
static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
int flags)
{
return (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) ?
aead_recvmsg_async(sock, msg, flags) :
aead_recvmsg_sync(sock, msg, flags);
}
static unsigned int aead_poll(struct file *file, struct socket *sock,
poll_table *wait)
{
......@@ -540,6 +744,7 @@ static void aead_sock_destruct(struct sock *sk)
unsigned int ivlen = crypto_aead_ivsize(
crypto_aead_reqtfm(&ctx->aead_req));
WARN_ON(atomic_read(&sk->sk_refcnt) != 0);
aead_put_sgl(sk);
sock_kzfree_s(sk, ctx->iv, ivlen);
sock_kfree_s(sk, ctx, ctx->len);
......@@ -574,6 +779,7 @@ static int aead_accept_parent(void *private, struct sock *sk)
ctx->aead_assoclen = 0;
af_alg_init_completion(&ctx->completion);
sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES);
INIT_LIST_HEAD(&ctx->list);
ask->private = ctx;
......
......@@ -237,6 +237,7 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
break;
case OID_sha224:
ctx->sinfo->sig.hash_algo = "sha224";
break;
default:
printk("Unsupported digest algo: %u\n", ctx->last_oid);
return -ENOPKG;
......
......@@ -592,8 +592,10 @@ static const struct drbg_state_ops drbg_ctr_ops = {
******************************************************************/
#if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC)
static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
unsigned char *outval, const struct list_head *in);
static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval,
const struct list_head *in);
static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg,
const unsigned char *key);
static int drbg_init_hash_kernel(struct drbg_state *drbg);
static int drbg_fini_hash_kernel(struct drbg_state *drbg);
#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */
......@@ -619,9 +621,11 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,
LIST_HEAD(seedlist);
LIST_HEAD(vdatalist);
if (!reseed)
if (!reseed) {
/* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */
memset(drbg->V, 1, drbg_statelen(drbg));
drbg_kcapi_hmacsetkey(drbg, drbg->C);
}
drbg_string_fill(&seed1, drbg->V, drbg_statelen(drbg));
list_add_tail(&seed1.list, &seedlist);
......@@ -641,12 +645,13 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,
prefix = DRBG_PREFIX1;
/* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */
seed2.buf = &prefix;
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->C, &seedlist);
ret = drbg_kcapi_hash(drbg, drbg->C, &seedlist);
if (ret)
return ret;
drbg_kcapi_hmacsetkey(drbg, drbg->C);
/* 10.1.2.2 step 2 and 5 -- HMAC for V */
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &vdatalist);
ret = drbg_kcapi_hash(drbg, drbg->V, &vdatalist);
if (ret)
return ret;
......@@ -681,7 +686,7 @@ static int drbg_hmac_generate(struct drbg_state *drbg,
while (len < buflen) {
unsigned int outlen = 0;
/* 10.1.2.5 step 4.1 */
ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &datalist);
ret = drbg_kcapi_hash(drbg, drbg->V, &datalist);
if (ret)
return ret;
outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
......@@ -796,7 +801,7 @@ static int drbg_hash_df(struct drbg_state *drbg,
while (len < outlen) {
short blocklen = 0;
/* 10.4.1 step 4.1 */
ret = drbg_kcapi_hash(drbg, NULL, tmp, entropylist);
ret = drbg_kcapi_hash(drbg, tmp, entropylist);
if (ret)
goto out;
/* 10.4.1 step 4.2 */
......@@ -874,7 +879,7 @@ static int drbg_hash_process_addtl(struct drbg_state *drbg,
list_add_tail(&data1.list, &datalist);
list_add_tail(&data2.list, &datalist);
list_splice_tail(addtl, &datalist);
ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist);
ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist);
if (ret)
goto out;
......@@ -907,7 +912,7 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
while (len < buflen) {
unsigned int outlen = 0;
/* 10.1.1.4 step hashgen 4.1 */
ret = drbg_kcapi_hash(drbg, NULL, dst, &datalist);
ret = drbg_kcapi_hash(drbg, dst, &datalist);
if (ret) {
len = ret;
goto out;
......@@ -956,7 +961,7 @@ static int drbg_hash_generate(struct drbg_state *drbg,
list_add_tail(&data1.list, &datalist);
drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
list_add_tail(&data2.list, &datalist);
ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist);
ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist);
if (ret) {
len = ret;
goto out;
......@@ -1600,14 +1605,20 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg)
return 0;
}
static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
unsigned char *outval, const struct list_head *in)
static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg,
const unsigned char *key)
{
struct sdesc *sdesc = (struct sdesc *)drbg->priv_data;
crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg));
}
static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval,
const struct list_head *in)
{
struct sdesc *sdesc = (struct sdesc *)drbg->priv_data;
struct drbg_string *input = NULL;
if (key)
crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg));
crypto_shash_init(&sdesc->shash);
list_for_each_entry(input, in, list)
crypto_shash_update(&sdesc->shash, input->buf, input->len);
......
......@@ -32,7 +32,7 @@ static int lzo_init(struct crypto_tfm *tfm)
struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
ctx->lzo_comp_mem = kmalloc(LZO1X_MEM_COMPRESS,
GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
GFP_KERNEL | __GFP_NOWARN);
if (!ctx->lzo_comp_mem)
ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS);
if (!ctx->lzo_comp_mem)
......
......@@ -35,6 +35,10 @@
#include "internal.h"
static bool notests;
module_param(notests, bool, 0644);
MODULE_PARM_DESC(notests, "disable crypto self-tests");
#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
/* a perfect nop */
......@@ -3885,6 +3889,11 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
int j;
int rc;
if (!fips_enabled && notests) {
printk_once(KERN_INFO "alg: self-tests disabled\n");
return 0;
}
alg_test_descs_check_order();
if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
......
......@@ -268,19 +268,6 @@ config HW_RANDOM_NOMADIK
If unsure, say Y.
config HW_RANDOM_PPC4XX
tristate "PowerPC 4xx generic true random number generator support"
depends on PPC && 4xx
default HW_RANDOM
---help---
This driver provides the kernel-side support for the TRNG hardware
found in the security function of some PowerPC 4xx SoCs.
To compile this driver as a module, choose M here: the
module will be called ppc4xx-rng.
If unsure, say N.
config HW_RANDOM_PSERIES
tristate "pSeries HW Random Number Generator support"
depends on PPC64 && IBMVIO
......@@ -309,7 +296,8 @@ config HW_RANDOM_POWERNV
config HW_RANDOM_EXYNOS
tristate "EXYNOS HW random number generator support"
depends on ARCH_EXYNOS
depends on ARCH_EXYNOS || COMPILE_TEST
depends on HAS_IOMEM
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
......@@ -333,6 +321,19 @@ config HW_RANDOM_TPM
If unsure, say Y.
config HW_RANDOM_HISI
tristate "Hisilicon Random Number Generator support"
depends on HW_RANDOM && ARCH_HISI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Hisilicon Hip04 and Hip05 SoC.
To compile this driver as a module, choose M here: the
module will be called hisi-rng.
If unsure, say Y.
config HW_RANDOM_MSM
tristate "Qualcomm SoCs Random Number Generator support"
depends on HW_RANDOM && ARCH_QCOM
......
......@@ -22,10 +22,10 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o
obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
......
......@@ -2,7 +2,7 @@
* exynos-rng.c - Random Number Generator driver for the exynos
*
* Copyright (C) 2012 Samsung Electronics
* Jonghwa Lee <jonghwa3.lee@smasung.com>
* Jonghwa Lee <jonghwa3.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -77,7 +77,8 @@ static int exynos_init(struct hwrng *rng)
pm_runtime_get_sync(exynos_rng->dev);
ret = exynos_rng_configure(exynos_rng);
pm_runtime_put_noidle(exynos_rng->dev);
pm_runtime_mark_last_busy(exynos_rng->dev);
pm_runtime_put_autosuspend(exynos_rng->dev);
return ret;
}
......@@ -89,6 +90,7 @@ static int exynos_read(struct hwrng *rng, void *buf,
struct exynos_rng, rng);
u32 *data = buf;
int retry = 100;
int ret = 4;
pm_runtime_get_sync(exynos_rng->dev);
......@@ -97,23 +99,27 @@ static int exynos_read(struct hwrng *rng, void *buf,
while (!(exynos_rng_readl(exynos_rng,
EXYNOS_PRNG_STATUS_OFFSET) & PRNG_DONE) && --retry)
cpu_relax();
if (!retry)
return -ETIMEDOUT;
if (!retry) {
ret = -ETIMEDOUT;
goto out;
}
exynos_rng_writel(exynos_rng, PRNG_DONE, EXYNOS_PRNG_STATUS_OFFSET);
*data = exynos_rng_readl(exynos_rng, EXYNOS_PRNG_OUT1_OFFSET);
out:
pm_runtime_mark_last_busy(exynos_rng->dev);
pm_runtime_put_sync_autosuspend(exynos_rng->dev);
return 4;
return ret;
}
static int exynos_rng_probe(struct platform_device *pdev)
{
struct exynos_rng *exynos_rng;
struct resource *res;
int ret;
exynos_rng = devm_kzalloc(&pdev->dev, sizeof(struct exynos_rng),
GFP_KERNEL);
......@@ -141,7 +147,21 @@ static int exynos_rng_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
ret = devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
if (ret) {
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
}
return ret;
}
static int exynos_rng_remove(struct platform_device *pdev)
{
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
static int __maybe_unused exynos_rng_runtime_suspend(struct device *dev)
......@@ -201,6 +221,7 @@ static struct platform_driver exynos_rng_driver = {
.of_match_table = exynos_rng_dt_match,
},
.probe = exynos_rng_probe,
.remove = exynos_rng_remove,
};
module_platform_driver(exynos_rng_driver);
......
/*
* Copyright (C) 2016 HiSilicon Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#define RNG_SEED 0x0
#define RNG_CTRL 0x4
#define RNG_SEED_SEL BIT(2)
#define RNG_RING_EN BIT(1)
#define RNG_EN BIT(0)
#define RNG_RAN_NUM 0x10
#define RNG_PHY_SEED 0x14
#define to_hisi_rng(p) container_of(p, struct hisi_rng, rng)
static int seed_sel;
module_param(seed_sel, int, S_IRUGO);
MODULE_PARM_DESC(seed_sel, "Auto reload seed. 0, use LFSR(default); 1, use ring oscillator.");
struct hisi_rng {
void __iomem *base;
struct hwrng rng;
};
static int hisi_rng_init(struct hwrng *rng)
{
struct hisi_rng *hrng = to_hisi_rng(rng);
int val = RNG_EN;
u32 seed;
/* get a random number as initial seed */
get_random_bytes(&seed, sizeof(seed));
writel_relaxed(seed, hrng->base + RNG_SEED);
/**
* The seed is reload periodically, there are two choice
* of seeds, default seed using the value from LFSR, or
* will use seed generated by ring oscillator.
*/
if (seed_sel == 1)
val |= RNG_RING_EN | RNG_SEED_SEL;
writel_relaxed(val, hrng->base + RNG_CTRL);
return 0;
}
static void hisi_rng_cleanup(struct hwrng *rng)
{
struct hisi_rng *hrng = to_hisi_rng(rng);
writel_relaxed(0, hrng->base + RNG_CTRL);
}
static int hisi_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
struct hisi_rng *hrng = to_hisi_rng(rng);
u32 *data = buf;
*data = readl_relaxed(hrng->base + RNG_RAN_NUM);
return 4;
}
static int hisi_rng_probe(struct platform_device *pdev)
{
struct hisi_rng *rng;
struct resource *res;
int ret;
rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
if (!rng)
return -ENOMEM;
platform_set_drvdata(pdev, rng);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rng->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(rng->base))
return PTR_ERR(rng->base);
rng->rng.name = pdev->name;
rng->rng.init = hisi_rng_init;
rng->rng.cleanup = hisi_rng_cleanup;
rng->rng.read = hisi_rng_read;
ret = devm_hwrng_register(&pdev->dev, &rng->rng);
if (ret) {
dev_err(&pdev->dev, "failed to register hwrng\n");
return ret;
}
return 0;
}
static const struct of_device_id hisi_rng_dt_ids[] = {
{ .compatible = "hisilicon,hip04-rng" },
{ .compatible = "hisilicon,hip05-rng" },
{ }
};
MODULE_DEVICE_TABLE(of, hisi_rng_dt_ids);
static struct platform_driver hisi_rng_driver = {
.probe = hisi_rng_probe,
.driver = {
.name = "hisi-rng",
.of_match_table = of_match_ptr(hisi_rng_dt_ids),
},
};
module_platform_driver(hisi_rng_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kefeng Wang <wangkefeng.wang@huawei>");
MODULE_DESCRIPTION("Hisilicon random number generator driver");
/*
* Generic PowerPC 44x RNG driver
*
* Copyright 2011 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <asm/io.h>
#define PPC4XX_TRNG_DEV_CTRL 0x60080
#define PPC4XX_TRNGE 0x00020000
#define PPC4XX_TRNG_CTRL 0x0008
#define PPC4XX_TRNG_CTRL_DALM 0x20
#define PPC4XX_TRNG_STAT 0x0004
#define PPC4XX_TRNG_STAT_B 0x1
#define PPC4XX_TRNG_DATA 0x0000
#define MODULE_NAME "ppc4xx_rng"
static int ppc4xx_rng_data_present(struct hwrng *rng, int wait)
{
void __iomem *rng_regs = (void __iomem *) rng->priv;
int busy, i, present = 0;
for (i = 0; i < 20; i++) {
busy = (in_le32(rng_regs + PPC4XX_TRNG_STAT) & PPC4XX_TRNG_STAT_B);
if (!busy || !wait) {
present = 1;
break;
}
udelay(10);
}
return present;
}
static int ppc4xx_rng_data_read(struct hwrng *rng, u32 *data)
{
void __iomem *rng_regs = (void __iomem *) rng->priv;
*data = in_le32(rng_regs + PPC4XX_TRNG_DATA);
return 4;
}
static int ppc4xx_rng_enable(int enable)
{
struct device_node *ctrl;
void __iomem *ctrl_reg;
int err = 0;
u32 val;
/* Find the main crypto device node and map it to turn the TRNG on */
ctrl = of_find_compatible_node(NULL, NULL, "amcc,ppc4xx-crypto");
if (!ctrl)
return -ENODEV;
ctrl_reg = of_iomap(ctrl, 0);
if (!ctrl_reg) {
err = -ENODEV;
goto out;
}
val = in_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL);
if (enable)
val |= PPC4XX_TRNGE;
else
val = val & ~PPC4XX_TRNGE;
out_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL, val);
iounmap(ctrl_reg);
out:
of_node_put(ctrl);
return err;
}
static struct hwrng ppc4xx_rng = {
.name = MODULE_NAME,
.data_present = ppc4xx_rng_data_present,
.data_read = ppc4xx_rng_data_read,
};
static int ppc4xx_rng_probe(struct platform_device *dev)
{
void __iomem *rng_regs;
int err = 0;
rng_regs = of_iomap(dev->dev.of_node, 0);
if (!rng_regs)
return -ENODEV;
err = ppc4xx_rng_enable(1);
if (err)
return err;
out_le32(rng_regs + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
ppc4xx_rng.priv = (unsigned long) rng_regs;
err = hwrng_register(&ppc4xx_rng);
return err;
}
static int ppc4xx_rng_remove(struct platform_device *dev)
{
void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv;
hwrng_unregister(&ppc4xx_rng);
ppc4xx_rng_enable(0);
iounmap(rng_regs);
return 0;
}
static const struct of_device_id ppc4xx_rng_match[] = {
{ .compatible = "ppc4xx-rng", },
{ .compatible = "amcc,ppc460ex-rng", },
{ .compatible = "amcc,ppc440epx-rng", },
{},
};
MODULE_DEVICE_TABLE(of, ppc4xx_rng_match);
static struct platform_driver ppc4xx_rng_driver = {
.driver = {
.name = MODULE_NAME,
.of_match_table = ppc4xx_rng_match,
},
.probe = ppc4xx_rng_probe,
.remove = ppc4xx_rng_remove,
};
module_platform_driver(ppc4xx_rng_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Josh Boyer <jwboyer@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("HW RNG driver for PPC 4xx processors");
......@@ -279,6 +279,14 @@ config CRYPTO_DEV_PPC4XX
help
This option allows you to have support for AMCC crypto acceleration.
config HW_RANDOM_PPC4XX
bool "PowerPC 4xx generic true random number generator support"
depends on CRYPTO_DEV_PPC4XX && HW_RANDOM
default y
---help---
This option provides the kernel-side support for the TRNG hardware
found in the security function of some PowerPC 4xx SoCs.
config CRYPTO_DEV_OMAP_SHAM
tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator"
depends on ARCH_OMAP2PLUS
......@@ -302,15 +310,16 @@ config CRYPTO_DEV_OMAP_AES
want to use the OMAP module for AES algorithms.
config CRYPTO_DEV_OMAP_DES
tristate "Support for OMAP DES3DES hw engine"
tristate "Support for OMAP DES/3DES hw engine"
depends on ARCH_OMAP2PLUS
select CRYPTO_DES
select CRYPTO_BLKCIPHER
select CRYPTO_ENGINE
help
OMAP processors have DES/3DES module accelerator. Select this if you
want to use the OMAP module for DES and 3DES algorithms. Currently
the ECB and CBC modes of operation supported by the driver. Also
accesses made on unaligned boundaries are also supported.
the ECB and CBC modes of operation are supported by the driver. Also
accesses made on unaligned boundaries are supported.
config CRYPTO_DEV_PICOXCELL
tristate "Support for picoXcell IPSEC and Layer2 crypto engines"
......@@ -340,9 +349,19 @@ config CRYPTO_DEV_SAHARA
This option enables support for the SAHARA HW crypto accelerator
found in some Freescale i.MX chips.
config CRYPTO_DEV_MXC_SCC
tristate "Support for Freescale Security Controller (SCC)"
depends on ARCH_MXC && OF
select CRYPTO_BLKCIPHER
select CRYPTO_DES
help
This option enables support for the Security Controller (SCC)
found in Freescale i.MX25 chips.
config CRYPTO_DEV_S5P
tristate "Support for Samsung S5PV210/Exynos crypto accelerator"
depends on ARCH_S5PV210 || ARCH_EXYNOS
depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
depends on HAS_IOMEM && HAS_DMA
select CRYPTO_AES
select CRYPTO_BLKCIPHER
help
......
......@@ -23,6 +23,7 @@ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += mxc-scc.o
obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/
......
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
crypto4xx-y := crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
crypto4xx-$(CONFIG_HW_RANDOM_PPC4XX) += crypto4xx_trng.o
......@@ -40,6 +40,7 @@
#include "crypto4xx_reg_def.h"
#include "crypto4xx_core.h"
#include "crypto4xx_sa.h"
#include "crypto4xx_trng.h"
#define PPC4XX_SEC_VERSION_STR "0.5"
......@@ -1225,6 +1226,7 @@ static int crypto4xx_probe(struct platform_device *ofdev)
if (rc)
goto err_start_dev;
ppc4xx_trng_probe(core_dev);
return 0;
err_start_dev:
......@@ -1252,6 +1254,8 @@ static int crypto4xx_remove(struct platform_device *ofdev)
struct device *dev = &ofdev->dev;
struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
ppc4xx_trng_remove(core_dev);
free_irq(core_dev->irq, dev);
irq_dispose_mapping(core_dev->irq);
......@@ -1272,7 +1276,7 @@ MODULE_DEVICE_TABLE(of, crypto4xx_match);
static struct platform_driver crypto4xx_driver = {
.driver = {
.name = "crypto4xx",
.name = MODULE_NAME,
.of_match_table = crypto4xx_match,
},
.probe = crypto4xx_probe,
......@@ -1284,4 +1288,3 @@ module_platform_driver(crypto4xx_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("James Hsiao <jhsiao@amcc.com>");
MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator");
......@@ -24,6 +24,8 @@
#include <crypto/internal/hash.h>
#define MODULE_NAME "crypto4xx"
#define PPC460SX_SDR0_SRST 0x201
#define PPC405EX_SDR0_SRST 0x200
#define PPC460EX_SDR0_SRST 0x201
......@@ -72,6 +74,7 @@ struct crypto4xx_device {
char *name;
u64 ce_phy_address;
void __iomem *ce_base;
void __iomem *trng_base;
void *pdr; /* base address of packet
descriptor ring */
......@@ -106,6 +109,7 @@ struct crypto4xx_core_device {
struct device *device;
struct platform_device *ofdev;
struct crypto4xx_device *dev;
struct hwrng *trng;
u32 int_status;
u32 irq;
struct tasklet_struct tasklet;
......
......@@ -125,6 +125,7 @@
#define PPC4XX_INTERRUPT_CLR 0x3ffff
#define PPC4XX_PRNG_CTRL_AUTO_EN 0x3
#define PPC4XX_DC_3DES_EN 1
#define PPC4XX_TRNG_EN 0x00020000
#define PPC4XX_INT_DESCR_CNT 4
#define PPC4XX_INT_TIMEOUT_CNT 0
#define PPC4XX_INT_CFG 1
......
/*
* Generic PowerPC 44x RNG driver
*
* Copyright 2011 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/io.h>
#include "crypto4xx_core.h"
#include "crypto4xx_trng.h"
#include "crypto4xx_reg_def.h"
#define PPC4XX_TRNG_CTRL 0x0008
#define PPC4XX_TRNG_CTRL_DALM 0x20
#define PPC4XX_TRNG_STAT 0x0004
#define PPC4XX_TRNG_STAT_B 0x1
#define PPC4XX_TRNG_DATA 0x0000
static int ppc4xx_trng_data_present(struct hwrng *rng, int wait)
{
struct crypto4xx_device *dev = (void *)rng->priv;
int busy, i, present = 0;
for (i = 0; i < 20; i++) {
busy = (in_le32(dev->trng_base + PPC4XX_TRNG_STAT) &
PPC4XX_TRNG_STAT_B);
if (!busy || !wait) {
present = 1;
break;
}
udelay(10);
}
return present;
}
static int ppc4xx_trng_data_read(struct hwrng *rng, u32 *data)
{
struct crypto4xx_device *dev = (void *)rng->priv;
*data = in_le32(dev->trng_base + PPC4XX_TRNG_DATA);
return 4;
}
static void ppc4xx_trng_enable(struct crypto4xx_device *dev, bool enable)
{
u32 device_ctrl;
device_ctrl = readl(dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
if (enable)
device_ctrl |= PPC4XX_TRNG_EN;
else
device_ctrl &= ~PPC4XX_TRNG_EN;
writel(device_ctrl, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
}
static const struct of_device_id ppc4xx_trng_match[] = {
{ .compatible = "ppc4xx-rng", },
{ .compatible = "amcc,ppc460ex-rng", },
{ .compatible = "amcc,ppc440epx-rng", },
{},
};
void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
{
struct crypto4xx_device *dev = core_dev->dev;
struct device_node *trng = NULL;
struct hwrng *rng = NULL;
int err;
/* Find the TRNG device node and map it */
trng = of_find_matching_node(NULL, ppc4xx_trng_match);
if (!trng || !of_device_is_available(trng))
return;
dev->trng_base = of_iomap(trng, 0);
of_node_put(trng);
if (!dev->trng_base)
goto err_out;
rng = kzalloc(sizeof(*rng), GFP_KERNEL);
if (!rng)
goto err_out;
rng->name = MODULE_NAME;
rng->data_present = ppc4xx_trng_data_present;
rng->data_read = ppc4xx_trng_data_read;
rng->priv = (unsigned long) dev;
core_dev->trng = rng;
ppc4xx_trng_enable(dev, true);
out_le32(dev->trng_base + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
err = devm_hwrng_register(core_dev->device, core_dev->trng);
if (err) {
ppc4xx_trng_enable(dev, false);
dev_err(core_dev->device, "failed to register hwrng (%d).\n",
err);
goto err_out;
}
return;
err_out:
of_node_put(trng);
iounmap(dev->trng_base);
kfree(rng);
dev->trng_base = NULL;
core_dev->trng = NULL;
}
void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev)
{
if (core_dev && core_dev->trng) {
struct crypto4xx_device *dev = core_dev->dev;
devm_hwrng_unregister(core_dev->device, core_dev->trng);
ppc4xx_trng_enable(dev, false);
iounmap(dev->trng_base);
kfree(core_dev->trng);
}
}
MODULE_ALIAS("ppc4xx_rng");
/**
* AMCC SoC PPC4xx Crypto Driver
*
* Copyright (c) 2008 Applied Micro Circuits Corporation.
* All rights reserved. James Hsiao <jhsiao@amcc.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* This file defines the security context
* associate format.
*/
#ifndef __CRYPTO4XX_TRNG_H__
#define __CRYPTO4XX_TRNG_H__
#ifdef CONFIG_HW_RANDOM_PPC4XX
void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev);
void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev);
#else
static inline void ppc4xx_trng_probe(
struct crypto4xx_device *dev __maybe_unused) { }
static inline void ppc4xx_trng_remove(
struct crypto4xx_device *dev __maybe_unused) { }
#endif
#endif
......@@ -248,7 +248,7 @@ static void caam_jr_dequeue(unsigned long devarg)
struct device *caam_jr_alloc(void)
{
struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL;
struct device *dev = NULL;
struct device *dev = ERR_PTR(-ENODEV);
int min_tfm_cnt = INT_MAX;
int tfm_cnt;
......
......@@ -3,6 +3,8 @@ config CRYPTO_DEV_CCP_DD
depends on CRYPTO_DEV_CCP
default m
select HW_RANDOM
select DMA_ENGINE
select DMADEVICES
select CRYPTO_SHA1
select CRYPTO_SHA256
help
......
obj-$(CONFIG_CRYPTO_DEV_CCP_DD) += ccp.o
ccp-objs := ccp-dev.o ccp-ops.o ccp-dev-v3.o ccp-platform.o
ccp-objs := ccp-dev.o \
ccp-ops.o \
ccp-dev-v3.o \
ccp-platform.o \
ccp-dmaengine.o
ccp-$(CONFIG_PCI) += ccp-pci.o
obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
......
......@@ -406,6 +406,11 @@ static int ccp_init(struct ccp_device *ccp)
goto e_kthread;
}
/* Register the DMA engine support */
ret = ccp_dmaengine_register(ccp);
if (ret)
goto e_hwrng;
ccp_add_device(ccp);
/* Enable interrupts */
......@@ -413,6 +418,9 @@ static int ccp_init(struct ccp_device *ccp)
return 0;
e_hwrng:
hwrng_unregister(&ccp->hwrng);
e_kthread:
for (i = 0; i < ccp->cmd_q_count; i++)
if (ccp->cmd_q[i].kthread)
......@@ -436,6 +444,9 @@ static void ccp_destroy(struct ccp_device *ccp)
/* Remove this device from the list of available units first */
ccp_del_device(ccp);
/* Unregister the DMA engine */
ccp_dmaengine_unregister(ccp);
/* Unregister the RNG */
hwrng_unregister(&ccp->hwrng);
......@@ -515,7 +526,7 @@ static irqreturn_t ccp_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
static struct ccp_actions ccp3_actions = {
static const struct ccp_actions ccp3_actions = {
.perform_aes = ccp_perform_aes,
.perform_xts_aes = ccp_perform_xts_aes,
.perform_sha = ccp_perform_sha,
......
......@@ -16,7 +16,7 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/rwlock_types.h>
#include <linux/spinlock_types.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/delay.h>
......
......@@ -22,6 +22,9 @@
#include <linux/dmapool.h>
#include <linux/hw_random.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/dmaengine.h>
#define MAX_CCP_NAME_LEN 16
#define MAX_DMAPOOL_NAME_LEN 32
......@@ -159,7 +162,7 @@ struct ccp_actions {
/* Structure to hold CCP version-specific values */
struct ccp_vdata {
unsigned int version;
struct ccp_actions *perform;
const struct ccp_actions *perform;
};
extern struct ccp_vdata ccpv3;
......@@ -167,6 +170,39 @@ extern struct ccp_vdata ccpv3;
struct ccp_device;
struct ccp_cmd;
struct ccp_dma_cmd {
struct list_head entry;
struct ccp_cmd ccp_cmd;
};
struct ccp_dma_desc {
struct list_head entry;
struct ccp_device *ccp;
struct list_head pending;
struct list_head active;
enum dma_status status;
struct dma_async_tx_descriptor tx_desc;
size_t len;
};
struct ccp_dma_chan {
struct ccp_device *ccp;
spinlock_t lock;
struct list_head pending;
struct list_head active;
struct list_head complete;
struct tasklet_struct cleanup_tasklet;
enum dma_status status;
struct dma_chan dma_chan;
};
struct ccp_cmd_queue {
struct ccp_device *ccp;
......@@ -260,6 +296,14 @@ struct ccp_device {
struct hwrng hwrng;
unsigned int hwrng_retries;
/*
* Support for the CCP DMA capabilities
*/
struct dma_device dma_dev;
struct ccp_dma_chan *ccp_dma_chan;
struct kmem_cache *dma_cmd_cache;
struct kmem_cache *dma_desc_cache;
/*
* A counter used to generate job-ids for cmds submitted to the CCP
*/
......@@ -418,4 +462,7 @@ int ccp_cmd_queue_thread(void *data);
int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd);
int ccp_dmaengine_register(struct ccp_device *ccp);
void ccp_dmaengine_unregister(struct ccp_device *ccp);
#endif
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
* Copyright (C) 2016 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <gary.hook@amd.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/dmaengine.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/ccp.h>
#include "ccp-dev.h"
#include "../../dma/dmaengine.h"
#define CCP_DMA_WIDTH(_mask) \
({ \
u64 mask = _mask + 1; \
(mask == 0) ? 64 : fls64(mask); \
})
static void ccp_free_cmd_resources(struct ccp_device *ccp,
struct list_head *list)
{
struct ccp_dma_cmd *cmd, *ctmp;
list_for_each_entry_safe(cmd, ctmp, list, entry) {
list_del(&cmd->entry);
kmem_cache_free(ccp->dma_cmd_cache, cmd);
}
}
static void ccp_free_desc_resources(struct ccp_device *ccp,
struct list_head *list)
{
struct ccp_dma_desc *desc, *dtmp;
list_for_each_entry_safe(desc, dtmp, list, entry) {
ccp_free_cmd_resources(ccp, &desc->active);
ccp_free_cmd_resources(ccp, &desc->pending);
list_del(&desc->entry);
kmem_cache_free(ccp->dma_desc_cache, desc);
}
}
static void ccp_free_chan_resources(struct dma_chan *dma_chan)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
unsigned long flags;
dev_dbg(chan->ccp->dev, "%s - chan=%p\n", __func__, chan);
spin_lock_irqsave(&chan->lock, flags);
ccp_free_desc_resources(chan->ccp, &chan->complete);
ccp_free_desc_resources(chan->ccp, &chan->active);
ccp_free_desc_resources(chan->ccp, &chan->pending);
spin_unlock_irqrestore(&chan->lock, flags);
}
static void ccp_cleanup_desc_resources(struct ccp_device *ccp,
struct list_head *list)
{
struct ccp_dma_desc *desc, *dtmp;
list_for_each_entry_safe_reverse(desc, dtmp, list, entry) {
if (!async_tx_test_ack(&desc->tx_desc))
continue;
dev_dbg(ccp->dev, "%s - desc=%p\n", __func__, desc);
ccp_free_cmd_resources(ccp, &desc->active);
ccp_free_cmd_resources(ccp, &desc->pending);
list_del(&desc->entry);
kmem_cache_free(ccp->dma_desc_cache, desc);
}
}
static void ccp_do_cleanup(unsigned long data)
{
struct ccp_dma_chan *chan = (struct ccp_dma_chan *)data;
unsigned long flags;
dev_dbg(chan->ccp->dev, "%s - chan=%s\n", __func__,
dma_chan_name(&chan->dma_chan));
spin_lock_irqsave(&chan->lock, flags);
ccp_cleanup_desc_resources(chan->ccp, &chan->complete);
spin_unlock_irqrestore(&chan->lock, flags);
}
static int ccp_issue_next_cmd(struct ccp_dma_desc *desc)
{
struct ccp_dma_cmd *cmd;
int ret;
cmd = list_first_entry(&desc->pending, struct ccp_dma_cmd, entry);
list_move(&cmd->entry, &desc->active);
dev_dbg(desc->ccp->dev, "%s - tx %d, cmd=%p\n", __func__,
desc->tx_desc.cookie, cmd);
ret = ccp_enqueue_cmd(&cmd->ccp_cmd);
if (!ret || (ret == -EINPROGRESS) || (ret == -EBUSY))
return 0;
dev_dbg(desc->ccp->dev, "%s - error: ret=%d, tx %d, cmd=%p\n", __func__,
ret, desc->tx_desc.cookie, cmd);
return ret;
}
static void ccp_free_active_cmd(struct ccp_dma_desc *desc)
{
struct ccp_dma_cmd *cmd;
cmd = list_first_entry_or_null(&desc->active, struct ccp_dma_cmd,
entry);
if (!cmd)
return;
dev_dbg(desc->ccp->dev, "%s - freeing tx %d cmd=%p\n",
__func__, desc->tx_desc.cookie, cmd);
list_del(&cmd->entry);
kmem_cache_free(desc->ccp->dma_cmd_cache, cmd);
}
static struct ccp_dma_desc *__ccp_next_dma_desc(struct ccp_dma_chan *chan,
struct ccp_dma_desc *desc)
{
/* Move current DMA descriptor to the complete list */
if (desc)
list_move(&desc->entry, &chan->complete);
/* Get the next DMA descriptor on the active list */
desc = list_first_entry_or_null(&chan->active, struct ccp_dma_desc,
entry);
return desc;
}
static struct ccp_dma_desc *ccp_handle_active_desc(struct ccp_dma_chan *chan,
struct ccp_dma_desc *desc)
{
struct dma_async_tx_descriptor *tx_desc;
unsigned long flags;
/* Loop over descriptors until one is found with commands */
do {
if (desc) {
/* Remove the DMA command from the list and free it */
ccp_free_active_cmd(desc);
if (!list_empty(&desc->pending)) {
/* No errors, keep going */
if (desc->status != DMA_ERROR)
return desc;
/* Error, free remaining commands and move on */
ccp_free_cmd_resources(desc->ccp,
&desc->pending);
}
tx_desc = &desc->tx_desc;
} else {
tx_desc = NULL;
}
spin_lock_irqsave(&chan->lock, flags);
if (desc) {
if (desc->status != DMA_ERROR)
desc->status = DMA_COMPLETE;
dev_dbg(desc->ccp->dev,
"%s - tx %d complete, status=%u\n", __func__,
desc->tx_desc.cookie, desc->status);
dma_cookie_complete(tx_desc);
}
desc = __ccp_next_dma_desc(chan, desc);
spin_unlock_irqrestore(&chan->lock, flags);
if (tx_desc) {
if (tx_desc->callback &&
(tx_desc->flags & DMA_PREP_INTERRUPT))
tx_desc->callback(tx_desc->callback_param);
dma_run_dependencies(tx_desc);
}
} while (desc);
return NULL;
}
static struct ccp_dma_desc *__ccp_pending_to_active(struct ccp_dma_chan *chan)
{
struct ccp_dma_desc *desc;
if (list_empty(&chan->pending))
return NULL;
desc = list_empty(&chan->active)
? list_first_entry(&chan->pending, struct ccp_dma_desc, entry)
: NULL;
list_splice_tail_init(&chan->pending, &chan->active);
return desc;
}
static void ccp_cmd_callback(void *data, int err)
{
struct ccp_dma_desc *desc = data;
struct ccp_dma_chan *chan;
int ret;
if (err == -EINPROGRESS)
return;
chan = container_of(desc->tx_desc.chan, struct ccp_dma_chan,
dma_chan);
dev_dbg(chan->ccp->dev, "%s - tx %d callback, err=%d\n",
__func__, desc->tx_desc.cookie, err);
if (err)
desc->status = DMA_ERROR;
while (true) {
/* Check for DMA descriptor completion */
desc = ccp_handle_active_desc(chan, desc);
/* Don't submit cmd if no descriptor or DMA is paused */
if (!desc || (chan->status == DMA_PAUSED))
break;
ret = ccp_issue_next_cmd(desc);
if (!ret)
break;
desc->status = DMA_ERROR;
}
tasklet_schedule(&chan->cleanup_tasklet);
}
static dma_cookie_t ccp_tx_submit(struct dma_async_tx_descriptor *tx_desc)
{
struct ccp_dma_desc *desc = container_of(tx_desc, struct ccp_dma_desc,
tx_desc);
struct ccp_dma_chan *chan;
dma_cookie_t cookie;
unsigned long flags;
chan = container_of(tx_desc->chan, struct ccp_dma_chan, dma_chan);
spin_lock_irqsave(&chan->lock, flags);
cookie = dma_cookie_assign(tx_desc);
list_add_tail(&desc->entry, &chan->pending);
spin_unlock_irqrestore(&chan->lock, flags);
dev_dbg(chan->ccp->dev, "%s - added tx descriptor %d to pending list\n",
__func__, cookie);
return cookie;
}
static struct ccp_dma_cmd *ccp_alloc_dma_cmd(struct ccp_dma_chan *chan)
{
struct ccp_dma_cmd *cmd;
cmd = kmem_cache_alloc(chan->ccp->dma_cmd_cache, GFP_NOWAIT);
if (cmd)
memset(cmd, 0, sizeof(*cmd));
return cmd;
}
static struct ccp_dma_desc *ccp_alloc_dma_desc(struct ccp_dma_chan *chan,
unsigned long flags)
{
struct ccp_dma_desc *desc;
desc = kmem_cache_alloc(chan->ccp->dma_desc_cache, GFP_NOWAIT);
if (!desc)
return NULL;
memset(desc, 0, sizeof(*desc));
dma_async_tx_descriptor_init(&desc->tx_desc, &chan->dma_chan);
desc->tx_desc.flags = flags;
desc->tx_desc.tx_submit = ccp_tx_submit;
desc->ccp = chan->ccp;
INIT_LIST_HEAD(&desc->pending);
INIT_LIST_HEAD(&desc->active);
desc->status = DMA_IN_PROGRESS;
return desc;
}
static struct ccp_dma_desc *ccp_create_desc(struct dma_chan *dma_chan,
struct scatterlist *dst_sg,
unsigned int dst_nents,
struct scatterlist *src_sg,
unsigned int src_nents,
unsigned long flags)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
struct ccp_device *ccp = chan->ccp;
struct ccp_dma_desc *desc;
struct ccp_dma_cmd *cmd;
struct ccp_cmd *ccp_cmd;
struct ccp_passthru_nomap_engine *ccp_pt;
unsigned int src_offset, src_len;
unsigned int dst_offset, dst_len;
unsigned int len;
unsigned long sflags;
size_t total_len;
if (!dst_sg || !src_sg)
return NULL;
if (!dst_nents || !src_nents)
return NULL;
desc = ccp_alloc_dma_desc(chan, flags);
if (!desc)
return NULL;
total_len = 0;
src_len = sg_dma_len(src_sg);
src_offset = 0;
dst_len = sg_dma_len(dst_sg);
dst_offset = 0;
while (true) {
if (!src_len) {
src_nents--;
if (!src_nents)
break;
src_sg = sg_next(src_sg);
if (!src_sg)
break;
src_len = sg_dma_len(src_sg);
src_offset = 0;
continue;
}
if (!dst_len) {
dst_nents--;
if (!dst_nents)
break;
dst_sg = sg_next(dst_sg);
if (!dst_sg)
break;
dst_len = sg_dma_len(dst_sg);
dst_offset = 0;
continue;
}
len = min(dst_len, src_len);
cmd = ccp_alloc_dma_cmd(chan);
if (!cmd)
goto err;
ccp_cmd = &cmd->ccp_cmd;
ccp_pt = &ccp_cmd->u.passthru_nomap;
ccp_cmd->flags = CCP_CMD_MAY_BACKLOG;
ccp_cmd->flags |= CCP_CMD_PASSTHRU_NO_DMA_MAP;
ccp_cmd->engine = CCP_ENGINE_PASSTHRU;
ccp_pt->bit_mod = CCP_PASSTHRU_BITWISE_NOOP;
ccp_pt->byte_swap = CCP_PASSTHRU_BYTESWAP_NOOP;
ccp_pt->src_dma = sg_dma_address(src_sg) + src_offset;
ccp_pt->dst_dma = sg_dma_address(dst_sg) + dst_offset;
ccp_pt->src_len = len;
ccp_pt->final = 1;
ccp_cmd->callback = ccp_cmd_callback;
ccp_cmd->data = desc;
list_add_tail(&cmd->entry, &desc->pending);
dev_dbg(ccp->dev,
"%s - cmd=%p, src=%pad, dst=%pad, len=%llu\n", __func__,
cmd, &ccp_pt->src_dma,
&ccp_pt->dst_dma, ccp_pt->src_len);
total_len += len;
src_len -= len;
src_offset += len;
dst_len -= len;
dst_offset += len;
}
desc->len = total_len;
if (list_empty(&desc->pending))
goto err;
dev_dbg(ccp->dev, "%s - desc=%p\n", __func__, desc);
spin_lock_irqsave(&chan->lock, sflags);
list_add_tail(&desc->entry, &chan->pending);
spin_unlock_irqrestore(&chan->lock, sflags);
return desc;
err:
ccp_free_cmd_resources(ccp, &desc->pending);
kmem_cache_free(ccp->dma_desc_cache, desc);
return NULL;
}
static struct dma_async_tx_descriptor *ccp_prep_dma_memcpy(
struct dma_chan *dma_chan, dma_addr_t dst, dma_addr_t src, size_t len,
unsigned long flags)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
struct ccp_dma_desc *desc;
struct scatterlist dst_sg, src_sg;
dev_dbg(chan->ccp->dev,
"%s - src=%pad, dst=%pad, len=%zu, flags=%#lx\n",
__func__, &src, &dst, len, flags);
sg_init_table(&dst_sg, 1);
sg_dma_address(&dst_sg) = dst;
sg_dma_len(&dst_sg) = len;
sg_init_table(&src_sg, 1);
sg_dma_address(&src_sg) = src;
sg_dma_len(&src_sg) = len;
desc = ccp_create_desc(dma_chan, &dst_sg, 1, &src_sg, 1, flags);
if (!desc)
return NULL;
return &desc->tx_desc;
}
static struct dma_async_tx_descriptor *ccp_prep_dma_sg(
struct dma_chan *dma_chan, struct scatterlist *dst_sg,
unsigned int dst_nents, struct scatterlist *src_sg,
unsigned int src_nents, unsigned long flags)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
struct ccp_dma_desc *desc;
dev_dbg(chan->ccp->dev,
"%s - src=%p, src_nents=%u dst=%p, dst_nents=%u, flags=%#lx\n",
__func__, src_sg, src_nents, dst_sg, dst_nents, flags);
desc = ccp_create_desc(dma_chan, dst_sg, dst_nents, src_sg, src_nents,
flags);
if (!desc)
return NULL;
return &desc->tx_desc;
}
static struct dma_async_tx_descriptor *ccp_prep_dma_interrupt(
struct dma_chan *dma_chan, unsigned long flags)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
struct ccp_dma_desc *desc;
desc = ccp_alloc_dma_desc(chan, flags);
if (!desc)
return NULL;
return &desc->tx_desc;
}
static void ccp_issue_pending(struct dma_chan *dma_chan)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
struct ccp_dma_desc *desc;
unsigned long flags;
dev_dbg(chan->ccp->dev, "%s\n", __func__);
spin_lock_irqsave(&chan->lock, flags);
desc = __ccp_pending_to_active(chan);
spin_unlock_irqrestore(&chan->lock, flags);
/* If there was nothing active, start processing */
if (desc)
ccp_cmd_callback(desc, 0);
}
static enum dma_status ccp_tx_status(struct dma_chan *dma_chan,
dma_cookie_t cookie,
struct dma_tx_state *state)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
struct ccp_dma_desc *desc;
enum dma_status ret;
unsigned long flags;
if (chan->status == DMA_PAUSED) {
ret = DMA_PAUSED;
goto out;
}
ret = dma_cookie_status(dma_chan, cookie, state);
if (ret == DMA_COMPLETE) {
spin_lock_irqsave(&chan->lock, flags);
/* Get status from complete chain, if still there */
list_for_each_entry(desc, &chan->complete, entry) {
if (desc->tx_desc.cookie != cookie)
continue;
ret = desc->status;
break;
}
spin_unlock_irqrestore(&chan->lock, flags);
}
out:
dev_dbg(chan->ccp->dev, "%s - %u\n", __func__, ret);
return ret;
}
static int ccp_pause(struct dma_chan *dma_chan)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
chan->status = DMA_PAUSED;
/*TODO: Wait for active DMA to complete before returning? */
return 0;
}
static int ccp_resume(struct dma_chan *dma_chan)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
struct ccp_dma_desc *desc;
unsigned long flags;
spin_lock_irqsave(&chan->lock, flags);
desc = list_first_entry_or_null(&chan->active, struct ccp_dma_desc,
entry);
spin_unlock_irqrestore(&chan->lock, flags);
/* Indicate the channel is running again */
chan->status = DMA_IN_PROGRESS;
/* If there was something active, re-start */
if (desc)
ccp_cmd_callback(desc, 0);
return 0;
}
static int ccp_terminate_all(struct dma_chan *dma_chan)
{
struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
dma_chan);
unsigned long flags;
dev_dbg(chan->ccp->dev, "%s\n", __func__);
/*TODO: Wait for active DMA to complete before continuing */
spin_lock_irqsave(&chan->lock, flags);
/*TODO: Purge the complete list? */
ccp_free_desc_resources(chan->ccp, &chan->active);
ccp_free_desc_resources(chan->ccp, &chan->pending);
spin_unlock_irqrestore(&chan->lock, flags);
return 0;
}
int ccp_dmaengine_register(struct ccp_device *ccp)
{
struct ccp_dma_chan *chan;
struct dma_device *dma_dev = &ccp->dma_dev;
struct dma_chan *dma_chan;
char *dma_cmd_cache_name;
char *dma_desc_cache_name;
unsigned int i;
int ret;
ccp->ccp_dma_chan = devm_kcalloc(ccp->dev, ccp->cmd_q_count,
sizeof(*(ccp->ccp_dma_chan)),
GFP_KERNEL);
if (!ccp->ccp_dma_chan)
return -ENOMEM;
dma_cmd_cache_name = devm_kasprintf(ccp->dev, GFP_KERNEL,
"%s-dmaengine-cmd-cache",
ccp->name);
if (!dma_cmd_cache_name)
return -ENOMEM;
ccp->dma_cmd_cache = kmem_cache_create(dma_cmd_cache_name,
sizeof(struct ccp_dma_cmd),
sizeof(void *),
SLAB_HWCACHE_ALIGN, NULL);
if (!ccp->dma_cmd_cache)
return -ENOMEM;
dma_desc_cache_name = devm_kasprintf(ccp->dev, GFP_KERNEL,
"%s-dmaengine-desc-cache",
ccp->name);
if (!dma_cmd_cache_name)
return -ENOMEM;
ccp->dma_desc_cache = kmem_cache_create(dma_desc_cache_name,
sizeof(struct ccp_dma_desc),
sizeof(void *),
SLAB_HWCACHE_ALIGN, NULL);
if (!ccp->dma_desc_cache) {
ret = -ENOMEM;
goto err_cache;
}
dma_dev->dev = ccp->dev;
dma_dev->src_addr_widths = CCP_DMA_WIDTH(dma_get_mask(ccp->dev));
dma_dev->dst_addr_widths = CCP_DMA_WIDTH(dma_get_mask(ccp->dev));
dma_dev->directions = DMA_MEM_TO_MEM;
dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
dma_cap_set(DMA_SG, dma_dev->cap_mask);
dma_cap_set(DMA_INTERRUPT, dma_dev->cap_mask);
INIT_LIST_HEAD(&dma_dev->channels);
for (i = 0; i < ccp->cmd_q_count; i++) {
chan = ccp->ccp_dma_chan + i;
dma_chan = &chan->dma_chan;
chan->ccp = ccp;
spin_lock_init(&chan->lock);
INIT_LIST_HEAD(&chan->pending);
INIT_LIST_HEAD(&chan->active);
INIT_LIST_HEAD(&chan->complete);
tasklet_init(&chan->cleanup_tasklet, ccp_do_cleanup,
(unsigned long)chan);
dma_chan->device = dma_dev;
dma_cookie_init(dma_chan);
list_add_tail(&dma_chan->device_node, &dma_dev->channels);
}
dma_dev->device_free_chan_resources = ccp_free_chan_resources;
dma_dev->device_prep_dma_memcpy = ccp_prep_dma_memcpy;
dma_dev->device_prep_dma_sg = ccp_prep_dma_sg;
dma_dev->device_prep_dma_interrupt = ccp_prep_dma_interrupt;
dma_dev->device_issue_pending = ccp_issue_pending;
dma_dev->device_tx_status = ccp_tx_status;
dma_dev->device_pause = ccp_pause;
dma_dev->device_resume = ccp_resume;
dma_dev->device_terminate_all = ccp_terminate_all;
ret = dma_async_device_register(dma_dev);
if (ret)
goto err_reg;
return 0;
err_reg:
kmem_cache_destroy(ccp->dma_desc_cache);
err_cache:
kmem_cache_destroy(ccp->dma_cmd_cache);
return ret;
}
void ccp_dmaengine_unregister(struct ccp_device *ccp)
{
struct dma_device *dma_dev = &ccp->dma_dev;
dma_async_device_unregister(dma_dev);
kmem_cache_destroy(ccp->dma_desc_cache);
kmem_cache_destroy(ccp->dma_cmd_cache);
}
......@@ -1427,6 +1427,70 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
return ret;
}
static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
struct ccp_cmd *cmd)
{
struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap;
struct ccp_dm_workarea mask;
struct ccp_op op;
int ret;
if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
return -EINVAL;
if (!pt->src_dma || !pt->dst_dma)
return -EINVAL;
if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
return -EINVAL;
if (!pt->mask)
return -EINVAL;
}
BUILD_BUG_ON(CCP_PASSTHRU_KSB_COUNT != 1);
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
op.jobid = ccp_gen_jobid(cmd_q->ccp);
if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
/* Load the mask */
op.ksb_key = cmd_q->ksb_key;
mask.length = pt->mask_len;
mask.dma.address = pt->mask;
mask.dma.length = pt->mask_len;
ret = ccp_copy_to_ksb(cmd_q, &mask, op.jobid, op.ksb_key,
CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
return ret;
}
}
/* Send data to the CCP Passthru engine */
op.eom = 1;
op.soc = 1;
op.src.type = CCP_MEMTYPE_SYSTEM;
op.src.u.dma.address = pt->src_dma;
op.src.u.dma.offset = 0;
op.src.u.dma.length = pt->src_len;
op.dst.type = CCP_MEMTYPE_SYSTEM;
op.dst.u.dma.address = pt->dst_dma;
op.dst.u.dma.offset = 0;
op.dst.u.dma.length = pt->src_len;
ret = cmd_q->ccp->vdata->perform->perform_passthru(&op);
if (ret)
cmd->engine_error = cmd_q->cmd_error;
return ret;
}
static int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
{
struct ccp_ecc_engine *ecc = &cmd->u.ecc;
......@@ -1762,7 +1826,10 @@ int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
ret = ccp_run_rsa_cmd(cmd_q, cmd);
break;
case CCP_ENGINE_PASSTHRU:
ret = ccp_run_passthru_cmd(cmd_q, cmd);
if (cmd->flags & CCP_CMD_PASSTHRU_NO_DMA_MAP)
ret = ccp_run_passthru_nomap_cmd(cmd_q, cmd);
else
ret = ccp_run_passthru_cmd(cmd_q, cmd);
break;
case CCP_ENGINE_ECC:
ret = ccp_run_ecc_cmd(cmd_q, cmd);
......
......@@ -475,18 +475,18 @@ static int mv_cesa_probe(struct platform_device *pdev)
engine->regs = cesa->regs + CESA_ENGINE_OFF(i);
if (dram && cesa->caps->has_tdma)
mv_cesa_conf_mbus_windows(&cesa->engines[i], dram);
mv_cesa_conf_mbus_windows(engine, dram);
writel(0, cesa->engines[i].regs + CESA_SA_INT_STATUS);
writel(0, engine->regs + CESA_SA_INT_STATUS);
writel(CESA_SA_CFG_STOP_DIG_ERR,
cesa->engines[i].regs + CESA_SA_CFG);
engine->regs + CESA_SA_CFG);
writel(engine->sram_dma & CESA_SA_SRAM_MSK,
cesa->engines[i].regs + CESA_SA_DESC_P0);
engine->regs + CESA_SA_DESC_P0);
ret = devm_request_threaded_irq(dev, irq, NULL, mv_cesa_int,
IRQF_ONESHOT,
dev_name(&pdev->dev),
&cesa->engines[i]);
engine);
if (ret)
goto err_cleanup;
}
......
......@@ -768,8 +768,7 @@ static int mv_cesa_ahash_export(struct ahash_request *req, void *hash,
*len = creq->len;
memcpy(hash, creq->state, digsize);
memset(cache, 0, blocksize);
if (creq->cache)
memcpy(cache, creq->cache, creq->cache_ptr);
memcpy(cache, creq->cache, creq->cache_ptr);
return 0;
}
......
......@@ -99,12 +99,11 @@ mv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags)
struct mv_cesa_tdma_desc *new_tdma = NULL;
dma_addr_t dma_handle;
new_tdma = dma_pool_alloc(cesa_dev->dma->tdma_desc_pool, flags,
&dma_handle);
new_tdma = dma_pool_zalloc(cesa_dev->dma->tdma_desc_pool, flags,
&dma_handle);
if (!new_tdma)
return ERR_PTR(-ENOMEM);
memset(new_tdma, 0, sizeof(*new_tdma));
new_tdma->cur_dma = dma_handle;
if (chain->last) {
chain->last->next_dma = cpu_to_le32(dma_handle);
......
/*
* Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
*
* The driver is based on information gathered from
* drivers/mxc/security/mxc_scc.c which can be found in
* the Freescale linux-2.6-imx.git in the imx_2.6.35_maintain branch.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* 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/crypto.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <crypto/algapi.h>
#include <crypto/des.h>
/* Secure Memory (SCM) registers */
#define SCC_SCM_RED_START 0x0000
#define SCC_SCM_BLACK_START 0x0004
#define SCC_SCM_LENGTH 0x0008
#define SCC_SCM_CTRL 0x000C
#define SCC_SCM_STATUS 0x0010
#define SCC_SCM_ERROR_STATUS 0x0014
#define SCC_SCM_INTR_CTRL 0x0018
#define SCC_SCM_CFG 0x001C
#define SCC_SCM_INIT_VECTOR_0 0x0020
#define SCC_SCM_INIT_VECTOR_1 0x0024
#define SCC_SCM_RED_MEMORY 0x0400
#define SCC_SCM_BLACK_MEMORY 0x0800
/* Security Monitor (SMN) Registers */
#define SCC_SMN_STATUS 0x1000
#define SCC_SMN_COMMAND 0x1004
#define SCC_SMN_SEQ_START 0x1008
#define SCC_SMN_SEQ_END 0x100C
#define SCC_SMN_SEQ_CHECK 0x1010
#define SCC_SMN_BIT_COUNT 0x1014
#define SCC_SMN_BITBANK_INC_SIZE 0x1018
#define SCC_SMN_BITBANK_DECREMENT 0x101C
#define SCC_SMN_COMPARE_SIZE 0x1020
#define SCC_SMN_PLAINTEXT_CHECK 0x1024
#define SCC_SMN_CIPHERTEXT_CHECK 0x1028
#define SCC_SMN_TIMER_IV 0x102C
#define SCC_SMN_TIMER_CONTROL 0x1030
#define SCC_SMN_DEBUG_DETECT_STAT 0x1034
#define SCC_SMN_TIMER 0x1038
#define SCC_SCM_CTRL_START_CIPHER BIT(2)
#define SCC_SCM_CTRL_CBC_MODE BIT(1)
#define SCC_SCM_CTRL_DECRYPT_MODE BIT(0)
#define SCC_SCM_STATUS_LEN_ERR BIT(12)
#define SCC_SCM_STATUS_SMN_UNBLOCKED BIT(11)
#define SCC_SCM_STATUS_CIPHERING_DONE BIT(10)
#define SCC_SCM_STATUS_ZEROIZING_DONE BIT(9)
#define SCC_SCM_STATUS_INTR_STATUS BIT(8)
#define SCC_SCM_STATUS_SEC_KEY BIT(7)
#define SCC_SCM_STATUS_INTERNAL_ERR BIT(6)
#define SCC_SCM_STATUS_BAD_SEC_KEY BIT(5)
#define SCC_SCM_STATUS_ZEROIZE_FAIL BIT(4)
#define SCC_SCM_STATUS_SMN_BLOCKED BIT(3)
#define SCC_SCM_STATUS_CIPHERING BIT(2)
#define SCC_SCM_STATUS_ZEROIZING BIT(1)
#define SCC_SCM_STATUS_BUSY BIT(0)
#define SCC_SMN_STATUS_STATE_MASK 0x0000001F
#define SCC_SMN_STATE_START 0x0
/* The SMN is zeroizing its RAM during reset */
#define SCC_SMN_STATE_ZEROIZE_RAM 0x5
/* SMN has passed internal checks */
#define SCC_SMN_STATE_HEALTH_CHECK 0x6
/* Fatal Security Violation. SMN is locked, SCM is inoperative. */
#define SCC_SMN_STATE_FAIL 0x9
/* SCC is in secure state. SCM is using secret key. */
#define SCC_SMN_STATE_SECURE 0xA
/* SCC is not secure. SCM is using default key. */
#define SCC_SMN_STATE_NON_SECURE 0xC
#define SCC_SCM_INTR_CTRL_ZEROIZE_MEM BIT(2)
#define SCC_SCM_INTR_CTRL_CLR_INTR BIT(1)
#define SCC_SCM_INTR_CTRL_MASK_INTR BIT(0)
/* Size, in blocks, of Red memory. */
#define SCC_SCM_CFG_BLACK_SIZE_MASK 0x07fe0000
#define SCC_SCM_CFG_BLACK_SIZE_SHIFT 17
/* Size, in blocks, of Black memory. */
#define SCC_SCM_CFG_RED_SIZE_MASK 0x0001ff80
#define SCC_SCM_CFG_RED_SIZE_SHIFT 7
/* Number of bytes per block. */
#define SCC_SCM_CFG_BLOCK_SIZE_MASK 0x0000007f
#define SCC_SMN_COMMAND_TAMPER_LOCK BIT(4)
#define SCC_SMN_COMMAND_CLR_INTR BIT(3)
#define SCC_SMN_COMMAND_CLR_BIT_BANK BIT(2)
#define SCC_SMN_COMMAND_EN_INTR BIT(1)
#define SCC_SMN_COMMAND_SET_SOFTWARE_ALARM BIT(0)
#define SCC_KEY_SLOTS 20
#define SCC_MAX_KEY_SIZE 32
#define SCC_KEY_SLOT_SIZE 32
#define SCC_CRC_CCITT_START 0xFFFF
/*
* Offset into each RAM of the base of the area which is not
* used for Stored Keys.
*/
#define SCC_NON_RESERVED_OFFSET (SCC_KEY_SLOTS * SCC_KEY_SLOT_SIZE)
/* Fixed padding for appending to plaintext to fill out a block */
static char scc_block_padding[8] = { 0x80, 0, 0, 0, 0, 0, 0, 0 };
enum mxc_scc_state {
SCC_STATE_OK,
SCC_STATE_UNIMPLEMENTED,
SCC_STATE_FAILED
};
struct mxc_scc {
struct device *dev;
void __iomem *base;
struct clk *clk;
bool hw_busy;
spinlock_t lock;
struct crypto_queue queue;
struct crypto_async_request *req;
int block_size_bytes;
int black_ram_size_blocks;
int memory_size_bytes;
int bytes_remaining;
void __iomem *red_memory;
void __iomem *black_memory;
};
struct mxc_scc_ctx {
struct mxc_scc *scc;
struct scatterlist *sg_src;
size_t src_nents;
struct scatterlist *sg_dst;
size_t dst_nents;
unsigned int offset;
unsigned int size;
unsigned int ctrl;
};
struct mxc_scc_crypto_tmpl {
struct mxc_scc *scc;
struct crypto_alg alg;
};
static int mxc_scc_get_data(struct mxc_scc_ctx *ctx,
struct crypto_async_request *req)
{
struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
struct mxc_scc *scc = ctx->scc;
size_t len;
void __iomem *from;
if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE)
from = scc->red_memory;
else
from = scc->black_memory;
dev_dbg(scc->dev, "pcopy: from 0x%p %d bytes\n", from,
ctx->dst_nents * 8);
len = sg_pcopy_from_buffer(ablkreq->dst, ctx->dst_nents,
from, ctx->size, ctx->offset);
if (!len) {
dev_err(scc->dev, "pcopy err from 0x%p (len=%d)\n", from, len);
return -EINVAL;
}
#ifdef DEBUG
print_hex_dump(KERN_ERR,
"red memory@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4,
scc->red_memory, ctx->size, 1);
print_hex_dump(KERN_ERR,
"black memory@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4,
scc->black_memory, ctx->size, 1);
#endif
ctx->offset += len;
if (ctx->offset < ablkreq->nbytes)
return -EINPROGRESS;
return 0;
}
static int mxc_scc_ablkcipher_req_init(struct ablkcipher_request *req,
struct mxc_scc_ctx *ctx)
{
struct mxc_scc *scc = ctx->scc;
int nents;
nents = sg_nents_for_len(req->src, req->nbytes);
if (nents < 0) {
dev_err(scc->dev, "Invalid number of src SC");
return nents;
}
ctx->src_nents = nents;
nents = sg_nents_for_len(req->dst, req->nbytes);
if (nents < 0) {
dev_err(scc->dev, "Invalid number of dst SC");
return nents;
}
ctx->dst_nents = nents;
ctx->size = 0;
ctx->offset = 0;
return 0;
}
static int mxc_scc_ablkcipher_req_complete(struct crypto_async_request *req,
struct mxc_scc_ctx *ctx,
int result)
{
struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
struct mxc_scc *scc = ctx->scc;
scc->req = NULL;
scc->bytes_remaining = scc->memory_size_bytes;
if (ctx->ctrl & SCC_SCM_CTRL_CBC_MODE)
memcpy(ablkreq->info, scc->base + SCC_SCM_INIT_VECTOR_0,
scc->block_size_bytes);
req->complete(req, result);
scc->hw_busy = false;
return 0;
}
static int mxc_scc_put_data(struct mxc_scc_ctx *ctx,
struct ablkcipher_request *req)
{
u8 padding_buffer[sizeof(u16) + sizeof(scc_block_padding)];
size_t len = min_t(size_t, req->nbytes - ctx->offset,
ctx->scc->bytes_remaining);
unsigned int padding_byte_count = 0;
struct mxc_scc *scc = ctx->scc;
void __iomem *to;
if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE)
to = scc->black_memory;
else
to = scc->red_memory;
if (ctx->ctrl & SCC_SCM_CTRL_CBC_MODE && req->info)
memcpy(scc->base + SCC_SCM_INIT_VECTOR_0, req->info,
scc->block_size_bytes);
len = sg_pcopy_to_buffer(req->src, ctx->src_nents,
to, len, ctx->offset);
if (!len) {
dev_err(scc->dev, "pcopy err to 0x%p (len=%d)\n", to, len);
return -EINVAL;
}
ctx->size = len;
#ifdef DEBUG
dev_dbg(scc->dev, "copied %d bytes to 0x%p\n", len, to);
print_hex_dump(KERN_ERR,
"init vector0@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4,
scc->base + SCC_SCM_INIT_VECTOR_0, scc->block_size_bytes,
1);
print_hex_dump(KERN_ERR,
"red memory@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4,
scc->red_memory, ctx->size, 1);
print_hex_dump(KERN_ERR,
"black memory@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4,
scc->black_memory, ctx->size, 1);
#endif
scc->bytes_remaining -= len;
padding_byte_count = len % scc->block_size_bytes;
if (padding_byte_count) {
memcpy(padding_buffer, scc_block_padding, padding_byte_count);
memcpy(to + len, padding_buffer, padding_byte_count);
ctx->size += padding_byte_count;
}
#ifdef DEBUG
print_hex_dump(KERN_ERR,
"data to encrypt@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4,
to, ctx->size, 1);
#endif
return 0;
}
static void mxc_scc_ablkcipher_next(struct mxc_scc_ctx *ctx,
struct crypto_async_request *req)
{
struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
struct mxc_scc *scc = ctx->scc;
int err;
dev_dbg(scc->dev, "dispatch request (nbytes=%d, src=%p, dst=%p)\n",
ablkreq->nbytes, ablkreq->src, ablkreq->dst);
writel(0, scc->base + SCC_SCM_ERROR_STATUS);
err = mxc_scc_put_data(ctx, ablkreq);
if (err) {
mxc_scc_ablkcipher_req_complete(req, ctx, err);
return;
}
dev_dbg(scc->dev, "Start encryption (0x%p/0x%p)\n",
(void *)readl(scc->base + SCC_SCM_RED_START),
(void *)readl(scc->base + SCC_SCM_BLACK_START));
/* clear interrupt control registers */
writel(SCC_SCM_INTR_CTRL_CLR_INTR,
scc->base + SCC_SCM_INTR_CTRL);
writel((ctx->size / ctx->scc->block_size_bytes) - 1,
scc->base + SCC_SCM_LENGTH);
dev_dbg(scc->dev, "Process %d block(s) in 0x%p\n",
ctx->size / ctx->scc->block_size_bytes,
(ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) ? scc->black_memory :
scc->red_memory);
writel(ctx->ctrl, scc->base + SCC_SCM_CTRL);
}
static irqreturn_t mxc_scc_int(int irq, void *priv)
{
struct crypto_async_request *req;
struct mxc_scc_ctx *ctx;
struct mxc_scc *scc = priv;
int status;
int ret;
status = readl(scc->base + SCC_SCM_STATUS);
/* clear interrupt control registers */
writel(SCC_SCM_INTR_CTRL_CLR_INTR, scc->base + SCC_SCM_INTR_CTRL);
if (status & SCC_SCM_STATUS_BUSY)
return IRQ_NONE;
req = scc->req;
if (req) {
ctx = crypto_tfm_ctx(req->tfm);
ret = mxc_scc_get_data(ctx, req);
if (ret != -EINPROGRESS)
mxc_scc_ablkcipher_req_complete(req, ctx, ret);
else
mxc_scc_ablkcipher_next(ctx, req);
}
return IRQ_HANDLED;
}
static int mxc_scc_cra_init(struct crypto_tfm *tfm)
{
struct mxc_scc_ctx *ctx = crypto_tfm_ctx(tfm);
struct crypto_alg *alg = tfm->__crt_alg;
struct mxc_scc_crypto_tmpl *algt;
algt = container_of(alg, struct mxc_scc_crypto_tmpl, alg);
ctx->scc = algt->scc;
return 0;
}
static void mxc_scc_dequeue_req_unlocked(struct mxc_scc_ctx *ctx)
{
struct crypto_async_request *req, *backlog;
if (ctx->scc->hw_busy)
return;
spin_lock_bh(&ctx->scc->lock);
backlog = crypto_get_backlog(&ctx->scc->queue);
req = crypto_dequeue_request(&ctx->scc->queue);
ctx->scc->req = req;
ctx->scc->hw_busy = true;
spin_unlock_bh(&ctx->scc->lock);
if (!req)
return;
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
mxc_scc_ablkcipher_next(ctx, req);
}
static int mxc_scc_queue_req(struct mxc_scc_ctx *ctx,
struct crypto_async_request *req)
{
int ret;
spin_lock_bh(&ctx->scc->lock);
ret = crypto_enqueue_request(&ctx->scc->queue, req);
spin_unlock_bh(&ctx->scc->lock);
if (ret != -EINPROGRESS)
return ret;
mxc_scc_dequeue_req_unlocked(ctx);
return -EINPROGRESS;
}
static int mxc_scc_des3_op(struct mxc_scc_ctx *ctx,
struct ablkcipher_request *req)
{
int err;
err = mxc_scc_ablkcipher_req_init(req, ctx);
if (err)
return err;
return mxc_scc_queue_req(ctx, &req->base);
}
static int mxc_scc_ecb_des_encrypt(struct ablkcipher_request *req)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
return mxc_scc_des3_op(ctx, req);
}
static int mxc_scc_ecb_des_decrypt(struct ablkcipher_request *req)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
ctx->ctrl |= SCC_SCM_CTRL_DECRYPT_MODE;
return mxc_scc_des3_op(ctx, req);
}
static int mxc_scc_cbc_des_encrypt(struct ablkcipher_request *req)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE;
return mxc_scc_des3_op(ctx, req);
}
static int mxc_scc_cbc_des_decrypt(struct ablkcipher_request *req)
{
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE;
ctx->ctrl |= SCC_SCM_CTRL_DECRYPT_MODE;
return mxc_scc_des3_op(ctx, req);
}
static void mxc_scc_hw_init(struct mxc_scc *scc)
{
int offset;
offset = SCC_NON_RESERVED_OFFSET / scc->block_size_bytes;
/* Fill the RED_START register */
writel(offset, scc->base + SCC_SCM_RED_START);
/* Fill the BLACK_START register */
writel(offset, scc->base + SCC_SCM_BLACK_START);
scc->red_memory = scc->base + SCC_SCM_RED_MEMORY +
SCC_NON_RESERVED_OFFSET;
scc->black_memory = scc->base + SCC_SCM_BLACK_MEMORY +
SCC_NON_RESERVED_OFFSET;
scc->bytes_remaining = scc->memory_size_bytes;
}
static int mxc_scc_get_config(struct mxc_scc *scc)
{
int config;
config = readl(scc->base + SCC_SCM_CFG);
scc->block_size_bytes = config & SCC_SCM_CFG_BLOCK_SIZE_MASK;
scc->black_ram_size_blocks = config & SCC_SCM_CFG_BLACK_SIZE_MASK;
scc->memory_size_bytes = (scc->block_size_bytes *
scc->black_ram_size_blocks) -
SCC_NON_RESERVED_OFFSET;
return 0;
}
static enum mxc_scc_state mxc_scc_get_state(struct mxc_scc *scc)
{
enum mxc_scc_state state;
int status;
status = readl(scc->base + SCC_SMN_STATUS) &
SCC_SMN_STATUS_STATE_MASK;
/* If in Health Check, try to bringup to secure state */
if (status & SCC_SMN_STATE_HEALTH_CHECK) {
/*
* Write a simple algorithm to the Algorithm Sequence
* Checker (ASC)
*/
writel(0xaaaa, scc->base + SCC_SMN_SEQ_START);
writel(0x5555, scc->base + SCC_SMN_SEQ_END);
writel(0x5555, scc->base + SCC_SMN_SEQ_CHECK);
status = readl(scc->base + SCC_SMN_STATUS) &
SCC_SMN_STATUS_STATE_MASK;
}
switch (status) {
case SCC_SMN_STATE_NON_SECURE:
case SCC_SMN_STATE_SECURE:
state = SCC_STATE_OK;
break;
case SCC_SMN_STATE_FAIL:
state = SCC_STATE_FAILED;
break;
default:
state = SCC_STATE_UNIMPLEMENTED;
break;
}
return state;
}
static struct mxc_scc_crypto_tmpl scc_ecb_des = {
.alg = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "ecb-des3-scc",
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct mxc_scc_ctx),
.cra_alignmask = 0,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = mxc_scc_cra_init,
.cra_u.ablkcipher = {
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.encrypt = mxc_scc_ecb_des_encrypt,
.decrypt = mxc_scc_ecb_des_decrypt,
}
}
};
static struct mxc_scc_crypto_tmpl scc_cbc_des = {
.alg = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "cbc-des3-scc",
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct mxc_scc_ctx),
.cra_alignmask = 0,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = mxc_scc_cra_init,
.cra_u.ablkcipher = {
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.encrypt = mxc_scc_cbc_des_encrypt,
.decrypt = mxc_scc_cbc_des_decrypt,
}
}
};
static struct mxc_scc_crypto_tmpl *scc_crypto_algs[] = {
&scc_ecb_des,
&scc_cbc_des,
};
static int mxc_scc_crypto_register(struct mxc_scc *scc)
{
int i;
int err = 0;
for (i = 0; i < ARRAY_SIZE(scc_crypto_algs); i++) {
scc_crypto_algs[i]->scc = scc;
err = crypto_register_alg(&scc_crypto_algs[i]->alg);
if (err)
goto err_out;
}
return 0;
err_out:
while (--i >= 0)
crypto_unregister_alg(&scc_crypto_algs[i]->alg);
return err;
}
static void mxc_scc_crypto_unregister(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(scc_crypto_algs); i++)
crypto_unregister_alg(&scc_crypto_algs[i]->alg);
}
static int mxc_scc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct mxc_scc *scc;
enum mxc_scc_state state;
int irq;
int ret;
int i;
scc = devm_kzalloc(dev, sizeof(*scc), GFP_KERNEL);
if (!scc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
scc->base = devm_ioremap_resource(dev, res);
if (IS_ERR(scc->base))
return PTR_ERR(scc->base);
scc->clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(scc->clk)) {
dev_err(dev, "Could not get ipg clock\n");
return PTR_ERR(scc->clk);
}
clk_prepare_enable(scc->clk);
/* clear error status register */
writel(0x0, scc->base + SCC_SCM_ERROR_STATUS);
/* clear interrupt control registers */
writel(SCC_SCM_INTR_CTRL_CLR_INTR |
SCC_SCM_INTR_CTRL_MASK_INTR,
scc->base + SCC_SCM_INTR_CTRL);
writel(SCC_SMN_COMMAND_CLR_INTR |
SCC_SMN_COMMAND_EN_INTR,
scc->base + SCC_SMN_COMMAND);
scc->dev = dev;
platform_set_drvdata(pdev, scc);
ret = mxc_scc_get_config(scc);
if (ret)
goto err_out;
state = mxc_scc_get_state(scc);
if (state != SCC_STATE_OK) {
dev_err(dev, "SCC in unusable state %d\n", state);
ret = -EINVAL;
goto err_out;
}
mxc_scc_hw_init(scc);
spin_lock_init(&scc->lock);
/* FIXME: calculate queue from RAM slots */
crypto_init_queue(&scc->queue, 50);
for (i = 0; i < 2; i++) {
irq = platform_get_irq(pdev, i);
if (irq < 0) {
dev_err(dev, "failed to get irq resource\n");
ret = -EINVAL;
goto err_out;
}
ret = devm_request_threaded_irq(dev, irq, NULL, mxc_scc_int,
IRQF_ONESHOT, dev_name(dev), scc);
if (ret)
goto err_out;
}
ret = mxc_scc_crypto_register(scc);
if (ret) {
dev_err(dev, "could not register algorithms");
goto err_out;
}
dev_info(dev, "registered successfully.\n");
return 0;
err_out:
clk_disable_unprepare(scc->clk);
return ret;
}
static int mxc_scc_remove(struct platform_device *pdev)
{
struct mxc_scc *scc = platform_get_drvdata(pdev);
mxc_scc_crypto_unregister();
clk_disable_unprepare(scc->clk);
return 0;
}
static const struct of_device_id mxc_scc_dt_ids[] = {
{ .compatible = "fsl,imx25-scc", .data = NULL, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxc_scc_dt_ids);
static struct platform_driver mxc_scc_driver = {
.probe = mxc_scc_probe,
.remove = mxc_scc_remove,
.driver = {
.name = "mxc-scc",
.of_match_table = mxc_scc_dt_ids,
},
};
module_platform_driver(mxc_scc_driver);
MODULE_AUTHOR("Steffen Trumtrar <kernel@pengutronix.de>");
MODULE_DESCRIPTION("Freescale i.MX25 SCC Crypto driver");
MODULE_LICENSE("GPL v2");
......@@ -1598,7 +1598,7 @@ static void *new_queue(unsigned long q_type)
static void free_queue(void *p, unsigned long q_type)
{
return kmem_cache_free(queue_cache[q_type - 1], p);
kmem_cache_free(queue_cache[q_type - 1], p);
}
static int queue_cache_init(void)
......
......@@ -26,7 +26,6 @@
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/omap-dma.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
......@@ -176,9 +175,7 @@ struct omap_aes_dev {
struct scatter_walk in_walk;
struct scatter_walk out_walk;
int dma_in;
struct dma_chan *dma_lch_in;
int dma_out;
struct dma_chan *dma_lch_out;
int in_sg_len;
int out_sg_len;
......@@ -351,30 +348,21 @@ static void omap_aes_dma_out_callback(void *data)
static int omap_aes_dma_init(struct omap_aes_dev *dd)
{
int err = -ENOMEM;
dma_cap_mask_t mask;
int err;
dd->dma_lch_out = NULL;
dd->dma_lch_in = NULL;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dd->dma_lch_in = dma_request_slave_channel_compat(mask,
omap_dma_filter_fn,
&dd->dma_in,
dd->dev, "rx");
if (!dd->dma_lch_in) {
dd->dma_lch_in = dma_request_chan(dd->dev, "rx");
if (IS_ERR(dd->dma_lch_in)) {
dev_err(dd->dev, "Unable to request in DMA channel\n");
goto err_dma_in;
return PTR_ERR(dd->dma_lch_in);
}
dd->dma_lch_out = dma_request_slave_channel_compat(mask,
omap_dma_filter_fn,
&dd->dma_out,
dd->dev, "tx");
if (!dd->dma_lch_out) {
dd->dma_lch_out = dma_request_chan(dd->dev, "tx");
if (IS_ERR(dd->dma_lch_out)) {
dev_err(dd->dev, "Unable to request out DMA channel\n");
err = PTR_ERR(dd->dma_lch_out);
goto err_dma_out;
}
......@@ -382,14 +370,15 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd)
err_dma_out:
dma_release_channel(dd->dma_lch_in);
err_dma_in:
if (err)
pr_err("error: %d\n", err);
return err;
}
static void omap_aes_dma_cleanup(struct omap_aes_dev *dd)
{
if (dd->pio_only)
return;
dma_release_channel(dd->dma_lch_out);
dma_release_channel(dd->dma_lch_in);
}
......@@ -1080,9 +1069,6 @@ static int omap_aes_get_res_of(struct omap_aes_dev *dd,
goto err;
}
dd->dma_out = -1; /* Dummy value that's unused */
dd->dma_in = -1; /* Dummy value that's unused */
dd->pdata = match->data;
err:
......@@ -1116,24 +1102,6 @@ static int omap_aes_get_res_pdev(struct omap_aes_dev *dd,
}
memcpy(res, r, sizeof(*res));
/* Get the DMA out channel */
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) {
dev_err(dev, "no DMA out resource info\n");
err = -ENODEV;
goto err;
}
dd->dma_out = r->start;
/* Get the DMA in channel */
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) {
dev_err(dev, "no DMA in resource info\n");
err = -ENODEV;
goto err;
}
dd->dma_in = r->start;
/* Only OMAP2/3 can be non-DT */
dd->pdata = &omap_aes_pdata_omap2;
......@@ -1191,7 +1159,9 @@ static int omap_aes_probe(struct platform_device *pdev)
tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd);
err = omap_aes_dma_init(dd);
if (err && AES_REG_IRQ_STATUS(dd) && AES_REG_IRQ_ENABLE(dd)) {
if (err == -EPROBE_DEFER) {
goto err_irq;
} else if (err && AES_REG_IRQ_STATUS(dd) && AES_REG_IRQ_ENABLE(dd)) {
dd->pio_only = 1;
irq = platform_get_irq(pdev, 0);
......@@ -1248,8 +1218,8 @@ static int omap_aes_probe(struct platform_device *pdev)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
crypto_unregister_alg(
&dd->pdata->algs_info[i].algs_list[j]);
if (!dd->pio_only)
omap_aes_dma_cleanup(dd);
omap_aes_dma_cleanup(dd);
err_irq:
tasklet_kill(&dd->done_task);
pm_runtime_disable(dev);
......
......@@ -29,7 +29,6 @@
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/omap-dma.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
......@@ -39,6 +38,7 @@
#include <linux/interrupt.h>
#include <crypto/scatterwalk.h>
#include <crypto/des.h>
#include <crypto/algapi.h>
#define DST_MAXBURST 2
......@@ -132,14 +132,10 @@ struct omap_des_dev {
unsigned long flags;
int err;
/* spinlock used for queues */
spinlock_t lock;
struct crypto_queue queue;
struct tasklet_struct done_task;
struct tasklet_struct queue_task;
struct ablkcipher_request *req;
struct crypto_engine *engine;
/*
* total is used by PIO mode for book keeping so introduce
* variable total_save as need it to calc page_order
......@@ -158,9 +154,7 @@ struct omap_des_dev {
struct scatter_walk in_walk;
struct scatter_walk out_walk;
int dma_in;
struct dma_chan *dma_lch_in;
int dma_out;
struct dma_chan *dma_lch_out;
int in_sg_len;
int out_sg_len;
......@@ -340,30 +334,21 @@ static void omap_des_dma_out_callback(void *data)
static int omap_des_dma_init(struct omap_des_dev *dd)
{
int err = -ENOMEM;
dma_cap_mask_t mask;
int err;
dd->dma_lch_out = NULL;
dd->dma_lch_in = NULL;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dd->dma_lch_in = dma_request_slave_channel_compat(mask,
omap_dma_filter_fn,
&dd->dma_in,
dd->dev, "rx");
if (!dd->dma_lch_in) {
dd->dma_lch_in = dma_request_chan(dd->dev, "rx");
if (IS_ERR(dd->dma_lch_in)) {
dev_err(dd->dev, "Unable to request in DMA channel\n");
goto err_dma_in;
return PTR_ERR(dd->dma_lch_in);
}
dd->dma_lch_out = dma_request_slave_channel_compat(mask,
omap_dma_filter_fn,
&dd->dma_out,
dd->dev, "tx");
if (!dd->dma_lch_out) {
dd->dma_lch_out = dma_request_chan(dd->dev, "tx");
if (IS_ERR(dd->dma_lch_out)) {
dev_err(dd->dev, "Unable to request out DMA channel\n");
err = PTR_ERR(dd->dma_lch_out);
goto err_dma_out;
}
......@@ -371,14 +356,15 @@ static int omap_des_dma_init(struct omap_des_dev *dd)
err_dma_out:
dma_release_channel(dd->dma_lch_in);
err_dma_in:
if (err)
pr_err("error: %d\n", err);
return err;
}
static void omap_des_dma_cleanup(struct omap_des_dev *dd)
{
if (dd->pio_only)
return;
dma_release_channel(dd->dma_lch_out);
dma_release_channel(dd->dma_lch_in);
}
......@@ -520,9 +506,7 @@ static void omap_des_finish_req(struct omap_des_dev *dd, int err)
pr_debug("err: %d\n", err);
pm_runtime_put(dd->dev);
dd->flags &= ~FLAGS_BUSY;
req->base.complete(&req->base, err);
crypto_finalize_request(dd->engine, req, err);
}
static int omap_des_crypt_dma_stop(struct omap_des_dev *dd)
......@@ -585,34 +569,24 @@ static int omap_des_copy_sgs(struct omap_des_dev *dd)
}
static int omap_des_handle_queue(struct omap_des_dev *dd,
struct ablkcipher_request *req)
struct ablkcipher_request *req)
{
struct crypto_async_request *async_req, *backlog;
struct omap_des_ctx *ctx;
struct omap_des_reqctx *rctx;
unsigned long flags;
int err, ret = 0;
spin_lock_irqsave(&dd->lock, flags);
if (req)
ret = ablkcipher_enqueue_request(&dd->queue, req);
if (dd->flags & FLAGS_BUSY) {
spin_unlock_irqrestore(&dd->lock, flags);
return ret;
}
backlog = crypto_get_backlog(&dd->queue);
async_req = crypto_dequeue_request(&dd->queue);
if (async_req)
dd->flags |= FLAGS_BUSY;
spin_unlock_irqrestore(&dd->lock, flags);
return crypto_transfer_request_to_engine(dd->engine, req);
if (!async_req)
return ret;
return 0;
}
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
static int omap_des_prepare_req(struct crypto_engine *engine,
struct ablkcipher_request *req)
{
struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
struct omap_des_dev *dd = omap_des_find_dev(ctx);
struct omap_des_reqctx *rctx;
req = ablkcipher_request_cast(async_req);
if (!dd)
return -ENODEV;
/* assign new request to device */
dd->req = req;
......@@ -642,16 +616,20 @@ static int omap_des_handle_queue(struct omap_des_dev *dd,
dd->ctx = ctx;
ctx->dd = dd;
err = omap_des_write_ctrl(dd);
if (!err)
err = omap_des_crypt_dma_start(dd);
if (err) {
/* des_task will not finish it, so do it here */
omap_des_finish_req(dd, err);
tasklet_schedule(&dd->queue_task);
}
return omap_des_write_ctrl(dd);
}
static int omap_des_crypt_req(struct crypto_engine *engine,
struct ablkcipher_request *req)
{
struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
struct omap_des_dev *dd = omap_des_find_dev(ctx);
if (!dd)
return -ENODEV;
return ret; /* return ret, which is enqueue return value */
return omap_des_crypt_dma_start(dd);
}
static void omap_des_done_task(unsigned long data)
......@@ -683,18 +661,10 @@ static void omap_des_done_task(unsigned long data)
}
omap_des_finish_req(dd, 0);
omap_des_handle_queue(dd, NULL);
pr_debug("exit\n");
}
static void omap_des_queue_task(unsigned long data)
{
struct omap_des_dev *dd = (struct omap_des_dev *)data;
omap_des_handle_queue(dd, NULL);
}
static int omap_des_crypt(struct ablkcipher_request *req, unsigned long mode)
{
struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
......@@ -999,8 +969,6 @@ static int omap_des_get_of(struct omap_des_dev *dd,
return -EINVAL;
}
dd->dma_out = -1; /* Dummy value that's unused */
dd->dma_in = -1; /* Dummy value that's unused */
dd->pdata = match->data;
return 0;
......@@ -1016,33 +984,10 @@ static int omap_des_get_of(struct omap_des_dev *dd,
static int omap_des_get_pdev(struct omap_des_dev *dd,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *r;
int err = 0;
/* Get the DMA out channel */
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) {
dev_err(dev, "no DMA out resource info\n");
err = -ENODEV;
goto err;
}
dd->dma_out = r->start;
/* Get the DMA in channel */
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) {
dev_err(dev, "no DMA in resource info\n");
err = -ENODEV;
goto err;
}
dd->dma_in = r->start;
/* non-DT devices get pdata from pdev */
dd->pdata = pdev->dev.platform_data;
err:
return err;
return 0;
}
static int omap_des_probe(struct platform_device *pdev)
......@@ -1062,9 +1007,6 @@ static int omap_des_probe(struct platform_device *pdev)
dd->dev = dev;
platform_set_drvdata(pdev, dd);
spin_lock_init(&dd->lock);
crypto_init_queue(&dd->queue, OMAP_DES_QUEUE_LENGTH);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "no MEM resource info\n");
......@@ -1103,10 +1045,11 @@ static int omap_des_probe(struct platform_device *pdev)
(reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd);
tasklet_init(&dd->queue_task, omap_des_queue_task, (unsigned long)dd);
err = omap_des_dma_init(dd);
if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) {
if (err == -EPROBE_DEFER) {
goto err_irq;
} else if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) {
dd->pio_only = 1;
irq = platform_get_irq(pdev, 0);
......@@ -1144,17 +1087,30 @@ static int omap_des_probe(struct platform_device *pdev)
}
}
/* Initialize des crypto engine */
dd->engine = crypto_engine_alloc_init(dev, 1);
if (!dd->engine)
goto err_algs;
dd->engine->prepare_request = omap_des_prepare_req;
dd->engine->crypt_one_request = omap_des_crypt_req;
err = crypto_engine_start(dd->engine);
if (err)
goto err_engine;
return 0;
err_engine:
crypto_engine_exit(dd->engine);
err_algs:
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
crypto_unregister_alg(
&dd->pdata->algs_info[i].algs_list[j]);
if (!dd->pio_only)
omap_des_dma_cleanup(dd);
omap_des_dma_cleanup(dd);
err_irq:
tasklet_kill(&dd->done_task);
tasklet_kill(&dd->queue_task);
err_get:
pm_runtime_disable(dev);
err_res:
......@@ -1182,7 +1138,6 @@ static int omap_des_remove(struct platform_device *pdev)
&dd->pdata->algs_info[i].algs_list[j]);
tasklet_kill(&dd->done_task);
tasklet_kill(&dd->queue_task);
omap_des_dma_cleanup(dd);
pm_runtime_disable(dd->dev);
dd = NULL;
......
......@@ -29,7 +29,6 @@
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/omap-dma.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
......@@ -219,7 +218,6 @@ struct omap_sham_dev {
int irq;
spinlock_t lock;
int err;
unsigned int dma;
struct dma_chan *dma_lch;
struct tasklet_struct done_task;
u8 polling_mode;
......@@ -1842,7 +1840,6 @@ static int omap_sham_get_res_of(struct omap_sham_dev *dd,
goto err;
}
dd->dma = -1; /* Dummy value that's unused */
dd->pdata = match->data;
err:
......@@ -1884,15 +1881,6 @@ static int omap_sham_get_res_pdev(struct omap_sham_dev *dd,
goto err;
}
/* Get the DMA */
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) {
dev_err(dev, "no DMA resource info\n");
err = -ENODEV;
goto err;
}
dd->dma = r->start;
/* Only OMAP2/3 can be non-DT */
dd->pdata = &omap_sham_pdata_omap2;
......@@ -1946,9 +1934,12 @@ static int omap_sham_probe(struct platform_device *pdev)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dd->dma_lch = dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
&dd->dma, dev, "rx");
if (!dd->dma_lch) {
dd->dma_lch = dma_request_chan(dev, "rx");
if (IS_ERR(dd->dma_lch)) {
err = PTR_ERR(dd->dma_lch);
if (err == -EPROBE_DEFER)
goto data_err;
dd->polling_mode = 1;
dev_dbg(dev, "using polling mode instead of dma\n");
}
......@@ -1995,7 +1986,7 @@ static int omap_sham_probe(struct platform_device *pdev)
&dd->pdata->algs_info[i].algs_list[j]);
err_pm:
pm_runtime_disable(dev);
if (dd->dma_lch)
if (dd->polling_mode)
dma_release_channel(dd->dma_lch);
data_err:
dev_err(dev, "initialization failed.\n");
......@@ -2021,7 +2012,7 @@ static int omap_sham_remove(struct platform_device *pdev)
tasklet_kill(&dd->done_task);
pm_runtime_disable(&pdev->dev);
if (dd->dma_lch)
if (!dd->polling_mode)
dma_release_channel(dd->dma_lch);
return 0;
......
......@@ -300,9 +300,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n");
return;
}
if (adf_dev_stop(accel_dev))
dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
adf_disable_aer(accel_dev);
adf_cleanup_accel(accel_dev);
......
......@@ -109,29 +109,6 @@ static void adf_vf_void_noop(struct adf_accel_dev *accel_dev)
{
}
static int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
if (adf_iov_putmsg(accel_dev, msg, 0)) {
dev_err(&GET_DEV(accel_dev),
"Failed to send Init event to PF\n");
return -EFAULT;
}
return 0;
}
static void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
if (adf_iov_putmsg(accel_dev, msg, 0))
dev_err(&GET_DEV(accel_dev),
"Failed to send Shutdown event to PF\n");
}
void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data)
{
hw_data->dev_class = &c3xxxiov_class;
......
......@@ -238,6 +238,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto out_err_free_reg;
set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
ret = adf_dev_init(accel_dev);
if (ret)
goto out_err_dev_shutdown;
......@@ -270,9 +272,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n");
return;
}
if (adf_dev_stop(accel_dev))
dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
adf_cleanup_accel(accel_dev);
adf_cleanup_pci_dev(accel_dev);
......
......@@ -300,9 +300,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n");
return;
}
if (adf_dev_stop(accel_dev))
dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
adf_disable_aer(accel_dev);
adf_cleanup_accel(accel_dev);
......
......@@ -109,29 +109,6 @@ static void adf_vf_void_noop(struct adf_accel_dev *accel_dev)
{
}
static int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
if (adf_iov_putmsg(accel_dev, msg, 0)) {
dev_err(&GET_DEV(accel_dev),
"Failed to send Init event to PF\n");
return -EFAULT;
}
return 0;
}
static void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
if (adf_iov_putmsg(accel_dev, msg, 0))
dev_err(&GET_DEV(accel_dev),
"Failed to send Shutdown event to PF\n");
}
void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data)
{
hw_data->dev_class = &c62xiov_class;
......
......@@ -238,6 +238,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto out_err_free_reg;
set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
ret = adf_dev_init(accel_dev);
if (ret)
goto out_err_dev_shutdown;
......@@ -270,9 +272,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n");
return;
}
if (adf_dev_stop(accel_dev))
dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
adf_cleanup_accel(accel_dev);
adf_cleanup_pci_dev(accel_dev);
......
......@@ -9,7 +9,6 @@ clean-files += qat_rsaprivkey-asn1.c qat_rsaprivkey-asn1.h
obj-$(CONFIG_CRYPTO_DEV_QAT) += intel_qat.o
intel_qat-objs := adf_cfg.o \
adf_isr.o \
adf_vf_isr.o \
adf_ctl_drv.o \
adf_dev_mgr.o \
adf_init.o \
......@@ -27,4 +26,5 @@ intel_qat-objs := adf_cfg.o \
qat_hal.o
intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o
intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o
intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o \
adf_vf2pf_msg.o adf_vf_isr.o
......@@ -61,7 +61,7 @@
#define ADF_DH895XCC_MAILBOX_STRIDE 0x1000
#define ADF_ADMINMSG_LEN 32
static const u8 const_tab[1024] = {
static const u8 const_tab[1024] __aligned(1024) = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
......
......@@ -57,10 +57,8 @@
#define ADF_RING_DC_SIZE "NumConcurrentRequests"
#define ADF_RING_ASYM_TX "RingAsymTx"
#define ADF_RING_SYM_TX "RingSymTx"
#define ADF_RING_RND_TX "RingNrbgTx"
#define ADF_RING_ASYM_RX "RingAsymRx"
#define ADF_RING_SYM_RX "RingSymRx"
#define ADF_RING_RND_RX "RingNrbgRx"
#define ADF_RING_DC_TX "RingTx"
#define ADF_RING_DC_RX "RingRx"
#define ADF_ETRMGR_BANK "Bank"
......
......@@ -67,7 +67,7 @@
#define ADF_STATUS_AE_INITIALISED 4
#define ADF_STATUS_AE_UCODE_LOADED 5
#define ADF_STATUS_AE_STARTED 6
#define ADF_STATUS_ORPHAN_TH_RUNNING 7
#define ADF_STATUS_PF_RUNNING 7
#define ADF_STATUS_IRQ_ALLOCATED 8
enum adf_dev_reset_mode {
......@@ -103,7 +103,7 @@ int adf_service_unregister(struct service_hndl *service);
int adf_dev_init(struct adf_accel_dev *accel_dev);
int adf_dev_start(struct adf_accel_dev *accel_dev);
int adf_dev_stop(struct adf_accel_dev *accel_dev);
void adf_dev_stop(struct adf_accel_dev *accel_dev);
void adf_dev_shutdown(struct adf_accel_dev *accel_dev);
int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr);
......@@ -236,8 +236,13 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,
uint32_t vf_mask);
void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev);
void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev);
int adf_vf2pf_init(struct adf_accel_dev *accel_dev);
void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev);
int adf_init_pf_wq(void);
void adf_exit_pf_wq(void);
int adf_init_vf_wq(void);
void adf_exit_vf_wq(void);
#else
static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs)
{
......@@ -256,6 +261,15 @@ static inline void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev)
{
}
static inline int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
{
return 0;
}
static inline void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
{
}
static inline int adf_init_pf_wq(void)
{
return 0;
......@@ -264,5 +278,15 @@ static inline int adf_init_pf_wq(void)
static inline void adf_exit_pf_wq(void)
{
}
static inline int adf_init_vf_wq(void)
{
return 0;
}
static inline void adf_exit_vf_wq(void)
{
}
#endif
#endif
......@@ -270,26 +270,33 @@ static int adf_ctl_is_device_in_use(int id)
return 0;
}
static int adf_ctl_stop_devices(uint32_t id)
static void adf_ctl_stop_devices(uint32_t id)
{
struct adf_accel_dev *accel_dev;
int ret = 0;
list_for_each_entry_reverse(accel_dev, adf_devmgr_get_head(), list) {
list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) {
if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) {
if (!adf_dev_started(accel_dev))
continue;
if (adf_dev_stop(accel_dev)) {
dev_err(&GET_DEV(accel_dev),
"Failed to stop qat_dev%d\n", id);
ret = -EFAULT;
} else {
adf_dev_shutdown(accel_dev);
}
/* First stop all VFs */
if (!accel_dev->is_vf)
continue;
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
}
}
list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) {
if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) {
if (!adf_dev_started(accel_dev))
continue;
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
}
}
return ret;
}
static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd,
......@@ -318,9 +325,8 @@ static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd,
pr_info("QAT: Stopping acceleration device qat_dev%d.\n",
ctl_data->device_id);
ret = adf_ctl_stop_devices(ctl_data->device_id);
if (ret)
pr_err("QAT: failed to stop device.\n");
adf_ctl_stop_devices(ctl_data->device_id);
out:
kfree(ctl_data);
return ret;
......@@ -465,12 +471,17 @@ static int __init adf_register_ctl_device_driver(void)
if (adf_init_pf_wq())
goto err_pf_wq;
if (adf_init_vf_wq())
goto err_vf_wq;
if (qat_crypto_register())
goto err_crypto_register;
return 0;
err_crypto_register:
adf_exit_vf_wq();
err_vf_wq:
adf_exit_pf_wq();
err_pf_wq:
adf_exit_aer();
......@@ -485,6 +496,7 @@ static void __exit adf_unregister_ctl_device_driver(void)
{
adf_chr_drv_destroy();
adf_exit_aer();
adf_exit_vf_wq();
adf_exit_pf_wq();
qat_crypto_unregister();
adf_clean_vf_map(false);
......
......@@ -236,9 +236,9 @@ EXPORT_SYMBOL_GPL(adf_dev_start);
* is shuting down.
* To be used by QAT device specific drivers.
*
* Return: 0 on success, error code otherwise.
* Return: void
*/
int adf_dev_stop(struct adf_accel_dev *accel_dev)
void adf_dev_stop(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
struct list_head *list_itr;
......@@ -246,9 +246,9 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev)
int ret;
if (!adf_dev_started(accel_dev) &&
!test_bit(ADF_STATUS_STARTING, &accel_dev->status)) {
return 0;
}
!test_bit(ADF_STATUS_STARTING, &accel_dev->status))
return;
clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
......@@ -279,8 +279,6 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev)
else
clear_bit(ADF_STATUS_AE_STARTED, &accel_dev->status);
}
return 0;
}
EXPORT_SYMBOL_GPL(adf_dev_stop);
......@@ -329,6 +327,8 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
clear_bit(accel_dev->accel_id, &service->init_status);
}
hw_data->disable_iov(accel_dev);
if (test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status)) {
hw_data->free_irq(accel_dev);
clear_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status);
......@@ -344,7 +344,6 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
if (hw_data->exit_admin_comms)
hw_data->exit_admin_comms(accel_dev);
hw_data->disable_iov(accel_dev);
adf_cleanup_etr_data(accel_dev);
adf_dev_restore(accel_dev);
}
......
......@@ -302,7 +302,7 @@ static void adf_cleanup_bh(struct adf_accel_dev *accel_dev)
}
/**
* adf_vf_isr_resource_free() - Free IRQ for acceleration device
* adf_isr_resource_free() - Free IRQ for acceleration device
* @accel_dev: Pointer to acceleration device.
*
* Function frees interrupts for acceleration device.
......@@ -317,7 +317,7 @@ void adf_isr_resource_free(struct adf_accel_dev *accel_dev)
EXPORT_SYMBOL_GPL(adf_isr_resource_free);
/**
* adf_vf_isr_resource_alloc() - Allocate IRQ for acceleration device
* adf_isr_resource_alloc() - Allocate IRQ for acceleration device
* @accel_dev: Pointer to acceleration device.
*
* Function allocates interrupts for acceleration device.
......
......@@ -249,13 +249,7 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs)
return -EBUSY;
}
if (adf_dev_stop(accel_dev)) {
dev_err(&GET_DEV(accel_dev),
"Failed to stop qat_dev%d\n",
accel_dev->accel_id);
return -EFAULT;
}
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
}
......
/*
This file is provided under a dual BSD/GPLv2 license. When using or
redistributing this file, you may do so under either license.
GPL LICENSE SUMMARY
Copyright(c) 2015 Intel Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License 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.
Contact Information:
qat-linux@intel.com
BSD LICENSE
Copyright(c) 2015 Intel Corporation.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "adf_accel_devices.h"
#include "adf_common_drv.h"
#include "adf_pf2vf_msg.h"
/**
* adf_vf2pf_init() - send init msg to PF
* @accel_dev: Pointer to acceleration VF device.
*
* Function sends an init messge from the VF to a PF
*
* Return: 0 on success, error code otherwise.
*/
int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
if (adf_iov_putmsg(accel_dev, msg, 0)) {
dev_err(&GET_DEV(accel_dev),
"Failed to send Init event to PF\n");
return -EFAULT;
}
set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
return 0;
}
EXPORT_SYMBOL_GPL(adf_vf2pf_init);
/**
* adf_vf2pf_shutdown() - send shutdown msg to PF
* @accel_dev: Pointer to acceleration VF device.
*
* Function sends a shutdown messge from the VF to a PF
*
* Return: void
*/
void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
if (test_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status))
if (adf_iov_putmsg(accel_dev, msg, 0))
dev_err(&GET_DEV(accel_dev),
"Failed to send Shutdown event to PF\n");
}
EXPORT_SYMBOL_GPL(adf_vf2pf_shutdown);
......@@ -51,6 +51,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include "adf_accel_devices.h"
#include "adf_common_drv.h"
#include "adf_cfg.h"
......@@ -64,6 +65,13 @@
#define ADF_VINTSOU_BUN BIT(0)
#define ADF_VINTSOU_PF2VF BIT(1)
static struct workqueue_struct *adf_vf_stop_wq;
struct adf_vf_stop_data {
struct adf_accel_dev *accel_dev;
struct work_struct work;
};
static int adf_enable_msi(struct adf_accel_dev *accel_dev)
{
struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
......@@ -90,6 +98,20 @@ static void adf_disable_msi(struct adf_accel_dev *accel_dev)
pci_disable_msi(pdev);
}
static void adf_dev_stop_async(struct work_struct *work)
{
struct adf_vf_stop_data *stop_data =
container_of(work, struct adf_vf_stop_data, work);
struct adf_accel_dev *accel_dev = stop_data->accel_dev;
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
/* Re-enable PF2VF interrupts */
adf_enable_pf2vf_interrupts(accel_dev);
kfree(stop_data);
}
static void adf_pf2vf_bh_handler(void *data)
{
struct adf_accel_dev *accel_dev = data;
......@@ -107,11 +129,29 @@ static void adf_pf2vf_bh_handler(void *data)
goto err;
switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) {
case ADF_PF2VF_MSGTYPE_RESTARTING:
case ADF_PF2VF_MSGTYPE_RESTARTING: {
struct adf_vf_stop_data *stop_data;
dev_dbg(&GET_DEV(accel_dev),
"Restarting msg received from PF 0x%x\n", msg);
adf_dev_stop(accel_dev);
break;
clear_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
stop_data = kzalloc(sizeof(*stop_data), GFP_ATOMIC);
if (!stop_data) {
dev_err(&GET_DEV(accel_dev),
"Couldn't schedule stop for vf_%d\n",
accel_dev->accel_id);
return;
}
stop_data->accel_dev = accel_dev;
INIT_WORK(&stop_data->work, adf_dev_stop_async);
queue_work(adf_vf_stop_wq, &stop_data->work);
/* To ack, clear the PF2VFINT bit */
msg &= ~BIT(0);
ADF_CSR_WR(pmisc_bar_addr, hw_data->get_pf2vf_offset(0), msg);
return;
}
case ADF_PF2VF_MSGTYPE_VERSION_RESP:
dev_dbg(&GET_DEV(accel_dev),
"Version resp received from PF 0x%x\n", msg);
......@@ -278,3 +318,18 @@ int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev)
return -EFAULT;
}
EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc);
int __init adf_init_vf_wq(void)
{
adf_vf_stop_wq = create_workqueue("adf_vf_stop_wq");
return !adf_vf_stop_wq ? -EFAULT : 0;
}
void adf_exit_vf_wq(void)
{
if (adf_vf_stop_wq)
destroy_workqueue(adf_vf_stop_wq);
adf_vf_stop_wq = NULL;
}
......@@ -593,7 +593,7 @@ int qat_rsa_get_d(void *context, size_t hdrlen, unsigned char tag,
ret = -ENOMEM;
ctx->d = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_d, GFP_KERNEL);
if (!ctx->n)
if (!ctx->d)
goto err;
memcpy(ctx->d + (ctx->key_sz - vlen), ptr, vlen);
......@@ -711,7 +711,7 @@ static void qat_rsa_exit_tfm(struct crypto_akcipher *tfm)
}
qat_crypto_put_instance(ctx->inst);
ctx->n = NULL;
ctx->d = NULL;
ctx->e = NULL;
ctx->d = NULL;
}
......
......@@ -302,9 +302,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n");
return;
}
if (adf_dev_stop(accel_dev))
dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
adf_disable_aer(accel_dev);
adf_cleanup_accel(accel_dev);
......
......@@ -109,29 +109,6 @@ static void adf_vf_void_noop(struct adf_accel_dev *accel_dev)
{
}
static int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
if (adf_iov_putmsg(accel_dev, msg, 0)) {
dev_err(&GET_DEV(accel_dev),
"Failed to send Init event to PF\n");
return -EFAULT;
}
return 0;
}
static void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
{
u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
(ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
if (adf_iov_putmsg(accel_dev, msg, 0))
dev_err(&GET_DEV(accel_dev),
"Failed to send Shutdown event to PF\n");
}
void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data)
{
hw_data->dev_class = &dh895xcciov_class;
......
......@@ -238,6 +238,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto out_err_free_reg;
set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
ret = adf_dev_init(accel_dev);
if (ret)
goto out_err_dev_shutdown;
......@@ -270,9 +272,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n");
return;
}
if (adf_dev_stop(accel_dev))
dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev);
adf_cleanup_accel(accel_dev);
adf_cleanup_pci_dev(accel_dev);
......
......@@ -11,65 +11,64 @@
*
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/crypto.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/crypto.h>
#include <linux/interrupt.h>
#include <crypto/algapi.h>
#include <crypto/aes.h>
#include <crypto/ctr.h>
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/scatterwalk.h>
#define _SBF(s, v) ((v) << (s))
#define _BIT(b) _SBF(b, 1)
/* Feed control registers */
#define SSS_REG_FCINTSTAT 0x0000
#define SSS_FCINTSTAT_BRDMAINT _BIT(3)
#define SSS_FCINTSTAT_BTDMAINT _BIT(2)
#define SSS_FCINTSTAT_HRDMAINT _BIT(1)
#define SSS_FCINTSTAT_PKDMAINT _BIT(0)
#define SSS_FCINTSTAT_BRDMAINT BIT(3)
#define SSS_FCINTSTAT_BTDMAINT BIT(2)
#define SSS_FCINTSTAT_HRDMAINT BIT(1)
#define SSS_FCINTSTAT_PKDMAINT BIT(0)
#define SSS_REG_FCINTENSET 0x0004
#define SSS_FCINTENSET_BRDMAINTENSET _BIT(3)
#define SSS_FCINTENSET_BTDMAINTENSET _BIT(2)
#define SSS_FCINTENSET_HRDMAINTENSET _BIT(1)
#define SSS_FCINTENSET_PKDMAINTENSET _BIT(0)
#define SSS_FCINTENSET_BRDMAINTENSET BIT(3)
#define SSS_FCINTENSET_BTDMAINTENSET BIT(2)
#define SSS_FCINTENSET_HRDMAINTENSET BIT(1)
#define SSS_FCINTENSET_PKDMAINTENSET BIT(0)
#define SSS_REG_FCINTENCLR 0x0008
#define SSS_FCINTENCLR_BRDMAINTENCLR _BIT(3)
#define SSS_FCINTENCLR_BTDMAINTENCLR _BIT(2)
#define SSS_FCINTENCLR_HRDMAINTENCLR _BIT(1)
#define SSS_FCINTENCLR_PKDMAINTENCLR _BIT(0)
#define SSS_FCINTENCLR_BRDMAINTENCLR BIT(3)
#define SSS_FCINTENCLR_BTDMAINTENCLR BIT(2)
#define SSS_FCINTENCLR_HRDMAINTENCLR BIT(1)
#define SSS_FCINTENCLR_PKDMAINTENCLR BIT(0)
#define SSS_REG_FCINTPEND 0x000C
#define SSS_FCINTPEND_BRDMAINTP _BIT(3)
#define SSS_FCINTPEND_BTDMAINTP _BIT(2)
#define SSS_FCINTPEND_HRDMAINTP _BIT(1)
#define SSS_FCINTPEND_PKDMAINTP _BIT(0)
#define SSS_FCINTPEND_BRDMAINTP BIT(3)
#define SSS_FCINTPEND_BTDMAINTP BIT(2)
#define SSS_FCINTPEND_HRDMAINTP BIT(1)
#define SSS_FCINTPEND_PKDMAINTP BIT(0)
#define SSS_REG_FCFIFOSTAT 0x0010
#define SSS_FCFIFOSTAT_BRFIFOFUL _BIT(7)
#define SSS_FCFIFOSTAT_BRFIFOEMP _BIT(6)
#define SSS_FCFIFOSTAT_BTFIFOFUL _BIT(5)
#define SSS_FCFIFOSTAT_BTFIFOEMP _BIT(4)
#define SSS_FCFIFOSTAT_HRFIFOFUL _BIT(3)
#define SSS_FCFIFOSTAT_HRFIFOEMP _BIT(2)
#define SSS_FCFIFOSTAT_PKFIFOFUL _BIT(1)
#define SSS_FCFIFOSTAT_PKFIFOEMP _BIT(0)
#define SSS_FCFIFOSTAT_BRFIFOFUL BIT(7)
#define SSS_FCFIFOSTAT_BRFIFOEMP BIT(6)
#define SSS_FCFIFOSTAT_BTFIFOFUL BIT(5)
#define SSS_FCFIFOSTAT_BTFIFOEMP BIT(4)
#define SSS_FCFIFOSTAT_HRFIFOFUL BIT(3)
#define SSS_FCFIFOSTAT_HRFIFOEMP BIT(2)
#define SSS_FCFIFOSTAT_PKFIFOFUL BIT(1)
#define SSS_FCFIFOSTAT_PKFIFOEMP BIT(0)
#define SSS_REG_FCFIFOCTRL 0x0014
#define SSS_FCFIFOCTRL_DESSEL _BIT(2)
#define SSS_FCFIFOCTRL_DESSEL BIT(2)
#define SSS_HASHIN_INDEPENDENT _SBF(0, 0x00)
#define SSS_HASHIN_CIPHER_INPUT _SBF(0, 0x01)
#define SSS_HASHIN_CIPHER_OUTPUT _SBF(0, 0x02)
......@@ -77,52 +76,52 @@
#define SSS_REG_FCBRDMAS 0x0020
#define SSS_REG_FCBRDMAL 0x0024
#define SSS_REG_FCBRDMAC 0x0028
#define SSS_FCBRDMAC_BYTESWAP _BIT(1)
#define SSS_FCBRDMAC_FLUSH _BIT(0)
#define SSS_FCBRDMAC_BYTESWAP BIT(1)
#define SSS_FCBRDMAC_FLUSH BIT(0)
#define SSS_REG_FCBTDMAS 0x0030
#define SSS_REG_FCBTDMAL 0x0034
#define SSS_REG_FCBTDMAC 0x0038
#define SSS_FCBTDMAC_BYTESWAP _BIT(1)
#define SSS_FCBTDMAC_FLUSH _BIT(0)
#define SSS_FCBTDMAC_BYTESWAP BIT(1)
#define SSS_FCBTDMAC_FLUSH BIT(0)
#define SSS_REG_FCHRDMAS 0x0040
#define SSS_REG_FCHRDMAL 0x0044
#define SSS_REG_FCHRDMAC 0x0048
#define SSS_FCHRDMAC_BYTESWAP _BIT(1)
#define SSS_FCHRDMAC_FLUSH _BIT(0)
#define SSS_FCHRDMAC_BYTESWAP BIT(1)
#define SSS_FCHRDMAC_FLUSH BIT(0)
#define SSS_REG_FCPKDMAS 0x0050
#define SSS_REG_FCPKDMAL 0x0054
#define SSS_REG_FCPKDMAC 0x0058
#define SSS_FCPKDMAC_BYTESWAP _BIT(3)
#define SSS_FCPKDMAC_DESCEND _BIT(2)
#define SSS_FCPKDMAC_TRANSMIT _BIT(1)
#define SSS_FCPKDMAC_FLUSH _BIT(0)
#define SSS_FCPKDMAC_BYTESWAP BIT(3)
#define SSS_FCPKDMAC_DESCEND BIT(2)
#define SSS_FCPKDMAC_TRANSMIT BIT(1)
#define SSS_FCPKDMAC_FLUSH BIT(0)
#define SSS_REG_FCPKDMAO 0x005C
/* AES registers */
#define SSS_REG_AES_CONTROL 0x00
#define SSS_AES_BYTESWAP_DI _BIT(11)
#define SSS_AES_BYTESWAP_DO _BIT(10)
#define SSS_AES_BYTESWAP_IV _BIT(9)
#define SSS_AES_BYTESWAP_CNT _BIT(8)
#define SSS_AES_BYTESWAP_KEY _BIT(7)
#define SSS_AES_KEY_CHANGE_MODE _BIT(6)
#define SSS_AES_BYTESWAP_DI BIT(11)
#define SSS_AES_BYTESWAP_DO BIT(10)
#define SSS_AES_BYTESWAP_IV BIT(9)
#define SSS_AES_BYTESWAP_CNT BIT(8)
#define SSS_AES_BYTESWAP_KEY BIT(7)
#define SSS_AES_KEY_CHANGE_MODE BIT(6)
#define SSS_AES_KEY_SIZE_128 _SBF(4, 0x00)
#define SSS_AES_KEY_SIZE_192 _SBF(4, 0x01)
#define SSS_AES_KEY_SIZE_256 _SBF(4, 0x02)
#define SSS_AES_FIFO_MODE _BIT(3)
#define SSS_AES_FIFO_MODE BIT(3)
#define SSS_AES_CHAIN_MODE_ECB _SBF(1, 0x00)
#define SSS_AES_CHAIN_MODE_CBC _SBF(1, 0x01)
#define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02)
#define SSS_AES_MODE_DECRYPT _BIT(0)
#define SSS_AES_MODE_DECRYPT BIT(0)
#define SSS_REG_AES_STATUS 0x04
#define SSS_AES_BUSY _BIT(2)
#define SSS_AES_INPUT_READY _BIT(1)
#define SSS_AES_OUTPUT_READY _BIT(0)
#define SSS_AES_BUSY BIT(2)
#define SSS_AES_INPUT_READY BIT(1)
#define SSS_AES_OUTPUT_READY BIT(0)
#define SSS_REG_AES_IN_DATA(s) (0x10 + (s << 2))
#define SSS_REG_AES_OUT_DATA(s) (0x20 + (s << 2))
......@@ -139,7 +138,7 @@
SSS_AES_REG(dev, reg))
/* HW engine modes */
#define FLAGS_AES_DECRYPT _BIT(0)
#define FLAGS_AES_DECRYPT BIT(0)
#define FLAGS_AES_MODE_MASK _SBF(1, 0x03)
#define FLAGS_AES_CBC _SBF(1, 0x01)
#define FLAGS_AES_CTR _SBF(1, 0x02)
......@@ -149,7 +148,6 @@
/**
* struct samsung_aes_variant - platform specific SSS driver data
* @has_hash_irq: true if SSS module uses hash interrupt, false otherwise
* @aes_offset: AES register offset from SSS module's base.
*
* Specifies platform specific configuration of SSS module.
......@@ -157,7 +155,6 @@
* expansion of its usage.
*/
struct samsung_aes_variant {
bool has_hash_irq;
unsigned int aes_offset;
};
......@@ -178,7 +175,6 @@ struct s5p_aes_dev {
struct clk *clk;
void __iomem *ioaddr;
void __iomem *aes_ioaddr;
int irq_hash;
int irq_fc;
struct ablkcipher_request *req;
......@@ -186,6 +182,10 @@ struct s5p_aes_dev {
struct scatterlist *sg_src;
struct scatterlist *sg_dst;
/* In case of unaligned access: */
struct scatterlist *sg_src_cpy;
struct scatterlist *sg_dst_cpy;
struct tasklet_struct tasklet;
struct crypto_queue queue;
bool busy;
......@@ -197,12 +197,10 @@ struct s5p_aes_dev {
static struct s5p_aes_dev *s5p_dev;
static const struct samsung_aes_variant s5p_aes_data = {
.has_hash_irq = true,
.aes_offset = 0x4000,
};
static const struct samsung_aes_variant exynos_aes_data = {
.has_hash_irq = false,
.aes_offset = 0x200,
};
......@@ -245,8 +243,45 @@ static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg));
}
static void s5p_free_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist **sg)
{
int len;
if (!*sg)
return;
len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE);
free_pages((unsigned long)sg_virt(*sg), get_order(len));
kfree(*sg);
*sg = NULL;
}
static void s5p_sg_copy_buf(void *buf, struct scatterlist *sg,
unsigned int nbytes, int out)
{
struct scatter_walk walk;
if (!nbytes)
return;
scatterwalk_start(&walk, sg);
scatterwalk_copychunks(buf, &walk, nbytes, out);
scatterwalk_done(&walk, out, 0);
}
static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
{
if (dev->sg_dst_cpy) {
dev_dbg(dev->dev,
"Copying %d bytes of output data back to original place\n",
dev->req->nbytes);
s5p_sg_copy_buf(sg_virt(dev->sg_dst_cpy), dev->req->dst,
dev->req->nbytes, 1);
}
s5p_free_sg_cpy(dev, &dev->sg_src_cpy);
s5p_free_sg_cpy(dev, &dev->sg_dst_cpy);
/* holding a lock outside */
dev->req->base.complete(&dev->req->base, err);
dev->busy = false;
......@@ -262,15 +297,37 @@ static void s5p_unset_indata(struct s5p_aes_dev *dev)
dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE);
}
static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src,
struct scatterlist **dst)
{
void *pages;
int len;
*dst = kmalloc(sizeof(**dst), GFP_ATOMIC);
if (!*dst)
return -ENOMEM;
len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE);
pages = (void *)__get_free_pages(GFP_ATOMIC, get_order(len));
if (!pages) {
kfree(*dst);
*dst = NULL;
return -ENOMEM;
}
s5p_sg_copy_buf(pages, src, dev->req->nbytes, 0);
sg_init_table(*dst, 1);
sg_set_buf(*dst, pages, len);
return 0;
}
static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
{
int err;
if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
err = -EINVAL;
goto exit;
}
if (!sg_dma_len(sg)) {
if (!sg->length) {
err = -EINVAL;
goto exit;
}
......@@ -284,7 +341,7 @@ static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
dev->sg_dst = sg;
err = 0;
exit:
exit:
return err;
}
......@@ -292,11 +349,7 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
{
int err;
if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
err = -EINVAL;
goto exit;
}
if (!sg_dma_len(sg)) {
if (!sg->length) {
err = -EINVAL;
goto exit;
}
......@@ -310,47 +363,59 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
dev->sg_src = sg;
err = 0;
exit:
exit:
return err;
}
static void s5p_aes_tx(struct s5p_aes_dev *dev)
/*
* Returns true if new transmitting (output) data is ready and its
* address+length have to be written to device (by calling
* s5p_set_dma_outdata()). False otherwise.
*/
static bool s5p_aes_tx(struct s5p_aes_dev *dev)
{
int err = 0;
bool ret = false;
s5p_unset_outdata(dev);
if (!sg_is_last(dev->sg_dst)) {
err = s5p_set_outdata(dev, sg_next(dev->sg_dst));
if (err) {
if (err)
s5p_aes_complete(dev, err);
return;
}
s5p_set_dma_outdata(dev, dev->sg_dst);
else
ret = true;
} else {
s5p_aes_complete(dev, err);
dev->busy = true;
tasklet_schedule(&dev->tasklet);
}
return ret;
}
static void s5p_aes_rx(struct s5p_aes_dev *dev)
/*
* Returns true if new receiving (input) data is ready and its
* address+length have to be written to device (by calling
* s5p_set_dma_indata()). False otherwise.
*/
static bool s5p_aes_rx(struct s5p_aes_dev *dev)
{
int err;
bool ret = false;
s5p_unset_indata(dev);
if (!sg_is_last(dev->sg_src)) {
err = s5p_set_indata(dev, sg_next(dev->sg_src));
if (err) {
if (err)
s5p_aes_complete(dev, err);
return;
}
s5p_set_dma_indata(dev, dev->sg_src);
else
ret = true;
}
return ret;
}
static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
......@@ -359,18 +424,29 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
struct s5p_aes_dev *dev = platform_get_drvdata(pdev);
uint32_t status;
unsigned long flags;
bool set_dma_tx = false;
bool set_dma_rx = false;
spin_lock_irqsave(&dev->lock, flags);
if (irq == dev->irq_fc) {
status = SSS_READ(dev, FCINTSTAT);
if (status & SSS_FCINTSTAT_BRDMAINT)
s5p_aes_rx(dev);
if (status & SSS_FCINTSTAT_BTDMAINT)
s5p_aes_tx(dev);
SSS_WRITE(dev, FCINTPEND, status);
}
status = SSS_READ(dev, FCINTSTAT);
if (status & SSS_FCINTSTAT_BRDMAINT)
set_dma_rx = s5p_aes_rx(dev);
if (status & SSS_FCINTSTAT_BTDMAINT)
set_dma_tx = s5p_aes_tx(dev);
SSS_WRITE(dev, FCINTPEND, status);
/*
* Writing length of DMA block (either receiving or transmitting)
* will start the operation immediately, so this should be done
* at the end (even after clearing pending interrupts to not miss the
* interrupt).
*/
if (set_dma_tx)
s5p_set_dma_outdata(dev, dev->sg_dst);
if (set_dma_rx)
s5p_set_dma_indata(dev, dev->sg_src);
spin_unlock_irqrestore(&dev->lock, flags);
......@@ -395,6 +471,71 @@ static void s5p_set_aes(struct s5p_aes_dev *dev,
memcpy_toio(keystart, key, keylen);
}
static bool s5p_is_sg_aligned(struct scatterlist *sg)
{
while (sg) {
if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE))
return false;
sg = sg_next(sg);
}
return true;
}
static int s5p_set_indata_start(struct s5p_aes_dev *dev,
struct ablkcipher_request *req)
{
struct scatterlist *sg;
int err;
dev->sg_src_cpy = NULL;
sg = req->src;
if (!s5p_is_sg_aligned(sg)) {
dev_dbg(dev->dev,
"At least one unaligned source scatter list, making a copy\n");
err = s5p_make_sg_cpy(dev, sg, &dev->sg_src_cpy);
if (err)
return err;
sg = dev->sg_src_cpy;
}
err = s5p_set_indata(dev, sg);
if (err) {
s5p_free_sg_cpy(dev, &dev->sg_src_cpy);
return err;
}
return 0;
}
static int s5p_set_outdata_start(struct s5p_aes_dev *dev,
struct ablkcipher_request *req)
{
struct scatterlist *sg;
int err;
dev->sg_dst_cpy = NULL;
sg = req->dst;
if (!s5p_is_sg_aligned(sg)) {
dev_dbg(dev->dev,
"At least one unaligned dest scatter list, making a copy\n");
err = s5p_make_sg_cpy(dev, sg, &dev->sg_dst_cpy);
if (err)
return err;
sg = dev->sg_dst_cpy;
}
err = s5p_set_outdata(dev, sg);
if (err) {
s5p_free_sg_cpy(dev, &dev->sg_dst_cpy);
return err;
}
return 0;
}
static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
{
struct ablkcipher_request *req = dev->req;
......@@ -431,19 +572,19 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR);
SSS_WRITE(dev, FCFIFOCTRL, 0x00);
err = s5p_set_indata(dev, req->src);
err = s5p_set_indata_start(dev, req);
if (err)
goto indata_error;
err = s5p_set_outdata(dev, req->dst);
err = s5p_set_outdata_start(dev, req);
if (err)
goto outdata_error;
SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
s5p_set_dma_indata(dev, req->src);
s5p_set_dma_outdata(dev, req->dst);
s5p_set_dma_indata(dev, dev->sg_src);
s5p_set_dma_outdata(dev, dev->sg_dst);
SSS_WRITE(dev, FCINTENSET,
SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET);
......@@ -452,10 +593,10 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
return;
outdata_error:
outdata_error:
s5p_unset_indata(dev);
indata_error:
indata_error:
s5p_aes_complete(dev, err);
spin_unlock_irqrestore(&dev->lock, flags);
}
......@@ -506,7 +647,7 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
tasklet_schedule(&dev->tasklet);
exit:
exit:
return err;
}
......@@ -671,21 +812,6 @@ static int s5p_aes_probe(struct platform_device *pdev)
goto err_irq;
}
if (variant->has_hash_irq) {
pdata->irq_hash = platform_get_irq(pdev, 1);
if (pdata->irq_hash < 0) {
err = pdata->irq_hash;
dev_warn(dev, "hash interrupt is not available.\n");
goto err_irq;
}
err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt,
IRQF_SHARED, pdev->name, pdev);
if (err < 0) {
dev_warn(dev, "hash interrupt is not available.\n");
goto err_irq;
}
}
pdata->busy = false;
pdata->variant = variant;
pdata->dev = dev;
......@@ -705,7 +831,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
return 0;
err_algs:
err_algs:
dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, err);
for (j = 0; j < i; j++)
......@@ -713,7 +839,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
tasklet_kill(&pdata->tasklet);
err_irq:
err_irq:
clk_disable_unprepare(pdata->clk);
s5p_dev = NULL;
......
......@@ -35,6 +35,7 @@ static int sun4i_ss_opti_poll(struct ablkcipher_request *areq)
unsigned int todo;
struct sg_mapping_iter mi, mo;
unsigned int oi, oo; /* offset for in and out */
unsigned long flags;
if (areq->nbytes == 0)
return 0;
......@@ -49,7 +50,7 @@ static int sun4i_ss_opti_poll(struct ablkcipher_request *areq)
return -EINVAL;
}
spin_lock_bh(&ss->slock);
spin_lock_irqsave(&ss->slock, flags);
for (i = 0; i < op->keylen; i += 4)
writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
......@@ -117,7 +118,7 @@ static int sun4i_ss_opti_poll(struct ablkcipher_request *areq)
sg_miter_stop(&mi);
sg_miter_stop(&mo);
writel(0, ss->base + SS_CTL);
spin_unlock_bh(&ss->slock);
spin_unlock_irqrestore(&ss->slock, flags);
return err;
}
......@@ -149,6 +150,7 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
unsigned int ob = 0; /* offset in buf */
unsigned int obo = 0; /* offset in bufo*/
unsigned int obl = 0; /* length of data in bufo */
unsigned long flags;
if (areq->nbytes == 0)
return 0;
......@@ -181,7 +183,7 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
if (no_chunk == 1)
return sun4i_ss_opti_poll(areq);
spin_lock_bh(&ss->slock);
spin_lock_irqsave(&ss->slock, flags);
for (i = 0; i < op->keylen; i += 4)
writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
......@@ -307,7 +309,7 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
sg_miter_stop(&mi);
sg_miter_stop(&mo);
writel(0, ss->base + SS_CTL);
spin_unlock_bh(&ss->slock);
spin_unlock_irqrestore(&ss->slock, flags);
return err;
}
......
......@@ -835,6 +835,16 @@ struct talitos_ahash_req_ctx {
struct scatterlist *psrc;
};
struct talitos_export_state {
u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
u8 buf[HASH_MAX_BLOCK_SIZE];
unsigned int swinit;
unsigned int first;
unsigned int last;
unsigned int to_hash_later;
unsigned int nbuf;
};
static int aead_setkey(struct crypto_aead *authenc,
const u8 *key, unsigned int keylen)
{
......@@ -1981,6 +1991,46 @@ static int ahash_digest(struct ahash_request *areq)
return ahash_process_req(areq, areq->nbytes);
}
static int ahash_export(struct ahash_request *areq, void *out)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
struct talitos_export_state *export = out;
memcpy(export->hw_context, req_ctx->hw_context,
req_ctx->hw_context_size);
memcpy(export->buf, req_ctx->buf, req_ctx->nbuf);
export->swinit = req_ctx->swinit;
export->first = req_ctx->first;
export->last = req_ctx->last;
export->to_hash_later = req_ctx->to_hash_later;
export->nbuf = req_ctx->nbuf;
return 0;
}
static int ahash_import(struct ahash_request *areq, const void *in)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
const struct talitos_export_state *export = in;
memset(req_ctx, 0, sizeof(*req_ctx));
req_ctx->hw_context_size =
(crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
: TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
memcpy(req_ctx->hw_context, export->hw_context,
req_ctx->hw_context_size);
memcpy(req_ctx->buf, export->buf, export->nbuf);
req_ctx->swinit = export->swinit;
req_ctx->first = export->first;
req_ctx->last = export->last;
req_ctx->to_hash_later = export->to_hash_later;
req_ctx->nbuf = export->nbuf;
return 0;
}
struct keyhash_result {
struct completion completion;
int err;
......@@ -2458,6 +2508,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = MD5_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "md5",
.cra_driver_name = "md5-talitos",
......@@ -2473,6 +2524,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA1_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "sha1",
.cra_driver_name = "sha1-talitos",
......@@ -2488,6 +2540,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA224_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "sha224",
.cra_driver_name = "sha224-talitos",
......@@ -2503,6 +2556,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA256_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "sha256",
.cra_driver_name = "sha256-talitos",
......@@ -2518,6 +2572,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA384_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "sha384",
.cra_driver_name = "sha384-talitos",
......@@ -2533,6 +2588,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA512_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "sha512",
.cra_driver_name = "sha512-talitos",
......@@ -2548,6 +2604,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = MD5_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "hmac(md5)",
.cra_driver_name = "hmac-md5-talitos",
......@@ -2563,6 +2620,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA1_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "hmac(sha1)",
.cra_driver_name = "hmac-sha1-talitos",
......@@ -2578,6 +2636,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA224_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "hmac(sha224)",
.cra_driver_name = "hmac-sha224-talitos",
......@@ -2593,6 +2652,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA256_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "hmac(sha256)",
.cra_driver_name = "hmac-sha256-talitos",
......@@ -2608,6 +2668,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA384_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "hmac(sha384)",
.cra_driver_name = "hmac-sha384-talitos",
......@@ -2623,6 +2684,7 @@ static struct talitos_alg_template driver_algs[] = {
{ .type = CRYPTO_ALG_TYPE_AHASH,
.alg.hash = {
.halg.digestsize = SHA512_DIGEST_SIZE,
.halg.statesize = sizeof(struct talitos_export_state),
.halg.base = {
.cra_name = "hmac(sha512)",
.cra_driver_name = "hmac-sha512-talitos",
......@@ -2814,6 +2876,8 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
t_alg->algt.alg.hash.finup = ahash_finup;
t_alg->algt.alg.hash.digest = ahash_digest;
t_alg->algt.alg.hash.setkey = ahash_setkey;
t_alg->algt.alg.hash.import = ahash_import;
t_alg->algt.alg.hash.export = ahash_export;
if (!(priv->features & TALITOS_FTR_HMAC_OK) &&
!strncmp(alg->cra_name, "hmac", 4)) {
......
......@@ -139,6 +139,26 @@ my $vmr = sub {
" vor $vx,$vy,$vy";
};
# Some ABIs specify vrsave, special-purpose register #256, as reserved
# for system use.
my $no_vrsave = ($flavour =~ /aix|linux64le/);
my $mtspr = sub {
my ($f,$idx,$ra) = @_;
if ($idx == 256 && $no_vrsave) {
" or $ra,$ra,$ra";
} else {
" mtspr $idx,$ra";
}
};
my $mfspr = sub {
my ($f,$rd,$idx) = @_;
if ($idx == 256 && $no_vrsave) {
" li $rd,-1";
} else {
" mfspr $rd,$idx";
}
};
# PowerISA 2.06 stuff
sub vsxmem_op {
my ($f, $vrt, $ra, $rb, $op) = @_;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册