iommu/dart: Exclude MSI doorbell from PCIe device IOVA range
authorMarc Zyngier <maz@kernel.org>
Wed, 29 Sep 2021 16:38:41 +0000 (17:38 +0100)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 4 Nov 2021 21:29:30 +0000 (16:29 -0500)
The MSI doorbell on Apple HW can be any address in the low 4GB range.
However, the MSI write is matched by the PCIe block before hitting the
iommu. It must thus be excluded from the IOVA range that is assigned to any
PCIe device.

Link: https://lore.kernel.org/r/20210929163847.2807812-9-maz@kernel.org
Tested-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Sven Peter <sven@svenpeter.dev>
drivers/iommu/apple-dart.c
drivers/pci/controller/Kconfig
drivers/pci/controller/pcie-apple.c

index 559db9259e65c76ebf1eef2e02dd2c61be2de929..f1f1f024c604c2eb57f8528db350444f6f696025 100644 (file)
@@ -721,6 +721,31 @@ static int apple_dart_def_domain_type(struct device *dev)
        return 0;
 }
 
+#ifndef CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR
+/* Keep things compiling when CONFIG_PCI_APPLE isn't selected */
+#define CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR    0
+#endif
+#define DOORBELL_ADDR  (CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR & PAGE_MASK)
+
+static void apple_dart_get_resv_regions(struct device *dev,
+                                       struct list_head *head)
+{
+       if (IS_ENABLED(CONFIG_PCIE_APPLE) && dev_is_pci(dev)) {
+               struct iommu_resv_region *region;
+               int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+               region = iommu_alloc_resv_region(DOORBELL_ADDR,
+                                                PAGE_SIZE, prot,
+                                                IOMMU_RESV_MSI);
+               if (!region)
+                       return;
+
+               list_add_tail(&region->list, head);
+       }
+
+       iommu_dma_get_resv_regions(dev, head);
+}
+
 static const struct iommu_ops apple_dart_iommu_ops = {
        .domain_alloc = apple_dart_domain_alloc,
        .domain_free = apple_dart_domain_free,
@@ -737,6 +762,8 @@ static const struct iommu_ops apple_dart_iommu_ops = {
        .device_group = apple_dart_device_group,
        .of_xlate = apple_dart_of_xlate,
        .def_domain_type = apple_dart_def_domain_type,
+       .get_resv_regions = apple_dart_get_resv_regions,
+       .put_resv_regions = generic_iommu_put_resv_regions,
        .pgsize_bitmap = -1UL, /* Restricted during dart probe */
 };
 
index 953d9acc031f88b33d6673b4b0b5ca06f9442161..5661d4a84832ed8df40ebd58fe4e01b0aa91049d 100644 (file)
@@ -312,6 +312,11 @@ config PCIE_HISI_ERR
          Say Y here if you want error handling support
          for the PCIe controller's errors on HiSilicon HIP SoCs
 
+config PCIE_APPLE_MSI_DOORBELL_ADDR
+       hex
+       default 0xfffff000
+       depends on PCIE_APPLE
+
 config PCIE_APPLE
        tristate "Apple PCIe controller"
        depends on ARCH_APPLE || COMPILE_TEST
index 8f413509e37daf63de7646d4fb5cc8c17b40df6c..3646638f3df00325a38683c11043a183d9521eff 100644 (file)
  * The doorbell address is set to 0xfffff000, which by convention
  * matches what MacOS does, and it is possible to use any other
  * address (in the bottom 4GB, as the base register is only 32bit).
+ * However, it has to be excluded from the IOVA range, and the DART
+ * driver has to know about it.
  */
-#define DOORBELL_ADDR                  0xfffff000
+#define DOORBELL_ADDR          CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR
 
 struct apple_pcie {
        struct mutex            lock;