Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / char / hw_random.c
index 090ce07..29dc87e 100644 (file)
@@ -1,4 +1,9 @@
 /*
+        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);
@@ -99,6 +100,11 @@ static unsigned int via_data_present (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);
@@ -125,7 +131,10 @@ enum {
        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[] = {
@@ -143,6 +152,9 @@ 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 }
 };
 
 /*
@@ -159,10 +171,14 @@ static struct pci_device_id rng_pci_tbl[] = {
 
        { 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);
@@ -191,7 +207,7 @@ 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)
 {
@@ -322,7 +338,8 @@ static int __init amd_init (struct pci_dev *dev)
        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;
 
@@ -369,7 +386,7 @@ enum {
        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
@@ -463,6 +480,57 @@ static void via_cleanup(void)
 }
 #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;
+}
 
 /***********************************************************************
  *
@@ -483,9 +551,9 @@ 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 spinlock_t rng_lock = SPIN_LOCK_UNLOCKED;
+       static DEFINE_SPINLOCK(rng_lock);
        unsigned int have_data;
        u32 data = 0;
        ssize_t ret = 0;
@@ -516,10 +584,7 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
                        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 ?? */
 
@@ -580,9 +645,9 @@ static int __init rng_init (void)
 
        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;
@@ -606,7 +671,7 @@ 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;