Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[firefly-linux-kernel-4.4.55.git] / drivers / iommu / omap-iommu.c
index 6899dcd02dfa0e35df014c42651ba4c5b4f6bb67..e70ee2b59df95b9427c4c1594384776d97103015 100644 (file)
  * @pgtable:   the page table
  * @iommu_dev: an omap iommu device attached to this domain. only a single
  *             iommu device can be attached for now.
+ * @dev:       Device using this domain.
  * @lock:      domain lock, should be taken when attaching/detaching
  */
 struct omap_iommu_domain {
        u32 *pgtable;
        struct omap_iommu *iommu_dev;
+       struct device *dev;
        spinlock_t lock;
 };
 
@@ -1081,6 +1083,7 @@ omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
        }
 
        omap_domain->iommu_dev = arch_data->iommu_dev = oiommu;
+       omap_domain->dev = dev;
        oiommu->domain = domain;
 
 out:
@@ -1088,19 +1091,16 @@ out:
        return ret;
 }
 
-static void omap_iommu_detach_dev(struct iommu_domain *domain,
-                                struct device *dev)
+static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain,
+                       struct device *dev)
 {
-       struct omap_iommu_domain *omap_domain = domain->priv;
-       struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
        struct omap_iommu *oiommu = dev_to_omap_iommu(dev);
-
-       spin_lock(&omap_domain->lock);
+       struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
 
        /* only a single device is supported per domain for now */
        if (omap_domain->iommu_dev != oiommu) {
                dev_err(dev, "invalid iommu device\n");
-               goto out;
+               return;
        }
 
        iopgtable_clear_entry_all(oiommu);
@@ -1108,8 +1108,16 @@ static void omap_iommu_detach_dev(struct iommu_domain *domain,
        omap_iommu_detach(oiommu);
 
        omap_domain->iommu_dev = arch_data->iommu_dev = NULL;
+       omap_domain->dev = NULL;
+}
 
-out:
+static void omap_iommu_detach_dev(struct iommu_domain *domain,
+                                struct device *dev)
+{
+       struct omap_iommu_domain *omap_domain = domain->priv;
+
+       spin_lock(&omap_domain->lock);
+       _omap_iommu_detach_dev(omap_domain, dev);
        spin_unlock(&omap_domain->lock);
 }
 
@@ -1148,13 +1156,19 @@ out:
        return -ENOMEM;
 }
 
-/* assume device was already detached */
 static void omap_iommu_domain_destroy(struct iommu_domain *domain)
 {
        struct omap_iommu_domain *omap_domain = domain->priv;
 
        domain->priv = NULL;
 
+       /*
+        * An iommu device is still attached
+        * (currently, only one device can be attached) ?
+        */
+       if (omap_domain->iommu_dev)
+               _omap_iommu_detach_dev(omap_domain, omap_domain->dev);
+
        kfree(omap_domain->pgtable);
        kfree(omap_domain);
 }