RNG cleanup & new drivers attempt #1
cover RNG cleanup & new drivers attempt #1
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 - [email protected] - http://www.plexity.net
Even a stopped clock gives the right time twice a day.
PATCH 1/5 Remove existing hw_random implementation
Remove existing hw_random implementation so that it can be replaced with a generic cross-architecture RNG codebase.
drivers/char/Kconfig +0 -15
@@ -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
drivers/char/Makefile +0 -1
@@ -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
drivers/char/hw_random.c deleted +0 -627
627 lines not on this page · raw message
--
Deepak Saxena - [email protected] - http://www.plexity.net
Even a stopped clock gives the right time twice a day.
PATCH 2/5 Core HW RNG support
In reply to [email protected]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).
drivers/char/Makefile +1 -0
@@ -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/
drivers/char/rng/Makefile new file +8 -0
@@ -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 +
drivers/char/rng/core.c new file +141 -0
141 lines not on this page · raw message
drivers/char/rng/rng.h new file +24 -0
@@ -0,0 +1,24 @@ +/* +* driver/char/rng/rng.h +* +* RNG definitions shared by drivers +* +* Author: Deepak Saxena <[email protected]> +* +* 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 *);
drivers/char/rng/Kconfig new file +46 -0
46 lines not on this page · raw message
drivers/char/Kconfig +2 -0
@@ -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 - [email protected] - http://www.plexity.net
Even a stopped clock gives the right time twice a day.
Re: [patch 2/5] Core HW RNG support
Hi!
drivers/char/rng/Makefile
Quoted 14 lines
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 <[email protected]>Index: linux-2.6-rng/drivers/char/rng/Makefile
===================================================================drivers/char/rng/Makefile new file +0
-0
Could we have it named drivers/char/random, or perhaps just drivers/random?
Pavel
Signature · 1 line
Thanks, Sharp!
PATCH 3/5 Intel IXP4xx driver
In reply to [email protected]RNG driver for Intel IXP4xx NPU.
---
Tested and works.
drivers/char/rng/ixp4xx-rng.c new file +66 -0
@@ -0,0 +1,66 @@ +/* +* drivers/char/rng/ixp4xx-rng.c +* +* RNG driver for Intel IXP4xx family of NPUs +* +* Author: Deepak Saxena <[email protected]> +* +* 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 <[email protected]>" ); +MODULE_DESCRIPTION ("H/W Random Number Generator (RNG) driver for IXP4xx" ); +MODULE_LICENSE ("GPL" );
include/asm-arm/arch-ixp4xx/ixp4xx-regs.h +2 -0
@@ -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 - [email protected] - http://www.plexity.net
Even a stopped clock gives the right time twice a day.
PATCH 4/5 x86 driver
In reply to [email protected]x86 RNG driver. This is basically the existing driver with the user space interface bits ripped out.
---
This builds but I have not tested it yet as I do not have the needed HW.
drivers/char/rng/x86-rng.c new file +528 -0
@@ -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 <[email protected]> +* +* derived from +* +* Hardware driver for the AMD 768 Random Number Generator (RNG) +* (c) Copyright 2001 Red Hat Inc <[email protected]> +* +* derived from +* +* Hardware driver for Intel i810 Random Number Generator (RNG) +* Copyright 2000,2001 Jeff Garzik <[email protected]> +* Copyright 2000,2001 Philipp Rumpf <[email protected]> +* +* 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 - [email protected] - http://www.plexity.net
Even a stopped clock gives the right time twice a day.
PATCH 5/5 TI OMAP driver
In reply to [email protected]This patch implements the OMAP RNG driver.
---
Builts but untested as I do not hardware.
drivers/char/rng/omap-rng.c new file +208 -0
@@ -0,0 +1,208 @@ +/* +* driver/char/rng/omap-rng.c +* +* RNG driver for TI OMAP CPU family +* +* Author: Deepak Saxena <[email protected]> +* +* Copyright 2005 (c) MontaVista Software, Inc. +* +* Mostly based on original driver: +* +* Copyright (C) 2005 Nokia Corporation +* Author: Juha Yrj�l� <[email protected]> +* +* 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 - [email protected] - http://www.plexity.net
Even a stopped clock gives the right time twice a day.
Re: [patch 5/5] TI OMAP driver
Quoted 18 lines · 10/19/2005 10:19 AM, [email protected] wrote/a écrit:
This patch implements the OMAP RNG driver.
Signed-off-by Deepak Saxena <[email protected]>---
Builts but untested as I do not hardware.
Index:
linux-omap-2.6/drivers/char/rng/omap-rng.c
===================================================================drivers/char/rng/omap-rng.c new file +5
-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 );
drivers/char/rng/omap-rng.c line 172
Quoted 10 lines
drivers/char/rng/omap-rng.c new file +10
-0+ +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
Re: [patch 5/5] TI OMAP driver
On Oct 19 2005, at 11:36, Eric Piel was caught saying:
Quoted 17 lines
Quoted 10 lines
+static int
omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)drivers/char/rng/omap-rng.c new file +7
-0+{ +omap_rng_write_reg (RNG_MASK_REG ,0x0 ); + +return 0 ; +} + +static int omap_rng_suspend(struct device *dev, pm_message_t message, u32level)
drivers/char/rng/omap-rng.c line 172
Quoted 5 lines
drivers/char/rng/omap-rng.c new file +5
-0+{ +omap_rng_write_reg (RNG_MASK_REG ,0x1 ); + +return 1 ; +}Probably one of them should be called
omap_rng_resume()?
Quoted 1 line
Eric
Tnx!
~Deepak
Signature · 5 lines
Deepak Saxena - [email protected] - 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
Re: [patch 5/5] TI OMAP driver
Quoted 18 lines · Deepak Saxena
On Oct 19 2005, at 11:36, Eric Piel was caught saying:
Quoted 17 lines
Quoted 10 lines
+static int
omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)drivers/char/rng/omap-rng.c new file +7
-0+{ +omap_rng_write_reg (RNG_MASK_REG ,0x0 ); + +return 0 ; +} + +static int omap_rng_suspend(struct device *dev, pm_message_t message, u32level)
drivers/char/rng/omap-rng.c line 172
Quoted 5 lines
drivers/char/rng/omap-rng.c new file +5
-0+{ +omap_rng_write_reg (RNG_MASK_REG ,0x1 ); + +return 1 ; +}Probably one of them should be called
omap_rng_resume()?
Quoted 5 lines
Quoted 1 line
Eric
Tnx!
~Deepak
Cool, works on OMAP OSK after renaming the function above.
Tony
Re: [patch 5/5] TI OMAP driver
Hi,
Quoted 2 lines · Tony Lindgren
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
drivers/char/rng/omap-rng.c +1 -1
@@ -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;
Re: [patch 5/5] TI OMAP driver
Quoted 6 lines · Tony Lindgren
Hi,
Quoted 2 lines · Tony Lindgren
Cool, works on OMAP OSK after renaming the function above.
Quoted 8 lines
Looks like the following
__iomempatch 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
drivers/char/rng/omap-rng.c +2 -1
@@ -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)
Re: [patch 5/5] TI OMAP driver
On Oct 21 2005, at 22:10, Tony Lindgren was caught saying:
Quoted 8 lines · Tony Lindgren
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
Signature · 5 lines
Deepak Saxena - [email protected] - 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
Quoted 11 lines · [email protected] 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
On Oct 19 2005, at 11:01, Jeff Garzik was caught saying:
Quoted 9 lines
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).
Quoted 6 lines
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
Signature · 5 lines
Deepak Saxena - [email protected] - 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