// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
#include <crypto/akcipher.h>
#include <crypto/dh.h>
#include <crypto/internal/akcipher.h>
#include <crypto/internal/kpp.h>
#include <crypto/internal/rsa.h>
#include <crypto/kpp.h>
#include <crypto/scatterwalk.h>
#include <linux/dma-mapping.h>
#include <linux/fips.h>
#include <linux/module.h>
#include <linux/time.h>
#include "hpre.h"
struct hpre_ctx;
#define HPRE_CRYPTO_ALG_PRI 1000
#define HPRE_ALIGN_SZ 64
#define HPRE_BITS_2_BYTES_SHIFT 3
#define HPRE_RSA_512BITS_KSZ 64
#define HPRE_RSA_1536BITS_KSZ 192
#define HPRE_CRT_PRMS 5
#define HPRE_CRT_Q 2
#define HPRE_CRT_P 3
#define HPRE_CRT_INV 4
#define HPRE_DH_G_FLAG 0x02
#define HPRE_TRY_SEND_TIMES 100
#define HPRE_INVLD_REQ_ID (-1)
#define HPRE_DEV(ctx) (&((ctx)->qp->qm->pdev->dev))
#define HPRE_SQE_ALG_BITS 5
#define HPRE_SQE_DONE_SHIFT 30
#define HPRE_DH_MAX_P_SZ 512
#define HPRE_DFX_SEC_TO_US 1000000
#define HPRE_DFX_US_TO_NS 1000
typedef void (*hpre_cb)(struct hpre_ctx *ctx, void *sqe);
struct hpre_rsa_ctx {
/* low address: e--->n */
char *pubkey;
dma_addr_t dma_pubkey;
/* low address: d--->n */
char *prikey;
dma_addr_t dma_prikey;
/* low address: dq->dp->q->p->qinv */
char *crt_prikey;
dma_addr_t dma_crt_prikey;
struct crypto_akcipher *soft_tfm;
};
struct hpre_dh_ctx {
/*
* If base is g we compute the public key
* ya = g^xa mod p; [RFC2631 sec 2.1.1]
* else if base if the counterpart public key we
* compute the shared secret
* ZZ = yb^xa mod p; [RFC2631 sec 2.1.1]
*/
char *xa_p; /* low address: d--->n, please refer to Hisilicon HPRE UM */
dma_addr_t dma_xa_p;
char *g; /* m */
dma_addr_t dma_g;
};
struct hpre_ctx {
struct hisi_qp *qp;
struct hpre_asym_request **req_list;
struct hpre *hpre;
spinlock_t req_lock;
unsigned int key_sz;
bool crt_g2_mode;
struct idr req_idr;
union {
struct hpre_rsa_ctx rsa;
struct hpre_dh_ctx dh;
};
};
struct hpre_asym_request {
char *src;
char *dst;
struct hpre_sqe req;
struct hpre_ctx *ctx;
union {
struct akcipher_request *rsa;
struct kpp_request *dh;
} areq;
int err;
int req_id;
hpre_cb cb;
struct timespec64 req_time;
};
static DEFINE_MUTEX(hpre_alg_lock);
static unsigned int hpre_active_devs;
static int hpre_alloc_req_id(struct hpre_ctx *ctx)
{
unsigned long flags;
int id;
spin_lock_irqsave(&ctx->req_lock, flags);
id = idr_alloc(&ctx->req_idr, NULL, 0, QM_Q_DEPTH, GFP_ATOMIC);
spin_unlock_irqrestore(&ctx->req_lock, flags);
return id;
}
static void hpre_free_req_id(struct hpre_ctx *ctx, int req_id)
{
unsigned long flags;
spin_lock_irqsave(&ctx->req_lock, flags);
idr_remove(&ctx->req_idr, req_id);
spin_unlock_irqrestore(&ctx->req_lock, flags);
}
static int hpre_add_req_to_ctx(struct hpre_asym_request *hpre_req)
{
struct hpre_ctx *ctx;
struct hpre_dfx *dfx;
int id;
ctx = hpre_req->ctx;
id = hpre_alloc_req_id(