Path: blob/master/drivers/char/hw_random/geode-rng.c
15111 views
/*1* RNG driver for AMD Geode RNGs2*3* Copyright 2005 (c) MontaVista Software, Inc.4*5* with the majority of the code coming from:6*7* Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)8* (c) Copyright 2003 Red Hat Inc <[email protected]>9*10* derived from11*12* Hardware driver for the AMD 768 Random Number Generator (RNG)13* (c) Copyright 2001 Red Hat Inc14*15* derived from16*17* Hardware driver for Intel i810 Random Number Generator (RNG)18* Copyright 2000,2001 Jeff Garzik <[email protected]>19* Copyright 2000,2001 Philipp Rumpf <[email protected]>20*21* This file is licensed under the terms of the GNU General Public22* License version 2. This program is licensed "as is" without any23* warranty of any kind, whether express or implied.24*/2526#include <linux/module.h>27#include <linux/kernel.h>28#include <linux/pci.h>29#include <linux/hw_random.h>30#include <linux/delay.h>31#include <asm/io.h>323334#define PFX KBUILD_MODNAME ": "3536#define GEODE_RNG_DATA_REG 0x5037#define GEODE_RNG_STATUS_REG 0x543839/*40* Data for PCI driver interface41*42* This data only exists for exporting the supported43* PCI ids via MODULE_DEVICE_TABLE. We do not actually44* register a pci_driver, because someone else might one day45* want to register another driver on the same PCI id.46*/47static const struct pci_device_id pci_tbl[] = {48{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), 0, },49{ 0, }, /* terminate list */50};51MODULE_DEVICE_TABLE(pci, pci_tbl);525354static int geode_rng_data_read(struct hwrng *rng, u32 *data)55{56void __iomem *mem = (void __iomem *)rng->priv;5758*data = readl(mem + GEODE_RNG_DATA_REG);5960return 4;61}6263static int geode_rng_data_present(struct hwrng *rng, int wait)64{65void __iomem *mem = (void __iomem *)rng->priv;66int data, i;6768for (i = 0; i < 20; i++) {69data = !!(readl(mem + GEODE_RNG_STATUS_REG));70if (data || !wait)71break;72udelay(10);73}74return data;75}767778static struct hwrng geode_rng = {79.name = "geode",80.data_present = geode_rng_data_present,81.data_read = geode_rng_data_read,82};838485static int __init mod_init(void)86{87int err = -ENODEV;88struct pci_dev *pdev = NULL;89const struct pci_device_id *ent;90void __iomem *mem;91unsigned long rng_base;9293for_each_pci_dev(pdev) {94ent = pci_match_id(pci_tbl, pdev);95if (ent)96goto found;97}98/* Device not found. */99goto out;100101found:102rng_base = pci_resource_start(pdev, 0);103if (rng_base == 0)104goto out;105err = -ENOMEM;106mem = ioremap(rng_base, 0x58);107if (!mem)108goto out;109geode_rng.priv = (unsigned long)mem;110111printk(KERN_INFO "AMD Geode RNG detected\n");112err = hwrng_register(&geode_rng);113if (err) {114printk(KERN_ERR PFX "RNG registering failed (%d)\n",115err);116goto err_unmap;117}118out:119return err;120121err_unmap:122iounmap(mem);123goto out;124}125126static void __exit mod_exit(void)127{128void __iomem *mem = (void __iomem *)geode_rng.priv;129130hwrng_unregister(&geode_rng);131iounmap(mem);132}133134module_init(mod_init);135module_exit(mod_exit);136137MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs");138MODULE_LICENSE("GPL");139140141