/*
+ Added support for the AMD Geode LX RNG
+ (c) Copyright 2004-2005 Advanced Micro Devices, Inc.
+
+ derived from
+
Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
/*
* debugging macros
*/
-#undef RNG_DEBUG /* define to enable copious debugging info */
-#ifdef RNG_DEBUG
-/* note: prints function name for you */
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
+/* 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_NDEBUG /* define to disable lightweight runtime checks */
+#undef RNG_NDEBUG /* define to enable lightweight runtime checks */
#ifdef RNG_NDEBUG
-#define assert(expr)
+#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) \
- if(!(expr)) { \
- printk( "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
+#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);
+ loff_t * offp);
static int __init intel_init (struct pci_dev *dev);
static void intel_cleanup(void);
static u32 via_data_read (void);
#endif
+static int __init geode_init(struct pci_dev *dev);
+static void geode_cleanup(void);
+static unsigned int geode_data_present (void);
+static u32 geode_data_read (void);
+
struct rng_operations {
int (*init) (struct pci_dev *dev);
void (*cleanup) (void);
rng_hw_none,
rng_hw_intel,
rng_hw_amd,
+#ifdef __i386__
rng_hw_via,
+#endif
+ rng_hw_geode,
};
static struct rng_operations rng_vendor_ops[] = {
/* rng_hw_via */
{ via_init, via_cleanup, via_data_present, via_data_read, 1 },
#endif
+
+ /* rng_hw_geode */
+ { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 }
};
/*
{ 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, 0x2430, 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 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode },
+
{ 0, }, /* terminate list */
};
MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
#define INTEL_RNG_ADDR_LEN 3
/* token to our ioremap'd RNG register area */
-static void *rng_mem;
+static void __iomem *rng_mem;
static inline u8 intel_hwstatus (void)
{
rnen |= (1 << 7); /* PMIO enable */
pci_write_config_byte(dev, 0x41, rnen);
- printk(KERN_INFO PFX "AMD768 system management I/O registers at 0x%X.\n", pmbase);
+ pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n",
+ pmbase);
amd_dev = dev;
VIA_RNG_CHUNK_1_MASK = 0xFF,
};
-u32 via_rng_datum;
+static u32 via_rng_datum;
/*
* Investigate using the 'rep' prefix to obtain 32 bits of random data
}
#endif
+/***********************************************************************
+ *
+ * AMD Geode RNG operations
+ *
+ */
+
+static void __iomem *geode_rng_base = NULL;
+
+#define GEODE_RNG_DATA_REG 0x50
+#define GEODE_RNG_STATUS_REG 0x54
+
+static u32 geode_data_read(void)
+{
+ u32 val;
+
+ assert(geode_rng_base != NULL);
+ val = readl(geode_rng_base + GEODE_RNG_DATA_REG);
+ return val;
+}
+
+static unsigned int geode_data_present(void)
+{
+ u32 val;
+
+ assert(geode_rng_base != NULL);
+ val = readl(geode_rng_base + GEODE_RNG_STATUS_REG);
+ return val;
+}
+
+static void geode_cleanup(void)
+{
+ iounmap(geode_rng_base);
+ geode_rng_base = NULL;
+}
+
+static int geode_init(struct pci_dev *dev)
+{
+ unsigned long rng_base = pci_resource_start(dev, 0);
+
+ if (rng_base == 0)
+ return 1;
+
+ geode_rng_base = ioremap(rng_base, 0x58);
+
+ if (geode_rng_base == NULL) {
+ printk(KERN_ERR PFX "Cannot ioremap RNG memory\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
/***********************************************************************
*
static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
- loff_t * offp)
+ loff_t * offp)
{
- static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED;
+ static DEFINE_SPINLOCK(rng_lock);
unsigned int have_data;
u32 data = 0;
ssize_t ret = 0;
return ret ? : -EAGAIN;
if(need_resched())
- {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- }
+ schedule_timeout_interruptible(1);
else
udelay(200); /* FIXME: We could poll for 250uS ?? */
DPRINTK ("ENTER\n");
- /* Probe for Intel, AMD RNGs */
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- ent = pci_match_device (rng_pci_tbl, pdev);
+ /* Probe for Intel, AMD, Geode 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;
if (rc)
return rc;
- printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
+ pr_info( RNG_DRIVER_NAME " loaded\n");
DPRINTK ("EXIT, returning 0\n");
return 0;