Message ID | 20191029210821.1954-9-suneelglinux@gmail.com |
---|---|
State | RFC |
Delegated to: | Tom Rini |
Headers | show |
Series | arm: Introduce Marvell/Cavium OcteonTX | expand |
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
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; } +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"); + 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) { + printf("Error: SRIOV capability not found\n"); + 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; }; /* 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); + #ifdef CONFIG_DM_PCI_COMPAT /* Compatibility with old naming */ static inline int pci_write_config_dword(pci_dev_t pcidev, int offset,