1 /* 2 * RNG driver for AMD Geode RNGs 3 * 4 * Copyright 2005 (c) MontaVista Software, Inc. 5 * 6 * with the majority of the code coming from: 7 * 8 * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) 9 * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> 10 * 11 * derived from 12 * 13 * Hardware driver for the AMD 768 Random Number Generator (RNG) 14 * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> 15 * 16 * derived from 17 * 18 * Hardware driver for Intel i810 Random Number Generator (RNG) 19 * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> 20 * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> 21 * 22 * This file is licensed under the terms of the GNU General Public 23 * License version 2. This program is licensed "as is" without any 24 * warranty of any kind, whether express or implied. 25 */ 26 27 #include <linux/module.h> 28 #include <linux/kernel.h> 29 #include <linux/pci.h> 30 #include <linux/hw_random.h> 31 #include <asm/io.h> 32 33 34 #define PFX KBUILD_MODNAME ": " 35 36 #define GEODE_RNG_DATA_REG 0x50 37 #define GEODE_RNG_STATUS_REG 0x54 38 39 /* 40 * Data for PCI driver interface 41 * 42 * This data only exists for exporting the supported 43 * PCI ids via MODULE_DEVICE_TABLE. We do not actually 44 * register a pci_driver, because someone else might one day 45 * want to register another driver on the same PCI id. 46 */ 47 static const struct pci_device_id pci_tbl[] = { 48 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, 49 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, 50 { 0, }, /* terminate list */ 51 }; 52 MODULE_DEVICE_TABLE(pci, pci_tbl); 53 54 55 static int geode_rng_data_read(struct hwrng *rng, u32 *data) 56 { 57 void __iomem *mem = (void __iomem *)rng->priv; 58 59 *data = readl(mem + GEODE_RNG_DATA_REG); 60 61 return 4; 62 } 63 64 static int geode_rng_data_present(struct hwrng *rng) 65 { 66 void __iomem *mem = (void __iomem *)rng->priv; 67 68 return !!(readl(mem + GEODE_RNG_STATUS_REG)); 69 } 70 71 72 static struct hwrng geode_rng = { 73 .name = "geode", 74 .data_present = geode_rng_data_present, 75 .data_read = geode_rng_data_read, 76 }; 77 78 79 static int __init mod_init(void) 80 { 81 int err = -ENODEV; 82 struct pci_dev *pdev = NULL; 83 const struct pci_device_id *ent; 84 void __iomem *mem; 85 unsigned long rng_base; 86 87 for_each_pci_dev(pdev) { 88 ent = pci_match_id(pci_tbl, pdev); 89 if (ent) 90 goto found; 91 } 92 /* Device not found. */ 93 goto out; 94 95 found: 96 rng_base = pci_resource_start(pdev, 0); 97 if (rng_base == 0) 98 goto out; 99 err = -ENOMEM; 100 mem = ioremap(rng_base, 0x58); 101 if (!mem) 102 goto out; 103 geode_rng.priv = (unsigned long)mem; 104 105 printk(KERN_INFO "AMD Geode RNG detected\n"); 106 err = hwrng_register(&geode_rng); 107 if (err) { 108 printk(KERN_ERR PFX "RNG registering failed (%d)\n", 109 err); 110 goto err_unmap; 111 } 112 out: 113 return err; 114 115 err_unmap: 116 iounmap(mem); 117 goto out; 118 } 119 120 static void __exit mod_exit(void) 121 { 122 void __iomem *mem = (void __iomem *)geode_rng.priv; 123 124 hwrng_unregister(&geode_rng); 125 iounmap(mem); 126 } 127 128 module_init(mod_init); 129 module_exit(mod_exit); 130 131 MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); 132 MODULE_LICENSE("GPL"); 133