Commit 7ce3f912 authored by Sinan Kaya's avatar Sinan Kaya Committed by Bjorn Helgaas

PCI: Enable PASID only if entire path supports End-End TLP prefixes

A PCIe endpoint carries the process address space identifier (PASID) in
the TLP prefix as part of the memory read/write transaction. The address
information in the TLP is relevant only for a given PASID context.

An IOMMU takes PASID value and the address information from the
TLP to look up the physical address in the system.

PASID is an End-End TLP Prefix (PCIe r4.0, sec 6.20).  Sec 2.2.10.2 says

  It is an error to receive a TLP with an End-End TLP Prefix by a
  Receiver that does not support End-End TLP Prefixes. A TLP in
  violation of this rule is handled as a Malformed TLP. This is a
  reported error associated with the Receiving Port (see Section 6.2).

Prevent error condition by proactively requiring End-End TLP prefix to be
supported on the entire data path between the endpoint and the root port
before enabling PASID.
Signed-off-by: default avatarSinan Kaya <okaya@codeaurora.org>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent ce397d21
...@@ -273,6 +273,9 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) ...@@ -273,6 +273,9 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
if (WARN_ON(pdev->pasid_enabled)) if (WARN_ON(pdev->pasid_enabled))
return -EBUSY; return -EBUSY;
if (!pdev->eetlp_prefix_path)
return -EINVAL;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos) if (!pos)
return -EINVAL; return -EINVAL;
......
...@@ -2042,6 +2042,29 @@ static void pci_configure_ltr(struct pci_dev *dev) ...@@ -2042,6 +2042,29 @@ static void pci_configure_ltr(struct pci_dev *dev)
#endif #endif
} }
static void pci_configure_eetlp_prefix(struct pci_dev *dev)
{
#ifdef CONFIG_PCI_PASID
struct pci_dev *bridge;
u32 cap;
if (!pci_is_pcie(dev))
return;
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
if (!(cap & PCI_EXP_DEVCAP2_EE_PREFIX))
return;
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
dev->eetlp_prefix_path = 1;
else {
bridge = pci_upstream_bridge(dev);
if (bridge && bridge->eetlp_prefix_path)
dev->eetlp_prefix_path = 1;
}
#endif
}
static void pci_configure_device(struct pci_dev *dev) static void pci_configure_device(struct pci_dev *dev)
{ {
struct hotplug_params hpp; struct hotplug_params hpp;
...@@ -2051,6 +2074,7 @@ static void pci_configure_device(struct pci_dev *dev) ...@@ -2051,6 +2074,7 @@ static void pci_configure_device(struct pci_dev *dev)
pci_configure_extended_tags(dev, NULL); pci_configure_extended_tags(dev, NULL);
pci_configure_relaxed_ordering(dev); pci_configure_relaxed_ordering(dev);
pci_configure_ltr(dev); pci_configure_ltr(dev);
pci_configure_eetlp_prefix(dev);
memset(&hpp, 0, sizeof(hpp)); memset(&hpp, 0, sizeof(hpp));
ret = pci_get_hp_params(dev, &hpp); ret = pci_get_hp_params(dev, &hpp);
......
...@@ -350,6 +350,7 @@ struct pci_dev { ...@@ -350,6 +350,7 @@ struct pci_dev {
unsigned int ltr_path:1; /* Latency Tolerance Reporting unsigned int ltr_path:1; /* Latency Tolerance Reporting
supported from root to here */ supported from root to here */
#endif #endif
unsigned int eetlp_prefix_path:1; /* End-to-End TLP Prefix */
pci_channel_state_t error_state; /* Current connectivity state */ pci_channel_state_t error_state; /* Current connectivity state */
struct device dev; /* Generic device interface */ struct device dev; /* Generic device interface */
......
...@@ -636,6 +636,7 @@ ...@@ -636,6 +636,7 @@
#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ #define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */
#define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ #define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */
#define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */ #define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */
#define PCI_EXP_DEVCAP2_EE_PREFIX 0x00200000 /* End-End TLP Prefix */
#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ #define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */
#define PCI_EXP_DEVCTL2_COMP_TMOUT_DIS 0x0010 /* Completion Timeout Disable */ #define PCI_EXP_DEVCTL2_COMP_TMOUT_DIS 0x0010 /* Completion Timeout Disable */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment