Merge tag 'sound-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / crypto / talitos.c
index dff88838dce762c33ca7e898420f051c3a2f80cb..9c80e0cb16647035fbfeea22ea1b3c9e6bf0a1b1 100644 (file)
 #include "talitos.h"
 
 static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
-                          bool is_sec1)
+                          unsigned int len, bool is_sec1)
 {
        ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr));
-       if (!is_sec1)
+       if (is_sec1) {
+               ptr->len1 = cpu_to_be16(len);
+       } else {
+               ptr->len = cpu_to_be16(len);
                ptr->eptr = upper_32_bits(dma_addr);
+       }
 }
 
 static void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
                             struct talitos_ptr *src_ptr, bool is_sec1)
 {
        dst_ptr->ptr = src_ptr->ptr;
-       if (!is_sec1)
-               dst_ptr->eptr = src_ptr->eptr;
-}
-
-static void to_talitos_ptr_len(struct talitos_ptr *ptr, unsigned int len,
-                              bool is_sec1)
-{
        if (is_sec1) {
-               ptr->res = 0;
-               ptr->len1 = cpu_to_be16(len);
+               dst_ptr->len1 = src_ptr->len1;
        } else {
-               ptr->len = cpu_to_be16(len);
+               dst_ptr->len = src_ptr->len;
+               dst_ptr->eptr = src_ptr->eptr;
        }
 }
 
@@ -116,9 +113,7 @@ static void map_single_talitos_ptr(struct device *dev,
        struct talitos_private *priv = dev_get_drvdata(dev);
        bool is_sec1 = has_ftr_sec1(priv);
 
-       to_talitos_ptr_len(ptr, len, is_sec1);
-       to_talitos_ptr(ptr, dma_addr, is_sec1);
-       to_talitos_ptr_ext_set(ptr, 0, is_sec1);
+       to_talitos_ptr(ptr, dma_addr, len, is_sec1);
 }
 
 /*
@@ -165,6 +160,10 @@ static int reset_channel(struct device *dev, int ch)
        /* set 36-bit addressing, done writeback enable and done IRQ enable */
        setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, TALITOS_CCCR_LO_EAE |
                  TALITOS_CCCR_LO_CDWE | TALITOS_CCCR_LO_CDIE);
+       /* enable chaining descriptors */
+       if (is_sec1)
+               setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
+                         TALITOS_CCCR_LO_NE);
 
        /* and ICCR writeback, if available */
        if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
@@ -287,7 +286,6 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
        /* map descriptor and save caller data */
        if (is_sec1) {
                desc->hdr1 = desc->hdr;
-               desc->next_desc = 0;
                request->dma_desc = dma_map_single(dev, &desc->hdr1,
                                                   TALITOS_DESC_SIZE,
                                                   DMA_BIDIRECTIONAL);
@@ -339,7 +337,12 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
 
                /* descriptors with their done bits set don't get the error */
                rmb();
-               hdr = is_sec1 ? request->desc->hdr1 : request->desc->hdr;
+               if (!is_sec1)
+                       hdr = request->desc->hdr;
+               else if (request->desc->next_desc)
+                       hdr = (request->desc + 1)->hdr1;
+               else
+                       hdr = request->desc->hdr1;
 
                if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
                        status = 0;
@@ -393,8 +396,6 @@ static void talitos1_done_##name(unsigned long data)                        \
                                                                        \
        if (ch_done_mask & 0x10000000)                                  \
                flush_channel(dev, 0, 0, 0);                    \
-       if (priv->num_channels == 1)                                    \
-               goto out;                                               \
        if (ch_done_mask & 0x40000000)                                  \
                flush_channel(dev, 1, 0, 0);                    \
        if (ch_done_mask & 0x00010000)                                  \
@@ -402,7 +403,6 @@ static void talitos1_done_##name(unsigned long data)                        \
        if (ch_done_mask & 0x00040000)                                  \
                flush_channel(dev, 3, 0, 0);                    \
                                                                        \
-out:                                                                   \
        /* At this point, all completed channels have been processed */ \
        /* Unmask done interrupts for channels completed later on. */   \
        spin_lock_irqsave(&priv->reg_lock, flags);                      \
@@ -412,6 +412,7 @@ out:                                                                        \
 }
 
 DEF_TALITOS1_DONE(4ch, TALITOS1_ISR_4CHDONE)
+DEF_TALITOS1_DONE(ch0, TALITOS1_ISR_CH_0_DONE)
 
 #define DEF_TALITOS2_DONE(name, ch_done_mask)                          \
 static void talitos2_done_##name(unsigned long data)                   \
@@ -422,8 +423,6 @@ static void talitos2_done_##name(unsigned long data)                        \
                                                                        \
        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))                                    \
@@ -431,7 +430,6 @@ static void talitos2_done_##name(unsigned long data)                        \
        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. */   \
        spin_lock_irqsave(&priv->reg_lock, flags);                      \
@@ -441,6 +439,7 @@ out:                                                                        \
 }
 
 DEF_TALITOS2_DONE(4ch, TALITOS2_ISR_4CHDONE)
+DEF_TALITOS2_DONE(ch0, TALITOS2_ISR_CH_0_DONE)
 DEF_TALITOS2_DONE(ch0_2, TALITOS2_ISR_CH_0_2_DONE)
 DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE)
 
@@ -464,7 +463,8 @@ static u32 current_desc_hdr(struct device *dev, int ch)
        tail = priv->chan[ch].tail;
 
        iter = tail;
-       while (priv->chan[ch].fifo[iter].dma_desc != cur_desc) {
+       while (priv->chan[ch].fifo[iter].dma_desc != cur_desc &&
+              priv->chan[ch].fifo[iter].desc->next_desc != cur_desc) {
                iter = (iter + 1) & (priv->fifo_len - 1);
                if (iter == tail) {
                        dev_err(dev, "couldn't locate current descriptor\n");
@@ -472,6 +472,9 @@ static u32 current_desc_hdr(struct device *dev, int ch)
                }
        }
 
+       if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc)
+               return (priv->chan[ch].fifo[iter].desc + 1)->hdr;
+
        return priv->chan[ch].fifo[iter].desc->hdr;
 }
 
@@ -825,9 +828,12 @@ struct talitos_ctx {
        __be32 desc_hdr_template;
        u8 key[TALITOS_MAX_KEY_SIZE];
        u8 iv[TALITOS_MAX_IV_LENGTH];
+       dma_addr_t dma_key;
        unsigned int keylen;
        unsigned int enckeylen;
        unsigned int authkeylen;
+       dma_addr_t dma_buf;
+       dma_addr_t dma_hw_context;
 };
 
 #define HASH_MAX_BLOCK_SIZE            SHA512_BLOCK_SIZE
@@ -836,8 +842,8 @@ struct talitos_ctx {
 struct talitos_ahash_req_ctx {
        u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
        unsigned int hw_context_size;
-       u8 buf[HASH_MAX_BLOCK_SIZE];
-       u8 bufnext[HASH_MAX_BLOCK_SIZE];
+       u8 buf[2][HASH_MAX_BLOCK_SIZE];
+       int buf_idx;
        unsigned int swinit;
        unsigned int first;
        unsigned int last;
@@ -861,6 +867,7 @@ static int aead_setkey(struct crypto_aead *authenc,
                       const u8 *key, unsigned int keylen)
 {
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct device *dev = ctx->dev;
        struct crypto_authenc_keys keys;
 
        if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
@@ -869,12 +876,17 @@ static int aead_setkey(struct crypto_aead *authenc,
        if (keys.authkeylen + keys.enckeylen > TALITOS_MAX_KEY_SIZE)
                goto badkey;
 
+       if (ctx->keylen)
+               dma_unmap_single(dev, ctx->dma_key, ctx->keylen, DMA_TO_DEVICE);
+
        memcpy(ctx->key, keys.authkey, keys.authkeylen);
        memcpy(&ctx->key[keys.authkeylen], keys.enckey, keys.enckeylen);
 
        ctx->keylen = keys.authkeylen + keys.enckeylen;
        ctx->enckeylen = keys.enckeylen;
        ctx->authkeylen = keys.authkeylen;
+       ctx->dma_key = dma_map_single(dev, ctx->key, ctx->keylen,
+                                     DMA_TO_DEVICE);
 
        return 0;
 
@@ -948,13 +960,13 @@ static void ipsec_esp_unmap(struct device *dev,
        struct crypto_aead *aead = crypto_aead_reqtfm(areq);
        struct talitos_ctx *ctx = crypto_aead_ctx(aead);
        unsigned int ivsize = crypto_aead_ivsize(aead);
+       bool is_ipsec_esp = edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP;
+       struct talitos_ptr *civ_ptr = &edesc->desc.ptr[is_ipsec_esp ? 2 : 3];
 
-       if (edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP)
+       if (is_ipsec_esp)
                unmap_single_talitos_ptr(dev, &edesc->desc.ptr[6],
                                         DMA_FROM_DEVICE);
-       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[3], DMA_TO_DEVICE);
-       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE);
-       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[0], DMA_TO_DEVICE);
+       unmap_single_talitos_ptr(dev, civ_ptr, DMA_TO_DEVICE);
 
        talitos_sg_unmap(dev, edesc, areq->src, areq->dst, areq->cryptlen,
                         areq->assoclen);
@@ -963,7 +975,7 @@ static void ipsec_esp_unmap(struct device *dev,
                dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
                                 DMA_BIDIRECTIONAL);
 
-       if (!(edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP)) {
+       if (!is_ipsec_esp) {
                unsigned int dst_nents = edesc->dst_nents ? : 1;
 
                sg_pcopy_to_buffer(areq->dst, dst_nents, ctx->iv, ivsize,
@@ -983,6 +995,7 @@ static void ipsec_esp_encrypt_done(struct device *dev,
        struct aead_request *areq = context;
        struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
        unsigned int authsize = crypto_aead_authsize(authenc);
+       unsigned int ivsize = crypto_aead_ivsize(authenc);
        struct talitos_edesc *edesc;
        struct scatterlist *sg;
        void *icvdata;
@@ -1003,6 +1016,8 @@ static void ipsec_esp_encrypt_done(struct device *dev,
                       icvdata, authsize);
        }
 
+       dma_unmap_single(dev, edesc->iv_dma, ivsize, DMA_TO_DEVICE);
+
        kfree(edesc);
 
        aead_request_complete(areq, err);
@@ -1097,8 +1112,7 @@ static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count,
                        len = cryptlen;
 
                to_talitos_ptr(link_tbl_ptr + count,
-                              sg_dma_address(sg) + offset, 0);
-               to_talitos_ptr_len(link_tbl_ptr + count, len, 0);
+                              sg_dma_address(sg) + offset, len, 0);
                to_talitos_ptr_ext_set(link_tbl_ptr + count, 0, 0);
                count++;
                cryptlen -= len;
@@ -1116,7 +1130,7 @@ next:
        return count;
 }
 
-int talitos_sg_map(struct device *dev, struct scatterlist *src,
+static int talitos_sg_map(struct device *dev, struct scatterlist *src,
                   unsigned int len, struct talitos_edesc *edesc,
                   struct talitos_ptr *ptr,
                   int sg_count, unsigned int offset, int tbl_off)
@@ -1124,15 +1138,12 @@ int talitos_sg_map(struct device *dev, struct scatterlist *src,
        struct talitos_private *priv = dev_get_drvdata(dev);
        bool is_sec1 = has_ftr_sec1(priv);
 
-       to_talitos_ptr_len(ptr, len, is_sec1);
-       to_talitos_ptr_ext_set(ptr, 0, is_sec1);
-
        if (sg_count == 1) {
-               to_talitos_ptr(ptr, sg_dma_address(src) + offset, is_sec1);
+               to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1);
                return sg_count;
        }
        if (is_sec1) {
-               to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, is_sec1);
+               to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, len, is_sec1);
                return sg_count;
        }
        sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len,
@@ -1143,7 +1154,7 @@ int talitos_sg_map(struct device *dev, struct scatterlist *src,
                return sg_count;
        }
        to_talitos_ptr(ptr, edesc->dma_link_tbl +
-                           tbl_off * sizeof(struct talitos_ptr), is_sec1);
+                           tbl_off * sizeof(struct talitos_ptr), len, is_sec1);
        to_talitos_ptr_ext_or(ptr, DESC_PTR_LNKTBL_JUMP, is_sec1);
 
        return sg_count;
@@ -1170,10 +1181,12 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
        bool sync_needed = false;
        struct talitos_private *priv = dev_get_drvdata(dev);
        bool is_sec1 = has_ftr_sec1(priv);
+       bool is_ipsec_esp = desc->hdr & DESC_HDR_TYPE_IPSEC_ESP;
+       struct talitos_ptr *civ_ptr = &desc->ptr[is_ipsec_esp ? 2 : 3];
+       struct talitos_ptr *ckey_ptr = &desc->ptr[is_ipsec_esp ? 3 : 2];
 
        /* hmac key */
-       map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
-                              DMA_TO_DEVICE);
+       to_talitos_ptr(&desc->ptr[0], ctx->dma_key, ctx->authkeylen, is_sec1);
 
        sg_count = edesc->src_nents ?: 1;
        if (is_sec1 && sg_count > 1)
@@ -1194,25 +1207,11 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
        }
 
        /* cipher iv */
-       if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) {
-               to_talitos_ptr(&desc->ptr[2], edesc->iv_dma, is_sec1);
-               to_talitos_ptr_len(&desc->ptr[2], ivsize, is_sec1);
-               to_talitos_ptr_ext_set(&desc->ptr[2], 0, is_sec1);
-       } else {
-               to_talitos_ptr(&desc->ptr[3], edesc->iv_dma, is_sec1);
-               to_talitos_ptr_len(&desc->ptr[3], ivsize, is_sec1);
-               to_talitos_ptr_ext_set(&desc->ptr[3], 0, is_sec1);
-       }
+       to_talitos_ptr(civ_ptr, edesc->iv_dma, ivsize, is_sec1);
 
        /* cipher key */
-       if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)
-               map_single_talitos_ptr(dev, &desc->ptr[3], ctx->enckeylen,
-                                      (char *)&ctx->key + ctx->authkeylen,
-                                      DMA_TO_DEVICE);
-       else
-               map_single_talitos_ptr(dev, &desc->ptr[2], ctx->enckeylen,
-                                      (char *)&ctx->key + ctx->authkeylen,
-                                      DMA_TO_DEVICE);
+       to_talitos_ptr(ckey_ptr, ctx->dma_key  + ctx->authkeylen,
+                      ctx->enckeylen, is_sec1);
 
        /*
         * cipher in
@@ -1220,24 +1219,20 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
         * extent is bytes of HMAC postpended to ciphertext,
         * typically 12 for ipsec
         */
-       to_talitos_ptr_len(&desc->ptr[4], cryptlen, is_sec1);
-       to_talitos_ptr_ext_set(&desc->ptr[4], 0, is_sec1);
-
        sg_link_tbl_len = cryptlen;
 
-       if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) {
+       if (is_ipsec_esp) {
                to_talitos_ptr_ext_set(&desc->ptr[4], authsize, is_sec1);
 
-               if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV)
+               if (desc->hdr & DESC_HDR_MODE1_MDEU_CICV)
                        sg_link_tbl_len += authsize;
        }
 
-       sg_count = talitos_sg_map(dev, areq->src, cryptlen, edesc,
-                                 &desc->ptr[4], sg_count, areq->assoclen,
-                                 tbl_off);
+       ret = talitos_sg_map(dev, areq->src, sg_link_tbl_len, edesc,
+                            &desc->ptr[4], sg_count, areq->assoclen, tbl_off);
 
-       if (sg_count > 1) {
-               tbl_off += sg_count;
+       if (ret > 1) {
+               tbl_off += ret;
                sync_needed = true;
        }
 
@@ -1248,47 +1243,59 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
                        dma_map_sg(dev, areq->dst, sg_count, DMA_FROM_DEVICE);
        }
 
-       sg_count = talitos_sg_map(dev, areq->dst, cryptlen, edesc,
-                                 &desc->ptr[5], sg_count, areq->assoclen,
-                                 tbl_off);
+       ret = talitos_sg_map(dev, areq->dst, cryptlen, edesc, &desc->ptr[5],
+                            sg_count, areq->assoclen, tbl_off);
 
-       if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)
+       if (is_ipsec_esp)
                to_talitos_ptr_ext_or(&desc->ptr[5], authsize, is_sec1);
 
-       if (sg_count > 1) {
+       /* ICV data */
+       if (ret > 1) {
+               tbl_off += ret;
                edesc->icv_ool = true;
                sync_needed = true;
 
-               if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) {
+               if (is_ipsec_esp) {
                        struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off];
                        int offset = (edesc->src_nents + edesc->dst_nents + 2) *
                                     sizeof(struct talitos_ptr) + authsize;
 
                        /* Add an entry to the link table for ICV data */
-                       tbl_ptr += sg_count - 1;
-                       to_talitos_ptr_ext_set(tbl_ptr, 0, is_sec1);
-                       tbl_ptr++;
+                       to_talitos_ptr_ext_set(tbl_ptr - 1, 0, is_sec1);
                        to_talitos_ptr_ext_set(tbl_ptr, DESC_PTR_LNKTBL_RETURN,
                                               is_sec1);
-                       to_talitos_ptr_len(tbl_ptr, authsize, is_sec1);
 
                        /* icv data follows link tables */
                        to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl + offset,
-                                      is_sec1);
+                                      authsize, is_sec1);
+               } else {
+                       dma_addr_t addr = edesc->dma_link_tbl;
+
+                       if (is_sec1)
+                               addr += areq->assoclen + cryptlen;
+                       else
+                               addr += sizeof(struct talitos_ptr) * tbl_off;
+
+                       to_talitos_ptr(&desc->ptr[6], addr, authsize, is_sec1);
+               }
+       } else if (!is_ipsec_esp) {
+               ret = talitos_sg_map(dev, areq->dst, authsize, edesc,
+                                    &desc->ptr[6], sg_count, areq->assoclen +
+                                                             cryptlen,
+                                    tbl_off);
+               if (ret > 1) {
+                       tbl_off += ret;
+                       edesc->icv_ool = true;
+                       sync_needed = true;
+               } else {
+                       edesc->icv_ool = false;
                }
        } else {
                edesc->icv_ool = false;
        }
 
-       /* ICV data */
-       if (!(desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)) {
-               to_talitos_ptr_len(&desc->ptr[6], authsize, is_sec1);
-               to_talitos_ptr(&desc->ptr[6], edesc->dma_link_tbl +
-                              areq->assoclen + cryptlen, is_sec1);
-       }
-
        /* iv out */
-       if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)
+       if (is_ipsec_esp)
                map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv,
                                       DMA_FROM_DEVICE);
 
@@ -1387,22 +1394,31 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
                alloc_len += icv_stashing ? authsize : 0;
        }
 
+       /* if its a ahash, add space for a second desc next to the first one */
+       if (is_sec1 && !dst)
+               alloc_len += sizeof(struct talitos_desc);
+
        edesc = kmalloc(alloc_len, GFP_DMA | flags);
        if (!edesc) {
                dev_err(dev, "could not allocate edescriptor\n");
                err = ERR_PTR(-ENOMEM);
                goto error_sg;
        }
+       memset(&edesc->desc, 0, sizeof(edesc->desc));
 
        edesc->src_nents = src_nents;
        edesc->dst_nents = dst_nents;
        edesc->iv_dma = iv_dma;
        edesc->dma_len = dma_len;
-       if (dma_len)
-               edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
+       if (dma_len) {
+               void *addr = &edesc->link_tbl[0];
+
+               if (is_sec1 && !dst)
+                       addr += sizeof(struct talitos_desc);
+               edesc->dma_link_tbl = dma_map_single(dev, addr,
                                                     edesc->dma_len,
                                                     DMA_BIDIRECTIONAL);
-
+       }
        return edesc;
 error_sg:
        if (iv_dma)
@@ -1468,7 +1484,6 @@ static int aead_decrypt(struct aead_request *req)
                                  DESC_HDR_MODE1_MDEU_CICV;
 
                /* reset integrity check result bits */
-               edesc->desc.hdr_lo = 0;
 
                return ipsec_esp(edesc, req, ipsec_esp_decrypt_hwauth_done);
        }
@@ -1494,15 +1509,29 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher,
                             const u8 *key, unsigned int keylen)
 {
        struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+       struct device *dev = ctx->dev;
+       u32 tmp[DES_EXPKEY_WORDS];
 
        if (keylen > TALITOS_MAX_KEY_SIZE) {
                crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
                return -EINVAL;
        }
 
+       if (unlikely(crypto_ablkcipher_get_flags(cipher) &
+                    CRYPTO_TFM_REQ_WEAK_KEY) &&
+           !des_ekey(tmp, key)) {
+               crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_WEAK_KEY);
+               return -EINVAL;
+       }
+
+       if (ctx->keylen)
+               dma_unmap_single(dev, ctx->dma_key, ctx->keylen, DMA_TO_DEVICE);
+
        memcpy(&ctx->key, key, keylen);
        ctx->keylen = keylen;
 
+       ctx->dma_key = dma_map_single(dev, ctx->key, keylen, DMA_TO_DEVICE);
+
        return 0;
 }
 
@@ -1513,7 +1542,6 @@ static void common_nonsnoop_unmap(struct device *dev,
        unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
 
        talitos_sg_unmap(dev, edesc, areq->src, areq->dst, areq->nbytes, 0);
-       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE);
        unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], DMA_TO_DEVICE);
 
        if (edesc->dma_len)
@@ -1555,16 +1583,12 @@ static int common_nonsnoop(struct talitos_edesc *edesc,
        bool is_sec1 = has_ftr_sec1(priv);
 
        /* first DWORD empty */
-       desc->ptr[0] = zero_entry;
 
        /* cipher iv */
-       to_talitos_ptr(&desc->ptr[1], edesc->iv_dma, is_sec1);
-       to_talitos_ptr_len(&desc->ptr[1], ivsize, is_sec1);
-       to_talitos_ptr_ext_set(&desc->ptr[1], 0, is_sec1);
+       to_talitos_ptr(&desc->ptr[1], edesc->iv_dma, ivsize, is_sec1);
 
        /* cipher key */
-       map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
-                              (char *)&ctx->key, DMA_TO_DEVICE);
+       to_talitos_ptr(&desc->ptr[2], ctx->dma_key, ctx->keylen, is_sec1);
 
        sg_count = edesc->src_nents ?: 1;
        if (is_sec1 && sg_count > 1)
@@ -1599,7 +1623,6 @@ static int common_nonsnoop(struct talitos_edesc *edesc,
                               DMA_FROM_DEVICE);
 
        /* last DWORD empty */
-       desc->ptr[6] = zero_entry;
 
        if (sync_needed)
                dma_sync_single_for_device(dev, edesc->dma_link_tbl,
@@ -1663,26 +1686,16 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
                                       struct ahash_request *areq)
 {
        struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
-       struct talitos_private *priv = dev_get_drvdata(dev);
-       bool is_sec1 = has_ftr_sec1(priv);
-
-       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
 
        talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0);
 
-       /* When using hashctx-in, must unmap it. */
-       if (from_talitos_ptr_len(&edesc->desc.ptr[1], is_sec1))
-               unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1],
-                                        DMA_TO_DEVICE);
-
-       if (from_talitos_ptr_len(&edesc->desc.ptr[2], is_sec1))
-               unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2],
-                                        DMA_TO_DEVICE);
-
        if (edesc->dma_len)
                dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
                                 DMA_BIDIRECTIONAL);
 
+       if (edesc->desc.next_desc)
+               dma_unmap_single(dev, be32_to_cpu(edesc->desc.next_desc),
+                                TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
 }
 
 static void ahash_done(struct device *dev,
@@ -1696,7 +1709,7 @@ static void ahash_done(struct device *dev,
 
        if (!req_ctx->last && req_ctx->to_hash_later) {
                /* Position any partial block for next update/final/finup */
-               memcpy(req_ctx->buf, req_ctx->bufnext, req_ctx->to_hash_later);
+               req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
                req_ctx->nbuf = req_ctx->to_hash_later;
        }
        common_nonsnoop_hash_unmap(dev, edesc, areq);
@@ -1710,7 +1723,7 @@ static void ahash_done(struct device *dev,
  * SEC1 doesn't like hashing of 0 sized message, so we do the padding
  * ourself and submit a padded block
  */
-void talitos_handle_buggy_hash(struct talitos_ctx *ctx,
+static void talitos_handle_buggy_hash(struct talitos_ctx *ctx,
                               struct talitos_edesc *edesc,
                               struct talitos_ptr *ptr)
 {
@@ -1729,6 +1742,7 @@ void talitos_handle_buggy_hash(struct talitos_ctx *ctx,
 
 static int common_nonsnoop_hash(struct talitos_edesc *edesc,
                                struct ahash_request *areq, unsigned int length,
+                               unsigned int offset,
                                void (*callback) (struct device *dev,
                                                  struct talitos_desc *desc,
                                                  void *context, int error))
@@ -1745,44 +1759,48 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
        int sg_count;
 
        /* first DWORD empty */
-       desc->ptr[0] = zero_entry;
 
        /* hash context in */
        if (!req_ctx->first || req_ctx->swinit) {
-               map_single_talitos_ptr(dev, &desc->ptr[1],
-                                      req_ctx->hw_context_size,
-                                      (char *)req_ctx->hw_context,
-                                      DMA_TO_DEVICE);
+               to_talitos_ptr(&desc->ptr[1], ctx->dma_hw_context,
+                              req_ctx->hw_context_size, is_sec1);
                req_ctx->swinit = 0;
-       } else {
-               desc->ptr[1] = zero_entry;
        }
        /* Indicate next op is not the first. */
        req_ctx->first = 0;
 
        /* HMAC key */
        if (ctx->keylen)
-               map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
-                                      (char *)&ctx->key, DMA_TO_DEVICE);
-       else
-               desc->ptr[2] = zero_entry;
+               to_talitos_ptr(&desc->ptr[2], ctx->dma_key, ctx->keylen,
+                              is_sec1);
+
+       if (is_sec1 && req_ctx->nbuf)
+               length -= req_ctx->nbuf;
 
        sg_count = edesc->src_nents ?: 1;
        if (is_sec1 && sg_count > 1)
-               sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length);
-       else
+               sg_pcopy_to_buffer(req_ctx->psrc, sg_count,
+                                  edesc->buf + sizeof(struct talitos_desc),
+                                  length, req_ctx->nbuf);
+       else if (length)
                sg_count = dma_map_sg(dev, req_ctx->psrc, sg_count,
                                      DMA_TO_DEVICE);
        /*
         * data in
         */
-       sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
-                                 &desc->ptr[3], sg_count, 0, 0);
-       if (sg_count > 1)
-               sync_needed = true;
+       if (is_sec1 && req_ctx->nbuf) {
+               dma_addr_t dma_buf = ctx->dma_buf + req_ctx->buf_idx *
+                                                   HASH_MAX_BLOCK_SIZE;
+
+               to_talitos_ptr(&desc->ptr[3], dma_buf, req_ctx->nbuf, is_sec1);
+       } else {
+               sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
+                                         &desc->ptr[3], sg_count, offset, 0);
+               if (sg_count > 1)
+                       sync_needed = true;
+       }
 
        /* fifth DWORD empty */
-       desc->ptr[4] = zero_entry;
 
        /* hash/HMAC out -or- hash context out */
        if (req_ctx->last)
@@ -1790,16 +1808,44 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
                                       crypto_ahash_digestsize(tfm),
                                       areq->result, DMA_FROM_DEVICE);
        else
-               map_single_talitos_ptr(dev, &desc->ptr[5],
-                                      req_ctx->hw_context_size,
-                                      req_ctx->hw_context, DMA_FROM_DEVICE);
+               to_talitos_ptr(&desc->ptr[5], ctx->dma_hw_context,
+                              req_ctx->hw_context_size, is_sec1);
 
        /* last DWORD empty */
-       desc->ptr[6] = zero_entry;
 
        if (is_sec1 && from_talitos_ptr_len(&desc->ptr[3], true) == 0)
                talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]);
 
+       if (is_sec1 && req_ctx->nbuf && length) {
+               struct talitos_desc *desc2 = desc + 1;
+               dma_addr_t next_desc;
+
+               memset(desc2, 0, sizeof(*desc2));
+               desc2->hdr = desc->hdr;
+               desc2->hdr &= ~DESC_HDR_MODE0_MDEU_INIT;
+               desc2->hdr1 = desc2->hdr;
+               desc->hdr &= ~DESC_HDR_MODE0_MDEU_PAD;
+               desc->hdr |= DESC_HDR_MODE0_MDEU_CONT;
+               desc->hdr &= ~DESC_HDR_DONE_NOTIFY;
+
+               to_talitos_ptr(&desc2->ptr[1], ctx->dma_hw_context,
+                              req_ctx->hw_context_size, is_sec1);
+
+               copy_talitos_ptr(&desc2->ptr[2], &desc->ptr[2], is_sec1);
+               sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
+                                         &desc2->ptr[3], sg_count, offset, 0);
+               if (sg_count > 1)
+                       sync_needed = true;
+               copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
+               if (req_ctx->last)
+                       to_talitos_ptr(&desc->ptr[5], ctx->dma_hw_context,
+                                      req_ctx->hw_context_size, is_sec1);
+
+               next_desc = dma_map_single(dev, &desc2->hdr1, TALITOS_DESC_SIZE,
+                                          DMA_BIDIRECTIONAL);
+               desc->next_desc = cpu_to_be32(next_desc);
+       }
+
        if (sync_needed)
                dma_sync_single_for_device(dev, edesc->dma_link_tbl,
                                           edesc->dma_len, DMA_BIDIRECTIONAL);
@@ -1818,6 +1864,11 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
        struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
        struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
        struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+       struct talitos_private *priv = dev_get_drvdata(ctx->dev);
+       bool is_sec1 = has_ftr_sec1(priv);
+
+       if (is_sec1)
+               nbytes -= req_ctx->nbuf;
 
        return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, NULL, 0,
                                   nbytes, 0, 0, 0, areq->base.flags, false);
@@ -1826,17 +1877,35 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
 static int ahash_init(struct ahash_request *areq)
 {
        struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+       struct device *dev = ctx->dev;
        struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+       unsigned int size;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       bool is_sec1 = has_ftr_sec1(priv);
 
        /* Initialize the context */
+       req_ctx->buf_idx = 0;
        req_ctx->nbuf = 0;
        req_ctx->first = 1; /* first indicates h/w must init its context */
        req_ctx->swinit = 0; /* assume h/w init of context */
-       req_ctx->hw_context_size =
-               (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+       size =  (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
                        ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
                        : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+       req_ctx->hw_context_size = size;
 
+       if (ctx->dma_hw_context)
+               dma_unmap_single(dev, ctx->dma_hw_context, size,
+                                DMA_BIDIRECTIONAL);
+       ctx->dma_hw_context = dma_map_single(dev, req_ctx->hw_context, size,
+                                            DMA_BIDIRECTIONAL);
+       if (ctx->dma_buf)
+               dma_unmap_single(dev, ctx->dma_buf, sizeof(req_ctx->buf),
+                                DMA_TO_DEVICE);
+       if (is_sec1)
+               ctx->dma_buf = dma_map_single(dev, req_ctx->buf,
+                                             sizeof(req_ctx->buf),
+                                             DMA_TO_DEVICE);
        return 0;
 }
 
@@ -1847,6 +1916,9 @@ static int ahash_init(struct ahash_request *areq)
 static int ahash_init_sha224_swinit(struct ahash_request *areq)
 {
        struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+       struct device *dev = ctx->dev;
 
        ahash_init(areq);
        req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
@@ -1864,6 +1936,9 @@ static int ahash_init_sha224_swinit(struct ahash_request *areq)
        req_ctx->hw_context[8] = 0;
        req_ctx->hw_context[9] = 0;
 
+       dma_sync_single_for_device(dev, ctx->dma_hw_context,
+                                  req_ctx->hw_context_size, DMA_TO_DEVICE);
+
        return 0;
 }
 
@@ -1879,6 +1954,11 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
        unsigned int to_hash_later;
        unsigned int nsg;
        int nents;
+       struct device *dev = ctx->dev;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       bool is_sec1 = has_ftr_sec1(priv);
+       int offset = 0;
+       u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
 
        if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
                /* Buffer up to one whole block */
@@ -1888,7 +1968,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
                        return nents;
                }
                sg_copy_to_buffer(areq->src, nents,
-                                 req_ctx->buf + req_ctx->nbuf, nbytes);
+                                 ctx_buf + req_ctx->nbuf, nbytes);
                req_ctx->nbuf += nbytes;
                return 0;
        }
@@ -1909,13 +1989,27 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
        }
 
        /* Chain in any previously buffered data */
-       if (req_ctx->nbuf) {
+       if (!is_sec1 && req_ctx->nbuf) {
                nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1;
                sg_init_table(req_ctx->bufsl, nsg);
-               sg_set_buf(req_ctx->bufsl, req_ctx->buf, req_ctx->nbuf);
+               sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
                if (nsg > 1)
                        sg_chain(req_ctx->bufsl, 2, areq->src);
                req_ctx->psrc = req_ctx->bufsl;
+       } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
+               if (nbytes_to_hash > blocksize)
+                       offset = blocksize - req_ctx->nbuf;
+               else
+                       offset = nbytes_to_hash - req_ctx->nbuf;
+               nents = sg_nents_for_len(areq->src, offset);
+               if (nents < 0) {
+                       dev_err(ctx->dev, "Invalid number of src SG.\n");
+                       return nents;
+               }
+               sg_copy_to_buffer(areq->src, nents,
+                                 ctx_buf + req_ctx->nbuf, offset);
+               req_ctx->nbuf += offset;
+               req_ctx->psrc = areq->src;
        } else
                req_ctx->psrc = areq->src;
 
@@ -1926,7 +2020,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
                        return nents;
                }
                sg_pcopy_to_buffer(areq->src, nents,
-                                     req_ctx->bufnext,
+                                  req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
                                      to_hash_later,
                                      nbytes - to_hash_later);
        }
@@ -1948,6 +2042,13 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
        /* request SEC to INIT hash. */
        if (req_ctx->first && !req_ctx->swinit)
                edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
+       if (is_sec1) {
+               dma_addr_t dma_buf = ctx->dma_buf + req_ctx->buf_idx *
+                                                   HASH_MAX_BLOCK_SIZE;
+
+               dma_sync_single_for_device(dev, dma_buf,
+                                          req_ctx->nbuf, DMA_TO_DEVICE);
+       }
 
        /* When the tfm context has a keylen, it's an HMAC.
         * A first or last (ie. not middle) descriptor must request HMAC.
@@ -1955,7 +2056,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
        if (ctx->keylen && (req_ctx->first || req_ctx->last))
                edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
 
-       return common_nonsnoop_hash(edesc, areq, nbytes_to_hash,
+       return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, offset,
                                    ahash_done);
 }
 
@@ -2001,10 +2102,15 @@ 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;
+       struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ahash_ctx(ahash);
+       struct device *dev = ctx->dev;
 
+       dma_sync_single_for_cpu(dev, ctx->dma_hw_context,
+                               req_ctx->hw_context_size, DMA_FROM_DEVICE);
        memcpy(export->hw_context, req_ctx->hw_context,
               req_ctx->hw_context_size);
-       memcpy(export->buf, req_ctx->buf, req_ctx->nbuf);
+       memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
        export->swinit = req_ctx->swinit;
        export->first = req_ctx->first;
        export->last = req_ctx->last;
@@ -2019,15 +2125,32 @@ 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;
+       unsigned int size;
+       struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+       struct device *dev = ctx->dev;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       bool is_sec1 = has_ftr_sec1(priv);
 
        memset(req_ctx, 0, sizeof(*req_ctx));
-       req_ctx->hw_context_size =
-               (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+       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->hw_context_size = size;
+       if (ctx->dma_hw_context)
+               dma_unmap_single(dev, ctx->dma_hw_context, size,
+                                DMA_BIDIRECTIONAL);
+
+       memcpy(req_ctx->hw_context, export->hw_context, size);
+       ctx->dma_hw_context = dma_map_single(dev, req_ctx->hw_context, size,
+                                            DMA_BIDIRECTIONAL);
+       if (ctx->dma_buf)
+               dma_unmap_single(dev, ctx->dma_buf, sizeof(req_ctx->buf),
+                                DMA_TO_DEVICE);
+       memcpy(req_ctx->buf[0], export->buf, export->nbuf);
+       if (is_sec1)
+               ctx->dma_buf = dma_map_single(dev, req_ctx->buf,
+                                             sizeof(req_ctx->buf),
+                                             DMA_TO_DEVICE);
        req_ctx->swinit = export->swinit;
        req_ctx->first = export->first;
        req_ctx->last = export->last;
@@ -2037,22 +2160,6 @@ static int ahash_import(struct ahash_request *areq, const void *in)
        return 0;
 }
 
-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)
 {
@@ -2060,10 +2167,10 @@ static int keyhash(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen,
 
        struct scatterlist sg[1];
        struct ahash_request *req;
-       struct keyhash_result hresult;
+       struct crypto_wait wait;
        int ret;
 
-       init_completion(&hresult.completion);
+       crypto_init_wait(&wait);
 
        req = ahash_request_alloc(tfm, GFP_KERNEL);
        if (!req)
@@ -2072,25 +2179,13 @@ static int keyhash(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen,
        /* 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);
+                                  crypto_req_done, &wait);
 
        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;
-       }
+       ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
+
        ahash_request_free(req);
 
        return ret;
@@ -2100,6 +2195,7 @@ 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));
+       struct device *dev = ctx->dev;
        unsigned int blocksize =
                        crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
        unsigned int digestsize = crypto_ahash_digestsize(tfm);
@@ -2122,7 +2218,11 @@ static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
                memcpy(ctx->key, hash, digestsize);
        }
 
+       if (ctx->keylen)
+               dma_unmap_single(dev, ctx->dma_key, ctx->keylen, DMA_TO_DEVICE);
+
        ctx->keylen = keysize;
+       ctx->dma_key = dma_map_single(dev, ctx->key, keysize, DMA_TO_DEVICE);
 
        return 0;
 }
@@ -2614,7 +2714,7 @@ static struct talitos_alg_template driver_algs[] = {
                                .ivsize = AES_BLOCK_SIZE,
                        }
                },
-               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+               .desc_hdr_template = DESC_HDR_TYPE_AESU_CTR_NONSNOOP |
                                     DESC_HDR_SEL0_AESU |
                                     DESC_HDR_MODE0_AESU_CTR,
        },
@@ -2951,6 +3051,36 @@ static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
        return 0;
 }
 
+static void talitos_cra_exit(struct crypto_tfm *tfm)
+{
+       struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct device *dev = ctx->dev;
+
+       if (ctx->keylen)
+               dma_unmap_single(dev, ctx->dma_key, ctx->keylen, DMA_TO_DEVICE);
+}
+
+static void talitos_cra_exit_ahash(struct crypto_tfm *tfm)
+{
+       struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct device *dev = ctx->dev;
+       unsigned int size;
+
+       talitos_cra_exit(tfm);
+
+       size = (crypto_ahash_digestsize(__crypto_ahash_cast(tfm)) <=
+               SHA256_DIGEST_SIZE)
+              ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+              : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+
+       if (ctx->dma_hw_context)
+               dma_unmap_single(dev, ctx->dma_hw_context, size,
+                                DMA_BIDIRECTIONAL);
+       if (ctx->dma_buf)
+               dma_unmap_single(dev, ctx->dma_buf, HASH_MAX_BLOCK_SIZE * 2,
+                                DMA_TO_DEVICE);
+}
+
 /*
  * given the alg's descriptor header template, determine whether descriptor
  * type and primary/secondary execution units required match the hw
@@ -2989,17 +3119,11 @@ static int talitos_remove(struct platform_device *ofdev)
                        break;
                }
                list_del(&t_alg->entry);
-               kfree(t_alg);
        }
 
        if (hw_supports(dev, DESC_HDR_SEL0_RNG))
                talitos_unregister_rng(dev);
 
-       for (i = 0; priv->chan && i < priv->num_channels; i++)
-               kfree(priv->chan[i].fifo);
-
-       kfree(priv->chan);
-
        for (i = 0; i < 2; i++)
                if (priv->irq[i]) {
                        free_irq(priv->irq[i], dev);
@@ -3010,10 +3134,6 @@ static int talitos_remove(struct platform_device *ofdev)
        if (priv->irq[1])
                tasklet_kill(&priv->done_task[1]);
 
-       iounmap(priv->reg);
-
-       kfree(priv);
-
        return 0;
 }
 
@@ -3025,7 +3145,8 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
        struct talitos_crypto_alg *t_alg;
        struct crypto_alg *alg;
 
-       t_alg = kzalloc(sizeof(struct talitos_crypto_alg), GFP_KERNEL);
+       t_alg = devm_kzalloc(dev, sizeof(struct talitos_crypto_alg),
+                            GFP_KERNEL);
        if (!t_alg)
                return ERR_PTR(-ENOMEM);
 
@@ -3035,6 +3156,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
        case CRYPTO_ALG_TYPE_ABLKCIPHER:
                alg = &t_alg->algt.alg.crypto;
                alg->cra_init = talitos_cra_init;
+               alg->cra_exit = talitos_cra_exit;
                alg->cra_type = &crypto_ablkcipher_type;
                alg->cra_ablkcipher.setkey = ablkcipher_setkey;
                alg->cra_ablkcipher.encrypt = ablkcipher_encrypt;
@@ -3043,14 +3165,21 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
                break;
        case CRYPTO_ALG_TYPE_AEAD:
                alg = &t_alg->algt.alg.aead.base;
+               alg->cra_exit = talitos_cra_exit;
                t_alg->algt.alg.aead.init = talitos_cra_init_aead;
                t_alg->algt.alg.aead.setkey = aead_setkey;
                t_alg->algt.alg.aead.encrypt = aead_encrypt;
                t_alg->algt.alg.aead.decrypt = aead_decrypt;
+               if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) &&
+                   !strncmp(alg->cra_name, "authenc(hmac(sha224)", 20)) {
+                       devm_kfree(dev, t_alg);
+                       return ERR_PTR(-ENOTSUPP);
+               }
                break;
        case CRYPTO_ALG_TYPE_AHASH:
                alg = &t_alg->algt.alg.hash.halg.base;
                alg->cra_init = talitos_cra_init_ahash;
+               alg->cra_exit = talitos_cra_exit_ahash;
                alg->cra_type = &crypto_ahash_type;
                t_alg->algt.alg.hash.init = ahash_init;
                t_alg->algt.alg.hash.update = ahash_update;
@@ -3064,7 +3193,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
 
                if (!(priv->features & TALITOS_FTR_HMAC_OK) &&
                    !strncmp(alg->cra_name, "hmac", 4)) {
-                       kfree(t_alg);
+                       devm_kfree(dev, t_alg);
                        return ERR_PTR(-ENOTSUPP);
                }
                if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) &&
@@ -3079,7 +3208,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
                break;
        default:
                dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type);
-               kfree(t_alg);
+               devm_kfree(dev, t_alg);
                return ERR_PTR(-EINVAL);
        }
 
@@ -3156,11 +3285,11 @@ static int talitos_probe(struct platform_device *ofdev)
        struct device *dev = &ofdev->dev;
        struct device_node *np = ofdev->dev.of_node;
        struct talitos_private *priv;
-       const unsigned int *prop;
        int i, err;
        int stride;
+       struct resource *res;
 
-       priv = kzalloc(sizeof(struct talitos_private), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(struct talitos_private), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -3172,7 +3301,10 @@ static int talitos_probe(struct platform_device *ofdev)
 
        spin_lock_init(&priv->reg_lock);
 
-       priv->reg = of_iomap(np, 0);
+       res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+       priv->reg = devm_ioremap(dev, res->start, resource_size(res));
        if (!priv->reg) {
                dev_err(dev, "failed to of_iomap\n");
                err = -ENOMEM;
@@ -3180,21 +3312,11 @@ static int talitos_probe(struct platform_device *ofdev)
        }
 
        /* get SEC version capabilities from device tree */
-       prop = of_get_property(np, "fsl,num-channels", NULL);
-       if (prop)
-               priv->num_channels = *prop;
-
-       prop = of_get_property(np, "fsl,channel-fifo-len", NULL);
-       if (prop)
-               priv->chfifo_len = *prop;
-
-       prop = of_get_property(np, "fsl,exec-units-mask", NULL);
-       if (prop)
-               priv->exec_units = *prop;
-
-       prop = of_get_property(np, "fsl,descriptor-types-mask", NULL);
-       if (prop)
-               priv->desc_types = *prop;
+       of_property_read_u32(np, "fsl,num-channels", &priv->num_channels);
+       of_property_read_u32(np, "fsl,channel-fifo-len", &priv->chfifo_len);
+       of_property_read_u32(np, "fsl,exec-units-mask", &priv->exec_units);
+       of_property_read_u32(np, "fsl,descriptor-types-mask",
+                            &priv->desc_types);
 
        if (!is_power_of_2(priv->num_channels) || !priv->chfifo_len ||
            !priv->exec_units || !priv->desc_types) {
@@ -3244,22 +3366,29 @@ static int talitos_probe(struct platform_device *ofdev)
                goto err_out;
 
        if (of_device_is_compatible(np, "fsl,sec1.0")) {
-               tasklet_init(&priv->done_task[0], talitos1_done_4ch,
-                            (unsigned long)dev);
-       } else {
-               if (!priv->irq[1]) {
-                       tasklet_init(&priv->done_task[0], talitos2_done_4ch,
+               if (priv->num_channels == 1)
+                       tasklet_init(&priv->done_task[0], talitos1_done_ch0,
                                     (unsigned long)dev);
-               } else {
+               else
+                       tasklet_init(&priv->done_task[0], talitos1_done_4ch,
+                                    (unsigned long)dev);
+       } else {
+               if (priv->irq[1]) {
                        tasklet_init(&priv->done_task[0], talitos2_done_ch0_2,
                                     (unsigned long)dev);
                        tasklet_init(&priv->done_task[1], talitos2_done_ch1_3,
                                     (unsigned long)dev);
+               } else if (priv->num_channels == 1) {
+                       tasklet_init(&priv->done_task[0], talitos2_done_ch0,
+                                    (unsigned long)dev);
+               } else {
+                       tasklet_init(&priv->done_task[0], talitos2_done_4ch,
+                                    (unsigned long)dev);
                }
        }
 
-       priv->chan = kzalloc(sizeof(struct talitos_channel) *
-                            priv->num_channels, GFP_KERNEL);
+       priv->chan = devm_kzalloc(dev, sizeof(struct talitos_channel) *
+                                      priv->num_channels, GFP_KERNEL);
        if (!priv->chan) {
                dev_err(dev, "failed to allocate channel management space\n");
                err = -ENOMEM;
@@ -3276,8 +3405,9 @@ static int talitos_probe(struct platform_device *ofdev)
                spin_lock_init(&priv->chan[i].head_lock);
                spin_lock_init(&priv->chan[i].tail_lock);
 
-               priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) *
-                                            priv->fifo_len, GFP_KERNEL);
+               priv->chan[i].fifo = devm_kzalloc(dev,
+                                               sizeof(struct talitos_request) *
+                                               priv->fifo_len, GFP_KERNEL);
                if (!priv->chan[i].fifo) {
                        dev_err(dev, "failed to allocate request fifo %d\n", i);
                        err = -ENOMEM;
@@ -3343,7 +3473,7 @@ static int talitos_probe(struct platform_device *ofdev)
                        if (err) {
                                dev_err(dev, "%s alg registration failed\n",
                                        alg->cra_driver_name);
-                               kfree(t_alg);
+                               devm_kfree(dev, t_alg);
                        } else
                                list_add_tail(&t_alg->entry, &priv->alg_list);
                }