In nested mode we enforce the rule that all devices belonging
to the same iommu_domain share the same msi_domain.

Indeed if there were several physical MSI doorbells being used
within a single iommu_domain, it becomes really difficult to
resolve the nested stage mapping translating into the correct
physical doorbell. So let's forbid this situation.

Signed-off-by: Eric Auger <eric.au...@redhat.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 41 +++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 24124361dd3b..5a05c2074c8a 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2265,6 +2265,37 @@ static void arm_smmu_detach_dev(struct arm_smmu_master 
*master)
        arm_smmu_install_ste_for_dev(master);
 }
 
+static bool arm_smmu_share_msi_domain(struct iommu_domain *domain,
+                                     struct device *dev)
+{
+       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+       struct irq_domain *irqd = dev_get_msi_domain(dev);
+       struct arm_smmu_master *master;
+       unsigned long flags;
+       bool share = false;
+
+       if (!irqd)
+               return true;
+
+       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
+       list_for_each_entry(master, &smmu_domain->devices, domain_head) {
+               struct irq_domain *d = dev_get_msi_domain(master->dev);
+
+               if (!d)
+                       continue;
+               if (irqd != d) {
+                       dev_info(dev, "Nested mode forbids to attach devices "
+                                "using different physical MSI doorbells "
+                                "to the same iommu_domain");
+                       goto unlock;
+               }
+       }
+       share = true;
+unlock:
+       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+       return share;
+}
+
 static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
        int ret = 0;
@@ -2316,6 +2347,16 @@ static int arm_smmu_attach_dev(struct iommu_domain 
*domain, struct device *dev)
                ret = -EINVAL;
                goto out_unlock;
        }
+       /*
+        * In nested mode we must check all devices belonging to the
+        * domain share the same physical MSI doorbell. Otherwise nested
+        * stage MSI binding is not supported.
+        */
+       if (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED &&
+               !arm_smmu_share_msi_domain(domain, dev)) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
        master->domain = smmu_domain;
 
-- 
2.21.3

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to