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 7e6ac14..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>
  
@@ -95,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);
@@ -121,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[] = {
@@ -139,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 }
 };
 
 /*
@@ -155,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);
@@ -460,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;
+}
 
 /***********************************************************************
  *
@@ -513,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 ?? */
 
@@ -577,9 +645,9 @@ static int __init rng_init (void)
 
        DPRINTK ("ENTER\n");
 
-       /* Probe for Intel, AMD RNGs */
+       /* Probe for Intel, AMD, Geode RNGs */
        for_each_pci_dev(pdev) {
-               ent = pci_match_device (rng_pci_tbl, pdev);
+               ent = pci_match_id(rng_pci_tbl, pdev);
                if (ent) {
                        rng_ops = &rng_vendor_ops[ent->driver_data];
                        goto match;