// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2016-2017 HiSilicon Limited. */
#include <linux/crypto.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/internal/des.h>
#include <crypto/skcipher.h>
#include <crypto/xts.h>
#include <crypto/internal/skcipher.h>
#include "sec_drv.h"
#define SEC_MAX_CIPHER_KEY 64
#define SEC_REQ_LIMIT SZ_32M
struct sec_c_alg_cfg {
unsigned c_alg : 3;
unsigned c_mode : 3;
unsigned key_len : 2;
unsigned c_width : 2;
};
static const struct sec_c_alg_cfg sec_c_alg_cfgs[] = {
[SEC_C_DES_ECB_64] = {
.c_alg = SEC_C_ALG_DES,
.c_mode = SEC_C_MODE_ECB,
.key_len = SEC_KEY_LEN_DES,
},
[SEC_C_DES_CBC_64] = {
.c_alg = SEC_C_ALG_DES,
.c_mode = SEC_C_MODE_CBC,
.key_len = SEC_KEY_LEN_DES,
},
[SEC_C_3DES_ECB_192_3KEY] = {
.c_alg = SEC_C_ALG_3DES,
.c_mode = SEC_C_MODE_ECB,
.key_len = SEC_KEY_LEN_3DES_3_KEY,
},
[SEC_C_3DES_ECB_192_2KEY] = {
.c_alg = SEC_C_ALG_3DES,
.c_mode = SEC_C_MODE_ECB,
.key_len = SEC_KEY_LEN_3DES_2_KEY,
},
[SEC_C_3DES_CBC_192_3KEY] = {
.c_alg = SEC_C_ALG_3DES,
.c_mode = SEC_C_MODE_CBC,
.key_len = SEC_KEY_LEN_3DES_3_KEY,
},
[SEC_C_3DES_CBC_192_2KEY] = {
.c_alg = SEC_C_ALG_3DES,
.c_mode = SEC_C_MODE_CBC,
.key_len = SEC_KEY_LEN_3DES_2_KEY,
},
[SEC_C_AES_ECB_128] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_ECB,
.key_len = SEC_KEY_LEN_AES_128,
},
[SEC_C_AES_ECB_192] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_ECB,
.key_len = SEC_KEY_LEN_AES_192,
},
[SEC_C_AES_ECB_256] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_ECB,
.key_len = SEC_KEY_LEN_AES_256,
},
[SEC_C_AES_CBC_128] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_CBC,
.key_len = SEC_KEY_LEN_AES_128,
},
[SEC_C_AES_CBC_192] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_CBC,
.key_len = SEC_KEY_LEN_AES_192,
},
[SEC_C_AES_CBC_256] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_CBC,
.key_len = SEC_KEY_LEN_AES_256,
},
[SEC_C_AES_CTR_128] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_CTR,
.key_len = SEC_KEY_LEN_AES_128,
},
[SEC_C_AES_CTR_192] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_CTR,
.key_len = SEC_KEY_LEN_AES_192,
},
[SEC_C_AES_CTR_256] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_CTR,
.key_len = SEC_KEY_LEN_AES_256,
},
[SEC_C_AES_XTS_128] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_XTS,
.key_len = SEC_KEY_LEN_AES_128,
},
[SEC_C_AES_XTS_256] = {
.c_alg = SEC_C_ALG_AES,
.c_mode = SEC_C_MODE_XTS,
.key_len = SEC_KEY_LEN_AES_256,
},
[SEC_C_NULL] = {
},
};
/*
* Mutex used to ensure safe operation of reference count of
* alg providers
*/
static DEFINE_MUTEX(algs_lock);
static unsigned int active_devs;
static void sec_alg_skcipher_init_template(struct sec_alg_tfm_ctx *ctx,
struct sec_bd_info *req,
enum sec_cipher_alg alg)
{
const struct sec_c_alg_cfg *cfg = &sec_c_alg_cfgs[alg];
memset(req, 0, sizeof(*req));
req->w0 |= cfg->c_mode << SEC_BD_W0_C_MODE_S;
req->w1 |= cfg->c_alg << SEC_BD_W1_C_ALG_S;
req->w3 |= cfg->key_len << SEC_BD_W3_C_KEY_LEN_S;
req->w0 |= cfg->c_width << SEC_BD_W0_C_WIDTH_S;
req->cipher_key_addr_lo = lower_32_bits(ctx->pkey);
req->cipher_key_addr_hi = upper_32_bits(ctx->pkey);
}
static void sec_alg_skcipher_init_context(struct crypto_skcipher *atfm,
const u8 *key,
unsigned int keylen,
enum sec_cipher_alg alg)
{
struct crypto_tfm *tfm = crypto_skcipher_tfm(atfm);
struct sec_alg_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
ctx->cipher_alg = alg;
memcpy(ctx->key, key, <