This checks whether a domain should use first level page table
for map/unmap. And if so, we should attach the domain to the
device in first level translation mode.

Cc: Ashok Raj <[email protected]>
Cc: Jacob Pan <[email protected]>
Cc: Kevin Tian <[email protected]>
Cc: Liu Yi L <[email protected]>
Cc: Yi Sun <[email protected]>
Cc: Sanjay Kumar <[email protected]>
Signed-off-by: Lu Baolu <[email protected]>
---
 drivers/iommu/intel-iommu.c | 41 ++++++++++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 103480016010..d539e6a6c3dd 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1722,6 +1722,26 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 #endif
 }
 
+/*
+ * Check and return whether first level is used by default for
+ * DMA translation.
+ */
+static bool first_level_by_default(void)
+{
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
+
+       rcu_read_lock();
+       for_each_active_iommu(iommu, drhd)
+               if (!sm_supported(iommu) ||
+                   !ecap_flts(iommu->ecap) ||
+                   !cap_caching_mode(iommu->cap))
+                       return false;
+       rcu_read_unlock();
+
+       return true;
+}
+
 static struct dmar_domain *alloc_domain(int flags)
 {
        struct dmar_domain *domain;
@@ -1736,6 +1756,9 @@ static struct dmar_domain *alloc_domain(int flags)
        domain->has_iotlb_device = false;
        INIT_LIST_HEAD(&domain->devices);
 
+       if (first_level_by_default())
+               domain->flags |= DOMAIN_FLAG_FIRST_LEVEL_TRANS;
+
        return domain;
 }
 
@@ -2625,6 +2648,11 @@ static struct dmar_domain 
*dmar_insert_one_dev_info(struct intel_iommu *iommu,
                if (hw_pass_through && domain_type_is_si(domain))
                        ret = intel_pasid_setup_pass_through(iommu, domain,
                                        dev, PASID_RID2PASID);
+               else if (domain_type_is_flt(domain))
+                       ret = intel_pasid_setup_first_level(iommu, dev,
+                                       domain->pgd, PASID_RID2PASID,
+                                       domain->iommu_did[iommu->seq_id],
+                                       PASID_FLAG_SUPERVISOR_MODE);
                else
                        ret = intel_pasid_setup_second_level(iommu, domain,
                                        dev, PASID_RID2PASID);
@@ -5349,8 +5377,14 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
                goto attach_failed;
 
        /* Setup the PASID entry for mediated devices: */
-       ret = intel_pasid_setup_second_level(iommu, domain, dev,
-                                            domain->default_pasid);
+       if (domain_type_is_flt(domain))
+               ret = intel_pasid_setup_first_level(iommu, dev,
+                               domain->pgd, domain->default_pasid,
+                               domain->iommu_did[iommu->seq_id],
+                               PASID_FLAG_SUPERVISOR_MODE);
+       else
+               ret = intel_pasid_setup_second_level(iommu, domain, dev,
+                                                    domain->default_pasid);
        if (ret)
                goto table_failed;
        spin_unlock(&iommu->lock);
@@ -5583,7 +5617,8 @@ static phys_addr_t intel_iommu_iova_to_phys(struct 
iommu_domain *domain,
        int level = 0;
        u64 phys = 0;
 
-       if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
+       if ((dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN) ||
+           (dmar_domain->flags & DOMAIN_FLAG_FIRST_LEVEL_TRANS))
                return 0;
 
        pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
-- 
2.17.1

Reply via email to