qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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 */
> +

       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).