diff options
author | 2018-09-06 20:30:54 -0400 | |
---|---|---|
committer | 2018-10-01 07:28:00 -0700 | |
commit | 7d21ee4c719f00896767ce19c4c01a56374c2ced (patch) | |
tree | 81ddf922c44d62db19a3048aa1fc0f2f1b2bdd76 /kernel/dma | |
parent | dma-direct: add an explicit dma_direct_get_required_mask (diff) | |
download | linux-7d21ee4c719f00896767ce19c4c01a56374c2ced.tar.gz linux-7d21ee4c719f00896767ce19c4c01a56374c2ced.tar.bz2 linux-7d21ee4c719f00896767ce19c4c01a56374c2ced.zip |
dma-direct: refine dma_direct_alloc zone selection
We need to take the DMA offset and encryption bit into account when
selecting a zone. User the opportunity to factor out the zone
selection into a helper for reuse.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Diffstat (limited to 'kernel/dma')
-rw-r--r-- | kernel/dma/direct.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index f32b33cfa331..e78548397a92 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -69,6 +69,22 @@ u64 dma_direct_get_required_mask(struct device *dev) return (1ULL << (fls64(max_dma) - 1)) * 2 - 1; } +static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask, + u64 *phys_mask) +{ + if (force_dma_unencrypted()) + *phys_mask = __dma_to_phys(dev, dma_mask); + else + *phys_mask = dma_to_phys(dev, dma_mask); + + /* GFP_DMA32 and GFP_DMA are no ops without the corresponding zones: */ + if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)) + return GFP_DMA; + if (*phys_mask <= DMA_BIT_MASK(32)) + return GFP_DMA32; + return 0; +} + static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size) { return phys_to_dma_direct(dev, phys) + size - 1 <= @@ -81,17 +97,13 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size, unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; int page_order = get_order(size); struct page *page = NULL; + u64 phys_mask; void *ret; /* we always manually zero the memory once we are done: */ gfp &= ~__GFP_ZERO; - - /* GFP_DMA32 and GFP_DMA are no ops without the corresponding zones: */ - if (dev->coherent_dma_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)) - gfp |= GFP_DMA; - if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA)) - gfp |= GFP_DMA32; - + gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, + &phys_mask); again: /* CMA can be used only in the context which permits sleeping */ if (gfpflags_allow_blocking(gfp)) { @@ -110,15 +122,14 @@ again: page = NULL; if (IS_ENABLED(CONFIG_ZONE_DMA32) && - dev->coherent_dma_mask < DMA_BIT_MASK(64) && + phys_mask < DMA_BIT_MASK(64) && !(gfp & (GFP_DMA32 | GFP_DMA))) { gfp |= GFP_DMA32; goto again; } if (IS_ENABLED(CONFIG_ZONE_DMA) && - dev->coherent_dma_mask < DMA_BIT_MASK(32) && - !(gfp & GFP_DMA)) { + phys_mask < DMA_BIT_MASK(32) && !(gfp & GFP_DMA)) { gfp = (gfp & ~GFP_DMA32) | GFP_DMA; goto again; } |