
Hi Suneel,
On Tue, 29 Oct 2019 at 14:08, Suneel Garapati suneelglinux@gmail.com wrote:
From: Suneel Garapati sgarapati@marvell.com
If SR-IOV capability is present, use it to initialize Virtual function (VF) 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.
Please expand your abbreviations .
This seems like a nice implementation overall, but it needs a sandbox test and some documentation.
Signed-off-by: Suneel Garapati sgarapati@marvell.com
drivers/pci/pci-uclass.c | 113 +++++++++++++++++++++++++++++++++++++++ include/pci.h | 18 +++++++ 2 files changed, 131 insertions(+)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 51f7135723..3be49c7115 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -1535,6 +1535,119 @@ int dm_pci_flr(struct udevice *dev) return 0; }
is this supported to be exported? It needs a comment.
+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) {
printf("Error: SRIOV capability not found\n");
debug()
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++) {
This function is way too long - can you please split?
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));
'\0'
find_id.vendor = vendor;
find_id.device = device;
find_id.class = class;
ret = pci_find_and_bind_driver(bus, &find_id,
bdf, &dev);
Can you share any code with pci_bind_bus_devices(), perhaps but pulling part of it into a function?
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) {
printf("Error: SRIOV capability not found\n");
debug()
return -ENOENT;
}
dm_pci_read_config16(pdev, pos + PCI_SRIOV_TOTAL_VF, &total_vf);
return total_vf;
+}
UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", diff --git a/include/pci.h b/include/pci.h index 0b14842285..1343d0e9fb 100644 --- a/include/pci.h +++ b/include/pci.h @@ -475,6 +475,17 @@ #define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ #define PCI_EXP_DEVCTL 8 /* Device Control */ #define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ +/* 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 */
@@ -868,6 +879,10 @@ struct pci_child_platdata { unsigned short vendor; unsigned short device; unsigned int class;
bool is_virtfn;
struct udevice *pfdev;
int virtid;
Add comments. You can see them above!
};
/* PCI bus operations */ @@ -1178,6 +1193,9 @@ int pci_generic_mmap_read_config( ulong *valuep, enum pci_size_t size);
+int pci_sriov_init(struct udevice *pdev, int vf_en); +int pci_sriov_get_totalvfs(struct udevice *pdev);
Comments!
#ifdef CONFIG_DM_PCI_COMPAT /* Compatibility with old naming */ static inline int pci_write_config_dword(pci_dev_t pcidev, int offset, -- 2.23.0
Regards, Simon