]> www.infradead.org Git - users/willy/xarray.git/commitdiff
PCI/ACS: Enable Translation Blocking for external devices
authorRajat Jain <rajatja@google.com>
Tue, 7 Jul 2020 22:46:04 +0000 (15:46 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 16 Sep 2020 21:42:22 +0000 (16:42 -0500)
Translation Blocking is a required feature for Downstream Ports (Root
Ports or Switch Downstream Ports) that implement ACS.  When enabled, the
Port checks the Address Type (AT) of each upstream Memory Request it
receives.

The default AT (00b) means "untranslated" and the IOMMU can decide whether
to treat the address as I/O virtual or physical.

If AT is not the default, i.e., if the Memory Request contains an
already-translated (physical) address, the Port blocks the request and
reports an ACS error.

When enabling ACS, enable Translation Blocking for external-facing ports
and untrusted (external) devices.  This is to help prevent attacks from
external devices that initiate DMA with physical addresses that bypass the
IOMMU.

[bhelgaas: commit log, simplify setting bit and drop warning; TB is
required for Downstream Ports with ACS, so we should never see the warning]
Link: https://lore.kernel.org/r/20200707224604.3737893-4-rajatja@google.com
Signed-off-by: Rajat Jain <rajatja@google.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/pci.c
drivers/pci/quirks.c

index a458c46d7e39d13c722d733cebc1c80d7f4b3ae1..8b649b01aad340fb6631b73474ec17401b3a3a24 100644 (file)
@@ -876,6 +876,10 @@ static void pci_std_enable_acs(struct pci_dev *dev)
        /* Upstream Forwarding */
        ctrl |= (cap & PCI_ACS_UF);
 
+       /* Enable Translation Blocking for external devices */
+       if (dev->external_facing || dev->untrusted)
+               ctrl |= (cap & PCI_ACS_TB);
+
        pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
 }
 
index bdf9b52567e030640b5ee98ad9e1cded7be37f72..8f409d442bc0b5947a5a7413e5c8c1bfbbeec843 100644 (file)
@@ -4949,6 +4949,13 @@ static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
        }
 }
 
+/*
+ * Currently this quirk does the equivalent of
+ * PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
+ *
+ * TODO: This quirk also needs to do equivalent of PCI_ACS_TB,
+ * if dev->external_facing || dev->untrusted
+ */
 static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
 {
        if (!pci_quirk_intel_pch_acs_match(dev))
@@ -4988,6 +4995,9 @@ static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)
        ctrl |= (cap & PCI_ACS_CR);
        ctrl |= (cap & PCI_ACS_UF);
 
+       if (dev->external_facing || dev->untrusted)
+               ctrl |= (cap & PCI_ACS_TB);
+
        pci_write_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, ctrl);
 
        pci_info(dev, "Intel SPT PCH root port ACS workaround enabled\n");