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 virtio_device *vdev;
  32        struct hwrng hwrng;
  33        struct virtqueue *vq;
  34        unsigned int data_avail;
  35        struct completion have_data;
  36        bool busy;
  37        char name[25];
  38        int index;
  39};
  40
  41static bool probe_done;
  42
  43static void random_recv_done(struct virtqueue *vq)
  44{
  45        struct virtrng_info *vi = vq->vdev->priv;
  46
  47        /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
  48        if (!virtqueue_get_buf(vi->vq, &vi->data_avail))
  49                return;
  50
  51        complete(&vi->have_data);
  52}
  53
  54/* The host will fill any buffer we give it with sweet, sweet randomness. */
  55static void register_buffer(struct virtrng_info *vi, u8 *buf, size_t size)
  56{
  57        struct scatterlist sg;
  58
  59        sg_init_one(&sg, buf, size);
  60
  61        /* There should always be room for one buffer. */
  62        virtqueue_add_inbuf(vi->vq, &sg, 1, buf, GFP_KERNEL);
  63
  64        virtqueue_kick(vi->vq);
  65}
  66
  67static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
  68{
  69        int ret;
  70        struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
  71
  72        /*
  73         * Don't ask host for data till we're setup.  This call can
  74         * happen during hwrng_register(), after commit d9e7972619.
  75         */
  76        if (unlikely(!probe_done))
  77                return 0;
  78
  79        if (!vi->busy) {
  80                vi->busy = true;
  81                init_completion(&vi->have_data);
  82                register_buffer(vi, buf, size);
  83        }
  84
  85        if (!wait)
  86                return 0;
  87
  88        ret = wait_for_completion_killable(&vi->have_data);
  89        if (ret < 0)
  90                return ret;
  91
  92        vi->busy = false;
  93
  94        return vi->data_avail;
  95}
  96
  97static void virtio_cleanup(struct hwrng *rng)
  98{
  99        struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
 100
 101        if (vi->busy)
 102                wait_for_completion(&vi->have_data);
 103}
 104
 105static int probe_common(struct virtio_device *vdev)
 106{
 107        int err, index;
 108        struct virtrng_info *vi = NULL;
 109
 110        vi = kzalloc(sizeof(struct virtrng_info), GFP_KERNEL);
 111        if (!vi)
 112                return -ENOMEM;
 113
 114        vi->index = index = ida_simple_get(&rng_index_ida, 0, 0, GFP_KERNEL);
 115        if (index < 0) {
 116                kfree(vi);
 117                return index;
 118        }
 119        sprintf(vi->name, "virtio_rng.%d", index);
 120        init_completion(&vi->have_data);
 121
 122        vi->hwrng = (struct hwrng) {
 123                .read = virtio_read,
 124                .cleanup = virtio_cleanup,
 125                .priv = (unsigned long)vi,
 126                .name = vi->name,
 127        };
 128        vdev->priv = vi;
 129
 130        /* We expect a single virtqueue. */
 131        vi->vq = virtio_find_single_vq(vdev, random_recv_done, "input");
 132        if (IS_ERR(vi->vq)) {
 133                err = PTR_ERR(vi->vq);
 134                vi->vq = NULL;
 135                kfree(vi);
 136                ida_simple_remove(&rng_index_ida, index);
 137                return err;
 138        }
 139
 140        err = hwrng_register(&vi->hwrng);
 141        if (err) {
 142                vdev->config->del_vqs(vdev);
 143                vi->vq = NULL;
 144                kfree(vi);
 145                ida_simple_remove(&rng_index_ida, index);
 146                return err;
 147        }
 148
 149        probe_done = true;
 150        return 0;
 151}
 152
 153static void remove_common(struct virtio_device *vdev)
 154{
 155        struct virtrng_info *vi = vdev->priv;
 156        vdev->config->reset(vdev);
 157        vi->busy = false;
 158        hwrng_unregister(&vi->hwrng);
 159        vdev->config->del_vqs(vdev);
 160        ida_simple_remove(&rng_index_ida, vi->index);
 161        kfree(vi);
 162}
 163
 164static int virtrng_probe(struct virtio_device *vdev)
 165{
 166        return probe_common(vdev);
 167}
 168
 169static void virtrng_remove(struct virtio_device *vdev)
 170{
 171        remove_common(vdev);
 172}
 173
 174#ifdef CONFIG_PM_SLEEP
 175static int virtrng_freeze(struct virtio_device *vdev)
 176{
 177        remove_common(vdev);
 178        return 0;
 179}
 180
 181static int virtrng_restore(struct virtio_device *vdev)
 182{
 183        return probe_common(vdev);
 184}
 185#endif
 186
 187static struct virtio_device_id id_table[] = {
 188        { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
 189        { 0 },
 190};
 191
 192static struct virtio_driver virtio_rng_driver = {
 193        .driver.name =  KBUILD_MODNAME,
 194        .driver.owner = THIS_MODULE,
 195        .id_table =     id_table,
 196        .probe =        virtrng_probe,
 197        .remove =       virtrng_remove,
 198#ifdef CONFIG_PM_SLEEP
 199        .freeze =       virtrng_freeze,
 200        .restore =      virtrng_restore,
 201#endif
 202};
 203
 204module_virtio_driver(virtio_rng_driver);
 205MODULE_DEVICE_TABLE(virtio, id_table);
 206MODULE_DESCRIPTION("Virtio random number driver");
 207MODULE_LICENSE("GPL");
 208