Path: blob/master/drivers/char/hw_random/virtio-rng.c
15111 views
/*1* Randomness driver for virtio2* Copyright (C) 2007, 2008 Rusty Russell IBM Corporation3*4* This program is free software; you can redistribute it and/or modify5* it under the terms of the GNU General Public License as published by6* the Free Software Foundation; either version 2 of the License, or7* (at your option) any later version.8*9* This program is distributed in the hope that it will be useful,10* but WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12* GNU General Public License for more details.13*14* You should have received a copy of the GNU General Public License15* along with this program; if not, write to the Free Software16* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA17*/1819#include <linux/err.h>20#include <linux/hw_random.h>21#include <linux/scatterlist.h>22#include <linux/spinlock.h>23#include <linux/virtio.h>24#include <linux/virtio_rng.h>2526static struct virtqueue *vq;27static unsigned int data_avail;28static DECLARE_COMPLETION(have_data);29static bool busy;3031static void random_recv_done(struct virtqueue *vq)32{33/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */34if (!virtqueue_get_buf(vq, &data_avail))35return;3637complete(&have_data);38}3940/* The host will fill any buffer we give it with sweet, sweet randomness. */41static void register_buffer(u8 *buf, size_t size)42{43struct scatterlist sg;4445sg_init_one(&sg, buf, size);4647/* There should always be room for one buffer. */48if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0)49BUG();5051virtqueue_kick(vq);52}5354static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)55{5657if (!busy) {58busy = true;59init_completion(&have_data);60register_buffer(buf, size);61}6263if (!wait)64return 0;6566wait_for_completion(&have_data);6768busy = false;6970return data_avail;71}7273static void virtio_cleanup(struct hwrng *rng)74{75if (busy)76wait_for_completion(&have_data);77}787980static struct hwrng virtio_hwrng = {81.name = "virtio",82.cleanup = virtio_cleanup,83.read = virtio_read,84};8586static int virtrng_probe(struct virtio_device *vdev)87{88int err;8990/* We expect a single virtqueue. */91vq = virtio_find_single_vq(vdev, random_recv_done, "input");92if (IS_ERR(vq))93return PTR_ERR(vq);9495err = hwrng_register(&virtio_hwrng);96if (err) {97vdev->config->del_vqs(vdev);98return err;99}100101return 0;102}103104static void __devexit virtrng_remove(struct virtio_device *vdev)105{106vdev->config->reset(vdev);107hwrng_unregister(&virtio_hwrng);108vdev->config->del_vqs(vdev);109}110111static struct virtio_device_id id_table[] = {112{ VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },113{ 0 },114};115116static struct virtio_driver virtio_rng_driver = {117.driver.name = KBUILD_MODNAME,118.driver.owner = THIS_MODULE,119.id_table = id_table,120.probe = virtrng_probe,121.remove = __devexit_p(virtrng_remove),122};123124static int __init init(void)125{126return register_virtio_driver(&virtio_rng_driver);127}128129static void __exit fini(void)130{131unregister_virtio_driver(&virtio_rng_driver);132}133module_init(init);134module_exit(fini);135136MODULE_DEVICE_TABLE(virtio, id_table);137MODULE_DESCRIPTION("Virtio random number driver");138MODULE_LICENSE("GPL");139140141