pci: pci-uclass: Add support for Single-Root I/O Virtualization

SR-IOV - Single Root I/O Virtualization
PF - Physical Function VF - Virtual Function

If SR-IOV capability is present, use it to initialize Virtual Function
PCI device instances. pci_sriov_init function will read SR-IOV
registers to create VF devices under the PF PCI device and also bind
driver if available. This function needs to be invoked from Physical
function device driver which expects VF device support, creating
minimal impact on existing framework.

Signed-off-by: Suneel Garapati <sgarapati@marvell.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
Suneel Garapati
2019-10-19 16:07:20 -07:00
committed by Stefan Roese
parent 636cc1773a
commit b8852dcfcb
3 changed files with 162 additions and 0 deletions

View File

@@ -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

View File

@@ -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",