On Thu, 20 Mar 2025, Michał Winiarski wrote: > Drivers could leverage the fact that the VF BAR MMIO reservation is > created for total number of VFs supported by the device by resizing the > BAR to larger size when smaller number of VFs is enabled. > > Add a pci_iov_vf_bar_set_size() function to control the size and a > pci_iov_vf_bar_get_sizes() helper to get the VF BAR sizes that will > allow up to num_vfs to be successfully enabled with the current > underlying reservation size. > > Signed-off-by: Michał Winiarski <michal.winiar...@intel.com> > --- > drivers/pci/iov.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ > include/linux/pci.h | 6 ++++ > 2 files changed, 84 insertions(+) > > diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c > index 861273ad9a580..751eef232685c 100644 > --- a/drivers/pci/iov.c > +++ b/drivers/pci/iov.c > @@ -1291,3 +1291,81 @@ int pci_sriov_configure_simple(struct pci_dev *dev, > int nr_virtfn) > return nr_virtfn; > } > EXPORT_SYMBOL_GPL(pci_sriov_configure_simple); > + > +/** > + * pci_iov_vf_bar_set_size - set a new size for a VF BAR > + * @dev: the PCI device > + * @resno: the resource number > + * @size: new size as defined in the spec (0=1MB, 31=128TB) > + * > + * Set the new size of a VF BAR that supports VF resizable BAR capability. > + * Unlike pci_resize_resource(), this does not cause the resource that > + * reserves the MMIO space (originally up to total_VFs) to be resized, which > + * means that following calls to pci_enable_sriov() can fail if the resources > + * no longer fit. > + * > + * Returns 0 on success, or negative on failure.
Return: is the correct kernel doc style. > + */ > +int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size) > +{ > + int ret; > + u32 sizes; > + > + if (!pci_resource_is_iov(resno)) > + return -EINVAL; > + > + if (pci_iov_is_memory_decoding_enabled(dev)) > + return -EBUSY; > + > + sizes = pci_rebar_get_possible_sizes(dev, resno); > + if (!sizes) > + return -ENOTSUPP; > + > + if (!(sizes & BIT(size))) > + return -EINVAL; > + > + ret = pci_rebar_set_size(dev, resno, size); > + if (ret) > + return ret; > + > + pci_iov_resource_set_size(dev, resno, pci_rebar_size_to_bytes(size)); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(pci_iov_vf_bar_set_size); > + > +/** > + * pci_iov_vf_bar_get_sizes - get VF BAR sizes allowing to create up to > num_vfs > + * @dev: the PCI device > + * @resno: the resource number > + * @num_vfs: number of VFs > + * > + * Get the sizes of a VF resizable BAR that can be accommodated within the > + * resource that reserves the MMIO space if num_vfs are enabled. I'd rephrase to: Get the sizes of a VF resizable BAR that can be accommodate @num_vfs within the currently assigned size of the resource @resno. > + * > + * Returns 0 if BAR isn't resizable, otherwise returns a bitmask in format Return: a bitmask of sizes > + * defined in the spec (bit 0=1MB, bit 31=128TB). > + */ > +u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs) > +{ > + resource_size_t size; > + u32 sizes; > + int i; > + > + sizes = pci_rebar_get_possible_sizes(dev, resno); > + if (!sizes) > + return 0; > + > + while (sizes > 0) { > + i = __fls(sizes); > + size = pci_rebar_size_to_bytes(i); > + > + if (size * num_vfs <= pci_resource_len(dev, resno)) > + break; > + > + sizes &= ~BIT(i); > + } Couldn't this be handled without a loop: bar_sizes = (round_up(pci_resource_len(dev, resno) / num_vfs) - 1) >> ilog2(SZ_1M); sizes &= bar_sizes; (Just to given an idea, I wrote this into the email so it might contain some off-by-one errors or like). > + > + return sizes; > +} > +EXPORT_SYMBOL_GPL(pci_iov_vf_bar_get_sizes); > diff --git a/include/linux/pci.h b/include/linux/pci.h > index 0e8e3fd77e967..c8708f3749757 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -2389,6 +2389,8 @@ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 > numvfs); > int pci_sriov_get_totalvfs(struct pci_dev *dev); > int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn); > resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno); > +int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size); > +u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs); > void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe); > > /* Arch may override these (weak) */ > @@ -2441,6 +2443,10 @@ static inline int pci_sriov_get_totalvfs(struct > pci_dev *dev) > #define pci_sriov_configure_simple NULL > static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int > resno) > { return 0; } > +static inline int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, > int size) > +{ return -ENODEV; } > +static inline u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, > int num_vfs) > +{ return 0; } > static inline void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe) > { } > #endif > > -- i.