aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Murphy <robin.murphy@arm.com>2014-11-25 12:50:55 -0500
committerJoerg Roedel <jroedel@suse.de>2014-12-02 07:05:04 -0500
commit18f23409909a9547ac7c149013286f36fcffa433 (patch)
tree898b6a507099ba1e47184462bacb9c7990f4ca51
parent0690cbd2e55a72a8eae557c389d1a136ed9fa142 (diff)
iommu: Decouple iommu_map_sg from CPU page size
If the IOMMU supports pages smaller than the CPU page size, segments which lie at offsets within the CPU page may be mapped based on the finer-grained IOMMU page boundaries. This minimises the amount of non-buffer memory between the CPU page boundary and the start of the segment which must be mapped and therefore exposed to the device, and brings the default iommu_map_sg implementation in line with iommu_map/unmap with respect to alignment. Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/iommu.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 02e4313e937c..1bd63352ab17 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1143,14 +1143,24 @@ size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
1143{ 1143{
1144 struct scatterlist *s; 1144 struct scatterlist *s;
1145 size_t mapped = 0; 1145 size_t mapped = 0;
1146 unsigned int i; 1146 unsigned int i, min_pagesz;
1147 int ret; 1147 int ret;
1148 1148
1149 for_each_sg(sg, s, nents, i) { 1149 if (unlikely(domain->ops->pgsize_bitmap == 0UL))
1150 phys_addr_t phys = page_to_phys(sg_page(s)); 1150 return 0;
1151 1151
1152 /* We are mapping on page boundarys, so offset must be 0 */ 1152 min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap);
1153 if (s->offset) 1153
1154 for_each_sg(sg, s, nents, i) {
1155 phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;
1156
1157 /*
1158 * We are mapping on IOMMU page boundaries, so offset within
1159 * the page must be 0. However, the IOMMU may support pages
1160 * smaller than PAGE_SIZE, so s->offset may still represent
1161 * an offset of that boundary within the CPU page.
1162 */
1163 if (!IS_ALIGNED(s->offset, min_pagesz))
1154 goto out_err; 1164 goto out_err;
1155 1165
1156 ret = iommu_map(domain, iova + mapped, phys, s->length, prot); 1166 ret = iommu_map(domain, iova + mapped, phys, s->length, prot);