aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilly Tarreau <w@1wt.eu>2008-09-21 21:15:50 +0200
committerWilly Tarreau <w@1wt.eu>2008-11-09 23:30:27 +0100
commitd1d9d14801d6e5fdc7f1b12bbceb092a8154c651 (patch)
tree0c53ac1a7a6c2c78a7d8eba9f3f1d84bc239d309
parent289e5d6384fd1f177cab5fa62f29f62ca22852e9 (diff)
downloadlinux-2.4-d1d9d14801d6e5fdc7f1b12bbceb092a8154c651.tar.gz
char: add support for AMD Geode LX hardware RNG
This driver provides support for AMD Geode LX HW RNG. It periodically collects entropy from the hardware to feed it into the kernel pool. This driver was partly inspired by the geoderng driver in 2.6.25 and by a few other drivers in 2.4. Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--Documentation/Configure.help16
-rw-r--r--drivers/char/Config.in3
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/geode-rng.c114
-rw-r--r--include/linux/pci_ids.h1
5 files changed, 135 insertions, 0 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 61b9d401565ccd..6d51d635eacc8e 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -20201,6 +20201,22 @@ CONFIG_HW_RANDOM
If unsure, say N.
+AMD Geode LX HW Random Number Generator support
+CONFIG_GEODE_RNG
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on the AMD Geode LX.
+
+ It runs a timer function which automatically adds entropy directly
+ into the kernel pool. You may need this driver if your system runs
+ headless and has no other source of entropy.
+
+ To compile this driver as a module ( = code which can be inserted in
+ and removed from the running kernel whenever you want), say M here
+ and read <file:Documentation/modules.txt>. The module will be called
+ hw_random.
+
+ If unsure, say N.
+
Power Management support
CONFIG_PM
"Power Management" means that parts of your computer are shut
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 6acc619a10851f..acfb96cc6428a4 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -308,6 +308,9 @@ if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o \
"$CONFIG_X86_64" = "y" ]; then
dep_tristate 'Intel/AMD/VIA HW Random Number Generator support' CONFIG_HW_RANDOM $CONFIG_PCI
fi
+if [ "$CONFIG_X86" = "y" ]; then
+ dep_tristate 'AMD Geode Random Number Generator support' CONFIG_GEODE_RNG $CONFIG_PCI
+fi
dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index c92cf97b02fa00..94993c00f58cde 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -263,6 +263,7 @@ obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_DS1742) += ds1742.o
obj-$(CONFIG_INTEL_RNG) += i810_rng.o
obj-$(CONFIG_AMD_RNG) += amd768_rng.o
+obj-$(CONFIG_GEODE_RNG) += geode-rng.o
obj-$(CONFIG_HW_RANDOM) += hw_random.o
obj-$(CONFIG_AMD_PM768) += amd76x_pm.o
obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
diff --git a/drivers/char/geode-rng.c b/drivers/char/geode-rng.c
new file mode 100644
index 00000000000000..62552896e0280e
--- /dev/null
+++ b/drivers/char/geode-rng.c
@@ -0,0 +1,114 @@
+/*
+ * RNG driver for AMD Geode RNGs
+ *
+ * Copyright 2008 Willy Tarreau <w@1wt.eu>
+ *
+ * Inspired by drivers/char/hw_random/geode-rng.c from kernel 2.6.25.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+
+/* We read the random generator every 50 ms */
+#define RNG_INTERVAL (HZ/20+1)
+
+#define GEODE_RNG_DATA_REG 0x50
+#define GEODE_RNG_STATUS_REG 0x54
+
+static struct timer_list timer;
+static void __iomem *rng_addr;
+static u32 rng_data[2];
+static int nb_data;
+
+static u32 geode_rng_data_read(void)
+{
+ return readl(rng_addr + GEODE_RNG_DATA_REG);
+}
+
+static int geode_rng_data_present(void)
+{
+ return !!(readl(rng_addr + GEODE_RNG_STATUS_REG));
+}
+
+static void geode_rng_timer(unsigned long data)
+{
+ if (!geode_rng_data_present())
+ goto out;
+
+ rng_data[nb_data] = geode_rng_data_read();
+ nb_data++;
+ if (nb_data > 1) {
+ nb_data = 0;
+ /* We have collected 64 bits. Maybe we should reduce the
+ * announced entropy ? At least, check for changing data
+ * and refuse to feed consts.
+ */
+ if (rng_data[0] != rng_data[1])
+ batch_entropy_store(rng_data[0], rng_data[1], 64);
+ }
+ out:
+ timer.expires = jiffies + RNG_INTERVAL;
+ add_timer(&timer);
+}
+
+static int __init geode_rng_init(void)
+{
+ struct pci_dev *pdev = NULL;
+ unsigned long rng_base;
+ int err = -ENODEV;
+
+ pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, NULL);
+
+ if (pdev == NULL) {
+ printk(KERN_ERR "geode-rng: AMD Geode RNG device not found\n");
+ goto out;
+ }
+
+ if ((err = pci_enable_device(pdev)))
+ goto out;
+
+ if ((err = pci_enable_device_bars(pdev, 1)))
+ goto out;
+
+ rng_base = pci_resource_start(pdev, 0);
+ if (rng_base == 0)
+ goto out;
+
+ err = -ENOMEM;
+ rng_addr = ioremap(rng_base, 0x58);
+ if (!rng_addr)
+ goto out;
+
+ printk(KERN_INFO "AMD Geode RNG detected and enabled\n");
+
+ init_timer(&timer);
+ timer.function = geode_rng_timer;
+ timer.data = 0;
+ timer.expires = jiffies + RNG_INTERVAL;
+ add_timer(&timer);
+ err = 0;
+out:
+ return err;
+}
+
+static void __exit geode_rng_exit(void)
+{
+ del_timer_sync(&timer);
+ iounmap(rng_addr);
+}
+
+module_init(geode_rng_init);
+module_exit(geode_rng_exit);
+
+MODULE_AUTHOR("Willy Tarreau");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d92ae7686e61fa..c84ec136eecc80 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -435,6 +435,7 @@
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
#define PCI_DEVICE_ID_AMD_SCSI 0x2020
+#define PCI_DEVICE_ID_AMD_LX_AES 0x2082
#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0