public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 0/5] RNG cleanup & new drivers attempt #1
@ 2005-10-19  8:19 dsaxena
  2005-10-19  8:19 ` [patch 1/5] Remove existing hw_random implementation dsaxena
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: dsaxena @ 2005-10-19  8:19 UTC (permalink / raw)
  To: linux-kernel; +Cc: jgarzik, akpm, tony

This patch set is my first pass at adding support for some more
RNG drivers to the kernel. My basic goal was to keep the same
user space interface as exists, but not have to reproduce all
the same 100 lines of user space interface code across every new
driver (as we currently do with watchdogs...)

The new code separate the HW specifc driver from the user 
interface code and just adds a few function pointers so that
the two can talk to each other. I opted out of using a sysfs
class and all that complication b/c there will be one and only
one RNG device at a time from all the HW I can see.

I've added drivers for Intels' IXP4xx and for the TI OMAP,
though the later has not been tested (it builds) as I don't 
have the hardware. Same goes for x86...builds but no HW for 
me to test locally. Freescale MPC8xxx is next but that requires 
a bit more work.

As for the discussion on moving the implementation completely
out of the kernel, it is not completely doable. While we
can do it for simple HW such as the IXP and X86, there are
some cases that basically require us to have kernel code:

- On systems like OMAP, we want to be able to suspend/resume
  the RNG device and the device clocks and that needs to be done
  from kernel space as part of the PM path.

- On the MPC8xxx, the RNG is just part of a large crypto unit
  that also does SHA-1 and MD5 along with some other operations
  for which I'd like to see (and will probably write) a driver. The 
  RNG commands are queued in a chain along with the other units and 
  trying to get user space to share that queue will just be a mess.

So..we might as well keep them all in the kernel instead of having 
to know about some HW and not know about others.

Some of the things on my TODO list:

- Allow a fastpath where we don't even have the user space portion
  and the HW drivers just feed the entropy pool directly. While
  this bypasses the FIPS tests and such, there are some applications
  where this is OK or where we really don't want the extra proccess 
  context switching. This is specially true on ARM. I'll have to add 
  IRQ driven support to the drivers to that, but that's trivial. There 
  is also some HW (MPC8xxx for example) that does periodic self-tests 
  in HW and lists itself as "FIPs-compliant" and will trigger an error if 
  data should no longer be trusted and in that case doing a software
  test might also be undesirable. But...we should let the user decide
  at build time (or runtime?).

- Since I'm adding IRQ support, go ahead and add poll(2) support so
  that when we do have a user space daemon, it's not constantly
  poking at us.

~Deepak

(This is my first time using the magical quilt mail scripts so apologies
 in advance if anything breaks)

--
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

Even a stopped clock gives the right time twice a day.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [patch 1/5] Remove existing hw_random implementation
  2005-10-19  8:19 [patch 0/5] RNG cleanup & new drivers attempt #1 dsaxena
@ 2005-10-19  8:19 ` dsaxena
  2005-10-19  8:19 ` [patch 2/5] Core HW RNG support dsaxena
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: dsaxena @ 2005-10-19  8:19 UTC (permalink / raw)
  To: linux-kernel; +Cc: jgarzik, akpm, tony

[-- Attachment #1: rng/remove_current_rng.patch --]
[-- Type: text/plain, Size: 16432 bytes --]

Remove existing hw_random implementation so that it can be
replaced with a generic cross-architecture RNG codebase.

Signed-off-by: Deepak Saxena <dsaxena@plexity.net>


Index: linux-2.6-rng/drivers/char/Kconfig
===================================================================
--- linux-2.6-rng.orig/drivers/char/Kconfig
+++ linux-2.6-rng/drivers/char/Kconfig
@@ -644,21 +644,6 @@ config NWFLASH
 
 	  If you're not sure, say N.
 
-config HW_RANDOM
-	tristate "Intel/AMD/VIA HW Random Number Generator support"
-	depends on (X86 || IA64) && PCI
-	---help---
-	  This driver provides kernel-side support for the Random Number
-	  Generator hardware found on Intel i8xx-based motherboards,
-	  AMD 76x-based motherboards, and Via Nehemiah CPUs.
-
-	  Provides a character driver, used to read() entropy data.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called hw_random.
-
-	  If unsure, say N.
-
 config NVRAM
 	tristate "/dev/nvram support"
 	depends on ATARI || X86 || X86_64 || ARM || GENERIC_NVRAM
Index: linux-2.6-rng/drivers/char/Makefile
===================================================================
--- linux-2.6-rng.orig/drivers/char/Makefile
+++ linux-2.6-rng/drivers/char/Makefile
@@ -73,7 +73,6 @@ endif
 obj-$(CONFIG_TOSHIBA) += toshiba.o
 obj-$(CONFIG_I8K) += i8k.o
 obj-$(CONFIG_DS1620) += ds1620.o
-obj-$(CONFIG_HW_RANDOM) += hw_random.o
 obj-$(CONFIG_FTAPE) += ftape/
 obj-$(CONFIG_COBALT_LCD) += lcd.o
 obj-$(CONFIG_PPDEV) += ppdev.o
Index: linux-2.6-rng/drivers/char/hw_random.c
===================================================================
--- linux-2.6-rng.orig/drivers/char/hw_random.c
+++ /dev/null
@@ -1,627 +0,0 @@
-/*
- 	Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
-	(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
- 
- 	derived from
- 
-        Hardware driver for the AMD 768 Random Number Generator (RNG)
-        (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
-
- 	derived from
- 
-	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
-	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
-
-	Please read Documentation/hw_random.txt for details on use.
-
-	----------------------------------------------------------
-	This software may be used and distributed according to the terms
-        of the GNU General Public License, incorporated herein by reference.
-
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/random.h>
-#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#ifdef __i386__
-#include <asm/msr.h>
-#include <asm/cpufeature.h>
-#endif
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-
-/*
- * core module and version information
- */
-#define RNG_VERSION "1.0.0"
-#define RNG_MODULE_NAME "hw_random"
-#define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
-#define PFX RNG_MODULE_NAME ": "
-
-
-/*
- * debugging macros
- */
-
-/* pr_debug() collapses to a no-op if DEBUG is not defined */
-#define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args)
-
-
-#undef RNG_NDEBUG        /* define to enable lightweight runtime checks */
-#ifdef RNG_NDEBUG
-#define assert(expr)							\
-		if(!(expr)) {						\
-		printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s,"	\
-		"line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__);	\
-		}
-#else
-#define assert(expr)
-#endif
-
-#define RNG_MISCDEV_MINOR		183 /* official */
-
-static int rng_dev_open (struct inode *inode, struct file *filp);
-static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
-				loff_t * offp);
-
-static int __init intel_init (struct pci_dev *dev);
-static void intel_cleanup(void);
-static unsigned int intel_data_present (void);
-static u32 intel_data_read (void);
-
-static int __init amd_init (struct pci_dev *dev);
-static void amd_cleanup(void);
-static unsigned int amd_data_present (void);
-static u32 amd_data_read (void);
-
-#ifdef __i386__
-static int __init via_init(struct pci_dev *dev);
-static void via_cleanup(void);
-static unsigned int via_data_present (void);
-static u32 via_data_read (void);
-#endif
-
-struct rng_operations {
-	int (*init) (struct pci_dev *dev);
-	void (*cleanup) (void);
-	unsigned int (*data_present) (void);
-	u32 (*data_read) (void);
-	unsigned int n_bytes; /* number of bytes per ->data_read */
-};
-static struct rng_operations *rng_ops;
-
-static struct file_operations rng_chrdev_ops = {
-	.owner		= THIS_MODULE,
-	.open		= rng_dev_open,
-	.read		= rng_dev_read,
-};
-
-
-static struct miscdevice rng_miscdev = {
-	RNG_MISCDEV_MINOR,
-	RNG_MODULE_NAME,
-	&rng_chrdev_ops,
-};
-
-enum {
-	rng_hw_none,
-	rng_hw_intel,
-	rng_hw_amd,
-	rng_hw_via,
-};
-
-static struct rng_operations rng_vendor_ops[] = {
-	/* rng_hw_none */
-	{ },
-
-	/* rng_hw_intel */
-	{ intel_init, intel_cleanup, intel_data_present,
-	  intel_data_read, 1 },
-
-	/* rng_hw_amd */
-	{ amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 },
-
-#ifdef __i386__
-	/* rng_hw_via */
-	{ via_init, via_cleanup, via_data_present, via_data_read, 1 },
-#endif
-};
-
-/*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
-static struct pci_device_id rng_pci_tbl[] = {
-	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
-	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
-
-	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-
-	{ 0, },	/* terminate list */
-};
-MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
-
-
-/***********************************************************************
- *
- * Intel RNG operations
- *
- */
-
-/*
- * RNG registers (offsets from rng_mem)
- */
-#define INTEL_RNG_HW_STATUS			0
-#define         INTEL_RNG_PRESENT		0x40
-#define         INTEL_RNG_ENABLED		0x01
-#define INTEL_RNG_STATUS			1
-#define         INTEL_RNG_DATA_PRESENT		0x01
-#define INTEL_RNG_DATA				2
-
-/*
- * Magic address at which Intel PCI bridges locate the RNG
- */
-#define INTEL_RNG_ADDR				0xFFBC015F
-#define INTEL_RNG_ADDR_LEN			3
-
-/* token to our ioremap'd RNG register area */
-static void __iomem *rng_mem;
-
-static inline u8 intel_hwstatus (void)
-{
-	assert (rng_mem != NULL);
-	return readb (rng_mem + INTEL_RNG_HW_STATUS);
-}
-
-static inline u8 intel_hwstatus_set (u8 hw_status)
-{
-	assert (rng_mem != NULL);
-	writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);
-	return intel_hwstatus ();
-}
-
-static unsigned int intel_data_present(void)
-{
-	assert (rng_mem != NULL);
-
-	return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ?
-		1 : 0;
-}
-
-static u32 intel_data_read(void)
-{
-	assert (rng_mem != NULL);
-
-	return readb (rng_mem + INTEL_RNG_DATA);
-}
-
-static int __init intel_init (struct pci_dev *dev)
-{
-	int rc;
-	u8 hw_status;
-
-	DPRINTK ("ENTER\n");
-
-	rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
-	if (rng_mem == NULL) {
-		printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
-		rc = -EBUSY;
-		goto err_out;
-	}
-
-	/* Check for Intel 82802 */
-	hw_status = intel_hwstatus ();
-	if ((hw_status & INTEL_RNG_PRESENT) == 0) {
-		printk (KERN_ERR PFX "RNG not detected\n");
-		rc = -ENODEV;
-		goto err_out_free_map;
-	}
-
-	/* turn RNG h/w on, if it's off */
-	if ((hw_status & INTEL_RNG_ENABLED) == 0)
-		hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED);
-	if ((hw_status & INTEL_RNG_ENABLED) == 0) {
-		printk (KERN_ERR PFX "cannot enable RNG, aborting\n");
-		rc = -EIO;
-		goto err_out_free_map;
-	}
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-
-err_out_free_map:
-	iounmap (rng_mem);
-	rng_mem = NULL;
-err_out:
-	DPRINTK ("EXIT, returning %d\n", rc);
-	return rc;
-}
-
-static void intel_cleanup(void)
-{
-	u8 hw_status;
-
-	hw_status = intel_hwstatus ();
-	if (hw_status & INTEL_RNG_ENABLED)
-		intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED);
-	else
-		printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
-	iounmap(rng_mem);
-	rng_mem = NULL;
-}
-
-/***********************************************************************
- *
- * AMD RNG operations
- *
- */
-
-static u32 pmbase;			/* PMxx I/O base */
-static struct pci_dev *amd_dev;
-
-static unsigned int amd_data_present (void)
-{
-      	return inl(pmbase + 0xF4) & 1;
-}
-
-
-static u32 amd_data_read (void)
-{
-	return inl(pmbase + 0xF0);
-}
-
-static int __init amd_init (struct pci_dev *dev)
-{
-	int rc;
-	u8 rnen;
-
-	DPRINTK ("ENTER\n");
-
-	pci_read_config_dword(dev, 0x58, &pmbase);
-
-	pmbase &= 0x0000FF00;
-
-	if (pmbase == 0)
-	{
-		printk (KERN_ERR PFX "power management base not set\n");
-		rc = -EIO;
-		goto err_out;
-	}
-
-	pci_read_config_byte(dev, 0x40, &rnen);
-	rnen |= (1 << 7);	/* RNG on */
-	pci_write_config_byte(dev, 0x40, rnen);
-
-	pci_read_config_byte(dev, 0x41, &rnen);
-	rnen |= (1 << 7);	/* PMIO enable */
-	pci_write_config_byte(dev, 0x41, rnen);
-
-	pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n",
-			pmbase);
-
-	amd_dev = dev;
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-
-err_out:
-	DPRINTK ("EXIT, returning %d\n", rc);
-	return rc;
-}
-
-static void amd_cleanup(void)
-{
-	u8 rnen;
-
-	pci_read_config_byte(amd_dev, 0x40, &rnen);
-	rnen &= ~(1 << 7);	/* RNG off */
-	pci_write_config_byte(amd_dev, 0x40, rnen);
-
-	/* FIXME: twiddle pmio, also? */
-}
-
-#ifdef __i386__
-/***********************************************************************
- *
- * VIA RNG operations
- *
- */
-
-enum {
-	VIA_STRFILT_CNT_SHIFT	= 16,
-	VIA_STRFILT_FAIL	= (1 << 15),
-	VIA_STRFILT_ENABLE	= (1 << 14),
-	VIA_RAWBITS_ENABLE	= (1 << 13),
-	VIA_RNG_ENABLE		= (1 << 6),
-	VIA_XSTORE_CNT_MASK	= 0x0F,
-
-	VIA_RNG_CHUNK_8		= 0x00,	/* 64 rand bits, 64 stored bits */
-	VIA_RNG_CHUNK_4		= 0x01,	/* 32 rand bits, 32 stored bits */
-	VIA_RNG_CHUNK_4_MASK	= 0xFFFFFFFF,
-	VIA_RNG_CHUNK_2		= 0x02,	/* 16 rand bits, 32 stored bits */
-	VIA_RNG_CHUNK_2_MASK	= 0xFFFF,
-	VIA_RNG_CHUNK_1		= 0x03,	/* 8 rand bits, 32 stored bits */
-	VIA_RNG_CHUNK_1_MASK	= 0xFF,
-};
-
-static u32 via_rng_datum;
-
-/*
- * Investigate using the 'rep' prefix to obtain 32 bits of random data
- * in one insn.  The upside is potentially better performance.  The
- * downside is that the instruction becomes no longer atomic.  Due to
- * this, just like familiar issues with /dev/random itself, the worst
- * case of a 'rep xstore' could potentially pause a cpu for an
- * unreasonably long time.  In practice, this condition would likely
- * only occur when the hardware is failing.  (or so we hope :))
- *
- * Another possible performance boost may come from simply buffering
- * until we have 4 bytes, thus returning a u32 at a time,
- * instead of the current u8-at-a-time.
- */
-
-static inline u32 xstore(u32 *addr, u32 edx_in)
-{
-	u32 eax_out;
-
-	asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
-		:"=m"(*addr), "=a"(eax_out)
-		:"D"(addr), "d"(edx_in));
-
-	return eax_out;
-}
-
-static unsigned int via_data_present(void)
-{
-	u32 bytes_out;
-
-	/* We choose the recommended 1-byte-per-instruction RNG rate,
-	 * for greater randomness at the expense of speed.  Larger
-	 * values 2, 4, or 8 bytes-per-instruction yield greater
-	 * speed at lesser randomness.
-	 *
-	 * If you change this to another VIA_CHUNK_n, you must also
-	 * change the ->n_bytes values in rng_vendor_ops[] tables.
-	 * VIA_CHUNK_8 requires further code changes.
-	 *
-	 * A copy of MSR_VIA_RNG is placed in eax_out when xstore
-	 * completes.
-	 */
-	via_rng_datum = 0; /* paranoia, not really necessary */
-	bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
-	if (bytes_out == 0)
-		return 0;
-
-	return 1;
-}
-
-static u32 via_data_read(void)
-{
-	return via_rng_datum;
-}
-
-static int __init via_init(struct pci_dev *dev)
-{
-	u32 lo, hi, old_lo;
-
-	/* Control the RNG via MSR.  Tread lightly and pay very close
-	 * close attention to values written, as the reserved fields
-	 * are documented to be "undefined and unpredictable"; but it
-	 * does not say to write them as zero, so I make a guess that
-	 * we restore the values we find in the register.
-	 */
-	rdmsr(MSR_VIA_RNG, lo, hi);
-
-	old_lo = lo;
-	lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
-	lo &= ~VIA_XSTORE_CNT_MASK;
-	lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
-	lo |= VIA_RNG_ENABLE;
-
-	if (lo != old_lo)
-		wrmsr(MSR_VIA_RNG, lo, hi);
-
-	/* perhaps-unnecessary sanity check; remove after testing if
-	   unneeded */
-	rdmsr(MSR_VIA_RNG, lo, hi);
-	if ((lo & VIA_RNG_ENABLE) == 0) {
-		printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void via_cleanup(void)
-{
-	/* do nothing */
-}
-#endif
-
-
-/***********************************************************************
- *
- * /dev/hwrandom character device handling (major 10, minor 183)
- *
- */
-
-static int rng_dev_open (struct inode *inode, struct file *filp)
-{
-	/* enforce read-only access to this chrdev */
-	if ((filp->f_mode & FMODE_READ) == 0)
-		return -EINVAL;
-	if (filp->f_mode & FMODE_WRITE)
-		return -EINVAL;
-
-	return 0;
-}
-
-
-static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
-				loff_t * offp)
-{
-	static DEFINE_SPINLOCK(rng_lock);
-	unsigned int have_data;
-	u32 data = 0;
-	ssize_t ret = 0;
-
-	while (size) {
-		spin_lock(&rng_lock);
-
-		have_data = 0;
-		if (rng_ops->data_present()) {
-			data = rng_ops->data_read();
-			have_data = rng_ops->n_bytes;
-		}
-
-		spin_unlock (&rng_lock);
-
-		while (have_data && size) {
-			if (put_user((u8)data, buf++)) {
-				ret = ret ? : -EFAULT;
-				break;
-			}
-			size--;
-			ret++;
-			have_data--;
-			data>>=8;
-		}
-
-		if (filp->f_flags & O_NONBLOCK)
-			return ret ? : -EAGAIN;
-
-		if(need_resched())
-			schedule_timeout_interruptible(1);
-		else
-			udelay(200);	/* FIXME: We could poll for 250uS ?? */
-
-		if (signal_pending (current))
-			return ret ? : -ERESTARTSYS;
-	}
-	return ret;
-}
-
-
-
-/*
- * rng_init_one - look for and attempt to init a single RNG
- */
-static int __init rng_init_one (struct pci_dev *dev)
-{
-	int rc;
-
-	DPRINTK ("ENTER\n");
-
-	assert(rng_ops != NULL);
-
-	rc = rng_ops->init(dev);
-	if (rc)
-		goto err_out;
-
-	rc = misc_register (&rng_miscdev);
-	if (rc) {
-		printk (KERN_ERR PFX "misc device register failed\n");
-		goto err_out_cleanup_hw;
-	}
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-
-err_out_cleanup_hw:
-	rng_ops->cleanup();
-err_out:
-	DPRINTK ("EXIT, returning %d\n", rc);
-	return rc;
-}
-
-
-
-MODULE_AUTHOR("The Linux Kernel team");
-MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
-MODULE_LICENSE("GPL");
-
-
-/*
- * rng_init - initialize RNG module
- */
-static int __init rng_init (void)
-{
-	int rc;
-	struct pci_dev *pdev = NULL;
-	const struct pci_device_id *ent;
-
-	DPRINTK ("ENTER\n");
-
-	/* Probe for Intel, AMD RNGs */
-	for_each_pci_dev(pdev) {
-		ent = pci_match_id(rng_pci_tbl, pdev);
-		if (ent) {
-			rng_ops = &rng_vendor_ops[ent->driver_data];
-			goto match;
-		}
-	}
-
-#ifdef __i386__
-	/* Probe for VIA RNG */
-	if (cpu_has_xstore) {
-		rng_ops = &rng_vendor_ops[rng_hw_via];
-		pdev = NULL;
-		goto match;
-	}
-#endif
-
-	DPRINTK ("EXIT, returning -ENODEV\n");
-	return -ENODEV;
-
-match:
-	rc = rng_init_one (pdev);
-	if (rc)
-		return rc;
-
-	pr_info( RNG_DRIVER_NAME " loaded\n");
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-}
-
-
-/*
- * rng_init - shutdown RNG module
- */
-static void __exit rng_cleanup (void)
-{
-	DPRINTK ("ENTER\n");
-
-	misc_deregister (&rng_miscdev);
-
-	if (rng_ops->cleanup)
-		rng_ops->cleanup();
-
-	DPRINTK ("EXIT\n");
-}
-
-
-module_init (rng_init);
-module_exit (rng_cleanup);

--
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

Even a stopped clock gives the right time twice a day.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [patch 2/5] Core HW RNG support
  2005-10-19  8:19 [patch 0/5] RNG cleanup & new drivers attempt #1 dsaxena
  2005-10-19  8:19 ` [patch 1/5] Remove existing hw_random implementation dsaxena
@ 2005-10-19  8:19 ` dsaxena
  2005-10-24 10:45   ` Pavel Machek
  2005-10-19  8:19 ` [patch 3/5] Intel IXP4xx driver dsaxena
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: dsaxena @ 2005-10-19  8:19 UTC (permalink / raw)
  To: linux-kernel; +Cc: jgarzik, akpm, tony

[-- Attachment #1: rng/add_new_rng_core.patch --]
[-- Type: text/plain, Size: 7620 bytes --]

This patch adds support for the HW RNG core. The core code
simply implements the user space interface and calls HW-specific
function pointers to do the real data gathering. We do this
instead of having each driver re-implement the user space functionality
so we do not end up with a bunch of drivers replicating the exact 
same 50 lines of code (see drivers/watchdog). 

Signed-off-by: Deepak Saxena <dsaxena@plexity.net>


Index: linux-2.6-rng/drivers/char/Makefile
===================================================================
--- linux-2.6-rng.orig/drivers/char/Makefile
+++ linux-2.6-rng/drivers/char/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_AGP) += agp/
 obj-$(CONFIG_DRM) += drm/
 obj-$(CONFIG_PCMCIA) += pcmcia/
 obj-$(CONFIG_IPMI_HANDLER) += ipmi/
+obj-$(CONFIG_RNG) += rng/
 
 obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM) += tpm/
Index: linux-2.6-rng/drivers/char/rng/Makefile
===================================================================
--- /dev/null
+++ linux-2.6-rng/drivers/char/rng/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for HW Random Number Generator (RNG) device drivers.
+#
+
+obj-$(CONFIG_IXP4XX_RNG) += ixp4xx-rng.o core.o
+obj-$(CONFIG_X86_RNG) += x86-rng.o core.o
+obj-$(CONFIG_OMAP_RNG) += omap-rng.o core.o
+
Index: linux-2.6-rng/drivers/char/rng/core.c
===================================================================
--- /dev/null
+++ linux-2.6-rng/drivers/char/rng/core.c
@@ -0,0 +1,141 @@
+/*
+ * drivers/rng/core.c
+ *
+ * Core HW Random Number Generator (RNG) driver
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with parts from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+
+#include "rng.h"
+
+#define RNG_MISCDEV_MINOR		183 /* official */
+
+/*
+ * The one and only RNG device.
+ */
+static struct rng_operations *one_rng_to_rule_them_all;
+
+/***********************************************************************
+ *
+ * /dev/hwrandom character device handling (major 10, minor 183)
+ *
+ */
+static int rng_dev_open (struct inode *inode, struct file *filp)
+{
+	/* enforce read-only access to this chrdev */
+	if ((filp->f_mode & FMODE_READ) == 0)
+		return -EINVAL;
+	if (filp->f_mode & FMODE_WRITE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
+				loff_t * offp)
+{
+	static DEFINE_SPINLOCK(rng_lock);
+	unsigned int have_data;
+	u32 data = 0;
+	ssize_t ret = 0;
+
+	while (size) {
+		spin_lock(&rng_lock);
+
+		have_data = 0;
+		if (one_rng_to_rule_them_all->data_present())
+			have_data = one_rng_to_rule_them_all->data_read(&data);
+
+		spin_unlock (&rng_lock);
+
+		while (have_data && size) {
+			if (put_user((u8)data, buf++)) {
+				ret = ret ? : -EFAULT;
+				break;
+			}
+			size--;
+			ret++;
+			have_data--;
+			data>>=8;
+		}
+
+		if (filp->f_flags & O_NONBLOCK)
+			return ret ? : -EAGAIN;
+
+		if(need_resched())
+			schedule_timeout_interruptible(1);
+		else
+			udelay(200);	/* FIXME: We could poll for 250uS ?? */
+
+		if (signal_pending (current))
+			return ret ? : -ERESTARTSYS;
+	}
+	return ret;
+}
+
+static struct file_operations rng_chrdev_ops = {
+	.owner		= THIS_MODULE,
+	.open		= rng_dev_open,
+	.read		= rng_dev_read,
+};
+
+static struct miscdevice rng_miscdev = {
+	RNG_MISCDEV_MINOR,
+	"hw_random",
+	&rng_chrdev_ops,
+};
+
+int __init register_rng(struct rng_operations *rng_ops)
+{
+	int retval;
+
+	one_rng_to_rule_them_all = rng_ops;
+
+	retval = misc_register(&rng_miscdev);
+	if (retval)
+		printk(KERN_ERR "misc device register failed\n");
+
+	return retval;
+}
+
+void __exit rng_unregister(struct rng_operations *rng_ops)
+{
+	misc_deregister(&rng_miscdev);
+}
+
Index: linux-2.6-rng/drivers/char/rng/rng.h
===================================================================
--- /dev/null
+++ linux-2.6-rng/drivers/char/rng/rng.h
@@ -0,0 +1,24 @@
+/*
+ * driver/char/rng/rng.h
+ *
+ * RNG definitions shared by drivers
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+struct rng_operations {
+	/* Is there data in the FIFO? */
+	int (*data_present) (void);
+
+	/* Read data and return number of bytes read (up to 4) */
+	int (*data_read) (u32 *buffer);
+};
+
+int register_rng(struct rng_operations *);
+void unregister_rng(struct rng_operations *);
Index: linux-2.6-rng/drivers/char/rng/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6-rng/drivers/char/rng/Kconfig
@@ -0,0 +1,46 @@
+#
+# Hardware Random Number Generator (RNG) configuration
+#
+# We only support one RNG at a time
+#
+
+config X86_RNG
+	tristate "Intel/AMD/VIA HW Random Number Generator support"
+	depends on (X86 || IA64) && PCI
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on Intel i8xx-based motherboards,
+	  AMD 76x-based motherboards, and Via Nehemiah CPUs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called x86-rng.
+
+	  If unsure, say N.
+
+config IXP4XX_RNG
+	tristate "Intel IXP4xx NPU HW Random Number Generator support"
+	depends on ARCH_IXP4XX
+	---help---
+	  This driver provides kernel-side support for the Random
+	  Number Generator hardware found on the Intel IXP4xx NPU.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ixp4xx-rng.
+
+config OMAP_RNG
+	tristate "OMAP Random Number Generator support"
+	depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+ 	---help---
+ 	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on OMAP16xx and OMAP24xx multimedia
+	  processors.
+ 
+	  To compile this driver as a module, choose M here: the
+	  module will be called omap-rng.
+
+ 	  If unsure, say N.
+
+config RNG
+	bool
+	depends on IXP4XX_RNG || X86_RNG || OMAP_RNG
+	default y
Index: linux-2.6-rng/drivers/char/Kconfig
===================================================================
--- linux-2.6-rng.orig/drivers/char/Kconfig
+++ linux-2.6-rng/drivers/char/Kconfig
@@ -644,6 +644,8 @@ config NWFLASH
 
 	  If you're not sure, say N.
 
+source "drivers/char/rng/Kconfig"
+
 config NVRAM
 	tristate "/dev/nvram support"
 	depends on ATARI || X86 || X86_64 || ARM || GENERIC_NVRAM

--
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

Even a stopped clock gives the right time twice a day.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [patch 3/5] Intel IXP4xx driver
  2005-10-19  8:19 [patch 0/5] RNG cleanup & new drivers attempt #1 dsaxena
  2005-10-19  8:19 ` [patch 1/5] Remove existing hw_random implementation dsaxena
  2005-10-19  8:19 ` [patch 2/5] Core HW RNG support dsaxena
@ 2005-10-19  8:19 ` dsaxena
  2005-10-19  8:19 ` [patch 4/5] x86 driver dsaxena
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: dsaxena @ 2005-10-19  8:19 UTC (permalink / raw)
  To: linux-kernel; +Cc: jgarzik, akpm, tony

[-- Attachment #1: rng/rng_ixp4xx_driver.patch --]
[-- Type: text/plain, Size: 2415 bytes --]

RNG driver for Intel IXP4xx NPU.

Signed-off-by: Deepak Saxena <dsaxena@plexity.net>

---

Tested and works.

Index: linux-2.6-rng/drivers/char/rng/ixp4xx-rng.c
===================================================================
--- /dev/null
+++ linux-2.6-rng/drivers/char/rng/ixp4xx-rng.c
@@ -0,0 +1,66 @@
+/*
+ * drivers/char/rng/ixp4xx-rng.c
+ *
+ * RNG driver for Intel IXP4xx family of NPUs
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "rng.h"
+
+static u32* __iomem rng_base;
+
+static int ixp4xx_rng_data_present(void)
+{
+	return 1;
+}
+
+static int ixp4xx_rng_data_read(u32 *buffer)
+{
+	*buffer = __raw_readl(rng_base);
+
+	return 4;
+}
+
+struct rng_operations ixp4xx_rng_ops = {
+	.data_present	= ixp4xx_rng_data_present,
+	.data_read	= ixp4xx_rng_data_read,
+};
+
+static int __init ixp4xx_rng_init(void)
+{
+	rng_base = (u32* __iomem) ioremap(0x70002100, 4);
+	if (!rng_base) return -ENOMEM;
+
+	return register_rng(&ixp4xx_rng_ops);
+}
+
+static void __exit ixp4xx_rng_exit(void)
+{
+	unregister_rng(&ixp4xx_rng_ops);
+	iounmap(rng_base);
+}
+
+subsys_initcall(ixp4xx_rng_init);
+module_exit(ixp4xx_rng_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx");
+MODULE_LICENSE("GPL");
Index: linux-2.6-rng/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
===================================================================
--- linux-2.6-rng.orig/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
+++ linux-2.6-rng/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
@@ -36,6 +36,8 @@
  *
  * 0x6000000	0x00004000	ioremap'd	QMgr
  *
+ * 0x7000000    0x00004000      ioremap'd       Public-Key Exchange Unit
+ *
  * 0xC0000000	0x00001000	0xffbfe000	PCI CFG 
  *
  * 0xC4000000	0x00001000	0xffbfd000	EXP CFG 

--
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

Even a stopped clock gives the right time twice a day.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [patch 4/5] x86 driver
  2005-10-19  8:19 [patch 0/5] RNG cleanup & new drivers attempt #1 dsaxena
                   ` (2 preceding siblings ...)
  2005-10-19  8:19 ` [patch 3/5] Intel IXP4xx driver dsaxena
@ 2005-10-19  8:19 ` dsaxena
  2005-10-19  8:19 ` [patch 5/5] TI OMAP driver dsaxena
  2005-10-19 15:01 ` [patch 0/5] RNG cleanup & new drivers attempt #1 Jeff Garzik
  5 siblings, 0 replies; 16+ messages in thread
From: dsaxena @ 2005-10-19  8:19 UTC (permalink / raw)
  To: linux-kernel; +Cc: jgarzik, akpm, tony

[-- Attachment #1: rng/rng_x86_driver.patch --]
[-- Type: text/plain, Size: 13184 bytes --]

x86 RNG driver. This is basically the existing driver with
the user space interface bits ripped out. 

Signed-off-by: Deepak Saxena <dsaxena@plexity.net>

---

This builds but I have not tested it yet as I do not have the needed HW.

Index: linux-2.6-rng/drivers/char/rng/x86-rng.c
===================================================================
--- /dev/null
+++ linux-2.6-rng/drivers/char/rng/x86-rng.c
@@ -0,0 +1,528 @@
+/*
+ * drivers/char/rng/x86.c
+ *
+ * RNG driver for Intel/AMD/VIA RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/msr.h>
+#include <asm/cpufeature.h>
+
+#include <asm/io.h>
+
+#include "rng.h"
+
+/*
+ * debugging macros
+ */
+
+/* pr_debug() collapses to a no-op if DEBUG is not defined */
+#define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args)
+
+#define RNG_VERSION "1.1.0"
+#define RNG_MODULE_NAME "x86-rng"
+#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
+#define PFX RNG_MODULE_NAME ": "
+
+#undef RNG_NDEBUG        /* define to enable lightweight runtime checks */
+#ifdef RNG_NDEBUG
+#define assert(expr)							\
+		if(!(expr)) {						\
+		printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s,"	\
+		"line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__);	\
+		}
+#else
+#define assert(expr)
+#endif
+
+
+struct x86_rng_operations {
+	int (*init)	(struct pci_dev *dev);
+	void (*cleanup)	(void);
+	struct rng_operations rng_ops;
+};
+
+static struct x86_rng_operations *x86_rng_ops;
+
+static int __init intel_init (struct pci_dev *dev);
+static void intel_cleanup(void);
+static int intel_data_present (void);
+static int intel_data_read (u32 *data);
+
+static int __init amd_init (struct pci_dev *dev);
+static void amd_cleanup(void);
+static int amd_data_present (void);
+static int amd_data_read (u32 *data);
+
+#ifdef __i386__
+static int __init via_init(struct pci_dev *dev);
+static void via_cleanup(void);
+static int via_data_present (void);
+static int via_data_read (u32 *date);
+#endif
+
+enum {
+	rng_hw_none,
+	rng_hw_intel,
+	rng_hw_amd,
+	rng_hw_via,
+};
+
+static struct x86_rng_operations rng_vendor_ops[] = {
+	/* rng_hw_none */
+	{ },
+
+	/* rng_hw_intel */
+	{
+		.init			= intel_init,
+		.cleanup		= intel_cleanup,
+		.rng_ops.data_present	= intel_data_present,
+		.rng_ops.data_read	= intel_data_read
+	},
+
+	/* rng_hw_amd */
+	{
+		.init			= amd_init,
+		.cleanup		= amd_cleanup,
+		.rng_ops.data_present	= amd_data_present,
+		.rng_ops.data_read	= amd_data_read
+	},
+
+#ifdef __i386__
+	/* rng_hw_via */
+	{
+		.init			= via_init,
+		.cleanup		= via_cleanup,
+		.rng_ops.data_present	= via_data_present,
+		.rng_ops.data_read	= via_data_read
+	}
+#endif
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id rng_pci_tbl[] = {
+	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
+	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
+
+	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+
+	{ 0, },	/* terminate list */
+};
+MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
+
+/***********************************************************************
+ *
+ * Intel RNG operations
+ *
+ */
+
+/*
+ * RNG registers (offsets from rng_mem)
+ */
+#define INTEL_RNG_HW_STATUS			0
+#define         INTEL_RNG_PRESENT		0x40
+#define         INTEL_RNG_ENABLED		0x01
+#define INTEL_RNG_STATUS			1
+#define         INTEL_RNG_DATA_PRESENT		0x01
+#define INTEL_RNG_DATA				2
+
+/*
+ * Magic address at which Intel PCI bridges locate the RNG
+ */
+#define INTEL_RNG_ADDR				0xFFBC015F
+#define INTEL_RNG_ADDR_LEN			3
+
+/* token to our ioremap'd RNG register area */
+static void __iomem *rng_mem;
+
+static inline u8 intel_hwstatus (void)
+{
+	assert (rng_mem != NULL);
+	return readb (rng_mem + INTEL_RNG_HW_STATUS);
+}
+
+static inline u8 intel_hwstatus_set (u8 hw_status)
+{
+	assert (rng_mem != NULL);
+	writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);
+	return intel_hwstatus ();
+}
+
+static int intel_data_present(void)
+{
+	assert (rng_mem != NULL);
+
+	return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ?
+		1 : 0;
+}
+
+static int intel_data_read(u32 *data)
+{
+	assert (rng_mem != NULL);
+
+	*data = readb (rng_mem + INTEL_RNG_DATA);
+
+	return 1;
+}
+
+static int __init intel_init (struct pci_dev *dev)
+{
+	int rc;
+	u8 hw_status;
+
+	DPRINTK ("ENTER\n");
+
+	rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
+	if (rng_mem == NULL) {
+		printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
+		rc = -EBUSY;
+		goto err_out;
+	}
+
+	/* Check for Intel 82802 */
+	hw_status = intel_hwstatus ();
+	if ((hw_status & INTEL_RNG_PRESENT) == 0) {
+		printk (KERN_ERR PFX "RNG not detected\n");
+		rc = -ENODEV;
+		goto err_out_free_map;
+	}
+
+	/* turn RNG h/w on, if it's off */
+	if ((hw_status & INTEL_RNG_ENABLED) == 0)
+		hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED);
+	if ((hw_status & INTEL_RNG_ENABLED) == 0) {
+		printk (KERN_ERR PFX "cannot enable RNG, aborting\n");
+		rc = -EIO;
+		goto err_out_free_map;
+	}
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_out_free_map:
+	iounmap (rng_mem);
+	rng_mem = NULL;
+err_out:
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+static void intel_cleanup(void)
+{
+	u8 hw_status;
+
+	hw_status = intel_hwstatus ();
+	if (hw_status & INTEL_RNG_ENABLED)
+		intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED);
+	else
+		printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
+	iounmap(rng_mem);
+	rng_mem = NULL;
+}
+
+/***********************************************************************
+ *
+ * AMD RNG operations
+ *
+ */
+
+static u32 pmbase;			/* PMxx I/O base */
+static struct pci_dev *amd_dev;
+
+static int amd_data_present (void)
+{
+      	return inl(pmbase + 0xF4) & 1;
+}
+
+
+static int amd_data_read (u32 *data)
+{
+	*data = inl(pmbase + 0xF0);
+
+	return 4;
+}
+
+static int __init amd_init (struct pci_dev *dev)
+{
+	int rc;
+	u8 rnen;
+
+	DPRINTK ("ENTER\n");
+
+	pci_read_config_dword(dev, 0x58, &pmbase);
+
+	pmbase &= 0x0000FF00;
+
+	if (pmbase == 0)
+	{
+		printk (KERN_ERR PFX "power management base not set\n");
+		rc = -EIO;
+		goto err_out;
+	}
+
+	pci_read_config_byte(dev, 0x40, &rnen);
+	rnen |= (1 << 7);	/* RNG on */
+	pci_write_config_byte(dev, 0x40, rnen);
+
+	pci_read_config_byte(dev, 0x41, &rnen);
+	rnen |= (1 << 7);	/* PMIO enable */
+	pci_write_config_byte(dev, 0x41, rnen);
+
+	pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n",
+			pmbase);
+
+	amd_dev = dev;
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_out:
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+static void amd_cleanup(void)
+{
+	u8 rnen;
+
+	pci_read_config_byte(amd_dev, 0x40, &rnen);
+	rnen &= ~(1 << 7);	/* RNG off */
+	pci_write_config_byte(amd_dev, 0x40, rnen);
+
+	/* FIXME: twiddle pmio, also? */
+}
+
+#ifdef __i386__
+/***********************************************************************
+ *
+ * VIA RNG operations
+ *
+ */
+
+enum {
+	VIA_STRFILT_CNT_SHIFT	= 16,
+	VIA_STRFILT_FAIL	= (1 << 15),
+	VIA_STRFILT_ENABLE	= (1 << 14),
+	VIA_RAWBITS_ENABLE	= (1 << 13),
+	VIA_RNG_ENABLE		= (1 << 6),
+	VIA_XSTORE_CNT_MASK	= 0x0F,
+
+	VIA_RNG_CHUNK_8		= 0x00,	/* 64 rand bits, 64 stored bits */
+	VIA_RNG_CHUNK_4		= 0x01,	/* 32 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_4_MASK	= 0xFFFFFFFF,
+	VIA_RNG_CHUNK_2		= 0x02,	/* 16 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_2_MASK	= 0xFFFF,
+	VIA_RNG_CHUNK_1		= 0x03,	/* 8 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_1_MASK	= 0xFF,
+};
+
+static u32 via_rng_datum;
+
+/*
+ * Investigate using the 'rep' prefix to obtain 32 bits of random data
+ * in one insn.  The upside is potentially better performance.  The
+ * downside is that the instruction becomes no longer atomic.  Due to
+ * this, just like familiar issues with /dev/random itself, the worst
+ * case of a 'rep xstore' could potentially pause a cpu for an
+ * unreasonably long time.  In practice, this condition would likely
+ * only occur when the hardware is failing.  (or so we hope :))
+ *
+ * Another possible performance boost may come from simply buffering
+ * until we have 4 bytes, thus returning a u32 at a time,
+ * instead of the current u8-at-a-time.
+ */
+
+static inline u32 xstore(u32 *addr, u32 edx_in)
+{
+	u32 eax_out;
+
+	asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
+		:"=m"(*addr), "=a"(eax_out)
+		:"D"(addr), "d"(edx_in));
+
+	return eax_out;
+}
+
+static int via_data_present(void)
+{
+	u32 bytes_out;
+
+	/* We choose the recommended 1-byte-per-instruction RNG rate,
+	 * for greater randomness at the expense of speed.  Larger
+	 * values 2, 4, or 8 bytes-per-instruction yield greater
+	 * speed at lesser randomness.
+	 *
+	 * If you change this to another VIA_CHUNK_n, you must also
+	 * change the ->n_bytes values in rng_vendor_ops[] tables.
+	 * VIA_CHUNK_8 requires further code changes.
+	 *
+	 * A copy of MSR_VIA_RNG is placed in eax_out when xstore
+	 * completes.
+	 */
+	via_rng_datum = 0; /* paranoia, not really necessary */
+	bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
+	if (bytes_out == 0)
+		return 0;
+
+	return 1;
+}
+
+static int via_data_read(u32 *data)
+{
+	*data = via_rng_datum;
+
+	return 1;
+}
+
+static int __init via_init(struct pci_dev *dev)
+{
+	u32 lo, hi, old_lo;
+
+	/* Control the RNG via MSR.  Tread lightly and pay very close
+	 * close attention to values written, as the reserved fields
+	 * are documented to be "undefined and unpredictable"; but it
+	 * does not say to write them as zero, so I make a guess that
+	 * we restore the values we find in the register.
+	 */
+	rdmsr(MSR_VIA_RNG, lo, hi);
+
+	old_lo = lo;
+	lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
+	lo &= ~VIA_XSTORE_CNT_MASK;
+	lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
+	lo |= VIA_RNG_ENABLE;
+
+	if (lo != old_lo)
+		wrmsr(MSR_VIA_RNG, lo, hi);
+
+	/* perhaps-unnecessary sanity check; remove after testing if
+	   unneeded */
+	rdmsr(MSR_VIA_RNG, lo, hi);
+	if ((lo & VIA_RNG_ENABLE) == 0) {
+		printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void via_cleanup(void)
+{
+	/* do nothing */
+}
+#endif
+
+
+/*
+ * rng_init - initialize RNG module
+ */
+static int __init x86_rng_init(void)
+{
+	int rc;
+	struct pci_dev *pdev = NULL;
+	const struct pci_device_id *ent;
+
+	DPRINTK ("ENTER\n");
+
+	/* Probe for Intel, AMD RNGs */
+	for_each_pci_dev(pdev) {
+		ent = pci_match_id(rng_pci_tbl, pdev);
+		if (ent) {
+			x86_rng_ops = &rng_vendor_ops[ent->driver_data];
+			goto match;
+		}
+	}
+
+	/* Probe for VIA RNG */
+	if (cpu_has_xstore) {
+		x86_rng_ops = &rng_vendor_ops[rng_hw_via];
+		pdev = NULL;
+		goto match;
+	}
+
+	DPRINTK ("EXIT, returning -ENODEV\n");
+	return -ENODEV;
+
+match:
+	rc = x86_rng_ops->init(pdev);
+	if (rc)
+		return rc;
+
+	rc = register_rng(&x86_rng_ops->rng_ops);
+	if (rc) {
+		x86_rng_ops->cleanup();
+		return rc;
+	}
+
+	pr_info( RNG_DRIVER_NAME " loaded\n");
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+/*
+ * rng_init - shutdown RNG module
+ */
+static void __exit x86_rng_exit (void)
+{
+	DPRINTK ("ENTER\n");
+
+	unregister_rng(&x86_rng_ops->rng_ops);
+
+	if (x86_rng_ops->cleanup)
+		x86_rng_ops->cleanup();
+
+	DPRINTK ("EXIT\n");
+}
+
+subsys_initcall(x86_rng_init);
+module_exit(x86_rng_exit);
+
+MODULE_AUTHOR("The Linux Kernel team");
+MODULE_DESCRIPTION("H/W RNG driver for Intel/AMD/VIA chipsets");
+MODULE_LICENSE("GPL");

--
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

Even a stopped clock gives the right time twice a day.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [patch 5/5] TI OMAP driver
  2005-10-19  8:19 [patch 0/5] RNG cleanup & new drivers attempt #1 dsaxena
                   ` (3 preceding siblings ...)
  2005-10-19  8:19 ` [patch 4/5] x86 driver dsaxena
@ 2005-10-19  8:19 ` dsaxena
  2005-10-19  9:36   ` Eric Piel
  2005-10-19 15:01 ` [patch 0/5] RNG cleanup & new drivers attempt #1 Jeff Garzik
  5 siblings, 1 reply; 16+ messages in thread
From: dsaxena @ 2005-10-19  8:19 UTC (permalink / raw)
  To: linux-kernel; +Cc: jgarzik, akpm, tony

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: rng/rng_omap_driver.patch --]
[-- Type: text/plain, Size: 4964 bytes --]

This patch implements the OMAP RNG driver. 

Signed-off-by: Deepak Saxena <dsaxena@plexity.net>

---

Builts but untested as I do not hardware. 

Index: linux-omap-2.6/drivers/char/rng/omap-rng.c
===================================================================
--- /dev/null
+++ linux-omap-2.6/drivers/char/rng/omap-rng.c
@@ -0,0 +1,208 @@
+/*
+ * driver/char/rng/omap-rng.c
+ *
+ * RNG driver for TI OMAP CPU family
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Mostly based on original driver:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * 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.
+ *
+ * TODO:
+ *
+ * - Make status updated be interrupt driven so we don't poll
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/hardware/clock.h>
+
+#include "rng.h"
+
+#define RNG_OUT_REG		0x00		/* Output register */
+#define RNG_STAT_REG		0x04		/* Status register
+							[0] = STAT_BUSY */
+#define RNG_ALARM_REG		0x24		/* Alarm register
+							[7:0] = ALARM_COUNTER */
+#define RNG_CONFIG_REG		0x28		/* Configuration register
+							[11:6] = RESET_COUNT
+							[5:3]  = RING2_DELAY
+							[2:0]  = RING1_DELAY */
+#define RNG_REV_REG		0x3c		/* Revision register
+							[7:0] = REV_NB */
+#define RNG_MASK_REG		0x40		/* Mask and reset register
+							[2] = IT_EN
+							[1] = SOFTRESET
+							[0] = AUTOIDLE */
+#define RNG_SYSSTATUS		0x44		/* System status
+							[0] = RESETDONE */
+
+static u32 __iomem *rng_base;
+static struct clk *rng_ick;
+static struct device *rng_dev;
+
+static u32 omap_rng_read_reg(int reg)
+{
+	return __raw_readl(rng_base + reg);
+}
+
+static void omap_rng_write_reg(int reg, u32 val)
+{
+	__raw_writel(val, rng_base + reg);
+}
+
+static int omap_rng_data_present(void)
+{
+	return omap_rng_read_reg(RNG_STAT_REG);
+}
+
+static int omap_rng_data_read(u32 *data)
+{
+	*data = omap_rng_read_reg(RNG_OUT_REG);
+
+	return 4;
+}
+
+static struct rng_operations omap_rng_ops = {
+	.data_present	= omap_rng_data_present,
+	.data_read	= omap_rng_data_read,
+};
+
+static int __init omap_rng_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res, *mem;
+	int ret;
+
+	/*
+	 * A bit ugly, and it will never actually happen but there can
+	 * be only one RNG and this catches any bork
+	 */
+	if (rng_dev)
+		BUG();
+
+    	if (cpu_is_omap24xx()) {
+		rng_ick = clk_get(NULL, "rng_ick");
+		if (IS_ERR(rng_ick)) {
+			dev_err(dev, "Could not get rng_ick\n");
+			ret = PTR_ERR(rng_ick);
+			return ret;
+		}
+		else {
+			clk_use(rng_ick);
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res)
+		return -ENOENT;
+
+	mem = request_mem_region(res->start, res->end - res->start + 1,
+				 pdev->name);
+	if (mem == NULL)
+		return -EBUSY;
+
+	dev_set_drvdata(dev, mem);
+	rng_base = (u32 __iomem *)io_p2v(res->start);
+
+	ret = register_rng(&omap_rng_ops);
+	if (ret) {
+		release_resource(mem);
+		rng_base = NULL;
+		return ret;
+	}
+
+	dev_info(dev, "OMAP Random Number Generator ver. %02x\n",
+		omap_rng_read_reg(RNG_REV_REG));
+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
+
+	rng_dev = dev;
+
+	return 0;
+}
+
+static int __exit omap_rng_remove(struct device *dev)
+{
+	struct resource *mem = dev_get_drvdata(dev);
+
+	unregister_rng(&omap_rng_ops);
+
+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
+
+	if (cpu_is_omap24xx()) {
+		clk_unuse(rng_ick);
+		clk_put(rng_ick);
+	}
+
+	release_resource(mem);
+	rng_base = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)
+{
+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
+
+	return 0;
+}
+
+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)
+{
+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
+
+	return 1;
+}
+
+#else
+
+#define	omap_rng_suspend	NULL
+#define	omap_rng_resume		NULL
+
+#endif
+
+
+static struct device_driver omap_rng_driver = {
+	.name		= "omap_rng",
+	.bus		= &platform_bus_type,
+	.probe		= omap_rng_probe,
+	.remove		= __exit_p(omap_rng_remove),
+	.suspend	= omap_rng_suspend,
+	.resume		= omap_rng_resume
+};
+
+static int __init omap_rng_init(void)
+{
+	if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
+		return -ENODEV;
+
+	return driver_register(&omap_rng_driver);
+}
+
+static void __exit omap_rng_exit(void)
+{
+	driver_unregister(&omap_rng_driver);
+}
+
+module_init(omap_rng_init);
+module_exit(omap_rng_exit);
+
+MODULE_AUTHOR("Deepak Saxena (and others)");
+MODULE_LICENSE("GPL");

--
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

Even a stopped clock gives the right time twice a day.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 5/5] TI OMAP driver
  2005-10-19  8:19 ` [patch 5/5] TI OMAP driver dsaxena
@ 2005-10-19  9:36   ` Eric Piel
  2005-10-19  9:44     ` Deepak Saxena
  0 siblings, 1 reply; 16+ messages in thread
From: Eric Piel @ 2005-10-19  9:36 UTC (permalink / raw)
  To: dsaxena; +Cc: linux-kernel, jgarzik, akpm, tony

10/19/2005 10:19 AM, dsaxena@plexity.net wrote/a écrit:
> This patch implements the OMAP RNG driver. 
> 
> Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
> 
> ---
> 
> Builts but untested as I do not hardware. 
> 
> Index: linux-omap-2.6/drivers/char/rng/omap-rng.c
> ===================================================================
> --- /dev/null
> +++ linux-omap-2.6/drivers/char/rng/omap-rng.c

> +#ifdef CONFIG_PM
> +
> +static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)
> +{
> +	omap_rng_write_reg(RNG_MASK_REG, 0x0);
> +
> +	return 0;
> +}
> +
> +static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)
> +{
> +	omap_rng_write_reg(RNG_MASK_REG, 0x1);
> +
> +	return 1;
> +}
Probably one of them should be called omap_rng_resume() ?

Eric

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 5/5] TI OMAP driver
  2005-10-19  9:36   ` Eric Piel
@ 2005-10-19  9:44     ` Deepak Saxena
  2005-10-21 16:35       ` Tony Lindgren
  0 siblings, 1 reply; 16+ messages in thread
From: Deepak Saxena @ 2005-10-19  9:44 UTC (permalink / raw)
  To: Eric Piel; +Cc: linux-kernel

On Oct 19 2005, at 11:36, Eric Piel was caught saying:
> >+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 
> >level)
> >+{
> >+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
> >+
> >+	return 0;
> >+}
> >+
> >+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 
> >level)
> >+{
> >+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
> >+
> >+	return 1;
> >+}
> Probably one of them should be called omap_rng_resume() ?
> 
> Eric

Tnx!

~Deepak

-- 
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

When law and duty are one, united by religion, you never become fully
conscious, fully aware of yourself. You are always a little less than
an individual. - Frank Herbert

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 0/5] RNG cleanup & new drivers attempt #1
  2005-10-19  8:19 [patch 0/5] RNG cleanup & new drivers attempt #1 dsaxena
                   ` (4 preceding siblings ...)
  2005-10-19  8:19 ` [patch 5/5] TI OMAP driver dsaxena
@ 2005-10-19 15:01 ` Jeff Garzik
  2005-10-19 17:25   ` Deepak Saxena
  5 siblings, 1 reply; 16+ messages in thread
From: Jeff Garzik @ 2005-10-19 15:01 UTC (permalink / raw)
  To: dsaxena; +Cc: linux-kernel, jgarzik, akpm, tony

dsaxena@plexity.net wrote:
> - Allow a fastpath where we don't even have the user space portion
>   and the HW drivers just feed the entropy pool directly. While
>   this bypasses the FIPS tests and such, there are some applications
>   where this is OK or where we really don't want the extra proccess 
>   context switching. This is specially true on ARM. I'll have to add 
>   IRQ driven support to the drivers to that, but that's trivial. There 
>   is also some HW (MPC8xxx for example) that does periodic self-tests 
>   in HW and lists itself as "FIPs-compliant" and will trigger an error if 
>   data should no longer be trusted and in that case doing a software
>   test might also be undesirable. But...we should let the user decide
>   at build time (or runtime?).

Not interesting in pursuing this path.  This has been discussed 
endlessly, check the archives.

We want the FIPS tests.  Hardware (especially cheap hardware) is often 
known to go haywire.  Trusting hardware to do the FIPS tests is pretty 
silly, since you're trusting the piece that might go haywire to tell you 
its OK.  RNGs have a history of suddenly providing non-random data, for 
a variety of reasons (usually poor board wiring).

We also want the userspace daemon because that gives the sysadmin far 
more control over how much entropy is added to the system.  99.9% of the 
cases in the real world, we don't want the RNG pumping entropy into the 
pool at full speed.  That will likely pump in more data than a system 
needs, chewing CPU.  The admin can't even kill the daemon to reclaim his 
CPU, if its all in-kernel.

It's not brain surgery, to concoct a method by which an interrupt-driven 
device is used from userspace.

	Jeff



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 0/5] RNG cleanup & new drivers attempt #1
  2005-10-19 15:01 ` [patch 0/5] RNG cleanup & new drivers attempt #1 Jeff Garzik
@ 2005-10-19 17:25   ` Deepak Saxena
  0 siblings, 0 replies; 16+ messages in thread
From: Deepak Saxena @ 2005-10-19 17:25 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-kernel, jgarzik, akpm, tony

On Oct 19 2005, at 11:01, Jeff Garzik was caught saying:
> Not interesting in pursuing this path.  This has been discussed 
> endlessly, check the archives.
> 
> We want the FIPS tests.  Hardware (especially cheap hardware) is often 
> known to go haywire.  Trusting hardware to do the FIPS tests is pretty 
> silly, since you're trusting the piece that might go haywire to tell you 
> its OK.  RNGs have a history of suddenly providing non-random data, for 
> a variety of reasons (usually poor board wiring).
> 
> We also want the userspace daemon because that gives the sysadmin far 
> more control over how much entropy is added to the system.  99.9% of the 
> cases in the real world, we don't want the RNG pumping entropy into the 
> pool at full speed.  That will likely pump in more data than a system 
> needs, chewing CPU.  The admin can't even kill the daemon to reclaim his 
> CPU, if its all in-kernel.

OK, understood. But other than the fastpath idea, are you OK with 
the direction I took with the code?

~Deepak

-- 
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

When law and duty are one, united by religion, you never become fully
conscious, fully aware of yourself. You are always a little less than
an individual. - Frank Herbert

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 5/5] TI OMAP driver
  2005-10-19  9:44     ` Deepak Saxena
@ 2005-10-21 16:35       ` Tony Lindgren
  2005-10-21 18:00         ` Tony Lindgren
  0 siblings, 1 reply; 16+ messages in thread
From: Tony Lindgren @ 2005-10-21 16:35 UTC (permalink / raw)
  To: Deepak Saxena; +Cc: Eric Piel, linux-kernel

* Deepak Saxena <dsaxena@plexity.net> [051019 12:45]:
> On Oct 19 2005, at 11:36, Eric Piel was caught saying:
> > >+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 
> > >level)
> > >+{
> > >+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
> > >+
> > >+	return 0;
> > >+}
> > >+
> > >+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 
> > >level)
> > >+{
> > >+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
> > >+
> > >+	return 1;
> > >+}
> > Probably one of them should be called omap_rng_resume() ?
> > 
> > Eric
> 
> Tnx!
> 
> ~Deepak

Cool, works on OMAP OSK after renaming the function above.

Tony

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 5/5] TI OMAP driver
  2005-10-21 16:35       ` Tony Lindgren
@ 2005-10-21 18:00         ` Tony Lindgren
  2005-10-21 19:10           ` Tony Lindgren
  0 siblings, 1 reply; 16+ messages in thread
From: Tony Lindgren @ 2005-10-21 18:00 UTC (permalink / raw)
  To: Deepak Saxena; +Cc: Eric Piel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 382 bytes --]

Hi,

* Tony Lindgren <tony@atomide.com> [051021 19:38]:
> 
> Cool, works on OMAP OSK after renaming the function above.

Looks like the following __iomem patch is needed for this to
work on OMAP H4.

At least these two compilers get confused without the following
patch:

arm-xscale-linux-gnu-gcc (GCC) 3.4.4
gcc version 3.4.3 (release) (CodeSourcery ARM Q1B 2005)

Regards,

Tony


[-- Attachment #2: patch-omap-rng-24xx --]
[-- Type: text/plain, Size: 288 bytes --]

--- a/drivers/char/rng/omap-rng.c
+++ b/drivers/char/rng/omap-rng.c
@@ -51,7 +51,7 @@
 #define RNG_SYSSTATUS		0x44		/* System status
 							[0] = RESETDONE */
 
-static u32 __iomem *rng_base;
+static void __iomem *rng_base;
 static struct clk *rng_ick;
 static struct device *rng_dev;
 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 5/5] TI OMAP driver
  2005-10-21 18:00         ` Tony Lindgren
@ 2005-10-21 19:10           ` Tony Lindgren
  2005-10-23 18:12             ` Deepak Saxena
  0 siblings, 1 reply; 16+ messages in thread
From: Tony Lindgren @ 2005-10-21 19:10 UTC (permalink / raw)
  To: Deepak Saxena; +Cc: Eric Piel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 659 bytes --]

* Tony Lindgren <tony@atomide.com> [051021 21:03]:
> Hi,
> 
> * Tony Lindgren <tony@atomide.com> [051021 19:38]:
> > 
> > Cool, works on OMAP OSK after renaming the function above.
> 
> Looks like the following __iomem patch is needed for this to
> work on OMAP H4.
> 
> At least these two compilers get confused without the following
> patch:
> 
> arm-xscale-linux-gnu-gcc (GCC) 3.4.4
> gcc version 3.4.3 (release) (CodeSourcery ARM Q1B 2005)

Here's one more patch on top of my previous patch. Now it's
tested to work on 24xx too in addition to 16xx. The status
bit did not work on 24xx earlier, and looks like the status
bit is always ready on 16xx.

Tony

[-- Attachment #2: patch-omap-rng-24xx-works --]
[-- Type: text/plain, Size: 368 bytes --]

--- a/drivers/char/rng/omap-rng.c
+++ b/drivers/char/rng/omap-rng.c
@@ -65,9 +65,10 @@
 	__raw_writel(val, rng_base + reg);
 }
 
+/* REVISIT: Does the status bit really work on 16xx? */
 static int omap_rng_data_present(void)
 {
-	return omap_rng_read_reg(RNG_STAT_REG);
+	return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
 }
 
 static int omap_rng_data_read(u32 *data)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 5/5] TI OMAP driver
  2005-10-21 19:10           ` Tony Lindgren
@ 2005-10-23 18:12             ` Deepak Saxena
  0 siblings, 0 replies; 16+ messages in thread
From: Deepak Saxena @ 2005-10-23 18:12 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: Eric Piel, linux-kernel

On Oct 21 2005, at 22:10, Tony Lindgren was caught saying:
> * Tony Lindgren <tony@atomide.com> [051021 21:03]:
> 
> Here's one more patch on top of my previous patch. Now it's
> tested to work on 24xx too in addition to 16xx. The status
> bit did not work on 24xx earlier, and looks like the status
> bit is always ready on 16xx.
> 
> Tony

Tnx! I'll roll these in next time I post the patches.

~Deepak

-- 
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

When law and duty are one, united by religion, you never become fully
conscious, fully aware of yourself. You are always a little less than
an individual. - Frank Herbert

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [patch 2/5] Core HW RNG support
  2005-10-19  8:19 ` [patch 2/5] Core HW RNG support dsaxena
@ 2005-10-24 10:45   ` Pavel Machek
  0 siblings, 0 replies; 16+ messages in thread
From: Pavel Machek @ 2005-10-24 10:45 UTC (permalink / raw)
  To: dsaxena; +Cc: linux-kernel, jgarzik, akpm, tony

Hi!

> This patch adds support for the HW RNG core. The core code
> simply implements the user space interface and calls HW-specific
> function pointers to do the real data gathering. We do this
> instead of having each driver re-implement the user space functionality
> so we do not end up with a bunch of drivers replicating the exact 
> same 50 lines of code (see drivers/watchdog). 
> 
> Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
> 

> Index: linux-2.6-rng/drivers/char/rng/Makefile
> ===================================================================
> --- /dev/null
> +++ linux-2.6-rng/drivers/char/rng/Makefile

Could we have it named drivers/char/random, or perhaps just
drivers/random?

							Pavel

-- 
Thanks, Sharp!

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [patch 5/5] TI OMAP driver
  2005-10-29 19:12 [patch 0/5] HW RNG cleanup & new drivers Deepak Saxena
@ 2005-10-29 19:12 ` Deepak Saxena
  0 siblings, 0 replies; 16+ messages in thread
From: Deepak Saxena @ 2005-10-29 19:12 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, jgarzik, tony

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: rng/rng_omap_driver.patch --]
[-- Type: text/plain, Size: 4978 bytes --]

This patch implements the OMAP RNG driver. 

Signed-off-by: Deepak Saxena <dsaxena@plexity.net>

Index: linux-2.6-rng/drivers/char/rng/omap-rng.c
===================================================================
--- /dev/null
+++ linux-2.6-rng/drivers/char/rng/omap-rng.c
@@ -0,0 +1,209 @@
+/*
+ * driver/char/rng/omap-rng.c
+ *
+ * RNG driver for TI OMAP CPU family
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Mostly based on original driver:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * 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.
+ *
+ * TODO:
+ *
+ * - Make status updated be interrupt driven so we don't poll
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/hardware/clock.h>
+
+#include "rng.h"
+
+#define RNG_OUT_REG		0x00		/* Output register */
+#define RNG_STAT_REG		0x04		/* Status register
+							[0] = STAT_BUSY */
+#define RNG_ALARM_REG		0x24		/* Alarm register
+							[7:0] = ALARM_COUNTER */
+#define RNG_CONFIG_REG		0x28		/* Configuration register
+							[11:6] = RESET_COUNT
+							[5:3]  = RING2_DELAY
+							[2:0]  = RING1_DELAY */
+#define RNG_REV_REG		0x3c		/* Revision register
+							[7:0] = REV_NB */
+#define RNG_MASK_REG		0x40		/* Mask and reset register
+							[2] = IT_EN
+							[1] = SOFTRESET
+							[0] = AUTOIDLE */
+#define RNG_SYSSTATUS		0x44		/* System status
+							[0] = RESETDONE */
+
+static void __iomem *rng_base;
+static struct clk *rng_ick;
+static struct device *rng_dev;
+
+static u32 omap_rng_read_reg(int reg)
+{
+	return __raw_readl(rng_base + reg);
+}
+
+static void omap_rng_write_reg(int reg, u32 val)
+{
+	__raw_writel(val, rng_base + reg);
+}
+
+/* REVISIT: Does the status bit really work on 16xx? */
+static int omap_rng_data_present(void)
+{
+	return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+}
+
+static int omap_rng_data_read(u32 *data)
+{
+	*data = omap_rng_read_reg(RNG_OUT_REG);
+
+	return 4;
+}
+
+static struct rng_operations omap_rng_ops = {
+	.data_present	= omap_rng_data_present,
+	.data_read	= omap_rng_data_read,
+};
+
+static int __init omap_rng_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res, *mem;
+	int ret;
+
+	/*
+	 * A bit ugly, and it will never actually happen but there can
+	 * be only one RNG and this catches any bork
+	 */
+	if (rng_dev)
+		BUG();
+
+    	if (cpu_is_omap24xx()) {
+		rng_ick = clk_get(NULL, "rng_ick");
+		if (IS_ERR(rng_ick)) {
+			dev_err(dev, "Could not get rng_ick\n");
+			ret = PTR_ERR(rng_ick);
+			return ret;
+		}
+		else {
+			clk_use(rng_ick);
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res)
+		return -ENOENT;
+
+	mem = request_mem_region(res->start, res->end - res->start + 1,
+				 pdev->name);
+	if (mem == NULL)
+		return -EBUSY;
+
+	dev_set_drvdata(dev, mem);
+	rng_base = (u32 __iomem *)io_p2v(res->start);
+
+	ret = register_rng(&omap_rng_ops);
+	if (ret) {
+		release_resource(mem);
+		rng_base = NULL;
+		return ret;
+	}
+
+	dev_info(dev, "OMAP Random Number Generator ver. %02x\n",
+		omap_rng_read_reg(RNG_REV_REG));
+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
+
+	rng_dev = dev;
+
+	return 0;
+}
+
+static int __exit omap_rng_remove(struct device *dev)
+{
+	struct resource *mem = dev_get_drvdata(dev);
+
+	unregister_rng(&omap_rng_ops);
+
+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
+
+	if (cpu_is_omap24xx()) {
+		clk_unuse(rng_ick);
+		clk_put(rng_ick);
+	}
+
+	release_resource(mem);
+	rng_base = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)
+{
+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
+
+	return 0;
+}
+
+static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level)
+{
+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
+
+	return 1;
+}
+
+#else
+
+#define	omap_rng_suspend	NULL
+#define	omap_rng_resume		NULL
+
+#endif
+
+
+static struct device_driver omap_rng_driver = {
+	.name		= "omap_rng",
+	.bus		= &platform_bus_type,
+	.probe		= omap_rng_probe,
+	.remove		= __exit_p(omap_rng_remove),
+	.suspend	= omap_rng_suspend,
+	.resume		= omap_rng_resume
+};
+
+static int __init omap_rng_init(void)
+{
+	if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
+		return -ENODEV;
+
+	return driver_register(&omap_rng_driver);
+}
+
+static void __exit omap_rng_exit(void)
+{
+	driver_unregister(&omap_rng_driver);
+}
+
+module_init(omap_rng_init);
+module_exit(omap_rng_exit);
+
+MODULE_AUTHOR("Deepak Saxena (and others)");
+MODULE_LICENSE("GPL");

--
Deepak Saxena - dsaxena@plexity.net - http://www.plexity.net

Even a stopped clock gives the right time twice a day.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2005-10-29 19:25 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-10-19  8:19 [patch 0/5] RNG cleanup & new drivers attempt #1 dsaxena
2005-10-19  8:19 ` [patch 1/5] Remove existing hw_random implementation dsaxena
2005-10-19  8:19 ` [patch 2/5] Core HW RNG support dsaxena
2005-10-24 10:45   ` Pavel Machek
2005-10-19  8:19 ` [patch 3/5] Intel IXP4xx driver dsaxena
2005-10-19  8:19 ` [patch 4/5] x86 driver dsaxena
2005-10-19  8:19 ` [patch 5/5] TI OMAP driver dsaxena
2005-10-19  9:36   ` Eric Piel
2005-10-19  9:44     ` Deepak Saxena
2005-10-21 16:35       ` Tony Lindgren
2005-10-21 18:00         ` Tony Lindgren
2005-10-21 19:10           ` Tony Lindgren
2005-10-23 18:12             ` Deepak Saxena
2005-10-19 15:01 ` [patch 0/5] RNG cleanup & new drivers attempt #1 Jeff Garzik
2005-10-19 17:25   ` Deepak Saxena
  -- strict thread matches above, loose matches on Subject: below --
2005-10-29 19:12 [patch 0/5] HW RNG cleanup & new drivers Deepak Saxena
2005-10-29 19:12 ` [patch 5/5] TI OMAP driver Deepak Saxena

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox