2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-11-16 23:46:14 +03:00
/*
* 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"
2021-08-06 04:19:00 +03:00
static int vfio_mdev_open_device ( struct vfio_device * core_vdev )
{
struct mdev_device * mdev = to_mdev_device ( core_vdev - > dev ) ;
struct mdev_parent * parent = mdev - > type - > parent ;
if ( unlikely ( ! parent - > ops - > open_device ) )
return 0 ;
return parent - > ops - > open_device ( mdev ) ;
}
static void vfio_mdev_close_device ( struct vfio_device * core_vdev )
{
struct mdev_device * mdev = to_mdev_device ( core_vdev - > dev ) ;
struct mdev_parent * parent = mdev - > type - > parent ;
if ( likely ( parent - > ops - > close_device ) )
parent - > ops - > close_device ( mdev ) ;
}
2021-03-30 18:53:08 +03:00
static long vfio_mdev_unlocked_ioctl ( struct vfio_device * core_vdev ,
2016-11-16 23:46:14 +03:00
unsigned int cmd , unsigned long arg )
{
2021-03-30 18:53:08 +03:00
struct mdev_device * mdev = to_mdev_device ( core_vdev - > dev ) ;
2021-04-06 22:40:33 +03:00
struct mdev_parent * parent = mdev - > type - > parent ;
2016-11-16 23:46:14 +03:00
if ( unlikely ( ! parent - > ops - > ioctl ) )
2021-08-06 04:19:00 +03:00
return 0 ;
2016-11-16 23:46:14 +03:00
return parent - > ops - > ioctl ( mdev , cmd , arg ) ;
}
2021-03-30 18:53:08 +03:00
static ssize_t vfio_mdev_read ( struct vfio_device * core_vdev , char __user * buf ,
2016-11-16 23:46:14 +03:00
size_t count , loff_t * ppos )
{
2021-03-30 18:53:08 +03:00
struct mdev_device * mdev = to_mdev_device ( core_vdev - > dev ) ;
2021-04-06 22:40:33 +03:00
struct mdev_parent * parent = mdev - > type - > parent ;
2016-11-16 23:46:14 +03:00
if ( unlikely ( ! parent - > ops - > read ) )
return - EINVAL ;
return parent - > ops - > read ( mdev , buf , count , ppos ) ;
}
2021-03-30 18:53:08 +03:00
static ssize_t vfio_mdev_write ( struct vfio_device * core_vdev ,
const char __user * buf , size_t count ,
loff_t * ppos )
2016-11-16 23:46:14 +03:00
{
2021-03-30 18:53:08 +03:00
struct mdev_device * mdev = to_mdev_device ( core_vdev - > dev ) ;
2021-04-06 22:40:33 +03:00
struct mdev_parent * parent = mdev - > type - > parent ;
2016-11-16 23:46:14 +03:00
if ( unlikely ( ! parent - > ops - > write ) )
return - EINVAL ;
return parent - > ops - > write ( mdev , buf , count , ppos ) ;
}
2021-03-30 18:53:08 +03:00
static int vfio_mdev_mmap ( struct vfio_device * core_vdev ,
struct vm_area_struct * vma )
2016-11-16 23:46:14 +03:00
{
2021-03-30 18:53:08 +03:00
struct mdev_device * mdev = to_mdev_device ( core_vdev - > dev ) ;
2021-04-06 22:40:33 +03:00
struct mdev_parent * parent = mdev - > type - > parent ;
2016-11-16 23:46:14 +03:00
if ( unlikely ( ! parent - > ops - > mmap ) )
return - EINVAL ;
return parent - > ops - > mmap ( mdev , vma ) ;
}
2021-03-30 18:53:08 +03:00
static void vfio_mdev_request ( struct vfio_device * core_vdev , unsigned int count )
2020-12-04 00:35:11 +03:00
{
2021-03-30 18:53:08 +03:00
struct mdev_device * mdev = to_mdev_device ( core_vdev - > dev ) ;
2021-04-06 22:40:33 +03:00
struct mdev_parent * parent = mdev - > type - > parent ;
2020-12-04 00:35:11 +03:00
if ( parent - > ops - > request )
parent - > ops - > request ( mdev , count ) ;
else if ( count = = 0 )
dev_notice ( mdev_dev ( mdev ) ,
" No mdev vendor driver request callback support, blocked until released by user \n " ) ;
}
2016-11-16 23:46:14 +03:00
static const struct vfio_device_ops vfio_mdev_dev_ops = {
. name = " vfio-mdev " ,
2021-08-06 04:19:00 +03:00
. open_device = vfio_mdev_open_device ,
. close_device = vfio_mdev_close_device ,
2016-11-16 23:46:14 +03:00
. ioctl = vfio_mdev_unlocked_ioctl ,
. read = vfio_mdev_read ,
. write = vfio_mdev_write ,
. mmap = vfio_mdev_mmap ,
2020-12-04 00:35:11 +03:00
. request = vfio_mdev_request ,
2016-11-16 23:46:14 +03:00
} ;
2021-04-06 22:40:26 +03:00
static int vfio_mdev_probe ( struct mdev_device * mdev )
2016-11-16 23:46:14 +03:00
{
2021-03-30 18:53:07 +03:00
struct vfio_device * vdev ;
int ret ;
2016-11-16 23:46:14 +03:00
2021-03-30 18:53:07 +03:00
vdev = kzalloc ( sizeof ( * vdev ) , GFP_KERNEL ) ;
if ( ! vdev )
return - ENOMEM ;
2021-03-30 18:53:08 +03:00
vfio_init_group_dev ( vdev , & mdev - > dev , & vfio_mdev_dev_ops ) ;
2021-03-30 18:53:07 +03:00
ret = vfio_register_group_dev ( vdev ) ;
2021-08-06 04:18:59 +03:00
if ( ret )
goto out_uninit ;
2021-03-30 18:53:07 +03:00
dev_set_drvdata ( & mdev - > dev , vdev ) ;
return 0 ;
2021-08-06 04:18:59 +03:00
out_uninit :
vfio_uninit_group_dev ( vdev ) ;
kfree ( vdev ) ;
return ret ;
2016-11-16 23:46:14 +03:00
}
2021-04-06 22:40:26 +03:00
static void vfio_mdev_remove ( struct mdev_device * mdev )
2016-11-16 23:46:14 +03:00
{
2021-04-06 22:40:26 +03:00
struct vfio_device * vdev = dev_get_drvdata ( & mdev - > dev ) ;
2021-03-30 18:53:07 +03:00
vfio_unregister_group_dev ( vdev ) ;
2021-08-06 04:18:59 +03:00
vfio_uninit_group_dev ( vdev ) ;
2021-03-30 18:53:07 +03:00
kfree ( vdev ) ;
2016-11-16 23:46:14 +03:00
}
2021-06-17 17:22:14 +03:00
struct mdev_driver vfio_mdev_driver = {
2021-04-06 22:40:27 +03:00
. driver = {
. name = " vfio_mdev " ,
. owner = THIS_MODULE ,
. mod_name = KBUILD_MODNAME ,
} ,
2016-11-16 23:46:14 +03:00
. probe = vfio_mdev_probe ,
. remove = vfio_mdev_remove ,
} ;