On Wed, 2 Apr 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.winiarski@xxxxxxxxx> > --- > drivers/pci/iov.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ > include/linux/pci.h | 6 ++++ > 2 files changed, 75 insertions(+) > > diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c > index 2fafbd6a998f0..8a62049b56b41 100644 > --- a/drivers/pci/iov.c > +++ b/drivers/pci/iov.c > @@ -1313,3 +1313,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) > +{ > + int ret; > + u32 sizes; Please reverse the order of these variables. > + > + 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))) Add include for BIT(). Although adding a helper like this would be helpful for multiple callers: @@ -3780,6 +3780,88 @@ u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar) } EXPORT_SYMBOL(pci_rebar_get_possible_sizes); +/** + * pci_rebar_size_supported - check if size is supported for a resizable BAR + * @pdev: PCI device + * @bar: BAR to check + * @size: size as defined in the spec (0=1MB, 31=128TB) + * + * Return: %0 if @size is supported for @bar, + * %-EINVAL if @size is not supported, + * %-ENOTSUPP if @bar is not resizable. + */ +int pci_rebar_size_supported(struct pci_dev *pdev, int bar, int size) +{ + u64 sizes; + + sizes = pci_rebar_get_possible_sizes(pdev, bar); + if (!sizes) + return -ENOTSUPP; + + return BIT(size) & sizes ? 0 : -EINVAL; +} +EXPORT_SYMBOL_GPL(pci_rebar_size_supported); (Yes, I've some rebar helpers pending so this is extract from that.) > + 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) > +{ > + resource_size_t vf_len = pci_resource_len(dev, resno); > + u32 sizes; > + > + if (!num_vfs) > + return 0; > + > + do_div(vf_len, num_vfs); Add include for do_div(). > + sizes = (roundup_pow_of_two(vf_len + 1) - 1) >> ilog2(SZ_1M); Doesn't resource_size() already do that + 1 so why is a second one needed here? Add include for ilog() and SZ_*. > + > + 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 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.