18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VFIO based driver for Mediated device 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 68c2ecf20Sopenharmony_ci * Author: Neo Jia <cjia@nvidia.com> 78c2ecf20Sopenharmony_ci * Kirti Wankhede <kwankhede@nvidia.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/vfio.h> 168c2ecf20Sopenharmony_ci#include <linux/mdev.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "mdev_private.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define DRIVER_VERSION "0.1" 218c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "NVIDIA Corporation" 228c2ecf20Sopenharmony_ci#define DRIVER_DESC "VFIO based driver for Mediated device" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int vfio_mdev_open(void *device_data) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct mdev_device *mdev = device_data; 278c2ecf20Sopenharmony_ci struct mdev_parent *parent = mdev->parent; 288c2ecf20Sopenharmony_ci int ret; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (unlikely(!parent->ops->open)) 318c2ecf20Sopenharmony_ci return -EINVAL; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 348c2ecf20Sopenharmony_ci return -ENODEV; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci ret = parent->ops->open(mdev); 378c2ecf20Sopenharmony_ci if (ret) 388c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci return ret; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void vfio_mdev_release(void *device_data) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct mdev_device *mdev = device_data; 468c2ecf20Sopenharmony_ci struct mdev_parent *parent = mdev->parent; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (likely(parent->ops->release)) 498c2ecf20Sopenharmony_ci parent->ops->release(mdev); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic long vfio_mdev_unlocked_ioctl(void *device_data, 558c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct mdev_device *mdev = device_data; 588c2ecf20Sopenharmony_ci struct mdev_parent *parent = mdev->parent; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (unlikely(!parent->ops->ioctl)) 618c2ecf20Sopenharmony_ci return -EINVAL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return parent->ops->ioctl(mdev, cmd, arg); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic ssize_t vfio_mdev_read(void *device_data, char __user *buf, 678c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct mdev_device *mdev = device_data; 708c2ecf20Sopenharmony_ci struct mdev_parent *parent = mdev->parent; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (unlikely(!parent->ops->read)) 738c2ecf20Sopenharmony_ci return -EINVAL; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return parent->ops->read(mdev, buf, count, ppos); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic ssize_t vfio_mdev_write(void *device_data, const char __user *buf, 798c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct mdev_device *mdev = device_data; 828c2ecf20Sopenharmony_ci struct mdev_parent *parent = mdev->parent; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (unlikely(!parent->ops->write)) 858c2ecf20Sopenharmony_ci return -EINVAL; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return parent->ops->write(mdev, buf, count, ppos); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct mdev_device *mdev = device_data; 938c2ecf20Sopenharmony_ci struct mdev_parent *parent = mdev->parent; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (unlikely(!parent->ops->mmap)) 968c2ecf20Sopenharmony_ci return -EINVAL; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return parent->ops->mmap(mdev, vma); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const struct vfio_device_ops vfio_mdev_dev_ops = { 1028c2ecf20Sopenharmony_ci .name = "vfio-mdev", 1038c2ecf20Sopenharmony_ci .open = vfio_mdev_open, 1048c2ecf20Sopenharmony_ci .release = vfio_mdev_release, 1058c2ecf20Sopenharmony_ci .ioctl = vfio_mdev_unlocked_ioctl, 1068c2ecf20Sopenharmony_ci .read = vfio_mdev_read, 1078c2ecf20Sopenharmony_ci .write = vfio_mdev_write, 1088c2ecf20Sopenharmony_ci .mmap = vfio_mdev_mmap, 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int vfio_mdev_probe(struct device *dev) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct mdev_device *mdev = to_mdev_device(dev); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void vfio_mdev_remove(struct device *dev) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci vfio_del_group_dev(dev); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct mdev_driver vfio_mdev_driver = { 1248c2ecf20Sopenharmony_ci .name = "vfio_mdev", 1258c2ecf20Sopenharmony_ci .probe = vfio_mdev_probe, 1268c2ecf20Sopenharmony_ci .remove = vfio_mdev_remove, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int __init vfio_mdev_init(void) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci return mdev_register_driver(&vfio_mdev_driver, THIS_MODULE); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void __exit vfio_mdev_exit(void) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci mdev_unregister_driver(&vfio_mdev_driver); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cimodule_init(vfio_mdev_init) 1408c2ecf20Sopenharmony_cimodule_exit(vfio_mdev_exit) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 1438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1448c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 1458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 146