diff mbox

iommu: OMAP: device detach on domain destroy

Message ID 1333123429-3727-1-git-send-email-omar.luna@linaro.org
State Accepted
Commit 803b5277215c75a5cc3b3eb5d19015c7290601a5
Headers show

Commit Message

Omar Ramirez Luna March 30, 2012, 4:03 p.m. UTC
'domain_destroy with devices attached' case isn't yet handled, instead
code assumes that the device was already detached.

If the domain is destroyed the hardware still has access to invalid
pointers to its page table and internal iommu object. In order to
detach the users we need to track devices using the iommu, current
use cases only have one user of iommu per instance. When required
this can evolve to a list with the devices using the iommu_dev.

Reported-by: Joerg Roedel <joro@8bytes.org>
Reviewed-by: Ohad Ben-Cohen <ohad@wizery.com>
Signed-off-by: Omar Ramirez Luna <omar.luna@linaro.org>
---
 drivers/iommu/omap-iommu.c |   32 +++++++++++++++++++++++---------
 1 files changed, 23 insertions(+), 9 deletions(-)

Comments

Joerg Roedel April 12, 2012, 10:25 a.m. UTC | #1
On Fri, Mar 30, 2012 at 11:03:49AM -0500, Omar Ramirez Luna wrote:
> 'domain_destroy with devices attached' case isn't yet handled, instead
> code assumes that the device was already detached.
> 
> If the domain is destroyed the hardware still has access to invalid
> pointers to its page table and internal iommu object. In order to
> detach the users we need to track devices using the iommu, current
> use cases only have one user of iommu per instance. When required
> this can evolve to a list with the devices using the iommu_dev.
> 
> Reported-by: Joerg Roedel <joro@8bytes.org>
> Reviewed-by: Ohad Ben-Cohen <ohad@wizery.com>
> Signed-off-by: Omar Ramirez Luna <omar.luna@linaro.org>

Doesn't apply against 3.4-rc2. Please rebase and send a new version.


	Joerg
Omar Ramirez Luna April 18, 2012, 6:11 p.m. UTC | #2
Hi Joerg,

On 12 April 2012 05:25, Joerg Roedel <joerg.roedel@amd.com> wrote:
> Doesn't apply against 3.4-rc2. Please rebase and send a new version.

I rebased the patch and sent v2.

Thanks,

Omar
diff mbox

Patch

diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 821062a..e32bd15 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -41,11 +41,13 @@ 
  * @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;
 };
 
@@ -1074,6 +1076,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;
 
 	/* temporary workaround */
@@ -1084,19 +1087,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);
@@ -1104,11 +1104,19 @@  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;
 
 	/* temporary workaround */
 	clk_disable(oiommu->clk);
+}
 
-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);
 }
 
@@ -1147,13 +1155,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);
 }