Commit 4449f079 authored by Wei Yang's avatar Wei Yang Committed by Benjamin Herrenschmidt

PCI: Calculate maximum number of buses required for VFs

An SR-IOV device can change its First VF Offset and VF Stride based on the
values of ARI Capable Hierarchy and NumVFs.  The number of buses required
for all VFs is determined by NumVFs, First VF Offset, and VF Stride (see
SR-IOV spec r1.1, sec 2.1.2).

Previously pci_iov_bus_range() computed how many buses would be required by
TotalVFs, but this was based on a single NumVFs value and may not have been
the maximum for all NumVFs configurations.

Iterate over all valid NumVFs and calculate the maximum number of bus
numbers that could ever be required for VFs of this device.

[bhelgaas: changelog, compute busnr of NumVFs, not TotalVFs, remove
kerenl-doc comment marker]
Signed-off-by: default avatarWei Yang <weiyang@linux.vnet.ibm.com>
Acked-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent f59dca27
...@@ -46,6 +46,30 @@ static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn) ...@@ -46,6 +46,30 @@ static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn)
pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &iov->stride); pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &iov->stride);
} }
/*
* The PF consumes one bus number. NumVFs, First VF Offset, and VF Stride
* determine how many additional bus numbers will be consumed by VFs.
*
* Iterate over all valid NumVFs and calculate the maximum number of bus
* numbers that could ever be required.
*/
static inline u8 virtfn_max_buses(struct pci_dev *dev)
{
struct pci_sriov *iov = dev->sriov;
int nr_virtfn;
u8 max = 0;
u8 busnr;
for (nr_virtfn = 1; nr_virtfn <= iov->total_VFs; nr_virtfn++) {
pci_iov_set_numvfs(dev, nr_virtfn);
busnr = virtfn_bus(dev, nr_virtfn - 1);
if (busnr > max)
max = busnr;
}
return max;
}
static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
{ {
struct pci_bus *child; struct pci_bus *child;
...@@ -427,6 +451,7 @@ static int sriov_init(struct pci_dev *dev, int pos) ...@@ -427,6 +451,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
dev->sriov = iov; dev->sriov = iov;
dev->is_physfn = 1; dev->is_physfn = 1;
iov->max_VF_buses = virtfn_max_buses(dev);
return 0; return 0;
...@@ -556,15 +581,13 @@ void pci_restore_iov_state(struct pci_dev *dev) ...@@ -556,15 +581,13 @@ void pci_restore_iov_state(struct pci_dev *dev)
int pci_iov_bus_range(struct pci_bus *bus) int pci_iov_bus_range(struct pci_bus *bus)
{ {
int max = 0; int max = 0;
u8 busnr;
struct pci_dev *dev; struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
if (!dev->is_physfn) if (!dev->is_physfn)
continue; continue;
busnr = virtfn_bus(dev, dev->sriov->total_VFs - 1); if (dev->sriov->max_VF_buses > max)
if (busnr > max) max = dev->sriov->max_VF_buses;
max = busnr;
} }
return max ? max - bus->number : 0; return max ? max - bus->number : 0;
......
...@@ -243,6 +243,7 @@ struct pci_sriov { ...@@ -243,6 +243,7 @@ struct pci_sriov {
u16 stride; /* following VF stride */ u16 stride; /* following VF stride */
u32 pgsz; /* page size for BAR alignment */ u32 pgsz; /* page size for BAR alignment */
u8 link; /* Function Dependency Link */ u8 link; /* Function Dependency Link */
u8 max_VF_buses; /* max buses consumed by VFs */
u16 driver_max_VFs; /* max num VFs driver supports */ u16 driver_max_VFs; /* max num VFs driver supports */
struct pci_dev *dev; /* lowest numbered PF */ struct pci_dev *dev; /* lowest numbered PF */
struct pci_dev *self; /* this PF */ struct pci_dev *self; /* this PF */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment