summaryrefslogtreecommitdiff
path: root/drivers/iommu
diff options
context:
space:
mode:
authorRobin Murphy <robin.murphy@arm.com>2014-11-25 17:50:55 +0000
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:14:43 -0700
commit52d6bcee8dba7de673e5933dfa3114c15af0bd4a (patch)
tree053295404630dad96ece3f8ab3340f17cab93961 /drivers/iommu
parentc8c4b81806d122426c859c1d8a6c9e6d94ee7e25 (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>
Diffstat (limited to 'drivers/iommu')
-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 0ee7a15dcd33..dbda908fa95e 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1211,14 +1211,24 @@ size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
{
struct scatterlist *s;
size_t mapped = 0;
- unsigned int i;
+ unsigned int i, min_pagesz;
int ret;
- for_each_sg(sg, s, nents, i) {
- phys_addr_t phys = page_to_phys(sg_page(s));
+ if (unlikely(domain->ops->pgsize_bitmap == 0UL))
+ return 0;
- /* We are mapping on page boundarys, so offset must be 0 */
- if (s->offset)
+ min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap);
+
+ for_each_sg(sg, s, nents, i) {
+ phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;
+
+ /*
+ * We are mapping on IOMMU page boundaries, so offset within
+ * the page must be 0. However, the IOMMU may support pages
+ * smaller than PAGE_SIZE, so s->offset may still represent
+ * an offset of that boundary within the CPU page.
+ */
+ if (!IS_ALIGNED(s->offset, min_pagesz))
goto out_err;
ret = iommu_map(domain, iova + mapped, phys, s->length, prot);