* 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);
.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[] =
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;
}
* 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)
/* 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)