root/drivers/crypto/caam/caamhash_desc.c
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
 * Shared descriptors for ahash algorithms
 *
 * Copyright 2017-2019 NXP
 */

#include "compat.h"
#include "desc_constr.h"
#include "caamhash_desc.h"

/**
 * cnstr_shdsc_ahash - ahash shared descriptor
 * @desc: pointer to buffer used for descriptor construction
 * @adata: pointer to authentication transform definitions.
 *         A split key is required for SEC Era < 6; the size of the split key
 *         is specified in this case.
 *         Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, SHA224,
 *         SHA256, SHA384, SHA512}.
 * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE}
 * @digestsize: algorithm's digest size
 * @ctx_len: size of Context Register
 * @import_ctx: true if previous Context Register needs to be restored
 *              must be true for ahash update and final
 *              must be false for ahash first and digest
 * @era: SEC Era
 */
void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
                       int digestsize, int ctx_len, bool import_ctx, int era)
{
        u32 op = adata->algtype;

        init_sh_desc(desc, HDR_SHARE_SERIAL);

        /* Append key if it has been set; ahash update excluded */
        if (state != OP_ALG_AS_UPDATE && adata->keylen) {
                u32 *skip_key_load;

                /* Skip key loading if already shared */
                skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
                                            JUMP_COND_SHRD);

                if (era < 6)
                        append_key_as_imm(desc, adata->key_virt,
                                          adata->keylen_pad,
                                          adata->keylen, CLASS_2 |
                                          KEY_DEST_MDHA_SPLIT | KEY_ENC);
                else
                        append_proto_dkp(desc, adata);

                set_jump_tgt_here(desc, skip_key_load);

                op |= OP_ALG_AAI_HMAC_PRECOMP;
        }

        /* If needed, import context from software */
        if (import_ctx)
                append_seq_load(desc, ctx_len, LDST_CLASS_2_CCB |
                                LDST_SRCDST_BYTE_CONTEXT);

        /* Class 2 operation */
        append_operation(desc, op | state | OP_ALG_ENCRYPT);

        /*
         * Load from buf and/or src and write to req->result or state->context
         * Calculate remaining bytes to read
         */
        append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
        /* Read remaining bytes */
        append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 |
                             FIFOLD_TYPE_MSG | KEY_VLF);
        /* Store class2 context bytes */
        append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
                         LDST_SRCDST_BYTE_CONTEXT);
}
EXPORT_SYMBOL(cnstr_shdsc_ahash);

/**
 * cnstr_shdsc_sk_hash - shared descriptor for symmetric key cipher-based
 *                       hash algorithms
 * @desc: pointer to buffer used for descriptor construction
 * @adata: pointer to authentication transform definitions.
 * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE}
 * @digestsize: algorithm's digest size
 * @ctx_len: size of Context Register
 */
void cnstr_shdsc_sk_hash(u32 * const desc, struct alginfo *adata, u32 state,
                         int digestsize, int ctx_len)
{
        u32 *skip_key_load;

        init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX);

        /* Skip loading of key, context if already shared */
        skip_key_load = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD);

        if (state == OP_ALG_AS_INIT || state == OP_ALG_AS_INITFINAL) {
                append_key_as_imm(desc, adata->key_virt, adata->keylen,
                                  adata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
        } else { /* UPDATE, FINALIZE */
                if (is_xcbc_aes(adata->algtype))
                        /* Load K1 */
                        append_key(desc, adata->key_dma, adata->keylen,
                                   CLASS_1 | KEY_DEST_CLASS_REG | KEY_ENC);
                else /* CMAC */
                        append_key_as_imm(desc, adata->key_virt, adata->keylen,
                                          adata->keylen, CLASS_1 |
                                          KEY_DEST_CLASS_REG);
                /* Restore context */
                append_seq_load(desc, ctx_len, LDST_CLASS_1_CCB |
                                LDST_SRCDST_BYTE_CONTEXT);
        }

        set_jump_tgt_here(desc, skip_key_load);

        /* Class 1 operation */
        append_operation(desc, adata->algtype | state | OP_ALG_ENCRYPT);

        /*
         * Load from buf and/or src and write to req->result or state->context
         * Calculate remaining bytes to read
         */
        append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);

        /* Read remaining bytes */
        append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 |
                             FIFOLD_TYPE_MSG | FIFOLDST_VLF);

        /*
         * Save context:
         * - xcbc: partial hash, keys K2 and K3
         * - cmac: partial hash, constant L = E(K,0)
         */
        append_seq_store(desc, digestsize, LDST_CLASS_1_CCB |
                         LDST_SRCDST_BYTE_CONTEXT);
        if (is_xcbc_aes(adata->algtype) && state == OP_ALG_AS_INIT)
                /* Save K1 */
                append_fifo_store(desc, adata->key_dma, adata->keylen,
                                  LDST_CLASS_1_CCB | FIFOST_TYPE_KEY_KEK);
}
EXPORT_SYMBOL(cnstr_shdsc_sk_hash);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("FSL CAAM ahash descriptors support");
MODULE_AUTHOR("NXP Semiconductors");