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,
};