Merge git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched
[sfrench/cifs-2.6.git] / drivers / char / hw_random / intel-rng.c
index f22e78e3c70ff81f71f3ecc3102fcade8bac958e..753f46052b874abdaa4f56ee55dd4dd2c542f3f5 100644 (file)
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/module.h>
+#include <linux/hw_random.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hw_random.h>
+#include <linux/stop_machine.h>
 #include <asm/io.h>
 
 
  */
 static const struct pci_device_id pci_tbl[] = {
 /* AA
-       { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
-       { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AA */
+       { PCI_DEVICE(0x8086, 0x2418) }, */
+       { PCI_DEVICE(0x8086, 0x2410) }, /* AA */
 /* AB
-       { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
-       { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AB */
+       { PCI_DEVICE(0x8086, 0x2428) }, */
+       { PCI_DEVICE(0x8086, 0x2420) }, /* AB */
 /* ??
-       { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+       { PCI_DEVICE(0x8086, 0x2430) }, */
 /* BAM, CAM, DBM, FBM, GxM
-       { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
-       { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BAM */
-       { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CAM */
-       { 0x8086, 0x24cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DBM */
-       { 0x8086, 0x2641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* FBM */
-       { 0x8086, 0x27b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM */
-       { 0x8086, 0x27bd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM DH */
+       { PCI_DEVICE(0x8086, 0x2448) }, */
+       { PCI_DEVICE(0x8086, 0x244c) }, /* BAM */
+       { PCI_DEVICE(0x8086, 0x248c) }, /* CAM */
+       { PCI_DEVICE(0x8086, 0x24cc) }, /* DBM */
+       { PCI_DEVICE(0x8086, 0x2641) }, /* FBM */
+       { PCI_DEVICE(0x8086, 0x27b9) }, /* GxM */
+       { PCI_DEVICE(0x8086, 0x27bd) }, /* GxM DH */
 /* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx
-       { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
-       { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BA */
-       { 0x8086, 0x2480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CA */
-       { 0x8086, 0x24c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DB */
-       { 0x8086, 0x24d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ex */
-       { 0x8086, 0x25a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 6300 */
-       { 0x8086, 0x2640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Fx */
-       { 0x8086, 0x2670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
-       { 0x8086, 0x27b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Gx */
+       { PCI_DEVICE(0x8086, 0x244e) }, */
+       { PCI_DEVICE(0x8086, 0x2440) }, /* BA */
+       { PCI_DEVICE(0x8086, 0x2480) }, /* CA */
+       { PCI_DEVICE(0x8086, 0x24c0) }, /* DB */
+       { PCI_DEVICE(0x8086, 0x24d0) }, /* Ex */
+       { PCI_DEVICE(0x8086, 0x25a1) }, /* 6300 */
+       { PCI_DEVICE(0x8086, 0x2640) }, /* Fx */
+       { PCI_DEVICE(0x8086, 0x2670) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2671) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2672) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2673) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2674) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2675) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2676) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2677) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2678) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x2679) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x267a) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x267b) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x267c) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x267d) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x267e) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x267f) }, /* 631x/632x */
+       { PCI_DEVICE(0x8086, 0x27b8) }, /* Gx */
 /* E
-       { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
-       { 0x8086, 0x2450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* E  */
+       { PCI_DEVICE(0x8086, 0x245e) }, */
+       { PCI_DEVICE(0x8086, 0x2450) }, /* E  */
        { 0, }, /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, pci_tbl);
@@ -217,52 +218,81 @@ static struct hwrng intel_rng = {
        .data_read      = intel_rng_data_read,
 };
 
+struct intel_rng_hw {
+       struct pci_dev *dev;
+       void __iomem *mem;
+       u8 bios_cntl_off;
+       u8 bios_cntl_val;
+       u8 fwh_dec_en1_off;
+       u8 fwh_dec_en1_val;
+};
 
-#ifdef CONFIG_SMP
-static char __initdata waitflag;
-
-static void __init intel_init_wait(void *unused)
-{
-       while (waitflag)
-               cpu_relax();
-}
-#endif
-
-static int __init mod_init(void)
+static int __init intel_rng_hw_init(void *_intel_rng_hw)
 {
-       int err = -ENODEV;
-       unsigned i;
-       struct pci_dev *dev = NULL;
-       void __iomem *mem;
-       unsigned long flags;
-       u8 bios_cntl_off, fwh_dec_en1_off;
-       u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff;
-       u8 hw_status, mfc, dvc;
+       struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;
+       u8 mfc, dvc;
+
+       /* interrupts disabled in stop_machine_run call */
+
+       if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+               pci_write_config_byte(intel_rng_hw->dev,
+                                     intel_rng_hw->fwh_dec_en1_off,
+                                     intel_rng_hw->fwh_dec_en1_val |
+                                     FWH_F8_EN_MASK);
+       if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
+               pci_write_config_byte(intel_rng_hw->dev,
+                                     intel_rng_hw->bios_cntl_off,
+                                     intel_rng_hw->bios_cntl_val |
+                                     BIOS_CNTL_WRITE_ENABLE_MASK);
+
+       writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+       writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem);
+       mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
+       dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
+       writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+
+       if (!(intel_rng_hw->bios_cntl_val &
+             (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+               pci_write_config_byte(intel_rng_hw->dev,
+                                     intel_rng_hw->bios_cntl_off,
+                                     intel_rng_hw->bios_cntl_val);
+       if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+               pci_write_config_byte(intel_rng_hw->dev,
+                                     intel_rng_hw->fwh_dec_en1_off,
+                                     intel_rng_hw->fwh_dec_en1_val);
 
-       for (i = 0; !dev && pci_tbl[i].vendor; ++i)
-               dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL);
+       if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
+           (dvc != INTEL_FWH_DEVICE_CODE_8M &&
+            dvc != INTEL_FWH_DEVICE_CODE_4M)) {
+               printk(KERN_ERR PFX "FWH not detected\n");
+               return -ENODEV;
+       }
 
-       if (!dev)
-               goto out; /* Device not found. */
+       return 0;
+}
 
-       if (no_fwh_detect < 0) {
-               pci_dev_put(dev);
-               goto fwh_done;
-       }
+static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
+                                       struct pci_dev *dev)
+{
+       intel_rng_hw->bios_cntl_val = 0xff;
+       intel_rng_hw->fwh_dec_en1_val = 0xff;
+       intel_rng_hw->dev = dev;
 
        /* Check for Intel 82802 */
        if (dev->device < 0x2640) {
-               fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
-               bios_cntl_off = BIOS_CNTL_REG_OLD;
+               intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
+               intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD;
        } else {
-               fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
-               bios_cntl_off = BIOS_CNTL_REG_NEW;
+               intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
+               intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW;
        }
 
-       pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
-       pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
+       pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off,
+                            &intel_rng_hw->fwh_dec_en1_val);
+       pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off,
+                            &intel_rng_hw->bios_cntl_val);
 
-       if ((bios_cntl_val &
+       if ((intel_rng_hw->bios_cntl_val &
             (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
            == BIOS_CNTL_LOCK_ENABLE_MASK) {
                static __initdata /*const*/ char warning[] =
@@ -271,18 +301,53 @@ static int __init mod_init(void)
                        KERN_WARNING PFX "you are certain that your system has a functional\n"
                        KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
 
-               pci_dev_put(dev);
                if (no_fwh_detect)
-                       goto fwh_done;
+                       return -ENODEV;
                printk(warning);
-               err = -EBUSY;
+               return -EBUSY;
+       }
+
+       intel_rng_hw->mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
+       if (intel_rng_hw->mem == NULL)
+               return -EBUSY;
+
+       return 0;
+}
+
+
+static int __init mod_init(void)
+{
+       int err = -ENODEV;
+       int i;
+       struct pci_dev *dev = NULL;
+       void __iomem *mem = mem;
+       u8 hw_status;
+       struct intel_rng_hw *intel_rng_hw;
+
+       for (i = 0; !dev && pci_tbl[i].vendor; ++i)
+               dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device,
+                                    NULL);
+
+       if (!dev)
+               goto out; /* Device not found. */
+
+       if (no_fwh_detect < 0) {
+               pci_dev_put(dev);
+               goto fwh_done;
+       }
+
+       intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL);
+       if (!intel_rng_hw) {
+               pci_dev_put(dev);
                goto out;
        }
 
-       mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
-       if (mem == NULL) {
+       err = intel_init_hw_struct(intel_rng_hw, dev);
+       if (err) {
                pci_dev_put(dev);
-               err = -EBUSY;
+               kfree(intel_rng_hw);
+               if (err == -ENODEV)
+                       goto fwh_done;
                goto out;
        }
 
@@ -290,59 +355,18 @@ static int __init mod_init(void)
         * Since the BIOS code/data is going to disappear from its normal
         * location with the Read ID command, all activity on the system
         * must be stopped until the state is back to normal.
+        *
+        * Use stop_machine_run because IPIs can be blocked by disabling
+        * interrupts.
         */
-#ifdef CONFIG_SMP
-       set_mb(waitflag, 1);
-       if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) {
-               set_mb(waitflag, 0);
-               pci_dev_put(dev);
-               printk(KERN_ERR PFX "cannot run on all processors\n");
-               err = -EAGAIN;
-               goto err_unmap;
-       }
-#endif
-       local_irq_save(flags);
-
-       if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
-               pci_write_config_byte(dev,
-                                     fwh_dec_en1_off,
-                                     fwh_dec_en1_val | FWH_F8_EN_MASK);
-       if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
-               pci_write_config_byte(dev,
-                                     bios_cntl_off,
-                                     bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
-
-       writeb(INTEL_FWH_RESET_CMD, mem);
-       writeb(INTEL_FWH_READ_ID_CMD, mem);
-       mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
-       dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
-       writeb(INTEL_FWH_RESET_CMD, mem);
-
-       if (!(bios_cntl_val &
-             (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
-               pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val);
-       if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
-               pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val);
-
-       local_irq_restore(flags);
-#ifdef CONFIG_SMP
-       /* Tell other CPUs to resume. */
-       set_mb(waitflag, 0);
-#endif
-
-       iounmap(mem);
+       err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS);
        pci_dev_put(dev);
-
-       if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
-           (dvc != INTEL_FWH_DEVICE_CODE_8M &&
-            dvc != INTEL_FWH_DEVICE_CODE_4M)) {
-               printk(KERN_ERR PFX "FWH not detected\n");
-               err = -ENODEV;
+       iounmap(intel_rng_hw->mem);
+       kfree(intel_rng_hw);
+       if (err)
                goto out;
-       }
 
 fwh_done:
-
        err = -ENOMEM;
        mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
        if (!mem)
@@ -352,22 +376,21 @@ fwh_done:
        /* Check for Random Number Generator */
        err = -ENODEV;
        hw_status = hwstatus_get(mem);
-       if ((hw_status & INTEL_RNG_PRESENT) == 0)
-               goto err_unmap;
+       if ((hw_status & INTEL_RNG_PRESENT) == 0) {
+               iounmap(mem);
+               goto out;
+       }
 
        printk(KERN_INFO "Intel 82802 RNG detected\n");
        err = hwrng_register(&intel_rng);
        if (err) {
                printk(KERN_ERR PFX "RNG registering failed (%d)\n",
                       err);
-               goto err_unmap;
+               iounmap(mem);
        }
 out:
        return err;
 
-err_unmap:
-       iounmap(mem);
-       goto out;
 }
 
 static void __exit mod_exit(void)