diff options
author | Joerg Roedel <jroedel@suse.de> | 2015-05-28 12:41:34 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2015-06-09 02:55:24 -0400 |
commit | beed2821b4f42c268222c4c1f1795e53340acf64 (patch) | |
tree | 58b594e5b1790a8fc33b4d2418abbe811c1c21f4 | |
parent | a1015c2b99b94cf521603b41debf167114031456 (diff) |
iommu: Create direct mappings in default domains
Use the information exported by the IOMMU drivers to create
direct mapped regions in the default domains.
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/iommu.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 6b8d6e7771e1..ffad1eaf450d 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) | |||
325 | } | 325 | } |
326 | EXPORT_SYMBOL_GPL(iommu_group_set_name); | 326 | EXPORT_SYMBOL_GPL(iommu_group_set_name); |
327 | 327 | ||
328 | static int iommu_group_create_direct_mappings(struct iommu_group *group, | ||
329 | struct device *dev) | ||
330 | { | ||
331 | struct iommu_domain *domain = group->default_domain; | ||
332 | struct iommu_dm_region *entry; | ||
333 | struct list_head mappings; | ||
334 | unsigned long pg_size; | ||
335 | int ret = 0; | ||
336 | |||
337 | if (!domain || domain->type != IOMMU_DOMAIN_DMA) | ||
338 | return 0; | ||
339 | |||
340 | BUG_ON(!domain->ops->pgsize_bitmap); | ||
341 | |||
342 | pg_size = 1UL << __ffs(domain->ops->pgsize_bitmap); | ||
343 | INIT_LIST_HEAD(&mappings); | ||
344 | |||
345 | iommu_get_dm_regions(dev, &mappings); | ||
346 | |||
347 | /* We need to consider overlapping regions for different devices */ | ||
348 | list_for_each_entry(entry, &mappings, list) { | ||
349 | dma_addr_t start, end, addr; | ||
350 | |||
351 | start = ALIGN(entry->start, pg_size); | ||
352 | end = ALIGN(entry->start + entry->length, pg_size); | ||
353 | |||
354 | for (addr = start; addr < end; addr += pg_size) { | ||
355 | phys_addr_t phys_addr; | ||
356 | |||
357 | phys_addr = iommu_iova_to_phys(domain, addr); | ||
358 | if (phys_addr) | ||
359 | continue; | ||
360 | |||
361 | ret = iommu_map(domain, addr, addr, pg_size, entry->prot); | ||
362 | if (ret) | ||
363 | goto out; | ||
364 | } | ||
365 | |||
366 | } | ||
367 | |||
368 | out: | ||
369 | iommu_put_dm_regions(dev, &mappings); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
328 | /** | 374 | /** |
329 | * iommu_group_add_device - add a device to an iommu group | 375 | * iommu_group_add_device - add a device to an iommu group |
330 | * @group: the group into which to add the device (reference should be held) | 376 | * @group: the group into which to add the device (reference should be held) |
@@ -381,6 +427,8 @@ rename: | |||
381 | 427 | ||
382 | dev->iommu_group = group; | 428 | dev->iommu_group = group; |
383 | 429 | ||
430 | iommu_group_create_direct_mappings(group, dev); | ||
431 | |||
384 | mutex_lock(&group->mutex); | 432 | mutex_lock(&group->mutex); |
385 | list_add_tail(&device->list, &group->devices); | 433 | list_add_tail(&device->list, &group->devices); |
386 | if (group->domain) | 434 | if (group->domain) |