diff options
author | Robin Murphy <robin.murphy@arm.com> | 2017-01-16 08:24:55 -0500 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2017-01-30 10:14:24 -0500 |
commit | 122fac030e912ed723fe94d8eb0d5d0f6b31535e (patch) | |
tree | ddfdbf1d6725f348ece0fffe7dc839077c32cc5a | |
parent | f51d7bb79c1124f7f02e9f472ef935eba13bca8e (diff) |
iommu/dma: Implement PCI allocation optimisation
Whilst PCI devices may have 64-bit DMA masks, they still benefit from
using 32-bit addresses wherever possible in order to avoid DAC (PCI) or
longer address packets (PCIe), which may incur a performance overhead.
Implement the same optimisation as other allocators by trying to get a
32-bit address first, only falling back to the full mask if that fails.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/dma-iommu.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 6c6e70c56d88..1c9ac26e3b68 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c | |||
@@ -287,19 +287,28 @@ int dma_info_to_prot(enum dma_data_direction dir, bool coherent, | |||
287 | } | 287 | } |
288 | 288 | ||
289 | static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, | 289 | static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, |
290 | dma_addr_t dma_limit) | 290 | dma_addr_t dma_limit, struct device *dev) |
291 | { | 291 | { |
292 | struct iova_domain *iovad = cookie_iovad(domain); | 292 | struct iova_domain *iovad = cookie_iovad(domain); |
293 | unsigned long shift = iova_shift(iovad); | 293 | unsigned long shift = iova_shift(iovad); |
294 | unsigned long length = iova_align(iovad, size) >> shift; | 294 | unsigned long length = iova_align(iovad, size) >> shift; |
295 | struct iova *iova = NULL; | ||
295 | 296 | ||
296 | if (domain->geometry.force_aperture) | 297 | if (domain->geometry.force_aperture) |
297 | dma_limit = min(dma_limit, domain->geometry.aperture_end); | 298 | dma_limit = min(dma_limit, domain->geometry.aperture_end); |
299 | |||
300 | /* Try to get PCI devices a SAC address */ | ||
301 | if (dma_limit > DMA_BIT_MASK(32) && dev_is_pci(dev)) | ||
302 | iova = alloc_iova(iovad, length, DMA_BIT_MASK(32) >> shift, | ||
303 | true); | ||
298 | /* | 304 | /* |
299 | * Enforce size-alignment to be safe - there could perhaps be an | 305 | * Enforce size-alignment to be safe - there could perhaps be an |
300 | * attribute to control this per-device, or at least per-domain... | 306 | * attribute to control this per-device, or at least per-domain... |
301 | */ | 307 | */ |
302 | return alloc_iova(iovad, length, dma_limit >> shift, true); | 308 | if (!iova) |
309 | iova = alloc_iova(iovad, length, dma_limit >> shift, true); | ||
310 | |||
311 | return iova; | ||
303 | } | 312 | } |
304 | 313 | ||
305 | /* The IOVA allocator knows what we mapped, so just unmap whatever that was */ | 314 | /* The IOVA allocator knows what we mapped, so just unmap whatever that was */ |
@@ -452,7 +461,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, | |||
452 | if (!pages) | 461 | if (!pages) |
453 | return NULL; | 462 | return NULL; |
454 | 463 | ||
455 | iova = __alloc_iova(domain, size, dev->coherent_dma_mask); | 464 | iova = __alloc_iova(domain, size, dev->coherent_dma_mask, dev); |
456 | if (!iova) | 465 | if (!iova) |
457 | goto out_free_pages; | 466 | goto out_free_pages; |
458 | 467 | ||
@@ -523,7 +532,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, | |||
523 | struct iova_domain *iovad = cookie_iovad(domain); | 532 | struct iova_domain *iovad = cookie_iovad(domain); |
524 | size_t iova_off = iova_offset(iovad, phys); | 533 | size_t iova_off = iova_offset(iovad, phys); |
525 | size_t len = iova_align(iovad, size + iova_off); | 534 | size_t len = iova_align(iovad, size + iova_off); |
526 | struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev)); | 535 | struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev), dev); |
527 | 536 | ||
528 | if (!iova) | 537 | if (!iova) |
529 | return DMA_ERROR_CODE; | 538 | return DMA_ERROR_CODE; |
@@ -681,7 +690,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, | |||
681 | prev = s; | 690 | prev = s; |
682 | } | 691 | } |
683 | 692 | ||
684 | iova = __alloc_iova(domain, iova_len, dma_get_mask(dev)); | 693 | iova = __alloc_iova(domain, iova_len, dma_get_mask(dev), dev); |
685 | if (!iova) | 694 | if (!iova) |
686 | goto out_restore_sg; | 695 | goto out_restore_sg; |
687 | 696 | ||
@@ -761,7 +770,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, | |||
761 | 770 | ||
762 | msi_page->phys = msi_addr; | 771 | msi_page->phys = msi_addr; |
763 | if (iovad) { | 772 | if (iovad) { |
764 | iova = __alloc_iova(domain, size, dma_get_mask(dev)); | 773 | iova = __alloc_iova(domain, size, dma_get_mask(dev), dev); |
765 | if (!iova) | 774 | if (!iova) |
766 | goto out_free_page; | 775 | goto out_free_page; |
767 | msi_page->iova = iova_dma_addr(iovad, iova); | 776 | msi_page->iova = iova_dma_addr(iovad, iova); |