linux/drivers/char/hw_random/virtio-rng.c
<<
>>
Prefs
   1/*
   2 * Randomness driver for virtio
   3 *  Copyright (C) 2007, 2008 Rusty Russell IBM Corporation
   4 *
   5 *  This program is free software; you can redistribute it and/or modify
   6 *  it under the terms of the GNU General Public License as published by
   7 *  the Free Software Foundation; either version 2 of the License, or
   8 *  (at your option) any later version.
   9 *
  10 *  This program is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *  GNU General Public License for more details.
  14 *
  15 *  You should have received a copy of the GNU General Public License
  16 *  along with this program; if not, write to the Free Software
  17 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  18 */
  19
  20#include <linux/err.h>
  21#include <linux/hw_random.h>
  22#include <linux/scatterlist.h>
  23#include <linux/spinlock.h>
  24#include <linux/virtio.h>
  25#include <linux/virtio_rng.h>
  26#include <linux/module.h>
  27
  28static DEFINE_IDA(rng_index_ida);
  29
  30struct virtrng_info {
  31        struct hwrng hwrng;
  32        struct virtqueue *vq;
  33        struct completion have_data;
  34        char name[25];
  35        unsigned int data_avail;
  36        int index;
  37        bool busy;
  38        bool hwrng_register_done;
  39        bool hwrng_removed;
  40};
  41
  42static void random_recv_done(struct virtqueue *vq)
  43{
  44        struct virtrng_info *vi = vq->vdev->priv;
  45
  46        /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
  47        if (!virtqueue_get_buf(vi->vq, &vi->data_avail))
  48                return;
  49
  50        complete(&vi->have_data);
  51}
  52
  53/* The host will fill any buffer we give it with sweet, sweet randomness. */
  54static void register_buffer(struct virtrng_info *vi, u8 *buf, size_t size)
  55{
  56        struct scatterlist sg;
  57
  58        sg_init_one(&sg, buf, size);
  59
  60        /* There should always be room for one buffer. */
  61        virtqueue_add_inbuf(vi->vq, &sg, 1, buf, GFP_KERNEL);
  62
  63        virtqueue_kick(vi->vq);
  64}
  65
  66static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
  67{
  68        int ret;
  69        struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
  70
  71        if (vi->hwrng_removed)
  72                return -ENODEV;
  73
  74        if (!vi->busy) {
  75                vi->busy = true;
  76                init_completion(&vi->have_data);
  77                register_buffer(vi, buf, size);
  78        }
  79
  80        if (!wait)
  81                return 0;
  82
  83        ret = wait_for_completion_killable(&vi->have_data);
  84        if (ret < 0)
  85                return ret;
  86
  87        vi->busy = false;
  88
  89        return vi->data_avail;
  90}
  91
  92static void virtio_cleanup(struct hwrng *rng)
  93{
  94        struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
  95
  96        if (vi->busy)
  97                wait_for_completion(&vi->have_data);
  98}
  99
 100static int probe_common(struct virtio_device *vdev)
 101{
 102        int err, index;
 103        struct virtrng_info *vi = NULL;
 104
 105        vi = kzalloc(sizeof(struct virtrng_info), GFP_KERNEL);
 106        if (!vi)
 107                return -ENOMEM;
 108
 109        vi->index = index = ida_simple_get(&rng_index_ida, 0, 0, GFP_KERNEL);
 110        if (index < 0) {
 111                err = index;
 112                goto err_ida;
 113        }
 114        sprintf(vi->name, "virtio_rng.%d", index);
 115        init_completion(&vi->have_data);
 116
 117        vi->hwrng = (struct hwrng) {
 118                .read = virtio_read,
 119                .cleanup = virtio_cleanup,
 120                .priv = (unsigned long)vi,
 121                .name = vi->name,
 122                .quality = 1000,
 123        };
 124        vdev->priv = vi;
 125
 126        /* We expect a single virtqueue. */
 127        vi->vq = virtio_find_single_vq(vdev, random_recv_done, "input");
 128        if (IS_ERR(vi->vq)) {
 129                err = PTR_ERR(vi->vq);
 130                goto err_find;
 131        }
 132
 133        return 0;
 134
 135err_find:
 136        ida_simple_remove(&rng_index_ida, index);
 137err_ida:
 138        kfree(vi);
 139        return err;
 140}
 141
 142static void remove_common(struct virtio_device *vdev)
 143{
 144        struct virtrng_info *vi = vdev->priv;
 145
 146        vi->hwrng_removed = true;
 147        vi->data_avail = 0;
 148        complete(&vi->have_data);
 149        vdev->config->reset(vdev);
 150        vi->busy = false;
 151        if (vi->hwrng_register_done)
 152                hwrng_unregister(&vi->hwrng);
 153        vdev->config->del_vqs(vdev);
 154        ida_simple_remove(&rng_index_ida, vi->index);
 155        kfree(vi);
 156}
 157
 158static int virtrng_probe(struct virtio_device *vdev)
 159{
 160        return probe_common(vdev);
 161}
 162
 163static void virtrng_remove(struct virtio_device *vdev)
 164{
 165        remove_common(vdev);
 166}
 167
 168static void virtrng_scan(struct virtio_device *vdev)
 169{
 170        struct virtrng_info *vi = vdev->priv;
 171        int err;
 172
 173        err = hwrng_register(&vi->hwrng);
 174        if (!err)
 175                vi->hwrng_register_done = true;
 176}
 177
 178#ifdef CONFIG_PM_SLEEP
 179static int virtrng_freeze(struct virtio_device *vdev)
 180{
 181        remove_common(vdev);
 182        return 0;
 183}
 184
 185static int virtrng_restore(struct virtio_device *vdev)
 186{
 187        return probe_common(vdev);
 188}
 189#endif
 190
 191static struct virtio_device_id id_table[] = {
 192        { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
 193        { 0 },
 194};
 195
 196static struct virtio_driver virtio_rng_driver = {
 197        .driver.name =  KBUILD_MODNAME,
 198        .driver.owner = THIS_MODULE,
 199        .id_table =     id_table,
 200        .probe =        virtrng_probe,
 201        .remove =       virtrng_remove,
 202        .scan =         virtrng_scan,
 203#ifdef CONFIG_PM_SLEEP
 204        .freeze =       virtrng_freeze,
 205        .restore =      virtrng_restore,
 206#endif
 207};
 208
 209module_virtio_driver(virtio_rng_driver);
 210MODULE_DEVICE_TABLE(virtio, id_table);
 211MODULE_DESCRIPTION("Virtio random number driver");
 212MODULE_LICENSE("GPL");
 213