On Tue, 27 May 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 | 73 +++++++++++++++++++++++++++++++++++++++++++++ > include/linux/pci.h | 6 ++++ > 2 files changed, 79 insertions(+) > > diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c > index f34173c70b32a..ac4375954c947 100644 > --- a/drivers/pci/iov.c > +++ b/drivers/pci/iov.c > @@ -8,11 +8,15 @@ > */ > > #include <linux/bitfield.h> > +#include <linux/bits.h> > +#include <linux/log2.h> > #include <linux/pci.h> > +#include <linux/sizes.h> > #include <linux/slab.h> > #include <linux/export.h> > #include <linux/string.h> > #include <linux/delay.h> > +#include <asm/div64.h> > #include "pci.h" > > #define VIRTFN_ID_LEN 17 /* "virtfn%u\0" for 2^32 - 1 */ > @@ -1313,3 +1317,72 @@ 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. > + * > + * Return: 0 on success, or negative on failure. > + */ > +int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size) > +{ > + u32 sizes; > + int ret; > + > + 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 accommodate @num_vfs within > + * the currently assigned size of the resource @resno. > + * > + * Return: A bitmask of sizes in format 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) > +{ > + u64 vf_len = pci_resource_len(dev, resno); > + u32 sizes; > + > + if (!num_vfs) > + return 0; > + > + do_div(vf_len, num_vfs); > + sizes = (roundup_pow_of_two(vf_len + 1) - 1) >> ilog2(SZ_1M); > + > + return sizes & pci_rebar_get_possible_sizes(dev, resno); > +} > +EXPORT_SYMBOL_GPL(pci_iov_vf_bar_get_sizes); > diff --git a/include/linux/pci.h b/include/linux/pci.h > index ab62bcb5f99c6..cc633b1a13d51 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -2437,6 +2437,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) */ > @@ -2489,6 +2491,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 > >
Reviewed-by: Ilpo Järvinen <ilpo.jarvi...@linux.intel.com> -- i.