From 79b3a418e090248d00ceba40b81da9dfac753367 Mon Sep 17 00:00:00 2001 From: Lee Nipper Date: Mon, 21 Nov 2011 16:13:25 +0800 Subject: crypto: talitos - add hmac algorithms Add these hmac algorithms to talitos: hmac(md5), hmac(sha1), hmac(sha224), hmac(sha256), hmac(sha384), hmac(sha512). These are all type ahash. Signed-off-by: Lee Nipper Fixed up to not register HMAC algorithms on sec2.0 devices. Rationale (from Lee): on an 8349E Rev1.1, there's a problem with hmac for any talitos hmac sequence requiring an intermediate hash context (Pointer DWORD 1); the result is an incorrect hmac. An intermediate hash context is required for something longer than (65536-blocksize), and for other cases when update/finup/final are used inefficiently. Interestingly, a normal hash (without hmac) works perfectly when using an intermediate context. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 2 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index dbe76b5..8ce8731 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -157,6 +157,7 @@ struct talitos_private { #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 #define TALITOS_FTR_HW_AUTH_CHECK 0x00000002 #define TALITOS_FTR_SHA224_HWINIT 0x00000004 +#define TALITOS_FTR_HMAC_OK 0x00000008 static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr) { @@ -1874,6 +1875,97 @@ static int ahash_digest(struct ahash_request *areq) return ahash_process_req(areq, areq->nbytes); } +struct keyhash_result { + struct completion completion; + int err; +}; + +static void keyhash_complete(struct crypto_async_request *req, int err) +{ + struct keyhash_result *res = req->data; + + if (err == -EINPROGRESS) + return; + + res->err = err; + complete(&res->completion); +} + +static int keyhash(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen, + u8 *hash) +{ + struct talitos_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); + + struct scatterlist sg[1]; + struct ahash_request *req; + struct keyhash_result hresult; + int ret; + + init_completion(&hresult.completion); + + req = ahash_request_alloc(tfm, GFP_KERNEL); + if (!req) + return -ENOMEM; + + /* Keep tfm keylen == 0 during hash of the long key */ + ctx->keylen = 0; + ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + keyhash_complete, &hresult); + + sg_init_one(&sg[0], key, keylen); + + ahash_request_set_crypt(req, sg, hash, keylen); + ret = crypto_ahash_digest(req); + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible( + &hresult.completion); + if (!ret) + ret = hresult.err; + break; + default: + break; + } + ahash_request_free(req); + + return ret; +} + +static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen) +{ + struct talitos_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); + unsigned int blocksize = + crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); + unsigned int digestsize = crypto_ahash_digestsize(tfm); + unsigned int keysize = keylen; + u8 hash[SHA512_DIGEST_SIZE]; + int ret; + + if (keylen <= blocksize) + memcpy(ctx->key, key, keysize); + else { + /* Must get the hash of the long key */ + ret = keyhash(tfm, key, keylen, hash); + + if (ret) { + crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + keysize = digestsize; + memcpy(ctx->key, hash, digestsize); + } + + ctx->keylen = keysize; + + return 0; +} + + struct talitos_alg_template { u32 type; union { @@ -2217,6 +2309,138 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_SEL0_MDEUB | DESC_HDR_MODE0_MDEUB_SHA512, }, + { .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .setkey = ahash_setkey, + .halg.digestsize = MD5_DIGEST_SIZE, + .halg.base = { + .cra_name = "hmac(md5)", + .cra_driver_name = "hmac-md5-talitos", + .cra_blocksize = MD5_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ahash_type + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_MDEUA | + DESC_HDR_MODE0_MDEU_MD5, + }, + { .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .setkey = ahash_setkey, + .halg.digestsize = SHA1_DIGEST_SIZE, + .halg.base = { + .cra_name = "hmac(sha1)", + .cra_driver_name = "hmac-sha1-talitos", + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ahash_type + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_MDEUA | + DESC_HDR_MODE0_MDEU_SHA1, + }, + { .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .setkey = ahash_setkey, + .halg.digestsize = SHA224_DIGEST_SIZE, + .halg.base = { + .cra_name = "hmac(sha224)", + .cra_driver_name = "hmac-sha224-talitos", + .cra_blocksize = SHA224_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ahash_type + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_MDEUA | + DESC_HDR_MODE0_MDEU_SHA224, + }, + { .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .setkey = ahash_setkey, + .halg.digestsize = SHA256_DIGEST_SIZE, + .halg.base = { + .cra_name = "hmac(sha256)", + .cra_driver_name = "hmac-sha256-talitos", + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ahash_type + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_MDEUA | + DESC_HDR_MODE0_MDEU_SHA256, + }, + { .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .setkey = ahash_setkey, + .halg.digestsize = SHA384_DIGEST_SIZE, + .halg.base = { + .cra_name = "hmac(sha384)", + .cra_driver_name = "hmac-sha384-talitos", + .cra_blocksize = SHA384_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ahash_type + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_MDEUB | + DESC_HDR_MODE0_MDEUB_SHA384, + }, + { .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .setkey = ahash_setkey, + .halg.digestsize = SHA512_DIGEST_SIZE, + .halg.base = { + .cra_name = "hmac(sha512)", + .cra_driver_name = "hmac-sha512-talitos", + .cra_blocksize = SHA512_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ahash_type + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_MDEUB | + DESC_HDR_MODE0_MDEUB_SHA512, + } }; struct talitos_crypto_alg { @@ -2373,8 +2597,12 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, case CRYPTO_ALG_TYPE_AHASH: alg = &t_alg->algt.alg.hash.halg.base; alg->cra_init = talitos_cra_init_ahash; + if (!(priv->features & TALITOS_FTR_HMAC_OK) && + !strncmp(alg->cra_name, "hmac", 4)) + return ERR_PTR(-ENOTSUPP); if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) && - !strcmp(alg->cra_name, "sha224")) { + (!strcmp(alg->cra_name, "sha224") || + !strcmp(alg->cra_name, "hmac(sha224)"))) { t_alg->algt.alg.hash.init = ahash_init_sha224_swinit; t_alg->algt.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2471,7 +2699,8 @@ static int talitos_probe(struct platform_device *ofdev) if (of_device_is_compatible(np, "fsl,sec2.1")) priv->features |= TALITOS_FTR_HW_AUTH_CHECK | - TALITOS_FTR_SHA224_HWINIT; + TALITOS_FTR_SHA224_HWINIT | + TALITOS_FTR_HMAC_OK; priv->chan = kzalloc(sizeof(struct talitos_channel) * priv->num_channels, GFP_KERNEL); @@ -2530,6 +2759,10 @@ static int talitos_probe(struct platform_device *ofdev) t_alg = talitos_alg_alloc(dev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); + if (err == -ENOTSUPP) { + kfree(t_alg); + continue; + } goto err_out; } -- cgit v1.1 From 5b859b6ebb18b37244d44b5300bf765694b7303c Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 21 Nov 2011 16:13:26 +0800 Subject: crypto: talitos - be less noisy on startup talitos prints every algorithm it registers at module load time. Algorithms are being added that make for an excessively noisy console (latest HMACs patch makes an SEC 3.1 print 20 lines). Instead, display the SEC h/w version number, and inform the user of algorithm registration status in /proc/crypto, like so: talitos ffe30000.crypto: fsl,sec3.1 algorithms registered in /proc/crypto Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 8ce8731..c372a18 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2784,12 +2784,13 @@ static int talitos_probe(struct platform_device *ofdev) dev_err(dev, "%s alg registration failed\n", name); kfree(t_alg); - } else { + } else list_add_tail(&t_alg->entry, &priv->alg_list); - dev_info(dev, "%s\n", name); - } } } + if (!list_empty(&priv->alg_list)) + dev_info(dev, "%s algorithms registered in /proc/crypto\n", + (char *)of_get_property(np, "compatible", NULL)); return 0; -- cgit v1.1 From ad42d5fc85383278663ecb58a24f6547ad0ba735 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 21 Nov 2011 16:13:27 +0800 Subject: crypto: talitos - prepare driver for channel remap support Add a reg member to the channel struct and use it to access channels. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index c372a18..7f82e91 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -99,6 +99,8 @@ struct talitos_request { /* per-channel fifo management */ struct talitos_channel { + void __iomem *reg; + /* request fifo */ struct talitos_request *fifo; @@ -197,9 +199,9 @@ static int reset_channel(struct device *dev, int ch) struct talitos_private *priv = dev_get_drvdata(dev); unsigned int timeout = TALITOS_TIMEOUT; - setbits32(priv->reg + TALITOS_CCCR(ch), TALITOS_CCCR_RESET); + setbits32(priv->chan[ch].reg + TALITOS_CCCR, TALITOS_CCCR_RESET); - while ((in_be32(priv->reg + TALITOS_CCCR(ch)) & TALITOS_CCCR_RESET) + while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) & TALITOS_CCCR_RESET) && --timeout) cpu_relax(); @@ -209,12 +211,12 @@ static int reset_channel(struct device *dev, int ch) } /* set 36-bit addressing, done writeback enable and done IRQ enable */ - setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_EAE | + setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, TALITOS_CCCR_LO_EAE | TALITOS_CCCR_LO_CDWE | TALITOS_CCCR_LO_CDIE); /* and ICCR writeback, if available */ if (priv->features & TALITOS_FTR_HW_AUTH_CHECK) - setbits32(priv->reg + TALITOS_CCCR_LO(ch), + setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, TALITOS_CCCR_LO_IWSE); return 0; @@ -328,8 +330,9 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, /* GO! */ wmb(); - out_be32(priv->reg + TALITOS_FF(ch), upper_32_bits(request->dma_desc)); - out_be32(priv->reg + TALITOS_FF_LO(ch), + out_be32(priv->chan[ch].reg + TALITOS_FF, + upper_32_bits(request->dma_desc)); + out_be32(priv->chan[ch].reg + TALITOS_FF_LO, lower_32_bits(request->dma_desc)); spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); @@ -423,7 +426,7 @@ static u32 current_desc_hdr(struct device *dev, int ch) int tail = priv->chan[ch].tail; dma_addr_t cur_desc; - cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch)); + cur_desc = in_be32(priv->chan[ch].reg + TALITOS_CDPR_LO); while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) { tail = (tail + 1) & (priv->fifo_len - 1); @@ -445,7 +448,7 @@ static void report_eu_error(struct device *dev, int ch, u32 desc_hdr) int i; if (!desc_hdr) - desc_hdr = in_be32(priv->reg + TALITOS_DESCBUF(ch)); + desc_hdr = in_be32(priv->chan[ch].reg + TALITOS_DESCBUF); switch (desc_hdr & DESC_HDR_SEL0_MASK) { case DESC_HDR_SEL0_AFEU: @@ -507,8 +510,8 @@ static void report_eu_error(struct device *dev, int ch, u32 desc_hdr) for (i = 0; i < 8; i++) dev_err(dev, "DESCBUF 0x%08x_%08x\n", - in_be32(priv->reg + TALITOS_DESCBUF(ch) + 8*i), - in_be32(priv->reg + TALITOS_DESCBUF_LO(ch) + 8*i)); + in_be32(priv->chan[ch].reg + TALITOS_DESCBUF + 8*i), + in_be32(priv->chan[ch].reg + TALITOS_DESCBUF_LO + 8*i)); } /* @@ -529,8 +532,8 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo) error = -EINVAL; - v = in_be32(priv->reg + TALITOS_CCPSR(ch)); - v_lo = in_be32(priv->reg + TALITOS_CCPSR_LO(ch)); + v = in_be32(priv->chan[ch].reg + TALITOS_CCPSR); + v_lo = in_be32(priv->chan[ch].reg + TALITOS_CCPSR_LO); if (v_lo & TALITOS_CCPSR_LO_DOF) { dev_err(dev, "double fetch fifo overflow error\n"); @@ -568,10 +571,10 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo) if (reset_ch) { reset_channel(dev, ch); } else { - setbits32(priv->reg + TALITOS_CCCR(ch), + setbits32(priv->chan[ch].reg + TALITOS_CCCR, TALITOS_CCCR_CONT); - setbits32(priv->reg + TALITOS_CCCR_LO(ch), 0); - while ((in_be32(priv->reg + TALITOS_CCCR(ch)) & + setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, 0); + while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) & TALITOS_CCCR_CONT) && --timeout) cpu_relax(); if (timeout == 0) { @@ -2710,6 +2713,10 @@ static int talitos_probe(struct platform_device *ofdev) goto err_out; } + for (i = 0; i < priv->num_channels; i++) + priv->chan[i].reg = priv->reg + TALITOS_CH_BASE_OFFSET + + TALITOS_CH_STRIDE * (i + 1); + for (i = 0; i < priv->num_channels; i++) { spin_lock_init(&priv->chan[i].head_lock); spin_lock_init(&priv->chan[i].tail_lock); -- cgit v1.1 From c3e337f88a5b3784cb3c806ffd650d06adff1ea5 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 21 Nov 2011 16:13:27 +0800 Subject: crypto: talitos - support for channel remap and 2nd IRQ Some later SEC v3.x are equipped with a second IRQ line. By correctly assigning IRQ affinity, this feature can be used to increase performance on dual core parts, like the MPC8572E and P2020E. The existence of the 2nd IRQ is determined from the device node's interrupt property. If present, the driver remaps two of four channels, which in turn makes those channels trigger their interrupts on the 2nd line instead of the first. To handle single- and dual-IRQ combinations efficiently, talitos gets two new interrupt handlers and back-half workers. [includes a fix to MCR_LO's address.] Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 207 +++++++++++++++++++++++++++++++---------------- 1 file changed, 138 insertions(+), 69 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 7f82e91..92c0ca7 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -122,7 +122,7 @@ struct talitos_private { struct device *dev; struct platform_device *ofdev; void __iomem *reg; - int irq; + int irq[2]; /* SEC version geometry (from device tree node) */ unsigned int num_channels; @@ -146,7 +146,7 @@ struct talitos_private { atomic_t last_chan ____cacheline_aligned; /* request callback tasklet */ - struct tasklet_struct done_task; + struct tasklet_struct done_task[2]; /* list of registered algorithms */ struct list_head alg_list; @@ -226,13 +226,19 @@ static int reset_device(struct device *dev) { struct talitos_private *priv = dev_get_drvdata(dev); unsigned int timeout = TALITOS_TIMEOUT; + u32 mcr = TALITOS_MCR_SWR; - setbits32(priv->reg + TALITOS_MCR, TALITOS_MCR_SWR); + setbits32(priv->reg + TALITOS_MCR, mcr); while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR) && --timeout) cpu_relax(); + if (priv->irq[1] != NO_IRQ) { + mcr = TALITOS_MCR_RCA1 | TALITOS_MCR_RCA3; + setbits32(priv->reg + TALITOS_MCR, mcr); + } + if (timeout == 0) { dev_err(dev, "failed to reset device\n"); return -EIO; @@ -401,21 +407,32 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) /* * process completed requests for channels that have done status */ -static void talitos_done(unsigned long data) -{ - struct device *dev = (struct device *)data; - struct talitos_private *priv = dev_get_drvdata(dev); - int ch; - - for (ch = 0; ch < priv->num_channels; ch++) - flush_channel(dev, ch, 0, 0); - - /* At this point, all completed channels have been processed. - * Unmask done interrupts for channels completed later on. - */ - setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT); - setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT); -} +#define DEF_TALITOS_DONE(name, ch_done_mask) \ +static void talitos_done_##name(unsigned long data) \ +{ \ + struct device *dev = (struct device *)data; \ + struct talitos_private *priv = dev_get_drvdata(dev); \ + \ + if (ch_done_mask & 1) \ + flush_channel(dev, 0, 0, 0); \ + if (priv->num_channels == 1) \ + goto out; \ + if (ch_done_mask & (1 << 2)) \ + flush_channel(dev, 1, 0, 0); \ + if (ch_done_mask & (1 << 4)) \ + flush_channel(dev, 2, 0, 0); \ + if (ch_done_mask & (1 << 6)) \ + flush_channel(dev, 3, 0, 0); \ + \ +out: \ + /* At this point, all completed channels have been processed */ \ + /* Unmask done interrupts for channels completed later on. */ \ + setbits32(priv->reg + TALITOS_IMR, ch_done_mask); \ + setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT); \ +} +DEF_TALITOS_DONE(4ch, TALITOS_ISR_4CHDONE) +DEF_TALITOS_DONE(ch0_2, TALITOS_ISR_CH_0_2_DONE) +DEF_TALITOS_DONE(ch1_3, TALITOS_ISR_CH_1_3_DONE) /* * locate current (offending) descriptor @@ -584,7 +601,7 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo) } } } - if (reset_dev || isr & ~TALITOS_ISR_CHERR || isr_lo) { + if (reset_dev || isr & ~TALITOS_ISR_4CHERR || isr_lo) { dev_err(dev, "done overflow, internal time out, or rngu error: " "ISR 0x%08x_%08x\n", isr, isr_lo); @@ -597,30 +614,35 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo) } } -static irqreturn_t talitos_interrupt(int irq, void *data) -{ - struct device *dev = data; - struct talitos_private *priv = dev_get_drvdata(dev); - u32 isr, isr_lo; - - isr = in_be32(priv->reg + TALITOS_ISR); - isr_lo = in_be32(priv->reg + TALITOS_ISR_LO); - /* Acknowledge interrupt */ - out_be32(priv->reg + TALITOS_ICR, isr); - out_be32(priv->reg + TALITOS_ICR_LO, isr_lo); - - if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo)) - talitos_error((unsigned long)data, isr, isr_lo); - else - if (likely(isr & TALITOS_ISR_CHDONE)) { - /* mask further done interrupts. */ - clrbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE); - /* done_task will unmask done interrupts at exit */ - tasklet_schedule(&priv->done_task); - } - - return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE; -} +#define DEF_TALITOS_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet) \ +static irqreturn_t talitos_interrupt_##name(int irq, void *data) \ +{ \ + struct device *dev = data; \ + struct talitos_private *priv = dev_get_drvdata(dev); \ + u32 isr, isr_lo; \ + \ + isr = in_be32(priv->reg + TALITOS_ISR); \ + isr_lo = in_be32(priv->reg + TALITOS_ISR_LO); \ + /* Acknowledge interrupt */ \ + out_be32(priv->reg + TALITOS_ICR, isr & (ch_done_mask | ch_err_mask)); \ + out_be32(priv->reg + TALITOS_ICR_LO, isr_lo); \ + \ + if (unlikely((isr & ~TALITOS_ISR_4CHDONE) & ch_err_mask || isr_lo)) \ + talitos_error((unsigned long)data, isr, isr_lo); \ + else \ + if (likely(isr & ch_done_mask)) { \ + /* mask further done interrupts. */ \ + clrbits32(priv->reg + TALITOS_IMR, ch_done_mask); \ + /* done_task will unmask done interrupts at exit */ \ + tasklet_schedule(&priv->done_task[tlet]); \ + } \ + \ + return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED : \ + IRQ_NONE; \ +} +DEF_TALITOS_INTERRUPT(4ch, TALITOS_ISR_4CHDONE, TALITOS_ISR_4CHERR, 0) +DEF_TALITOS_INTERRUPT(ch0_2, TALITOS_ISR_CH_0_2_DONE, TALITOS_ISR_CH_0_2_ERR, 0) +DEF_TALITOS_INTERRUPT(ch1_3, TALITOS_ISR_CH_1_3_DONE, TALITOS_ISR_CH_1_3_ERR, 1) /* * hwrng @@ -2558,12 +2580,15 @@ static int talitos_remove(struct platform_device *ofdev) kfree(priv->chan); - if (priv->irq != NO_IRQ) { - free_irq(priv->irq, dev); - irq_dispose_mapping(priv->irq); - } + for (i = 0; i < 2; i++) + if (priv->irq[i] != NO_IRQ) { + free_irq(priv->irq[i], dev); + irq_dispose_mapping(priv->irq[i]); + } - tasklet_kill(&priv->done_task); + tasklet_kill(&priv->done_task[0]); + if (priv->irq[1] != NO_IRQ) + tasklet_kill(&priv->done_task[1]); iounmap(priv->reg); @@ -2628,6 +2653,54 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, return t_alg; } +static int talitos_probe_irq(struct platform_device *ofdev) +{ + struct device *dev = &ofdev->dev; + struct device_node *np = ofdev->dev.of_node; + struct talitos_private *priv = dev_get_drvdata(dev); + int err; + + priv->irq[0] = irq_of_parse_and_map(np, 0); + if (priv->irq[0] == NO_IRQ) { + dev_err(dev, "failed to map irq\n"); + return -EINVAL; + } + + priv->irq[1] = irq_of_parse_and_map(np, 1); + + /* get the primary irq line */ + if (priv->irq[1] == NO_IRQ) { + err = request_irq(priv->irq[0], talitos_interrupt_4ch, 0, + dev_driver_string(dev), dev); + goto primary_out; + } + + err = request_irq(priv->irq[0], talitos_interrupt_ch0_2, 0, + dev_driver_string(dev), dev); + if (err) + goto primary_out; + + /* get the secondary irq line */ + err = request_irq(priv->irq[1], talitos_interrupt_ch1_3, 0, + dev_driver_string(dev), dev); + if (err) { + dev_err(dev, "failed to request secondary irq\n"); + irq_dispose_mapping(priv->irq[1]); + priv->irq[1] = NO_IRQ; + } + + return err; + +primary_out: + if (err) { + dev_err(dev, "failed to request primary irq\n"); + irq_dispose_mapping(priv->irq[0]); + priv->irq[0] = NO_IRQ; + } + + return err; +} + static int talitos_probe(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; @@ -2644,28 +2717,22 @@ static int talitos_probe(struct platform_device *ofdev) priv->ofdev = ofdev; - tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev); - - INIT_LIST_HEAD(&priv->alg_list); - - priv->irq = irq_of_parse_and_map(np, 0); - - if (priv->irq == NO_IRQ) { - dev_err(dev, "failed to map irq\n"); - err = -EINVAL; + err = talitos_probe_irq(ofdev); + if (err) goto err_out; - } - /* get the irq line */ - err = request_irq(priv->irq, talitos_interrupt, 0, - dev_driver_string(dev), dev); - if (err) { - dev_err(dev, "failed to request irq %d\n", priv->irq); - irq_dispose_mapping(priv->irq); - priv->irq = NO_IRQ; - goto err_out; + if (priv->irq[1] == NO_IRQ) { + tasklet_init(&priv->done_task[0], talitos_done_4ch, + (unsigned long)dev); + } else { + tasklet_init(&priv->done_task[0], talitos_done_ch0_2, + (unsigned long)dev); + tasklet_init(&priv->done_task[1], talitos_done_ch1_3, + (unsigned long)dev); } + INIT_LIST_HEAD(&priv->alg_list); + priv->reg = of_iomap(np, 0); if (!priv->reg) { dev_err(dev, "failed to of_iomap\n"); @@ -2713,9 +2780,11 @@ static int talitos_probe(struct platform_device *ofdev) goto err_out; } - for (i = 0; i < priv->num_channels; i++) - priv->chan[i].reg = priv->reg + TALITOS_CH_BASE_OFFSET + - TALITOS_CH_STRIDE * (i + 1); + for (i = 0; i < priv->num_channels; i++) { + priv->chan[i].reg = priv->reg + TALITOS_CH_STRIDE * (i + 1); + if ((priv->irq[1] == NO_IRQ) || !(i & 1)) + priv->chan[i].reg += TALITOS_CH_BASE_OFFSET; + } for (i = 0; i < priv->num_channels; i++) { spin_lock_init(&priv->chan[i].head_lock); -- cgit v1.1 From 741e8c2d8177eca656bc015ef83ab84d817edf8c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 26 Nov 2011 21:26:19 +0800 Subject: crypto: convert drivers/crypto/* to use module_platform_driver() This patch converts the drivers in drivers/crypto/* to use the module_platform_driver() macro which makes the code smaller and a bit simpler. Cc: James Hsiao Cc: Sebastian Andrzej Siewior Cc: Kim Phillips Cc: "David S. Miller" Signed-off-by: Axel Lin Acked-by: Vladimir Zapolskiy Acked-by: Jamie Iles Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 92c0ca7..230509e 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2894,17 +2894,7 @@ static struct platform_driver talitos_driver = { .remove = talitos_remove, }; -static int __init talitos_init(void) -{ - return platform_driver_register(&talitos_driver); -} -module_init(talitos_init); - -static void __exit talitos_exit(void) -{ - platform_driver_unregister(&talitos_driver); -} -module_exit(talitos_exit); +module_platform_driver(talitos_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kim Phillips "); -- cgit v1.1 From 0b2730d8d8b38e009607d5a094d48fcce73af547 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 12 Dec 2011 14:59:10 -0600 Subject: crypto: talitos - fix bad kfree Fix a kfree to an invalid address which causes an oops when running on SEC v2.0 h/w (introduced in commit 702331b "crypto: talitos - add hmac algorithms"). Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 230509e..d376cc7 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2626,8 +2626,10 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, alg = &t_alg->algt.alg.hash.halg.base; alg->cra_init = talitos_cra_init_ahash; if (!(priv->features & TALITOS_FTR_HMAC_OK) && - !strncmp(alg->cra_name, "hmac", 4)) + !strncmp(alg->cra_name, "hmac", 4)) { + kfree(t_alg); return ERR_PTR(-ENOTSUPP); + } if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) && (!strcmp(alg->cra_name, "sha224") || !strcmp(alg->cra_name, "hmac(sha224)"))) { @@ -2835,10 +2837,8 @@ static int talitos_probe(struct platform_device *ofdev) t_alg = talitos_alg_alloc(dev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - if (err == -ENOTSUPP) { - kfree(t_alg); + if (err == -ENOTSUPP) continue; - } goto err_out; } -- cgit v1.1 From 2cdba3cf6ffc1fbf880a6fbfa9e7bb757e3d6526 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 12 Dec 2011 14:59:11 -0600 Subject: crypto: talitos - remove NO_IRQ references As prescribed by Linus: https://lkml.org/lkml/2011/12/2/290 Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index d376cc7..503d0d8 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -234,7 +234,7 @@ static int reset_device(struct device *dev) && --timeout) cpu_relax(); - if (priv->irq[1] != NO_IRQ) { + if (priv->irq[1]) { mcr = TALITOS_MCR_RCA1 | TALITOS_MCR_RCA3; setbits32(priv->reg + TALITOS_MCR, mcr); } @@ -2581,13 +2581,13 @@ static int talitos_remove(struct platform_device *ofdev) kfree(priv->chan); for (i = 0; i < 2; i++) - if (priv->irq[i] != NO_IRQ) { + if (priv->irq[i]) { free_irq(priv->irq[i], dev); irq_dispose_mapping(priv->irq[i]); } tasklet_kill(&priv->done_task[0]); - if (priv->irq[1] != NO_IRQ) + if (priv->irq[1]) tasklet_kill(&priv->done_task[1]); iounmap(priv->reg); @@ -2663,7 +2663,7 @@ static int talitos_probe_irq(struct platform_device *ofdev) int err; priv->irq[0] = irq_of_parse_and_map(np, 0); - if (priv->irq[0] == NO_IRQ) { + if (!priv->irq[0]) { dev_err(dev, "failed to map irq\n"); return -EINVAL; } @@ -2671,7 +2671,7 @@ static int talitos_probe_irq(struct platform_device *ofdev) priv->irq[1] = irq_of_parse_and_map(np, 1); /* get the primary irq line */ - if (priv->irq[1] == NO_IRQ) { + if (!priv->irq[1]) { err = request_irq(priv->irq[0], talitos_interrupt_4ch, 0, dev_driver_string(dev), dev); goto primary_out; @@ -2688,7 +2688,7 @@ static int talitos_probe_irq(struct platform_device *ofdev) if (err) { dev_err(dev, "failed to request secondary irq\n"); irq_dispose_mapping(priv->irq[1]); - priv->irq[1] = NO_IRQ; + priv->irq[1] = 0; } return err; @@ -2697,7 +2697,7 @@ primary_out: if (err) { dev_err(dev, "failed to request primary irq\n"); irq_dispose_mapping(priv->irq[0]); - priv->irq[0] = NO_IRQ; + priv->irq[0] = 0; } return err; @@ -2723,7 +2723,7 @@ static int talitos_probe(struct platform_device *ofdev) if (err) goto err_out; - if (priv->irq[1] == NO_IRQ) { + if (!priv->irq[1]) { tasklet_init(&priv->done_task[0], talitos_done_4ch, (unsigned long)dev); } else { @@ -2784,7 +2784,7 @@ static int talitos_probe(struct platform_device *ofdev) for (i = 0; i < priv->num_channels; i++) { priv->chan[i].reg = priv->reg + TALITOS_CH_STRIDE * (i + 1); - if ((priv->irq[1] == NO_IRQ) || !(i & 1)) + if (!priv->irq[1] || !(i & 1)) priv->chan[i].reg += TALITOS_CH_BASE_OFFSET; } -- cgit v1.1 From 5e718a09e5cafc8922f3fe22206423449a2801c9 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 12 Dec 2011 14:59:12 -0600 Subject: crypto: talitos - convert talitos_error to struct device SEC2/3 h/w doesn't have a dedicated interrupt for errors, and the only callsite for talitos_error has already done the type conversion, so simplify talitos_error to take a pointer to a struct device. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/crypto/talitos.c') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 503d0d8..2d8c789 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -534,9 +534,8 @@ static void report_eu_error(struct device *dev, int ch, u32 desc_hdr) /* * recover from error interrupts */ -static void talitos_error(unsigned long data, u32 isr, u32 isr_lo) +static void talitos_error(struct device *dev, u32 isr, u32 isr_lo) { - struct device *dev = (struct device *)data; struct talitos_private *priv = dev_get_drvdata(dev); unsigned int timeout = TALITOS_TIMEOUT; int ch, error, reset_dev = 0, reset_ch = 0; @@ -628,7 +627,7 @@ static irqreturn_t talitos_interrupt_##name(int irq, void *data) \ out_be32(priv->reg + TALITOS_ICR_LO, isr_lo); \ \ if (unlikely((isr & ~TALITOS_ISR_4CHDONE) & ch_err_mask || isr_lo)) \ - talitos_error((unsigned long)data, isr, isr_lo); \ + talitos_error(dev, isr, isr_lo); \ else \ if (likely(isr & ch_done_mask)) { \ /* mask further done interrupts. */ \ -- cgit v1.1