요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. 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
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
VFIO mediated device framework의 목적
1-43이 문서는 NVIDIA의 Neo Jia와 Kirti Wankhede가 작성한 VFIO mediated device 설명서입니다. Built-in SR-IOV capability가 없는 DMA device를 virtualize할 때 vendor마다 별도 management API를 만들던 문제를 공통 요구와 unified interface로 해결합니다.
VFIO는 IOMMU와 device 종류에 독립적인 direct-device-access framework입니다. IOMMU가 보호하는 환경에서 GPU, network adapter, compute accelerator를 VM이나 userspace application에 안전하게 직접 노출하며 이 framework를 mediated device에도 재사용합니다.
Mediated core driver는 서로 다른 physical driver가 공통으로 mdev를 생성·제거하고 mediated bus driver 및 IOMMU group에 add·remove할 interface를 제공합니다.
Core는 mediated bus driver 등록도 지원합니다. 대표적으로 `vfio_mdev` driver는 VFIO API를 제공하고 mdev를 VFIO group에 연결하거나 제거합니다.
.. 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.
MDEV core, bus driver와 physical parent 구조
44-75MDEV core module `mdev.ko`는 위쪽의 mdev bus driver와 아래쪽 physical device interface를 함께 관리합니다.
`vfio_mdev.ko`는 `mdev_register_driver()`로 bus driver를 등록하고 core는 새 mdev에 `probe()`·`remove()`를 호출합니다. VFIO userspace API는 이 driver를 통해 접근합니다.
`ccw_device.ko`, `i915.ko` 같은 physical driver는 `mdev_register_parent()`로 parent와 callback을 core에 등록합니다. NVIDIA, Intel, IBM device는 이 framework를 처음 사용한 사례로 도식에 제시됩니다.
공통 MDEV core가 physical parent resource와 VFIO userspace-facing bus driver를 연결합니다.
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 +--------------+
| +-----------+ |
+---------------+
mdev_driver와 parent 등록 interface
76-135Mediated core는 mediated bus driver registration interface와 physical device driver interface를 제공합니다.
`struct mdev_driver`는 mdev 생성·제거 때의 `probe`·`remove`, type별 생성 가능 수를 반환하는 `get_available`, type 설명을 쓰는 `show_description`, 기반 `device_driver`를 포함합니다.
Bus driver는 `mdev_register_driver()`와 `mdev_unregister_driver()`로 core에 등록·해제합니다. Probe는 `mdev_device` 위에 `vfio_device`를 만들고 적절한 `vfio_device_ops` 구현과 연결해야 합니다.
기존 physical device에 GUID 생성 sysfs를 추가하려면 `mdev_register_parent(parent, dev, mdev_driver)`를 호출합니다. 그러면 `mdev_supported_types/XX/create`가 생기고 여기에 GUID를 써서 생성한 `mdev_device`가 지정 driver에 attach됩니다.
Driver removal은 `mdev_unregister_parent()`를 호출하며 이 과정에서 생성된 모든 mdev를 unbind·destroy하고 관련 sysfs file을 제거합니다.
Bus driver와 physical parent를 등록한 뒤 sysfs create가 mdev binding을 시작합니다.
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.
Physical device별 supported type sysfs
136-220Sysfs management interface는 libvirt 같은 userspace가 hardware 종류에 독립적으로 mdev를 query·configure하게 합니다. Runtime hot plug, 한 VM의 여러 mdev, 서로 다른 physical device에서 온 mdev 조합을 지원할 수 있습니다.
`/sys/class/mdev_bus/`에는 mdev core에 등록된 physical device link가 있습니다. 각 parent 아래 `mdev_supported_types/<type-id>/`에는 `create`, `name`, `available_instances`, `device_api`, 선택적 `description`, 생성 device link directory가 놓입니다.
`<type-id>`, `device_api`, `available_instances`는 vendor driver가 제공해야 하는 mandatory attribute입니다. Type directory 이름은 `dev_driver_string(parent->dev)`를 vendor group name 앞에 붙여 `driver-group` 형식으로 만듭니다.
`device_api`는 예를 들어 PCI용 `vfio-pci`처럼 생성될 device API를, `available_instances`는 추가 생성 가능한 개수를, `devices`는 이미 생성된 instance link를 보여 줍니다. `name`은 사람이 읽을 이름이고 `description`은 선택적 기능 설명입니다.
Parent에서 지원 type과 생성 가능한 instance, 생성 device link를 탐색합니다.
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.
mdev instance 제거와 runtime hot plug
221-248생성된 mdev는 parent 아래 `$MDEV_UUID` directory로 나타나며 write-only `remove`, type directory를 가리키는 `mdev_type` link, 선택적 vendor-specific attribute를 가집니다.
`remove`에 `1`을 쓰면 mdev를 destroy합니다. Device가 active이고 vendor driver가 hot unplug를 지원하지 않으면 `remove()` callback이 실패할 수 있습니다.
예제 명령은 `echo 1 > /sys/bus/mdev/devices/$mdev_UUID/remove`입니다. Mdev는 runtime에 생성·할당할 수 있고 hot-plug 절차는 PCI device hot plug와 같습니다.
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.
VFIO page translation API와 IOMMU backend
249-273VFIO driver는 `vfio_pin_pages()`와 `vfio_unpin_pages()`로 user PFN에 해당하는 page를 host 측에서 pin·unpin합니다. API는 `vfio_device`, IOVA, page 수, protection과 반환 page array를 사용합니다.
이 함수들은 `struct vfio_iommu_driver_ops`의 `pin_pages`·`unpin_pages` callback을 통해 backend IOMMU module로 들어갑니다. 현재 TYPE1 IOMMU가 지원하며 PPC64 sPAPR 같은 다른 backend도 두 callback을 제공해야 합니다.
참고 정의는 `Documentation/driver-api/vfio.rst`, `include/linux/mdev.h`의 `mdev_driver`·`mdev_parent_ops`, `include/linux/vfio.h`의 `vfio_iommu_driver_ops`에 있습니다.
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
요약·해설
vfio-mediated-device.rst:1-273MDEV core는 physical driver가 제공하는 parent resource를 표준 type·UUID sysfs로 노출하고 mediated bus driver가 이를 vfio_device로 bind하게 합니다. Instance 수, hot-unplug 가능 여부와 IOMMU page pin 수명주기를 vendor driver가 정확히 구현해야 합니다.