driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBATCK CVE: NA
----------------------------------------------------------------------
When trng device is busy and fails to apply for tfm, the driver applies for software computed tfm to prevent task failures.
Signed-off-by: Weili Qian qianweili@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- drivers/crypto/hisilicon/Kconfig | 1 + drivers/crypto/hisilicon/trng/trng.c | 52 +++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig index 4137a8bf131f..257c64809b48 100644 --- a/drivers/crypto/hisilicon/Kconfig +++ b/drivers/crypto/hisilicon/Kconfig @@ -80,5 +80,6 @@ config CRYPTO_DEV_HISI_TRNG depends on ARM64 && ACPI select HW_RANDOM select CRYPTO_RNG + select CRYPTO_DRBG_CTR help Support for HiSilicon TRNG Driver. diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c index a1eaac5f3311..8f1743a053df 100644 --- a/drivers/crypto/hisilicon/trng/trng.c +++ b/drivers/crypto/hisilicon/trng/trng.c @@ -41,6 +41,7 @@ #define SEED_SHIFT_24 24 #define SEED_SHIFT_16 16 #define SEED_SHIFT_8 8 +#define WAIT_PERIOD 20
struct hisi_trng_list { struct mutex lock; @@ -53,6 +54,7 @@ struct hisi_trng { struct hisi_trng_list *trng_list; struct list_head list; struct hwrng rng; + u32 ctx_num; u32 ver; bool is_used; struct mutex mutex; @@ -60,6 +62,7 @@ struct hisi_trng {
struct hisi_trng_ctx { struct hisi_trng *trng; + struct crypto_rng *drbg; };
static atomic_t trng_active_devs; @@ -85,6 +88,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) { struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct crypto_rng *drbg = ctx->drbg; struct hisi_trng *trng = ctx->trng; u32 val = 0; int ret = 0; @@ -95,6 +99,12 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, return -EINVAL; }
+ /* when the device is busy, use soft tfm instead */ + if (drbg) { + crypto_rng_set_entropy(drbg, seed, slen); + return crypto_rng_reset(drbg, NULL, 0); + } + writel(0x0, trng->base + SW_DRBG_BLOCKS); hisi_trng_set_seed(trng, seed);
@@ -114,6 +124,7 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen, u8 *dstn, unsigned int dlen) { struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct crypto_rng *drbg = ctx->drbg; struct hisi_trng *trng = ctx->trng; u32 data[SW_DRBG_DATA_NUM]; u32 currsize = 0; @@ -127,6 +138,9 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, return -EINVAL; }
+ if (drbg) + return crypto_rng_generate(drbg, src, slen, dstn, dlen); + do { ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, val, val & BIT(1), SLEEP_US, TIMEOUT_US); @@ -156,19 +170,41 @@ static int hisi_trng_init(struct crypto_tfm *tfm) { struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); struct hisi_trng *trng; - int ret = -EBUSY; + int ret = 0;
mutex_lock(&trng_devices.lock); list_for_each_entry(trng, &trng_devices.list, list) { if (!trng->is_used) { trng->is_used = true; + trng->ctx_num++; ctx->trng = trng; - ret = 0; break; } } mutex_unlock(&trng_devices.lock);
+ if (!ctx->trng) { + ctx->drbg = crypto_alloc_rng("drbg_nopr_ctr_aes256", 0, 0); + if (IS_ERR(ctx->drbg)) { + pr_err("Can not alloc rng!\n"); + ret = PTR_ERR(ctx->drbg); + return ret; + } + + mutex_lock(&trng_devices.lock); + if (list_empty(&trng_devices.list)) { + mutex_unlock(&trng_devices.lock); + crypto_free_rng(ctx->drbg); + return -ENODEV; + } + + trng = list_first_entry(&trng_devices.list, + struct hisi_trng, list); + trng->ctx_num++; + ctx->trng = trng; + mutex_unlock(&trng_devices.lock); + } + return ret; }
@@ -177,7 +213,12 @@ static void hisi_trng_exit(struct crypto_tfm *tfm) struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
mutex_lock(&trng_devices.lock); - ctx->trng->is_used = false; + if (!ctx->drbg) + ctx->trng->is_used = false; + else + crypto_free_rng(ctx->drbg); + + ctx->trng->ctx_num--; mutex_unlock(&trng_devices.lock); }
@@ -239,7 +280,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng) int ret = -EBUSY;
mutex_lock(&trng_devices.lock); - if (!trng->is_used) { + if (!trng->ctx_num) { list_del(&trng->list); ret = 0; } @@ -264,6 +305,7 @@ static int hisi_trng_probe(struct platform_device *pdev) return PTR_ERR(trng->base);
trng->is_used = false; + trng->ctx_num = 0; trng->ver = readl(trng->base + HISI_TRNG_VERSION); if (!trng_devices.is_init) { INIT_LIST_HEAD(&trng_devices.list); @@ -310,7 +352,7 @@ static void hisi_trng_remove(struct platform_device *pdev)
/* Wait until the task is finished */ while (hisi_trng_del_from_list(trng)) - ; + msleep(WAIT_PERIOD);
if (trng->ver != HISI_TRNG_VER_V1 && atomic_dec_return(&trng_active_devs) == 0)