On Thu, Apr 03, 2025 at 01:20:58PM +0300, Ilpo Järvinen wrote:
> 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.winiar...@intel.com>
> > ---
> >  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;

Hi,
I thought this series was already ready to be merged, but now I just
went back through the review comments for v7 and realized that I missed
this email and never applied the changes you requested.
Sorry for the delay.

> Please reverse the order of these variables.

Ok.

> 
> > +
> > +   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.)

Added include for BIT(). I'll wait for your series with helpers :)

> 
> > +           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().

Ok.

> 
> > +   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?

It's not about resource_size() doing + 1 for the resource length, it's
needed because roundup_pow_of_two() is not rounding up to the next power
of two if the input is already a power of two. So we need to add 1 to
ensure that we get the next size up to make the math with bitmap
representing BAR sizes work correctly.

> 
> Add include for ilog() and SZ_*.

Ok.

Thanks,
-Michał

> 
> > +
> > +   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.

Reply via email to