[PATCH 4/4] PCI: Add support for PASID capability

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Devices supporting Process Address Space Identifiers
(PASIDs) can use an IOMMU to access multiple IO address
spaces at the same time. A PCIe device indicates support for
this feature by implementing the PASID capability. This
patch adds support for the capability to the Linux kernel.

Signed-off-by: Joerg Roedel <joerg.roedel@xxxxxxx>
---
 drivers/pci/Kconfig      |   13 +++++
 drivers/pci/ats.c        |  113 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-ats.h  |   31 +++++++++++++
 include/linux/pci_regs.h |    8 +++
 4 files changed, 165 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index fb1e9707..cec6606 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -94,6 +94,19 @@ config PCI_PRI
 
 	  If unsure, say N.
 
+config PCI_PASID
+	bool "PCI PASID support"
+	depends on PCI
+	select PCI_ATS
+	help
+	  Process Address Space Identifiers (PASIDs) can be used by PCI devices
+	  to access more than one IO address space at the same time. To make
+	  use of this feature an IOMMU is required which also supports PASIDs.
+	  Select this option if you have such an IOMMU and want to compile the
+	  driver for it into your kernel.
+
+	  If unsure, say N.
+
 config PCI_IOAPIC
 	bool
 	depends on PCI
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index bf892a0..f727a09 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -7,6 +7,7 @@
  * PCI Express I/O Virtualization (IOV) support.
  *   Address Translation Service 1.0
  *   Page Request Interface added by Joerg Roedel <joerg.roedel@xxxxxxx>
+ *   PASID support added by Joerg Roedel <joerg.roedel@xxxxxxx>
  */
 
 #include <linux/pci-ats.h>
@@ -323,3 +324,115 @@ int pci_pri_status(struct pci_dev *pdev)
 }
 EXPORT_SYMBOL_GPL(pci_pri_status);
 #endif /* CONFIG_PCI_PRI */
+
+#ifdef CONFIG_PCI_PASID
+/**
+ * pci_enable_pasid - Enable the PASID capability
+ * @pdev: PCI device structure
+ * @features: Features to enable
+ *
+ * Returns 0 on success, negative value on error. This function checks
+ * whether the features are actually supported by the device and returns
+ * an error if not.
+ */
+int pci_enable_pasid(struct pci_dev *pdev, int features)
+{
+	u16 control, supported;
+	int pos;
+
+	pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
+	if (!pos)
+		return -EINVAL;
+
+	pci_read_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, &control);
+	pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF,     &supported);
+
+	if (!(supported & PCI_PASID_ENABLE))
+		return -EINVAL;
+
+	supported &= PCI_PASID_EXEC | PCI_PASID_PRIV;
+
+	/* User wants to enable anything unsupported? */
+	if ((supported & features) != features)
+		return -EINVAL;
+
+	control = PCI_PASID_ENABLE | features;
+
+	pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_enable_pasid);
+
+/**
+ * pci_disable_pasid - Disable the PASID capability
+ * @pdev: PCI device structure
+ *
+ */
+void pci_disable_pasid(struct pci_dev *pdev)
+{
+	u16 control = 0;
+	int pos;
+
+	pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
+	if (!pos)
+		return;
+
+	pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
+}
+EXPORT_SYMBOL_GPL(pci_disable_pasid);
+
+/**
+ * pci_pasid_features - Check which PASID features are supported
+ * @pdev: PCI device structure
+ *
+ * Returns a negative value when no PASI capability is present.
+ * Otherwise is returns a bitmask with supported features. Current
+ * features reported are:
+ * PCI_PASID_ENABLE - PASID capability can be enabled
+ * PCI_PASID_EXEC - Execute permission supported
+ * PCI_PASID_PRIV - Priviledged mode supported
+ */
+int pci_pasid_features(struct pci_dev *pdev)
+{
+	u16 supported;
+	int pos;
+
+	pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
+	if (!pos)
+		return -EINVAL;
+
+	pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
+
+	supported &= PCI_PASID_ENABLE | PCI_PASID_EXEC | PCI_PASID_PRIV;
+
+	return supported;
+}
+EXPORT_SYMBOL_GPL(pci_pasid_features);
+
+#define PASID_NUMBER_SHIFT	8
+#define PASID_NUMBER_MASK	(0x1f << PASID_NUMBER_SHIFT)
+/**
+ * pci_max_pasid - Get maximum number of PASIDs supported by device
+ * @pdev: PCI device structure
+ *
+ * Returns negative value when PASID capability is not present.
+ * Otherwise it returns the numer of supported PASIDs.
+ */
+int pci_max_pasids(struct pci_dev *pdev)
+{
+	u16 supported;
+	int pos;
+
+	pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
+	if (!pos)
+		return -EINVAL;
+
+	pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
+
+	supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
+
+	return (1 << supported);
+}
+EXPORT_SYMBOL_GPL(pci_max_pasids);
+#endif /* CONFIG_PCI_PASID */
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 0713952..e3d0b38 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -93,4 +93,35 @@ static inline int pci_pri_status(struct pci_dev *pdev)
 }
 #endif /* CONFIG_PCI_PRI */
 
+#ifdef CONFIG_PCI_PASID
+
+extern int pci_enable_pasid(struct pci_dev *pdev, int features);
+extern void pci_disable_pasid(struct pci_dev *pdev);
+extern int pci_pasid_features(struct pci_dev *pdev);
+extern int pci_max_pasids(struct pci_dev *pdev);
+
+#else  /* CONFIG_PCI_PASID */
+
+static inline int pci_enable_pasid(struct pci_dev *pdev, int features)
+{
+	return -EINVAL;
+}
+
+static inline void pci_disable_pasid(struct pci_dev *pdev)
+{
+}
+
+static inline int pci_pasid_features(struct pci_dev *pdev)
+{
+	return -EINVAL;
+}
+
+static inline int pci_max_pasids(struct pci_dev *pdev)
+{
+	return -EINVAL;
+}
+
+#endif /* CONFIG_PCI_PASID */
+
+
 #endif /* LINUX_PCI_ATS_H*/
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 7fc32af..b5d9657 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -675,6 +675,14 @@
 #define PCI_PRI_MAX_REQ_OFF	0x08	/* Cap offset for max reqs supported */
 #define PCI_PRI_ALLOC_REQ_OFF	0x0c	/* Cap offset for max reqs allowed */
 
+/* PASID capability */
+#define PCI_PASID_CAP		0x1b    /* PASID capability ID */
+#define PCI_PASID_CAP_OFF	0x04    /* PASID feature register */
+#define PCI_PASID_CONTROL_OFF   0x06    /* PASID control register */
+#define PCI_PASID_ENABLE	0x01	/* Enable/Supported bit */
+#define PCI_PASID_EXEC		0x02	/* Exec permissions Enable/Supported */
+#define PCI_PASID_PRIV		0x04	/* Priviledge Mode Enable/Support */
+
 /* Single Root I/O Virtualization */
 #define PCI_SRIOV_CAP		0x04	/* SR-IOV Capabilities */
 #define  PCI_SRIOV_CAP_VFM	0x01	/* VF Migration Capable */
-- 
1.7.4.1


--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux