mirror of https://gitee.com/openkylin/linux.git
iommu: OMAP: device detach on domain destroy
'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> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
parent
0034102808
commit
803b527721
|
@ -41,11 +41,13 @@
|
||||||
* @pgtable: the page table
|
* @pgtable: the page table
|
||||||
* @iommu_dev: an omap iommu device attached to this domain. only a single
|
* @iommu_dev: an omap iommu device attached to this domain. only a single
|
||||||
* iommu device can be attached for now.
|
* iommu device can be attached for now.
|
||||||
|
* @dev: Device using this domain.
|
||||||
* @lock: domain lock, should be taken when attaching/detaching
|
* @lock: domain lock, should be taken when attaching/detaching
|
||||||
*/
|
*/
|
||||||
struct omap_iommu_domain {
|
struct omap_iommu_domain {
|
||||||
u32 *pgtable;
|
u32 *pgtable;
|
||||||
struct omap_iommu *iommu_dev;
|
struct omap_iommu *iommu_dev;
|
||||||
|
struct device *dev;
|
||||||
spinlock_t lock;
|
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->iommu_dev = arch_data->iommu_dev = oiommu;
|
||||||
|
omap_domain->dev = dev;
|
||||||
oiommu->domain = domain;
|
oiommu->domain = domain;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -1088,19 +1091,16 @@ omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_iommu_detach_dev(struct iommu_domain *domain,
|
static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain,
|
||||||
struct device *dev)
|
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);
|
struct omap_iommu *oiommu = dev_to_omap_iommu(dev);
|
||||||
|
struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
|
||||||
spin_lock(&omap_domain->lock);
|
|
||||||
|
|
||||||
/* only a single device is supported per domain for now */
|
/* only a single device is supported per domain for now */
|
||||||
if (omap_domain->iommu_dev != oiommu) {
|
if (omap_domain->iommu_dev != oiommu) {
|
||||||
dev_err(dev, "invalid iommu device\n");
|
dev_err(dev, "invalid iommu device\n");
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
iopgtable_clear_entry_all(oiommu);
|
iopgtable_clear_entry_all(oiommu);
|
||||||
|
@ -1108,8 +1108,16 @@ static void omap_iommu_detach_dev(struct iommu_domain *domain,
|
||||||
omap_iommu_detach(oiommu);
|
omap_iommu_detach(oiommu);
|
||||||
|
|
||||||
omap_domain->iommu_dev = arch_data->iommu_dev = NULL;
|
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);
|
spin_unlock(&omap_domain->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1148,13 +1156,19 @@ static int omap_iommu_domain_init(struct iommu_domain *domain)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assume device was already detached */
|
|
||||||
static void omap_iommu_domain_destroy(struct iommu_domain *domain)
|
static void omap_iommu_domain_destroy(struct iommu_domain *domain)
|
||||||
{
|
{
|
||||||
struct omap_iommu_domain *omap_domain = domain->priv;
|
struct omap_iommu_domain *omap_domain = domain->priv;
|
||||||
|
|
||||||
domain->priv = NULL;
|
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->pgtable);
|
||||||
kfree(omap_domain);
|
kfree(omap_domain);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue