Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  caamalg_qi2.c   Sprache: C

 
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
 * Copyright 2015-2016 Freescale Semiconductor Inc.
 * Copyright 2017-2019 NXP
 */


#include "compat.h"
#include "regs.h"
#include "caamalg_qi2.h"
#include "dpseci_cmd.h"
#include "desc_constr.h"
#include "error.h"
#include "sg_sw_sec4.h"
#include "sg_sw_qm2.h"
#include "key_gen.h"
#include "caamalg_desc.h"
#include "caamhash_desc.h"
#include "dpseci-debugfs.h"
#include <linux/dma-mapping.h>
#include <linux/fsl/mc.h>
#include <linux/kernel.h>
#include <linux/string_choices.h>
#include <soc/fsl/dpaa2-io.h>
#include <soc/fsl/dpaa2-fd.h>
#include <crypto/xts.h>
#include <linux/unaligned.h>

#define CAAM_CRA_PRIORITY 2000

/* max key is sum of AES_MAX_KEY_SIZE, max split key size */
#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE + \
     SHA512_DIGEST_SIZE * 2)

/*
 * This is a cache of buffers, from which the users of CAAM QI driver
 * can allocate short buffers. It's speedier than doing kmalloc on the hotpath.
 * NOTE: A more elegant solution would be to have some headroom in the frames
 *       being processed. This can be added by the dpaa2-eth driver. This would
 *       pose a problem for userspace application processing which cannot
 *       know of this limitation. So for now, this will work.
 * NOTE: The memcache is SMP-safe. No need to handle spinlocks in-here
 */

static struct kmem_cache *qi_cache;

struct caam_alg_entry {
 struct device *dev;
 int class1_alg_type;
 int class2_alg_type;
 bool rfc3686;
 bool geniv;
 bool nodkp;
};

struct caam_aead_alg {
 struct aead_alg aead;
 struct caam_alg_entry caam;
 bool registered;
};

struct caam_skcipher_alg {
 struct skcipher_alg skcipher;
 struct caam_alg_entry caam;
 bool registered;
};

/**
 * struct caam_ctx - per-session context
 * @flc: Flow Contexts array
 * @key:  [authentication key], encryption key
 * @flc_dma: I/O virtual addresses of the Flow Contexts
 * @key_dma: I/O virtual address of the key
 * @dir: DMA direction for mapping key and Flow Contexts
 * @dev: dpseci device
 * @adata: authentication algorithm details
 * @cdata: encryption algorithm details
 * @authsize: authentication tag (a.k.a. ICV / MAC) size
 * @xts_key_fallback: true if fallback tfm needs to be used due
 *       to unsupported xts key lengths
 * @fallback: xts fallback tfm
 */

struct caam_ctx {
 struct caam_flc flc[NUM_OP];
 u8 key[CAAM_MAX_KEY_SIZE];
 dma_addr_t flc_dma[NUM_OP];
 dma_addr_t key_dma;
 enum dma_data_direction dir;
 struct device *dev;
 struct alginfo adata;
 struct alginfo cdata;
 unsigned int authsize;
 bool xts_key_fallback;
 struct crypto_skcipher *fallback;
};

static void *dpaa2_caam_iova_to_virt(struct dpaa2_caam_priv *priv,
         dma_addr_t iova_addr)
{
 phys_addr_t phys_addr;

 phys_addr = priv->domain ? iommu_iova_to_phys(priv->domain, iova_addr) :
       iova_addr;

 return phys_to_virt(phys_addr);
}

/*
 * qi_cache_zalloc - Allocate buffers from CAAM-QI cache
 *
 * Allocate data on the hotpath. Instead of using kzalloc, one can use the
 * services of the CAAM QI memory cache (backed by kmem_cache). The buffers
 * will have a size of CAAM_QI_MEMCACHE_SIZE, which should be sufficient for
 * hosting 16 SG entries.
 *
 * @flags - flags that would be used for the equivalent kmalloc(..) call
 *
 * Returns a pointer to a retrieved buffer on success or NULL on failure.
 */

static inline void *qi_cache_zalloc(gfp_t flags)
{
 return kmem_cache_zalloc(qi_cache, flags);
}

/*
 * qi_cache_free - Frees buffers allocated from CAAM-QI cache
 *
 * @obj - buffer previously allocated by qi_cache_zalloc
 *
 * No checking is being done, the call is a passthrough call to
 * kmem_cache_free(...)
 */

static inline void qi_cache_free(void *obj)
{
 kmem_cache_free(qi_cache, obj);
}

static struct caam_request *to_caam_req(struct crypto_async_request *areq)
{
 switch (crypto_tfm_alg_type(areq->tfm)) {
 case CRYPTO_ALG_TYPE_SKCIPHER:
  return skcipher_request_ctx_dma(skcipher_request_cast(areq));
 case CRYPTO_ALG_TYPE_AEAD:
  return aead_request_ctx_dma(
   container_of(areq, struct aead_request, base));
 case CRYPTO_ALG_TYPE_AHASH:
  return ahash_request_ctx_dma(ahash_request_cast(areq));
 default:
  return ERR_PTR(-EINVAL);
 }
}

static void caam_unmap(struct device *dev, struct scatterlist *src,
         struct scatterlist *dst, int src_nents,
         int dst_nents, dma_addr_t iv_dma, int ivsize,
         enum dma_data_direction iv_dir, dma_addr_t qm_sg_dma,
         int qm_sg_bytes)
{
 if (dst != src) {
  if (src_nents)
   dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE);
  if (dst_nents)
   dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE);
 } else {
  dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL);
 }

 if (iv_dma)
  dma_unmap_single(dev, iv_dma, ivsize, iv_dir);

 if (qm_sg_bytes)
  dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE);
}

static int aead_set_sh_desc(struct crypto_aead *aead)
{
 struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
       typeof(*alg), aead);
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 unsigned int ivsize = crypto_aead_ivsize(aead);
 struct device *dev = ctx->dev;
 struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
 struct caam_flc *flc;
 u32 *desc;
 u32 ctx1_iv_off = 0;
 u32 *nonce = NULL;
 unsigned int data_len[2];
 u32 inl_mask;
 const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
          OP_ALG_AAI_CTR_MOD128);
 const bool is_rfc3686 = alg->caam.rfc3686;

 if (!ctx->cdata.keylen || !ctx->authsize)
  return 0;

 /*
 * AES-CTR needs to load IV in CONTEXT1 reg
 * at an offset of 128bits (16bytes)
 * CONTEXT1[255:128] = IV
 */

 if (ctr_mode)
  ctx1_iv_off = 16;

 /*
 * RFC3686 specific:
 * CONTEXT1[255:128] = {NONCE, IV, COUNTER}
 */

 if (is_rfc3686) {
  ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE;
  nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad +
    ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE);
 }

 /*
 * In case |user key| > |derived key|, using DKP<imm,imm> would result
 * in invalid opcodes (last bytes of user key) in the resulting
 * descriptor. Use DKP<ptr,imm> instead => both virtual and dma key
 * addresses are needed.
 */

 ctx->adata.key_virt = ctx->key;
 ctx->adata.key_dma = ctx->key_dma;

 ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
 ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;

 data_len[0] = ctx->adata.keylen_pad;
 data_len[1] = ctx->cdata.keylen;

 /* aead_encrypt shared descriptor */
 if (desc_inline_query((alg->caam.geniv ? DESC_QI_AEAD_GIVENC_LEN :
       DESC_QI_AEAD_ENC_LEN) +
         (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0),
         DESC_JOB_IO_LEN, data_len, &inl_mask,
         ARRAY_SIZE(data_len)) < 0)
  return -EINVAL;

 ctx->adata.key_inline = !!(inl_mask & 1);
 ctx->cdata.key_inline = !!(inl_mask & 2);

 flc = &ctx->flc[ENCRYPT];
 desc = flc->sh_desc;

 if (alg->caam.geniv)
  cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata,
       ivsize, ctx->authsize, is_rfc3686,
       nonce, ctx1_iv_off, true,
       priv->sec_attr.era);
 else
  cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata,
           ivsize, ctx->authsize, is_rfc3686, nonce,
           ctx1_iv_off, true, priv->sec_attr.era);

 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 /* aead_decrypt shared descriptor */
 if (desc_inline_query(DESC_QI_AEAD_DEC_LEN +
         (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0),
         DESC_JOB_IO_LEN, data_len, &inl_mask,
         ARRAY_SIZE(data_len)) < 0)
  return -EINVAL;

 ctx->adata.key_inline = !!(inl_mask & 1);
 ctx->cdata.key_inline = !!(inl_mask & 2);

 flc = &ctx->flc[DECRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata,
          ivsize, ctx->authsize, alg->caam.geniv,
          is_rfc3686, nonce, ctx1_iv_off, true,
          priv->sec_attr.era);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 return 0;
}

static int aead_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(authenc);

 ctx->authsize = authsize;
 aead_set_sh_desc(authenc);

 return 0;
}

static int aead_setkey(struct crypto_aead *aead, const u8 *key,
         unsigned int keylen)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct device *dev = ctx->dev;
 struct crypto_authenc_keys keys;

 if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
  goto badkey;

 dev_dbg(dev, "keylen %d enckeylen %d authkeylen %d\n",
  keys.authkeylen + keys.enckeylen, keys.enckeylen,
  keys.authkeylen);
 print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);

 ctx->adata.keylen = keys.authkeylen;
 ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
           OP_ALG_ALGSEL_MASK);

 if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
  goto badkey;

 memcpy(ctx->key, keys.authkey, keys.authkeylen);
 memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
 dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad +
       keys.enckeylen, ctx->dir);
 print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
        ctx->adata.keylen_pad + keys.enckeylen, 1);

 ctx->cdata.keylen = keys.enckeylen;

 memzero_explicit(&keys, sizeof(keys));
 return aead_set_sh_desc(aead);
badkey:
 memzero_explicit(&keys, sizeof(keys));
 return -EINVAL;
}

static int des3_aead_setkey(struct crypto_aead *aead, const u8 *key,
       unsigned int keylen)
{
 struct crypto_authenc_keys keys;
 int err;

 err = crypto_authenc_extractkeys(&keys, key, keylen);
 if (unlikely(err))
  goto out;

 err = -EINVAL;
 if (keys.enckeylen != DES3_EDE_KEY_SIZE)
  goto out;

 err = crypto_des3_ede_verify_key(crypto_aead_tfm(aead), keys.enckey) ?:
       aead_setkey(aead, key, keylen);

out:
 memzero_explicit(&keys, sizeof(keys));
 return err;
}

static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
        bool encrypt)
{
 struct crypto_aead *aead = crypto_aead_reqtfm(req);
 struct caam_request *req_ctx = aead_request_ctx_dma(req);
 struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
 struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
       typeof(*alg), aead);
 struct device *dev = ctx->dev;
 gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
        GFP_KERNEL : GFP_ATOMIC;
 int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
 int src_len, dst_len = 0;
 struct aead_edesc *edesc;
 dma_addr_t qm_sg_dma, iv_dma = 0;
 int ivsize = 0;
 unsigned int authsize = ctx->authsize;
 int qm_sg_index = 0, qm_sg_nents = 0, qm_sg_bytes;
 int in_len, out_len;
 struct dpaa2_sg_entry *sg_table;

 /* allocate space for base edesc, link tables and IV */
 edesc = qi_cache_zalloc(flags);
 if (unlikely(!edesc)) {
  dev_err(dev, "could not allocate extended descriptor\n");
  return ERR_PTR(-ENOMEM);
 }

 if (unlikely(req->dst != req->src)) {
  src_len = req->assoclen + req->cryptlen;
  dst_len = src_len + (encrypt ? authsize : (-authsize));

  src_nents = sg_nents_for_len(req->src, src_len);
  if (unlikely(src_nents < 0)) {
   dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
    src_len);
   qi_cache_free(edesc);
   return ERR_PTR(src_nents);
  }

  dst_nents = sg_nents_for_len(req->dst, dst_len);
  if (unlikely(dst_nents < 0)) {
   dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
    dst_len);
   qi_cache_free(edesc);
   return ERR_PTR(dst_nents);
  }

  if (src_nents) {
   mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
            DMA_TO_DEVICE);
   if (unlikely(!mapped_src_nents)) {
    dev_err(dev, "unable to map source\n");
    qi_cache_free(edesc);
    return ERR_PTR(-ENOMEM);
   }
  } else {
   mapped_src_nents = 0;
  }

  if (dst_nents) {
   mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
            DMA_FROM_DEVICE);
   if (unlikely(!mapped_dst_nents)) {
    dev_err(dev, "unable to map destination\n");
    dma_unmap_sg(dev, req->src, src_nents,
          DMA_TO_DEVICE);
    qi_cache_free(edesc);
    return ERR_PTR(-ENOMEM);
   }
  } else {
   mapped_dst_nents = 0;
  }
 } else {
  src_len = req->assoclen + req->cryptlen +
     (encrypt ? authsize : 0);

  src_nents = sg_nents_for_len(req->src, src_len);
  if (unlikely(src_nents < 0)) {
   dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
    src_len);
   qi_cache_free(edesc);
   return ERR_PTR(src_nents);
  }

  mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
           DMA_BIDIRECTIONAL);
  if (unlikely(!mapped_src_nents)) {
   dev_err(dev, "unable to map source\n");
   qi_cache_free(edesc);
   return ERR_PTR(-ENOMEM);
  }
 }

 if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv)
  ivsize = crypto_aead_ivsize(aead);

 /*
 * Create S/G table: req->assoclen, [IV,] req->src [, req->dst].
 * Input is not contiguous.
 * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
 * the end of the table by allocating more S/G entries. Logic:
 * if (src != dst && output S/G)
 *      pad output S/G, if needed
 * else if (src == dst && S/G)
 *      overlapping S/Gs; pad one of them
 * else if (input S/G) ...
 *      pad input S/G, if needed
 */

 qm_sg_nents = 1 + !!ivsize + mapped_src_nents;
 if (mapped_dst_nents > 1)
  qm_sg_nents += pad_sg_nents(mapped_dst_nents);
 else if ((req->src == req->dst) && (mapped_src_nents > 1))
  qm_sg_nents = max(pad_sg_nents(qm_sg_nents),
      1 + !!ivsize +
      pad_sg_nents(mapped_src_nents));
 else
  qm_sg_nents = pad_sg_nents(qm_sg_nents);

 sg_table = &edesc->sgt[0];
 qm_sg_bytes = qm_sg_nents * sizeof(*sg_table);
 if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize >
       CAAM_QI_MEMCACHE_SIZE)) {
  dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
   qm_sg_nents, ivsize);
  caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
      0, DMA_NONE, 0, 0);
  qi_cache_free(edesc);
  return ERR_PTR(-ENOMEM);
 }

 if (ivsize) {
  u8 *iv = (u8 *)(sg_table + qm_sg_nents);

  /* Make sure IV is located in a DMAable area */
  memcpy(iv, req->iv, ivsize);

  iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
  if (dma_mapping_error(dev, iv_dma)) {
   dev_err(dev, "unable to map IV\n");
   caam_unmap(dev, req->src, req->dst, src_nents,
       dst_nents, 0, 0, DMA_NONE, 0, 0);
   qi_cache_free(edesc);
   return ERR_PTR(-ENOMEM);
  }
 }

 edesc->src_nents = src_nents;
 edesc->dst_nents = dst_nents;
 edesc->iv_dma = iv_dma;

 if ((alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK) ==
     OP_ALG_ALGSEL_CHACHA20 && ivsize != CHACHAPOLY_IV_SIZE)
  /*
 * The associated data comes already with the IV but we need
 * to skip it when we authenticate or encrypt...
 */

  edesc->assoclen = cpu_to_caam32(req->assoclen - ivsize);
 else
  edesc->assoclen = cpu_to_caam32(req->assoclen);
 edesc->assoclen_dma = dma_map_single(dev, &edesc->assoclen, 4,
          DMA_TO_DEVICE);
 if (dma_mapping_error(dev, edesc->assoclen_dma)) {
  dev_err(dev, "unable to map assoclen\n");
  caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
      iv_dma, ivsize, DMA_TO_DEVICE, 0, 0);
  qi_cache_free(edesc);
  return ERR_PTR(-ENOMEM);
 }

 dma_to_qm_sg_one(sg_table, edesc->assoclen_dma, 4, 0);
 qm_sg_index++;
 if (ivsize) {
  dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0);
  qm_sg_index++;
 }
 sg_to_qm_sg_last(req->src, src_len, sg_table + qm_sg_index, 0);
 qm_sg_index += mapped_src_nents;

 if (mapped_dst_nents > 1)
  sg_to_qm_sg_last(req->dst, dst_len, sg_table + qm_sg_index, 0);

 qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
 if (dma_mapping_error(dev, qm_sg_dma)) {
  dev_err(dev, "unable to map S/G table\n");
  dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
  caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
      iv_dma, ivsize, DMA_TO_DEVICE, 0, 0);
  qi_cache_free(edesc);
  return ERR_PTR(-ENOMEM);
 }

 edesc->qm_sg_dma = qm_sg_dma;
 edesc->qm_sg_bytes = qm_sg_bytes;

 out_len = req->assoclen + req->cryptlen +
    (encrypt ? ctx->authsize : (-ctx->authsize));
 in_len = 4 + ivsize + req->assoclen + req->cryptlen;

 memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
 dpaa2_fl_set_final(in_fle, true);
 dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
 dpaa2_fl_set_addr(in_fle, qm_sg_dma);
 dpaa2_fl_set_len(in_fle, in_len);

 if (req->dst == req->src) {
  if (mapped_src_nents == 1) {
   dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
   dpaa2_fl_set_addr(out_fle, sg_dma_address(req->src));
  } else {
   dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
   dpaa2_fl_set_addr(out_fle, qm_sg_dma +
       (1 + !!ivsize) * sizeof(*sg_table));
  }
 } else if (!mapped_dst_nents) {
  /*
 * crypto engine requires the output entry to be present when
 * "frame list" FD is used.
 * Since engine does not support FMT=2'b11 (unused entry type),
 * leaving out_fle zeroized is the best option.
 */

  goto skip_out_fle;
 } else if (mapped_dst_nents == 1) {
  dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
  dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
 } else {
  dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
  dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index *
      sizeof(*sg_table));
 }

 dpaa2_fl_set_len(out_fle, out_len);

skip_out_fle:
 return edesc;
}

static int chachapoly_set_sh_desc(struct crypto_aead *aead)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 unsigned int ivsize = crypto_aead_ivsize(aead);
 struct device *dev = ctx->dev;
 struct caam_flc *flc;
 u32 *desc;

 if (!ctx->cdata.keylen || !ctx->authsize)
  return 0;

 flc = &ctx->flc[ENCRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_chachapoly(desc, &ctx->cdata, &ctx->adata, ivsize,
          ctx->authsize, truetrue);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 flc = &ctx->flc[DECRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_chachapoly(desc, &ctx->cdata, &ctx->adata, ivsize,
          ctx->authsize, falsetrue);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 return 0;
}

static int chachapoly_setauthsize(struct crypto_aead *aead,
      unsigned int authsize)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);

 if (authsize != POLY1305_DIGEST_SIZE)
  return -EINVAL;

 ctx->authsize = authsize;
 return chachapoly_set_sh_desc(aead);
}

static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key,
        unsigned int keylen)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 unsigned int ivsize = crypto_aead_ivsize(aead);
 unsigned int saltlen = CHACHAPOLY_IV_SIZE - ivsize;

 if (keylen != CHACHA_KEY_SIZE + saltlen)
  return -EINVAL;

 memcpy(ctx->key, key, keylen);
 ctx->cdata.key_virt = ctx->key;
 ctx->cdata.keylen = keylen - saltlen;

 return chachapoly_set_sh_desc(aead);
}

static int gcm_set_sh_desc(struct crypto_aead *aead)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct device *dev = ctx->dev;
 unsigned int ivsize = crypto_aead_ivsize(aead);
 struct caam_flc *flc;
 u32 *desc;
 int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
   ctx->cdata.keylen;

 if (!ctx->cdata.keylen || !ctx->authsize)
  return 0;

 /*
 * AES GCM encrypt shared descriptor
 * Job Descriptor and Shared Descriptor
 * must fit into the 64-word Descriptor h/w Buffer
 */

 if (rem_bytes >= DESC_QI_GCM_ENC_LEN) {
  ctx->cdata.key_inline = true;
  ctx->cdata.key_virt = ctx->key;
 } else {
  ctx->cdata.key_inline = false;
  ctx->cdata.key_dma = ctx->key_dma;
 }

 flc = &ctx->flc[ENCRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, true);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 /*
 * Job Descriptor and Shared Descriptors
 * must all fit into the 64-word Descriptor h/w Buffer
 */

 if (rem_bytes >= DESC_QI_GCM_DEC_LEN) {
  ctx->cdata.key_inline = true;
  ctx->cdata.key_virt = ctx->key;
 } else {
  ctx->cdata.key_inline = false;
  ctx->cdata.key_dma = ctx->key_dma;
 }

 flc = &ctx->flc[DECRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, true);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 return 0;
}

static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(authenc);
 int err;

 err = crypto_gcm_check_authsize(authsize);
 if (err)
  return err;

 ctx->authsize = authsize;
 gcm_set_sh_desc(authenc);

 return 0;
}

static int gcm_setkey(struct crypto_aead *aead,
        const u8 *key, unsigned int keylen)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct device *dev = ctx->dev;
 int ret;

 ret = aes_check_keylen(keylen);
 if (ret)
  return ret;
 print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);

 memcpy(ctx->key, key, keylen);
 dma_sync_single_for_device(dev, ctx->key_dma, keylen, ctx->dir);
 ctx->cdata.keylen = keylen;

 return gcm_set_sh_desc(aead);
}

static int rfc4106_set_sh_desc(struct crypto_aead *aead)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct device *dev = ctx->dev;
 unsigned int ivsize = crypto_aead_ivsize(aead);
 struct caam_flc *flc;
 u32 *desc;
 int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
   ctx->cdata.keylen;

 if (!ctx->cdata.keylen || !ctx->authsize)
  return 0;

 ctx->cdata.key_virt = ctx->key;

 /*
 * RFC4106 encrypt shared descriptor
 * Job Descriptor and Shared Descriptor
 * must fit into the 64-word Descriptor h/w Buffer
 */

 if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) {
  ctx->cdata.key_inline = true;
 } else {
  ctx->cdata.key_inline = false;
  ctx->cdata.key_dma = ctx->key_dma;
 }

 flc = &ctx->flc[ENCRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
      true);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 /*
 * Job Descriptor and Shared Descriptors
 * must all fit into the 64-word Descriptor h/w Buffer
 */

 if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) {
  ctx->cdata.key_inline = true;
 } else {
  ctx->cdata.key_inline = false;
  ctx->cdata.key_dma = ctx->key_dma;
 }

 flc = &ctx->flc[DECRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
      true);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 return 0;
}

static int rfc4106_setauthsize(struct crypto_aead *authenc,
          unsigned int authsize)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(authenc);
 int err;

 err = crypto_rfc4106_check_authsize(authsize);
 if (err)
  return err;

 ctx->authsize = authsize;
 rfc4106_set_sh_desc(authenc);

 return 0;
}

static int rfc4106_setkey(struct crypto_aead *aead,
     const u8 *key, unsigned int keylen)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct device *dev = ctx->dev;
 int ret;

 ret = aes_check_keylen(keylen - 4);
 if (ret)
  return ret;

 print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);

 memcpy(ctx->key, key, keylen);
 /*
 * The last four bytes of the key material are used as the salt value
 * in the nonce. Update the AES key length.
 */

 ctx->cdata.keylen = keylen - 4;
 dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen,
       ctx->dir);

 return rfc4106_set_sh_desc(aead);
}

static int rfc4543_set_sh_desc(struct crypto_aead *aead)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct device *dev = ctx->dev;
 unsigned int ivsize = crypto_aead_ivsize(aead);
 struct caam_flc *flc;
 u32 *desc;
 int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
   ctx->cdata.keylen;

 if (!ctx->cdata.keylen || !ctx->authsize)
  return 0;

 ctx->cdata.key_virt = ctx->key;

 /*
 * RFC4543 encrypt shared descriptor
 * Job Descriptor and Shared Descriptor
 * must fit into the 64-word Descriptor h/w Buffer
 */

 if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) {
  ctx->cdata.key_inline = true;
 } else {
  ctx->cdata.key_inline = false;
  ctx->cdata.key_dma = ctx->key_dma;
 }

 flc = &ctx->flc[ENCRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
      true);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 /*
 * Job Descriptor and Shared Descriptors
 * must all fit into the 64-word Descriptor h/w Buffer
 */

 if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) {
  ctx->cdata.key_inline = true;
 } else {
  ctx->cdata.key_inline = false;
  ctx->cdata.key_dma = ctx->key_dma;
 }

 flc = &ctx->flc[DECRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
      true);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 return 0;
}

static int rfc4543_setauthsize(struct crypto_aead *authenc,
          unsigned int authsize)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(authenc);

 if (authsize != 16)
  return -EINVAL;

 ctx->authsize = authsize;
 rfc4543_set_sh_desc(authenc);

 return 0;
}

static int rfc4543_setkey(struct crypto_aead *aead,
     const u8 *key, unsigned int keylen)
{
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct device *dev = ctx->dev;
 int ret;

 ret = aes_check_keylen(keylen - 4);
 if (ret)
  return ret;

 print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);

 memcpy(ctx->key, key, keylen);
 /*
 * The last four bytes of the key material are used as the salt value
 * in the nonce. Update the AES key length.
 */

 ctx->cdata.keylen = keylen - 4;
 dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen,
       ctx->dir);

 return rfc4543_set_sh_desc(aead);
}

static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
      unsigned int keylen, const u32 ctx1_iv_off)
{
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
 struct caam_skcipher_alg *alg =
  container_of(crypto_skcipher_alg(skcipher),
        struct caam_skcipher_alg, skcipher);
 struct device *dev = ctx->dev;
 struct caam_flc *flc;
 unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
 u32 *desc;
 const bool is_rfc3686 = alg->caam.rfc3686;

 print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);

 ctx->cdata.keylen = keylen;
 ctx->cdata.key_virt = key;
 ctx->cdata.key_inline = true;

 /* skcipher_encrypt shared descriptor */
 flc = &ctx->flc[ENCRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_skcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686,
       ctx1_iv_off);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 /* skcipher_decrypt shared descriptor */
 flc = &ctx->flc[DECRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_skcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686,
       ctx1_iv_off);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 return 0;
}

static int aes_skcipher_setkey(struct crypto_skcipher *skcipher,
          const u8 *key, unsigned int keylen)
{
 int err;

 err = aes_check_keylen(keylen);
 if (err)
  return err;

 return skcipher_setkey(skcipher, key, keylen, 0);
}

static int rfc3686_skcipher_setkey(struct crypto_skcipher *skcipher,
       const u8 *key, unsigned int keylen)
{
 u32 ctx1_iv_off;
 int err;

 /*
 * RFC3686 specific:
 * | CONTEXT1[255:128] = {NONCE, IV, COUNTER}
 * | *key = {KEY, NONCE}
 */

 ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE;
 keylen -= CTR_RFC3686_NONCE_SIZE;

 err = aes_check_keylen(keylen);
 if (err)
  return err;

 return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off);
}

static int ctr_skcipher_setkey(struct crypto_skcipher *skcipher,
          const u8 *key, unsigned int keylen)
{
 u32 ctx1_iv_off;
 int err;

 /*
 * AES-CTR needs to load IV in CONTEXT1 reg
 * at an offset of 128bits (16bytes)
 * CONTEXT1[255:128] = IV
 */

 ctx1_iv_off = 16;

 err = aes_check_keylen(keylen);
 if (err)
  return err;

 return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off);
}

static int chacha20_skcipher_setkey(struct crypto_skcipher *skcipher,
        const u8 *key, unsigned int keylen)
{
 if (keylen != CHACHA_KEY_SIZE)
  return -EINVAL;

 return skcipher_setkey(skcipher, key, keylen, 0);
}

static int des_skcipher_setkey(struct crypto_skcipher *skcipher,
          const u8 *key, unsigned int keylen)
{
 return verify_skcipher_des_key(skcipher, key) ?:
        skcipher_setkey(skcipher, key, keylen, 0);
}

static int des3_skcipher_setkey(struct crypto_skcipher *skcipher,
           const u8 *key, unsigned int keylen)
{
 return verify_skcipher_des3_key(skcipher, key) ?:
        skcipher_setkey(skcipher, key, keylen, 0);
}

static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
          unsigned int keylen)
{
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
 struct device *dev = ctx->dev;
 struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
 struct caam_flc *flc;
 u32 *desc;
 int err;

 err = xts_verify_key(skcipher, key, keylen);
 if (err) {
  dev_dbg(dev, "key size mismatch\n");
  return err;
 }

 if (keylen != 2 * AES_KEYSIZE_128 && keylen != 2 * AES_KEYSIZE_256)
  ctx->xts_key_fallback = true;

 if (priv->sec_attr.era <= 8 || ctx->xts_key_fallback) {
  err = crypto_skcipher_setkey(ctx->fallback, key, keylen);
  if (err)
   return err;
 }

 ctx->cdata.keylen = keylen;
 ctx->cdata.key_virt = key;
 ctx->cdata.key_inline = true;

 /* xts_skcipher_encrypt shared descriptor */
 flc = &ctx->flc[ENCRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_xts_skcipher_encap(desc, &ctx->cdata);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 /* xts_skcipher_decrypt shared descriptor */
 flc = &ctx->flc[DECRYPT];
 desc = flc->sh_desc;
 cnstr_shdsc_xts_skcipher_decap(desc, &ctx->cdata);
 flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
 dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
       sizeof(flc->flc) + desc_bytes(desc),
       ctx->dir);

 return 0;
}

static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
{
 struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 struct caam_request *req_ctx = skcipher_request_ctx_dma(req);
 struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
 struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
 struct device *dev = ctx->dev;
 gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
         GFP_KERNEL : GFP_ATOMIC;
 int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
 struct skcipher_edesc *edesc;
 dma_addr_t iv_dma;
 u8 *iv;
 int ivsize = crypto_skcipher_ivsize(skcipher);
 int dst_sg_idx, qm_sg_ents, qm_sg_bytes;
 struct dpaa2_sg_entry *sg_table;

 src_nents = sg_nents_for_len(req->src, req->cryptlen);
 if (unlikely(src_nents < 0)) {
  dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
   req->cryptlen);
  return ERR_PTR(src_nents);
 }

 if (unlikely(req->dst != req->src)) {
  dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
  if (unlikely(dst_nents < 0)) {
   dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
    req->cryptlen);
   return ERR_PTR(dst_nents);
  }

  mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
           DMA_TO_DEVICE);
  if (unlikely(!mapped_src_nents)) {
   dev_err(dev, "unable to map source\n");
   return ERR_PTR(-ENOMEM);
  }

  mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
           DMA_FROM_DEVICE);
  if (unlikely(!mapped_dst_nents)) {
   dev_err(dev, "unable to map destination\n");
   dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
   return ERR_PTR(-ENOMEM);
  }
 } else {
  mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
           DMA_BIDIRECTIONAL);
  if (unlikely(!mapped_src_nents)) {
   dev_err(dev, "unable to map source\n");
   return ERR_PTR(-ENOMEM);
  }
 }

 qm_sg_ents = 1 + mapped_src_nents;
 dst_sg_idx = qm_sg_ents;

 /*
 * Input, output HW S/G tables: [IV, src][dst, IV]
 * IV entries point to the same buffer
 * If src == dst, S/G entries are reused (S/G tables overlap)
 *
 * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
 * the end of the table by allocating more S/G entries.
 */

 if (req->src != req->dst)
  qm_sg_ents += pad_sg_nents(mapped_dst_nents + 1);
 else
  qm_sg_ents = 1 + pad_sg_nents(qm_sg_ents);

 qm_sg_bytes = qm_sg_ents * sizeof(struct dpaa2_sg_entry);
 if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes +
       ivsize > CAAM_QI_MEMCACHE_SIZE)) {
  dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
   qm_sg_ents, ivsize);
  caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
      0, DMA_NONE, 0, 0);
  return ERR_PTR(-ENOMEM);
 }

 /* allocate space for base edesc, link tables and IV */
 edesc = qi_cache_zalloc(flags);
 if (unlikely(!edesc)) {
  dev_err(dev, "could not allocate extended descriptor\n");
  caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
      0, DMA_NONE, 0, 0);
  return ERR_PTR(-ENOMEM);
 }

 /* Make sure IV is located in a DMAable area */
 sg_table = &edesc->sgt[0];
 iv = (u8 *)(sg_table + qm_sg_ents);
 memcpy(iv, req->iv, ivsize);

 iv_dma = dma_map_single(dev, iv, ivsize, DMA_BIDIRECTIONAL);
 if (dma_mapping_error(dev, iv_dma)) {
  dev_err(dev, "unable to map IV\n");
  caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
      0, DMA_NONE, 0, 0);
  qi_cache_free(edesc);
  return ERR_PTR(-ENOMEM);
 }

 edesc->src_nents = src_nents;
 edesc->dst_nents = dst_nents;
 edesc->iv_dma = iv_dma;
 edesc->qm_sg_bytes = qm_sg_bytes;

 dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
 sg_to_qm_sg(req->src, req->cryptlen, sg_table + 1, 0);

 if (req->src != req->dst)
  sg_to_qm_sg(req->dst, req->cryptlen, sg_table + dst_sg_idx, 0);

 dma_to_qm_sg_one(sg_table + dst_sg_idx + mapped_dst_nents, iv_dma,
    ivsize, 0);

 edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes,
       DMA_TO_DEVICE);
 if (dma_mapping_error(dev, edesc->qm_sg_dma)) {
  dev_err(dev, "unable to map S/G table\n");
  caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
      iv_dma, ivsize, DMA_BIDIRECTIONAL, 0, 0);
  qi_cache_free(edesc);
  return ERR_PTR(-ENOMEM);
 }

 memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
 dpaa2_fl_set_final(in_fle, true);
 dpaa2_fl_set_len(in_fle, req->cryptlen + ivsize);
 dpaa2_fl_set_len(out_fle, req->cryptlen + ivsize);

 dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
 dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);

 dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);

 if (req->src == req->dst)
  dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma +
      sizeof(*sg_table));
 else
  dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx *
      sizeof(*sg_table));

 return edesc;
}

static void aead_unmap(struct device *dev, struct aead_edesc *edesc,
         struct aead_request *req)
{
 struct crypto_aead *aead = crypto_aead_reqtfm(req);
 int ivsize = crypto_aead_ivsize(aead);

 caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
     edesc->iv_dma, ivsize, DMA_TO_DEVICE, edesc->qm_sg_dma,
     edesc->qm_sg_bytes);
 dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
}

static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
      struct skcipher_request *req)
{
 struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 int ivsize = crypto_skcipher_ivsize(skcipher);

 caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
     edesc->iv_dma, ivsize, DMA_BIDIRECTIONAL, edesc->qm_sg_dma,
     edesc->qm_sg_bytes);
}

static void aead_encrypt_done(void *cbk_ctx, u32 status)
{
 struct crypto_async_request *areq = cbk_ctx;
 struct aead_request *req = container_of(areq, struct aead_request,
      base);
 struct caam_request *req_ctx = to_caam_req(areq);
 struct aead_edesc *edesc = req_ctx->edesc;
 struct crypto_aead *aead = crypto_aead_reqtfm(req);
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 int ecode = 0;

 dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);

 if (unlikely(status))
  ecode = caam_qi2_strstatus(ctx->dev, status);

 aead_unmap(ctx->dev, edesc, req);
 qi_cache_free(edesc);
 aead_request_complete(req, ecode);
}

static void aead_decrypt_done(void *cbk_ctx, u32 status)
{
 struct crypto_async_request *areq = cbk_ctx;
 struct aead_request *req = container_of(areq, struct aead_request,
      base);
 struct caam_request *req_ctx = to_caam_req(areq);
 struct aead_edesc *edesc = req_ctx->edesc;
 struct crypto_aead *aead = crypto_aead_reqtfm(req);
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 int ecode = 0;

 dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);

 if (unlikely(status))
  ecode = caam_qi2_strstatus(ctx->dev, status);

 aead_unmap(ctx->dev, edesc, req);
 qi_cache_free(edesc);
 aead_request_complete(req, ecode);
}

static int aead_encrypt(struct aead_request *req)
{
 struct aead_edesc *edesc;
 struct crypto_aead *aead = crypto_aead_reqtfm(req);
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct caam_request *caam_req = aead_request_ctx_dma(req);
 int ret;

 /* allocate extended descriptor */
 edesc = aead_edesc_alloc(req, true);
 if (IS_ERR(edesc))
  return PTR_ERR(edesc);

 caam_req->flc = &ctx->flc[ENCRYPT];
 caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
 caam_req->cbk = aead_encrypt_done;
 caam_req->ctx = &req->base;
 caam_req->edesc = edesc;
 ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
 if (ret != -EINPROGRESS &&
     !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
  aead_unmap(ctx->dev, edesc, req);
  qi_cache_free(edesc);
 }

 return ret;
}

static int aead_decrypt(struct aead_request *req)
{
 struct aead_edesc *edesc;
 struct crypto_aead *aead = crypto_aead_reqtfm(req);
 struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
 struct caam_request *caam_req = aead_request_ctx_dma(req);
 int ret;

 /* allocate extended descriptor */
 edesc = aead_edesc_alloc(req, false);
 if (IS_ERR(edesc))
  return PTR_ERR(edesc);

 caam_req->flc = &ctx->flc[DECRYPT];
 caam_req->flc_dma = ctx->flc_dma[DECRYPT];
 caam_req->cbk = aead_decrypt_done;
 caam_req->ctx = &req->base;
 caam_req->edesc = edesc;
 ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
 if (ret != -EINPROGRESS &&
     !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
  aead_unmap(ctx->dev, edesc, req);
  qi_cache_free(edesc);
 }

 return ret;
}

static int ipsec_gcm_encrypt(struct aead_request *req)
{
 return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_encrypt(req);
}

static int ipsec_gcm_decrypt(struct aead_request *req)
{
 return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_decrypt(req);
}

static void skcipher_encrypt_done(void *cbk_ctx, u32 status)
{
 struct crypto_async_request *areq = cbk_ctx;
 struct skcipher_request *req = skcipher_request_cast(areq);
 struct caam_request *req_ctx = to_caam_req(areq);
 struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
 struct skcipher_edesc *edesc = req_ctx->edesc;
 int ecode = 0;
 int ivsize = crypto_skcipher_ivsize(skcipher);

 dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);

 if (unlikely(status))
  ecode = caam_qi2_strstatus(ctx->dev, status);

 print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
        edesc->src_nents > 1 ? 100 : ivsize, 1);
 caam_dump_sg("dst @" __stringify(__LINE__)": ",
       DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
       edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);

 skcipher_unmap(ctx->dev, edesc, req);

 /*
 * The crypto API expects us to set the IV (req->iv) to the last
 * ciphertext block (CBC mode) or last counter (CTR mode).
 * This is used e.g. by the CTS mode.
 */

 if (!ecode)
  memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes,
         ivsize);

 qi_cache_free(edesc);
 skcipher_request_complete(req, ecode);
}

static void skcipher_decrypt_done(void *cbk_ctx, u32 status)
{
 struct crypto_async_request *areq = cbk_ctx;
 struct skcipher_request *req = skcipher_request_cast(areq);
 struct caam_request *req_ctx = to_caam_req(areq);
 struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
 struct skcipher_edesc *edesc = req_ctx->edesc;
 int ecode = 0;
 int ivsize = crypto_skcipher_ivsize(skcipher);

 dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);

 if (unlikely(status))
  ecode = caam_qi2_strstatus(ctx->dev, status);

 print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
        DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
        edesc->src_nents > 1 ? 100 : ivsize, 1);
 caam_dump_sg("dst @" __stringify(__LINE__)": ",
       DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
       edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);

 skcipher_unmap(ctx->dev, edesc, req);

 /*
 * The crypto API expects us to set the IV (req->iv) to the last
 * ciphertext block (CBC mode) or last counter (CTR mode).
 * This is used e.g. by the CTS mode.
 */

 if (!ecode)
  memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes,
         ivsize);

 qi_cache_free(edesc);
 skcipher_request_complete(req, ecode);
}

static inline bool xts_skcipher_ivsize(struct skcipher_request *req)
{
 struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 unsigned int ivsize = crypto_skcipher_ivsize(skcipher);

 return !!get_unaligned((u64 *)(req->iv + (ivsize / 2)));
}

static int skcipher_encrypt(struct skcipher_request *req)
{
 struct skcipher_edesc *edesc;
 struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
 struct caam_request *caam_req = skcipher_request_ctx_dma(req);
 struct dpaa2_caam_priv *priv = dev_get_drvdata(ctx->dev);
 int ret;

 /*
 * XTS is expected to return an error even for input length = 0
 * Note that the case input length < block size will be caught during
 * HW offloading and return an error.
 */

 if (!req->cryptlen && !ctx->fallback)
  return 0;

 if (ctx->fallback && ((priv->sec_attr.era <= 8 && xts_skcipher_ivsize(req)) ||
         ctx->xts_key_fallback)) {
  skcipher_request_set_tfm(&caam_req->fallback_req, ctx->fallback);
  skcipher_request_set_callback(&caam_req->fallback_req,
           req->base.flags,
           req->base.complete,
           req->base.data);
  skcipher_request_set_crypt(&caam_req->fallback_req, req->src,
        req->dst, req->cryptlen, req->iv);

  return crypto_skcipher_encrypt(&caam_req->fallback_req);
 }

 /* allocate extended descriptor */
 edesc = skcipher_edesc_alloc(req);
 if (IS_ERR(edesc))
  return PTR_ERR(edesc);

 caam_req->flc = &ctx->flc[ENCRYPT];
 caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
 caam_req->cbk = skcipher_encrypt_done;
 caam_req->ctx = &req->base;
 caam_req->edesc = edesc;
 ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
 if (ret != -EINPROGRESS &&
     !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
  skcipher_unmap(ctx->dev, edesc, req);
  qi_cache_free(edesc);
 }

 return ret;
}

static int skcipher_decrypt(struct skcipher_request *req)
{
 struct skcipher_edesc *edesc;
 struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
 struct caam_request *caam_req = skcipher_request_ctx_dma(req);
 struct dpaa2_caam_priv *priv = dev_get_drvdata(ctx->dev);
 int ret;

 /*
 * XTS is expected to return an error even for input length = 0
 * Note that the case input length < block size will be caught during
 * HW offloading and return an error.
 */

 if (!req->cryptlen && !ctx->fallback)
  return 0;

 if (ctx->fallback && ((priv->sec_attr.era <= 8 && xts_skcipher_ivsize(req)) ||
         ctx->xts_key_fallback)) {
  skcipher_request_set_tfm(&caam_req->fallback_req, ctx->fallback);
  skcipher_request_set_callback(&caam_req->fallback_req,
           req->base.flags,
           req->base.complete,
           req->base.data);
  skcipher_request_set_crypt(&caam_req->fallback_req, req->src,
        req->dst, req->cryptlen, req->iv);

  return crypto_skcipher_decrypt(&caam_req->fallback_req);
 }

 /* allocate extended descriptor */
 edesc = skcipher_edesc_alloc(req);
 if (IS_ERR(edesc))
  return PTR_ERR(edesc);

 caam_req->flc = &ctx->flc[DECRYPT];
 caam_req->flc_dma = ctx->flc_dma[DECRYPT];
 caam_req->cbk = skcipher_decrypt_done;
 caam_req->ctx = &req->base;
 caam_req->edesc = edesc;
 ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
 if (ret != -EINPROGRESS &&
     !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
  skcipher_unmap(ctx->dev, edesc, req);
  qi_cache_free(edesc);
 }

 return ret;
}

static int caam_cra_init(struct caam_ctx *ctx, struct caam_alg_entry *caam,
    bool uses_dkp)
{
 dma_addr_t dma_addr;
 int i;

 /* copy descriptor header template value */
 ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type;
 ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type;

 ctx->dev = caam->dev;
 ctx->dir = uses_dkp ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;

 dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc,
     offsetof(struct caam_ctx, flc_dma),
     ctx->dir, DMA_ATTR_SKIP_CPU_SYNC);
 if (dma_mapping_error(ctx->dev, dma_addr)) {
  dev_err(ctx->dev, "unable to map key, shared descriptors\n");
  return -ENOMEM;
 }

 for (i = 0; i < NUM_OP; i++)
  ctx->flc_dma[i] = dma_addr + i * sizeof(ctx->flc[i]);
 ctx->key_dma = dma_addr + NUM_OP * sizeof(ctx->flc[0]);

 return 0;
}

static int caam_cra_init_skcipher(struct crypto_skcipher *tfm)
{
 struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
 struct caam_skcipher_alg *caam_alg =
  container_of(alg, typeof(*caam_alg), skcipher);
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(tfm);
 u32 alg_aai = caam_alg->caam.class1_alg_type & OP_ALG_AAI_MASK;
 int ret = 0;

 if (alg_aai == OP_ALG_AAI_XTS) {
  const char *tfm_name = crypto_tfm_alg_name(&tfm->base);
  struct crypto_skcipher *fallback;

  fallback = crypto_alloc_skcipher(tfm_name, 0,
       CRYPTO_ALG_NEED_FALLBACK);
  if (IS_ERR(fallback)) {
   dev_err(caam_alg->caam.dev,
    "Failed to allocate %s fallback: %ld\n",
    tfm_name, PTR_ERR(fallback));
   return PTR_ERR(fallback);
  }

  ctx->fallback = fallback;
  crypto_skcipher_set_reqsize_dma(
   tfm, sizeof(struct caam_request) +
        crypto_skcipher_reqsize(fallback));
 } else {
  crypto_skcipher_set_reqsize_dma(tfm,
      sizeof(struct caam_request));
 }

 ret = caam_cra_init(ctx, &caam_alg->caam, false);
 if (ret && ctx->fallback)
  crypto_free_skcipher(ctx->fallback);

 return ret;
}

static int caam_cra_init_aead(struct crypto_aead *tfm)
{
 struct aead_alg *alg = crypto_aead_alg(tfm);
 struct caam_aead_alg *caam_alg = container_of(alg, typeof(*caam_alg),
            aead);

 crypto_aead_set_reqsize_dma(tfm, sizeof(struct caam_request));
 return caam_cra_init(crypto_aead_ctx_dma(tfm), &caam_alg->caam,
        !caam_alg->caam.nodkp);
}

static void caam_exit_common(struct caam_ctx *ctx)
{
 dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0],
          offsetof(struct caam_ctx, flc_dma), ctx->dir,
          DMA_ATTR_SKIP_CPU_SYNC);
}

static void caam_cra_exit(struct crypto_skcipher *tfm)
{
 struct caam_ctx *ctx = crypto_skcipher_ctx_dma(tfm);

 if (ctx->fallback)
  crypto_free_skcipher(ctx->fallback);
 caam_exit_common(ctx);
}

static void caam_cra_exit_aead(struct crypto_aead *tfm)
{
 caam_exit_common(crypto_aead_ctx_dma(tfm));
}

static struct caam_skcipher_alg driver_algs[] = {
 {
  .skcipher = {
   .base = {
    .cra_name = "cbc(aes)",
    .cra_driver_name = "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aes_skcipher_setkey,
   .encrypt = skcipher_encrypt,
   .decrypt = skcipher_decrypt,
   .min_keysize = AES_MIN_KEY_SIZE,
   .max_keysize = AES_MAX_KEY_SIZE,
   .ivsize = AES_BLOCK_SIZE,
  },
  .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
 },
 {
  .skcipher = {
   .base = {
    .cra_name = "cbc(des3_ede)",
    .cra_driver_name = "cbc-3des-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_skcipher_setkey,
   .encrypt = skcipher_encrypt,
   .decrypt = skcipher_decrypt,
   .min_keysize = DES3_EDE_KEY_SIZE,
   .max_keysize = DES3_EDE_KEY_SIZE,
   .ivsize = DES3_EDE_BLOCK_SIZE,
  },
  .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
 },
 {
  .skcipher = {
   .base = {
    .cra_name = "cbc(des)",
    .cra_driver_name = "cbc-des-caam-qi2",
    .cra_blocksize = DES_BLOCK_SIZE,
   },
   .setkey = des_skcipher_setkey,
   .encrypt = skcipher_encrypt,
   .decrypt = skcipher_decrypt,
   .min_keysize = DES_KEY_SIZE,
   .max_keysize = DES_KEY_SIZE,
   .ivsize = DES_BLOCK_SIZE,
  },
  .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
 },
 {
  .skcipher = {
   .base = {
    .cra_name = "ctr(aes)",
    .cra_driver_name = "ctr-aes-caam-qi2",
    .cra_blocksize = 1,
   },
   .setkey = ctr_skcipher_setkey,
   .encrypt = skcipher_encrypt,
   .decrypt = skcipher_decrypt,
   .min_keysize = AES_MIN_KEY_SIZE,
   .max_keysize = AES_MAX_KEY_SIZE,
   .ivsize = AES_BLOCK_SIZE,
   .chunksize = AES_BLOCK_SIZE,
  },
  .caam.class1_alg_type = OP_ALG_ALGSEL_AES |
     OP_ALG_AAI_CTR_MOD128,
 },
 {
  .skcipher = {
   .base = {
    .cra_name = "rfc3686(ctr(aes))",
    .cra_driver_name = "rfc3686-ctr-aes-caam-qi2",
    .cra_blocksize = 1,
   },
   .setkey = rfc3686_skcipher_setkey,
   .encrypt = skcipher_encrypt,
   .decrypt = skcipher_decrypt,
   .min_keysize = AES_MIN_KEY_SIZE +
           CTR_RFC3686_NONCE_SIZE,
   .max_keysize = AES_MAX_KEY_SIZE +
           CTR_RFC3686_NONCE_SIZE,
   .ivsize = CTR_RFC3686_IV_SIZE,
   .chunksize = AES_BLOCK_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES |
        OP_ALG_AAI_CTR_MOD128,
   .rfc3686 = true,
  },
 },
 {
  .skcipher = {
   .base = {
    .cra_name = "xts(aes)",
    .cra_driver_name = "xts-aes-caam-qi2",
    .cra_flags = CRYPTO_ALG_NEED_FALLBACK,
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = xts_skcipher_setkey,
   .encrypt = skcipher_encrypt,
   .decrypt = skcipher_decrypt,
   .min_keysize = 2 * AES_MIN_KEY_SIZE,
   .max_keysize = 2 * AES_MAX_KEY_SIZE,
   .ivsize = AES_BLOCK_SIZE,
  },
  .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
 },
 {
  .skcipher = {
   .base = {
    .cra_name = "chacha20",
    .cra_driver_name = "chacha20-caam-qi2",
    .cra_blocksize = 1,
   },
   .setkey = chacha20_skcipher_setkey,
   .encrypt = skcipher_encrypt,
   .decrypt = skcipher_decrypt,
   .min_keysize = CHACHA_KEY_SIZE,
   .max_keysize = CHACHA_KEY_SIZE,
   .ivsize = CHACHA_IV_SIZE,
  },
  .caam.class1_alg_type = OP_ALG_ALGSEL_CHACHA20,
 },
};

static struct caam_aead_alg driver_aeads[] = {
 {
  .aead = {
   .base = {
    .cra_name = "rfc4106(gcm(aes))",
    .cra_driver_name = "rfc4106-gcm-aes-caam-qi2",
    .cra_blocksize = 1,
   },
   .setkey = rfc4106_setkey,
   .setauthsize = rfc4106_setauthsize,
   .encrypt = ipsec_gcm_encrypt,
   .decrypt = ipsec_gcm_decrypt,
   .ivsize = 8,
   .maxauthsize = AES_BLOCK_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
   .nodkp = true,
  },
 },
 {
  .aead = {
   .base = {
    .cra_name = "rfc4543(gcm(aes))",
    .cra_driver_name = "rfc4543-gcm-aes-caam-qi2",
    .cra_blocksize = 1,
   },
   .setkey = rfc4543_setkey,
   .setauthsize = rfc4543_setauthsize,
   .encrypt = ipsec_gcm_encrypt,
   .decrypt = ipsec_gcm_decrypt,
   .ivsize = 8,
   .maxauthsize = AES_BLOCK_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
   .nodkp = true,
  },
 },
 /* Galois Counter Mode */
 {
  .aead = {
   .base = {
    .cra_name = "gcm(aes)",
    .cra_driver_name = "gcm-aes-caam-qi2",
    .cra_blocksize = 1,
   },
   .setkey = gcm_setkey,
   .setauthsize = gcm_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = 12,
   .maxauthsize = AES_BLOCK_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
   .nodkp = true,
  }
 },
 /* single-pass ipsec_esp descriptor */
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(md5),cbc(aes))",
    .cra_driver_name = "authenc-hmac-md5-"
         "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = MD5_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_MD5 |
        OP_ALG_AAI_HMAC_PRECOMP,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(md5),"
         "cbc(aes)))",
    .cra_driver_name = "echainiv-authenc-hmac-md5-"
         "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = MD5_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_MD5 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha1),cbc(aes))",
    .cra_driver_name = "authenc-hmac-sha1-"
         "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA1_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
        OP_ALG_AAI_HMAC_PRECOMP,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha1),"
         "cbc(aes)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha1-cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA1_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  },
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha224),cbc(aes))",
    .cra_driver_name = "authenc-hmac-sha224-"
         "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA224_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
        OP_ALG_AAI_HMAC_PRECOMP,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha224),"
         "cbc(aes)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha224-cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA224_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha256),cbc(aes))",
    .cra_driver_name = "authenc-hmac-sha256-"
         "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA256_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
        OP_ALG_AAI_HMAC_PRECOMP,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha256),"
         "cbc(aes)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha256-cbc-aes-"
         "caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA256_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha384),cbc(aes))",
    .cra_driver_name = "authenc-hmac-sha384-"
         "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA384_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
        OP_ALG_AAI_HMAC_PRECOMP,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha384),"
         "cbc(aes)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha384-cbc-aes-"
         "caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA384_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha512),cbc(aes))",
    .cra_driver_name = "authenc-hmac-sha512-"
         "cbc-aes-caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA512_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
        OP_ALG_AAI_HMAC_PRECOMP,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha512),"
         "cbc(aes)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha512-cbc-aes-"
         "caam-qi2",
    .cra_blocksize = AES_BLOCK_SIZE,
   },
   .setkey = aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = AES_BLOCK_SIZE,
   .maxauthsize = SHA512_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(md5),cbc(des3_ede))",
    .cra_driver_name = "authenc-hmac-md5-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = MD5_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_MD5 |
        OP_ALG_AAI_HMAC_PRECOMP,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(md5),"
         "cbc(des3_ede)))",
    .cra_driver_name = "echainiv-authenc-hmac-md5-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = MD5_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_MD5 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha1),"
         "cbc(des3_ede))",
    .cra_driver_name = "authenc-hmac-sha1-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = SHA1_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
        OP_ALG_AAI_HMAC_PRECOMP,
  },
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha1),"
         "cbc(des3_ede)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha1-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = SHA1_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha224),"
         "cbc(des3_ede))",
    .cra_driver_name = "authenc-hmac-sha224-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = SHA224_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
        OP_ALG_AAI_HMAC_PRECOMP,
  },
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha224),"
         "cbc(des3_ede)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha224-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = SHA224_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha256),"
         "cbc(des3_ede))",
    .cra_driver_name = "authenc-hmac-sha256-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = SHA256_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
        OP_ALG_AAI_HMAC_PRECOMP,
  },
 },
 {
  .aead = {
   .base = {
    .cra_name = "echainiv(authenc(hmac(sha256),"
         "cbc(des3_ede)))",
    .cra_driver_name = "echainiv-authenc-"
         "hmac-sha256-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = SHA256_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
   .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
        OP_ALG_AAI_HMAC_PRECOMP,
   .geniv = true,
  }
 },
 {
  .aead = {
   .base = {
    .cra_name = "authenc(hmac(sha384),"
         "cbc(des3_ede))",
    .cra_driver_name = "authenc-hmac-sha384-"
         "cbc-des3_ede-caam-qi2",
    .cra_blocksize = DES3_EDE_BLOCK_SIZE,
   },
   .setkey = des3_aead_setkey,
   .setauthsize = aead_setauthsize,
   .encrypt = aead_encrypt,
   .decrypt = aead_decrypt,
   .ivsize = DES3_EDE_BLOCK_SIZE,
   .maxauthsize = SHA384_DIGEST_SIZE,
  },
  .caam = {
   .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=97 G=96

¤ Dauer der Verarbeitung: 0.63 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge