| .. SPDX-License-Identifier: GPL-2.0-only | |
| .. include:: <isonum.txt> | |
| ===================== | |
| VFIO Mediated devices | |
| ===================== | |
| :Copyright: |copy| 2016, NVIDIA CORPORATION. All rights reserved. | |
| :Author: Neo Jia <cjia@nvidia.com> | |
| :Author: Kirti Wankhede <kwankhede@nvidia.com> | |
| Virtual Function I/O (VFIO) Mediated devices[1] | |
| =============================================== | |
| The number of use cases for virtualizing DMA devices that do not have built-in | |
| SR_IOV capability is increasing. Previously, to virtualize such devices, | |
| developers had to create their own management interfaces and APIs, and then | |
| integrate them with user space software. To simplify integration with user space | |
| software, we have identified common requirements and a unified management | |
| interface for such devices. | |
| The VFIO driver framework provides unified APIs for direct device access. It is | |
| an IOMMU/device-agnostic framework for exposing direct device access to user | |
| space in a secure, IOMMU-protected environment. This framework is used for | |
| multiple devices, such as GPUs, network adapters, and compute accelerators. With | |
| direct device access, virtual machines or user space applications have direct | |
| access to the physical device. This framework is reused for mediated devices. | |
| The mediated core driver provides a common interface for mediated device | |
| management that can be used by drivers of different devices. This module | |
| provides a generic interface to perform these operations: | |
| * Create and destroy a mediated device | |
| * Add a mediated device to and remove it from a mediated bus driver | |
| * Add a mediated device to and remove it from an IOMMU group | |
| The mediated core driver also provides an interface to register a bus driver. | |
| For example, the mediated VFIO mdev driver is designed for mediated devices and | |
| supports VFIO APIs. The mediated bus driver adds a mediated device to and | |
| removes it from a VFIO group. | |
| The following high-level block diagram shows the main components and interfaces | |
| in the VFIO mediated driver framework. The diagram shows NVIDIA, Intel, and IBM | |
| devices as examples, as these devices are the first devices to use this module:: | |
| +---------------+ | |
| | | | |
| | +-----------+ | mdev_register_driver() +--------------+ | |
| | | | +<------------------------+ | | |
| | | mdev | | | | | |
| | | bus | +------------------------>+ vfio_mdev.ko |<-> VFIO user | |
| | | driver | | probe()/remove() | | APIs | |
| | | | | +--------------+ | |
| | +-----------+ | | |
| | | | |
| | MDEV CORE | | |
| | MODULE | | |
| | mdev.ko | | |
| | +-----------+ | mdev_register_parent() +--------------+ | |
| | | | +<------------------------+ | | |
| | | | | | ccw_device.ko|<-> physical | |
| | | | +------------------------>+ | device | |
| | | | | callbacks +--------------+ | |
| | | Physical | | | |
| | | device | | mdev_register_parent() +--------------+ | |
| | | interface | |<------------------------+ | | |
| | | | | | i915.ko |<-> physical | |
| | | | +------------------------>+ | device | |
| | | | | callbacks +--------------+ | |
| | +-----------+ | | |
| +---------------+ | |
| Registration Interfaces | |
| ======================= | |
| The mediated core driver provides the following types of registration | |
| interfaces: | |
| * Registration interface for a mediated bus driver | |
| * Physical device driver interface | |
| Registration Interface for a Mediated Bus Driver | |
| ------------------------------------------------ | |
| The registration interface for a mediated device driver provides the following | |
| structure to represent a mediated device's driver:: | |
| /* | |
| * struct mdev_driver [2] - Mediated device's driver | |
| * @probe: called when new device created | |
| * @remove: called when device removed | |
| * @driver: device driver structure | |
| */ | |
| struct mdev_driver { | |
| int (*probe) (struct mdev_device *dev); | |
| void (*remove) (struct mdev_device *dev); | |
| unsigned int (*get_available)(struct mdev_type *mtype); | |
| ssize_t (*show_description)(struct mdev_type *mtype, char *buf); | |
| struct device_driver driver; | |
| }; | |
| A mediated bus driver for mdev should use this structure in the function calls | |
| to register and unregister itself with the core driver: | |
| * Register:: | |
| int mdev_register_driver(struct mdev_driver *drv); | |
| * Unregister:: | |
| void mdev_unregister_driver(struct mdev_driver *drv); | |
| The mediated bus driver's probe function should create a vfio_device on top of | |
| the mdev_device and connect it to an appropriate implementation of | |
| vfio_device_ops. | |
| When a driver wants to add the GUID creation sysfs to an existing device it has | |
| probe'd to then it should call:: | |
| int mdev_register_parent(struct mdev_parent *parent, struct device *dev, | |
| struct mdev_driver *mdev_driver); | |
| This will provide the 'mdev_supported_types/XX/create' files which can then be | |
| used to trigger the creation of a mdev_device. The created mdev_device will be | |
| attached to the specified driver. | |
| When the driver needs to remove itself it calls:: | |
| void mdev_unregister_parent(struct mdev_parent *parent); | |
| Which will unbind and destroy all the created mdevs and remove the sysfs files. | |
| Mediated Device Management Interface Through sysfs | |
| ================================================== | |
| The management interface through sysfs enables user space software, such as | |
| libvirt, to query and configure mediated devices in a hardware-agnostic fashion. | |
| This management interface provides flexibility to the underlying physical | |
| device's driver to support features such as: | |
| * Mediated device hot plug | |
| * Multiple mediated devices in a single virtual machine | |
| * Multiple mediated devices from different physical devices | |
| Links in the mdev_bus Class Directory | |
| ------------------------------------- | |
| The /sys/class/mdev_bus/ directory contains links to devices that are registered | |
| with the mdev core driver. | |
| Directories and files under the sysfs for Each Physical Device | |
| -------------------------------------------------------------- | |
| :: | |
| |- [parent physical device] | |
| |--- Vendor-specific-attributes [optional] | |
| |--- [mdev_supported_types] | |
| | |--- [<type-id>] | |
| | | |--- create | |
| | | |--- name | |
| | | |--- available_instances | |
| | | |--- device_api | |
| | | |--- description | |
| | | |--- [devices] | |
| | |--- [<type-id>] | |
| | | |--- create | |
| | | |--- name | |
| | | |--- available_instances | |
| | | |--- device_api | |
| | | |--- description | |
| | | |--- [devices] | |
| | |--- [<type-id>] | |
| | |--- create | |
| | |--- name | |
| | |--- available_instances | |
| | |--- device_api | |
| | |--- description | |
| | |--- [devices] | |
| * [mdev_supported_types] | |
| The list of currently supported mediated device types and their details. | |
| [<type-id>], device_api, and available_instances are mandatory attributes | |
| that should be provided by vendor driver. | |
| * [<type-id>] | |
| The [<type-id>] name is created by adding the device driver string as a prefix | |
| to the string provided by the vendor driver. This format of this name is as | |
| follows:: | |
| sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name); | |
| * device_api | |
| This attribute shows which device API is being created, for example, | |
| "vfio-pci" for a PCI device. | |
| * available_instances | |
| This attribute shows the number of devices of type <type-id> that can be | |
| created. | |
| * [device] | |
| This directory contains links to the devices of type <type-id> that have been | |
| created. | |
| * name | |
| This attribute shows a human readable name. | |
| * description | |
| This attribute can show brief features/description of the type. This is an | |
| optional attribute. | |
| Directories and Files Under the sysfs for Each mdev Device | |
| ---------------------------------------------------------- | |
| :: | |
| |- [parent phy device] | |
| |--- [$MDEV_UUID] | |
| |--- remove | |
| |--- mdev_type {link to its type} | |
| |--- vendor-specific-attributes [optional] | |
| * remove (write only) | |
| Writing '1' to the 'remove' file destroys the mdev device. The vendor driver can | |
| fail the remove() callback if that device is active and the vendor driver | |
| doesn't support hot unplug. | |
| Example:: | |
| # echo 1 > /sys/bus/mdev/devices/$mdev_UUID/remove | |
| Mediated device Hot plug | |
| ------------------------ | |
| Mediated devices can be created and assigned at runtime. The procedure to hot | |
| plug a mediated device is the same as the procedure to hot plug a PCI device. | |
| Translation APIs for Mediated Devices | |
| ===================================== | |
| The following APIs are provided for translating user pfn to host pfn in a VFIO | |
| driver:: | |
| int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova, | |
| int npage, int prot, struct page **pages); | |
| void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova, | |
| int npage); | |
| These functions call back into the back-end IOMMU module by using the pin_pages | |
| and unpin_pages callbacks of the struct vfio_iommu_driver_ops[4]. Currently | |
| these callbacks are supported in the TYPE1 IOMMU module. To enable them for | |
| other IOMMU backend modules, such as PPC64 sPAPR module, they need to provide | |
| these two callback functions. | |
| References | |
| ========== | |
| 1. See Documentation/driver-api/vfio.rst for more information on VFIO. | |
| 2. struct mdev_driver in include/linux/mdev.h | |
| 3. struct mdev_parent_ops in include/linux/mdev.h | |
| 4. struct vfio_iommu_driver_ops in include/linux/vfio.h |