Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * VFIO based driver for Mediated device
  4 *
  5 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
  6 *     Author: Neo Jia <cjia@nvidia.com>
  7 *             Kirti Wankhede <kwankhede@nvidia.com>
  8 */
  9
 10#include <linux/init.h>
 11#include <linux/module.h>
 12#include <linux/device.h>
 13#include <linux/kernel.h>
 14#include <linux/slab.h>
 15#include <linux/vfio.h>
 16#include <linux/mdev.h>
 17
 18#include "mdev_private.h"
 19
 20#define DRIVER_VERSION  "0.1"
 21#define DRIVER_AUTHOR   "NVIDIA Corporation"
 22#define DRIVER_DESC     "VFIO based driver for Mediated device"
 23
 24static int vfio_mdev_open(void *device_data)
 25{
 26	struct mdev_device *mdev = device_data;
 27	struct mdev_parent *parent = mdev->parent;
 28	int ret;
 29
 30	if (unlikely(!parent->ops->open))
 31		return -EINVAL;
 32
 33	if (!try_module_get(THIS_MODULE))
 34		return -ENODEV;
 35
 36	ret = parent->ops->open(mdev);
 37	if (ret)
 38		module_put(THIS_MODULE);
 39
 40	return ret;
 41}
 42
 43static void vfio_mdev_release(void *device_data)
 44{
 45	struct mdev_device *mdev = device_data;
 46	struct mdev_parent *parent = mdev->parent;
 47
 48	if (likely(parent->ops->release))
 49		parent->ops->release(mdev);
 50
 51	module_put(THIS_MODULE);
 52}
 53
 54static long vfio_mdev_unlocked_ioctl(void *device_data,
 55				     unsigned int cmd, unsigned long arg)
 56{
 57	struct mdev_device *mdev = device_data;
 58	struct mdev_parent *parent = mdev->parent;
 59
 60	if (unlikely(!parent->ops->ioctl))
 61		return -EINVAL;
 62
 63	return parent->ops->ioctl(mdev, cmd, arg);
 64}
 65
 66static ssize_t vfio_mdev_read(void *device_data, char __user *buf,
 67			      size_t count, loff_t *ppos)
 68{
 69	struct mdev_device *mdev = device_data;
 70	struct mdev_parent *parent = mdev->parent;
 71
 72	if (unlikely(!parent->ops->read))
 73		return -EINVAL;
 74
 75	return parent->ops->read(mdev, buf, count, ppos);
 76}
 77
 78static ssize_t vfio_mdev_write(void *device_data, const char __user *buf,
 79			       size_t count, loff_t *ppos)
 80{
 81	struct mdev_device *mdev = device_data;
 82	struct mdev_parent *parent = mdev->parent;
 83
 84	if (unlikely(!parent->ops->write))
 85		return -EINVAL;
 86
 87	return parent->ops->write(mdev, buf, count, ppos);
 88}
 89
 90static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma)
 91{
 92	struct mdev_device *mdev = device_data;
 93	struct mdev_parent *parent = mdev->parent;
 94
 95	if (unlikely(!parent->ops->mmap))
 96		return -EINVAL;
 97
 98	return parent->ops->mmap(mdev, vma);
 99}
100
101static const struct vfio_device_ops vfio_mdev_dev_ops = {
102	.name		= "vfio-mdev",
103	.open		= vfio_mdev_open,
104	.release	= vfio_mdev_release,
105	.ioctl		= vfio_mdev_unlocked_ioctl,
106	.read		= vfio_mdev_read,
107	.write		= vfio_mdev_write,
108	.mmap		= vfio_mdev_mmap,
109};
110
111static int vfio_mdev_probe(struct device *dev)
112{
113	struct mdev_device *mdev = to_mdev_device(dev);
114
115	return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev);
116}
117
118static void vfio_mdev_remove(struct device *dev)
119{
120	vfio_del_group_dev(dev);
121}
122
123static struct mdev_driver vfio_mdev_driver = {
124	.name	= "vfio_mdev",
125	.probe	= vfio_mdev_probe,
126	.remove	= vfio_mdev_remove,
127};
128
129static int __init vfio_mdev_init(void)
130{
131	return mdev_register_driver(&vfio_mdev_driver, THIS_MODULE);
132}
133
134static void __exit vfio_mdev_exit(void)
135{
136	mdev_unregister_driver(&vfio_mdev_driver);
137}
138
139module_init(vfio_mdev_init)
140module_exit(vfio_mdev_exit)
141
142MODULE_VERSION(DRIVER_VERSION);
143MODULE_LICENSE("GPL v2");
144MODULE_AUTHOR(DRIVER_AUTHOR);
145MODULE_DESCRIPTION(DRIVER_DESC);