Merge branches 'apple/dart', 'arm/mediatek', 'arm/renesas', 'arm/rockchip', 'arm...
[platform/kernel/linux-starfive.git] / drivers / iommu / intel / iommu.c
index 5c8c5cd..dd8ff35 100644 (file)
@@ -113,13 +113,17 @@ static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
 
 /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
    are never going to work. */
-static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
+static inline unsigned long mm_to_dma_pfn_start(unsigned long mm_pfn)
 {
        return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
 }
+static inline unsigned long mm_to_dma_pfn_end(unsigned long mm_pfn)
+{
+       return ((mm_pfn + 1) << (PAGE_SHIFT - VTD_PAGE_SHIFT)) - 1;
+}
 static inline unsigned long page_to_dma_pfn(struct page *pg)
 {
-       return mm_to_dma_pfn(page_to_pfn(pg));
+       return mm_to_dma_pfn_start(page_to_pfn(pg));
 }
 static inline unsigned long virt_to_dma_pfn(void *p)
 {
@@ -877,7 +881,7 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
        }
        /* For request-without-pasid, get the pasid from context entry */
        if (intel_iommu_sm && pasid == IOMMU_PASID_INVALID)
-               pasid = PASID_RID2PASID;
+               pasid = IOMMU_NO_PASID;
 
        dir_index = pasid >> PASID_PDE_SHIFT;
        pde = &dir[dir_index];
@@ -1359,6 +1363,7 @@ domain_lookup_dev_info(struct dmar_domain *domain,
 
 static void domain_update_iotlb(struct dmar_domain *domain)
 {
+       struct dev_pasid_info *dev_pasid;
        struct device_domain_info *info;
        bool has_iotlb_device = false;
        unsigned long flags;
@@ -1370,6 +1375,14 @@ static void domain_update_iotlb(struct dmar_domain *domain)
                        break;
                }
        }
+
+       list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
+               info = dev_iommu_priv_get(dev_pasid->dev);
+               if (info->ats_enabled) {
+                       has_iotlb_device = true;
+                       break;
+               }
+       }
        domain->has_iotlb_device = has_iotlb_device;
        spin_unlock_irqrestore(&domain->lock, flags);
 }
@@ -1449,12 +1462,13 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
        qdep = info->ats_qdep;
        qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
                           qdep, addr, mask);
-       quirk_extra_dev_tlb_flush(info, addr, mask, PASID_RID2PASID, qdep);
+       quirk_extra_dev_tlb_flush(info, addr, mask, IOMMU_NO_PASID, qdep);
 }
 
 static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
                                  u64 addr, unsigned mask)
 {
+       struct dev_pasid_info *dev_pasid;
        struct device_domain_info *info;
        unsigned long flags;
 
@@ -1464,6 +1478,36 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
        spin_lock_irqsave(&domain->lock, flags);
        list_for_each_entry(info, &domain->devices, link)
                __iommu_flush_dev_iotlb(info, addr, mask);
+
+       list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
+               info = dev_iommu_priv_get(dev_pasid->dev);
+
+               if (!info->ats_enabled)
+                       continue;
+
+               qi_flush_dev_iotlb_pasid(info->iommu,
+                                        PCI_DEVID(info->bus, info->devfn),
+                                        info->pfsid, dev_pasid->pasid,
+                                        info->ats_qdep, addr,
+                                        mask);
+       }
+       spin_unlock_irqrestore(&domain->lock, flags);
+}
+
+static void domain_flush_pasid_iotlb(struct intel_iommu *iommu,
+                                    struct dmar_domain *domain, u64 addr,
+                                    unsigned long npages, bool ih)
+{
+       u16 did = domain_id_iommu(domain, iommu);
+       struct dev_pasid_info *dev_pasid;
+       unsigned long flags;
+
+       spin_lock_irqsave(&domain->lock, flags);
+       list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain)
+               qi_flush_piotlb(iommu, did, dev_pasid->pasid, addr, npages, ih);
+
+       if (!list_empty(&domain->devices))
+               qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih);
        spin_unlock_irqrestore(&domain->lock, flags);
 }
 
@@ -1484,7 +1528,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
                ih = 1 << 6;
 
        if (domain->use_first_level) {
-               qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr, pages, ih);
+               domain_flush_pasid_iotlb(iommu, domain, addr, pages, ih);
        } else {
                unsigned long bitmask = aligned_pages - 1;
 
@@ -1554,7 +1598,7 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain)
                u16 did = domain_id_iommu(dmar_domain, iommu);
 
                if (dmar_domain->use_first_level)
-                       qi_flush_piotlb(iommu, did, PASID_RID2PASID, 0, -1, 0);
+                       domain_flush_pasid_iotlb(iommu, dmar_domain, 0, -1, 0);
                else
                        iommu->flush.flush_iotlb(iommu, did, 0, 0,
                                                 DMA_TLB_DSI_FLUSH);
@@ -1726,6 +1770,7 @@ static struct dmar_domain *alloc_domain(unsigned int type)
                domain->use_first_level = true;
        domain->has_iotlb_device = false;
        INIT_LIST_HEAD(&domain->devices);
+       INIT_LIST_HEAD(&domain->dev_pasids);
        spin_lock_init(&domain->lock);
        xa_init(&domain->iommu_array);
 
@@ -1940,7 +1985,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
                                context_pdts(pds);
 
                /* Setup the RID_PASID field: */
-               context_set_sm_rid2pasid(context, PASID_RID2PASID);
+               context_set_sm_rid2pasid(context, IOMMU_NO_PASID);
 
                /*
                 * Setup the Device-TLB enable bit and Page request
@@ -2362,8 +2407,8 @@ static int __init si_domain_init(int hw)
 
                for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
                        ret = iommu_domain_identity_map(si_domain,
-                                       mm_to_dma_pfn(start_pfn),
-                                       mm_to_dma_pfn(end_pfn));
+                                       mm_to_dma_pfn_start(start_pfn),
+                                       mm_to_dma_pfn_end(end_pfn));
                        if (ret)
                                return ret;
                }
@@ -2384,8 +2429,8 @@ static int __init si_domain_init(int hw)
                                continue;
 
                        ret = iommu_domain_identity_map(si_domain,
-                                       mm_to_dma_pfn(start >> PAGE_SHIFT),
-                                       mm_to_dma_pfn(end >> PAGE_SHIFT));
+                                       mm_to_dma_pfn_start(start >> PAGE_SHIFT),
+                                       mm_to_dma_pfn_end(end >> PAGE_SHIFT));
                        if (ret)
                                return ret;
                }
@@ -2420,13 +2465,13 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
                /* Setup the PASID entry for requests without PASID: */
                if (hw_pass_through && domain_type_is_si(domain))
                        ret = intel_pasid_setup_pass_through(iommu, domain,
-                                       dev, PASID_RID2PASID);
+                                       dev, IOMMU_NO_PASID);
                else if (domain->use_first_level)
                        ret = domain_setup_first_level(iommu, domain, dev,
-                                       PASID_RID2PASID);
+                                       IOMMU_NO_PASID);
                else
                        ret = intel_pasid_setup_second_level(iommu, domain,
-                                       dev, PASID_RID2PASID);
+                                       dev, IOMMU_NO_PASID);
                if (ret) {
                        dev_err(dev, "Setup RID2PASID failed\n");
                        device_block_translation(dev);
@@ -2446,30 +2491,6 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
        return 0;
 }
 
-static bool device_has_rmrr(struct device *dev)
-{
-       struct dmar_rmrr_unit *rmrr;
-       struct device *tmp;
-       int i;
-
-       rcu_read_lock();
-       for_each_rmrr_units(rmrr) {
-               /*
-                * Return TRUE if this RMRR contains the device that
-                * is passed in.
-                */
-               for_each_active_dev_scope(rmrr->devices,
-                                         rmrr->devices_cnt, i, tmp)
-                       if (tmp == dev ||
-                           is_downstream_to_pci_bridge(dev, tmp)) {
-                               rcu_read_unlock();
-                               return true;
-                       }
-       }
-       rcu_read_unlock();
-       return false;
-}
-
 /**
  * device_rmrr_is_relaxable - Test whether the RMRR of this device
  * is relaxable (ie. is allowed to be not enforced under some conditions)
@@ -2500,34 +2521,6 @@ static bool device_rmrr_is_relaxable(struct device *dev)
 }
 
 /*
- * There are a couple cases where we need to restrict the functionality of
- * devices associated with RMRRs.  The first is when evaluating a device for
- * identity mapping because problems exist when devices are moved in and out
- * of domains and their respective RMRR information is lost.  This means that
- * a device with associated RMRRs will never be in a "passthrough" domain.
- * The second is use of the device through the IOMMU API.  This interface
- * expects to have full control of the IOVA space for the device.  We cannot
- * satisfy both the requirement that RMRR access is maintained and have an
- * unencumbered IOVA space.  We also have no ability to quiesce the device's
- * use of the RMRR space or even inform the IOMMU API user of the restriction.
- * We therefore prevent devices associated with an RMRR from participating in
- * the IOMMU API, which eliminates them from device assignment.
- *
- * In both cases, devices which have relaxable RMRRs are not concerned by this
- * restriction. See device_rmrr_is_relaxable comment.
- */
-static bool device_is_rmrr_locked(struct device *dev)
-{
-       if (!device_has_rmrr(dev))
-               return false;
-
-       if (device_rmrr_is_relaxable(dev))
-               return false;
-
-       return true;
-}
-
-/*
  * Return the required default domain type for a specific device.
  *
  * @dev: the device in query
@@ -3560,8 +3553,8 @@ static int intel_iommu_memory_notifier(struct notifier_block *nb,
                                       unsigned long val, void *v)
 {
        struct memory_notify *mhp = v;
-       unsigned long start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
-       unsigned long last_vpfn = mm_to_dma_pfn(mhp->start_pfn +
+       unsigned long start_vpfn = mm_to_dma_pfn_start(mhp->start_pfn);
+       unsigned long last_vpfn = mm_to_dma_pfn_end(mhp->start_pfn +
                        mhp->nr_pages - 1);
 
        switch (val) {
@@ -3756,7 +3749,6 @@ static int __init probe_acpi_namespace_devices(void)
                for_each_active_dev_scope(drhd->devices,
                                          drhd->devices_cnt, i, dev) {
                        struct acpi_device_physical_node *pn;
-                       struct iommu_group *group;
                        struct acpi_device *adev;
 
                        if (dev->bus != &acpi_bus_type)
@@ -3766,12 +3758,6 @@ static int __init probe_acpi_namespace_devices(void)
                        mutex_lock(&adev->physical_node_lock);
                        list_for_each_entry(pn,
                                            &adev->physical_node_list, node) {
-                               group = iommu_group_get(pn->dev);
-                               if (group) {
-                                       iommu_group_put(group);
-                                       continue;
-                               }
-
                                ret = iommu_probe_device(pn->dev);
                                if (ret)
                                        break;
@@ -3968,7 +3954,7 @@ static void dmar_remove_one_dev_info(struct device *dev)
        if (!dev_is_real_dma_subdevice(info->dev)) {
                if (dev_is_pci(info->dev) && sm_supported(iommu))
                        intel_pasid_tear_down_entry(iommu, info->dev,
-                                       PASID_RID2PASID, false);
+                                       IOMMU_NO_PASID, false);
 
                iommu_disable_pci_caps(info);
                domain_context_clear(info);
@@ -3997,7 +3983,7 @@ static void device_block_translation(struct device *dev)
        if (!dev_is_real_dma_subdevice(dev)) {
                if (sm_supported(iommu))
                        intel_pasid_tear_down_entry(iommu, dev,
-                                                   PASID_RID2PASID, false);
+                                                   IOMMU_NO_PASID, false);
                else
                        domain_context_clear(info);
        }
@@ -4139,12 +4125,6 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
        struct device_domain_info *info = dev_iommu_priv_get(dev);
        int ret;
 
-       if (domain->type == IOMMU_DOMAIN_UNMANAGED &&
-           device_is_rmrr_locked(dev)) {
-               dev_warn(dev, "Device is ineligible for IOMMU domain attach due to platform RMRR requirement.  Contact your platform vendor.\n");
-               return -EPERM;
-       }
-
        if (info->domain)
                device_block_translation(dev);
 
@@ -4271,7 +4251,7 @@ static void intel_iommu_tlb_sync(struct iommu_domain *domain,
        unsigned long i;
 
        nrpages = aligned_nrpages(gather->start, size);
-       start_pfn = mm_to_dma_pfn(iova_pfn);
+       start_pfn = mm_to_dma_pfn_start(iova_pfn);
 
        xa_for_each(&dmar_domain->iommu_array, i, info)
                iommu_flush_iotlb_psi(info->iommu, dmar_domain,
@@ -4331,7 +4311,7 @@ static void domain_set_force_snooping(struct dmar_domain *domain)
 
        list_for_each_entry(info, &domain->devices, link)
                intel_pasid_setup_page_snoop_control(info->iommu, info->dev,
-                                                    PASID_RID2PASID);
+                                                    IOMMU_NO_PASID);
 }
 
 static bool intel_iommu_enforce_cache_coherency(struct iommu_domain *domain)
@@ -4713,23 +4693,96 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain,
 static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
 {
        struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
+       struct dev_pasid_info *curr, *dev_pasid = NULL;
+       struct dmar_domain *dmar_domain;
        struct iommu_domain *domain;
+       unsigned long flags;
 
-       /* Domain type specific cleanup: */
        domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0);
-       if (domain) {
-               switch (domain->type) {
-               case IOMMU_DOMAIN_SVA:
-                       intel_svm_remove_dev_pasid(dev, pasid);
-                       break;
-               default:
-                       /* should never reach here */
-                       WARN_ON(1);
+       if (WARN_ON_ONCE(!domain))
+               goto out_tear_down;
+
+       /*
+        * The SVA implementation needs to handle its own stuffs like the mm
+        * notification. Before consolidating that code into iommu core, let
+        * the intel sva code handle it.
+        */
+       if (domain->type == IOMMU_DOMAIN_SVA) {
+               intel_svm_remove_dev_pasid(dev, pasid);
+               goto out_tear_down;
+       }
+
+       dmar_domain = to_dmar_domain(domain);
+       spin_lock_irqsave(&dmar_domain->lock, flags);
+       list_for_each_entry(curr, &dmar_domain->dev_pasids, link_domain) {
+               if (curr->dev == dev && curr->pasid == pasid) {
+                       list_del(&curr->link_domain);
+                       dev_pasid = curr;
                        break;
                }
        }
+       WARN_ON_ONCE(!dev_pasid);
+       spin_unlock_irqrestore(&dmar_domain->lock, flags);
 
+       domain_detach_iommu(dmar_domain, iommu);
+       kfree(dev_pasid);
+out_tear_down:
        intel_pasid_tear_down_entry(iommu, dev, pasid, false);
+       intel_drain_pasid_prq(dev, pasid);
+}
+
+static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
+                                    struct device *dev, ioasid_t pasid)
+{
+       struct device_domain_info *info = dev_iommu_priv_get(dev);
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+       struct intel_iommu *iommu = info->iommu;
+       struct dev_pasid_info *dev_pasid;
+       unsigned long flags;
+       int ret;
+
+       if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
+               return -EOPNOTSUPP;
+
+       if (context_copied(iommu, info->bus, info->devfn))
+               return -EBUSY;
+
+       ret = prepare_domain_attach_device(domain, dev);
+       if (ret)
+               return ret;
+
+       dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
+       if (!dev_pasid)
+               return -ENOMEM;
+
+       ret = domain_attach_iommu(dmar_domain, iommu);
+       if (ret)
+               goto out_free;
+
+       if (domain_type_is_si(dmar_domain))
+               ret = intel_pasid_setup_pass_through(iommu, dmar_domain,
+                                                    dev, pasid);
+       else if (dmar_domain->use_first_level)
+               ret = domain_setup_first_level(iommu, dmar_domain,
+                                              dev, pasid);
+       else
+               ret = intel_pasid_setup_second_level(iommu, dmar_domain,
+                                                    dev, pasid);
+       if (ret)
+               goto out_detach_iommu;
+
+       dev_pasid->dev = dev;
+       dev_pasid->pasid = pasid;
+       spin_lock_irqsave(&dmar_domain->lock, flags);
+       list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
+       spin_unlock_irqrestore(&dmar_domain->lock, flags);
+
+       return 0;
+out_detach_iommu:
+       domain_detach_iommu(dmar_domain, iommu);
+out_free:
+       kfree(dev_pasid);
+       return ret;
 }
 
 const struct iommu_ops intel_iommu_ops = {
@@ -4751,6 +4804,7 @@ const struct iommu_ops intel_iommu_ops = {
 #endif
        .default_domain_ops = &(const struct iommu_domain_ops) {
                .attach_dev             = intel_iommu_attach_device,
+               .set_dev_pasid          = intel_iommu_set_dev_pasid,
                .map_pages              = intel_iommu_map_pages,
                .unmap_pages            = intel_iommu_unmap_pages,
                .iotlb_sync_map         = intel_iommu_iotlb_sync_map,
@@ -4987,7 +5041,7 @@ void quirk_extra_dev_tlb_flush(struct device_domain_info *info,
                return;
 
        sid = PCI_DEVID(info->bus, info->devfn);
-       if (pasid == PASID_RID2PASID) {
+       if (pasid == IOMMU_NO_PASID) {
                qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
                                   qdep, address, mask);
        } else {