qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Alex Williamson <alex.williamson@redhat.com>
To: benh@kernel.crashing.org, aik@ozlabs.ru,
	david@gibson.dropbear.id.au, joerg.roedel@amd.com,
	dwmw2@infradead.org
Cc: aafabbri@cisco.com, alex.williamson@redhat.com,
	kvm@vger.kernel.org, B07421@freescale.com,
	linux-pci@vger.kernel.org, konrad.wilk@oracle.com, agraf@suse.de,
	qemu-devel@nongnu.org, chrisw@sous-sol.org, B08248@freescale.com,
	iommu@lists.linux-foundation.org, ddutile@redhat.com,
	avi@redhat.com, gregkh@linuxfoundation.org, bhelgaas@google.com,
	linux-kernel@vger.kernel.org, benve@cisco.com
Subject: [Qemu-devel] [PATCH v2 05/13] pci: Add ACS validation utility
Date: Mon, 21 May 2012 23:05:08 -0600	[thread overview]
Message-ID: <20120522050508.5871.96269.stgit@bling.home> (raw)
In-Reply-To: <20120522043607.5871.11340.stgit@bling.home>

In a PCI environment, transactions aren't always required to reach
the root bus before being re-routed.  Intermediate switches between
an endpoint and the root bus can redirect DMA back downstream before
things like IOMMUs have a chance to intervene.  Legacy PCI is always
susceptible to this as it operates on a shared bus.  PCIe added a
new capability to describe and control this behavior, Access Control
Services, or ACS.  The utility function pci_acs_enabled() allows us
to test the ACS capabilities of an individual devices against a set
of flags while pci_acs_path_enabled() tests a complete path from
a given downstream device up to the specified upstream device.  We
also include the ability to add device specific tests as it's
likely we'll see devices that do no implement ACS, but want to
indicate support for various capabilities in this space.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---

 drivers/pci/pci.c    |   76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/quirks.c |   29 +++++++++++++++++++
 include/linux/pci.h  |   10 ++++++-
 3 files changed, 114 insertions(+), 1 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 111569c..ab6c2a6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2359,6 +2359,82 @@ void pci_enable_acs(struct pci_dev *dev)
 }
 
 /**
+ * pci_acs_enable - test ACS against required flags for a given device
+ * @pdev: device to test
+ * @acs_flags: required PCI ACS flags
+ *
+ * Return true if the device supports the provided flags.  Automatically
+ * filters out flags that are not implemented on multifunction devices.
+ */
+bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
+{
+	int pos;
+	u16 ctrl;
+
+	if (pci_dev_specific_acs_enabled(pdev, acs_flags))
+		return true;
+
+	if (!pci_is_pcie(pdev))
+		return false;
+
+	if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
+	    pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
+		pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+		if (!pos)
+			return false;
+
+		pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+		if ((ctrl & acs_flags) != acs_flags)
+			return false;
+	} else if (pdev->multifunction) {
+		/* Filter out flags not applicable to multifunction */
+		acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
+			      PCI_ACS_EC | PCI_ACS_DT);
+
+		pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+		if (!pos)
+			return false;
+
+		pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+		if ((ctrl & acs_flags) != acs_flags)
+			return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(pci_acs_enabled);
+
+/**
+ * pci_acs_path_enable - test ACS flags from start to end in a hierarchy
+ * @start: starting downstream device
+ * @end: ending upstream device or NULL to search to the root bus
+ * @acs_flags: required flags
+ *
+ * Walk up a device tree from start to end testing PCI ACS support.  If
+ * any step along the way does not support the required flags, return false.
+ */
+bool pci_acs_path_enabled(struct pci_dev *start,
+			  struct pci_dev *end, u16 acs_flags)
+{
+	struct pci_dev *pdev, *parent = start;
+
+	do {
+		pdev = parent;
+
+		if (!pci_acs_enabled(pdev, acs_flags))
+			return false;
+
+		if (pci_is_root_bus(pdev->bus))
+			return (end == NULL);
+
+		parent = pdev->bus->self;
+	} while (pdev != end);
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(pci_acs_path_enabled);
+
+/**
  * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
  * @dev: the PCI device
  * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index a2dd77f..4ed6aa6 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3149,3 +3149,32 @@ struct pci_dev *pci_dma_source(struct pci_dev *dev)
 
 	return dev;
 }
+
+static const struct pci_dev_acs_enabled {
+	u16 vendor;
+	u16 device;
+	bool (*acs_enabled)(struct pci_dev *dev, u16 acs_flags);
+} pci_dev_acs_enabled[] = {
+	{ 0 }
+};
+
+bool pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
+{
+	const struct pci_dev_acs_enabled *i;
+
+	/*
+	 * Allow devices that do not expose standard PCI ACS capabilities
+	 * or control to indicate their support here.  Multi-function devices
+	 * which do not allow internal peer-to-peer between functions, but
+	 * do not implement PCI ACS may wish to return true here.
+	 */
+	for (i = pci_dev_acs_enabled; i->acs_enabled; i++) {
+		if ((i->vendor == dev->vendor ||
+		     i->vendor == (u16)PCI_ANY_ID) &&
+		    (i->device == dev->device ||
+		     i->device == (u16)PCI_ANY_ID))
+			return i->acs_enabled(dev, acs_flags);
+	}
+
+	return false;
+}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 02dbfed..2559735 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1480,6 +1480,7 @@ enum pci_fixup_pass {
 #ifdef CONFIG_PCI_QUIRKS
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
 struct pci_dev *pci_dma_source(struct pci_dev *dev);
+bool pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
 #else
 static inline void pci_fixup_device(enum pci_fixup_pass pass,
 				    struct pci_dev *dev) {}
@@ -1487,6 +1488,11 @@ static inline struct pci_dev *pci_dma_source(struct pci_dev *dev)
 {
 	return dev;
 }
+static inline bool pci_dev_specific_acs_enabled(struct pci_dev *dev,
+						u16 acs_flags)
+{
+	return false;
+}
 #endif
 
 void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
@@ -1589,7 +1595,9 @@ static inline bool pci_is_pcie(struct pci_dev *dev)
 }
 
 void pci_request_acs(void);
-
+bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags);
+bool pci_acs_path_enabled(struct pci_dev *start,
+			  struct pci_dev *end, u16 acs_flags);
 
 #define PCI_VPD_LRDT			0x80	/* Large Resource Data Type */
 #define PCI_VPD_LRDT_ID(x)		(x | PCI_VPD_LRDT)

  parent reply	other threads:[~2012-05-22  5:05 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-22  5:04 [Qemu-devel] [PATCH v2 00/13] IOMMU Groups + VFIO Alex Williamson
2012-05-22  5:04 ` [Qemu-devel] [PATCH v2 01/13] driver core: Add iommu_group tracking to struct device Alex Williamson
2012-05-22  5:04 ` [Qemu-devel] [PATCH v2 02/13] iommu: IOMMU Groups Alex Williamson
2012-05-22  5:04 ` [Qemu-devel] [PATCH v2 03/13] iommu: IOMMU groups for VT-d and AMD-Vi Alex Williamson
2012-05-24 21:01   ` Don Dutile
2012-05-24 21:49     ` Alex Williamson
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 04/13] pci: Add PCI DMA source ID quirk Alex Williamson
2012-05-22  5:05 ` Alex Williamson [this message]
2012-05-24 21:30   ` [Qemu-devel] [PATCH v2 05/13] pci: Add ACS validation utility Don Dutile
2012-05-24 22:35     ` Alex Williamson
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 06/13] iommu: Make use of DMA quirking and ACS enabled check for groups Alex Williamson
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 07/13] vfio: VFIO core Alex Williamson
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 08/13] vfio: Add documentation Alex Williamson
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 09/13] vfio: x86 IOMMU implementation Alex Williamson
2012-05-24 21:38   ` Don Dutile
2012-05-24 22:46     ` Alex Williamson
2012-05-25 15:22       ` Don Dutile
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 10/13] pci: export pci_user functions for use by other drivers Alex Williamson
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 11/13] pci: Create common pcibios_err_to_errno Alex Williamson
2012-05-22  5:05 ` [Qemu-devel] [PATCH v2 12/13] pci: Misc pci_reg additions Alex Williamson
2012-05-24 21:49   ` Don Dutile
2012-05-24 22:17     ` Alex Williamson
2012-05-22  5:06 ` [Qemu-devel] [PATCH v2 13/13] vfio: Add PCI device driver Alex Williamson
2012-05-24 21:56 ` [Qemu-devel] [PATCH v2 00/13] IOMMU Groups + VFIO Don Dutile

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=20120522050508.5871.96269.stgit@bling.home \
    --to=alex.williamson@redhat.com \
    --cc=B07421@freescale.com \
    --cc=B08248@freescale.com \
    --cc=aafabbri@cisco.com \
    --cc=agraf@suse.de \
    --cc=aik@ozlabs.ru \
    --cc=avi@redhat.com \
    --cc=benh@kernel.crashing.org \
    --cc=benve@cisco.com \
    --cc=bhelgaas@google.com \
    --cc=chrisw@sous-sol.org \
    --cc=david@gibson.dropbear.id.au \
    --cc=ddutile@redhat.com \
    --cc=dwmw2@infradead.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=iommu@lists.linux-foundation.org \
    --cc=joerg.roedel@amd.com \
    --cc=konrad.wilk@oracle.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=qemu-devel@nongnu.org \
    /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).