Skip to content

Commit 3d31350

Browse files
Weili Qianherbertx
authored andcommitted
crypto: hisilicon/trng - support tfms sharing the device
Since the number of devices is limited, and the number of tfms may exceed the number of devices, to ensure that tfms can be successfully allocated, support tfms sharing the same device. Fixes: e4d9d10 ("crypto: hisilicon/trng - add support for PRNG") Signed-off-by: Weili Qian <qianweili@huawei.com> Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent ea37779 commit 3d31350

1 file changed

Lines changed: 86 additions & 35 deletions

File tree

  • drivers/crypto/hisilicon/trng

drivers/crypto/hisilicon/trng/trng.c

Lines changed: 86 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#define SEED_SHIFT_24 24
4141
#define SEED_SHIFT_16 16
4242
#define SEED_SHIFT_8 8
43+
#define SW_MAX_RANDOM_BYTES 65520
4344

4445
struct hisi_trng_list {
4546
struct mutex lock;
@@ -53,8 +54,10 @@ struct hisi_trng {
5354
struct list_head list;
5455
struct hwrng rng;
5556
u32 ver;
56-
bool is_used;
57-
struct mutex mutex;
57+
u32 ctx_num;
58+
/* The bytes of the random number generated since the last seeding. */
59+
u32 random_bytes;
60+
struct mutex lock;
5861
};
5962

6063
struct hisi_trng_ctx {
@@ -63,10 +66,14 @@ struct hisi_trng_ctx {
6366

6467
static atomic_t trng_active_devs;
6568
static struct hisi_trng_list trng_devices;
69+
static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
6670

67-
static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
71+
static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
6872
{
6973
u32 val, seed_reg, i;
74+
int ret;
75+
76+
writel(0x0, trng->base + SW_DRBG_BLOCKS);
7077

7178
for (i = 0; i < SW_DRBG_SEED_SIZE;
7279
i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
@@ -78,59 +85,74 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
7885
seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
7986
writel(val, trng->base + SW_DRBG_SEED(seed_reg));
8087
}
88+
89+
writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
90+
trng->base + SW_DRBG_BLOCKS);
91+
writel(0x1, trng->base + SW_DRBG_INIT);
92+
ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
93+
val, val & BIT(0), SLEEP_US, TIMEOUT_US);
94+
if (ret) {
95+
pr_err("failed to init trng(%d)\n", ret);
96+
return -EIO;
97+
}
98+
99+
trng->random_bytes = 0;
100+
101+
return 0;
81102
}
82103

83104
static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
84105
unsigned int slen)
85106
{
86107
struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
87108
struct hisi_trng *trng = ctx->trng;
88-
u32 val = 0;
89-
int ret = 0;
109+
int ret;
90110

91111
if (slen < SW_DRBG_SEED_SIZE) {
92112
pr_err("slen(%u) is not matched with trng(%d)\n", slen,
93113
SW_DRBG_SEED_SIZE);
94114
return -EINVAL;
95115
}
96116

97-
writel(0x0, trng->base + SW_DRBG_BLOCKS);
98-
hisi_trng_set_seed(trng, seed);
117+
mutex_lock(&trng->lock);
118+
ret = hisi_trng_set_seed(trng, seed);
119+
mutex_unlock(&trng->lock);
99120

100-
writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
101-
trng->base + SW_DRBG_BLOCKS);
102-
writel(0x1, trng->base + SW_DRBG_INIT);
121+
return ret;
122+
}
103123

104-
ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
105-
val, val & BIT(0), SLEEP_US, TIMEOUT_US);
106-
if (ret)
107-
pr_err("fail to init trng(%d)\n", ret);
124+
static int hisi_trng_reseed(struct hisi_trng *trng)
125+
{
126+
u8 seed[SW_DRBG_SEED_SIZE];
127+
int size;
108128

109-
return ret;
129+
if (!trng->random_bytes)
130+
return 0;
131+
132+
size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
133+
if (size != SW_DRBG_SEED_SIZE)
134+
return -EIO;
135+
136+
return hisi_trng_set_seed(trng, seed);
110137
}
111138

112-
static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
113-
unsigned int slen, u8 *dstn, unsigned int dlen)
139+
static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
114140
{
115-
struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
116-
struct hisi_trng *trng = ctx->trng;
117141
u32 data[SW_DRBG_DATA_NUM];
118142
u32 currsize = 0;
119143
u32 val = 0;
120144
int ret;
121145
u32 i;
122146

123-
if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) {
124-
pr_err("dlen(%u) exceeds limit(%d)!\n", dlen,
125-
SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES);
126-
return -EINVAL;
127-
}
147+
ret = hisi_trng_reseed(trng);
148+
if (ret)
149+
return ret;
128150

129151
do {
130152
ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
131-
val, val & BIT(1), SLEEP_US, TIMEOUT_US);
153+
val, val & BIT(1), SLEEP_US, TIMEOUT_US);
132154
if (ret) {
133-
pr_err("fail to generate random number(%d)!\n", ret);
155+
pr_err("failed to generate random number(%d)!\n", ret);
134156
break;
135157
}
136158

@@ -145,38 +167,65 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
145167
currsize = dlen;
146168
}
147169

170+
trng->random_bytes += SW_DRBG_BYTES;
148171
writel(0x1, trng->base + SW_DRBG_GEN);
149172
} while (currsize < dlen);
150173

151174
return ret;
152175
}
153176

177+
static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
178+
unsigned int slen, u8 *dstn, unsigned int dlen)
179+
{
180+
struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
181+
struct hisi_trng *trng = ctx->trng;
182+
unsigned int currsize = 0;
183+
unsigned int block_size;
184+
int ret;
185+
186+
if (!dstn || !dlen) {
187+
pr_err("output is error, dlen %u!\n", dlen);
188+
return -EINVAL;
189+
}
190+
191+
do {
192+
block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
193+
mutex_lock(&trng->lock);
194+
ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
195+
mutex_unlock(&trng->lock);
196+
if (ret)
197+
return ret;
198+
currsize += block_size;
199+
} while (currsize < dlen);
200+
201+
return 0;
202+
}
203+
154204
static int hisi_trng_init(struct crypto_tfm *tfm)
155205
{
156206
struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
157207
struct hisi_trng *trng;
158-
int ret = -EBUSY;
208+
u32 ctx_num = ~0;
159209

160210
mutex_lock(&trng_devices.lock);
161211
list_for_each_entry(trng, &trng_devices.list, list) {
162-
if (!trng->is_used) {
163-
trng->is_used = true;
212+
if (trng->ctx_num < ctx_num) {
213+
ctx_num = trng->ctx_num;
164214
ctx->trng = trng;
165-
ret = 0;
166-
break;
167215
}
168216
}
217+
ctx->trng->ctx_num++;
169218
mutex_unlock(&trng_devices.lock);
170219

171-
return ret;
220+
return 0;
172221
}
173222

174223
static void hisi_trng_exit(struct crypto_tfm *tfm)
175224
{
176225
struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
177226

178227
mutex_lock(&trng_devices.lock);
179-
ctx->trng->is_used = false;
228+
ctx->trng->ctx_num--;
180229
mutex_unlock(&trng_devices.lock);
181230
}
182231

@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng)
238287
int ret = -EBUSY;
239288

240289
mutex_lock(&trng_devices.lock);
241-
if (!trng->is_used) {
290+
if (!trng->ctx_num) {
242291
list_del(&trng->list);
243292
ret = 0;
244293
}
@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev)
262311
if (IS_ERR(trng->base))
263312
return PTR_ERR(trng->base);
264313

265-
trng->is_used = false;
314+
trng->ctx_num = 0;
315+
trng->random_bytes = SW_MAX_RANDOM_BYTES;
316+
mutex_init(&trng->lock);
266317
trng->ver = readl(trng->base + HISI_TRNG_VERSION);
267318
if (!trng_devices.is_init) {
268319
INIT_LIST_HEAD(&trng_devices.list);

0 commit comments

Comments
 (0)