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/delay.h> 28 #include <linux/hw_random.h> 29 #include <linux/io.h> 30 #include <linux/kernel.h> 31 #include <linux/module.h> 32 #include <linux/pci.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_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), 0, }, 50 { 0, }, /* terminate list */ 51 }; 52 MODULE_DEVICE_TABLE(pci, pci_tbl); 53 54 struct amd_geode_priv { 55 struct pci_dev *pcidev; 56 void __iomem *membase; 57 }; 58 59 static int geode_rng_data_read(struct hwrng *rng, u32 *data) 60 { 61 struct amd_geode_priv *priv = (struct amd_geode_priv *)rng->priv; 62 void __iomem *mem = priv->membase; 63 64 *data = readl(mem + GEODE_RNG_DATA_REG); 65 66 return 4; 67 } 68 69 static int geode_rng_data_present(struct hwrng *rng, int wait) 70 { 71 struct amd_geode_priv *priv = (struct amd_geode_priv *)rng->priv; 72 void __iomem *mem = priv->membase; 73 int data, i; 74 75 for (i = 0; i < 20; i++) { 76 data = !!(readl(mem + GEODE_RNG_STATUS_REG)); 77 if (data || !wait) 78 break; 79 udelay(10); 80 } 81 return data; 82 } 83 84 85 static struct hwrng geode_rng = { 86 .name = "geode", 87 .data_present = geode_rng_data_present, 88 .data_read = geode_rng_data_read, 89 }; 90 91 92 static int __init geode_rng_init(void) 93 { 94 int err = -ENODEV; 95 struct pci_dev *pdev = NULL; 96 const struct pci_device_id *ent; 97 void __iomem *mem; 98 unsigned long rng_base; 99 struct amd_geode_priv *priv; 100 101 for_each_pci_dev(pdev) { 102 ent = pci_match_id(pci_tbl, pdev); 103 if (ent) 104 goto found; 105 } 106 /* Device not found. */ 107 return err; 108 109 found: 110 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 111 if (!priv) { 112 err = -ENOMEM; 113 goto put_dev; 114 } 115 116 rng_base = pci_resource_start(pdev, 0); 117 if (rng_base == 0) 118 goto free_priv; 119 err = -ENOMEM; 120 mem = ioremap(rng_base, 0x58); 121 if (!mem) 122 goto free_priv; 123 124 geode_rng.priv = (unsigned long)priv; 125 priv->membase = mem; 126 priv->pcidev = pdev; 127 128 pr_info("AMD Geode RNG detected\n"); 129 err = hwrng_register(&geode_rng); 130 if (err) { 131 pr_err(PFX "RNG registering failed (%d)\n", 132 err); 133 goto err_unmap; 134 } 135 return err; 136 137 err_unmap: 138 iounmap(mem); 139 free_priv: 140 kfree(priv); 141 put_dev: 142 pci_dev_put(pdev); 143 return err; 144 } 145 146 static void __exit geode_rng_exit(void) 147 { 148 struct amd_geode_priv *priv; 149 150 priv = (struct amd_geode_priv *)geode_rng.priv; 151 hwrng_unregister(&geode_rng); 152 iounmap(priv->membase); 153 pci_dev_put(priv->pcidev); 154 kfree(priv); 155 } 156 157 module_init(geode_rng_init); 158 module_exit(geode_rng_exit); 159 160 MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); 161 MODULE_LICENSE("GPL"); 162