summaryrefslogtreecommitdiffstats
path: root/kernel/dma/pool.c
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2020-04-14 17:04:58 -0700
committerChristoph Hellwig <hch@lst.de>2020-04-25 13:17:05 +0200
commit76a19940bd62a81148c303f3df6d0cee9ae4b509 (patch)
tree71caddd9ff61acea7bb981c723e33575278431c4 /kernel/dma/pool.c
parent54adadf9b08571fb8b11dc9d0d3a2ddd39825efd (diff)
downloadlinux-76a19940bd62a81148c303f3df6d0cee9ae4b509.tar.gz
linux-76a19940bd62a81148c303f3df6d0cee9ae4b509.tar.bz2
linux-76a19940bd62a81148c303f3df6d0cee9ae4b509.zip
dma-direct: atomic allocations must come from atomic coherent pools
When a device requires unencrypted memory and the context does not allow blocking, memory must be returned from the atomic coherent pools. This avoids the remap when CONFIG_DMA_DIRECT_REMAP is not enabled and the config only requires CONFIG_DMA_COHERENT_POOL. This will be used for CONFIG_AMD_MEM_ENCRYPT in a subsequent patch. Keep all memory in these pools unencrypted. When set_memory_decrypted() fails, this prohibits the memory from being added. If adding memory to the genpool fails, and set_memory_encrypted() subsequently fails, there is no alternative other than leaking the memory. Signed-off-by: David Rientjes <rientjes@google.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'kernel/dma/pool.c')
-rw-r--r--kernel/dma/pool.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
index ffe866c2c034..c8d61b3a7bd6 100644
--- a/kernel/dma/pool.c
+++ b/kernel/dma/pool.c
@@ -8,6 +8,7 @@
#include <linux/dma-contiguous.h>
#include <linux/init.h>
#include <linux/genalloc.h>
+#include <linux/set_memory.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -53,22 +54,42 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
arch_dma_prep_coherent(page, pool_size);
+#ifdef CONFIG_DMA_DIRECT_REMAP
addr = dma_common_contiguous_remap(page, pool_size,
pgprot_dmacoherent(PAGE_KERNEL),
__builtin_return_address(0));
if (!addr)
goto free_page;
-
+#else
+ addr = page_to_virt(page);
+#endif
+ /*
+ * Memory in the atomic DMA pools must be unencrypted, the pools do not
+ * shrink so no re-encryption occurs in dma_direct_free_pages().
+ */
+ ret = set_memory_decrypted((unsigned long)page_to_virt(page),
+ 1 << order);
+ if (ret)
+ goto remove_mapping;
ret = gen_pool_add_virt(pool, (unsigned long)addr, page_to_phys(page),
pool_size, NUMA_NO_NODE);
if (ret)
- goto remove_mapping;
+ goto encrypt_mapping;
return 0;
+encrypt_mapping:
+ ret = set_memory_encrypted((unsigned long)page_to_virt(page),
+ 1 << order);
+ if (WARN_ON_ONCE(ret)) {
+ /* Decrypt succeeded but encrypt failed, purposely leak */
+ goto out;
+ }
remove_mapping:
+#ifdef CONFIG_DMA_DIRECT_REMAP
dma_common_free_remap(addr, pool_size);
-free_page:
+#endif
+free_page: __maybe_unused
if (!dma_release_from_contiguous(NULL, page, 1 << order))
__free_pages(page, order);
out: