linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alex Williamson <alex.williamson@redhat.com>
To: linux-pci@vger.kernel.org, iommu@lists.linux-foundation.org
Cc: bhelgaas@google.com, acooks@gmail.com,
	linux-kernel@vger.kernel.org, eddy0596@gmail.com,
	linux@horizon.com
Subject: [PATCH v4 01/16] PCI: Add DMA alias iterator
Date: Thu, 22 May 2014 17:07:30 -0600	[thread overview]
Message-ID: <20140522230730.2856.39308.stgit@bling.home> (raw)
In-Reply-To: <20140522230230.2856.40017.stgit@bling.home>

In a mixed PCI/PCI-X/PCI-e topology, bridges can take ownership of
transactions, replacing the original requester ID with their own.
Sometimes we just want to know the resulting device or resulting
alias, sometimes we want each step in the chain.  This iterator
allows either usage.  When an endpoint is connected via an unbroken
chain of PCIe switches and root ports, it has no alias and its
requester ID is visible to the root bus.  When PCI/X get in the way,
we pick up aliases for bridges.

The reason why we potentially care about each step in the path is
because of PCI-X.  PCI-X has the concept of a requester ID, but
bridges may or may not take ownership of various types of
transactions.  We therefore leave it to the consumer of this function
to prune out what they don't care about rather than attempt to flatten
the alias ourselves.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---
 drivers/pci/search.c |   70 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci.h  |    4 +++
 2 files changed, 74 insertions(+)

diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 4a1b972..5601cdb 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -18,6 +18,76 @@ DECLARE_RWSEM(pci_bus_sem);
 EXPORT_SYMBOL_GPL(pci_bus_sem);
 
 /*
+ * pci_for_each_dma_alias - Iterate over DMA aliases for a device
+ * @pdev: starting downstream device
+ * @fn: function to call for each alias
+ * @data: opaque data to pass to @fn
+ *
+ * Starting @pdev, walk up the bus calling @fn for each possible alias
+ * of @pdev at the root bus.
+ */
+int pci_for_each_dma_alias(struct pci_dev *pdev,
+			   int (*fn)(struct pci_dev *pdev,
+				     u16 alias, void *data), void *data)
+{
+	struct pci_bus *bus;
+	int ret;
+
+	ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data);
+	if (ret)
+		return ret;
+
+	for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
+		struct pci_dev *tmp;
+
+		/* Skip virtual buses */
+		if (!bus->self)
+			continue;
+
+		tmp = bus->self;
+
+		/*
+		 * PCIe-to-PCI/X bridges alias transactions from downstream
+		 * devices using the subordinate bus number (PCI Express to
+		 * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3).  For all cases
+		 * where the upstream bus is PCI/X we alias to the bridge
+		 * (there are various conditions in the previous reference
+		 * where the bridge may take ownership of transactions, even
+		 * when the secondary interface is PCI-X).
+		 */
+		if (pci_is_pcie(tmp)) {
+			switch (pci_pcie_type(tmp)) {
+			case PCI_EXP_TYPE_ROOT_PORT:
+			case PCI_EXP_TYPE_UPSTREAM:
+			case PCI_EXP_TYPE_DOWNSTREAM:
+				continue;
+			case PCI_EXP_TYPE_PCI_BRIDGE:
+				ret = fn(tmp,
+					 PCI_DEVID(tmp->subordinate->number,
+						   PCI_DEVFN(0, 0)), data);
+				if (ret)
+					return ret;
+				continue;
+			case PCI_EXP_TYPE_PCIE_BRIDGE:
+				ret = fn(tmp,
+					 PCI_DEVID(tmp->bus->number,
+						   tmp->devfn), data);
+				if (ret)
+					return ret;
+				continue;
+			}
+		} else {
+			ret = fn(tmp, PCI_DEVID(tmp->bus->number, tmp->devfn),
+				 data);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+/*
  * find the upstream PCIe-to-PCI bridge of a PCI device
  * if the device is PCIE, return NULL
  * if the device isn't connected to a PCIe bridge (that is its parent is a
diff --git a/include/linux/pci.h b/include/linux/pci.h
index aab57b4..14b074b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1795,6 +1795,10 @@ static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
 }
 #endif
 
+int pci_for_each_dma_alias(struct pci_dev *pdev,
+			   int (*fn)(struct pci_dev *pdev,
+				     u16 alias, void *data), void *data);
+
 /**
  * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device
  * @pdev: the PCI device


  reply	other threads:[~2014-05-22 23:07 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-22 23:07 [PATCH v4 00/16] PCI/iommu: Fix DMA alias problems Alex Williamson
2014-05-22 23:07 ` Alex Williamson [this message]
2014-05-22 23:07 ` [PATCH v4 02/16] PCI: define pci_dev_flags as bit shifts Alex Williamson
2014-05-22 23:07 ` [PATCH v4 03/16] PCI: quirk pci_for_each_dma_alias() Alex Williamson
2014-05-22 23:07 ` [PATCH v4 04/16] PCI: quirk dma_alias_devfn for Ricoh devices Alex Williamson
2014-05-22 23:07 ` [PATCH v4 05/16] PCI: quirk dma_alias_devfn for Marvell devices Alex Williamson
2014-05-23  1:29   ` George Spelvin
2014-05-28 17:55   ` Bjorn Helgaas
2014-05-28 18:04     ` Alex Williamson
2014-05-28 20:54   ` [PATCH v4.1 " Alex Williamson
2014-05-22 23:08 ` [PATCH v4 06/16] PCI: Quirk pci_for_each_dma_alias() for bridges Alex Williamson
2014-05-28 18:00   ` Bjorn Helgaas
2014-05-28 19:09     ` Alex Williamson
2014-05-28 20:57   ` [PATCH v4.1 " Alex Williamson
2014-05-22 23:08 ` [PATCH v4 07/16] PCI: Add quirks for ASMedia and Tundra bridges Alex Williamson
2014-05-22 23:08 ` [PATCH v4 08/16] iommu: Create central IOMMU group lookup/creation interface Alex Williamson
2014-05-22 23:08 ` [PATCH v4 09/16] iommu/amd: Update to use PCI DMA aliases Alex Williamson
2014-05-22 23:08 ` [PATCH v4 10/16] iommu/amd: Use iommu_group_get_for_dev() Alex Williamson
2014-05-22 23:08 ` [PATCH v4 11/16] iommu/intel: " Alex Williamson
2014-05-22 23:08 ` [PATCH v4 12/16] iommu/intel: Update to use PCI DMA aliases Alex Williamson
2014-05-22 23:08 ` [PATCH v4 13/16] iommu/fsl: Use iommu_group_get_for_dev() for IOMMU groups Alex Williamson
2014-05-30  9:17   ` Varun Sethi
2014-05-22 23:08 ` [PATCH v4 14/16] iommu: Remove pci.h Alex Williamson
2014-05-22 23:08 ` [PATCH v4 15/16] PCI: Remove pci_find_upstream_pcie_bridge() Alex Williamson
2014-05-22 23:09 ` [PATCH v4 16/16] PCI: Remove pci_get_dma_source() Alex Williamson
2014-05-28  5:23 ` [PATCH v4 00/16] PCI/iommu: Fix DMA alias problems Pat Erley
2014-05-28 20:29 ` Bjorn Helgaas
2014-05-28 20:45   ` Alex Williamson
2014-05-30  5:30   ` Andrew Cooks
2014-06-09 18:01 ` Alex Williamson
2014-06-16 14:47 ` Joerg Roedel
2014-06-16 15:34   ` Alex Williamson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140522230730.2856.39308.stgit@bling.home \
    --to=alex.williamson@redhat.com \
    --cc=acooks@gmail.com \
    --cc=bhelgaas@google.com \
    --cc=eddy0596@gmail.com \
    --cc=iommu@lists.linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux@horizon.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).