aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/Kconfig10
-rw-r--r--drivers/pci/pci-uclass.c114
-rw-r--r--include/pci.h38
3 files changed, 162 insertions, 0 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 1c47a21..4635752 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -53,6 +53,16 @@ config PCI_REGION_MULTI_ENTRY
region type. This helps to add support for SoC's like OcteonTX/TX2
where every peripheral is on the PCI bus.
+config PCI_SRIOV
+ bool "Enable Single Root I/O Virtualization support for PCI"
+ depends on PCI || DM_PCI
+ default n
+ help
+ Say Y here if you want to enable PCI Single Root I/O Virtualization
+ capability support. This helps to enumerate Virtual Function devices
+ if available on a PCI Physical Function device and probe for
+ applicable drivers.
+
config PCIE_ECAM_GENERIC
bool "Generic ECAM-based PCI host controller support"
default n
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index fa6115a..51871bf 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -1586,6 +1586,120 @@ int dm_pci_flr(struct udevice *dev)
return 0;
}
+#if defined(CONFIG_PCI_SRIOV)
+int pci_sriov_init(struct udevice *pdev, int vf_en)
+{
+ u16 vendor, device;
+ struct udevice *bus;
+ struct udevice *dev;
+ pci_dev_t bdf;
+ u16 ctrl;
+ u16 num_vfs;
+ u16 total_vf;
+ u16 vf_offset;
+ u16 vf_stride;
+ int vf, ret;
+ int pos;
+
+ pos = dm_pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (!pos) {
+ debug("Error: SRIOV capability not found\n");
+ return -ENOENT;
+ }
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_CTRL, &ctrl);
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_TOTAL_VF, &total_vf);
+ if (vf_en > total_vf)
+ vf_en = total_vf;
+ dm_pci_write_config16(pdev, pos + PCI_SRIOV_NUM_VF, vf_en);
+
+ ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+ dm_pci_write_config16(pdev, pos + PCI_SRIOV_CTRL, ctrl);
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_NUM_VF, &num_vfs);
+ if (num_vfs > vf_en)
+ num_vfs = vf_en;
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_OFFSET, &vf_offset);
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_STRIDE, &vf_stride);
+
+ dm_pci_read_config16(pdev, PCI_VENDOR_ID, &vendor);
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_DID, &device);
+
+ bdf = dm_pci_get_bdf(pdev);
+
+ pci_get_bus(PCI_BUS(bdf), &bus);
+
+ if (!bus)
+ return -ENODEV;
+
+ bdf += PCI_BDF(0, 0, vf_offset);
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ struct pci_child_platdata *pplat;
+ ulong class;
+
+ pci_bus_read_config(bus, bdf, PCI_CLASS_DEVICE,
+ &class, PCI_SIZE_16);
+
+ debug("%s: bus %d/%s: found VF %x:%x\n", __func__,
+ bus->seq, bus->name, PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ /* Find this device in the device tree */
+ ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
+
+ if (ret == -ENODEV) {
+ struct pci_device_id find_id;
+
+ memset(&find_id, '\0', sizeof(find_id));
+ find_id.vendor = vendor;
+ find_id.device = device;
+ find_id.class = class;
+
+ ret = pci_find_and_bind_driver(bus, &find_id,
+ bdf, &dev);
+
+ if (ret)
+ return ret;
+ }
+
+ /* Update the platform data */
+ pplat = dev_get_parent_platdata(dev);
+ pplat->devfn = PCI_MASK_BUS(bdf);
+ pplat->vendor = vendor;
+ pplat->device = device;
+ pplat->class = class;
+ pplat->is_virtfn = true;
+ pplat->pfdev = pdev;
+ pplat->virtid = vf * vf_stride + vf_offset;
+
+ debug("%s: bus %d/%s: found VF %x:%x %x:%x class %lx id %x\n",
+ __func__, dev->seq, dev->name, PCI_DEV(bdf),
+ PCI_FUNC(bdf), vendor, device, class, pplat->virtid);
+ bdf += PCI_BDF(0, 0, vf_stride);
+ }
+
+ return 0;
+}
+
+int pci_sriov_get_totalvfs(struct udevice *pdev)
+{
+ u16 total_vf;
+ int pos;
+
+ pos = dm_pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (!pos) {
+ debug("Error: SRIOV capability not found\n");
+ return -ENOENT;
+ }
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_TOTAL_VF, &total_vf);
+
+ return total_vf;
+}
+#endif /* SRIOV */
+
UCLASS_DRIVER(pci) = {
.id = UCLASS_PCI,
.name = "pci",
diff --git a/include/pci.h b/include/pci.h
index da755af..115d331 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -493,6 +493,17 @@
#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */
#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */
#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */
+/* Single Root I/O Virtualization Registers */
+#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
+#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */
+#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */
+#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */
+#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */
+#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */
+#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */
+#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */
+#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */
+#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */
/* Include the ID list */
@@ -890,12 +901,20 @@ struct udevice;
* @vendor: PCI vendor ID (see pci_ids.h)
* @device: PCI device ID (see pci_ids.h)
* @class: PCI class, 3 bytes: (base, sub, prog-if)
+ * @is_virtfn: True for Virtual Function device
+ * @pfdev: Handle to Physical Function device
+ * @virtid: Virtual Function Index
*/
struct pci_child_platdata {
int devfn;
unsigned short vendor;
unsigned short device;
unsigned int class;
+
+ /* Variables for CONFIG_PCI_SRIOV */
+ bool is_virtfn;
+ struct udevice *pfdev;
+ int virtid;
};
/* PCI bus operations */
@@ -1208,6 +1227,25 @@ int pci_generic_mmap_read_config(
ulong *valuep,
enum pci_size_t size);
+#if defined(CONFIG_PCI_SRIOV)
+/**
+ * pci_sriov_init() - Scan Virtual Function devices
+ *
+ * @pdev: Physical Function udevice handle
+ * @vf_en: Number of Virtual Function devices to enable
+ * @return 0 on success, -ve on error
+ */
+int pci_sriov_init(struct udevice *pdev, int vf_en);
+
+/**
+ * pci_sriov_get_totalvfs() - Get total available Virtual Function devices
+ *
+ * @pdev: Physical Function udevice handle
+ * @return count on success, -ve on error
+ */
+int pci_sriov_get_totalvfs(struct udevice *pdev);
+#endif
+
#ifdef CONFIG_DM_PCI_COMPAT
/* Compatibility with old naming */
static inline int pci_write_config_dword(pci_dev_t pcidev, int offset,