aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/omap-iommu.c
diff options
context:
space:
mode:
authorOmar Ramirez Luna <omar.luna@linaro.org>2012-04-18 14:09:41 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-04-19 09:07:23 -0400
commit803b5277215c75a5cc3b3eb5d19015c7290601a5 (patch)
treeffc0b3bf827fddac1482d0bc85848c2057160713 /drivers/iommu/omap-iommu.c
parent0034102808e0dbbf3a2394b82b1bb40b5778de9e (diff)
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>
Diffstat (limited to 'drivers/iommu/omap-iommu.c')
-rw-r--r--drivers/iommu/omap-iommu.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 6899dcd02dfa..e70ee2b59df9 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -41,11 +41,13 @@
41 * @pgtable: the page table 41 * @pgtable: the page table
42 * @iommu_dev: an omap iommu device attached to this domain. only a single 42 * @iommu_dev: an omap iommu device attached to this domain. only a single
43 * iommu device can be attached for now. 43 * iommu device can be attached for now.
44 * @dev: Device using this domain.
44 * @lock: domain lock, should be taken when attaching/detaching 45 * @lock: domain lock, should be taken when attaching/detaching
45 */ 46 */
46struct omap_iommu_domain { 47struct omap_iommu_domain {
47 u32 *pgtable; 48 u32 *pgtable;
48 struct omap_iommu *iommu_dev; 49 struct omap_iommu *iommu_dev;
50 struct device *dev;
49 spinlock_t lock; 51 spinlock_t lock;
50}; 52};
51 53
@@ -1081,6 +1083,7 @@ omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
1081 } 1083 }
1082 1084
1083 omap_domain->iommu_dev = arch_data->iommu_dev = oiommu; 1085 omap_domain->iommu_dev = arch_data->iommu_dev = oiommu;
1086 omap_domain->dev = dev;
1084 oiommu->domain = domain; 1087 oiommu->domain = domain;
1085 1088
1086out: 1089out:
@@ -1088,19 +1091,16 @@ out:
1088 return ret; 1091 return ret;
1089} 1092}
1090 1093
1091static void omap_iommu_detach_dev(struct iommu_domain *domain, 1094static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain,
1092 struct device *dev) 1095 struct device *dev)
1093{ 1096{
1094 struct omap_iommu_domain *omap_domain = domain->priv;
1095 struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
1096 struct omap_iommu *oiommu = dev_to_omap_iommu(dev); 1097 struct omap_iommu *oiommu = dev_to_omap_iommu(dev);
1097 1098 struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
1098 spin_lock(&omap_domain->lock);
1099 1099
1100 /* only a single device is supported per domain for now */ 1100 /* only a single device is supported per domain for now */
1101 if (omap_domain->iommu_dev != oiommu) { 1101 if (omap_domain->iommu_dev != oiommu) {
1102 dev_err(dev, "invalid iommu device\n"); 1102 dev_err(dev, "invalid iommu device\n");
1103 goto out; 1103 return;
1104 } 1104 }
1105 1105
1106 iopgtable_clear_entry_all(oiommu); 1106 iopgtable_clear_entry_all(oiommu);
@@ -1108,8 +1108,16 @@ static void omap_iommu_detach_dev(struct iommu_domain *domain,
1108 omap_iommu_detach(oiommu); 1108 omap_iommu_detach(oiommu);
1109 1109
1110 omap_domain->iommu_dev = arch_data->iommu_dev = NULL; 1110 omap_domain->iommu_dev = arch_data->iommu_dev = NULL;
1111 omap_domain->dev = NULL;
1112}
1111 1113
1112out: 1114static void omap_iommu_detach_dev(struct iommu_domain *domain,
1115 struct device *dev)
1116{
1117 struct omap_iommu_domain *omap_domain = domain->priv;
1118
1119 spin_lock(&omap_domain->lock);
1120 _omap_iommu_detach_dev(omap_domain, dev);
1113 spin_unlock(&omap_domain->lock); 1121 spin_unlock(&omap_domain->lock);
1114} 1122}
1115 1123
@@ -1148,13 +1156,19 @@ out:
1148 return -ENOMEM; 1156 return -ENOMEM;
1149} 1157}
1150 1158
1151/* assume device was already detached */
1152static void omap_iommu_domain_destroy(struct iommu_domain *domain) 1159static void omap_iommu_domain_destroy(struct iommu_domain *domain)
1153{ 1160{
1154 struct omap_iommu_domain *omap_domain = domain->priv; 1161 struct omap_iommu_domain *omap_domain = domain->priv;
1155 1162
1156 domain->priv = NULL; 1163 domain->priv = NULL;
1157 1164
1165 /*
1166 * An iommu device is still attached
1167 * (currently, only one device can be attached) ?
1168 */
1169 if (omap_domain->iommu_dev)
1170 _omap_iommu_detach_dev(omap_domain, omap_domain->dev);
1171
1158 kfree(omap_domain->pgtable); 1172 kfree(omap_domain->pgtable);
1159 kfree(omap_domain); 1173 kfree(omap_domain);
1160} 1174}