aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2014-11-04 08:53:51 -0500
committerJoerg Roedel <jroedel@suse.de>2014-11-04 08:53:51 -0500
commit38ec010d9b04ed94845f8ff6f10d33eb6bbfe180 (patch)
tree7e54787fbc0961a02707f38e5b39bfa2f22605c4
parent315786ebbf4ad6552b6fd8e0e7b2ea220fcbfdbd (diff)
iommu: Do more input validation in iommu_map_sg()
The IOMMU-API works on page boundarys, unlike the DMA-API which can work with sub-page buffers. The sg->offset field does not make sense on the IOMMU level, so force it to be 0. Do some error-path consolidation while at it. Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/iommu.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 46727ce9280d..08c53c5a046f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1127,26 +1127,33 @@ EXPORT_SYMBOL_GPL(iommu_unmap);
1127size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova, 1127size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
1128 struct scatterlist *sg, unsigned int nents, int prot) 1128 struct scatterlist *sg, unsigned int nents, int prot)
1129{ 1129{
1130 int ret; 1130 struct scatterlist *s;
1131 size_t mapped = 0; 1131 size_t mapped = 0;
1132 unsigned int i; 1132 unsigned int i;
1133 struct scatterlist *s; 1133 int ret;
1134 1134
1135 for_each_sg(sg, s, nents, i) { 1135 for_each_sg(sg, s, nents, i) {
1136 phys_addr_t phys = page_to_phys(sg_page(s)); 1136 phys_addr_t phys = page_to_phys(sg_page(s));
1137 size_t page_len = s->offset + s->length;
1138 1137
1139 ret = iommu_map(domain, iova + mapped, phys, page_len, prot); 1138 /* We are mapping on page boundarys, so offset must be 0 */
1140 if (ret) { 1139 if (s->offset)
1141 /* undo mappings already done */ 1140 goto out_err;
1142 iommu_unmap(domain, iova, mapped); 1141
1143 mapped = 0; 1142 ret = iommu_map(domain, iova + mapped, phys, s->length, prot);
1144 break; 1143 if (ret)
1145 } 1144 goto out_err;
1146 mapped += page_len; 1145
1146 mapped += s->length;
1147 } 1147 }
1148 1148
1149 return mapped; 1149 return mapped;
1150
1151out_err:
1152 /* undo mappings already done */
1153 iommu_unmap(domain, iova, mapped);
1154
1155 return 0;
1156
1150} 1157}
1151EXPORT_SYMBOL_GPL(default_iommu_map_sg); 1158EXPORT_SYMBOL_GPL(default_iommu_map_sg);
1152 1159