Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Clean up pci_scan_slot()

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, which duplicates the code from the scan loop.

Furthermore the non-ARI branch of next_fn() is generally hard to understand
and especially the check for multifunction devices is hidden in the
handling of NULL devices for non-contiguous multifunction. It also signals
that no further functions need to be scanned by returning 0 via wraparound
and this is a valid function number.

Improve upon this by transforming the conditions in next_fn() to be easier
to understand.

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. This also makes it more explicit that only
function 0 must exist.

No functional change is intended.

Link: https://lore.kernel.org/r/20220628143100.3228092-2-schnelle@linux.ibm.com
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Jan Kiszka <jan.kiszka@siemens.com>

authored by

Niklas Schnelle and committed by
Bjorn Helgaas
c3df83e0 f2906aa8

+19 -19
+19 -19
drivers/pci/probe.c
··· 2579 2579 } 2580 2580 EXPORT_SYMBOL(pci_scan_single_device); 2581 2581 2582 - static unsigned int next_fn(struct pci_bus *bus, struct pci_dev *dev, 2583 - unsigned int fn) 2582 + static int next_fn(struct pci_bus *bus, struct pci_dev *dev, int fn) 2584 2583 { 2585 2584 int pos; 2586 2585 u16 cap = 0; ··· 2587 2588 2588 2589 if (pci_ari_enabled(bus)) { 2589 2590 if (!dev) 2590 - return 0; 2591 + return -ENODEV; 2591 2592 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); 2592 2593 if (!pos) 2593 - return 0; 2594 + return -ENODEV; 2594 2595 2595 2596 pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap); 2596 2597 next_fn = PCI_ARI_CAP_NFN(cap); 2597 2598 if (next_fn <= fn) 2598 - return 0; /* protect against malformed list */ 2599 + return -ENODEV; /* protect against malformed list */ 2599 2600 2600 2601 return next_fn; 2601 2602 } 2602 2603 2603 - /* dev may be NULL for non-contiguous multifunction devices */ 2604 - if (!dev || dev->multifunction) 2605 - return (fn + 1) % 8; 2604 + if (fn >= 7) 2605 + return -ENODEV; 2606 + /* only multifunction devices may have more functions */ 2607 + if (dev && !dev->multifunction) 2608 + return -ENODEV; 2606 2609 2607 - return 0; 2610 + return fn + 1; 2608 2611 } 2609 2612 2610 2613 static int only_one_child(struct pci_bus *bus) ··· 2644 2643 */ 2645 2644 int pci_scan_slot(struct pci_bus *bus, int devfn) 2646 2645 { 2647 - unsigned int fn, nr = 0; 2648 2646 struct pci_dev *dev; 2647 + int fn = 0, nr = 0; 2649 2648 2650 2649 if (only_one_child(bus) && (devfn > 0)) 2651 2650 return 0; /* Already scanned the entire slot */ 2652 2651 2653 - dev = pci_scan_single_device(bus, devfn); 2654 - if (!dev) 2655 - return 0; 2656 - if (!pci_dev_is_added(dev)) 2657 - nr++; 2658 - 2659 - for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) { 2652 + do { 2660 2653 dev = pci_scan_single_device(bus, devfn + fn); 2661 2654 if (dev) { 2662 2655 if (!pci_dev_is_added(dev)) 2663 2656 nr++; 2664 - dev->multifunction = 1; 2657 + if (fn > 0) 2658 + dev->multifunction = 1; 2659 + } else if (fn == 0) { 2660 + /* function 0 is required */ 2661 + break; 2665 2662 } 2666 - } 2663 + fn = next_fn(bus, dev, fn); 2664 + } while (fn >= 0); 2667 2665 2668 2666 /* Only one slot has PCIe device */ 2669 2667 if (bus->self && nr)