Message ID | 20220412143040.1882096-2-schnelle@linux.ibm.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | PCI: Rework pci_scan_slot() and isolated PCI functions | expand |
On Tue, 2022-04-12 at 16:30 +0200, Niklas Schnelle wrote: > While determining the next PCI function is factored out of > pci_scan_slot() into next_fn() the former still handles the first > function as a special case duplicating the code from the scan loop and > splitting the condition that the first function exits from it being > multifunction which is tested in next_fn(). > > Furthermore the non ARI branch of next_fn() mixes the case that > multifunction devices may have non-contiguous function ranges and dev > may thus be NULL with the multifunction requirement. It also signals > that no further functions need to be scanned by returning 0 which is > a valid function number. > > Improve upon this by moving all conditions for having to scan for more > functions into next_fn() and make them obvious and commented. > > By changing next_fn() to return -ENODEV instead of 0 when there is no > next function we can then handle the initial function inside the loop > and deduplicate the shared handling. > > No functional change is intended. > > Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com> > --- > drivers/pci/probe.c | 41 +++++++++++++++++++---------------------- > 1 file changed, 19 insertions(+), 22 deletions(-) > > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index 17a969942d37..389aa1f9cb2c 100644 > --- a/drivers/pci/probe.c > +++ b/drivers/pci/probe.c > @@ -2579,33 +2579,35 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) > } > EXPORT_SYMBOL(pci_scan_single_device); > > -static unsigned int next_fn(struct pci_bus *bus, struct pci_dev *dev, > - unsigned int fn) > +static int next_fn(struct pci_bus *bus, struct pci_dev *dev, int fn) > { > int pos; > u16 cap = 0; > unsigned int next_fn; > > - if (pci_ari_enabled(bus)) { > - if (!dev) > - return 0; This part here theoretically changes the behavior slightly. If the ARI information is wrong/lands us in a "hole" we may look for more functions via the non-ARI path. Not sure if that is relevant though as in the worst case we might find functions that we otherwise wouldn't have seen. Seems rather obsure to me but I might be wrong, we currently don't see the ARI capability in Linux on IBM Z so I have less experience with this. I did of course boot test on my x86_64 workstation. > + if (dev && pci_ari_enabled(bus)) { > pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); > if (!pos) > - return 0; > + return -ENODEV; > > pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap); > next_fn = PCI_ARI_CAP_NFN(cap); > if (next_fn <= fn) > - return 0; /* protect against malformed list */ > + return -ENODEV; /* protect against malformed list */ > > return next_fn; > } > > - /* dev may be NULL for non-contiguous multifunction devices */ > - if (!dev || dev->multifunction) > - return (fn + 1) % 8; > - > - return 0; > + /* only multifunction devices may have more functions */ > + if (dev && !dev->multifunction) > + return -ENODEV; > + /* > + * A function 0 is required but multifunction devices may > + * be non-contiguous so dev can be NULL otherwise. > + */ > + if (!fn && !dev) > + return -ENODEV; > + return (fn <= 6) ? fn + 1 : -ENODEV; > } > > ---8<---
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 17a969942d37..389aa1f9cb2c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2579,33 +2579,35 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) } EXPORT_SYMBOL(pci_scan_single_device); -static unsigned int next_fn(struct pci_bus *bus, struct pci_dev *dev, - unsigned int fn) +static int next_fn(struct pci_bus *bus, struct pci_dev *dev, int fn) { int pos; u16 cap = 0; unsigned int next_fn; - if (pci_ari_enabled(bus)) { - if (!dev) - return 0; + if (dev && pci_ari_enabled(bus)) { pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); if (!pos) - return 0; + return -ENODEV; pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap); next_fn = PCI_ARI_CAP_NFN(cap); if (next_fn <= fn) - return 0; /* protect against malformed list */ + return -ENODEV; /* protect against malformed list */ return next_fn; } - /* dev may be NULL for non-contiguous multifunction devices */ - if (!dev || dev->multifunction) - return (fn + 1) % 8; - - return 0; + /* only multifunction devices may have more functions */ + if (dev && !dev->multifunction) + return -ENODEV; + /* + * A function 0 is required but multifunction devices may + * be non-contiguous so dev can be NULL otherwise. + */ + if (!fn && !dev) + return -ENODEV; + return (fn <= 6) ? fn + 1 : -ENODEV; } static int only_one_child(struct pci_bus *bus) @@ -2643,24 +2645,19 @@ static int only_one_child(struct pci_bus *bus) */ int pci_scan_slot(struct pci_bus *bus, int devfn) { - unsigned int fn, nr = 0; - struct pci_dev *dev; + int fn, nr = 0; + struct pci_dev *dev = NULL; if (only_one_child(bus) && (devfn > 0)) return 0; /* Already scanned the entire slot */ - dev = pci_scan_single_device(bus, devfn); - if (!dev) - return 0; - if (!pci_dev_is_added(dev)) - nr++; - - for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) { + for (fn = 0; fn >= 0; fn = next_fn(bus, dev, fn)) { dev = pci_scan_single_device(bus, devfn + fn); if (dev) { if (!pci_dev_is_added(dev)) nr++; - dev->multifunction = 1; + if (nr > 1) + dev->multifunction = 1; } }
While determining the next PCI function is factored out of pci_scan_slot() into next_fn() the former still handles the first function as a special case duplicating the code from the scan loop and splitting the condition that the first function exits from it being multifunction which is tested in next_fn(). Furthermore the non ARI branch of next_fn() mixes the case that multifunction devices may have non-contiguous function ranges and dev may thus be NULL with the multifunction requirement. It also signals that no further functions need to be scanned by returning 0 which is a valid function number. Improve upon this by moving all conditions for having to scan for more functions into next_fn() and make them obvious and commented. By changing next_fn() to return -ENODEV instead of 0 when there is no next function we can then handle the initial function inside the loop and deduplicate the shared handling. No functional change is intended. Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com> --- drivers/pci/probe.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-)