Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/crypto/exynos-rng.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* exynos-rng.c - Random Number Generator driver for the Exynos
4
*
5
* Copyright (c) 2017 Krzysztof Kozlowski <[email protected]>
6
*
7
* Loosely based on old driver from drivers/char/hw_random/exynos-rng.c:
8
* Copyright (C) 2012 Samsung Electronics
9
* Jonghwa Lee <[email protected]>
10
*/
11
12
#include <linux/clk.h>
13
#include <linux/crypto.h>
14
#include <linux/err.h>
15
#include <linux/io.h>
16
#include <linux/module.h>
17
#include <linux/mutex.h>
18
#include <linux/of.h>
19
#include <linux/platform_device.h>
20
21
#include <crypto/internal/rng.h>
22
23
#define EXYNOS_RNG_CONTROL 0x0
24
#define EXYNOS_RNG_STATUS 0x10
25
26
#define EXYNOS_RNG_SEED_CONF 0x14
27
#define EXYNOS_RNG_GEN_PRNG BIT(1)
28
29
#define EXYNOS_RNG_SEED_BASE 0x140
30
#define EXYNOS_RNG_SEED(n) (EXYNOS_RNG_SEED_BASE + (n * 0x4))
31
#define EXYNOS_RNG_OUT_BASE 0x160
32
#define EXYNOS_RNG_OUT(n) (EXYNOS_RNG_OUT_BASE + (n * 0x4))
33
34
/* EXYNOS_RNG_CONTROL bit fields */
35
#define EXYNOS_RNG_CONTROL_START 0x18
36
/* EXYNOS_RNG_STATUS bit fields */
37
#define EXYNOS_RNG_STATUS_SEED_SETTING_DONE BIT(1)
38
#define EXYNOS_RNG_STATUS_RNG_DONE BIT(5)
39
40
/* Five seed and output registers, each 4 bytes */
41
#define EXYNOS_RNG_SEED_REGS 5
42
#define EXYNOS_RNG_SEED_SIZE (EXYNOS_RNG_SEED_REGS * 4)
43
44
enum exynos_prng_type {
45
EXYNOS_PRNG_UNKNOWN = 0,
46
EXYNOS_PRNG_EXYNOS4,
47
EXYNOS_PRNG_EXYNOS5,
48
};
49
50
/*
51
* Driver re-seeds itself with generated random numbers to hinder
52
* backtracking of the original seed.
53
*
54
* Time for next re-seed in ms.
55
*/
56
#define EXYNOS_RNG_RESEED_TIME 1000
57
#define EXYNOS_RNG_RESEED_BYTES 65536
58
59
/*
60
* In polling mode, do not wait infinitely for the engine to finish the work.
61
*/
62
#define EXYNOS_RNG_WAIT_RETRIES 100
63
64
/* Context for crypto */
65
struct exynos_rng_ctx {
66
struct exynos_rng_dev *rng;
67
};
68
69
/* Device associated memory */
70
struct exynos_rng_dev {
71
struct device *dev;
72
enum exynos_prng_type type;
73
void __iomem *mem;
74
struct clk *clk;
75
struct mutex lock;
76
/* Generated numbers stored for seeding during resume */
77
u8 seed_save[EXYNOS_RNG_SEED_SIZE];
78
unsigned int seed_save_len;
79
/* Time of last seeding in jiffies */
80
unsigned long last_seeding;
81
/* Bytes generated since last seeding */
82
unsigned long bytes_seeding;
83
};
84
85
static struct exynos_rng_dev *exynos_rng_dev;
86
87
static u32 exynos_rng_readl(struct exynos_rng_dev *rng, u32 offset)
88
{
89
return readl_relaxed(rng->mem + offset);
90
}
91
92
static void exynos_rng_writel(struct exynos_rng_dev *rng, u32 val, u32 offset)
93
{
94
writel_relaxed(val, rng->mem + offset);
95
}
96
97
static int exynos_rng_set_seed(struct exynos_rng_dev *rng,
98
const u8 *seed, unsigned int slen)
99
{
100
u32 val;
101
int i;
102
103
/* Round seed length because loop iterates over full register size */
104
slen = ALIGN_DOWN(slen, 4);
105
106
if (slen < EXYNOS_RNG_SEED_SIZE)
107
return -EINVAL;
108
109
for (i = 0; i < slen ; i += 4) {
110
unsigned int seed_reg = (i / 4) % EXYNOS_RNG_SEED_REGS;
111
112
val = seed[i] << 24;
113
val |= seed[i + 1] << 16;
114
val |= seed[i + 2] << 8;
115
val |= seed[i + 3] << 0;
116
117
exynos_rng_writel(rng, val, EXYNOS_RNG_SEED(seed_reg));
118
}
119
120
val = exynos_rng_readl(rng, EXYNOS_RNG_STATUS);
121
if (!(val & EXYNOS_RNG_STATUS_SEED_SETTING_DONE)) {
122
dev_warn(rng->dev, "Seed setting not finished\n");
123
return -EIO;
124
}
125
126
rng->last_seeding = jiffies;
127
rng->bytes_seeding = 0;
128
129
return 0;
130
}
131
132
/*
133
* Start the engine and poll for finish. Then read from output registers
134
* filling the 'dst' buffer up to 'dlen' bytes or up to size of generated
135
* random data (EXYNOS_RNG_SEED_SIZE).
136
*
137
* On success: return 0 and store number of read bytes under 'read' address.
138
* On error: return -ERRNO.
139
*/
140
static int exynos_rng_get_random(struct exynos_rng_dev *rng,
141
u8 *dst, unsigned int dlen,
142
unsigned int *read)
143
{
144
int retry = EXYNOS_RNG_WAIT_RETRIES;
145
146
if (rng->type == EXYNOS_PRNG_EXYNOS4) {
147
exynos_rng_writel(rng, EXYNOS_RNG_CONTROL_START,
148
EXYNOS_RNG_CONTROL);
149
} else if (rng->type == EXYNOS_PRNG_EXYNOS5) {
150
exynos_rng_writel(rng, EXYNOS_RNG_GEN_PRNG,
151
EXYNOS_RNG_SEED_CONF);
152
}
153
154
while (!(exynos_rng_readl(rng,
155
EXYNOS_RNG_STATUS) & EXYNOS_RNG_STATUS_RNG_DONE) && --retry)
156
cpu_relax();
157
158
if (!retry)
159
return -ETIMEDOUT;
160
161
/* Clear status bit */
162
exynos_rng_writel(rng, EXYNOS_RNG_STATUS_RNG_DONE,
163
EXYNOS_RNG_STATUS);
164
*read = min_t(size_t, dlen, EXYNOS_RNG_SEED_SIZE);
165
memcpy_fromio(dst, rng->mem + EXYNOS_RNG_OUT_BASE, *read);
166
rng->bytes_seeding += *read;
167
168
return 0;
169
}
170
171
/* Re-seed itself from time to time */
172
static void exynos_rng_reseed(struct exynos_rng_dev *rng)
173
{
174
unsigned long next_seeding = rng->last_seeding + \
175
msecs_to_jiffies(EXYNOS_RNG_RESEED_TIME);
176
unsigned long now = jiffies;
177
unsigned int read = 0;
178
u8 seed[EXYNOS_RNG_SEED_SIZE];
179
180
if (time_before(now, next_seeding) &&
181
rng->bytes_seeding < EXYNOS_RNG_RESEED_BYTES)
182
return;
183
184
if (exynos_rng_get_random(rng, seed, sizeof(seed), &read))
185
return;
186
187
exynos_rng_set_seed(rng, seed, read);
188
189
/* Let others do some of their job. */
190
mutex_unlock(&rng->lock);
191
mutex_lock(&rng->lock);
192
}
193
194
static int exynos_rng_generate(struct crypto_rng *tfm,
195
const u8 *src, unsigned int slen,
196
u8 *dst, unsigned int dlen)
197
{
198
struct exynos_rng_ctx *ctx = crypto_rng_ctx(tfm);
199
struct exynos_rng_dev *rng = ctx->rng;
200
unsigned int read = 0;
201
int ret;
202
203
ret = clk_prepare_enable(rng->clk);
204
if (ret)
205
return ret;
206
207
mutex_lock(&rng->lock);
208
do {
209
ret = exynos_rng_get_random(rng, dst, dlen, &read);
210
if (ret)
211
break;
212
213
dlen -= read;
214
dst += read;
215
216
exynos_rng_reseed(rng);
217
} while (dlen > 0);
218
mutex_unlock(&rng->lock);
219
220
clk_disable_unprepare(rng->clk);
221
222
return ret;
223
}
224
225
static int exynos_rng_seed(struct crypto_rng *tfm, const u8 *seed,
226
unsigned int slen)
227
{
228
struct exynos_rng_ctx *ctx = crypto_rng_ctx(tfm);
229
struct exynos_rng_dev *rng = ctx->rng;
230
int ret;
231
232
ret = clk_prepare_enable(rng->clk);
233
if (ret)
234
return ret;
235
236
mutex_lock(&rng->lock);
237
ret = exynos_rng_set_seed(ctx->rng, seed, slen);
238
mutex_unlock(&rng->lock);
239
240
clk_disable_unprepare(rng->clk);
241
242
return ret;
243
}
244
245
static int exynos_rng_kcapi_init(struct crypto_tfm *tfm)
246
{
247
struct exynos_rng_ctx *ctx = crypto_tfm_ctx(tfm);
248
249
ctx->rng = exynos_rng_dev;
250
251
return 0;
252
}
253
254
static struct rng_alg exynos_rng_alg = {
255
.generate = exynos_rng_generate,
256
.seed = exynos_rng_seed,
257
.seedsize = EXYNOS_RNG_SEED_SIZE,
258
.base = {
259
.cra_name = "stdrng",
260
.cra_driver_name = "exynos_rng",
261
.cra_priority = 300,
262
.cra_ctxsize = sizeof(struct exynos_rng_ctx),
263
.cra_module = THIS_MODULE,
264
.cra_init = exynos_rng_kcapi_init,
265
}
266
};
267
268
static int exynos_rng_probe(struct platform_device *pdev)
269
{
270
struct exynos_rng_dev *rng;
271
int ret;
272
273
if (exynos_rng_dev)
274
return -EEXIST;
275
276
rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
277
if (!rng)
278
return -ENOMEM;
279
280
rng->type = (uintptr_t)of_device_get_match_data(&pdev->dev);
281
282
mutex_init(&rng->lock);
283
284
rng->dev = &pdev->dev;
285
rng->clk = devm_clk_get(&pdev->dev, "secss");
286
if (IS_ERR(rng->clk)) {
287
dev_err(&pdev->dev, "Couldn't get clock.\n");
288
return PTR_ERR(rng->clk);
289
}
290
291
rng->mem = devm_platform_ioremap_resource(pdev, 0);
292
if (IS_ERR(rng->mem))
293
return PTR_ERR(rng->mem);
294
295
platform_set_drvdata(pdev, rng);
296
297
exynos_rng_dev = rng;
298
299
ret = crypto_register_rng(&exynos_rng_alg);
300
if (ret) {
301
dev_err(&pdev->dev,
302
"Couldn't register rng crypto alg: %d\n", ret);
303
exynos_rng_dev = NULL;
304
}
305
306
return ret;
307
}
308
309
static void exynos_rng_remove(struct platform_device *pdev)
310
{
311
crypto_unregister_rng(&exynos_rng_alg);
312
313
exynos_rng_dev = NULL;
314
}
315
316
static int __maybe_unused exynos_rng_suspend(struct device *dev)
317
{
318
struct exynos_rng_dev *rng = dev_get_drvdata(dev);
319
int ret;
320
321
/* If we were never seeded then after resume it will be the same */
322
if (!rng->last_seeding)
323
return 0;
324
325
rng->seed_save_len = 0;
326
ret = clk_prepare_enable(rng->clk);
327
if (ret)
328
return ret;
329
330
mutex_lock(&rng->lock);
331
332
/* Get new random numbers and store them for seeding on resume. */
333
exynos_rng_get_random(rng, rng->seed_save, sizeof(rng->seed_save),
334
&(rng->seed_save_len));
335
336
mutex_unlock(&rng->lock);
337
338
dev_dbg(rng->dev, "Stored %u bytes for seeding on system resume\n",
339
rng->seed_save_len);
340
341
clk_disable_unprepare(rng->clk);
342
343
return 0;
344
}
345
346
static int __maybe_unused exynos_rng_resume(struct device *dev)
347
{
348
struct exynos_rng_dev *rng = dev_get_drvdata(dev);
349
int ret;
350
351
/* Never seeded so nothing to do */
352
if (!rng->last_seeding)
353
return 0;
354
355
ret = clk_prepare_enable(rng->clk);
356
if (ret)
357
return ret;
358
359
mutex_lock(&rng->lock);
360
361
ret = exynos_rng_set_seed(rng, rng->seed_save, rng->seed_save_len);
362
363
mutex_unlock(&rng->lock);
364
365
clk_disable_unprepare(rng->clk);
366
367
return ret;
368
}
369
370
static SIMPLE_DEV_PM_OPS(exynos_rng_pm_ops, exynos_rng_suspend,
371
exynos_rng_resume);
372
373
static const struct of_device_id exynos_rng_dt_match[] = {
374
{
375
.compatible = "samsung,exynos4-rng",
376
.data = (const void *)EXYNOS_PRNG_EXYNOS4,
377
}, {
378
.compatible = "samsung,exynos5250-prng",
379
.data = (const void *)EXYNOS_PRNG_EXYNOS5,
380
},
381
{ },
382
};
383
MODULE_DEVICE_TABLE(of, exynos_rng_dt_match);
384
385
static struct platform_driver exynos_rng_driver = {
386
.driver = {
387
.name = "exynos-rng",
388
.pm = &exynos_rng_pm_ops,
389
.of_match_table = exynos_rng_dt_match,
390
},
391
.probe = exynos_rng_probe,
392
.remove = exynos_rng_remove,
393
};
394
395
module_platform_driver(exynos_rng_driver);
396
397
MODULE_DESCRIPTION("Exynos H/W Random Number Generator driver");
398
MODULE_AUTHOR("Krzysztof Kozlowski <[email protected]>");
399
MODULE_LICENSE("GPL v2");
400
401