aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hw_random
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 06:44:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 06:44:48 -0400
commit87d7bcee4f5973a593b0d50134364cfe5652ff33 (patch)
tree677125896b64de2f5acfa204955442f58e74cfa9 /drivers/char/hw_random
parent0223f9aaef94a09ffc0b6abcba732e62a483b88c (diff)
parentbe34c4ef693ff5c10f55606dbd656ddf0b4a8340 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto update from Herbert Xu: - add multibuffer infrastructure (single_task_running scheduler helper, OKed by Peter on lkml. - add SHA1 multibuffer implementation for AVX2. - reenable "by8" AVX CTR optimisation after fixing counter overflow. - add APM X-Gene SoC RNG support. - SHA256/SHA512 now handles unaligned input correctly. - set lz4 decompressed length correctly. - fix algif socket buffer allocation failure for 64K page machines. - misc fixes * git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (47 commits) crypto: sha - Handle unaligned input data in generic sha256 and sha512. Revert "crypto: aesni - disable "by8" AVX CTR optimization" crypto: aesni - remove unused defines in "by8" variant crypto: aesni - fix counter overflow handling in "by8" variant hwrng: printk replacement crypto: qat - Removed unneeded partial state crypto: qat - Fix typo in name of tasklet_struct crypto: caam - Dynamic allocation of addresses for various memory blocks in CAAM. crypto: mcryptd - Fix typos in CRYPTO_MCRYPTD description crypto: algif - avoid excessive use of socket buffer in skcipher arm64: dts: add random number generator dts node to APM X-Gene platform. Documentation: rng: Add X-Gene SoC RNG driver documentation hwrng: xgene - add support for APM X-Gene SoC RNG support crypto: mv_cesa - Add missing #define crypto: testmgr - add test for lz4 and lz4hc crypto: lz4,lz4hc - fix decompression crypto: qat - Use pci_enable_msix_exact() instead of pci_enable_msix() crypto: drbg - fix maximum value checks on 32 bit systems crypto: drbg - fix sparse warning for cpu_to_be[32|64] crypto: sha-mb - sha1_mb_alg_state can be static ...
Diffstat (limited to 'drivers/char/hw_random')
-rw-r--r--drivers/char/hw_random/Kconfig13
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/amd-rng.c4
-rw-r--r--drivers/char/hw_random/geode-rng.c4
-rw-r--r--drivers/char/hw_random/intel-rng.c13
-rw-r--r--drivers/char/hw_random/pasemi-rng.c2
-rw-r--r--drivers/char/hw_random/pseries-rng.c2
-rw-r--r--drivers/char/hw_random/via-rng.c8
-rw-r--r--drivers/char/hw_random/xgene-rng.c423
9 files changed, 453 insertions, 17 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 836b061ced35..91a04ae8003c 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -333,6 +333,19 @@ config HW_RANDOM_MSM
333 333
334 If unsure, say Y. 334 If unsure, say Y.
335 335
336config HW_RANDOM_XGENE
337 tristate "APM X-Gene True Random Number Generator (TRNG) support"
338 depends on HW_RANDOM && ARCH_XGENE
339 default HW_RANDOM
340 ---help---
341 This driver provides kernel-side support for the Random Number
342 Generator hardware found on APM X-Gene SoC.
343
344 To compile this driver as a module, choose M here: the
345 module will be called xgene_rng.
346
347 If unsure, say Y.
348
336endif # HW_RANDOM 349endif # HW_RANDOM
337 350
338config UML_RANDOM 351config UML_RANDOM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 199ed283e149..0b4cd57f4e24 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
29obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o 29obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
30obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o 30obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
31obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o 31obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
32obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index c6af038682f1..48f6a83cdd61 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -142,10 +142,10 @@ found:
142 amd_rng.priv = (unsigned long)pmbase; 142 amd_rng.priv = (unsigned long)pmbase;
143 amd_pdev = pdev; 143 amd_pdev = pdev;
144 144
145 printk(KERN_INFO "AMD768 RNG detected\n"); 145 pr_info("AMD768 RNG detected\n");
146 err = hwrng_register(&amd_rng); 146 err = hwrng_register(&amd_rng);
147 if (err) { 147 if (err) {
148 printk(KERN_ERR PFX "RNG registering failed (%d)\n", 148 pr_err(PFX "RNG registering failed (%d)\n",
149 err); 149 err);
150 release_region(pmbase + 0xF0, 8); 150 release_region(pmbase + 0xF0, 8);
151 goto out; 151 goto out;
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index 4c4d4e140f98..0d0579fe465e 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -109,10 +109,10 @@ found:
109 goto out; 109 goto out;
110 geode_rng.priv = (unsigned long)mem; 110 geode_rng.priv = (unsigned long)mem;
111 111
112 printk(KERN_INFO "AMD Geode RNG detected\n"); 112 pr_info("AMD Geode RNG detected\n");
113 err = hwrng_register(&geode_rng); 113 err = hwrng_register(&geode_rng);
114 if (err) { 114 if (err) {
115 printk(KERN_ERR PFX "RNG registering failed (%d)\n", 115 pr_err(PFX "RNG registering failed (%d)\n",
116 err); 116 err);
117 goto err_unmap; 117 goto err_unmap;
118 } 118 }
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 86fe45c19968..290c880266bf 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -199,7 +199,7 @@ static int intel_rng_init(struct hwrng *rng)
199 if ((hw_status & INTEL_RNG_ENABLED) == 0) 199 if ((hw_status & INTEL_RNG_ENABLED) == 0)
200 hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED); 200 hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED);
201 if ((hw_status & INTEL_RNG_ENABLED) == 0) { 201 if ((hw_status & INTEL_RNG_ENABLED) == 0) {
202 printk(KERN_ERR PFX "cannot enable RNG, aborting\n"); 202 pr_err(PFX "cannot enable RNG, aborting\n");
203 goto out; 203 goto out;
204 } 204 }
205 err = 0; 205 err = 0;
@@ -216,7 +216,7 @@ static void intel_rng_cleanup(struct hwrng *rng)
216 if (hw_status & INTEL_RNG_ENABLED) 216 if (hw_status & INTEL_RNG_ENABLED)
217 hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED); 217 hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED);
218 else 218 else
219 printk(KERN_WARNING PFX "unusual: RNG already disabled\n"); 219 pr_warn(PFX "unusual: RNG already disabled\n");
220} 220}
221 221
222 222
@@ -274,7 +274,7 @@ static int __init intel_rng_hw_init(void *_intel_rng_hw)
274 if (mfc != INTEL_FWH_MANUFACTURER_CODE || 274 if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
275 (dvc != INTEL_FWH_DEVICE_CODE_8M && 275 (dvc != INTEL_FWH_DEVICE_CODE_8M &&
276 dvc != INTEL_FWH_DEVICE_CODE_4M)) { 276 dvc != INTEL_FWH_DEVICE_CODE_4M)) {
277 printk(KERN_NOTICE PFX "FWH not detected\n"); 277 pr_notice(PFX "FWH not detected\n");
278 return -ENODEV; 278 return -ENODEV;
279 } 279 }
280 280
@@ -306,7 +306,6 @@ static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
306 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)) 306 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
307 == BIOS_CNTL_LOCK_ENABLE_MASK) { 307 == BIOS_CNTL_LOCK_ENABLE_MASK) {
308 static __initdata /*const*/ char warning[] = 308 static __initdata /*const*/ char warning[] =
309 KERN_WARNING
310PFX "Firmware space is locked read-only. If you can't or\n" 309PFX "Firmware space is locked read-only. If you can't or\n"
311PFX "don't want to disable this in firmware setup, and if\n" 310PFX "don't want to disable this in firmware setup, and if\n"
312PFX "you are certain that your system has a functional\n" 311PFX "you are certain that your system has a functional\n"
@@ -314,7 +313,7 @@ PFX "RNG, try using the 'no_fwh_detect' option.\n";
314 313
315 if (no_fwh_detect) 314 if (no_fwh_detect)
316 return -ENODEV; 315 return -ENODEV;
317 printk(warning); 316 pr_warn("%s", warning);
318 return -EBUSY; 317 return -EBUSY;
319 } 318 }
320 319
@@ -392,10 +391,10 @@ fwh_done:
392 goto out; 391 goto out;
393 } 392 }
394 393
395 printk(KERN_INFO "Intel 82802 RNG detected\n"); 394 pr_info("Intel 82802 RNG detected\n");
396 err = hwrng_register(&intel_rng); 395 err = hwrng_register(&intel_rng);
397 if (err) { 396 if (err) {
398 printk(KERN_ERR PFX "RNG registering failed (%d)\n", 397 pr_err(PFX "RNG registering failed (%d)\n",
399 err); 398 err);
400 iounmap(mem); 399 iounmap(mem);
401 } 400 }
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index c66279bb6ef3..c0347d1dded0 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -113,7 +113,7 @@ static int rng_probe(struct platform_device *ofdev)
113 113
114 pasemi_rng.priv = (unsigned long)rng_regs; 114 pasemi_rng.priv = (unsigned long)rng_regs;
115 115
116 printk(KERN_INFO "Registering PA Semi RNG\n"); 116 pr_info("Registering PA Semi RNG\n");
117 117
118 err = hwrng_register(&pasemi_rng); 118 err = hwrng_register(&pasemi_rng);
119 119
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
index ab7ffdec0ec3..6226aa08c36a 100644
--- a/drivers/char/hw_random/pseries-rng.c
+++ b/drivers/char/hw_random/pseries-rng.c
@@ -86,7 +86,7 @@ static struct vio_driver pseries_rng_driver = {
86 86
87static int __init rng_init(void) 87static int __init rng_init(void)
88{ 88{
89 printk(KERN_INFO "Registering IBM pSeries RNG driver\n"); 89 pr_info("Registering IBM pSeries RNG driver\n");
90 return vio_register_driver(&pseries_rng_driver); 90 return vio_register_driver(&pseries_rng_driver);
91} 91}
92 92
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index de5a6dcfb3e2..a3bebef255ad 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -141,7 +141,7 @@ static int via_rng_init(struct hwrng *rng)
141 * register */ 141 * register */
142 if ((c->x86 == 6) && (c->x86_model >= 0x0f)) { 142 if ((c->x86 == 6) && (c->x86_model >= 0x0f)) {
143 if (!cpu_has_xstore_enabled) { 143 if (!cpu_has_xstore_enabled) {
144 printk(KERN_ERR PFX "can't enable hardware RNG " 144 pr_err(PFX "can't enable hardware RNG "
145 "if XSTORE is not enabled\n"); 145 "if XSTORE is not enabled\n");
146 return -ENODEV; 146 return -ENODEV;
147 } 147 }
@@ -180,7 +180,7 @@ static int via_rng_init(struct hwrng *rng)
180 unneeded */ 180 unneeded */
181 rdmsr(MSR_VIA_RNG, lo, hi); 181 rdmsr(MSR_VIA_RNG, lo, hi);
182 if ((lo & VIA_RNG_ENABLE) == 0) { 182 if ((lo & VIA_RNG_ENABLE) == 0) {
183 printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n"); 183 pr_err(PFX "cannot enable VIA C3 RNG, aborting\n");
184 return -ENODEV; 184 return -ENODEV;
185 } 185 }
186 186
@@ -202,10 +202,10 @@ static int __init mod_init(void)
202 202
203 if (!cpu_has_xstore) 203 if (!cpu_has_xstore)
204 return -ENODEV; 204 return -ENODEV;
205 printk(KERN_INFO "VIA RNG detected\n"); 205 pr_info("VIA RNG detected\n");
206 err = hwrng_register(&via_rng); 206 err = hwrng_register(&via_rng);
207 if (err) { 207 if (err) {
208 printk(KERN_ERR PFX "RNG registering failed (%d)\n", 208 pr_err(PFX "RNG registering failed (%d)\n",
209 err); 209 err);
210 goto out; 210 goto out;
211 } 211 }
diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c
new file mode 100644
index 000000000000..23caa05380a8
--- /dev/null
+++ b/drivers/char/hw_random/xgene-rng.c
@@ -0,0 +1,423 @@
1/*
2 * APM X-Gene SoC RNG Driver
3 *
4 * Copyright (c) 2014, Applied Micro Circuits Corporation
5 * Author: Rameshwar Prasad Sahu <rsahu@apm.com>
6 * Shamal Winchurkar <swinchurkar@apm.com>
7 * Feng Kan <fkan@apm.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <linux/clk.h>
25#include <linux/delay.h>
26#include <linux/hw_random.h>
27#include <linux/init.h>
28#include <linux/interrupt.h>
29#include <linux/module.h>
30#include <linux/of_platform.h>
31#include <linux/of_irq.h>
32#include <linux/of_address.h>
33#include <linux/timer.h>
34
35#define RNG_MAX_DATUM 4
36#define MAX_TRY 100
37#define XGENE_RNG_RETRY_COUNT 20
38#define XGENE_RNG_RETRY_INTERVAL 10
39
40/* RNG Registers */
41#define RNG_INOUT_0 0x00
42#define RNG_INTR_STS_ACK 0x10
43#define RNG_CONTROL 0x14
44#define RNG_CONFIG 0x18
45#define RNG_ALARMCNT 0x1c
46#define RNG_FROENABLE 0x20
47#define RNG_FRODETUNE 0x24
48#define RNG_ALARMMASK 0x28
49#define RNG_ALARMSTOP 0x2c
50#define RNG_OPTIONS 0x78
51#define RNG_EIP_REV 0x7c
52
53#define MONOBIT_FAIL_MASK BIT(7)
54#define POKER_FAIL_MASK BIT(6)
55#define LONG_RUN_FAIL_MASK BIT(5)
56#define RUN_FAIL_MASK BIT(4)
57#define NOISE_FAIL_MASK BIT(3)
58#define STUCK_OUT_MASK BIT(2)
59#define SHUTDOWN_OFLO_MASK BIT(1)
60#define READY_MASK BIT(0)
61
62#define MAJOR_HW_REV_RD(src) (((src) & 0x0f000000) >> 24)
63#define MINOR_HW_REV_RD(src) (((src) & 0x00f00000) >> 20)
64#define HW_PATCH_LEVEL_RD(src) (((src) & 0x000f0000) >> 16)
65#define MAX_REFILL_CYCLES_SET(dst, src) \
66 ((dst & ~0xffff0000) | (((u32)src << 16) & 0xffff0000))
67#define MIN_REFILL_CYCLES_SET(dst, src) \
68 ((dst & ~0x000000ff) | (((u32)src) & 0x000000ff))
69#define ALARM_THRESHOLD_SET(dst, src) \
70 ((dst & ~0x000000ff) | (((u32)src) & 0x000000ff))
71#define ENABLE_RNG_SET(dst, src) \
72 ((dst & ~BIT(10)) | (((u32)src << 10) & BIT(10)))
73#define REGSPEC_TEST_MODE_SET(dst, src) \
74 ((dst & ~BIT(8)) | (((u32)src << 8) & BIT(8)))
75#define MONOBIT_FAIL_MASK_SET(dst, src) \
76 ((dst & ~BIT(7)) | (((u32)src << 7) & BIT(7)))
77#define POKER_FAIL_MASK_SET(dst, src) \
78 ((dst & ~BIT(6)) | (((u32)src << 6) & BIT(6)))
79#define LONG_RUN_FAIL_MASK_SET(dst, src) \
80 ((dst & ~BIT(5)) | (((u32)src << 5) & BIT(5)))
81#define RUN_FAIL_MASK_SET(dst, src) \
82 ((dst & ~BIT(4)) | (((u32)src << 4) & BIT(4)))
83#define NOISE_FAIL_MASK_SET(dst, src) \
84 ((dst & ~BIT(3)) | (((u32)src << 3) & BIT(3)))
85#define STUCK_OUT_MASK_SET(dst, src) \
86 ((dst & ~BIT(2)) | (((u32)src << 2) & BIT(2)))
87#define SHUTDOWN_OFLO_MASK_SET(dst, src) \
88 ((dst & ~BIT(1)) | (((u32)src << 1) & BIT(1)))
89
90struct xgene_rng_dev {
91 u32 irq;
92 void __iomem *csr_base;
93 u32 revision;
94 u32 datum_size;
95 u32 failure_cnt; /* Failure count last minute */
96 unsigned long failure_ts;/* First failure timestamp */
97 struct timer_list failure_timer;
98 struct device *dev;
99 struct clk *clk;
100};
101
102static void xgene_rng_expired_timer(unsigned long arg)
103{
104 struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) arg;
105
106 /* Clear failure counter as timer expired */
107 disable_irq(ctx->irq);
108 ctx->failure_cnt = 0;
109 del_timer(&ctx->failure_timer);
110 enable_irq(ctx->irq);
111}
112
113static void xgene_rng_start_timer(struct xgene_rng_dev *ctx)
114{
115 ctx->failure_timer.data = (unsigned long) ctx;
116 ctx->failure_timer.function = xgene_rng_expired_timer;
117 ctx->failure_timer.expires = jiffies + 120 * HZ;
118 add_timer(&ctx->failure_timer);
119}
120
121/*
122 * Initialize or reinit free running oscillators (FROs)
123 */
124static void xgene_rng_init_fro(struct xgene_rng_dev *ctx, u32 fro_val)
125{
126 writel(fro_val, ctx->csr_base + RNG_FRODETUNE);
127 writel(0x00000000, ctx->csr_base + RNG_ALARMMASK);
128 writel(0x00000000, ctx->csr_base + RNG_ALARMSTOP);
129 writel(0xFFFFFFFF, ctx->csr_base + RNG_FROENABLE);
130}
131
132static void xgene_rng_chk_overflow(struct xgene_rng_dev *ctx)
133{
134 u32 val;
135
136 val = readl(ctx->csr_base + RNG_INTR_STS_ACK);
137 if (val & MONOBIT_FAIL_MASK)
138 /*
139 * LFSR detected an out-of-bounds number of 1s after
140 * checking 20,000 bits (test T1 as specified in the
141 * AIS-31 standard)
142 */
143 dev_err(ctx->dev, "test monobit failure error 0x%08X\n", val);
144 if (val & POKER_FAIL_MASK)
145 /*
146 * LFSR detected an out-of-bounds value in at least one
147 * of the 16 poker_count_X counters or an out of bounds sum
148 * of squares value after checking 20,000 bits (test T2 as
149 * specified in the AIS-31 standard)
150 */
151 dev_err(ctx->dev, "test poker failure error 0x%08X\n", val);
152 if (val & LONG_RUN_FAIL_MASK)
153 /*
154 * LFSR detected a sequence of 34 identical bits
155 * (test T4 as specified in the AIS-31 standard)
156 */
157 dev_err(ctx->dev, "test long run failure error 0x%08X\n", val);
158 if (val & RUN_FAIL_MASK)
159 /*
160 * LFSR detected an outof-bounds value for at least one
161 * of the running counters after checking 20,000 bits
162 * (test T3 as specified in the AIS-31 standard)
163 */
164 dev_err(ctx->dev, "test run failure error 0x%08X\n", val);
165 if (val & NOISE_FAIL_MASK)
166 /* LFSR detected a sequence of 48 identical bits */
167 dev_err(ctx->dev, "noise failure error 0x%08X\n", val);
168 if (val & STUCK_OUT_MASK)
169 /*
170 * Detected output data registers generated same value twice
171 * in a row
172 */
173 dev_err(ctx->dev, "stuck out failure error 0x%08X\n", val);
174
175 if (val & SHUTDOWN_OFLO_MASK) {
176 u32 frostopped;
177
178 /* FROs shut down after a second error event. Try recover. */
179 if (++ctx->failure_cnt == 1) {
180 /* 1st time, just recover */
181 ctx->failure_ts = jiffies;
182 frostopped = readl(ctx->csr_base + RNG_ALARMSTOP);
183 xgene_rng_init_fro(ctx, frostopped);
184
185 /*
186 * We must start a timer to clear out this error
187 * in case the system timer wrap around
188 */
189 xgene_rng_start_timer(ctx);
190 } else {
191 /* 2nd time failure in lesser than 1 minute? */
192 if (time_after(ctx->failure_ts + 60 * HZ, jiffies)) {
193 dev_err(ctx->dev,
194 "FRO shutdown failure error 0x%08X\n",
195 val);
196 } else {
197 /* 2nd time failure after 1 minutes, recover */
198 ctx->failure_ts = jiffies;
199 ctx->failure_cnt = 1;
200 /*
201 * We must start a timer to clear out this
202 * error in case the system timer wrap
203 * around
204 */
205 xgene_rng_start_timer(ctx);
206 }
207 frostopped = readl(ctx->csr_base + RNG_ALARMSTOP);
208 xgene_rng_init_fro(ctx, frostopped);
209 }
210 }
211 /* Clear them all */
212 writel(val, ctx->csr_base + RNG_INTR_STS_ACK);
213}
214
215static irqreturn_t xgene_rng_irq_handler(int irq, void *id)
216{
217 struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) id;
218
219 /* RNG Alarm Counter overflow */
220 xgene_rng_chk_overflow(ctx);
221
222 return IRQ_HANDLED;
223}
224
225static int xgene_rng_data_present(struct hwrng *rng, int wait)
226{
227 struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv;
228 u32 i, val = 0;
229
230 for (i = 0; i < XGENE_RNG_RETRY_COUNT; i++) {
231 val = readl(ctx->csr_base + RNG_INTR_STS_ACK);
232 if ((val & READY_MASK) || !wait)
233 break;
234 udelay(XGENE_RNG_RETRY_INTERVAL);
235 }
236
237 return (val & READY_MASK);
238}
239
240static int xgene_rng_data_read(struct hwrng *rng, u32 *data)
241{
242 struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv;
243 int i;
244
245 for (i = 0; i < ctx->datum_size; i++)
246 data[i] = readl(ctx->csr_base + RNG_INOUT_0 + i * 4);
247
248 /* Clear ready bit to start next transaction */
249 writel(READY_MASK, ctx->csr_base + RNG_INTR_STS_ACK);
250
251 return ctx->datum_size << 2;
252}
253
254static void xgene_rng_init_internal(struct xgene_rng_dev *ctx)
255{
256 u32 val;
257
258 writel(0x00000000, ctx->csr_base + RNG_CONTROL);
259
260 val = MAX_REFILL_CYCLES_SET(0, 10);
261 val = MIN_REFILL_CYCLES_SET(val, 10);
262 writel(val, ctx->csr_base + RNG_CONFIG);
263
264 val = ALARM_THRESHOLD_SET(0, 0xFF);
265 writel(val, ctx->csr_base + RNG_ALARMCNT);
266
267 xgene_rng_init_fro(ctx, 0);
268
269 writel(MONOBIT_FAIL_MASK |
270 POKER_FAIL_MASK |
271 LONG_RUN_FAIL_MASK |
272 RUN_FAIL_MASK |
273 NOISE_FAIL_MASK |
274 STUCK_OUT_MASK |
275 SHUTDOWN_OFLO_MASK |
276 READY_MASK, ctx->csr_base + RNG_INTR_STS_ACK);
277
278 val = ENABLE_RNG_SET(0, 1);
279 val = MONOBIT_FAIL_MASK_SET(val, 1);
280 val = POKER_FAIL_MASK_SET(val, 1);
281 val = LONG_RUN_FAIL_MASK_SET(val, 1);
282 val = RUN_FAIL_MASK_SET(val, 1);
283 val = NOISE_FAIL_MASK_SET(val, 1);
284 val = STUCK_OUT_MASK_SET(val, 1);
285 val = SHUTDOWN_OFLO_MASK_SET(val, 1);
286 writel(val, ctx->csr_base + RNG_CONTROL);
287}
288
289static int xgene_rng_init(struct hwrng *rng)
290{
291 struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv;
292
293 ctx->failure_cnt = 0;
294 init_timer(&ctx->failure_timer);
295
296 ctx->revision = readl(ctx->csr_base + RNG_EIP_REV);
297
298 dev_dbg(ctx->dev, "Rev %d.%d.%d\n",
299 MAJOR_HW_REV_RD(ctx->revision),
300 MINOR_HW_REV_RD(ctx->revision),
301 HW_PATCH_LEVEL_RD(ctx->revision));
302
303 dev_dbg(ctx->dev, "Options 0x%08X",
304 readl(ctx->csr_base + RNG_OPTIONS));
305
306 xgene_rng_init_internal(ctx);
307
308 ctx->datum_size = RNG_MAX_DATUM;
309
310 return 0;
311}
312
313static struct hwrng xgene_rng_func = {
314 .name = "xgene-rng",
315 .init = xgene_rng_init,
316 .data_present = xgene_rng_data_present,
317 .data_read = xgene_rng_data_read,
318};
319
320static int xgene_rng_probe(struct platform_device *pdev)
321{
322 struct resource *res;
323 struct xgene_rng_dev *ctx;
324 int rc = 0;
325
326 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
327 if (!ctx)
328 return -ENOMEM;
329
330 ctx->dev = &pdev->dev;
331 platform_set_drvdata(pdev, ctx);
332
333 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
334 ctx->csr_base = devm_ioremap_resource(&pdev->dev, res);
335 if (IS_ERR(ctx->csr_base))
336 return PTR_ERR(ctx->csr_base);
337
338 ctx->irq = platform_get_irq(pdev, 0);
339 if (ctx->irq < 0) {
340 dev_err(&pdev->dev, "No IRQ resource\n");
341 return ctx->irq;
342 }
343
344 dev_dbg(&pdev->dev, "APM X-Gene RNG BASE %p ALARM IRQ %d",
345 ctx->csr_base, ctx->irq);
346
347 rc = devm_request_irq(&pdev->dev, ctx->irq, xgene_rng_irq_handler, 0,
348 dev_name(&pdev->dev), ctx);
349 if (rc) {
350 dev_err(&pdev->dev, "Could not request RNG alarm IRQ\n");
351 return rc;
352 }
353
354 /* Enable IP clock */
355 ctx->clk = devm_clk_get(&pdev->dev, NULL);
356 if (IS_ERR(ctx->clk)) {
357 dev_warn(&pdev->dev, "Couldn't get the clock for RNG\n");
358 } else {
359 rc = clk_prepare_enable(ctx->clk);
360 if (rc) {
361 dev_warn(&pdev->dev,
362 "clock prepare enable failed for RNG");
363 return rc;
364 }
365 }
366
367 xgene_rng_func.priv = (unsigned long) ctx;
368
369 rc = hwrng_register(&xgene_rng_func);
370 if (rc) {
371 dev_err(&pdev->dev, "RNG registering failed error %d\n", rc);
372 if (!IS_ERR(ctx->clk))
373 clk_disable_unprepare(ctx->clk);
374 return rc;
375 }
376
377 rc = device_init_wakeup(&pdev->dev, 1);
378 if (rc) {
379 dev_err(&pdev->dev, "RNG device_init_wakeup failed error %d\n",
380 rc);
381 if (!IS_ERR(ctx->clk))
382 clk_disable_unprepare(ctx->clk);
383 hwrng_unregister(&xgene_rng_func);
384 return rc;
385 }
386
387 return 0;
388}
389
390static int xgene_rng_remove(struct platform_device *pdev)
391{
392 struct xgene_rng_dev *ctx = platform_get_drvdata(pdev);
393 int rc;
394
395 rc = device_init_wakeup(&pdev->dev, 0);
396 if (rc)
397 dev_err(&pdev->dev, "RNG init wakeup failed error %d\n", rc);
398 if (!IS_ERR(ctx->clk))
399 clk_disable_unprepare(ctx->clk);
400 hwrng_unregister(&xgene_rng_func);
401
402 return rc;
403}
404
405static const struct of_device_id xgene_rng_of_match[] = {
406 { .compatible = "apm,xgene-rng" },
407 { }
408};
409
410MODULE_DEVICE_TABLE(of, xgene_rng_of_match);
411
412static struct platform_driver xgene_rng_driver = {
413 .probe = xgene_rng_probe,
414 .remove = xgene_rng_remove,
415 .driver = {
416 .name = "xgene-rng",
417 .of_match_table = xgene_rng_of_match,
418 },
419};
420
421module_platform_driver(xgene_rng_driver);
422MODULE_DESCRIPTION("APM X-Gene RNG driver");
423MODULE_LICENSE("GPL");