From patchwork Sun Dec 13 13:10:02 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 67028 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nBDDvLmC013366 for ; Sun, 13 Dec 2009 13:57:21 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753427AbZLMN5V (ORCPT ); Sun, 13 Dec 2009 08:57:21 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753428AbZLMN5V (ORCPT ); Sun, 13 Dec 2009 08:57:21 -0500 Received: from smtp-noauth7.primus.ca ([216.254.180.38]:47924 "HELO mail-05.primus.ca" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with SMTP id S1753427AbZLMN5U (ORCPT ); Sun, 13 Dec 2009 08:57:20 -0500 Received: from dsl-173-206-141-177.tor.primus.ca ([173.206.141.177] helo=harry.int.wil.cx) by mail-05.primus.ca with esmtp (Exim 4.69) (envelope-from ) id 1NJoKz-0005xv-28; Sun, 13 Dec 2009 08:18:13 -0500 Received: by harry.int.wil.cx (Postfix, from userid 1000) id 425D156AB1; Sun, 13 Dec 2009 08:10:11 -0500 (EST) From: Matthew Wilcox To: linux-pci@vger.kernel.org, jbarnes@virtuousgeek.org Cc: Matthew Wilcox , Matthew Wilcox Subject: [PATCH] Rewrite pci_scan_slot Date: Sun, 13 Dec 2009 08:10:02 -0500 Message-Id: <1260709802-9418-1-git-send-email-matthew@wil.cx> X-Mailer: git-send-email 1.6.5 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 98ffb2d..663d400 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1081,6 +1081,37 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) } EXPORT_SYMBOL(pci_scan_single_device); +static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn) +{ + u16 cap; + unsigned pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); + if (!pos) + return 0; + pci_read_config_word(dev, pos + 4, &cap); + return cap >> 8; +} + +static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn) +{ + return (fn + 1) % 8; +} + +static unsigned no_next_fn(struct pci_dev *dev, unsigned fn) +{ + return 0; +} + +static int only_one_child(struct pci_bus *bus) +{ + struct pci_dev *parent = bus->self; + if (!parent || !pci_is_pcie(parent)) + return 0; + if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT || + parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) + return 1; + return 0; +} + /** * pci_scan_slot - scan a PCI slot on a bus for devices. * @bus: PCI bus to scan @@ -1094,21 +1125,28 @@ EXPORT_SYMBOL(pci_scan_single_device); */ int pci_scan_slot(struct pci_bus *bus, int devfn) { - int fn, nr = 0; + unsigned fn, nr = 0; struct pci_dev *dev; + unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn; + + if (only_one_child(bus) && (devfn > 0)) + return 0; /* Already scanned the entire slot */ dev = pci_scan_single_device(bus, devfn); if (dev && !dev->is_added) /* new device? */ nr++; - if (dev && dev->multifunction) { - for (fn = 1; fn < 8; fn++) { - dev = pci_scan_single_device(bus, devfn + fn); - if (dev) { - if (!dev->is_added) - nr++; - dev->multifunction = 1; - } + if (pci_ari_enabled(bus)) + next_fn = next_ari_fn; + else if (dev && dev->multifunction) + next_fn = next_trad_fn; + + for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) { + dev = pci_scan_single_device(bus, devfn + fn); + if (dev) { + if (!dev->is_added) + nr++; + dev->multifunction = 1; } }