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 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 <linux/delay.h> 32 #include <asm/io.h> 33 34 35 #define PFX KBUILD_MODNAME ": " 36 37 #define GEODE_RNG_DATA_REG 0x50 38 #define GEODE_RNG_STATUS_REG 0x54 39 40 /* 41 * Data for PCI driver interface 42 * 43 * This data only exists for exporting the supported 44 * PCI ids via MODULE_DEVICE_TABLE. We do not actually 45 * register a pci_driver, because someone else might one day 46 * want to register another driver on the same PCI id. 47 */ 48 static const struct pci_device_id pci_tbl[] = { 49 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, 50 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, 51 { 0, }, /* terminate list */ 52 }; 53 MODULE_DEVICE_TABLE(pci, pci_tbl); 54 55 56 static int geode_rng_data_read(struct hwrng *rng, u32 *data) 57 { 58 void __iomem *mem = (void __iomem *)rng->priv; 59 60 *data = readl(mem + GEODE_RNG_DATA_REG); 61 62 return 4; 63 } 64 65 static int geode_rng_data_present(struct hwrng *rng, int wait) 66 { 67 void __iomem *mem = (void __iomem *)rng->priv; 68 int data, i; 69 70 for (i = 0; i < 20; i++) { 71 data = !!(readl(mem + GEODE_RNG_STATUS_REG)); 72 if (data || !wait) 73 break; 74 udelay(10); 75 } 76 return data; 77 } 78 79 80 static struct hwrng geode_rng = { 81 .name = "geode", 82 .data_present = geode_rng_data_present, 83 .data_read = geode_rng_data_read, 84 }; 85 86 87 static int __init mod_init(void) 88 { 89 int err = -ENODEV; 90 struct pci_dev *pdev = NULL; 91 const struct pci_device_id *ent; 92 void __iomem *mem; 93 unsigned long rng_base; 94 95 for_each_pci_dev(pdev) { 96 ent = pci_match_id(pci_tbl, pdev); 97 if (ent) 98 goto found; 99 } 100 /* Device not found. */ 101 goto out; 102 103 found: 104 rng_base = pci_resource_start(pdev, 0); 105 if (rng_base == 0) 106 goto out; 107 err = -ENOMEM; 108 mem = ioremap(rng_base, 0x58); 109 if (!mem) 110 goto out; 111 geode_rng.priv = (unsigned long)mem; 112 113 printk(KERN_INFO "AMD Geode RNG detected\n"); 114 err = hwrng_register(&geode_rng); 115 if (err) { 116 printk(KERN_ERR PFX "RNG registering failed (%d)\n", 117 err); 118 goto err_unmap; 119 } 120 out: 121 return err; 122 123 err_unmap: 124 iounmap(mem); 125 goto out; 126 } 127 128 static void __exit mod_exit(void) 129 { 130 void __iomem *mem = (void __iomem *)geode_rng.priv; 131 132 hwrng_unregister(&geode_rng); 133 iounmap(mem); 134 } 135 136 module_init(mod_init); 137 module_exit(mod_exit); 138 139 MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); 140 MODULE_LICENSE("GPL"); 141