aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hw_random
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/hw_random')
-rw-r--r--drivers/char/hw_random/Kconfig14
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/intel-rng.c219
-rw-r--r--drivers/char/hw_random/pasemi-rng.c156
-rw-r--r--drivers/char/hw_random/via-rng.c1
5 files changed, 293 insertions, 98 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 5f3acd8e64b8..7cda04b33534 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -91,3 +91,17 @@ config HW_RANDOM_OMAP
91 module will be called omap-rng. 91 module will be called omap-rng.
92 92
93 If unsure, say Y. 93 If unsure, say Y.
94
95config HW_RANDOM_PASEMI
96 tristate "PA Semi HW Random Number Generator support"
97 depends on HW_RANDOM && PPC_PASEMI
98 default HW_RANDOM
99 ---help---
100 This driver provides kernel-side support for the Random Number
101 Generator hardware found on PA6T-1682M processor.
102
103 To compile this driver as a module, choose M here: the
104 module will be called pasemi-rng.
105
106 If unsure, say Y.
107
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c41fa19454e3..c8b7300e2fb1 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
10obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o 10obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
11obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o 11obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
12obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o 12obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
13obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index cc1046e6ee02..4ae9811d1a6c 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -24,10 +24,11 @@
24 * warranty of any kind, whether express or implied. 24 * warranty of any kind, whether express or implied.
25 */ 25 */
26 26
27#include <linux/module.h> 27#include <linux/hw_random.h>
28#include <linux/kernel.h> 28#include <linux/kernel.h>
29#include <linux/module.h>
29#include <linux/pci.h> 30#include <linux/pci.h>
30#include <linux/hw_random.h> 31#include <linux/stop_machine.h>
31#include <asm/io.h> 32#include <asm/io.h>
32 33
33 34
@@ -217,30 +218,117 @@ static struct hwrng intel_rng = {
217 .data_read = intel_rng_data_read, 218 .data_read = intel_rng_data_read,
218}; 219};
219 220
221struct intel_rng_hw {
222 struct pci_dev *dev;
223 void __iomem *mem;
224 u8 bios_cntl_off;
225 u8 bios_cntl_val;
226 u8 fwh_dec_en1_off;
227 u8 fwh_dec_en1_val;
228};
220 229
221#ifdef CONFIG_SMP 230static int __init intel_rng_hw_init(void *_intel_rng_hw)
222static char __initdata waitflag; 231{
232 struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;
233 u8 mfc, dvc;
234
235 /* interrupts disabled in stop_machine_run call */
236
237 if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
238 pci_write_config_byte(intel_rng_hw->dev,
239 intel_rng_hw->fwh_dec_en1_off,
240 intel_rng_hw->fwh_dec_en1_val |
241 FWH_F8_EN_MASK);
242 if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
243 pci_write_config_byte(intel_rng_hw->dev,
244 intel_rng_hw->bios_cntl_off,
245 intel_rng_hw->bios_cntl_val |
246 BIOS_CNTL_WRITE_ENABLE_MASK);
247
248 writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
249 writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem);
250 mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
251 dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
252 writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
253
254 if (!(intel_rng_hw->bios_cntl_val &
255 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
256 pci_write_config_byte(intel_rng_hw->dev,
257 intel_rng_hw->bios_cntl_off,
258 intel_rng_hw->bios_cntl_val);
259 if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
260 pci_write_config_byte(intel_rng_hw->dev,
261 intel_rng_hw->fwh_dec_en1_off,
262 intel_rng_hw->fwh_dec_en1_val);
223 263
224static void __init intel_init_wait(void *unused) 264 if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
265 (dvc != INTEL_FWH_DEVICE_CODE_8M &&
266 dvc != INTEL_FWH_DEVICE_CODE_4M)) {
267 printk(KERN_ERR PFX "FWH not detected\n");
268 return -ENODEV;
269 }
270
271 return 0;
272}
273
274static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
275 struct pci_dev *dev)
225{ 276{
226 while (waitflag) 277 intel_rng_hw->bios_cntl_val = 0xff;
227 cpu_relax(); 278 intel_rng_hw->fwh_dec_en1_val = 0xff;
279 intel_rng_hw->dev = dev;
280
281 /* Check for Intel 82802 */
282 if (dev->device < 0x2640) {
283 intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
284 intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD;
285 } else {
286 intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
287 intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW;
288 }
289
290 pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off,
291 &intel_rng_hw->fwh_dec_en1_val);
292 pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off,
293 &intel_rng_hw->bios_cntl_val);
294
295 if ((intel_rng_hw->bios_cntl_val &
296 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
297 == BIOS_CNTL_LOCK_ENABLE_MASK) {
298 static __initdata /*const*/ char warning[] =
299 KERN_WARNING PFX "Firmware space is locked read-only. "
300 KERN_WARNING PFX "If you can't or\n don't want to "
301 KERN_WARNING PFX "disable this in firmware setup, and "
302 KERN_WARNING PFX "if\n you are certain that your "
303 KERN_WARNING PFX "system has a functional\n RNG, try"
304 KERN_WARNING PFX "using the 'no_fwh_detect' option.\n";
305
306 if (no_fwh_detect)
307 return -ENODEV;
308 printk(warning);
309 return -EBUSY;
310 }
311
312 intel_rng_hw->mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
313 if (intel_rng_hw->mem == NULL)
314 return -EBUSY;
315
316 return 0;
228} 317}
229#endif 318
230 319
231static int __init mod_init(void) 320static int __init mod_init(void)
232{ 321{
233 int err = -ENODEV; 322 int err = -ENODEV;
234 unsigned i; 323 int i;
235 struct pci_dev *dev = NULL; 324 struct pci_dev *dev = NULL;
236 void __iomem *mem; 325 void __iomem *mem = mem;
237 unsigned long flags; 326 u8 hw_status;
238 u8 bios_cntl_off, fwh_dec_en1_off; 327 struct intel_rng_hw *intel_rng_hw;
239 u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff;
240 u8 hw_status, mfc, dvc;
241 328
242 for (i = 0; !dev && pci_tbl[i].vendor; ++i) 329 for (i = 0; !dev && pci_tbl[i].vendor; ++i)
243 dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL); 330 dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device,
331 NULL);
244 332
245 if (!dev) 333 if (!dev)
246 goto out; /* Device not found. */ 334 goto out; /* Device not found. */
@@ -250,39 +338,18 @@ static int __init mod_init(void)
250 goto fwh_done; 338 goto fwh_done;
251 } 339 }
252 340
253 /* Check for Intel 82802 */ 341 intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL);
254 if (dev->device < 0x2640) { 342 if (!intel_rng_hw) {
255 fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
256 bios_cntl_off = BIOS_CNTL_REG_OLD;
257 } else {
258 fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
259 bios_cntl_off = BIOS_CNTL_REG_NEW;
260 }
261
262 pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
263 pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
264
265 if ((bios_cntl_val &
266 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
267 == BIOS_CNTL_LOCK_ENABLE_MASK) {
268 static __initdata /*const*/ char warning[] =
269 KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n"
270 KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n"
271 KERN_WARNING PFX "you are certain that your system has a functional\n"
272 KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
273
274 pci_dev_put(dev); 343 pci_dev_put(dev);
275 if (no_fwh_detect)
276 goto fwh_done;
277 printk(warning);
278 err = -EBUSY;
279 goto out; 344 goto out;
280 } 345 }
281 346
282 mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN); 347 err = intel_init_hw_struct(intel_rng_hw, dev);
283 if (mem == NULL) { 348 if (err) {
284 pci_dev_put(dev); 349 pci_dev_put(dev);
285 err = -EBUSY; 350 kfree(intel_rng_hw);
351 if (err == -ENODEV)
352 goto fwh_done;
286 goto out; 353 goto out;
287 } 354 }
288 355
@@ -290,59 +357,18 @@ static int __init mod_init(void)
290 * Since the BIOS code/data is going to disappear from its normal 357 * Since the BIOS code/data is going to disappear from its normal
291 * location with the Read ID command, all activity on the system 358 * location with the Read ID command, all activity on the system
292 * must be stopped until the state is back to normal. 359 * must be stopped until the state is back to normal.
360 *
361 * Use stop_machine_run because IPIs can be blocked by disabling
362 * interrupts.
293 */ 363 */
294#ifdef CONFIG_SMP 364 err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS);
295 set_mb(waitflag, 1);
296 if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) {
297 set_mb(waitflag, 0);
298 pci_dev_put(dev);
299 printk(KERN_ERR PFX "cannot run on all processors\n");
300 err = -EAGAIN;
301 goto err_unmap;
302 }
303#endif
304 local_irq_save(flags);
305
306 if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
307 pci_write_config_byte(dev,
308 fwh_dec_en1_off,
309 fwh_dec_en1_val | FWH_F8_EN_MASK);
310 if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
311 pci_write_config_byte(dev,
312 bios_cntl_off,
313 bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
314
315 writeb(INTEL_FWH_RESET_CMD, mem);
316 writeb(INTEL_FWH_READ_ID_CMD, mem);
317 mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
318 dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
319 writeb(INTEL_FWH_RESET_CMD, mem);
320
321 if (!(bios_cntl_val &
322 (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
323 pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val);
324 if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
325 pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val);
326
327 local_irq_restore(flags);
328#ifdef CONFIG_SMP
329 /* Tell other CPUs to resume. */
330 set_mb(waitflag, 0);
331#endif
332
333 iounmap(mem);
334 pci_dev_put(dev); 365 pci_dev_put(dev);
335 366 iounmap(intel_rng_hw->mem);
336 if (mfc != INTEL_FWH_MANUFACTURER_CODE || 367 kfree(intel_rng_hw);
337 (dvc != INTEL_FWH_DEVICE_CODE_8M && 368 if (err)
338 dvc != INTEL_FWH_DEVICE_CODE_4M)) {
339 printk(KERN_ERR PFX "FWH not detected\n");
340 err = -ENODEV;
341 goto out; 369 goto out;
342 }
343 370
344fwh_done: 371fwh_done:
345
346 err = -ENOMEM; 372 err = -ENOMEM;
347 mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); 373 mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
348 if (!mem) 374 if (!mem)
@@ -352,22 +378,21 @@ fwh_done:
352 /* Check for Random Number Generator */ 378 /* Check for Random Number Generator */
353 err = -ENODEV; 379 err = -ENODEV;
354 hw_status = hwstatus_get(mem); 380 hw_status = hwstatus_get(mem);
355 if ((hw_status & INTEL_RNG_PRESENT) == 0) 381 if ((hw_status & INTEL_RNG_PRESENT) == 0) {
356 goto err_unmap; 382 iounmap(mem);
383 goto out;
384 }
357 385
358 printk(KERN_INFO "Intel 82802 RNG detected\n"); 386 printk(KERN_INFO "Intel 82802 RNG detected\n");
359 err = hwrng_register(&intel_rng); 387 err = hwrng_register(&intel_rng);
360 if (err) { 388 if (err) {
361 printk(KERN_ERR PFX "RNG registering failed (%d)\n", 389 printk(KERN_ERR PFX "RNG registering failed (%d)\n",
362 err); 390 err);
363 goto err_unmap; 391 iounmap(mem);
364 } 392 }
365out: 393out:
366 return err; 394 return err;
367 395
368err_unmap:
369 iounmap(mem);
370 goto out;
371} 396}
372 397
373static void __exit mod_exit(void) 398static void __exit mod_exit(void)
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
new file mode 100644
index 000000000000..fa6040b6c8f2
--- /dev/null
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -0,0 +1,156 @@
1/*
2 * Copyright (C) 2006-2007 PA Semi, Inc
3 *
4 * Maintained by: Olof Johansson <olof@lixom.net>
5 *
6 * Driver for the PWRficient onchip rng
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/module.h>
23#include <linux/kernel.h>
24#include <linux/platform_device.h>
25#include <linux/hw_random.h>
26#include <asm/of_platform.h>
27#include <asm/io.h>
28
29#define SDCRNG_CTL_REG 0x00
30#define SDCRNG_CTL_FVLD_M 0x0000f000
31#define SDCRNG_CTL_FVLD_S 12
32#define SDCRNG_CTL_KSZ 0x00000800
33#define SDCRNG_CTL_RSRC_CRG 0x00000010
34#define SDCRNG_CTL_RSRC_RRG 0x00000000
35#define SDCRNG_CTL_CE 0x00000004
36#define SDCRNG_CTL_RE 0x00000002
37#define SDCRNG_CTL_DR 0x00000001
38#define SDCRNG_CTL_SELECT_RRG_RNG (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG)
39#define SDCRNG_CTL_SELECT_CRG_RNG (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG)
40#define SDCRNG_VAL_REG 0x20
41
42#define MODULE_NAME "pasemi_rng"
43
44static int pasemi_rng_data_present(struct hwrng *rng)
45{
46 void __iomem *rng_regs = (void __iomem *)rng->priv;
47
48 return (in_le32(rng_regs + SDCRNG_CTL_REG)
49 & SDCRNG_CTL_FVLD_M) ? 1 : 0;
50}
51
52static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
53{
54 void __iomem *rng_regs = (void __iomem *)rng->priv;
55 *data = in_le32(rng_regs + SDCRNG_VAL_REG);
56 return 4;
57}
58
59static int pasemi_rng_init(struct hwrng *rng)
60{
61 void __iomem *rng_regs = (void __iomem *)rng->priv;
62 u32 ctl;
63
64 ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ;
65 out_le32(rng_regs + SDCRNG_CTL_REG, ctl);
66 out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR);
67
68 return 0;
69}
70
71static void pasemi_rng_cleanup(struct hwrng *rng)
72{
73 void __iomem *rng_regs = (void __iomem *)rng->priv;
74 u32 ctl;
75
76 ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE;
77 out_le32(rng_regs + SDCRNG_CTL_REG,
78 in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl);
79}
80
81static struct hwrng pasemi_rng = {
82 .name = MODULE_NAME,
83 .init = pasemi_rng_init,
84 .cleanup = pasemi_rng_cleanup,
85 .data_present = pasemi_rng_data_present,
86 .data_read = pasemi_rng_data_read,
87};
88
89static int __devinit rng_probe(struct of_device *ofdev,
90 const struct of_device_id *match)
91{
92 void __iomem *rng_regs;
93 struct device_node *rng_np = ofdev->node;
94 struct resource res;
95 int err = 0;
96
97 err = of_address_to_resource(rng_np, 0, &res);
98 if (err)
99 return -ENODEV;
100
101 rng_regs = ioremap(res.start, 0x100);
102
103 if (!rng_regs)
104 return -ENOMEM;
105
106 pasemi_rng.priv = (unsigned long)rng_regs;
107
108 printk(KERN_INFO "Registering PA Semi RNG\n");
109
110 err = hwrng_register(&pasemi_rng);
111
112 if (err)
113 iounmap(rng_regs);
114
115 return err;
116}
117
118static int __devexit rng_remove(struct of_device *dev)
119{
120 void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
121
122 hwrng_unregister(&pasemi_rng);
123 iounmap(rng_regs);
124
125 return 0;
126}
127
128static struct of_device_id rng_match[] = {
129 {
130 .compatible = "1682m-rng",
131 },
132 {},
133};
134
135static struct of_platform_driver rng_driver = {
136 .name = "pasemi-rng",
137 .match_table = rng_match,
138 .probe = rng_probe,
139 .remove = rng_remove,
140};
141
142static int __init rng_init(void)
143{
144 return of_register_platform_driver(&rng_driver);
145}
146module_init(rng_init);
147
148static void __exit rng_exit(void)
149{
150 of_unregister_platform_driver(&rng_driver);
151}
152module_exit(rng_exit);
153
154MODULE_LICENSE("GPL");
155MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
156MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 9ebf84d18655..ec435cb25c4f 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -26,7 +26,6 @@
26 26
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/kernel.h> 28#include <linux/kernel.h>
29#include <linux/pci.h>
30#include <linux/hw_random.h> 29#include <linux/hw_random.h>
31#include <asm/io.h> 30#include <asm/io.h>
32#include <asm/msr.h> 31#include <asm/msr.h>