2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-11-17 02:16:14 +05:30
/*
* VFIO based driver for Mediated device
*
* Copyright ( c ) 2016 , NVIDIA CORPORATION . All rights reserved .
* Author : Neo Jia < cjia @ nvidia . com >
* Kirti Wankhede < kwankhede @ nvidia . com >
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/vfio.h>
# include <linux/mdev.h>
# include "mdev_private.h"
# define DRIVER_VERSION "0.1"
# define DRIVER_AUTHOR "NVIDIA Corporation"
# define DRIVER_DESC "VFIO based driver for Mediated device"
static int vfio_mdev_open ( void * device_data )
{
struct mdev_device * mdev = device_data ;
2016-12-30 08:13:38 -07:00
struct mdev_parent * parent = mdev - > parent ;
2016-11-17 02:16:14 +05:30
int ret ;
if ( unlikely ( ! parent - > ops - > open ) )
return - EINVAL ;
if ( ! try_module_get ( THIS_MODULE ) )
return - ENODEV ;
ret = parent - > ops - > open ( mdev ) ;
if ( ret )
module_put ( THIS_MODULE ) ;
return ret ;
}
static void vfio_mdev_release ( void * device_data )
{
struct mdev_device * mdev = device_data ;
2016-12-30 08:13:38 -07:00
struct mdev_parent * parent = mdev - > parent ;
2016-11-17 02:16:14 +05:30
if ( likely ( parent - > ops - > release ) )
parent - > ops - > release ( mdev ) ;
module_put ( THIS_MODULE ) ;
}
static long vfio_mdev_unlocked_ioctl ( void * device_data ,
unsigned int cmd , unsigned long arg )
{
struct mdev_device * mdev = device_data ;
2016-12-30 08:13:38 -07:00
struct mdev_parent * parent = mdev - > parent ;
2016-11-17 02:16:14 +05:30
if ( unlikely ( ! parent - > ops - > ioctl ) )
return - EINVAL ;
return parent - > ops - > ioctl ( mdev , cmd , arg ) ;
}
static ssize_t vfio_mdev_read ( void * device_data , char __user * buf ,
size_t count , loff_t * ppos )
{
struct mdev_device * mdev = device_data ;
2016-12-30 08:13:38 -07:00
struct mdev_parent * parent = mdev - > parent ;
2016-11-17 02:16:14 +05:30
if ( unlikely ( ! parent - > ops - > read ) )
return - EINVAL ;
return parent - > ops - > read ( mdev , buf , count , ppos ) ;
}
static ssize_t vfio_mdev_write ( void * device_data , const char __user * buf ,
size_t count , loff_t * ppos )
{
struct mdev_device * mdev = device_data ;
2016-12-30 08:13:38 -07:00
struct mdev_parent * parent = mdev - > parent ;
2016-11-17 02:16:14 +05:30
if ( unlikely ( ! parent - > ops - > write ) )
return - EINVAL ;
return parent - > ops - > write ( mdev , buf , count , ppos ) ;
}
static int vfio_mdev_mmap ( void * device_data , struct vm_area_struct * vma )
{
struct mdev_device * mdev = device_data ;
2016-12-30 08:13:38 -07:00
struct mdev_parent * parent = mdev - > parent ;
2016-11-17 02:16:14 +05:30
if ( unlikely ( ! parent - > ops - > mmap ) )
return - EINVAL ;
return parent - > ops - > mmap ( mdev , vma ) ;
}
static const struct vfio_device_ops vfio_mdev_dev_ops = {
. name = " vfio-mdev " ,
. open = vfio_mdev_open ,
. release = vfio_mdev_release ,
. ioctl = vfio_mdev_unlocked_ioctl ,
. read = vfio_mdev_read ,
. write = vfio_mdev_write ,
. mmap = vfio_mdev_mmap ,
} ;
2017-12-22 07:12:26 +08:00
static int vfio_mdev_probe ( struct device * dev )
2016-11-17 02:16:14 +05:30
{
struct mdev_device * mdev = to_mdev_device ( dev ) ;
return vfio_add_group_dev ( dev , & vfio_mdev_dev_ops , mdev ) ;
}
2017-12-22 07:12:26 +08:00
static void vfio_mdev_remove ( struct device * dev )
2016-11-17 02:16:14 +05:30
{
vfio_del_group_dev ( dev ) ;
}
2017-12-22 07:12:26 +08:00
static struct mdev_driver vfio_mdev_driver = {
2016-11-17 02:16:14 +05:30
. name = " vfio_mdev " ,
. probe = vfio_mdev_probe ,
. remove = vfio_mdev_remove ,
} ;
static int __init vfio_mdev_init ( void )
{
return mdev_register_driver ( & vfio_mdev_driver , THIS_MODULE ) ;
}
static void __exit vfio_mdev_exit ( void )
{
mdev_unregister_driver ( & vfio_mdev_driver ) ;
}
module_init ( vfio_mdev_init )
module_exit ( vfio_mdev_exit )
MODULE_VERSION ( DRIVER_VERSION ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;