3. PCI Express I/O 虚拟化操作指南

版权:

© 2009 Intel Corporation

作者:

3.1. 概述

3.1.1. 什么是 SR-IOV

单根 I/O 虚拟化 (SR-IOV) 是一种 PCI Express 扩展功能,它使一个物理设备表现为多个虚拟设备。物理设备被称为物理功能 (PF),而虚拟设备被称为虚拟功能 (VF)。VF 的分配可以通过封装在功能中的寄存器由 PF 动态控制。默认情况下,此功能未启用,PF 表现为传统的 PCIe 设备。一旦开启,每个 VF 的 PCI 配置空间可以通过其自身的总线、设备和功能编号(路由 ID)进行访问。每个 VF 也有 PCI 内存空间,用于映射其寄存器集。VF 设备驱动程序在此寄存器集上操作,因此它可以正常工作并表现为一个真实存在的 PCI 设备。

3.2. 用户指南

3.2.1. 如何启用 SR-IOV 功能

有多种方法可用于启用 SR-IOV。第一种方法中,设备驱动程序(PF 驱动程序)将通过 SR-IOV 核心提供的 API 来控制功能的启用和禁用。如果硬件具有 SR-IOV 功能,加载其 PF 驱动程序将启用该功能以及与该 PF 相关联的所有 VF。某些 PF 驱动程序需要设置一个模块参数来确定要启用的 VF 数量。第二种方法中,写入 sysfs 文件 sriov_numvfs 将启用和禁用与 PCIe PF 相关联的 VF。此方法实现了每个 PF 的 VF 启用/禁用值,而第一种方法适用于同一设备的所有 PF。此外,PCI SRIOV 核心支持确保启用/禁用操作有效,以减少多个驱动程序中重复的相同检查,例如,检查 numvfs == 0(如果启用 VF),确保 numvfs <= totalvfs。第二种方法是推荐用于新/未来 VF 设备的方法。

3.2.2. 如何使用虚拟功能

VF 在内核中被视为热插拔的 PCI 设备,因此它们应该能够像真实的 PCI 设备一样工作。VF 需要与普通 PCI 设备相同的设备驱动程序。

3.3. 开发者指南

3.3.1. SR-IOV API

启用 SR-IOV 功能

  1. 对于第一种方法,在驱动程序中

    int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
    

‘nr_virtfn’ 是要启用的 VF 数量。

  1. 对于第二种方法,通过 sysfs

    echo 'nr_virtfn' > \
    /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
    

禁用 SR-IOV 功能

  1. 对于第一种方法,在驱动程序中

    void pci_disable_sriov(struct pci_dev *dev);
    
  2. 对于第二种方法,通过 sysfs

    echo  0 > \
    /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
    

要在主机上通过兼容驱动程序启用 VF 的自动探测,请在启用 SR-IOV 功能之前运行以下命令。这是默认行为。

echo 1 > \
/sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe

要在主机上通过兼容驱动程序禁用 VF 的自动探测,请在启用 SR-IOV 功能之前运行以下命令。更新此条目不会影响已探测的 VF。

echo  0 > \
/sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe

3.3.2. 使用示例

以下代码片段演示了 SR-IOV API 的用法。

static int dev_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
        pci_enable_sriov(dev, NR_VIRTFN);

        ...

        return 0;
}

static void dev_remove(struct pci_dev *dev)
{
        pci_disable_sriov(dev);

        ...
}

static int dev_suspend(struct device *dev)
{
        ...

        return 0;
}

static int dev_resume(struct device *dev)
{
        ...

        return 0;
}

static void dev_shutdown(struct pci_dev *dev)
{
        ...
}

static int dev_sriov_configure(struct pci_dev *dev, int numvfs)
{
        if (numvfs > 0) {
                ...
                pci_enable_sriov(dev, numvfs);
                ...
                return numvfs;
        }
        if (numvfs == 0) {
                ....
                pci_disable_sriov(dev);
                ...
                return 0;
        }
}

static struct pci_driver dev_driver = {
        .name =         "SR-IOV Physical Function driver",
        .id_table =     dev_id_table,
        .probe =        dev_probe,
        .remove =       dev_remove,
        .driver.pm =    &dev_pm_ops,
        .shutdown =     dev_shutdown,
        .sriov_configure = dev_sriov_configure,
};