1.什么是SR-IOV

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

2.用户指南

2.1 如何使能SR-IOV capability

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

2.2.如何使用Virtual Functions

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

3.开发指南

3.1 SR-IOV API

要启用 SR-IOV 功能:

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

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

“nr_virtfn”是要启用的 VF 数量。

b. 对于第二种方法,来自 sysfs:

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

要禁用 SR-IOV 功能:

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

  1. void pci_disable_sriov(struct pci_dev *dev);

b. 对于第二种方法,来自 sysfs:

echo 0 > \ /sys/bus/pci/devices//sriov_numvfs

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

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

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

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

3.2 使用示例

以下代码说明了 SR-IOV API 的用法。

  1. static int dev_probe(struct pci_dev *dev, const struct pci_device_id *id)
  2. {
  3. pci_enable_sriov(dev, NR_VIRTFN);
  4. ...
  5. return 0;
  6. }
  7. static void dev_remove(struct pci_dev *dev)
  8. {
  9. pci_disable_sriov(dev);
  10. ...
  11. }
  12. static int dev_suspend(struct device *dev)
  13. {
  14. ...
  15. return 0;
  16. }
  17. static int dev_resume(struct device *dev)
  18. {
  19. ...
  20. return 0;
  21. }
  22. static void dev_shutdown(struct pci_dev *dev)
  23. {
  24. ...
  25. }
  26. static int dev_sriov_configure(struct pci_dev *dev, int numvfs)
  27. {
  28. if (numvfs > 0) {
  29. ...
  30. pci_enable_sriov(dev, numvfs);
  31. ...
  32. return numvfs;
  33. }
  34. if (numvfs == 0) {
  35. ....
  36. pci_disable_sriov(dev);
  37. ...
  38. return 0;
  39. }
  40. }
  41. static struct pci_driver dev_driver = {
  42. .name = "SR-IOV Physical Function driver",
  43. .id_table = dev_id_table,
  44. .probe = dev_probe,
  45. .remove = dev_remove,
  46. .driver.pm = &dev_pm_ops,
  47. .shutdown = dev_shutdown,
  48. .sriov_configure = dev_sriov_configure,
  49. };

翻译自:3. PCI Express I/O Virtualization Howto