Commit | Line | Data |
---|---|---|
844dd05f | 1 | /* |
dd801483 CL |
2 | * hw_random/core.c: HWRNG core API |
3 | * | |
4 | * Copyright 2006 Michael Buesch <m@bues.ch> | |
5 | * Copyright 2005 (c) MontaVista Software, Inc. | |
6 | * | |
4f4cfa6c | 7 | * Please read Documentation/admin-guide/hw_random.rst for details on use. |
dd801483 CL |
8 | * |
9 | * This software may be used and distributed according to the terms | |
10 | * of the GNU General Public License, incorporated herein by reference. | |
844dd05f MB |
11 | */ |
12 | ||
affdec58 | 13 | #include <linux/delay.h> |
844dd05f | 14 | #include <linux/device.h> |
affdec58 CL |
15 | #include <linux/err.h> |
16 | #include <linux/fs.h> | |
844dd05f | 17 | #include <linux/hw_random.h> |
844dd05f | 18 | #include <linux/kernel.h> |
be4000bc | 19 | #include <linux/kthread.h> |
174cd4b1 | 20 | #include <linux/sched/signal.h> |
affdec58 CL |
21 | #include <linux/miscdevice.h> |
22 | #include <linux/module.h> | |
d9e79726 | 23 | #include <linux/random.h> |
affdec58 CL |
24 | #include <linux/sched.h> |
25 | #include <linux/slab.h> | |
7c0f6ba6 | 26 | #include <linux/uaccess.h> |
844dd05f | 27 | |
844dd05f | 28 | #define RNG_MODULE_NAME "hw_random" |
844dd05f MB |
29 | |
30 | static struct hwrng *current_rng; | |
10a515dd HF |
31 | /* the current rng has been explicitly chosen by user via sysfs */ |
32 | static int cur_rng_set_by_user; | |
be4000bc | 33 | static struct task_struct *hwrng_fill; |
2bbb6983 | 34 | /* list of registered rngs, sorted decending by quality */ |
844dd05f | 35 | static LIST_HEAD(rng_list); |
9372b35e | 36 | /* Protects rng_list and current_rng */ |
844dd05f | 37 | static DEFINE_MUTEX(rng_mutex); |
9372b35e RR |
38 | /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ |
39 | static DEFINE_MUTEX(reading_mutex); | |
9996508b | 40 | static int data_avail; |
be4000bc | 41 | static u8 *rng_buffer, *rng_fillbuf; |
0f734e6e TD |
42 | static unsigned short current_quality; |
43 | static unsigned short default_quality; /* = 0; default to "off" */ | |
be4000bc TD |
44 | |
45 | module_param(current_quality, ushort, 0644); | |
46 | MODULE_PARM_DESC(current_quality, | |
fae29f13 | 47 | "current hwrng entropy estimation per 1024 bits of input"); |
0f734e6e TD |
48 | module_param(default_quality, ushort, 0644); |
49 | MODULE_PARM_DESC(default_quality, | |
fae29f13 | 50 | "default entropy content of hwrng per 1024 bits of input"); |
be4000bc | 51 | |
ff77c150 | 52 | static void drop_current_rng(void); |
90ac41bd | 53 | static int hwrng_init(struct hwrng *rng); |
be4000bc | 54 | static void start_khwrngd(void); |
f7f154f1 | 55 | |
d3cc7996 AS |
56 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, |
57 | int wait); | |
58 | ||
f7f154f1 RR |
59 | static size_t rng_buffer_size(void) |
60 | { | |
61 | return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; | |
62 | } | |
844dd05f | 63 | |
d3cc7996 AS |
64 | static void add_early_randomness(struct hwrng *rng) |
65 | { | |
d3cc7996 AS |
66 | int bytes_read; |
67 | ||
9372b35e | 68 | mutex_lock(&reading_mutex); |
c05ac449 | 69 | bytes_read = rng_get_data(rng, rng_fillbuf, 32, 0); |
9372b35e | 70 | mutex_unlock(&reading_mutex); |
d3cc7996 | 71 | if (bytes_read > 0) |
c05ac449 | 72 | add_device_randomness(rng_fillbuf, bytes_read); |
d3cc7996 AS |
73 | } |
74 | ||
3a2c0ba5 RR |
75 | static inline void cleanup_rng(struct kref *kref) |
76 | { | |
77 | struct hwrng *rng = container_of(kref, struct hwrng, ref); | |
78 | ||
79 | if (rng->cleanup) | |
80 | rng->cleanup(rng); | |
a027f30d | 81 | |
77584ee5 | 82 | complete(&rng->cleanup_done); |
3a2c0ba5 RR |
83 | } |
84 | ||
90ac41bd | 85 | static int set_current_rng(struct hwrng *rng) |
3a2c0ba5 | 86 | { |
90ac41bd HX |
87 | int err; |
88 | ||
3a2c0ba5 | 89 | BUG_ON(!mutex_is_locked(&rng_mutex)); |
90ac41bd HX |
90 | |
91 | err = hwrng_init(rng); | |
92 | if (err) | |
93 | return err; | |
94 | ||
ff77c150 | 95 | drop_current_rng(); |
3a2c0ba5 | 96 | current_rng = rng; |
90ac41bd HX |
97 | |
98 | return 0; | |
3a2c0ba5 RR |
99 | } |
100 | ||
101 | static void drop_current_rng(void) | |
102 | { | |
103 | BUG_ON(!mutex_is_locked(&rng_mutex)); | |
104 | if (!current_rng) | |
105 | return; | |
106 | ||
107 | /* decrease last reference for triggering the cleanup */ | |
108 | kref_put(¤t_rng->ref, cleanup_rng); | |
109 | current_rng = NULL; | |
110 | } | |
111 | ||
112 | /* Returns ERR_PTR(), NULL or refcounted hwrng */ | |
daae28de LV |
113 | static struct hwrng *get_current_rng_nolock(void) |
114 | { | |
115 | if (current_rng) | |
116 | kref_get(¤t_rng->ref); | |
117 | ||
118 | return current_rng; | |
119 | } | |
120 | ||
3a2c0ba5 RR |
121 | static struct hwrng *get_current_rng(void) |
122 | { | |
123 | struct hwrng *rng; | |
124 | ||
125 | if (mutex_lock_interruptible(&rng_mutex)) | |
126 | return ERR_PTR(-ERESTARTSYS); | |
127 | ||
daae28de | 128 | rng = get_current_rng_nolock(); |
3a2c0ba5 RR |
129 | |
130 | mutex_unlock(&rng_mutex); | |
131 | return rng; | |
132 | } | |
133 | ||
134 | static void put_rng(struct hwrng *rng) | |
135 | { | |
136 | /* | |
137 | * Hold rng_mutex here so we serialize in case they set_current_rng | |
138 | * on rng again immediately. | |
139 | */ | |
140 | mutex_lock(&rng_mutex); | |
141 | if (rng) | |
142 | kref_put(&rng->ref, cleanup_rng); | |
143 | mutex_unlock(&rng_mutex); | |
144 | } | |
145 | ||
90ac41bd | 146 | static int hwrng_init(struct hwrng *rng) |
844dd05f | 147 | { |
15b66cd5 HX |
148 | if (kref_get_unless_zero(&rng->ref)) |
149 | goto skip_init; | |
150 | ||
d3cc7996 AS |
151 | if (rng->init) { |
152 | int ret; | |
153 | ||
154 | ret = rng->init(rng); | |
155 | if (ret) | |
156 | return ret; | |
157 | } | |
15b66cd5 HX |
158 | |
159 | kref_init(&rng->ref); | |
160 | reinit_completion(&rng->cleanup_done); | |
161 | ||
162 | skip_init: | |
0f734e6e | 163 | current_quality = rng->quality ? : default_quality; |
506bf0c0 KP |
164 | if (current_quality > 1024) |
165 | current_quality = 1024; | |
0f734e6e TD |
166 | |
167 | if (current_quality == 0 && hwrng_fill) | |
168 | kthread_stop(hwrng_fill); | |
be4000bc TD |
169 | if (current_quality > 0 && !hwrng_fill) |
170 | start_khwrngd(); | |
171 | ||
d3cc7996 | 172 | return 0; |
844dd05f MB |
173 | } |
174 | ||
844dd05f MB |
175 | static int rng_dev_open(struct inode *inode, struct file *filp) |
176 | { | |
177 | /* enforce read-only access to this chrdev */ | |
178 | if ((filp->f_mode & FMODE_READ) == 0) | |
179 | return -EINVAL; | |
180 | if (filp->f_mode & FMODE_WRITE) | |
181 | return -EINVAL; | |
182 | return 0; | |
183 | } | |
184 | ||
9996508b IM |
185 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, |
186 | int wait) { | |
187 | int present; | |
188 | ||
9372b35e | 189 | BUG_ON(!mutex_is_locked(&reading_mutex)); |
9996508b IM |
190 | if (rng->read) |
191 | return rng->read(rng, (void *)buffer, size, wait); | |
192 | ||
193 | if (rng->data_present) | |
194 | present = rng->data_present(rng, wait); | |
195 | else | |
196 | present = 1; | |
197 | ||
198 | if (present) | |
199 | return rng->data_read(rng, (u32 *)buffer); | |
200 | ||
201 | return 0; | |
202 | } | |
203 | ||
844dd05f MB |
204 | static ssize_t rng_dev_read(struct file *filp, char __user *buf, |
205 | size_t size, loff_t *offp) | |
206 | { | |
844dd05f | 207 | ssize_t ret = 0; |
984e976f | 208 | int err = 0; |
9996508b | 209 | int bytes_read, len; |
3a2c0ba5 | 210 | struct hwrng *rng; |
844dd05f MB |
211 | |
212 | while (size) { | |
3a2c0ba5 RR |
213 | rng = get_current_rng(); |
214 | if (IS_ERR(rng)) { | |
215 | err = PTR_ERR(rng); | |
844dd05f | 216 | goto out; |
9996508b | 217 | } |
3a2c0ba5 | 218 | if (!rng) { |
844dd05f | 219 | err = -ENODEV; |
3a2c0ba5 | 220 | goto out; |
844dd05f | 221 | } |
984e976f | 222 | |
1ab87298 JS |
223 | if (mutex_lock_interruptible(&reading_mutex)) { |
224 | err = -ERESTARTSYS; | |
225 | goto out_put; | |
226 | } | |
9996508b | 227 | if (!data_avail) { |
3a2c0ba5 | 228 | bytes_read = rng_get_data(rng, rng_buffer, |
f7f154f1 | 229 | rng_buffer_size(), |
9996508b IM |
230 | !(filp->f_flags & O_NONBLOCK)); |
231 | if (bytes_read < 0) { | |
232 | err = bytes_read; | |
9372b35e | 233 | goto out_unlock_reading; |
9996508b IM |
234 | } |
235 | data_avail = bytes_read; | |
893f1128 | 236 | } |
844dd05f | 237 | |
9996508b IM |
238 | if (!data_avail) { |
239 | if (filp->f_flags & O_NONBLOCK) { | |
240 | err = -EAGAIN; | |
9372b35e | 241 | goto out_unlock_reading; |
9996508b IM |
242 | } |
243 | } else { | |
244 | len = data_avail; | |
245 | if (len > size) | |
246 | len = size; | |
247 | ||
248 | data_avail -= len; | |
249 | ||
250 | if (copy_to_user(buf + ret, rng_buffer + data_avail, | |
251 | len)) { | |
252 | err = -EFAULT; | |
9372b35e | 253 | goto out_unlock_reading; |
9996508b IM |
254 | } |
255 | ||
256 | size -= len; | |
257 | ret += len; | |
844dd05f MB |
258 | } |
259 | ||
9372b35e | 260 | mutex_unlock(&reading_mutex); |
3a2c0ba5 | 261 | put_rng(rng); |
9996508b | 262 | |
844dd05f MB |
263 | if (need_resched()) |
264 | schedule_timeout_interruptible(1); | |
9996508b IM |
265 | |
266 | if (signal_pending(current)) { | |
267 | err = -ERESTARTSYS; | |
844dd05f | 268 | goto out; |
9996508b | 269 | } |
844dd05f MB |
270 | } |
271 | out: | |
272 | return ret ? : err; | |
3a2c0ba5 | 273 | |
9372b35e RR |
274 | out_unlock_reading: |
275 | mutex_unlock(&reading_mutex); | |
1ab87298 | 276 | out_put: |
3a2c0ba5 RR |
277 | put_rng(rng); |
278 | goto out; | |
844dd05f MB |
279 | } |
280 | ||
62322d25 | 281 | static const struct file_operations rng_chrdev_ops = { |
844dd05f MB |
282 | .owner = THIS_MODULE, |
283 | .open = rng_dev_open, | |
284 | .read = rng_dev_read, | |
6038f373 | 285 | .llseek = noop_llseek, |
844dd05f MB |
286 | }; |
287 | ||
0daa7a0a TI |
288 | static const struct attribute_group *rng_dev_groups[]; |
289 | ||
844dd05f | 290 | static struct miscdevice rng_miscdev = { |
fd50d71f | 291 | .minor = HWRNG_MINOR, |
844dd05f | 292 | .name = RNG_MODULE_NAME, |
e454cea2 | 293 | .nodename = "hwrng", |
844dd05f | 294 | .fops = &rng_chrdev_ops, |
0daa7a0a | 295 | .groups = rng_dev_groups, |
844dd05f MB |
296 | }; |
297 | ||
142a27f0 PM |
298 | static int enable_best_rng(void) |
299 | { | |
300 | int ret = -ENODEV; | |
301 | ||
302 | BUG_ON(!mutex_is_locked(&rng_mutex)); | |
303 | ||
304 | /* rng_list is sorted by quality, use the best (=first) one */ | |
305 | if (!list_empty(&rng_list)) { | |
306 | struct hwrng *new_rng; | |
307 | ||
308 | new_rng = list_entry(rng_list.next, struct hwrng, list); | |
309 | ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); | |
310 | if (!ret) | |
311 | cur_rng_set_by_user = 0; | |
0e4b5294 GH |
312 | } else { |
313 | drop_current_rng(); | |
314 | cur_rng_set_by_user = 0; | |
315 | ret = 0; | |
142a27f0 PM |
316 | } |
317 | ||
318 | return ret; | |
319 | } | |
320 | ||
98f481f2 Y |
321 | static ssize_t rng_current_store(struct device *dev, |
322 | struct device_attribute *attr, | |
323 | const char *buf, size_t len) | |
844dd05f | 324 | { |
cb028f16 | 325 | int err; |
daae28de | 326 | struct hwrng *rng, *old_rng, *new_rng; |
844dd05f MB |
327 | |
328 | err = mutex_lock_interruptible(&rng_mutex); | |
329 | if (err) | |
330 | return -ERESTARTSYS; | |
142a27f0 | 331 | |
daae28de | 332 | old_rng = current_rng; |
142a27f0 PM |
333 | if (sysfs_streq(buf, "")) { |
334 | err = enable_best_rng(); | |
335 | } else { | |
336 | list_for_each_entry(rng, &rng_list, list) { | |
337 | if (sysfs_streq(rng->name, buf)) { | |
338 | cur_rng_set_by_user = 1; | |
90ac41bd | 339 | err = set_current_rng(rng); |
142a27f0 PM |
340 | break; |
341 | } | |
844dd05f MB |
342 | } |
343 | } | |
daae28de | 344 | new_rng = get_current_rng_nolock(); |
844dd05f MB |
345 | mutex_unlock(&rng_mutex); |
346 | ||
daae28de LV |
347 | if (new_rng) { |
348 | if (new_rng != old_rng) | |
349 | add_early_randomness(new_rng); | |
350 | put_rng(new_rng); | |
351 | } | |
352 | ||
844dd05f MB |
353 | return err ? : len; |
354 | } | |
355 | ||
98f481f2 Y |
356 | static ssize_t rng_current_show(struct device *dev, |
357 | struct device_attribute *attr, | |
358 | char *buf) | |
844dd05f | 359 | { |
844dd05f | 360 | ssize_t ret; |
3a2c0ba5 | 361 | struct hwrng *rng; |
844dd05f | 362 | |
3a2c0ba5 RR |
363 | rng = get_current_rng(); |
364 | if (IS_ERR(rng)) | |
365 | return PTR_ERR(rng); | |
366 | ||
367 | ret = snprintf(buf, PAGE_SIZE, "%s\n", rng ? rng->name : "none"); | |
368 | put_rng(rng); | |
844dd05f MB |
369 | |
370 | return ret; | |
371 | } | |
372 | ||
98f481f2 Y |
373 | static ssize_t rng_available_show(struct device *dev, |
374 | struct device_attribute *attr, | |
375 | char *buf) | |
844dd05f MB |
376 | { |
377 | int err; | |
844dd05f MB |
378 | struct hwrng *rng; |
379 | ||
380 | err = mutex_lock_interruptible(&rng_mutex); | |
381 | if (err) | |
382 | return -ERESTARTSYS; | |
383 | buf[0] = '\0'; | |
384 | list_for_each_entry(rng, &rng_list, list) { | |
61daf055 RS |
385 | strlcat(buf, rng->name, PAGE_SIZE); |
386 | strlcat(buf, " ", PAGE_SIZE); | |
844dd05f | 387 | } |
61daf055 | 388 | strlcat(buf, "\n", PAGE_SIZE); |
844dd05f MB |
389 | mutex_unlock(&rng_mutex); |
390 | ||
61daf055 | 391 | return strlen(buf); |
844dd05f MB |
392 | } |
393 | ||
98f481f2 Y |
394 | static ssize_t rng_selected_show(struct device *dev, |
395 | struct device_attribute *attr, | |
396 | char *buf) | |
10a515dd | 397 | { |
91253022 | 398 | return sysfs_emit(buf, "%d\n", cur_rng_set_by_user); |
10a515dd HF |
399 | } |
400 | ||
98f481f2 Y |
401 | static DEVICE_ATTR_RW(rng_current); |
402 | static DEVICE_ATTR_RO(rng_available); | |
403 | static DEVICE_ATTR_RO(rng_selected); | |
844dd05f | 404 | |
0daa7a0a TI |
405 | static struct attribute *rng_dev_attrs[] = { |
406 | &dev_attr_rng_current.attr, | |
407 | &dev_attr_rng_available.attr, | |
10a515dd | 408 | &dev_attr_rng_selected.attr, |
0daa7a0a TI |
409 | NULL |
410 | }; | |
411 | ||
412 | ATTRIBUTE_GROUPS(rng_dev); | |
844dd05f | 413 | |
ac3a497f | 414 | static void __exit unregister_miscdev(void) |
844dd05f | 415 | { |
b844eba2 | 416 | misc_deregister(&rng_miscdev); |
844dd05f MB |
417 | } |
418 | ||
ac3a497f | 419 | static int __init register_miscdev(void) |
844dd05f | 420 | { |
0daa7a0a | 421 | return misc_register(&rng_miscdev); |
844dd05f MB |
422 | } |
423 | ||
be4000bc TD |
424 | static int hwrng_fillfn(void *unused) |
425 | { | |
426 | long rc; | |
427 | ||
08e97aec | 428 | while (!kthread_should_stop()) { |
3a2c0ba5 RR |
429 | struct hwrng *rng; |
430 | ||
431 | rng = get_current_rng(); | |
432 | if (IS_ERR(rng) || !rng) | |
be4000bc | 433 | break; |
9372b35e | 434 | mutex_lock(&reading_mutex); |
3a2c0ba5 | 435 | rc = rng_get_data(rng, rng_fillbuf, |
be4000bc | 436 | rng_buffer_size(), 1); |
9372b35e | 437 | mutex_unlock(&reading_mutex); |
3a2c0ba5 | 438 | put_rng(rng); |
be4000bc TD |
439 | if (rc <= 0) { |
440 | pr_warn("hwrng: no data available\n"); | |
441 | msleep_interruptible(10000); | |
442 | continue; | |
443 | } | |
9372b35e | 444 | /* Outside lock, sure, but y'know: randomness. */ |
be4000bc | 445 | add_hwgenerator_randomness((void *)rng_fillbuf, rc, |
e02b8765 | 446 | rc * current_quality * 8 >> 10); |
be4000bc | 447 | } |
9dda727d | 448 | hwrng_fill = NULL; |
be4000bc TD |
449 | return 0; |
450 | } | |
451 | ||
452 | static void start_khwrngd(void) | |
453 | { | |
454 | hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng"); | |
17fb874d | 455 | if (IS_ERR(hwrng_fill)) { |
4d0ec229 | 456 | pr_err("hwrng_fill thread creation failed\n"); |
be4000bc TD |
457 | hwrng_fill = NULL; |
458 | } | |
459 | } | |
460 | ||
844dd05f MB |
461 | int hwrng_register(struct hwrng *rng) |
462 | { | |
844dd05f | 463 | int err = -EINVAL; |
28443671 | 464 | struct hwrng *tmp; |
2bbb6983 | 465 | struct list_head *rng_list_ptr; |
28443671 | 466 | bool is_new_current = false; |
844dd05f | 467 | |
2a971e3b | 468 | if (!rng->name || (!rng->data_read && !rng->read)) |
844dd05f MB |
469 | goto out; |
470 | ||
471 | mutex_lock(&rng_mutex); | |
daae28de | 472 | |
844dd05f MB |
473 | /* Must not register two RNGs with the same name. */ |
474 | err = -EEXIST; | |
475 | list_for_each_entry(tmp, &rng_list, list) { | |
476 | if (strcmp(tmp->name, rng->name) == 0) | |
477 | goto out_unlock; | |
478 | } | |
479 | ||
15b66cd5 HX |
480 | init_completion(&rng->cleanup_done); |
481 | complete(&rng->cleanup_done); | |
482 | ||
2bbb6983 HF |
483 | /* rng_list is sorted by decreasing quality */ |
484 | list_for_each(rng_list_ptr, &rng_list) { | |
485 | tmp = list_entry(rng_list_ptr, struct hwrng, list); | |
486 | if (tmp->quality < rng->quality) | |
487 | break; | |
488 | } | |
489 | list_add_tail(&rng->list, rng_list_ptr); | |
490 | ||
28443671 LV |
491 | if (!current_rng || |
492 | (!cur_rng_set_by_user && rng->quality > current_rng->quality)) { | |
2bbb6983 HF |
493 | /* |
494 | * Set new rng as current as the new rng source | |
10a515dd HF |
495 | * provides better entropy quality and was not |
496 | * chosen by userspace. | |
2bbb6983 | 497 | */ |
90ac41bd | 498 | err = set_current_rng(rng); |
844dd05f MB |
499 | if (err) |
500 | goto out_unlock; | |
28443671 LV |
501 | /* to use current_rng in add_early_randomness() we need |
502 | * to take a ref | |
503 | */ | |
504 | is_new_current = true; | |
505 | kref_get(&rng->ref); | |
844dd05f | 506 | } |
daae28de | 507 | mutex_unlock(&rng_mutex); |
28443671 | 508 | if (is_new_current || !rng->init) { |
d3cc7996 AS |
509 | /* |
510 | * Use a new device's input to add some randomness to | |
511 | * the system. If this rng device isn't going to be | |
512 | * used right away, its init function hasn't been | |
daae28de LV |
513 | * called yet by set_current_rng(); so only use the |
514 | * randomness from devices that don't need an init callback | |
d3cc7996 AS |
515 | */ |
516 | add_early_randomness(rng); | |
517 | } | |
28443671 LV |
518 | if (is_new_current) |
519 | put_rng(rng); | |
520 | return 0; | |
844dd05f MB |
521 | out_unlock: |
522 | mutex_unlock(&rng_mutex); | |
523 | out: | |
524 | return err; | |
525 | } | |
526 | EXPORT_SYMBOL_GPL(hwrng_register); | |
527 | ||
b844eba2 | 528 | void hwrng_unregister(struct hwrng *rng) |
844dd05f | 529 | { |
daae28de | 530 | struct hwrng *old_rng, *new_rng; |
837bf7cc MB |
531 | int err; |
532 | ||
844dd05f MB |
533 | mutex_lock(&rng_mutex); |
534 | ||
daae28de | 535 | old_rng = current_rng; |
844dd05f | 536 | list_del(&rng->list); |
837bf7cc MB |
537 | if (current_rng == rng) { |
538 | err = enable_best_rng(); | |
539 | if (err) { | |
540 | drop_current_rng(); | |
541 | cur_rng_set_by_user = 0; | |
542 | } | |
543 | } | |
3a2c0ba5 | 544 | |
daae28de | 545 | new_rng = get_current_rng_nolock(); |
be4000bc | 546 | if (list_empty(&rng_list)) { |
1dacb395 | 547 | mutex_unlock(&rng_mutex); |
be4000bc TD |
548 | if (hwrng_fill) |
549 | kthread_stop(hwrng_fill); | |
1dacb395 AK |
550 | } else |
551 | mutex_unlock(&rng_mutex); | |
a027f30d | 552 | |
daae28de LV |
553 | if (new_rng) { |
554 | if (old_rng != new_rng) | |
555 | add_early_randomness(new_rng); | |
556 | put_rng(new_rng); | |
557 | } | |
558 | ||
77584ee5 | 559 | wait_for_completion(&rng->cleanup_done); |
844dd05f | 560 | } |
b844eba2 | 561 | EXPORT_SYMBOL_GPL(hwrng_unregister); |
844dd05f | 562 | |
4d9b519c DT |
563 | static void devm_hwrng_release(struct device *dev, void *res) |
564 | { | |
565 | hwrng_unregister(*(struct hwrng **)res); | |
566 | } | |
567 | ||
568 | static int devm_hwrng_match(struct device *dev, void *res, void *data) | |
569 | { | |
570 | struct hwrng **r = res; | |
571 | ||
572 | if (WARN_ON(!r || !*r)) | |
573 | return 0; | |
574 | ||
575 | return *r == data; | |
576 | } | |
577 | ||
578 | int devm_hwrng_register(struct device *dev, struct hwrng *rng) | |
579 | { | |
580 | struct hwrng **ptr; | |
581 | int error; | |
582 | ||
583 | ptr = devres_alloc(devm_hwrng_release, sizeof(*ptr), GFP_KERNEL); | |
584 | if (!ptr) | |
585 | return -ENOMEM; | |
586 | ||
587 | error = hwrng_register(rng); | |
588 | if (error) { | |
589 | devres_free(ptr); | |
590 | return error; | |
591 | } | |
592 | ||
593 | *ptr = rng; | |
594 | devres_add(dev, ptr); | |
595 | return 0; | |
596 | } | |
597 | EXPORT_SYMBOL_GPL(devm_hwrng_register); | |
598 | ||
599 | void devm_hwrng_unregister(struct device *dev, struct hwrng *rng) | |
600 | { | |
601 | devres_release(dev, devm_hwrng_release, devm_hwrng_match, rng); | |
602 | } | |
603 | EXPORT_SYMBOL_GPL(devm_hwrng_unregister); | |
604 | ||
ac3a497f HX |
605 | static int __init hwrng_modinit(void) |
606 | { | |
45645709 | 607 | int ret; |
58b022ac PM |
608 | |
609 | /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */ | |
610 | rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL); | |
611 | if (!rng_buffer) | |
612 | return -ENOMEM; | |
613 | ||
614 | rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL); | |
615 | if (!rng_fillbuf) { | |
616 | kfree(rng_buffer); | |
617 | return -ENOMEM; | |
618 | } | |
619 | ||
620 | ret = register_miscdev(); | |
621 | if (ret) { | |
622 | kfree(rng_fillbuf); | |
623 | kfree(rng_buffer); | |
624 | } | |
625 | ||
626 | return ret; | |
ac3a497f HX |
627 | } |
628 | ||
629 | static void __exit hwrng_modexit(void) | |
b7d44d94 ST |
630 | { |
631 | mutex_lock(&rng_mutex); | |
632 | BUG_ON(current_rng); | |
633 | kfree(rng_buffer); | |
be4000bc | 634 | kfree(rng_fillbuf); |
b7d44d94 | 635 | mutex_unlock(&rng_mutex); |
ac3a497f HX |
636 | |
637 | unregister_miscdev(); | |
b7d44d94 ST |
638 | } |
639 | ||
26a03981 | 640 | fs_initcall(hwrng_modinit); /* depends on misc_register() */ |
ac3a497f | 641 | module_exit(hwrng_modexit); |
844dd05f MB |
642 | |
643 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); | |
644 | MODULE_LICENSE("GPL"); |