[PATCH 11/22] iommu: Create direct mappings in default domains

From: Joerg Roedel
Date: Thu May 28 2015 - 12:43:26 EST


From: Joerg Roedel <jroedel@xxxxxxx>

Use the information exported by the IOMMU drivers to create
direct mapped regions in the default domains.

Signed-off-by: Joerg Roedel <jroedel@xxxxxxx>
---
drivers/iommu/iommu.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 6b8d6e7..ffad1ea 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -325,6 +325,52 @@ int iommu_group_set_name(struct iommu_group *group, const char *name)
}
EXPORT_SYMBOL_GPL(iommu_group_set_name);

+static int iommu_group_create_direct_mappings(struct iommu_group *group,
+ struct device *dev)
+{
+ struct iommu_domain *domain = group->default_domain;
+ struct iommu_dm_region *entry;
+ struct list_head mappings;
+ unsigned long pg_size;
+ int ret = 0;
+
+ if (!domain || domain->type != IOMMU_DOMAIN_DMA)
+ return 0;
+
+ BUG_ON(!domain->ops->pgsize_bitmap);
+
+ pg_size = 1UL << __ffs(domain->ops->pgsize_bitmap);
+ INIT_LIST_HEAD(&mappings);
+
+ iommu_get_dm_regions(dev, &mappings);
+
+ /* We need to consider overlapping regions for different devices */
+ list_for_each_entry(entry, &mappings, list) {
+ dma_addr_t start, end, addr;
+
+ start = ALIGN(entry->start, pg_size);
+ end = ALIGN(entry->start + entry->length, pg_size);
+
+ for (addr = start; addr < end; addr += pg_size) {
+ phys_addr_t phys_addr;
+
+ phys_addr = iommu_iova_to_phys(domain, addr);
+ if (phys_addr)
+ continue;
+
+ ret = iommu_map(domain, addr, addr, pg_size, entry->prot);
+ if (ret)
+ goto out;
+ }
+
+ }
+
+out:
+ iommu_put_dm_regions(dev, &mappings);
+
+ return ret;
+}
+
/**
* iommu_group_add_device - add a device to an iommu group
* @group: the group into which to add the device (reference should be held)
@@ -381,6 +427,8 @@ rename:

dev->iommu_group = group;

+ iommu_group_create_direct_mappings(group, dev);
+
mutex_lock(&group->mutex);
list_add_tail(&device->list, &group->devices);
if (group->domain)
--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/