diff options
| author | Michael Buesch <mb@bu3sch.de> | 2006-06-26 03:25:00 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:19 -0400 |
| commit | 96d63c0297ccfd6d9059c614b3f5555d9441a2b3 (patch) | |
| tree | c4d3abbb9b03456b8c258d75e2c3b260d8f9ccf5 | |
| parent | ca644bd5039566725b7c71a559e65ea91b7abfb5 (diff) | |
[PATCH] Add AMD HW RNG driver
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | drivers/char/hw_random/Kconfig | 13 | ||||
| -rw-r--r-- | drivers/char/hw_random/Makefile | 1 | ||||
| -rw-r--r-- | drivers/char/hw_random/amd-rng.c | 152 |
3 files changed, 166 insertions, 0 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index e9ae4b1313a7..950247313cad 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
| @@ -22,3 +22,16 @@ config HW_RANDOM_INTEL | |||
| 22 | module will be called intel-rng. | 22 | module will be called intel-rng. |
| 23 | 23 | ||
| 24 | If unsure, say Y. | 24 | If unsure, say Y. |
| 25 | |||
| 26 | config HW_RANDOM_AMD | ||
| 27 | tristate "AMD HW Random Number Generator support" | ||
| 28 | depends on HW_RANDOM && X86 && PCI | ||
| 29 | default y | ||
| 30 | ---help--- | ||
| 31 | This driver provides kernel-side support for the Random Number | ||
| 32 | Generator hardware found on AMD 76x-based motherboards. | ||
| 33 | |||
| 34 | To compile this driver as a module, choose M here: the | ||
| 35 | module will be called amd-rng. | ||
| 36 | |||
| 37 | If unsure, say Y. | ||
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index d3118e3750a4..40dbc097a5d6 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
| @@ -4,3 +4,4 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_HW_RANDOM) += core.o | 5 | obj-$(CONFIG_HW_RANDOM) += core.o |
| 6 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o | 6 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o |
| 7 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o | ||
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c new file mode 100644 index 000000000000..71e4e0f3fd54 --- /dev/null +++ b/drivers/char/hw_random/amd-rng.c | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | /* | ||
| 2 | * RNG driver for AMD RNGs | ||
| 3 | * | ||
| 4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
| 5 | * | ||
| 6 | * with the majority of the code coming from: | ||
| 7 | * | ||
| 8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
| 9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
| 10 | * | ||
| 11 | * derived from | ||
| 12 | * | ||
| 13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
| 14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
| 15 | * | ||
| 16 | * derived from | ||
| 17 | * | ||
| 18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
| 19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
| 20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
| 21 | * | ||
| 22 | * This file is licensed under the terms of the GNU General Public | ||
| 23 | * License version 2. This program is licensed "as is" without any | ||
| 24 | * warranty of any kind, whether express or implied. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/pci.h> | ||
| 30 | #include <linux/hw_random.h> | ||
| 31 | #include <asm/io.h> | ||
| 32 | |||
| 33 | |||
| 34 | #define PFX KBUILD_MODNAME ": " | ||
| 35 | |||
| 36 | |||
| 37 | /* | ||
| 38 | * Data for PCI driver interface | ||
| 39 | * | ||
| 40 | * This data only exists for exporting the supported | ||
| 41 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
| 42 | * register a pci_driver, because someone else might one day | ||
| 43 | * want to register another driver on the same PCI id. | ||
| 44 | */ | ||
| 45 | static const struct pci_device_id pci_tbl[] = { | ||
| 46 | { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
| 47 | { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
| 48 | { 0, }, /* terminate list */ | ||
| 49 | }; | ||
| 50 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
| 51 | |||
| 52 | static struct pci_dev *amd_pdev; | ||
| 53 | |||
| 54 | |||
| 55 | static int amd_rng_data_present(struct hwrng *rng) | ||
| 56 | { | ||
| 57 | u32 pmbase = (u32)rng->priv; | ||
| 58 | |||
| 59 | return !!(inl(pmbase + 0xF4) & 1); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int amd_rng_data_read(struct hwrng *rng, u32 *data) | ||
| 63 | { | ||
| 64 | u32 pmbase = (u32)rng->priv; | ||
| 65 | |||
| 66 | *data = inl(pmbase + 0xF0); | ||
| 67 | |||
| 68 | return 4; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int amd_rng_init(struct hwrng *rng) | ||
| 72 | { | ||
| 73 | u8 rnen; | ||
| 74 | |||
| 75 | pci_read_config_byte(amd_pdev, 0x40, &rnen); | ||
| 76 | rnen |= (1 << 7); /* RNG on */ | ||
| 77 | pci_write_config_byte(amd_pdev, 0x40, rnen); | ||
| 78 | |||
| 79 | pci_read_config_byte(amd_pdev, 0x41, &rnen); | ||
| 80 | rnen |= (1 << 7); /* PMIO enable */ | ||
| 81 | pci_write_config_byte(amd_pdev, 0x41, rnen); | ||
| 82 | |||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static void amd_rng_cleanup(struct hwrng *rng) | ||
| 87 | { | ||
| 88 | u8 rnen; | ||
| 89 | |||
| 90 | pci_read_config_byte(amd_pdev, 0x40, &rnen); | ||
| 91 | rnen &= ~(1 << 7); /* RNG off */ | ||
| 92 | pci_write_config_byte(amd_pdev, 0x40, rnen); | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | static struct hwrng amd_rng = { | ||
| 97 | .name = "amd", | ||
| 98 | .init = amd_rng_init, | ||
| 99 | .cleanup = amd_rng_cleanup, | ||
| 100 | .data_present = amd_rng_data_present, | ||
| 101 | .data_read = amd_rng_data_read, | ||
| 102 | }; | ||
| 103 | |||
| 104 | |||
| 105 | static int __init mod_init(void) | ||
| 106 | { | ||
| 107 | int err = -ENODEV; | ||
| 108 | struct pci_dev *pdev = NULL; | ||
| 109 | const struct pci_device_id *ent; | ||
| 110 | u32 pmbase; | ||
| 111 | |||
| 112 | for_each_pci_dev(pdev) { | ||
| 113 | ent = pci_match_id(pci_tbl, pdev); | ||
| 114 | if (ent) | ||
| 115 | goto found; | ||
| 116 | } | ||
| 117 | /* Device not found. */ | ||
| 118 | goto out; | ||
| 119 | |||
| 120 | found: | ||
| 121 | err = pci_read_config_dword(pdev, 0x58, &pmbase); | ||
| 122 | if (err) | ||
| 123 | goto out; | ||
| 124 | err = -EIO; | ||
| 125 | pmbase &= 0x0000FF00; | ||
| 126 | if (pmbase == 0) | ||
| 127 | goto out; | ||
| 128 | amd_rng.priv = (unsigned long)pmbase; | ||
| 129 | amd_pdev = pdev; | ||
| 130 | |||
| 131 | printk(KERN_INFO "AMD768 RNG detected\n"); | ||
| 132 | err = hwrng_register(&amd_rng); | ||
| 133 | if (err) { | ||
| 134 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
| 135 | err); | ||
| 136 | goto out; | ||
| 137 | } | ||
| 138 | out: | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | static void __exit mod_exit(void) | ||
| 143 | { | ||
| 144 | hwrng_unregister(&amd_rng); | ||
| 145 | } | ||
| 146 | |||
| 147 | subsys_initcall(mod_init); | ||
| 148 | module_exit(mod_exit); | ||
| 149 | |||
| 150 | MODULE_AUTHOR("The Linux Kernel team"); | ||
| 151 | MODULE_DESCRIPTION("H/W RNG driver for AMD chipsets"); | ||
| 152 | MODULE_LICENSE("GPL"); | ||
