From: Kirti Wankhede <kwankhede@nvidia.com>
To: Alex Williamson <alex.williamson@redhat.com>,
Neo Jia <cjia@nvidia.com>, Gerd Hoffmann <kraxel@redhat.com>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: "Ruan, Shuai" <shuai.ruan@intel.com>,
Kevin <kevin.tian@intel.com>,
kvm@vger.kernel.org, qemu-devel <qemu-devel@nongnu.org>,
Jike <jike.song@intel.com>, Zhiyuan <zhiyuan.lv@intel.com>
Subject: Re: [Qemu-devel] [RFC PATCH v1 1/1] vGPU core driver : to provide common interface for vGPU.
Date: Tue, 2 Feb 2016 07:18:07 +0530 [thread overview]
Message-ID: <56B00AD7.6070103@nvidia.com> (raw)
In-Reply-To: <56AFD231.3010404@nvidia.com>
Resending this mail again, somehow my previous mail didn't reached every
to everyone's inbox.
On 2/2/2016 3:16 AM, Kirti Wankhede wrote:
> Design for vGPU Driver:
> Main purpose of vGPU driver is to provide a common interface for vGPU
> management that can be used by differnt GPU drivers.
>
> This module would provide a generic interface to create the device, add
> it to vGPU bus, add device to IOMMU group and then add it to vfio group.
>
> High Level block diagram:
>
>
> +--------------+ vgpu_register_driver()+---------------+
> | __init() +------------------------->+ |
> | | | |
> | +<-------------------------+ vgpu.ko |
> | vfio_vgpu.ko | probe()/remove() | |
> | | +---------+ +---------+
> +--------------+ | +-------+-------+ |
> | ^ |
> | callback | |
> | +-------+--------+ |
> | |vgpu_register_device() |
> | | | |
> +---^-----+-----+ +-----+------+-+
> | nvidia.ko | | i915.ko |
> | | | |
> +-----------+ +------------+
>
> vGPU driver provides two types of registration interfaces:
> 1. Registration interface for vGPU bus driver:
>
> /**
> * struct vgpu_driver - vGPU device driver
> * @name: driver name
> * @probe: called when new device created
> * @remove: called when device removed
> * @driver: device driver structure
> *
> **/
> struct vgpu_driver {
> const char *name;
> int (*probe) (struct device *dev);
> void (*remove) (struct device *dev);
> struct device_driver driver;
> };
>
> int vgpu_register_driver(struct vgpu_driver *drv, struct module *owner);
> void vgpu_unregister_driver(struct vgpu_driver *drv);
>
> VFIO bus driver for vgpu, should use this interface to register with
> vGPU driver. With this, VFIO bus driver for vGPU devices is responsible
> to add vGPU device to VFIO group.
>
> 2. GPU driver interface
>
> /**
> * struct gpu_device_ops - Structure to be registered for each physical
> GPU to
> * register the device to vgpu module.
> *
> * @owner: The module owner.
> * @vgpu_supported_config: Called to get information about supported
> * vgpu types.
> * @dev : pci device structure of physical GPU.
> * @config: should return string listing supported
> * config
> * Returns integer: success (0) or error (< 0)
> * @vgpu_create: Called to allocate basic resouces in graphics
> * driver for a particular vgpu.
> * @dev: physical pci device structure on which vgpu
> * should be created
> * @uuid: uuid for which VM it is intended to
> * @instance: vgpu instance in that VM
> * @vgpu_id: This represents the type of vgpu to be
> * created
> * Returns integer: success (0) or error (< 0)
> * @vgpu_destroy: Called to free resources in graphics driver for
> * a vgpu instance of that VM.
> * @dev: physical pci device structure to which
> * this vgpu points to.
> * @uuid: uuid for which the vgpu belongs to.
> * @instance: vgpu instance in that VM
> * Returns integer: success (0) or error (< 0)
> * If VM is running and vgpu_destroy is called that
> * means the vGPU is being hotunpluged. Return error
> * if VM is running and graphics driver doesn't
> * support vgpu hotplug.
> * @vgpu_start: Called to do initiate vGPU initialization
> * process in graphics driver when VM boots before
> * qemu starts.
> * @uuid: UUID which is booting.
> * Returns integer: success (0) or error (< 0)
> * @vgpu_shutdown: Called to teardown vGPU related resources for
> * the VM
> * @uuid: UUID which is shutting down .
> * Returns integer: success (0) or error (< 0)
> * @read: Read emulation callback
> * @vdev: vgpu device structure
> * @buf: read buffer
> * @count: number bytes to read
> * @address_space: specifies for which address space
> * the request is: pci_config_space, IO register
> * space or MMIO space.
> * Retuns number on bytes read on success or error.
> * @write: Write emulation callback
> * @vdev: vgpu device structure
> * @buf: write buffer
> * @count: number bytes to be written
> * @address_space: specifies for which address space
> * the request is: pci_config_space, IO register
> * space or MMIO space.
> * Retuns number on bytes written on success or
> error.
> * @vgpu_set_irqs: Called to send about interrupts configuration
> * information that qemu set.
> * @vdev: vgpu device structure
> * @flags, index, start, count and *data : same as
> * that of struct vfio_irq_set of
> * VFIO_DEVICE_SET_IRQS API.
> *
> * Physical GPU that support vGPU should be register with vgpu module with
> * gpu_device_ops structure.
> */
>
> struct gpu_device_ops {
> struct module *owner;
> int (*vgpu_supported_config)(struct pci_dev *dev,
> char *config);
> int (*vgpu_create)(struct pci_dev *dev, uuid_le uuid,
> uint32_t instance, uint32_t vgpu_id);
> int (*vgpu_destroy)(struct pci_dev *dev, uuid_le uuid,
> uint32_t instance);
> int (*vgpu_start)(uuid_le uuid);
> int (*vgpu_shutdown)(uuid_le uuid);
> ssize_t (*read) (struct vgpu_device *vdev, char *buf,
> size_t count, uint32_t address_space,
> loff_t pos);
> ssize_t (*write)(struct vgpu_device *vdev, char *buf,
> size_t count, uint32_t address_space,
> loff_t pos);
> int (*vgpu_set_irqs)(struct vgpu_device *vdev,
> uint32_t flags, unsigned index,
> unsigned start, unsigned count,
> void *data);
> };
>
> int vgpu_register_device(struct pci_dev *dev, const struct
> gpu_device_ops *ops);
> void vgpu_unregister_device(struct pci_dev *dev);
>
> This registration interface should be used by GPU drivers to register
> each physical device to vGPU driver.
>
> This patch set is to review major APIs and design structure before
> continuing development and don't consider as final patch for review.
> These registration interfaces would evolve as the development proceed.
>
> Regards,
> Kirti
>
> Signed-off-by: Kirti Wankhede <kwankhede@nvidia.com>
> Signed-off-by: Neo Jia <cjia@nvidia.com>
> ---
> ---
> drivers/vgpu/vgpu-driver.c | 137 ++++++++++++++
> drivers/vgpu/vgpu_dev.c | 421
> ++++++++++++++++++++++++++++++++++++++++++++
> include/linux/vgpu.h | 189 ++++++++++++++++++++
> 3 files changed, 747 insertions(+), 0 deletions(-)
> create mode 100644 drivers/vgpu/vgpu-driver.c
> create mode 100644 drivers/vgpu/vgpu_dev.c
> create mode 100644 include/linux/vgpu.h
>
> diff --git a/drivers/vgpu/vgpu-driver.c b/drivers/vgpu/vgpu-driver.c
> new file mode 100644
> index 0000000..6b62f19
> --- /dev/null
> +++ b/drivers/vgpu/vgpu-driver.c
> @@ -0,0 +1,137 @@
> +/*
> + * VGPU driver
> + *
> + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
> + * Author: Neo Jia <cjia@nvidia.com>
> + * Kirti Wankhede <kwankhede@nvidia.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/fs.h>
> +#include <linux/vfio.h>
> +#include <linux/iommu.h>
> +#include <linux/sysfs.h>
> +#include <linux/ctype.h>
> +#include <linux/vgpu.h>
> +
> +#include "vgpu_private.h"
> +
> +static int vgpu_device_attach_iommu(struct vgpu_device *vgpu_dev)
> +{
> + int retval = 0;
> + struct iommu_group *group = NULL;
> +
> + group = iommu_group_alloc();
> + if (IS_ERR(group)) {
> + printk(KERN_ERR "VGPU: failed to allocate group!\n");
> + return PTR_ERR(group);
> + }
> +
> + retval = iommu_group_add_device(group, &vgpu_dev->dev);
> + if (retval) {
> + printk(KERN_ERR "VGPU: failed to add dev to group!\n");
> + iommu_group_put(group);
> + return retval;
> + }
> +
> + vgpu_dev->group = group;
> +
> + printk(KERN_INFO "VGPU: group_id = %d \n", iommu_group_id(group));
> + return retval;
> +}
> +
> +static void vgpu_device_detach_iommu(struct vgpu_device *vgpu_dev)
> +{
> + iommu_group_put(vgpu_dev->dev.iommu_group);
> + iommu_group_remove_device(&vgpu_dev->dev);
> + printk(KERN_INFO "VGPU: detaching iommu \n");
> +}
> +
> +static int vgpu_device_probe(struct device *dev)
> +{
> + struct vgpu_driver *drv = to_vgpu_driver(dev->driver);
> + struct vgpu_device *vgpu_dev = to_vgpu_device(dev);
> + int status = 0;
> +
> + status = vgpu_device_attach_iommu(vgpu_dev);
> + if (status) {
> + printk(KERN_ERR "Failed to attach IOMMU\n");
> + return status;
> + }
> +
> + if (drv && drv->probe) {
> + status = drv->probe(dev);
> + }
> +
> + return status;
> +}
> +
> +static int vgpu_device_remove(struct device *dev)
> +{
> + struct vgpu_driver *drv = to_vgpu_driver(dev->driver);
> + struct vgpu_device *vgpu_dev = to_vgpu_device(dev);
> + int status = 0;
> +
> + if (drv && drv->remove) {
> + drv->remove(dev);
> + }
> +
> + vgpu_device_detach_iommu(vgpu_dev);
> +
> + return status;
> +}
> +
> +struct bus_type vgpu_bus_type = {
> + .name = "vgpu",
> + .probe = vgpu_device_probe,
> + .remove = vgpu_device_remove,
> +};
> +EXPORT_SYMBOL_GPL(vgpu_bus_type);
> +
> +/**
> + * vgpu_register_driver - register a new vGPU driver
> + * @drv: the driver to register
> + * @owner: owner module of driver ro register
> + *
> + * Returns a negative value on error, otherwise 0.
> + */
> +int vgpu_register_driver(struct vgpu_driver *drv, struct module *owner)
> +{
> + /* initialize common driver fields */
> + drv->driver.name = drv->name;
> + drv->driver.bus = &vgpu_bus_type;
> + drv->driver.owner = owner;
> +
> + /* register with core */
> + return driver_register(&drv->driver);
> +}
> +EXPORT_SYMBOL(vgpu_register_driver);
> +
> +/**
> + * vgpu_unregister_driver - unregister vGPU driver
> + * @drv: the driver to unregister
> + *
> + */
> +void vgpu_unregister_driver(struct vgpu_driver *drv)
> +{
> + driver_unregister(&drv->driver);
> +}
> +EXPORT_SYMBOL(vgpu_unregister_driver);
> +
> +int vgpu_bus_register(void)
> +{
> + return bus_register(&vgpu_bus_type);
> +}
> +
> +void vgpu_bus_unregister(void)
> +{
> + bus_unregister(&vgpu_bus_type);
> +}
> +
> diff --git a/drivers/vgpu/vgpu_dev.c b/drivers/vgpu/vgpu_dev.c
> new file mode 100644
> index 0000000..e5a92a1
> --- /dev/null
> +++ b/drivers/vgpu/vgpu_dev.c
> @@ -0,0 +1,421 @@
> +/*
> + * VGPU Core Driver
> + *
> + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
> + * Author: Neo Jia <cjia@nvidia.com>
> + * Kirti Wankhede <kwankhede@nvidia.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/fs.h>
> +#include <linux/poll.h>
> +#include <linux/slab.h>
> +#include <linux/cdev.h>
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +#include <linux/uuid.h>
> +#include <linux/vfio.h>
> +#include <linux/iommu.h>
> +#include <linux/sysfs.h>
> +#include <linux/ctype.h>
> +#include <linux/vgpu.h>
> +
> +#include "vgpu_private.h"
> +
> +#define DRIVER_VERSION "0.1"
> +#define DRIVER_AUTHOR "NVIDIA Corporation"
> +#define DRIVER_DESC "VGPU Core Driver"
> +
> +/*
> + * #defines
> + */
> +
> +#define VGPU_CLASS_NAME "vgpu"
> +
> +/*
> + * Global Structures
> + */
> +
> +static struct vgpu {
> + struct list_head vgpu_devices_list;
> + struct mutex vgpu_devices_lock;
> + struct list_head gpu_devices_list;
> + struct mutex gpu_devices_lock;
> +} vgpu;
> +
> +
> +static struct class vgpu_class;
> +
> +/*
> + * Function prototypes
> + */
> +
> +unsigned int vgpu_poll(struct file *file, poll_table *wait);
> +long vgpu_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned
> long i_arg);
> +int vgpu_mmap(struct file *file, struct vm_area_struct *vma);
> +
> +int vgpu_open(struct inode *inode, struct file *file);
> +int vgpu_close(struct inode *inode, struct file *file);
> +ssize_t vgpu_read(struct file *file, char __user * buf,
> + size_t len, loff_t * ppos);
> +ssize_t vgpu_write(struct file *file, const char __user *data,
> + size_t len, loff_t *ppos);
> +
> +/*
> + * Functions
> + */
> +
> +struct vgpu_device *get_vgpu_device_from_group(struct iommu_group *group)
> +{
> + struct vgpu_device *vdev = NULL;
> +
> + mutex_lock(&vgpu.vgpu_devices_lock);
> + list_for_each_entry(vdev, &vgpu.vgpu_devices_list, list) {
> + if (vdev->group) {
> + if (iommu_group_id(vdev->group) == iommu_group_id(group)) {
> + mutex_unlock(&vgpu.vgpu_devices_lock);
> + return vdev;
> + }
> + }
> + }
> + mutex_unlock(&vgpu.vgpu_devices_lock);
> + return NULL;
> +}
> +
> +EXPORT_SYMBOL_GPL(get_vgpu_device_from_group);
> +
> +int vgpu_register_device(struct pci_dev *dev, const struct
> gpu_device_ops *ops)
> +{
> + int ret = 0;
> + struct gpu_device *gpu_dev, *tmp;
> +
> + if (!dev)
> + return -EINVAL;
> +
> + gpu_dev = kzalloc(sizeof(*gpu_dev), GFP_KERNEL);
> + if (!gpu_dev)
> + return -ENOMEM;
> +
> + gpu_dev->dev = dev;
> + gpu_dev->ops = ops;
> +
> + mutex_lock(&vgpu.gpu_devices_lock);
> +
> + /* Check for duplicates */
> + list_for_each_entry(tmp, &vgpu.gpu_devices_list, gpu_next) {
> + if (tmp->dev == dev) {
> + mutex_unlock(&vgpu.gpu_devices_lock);
> + kfree(gpu_dev);
> + return -EINVAL;
> + }
> + }
> +
> + ret = vgpu_create_pci_device_files(dev);
> + if (ret) {
> + mutex_unlock(&vgpu.gpu_devices_lock);
> + kfree(gpu_dev);
> + return ret;
> + }
> + list_add(&gpu_dev->gpu_next, &vgpu.gpu_devices_list);
> +
> + printk(KERN_INFO "VGPU: Registered dev 0x%x 0x%x, class 0x%x\n",
> dev->vendor, dev->device, dev->class);
> + mutex_unlock(&vgpu.gpu_devices_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(vgpu_register_device);
> +
> +void vgpu_unregister_device(struct pci_dev *dev)
> +{
> + struct gpu_device *gpu_dev;
> +
> + mutex_lock(&vgpu.gpu_devices_lock);
> + list_for_each_entry(gpu_dev, &vgpu.gpu_devices_list, gpu_next) {
> + if (gpu_dev->dev == dev) {
> + printk(KERN_INFO "VGPU: Unregistered dev 0x%x 0x%x, class
> 0x%x\n", dev->vendor, dev->device, dev->class);
> + vgpu_remove_pci_device_files(dev);
> + list_del(&gpu_dev->gpu_next);
> + mutex_unlock(&vgpu.gpu_devices_lock);
> + kfree(gpu_dev);
> + return;
> + }
> + }
> + mutex_unlock(&vgpu.gpu_devices_lock);
> +}
> +EXPORT_SYMBOL(vgpu_unregister_device);
> +
> +/*
> + * Helper Functions
> + */
> +
> +static struct vgpu_device *vgpu_device_alloc(uuid_le uuid, int
> instance, char *name)
> +{
> + struct vgpu_device *vgpu_dev = NULL;
> +
> + vgpu_dev = kzalloc(sizeof(*vgpu_dev), GFP_KERNEL);
> + if (!vgpu_dev)
> + return ERR_PTR(-ENOMEM);
> +
> + kref_init(&vgpu_dev->kref);
> + memcpy(&vgpu_dev->uuid, &uuid, sizeof(uuid_le));
> + vgpu_dev->vgpu_instance = instance;
> + strcpy(vgpu_dev->dev_name, name);
> +
> + mutex_lock(&vgpu.vgpu_devices_lock);
> + list_add(&vgpu_dev->list, &vgpu.vgpu_devices_list);
> + mutex_unlock(&vgpu.vgpu_devices_lock);
> +
> + return vgpu_dev;
> +}
> +
> +static void vgpu_device_free(struct vgpu_device *vgpu_dev)
> +{
> + if (vgpu_dev) {
> + mutex_lock(&vgpu.vgpu_devices_lock);
> + list_del(&vgpu_dev->list);
> + mutex_unlock(&vgpu.vgpu_devices_lock);
> + kfree(vgpu_dev);
> + }
> + return;
> +}
> +
> +struct vgpu_device *vgpu_drv_get_vgpu_device_by_uuid(uuid_le uuid, int
> instance)
> +{
> + struct vgpu_device *vdev = NULL;
> +
> + mutex_lock(&vgpu.vgpu_devices_lock);
> + list_for_each_entry(vdev, &vgpu.vgpu_devices_list, list) {
> + if ((uuid_le_cmp(vdev->uuid, uuid) == 0) &&
> + (vdev->vgpu_instance == instance)) {
> + mutex_unlock(&vgpu.vgpu_devices_lock);
> + return vdev;
> + }
> + }
> + mutex_unlock(&vgpu.vgpu_devices_lock);
> + return NULL;
> +}
> +
> +static void vgpu_device_release(struct device *dev)
> +{
> + struct vgpu_device *vgpu_dev = to_vgpu_device(dev);
> + vgpu_device_free(vgpu_dev);
> +}
> +
> +int create_vgpu_device(struct pci_dev *pdev, uuid_le uuid, uint32_t
> instance, uint32_t vgpu_id)
> +{
> + char name[64];
> + int numChar = 0;
> + int retval = 0;
> + struct vgpu_device *vgpu_dev = NULL;
> + struct gpu_device *gpu_dev;
> +
> + printk(KERN_INFO "VGPU: %s: device ", __FUNCTION__);
> +
> + numChar = sprintf(name, "%pUb-%d", uuid.b, instance);
> + name[numChar] = '\0';
> +
> + vgpu_dev = vgpu_device_alloc(uuid, instance, name);
> + if (IS_ERR(vgpu_dev)) {
> + return PTR_ERR(vgpu_dev);
> + }
> +
> + vgpu_dev->vgpu_id = vgpu_id;
> + vgpu_dev->dev.parent = NULL;
> + vgpu_dev->dev.bus = &vgpu_bus_type;
> + vgpu_dev->dev.release = vgpu_device_release;
> + dev_set_name(&vgpu_dev->dev, "%s", name);
> +
> + retval = device_register(&vgpu_dev->dev);
> + if (retval)
> + goto create_failed1;
> +
> + printk(KERN_INFO "UUID %pUb \n", vgpu_dev->uuid.b);
> +
> + mutex_lock(&vgpu.gpu_devices_lock);
> + list_for_each_entry(gpu_dev, &vgpu.gpu_devices_list, gpu_next) {
> + if (gpu_dev->dev == pdev) {
> + vgpu_dev->gpu_dev = gpu_dev;
> + if (gpu_dev->ops->vgpu_create) {
> + retval = gpu_dev->ops->vgpu_create(pdev, vgpu_dev->uuid,
> + instance, vgpu_id);
> + if (retval) {
> + mutex_unlock(&vgpu.gpu_devices_lock);
> + goto create_failed2;
> + }
> + }
> + break;
> + }
> + }
> + if (!vgpu_dev->gpu_dev) {
> + retval = -EINVAL;
> + goto create_failed2;
> + }
> +
> + mutex_unlock(&vgpu.gpu_devices_lock);
> +
> + return retval;
> +
> +create_failed2:
> + device_unregister(&vgpu_dev->dev);
> +
> +create_failed1:
> + vgpu_device_free(vgpu_dev);
> +
> + return retval;
> +}
> +
> +void destroy_vgpu_device(struct vgpu_device *vgpu_dev)
> +{
> + printk(KERN_INFO "VGPU: destroying device %s ", vgpu_dev->dev_name);
> + if (vgpu_dev->gpu_dev->ops->vgpu_destroy) {
> + int retval = 0;
> + retval =
> vgpu_dev->gpu_dev->ops->vgpu_destroy(vgpu_dev->gpu_dev->dev,
> + vgpu_dev->uuid,
> + vgpu_dev->vgpu_instance);
> + /* if vendor driver doesn't return success that means vendor driver
> doesn't
> + * support hot-unplug */
> + if (retval)
> + return;
> + }
> +
> + device_unregister(&vgpu_dev->dev);
> +}
> +
> +void destroy_vgpu_device_by_uuid(uuid_le uuid, int instance)
> +{
> + struct vgpu_device *vdev, *vgpu_dev = NULL;
> +
> + mutex_lock(&vgpu.vgpu_devices_lock);
> +
> + // search VGPU device
> + list_for_each_entry(vdev, &vgpu.vgpu_devices_list, list) {
> + if ((uuid_le_cmp(vdev->uuid, uuid) == 0) &&
> + (vdev->vgpu_instance == instance)) {
> + vgpu_dev = vdev;
> + break;
> + }
> + }
> +
> + mutex_unlock(&vgpu.vgpu_devices_lock);
> + if (vgpu_dev)
> + destroy_vgpu_device(vgpu_dev);
> +}
> +
> +void get_vgpu_supported_types(struct device *dev, char *str)
> +{
> + struct gpu_device *gpu_dev;
> +
> + mutex_lock(&vgpu.gpu_devices_lock);
> + list_for_each_entry(gpu_dev, &vgpu.gpu_devices_list, gpu_next) {
> + if (&gpu_dev->dev->dev == dev) {
> + if (gpu_dev->ops->vgpu_supported_config)
> + gpu_dev->ops->vgpu_supported_config(gpu_dev->dev, str);
> + break;
> + }
> + }
> + mutex_unlock(&vgpu.gpu_devices_lock);
> +}
> +
> +int vgpu_start_callback(struct vgpu_device *vgpu_dev)
> +{
> + int ret = 0;
> +
> + mutex_lock(&vgpu.gpu_devices_lock);
> + if (vgpu_dev->gpu_dev->ops->vgpu_start)
> + ret = vgpu_dev->gpu_dev->ops->vgpu_start(vgpu_dev->uuid);
> + mutex_unlock(&vgpu.gpu_devices_lock);
> + return ret;
> +}
> +
> +int vgpu_shutdown_callback(struct vgpu_device *vgpu_dev)
> +{
> + int ret = 0;
> +
> + mutex_lock(&vgpu.gpu_devices_lock);
> + if (vgpu_dev->gpu_dev->ops->vgpu_shutdown)
> + ret = vgpu_dev->gpu_dev->ops->vgpu_shutdown(vgpu_dev->uuid);
> + mutex_unlock(&vgpu.gpu_devices_lock);
> + return ret;
> +}
> +
> +int vgpu_set_irqs_callback(struct vgpu_device *vgpu_dev, uint32_t flags,
> + unsigned index, unsigned start, unsigned count,
> + void *data)
> +{
> + int ret = 0;
> +
> + mutex_lock(&vgpu.gpu_devices_lock);
> + if (vgpu_dev->gpu_dev->ops->vgpu_set_irqs)
> + ret = vgpu_dev->gpu_dev->ops->vgpu_set_irqs(vgpu_dev,
> flags,
> + index, start,
> count, data);
> + mutex_unlock(&vgpu.gpu_devices_lock);
> + return ret;
> +}
> +
> +char *vgpu_devnode(struct device *dev, umode_t *mode)
> +{
> + return kasprintf(GFP_KERNEL, "vgpu/%s", dev_name(dev));
> +}
> +
> +static void release_vgpubus_dev(struct device *dev)
> +{
> + struct vgpu_device *vgpu_dev = to_vgpu_device(dev);
> + destroy_vgpu_device(vgpu_dev);
> +}
> +
> +static struct class vgpu_class = {
> + .name = VGPU_CLASS_NAME,
> + .owner = THIS_MODULE,
> + .class_attrs = vgpu_class_attrs,
> + .dev_groups = vgpu_dev_groups,
> + .devnode = vgpu_devnode,
> + .dev_release = release_vgpubus_dev,
> +};
> +
> +static int __init vgpu_init(void)
> +{
> + int rc = 0;
> +
> + memset(&vgpu, 0 , sizeof(vgpu));
> +
> + mutex_init(&vgpu.vgpu_devices_lock);
> + INIT_LIST_HEAD(&vgpu.vgpu_devices_list);
> + mutex_init(&vgpu.gpu_devices_lock);
> + INIT_LIST_HEAD(&vgpu.gpu_devices_list);
> +
> + rc = class_register(&vgpu_class);
> + if (rc < 0) {
> + printk(KERN_ERR "Error: failed to register vgpu class\n");
> + goto failed1;
> + }
> +
> + rc = vgpu_bus_register();
> + if (rc < 0) {
> + printk(KERN_ERR "Error: failed to register vgpu bus\n");
> + class_unregister(&vgpu_class);
> + }
> +
> +failed1:
> + return rc;
> +}
> +
> +static void __exit vgpu_exit(void)
> +{
> + vgpu_bus_unregister();
> + class_unregister(&vgpu_class);
> +}
> +
> +module_init(vgpu_init)
> +module_exit(vgpu_exit)
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> diff --git a/include/linux/vgpu.h b/include/linux/vgpu.h
> new file mode 100644
> index 0000000..8595df5
> --- /dev/null
> +++ b/include/linux/vgpu.h
> @@ -0,0 +1,189 @@
> +/*
> + * VGPU definition
> + *
> + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
> + * Author:
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef VGPU_H
> +#define VGPU_H
> +
> +// Common Data structures
> +
> +struct pci_bar_info {
> + uint64_t start;
> + uint64_t end;
> + int flags;
> +};
> +
> +enum vgpu_emul_space_e {
> + vgpu_emul_space_config = 0, /*!< PCI configuration space */
> + vgpu_emul_space_io = 1, /*!< I/O register space */
> + vgpu_emul_space_mmio = 2 /*!< Memory-mapped I/O space */
> +};
> +
> +struct gpu_device;
> +
> +/*
> + * VGPU device
> + */
> +struct vgpu_device {
> + struct kref kref;
> + struct device dev;
> + struct gpu_device *gpu_dev;
> + struct iommu_group *group;
> +#define DEVICE_NAME_LEN (64)
> + char dev_name[DEVICE_NAME_LEN];
> + uuid_le uuid;
> + uint32_t vgpu_instance;
> + uint32_t vgpu_id;
> + char config_space[0x100]; // 4KB PCI cfg space
> + struct pci_bar_info bar[VFIO_PCI_NUM_REGIONS];
> + struct device_attribute *dev_attr_vgpu_status;
> + int vgpu_device_status;
> +
> + void *driver_data;
> +
> + struct list_head list;
> +};
> +
> +
> +/**
> + * struct gpu_device_ops - Structure to be registered for each physical
> GPU to
> + * register the device to vgpu module.
> + *
> + * @owner: The module owner.
> + * @vgpu_supported_config: Called to get information about supported
> vgpu types.
> + * @dev : pci device structure of physical GPU.
> + * @config: should return string listing supported config
> + * Returns integer: success (0) or error (< 0)
> + * @vgpu_create: Called to allocate basic resouces in graphics
> + * driver for a particular vgpu.
> + * @dev: physical pci device structure on which vgpu
> + * should be created
> + * @uuid: uuid for which VM it is intended to
> + * @instance: vgpu instance in that VM
> + * @vgpu_id: This represents the type of vgpu to be
> + * created
> + * Returns integer: success (0) or error (< 0)
> + * @vgpu_destroy: Called to free resources in graphics driver for
> + * a vgpu instance of that VM.
> + * @dev: physical pci device structure to which
> + * this vgpu points to.
> + * @uuid: uuid for which the vgpu belongs to.
> + * @instance: vgpu instance in that VM
> + * Returns integer: success (0) or error (< 0)
> + * If VM is running and vgpu_destroy is called that
> + * means the vGPU is being hotunpluged. Return error
> + * if VM is running and graphics driver doesn't
> + * support vgpu hotplug.
> + * @vgpu_start: Called to do initiate vGPU initialization
> + * process in graphics driver when VM boots before
> + * qemu starts.
> + * @uuid: UUID which is booting.
> + * Returns integer: success (0) or error (< 0)
> + * @vgpu_shutdown: Called to teardown vGPU related resources for
> + * the VM
> + * @uuid: UUID which is shutting down .
> + * Returns integer: success (0) or error (< 0)
> + * @read: Read emulation callback
> + * @vdev: vgpu device structure
> + * @buf: read buffer
> + * @count: number bytes to read
> + * @address_space: specifies for which address space
> + * the request is: pci_config_space, IO register
> + * space or MMIO space.
> + * Retuns number on bytes read on success or error.
> + * @write: Write emulation callback
> + * @vdev: vgpu device structure
> + * @buf: write buffer
> + * @count: number bytes to be written
> + * @address_space: specifies for which address space
> + * the request is: pci_config_space, IO register
> + * space or MMIO space.
> + * Retuns number on bytes written on success or error.
> + * @vgpu_set_irqs: Called to send about interrupts configuration
> + * information that qemu set.
> + * @vdev: vgpu device structure
> + * @flags, index, start, count and *data : same as
> + * that of struct vfio_irq_set of
> + * VFIO_DEVICE_SET_IRQS API.
> + *
> + * Physical GPU that support vGPU should be register with vgpu module with
> + * gpu_device_ops structure.
> + */
> +
> +struct gpu_device_ops {
> + struct module *owner;
> + int (*vgpu_supported_config)(struct pci_dev *dev, char *config);
> + int (*vgpu_create)(struct pci_dev *dev, uuid_le uuid,
> + uint32_t instance, uint32_t vgpu_id);
> + int (*vgpu_destroy)(struct pci_dev *dev, uuid_le uuid,
> + uint32_t instance);
> + int (*vgpu_start)(uuid_le uuid);
> + int (*vgpu_shutdown)(uuid_le uuid);
> + ssize_t (*read) (struct vgpu_device *vdev, char *buf, size_t count,
> + uint32_t address_space, loff_t pos);
> + ssize_t (*write)(struct vgpu_device *vdev, char *buf, size_t count,
> + uint32_t address_space,loff_t pos);
> + int (*vgpu_set_irqs)(struct vgpu_device *vdev, uint32_t flags,
> + unsigned index, unsigned start, unsigned count,
> + void *data);
> +
> +};
> +
> +/*
> + * Physical GPU
> + */
> +struct gpu_device {
> + struct pci_dev *dev;
> + const struct gpu_device_ops *ops;
> + struct list_head gpu_next;
> +};
> +
> +/**
> + * struct vgpu_driver - vGPU device driver
> + * @name: driver name
> + * @probe: called when new device created
> + * @remove: called when device removed
> + * @driver: device driver structure
> + *
> + **/
> +struct vgpu_driver {
> + const char *name;
> + int (*probe) (struct device *dev);
> + void (*remove) (struct device *dev);
> + struct device_driver driver;
> +};
> +
> +static inline struct vgpu_driver *to_vgpu_driver(struct device_driver
> *drv)
> +{
> + return drv ? container_of(drv, struct vgpu_driver, driver) : NULL;
> +}
> +
> +static inline struct vgpu_device *to_vgpu_device(struct device *dev)
> +{
> + return dev ? container_of(dev, struct vgpu_device, dev) : NULL;
> +}
> +
> +extern struct bus_type vgpu_bus_type;
> +
> +#define dev_is_vgpu(d) ((d)->bus == &vgpu_bus_type)
> +
> +extern int vgpu_register_device(struct pci_dev *dev, const struct
> gpu_device_ops *ops);
> +extern void vgpu_unregister_device(struct pci_dev *dev);
> +
> +extern int vgpu_register_driver(struct vgpu_driver *drv, struct module
> *owner);
> +extern void vgpu_unregister_driver(struct vgpu_driver *drv);
> +
> +extern int vgpu_map_virtual_bar(uint64_t virt_bar_addr, uint64_t
> phys_bar_addr, uint32_t len, uint32_t flags);
> +extern int vgpu_dma_do_translate(dma_addr_t * gfn_buffer, uint32_t count);
> +
> +struct vgpu_device *get_vgpu_device_from_group(struct iommu_group *group);
> +
> +#endif /* VGPU_H */
> +
next parent reply other threads:[~2016-02-02 1:48 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <56AFD231.3010404@nvidia.com>
2016-02-02 1:48 ` Kirti Wankhede [this message]
2016-02-02 7:42 ` [Qemu-devel] [RFC PATCH v1 1/1] vGPU core driver : to provide common interface for vGPU Tian, Kevin
2016-02-02 8:00 ` Gerd Hoffmann
2016-02-02 8:13 ` Neo Jia
2016-02-02 8:18 ` Tian, Kevin
2016-02-02 8:31 ` Neo Jia
2016-02-02 17:11 ` Alex Williamson
2016-02-03 5:41 ` Tian, Kevin
2016-02-03 8:28 ` Gerd Hoffmann
2016-02-03 19:32 ` Alex Williamson
2016-02-16 6:49 ` Tian, Kevin
2016-02-16 7:13 ` Neo Jia
2016-02-16 7:27 ` Tian, Kevin
2016-02-16 7:36 ` Neo Jia
2016-02-16 7:40 ` Tian, Kevin
2016-02-16 7:53 ` Neo Jia
2016-02-16 8:10 ` Tian, Kevin
2016-02-16 8:48 ` Neo Jia
2016-02-17 3:31 ` Tian, Kevin
2016-02-17 4:17 ` Neo Jia
2016-02-17 5:04 ` Tian, Kevin
2016-02-17 5:09 ` Eric Blake
2016-02-17 5:40 ` Neo Jia
2016-02-17 5:37 ` Neo Jia
2016-02-17 6:02 ` Tian, Kevin
2016-02-17 7:26 ` Neo Jia
2016-02-17 7:46 ` Tian, Kevin
2016-02-17 7:54 ` Neo Jia
2016-02-17 8:57 ` Tian, Kevin
2016-02-17 9:34 ` Neo Jia
2016-02-17 9:52 ` Tian, Kevin
2016-02-17 10:34 ` Neo Jia
2016-02-17 10:47 ` Tian, Kevin
2016-02-17 13:08 ` Gerd Hoffmann
2016-02-17 15:36 ` Neo Jia
2016-02-17 6:52 ` Gerd Hoffmann
2016-02-17 7:32 ` Neo Jia
2016-02-17 7:51 ` Tian, Kevin
2016-02-17 8:41 ` Neo Jia
2016-02-17 9:01 ` Tian, Kevin
2016-02-02 8:29 ` Gerd Hoffmann
2016-02-02 9:25 ` Kirti Wankhede
2016-02-03 5:56 ` Tian, Kevin
2016-02-03 13:21 ` Kirti Wankhede
2016-02-04 3:08 ` Tian, Kevin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=56B00AD7.6070103@nvidia.com \
--to=kwankhede@nvidia.com \
--cc=alex.williamson@redhat.com \
--cc=cjia@nvidia.com \
--cc=jike.song@intel.com \
--cc=kevin.tian@intel.com \
--cc=kraxel@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=shuai.ruan@intel.com \
--cc=zhiyuan.lv@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).