diff options
-rw-r--r-- | drivers/char/hw_random/amd-rng.c | 12 | ||||
-rw-r--r-- | drivers/char/hw_random/core.c | 24 | ||||
-rw-r--r-- | drivers/char/hw_random/geode-rng.c | 12 | ||||
-rw-r--r-- | drivers/char/hw_random/intel-rng.c | 15 | ||||
-rw-r--r-- | drivers/char/hw_random/omap-rng.c | 13 | ||||
-rw-r--r-- | drivers/char/hw_random/pasemi-rng.c | 14 | ||||
-rw-r--r-- | drivers/char/hw_random/via-rng.c | 19 | ||||
-rw-r--r-- | include/linux/hw_random.h | 2 |
8 files changed, 73 insertions, 38 deletions
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 556fd81fa815..c422e870dc52 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/hw_random.h> | 30 | #include <linux/hw_random.h> |
31 | #include <linux/delay.h> | ||
31 | #include <asm/io.h> | 32 | #include <asm/io.h> |
32 | 33 | ||
33 | 34 | ||
@@ -52,11 +53,18 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); | |||
52 | static struct pci_dev *amd_pdev; | 53 | static struct pci_dev *amd_pdev; |
53 | 54 | ||
54 | 55 | ||
55 | static int amd_rng_data_present(struct hwrng *rng) | 56 | static int amd_rng_data_present(struct hwrng *rng, int wait) |
56 | { | 57 | { |
57 | u32 pmbase = (u32)rng->priv; | 58 | u32 pmbase = (u32)rng->priv; |
59 | int data, i; | ||
58 | 60 | ||
59 | return !!(inl(pmbase + 0xF4) & 1); | 61 | for (i = 0; i < 20; i++) { |
62 | data = !!(inl(pmbase + 0xF4) & 1); | ||
63 | if (data || !wait) | ||
64 | break; | ||
65 | udelay(10); | ||
66 | } | ||
67 | return data; | ||
60 | } | 68 | } |
61 | 69 | ||
62 | static int amd_rng_data_read(struct hwrng *rng, u32 *data) | 70 | static int amd_rng_data_read(struct hwrng *rng, u32 *data) |
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 26a860adcb38..0118b9817a95 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c | |||
@@ -66,11 +66,11 @@ static inline void hwrng_cleanup(struct hwrng *rng) | |||
66 | rng->cleanup(rng); | 66 | rng->cleanup(rng); |
67 | } | 67 | } |
68 | 68 | ||
69 | static inline int hwrng_data_present(struct hwrng *rng) | 69 | static inline int hwrng_data_present(struct hwrng *rng, int wait) |
70 | { | 70 | { |
71 | if (!rng->data_present) | 71 | if (!rng->data_present) |
72 | return 1; | 72 | return 1; |
73 | return rng->data_present(rng); | 73 | return rng->data_present(rng, wait); |
74 | } | 74 | } |
75 | 75 | ||
76 | static inline int hwrng_data_read(struct hwrng *rng, u32 *data) | 76 | static inline int hwrng_data_read(struct hwrng *rng, u32 *data) |
@@ -94,8 +94,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, | |||
94 | { | 94 | { |
95 | u32 data; | 95 | u32 data; |
96 | ssize_t ret = 0; | 96 | ssize_t ret = 0; |
97 | int i, err = 0; | 97 | int err = 0; |
98 | int data_present; | ||
99 | int bytes_read; | 98 | int bytes_read; |
100 | 99 | ||
101 | while (size) { | 100 | while (size) { |
@@ -107,21 +106,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, | |||
107 | err = -ENODEV; | 106 | err = -ENODEV; |
108 | goto out; | 107 | goto out; |
109 | } | 108 | } |
110 | if (filp->f_flags & O_NONBLOCK) { | 109 | |
111 | data_present = hwrng_data_present(current_rng); | ||
112 | } else { | ||
113 | /* Some RNG require some time between data_reads to gather | ||
114 | * new entropy. Poll it. | ||
115 | */ | ||
116 | for (i = 0; i < 20; i++) { | ||
117 | data_present = hwrng_data_present(current_rng); | ||
118 | if (data_present) | ||
119 | break; | ||
120 | udelay(10); | ||
121 | } | ||
122 | } | ||
123 | bytes_read = 0; | 110 | bytes_read = 0; |
124 | if (data_present) | 111 | if (hwrng_data_present(current_rng, |
112 | !(filp->f_flags & O_NONBLOCK))) | ||
125 | bytes_read = hwrng_data_read(current_rng, &data); | 113 | bytes_read = hwrng_data_read(current_rng, &data); |
126 | mutex_unlock(&rng_mutex); | 114 | mutex_unlock(&rng_mutex); |
127 | 115 | ||
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index 8e8658dcd2e3..fed4ef5569f5 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/hw_random.h> | 30 | #include <linux/hw_random.h> |
31 | #include <linux/delay.h> | ||
31 | #include <asm/io.h> | 32 | #include <asm/io.h> |
32 | 33 | ||
33 | 34 | ||
@@ -61,11 +62,18 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data) | |||
61 | return 4; | 62 | return 4; |
62 | } | 63 | } |
63 | 64 | ||
64 | static int geode_rng_data_present(struct hwrng *rng) | 65 | static int geode_rng_data_present(struct hwrng *rng, int wait) |
65 | { | 66 | { |
66 | void __iomem *mem = (void __iomem *)rng->priv; | 67 | void __iomem *mem = (void __iomem *)rng->priv; |
68 | int data, i; | ||
67 | 69 | ||
68 | return !!(readl(mem + GEODE_RNG_STATUS_REG)); | 70 | for (i = 0; i < 20; i++) { |
71 | data = !!(readl(mem + GEODE_RNG_STATUS_REG)); | ||
72 | if (data || !wait) | ||
73 | break; | ||
74 | udelay(10); | ||
75 | } | ||
76 | return data; | ||
69 | } | 77 | } |
70 | 78 | ||
71 | 79 | ||
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 753f46052b87..5cc651ef75eb 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
31 | #include <linux/stop_machine.h> | 31 | #include <linux/stop_machine.h> |
32 | #include <linux/delay.h> | ||
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | 34 | ||
34 | 35 | ||
@@ -162,11 +163,19 @@ static inline u8 hwstatus_set(void __iomem *mem, | |||
162 | return hwstatus_get(mem); | 163 | return hwstatus_get(mem); |
163 | } | 164 | } |
164 | 165 | ||
165 | static int intel_rng_data_present(struct hwrng *rng) | 166 | static int intel_rng_data_present(struct hwrng *rng, int wait) |
166 | { | 167 | { |
167 | void __iomem *mem = (void __iomem *)rng->priv; | 168 | void __iomem *mem = (void __iomem *)rng->priv; |
168 | 169 | int data, i; | |
169 | return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT); | 170 | |
171 | for (i = 0; i < 20; i++) { | ||
172 | data = !!(readb(mem + INTEL_RNG_STATUS) & | ||
173 | INTEL_RNG_DATA_PRESENT); | ||
174 | if (data || !wait) | ||
175 | break; | ||
176 | udelay(10); | ||
177 | } | ||
178 | return data; | ||
170 | } | 179 | } |
171 | 180 | ||
172 | static int intel_rng_data_read(struct hwrng *rng, u32 *data) | 181 | static int intel_rng_data_read(struct hwrng *rng, u32 *data) |
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 3f35a1c562b1..7e319951fa41 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/err.h> | 29 | #include <linux/err.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/hw_random.h> | 31 | #include <linux/hw_random.h> |
32 | #include <linux/delay.h> | ||
32 | 33 | ||
33 | #include <asm/io.h> | 34 | #include <asm/io.h> |
34 | 35 | ||
@@ -65,9 +66,17 @@ static void omap_rng_write_reg(int reg, u32 val) | |||
65 | } | 66 | } |
66 | 67 | ||
67 | /* REVISIT: Does the status bit really work on 16xx? */ | 68 | /* REVISIT: Does the status bit really work on 16xx? */ |
68 | static int omap_rng_data_present(struct hwrng *rng) | 69 | static int omap_rng_data_present(struct hwrng *rng, int wait) |
69 | { | 70 | { |
70 | return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; | 71 | int data, i; |
72 | |||
73 | for (i = 0; i < 20; i++) { | ||
74 | data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; | ||
75 | if (data || !wait) | ||
76 | break; | ||
77 | udelay(10); | ||
78 | } | ||
79 | return data; | ||
71 | } | 80 | } |
72 | 81 | ||
73 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) | 82 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) |
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index fa6040b6c8f2..621adf25e580 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/hw_random.h> | 25 | #include <linux/hw_random.h> |
26 | #include <linux/delay.h> | ||
26 | #include <asm/of_platform.h> | 27 | #include <asm/of_platform.h> |
27 | #include <asm/io.h> | 28 | #include <asm/io.h> |
28 | 29 | ||
@@ -44,9 +45,16 @@ | |||
44 | static int pasemi_rng_data_present(struct hwrng *rng) | 45 | static int pasemi_rng_data_present(struct hwrng *rng) |
45 | { | 46 | { |
46 | void __iomem *rng_regs = (void __iomem *)rng->priv; | 47 | void __iomem *rng_regs = (void __iomem *)rng->priv; |
47 | 48 | int data, i; | |
48 | return (in_le32(rng_regs + SDCRNG_CTL_REG) | 49 | |
49 | & SDCRNG_CTL_FVLD_M) ? 1 : 0; | 50 | for (i = 0; i < 20; i++) { |
51 | data = (in_le32(rng_regs + SDCRNG_CTL_REG) | ||
52 | & SDCRNG_CTL_FVLD_M) ? 1 : 0; | ||
53 | if (data || !wait) | ||
54 | break; | ||
55 | udelay(10); | ||
56 | } | ||
57 | return data; | ||
50 | } | 58 | } |
51 | 59 | ||
52 | static int pasemi_rng_data_read(struct hwrng *rng, u32 *data) | 60 | static int pasemi_rng_data_read(struct hwrng *rng, u32 *data) |
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index ec435cb25c4f..868e39fd42e4 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | #include <linux/hw_random.h> | 29 | #include <linux/hw_random.h> |
30 | #include <linux/delay.h> | ||
30 | #include <asm/io.h> | 31 | #include <asm/io.h> |
31 | #include <asm/msr.h> | 32 | #include <asm/msr.h> |
32 | #include <asm/cpufeature.h> | 33 | #include <asm/cpufeature.h> |
@@ -77,10 +78,11 @@ static inline u32 xstore(u32 *addr, u32 edx_in) | |||
77 | return eax_out; | 78 | return eax_out; |
78 | } | 79 | } |
79 | 80 | ||
80 | static int via_rng_data_present(struct hwrng *rng) | 81 | static int via_rng_data_present(struct hwrng *rng, int wait) |
81 | { | 82 | { |
82 | u32 bytes_out; | 83 | u32 bytes_out; |
83 | u32 *via_rng_datum = (u32 *)(&rng->priv); | 84 | u32 *via_rng_datum = (u32 *)(&rng->priv); |
85 | int i; | ||
84 | 86 | ||
85 | /* We choose the recommended 1-byte-per-instruction RNG rate, | 87 | /* We choose the recommended 1-byte-per-instruction RNG rate, |
86 | * for greater randomness at the expense of speed. Larger | 88 | * for greater randomness at the expense of speed. Larger |
@@ -95,12 +97,15 @@ static int via_rng_data_present(struct hwrng *rng) | |||
95 | * completes. | 97 | * completes. |
96 | */ | 98 | */ |
97 | 99 | ||
98 | *via_rng_datum = 0; /* paranoia, not really necessary */ | 100 | for (i = 0; i < 20; i++) { |
99 | bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); | 101 | *via_rng_datum = 0; /* paranoia, not really necessary */ |
100 | bytes_out &= VIA_XSTORE_CNT_MASK; | 102 | bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); |
101 | if (bytes_out == 0) | 103 | bytes_out &= VIA_XSTORE_CNT_MASK; |
102 | return 0; | 104 | if (bytes_out || !wait) |
103 | return 1; | 105 | break; |
106 | udelay(10); | ||
107 | } | ||
108 | return bytes_out ? 1 : 0; | ||
104 | } | 109 | } |
105 | 110 | ||
106 | static int via_rng_data_read(struct hwrng *rng, u32 *data) | 111 | static int via_rng_data_read(struct hwrng *rng, u32 *data) |
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h index 21ea7610e177..85d11916e9ea 100644 --- a/include/linux/hw_random.h +++ b/include/linux/hw_random.h | |||
@@ -33,7 +33,7 @@ struct hwrng { | |||
33 | const char *name; | 33 | const char *name; |
34 | int (*init)(struct hwrng *rng); | 34 | int (*init)(struct hwrng *rng); |
35 | void (*cleanup)(struct hwrng *rng); | 35 | void (*cleanup)(struct hwrng *rng); |
36 | int (*data_present)(struct hwrng *rng); | 36 | int (*data_present)(struct hwrng *rng, int wait); |
37 | int (*data_read)(struct hwrng *rng, u32 *data); | 37 | int (*data_read)(struct hwrng *rng, u32 *data); |
38 | unsigned long priv; | 38 | unsigned long priv; |
39 | 39 | ||