2008-05-30 15:09:44 -05:00
/*
* Randomness driver for virtio
* Copyright ( C ) 2007 , 2008 Rusty Russell IBM Corporation
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2009-12-01 15:26:33 +08:00
2008-05-30 15:09:44 -05:00
# include <linux/err.h>
# include <linux/hw_random.h>
# include <linux/scatterlist.h>
# include <linux/spinlock.h>
# include <linux/virtio.h>
# include <linux/virtio_rng.h>
2011-07-03 13:35:48 -04:00
# include <linux/module.h>
2008-05-30 15:09:44 -05:00
static struct virtqueue * vq ;
2009-12-01 15:26:33 +08:00
static unsigned int data_avail ;
2008-05-30 15:09:44 -05:00
static DECLARE_COMPLETION ( have_data ) ;
2009-12-01 15:26:33 +08:00
static bool busy ;
2008-05-30 15:09:44 -05:00
static void random_recv_done ( struct virtqueue * vq )
{
2009-04-23 16:42:59 +09:30
/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
2010-04-13 16:11:42 +03:00
if ( ! virtqueue_get_buf ( vq , & data_avail ) )
2009-04-23 16:42:59 +09:30
return ;
2008-05-30 15:09:44 -05:00
complete ( & have_data ) ;
}
2009-12-01 15:26:33 +08:00
/* The host will fill any buffer we give it with sweet, sweet randomness. */
static void register_buffer ( u8 * buf , size_t size )
2008-05-30 15:09:44 -05:00
{
struct scatterlist sg ;
2009-12-01 15:26:33 +08:00
sg_init_one ( & sg , buf , size ) ;
2008-05-30 15:09:44 -05:00
/* There should always be room for one buffer. */
2013-03-20 15:44:29 +10:30
if ( virtqueue_add_inbuf ( vq , & sg , 1 , buf , GFP_KERNEL ) < 0 )
2008-05-30 15:09:44 -05:00
BUG ( ) ;
2009-12-01 15:26:33 +08:00
2010-04-13 16:11:42 +03:00
virtqueue_kick ( vq ) ;
2008-05-30 15:09:44 -05:00
}
2009-12-01 15:26:33 +08:00
static int virtio_read ( struct hwrng * rng , void * buf , size_t size , bool wait )
2008-05-30 15:09:44 -05:00
{
2012-05-28 12:18:40 +05:30
int ret ;
2008-05-30 15:09:44 -05:00
2009-12-01 15:26:33 +08:00
if ( ! busy ) {
busy = true ;
init_completion ( & have_data ) ;
register_buffer ( buf , size ) ;
}
2008-05-30 15:09:44 -05:00
if ( ! wait )
return 0 ;
2012-05-28 12:18:40 +05:30
ret = wait_for_completion_killable ( & have_data ) ;
if ( ret < 0 )
return ret ;
2009-06-12 22:16:39 -06:00
2009-12-01 15:26:33 +08:00
busy = false ;
2009-06-12 22:16:39 -06:00
2009-12-01 15:26:33 +08:00
return data_avail ;
2008-05-30 15:09:44 -05:00
}
2009-12-01 15:26:33 +08:00
static void virtio_cleanup ( struct hwrng * rng )
2008-05-30 15:09:44 -05:00
{
2009-12-01 15:26:33 +08:00
if ( busy )
wait_for_completion ( & have_data ) ;
2008-05-30 15:09:44 -05:00
}
2009-12-01 15:26:33 +08:00
2008-05-30 15:09:44 -05:00
static struct hwrng virtio_hwrng = {
2009-12-01 15:26:33 +08:00
. name = " virtio " ,
. cleanup = virtio_cleanup ,
. read = virtio_read ,
2008-05-30 15:09:44 -05:00
} ;
2012-05-28 12:18:42 +05:30
static int probe_common ( struct virtio_device * vdev )
2008-05-30 15:09:44 -05:00
{
int err ;
2013-03-08 11:30:18 +11:00
if ( vq ) {
/* We only support one device for now */
return - EBUSY ;
}
2008-05-30 15:09:44 -05:00
/* We expect a single virtqueue. */
2009-06-12 22:16:36 -06:00
vq = virtio_find_single_vq ( vdev , random_recv_done , " input " ) ;
2013-03-08 11:30:18 +11:00
if ( IS_ERR ( vq ) ) {
err = PTR_ERR ( vq ) ;
vq = NULL ;
return err ;
}
2008-05-30 15:09:44 -05:00
err = hwrng_register ( & virtio_hwrng ) ;
if ( err ) {
2009-06-12 22:16:36 -06:00
vdev - > config - > del_vqs ( vdev ) ;
2013-03-08 11:30:18 +11:00
vq = NULL ;
2008-05-30 15:09:44 -05:00
return err ;
}
return 0 ;
}
2012-05-28 12:18:42 +05:30
static void remove_common ( struct virtio_device * vdev )
2008-05-30 15:09:44 -05:00
{
vdev - > config - > reset ( vdev ) ;
2012-05-28 12:18:41 +05:30
busy = false ;
2008-05-30 15:09:44 -05:00
hwrng_unregister ( & virtio_hwrng ) ;
2009-06-12 22:16:36 -06:00
vdev - > config - > del_vqs ( vdev ) ;
2013-03-08 11:30:18 +11:00
vq = NULL ;
2008-05-30 15:09:44 -05:00
}
2012-05-28 12:18:42 +05:30
static int virtrng_probe ( struct virtio_device * vdev )
{
return probe_common ( vdev ) ;
}
2012-11-19 13:26:26 -05:00
static void virtrng_remove ( struct virtio_device * vdev )
2012-05-28 12:18:42 +05:30
{
remove_common ( vdev ) ;
}
2012-05-28 12:18:43 +05:30
# ifdef CONFIG_PM
static int virtrng_freeze ( struct virtio_device * vdev )
{
remove_common ( vdev ) ;
return 0 ;
}
static int virtrng_restore ( struct virtio_device * vdev )
{
return probe_common ( vdev ) ;
}
# endif
2008-05-30 15:09:44 -05:00
static struct virtio_device_id id_table [ ] = {
{ VIRTIO_ID_RNG , VIRTIO_DEV_ANY_ID } ,
{ 0 } ,
} ;
2010-01-15 17:01:26 -08:00
static struct virtio_driver virtio_rng_driver = {
2008-05-30 15:09:44 -05:00
. driver . name = KBUILD_MODNAME ,
. driver . owner = THIS_MODULE ,
. id_table = id_table ,
. probe = virtrng_probe ,
2012-12-21 15:12:08 -08:00
. remove = virtrng_remove ,
2012-05-28 12:18:43 +05:30
# ifdef CONFIG_PM
. freeze = virtrng_freeze ,
. restore = virtrng_restore ,
# endif
2008-05-30 15:09:44 -05:00
} ;
2013-02-13 16:59:28 +10:30
module_virtio_driver ( virtio_rng_driver ) ;
2008-05-30 15:09:44 -05:00
MODULE_DEVICE_TABLE ( virtio , id_table ) ;
MODULE_DESCRIPTION ( " Virtio random number driver " ) ;
MODULE_LICENSE ( " GPL " ) ;