aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/random.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2014-06-14 21:43:13 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-07-15 04:49:40 -0400
commit43759d4f429c8d55fd56f863542e20f4e6e8f589 (patch)
tree253a45901a3e3d83be2566e0ad59af1c2c171be7 /drivers/char/random.c
parent840f95077ffd640df9c74ad9796fa094a5c8075a (diff)
random: use an improved fast_mix() function
Use more efficient fast_mix() function. Thanks to George Spelvin for doing the leg work to find a more efficient mixing function. Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: George Spelvin <linux@horizon.com>
Diffstat (limited to 'drivers/char/random.c')
-rw-r--r--drivers/char/random.c92
1 files changed, 68 insertions, 24 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c
index dfe918a21e32..d3bb7927fb49 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -267,6 +267,8 @@
267#define CREATE_TRACE_POINTS 267#define CREATE_TRACE_POINTS
268#include <trace/events/random.h> 268#include <trace/events/random.h>
269 269
270/* #define ADD_INTERRUPT_BENCH */
271
270/* 272/*
271 * Configuration information 273 * Configuration information
272 */ 274 */
@@ -558,25 +560,29 @@ struct fast_pool {
558 * collector. It's hardcoded for an 128 bit pool and assumes that any 560 * collector. It's hardcoded for an 128 bit pool and assumes that any
559 * locks that might be needed are taken by the caller. 561 * locks that might be needed are taken by the caller.
560 */ 562 */
561static void fast_mix(struct fast_pool *f, __u32 input[4]) 563static void fast_mix(struct fast_pool *f)
562{ 564{
563 __u32 w; 565 __u32 a = f->pool[0], b = f->pool[1];
564 unsigned input_rotate = f->rotate; 566 __u32 c = f->pool[2], d = f->pool[3];
565 567
566 w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3]; 568 a += b; c += d;
567 f->pool[0] = (w >> 3) ^ twist_table[w & 7]; 569 b = rol32(a, 6); d = rol32(c, 27);
568 input_rotate = (input_rotate + 14) & 31; 570 d ^= a; b ^= c;
569 w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0]; 571
570 f->pool[1] = (w >> 3) ^ twist_table[w & 7]; 572 a += b; c += d;
571 input_rotate = (input_rotate + 7) & 31; 573 b = rol32(a, 16); d = rol32(c, 14);
572 w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1]; 574 d ^= a; b ^= c;
573 f->pool[2] = (w >> 3) ^ twist_table[w & 7]; 575
574 input_rotate = (input_rotate + 7) & 31; 576 a += b; c += d;
575 w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2]; 577 b = rol32(a, 6); d = rol32(c, 27);
576 f->pool[3] = (w >> 3) ^ twist_table[w & 7]; 578 d ^= a; b ^= c;
577 input_rotate = (input_rotate + 7) & 31; 579
578 580 a += b; c += d;
579 f->rotate = input_rotate; 581 b = rol32(a, 16); d = rol32(c, 14);
582 d ^= a; b ^= c;
583
584 f->pool[0] = a; f->pool[1] = b;
585 f->pool[2] = c; f->pool[3] = d;
580 f->count++; 586 f->count++;
581} 587}
582 588
@@ -829,6 +835,27 @@ EXPORT_SYMBOL_GPL(add_input_randomness);
829 835
830static DEFINE_PER_CPU(struct fast_pool, irq_randomness); 836static DEFINE_PER_CPU(struct fast_pool, irq_randomness);
831 837
838#ifdef ADD_INTERRUPT_BENCH
839static unsigned long avg_cycles, avg_deviation;
840
841#define AVG_SHIFT 8 /* Exponential average factor k=1/256 */
842#define FIXED_1_2 (1 << (AVG_SHIFT-1))
843
844static void add_interrupt_bench(cycles_t start)
845{
846 long delta = random_get_entropy() - start;
847
848 /* Use a weighted moving average */
849 delta = delta - ((avg_cycles + FIXED_1_2) >> AVG_SHIFT);
850 avg_cycles += delta;
851 /* And average deviation */
852 delta = abs(delta) - ((avg_deviation + FIXED_1_2) >> AVG_SHIFT);
853 avg_deviation += delta;
854}
855#else
856#define add_interrupt_bench(x)
857#endif
858
832void add_interrupt_randomness(int irq, int irq_flags) 859void add_interrupt_randomness(int irq, int irq_flags)
833{ 860{
834 struct entropy_store *r; 861 struct entropy_store *r;
@@ -836,22 +863,23 @@ void add_interrupt_randomness(int irq, int irq_flags)
836 struct pt_regs *regs = get_irq_regs(); 863 struct pt_regs *regs = get_irq_regs();
837 unsigned long now = jiffies; 864 unsigned long now = jiffies;
838 cycles_t cycles = random_get_entropy(); 865 cycles_t cycles = random_get_entropy();
839 __u32 input[4], c_high, j_high; 866 __u32 c_high, j_high;
840 __u64 ip; 867 __u64 ip;
841 unsigned long seed; 868 unsigned long seed;
842 int credit = 0; 869 int credit = 0;
843 870
844 c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; 871 c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
845 j_high = (sizeof(now) > 4) ? now >> 32 : 0; 872 j_high = (sizeof(now) > 4) ? now >> 32 : 0;
846 input[0] = cycles ^ j_high ^ irq; 873 fast_pool->pool[0] ^= cycles ^ j_high ^ irq;
847 input[1] = now ^ c_high; 874 fast_pool->pool[1] ^= now ^ c_high;
848 ip = regs ? instruction_pointer(regs) : _RET_IP_; 875 ip = regs ? instruction_pointer(regs) : _RET_IP_;
849 input[2] = ip; 876 fast_pool->pool[2] ^= ip;
850 input[3] = ip >> 32; 877 fast_pool->pool[3] ^= ip >> 32;
851 878
852 fast_mix(fast_pool, input); 879 fast_mix(fast_pool);
853 if ((irq_flags & __IRQF_TIMER) == 0) 880 if ((irq_flags & __IRQF_TIMER) == 0)
854 fast_pool->notimer_count++; 881 fast_pool->notimer_count++;
882 add_interrupt_bench(cycles);
855 883
856 if (cycles) { 884 if (cycles) {
857 if ((fast_pool->count < 64) && 885 if ((fast_pool->count < 64) &&
@@ -1650,6 +1678,22 @@ struct ctl_table random_table[] = {
1650 .mode = 0444, 1678 .mode = 0444,
1651 .proc_handler = proc_do_uuid, 1679 .proc_handler = proc_do_uuid,
1652 }, 1680 },
1681#ifdef ADD_INTERRUPT_BENCH
1682 {
1683 .procname = "add_interrupt_avg_cycles",
1684 .data = &avg_cycles,
1685 .maxlen = sizeof(avg_cycles),
1686 .mode = 0444,
1687 .proc_handler = proc_doulongvec_minmax,
1688 },
1689 {
1690 .procname = "add_interrupt_avg_deviation",
1691 .data = &avg_deviation,
1692 .maxlen = sizeof(avg_deviation),
1693 .mode = 0444,
1694 .proc_handler = proc_doulongvec_minmax,
1695 },
1696#endif
1653 { } 1697 { }
1654}; 1698};
1655#endif /* CONFIG_SYSCTL */ 1699#endif /* CONFIG_SYSCTL */