mediatek: switch over to extended upstream eip97 driver
authorJohn Crispin <john@phrozen.org>
Thu, 4 Jun 2020 12:20:34 +0000 (14:20 +0200)
committerJohn Crispin <john@phrozen.org>
Sun, 7 Jun 2020 15:52:21 +0000 (17:52 +0200)
Signed-off-by: John Crispin <john@phrozen.org>
target/linux/mediatek/patches-5.4/0500-v5.6-crypto-backport-inside-secure.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.4/0501-crypto-add-eip97-inside-secure-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.4/0502-dts-mt7623-eip97-inside-secure-support.patch [new file with mode: 0644]

diff --git a/target/linux/mediatek/patches-5.4/0500-v5.6-crypto-backport-inside-secure.patch b/target/linux/mediatek/patches-5.4/0500-v5.6-crypto-backport-inside-secure.patch
new file mode 100644 (file)
index 0000000..3237c12
--- /dev/null
@@ -0,0 +1,5464 @@
+--- a/drivers/crypto/inside-secure/safexcel.c
++++ b/drivers/crypto/inside-secure/safexcel.c
+@@ -75,9 +75,9 @@
+ }
+ static u32 eip197_trc_cache_probe(struct safexcel_crypto_priv *priv,
+-                                int maxbanks, u32 probemask)
++                                int maxbanks, u32 probemask, u32 stride)
+ {
+-      u32 val, addrhi, addrlo, addrmid;
++      u32 val, addrhi, addrlo, addrmid, addralias, delta, marker;
+       int actbank;
+       /*
+@@ -87,32 +87,37 @@
+       addrhi = 1 << (16 + maxbanks);
+       addrlo = 0;
+       actbank = min(maxbanks - 1, 0);
+-      while ((addrhi - addrlo) > 32) {
++      while ((addrhi - addrlo) > stride) {
+               /* write marker to lowest address in top half */
+               addrmid = (addrhi + addrlo) >> 1;
++              marker = (addrmid ^ 0xabadbabe) & probemask; /* Unique */
+               eip197_trc_cache_banksel(priv, addrmid, &actbank);
+-              writel((addrmid | (addrlo << 16)) & probemask,
++              writel(marker,
+                       priv->base + EIP197_CLASSIFICATION_RAMS +
+                       (addrmid & 0xffff));
+-              /* write marker to lowest address in bottom half */
+-              eip197_trc_cache_banksel(priv, addrlo, &actbank);
+-              writel((addrlo | (addrhi << 16)) & probemask,
+-                      priv->base + EIP197_CLASSIFICATION_RAMS +
+-                      (addrlo & 0xffff));
++              /* write invalid markers to possible aliases */
++              delta = 1 << __fls(addrmid);
++              while (delta >= stride) {
++                      addralias = addrmid - delta;
++                      eip197_trc_cache_banksel(priv, addralias, &actbank);
++                      writel(~marker,
++                             priv->base + EIP197_CLASSIFICATION_RAMS +
++                             (addralias & 0xffff));
++                      delta >>= 1;
++              }
+               /* read back marker from top half */
+               eip197_trc_cache_banksel(priv, addrmid, &actbank);
+               val = readl(priv->base + EIP197_CLASSIFICATION_RAMS +
+                           (addrmid & 0xffff));
+-              if (val == ((addrmid | (addrlo << 16)) & probemask)) {
++              if ((val & probemask) == marker)
+                       /* read back correct, continue with top half */
+                       addrlo = addrmid;
+-              } else {
++              else
+                       /* not read back correct, continue with bottom half */
+                       addrhi = addrmid;
+-              }
+       }
+       return addrhi;
+ }
+@@ -150,7 +155,7 @@
+                      htable_offset + i * sizeof(u32));
+ }
+-static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv)
++static int eip197_trc_cache_init(struct safexcel_crypto_priv *priv)
+ {
+       u32 val, dsize, asize;
+       int cs_rc_max, cs_ht_wc, cs_trc_rec_wc, cs_trc_lg_rec_wc;
+@@ -183,7 +188,7 @@
+       writel(val, priv->base + EIP197_TRC_PARAMS);
+       /* Probed data RAM size in bytes */
+-      dsize = eip197_trc_cache_probe(priv, maxbanks, 0xffffffff);
++      dsize = eip197_trc_cache_probe(priv, maxbanks, 0xffffffff, 32);
+       /*
+        * Now probe the administration RAM size pretty much the same way
+@@ -196,11 +201,18 @@
+       writel(val, priv->base + EIP197_TRC_PARAMS);
+       /* Probed admin RAM size in admin words */
+-      asize = eip197_trc_cache_probe(priv, 0, 0xbfffffff) >> 4;
++      asize = eip197_trc_cache_probe(priv, 0, 0x3fffffff, 16) >> 4;
+       /* Clear any ECC errors detected while probing! */
+       writel(0, priv->base + EIP197_TRC_ECCCTRL);
++      /* Sanity check probing results */
++      if (dsize < EIP197_MIN_DSIZE || asize < EIP197_MIN_ASIZE) {
++              dev_err(priv->dev, "Record cache probing failed (%d,%d).",
++                      dsize, asize);
++              return -ENODEV;
++      }
++
+       /*
+        * Determine optimal configuration from RAM sizes
+        * Note that we assume that the physical RAM configuration is sane
+@@ -251,6 +263,7 @@
+       dev_info(priv->dev, "TRC init: %dd,%da (%dr,%dh)\n",
+                dsize, asize, cs_rc_max, cs_ht_wc + cs_ht_wc);
++      return 0;
+ }
+ static void eip197_init_firmware(struct safexcel_crypto_priv *priv)
+@@ -298,13 +311,14 @@
+ static int eip197_write_firmware(struct safexcel_crypto_priv *priv,
+                                 const struct firmware *fw)
+ {
+-      const u32 *data = (const u32 *)fw->data;
++      const __be32 *data = (const __be32 *)fw->data;
+       int i;
+       /* Write the firmware */
+       for (i = 0; i < fw->size / sizeof(u32); i++)
+               writel(be32_to_cpu(data[i]),
+-                     priv->base + EIP197_CLASSIFICATION_RAMS + i * sizeof(u32));
++                     priv->base + EIP197_CLASSIFICATION_RAMS +
++                     i * sizeof(__be32));
+       /* Exclude final 2 NOPs from size */
+       return i - EIP197_FW_TERMINAL_NOPS;
+@@ -471,6 +485,14 @@
+               cd_fetch_cnt = ((1 << priv->hwconfig.hwcfsize) /
+                               cd_size_rnd) - 1;
+       }
++      /*
++       * Since we're using command desc's way larger than formally specified,
++       * we need to check whether we can fit even 1 for low-end EIP196's!
++       */
++      if (!cd_fetch_cnt) {
++              dev_err(priv->dev, "Unable to fit even 1 command desc!\n");
++              return -ENODEV;
++      }
+       for (i = 0; i < priv->config.rings; i++) {
+               /* ring base address */
+@@ -479,12 +501,12 @@
+               writel(upper_32_bits(priv->ring[i].cdr.base_dma),
+                      EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI);
+-              writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.cd_offset << 16) |
+-                     priv->config.cd_size,
++              writel(EIP197_xDR_DESC_MODE_64BIT | EIP197_CDR_DESC_MODE_ADCP |
++                     (priv->config.cd_offset << 14) | priv->config.cd_size,
+                      EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE);
+               writel(((cd_fetch_cnt *
+                        (cd_size_rnd << priv->hwconfig.hwdataw)) << 16) |
+-                     (cd_fetch_cnt * priv->config.cd_offset),
++                     (cd_fetch_cnt * (priv->config.cd_offset / sizeof(u32))),
+                      EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG);
+               /* Configure DMA tx control */
+@@ -527,13 +549,13 @@
+               writel(upper_32_bits(priv->ring[i].rdr.base_dma),
+                      EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI);
+-              writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.rd_offset << 16) |
++              writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.rd_offset << 14) |
+                      priv->config.rd_size,
+                      EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE);
+               writel(((rd_fetch_cnt *
+                        (rd_size_rnd << priv->hwconfig.hwdataw)) << 16) |
+-                     (rd_fetch_cnt * priv->config.rd_offset),
++                     (rd_fetch_cnt * (priv->config.rd_offset / sizeof(u32))),
+                      EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG);
+               /* Configure DMA tx control */
+@@ -559,7 +581,7 @@
+ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
+ {
+       u32 val;
+-      int i, ret, pe;
++      int i, ret, pe, opbuflo, opbufhi;
+       dev_dbg(priv->dev, "HW init: using %d pipe(s) and %d ring(s)\n",
+               priv->config.pes, priv->config.rings);
+@@ -595,8 +617,8 @@
+               writel(EIP197_DxE_THR_CTRL_RESET_PE,
+                      EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe));
+-              if (priv->flags & SAFEXCEL_HW_EIP197)
+-                      /* Reset HIA input interface arbiter (EIP197 only) */
++              if (priv->flags & EIP197_PE_ARB)
++                      /* Reset HIA input interface arbiter (if present) */
+                       writel(EIP197_HIA_RA_PE_CTRL_RESET,
+                              EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe));
+@@ -639,9 +661,16 @@
+                       ;
+               /* DMA transfer size to use */
++              if (priv->hwconfig.hwnumpes > 4) {
++                      opbuflo = 9;
++                      opbufhi = 10;
++              } else {
++                      opbuflo = 7;
++                      opbufhi = 8;
++              }
+               val = EIP197_HIA_DSE_CFG_DIS_DEBUG;
+-              val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(7) |
+-                     EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(8);
++              val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(opbuflo) |
++                     EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(opbufhi);
+               val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS);
+               val |= EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE;
+               /* FIXME: instability issues can occur for EIP97 but disabling
+@@ -655,8 +684,8 @@
+               writel(0, EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe));
+               /* Configure the procesing engine thresholds */
+-              writel(EIP197_PE_OUT_DBUF_THRES_MIN(7) |
+-                     EIP197_PE_OUT_DBUF_THRES_MAX(8),
++              writel(EIP197_PE_OUT_DBUF_THRES_MIN(opbuflo) |
++                     EIP197_PE_OUT_DBUF_THRES_MAX(opbufhi),
+                      EIP197_PE(priv) + EIP197_PE_OUT_DBUF_THRES(pe));
+               /* Processing Engine configuration */
+@@ -696,7 +725,7 @@
+               writel(0,
+                      EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR);
+-              writel((EIP197_DEFAULT_RING_SIZE * priv->config.cd_offset) << 2,
++              writel((EIP197_DEFAULT_RING_SIZE * priv->config.cd_offset),
+                      EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_SIZE);
+       }
+@@ -719,7 +748,7 @@
+                      EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR);
+               /* Ring size */
+-              writel((EIP197_DEFAULT_RING_SIZE * priv->config.rd_offset) << 2,
++              writel((EIP197_DEFAULT_RING_SIZE * priv->config.rd_offset),
+                      EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_SIZE);
+       }
+@@ -736,19 +765,28 @@
+       /* Clear any HIA interrupt */
+       writel(GENMASK(30, 20), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK);
+-      if (priv->flags & SAFEXCEL_HW_EIP197) {
+-              eip197_trc_cache_init(priv);
+-              priv->flags |= EIP197_TRC_CACHE;
++      if (priv->flags & EIP197_SIMPLE_TRC) {
++              writel(EIP197_STRC_CONFIG_INIT |
++                     EIP197_STRC_CONFIG_LARGE_REC(EIP197_CS_TRC_REC_WC) |
++                     EIP197_STRC_CONFIG_SMALL_REC(EIP197_CS_TRC_REC_WC),
++                     priv->base + EIP197_STRC_CONFIG);
++              writel(EIP197_PE_EIP96_TOKEN_CTRL2_CTX_DONE,
++                     EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL2(0));
++      } else if (priv->flags & SAFEXCEL_HW_EIP197) {
++              ret = eip197_trc_cache_init(priv);
++              if (ret)
++                      return ret;
++      }
++      if (priv->flags & EIP197_ICE) {
+               ret = eip197_load_firmwares(priv);
+               if (ret)
+                       return ret;
+       }
+-      safexcel_hw_setup_cdesc_rings(priv);
+-      safexcel_hw_setup_rdesc_rings(priv);
+-
+-      return 0;
++      return safexcel_hw_setup_cdesc_rings(priv) ?:
++             safexcel_hw_setup_rdesc_rings(priv) ?:
++             0;
+ }
+ /* Called with ring's lock taken */
+@@ -836,20 +874,24 @@
+       spin_unlock_bh(&priv->ring[ring].lock);
+       /* let the RDR know we have pending descriptors */
+-      writel((rdesc * priv->config.rd_offset) << 2,
++      writel((rdesc * priv->config.rd_offset),
+              EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT);
+       /* let the CDR know we have pending descriptors */
+-      writel((cdesc * priv->config.cd_offset) << 2,
++      writel((cdesc * priv->config.cd_offset),
+              EIP197_HIA_CDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT);
+ }
+ inline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv,
+-                                     struct safexcel_result_desc *rdesc)
++                                     void *rdp)
+ {
+-      if (likely((!rdesc->descriptor_overflow) &&
+-                 (!rdesc->buffer_overflow) &&
+-                 (!rdesc->result_data.error_code)))
++      struct safexcel_result_desc *rdesc = rdp;
++      struct result_data_desc *result_data = rdp + priv->config.res_offset;
++
++      if (likely((!rdesc->last_seg) || /* Rest only valid if last seg! */
++                 ((!rdesc->descriptor_overflow) &&
++                  (!rdesc->buffer_overflow) &&
++                  (!result_data->error_code))))
+               return 0;
+       if (rdesc->descriptor_overflow)
+@@ -858,13 +900,14 @@
+       if (rdesc->buffer_overflow)
+               dev_err(priv->dev, "Buffer overflow detected");
+-      if (rdesc->result_data.error_code & 0x4066) {
++      if (result_data->error_code & 0x4066) {
+               /* Fatal error (bits 1,2,5,6 & 14) */
+               dev_err(priv->dev,
+                       "result descriptor error (%x)",
+-                      rdesc->result_data.error_code);
++                      result_data->error_code);
++
+               return -EIO;
+-      } else if (rdesc->result_data.error_code &
++      } else if (result_data->error_code &
+                  (BIT(7) | BIT(4) | BIT(3) | BIT(0))) {
+               /*
+                * Give priority over authentication fails:
+@@ -872,7 +915,7 @@
+                * something wrong with the input!
+                */
+               return -EINVAL;
+-      } else if (rdesc->result_data.error_code & BIT(9)) {
++      } else if (result_data->error_code & BIT(9)) {
+               /* Authentication failed */
+               return -EBADMSG;
+       }
+@@ -931,16 +974,18 @@
+ {
+       struct safexcel_command_desc *cdesc;
+       struct safexcel_result_desc *rdesc;
++      struct safexcel_token  *dmmy;
+       int ret = 0;
+       /* Prepare command descriptor */
+-      cdesc = safexcel_add_cdesc(priv, ring, true, true, 0, 0, 0, ctxr_dma);
++      cdesc = safexcel_add_cdesc(priv, ring, true, true, 0, 0, 0, ctxr_dma,
++                                 &dmmy);
+       if (IS_ERR(cdesc))
+               return PTR_ERR(cdesc);
+       cdesc->control_data.type = EIP197_TYPE_EXTENDED;
+       cdesc->control_data.options = 0;
+-      cdesc->control_data.refresh = 0;
++      cdesc->control_data.context_lo &= ~EIP197_CONTEXT_SIZE_MASK;
+       cdesc->control_data.control0 = CONTEXT_CONTROL_INV_TR;
+       /* Prepare result descriptor */
+@@ -1003,7 +1048,7 @@
+ acknowledge:
+       if (i)
+               writel(EIP197_xDR_PROC_xD_PKT(i) |
+-                     EIP197_xDR_PROC_xD_COUNT(tot_descs * priv->config.rd_offset),
++                     (tot_descs * priv->config.rd_offset),
+                      EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT);
+       /* If the number of requests overflowed the counter, try to proceed more
+@@ -1171,6 +1216,44 @@
+       &safexcel_alg_xts_aes,
+       &safexcel_alg_gcm,
+       &safexcel_alg_ccm,
++      &safexcel_alg_crc32,
++      &safexcel_alg_cbcmac,
++      &safexcel_alg_xcbcmac,
++      &safexcel_alg_cmac,
++      &safexcel_alg_chacha20,
++      &safexcel_alg_chachapoly,
++      &safexcel_alg_chachapoly_esp,
++      &safexcel_alg_sm3,
++      &safexcel_alg_hmac_sm3,
++      &safexcel_alg_ecb_sm4,
++      &safexcel_alg_cbc_sm4,
++      &safexcel_alg_ofb_sm4,
++      &safexcel_alg_cfb_sm4,
++      &safexcel_alg_ctr_sm4,
++      &safexcel_alg_authenc_hmac_sha1_cbc_sm4,
++      &safexcel_alg_authenc_hmac_sm3_cbc_sm4,
++      &safexcel_alg_authenc_hmac_sha1_ctr_sm4,
++      &safexcel_alg_authenc_hmac_sm3_ctr_sm4,
++      &safexcel_alg_sha3_224,
++      &safexcel_alg_sha3_256,
++      &safexcel_alg_sha3_384,
++      &safexcel_alg_sha3_512,
++      &safexcel_alg_hmac_sha3_224,
++      &safexcel_alg_hmac_sha3_256,
++      &safexcel_alg_hmac_sha3_384,
++      &safexcel_alg_hmac_sha3_512,
++      &safexcel_alg_authenc_hmac_sha1_cbc_des,
++      &safexcel_alg_authenc_hmac_sha256_cbc_des3_ede,
++      &safexcel_alg_authenc_hmac_sha224_cbc_des3_ede,
++      &safexcel_alg_authenc_hmac_sha512_cbc_des3_ede,
++      &safexcel_alg_authenc_hmac_sha384_cbc_des3_ede,
++      &safexcel_alg_authenc_hmac_sha256_cbc_des,
++      &safexcel_alg_authenc_hmac_sha224_cbc_des,
++      &safexcel_alg_authenc_hmac_sha512_cbc_des,
++      &safexcel_alg_authenc_hmac_sha384_cbc_des,
++      &safexcel_alg_rfc4106_gcm,
++      &safexcel_alg_rfc4543_gcm,
++      &safexcel_alg_rfc4309_ccm,
+ };
+ static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv)
+@@ -1240,30 +1323,30 @@
+ static void safexcel_configure(struct safexcel_crypto_priv *priv)
+ {
+-      u32 val, mask = 0;
+-
+-      val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS);
+-
+-      /* Read number of PEs from the engine */
+-      if (priv->flags & SAFEXCEL_HW_EIP197)
+-              /* Wider field width for all EIP197 type engines */
+-              mask = EIP197_N_PES_MASK;
+-      else
+-              /* Narrow field width for EIP97 type engine */
+-              mask = EIP97_N_PES_MASK;
+-
+-      priv->config.pes = (val >> EIP197_N_PES_OFFSET) & mask;
++      u32 mask = BIT(priv->hwconfig.hwdataw) - 1;
+-      priv->config.rings = min_t(u32, val & GENMASK(3, 0), max_rings);
++      priv->config.pes = priv->hwconfig.hwnumpes;
++      priv->config.rings = min_t(u32, priv->hwconfig.hwnumrings, max_rings);
++      /* Cannot currently support more rings than we have ring AICs! */
++      priv->config.rings = min_t(u32, priv->config.rings,
++                                      priv->hwconfig.hwnumraic);
+-      val = (val & GENMASK(27, 25)) >> 25;
+-      mask = BIT(val) - 1;
+-
+-      priv->config.cd_size = (sizeof(struct safexcel_command_desc) / sizeof(u32));
++      priv->config.cd_size = EIP197_CD64_FETCH_SIZE;
+       priv->config.cd_offset = (priv->config.cd_size + mask) & ~mask;
++      priv->config.cdsh_offset = (EIP197_MAX_TOKENS + mask) & ~mask;
+-      priv->config.rd_size = (sizeof(struct safexcel_result_desc) / sizeof(u32));
++      /* res token is behind the descr, but ofs must be rounded to buswdth */
++      priv->config.res_offset = (EIP197_RD64_FETCH_SIZE + mask) & ~mask;
++      /* now the size of the descr is this 1st part plus the result struct */
++      priv->config.rd_size    = priv->config.res_offset +
++                                EIP197_RD64_RESULT_SIZE;
+       priv->config.rd_offset = (priv->config.rd_size + mask) & ~mask;
++
++      /* convert dwords to bytes */
++      priv->config.cd_offset *= sizeof(u32);
++      priv->config.cdsh_offset *= sizeof(u32);
++      priv->config.rd_offset *= sizeof(u32);
++      priv->config.res_offset *= sizeof(u32);
+ }
+ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv)
+@@ -1309,7 +1392,7 @@
+                                 int is_pci_dev)
+ {
+       struct device *dev = priv->dev;
+-      u32 peid, version, mask, val, hiaopt;
++      u32 peid, version, mask, val, hiaopt, hwopt, peopt;
+       int i, ret, hwctg;
+       priv->context_pool = dmam_pool_create("safexcel-context", dev,
+@@ -1371,13 +1454,16 @@
+        */
+       version = readl(EIP197_GLOBAL(priv) + EIP197_VERSION);
+       if (((priv->flags & SAFEXCEL_HW_EIP197) &&
+-           (EIP197_REG_LO16(version) != EIP197_VERSION_LE)) ||
++           (EIP197_REG_LO16(version) != EIP197_VERSION_LE) &&
++           (EIP197_REG_LO16(version) != EIP196_VERSION_LE)) ||
+           ((!(priv->flags & SAFEXCEL_HW_EIP197) &&
+            (EIP197_REG_LO16(version) != EIP97_VERSION_LE)))) {
+               /*
+                * We did not find the device that matched our initial probing
+                * (or our initial probing failed) Report appropriate error.
+                */
++              dev_err(priv->dev, "Probing for EIP97/EIP19x failed - no such device (read %08x)\n",
++                      version);
+               return -ENODEV;
+       }
+@@ -1385,6 +1471,14 @@
+       hwctg = version >> 28;
+       peid = version & 255;
++      /* Detect EIP206 processing pipe */
++      version = readl(EIP197_PE(priv) + + EIP197_PE_VERSION(0));
++      if (EIP197_REG_LO16(version) != EIP206_VERSION_LE) {
++              dev_err(priv->dev, "EIP%d: EIP206 not detected\n", peid);
++              return -ENODEV;
++      }
++      priv->hwconfig.ppver = EIP197_VERSION_MASK(version);
++
+       /* Detect EIP96 packet engine and version */
+       version = readl(EIP197_PE(priv) + EIP197_PE_EIP96_VERSION(0));
+       if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) {
+@@ -1393,10 +1487,13 @@
+       }
+       priv->hwconfig.pever = EIP197_VERSION_MASK(version);
++      hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS);
+       hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS);
+       if (priv->flags & SAFEXCEL_HW_EIP197) {
+               /* EIP197 */
++              peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0));
++
+               priv->hwconfig.hwdataw  = (hiaopt >> EIP197_HWDATAW_OFFSET) &
+                                         EIP197_HWDATAW_MASK;
+               priv->hwconfig.hwcfsize = ((hiaopt >> EIP197_CFSIZE_OFFSET) &
+@@ -1405,6 +1502,19 @@
+               priv->hwconfig.hwrfsize = ((hiaopt >> EIP197_RFSIZE_OFFSET) &
+                                          EIP197_RFSIZE_MASK) +
+                                         EIP197_RFSIZE_ADJUST;
++              priv->hwconfig.hwnumpes = (hiaopt >> EIP197_N_PES_OFFSET) &
++                                        EIP197_N_PES_MASK;
++              priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) &
++                                          EIP197_N_RINGS_MASK;
++              if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB)
++                      priv->flags |= EIP197_PE_ARB;
++              if (EIP206_OPT_ICE_TYPE(peopt) == 1)
++                      priv->flags |= EIP197_ICE;
++              /* If not a full TRC, then assume simple TRC */
++              if (!(hwopt & EIP197_OPT_HAS_TRC))
++                      priv->flags |= EIP197_SIMPLE_TRC;
++              /* EIP197 always has SOME form of TRC */
++              priv->flags |= EIP197_TRC_CACHE;
+       } else {
+               /* EIP97 */
+               priv->hwconfig.hwdataw  = (hiaopt >> EIP197_HWDATAW_OFFSET) &
+@@ -1413,6 +1523,23 @@
+                                         EIP97_CFSIZE_MASK;
+               priv->hwconfig.hwrfsize = (hiaopt >> EIP97_RFSIZE_OFFSET) &
+                                         EIP97_RFSIZE_MASK;
++              priv->hwconfig.hwnumpes = 1; /* by definition */
++              priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) &
++                                          EIP197_N_RINGS_MASK;
++      }
++
++      /* Scan for ring AIC's */
++      for (i = 0; i < EIP197_MAX_RING_AIC; i++) {
++              version = readl(EIP197_HIA_AIC_R(priv) +
++                              EIP197_HIA_AIC_R_VERSION(i));
++              if (EIP197_REG_LO16(version) != EIP201_VERSION_LE)
++                      break;
++      }
++      priv->hwconfig.hwnumraic = i;
++      /* Low-end EIP196 may not have any ring AIC's ... */
++      if (!priv->hwconfig.hwnumraic) {
++              dev_err(priv->dev, "No ring interrupt controller present!\n");
++              return -ENODEV;
+       }
+       /* Get supported algorithms from EIP96 transform engine */
+@@ -1420,10 +1547,12 @@
+                                   EIP197_PE_EIP96_OPTIONS(0));
+       /* Print single info line describing what we just detected */
+-      dev_info(priv->dev, "EIP%d:%x(%d)-HIA:%x(%d,%d,%d),PE:%x,alg:%08x\n",
+-               peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hiaver,
+-               priv->hwconfig.hwdataw, priv->hwconfig.hwcfsize,
+-               priv->hwconfig.hwrfsize, priv->hwconfig.pever,
++      dev_info(priv->dev, "EIP%d:%x(%d,%d,%d,%d)-HIA:%x(%d,%d,%d),PE:%x/%x,alg:%08x\n",
++               peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hwnumpes,
++               priv->hwconfig.hwnumrings, priv->hwconfig.hwnumraic,
++               priv->hwconfig.hiaver, priv->hwconfig.hwdataw,
++               priv->hwconfig.hwcfsize, priv->hwconfig.hwrfsize,
++               priv->hwconfig.ppver, priv->hwconfig.pever,
+                priv->hwconfig.algo_flags);
+       safexcel_configure(priv);
+@@ -1547,7 +1676,6 @@
+       }
+ }
+-#if IS_ENABLED(CONFIG_OF)
+ /* for Device Tree platform driver */
+ static int safexcel_probe(struct platform_device *pdev)
+@@ -1625,6 +1753,7 @@
+       safexcel_unregister_algorithms(priv);
+       safexcel_hw_reset_rings(priv);
++      clk_disable_unprepare(priv->reg_clk);
+       clk_disable_unprepare(priv->clk);
+       for (i = 0; i < priv->config.rings; i++)
+@@ -1666,9 +1795,7 @@
+               .of_match_table = safexcel_of_match_table,
+       },
+ };
+-#endif
+-#if IS_ENABLED(CONFIG_PCI)
+ /* PCIE devices - i.e. Inside Secure development boards */
+ static int safexcel_pci_probe(struct pci_dev *pdev,
+@@ -1759,7 +1886,7 @@
+       return rc;
+ }
+-void safexcel_pci_remove(struct pci_dev *pdev)
++static void safexcel_pci_remove(struct pci_dev *pdev)
+ {
+       struct safexcel_crypto_priv *priv = pci_get_drvdata(pdev);
+       int i;
+@@ -1789,54 +1916,32 @@
+       .probe         = safexcel_pci_probe,
+       .remove        = safexcel_pci_remove,
+ };
+-#endif
+-
+-/* Unfortunately, we have to resort to global variables here */
+-#if IS_ENABLED(CONFIG_PCI)
+-int pcireg_rc = -EINVAL; /* Default safe value */
+-#endif
+-#if IS_ENABLED(CONFIG_OF)
+-int ofreg_rc = -EINVAL; /* Default safe value */
+-#endif
+ static int __init safexcel_init(void)
+ {
+-#if IS_ENABLED(CONFIG_PCI)
++      int ret;
++
+       /* Register PCI driver */
+-      pcireg_rc = pci_register_driver(&safexcel_pci_driver);
+-#endif
++      ret = pci_register_driver(&safexcel_pci_driver);
+-#if IS_ENABLED(CONFIG_OF)
+       /* Register platform driver */
+-      ofreg_rc = platform_driver_register(&crypto_safexcel);
+- #if IS_ENABLED(CONFIG_PCI)
+-      /* Return success if either PCI or OF registered OK */
+-      return pcireg_rc ? ofreg_rc : 0;
+- #else
+-      return ofreg_rc;
+- #endif
+-#else
+- #if IS_ENABLED(CONFIG_PCI)
+-      return pcireg_rc;
+- #else
+-      return -EINVAL;
+- #endif
+-#endif
++      if (IS_ENABLED(CONFIG_OF) && !ret) {
++              ret = platform_driver_register(&crypto_safexcel);
++              if (ret)
++                      pci_unregister_driver(&safexcel_pci_driver);
++      }
++
++      return ret;
+ }
+ static void __exit safexcel_exit(void)
+ {
+-#if IS_ENABLED(CONFIG_OF)
+       /* Unregister platform driver */
+-      if (!ofreg_rc)
++      if (IS_ENABLED(CONFIG_OF))
+               platform_driver_unregister(&crypto_safexcel);
+-#endif
+-#if IS_ENABLED(CONFIG_PCI)
+       /* Unregister PCI driver if successfully registered before */
+-      if (!pcireg_rc)
+-              pci_unregister_driver(&safexcel_pci_driver);
+-#endif
++      pci_unregister_driver(&safexcel_pci_driver);
+ }
+ module_init(safexcel_init);
+--- a/drivers/crypto/inside-secure/safexcel_cipher.c
++++ b/drivers/crypto/inside-secure/safexcel_cipher.c
+@@ -5,18 +5,22 @@
+  * Antoine Tenart <antoine.tenart@free-electrons.com>
+  */
++#include <asm/unaligned.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmapool.h>
+-
+ #include <crypto/aead.h>
+ #include <crypto/aes.h>
+ #include <crypto/authenc.h>
++#include <crypto/chacha.h>
+ #include <crypto/ctr.h>
+ #include <crypto/internal/des.h>
+ #include <crypto/gcm.h>
+ #include <crypto/ghash.h>
++#include <crypto/poly1305.h>
+ #include <crypto/sha.h>
++#include <crypto/sm3.h>
++#include <crypto/sm4.h>
+ #include <crypto/xts.h>
+ #include <crypto/skcipher.h>
+ #include <crypto/internal/aead.h>
+@@ -33,6 +37,8 @@
+       SAFEXCEL_DES,
+       SAFEXCEL_3DES,
+       SAFEXCEL_AES,
++      SAFEXCEL_CHACHA20,
++      SAFEXCEL_SM4,
+ };
+ struct safexcel_cipher_ctx {
+@@ -41,8 +47,12 @@
+       u32 mode;
+       enum safexcel_cipher_alg alg;
+-      bool aead;
+-      int  xcm; /* 0=authenc, 1=GCM, 2 reserved for CCM */
++      u8 aead; /* !=0=AEAD, 2=IPSec ESP AEAD, 3=IPsec ESP GMAC */
++      u8 xcm;  /* 0=authenc, 1=GCM, 2 reserved for CCM */
++      u8 aadskip;
++      u8 blocksz;
++      u32 ivmask;
++      u32 ctrinit;
+       __le32 key[16];
+       u32 nonce;
+@@ -51,10 +61,11 @@
+       /* All the below is AEAD specific */
+       u32 hash_alg;
+       u32 state_sz;
+-      u32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)];
+-      u32 opad[SHA512_DIGEST_SIZE / sizeof(u32)];
++      __be32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)];
++      __be32 opad[SHA512_DIGEST_SIZE / sizeof(u32)];
+       struct crypto_cipher *hkaes;
++      struct crypto_aead *fback;
+ };
+ struct safexcel_cipher_req {
+@@ -65,206 +76,298 @@
+       int  nr_src, nr_dst;
+ };
+-static void safexcel_cipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
+-                                struct safexcel_command_desc *cdesc)
++static int safexcel_skcipher_iv(struct safexcel_cipher_ctx *ctx, u8 *iv,
++                              struct safexcel_command_desc *cdesc)
+ {
+-      u32 block_sz = 0;
+-
+       if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD) {
+               cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-
+               /* 32 bit nonce */
+               cdesc->control_data.token[0] = ctx->nonce;
+               /* 64 bit IV part */
+               memcpy(&cdesc->control_data.token[1], iv, 8);
+-              /* 32 bit counter, start at 1 (big endian!) */
+-              cdesc->control_data.token[3] = cpu_to_be32(1);
+-
+-              return;
+-      } else if (ctx->xcm == EIP197_XCM_MODE_GCM) {
+-              cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-
+-              /* 96 bit IV part */
+-              memcpy(&cdesc->control_data.token[0], iv, 12);
+-              /* 32 bit counter, start at 1 (big endian!) */
+-              cdesc->control_data.token[3] = cpu_to_be32(1);
+-
+-              return;
+-      } else if (ctx->xcm == EIP197_XCM_MODE_CCM) {
++              /* 32 bit counter, start at 0 or 1 (big endian!) */
++              cdesc->control_data.token[3] =
++                      (__force u32)cpu_to_be32(ctx->ctrinit);
++              return 4;
++      }
++      if (ctx->alg == SAFEXCEL_CHACHA20) {
+               cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-
+-              /* Variable length IV part */
+-              memcpy(&cdesc->control_data.token[0], iv, 15 - iv[0]);
+-              /* Start variable length counter at 0 */
+-              memset((u8 *)&cdesc->control_data.token[0] + 15 - iv[0],
+-                     0, iv[0] + 1);
+-
+-              return;
++              /* 96 bit nonce part */
++              memcpy(&cdesc->control_data.token[0], &iv[4], 12);
++              /* 32 bit counter */
++              cdesc->control_data.token[3] = *(u32 *)iv;
++              return 4;
+       }
+-      if (ctx->mode != CONTEXT_CONTROL_CRYPTO_MODE_ECB) {
+-              switch (ctx->alg) {
+-              case SAFEXCEL_DES:
+-                      block_sz = DES_BLOCK_SIZE;
+-                      cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
+-                      break;
+-              case SAFEXCEL_3DES:
+-                      block_sz = DES3_EDE_BLOCK_SIZE;
+-                      cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
+-                      break;
+-              case SAFEXCEL_AES:
+-                      block_sz = AES_BLOCK_SIZE;
+-                      cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-                      break;
+-              }
+-              memcpy(cdesc->control_data.token, iv, block_sz);
+-      }
++      cdesc->control_data.options |= ctx->ivmask;
++      memcpy(cdesc->control_data.token, iv, ctx->blocksz);
++      return ctx->blocksz / sizeof(u32);
+ }
+ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
+                                   struct safexcel_command_desc *cdesc,
++                                  struct safexcel_token *atoken,
+                                   u32 length)
+ {
+       struct safexcel_token *token;
++      int ivlen;
+-      safexcel_cipher_token(ctx, iv, cdesc);
+-
+-      /* skip over worst case IV of 4 dwords, no need to be exact */
+-      token = (struct safexcel_token *)(cdesc->control_data.token + 4);
++      ivlen = safexcel_skcipher_iv(ctx, iv, cdesc);
++      if (ivlen == 4) {
++              /* No space in cdesc, instruction moves to atoken */
++              cdesc->additional_cdata_size = 1;
++              token = atoken;
++      } else {
++              /* Everything fits in cdesc */
++              token = (struct safexcel_token *)(cdesc->control_data.token + 2);
++              /* Need to pad with NOP */
++              eip197_noop_token(&token[1]);
++      }
++
++      token->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++      token->packet_length = length;
++      token->stat = EIP197_TOKEN_STAT_LAST_PACKET |
++                    EIP197_TOKEN_STAT_LAST_HASH;
++      token->instructions = EIP197_TOKEN_INS_LAST |
++                            EIP197_TOKEN_INS_TYPE_CRYPTO |
++                            EIP197_TOKEN_INS_TYPE_OUTPUT;
++}
+-      token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+-      token[0].packet_length = length;
+-      token[0].stat = EIP197_TOKEN_STAT_LAST_PACKET |
+-                      EIP197_TOKEN_STAT_LAST_HASH;
+-      token[0].instructions = EIP197_TOKEN_INS_LAST |
+-                              EIP197_TOKEN_INS_TYPE_CRYPTO |
+-                              EIP197_TOKEN_INS_TYPE_OUTPUT;
++static void safexcel_aead_iv(struct safexcel_cipher_ctx *ctx, u8 *iv,
++                           struct safexcel_command_desc *cdesc)
++{
++      if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD ||
++          ctx->aead & EIP197_AEAD_TYPE_IPSEC_ESP) { /* _ESP and _ESP_GMAC */
++              /* 32 bit nonce */
++              cdesc->control_data.token[0] = ctx->nonce;
++              /* 64 bit IV part */
++              memcpy(&cdesc->control_data.token[1], iv, 8);
++              /* 32 bit counter, start at 0 or 1 (big endian!) */
++              cdesc->control_data.token[3] =
++                      (__force u32)cpu_to_be32(ctx->ctrinit);
++              return;
++      }
++      if (ctx->xcm == EIP197_XCM_MODE_GCM || ctx->alg == SAFEXCEL_CHACHA20) {
++              /* 96 bit IV part */
++              memcpy(&cdesc->control_data.token[0], iv, 12);
++              /* 32 bit counter, start at 0 or 1 (big endian!) */
++              cdesc->control_data.token[3] =
++                      (__force u32)cpu_to_be32(ctx->ctrinit);
++              return;
++      }
++      /* CBC */
++      memcpy(cdesc->control_data.token, iv, ctx->blocksz);
+ }
+ static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
+                               struct safexcel_command_desc *cdesc,
++                              struct safexcel_token *atoken,
+                               enum safexcel_cipher_direction direction,
+                               u32 cryptlen, u32 assoclen, u32 digestsize)
+ {
+-      struct safexcel_token *token;
++      struct safexcel_token *aadref;
++      int atoksize = 2; /* Start with minimum size */
++      int assocadj = assoclen - ctx->aadskip, aadalign;
+-      safexcel_cipher_token(ctx, iv, cdesc);
++      /* Always 4 dwords of embedded IV  for AEAD modes */
++      cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-      if (direction == SAFEXCEL_ENCRYPT) {
+-              /* align end of instruction sequence to end of token */
+-              token = (struct safexcel_token *)(cdesc->control_data.token +
+-                       EIP197_MAX_TOKENS - 13);
+-
+-              token[12].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-              token[12].packet_length = digestsize;
+-              token[12].stat = EIP197_TOKEN_STAT_LAST_HASH |
+-                               EIP197_TOKEN_STAT_LAST_PACKET;
+-              token[12].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
+-                                       EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
+-      } else {
++      if (direction == SAFEXCEL_DECRYPT)
+               cryptlen -= digestsize;
+-              /* align end of instruction sequence to end of token */
+-              token = (struct safexcel_token *)(cdesc->control_data.token +
+-                       EIP197_MAX_TOKENS - 14);
+-
+-              token[12].opcode = EIP197_TOKEN_OPCODE_RETRIEVE;
+-              token[12].packet_length = digestsize;
+-              token[12].stat = EIP197_TOKEN_STAT_LAST_HASH |
+-                               EIP197_TOKEN_STAT_LAST_PACKET;
+-              token[12].instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
+-
+-              token[13].opcode = EIP197_TOKEN_OPCODE_VERIFY;
+-              token[13].packet_length = digestsize |
+-                                        EIP197_TOKEN_HASH_RESULT_VERIFY;
+-              token[13].stat = EIP197_TOKEN_STAT_LAST_HASH |
+-                               EIP197_TOKEN_STAT_LAST_PACKET;
+-              token[13].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT;
+-      }
+-
+-      token[6].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+-      token[6].packet_length = assoclen;
+-
+-      if (likely(cryptlen)) {
+-              token[6].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+-
+-              token[10].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+-              token[10].packet_length = cryptlen;
+-              token[10].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-              token[10].instructions = EIP197_TOKEN_INS_LAST |
+-                                       EIP197_TOKEN_INS_TYPE_CRYPTO |
+-                                       EIP197_TOKEN_INS_TYPE_HASH |
+-                                       EIP197_TOKEN_INS_TYPE_OUTPUT;
+-      } else if (ctx->xcm != EIP197_XCM_MODE_CCM) {
+-              token[6].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-              token[6].instructions = EIP197_TOKEN_INS_LAST |
+-                                      EIP197_TOKEN_INS_TYPE_HASH;
+-      }
+-
+-      if (!ctx->xcm)
+-              return;
+-
+-      token[8].opcode = EIP197_TOKEN_OPCODE_INSERT_REMRES;
+-      token[8].packet_length = 0;
+-      token[8].instructions = AES_BLOCK_SIZE;
+-
+-      token[9].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-      token[9].packet_length = AES_BLOCK_SIZE;
+-      token[9].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
+-                              EIP197_TOKEN_INS_TYPE_CRYPTO;
+-
+-      if (ctx->xcm == EIP197_XCM_MODE_GCM) {
+-              token[6].instructions = EIP197_TOKEN_INS_LAST |
+-                                      EIP197_TOKEN_INS_TYPE_HASH;
+-      } else {
+-              u8 *cbcmaciv = (u8 *)&token[1];
+-              u32 *aadlen = (u32 *)&token[5];
+-
++      if (unlikely(ctx->xcm == EIP197_XCM_MODE_CCM)) {
+               /* Construct IV block B0 for the CBC-MAC */
+-              token[0].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-              token[0].packet_length = AES_BLOCK_SIZE +
+-                                       ((assoclen > 0) << 1);
+-              token[0].instructions = EIP197_TOKEN_INS_ORIGIN_TOKEN |
+-                                      EIP197_TOKEN_INS_TYPE_HASH;
+-              /* Variable length IV part */
+-              memcpy(cbcmaciv, iv, 15 - iv[0]);
+-              /* fixup flags byte */
+-              cbcmaciv[0] |= ((assoclen > 0) << 6) | ((digestsize - 2) << 2);
+-              /* Clear upper bytes of variable message length to 0 */
+-              memset(cbcmaciv + 15 - iv[0], 0, iv[0] - 1);
+-              /* insert lower 2 bytes of message length */
+-              cbcmaciv[14] = cryptlen >> 8;
+-              cbcmaciv[15] = cryptlen & 255;
+-
+-              if (assoclen) {
+-                      *aadlen = cpu_to_le32(cpu_to_be16(assoclen));
+-                      assoclen += 2;
++              u8 *final_iv = (u8 *)cdesc->control_data.token;
++              u8 *cbcmaciv = (u8 *)&atoken[1];
++              __le32 *aadlen = (__le32 *)&atoken[5];
++
++              if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
++                      /* Length + nonce */
++                      cdesc->control_data.token[0] = ctx->nonce;
++                      /* Fixup flags byte */
++                      *(__le32 *)cbcmaciv =
++                              cpu_to_le32(ctx->nonce |
++                                          ((assocadj > 0) << 6) |
++                                          ((digestsize - 2) << 2));
++                      /* 64 bit IV part */
++                      memcpy(&cdesc->control_data.token[1], iv, 8);
++                      memcpy(cbcmaciv + 4, iv, 8);
++                      /* Start counter at 0 */
++                      cdesc->control_data.token[3] = 0;
++                      /* Message length */
++                      *(__be32 *)(cbcmaciv + 12) = cpu_to_be32(cryptlen);
++              } else {
++                      /* Variable length IV part */
++                      memcpy(final_iv, iv, 15 - iv[0]);
++                      memcpy(cbcmaciv, iv, 15 - iv[0]);
++                      /* Start variable length counter at 0 */
++                      memset(final_iv + 15 - iv[0], 0, iv[0] + 1);
++                      memset(cbcmaciv + 15 - iv[0], 0, iv[0] - 1);
++                      /* fixup flags byte */
++                      cbcmaciv[0] |= ((assocadj > 0) << 6) |
++                                     ((digestsize - 2) << 2);
++                      /* insert lower 2 bytes of message length */
++                      cbcmaciv[14] = cryptlen >> 8;
++                      cbcmaciv[15] = cryptlen & 255;
++              }
++
++              atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++              atoken->packet_length = AES_BLOCK_SIZE +
++                                      ((assocadj > 0) << 1);
++              atoken->stat = 0;
++              atoken->instructions = EIP197_TOKEN_INS_ORIGIN_TOKEN |
++                                     EIP197_TOKEN_INS_TYPE_HASH;
++
++              if (likely(assocadj)) {
++                      *aadlen = cpu_to_le32((assocadj >> 8) |
++                                            (assocadj & 255) << 8);
++                      atoken += 6;
++                      atoksize += 7;
++              } else {
++                      atoken += 5;
++                      atoksize += 6;
+               }
+-              token[6].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+-
+-              /* Align AAD data towards hash engine */
+-              token[7].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-              assoclen &= 15;
+-              token[7].packet_length = assoclen ? 16 - assoclen : 0;
+-
++              /* Process AAD data */
++              aadref = atoken;
++              atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++              atoken->packet_length = assocadj;
++              atoken->stat = 0;
++              atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
++              atoken++;
++
++              /* For CCM only, align AAD data towards hash engine */
++              atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++              aadalign = (assocadj + 2) & 15;
++              atoken->packet_length = assocadj && aadalign ?
++                                              16 - aadalign :
++                                              0;
+               if (likely(cryptlen)) {
+-                      token[7].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+-
+-                      /* Align crypto data towards hash engine */
+-                      token[10].stat = 0;
++                      atoken->stat = 0;
++                      atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
++              } else {
++                      atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
++                      atoken->instructions = EIP197_TOKEN_INS_LAST |
++                                             EIP197_TOKEN_INS_TYPE_HASH;
++              }
++      } else {
++              safexcel_aead_iv(ctx, iv, cdesc);
+-                      token[11].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-                      cryptlen &= 15;
+-                      token[11].packet_length = cryptlen ? 16 - cryptlen : 0;
+-                      token[11].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-                      token[11].instructions = EIP197_TOKEN_INS_TYPE_HASH;
++              /* Process AAD data */
++              aadref = atoken;
++              atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++              atoken->packet_length = assocadj;
++              atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
++              atoken->instructions = EIP197_TOKEN_INS_LAST |
++                                     EIP197_TOKEN_INS_TYPE_HASH;
++      }
++      atoken++;
++
++      if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
++              /* For ESP mode (and not GMAC), skip over the IV */
++              atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++              atoken->packet_length = EIP197_AEAD_IPSEC_IV_SIZE;
++              atoken->stat = 0;
++              atoken->instructions = 0;
++              atoken++;
++              atoksize++;
++      } else if (unlikely(ctx->alg == SAFEXCEL_CHACHA20 &&
++                          direction == SAFEXCEL_DECRYPT)) {
++              /* Poly-chacha decryption needs a dummy NOP here ... */
++              atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++              atoken->packet_length = 16; /* According to Op Manual */
++              atoken->stat = 0;
++              atoken->instructions = 0;
++              atoken++;
++              atoksize++;
++      }
++
++      if  (ctx->xcm) {
++              /* For GCM and CCM, obtain enc(Y0) */
++              atoken->opcode = EIP197_TOKEN_OPCODE_INSERT_REMRES;
++              atoken->packet_length = 0;
++              atoken->stat = 0;
++              atoken->instructions = AES_BLOCK_SIZE;
++              atoken++;
++
++              atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++              atoken->packet_length = AES_BLOCK_SIZE;
++              atoken->stat = 0;
++              atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
++                                     EIP197_TOKEN_INS_TYPE_CRYPTO;
++              atoken++;
++              atoksize += 2;
++      }
++
++      if (likely(cryptlen || ctx->alg == SAFEXCEL_CHACHA20)) {
++              /* Fixup stat field for AAD direction instruction */
++              aadref->stat = 0;
++
++              /* Process crypto data */
++              atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++              atoken->packet_length = cryptlen;
++
++              if (unlikely(ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP_GMAC)) {
++                      /* Fixup instruction field for AAD dir instruction */
++                      aadref->instructions = EIP197_TOKEN_INS_TYPE_HASH;
++
++                      /* Do not send to crypt engine in case of GMAC */
++                      atoken->instructions = EIP197_TOKEN_INS_LAST |
++                                             EIP197_TOKEN_INS_TYPE_HASH |
++                                             EIP197_TOKEN_INS_TYPE_OUTPUT;
++              } else {
++                      atoken->instructions = EIP197_TOKEN_INS_LAST |
++                                             EIP197_TOKEN_INS_TYPE_CRYPTO |
++                                             EIP197_TOKEN_INS_TYPE_HASH |
++                                             EIP197_TOKEN_INS_TYPE_OUTPUT;
++              }
++
++              cryptlen &= 15;
++              if (unlikely(ctx->xcm == EIP197_XCM_MODE_CCM && cryptlen)) {
++                      atoken->stat = 0;
++                      /* For CCM only, pad crypto data to the hash engine */
++                      atoken++;
++                      atoksize++;
++                      atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++                      atoken->packet_length = 16 - cryptlen;
++                      atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
++                      atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
+               } else {
+-                      token[7].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-                      token[7].instructions = EIP197_TOKEN_INS_LAST |
+-                                              EIP197_TOKEN_INS_TYPE_HASH;
++                      atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
+               }
++              atoken++;
++              atoksize++;
+       }
++
++      if (direction == SAFEXCEL_ENCRYPT) {
++              /* Append ICV */
++              atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++              atoken->packet_length = digestsize;
++              atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
++                             EIP197_TOKEN_STAT_LAST_PACKET;
++              atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
++                                     EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
++      } else {
++              /* Extract ICV */
++              atoken->opcode = EIP197_TOKEN_OPCODE_RETRIEVE;
++              atoken->packet_length = digestsize;
++              atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
++                             EIP197_TOKEN_STAT_LAST_PACKET;
++              atoken->instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
++              atoken++;
++              atoksize++;
++
++              /* Verify ICV */
++              atoken->opcode = EIP197_TOKEN_OPCODE_VERIFY;
++              atoken->packet_length = digestsize |
++                                      EIP197_TOKEN_HASH_RESULT_VERIFY;
++              atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
++                             EIP197_TOKEN_STAT_LAST_PACKET;
++              atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT;
++      }
++
++      /* Fixup length of the token in the command descriptor */
++      cdesc->additional_cdata_size = atoksize;
+ }
+ static int safexcel_skcipher_aes_setkey(struct crypto_skcipher *ctfm,
+@@ -277,14 +380,12 @@
+       int ret, i;
+       ret = aes_expandkey(&aes, key, len);
+-      if (ret) {
+-              crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++      if (ret)
+               return ret;
+-      }
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+               for (i = 0; i < len / sizeof(u32); i++) {
+-                      if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++                      if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+                               ctx->base.needs_inv = true;
+                               break;
+                       }
+@@ -309,43 +410,57 @@
+       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct crypto_authenc_keys keys;
+       struct crypto_aes_ctx aes;
+-      int err = -EINVAL;
++      int err = -EINVAL, i;
+-      if (crypto_authenc_extractkeys(&keys, key, len) != 0)
++      if (unlikely(crypto_authenc_extractkeys(&keys, key, len)))
+               goto badkey;
+       if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD) {
+-              /* Minimum keysize is minimum AES key size + nonce size */
+-              if (keys.enckeylen < (AES_MIN_KEY_SIZE +
+-                                    CTR_RFC3686_NONCE_SIZE))
++              /* Must have at least space for the nonce here */
++              if (unlikely(keys.enckeylen < CTR_RFC3686_NONCE_SIZE))
+                       goto badkey;
+               /* last 4 bytes of key are the nonce! */
+               ctx->nonce = *(u32 *)(keys.enckey + keys.enckeylen -
+                                     CTR_RFC3686_NONCE_SIZE);
+               /* exclude the nonce here */
+-              keys.enckeylen -= CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++              keys.enckeylen -= CTR_RFC3686_NONCE_SIZE;
+       }
+       /* Encryption key */
+       switch (ctx->alg) {
++      case SAFEXCEL_DES:
++              err = verify_aead_des_key(ctfm, keys.enckey, keys.enckeylen);
++              if (unlikely(err))
++                      goto badkey;
++              break;
+       case SAFEXCEL_3DES:
+               err = verify_aead_des3_key(ctfm, keys.enckey, keys.enckeylen);
+               if (unlikely(err))
+-                      goto badkey_expflags;
++                      goto badkey;
+               break;
+       case SAFEXCEL_AES:
+               err = aes_expandkey(&aes, keys.enckey, keys.enckeylen);
+               if (unlikely(err))
+                       goto badkey;
+               break;
++      case SAFEXCEL_SM4:
++              if (unlikely(keys.enckeylen != SM4_KEY_SIZE))
++                      goto badkey;
++              break;
+       default:
+               dev_err(priv->dev, "aead: unsupported cipher algorithm\n");
+               goto badkey;
+       }
+-      if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma &&
+-          memcmp(ctx->key, keys.enckey, keys.enckeylen))
+-              ctx->base.needs_inv = true;
++      if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
++              for (i = 0; i < keys.enckeylen / sizeof(u32); i++) {
++                      if (le32_to_cpu(ctx->key[i]) !=
++                          ((u32 *)keys.enckey)[i]) {
++                              ctx->base.needs_inv = true;
++                              break;
++                      }
++              }
++      }
+       /* Auth key */
+       switch (ctx->hash_alg) {
+@@ -374,21 +489,24 @@
+                                        keys.authkeylen, &istate, &ostate))
+                       goto badkey;
+               break;
++      case CONTEXT_CONTROL_CRYPTO_ALG_SM3:
++              if (safexcel_hmac_setkey("safexcel-sm3", keys.authkey,
++                                       keys.authkeylen, &istate, &ostate))
++                      goto badkey;
++              break;
+       default:
+               dev_err(priv->dev, "aead: unsupported hash algorithm\n");
+               goto badkey;
+       }
+-      crypto_aead_set_flags(ctfm, crypto_aead_get_flags(ctfm) &
+-                                  CRYPTO_TFM_RES_MASK);
+-
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma &&
+           (memcmp(ctx->ipad, istate.state, ctx->state_sz) ||
+            memcmp(ctx->opad, ostate.state, ctx->state_sz)))
+               ctx->base.needs_inv = true;
+       /* Now copy the keys into the context */
+-      memcpy(ctx->key, keys.enckey, keys.enckeylen);
++      for (i = 0; i < keys.enckeylen / sizeof(u32); i++)
++              ctx->key[i] = cpu_to_le32(((u32 *)keys.enckey)[i]);
+       ctx->key_len = keys.enckeylen;
+       memcpy(ctx->ipad, &istate.state, ctx->state_sz);
+@@ -398,8 +516,6 @@
+       return 0;
+ badkey:
+-      crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+-badkey_expflags:
+       memzero_explicit(&keys, sizeof(keys));
+       return err;
+ }
+@@ -423,6 +539,17 @@
+                               CONTEXT_CONTROL_DIGEST_XCM |
+                               ctx->hash_alg |
+                               CONTEXT_CONTROL_SIZE(ctrl_size);
++              } else if (ctx->alg == SAFEXCEL_CHACHA20) {
++                      /* Chacha20-Poly1305 */
++                      cdesc->control_data.control0 =
++                              CONTEXT_CONTROL_KEY_EN |
++                              CONTEXT_CONTROL_CRYPTO_ALG_CHACHA20 |
++                              (sreq->direction == SAFEXCEL_ENCRYPT ?
++                                      CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT :
++                                      CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN) |
++                              ctx->hash_alg |
++                              CONTEXT_CONTROL_SIZE(ctrl_size);
++                      return 0;
+               } else {
+                       ctrl_size += ctx->state_sz / sizeof(u32) * 2;
+                       cdesc->control_data.control0 =
+@@ -431,17 +558,21 @@
+                               ctx->hash_alg |
+                               CONTEXT_CONTROL_SIZE(ctrl_size);
+               }
+-              if (sreq->direction == SAFEXCEL_ENCRYPT)
+-                      cdesc->control_data.control0 |=
+-                              (ctx->xcm == EIP197_XCM_MODE_CCM) ?
+-                                      CONTEXT_CONTROL_TYPE_HASH_ENCRYPT_OUT :
+-                                      CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT;
++              if (sreq->direction == SAFEXCEL_ENCRYPT &&
++                  (ctx->xcm == EIP197_XCM_MODE_CCM ||
++                   ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP_GMAC))
++                      cdesc->control_data.control0 |=
++                              CONTEXT_CONTROL_TYPE_HASH_ENCRYPT_OUT;
++              else if (sreq->direction == SAFEXCEL_ENCRYPT)
++                      cdesc->control_data.control0 |=
++                              CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT;
++              else if (ctx->xcm == EIP197_XCM_MODE_CCM)
++                      cdesc->control_data.control0 |=
++                              CONTEXT_CONTROL_TYPE_DECRYPT_HASH_IN;
+               else
+                       cdesc->control_data.control0 |=
+-                              (ctx->xcm == EIP197_XCM_MODE_CCM) ?
+-                                      CONTEXT_CONTROL_TYPE_DECRYPT_HASH_IN :
+-                                      CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN;
++                              CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN;
+       } else {
+               if (sreq->direction == SAFEXCEL_ENCRYPT)
+                       cdesc->control_data.control0 =
+@@ -480,6 +611,12 @@
+                               ctx->key_len >> ctx->xts);
+                       return -EINVAL;
+               }
++      } else if (ctx->alg == SAFEXCEL_CHACHA20) {
++              cdesc->control_data.control0 |=
++                      CONTEXT_CONTROL_CRYPTO_ALG_CHACHA20;
++      } else if (ctx->alg == SAFEXCEL_SM4) {
++              cdesc->control_data.control0 |=
++                      CONTEXT_CONTROL_CRYPTO_ALG_SM4;
+       }
+       return 0;
+@@ -563,6 +700,7 @@
+       unsigned int totlen;
+       unsigned int totlen_src = cryptlen + assoclen;
+       unsigned int totlen_dst = totlen_src;
++      struct safexcel_token *atoken;
+       int n_cdesc = 0, n_rdesc = 0;
+       int queued, i, ret = 0;
+       bool first = true;
+@@ -637,56 +775,60 @@
+       memcpy(ctx->base.ctxr->data, ctx->key, ctx->key_len);
+-      /* The EIP cannot deal with zero length input packets! */
+-      if (totlen == 0)
+-              totlen = 1;
++      if (!totlen) {
++              /*
++               * The EIP97 cannot deal with zero length input packets!
++               * So stuff a dummy command descriptor indicating a 1 byte
++               * (dummy) input packet, using the context record as source.
++               */
++              first_cdesc = safexcel_add_cdesc(priv, ring,
++                                               1, 1, ctx->base.ctxr_dma,
++                                               1, 1, ctx->base.ctxr_dma,
++                                               &atoken);
++              if (IS_ERR(first_cdesc)) {
++                      /* No space left in the command descriptor ring */
++                      ret = PTR_ERR(first_cdesc);
++                      goto cdesc_rollback;
++              }
++              n_cdesc = 1;
++              goto skip_cdesc;
++      }
+       /* command descriptors */
+       for_each_sg(src, sg, sreq->nr_src, i) {
+               int len = sg_dma_len(sg);
+               /* Do not overflow the request */
+-              if (queued - len < 0)
++              if (queued < len)
+                       len = queued;
+               cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc,
+                                          !(queued - len),
+                                          sg_dma_address(sg), len, totlen,
+-                                         ctx->base.ctxr_dma);
++                                         ctx->base.ctxr_dma, &atoken);
+               if (IS_ERR(cdesc)) {
+                       /* No space left in the command descriptor ring */
+                       ret = PTR_ERR(cdesc);
+                       goto cdesc_rollback;
+               }
+-              n_cdesc++;
+-              if (n_cdesc == 1) {
++              if (!n_cdesc)
+                       first_cdesc = cdesc;
+-              }
++              n_cdesc++;
+               queued -= len;
+               if (!queued)
+                       break;
+       }
+-
+-      if (unlikely(!n_cdesc)) {
+-              /*
+-               * Special case: zero length input buffer.
+-               * The engine always needs the 1st command descriptor, however!
+-               */
+-              first_cdesc = safexcel_add_cdesc(priv, ring, 1, 1, 0, 0, totlen,
+-                                               ctx->base.ctxr_dma);
+-              n_cdesc = 1;
+-      }
+-
++skip_cdesc:
+       /* Add context control words and token to first command descriptor */
+       safexcel_context_control(ctx, base, sreq, first_cdesc);
+       if (ctx->aead)
+-              safexcel_aead_token(ctx, iv, first_cdesc,
++              safexcel_aead_token(ctx, iv, first_cdesc, atoken,
+                                   sreq->direction, cryptlen,
+                                   assoclen, digestsize);
+       else
+-              safexcel_skcipher_token(ctx, iv, first_cdesc,
++              safexcel_skcipher_token(ctx, iv, first_cdesc, atoken,
+                                       cryptlen);
+       /* result descriptors */
+@@ -1073,6 +1215,8 @@
+       ctx->base.send = safexcel_skcipher_send;
+       ctx->base.handle_result = safexcel_skcipher_handle_result;
++      ctx->ivmask = EIP197_OPTION_4_TOKEN_IV_CMD;
++      ctx->ctrinit = 1;
+       return 0;
+ }
+@@ -1137,6 +1281,8 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_AES;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++      ctx->blocksz = 0;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+       return 0;
+ }
+@@ -1171,6 +1317,7 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_AES;
++      ctx->blocksz = AES_BLOCK_SIZE;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
+       return 0;
+ }
+@@ -1207,6 +1354,7 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_AES;
++      ctx->blocksz = AES_BLOCK_SIZE;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB;
+       return 0;
+ }
+@@ -1243,6 +1391,7 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_AES;
++      ctx->blocksz = AES_BLOCK_SIZE;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB;
+       return 0;
+ }
+@@ -1288,14 +1437,12 @@
+       /* exclude the nonce here */
+       keylen = len - CTR_RFC3686_NONCE_SIZE;
+       ret = aes_expandkey(&aes, key, keylen);
+-      if (ret) {
+-              crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++      if (ret)
+               return ret;
+-      }
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+               for (i = 0; i < keylen / sizeof(u32); i++) {
+-                      if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++                      if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+                               ctx->base.needs_inv = true;
+                               break;
+                       }
+@@ -1317,6 +1464,7 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_AES;
++      ctx->blocksz = AES_BLOCK_SIZE;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
+       return 0;
+ }
+@@ -1352,6 +1500,7 @@
+                              unsigned int len)
+ {
+       struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
++      struct safexcel_crypto_priv *priv = ctx->priv;
+       int ret;
+       ret = verify_skcipher_des_key(ctfm, key);
+@@ -1359,7 +1508,7 @@
+               return ret;
+       /* if context exits and key changed, need to invalidate it */
+-      if (ctx->base.ctxr_dma)
++      if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
+               if (memcmp(ctx->key, key, len))
+                       ctx->base.needs_inv = true;
+@@ -1375,6 +1524,8 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_DES;
++      ctx->blocksz = DES_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
+       return 0;
+ }
+@@ -1412,6 +1563,8 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_DES;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++      ctx->blocksz = 0;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+       return 0;
+ }
+@@ -1444,6 +1597,7 @@
+                                  const u8 *key, unsigned int len)
+ {
+       struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
++      struct safexcel_crypto_priv *priv = ctx->priv;
+       int err;
+       err = verify_skcipher_des3_key(ctfm, key);
+@@ -1451,13 +1605,11 @@
+               return err;
+       /* if context exits and key changed, need to invalidate it */
+-      if (ctx->base.ctxr_dma) {
++      if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
+               if (memcmp(ctx->key, key, len))
+                       ctx->base.needs_inv = true;
+-      }
+       memcpy(ctx->key, key, len);
+-
+       ctx->key_len = len;
+       return 0;
+@@ -1469,6 +1621,8 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_3DES;
++      ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
+       return 0;
+ }
+@@ -1506,6 +1660,8 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_3DES;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++      ctx->blocksz = 0;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+       return 0;
+ }
+@@ -1561,6 +1717,9 @@
+       ctx->priv = tmpl->priv;
+       ctx->alg  = SAFEXCEL_AES; /* default */
++      ctx->blocksz = AES_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_4_TOKEN_IV_CMD;
++      ctx->ctrinit = 1;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC; /* default */
+       ctx->aead = true;
+       ctx->base.send = safexcel_aead_send;
+@@ -1749,6 +1908,8 @@
+       safexcel_aead_sha1_cra_init(tfm);
+       ctx->alg = SAFEXCEL_3DES; /* override default */
++      ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+       return 0;
+ }
+@@ -1777,6 +1938,330 @@
+       },
+ };
++static int safexcel_aead_sha256_des3_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha256_cra_init(tfm);
++      ctx->alg = SAFEXCEL_3DES; /* override default */
++      ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des3_ede = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES3_EDE_BLOCK_SIZE,
++              .maxauthsize = SHA256_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha256),cbc(des3_ede))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha256-cbc-des3_ede",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha256_des3_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha224_des3_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha224_cra_init(tfm);
++      ctx->alg = SAFEXCEL_3DES; /* override default */
++      ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des3_ede = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES3_EDE_BLOCK_SIZE,
++              .maxauthsize = SHA224_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha224),cbc(des3_ede))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha224-cbc-des3_ede",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha224_des3_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha512_des3_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha512_cra_init(tfm);
++      ctx->alg = SAFEXCEL_3DES; /* override default */
++      ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des3_ede = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES3_EDE_BLOCK_SIZE,
++              .maxauthsize = SHA512_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha512),cbc(des3_ede))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha512-cbc-des3_ede",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha512_des3_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha384_des3_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha384_cra_init(tfm);
++      ctx->alg = SAFEXCEL_3DES; /* override default */
++      ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des3_ede = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES3_EDE_BLOCK_SIZE,
++              .maxauthsize = SHA384_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha384),cbc(des3_ede))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha384-cbc-des3_ede",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha384_des3_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha1_des_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha1_cra_init(tfm);
++      ctx->alg = SAFEXCEL_DES; /* override default */
++      ctx->blocksz = DES_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_des = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA1,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES_BLOCK_SIZE,
++              .maxauthsize = SHA1_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha1),cbc(des))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha1-cbc-des",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha1_des_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha256_des_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha256_cra_init(tfm);
++      ctx->alg = SAFEXCEL_DES; /* override default */
++      ctx->blocksz = DES_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES_BLOCK_SIZE,
++              .maxauthsize = SHA256_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha256),cbc(des))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha256-cbc-des",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha256_des_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha224_des_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha224_cra_init(tfm);
++      ctx->alg = SAFEXCEL_DES; /* override default */
++      ctx->blocksz = DES_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES_BLOCK_SIZE,
++              .maxauthsize = SHA224_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha224),cbc(des))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha224-cbc-des",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha224_des_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha512_des_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha512_cra_init(tfm);
++      ctx->alg = SAFEXCEL_DES; /* override default */
++      ctx->blocksz = DES_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES_BLOCK_SIZE,
++              .maxauthsize = SHA512_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha512),cbc(des))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha512-cbc-des",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha512_des_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sha384_des_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sha384_cra_init(tfm);
++      ctx->alg = SAFEXCEL_DES; /* override default */
++      ctx->blocksz = DES_BLOCK_SIZE;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = DES_BLOCK_SIZE,
++              .maxauthsize = SHA384_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha384),cbc(des))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha384-cbc-des",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = DES_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sha384_des_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
+ static int safexcel_aead_sha1_ctr_cra_init(struct crypto_tfm *tfm)
+ {
+       struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+@@ -1965,14 +2450,12 @@
+       /* Only half of the key data is cipher key */
+       keylen = (len >> 1);
+       ret = aes_expandkey(&aes, key, keylen);
+-      if (ret) {
+-              crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++      if (ret)
+               return ret;
+-      }
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+               for (i = 0; i < keylen / sizeof(u32); i++) {
+-                      if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++                      if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+                               ctx->base.needs_inv = true;
+                               break;
+                       }
+@@ -1984,15 +2467,13 @@
+       /* The other half is the tweak key */
+       ret = aes_expandkey(&aes, (u8 *)(key + keylen), keylen);
+-      if (ret) {
+-              crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++      if (ret)
+               return ret;
+-      }
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+               for (i = 0; i < keylen / sizeof(u32); i++) {
+-                      if (ctx->key[i + keylen / sizeof(u32)] !=
+-                          cpu_to_le32(aes.key_enc[i])) {
++                      if (le32_to_cpu(ctx->key[i + keylen / sizeof(u32)]) !=
++                          aes.key_enc[i]) {
+                               ctx->base.needs_inv = true;
+                               break;
+                       }
+@@ -2015,6 +2496,7 @@
+       safexcel_skcipher_cra_init(tfm);
+       ctx->alg  = SAFEXCEL_AES;
++      ctx->blocksz = AES_BLOCK_SIZE;
+       ctx->xts  = 1;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XTS;
+       return 0;
+@@ -2075,14 +2557,13 @@
+       ret = aes_expandkey(&aes, key, len);
+       if (ret) {
+-              crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               memzero_explicit(&aes, sizeof(aes));
+               return ret;
+       }
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+               for (i = 0; i < len / sizeof(u32); i++) {
+-                      if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++                      if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+                               ctx->base.needs_inv = true;
+                               break;
+                       }
+@@ -2099,8 +2580,6 @@
+       crypto_cipher_set_flags(ctx->hkaes, crypto_aead_get_flags(ctfm) &
+                               CRYPTO_TFM_REQ_MASK);
+       ret = crypto_cipher_setkey(ctx->hkaes, key, len);
+-      crypto_aead_set_flags(ctfm, crypto_cipher_get_flags(ctx->hkaes) &
+-                            CRYPTO_TFM_RES_MASK);
+       if (ret)
+               return ret;
+@@ -2109,7 +2588,7 @@
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+               for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++) {
+-                      if (ctx->ipad[i] != cpu_to_be32(hashkey[i])) {
++                      if (be32_to_cpu(ctx->ipad[i]) != hashkey[i]) {
+                               ctx->base.needs_inv = true;
+                               break;
+                       }
+@@ -2135,10 +2614,7 @@
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XCM; /* override default */
+       ctx->hkaes = crypto_alloc_cipher("aes", 0, 0);
+-      if (IS_ERR(ctx->hkaes))
+-              return PTR_ERR(ctx->hkaes);
+-
+-      return 0;
++      return PTR_ERR_OR_ZERO(ctx->hkaes);
+ }
+ static void safexcel_aead_gcm_cra_exit(struct crypto_tfm *tfm)
+@@ -2192,14 +2668,13 @@
+       ret = aes_expandkey(&aes, key, len);
+       if (ret) {
+-              crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               memzero_explicit(&aes, sizeof(aes));
+               return ret;
+       }
+       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+               for (i = 0; i < len / sizeof(u32); i++) {
+-                      if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++                      if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+                               ctx->base.needs_inv = true;
+                               break;
+                       }
+@@ -2235,6 +2710,7 @@
+       ctx->state_sz = 3 * AES_BLOCK_SIZE;
+       ctx->xcm = EIP197_XCM_MODE_CCM;
+       ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XCM; /* override default */
++      ctx->ctrinit = 0;
+       return 0;
+ }
+@@ -2301,5 +2777,949 @@
+                       .cra_exit = safexcel_aead_cra_exit,
+                       .cra_module = THIS_MODULE,
+               },
++      },
++};
++
++static void safexcel_chacha20_setkey(struct safexcel_cipher_ctx *ctx,
++                                   const u8 *key)
++{
++      struct safexcel_crypto_priv *priv = ctx->priv;
++
++      if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
++              if (memcmp(ctx->key, key, CHACHA_KEY_SIZE))
++                      ctx->base.needs_inv = true;
++
++      memcpy(ctx->key, key, CHACHA_KEY_SIZE);
++      ctx->key_len = CHACHA_KEY_SIZE;
++}
++
++static int safexcel_skcipher_chacha20_setkey(struct crypto_skcipher *ctfm,
++                                           const u8 *key, unsigned int len)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
++
++      if (len != CHACHA_KEY_SIZE)
++              return -EINVAL;
++
++      safexcel_chacha20_setkey(ctx, key);
++
++      return 0;
++}
++
++static int safexcel_skcipher_chacha20_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_skcipher_cra_init(tfm);
++      ctx->alg  = SAFEXCEL_CHACHA20;
++      ctx->ctrinit = 0;
++      ctx->mode = CONTEXT_CONTROL_CHACHA20_MODE_256_32;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_chacha20 = {
++      .type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++      .algo_mask = SAFEXCEL_ALG_CHACHA20,
++      .alg.skcipher = {
++              .setkey = safexcel_skcipher_chacha20_setkey,
++              .encrypt = safexcel_encrypt,
++              .decrypt = safexcel_decrypt,
++              .min_keysize = CHACHA_KEY_SIZE,
++              .max_keysize = CHACHA_KEY_SIZE,
++              .ivsize = CHACHA_IV_SIZE,
++              .base = {
++                      .cra_name = "chacha20",
++                      .cra_driver_name = "safexcel-chacha20",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_skcipher_chacha20_cra_init,
++                      .cra_exit = safexcel_skcipher_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_chachapoly_setkey(struct crypto_aead *ctfm,
++                                  const u8 *key, unsigned int len)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_aead_ctx(ctfm);
++
++      if (ctx->aead  == EIP197_AEAD_TYPE_IPSEC_ESP &&
++          len > EIP197_AEAD_IPSEC_NONCE_SIZE) {
++              /* ESP variant has nonce appended to key */
++              len -= EIP197_AEAD_IPSEC_NONCE_SIZE;
++              ctx->nonce = *(u32 *)(key + len);
++      }
++      if (len != CHACHA_KEY_SIZE)
++              return -EINVAL;
++
++      safexcel_chacha20_setkey(ctx, key);
++
++      return 0;
++}
++
++static int safexcel_aead_chachapoly_setauthsize(struct crypto_aead *tfm,
++                                       unsigned int authsize)
++{
++      if (authsize != POLY1305_DIGEST_SIZE)
++              return -EINVAL;
++      return 0;
++}
++
++static int safexcel_aead_chachapoly_crypt(struct aead_request *req,
++                                        enum safexcel_cipher_direction dir)
++{
++      struct safexcel_cipher_req *creq = aead_request_ctx(req);
++      struct crypto_aead *aead = crypto_aead_reqtfm(req);
++      struct crypto_tfm *tfm = crypto_aead_tfm(aead);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++      struct aead_request *subreq = aead_request_ctx(req);
++      u32 key[CHACHA_KEY_SIZE / sizeof(u32) + 1];
++      int ret = 0;
++
++      /*
++       * Instead of wasting time detecting umpteen silly corner cases,
++       * just dump all "small" requests to the fallback implementation.
++       * HW would not be faster on such small requests anyway.
++       */
++      if (likely((ctx->aead != EIP197_AEAD_TYPE_IPSEC_ESP ||
++                  req->assoclen >= EIP197_AEAD_IPSEC_IV_SIZE) &&
++                 req->cryptlen > POLY1305_DIGEST_SIZE)) {
++              return safexcel_queue_req(&req->base, creq, dir);
++      }
++
++      /* HW cannot do full (AAD+payload) zero length, use fallback */
++      memcpy(key, ctx->key, CHACHA_KEY_SIZE);
++      if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
++              /* ESP variant has nonce appended to the key */
++              key[CHACHA_KEY_SIZE / sizeof(u32)] = ctx->nonce;
++              ret = crypto_aead_setkey(ctx->fback, (u8 *)key,
++                                       CHACHA_KEY_SIZE +
++                                       EIP197_AEAD_IPSEC_NONCE_SIZE);
++      } else {
++              ret = crypto_aead_setkey(ctx->fback, (u8 *)key,
++                                       CHACHA_KEY_SIZE);
++      }
++      if (ret) {
++              crypto_aead_clear_flags(aead, CRYPTO_TFM_REQ_MASK);
++              crypto_aead_set_flags(aead, crypto_aead_get_flags(ctx->fback) &
++                                          CRYPTO_TFM_REQ_MASK);
++              return ret;
++      }
++
++      aead_request_set_tfm(subreq, ctx->fback);
++      aead_request_set_callback(subreq, req->base.flags, req->base.complete,
++                                req->base.data);
++      aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
++                             req->iv);
++      aead_request_set_ad(subreq, req->assoclen);
++
++      return (dir ==  SAFEXCEL_ENCRYPT) ?
++              crypto_aead_encrypt(subreq) :
++              crypto_aead_decrypt(subreq);
++}
++
++static int safexcel_aead_chachapoly_encrypt(struct aead_request *req)
++{
++      return safexcel_aead_chachapoly_crypt(req, SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_aead_chachapoly_decrypt(struct aead_request *req)
++{
++      return safexcel_aead_chachapoly_crypt(req, SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_aead_fallback_cra_init(struct crypto_tfm *tfm)
++{
++      struct crypto_aead *aead = __crypto_aead_cast(tfm);
++      struct aead_alg *alg = crypto_aead_alg(aead);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_cra_init(tfm);
++
++      /* Allocate fallback implementation */
++      ctx->fback = crypto_alloc_aead(alg->base.cra_name, 0,
++                                     CRYPTO_ALG_ASYNC |
++                                     CRYPTO_ALG_NEED_FALLBACK);
++      if (IS_ERR(ctx->fback))
++              return PTR_ERR(ctx->fback);
++
++      crypto_aead_set_reqsize(aead, max(sizeof(struct safexcel_cipher_req),
++                                        sizeof(struct aead_request) +
++                                        crypto_aead_reqsize(ctx->fback)));
++
++      return 0;
++}
++
++static int safexcel_aead_chachapoly_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_fallback_cra_init(tfm);
++      ctx->alg  = SAFEXCEL_CHACHA20;
++      ctx->mode = CONTEXT_CONTROL_CHACHA20_MODE_256_32 |
++                  CONTEXT_CONTROL_CHACHA20_MODE_CALC_OTK;
++      ctx->ctrinit = 0;
++      ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_POLY1305;
++      ctx->state_sz = 0; /* Precomputed by HW */
++      return 0;
++}
++
++static void safexcel_aead_fallback_cra_exit(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      crypto_free_aead(ctx->fback);
++      safexcel_aead_cra_exit(tfm);
++}
++
++struct safexcel_alg_template safexcel_alg_chachapoly = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_CHACHA20 | SAFEXCEL_ALG_POLY1305,
++      .alg.aead = {
++              .setkey = safexcel_aead_chachapoly_setkey,
++              .setauthsize = safexcel_aead_chachapoly_setauthsize,
++              .encrypt = safexcel_aead_chachapoly_encrypt,
++              .decrypt = safexcel_aead_chachapoly_decrypt,
++              .ivsize = CHACHAPOLY_IV_SIZE,
++              .maxauthsize = POLY1305_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "rfc7539(chacha20,poly1305)",
++                      .cra_driver_name = "safexcel-chacha20-poly1305",
++                      /* +1 to put it above HW chacha + SW poly */
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY + 1,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                   CRYPTO_ALG_NEED_FALLBACK,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_chachapoly_cra_init,
++                      .cra_exit = safexcel_aead_fallback_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_chachapolyesp_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++      int ret;
++
++      ret = safexcel_aead_chachapoly_cra_init(tfm);
++      ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP;
++      ctx->aadskip = EIP197_AEAD_IPSEC_IV_SIZE;
++      return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_chachapoly_esp = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_CHACHA20 | SAFEXCEL_ALG_POLY1305,
++      .alg.aead = {
++              .setkey = safexcel_aead_chachapoly_setkey,
++              .setauthsize = safexcel_aead_chachapoly_setauthsize,
++              .encrypt = safexcel_aead_chachapoly_encrypt,
++              .decrypt = safexcel_aead_chachapoly_decrypt,
++              .ivsize = CHACHAPOLY_IV_SIZE - EIP197_AEAD_IPSEC_NONCE_SIZE,
++              .maxauthsize = POLY1305_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "rfc7539esp(chacha20,poly1305)",
++                      .cra_driver_name = "safexcel-chacha20-poly1305-esp",
++                      /* +1 to put it above HW chacha + SW poly */
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY + 1,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                   CRYPTO_ALG_NEED_FALLBACK,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_chachapolyesp_cra_init,
++                      .cra_exit = safexcel_aead_fallback_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_skcipher_sm4_setkey(struct crypto_skcipher *ctfm,
++                                      const u8 *key, unsigned int len)
++{
++      struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++      struct safexcel_crypto_priv *priv = ctx->priv;
++
++      if (len != SM4_KEY_SIZE)
++              return -EINVAL;
++
++      if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
++              if (memcmp(ctx->key, key, SM4_KEY_SIZE))
++                      ctx->base.needs_inv = true;
++
++      memcpy(ctx->key, key, SM4_KEY_SIZE);
++      ctx->key_len = SM4_KEY_SIZE;
++
++      return 0;
++}
++
++static int safexcel_sm4_blk_encrypt(struct skcipher_request *req)
++{
++      /* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++      if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++              return -EINVAL;
++      else
++              return safexcel_queue_req(&req->base, skcipher_request_ctx(req),
++                                        SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_sm4_blk_decrypt(struct skcipher_request *req)
++{
++      /* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++      if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++              return -EINVAL;
++      else
++              return safexcel_queue_req(&req->base, skcipher_request_ctx(req),
++                                        SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_skcipher_sm4_ecb_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_skcipher_cra_init(tfm);
++      ctx->alg  = SAFEXCEL_SM4;
++      ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++      ctx->blocksz = 0;
++      ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_ecb_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++      .algo_mask = SAFEXCEL_ALG_SM4,
++      .alg.skcipher = {
++              .setkey = safexcel_skcipher_sm4_setkey,
++              .encrypt = safexcel_sm4_blk_encrypt,
++              .decrypt = safexcel_sm4_blk_decrypt,
++              .min_keysize = SM4_KEY_SIZE,
++              .max_keysize = SM4_KEY_SIZE,
++              .base = {
++                      .cra_name = "ecb(sm4)",
++                      .cra_driver_name = "safexcel-ecb-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = SM4_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_skcipher_sm4_ecb_cra_init,
++                      .cra_exit = safexcel_skcipher_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_skcipher_sm4_cbc_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_skcipher_cra_init(tfm);
++      ctx->alg  = SAFEXCEL_SM4;
++      ctx->blocksz = SM4_BLOCK_SIZE;
++      ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_cbc_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++      .algo_mask = SAFEXCEL_ALG_SM4,
++      .alg.skcipher = {
++              .setkey = safexcel_skcipher_sm4_setkey,
++              .encrypt = safexcel_sm4_blk_encrypt,
++              .decrypt = safexcel_sm4_blk_decrypt,
++              .min_keysize = SM4_KEY_SIZE,
++              .max_keysize = SM4_KEY_SIZE,
++              .ivsize = SM4_BLOCK_SIZE,
++              .base = {
++                      .cra_name = "cbc(sm4)",
++                      .cra_driver_name = "safexcel-cbc-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = SM4_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_skcipher_sm4_cbc_cra_init,
++                      .cra_exit = safexcel_skcipher_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_skcipher_sm4_ofb_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_skcipher_cra_init(tfm);
++      ctx->alg  = SAFEXCEL_SM4;
++      ctx->blocksz = SM4_BLOCK_SIZE;
++      ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_ofb_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++      .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB,
++      .alg.skcipher = {
++              .setkey = safexcel_skcipher_sm4_setkey,
++              .encrypt = safexcel_encrypt,
++              .decrypt = safexcel_decrypt,
++              .min_keysize = SM4_KEY_SIZE,
++              .max_keysize = SM4_KEY_SIZE,
++              .ivsize = SM4_BLOCK_SIZE,
++              .base = {
++                      .cra_name = "ofb(sm4)",
++                      .cra_driver_name = "safexcel-ofb-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_skcipher_sm4_ofb_cra_init,
++                      .cra_exit = safexcel_skcipher_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_skcipher_sm4_cfb_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_skcipher_cra_init(tfm);
++      ctx->alg  = SAFEXCEL_SM4;
++      ctx->blocksz = SM4_BLOCK_SIZE;
++      ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_cfb_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++      .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB,
++      .alg.skcipher = {
++              .setkey = safexcel_skcipher_sm4_setkey,
++              .encrypt = safexcel_encrypt,
++              .decrypt = safexcel_decrypt,
++              .min_keysize = SM4_KEY_SIZE,
++              .max_keysize = SM4_KEY_SIZE,
++              .ivsize = SM4_BLOCK_SIZE,
++              .base = {
++                      .cra_name = "cfb(sm4)",
++                      .cra_driver_name = "safexcel-cfb-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_skcipher_sm4_cfb_cra_init,
++                      .cra_exit = safexcel_skcipher_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_skcipher_sm4ctr_setkey(struct crypto_skcipher *ctfm,
++                                         const u8 *key, unsigned int len)
++{
++      struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      /* last 4 bytes of key are the nonce! */
++      ctx->nonce = *(u32 *)(key + len - CTR_RFC3686_NONCE_SIZE);
++      /* exclude the nonce here */
++      len -= CTR_RFC3686_NONCE_SIZE;
++
++      return safexcel_skcipher_sm4_setkey(ctfm, key, len);
++}
++
++static int safexcel_skcipher_sm4_ctr_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_skcipher_cra_init(tfm);
++      ctx->alg  = SAFEXCEL_SM4;
++      ctx->blocksz = SM4_BLOCK_SIZE;
++      ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_ctr_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++      .algo_mask = SAFEXCEL_ALG_SM4,
++      .alg.skcipher = {
++              .setkey = safexcel_skcipher_sm4ctr_setkey,
++              .encrypt = safexcel_encrypt,
++              .decrypt = safexcel_decrypt,
++              /* Add nonce size */
++              .min_keysize = SM4_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
++              .max_keysize = SM4_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
++              .ivsize = CTR_RFC3686_IV_SIZE,
++              .base = {
++                      .cra_name = "rfc3686(ctr(sm4))",
++                      .cra_driver_name = "safexcel-ctr-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_skcipher_sm4_ctr_cra_init,
++                      .cra_exit = safexcel_skcipher_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sm4_blk_encrypt(struct aead_request *req)
++{
++      /* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++      if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++              return -EINVAL;
++
++      return safexcel_queue_req(&req->base, aead_request_ctx(req),
++                                SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_aead_sm4_blk_decrypt(struct aead_request *req)
++{
++      struct crypto_aead *tfm = crypto_aead_reqtfm(req);
++
++      /* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++      if ((req->cryptlen - crypto_aead_authsize(tfm)) & (SM4_BLOCK_SIZE - 1))
++              return -EINVAL;
++
++      return safexcel_queue_req(&req->base, aead_request_ctx(req),
++                                SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_aead_sm4cbc_sha1_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_cra_init(tfm);
++      ctx->alg = SAFEXCEL_SM4;
++      ctx->blocksz = SM4_BLOCK_SIZE;
++      ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1;
++      ctx->state_sz = SHA1_DIGEST_SIZE;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SHA1,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_sm4_blk_encrypt,
++              .decrypt = safexcel_aead_sm4_blk_decrypt,
++              .ivsize = SM4_BLOCK_SIZE,
++              .maxauthsize = SHA1_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha1),cbc(sm4))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha1-cbc-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = SM4_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sm4cbc_sha1_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_fallback_setkey(struct crypto_aead *ctfm,
++                                       const u8 *key, unsigned int len)
++{
++      struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      /* Keep fallback cipher synchronized */
++      return crypto_aead_setkey(ctx->fback, (u8 *)key, len) ?:
++             safexcel_aead_setkey(ctfm, key, len);
++}
++
++static int safexcel_aead_fallback_setauthsize(struct crypto_aead *ctfm,
++                                            unsigned int authsize)
++{
++      struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      /* Keep fallback cipher synchronized */
++      return crypto_aead_setauthsize(ctx->fback, authsize);
++}
++
++static int safexcel_aead_fallback_crypt(struct aead_request *req,
++                                      enum safexcel_cipher_direction dir)
++{
++      struct crypto_aead *aead = crypto_aead_reqtfm(req);
++      struct crypto_tfm *tfm = crypto_aead_tfm(aead);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++      struct aead_request *subreq = aead_request_ctx(req);
++
++      aead_request_set_tfm(subreq, ctx->fback);
++      aead_request_set_callback(subreq, req->base.flags, req->base.complete,
++                                req->base.data);
++      aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
++                             req->iv);
++      aead_request_set_ad(subreq, req->assoclen);
++
++      return (dir ==  SAFEXCEL_ENCRYPT) ?
++              crypto_aead_encrypt(subreq) :
++              crypto_aead_decrypt(subreq);
++}
++
++static int safexcel_aead_sm4cbc_sm3_encrypt(struct aead_request *req)
++{
++      struct safexcel_cipher_req *creq = aead_request_ctx(req);
++
++      /* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++      if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++              return -EINVAL;
++      else if (req->cryptlen || req->assoclen) /* If input length > 0 only */
++              return safexcel_queue_req(&req->base, creq, SAFEXCEL_ENCRYPT);
++
++      /* HW cannot do full (AAD+payload) zero length, use fallback */
++      return safexcel_aead_fallback_crypt(req, SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_aead_sm4cbc_sm3_decrypt(struct aead_request *req)
++{
++      struct safexcel_cipher_req *creq = aead_request_ctx(req);
++      struct crypto_aead *tfm = crypto_aead_reqtfm(req);
++
++      /* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++      if ((req->cryptlen - crypto_aead_authsize(tfm)) & (SM4_BLOCK_SIZE - 1))
++              return -EINVAL;
++      else if (req->cryptlen > crypto_aead_authsize(tfm) || req->assoclen)
++              /* If input length > 0 only */
++              return safexcel_queue_req(&req->base, creq, SAFEXCEL_DECRYPT);
++
++      /* HW cannot do full (AAD+payload) zero length, use fallback */
++      return safexcel_aead_fallback_crypt(req, SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_aead_sm4cbc_sm3_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_fallback_cra_init(tfm);
++      ctx->alg = SAFEXCEL_SM4;
++      ctx->blocksz = SM4_BLOCK_SIZE;
++      ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_SM3;
++      ctx->state_sz = SM3_DIGEST_SIZE;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_cbc_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SM3,
++      .alg.aead = {
++              .setkey = safexcel_aead_fallback_setkey,
++              .setauthsize = safexcel_aead_fallback_setauthsize,
++              .encrypt = safexcel_aead_sm4cbc_sm3_encrypt,
++              .decrypt = safexcel_aead_sm4cbc_sm3_decrypt,
++              .ivsize = SM4_BLOCK_SIZE,
++              .maxauthsize = SM3_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sm3),cbc(sm4))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sm3-cbc-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                   CRYPTO_ALG_NEED_FALLBACK,
++                      .cra_blocksize = SM4_BLOCK_SIZE,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sm4cbc_sm3_cra_init,
++                      .cra_exit = safexcel_aead_fallback_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sm4ctr_sha1_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sm4cbc_sha1_cra_init(tfm);
++      ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_ctr_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SHA1,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = CTR_RFC3686_IV_SIZE,
++              .maxauthsize = SHA1_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sha1),rfc3686(ctr(sm4)))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sha1-ctr-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sm4ctr_sha1_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_aead_sm4ctr_sm3_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_aead_sm4cbc_sm3_cra_init(tfm);
++      ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_ctr_sm4 = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SM3,
++      .alg.aead = {
++              .setkey = safexcel_aead_setkey,
++              .encrypt = safexcel_aead_encrypt,
++              .decrypt = safexcel_aead_decrypt,
++              .ivsize = CTR_RFC3686_IV_SIZE,
++              .maxauthsize = SM3_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "authenc(hmac(sm3),rfc3686(ctr(sm4)))",
++                      .cra_driver_name = "safexcel-authenc-hmac-sm3-ctr-sm4",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_aead_sm4ctr_sm3_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
++      },
++};
++
++static int safexcel_rfc4106_gcm_setkey(struct crypto_aead *ctfm, const u8 *key,
++                                     unsigned int len)
++{
++      struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      /* last 4 bytes of key are the nonce! */
++      ctx->nonce = *(u32 *)(key + len - CTR_RFC3686_NONCE_SIZE);
++
++      len -= CTR_RFC3686_NONCE_SIZE;
++      return safexcel_aead_gcm_setkey(ctfm, key, len);
++}
++
++static int safexcel_rfc4106_gcm_setauthsize(struct crypto_aead *tfm,
++                                          unsigned int authsize)
++{
++      return crypto_rfc4106_check_authsize(authsize);
++}
++
++static int safexcel_rfc4106_encrypt(struct aead_request *req)
++{
++      return crypto_ipsec_check_assoclen(req->assoclen) ?:
++             safexcel_aead_encrypt(req);
++}
++
++static int safexcel_rfc4106_decrypt(struct aead_request *req)
++{
++      return crypto_ipsec_check_assoclen(req->assoclen) ?:
++             safexcel_aead_decrypt(req);
++}
++
++static int safexcel_rfc4106_gcm_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++      int ret;
++
++      ret = safexcel_aead_gcm_cra_init(tfm);
++      ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP;
++      ctx->aadskip = EIP197_AEAD_IPSEC_IV_SIZE;
++      return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_rfc4106_gcm = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_GHASH,
++      .alg.aead = {
++              .setkey = safexcel_rfc4106_gcm_setkey,
++              .setauthsize = safexcel_rfc4106_gcm_setauthsize,
++              .encrypt = safexcel_rfc4106_encrypt,
++              .decrypt = safexcel_rfc4106_decrypt,
++              .ivsize = GCM_RFC4106_IV_SIZE,
++              .maxauthsize = GHASH_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "rfc4106(gcm(aes))",
++                      .cra_driver_name = "safexcel-rfc4106-gcm-aes",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_rfc4106_gcm_cra_init,
++                      .cra_exit = safexcel_aead_gcm_cra_exit,
++              },
++      },
++};
++
++static int safexcel_rfc4543_gcm_setauthsize(struct crypto_aead *tfm,
++                                          unsigned int authsize)
++{
++      if (authsize != GHASH_DIGEST_SIZE)
++              return -EINVAL;
++
++      return 0;
++}
++
++static int safexcel_rfc4543_gcm_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++      int ret;
++
++      ret = safexcel_aead_gcm_cra_init(tfm);
++      ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP_GMAC;
++      return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_rfc4543_gcm = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_GHASH,
++      .alg.aead = {
++              .setkey = safexcel_rfc4106_gcm_setkey,
++              .setauthsize = safexcel_rfc4543_gcm_setauthsize,
++              .encrypt = safexcel_rfc4106_encrypt,
++              .decrypt = safexcel_rfc4106_decrypt,
++              .ivsize = GCM_RFC4543_IV_SIZE,
++              .maxauthsize = GHASH_DIGEST_SIZE,
++              .base = {
++                      .cra_name = "rfc4543(gcm(aes))",
++                      .cra_driver_name = "safexcel-rfc4543-gcm-aes",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_rfc4543_gcm_cra_init,
++                      .cra_exit = safexcel_aead_gcm_cra_exit,
++              },
++      },
++};
++
++static int safexcel_rfc4309_ccm_setkey(struct crypto_aead *ctfm, const u8 *key,
++                                     unsigned int len)
++{
++      struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      /* First byte of the nonce = L = always 3 for RFC4309 (4 byte ctr) */
++      *(u8 *)&ctx->nonce = EIP197_AEAD_IPSEC_COUNTER_SIZE - 1;
++      /* last 3 bytes of key are the nonce! */
++      memcpy((u8 *)&ctx->nonce + 1, key + len -
++             EIP197_AEAD_IPSEC_CCM_NONCE_SIZE,
++             EIP197_AEAD_IPSEC_CCM_NONCE_SIZE);
++
++      len -= EIP197_AEAD_IPSEC_CCM_NONCE_SIZE;
++      return safexcel_aead_ccm_setkey(ctfm, key, len);
++}
++
++static int safexcel_rfc4309_ccm_setauthsize(struct crypto_aead *tfm,
++                                          unsigned int authsize)
++{
++      /* Borrowed from crypto/ccm.c */
++      switch (authsize) {
++      case 8:
++      case 12:
++      case 16:
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static int safexcel_rfc4309_ccm_encrypt(struct aead_request *req)
++{
++      struct safexcel_cipher_req *creq = aead_request_ctx(req);
++
++      /* Borrowed from crypto/ccm.c */
++      if (req->assoclen != 16 && req->assoclen != 20)
++              return -EINVAL;
++
++      return safexcel_queue_req(&req->base, creq, SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_rfc4309_ccm_decrypt(struct aead_request *req)
++{
++      struct safexcel_cipher_req *creq = aead_request_ctx(req);
++
++      /* Borrowed from crypto/ccm.c */
++      if (req->assoclen != 16 && req->assoclen != 20)
++              return -EINVAL;
++
++      return safexcel_queue_req(&req->base, creq, SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_rfc4309_ccm_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++      int ret;
++
++      ret = safexcel_aead_ccm_cra_init(tfm);
++      ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP;
++      ctx->aadskip = EIP197_AEAD_IPSEC_IV_SIZE;
++      return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_rfc4309_ccm = {
++      .type = SAFEXCEL_ALG_TYPE_AEAD,
++      .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_CBC_MAC_ALL,
++      .alg.aead = {
++              .setkey = safexcel_rfc4309_ccm_setkey,
++              .setauthsize = safexcel_rfc4309_ccm_setauthsize,
++              .encrypt = safexcel_rfc4309_ccm_encrypt,
++              .decrypt = safexcel_rfc4309_ccm_decrypt,
++              .ivsize = EIP197_AEAD_IPSEC_IV_SIZE,
++              .maxauthsize = AES_BLOCK_SIZE,
++              .base = {
++                      .cra_name = "rfc4309(ccm(aes))",
++                      .cra_driver_name = "safexcel-rfc4309-ccm-aes",
++                      .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                      .cra_flags = CRYPTO_ALG_ASYNC |
++                                   CRYPTO_ALG_KERN_DRIVER_ONLY,
++                      .cra_blocksize = 1,
++                      .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++                      .cra_alignmask = 0,
++                      .cra_init = safexcel_rfc4309_ccm_cra_init,
++                      .cra_exit = safexcel_aead_cra_exit,
++                      .cra_module = THIS_MODULE,
++              },
+       },
+ };
+--- a/drivers/crypto/inside-secure/safexcel.h
++++ b/drivers/crypto/inside-secure/safexcel.h
+@@ -17,8 +17,11 @@
+ #define EIP197_HIA_VERSION_BE                 0xca35
+ #define EIP197_HIA_VERSION_LE                 0x35ca
+ #define EIP97_VERSION_LE                      0x9e61
++#define EIP196_VERSION_LE                     0x3bc4
+ #define EIP197_VERSION_LE                     0x3ac5
+ #define EIP96_VERSION_LE                      0x9f60
++#define EIP201_VERSION_LE                     0x36c9
++#define EIP206_VERSION_LE                     0x31ce
+ #define EIP197_REG_LO16(reg)                  (reg & 0xffff)
+ #define EIP197_REG_HI16(reg)                  ((reg >> 16) & 0xffff)
+ #define EIP197_VERSION_MASK(reg)              ((reg >> 16) & 0xfff)
+@@ -26,12 +29,23 @@
+                                               ((reg >> 4) & 0xf0) | \
+                                               ((reg >> 12) & 0xf))
++/* EIP197 HIA OPTIONS ENCODING */
++#define EIP197_HIA_OPT_HAS_PE_ARB             BIT(29)
++
++/* EIP206 OPTIONS ENCODING */
++#define EIP206_OPT_ICE_TYPE(n)                        ((n>>8)&3)
++
++/* EIP197 OPTIONS ENCODING */
++#define EIP197_OPT_HAS_TRC                    BIT(31)
++
+ /* Static configuration */
+ #define EIP197_DEFAULT_RING_SIZE              400
+-#define EIP197_MAX_TOKENS                     18
++#define EIP197_EMB_TOKENS                     4 /* Pad CD to 16 dwords */
++#define EIP197_MAX_TOKENS                     16
+ #define EIP197_MAX_RINGS                      4
+ #define EIP197_FETCH_DEPTH                    2
+ #define EIP197_MAX_BATCH_SZ                   64
++#define EIP197_MAX_RING_AIC                   14
+ #define EIP197_GFP_FLAGS(base)        ((base).flags & CRYPTO_TFM_REQ_MAY_SLEEP ? \
+                                GFP_KERNEL : GFP_ATOMIC)
+@@ -138,6 +152,7 @@
+ #define EIP197_HIA_AIC_R_ENABLED_STAT(r)      (0xe010 - EIP197_HIA_AIC_R_OFF(r))
+ #define EIP197_HIA_AIC_R_ACK(r)                       (0xe010 - EIP197_HIA_AIC_R_OFF(r))
+ #define EIP197_HIA_AIC_R_ENABLE_CLR(r)                (0xe014 - EIP197_HIA_AIC_R_OFF(r))
++#define EIP197_HIA_AIC_R_VERSION(r)           (0xe01c - EIP197_HIA_AIC_R_OFF(r))
+ #define EIP197_HIA_AIC_G_ENABLE_CTRL          0xf808
+ #define EIP197_HIA_AIC_G_ENABLED_STAT         0xf810
+ #define EIP197_HIA_AIC_G_ACK                  0xf810
+@@ -157,12 +172,16 @@
+ #define EIP197_PE_EIP96_FUNCTION_EN(n)                (0x1004 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_CONTEXT_CTRL(n)               (0x1008 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_CONTEXT_STAT(n)               (0x100c + (0x2000 * (n)))
++#define EIP197_PE_EIP96_TOKEN_CTRL2(n)                (0x102c + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_FUNCTION2_EN(n)               (0x1030 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_OPTIONS(n)            (0x13f8 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_VERSION(n)            (0x13fc + (0x2000 * (n)))
+ #define EIP197_PE_OUT_DBUF_THRES(n)           (0x1c00 + (0x2000 * (n)))
+ #define EIP197_PE_OUT_TBUF_THRES(n)           (0x1d00 + (0x2000 * (n)))
++#define EIP197_PE_OPTIONS(n)                  (0x1ff8 + (0x2000 * (n)))
++#define EIP197_PE_VERSION(n)                  (0x1ffc + (0x2000 * (n)))
+ #define EIP197_MST_CTRL                               0xfff4
++#define EIP197_OPTIONS                                0xfff8
+ #define EIP197_VERSION                                0xfffc
+ /* EIP197-specific registers, no indirection */
+@@ -178,6 +197,7 @@
+ #define EIP197_TRC_ECCADMINSTAT                       0xf0838
+ #define EIP197_TRC_ECCDATASTAT                        0xf083c
+ #define EIP197_TRC_ECCDATA                    0xf0840
++#define EIP197_STRC_CONFIG                    0xf43f0
+ #define EIP197_FLUE_CACHEBASE_LO(n)           (0xf6000 + (32 * (n)))
+ #define EIP197_FLUE_CACHEBASE_HI(n)           (0xf6004 + (32 * (n)))
+ #define EIP197_FLUE_CONFIG(n)                 (0xf6010 + (32 * (n)))
+@@ -188,6 +208,7 @@
+ /* EIP197_HIA_xDR_DESC_SIZE */
+ #define EIP197_xDR_DESC_MODE_64BIT            BIT(31)
++#define EIP197_CDR_DESC_MODE_ADCP             BIT(30)
+ /* EIP197_HIA_xDR_DMA_CFG */
+ #define EIP197_HIA_xDR_WR_RES_BUF             BIT(22)
+@@ -213,7 +234,6 @@
+ /* EIP197_HIA_xDR_PROC_COUNT */
+ #define EIP197_xDR_PROC_xD_PKT_OFFSET         24
+ #define EIP197_xDR_PROC_xD_PKT_MASK           GENMASK(6, 0)
+-#define EIP197_xDR_PROC_xD_COUNT(n)           ((n) << 2)
+ #define EIP197_xDR_PROC_xD_PKT(n)             ((n) << 24)
+ #define EIP197_xDR_PROC_CLR_COUNT             BIT(31)
+@@ -228,6 +248,8 @@
+ #define EIP197_HIA_RA_PE_CTRL_EN              BIT(30)
+ /* EIP197_HIA_OPTIONS */
++#define EIP197_N_RINGS_OFFSET                 0
++#define EIP197_N_RINGS_MASK                   GENMASK(3, 0)
+ #define EIP197_N_PES_OFFSET                   4
+ #define EIP197_N_PES_MASK                     GENMASK(4, 0)
+ #define EIP97_N_PES_MASK                      GENMASK(2, 0)
+@@ -237,13 +259,13 @@
+ #define EIP197_CFSIZE_OFFSET                  9
+ #define EIP197_CFSIZE_ADJUST                  4
+ #define EIP97_CFSIZE_OFFSET                   8
+-#define EIP197_CFSIZE_MASK                    GENMASK(3, 0)
+-#define EIP97_CFSIZE_MASK                     GENMASK(4, 0)
++#define EIP197_CFSIZE_MASK                    GENMASK(2, 0)
++#define EIP97_CFSIZE_MASK                     GENMASK(3, 0)
+ #define EIP197_RFSIZE_OFFSET                  12
+ #define EIP197_RFSIZE_ADJUST                  4
+ #define EIP97_RFSIZE_OFFSET                   12
+-#define EIP197_RFSIZE_MASK                    GENMASK(3, 0)
+-#define EIP97_RFSIZE_MASK                     GENMASK(4, 0)
++#define EIP197_RFSIZE_MASK                    GENMASK(2, 0)
++#define EIP97_RFSIZE_MASK                     GENMASK(3, 0)
+ /* EIP197_HIA_AIC_R_ENABLE_CTRL */
+ #define EIP197_CDR_IRQ(n)                     BIT((n) * 2)
+@@ -257,9 +279,9 @@
+ #define EIP197_HIA_DxE_CFG_MIN_CTRL_SIZE(n)   ((n) << 16)
+ #define EIP197_HIA_DxE_CFG_CTRL_CACHE_CTRL(n) (((n) & 0x7) << 20)
+ #define EIP197_HIA_DxE_CFG_MAX_CTRL_SIZE(n)   ((n) << 24)
+-#define EIP197_HIA_DFE_CFG_DIS_DEBUG          (BIT(31) | BIT(29))
++#define EIP197_HIA_DFE_CFG_DIS_DEBUG          GENMASK(31, 29)
+ #define EIP197_HIA_DSE_CFG_EN_SINGLE_WR               BIT(29)
+-#define EIP197_HIA_DSE_CFG_DIS_DEBUG          BIT(31)
++#define EIP197_HIA_DSE_CFG_DIS_DEBUG          GENMASK(31, 30)
+ /* EIP197_HIA_DFE/DSE_THR_CTRL */
+ #define EIP197_DxE_THR_CTRL_EN                        BIT(30)
+@@ -327,13 +349,21 @@
+ #define EIP197_ADDRESS_MODE                   BIT(8)
+ #define EIP197_CONTROL_MODE                   BIT(9)
++/* EIP197_PE_EIP96_TOKEN_CTRL2 */
++#define EIP197_PE_EIP96_TOKEN_CTRL2_CTX_DONE  BIT(3)
++
++/* EIP197_STRC_CONFIG */
++#define EIP197_STRC_CONFIG_INIT                       BIT(31)
++#define EIP197_STRC_CONFIG_LARGE_REC(s)               (s<<8)
++#define EIP197_STRC_CONFIG_SMALL_REC(s)               (s<<0)
++
+ /* EIP197_FLUE_CONFIG */
+ #define EIP197_FLUE_CONFIG_MAGIC              0xc7000004
+ /* Context Control */
+ struct safexcel_context_record {
+-      u32 control0;
+-      u32 control1;
++      __le32 control0;
++      __le32 control1;
+       __le32 data[40];
+ } __packed;
+@@ -358,10 +388,14 @@
+ #define CONTEXT_CONTROL_CRYPTO_ALG_AES128     (0x5 << 17)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_AES192     (0x6 << 17)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_AES256     (0x7 << 17)
++#define CONTEXT_CONTROL_CRYPTO_ALG_CHACHA20   (0x8 << 17)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SM4                (0xd << 17)
++#define CONTEXT_CONTROL_DIGEST_INITIAL                (0x0 << 21)
+ #define CONTEXT_CONTROL_DIGEST_PRECOMPUTED    (0x1 << 21)
+ #define CONTEXT_CONTROL_DIGEST_XCM            (0x2 << 21)
+ #define CONTEXT_CONTROL_DIGEST_HMAC           (0x3 << 21)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_MD5                (0x0 << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_CRC32      (0x0 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_SHA1               (0x2 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_SHA224     (0x4 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_SHA256     (0x3 << 23)
+@@ -371,17 +405,25 @@
+ #define CONTEXT_CONTROL_CRYPTO_ALG_XCBC128    (0x1 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_XCBC192    (0x2 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_XCBC256    (0x3 << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SM3                (0x7 << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_256   (0xb << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_224   (0xc << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_512   (0xd << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_384   (0xe << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_POLY1305   (0xf << 23)
+ #define CONTEXT_CONTROL_INV_FR                        (0x5 << 24)
+ #define CONTEXT_CONTROL_INV_TR                        (0x6 << 24)
+ /* control1 */
+ #define CONTEXT_CONTROL_CRYPTO_MODE_ECB               (0 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_CBC               (1 << 0)
++#define CONTEXT_CONTROL_CHACHA20_MODE_256_32  (2 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_OFB               (4 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_CFB               (5 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD  (6 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_XTS               (7 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_XCM               ((6 << 0) | BIT(17))
++#define CONTEXT_CONTROL_CHACHA20_MODE_CALC_OTK        (12 << 0)
+ #define CONTEXT_CONTROL_IV0                   BIT(5)
+ #define CONTEXT_CONTROL_IV1                   BIT(6)
+ #define CONTEXT_CONTROL_IV2                   BIT(7)
+@@ -394,6 +436,13 @@
+ #define EIP197_XCM_MODE_GCM                   1
+ #define EIP197_XCM_MODE_CCM                   2
++#define EIP197_AEAD_TYPE_IPSEC_ESP            2
++#define EIP197_AEAD_TYPE_IPSEC_ESP_GMAC               3
++#define EIP197_AEAD_IPSEC_IV_SIZE             8
++#define EIP197_AEAD_IPSEC_NONCE_SIZE          4
++#define EIP197_AEAD_IPSEC_COUNTER_SIZE                4
++#define EIP197_AEAD_IPSEC_CCM_NONCE_SIZE      3
++
+ /* The hash counter given to the engine in the context has a granularity of
+  * 64 bits.
+  */
+@@ -423,6 +472,8 @@
+ #define EIP197_TRC_PARAMS2_RC_SZ_SMALL(n)     ((n) << 18)
+ /* Cache helpers */
++#define EIP197_MIN_DSIZE                      1024
++#define EIP197_MIN_ASIZE                      8
+ #define EIP197_CS_TRC_REC_WC                  64
+ #define EIP197_CS_RC_SIZE                     (4 * sizeof(u32))
+ #define EIP197_CS_RC_NEXT(x)                  (x)
+@@ -447,7 +498,7 @@
+       u16 application_id;
+       u16 rsvd1;
+-      u32 rsvd2;
++      u32 rsvd2[5];
+ } __packed;
+@@ -465,16 +516,15 @@
+       u32 data_lo;
+       u32 data_hi;
+-
+-      struct result_data_desc result_data;
+ } __packed;
+ /*
+  * The EIP(1)97 only needs to fetch the descriptor part of
+  * the result descriptor, not the result token part!
+  */
+-#define EIP197_RD64_FETCH_SIZE                ((sizeof(struct safexcel_result_desc) -\
+-                                        sizeof(struct result_data_desc)) /\
++#define EIP197_RD64_FETCH_SIZE                (sizeof(struct safexcel_result_desc) /\
++                                       sizeof(u32))
++#define EIP197_RD64_RESULT_SIZE               (sizeof(struct result_data_desc) /\
+                                        sizeof(u32))
+ struct safexcel_token {
+@@ -505,6 +555,8 @@
+ {
+       token->opcode = EIP197_TOKEN_OPCODE_NOOP;
+       token->packet_length = BIT(2);
++      token->stat = 0;
++      token->instructions = 0;
+ }
+ /* Instructions */
+@@ -526,14 +578,13 @@
+       u16 application_id;
+       u16 rsvd;
+-      u8 refresh:2;
+-      u32 context_lo:30;
++      u32 context_lo;
+       u32 context_hi;
+       u32 control0;
+       u32 control1;
+-      u32 token[EIP197_MAX_TOKENS];
++      u32 token[EIP197_EMB_TOKENS];
+ } __packed;
+ #define EIP197_OPTION_MAGIC_VALUE     BIT(0)
+@@ -543,7 +594,10 @@
+ #define EIP197_OPTION_2_TOKEN_IV_CMD  GENMASK(11, 10)
+ #define EIP197_OPTION_4_TOKEN_IV_CMD  GENMASK(11, 9)
++#define EIP197_TYPE_BCLA              0x0
+ #define EIP197_TYPE_EXTENDED          0x3
++#define EIP197_CONTEXT_SMALL          0x2
++#define EIP197_CONTEXT_SIZE_MASK      0x3
+ /* Basic Command Descriptor format */
+ struct safexcel_command_desc {
+@@ -551,16 +605,22 @@
+       u8 rsvd0:5;
+       u8 last_seg:1;
+       u8 first_seg:1;
+-      u16 additional_cdata_size:8;
++      u8 additional_cdata_size:8;
+       u32 rsvd1;
+       u32 data_lo;
+       u32 data_hi;
++      u32 atok_lo;
++      u32 atok_hi;
++
+       struct safexcel_control_data_desc control_data;
+ } __packed;
++#define EIP197_CD64_FETCH_SIZE                (sizeof(struct safexcel_command_desc) /\
++                                      sizeof(u32))
++
+ /*
+  * Internal structures & functions
+  */
+@@ -578,15 +638,20 @@
+ struct safexcel_desc_ring {
+       void *base;
++      void *shbase;
+       void *base_end;
++      void *shbase_end;
+       dma_addr_t base_dma;
++      dma_addr_t shbase_dma;
+       /* write and read pointers */
+       void *write;
++      void *shwrite;
+       void *read;
+       /* descriptor element offset */
+-      unsigned offset;
++      unsigned int offset;
++      unsigned int shoffset;
+ };
+ enum safexcel_alg_type {
+@@ -601,9 +666,11 @@
+       u32 cd_size;
+       u32 cd_offset;
++      u32 cdsh_offset;
+       u32 rd_size;
+       u32 rd_offset;
++      u32 res_offset;
+ };
+ struct safexcel_work_data {
+@@ -654,6 +721,12 @@
+ /* Priority we use for advertising our algorithms */
+ #define SAFEXCEL_CRA_PRIORITY         300
++/* SM3 digest result for zero length message */
++#define EIP197_SM3_ZEROM_HASH "\x1A\xB2\x1D\x83\x55\xCF\xA1\x7F" \
++                              "\x8E\x61\x19\x48\x31\xE8\x1A\x8F" \
++                              "\x22\xBE\xC8\xC7\x28\xFE\xFB\x74" \
++                              "\x7E\xD0\x35\xEB\x50\x82\xAA\x2B"
++
+ /* EIP algorithm presence flags */
+ enum safexcel_eip_algorithms {
+       SAFEXCEL_ALG_BC0      = BIT(5),
+@@ -697,16 +770,23 @@
+ enum safexcel_flags {
+       EIP197_TRC_CACHE        = BIT(0),
+       SAFEXCEL_HW_EIP197      = BIT(1),
++      EIP197_PE_ARB           = BIT(2),
++      EIP197_ICE              = BIT(3),
++      EIP197_SIMPLE_TRC       = BIT(4),
+ };
+ struct safexcel_hwconfig {
+       enum safexcel_eip_algorithms algo_flags;
+       int hwver;
+       int hiaver;
++      int ppver;
+       int pever;
+       int hwdataw;
+       int hwcfsize;
+       int hwrfsize;
++      int hwnumpes;
++      int hwnumrings;
++      int hwnumraic;
+ };
+ struct safexcel_crypto_priv {
+@@ -778,7 +858,7 @@
+ void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring);
+ int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv,
+-                              struct safexcel_result_desc *rdesc);
++                              void *rdp);
+ void safexcel_complete(struct safexcel_crypto_priv *priv, int ring);
+ int safexcel_invalidate_cache(struct crypto_async_request *async,
+                             struct safexcel_crypto_priv *priv,
+@@ -797,7 +877,8 @@
+                                                bool first, bool last,
+                                                dma_addr_t data, u32 len,
+                                                u32 full_data_len,
+-                                               dma_addr_t context);
++                                               dma_addr_t context,
++                                               struct safexcel_token **atoken);
+ struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *priv,
+                                                int ring_id,
+                                               bool first, bool last,
+@@ -853,5 +934,43 @@
+ extern struct safexcel_alg_template safexcel_alg_xts_aes;
+ extern struct safexcel_alg_template safexcel_alg_gcm;
+ extern struct safexcel_alg_template safexcel_alg_ccm;
++extern struct safexcel_alg_template safexcel_alg_crc32;
++extern struct safexcel_alg_template safexcel_alg_cbcmac;
++extern struct safexcel_alg_template safexcel_alg_xcbcmac;
++extern struct safexcel_alg_template safexcel_alg_cmac;
++extern struct safexcel_alg_template safexcel_alg_chacha20;
++extern struct safexcel_alg_template safexcel_alg_chachapoly;
++extern struct safexcel_alg_template safexcel_alg_chachapoly_esp;
++extern struct safexcel_alg_template safexcel_alg_sm3;
++extern struct safexcel_alg_template safexcel_alg_hmac_sm3;
++extern struct safexcel_alg_template safexcel_alg_ecb_sm4;
++extern struct safexcel_alg_template safexcel_alg_cbc_sm4;
++extern struct safexcel_alg_template safexcel_alg_ofb_sm4;
++extern struct safexcel_alg_template safexcel_alg_cfb_sm4;
++extern struct safexcel_alg_template safexcel_alg_ctr_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_cbc_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_ctr_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_ctr_sm4;
++extern struct safexcel_alg_template safexcel_alg_sha3_224;
++extern struct safexcel_alg_template safexcel_alg_sha3_256;
++extern struct safexcel_alg_template safexcel_alg_sha3_384;
++extern struct safexcel_alg_template safexcel_alg_sha3_512;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_224;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_256;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_384;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_512;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_rfc4106_gcm;
++extern struct safexcel_alg_template safexcel_alg_rfc4543_gcm;
++extern struct safexcel_alg_template safexcel_alg_rfc4309_ccm;
+ #endif
+--- a/drivers/crypto/inside-secure/safexcel_hash.c
++++ b/drivers/crypto/inside-secure/safexcel_hash.c
+@@ -5,9 +5,13 @@
+  * Antoine Tenart <antoine.tenart@free-electrons.com>
+  */
++#include <crypto/aes.h>
+ #include <crypto/hmac.h>
+ #include <crypto/md5.h>
+ #include <crypto/sha.h>
++#include <crypto/sha3.h>
++#include <crypto/skcipher.h>
++#include <crypto/sm3.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmapool.h>
+@@ -19,9 +23,19 @@
+       struct safexcel_crypto_priv *priv;
+       u32 alg;
+-
+-      u32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)];
+-      u32 opad[SHA512_DIGEST_SIZE / sizeof(u32)];
++      u8  key_sz;
++      bool cbcmac;
++      bool do_fallback;
++      bool fb_init_done;
++      bool fb_do_setkey;
++
++      __le32 ipad[SHA3_512_BLOCK_SIZE / sizeof(__le32)];
++      __le32 opad[SHA3_512_BLOCK_SIZE / sizeof(__le32)];
++
++      struct crypto_cipher *kaes;
++      struct crypto_ahash *fback;
++      struct crypto_shash *shpre;
++      struct shash_desc *shdesc;
+ };
+ struct safexcel_ahash_req {
+@@ -31,6 +45,8 @@
+       bool needs_inv;
+       bool hmac_zlen;
+       bool len_is_le;
++      bool not_first;
++      bool xcbcmac;
+       int nents;
+       dma_addr_t result_dma;
+@@ -39,7 +55,9 @@
+       u8 state_sz;    /* expected state size, only set once */
+       u8 block_sz;    /* block size, only set once */
+-      u32 state[SHA512_DIGEST_SIZE / sizeof(u32)] __aligned(sizeof(u32));
++      u8 digest_sz;   /* output digest size, only set once */
++      __le32 state[SHA3_512_BLOCK_SIZE /
++                   sizeof(__le32)] __aligned(sizeof(__le32));
+       u64 len;
+       u64 processed;
+@@ -57,22 +75,36 @@
+ }
+ static void safexcel_hash_token(struct safexcel_command_desc *cdesc,
+-                              u32 input_length, u32 result_length)
++                              u32 input_length, u32 result_length,
++                              bool cbcmac)
+ {
+       struct safexcel_token *token =
+               (struct safexcel_token *)cdesc->control_data.token;
+       token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+       token[0].packet_length = input_length;
+-      token[0].stat = EIP197_TOKEN_STAT_LAST_HASH;
+       token[0].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+-      token[1].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-      token[1].packet_length = result_length;
+-      token[1].stat = EIP197_TOKEN_STAT_LAST_HASH |
++      input_length &= 15;
++      if (unlikely(cbcmac && input_length)) {
++              token[0].stat =  0;
++              token[1].opcode = EIP197_TOKEN_OPCODE_INSERT;
++              token[1].packet_length = 16 - input_length;
++              token[1].stat = EIP197_TOKEN_STAT_LAST_HASH;
++              token[1].instructions = EIP197_TOKEN_INS_TYPE_HASH;
++      } else {
++              token[0].stat = EIP197_TOKEN_STAT_LAST_HASH;
++              eip197_noop_token(&token[1]);
++      }
++
++      token[2].opcode = EIP197_TOKEN_OPCODE_INSERT;
++      token[2].stat = EIP197_TOKEN_STAT_LAST_HASH |
+                       EIP197_TOKEN_STAT_LAST_PACKET;
+-      token[1].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
++      token[2].packet_length = result_length;
++      token[2].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
+                               EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
++
++      eip197_noop_token(&token[3]);
+ }
+ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
+@@ -82,29 +114,49 @@
+       struct safexcel_crypto_priv *priv = ctx->priv;
+       u64 count = 0;
+-      cdesc->control_data.control0 |= ctx->alg;
++      cdesc->control_data.control0 = ctx->alg;
++      cdesc->control_data.control1 = 0;
+       /*
+        * Copy the input digest if needed, and setup the context
+        * fields. Do this now as we need it to setup the first command
+        * descriptor.
+        */
+-      if (!req->processed) {
+-              /* First - and possibly only - block of basic hash only */
+-              if (req->finish) {
++      if (unlikely(req->digest == CONTEXT_CONTROL_DIGEST_XCM)) {
++              if (req->xcbcmac)
++                      memcpy(ctx->base.ctxr->data, ctx->ipad, ctx->key_sz);
++              else
++                      memcpy(ctx->base.ctxr->data, req->state, req->state_sz);
++
++              if (!req->finish && req->xcbcmac)
++                      cdesc->control_data.control0 |=
++                              CONTEXT_CONTROL_DIGEST_XCM |
++                              CONTEXT_CONTROL_TYPE_HASH_OUT  |
++                              CONTEXT_CONTROL_NO_FINISH_HASH |
++                              CONTEXT_CONTROL_SIZE(req->state_sz /
++                                                   sizeof(u32));
++              else
+                       cdesc->control_data.control0 |=
++                              CONTEXT_CONTROL_DIGEST_XCM |
++                              CONTEXT_CONTROL_TYPE_HASH_OUT  |
++                              CONTEXT_CONTROL_SIZE(req->state_sz /
++                                                   sizeof(u32));
++              return;
++      } else if (!req->processed) {
++              /* First - and possibly only - block of basic hash only */
++              if (req->finish)
++                      cdesc->control_data.control0 |= req->digest |
+                               CONTEXT_CONTROL_TYPE_HASH_OUT |
+                               CONTEXT_CONTROL_RESTART_HASH  |
+                               /* ensure its not 0! */
+                               CONTEXT_CONTROL_SIZE(1);
+-              } else {
+-                      cdesc->control_data.control0 |=
++              else
++                      cdesc->control_data.control0 |= req->digest |
+                               CONTEXT_CONTROL_TYPE_HASH_OUT  |
+                               CONTEXT_CONTROL_RESTART_HASH   |
+                               CONTEXT_CONTROL_NO_FINISH_HASH |
+                               /* ensure its not 0! */
+                               CONTEXT_CONTROL_SIZE(1);
+-              }
+               return;
+       }
+@@ -204,7 +256,7 @@
+       }
+       if (sreq->result_dma) {
+-              dma_unmap_single(priv->dev, sreq->result_dma, sreq->state_sz,
++              dma_unmap_single(priv->dev, sreq->result_dma, sreq->digest_sz,
+                                DMA_FROM_DEVICE);
+               sreq->result_dma = 0;
+       }
+@@ -223,14 +275,15 @@
+                       memcpy(sreq->cache, sreq->state,
+                              crypto_ahash_digestsize(ahash));
+-                      memcpy(sreq->state, ctx->opad, sreq->state_sz);
++                      memcpy(sreq->state, ctx->opad, sreq->digest_sz);
+                       sreq->len = sreq->block_sz +
+                                   crypto_ahash_digestsize(ahash);
+                       sreq->processed = sreq->block_sz;
+                       sreq->hmac = 0;
+-                      ctx->base.needs_inv = true;
++                      if (priv->flags & EIP197_TRC_CACHE)
++                              ctx->base.needs_inv = true;
+                       areq->nbytes = 0;
+                       safexcel_ahash_enqueue(areq);
+@@ -238,8 +291,14 @@
+                       return 1;
+               }
+-              memcpy(areq->result, sreq->state,
+-                     crypto_ahash_digestsize(ahash));
++              if (unlikely(sreq->digest == CONTEXT_CONTROL_DIGEST_XCM &&
++                           ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_CRC32)) {
++                      /* Undo final XOR with 0xffffffff ...*/
++                      *(__le32 *)areq->result = ~sreq->state[0];
++              } else {
++                      memcpy(areq->result, sreq->state,
++                             crypto_ahash_digestsize(ahash));
++              }
+       }
+       cache_len = safexcel_queued_len(sreq);
+@@ -261,10 +320,11 @@
+       struct safexcel_command_desc *cdesc, *first_cdesc = NULL;
+       struct safexcel_result_desc *rdesc;
+       struct scatterlist *sg;
+-      int i, extra = 0, n_cdesc = 0, ret = 0;
+-      u64 queued, len, cache_len;
++      struct safexcel_token *dmmy;
++      int i, extra = 0, n_cdesc = 0, ret = 0, cache_len, skip = 0;
++      u64 queued, len;
+-      queued = len = safexcel_queued_len(req);
++      queued = safexcel_queued_len(req);
+       if (queued <= HASH_CACHE_SIZE)
+               cache_len = queued;
+       else
+@@ -287,15 +347,52 @@
+                                  areq->nbytes - extra);
+               queued -= extra;
+-              len -= extra;
+               if (!queued) {
+                       *commands = 0;
+                       *results = 0;
+                       return 0;
+               }
++
++              extra = 0;
++      }
++
++      if (unlikely(req->xcbcmac && req->processed > AES_BLOCK_SIZE)) {
++              if (unlikely(cache_len < AES_BLOCK_SIZE)) {
++                      /*
++                       * Cache contains less than 1 full block, complete.
++                       */
++                      extra = AES_BLOCK_SIZE - cache_len;
++                      if (queued > cache_len) {
++                              /* More data follows: borrow bytes */
++                              u64 tmp = queued - cache_len;
++
++                              skip = min_t(u64, tmp, extra);
++                              sg_pcopy_to_buffer(areq->src,
++                                      sg_nents(areq->src),
++                                      req->cache + cache_len,
++                                      skip, 0);
++                      }
++                      extra -= skip;
++                      memset(req->cache + cache_len + skip, 0, extra);
++                      if (!ctx->cbcmac && extra) {
++                              // 10- padding for XCBCMAC & CMAC
++                              req->cache[cache_len + skip] = 0x80;
++                              // HW will use K2 iso K3 - compensate!
++                              for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++)
++                                      ((__be32 *)req->cache)[i] ^=
++                                        cpu_to_be32(le32_to_cpu(
++                                          ctx->ipad[i] ^ ctx->ipad[i + 4]));
++                      }
++                      cache_len = AES_BLOCK_SIZE;
++                      queued = queued + extra;
++              }
++
++              /* XCBC continue: XOR previous result into 1st word */
++              crypto_xor(req->cache, (const u8 *)req->state, AES_BLOCK_SIZE);
+       }
++      len = queued;
+       /* Add a command descriptor for the cached data, if any */
+       if (cache_len) {
+               req->cache_dma = dma_map_single(priv->dev, req->cache,
+@@ -306,8 +403,9 @@
+               req->cache_sz = cache_len;
+               first_cdesc = safexcel_add_cdesc(priv, ring, 1,
+                                                (cache_len == len),
+-                                               req->cache_dma, cache_len, len,
+-                                               ctx->base.ctxr_dma);
++                                               req->cache_dma, cache_len,
++                                               len, ctx->base.ctxr_dma,
++                                               &dmmy);
+               if (IS_ERR(first_cdesc)) {
+                       ret = PTR_ERR(first_cdesc);
+                       goto unmap_cache;
+@@ -319,10 +417,6 @@
+                       goto send_command;
+       }
+-      /* Skip descriptor generation for zero-length requests */
+-      if (!areq->nbytes)
+-              goto send_command;
+-
+       /* Now handle the current ahash request buffer(s) */
+       req->nents = dma_map_sg(priv->dev, areq->src,
+                               sg_nents_for_len(areq->src,
+@@ -336,26 +430,34 @@
+       for_each_sg(areq->src, sg, req->nents, i) {
+               int sglen = sg_dma_len(sg);
++              if (unlikely(sglen <= skip)) {
++                      skip -= sglen;
++                      continue;
++              }
++
+               /* Do not overflow the request */
+-              if (queued < sglen)
++              if ((queued + skip) <= sglen)
+                       sglen = queued;
++              else
++                      sglen -= skip;
+               cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc,
+                                          !(queued - sglen),
+-                                         sg_dma_address(sg),
+-                                         sglen, len, ctx->base.ctxr_dma);
++                                         sg_dma_address(sg) + skip, sglen,
++                                         len, ctx->base.ctxr_dma, &dmmy);
+               if (IS_ERR(cdesc)) {
+                       ret = PTR_ERR(cdesc);
+                       goto unmap_sg;
+               }
+-              n_cdesc++;
+-              if (n_cdesc == 1)
++              if (!n_cdesc)
+                       first_cdesc = cdesc;
++              n_cdesc++;
+               queued -= sglen;
+               if (!queued)
+                       break;
++              skip = 0;
+       }
+ send_command:
+@@ -363,9 +465,9 @@
+       safexcel_context_control(ctx, req, first_cdesc);
+       /* Add the token */
+-      safexcel_hash_token(first_cdesc, len, req->state_sz);
++      safexcel_hash_token(first_cdesc, len, req->digest_sz, ctx->cbcmac);
+-      req->result_dma = dma_map_single(priv->dev, req->state, req->state_sz,
++      req->result_dma = dma_map_single(priv->dev, req->state, req->digest_sz,
+                                        DMA_FROM_DEVICE);
+       if (dma_mapping_error(priv->dev, req->result_dma)) {
+               ret = -EINVAL;
+@@ -374,7 +476,7 @@
+       /* Add a result descriptor */
+       rdesc = safexcel_add_rdesc(priv, ring, 1, 1, req->result_dma,
+-                                 req->state_sz);
++                                 req->digest_sz);
+       if (IS_ERR(rdesc)) {
+               ret = PTR_ERR(rdesc);
+               goto unmap_result;
+@@ -382,17 +484,20 @@
+       safexcel_rdr_req_set(priv, ring, rdesc, &areq->base);
+-      req->processed += len;
++      req->processed += len - extra;
+       *commands = n_cdesc;
+       *results = 1;
+       return 0;
+ unmap_result:
+-      dma_unmap_single(priv->dev, req->result_dma, req->state_sz,
++      dma_unmap_single(priv->dev, req->result_dma, req->digest_sz,
+                        DMA_FROM_DEVICE);
+ unmap_sg:
+-      dma_unmap_sg(priv->dev, areq->src, req->nents, DMA_TO_DEVICE);
++      if (req->nents) {
++              dma_unmap_sg(priv->dev, areq->src, req->nents, DMA_TO_DEVICE);
++              req->nents = 0;
++      }
+ cdesc_rollback:
+       for (i = 0; i < n_cdesc; i++)
+               safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr);
+@@ -590,16 +695,12 @@
+       if (ctx->base.ctxr) {
+               if (priv->flags & EIP197_TRC_CACHE && !ctx->base.needs_inv &&
+-                  req->processed &&
+-                  (/* invalidate for basic hash continuation finish */
+-                   (req->finish &&
+-                    (req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED)) ||
++                   /* invalidate for *any* non-XCBC continuation */
++                 ((req->not_first && !req->xcbcmac) ||
+                    /* invalidate if (i)digest changed */
+                    memcmp(ctx->base.ctxr->data, req->state, req->state_sz) ||
+-                   /* invalidate for HMAC continuation finish */
+-                   (req->finish && (req->processed != req->block_sz)) ||
+                    /* invalidate for HMAC finish with odigest changed */
+-                   (req->finish &&
++                   (req->finish && req->hmac &&
+                     memcmp(ctx->base.ctxr->data + (req->state_sz>>2),
+                            ctx->opad, req->state_sz))))
+                       /*
+@@ -622,6 +723,7 @@
+               if (!ctx->base.ctxr)
+                       return -ENOMEM;
+       }
++      req->not_first = true;
+       ring = ctx->base.ring;
+@@ -691,8 +793,34 @@
+               else if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA512)
+                       memcpy(areq->result, sha512_zero_message_hash,
+                              SHA512_DIGEST_SIZE);
++              else if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SM3) {
++                      memcpy(areq->result,
++                             EIP197_SM3_ZEROM_HASH, SM3_DIGEST_SIZE);
++              }
+               return 0;
++      } else if (unlikely(req->digest == CONTEXT_CONTROL_DIGEST_XCM &&
++                          ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_MD5 &&
++                          req->len == sizeof(u32) && !areq->nbytes)) {
++              /* Zero length CRC32 */
++              memcpy(areq->result, ctx->ipad, sizeof(u32));
++              return 0;
++      } else if (unlikely(ctx->cbcmac && req->len == AES_BLOCK_SIZE &&
++                          !areq->nbytes)) {
++              /* Zero length CBC MAC */
++              memset(areq->result, 0, AES_BLOCK_SIZE);
++              return 0;
++      } else if (unlikely(req->xcbcmac && req->len == AES_BLOCK_SIZE &&
++                          !areq->nbytes)) {
++              /* Zero length (X)CBC/CMAC */
++              int i;
++
++              for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++)
++                      ((__be32 *)areq->result)[i] =
++                              cpu_to_be32(le32_to_cpu(ctx->ipad[i + 4]));//K3
++              areq->result[0] ^= 0x80;                        // 10- padding
++              crypto_cipher_encrypt_one(ctx->kaes, areq->result, areq->result);
++              return 0;
+       } else if (unlikely(req->hmac &&
+                           (req->len == req->block_sz) &&
+                           !areq->nbytes)) {
+@@ -792,6 +920,7 @@
+       ctx->priv = tmpl->priv;
+       ctx->base.send = safexcel_ahash_send;
+       ctx->base.handle_result = safexcel_handle_result;
++      ctx->fb_do_setkey = false;
+       crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+                                sizeof(struct safexcel_ahash_req));
+@@ -808,6 +937,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA1_DIGEST_SIZE;
++      req->digest_sz = SHA1_DIGEST_SIZE;
+       req->block_sz = SHA1_BLOCK_SIZE;
+       return 0;
+@@ -889,6 +1019,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA1_DIGEST_SIZE;
++      req->digest_sz = SHA1_DIGEST_SIZE;
+       req->block_sz = SHA1_BLOCK_SIZE;
+       req->hmac = true;
+@@ -1125,6 +1256,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA256_DIGEST_SIZE;
++      req->digest_sz = SHA256_DIGEST_SIZE;
+       req->block_sz = SHA256_BLOCK_SIZE;
+       return 0;
+@@ -1180,6 +1312,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA256_DIGEST_SIZE;
++      req->digest_sz = SHA256_DIGEST_SIZE;
+       req->block_sz = SHA256_BLOCK_SIZE;
+       return 0;
+@@ -1248,6 +1381,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA256_DIGEST_SIZE;
++      req->digest_sz = SHA256_DIGEST_SIZE;
+       req->block_sz = SHA256_BLOCK_SIZE;
+       req->hmac = true;
+@@ -1318,6 +1452,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA256_DIGEST_SIZE;
++      req->digest_sz = SHA256_DIGEST_SIZE;
+       req->block_sz = SHA256_BLOCK_SIZE;
+       req->hmac = true;
+@@ -1375,6 +1510,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA512;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA512_DIGEST_SIZE;
++      req->digest_sz = SHA512_DIGEST_SIZE;
+       req->block_sz = SHA512_BLOCK_SIZE;
+       return 0;
+@@ -1430,6 +1566,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA384;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA512_DIGEST_SIZE;
++      req->digest_sz = SHA512_DIGEST_SIZE;
+       req->block_sz = SHA512_BLOCK_SIZE;
+       return 0;
+@@ -1498,6 +1635,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA512;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA512_DIGEST_SIZE;
++      req->digest_sz = SHA512_DIGEST_SIZE;
+       req->block_sz = SHA512_BLOCK_SIZE;
+       req->hmac = true;
+@@ -1568,6 +1706,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA384;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = SHA512_DIGEST_SIZE;
++      req->digest_sz = SHA512_DIGEST_SIZE;
+       req->block_sz = SHA512_BLOCK_SIZE;
+       req->hmac = true;
+@@ -1625,6 +1764,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_MD5;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = MD5_DIGEST_SIZE;
++      req->digest_sz = MD5_DIGEST_SIZE;
+       req->block_sz = MD5_HMAC_BLOCK_SIZE;
+       return 0;
+@@ -1686,6 +1826,7 @@
+       ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_MD5;
+       req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+       req->state_sz = MD5_DIGEST_SIZE;
++      req->digest_sz = MD5_DIGEST_SIZE;
+       req->block_sz = MD5_HMAC_BLOCK_SIZE;
+       req->len_is_le = true; /* MD5 is little endian! ... */
+       req->hmac = true;
+@@ -1738,5 +1879,1235 @@
+                               .cra_module = THIS_MODULE,
+                       },
+               },
++      },
++};
++
++static int safexcel_crc32_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++      int ret = safexcel_ahash_cra_init(tfm);
++
++      /* Default 'key' is all zeroes */
++      memset(ctx->ipad, 0, sizeof(u32));
++      return ret;
++}
++
++static int safexcel_crc32_init(struct ahash_request *areq)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      /* Start from loaded key */
++      req->state[0]   = (__force __le32)le32_to_cpu(~ctx->ipad[0]);
++      /* Set processed to non-zero to enable invalidation detection */
++      req->len        = sizeof(u32);
++      req->processed  = sizeof(u32);
++
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_CRC32;
++      req->digest = CONTEXT_CONTROL_DIGEST_XCM;
++      req->state_sz = sizeof(u32);
++      req->digest_sz = sizeof(u32);
++      req->block_sz = sizeof(u32);
++
++      return 0;
++}
++
++static int safexcel_crc32_setkey(struct crypto_ahash *tfm, const u8 *key,
++                               unsigned int keylen)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++
++      if (keylen != sizeof(u32))
++              return -EINVAL;
++
++      memcpy(ctx->ipad, key, sizeof(u32));
++      return 0;
++}
++
++static int safexcel_crc32_digest(struct ahash_request *areq)
++{
++      return safexcel_crc32_init(areq) ?: safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_crc32 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = 0,
++      .alg.ahash = {
++              .init = safexcel_crc32_init,
++              .update = safexcel_ahash_update,
++              .final = safexcel_ahash_final,
++              .finup = safexcel_ahash_finup,
++              .digest = safexcel_crc32_digest,
++              .setkey = safexcel_crc32_setkey,
++              .export = safexcel_ahash_export,
++              .import = safexcel_ahash_import,
++              .halg = {
++                      .digestsize = sizeof(u32),
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "crc32",
++                              .cra_driver_name = "safexcel-crc32",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_OPTIONAL_KEY |
++                                           CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY,
++                              .cra_blocksize = 1,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_crc32_cra_init,
++                              .cra_exit = safexcel_ahash_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_cbcmac_init(struct ahash_request *areq)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      /* Start from loaded keys */
++      memcpy(req->state, ctx->ipad, ctx->key_sz);
++      /* Set processed to non-zero to enable invalidation detection */
++      req->len        = AES_BLOCK_SIZE;
++      req->processed  = AES_BLOCK_SIZE;
++
++      req->digest   = CONTEXT_CONTROL_DIGEST_XCM;
++      req->state_sz = ctx->key_sz;
++      req->digest_sz = AES_BLOCK_SIZE;
++      req->block_sz = AES_BLOCK_SIZE;
++      req->xcbcmac  = true;
++
++      return 0;
++}
++
++static int safexcel_cbcmac_setkey(struct crypto_ahash *tfm, const u8 *key,
++                               unsigned int len)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++      struct crypto_aes_ctx aes;
++      int ret, i;
++
++      ret = aes_expandkey(&aes, key, len);
++      if (ret)
++              return ret;
++
++      memset(ctx->ipad, 0, 2 * AES_BLOCK_SIZE);
++      for (i = 0; i < len / sizeof(u32); i++)
++              ctx->ipad[i + 8] = (__force __le32)cpu_to_be32(aes.key_enc[i]);
++
++      if (len == AES_KEYSIZE_192) {
++              ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC192;
++              ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++      } else if (len == AES_KEYSIZE_256) {
++              ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC256;
++              ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++      } else {
++              ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128;
++              ctx->key_sz = AES_MIN_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++      }
++      ctx->cbcmac  = true;
++
++      memzero_explicit(&aes, sizeof(aes));
++      return 0;
++}
++
++static int safexcel_cbcmac_digest(struct ahash_request *areq)
++{
++      return safexcel_cbcmac_init(areq) ?: safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_cbcmac = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = 0,
++      .alg.ahash = {
++              .init = safexcel_cbcmac_init,
++              .update = safexcel_ahash_update,
++              .final = safexcel_ahash_final,
++              .finup = safexcel_ahash_finup,
++              .digest = safexcel_cbcmac_digest,
++              .setkey = safexcel_cbcmac_setkey,
++              .export = safexcel_ahash_export,
++              .import = safexcel_ahash_import,
++              .halg = {
++                      .digestsize = AES_BLOCK_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "cbcmac(aes)",
++                              .cra_driver_name = "safexcel-cbcmac-aes",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY,
++                              .cra_blocksize = 1,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_ahash_cra_init,
++                              .cra_exit = safexcel_ahash_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_xcbcmac_setkey(struct crypto_ahash *tfm, const u8 *key,
++                               unsigned int len)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++      struct crypto_aes_ctx aes;
++      u32 key_tmp[3 * AES_BLOCK_SIZE / sizeof(u32)];
++      int ret, i;
++
++      ret = aes_expandkey(&aes, key, len);
++      if (ret)
++              return ret;
++
++      /* precompute the XCBC key material */
++      crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
++      crypto_cipher_set_flags(ctx->kaes, crypto_ahash_get_flags(tfm) &
++                              CRYPTO_TFM_REQ_MASK);
++      ret = crypto_cipher_setkey(ctx->kaes, key, len);
++      if (ret)
++              return ret;
++
++      crypto_cipher_encrypt_one(ctx->kaes, (u8 *)key_tmp + 2 * AES_BLOCK_SIZE,
++              "\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1");
++      crypto_cipher_encrypt_one(ctx->kaes, (u8 *)key_tmp,
++              "\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2");
++      crypto_cipher_encrypt_one(ctx->kaes, (u8 *)key_tmp + AES_BLOCK_SIZE,
++              "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3");
++      for (i = 0; i < 3 * AES_BLOCK_SIZE / sizeof(u32); i++)
++              ctx->ipad[i] =
++                      cpu_to_le32((__force u32)cpu_to_be32(key_tmp[i]));
++
++      crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
++      crypto_cipher_set_flags(ctx->kaes, crypto_ahash_get_flags(tfm) &
++                              CRYPTO_TFM_REQ_MASK);
++      ret = crypto_cipher_setkey(ctx->kaes,
++                                 (u8 *)key_tmp + 2 * AES_BLOCK_SIZE,
++                                 AES_MIN_KEY_SIZE);
++      if (ret)
++              return ret;
++
++      ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128;
++      ctx->key_sz = AES_MIN_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++      ctx->cbcmac = false;
++
++      memzero_explicit(&aes, sizeof(aes));
++      return 0;
++}
++
++static int safexcel_xcbcmac_cra_init(struct crypto_tfm *tfm)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_ahash_cra_init(tfm);
++      ctx->kaes = crypto_alloc_cipher("aes", 0, 0);
++      return PTR_ERR_OR_ZERO(ctx->kaes);
++}
++
++static void safexcel_xcbcmac_cra_exit(struct crypto_tfm *tfm)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      crypto_free_cipher(ctx->kaes);
++      safexcel_ahash_cra_exit(tfm);
++}
++
++struct safexcel_alg_template safexcel_alg_xcbcmac = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = 0,
++      .alg.ahash = {
++              .init = safexcel_cbcmac_init,
++              .update = safexcel_ahash_update,
++              .final = safexcel_ahash_final,
++              .finup = safexcel_ahash_finup,
++              .digest = safexcel_cbcmac_digest,
++              .setkey = safexcel_xcbcmac_setkey,
++              .export = safexcel_ahash_export,
++              .import = safexcel_ahash_import,
++              .halg = {
++                      .digestsize = AES_BLOCK_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "xcbc(aes)",
++                              .cra_driver_name = "safexcel-xcbc-aes",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY,
++                              .cra_blocksize = AES_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_xcbcmac_cra_init,
++                              .cra_exit = safexcel_xcbcmac_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
++                              unsigned int len)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++      struct crypto_aes_ctx aes;
++      __be64 consts[4];
++      u64 _const[2];
++      u8 msb_mask, gfmask;
++      int ret, i;
++
++      ret = aes_expandkey(&aes, key, len);
++      if (ret)
++              return ret;
++
++      for (i = 0; i < len / sizeof(u32); i++)
++              ctx->ipad[i + 8] =
++                      cpu_to_le32((__force u32)cpu_to_be32(aes.key_enc[i]));
++
++      /* precompute the CMAC key material */
++      crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
++      crypto_cipher_set_flags(ctx->kaes, crypto_ahash_get_flags(tfm) &
++                              CRYPTO_TFM_REQ_MASK);
++      ret = crypto_cipher_setkey(ctx->kaes, key, len);
++      if (ret)
++              return ret;
++
++      /* code below borrowed from crypto/cmac.c */
++      /* encrypt the zero block */
++      memset(consts, 0, AES_BLOCK_SIZE);
++      crypto_cipher_encrypt_one(ctx->kaes, (u8 *)consts, (u8 *)consts);
++
++      gfmask = 0x87;
++      _const[0] = be64_to_cpu(consts[1]);
++      _const[1] = be64_to_cpu(consts[0]);
++
++      /* gf(2^128) multiply zero-ciphertext with u and u^2 */
++      for (i = 0; i < 4; i += 2) {
++              msb_mask = ((s64)_const[1] >> 63) & gfmask;
++              _const[1] = (_const[1] << 1) | (_const[0] >> 63);
++              _const[0] = (_const[0] << 1) ^ msb_mask;
++
++              consts[i + 0] = cpu_to_be64(_const[1]);
++              consts[i + 1] = cpu_to_be64(_const[0]);
++      }
++      /* end of code borrowed from crypto/cmac.c */
++
++      for (i = 0; i < 2 * AES_BLOCK_SIZE / sizeof(u32); i++)
++              ctx->ipad[i] = (__force __le32)cpu_to_be32(((u32 *)consts)[i]);
++
++      if (len == AES_KEYSIZE_192) {
++              ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC192;
++              ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++      } else if (len == AES_KEYSIZE_256) {
++              ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC256;
++              ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++      } else {
++              ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128;
++              ctx->key_sz = AES_MIN_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++      }
++      ctx->cbcmac = false;
++
++      memzero_explicit(&aes, sizeof(aes));
++      return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_cmac = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = 0,
++      .alg.ahash = {
++              .init = safexcel_cbcmac_init,
++              .update = safexcel_ahash_update,
++              .final = safexcel_ahash_final,
++              .finup = safexcel_ahash_finup,
++              .digest = safexcel_cbcmac_digest,
++              .setkey = safexcel_cmac_setkey,
++              .export = safexcel_ahash_export,
++              .import = safexcel_ahash_import,
++              .halg = {
++                      .digestsize = AES_BLOCK_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "cmac(aes)",
++                              .cra_driver_name = "safexcel-cmac-aes",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY,
++                              .cra_blocksize = AES_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_xcbcmac_cra_init,
++                              .cra_exit = safexcel_xcbcmac_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_sm3_init(struct ahash_request *areq)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SM3;
++      req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
++      req->state_sz = SM3_DIGEST_SIZE;
++      req->digest_sz = SM3_DIGEST_SIZE;
++      req->block_sz = SM3_BLOCK_SIZE;
++
++      return 0;
++}
++
++static int safexcel_sm3_digest(struct ahash_request *areq)
++{
++      int ret = safexcel_sm3_init(areq);
++
++      if (ret)
++              return ret;
++
++      return safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_sm3 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SM3,
++      .alg.ahash = {
++              .init = safexcel_sm3_init,
++              .update = safexcel_ahash_update,
++              .final = safexcel_ahash_final,
++              .finup = safexcel_ahash_finup,
++              .digest = safexcel_sm3_digest,
++              .export = safexcel_ahash_export,
++              .import = safexcel_ahash_import,
++              .halg = {
++                      .digestsize = SM3_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "sm3",
++                              .cra_driver_name = "safexcel-sm3",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY,
++                              .cra_blocksize = SM3_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_ahash_cra_init,
++                              .cra_exit = safexcel_ahash_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_hmac_sm3_setkey(struct crypto_ahash *tfm, const u8 *key,
++                                  unsigned int keylen)
++{
++      return safexcel_hmac_alg_setkey(tfm, key, keylen, "safexcel-sm3",
++                                      SM3_DIGEST_SIZE);
++}
++
++static int safexcel_hmac_sm3_init(struct ahash_request *areq)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      /* Start from ipad precompute */
++      memcpy(req->state, ctx->ipad, SM3_DIGEST_SIZE);
++      /* Already processed the key^ipad part now! */
++      req->len        = SM3_BLOCK_SIZE;
++      req->processed  = SM3_BLOCK_SIZE;
++
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SM3;
++      req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
++      req->state_sz = SM3_DIGEST_SIZE;
++      req->digest_sz = SM3_DIGEST_SIZE;
++      req->block_sz = SM3_BLOCK_SIZE;
++      req->hmac = true;
++
++      return 0;
++}
++
++static int safexcel_hmac_sm3_digest(struct ahash_request *areq)
++{
++      int ret = safexcel_hmac_sm3_init(areq);
++
++      if (ret)
++              return ret;
++
++      return safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sm3 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SM3,
++      .alg.ahash = {
++              .init = safexcel_hmac_sm3_init,
++              .update = safexcel_ahash_update,
++              .final = safexcel_ahash_final,
++              .finup = safexcel_ahash_finup,
++              .digest = safexcel_hmac_sm3_digest,
++              .setkey = safexcel_hmac_sm3_setkey,
++              .export = safexcel_ahash_export,
++              .import = safexcel_ahash_import,
++              .halg = {
++                      .digestsize = SM3_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "hmac(sm3)",
++                              .cra_driver_name = "safexcel-hmac-sm3",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY,
++                              .cra_blocksize = SM3_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_ahash_cra_init,
++                              .cra_exit = safexcel_ahash_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_sha3_224_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_224;
++      req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++      req->state_sz = SHA3_224_DIGEST_SIZE;
++      req->digest_sz = SHA3_224_DIGEST_SIZE;
++      req->block_sz = SHA3_224_BLOCK_SIZE;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_sha3_fbcheck(struct ahash_request *req)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct ahash_request *subreq = ahash_request_ctx(req);
++      int ret = 0;
++
++      if (ctx->do_fallback) {
++              ahash_request_set_tfm(subreq, ctx->fback);
++              ahash_request_set_callback(subreq, req->base.flags,
++                                         req->base.complete, req->base.data);
++              ahash_request_set_crypt(subreq, req->src, req->result,
++                                      req->nbytes);
++              if (!ctx->fb_init_done) {
++                      if (ctx->fb_do_setkey) {
++                              /* Set fallback cipher HMAC key */
++                              u8 key[SHA3_224_BLOCK_SIZE];
++
++                              memcpy(key, ctx->ipad,
++                                     crypto_ahash_blocksize(ctx->fback) / 2);
++                              memcpy(key +
++                                     crypto_ahash_blocksize(ctx->fback) / 2,
++                                     ctx->opad,
++                                     crypto_ahash_blocksize(ctx->fback) / 2);
++                              ret = crypto_ahash_setkey(ctx->fback, key,
++                                      crypto_ahash_blocksize(ctx->fback));
++                              memzero_explicit(key,
++                                      crypto_ahash_blocksize(ctx->fback));
++                              ctx->fb_do_setkey = false;
++                      }
++                      ret = ret ?: crypto_ahash_init(subreq);
++                      ctx->fb_init_done = true;
++              }
++      }
++      return ret;
++}
++
++static int safexcel_sha3_update(struct ahash_request *req)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct ahash_request *subreq = ahash_request_ctx(req);
++
++      ctx->do_fallback = true;
++      return safexcel_sha3_fbcheck(req) ?: crypto_ahash_update(subreq);
++}
++
++static int safexcel_sha3_final(struct ahash_request *req)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct ahash_request *subreq = ahash_request_ctx(req);
++
++      ctx->do_fallback = true;
++      return safexcel_sha3_fbcheck(req) ?: crypto_ahash_final(subreq);
++}
++
++static int safexcel_sha3_finup(struct ahash_request *req)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct ahash_request *subreq = ahash_request_ctx(req);
++
++      ctx->do_fallback |= !req->nbytes;
++      if (ctx->do_fallback)
++              /* Update or ex/import happened or len 0, cannot use the HW */
++              return safexcel_sha3_fbcheck(req) ?:
++                     crypto_ahash_finup(subreq);
++      else
++              return safexcel_ahash_finup(req);
++}
++
++static int safexcel_sha3_digest_fallback(struct ahash_request *req)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct ahash_request *subreq = ahash_request_ctx(req);
++
++      ctx->do_fallback = true;
++      ctx->fb_init_done = false;
++      return safexcel_sha3_fbcheck(req) ?: crypto_ahash_finup(subreq);
++}
++
++static int safexcel_sha3_224_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_sha3_224_init(req) ?: safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length hash, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_sha3_export(struct ahash_request *req, void *out)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct ahash_request *subreq = ahash_request_ctx(req);
++
++      ctx->do_fallback = true;
++      return safexcel_sha3_fbcheck(req) ?: crypto_ahash_export(subreq, out);
++}
++
++static int safexcel_sha3_import(struct ahash_request *req, const void *in)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct ahash_request *subreq = ahash_request_ctx(req);
++
++      ctx->do_fallback = true;
++      return safexcel_sha3_fbcheck(req) ?: crypto_ahash_import(subreq, in);
++      // return safexcel_ahash_import(req, in);
++}
++
++static int safexcel_sha3_cra_init(struct crypto_tfm *tfm)
++{
++      struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      safexcel_ahash_cra_init(tfm);
++
++      /* Allocate fallback implementation */
++      ctx->fback = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
++                                      CRYPTO_ALG_ASYNC |
++                                      CRYPTO_ALG_NEED_FALLBACK);
++      if (IS_ERR(ctx->fback))
++              return PTR_ERR(ctx->fback);
++
++      /* Update statesize from fallback algorithm! */
++      crypto_hash_alg_common(ahash)->statesize =
++              crypto_ahash_statesize(ctx->fback);
++      crypto_ahash_set_reqsize(ahash, max(sizeof(struct safexcel_ahash_req),
++                                          sizeof(struct ahash_request) +
++                                          crypto_ahash_reqsize(ctx->fback)));
++      return 0;
++}
++
++static void safexcel_sha3_cra_exit(struct crypto_tfm *tfm)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      crypto_free_ahash(ctx->fback);
++      safexcel_ahash_cra_exit(tfm);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_224 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_sha3_224_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_sha3_224_digest,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_224_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "sha3-224",
++                              .cra_driver_name = "safexcel-sha3-224",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_224_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_sha3_cra_init,
++                              .cra_exit = safexcel_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_sha3_256_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_256;
++      req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++      req->state_sz = SHA3_256_DIGEST_SIZE;
++      req->digest_sz = SHA3_256_DIGEST_SIZE;
++      req->block_sz = SHA3_256_BLOCK_SIZE;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_sha3_256_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_sha3_256_init(req) ?: safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length hash, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_256 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_sha3_256_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_sha3_256_digest,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_256_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "sha3-256",
++                              .cra_driver_name = "safexcel-sha3-256",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_256_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_sha3_cra_init,
++                              .cra_exit = safexcel_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_sha3_384_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_384;
++      req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++      req->state_sz = SHA3_384_DIGEST_SIZE;
++      req->digest_sz = SHA3_384_DIGEST_SIZE;
++      req->block_sz = SHA3_384_BLOCK_SIZE;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_sha3_384_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_sha3_384_init(req) ?: safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length hash, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_384 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_sha3_384_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_sha3_384_digest,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_384_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "sha3-384",
++                              .cra_driver_name = "safexcel-sha3-384",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_384_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_sha3_cra_init,
++                              .cra_exit = safexcel_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_sha3_512_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_512;
++      req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++      req->state_sz = SHA3_512_DIGEST_SIZE;
++      req->digest_sz = SHA3_512_DIGEST_SIZE;
++      req->block_sz = SHA3_512_BLOCK_SIZE;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_sha3_512_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_sha3_512_init(req) ?: safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length hash, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_512 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_sha3_512_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_sha3_512_digest,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_512_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "sha3-512",
++                              .cra_driver_name = "safexcel-sha3-512",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_512_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_sha3_cra_init,
++                              .cra_exit = safexcel_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_hmac_sha3_cra_init(struct crypto_tfm *tfm, const char *alg)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++      int ret;
++
++      ret = safexcel_sha3_cra_init(tfm);
++      if (ret)
++              return ret;
++
++      /* Allocate precalc basic digest implementation */
++      ctx->shpre = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
++      if (IS_ERR(ctx->shpre))
++              return PTR_ERR(ctx->shpre);
++
++      ctx->shdesc = kmalloc(sizeof(*ctx->shdesc) +
++                            crypto_shash_descsize(ctx->shpre), GFP_KERNEL);
++      if (!ctx->shdesc) {
++              crypto_free_shash(ctx->shpre);
++              return -ENOMEM;
++      }
++      ctx->shdesc->tfm = ctx->shpre;
++      return 0;
++}
++
++static void safexcel_hmac_sha3_cra_exit(struct crypto_tfm *tfm)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++      crypto_free_ahash(ctx->fback);
++      crypto_free_shash(ctx->shpre);
++      kfree(ctx->shdesc);
++      safexcel_ahash_cra_exit(tfm);
++}
++
++static int safexcel_hmac_sha3_setkey(struct crypto_ahash *tfm, const u8 *key,
++                                   unsigned int keylen)
++{
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      int ret = 0;
++
++      if (keylen > crypto_ahash_blocksize(tfm)) {
++              /*
++               * If the key is larger than the blocksize, then hash it
++               * first using our fallback cipher
++               */
++              ret = crypto_shash_digest(ctx->shdesc, key, keylen,
++                                        (u8 *)ctx->ipad);
++              keylen = crypto_shash_digestsize(ctx->shpre);
++
++              /*
++               * If the digest is larger than half the blocksize, we need to
++               * move the rest to opad due to the way our HMAC infra works.
++               */
++              if (keylen > crypto_ahash_blocksize(tfm) / 2)
++                      /* Buffers overlap, need to use memmove iso memcpy! */
++                      memmove(ctx->opad,
++                              (u8 *)ctx->ipad +
++                                      crypto_ahash_blocksize(tfm) / 2,
++                              keylen - crypto_ahash_blocksize(tfm) / 2);
++      } else {
++              /*
++               * Copy the key to our ipad & opad buffers
++               * Note that ipad and opad each contain one half of the key,
++               * to match the existing HMAC driver infrastructure.
++               */
++              if (keylen <= crypto_ahash_blocksize(tfm) / 2) {
++                      memcpy(ctx->ipad, key, keylen);
++              } else {
++                      memcpy(ctx->ipad, key,
++                             crypto_ahash_blocksize(tfm) / 2);
++                      memcpy(ctx->opad,
++                             key + crypto_ahash_blocksize(tfm) / 2,
++                             keylen - crypto_ahash_blocksize(tfm) / 2);
++              }
++      }
++
++      /* Pad key with zeroes */
++      if (keylen <= crypto_ahash_blocksize(tfm) / 2) {
++              memset((u8 *)ctx->ipad + keylen, 0,
++                     crypto_ahash_blocksize(tfm) / 2 - keylen);
++              memset(ctx->opad, 0, crypto_ahash_blocksize(tfm) / 2);
++      } else {
++              memset((u8 *)ctx->opad + keylen -
++                     crypto_ahash_blocksize(tfm) / 2, 0,
++                     crypto_ahash_blocksize(tfm) - keylen);
++      }
++
++      /* If doing fallback, still need to set the new key! */
++      ctx->fb_do_setkey = true;
++      return ret;
++}
++
++static int safexcel_hmac_sha3_224_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      /* Copy (half of) the key */
++      memcpy(req->state, ctx->ipad, SHA3_224_BLOCK_SIZE / 2);
++      /* Start of HMAC should have len == processed == blocksize */
++      req->len        = SHA3_224_BLOCK_SIZE;
++      req->processed  = SHA3_224_BLOCK_SIZE;
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_224;
++      req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++      req->state_sz = SHA3_224_BLOCK_SIZE / 2;
++      req->digest_sz = SHA3_224_DIGEST_SIZE;
++      req->block_sz = SHA3_224_BLOCK_SIZE;
++      req->hmac = true;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_hmac_sha3_224_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_hmac_sha3_224_init(req) ?:
++                     safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length HMAC, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_224_cra_init(struct crypto_tfm *tfm)
++{
++      return safexcel_hmac_sha3_cra_init(tfm, "sha3-224");
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sha3_224 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_hmac_sha3_224_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_hmac_sha3_224_digest,
++              .setkey = safexcel_hmac_sha3_setkey,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_224_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "hmac(sha3-224)",
++                              .cra_driver_name = "safexcel-hmac-sha3-224",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_224_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_hmac_sha3_224_cra_init,
++                              .cra_exit = safexcel_hmac_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_hmac_sha3_256_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      /* Copy (half of) the key */
++      memcpy(req->state, ctx->ipad, SHA3_256_BLOCK_SIZE / 2);
++      /* Start of HMAC should have len == processed == blocksize */
++      req->len        = SHA3_256_BLOCK_SIZE;
++      req->processed  = SHA3_256_BLOCK_SIZE;
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_256;
++      req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++      req->state_sz = SHA3_256_BLOCK_SIZE / 2;
++      req->digest_sz = SHA3_256_DIGEST_SIZE;
++      req->block_sz = SHA3_256_BLOCK_SIZE;
++      req->hmac = true;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_hmac_sha3_256_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_hmac_sha3_256_init(req) ?:
++                     safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length HMAC, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_256_cra_init(struct crypto_tfm *tfm)
++{
++      return safexcel_hmac_sha3_cra_init(tfm, "sha3-256");
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sha3_256 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_hmac_sha3_256_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_hmac_sha3_256_digest,
++              .setkey = safexcel_hmac_sha3_setkey,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_256_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "hmac(sha3-256)",
++                              .cra_driver_name = "safexcel-hmac-sha3-256",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_256_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_hmac_sha3_256_cra_init,
++                              .cra_exit = safexcel_hmac_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_hmac_sha3_384_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      /* Copy (half of) the key */
++      memcpy(req->state, ctx->ipad, SHA3_384_BLOCK_SIZE / 2);
++      /* Start of HMAC should have len == processed == blocksize */
++      req->len        = SHA3_384_BLOCK_SIZE;
++      req->processed  = SHA3_384_BLOCK_SIZE;
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_384;
++      req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++      req->state_sz = SHA3_384_BLOCK_SIZE / 2;
++      req->digest_sz = SHA3_384_DIGEST_SIZE;
++      req->block_sz = SHA3_384_BLOCK_SIZE;
++      req->hmac = true;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_hmac_sha3_384_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_hmac_sha3_384_init(req) ?:
++                     safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length HMAC, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_384_cra_init(struct crypto_tfm *tfm)
++{
++      return safexcel_hmac_sha3_cra_init(tfm, "sha3-384");
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sha3_384 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_hmac_sha3_384_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_hmac_sha3_384_digest,
++              .setkey = safexcel_hmac_sha3_setkey,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_384_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "hmac(sha3-384)",
++                              .cra_driver_name = "safexcel-hmac-sha3-384",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_384_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_hmac_sha3_384_cra_init,
++                              .cra_exit = safexcel_hmac_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
++      },
++};
++
++static int safexcel_hmac_sha3_512_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++      memset(req, 0, sizeof(*req));
++
++      /* Copy (half of) the key */
++      memcpy(req->state, ctx->ipad, SHA3_512_BLOCK_SIZE / 2);
++      /* Start of HMAC should have len == processed == blocksize */
++      req->len        = SHA3_512_BLOCK_SIZE;
++      req->processed  = SHA3_512_BLOCK_SIZE;
++      ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_512;
++      req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++      req->state_sz = SHA3_512_BLOCK_SIZE / 2;
++      req->digest_sz = SHA3_512_DIGEST_SIZE;
++      req->block_sz = SHA3_512_BLOCK_SIZE;
++      req->hmac = true;
++      ctx->do_fallback = false;
++      ctx->fb_init_done = false;
++      return 0;
++}
++
++static int safexcel_hmac_sha3_512_digest(struct ahash_request *req)
++{
++      if (req->nbytes)
++              return safexcel_hmac_sha3_512_init(req) ?:
++                     safexcel_ahash_finup(req);
++
++      /* HW cannot do zero length HMAC, use fallback instead */
++      return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_512_cra_init(struct crypto_tfm *tfm)
++{
++      return safexcel_hmac_sha3_cra_init(tfm, "sha3-512");
++}
++struct safexcel_alg_template safexcel_alg_hmac_sha3_512 = {
++      .type = SAFEXCEL_ALG_TYPE_AHASH,
++      .algo_mask = SAFEXCEL_ALG_SHA3,
++      .alg.ahash = {
++              .init = safexcel_hmac_sha3_512_init,
++              .update = safexcel_sha3_update,
++              .final = safexcel_sha3_final,
++              .finup = safexcel_sha3_finup,
++              .digest = safexcel_hmac_sha3_512_digest,
++              .setkey = safexcel_hmac_sha3_setkey,
++              .export = safexcel_sha3_export,
++              .import = safexcel_sha3_import,
++              .halg = {
++                      .digestsize = SHA3_512_DIGEST_SIZE,
++                      .statesize = sizeof(struct safexcel_ahash_export_state),
++                      .base = {
++                              .cra_name = "hmac(sha3-512)",
++                              .cra_driver_name = "safexcel-hmac-sha3-512",
++                              .cra_priority = SAFEXCEL_CRA_PRIORITY,
++                              .cra_flags = CRYPTO_ALG_ASYNC |
++                                           CRYPTO_ALG_KERN_DRIVER_ONLY |
++                                           CRYPTO_ALG_NEED_FALLBACK,
++                              .cra_blocksize = SHA3_512_BLOCK_SIZE,
++                              .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++                              .cra_init = safexcel_hmac_sha3_512_cra_init,
++                              .cra_exit = safexcel_hmac_sha3_cra_exit,
++                              .cra_module = THIS_MODULE,
++                      },
++              },
+       },
+ };
+--- a/drivers/crypto/inside-secure/safexcel_ring.c
++++ b/drivers/crypto/inside-secure/safexcel_ring.c
+@@ -14,7 +14,12 @@
+                                  struct safexcel_desc_ring *cdr,
+                                  struct safexcel_desc_ring *rdr)
+ {
+-      cdr->offset = sizeof(u32) * priv->config.cd_offset;
++      int i;
++      struct safexcel_command_desc *cdesc;
++      dma_addr_t atok;
++
++      /* Actual command descriptor ring */
++      cdr->offset = priv->config.cd_offset;
+       cdr->base = dmam_alloc_coherent(priv->dev,
+                                       cdr->offset * EIP197_DEFAULT_RING_SIZE,
+                                       &cdr->base_dma, GFP_KERNEL);
+@@ -24,7 +29,34 @@
+       cdr->base_end = cdr->base + cdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);
+       cdr->read = cdr->base;
+-      rdr->offset = sizeof(u32) * priv->config.rd_offset;
++      /* Command descriptor shadow ring for storing additional token data */
++      cdr->shoffset = priv->config.cdsh_offset;
++      cdr->shbase = dmam_alloc_coherent(priv->dev,
++                                        cdr->shoffset *
++                                        EIP197_DEFAULT_RING_SIZE,
++                                        &cdr->shbase_dma, GFP_KERNEL);
++      if (!cdr->shbase)
++              return -ENOMEM;
++      cdr->shwrite = cdr->shbase;
++      cdr->shbase_end = cdr->shbase + cdr->shoffset *
++                                      (EIP197_DEFAULT_RING_SIZE - 1);
++
++      /*
++       * Populate command descriptors with physical pointers to shadow descs.
++       * Note that we only need to do this once if we don't overwrite them.
++       */
++      cdesc = cdr->base;
++      atok = cdr->shbase_dma;
++      for (i = 0; i < EIP197_DEFAULT_RING_SIZE; i++) {
++              cdesc->atok_lo = lower_32_bits(atok);
++              cdesc->atok_hi = upper_32_bits(atok);
++              cdesc = (void *)cdesc + cdr->offset;
++              atok += cdr->shoffset;
++      }
++
++      rdr->offset = priv->config.rd_offset;
++      /* Use shoffset for result token offset here */
++      rdr->shoffset = priv->config.res_offset;
+       rdr->base = dmam_alloc_coherent(priv->dev,
+                                       rdr->offset * EIP197_DEFAULT_RING_SIZE,
+                                       &rdr->base_dma, GFP_KERNEL);
+@@ -42,11 +74,40 @@
+       return (atomic_inc_return(&priv->ring_used) % priv->config.rings);
+ }
+-static void *safexcel_ring_next_wptr(struct safexcel_crypto_priv *priv,
+-                                   struct safexcel_desc_ring *ring)
++static void *safexcel_ring_next_cwptr(struct safexcel_crypto_priv *priv,
++                                   struct safexcel_desc_ring *ring,
++                                   bool first,
++                                   struct safexcel_token **atoken)
+ {
+       void *ptr = ring->write;
++      if (first)
++              *atoken = ring->shwrite;
++
++      if ((ring->write == ring->read - ring->offset) ||
++          (ring->read == ring->base && ring->write == ring->base_end))
++              return ERR_PTR(-ENOMEM);
++
++      if (ring->write == ring->base_end) {
++              ring->write = ring->base;
++              ring->shwrite = ring->shbase;
++      } else {
++              ring->write += ring->offset;
++              ring->shwrite += ring->shoffset;
++      }
++
++      return ptr;
++}
++
++static void *safexcel_ring_next_rwptr(struct safexcel_crypto_priv *priv,
++                                   struct safexcel_desc_ring *ring,
++                                   struct result_data_desc **rtoken)
++{
++      void *ptr = ring->write;
++
++      /* Result token at relative offset shoffset */
++      *rtoken = ring->write + ring->shoffset;
++
+       if ((ring->write == ring->read - ring->offset) ||
+           (ring->read == ring->base && ring->write == ring->base_end))
+               return ERR_PTR(-ENOMEM);
+@@ -106,10 +167,13 @@
+       if (ring->write == ring->read)
+               return;
+-      if (ring->write == ring->base)
++      if (ring->write == ring->base) {
+               ring->write = ring->base_end;
+-      else
++              ring->shwrite = ring->shbase_end;
++      } else {
+               ring->write -= ring->offset;
++              ring->shwrite -= ring->shoffset;
++      }
+ }
+ struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *priv,
+@@ -117,26 +181,26 @@
+                                                bool first, bool last,
+                                                dma_addr_t data, u32 data_len,
+                                                u32 full_data_len,
+-                                               dma_addr_t context) {
++                                               dma_addr_t context,
++                                               struct safexcel_token **atoken)
++{
+       struct safexcel_command_desc *cdesc;
+-      int i;
+-      cdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].cdr);
++      cdesc = safexcel_ring_next_cwptr(priv, &priv->ring[ring_id].cdr,
++                                       first, atoken);
+       if (IS_ERR(cdesc))
+               return cdesc;
+-      memset(cdesc, 0, sizeof(struct safexcel_command_desc));
+-
+-      cdesc->first_seg = first;
+-      cdesc->last_seg = last;
+       cdesc->particle_size = data_len;
++      cdesc->rsvd0 = 0;
++      cdesc->last_seg = last;
++      cdesc->first_seg = first;
++      cdesc->additional_cdata_size = 0;
++      cdesc->rsvd1 = 0;
+       cdesc->data_lo = lower_32_bits(data);
+       cdesc->data_hi = upper_32_bits(data);
+-      if (first && context) {
+-              struct safexcel_token *token =
+-                      (struct safexcel_token *)cdesc->control_data.token;
+-
++      if (first) {
+               /*
+                * Note that the length here MUST be >0 or else the EIP(1)97
+                * may hang. Newer EIP197 firmware actually incorporates this
+@@ -146,20 +210,12 @@
+               cdesc->control_data.packet_length = full_data_len ?: 1;
+               cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE |
+                                             EIP197_OPTION_64BIT_CTX |
+-                                            EIP197_OPTION_CTX_CTRL_IN_CMD;
+-              cdesc->control_data.context_lo =
+-                      (lower_32_bits(context) & GENMASK(31, 2)) >> 2;
++                                            EIP197_OPTION_CTX_CTRL_IN_CMD |
++                                            EIP197_OPTION_RC_AUTO;
++              cdesc->control_data.type = EIP197_TYPE_BCLA;
++              cdesc->control_data.context_lo = lower_32_bits(context) |
++                                               EIP197_CONTEXT_SMALL;
+               cdesc->control_data.context_hi = upper_32_bits(context);
+-
+-              if (priv->version == EIP197B_MRVL ||
+-                  priv->version == EIP197D_MRVL)
+-                      cdesc->control_data.options |= EIP197_OPTION_RC_AUTO;
+-
+-              /* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */
+-              cdesc->control_data.refresh = 2;
+-
+-              for (i = 0; i < EIP197_MAX_TOKENS; i++)
+-                      eip197_noop_token(&token[i]);
+       }
+       return cdesc;
+@@ -171,18 +227,27 @@
+                                               dma_addr_t data, u32 len)
+ {
+       struct safexcel_result_desc *rdesc;
++      struct result_data_desc *rtoken;
+-      rdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].rdr);
++      rdesc = safexcel_ring_next_rwptr(priv, &priv->ring[ring_id].rdr,
++                                       &rtoken);
+       if (IS_ERR(rdesc))
+               return rdesc;
+-      memset(rdesc, 0, sizeof(struct safexcel_result_desc));
+-
+-      rdesc->first_seg = first;
+-      rdesc->last_seg = last;
+       rdesc->particle_size = len;
++      rdesc->rsvd0 = 0;
++      rdesc->descriptor_overflow = 0;
++      rdesc->buffer_overflow = 0;
++      rdesc->last_seg = last;
++      rdesc->first_seg = first;
++      rdesc->result_size = EIP197_RD64_RESULT_SIZE;
++      rdesc->rsvd1 = 0;
+       rdesc->data_lo = lower_32_bits(data);
+       rdesc->data_hi = upper_32_bits(data);
++      /* Clear length & error code in result token */
++      rtoken->packet_length = 0;
++      rtoken->error_code = 0;
++
+       return rdesc;
+ }
diff --git a/target/linux/mediatek/patches-5.4/0501-crypto-add-eip97-inside-secure-support.patch b/target/linux/mediatek/patches-5.4/0501-crypto-add-eip97-inside-secure-support.patch
new file mode 100644 (file)
index 0000000..197cbf4
--- /dev/null
@@ -0,0 +1,27 @@
+--- a/drivers/crypto/inside-secure/safexcel.c
++++ b/drivers/crypto/inside-secure/safexcel.c
+@@ -595,6 +595,14 @@
+               val |= EIP197_MST_CTRL_TX_MAX_CMD(5);
+               writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
+       }
++      /*
++       * Set maximum number of TX commands to 2^5 = 32 for EIP97 HW2.1
++       */
++      else {
++              val = 0;
++              val |= EIP97_MST_CTRL_TX_MAX_CMD(5);
++              writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
++      }
+       /* Configure wr/rd cache values */
+       writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) |
+--- a/drivers/crypto/inside-secure/safexcel.h
++++ b/drivers/crypto/inside-secure/safexcel.h
+@@ -306,6 +306,7 @@
+ #define EIP197_MST_CTRL_RD_CACHE(n)           (((n) & 0xf) << 0)
+ #define EIP197_MST_CTRL_WD_CACHE(n)           (((n) & 0xf) << 4)
+ #define EIP197_MST_CTRL_TX_MAX_CMD(n)         (((n) & 0xf) << 20)
++#define EIP97_MST_CTRL_TX_MAX_CMD(n)          (((n) & 0xf) << 4)
+ #define EIP197_MST_CTRL_BYTE_SWAP             BIT(24)
+ #define EIP197_MST_CTRL_NO_BYTE_SWAP          BIT(25)
+ #define EIP197_MST_CTRL_BYTE_SWAP_BITS          GENMASK(25, 24)
diff --git a/target/linux/mediatek/patches-5.4/0502-dts-mt7623-eip97-inside-secure-support.patch b/target/linux/mediatek/patches-5.4/0502-dts-mt7623-eip97-inside-secure-support.patch
new file mode 100644 (file)
index 0000000..06077fb
--- /dev/null
@@ -0,0 +1,23 @@
+--- a/arch/arm/boot/dts/mt7623.dtsi
++++ b/arch/arm/boot/dts/mt7623.dtsi
+@@ -1047,17 +1047,14 @@
+       };
+       crypto: crypto@1b240000 {
+-              compatible = "mediatek,eip97-crypto";
++              compatible = "inside-secure,safexcel-eip97";
+               reg = <0 0x1b240000 0 0x20000>;
+               interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>,
+-                           <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>,
+-                           <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
++                           <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
++              interrupt-names = "ring0", "ring1", "ring2", "ring3";
+               clocks = <&ethsys CLK_ETHSYS_CRYPTO>;
+-              clock-names = "cryp";
+-              power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+-              status = "disabled";
+       };
+       bdpsys: syscon@1c000000 {