diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index 18cd423fbc67..6bdd4f264733 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -45,6 +45,7 @@
#include <linux/dma-map-ops.h>
#include <linux/cma.h>
#include <linux/nospec.h>
+#include <linux/mem_encrypt.h>
#ifdef CONFIG_CMA_SIZE_MBYTES
#define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
@@ -419,6 +420,14 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp,
#ifdef CONFIG_DMA_NUMA_CMA
int nid = dev_to_node(dev);
#endif
+ /*
+ * CoCo shared allocations require CMA alignment large enough for the
+ * architecture's shared-buffer granule.
+ */
+ if (attrs & __DMA_ATTR_ALLOC_CC_SHARED) {
+ if (get_order(mem_cc_shared_granule_size()) > CONFIG_CMA_ALIGNMENT)
+ return NULL;
+ }
/* CMA can be used only in the context which permits sleeping */
if (!gfpflags_allow_blocking(gfp))diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index fe02e8a3c0bb..82d3ce39db0a 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -285,6 +285,9 @@ void *dma_direct_alloc(struct device *dev, size_t size,
return NULL;
}
+ if (mark_mem_decrypt)
+ size = mem_cc_align_to_shared_granule(size);
+
/* we always manually zero the memory once we are done */
page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO,
allow_highmem, attrs);
@@ -407,6 +410,9 @@ void dma_direct_free(struct device *dev, size_t size,
/* Swiotlb doesn't need a page attribute update on free */
mark_mem_encrypted = false;
+ if (mark_mem_encrypted && force_dma_unencrypted(dev))
+ size = mem_cc_align_to_shared_granule(size);
+
if (is_vmalloc_addr(cpu_addr)) {
vunmap(cpu_addr);
} else {@@ -453,6 +459,9 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
goto setup_page;
}
+ if (attrs & __DMA_ATTR_ALLOC_CC_SHARED)
+ size = mem_cc_align_to_shared_granule(size);
+
page = __dma_direct_alloc_pages(dev, size, gfp, false, attrs);
if (!page)
return NULL;
@@ -493,8 +502,11 @@ void dma_direct_free_pages(struct device *dev, size_t size,
if (swiotlb_pool)
mark_mem_encrypted = false;
- if (mark_mem_encrypted && dma_set_encrypted(dev, vaddr, size))
- return;
+ if (mark_mem_encrypted) {
+ size = mem_cc_align_to_shared_granule(size);
+ if (dma_set_encrypted(dev, vaddr, size))
+ return;
+ }
if (swiotlb_pool)
swiotlb_free_from_pool(dev, phys, swiotlb_pool);diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
index 00f422a1e896..fc4a834aaa14 100644
--- a/kernel/dma/pool.c
+++ b/kernel/dma/pool.c
@@ -91,7 +91,9 @@ static int atomic_pool_expand(struct dma_gen_pool *dma_pool, size_t pool_size,
void *addr;
int ret = -ENOMEM;
pgprot_t prot __maybe_unused;
+ unsigned int min_encrypt_order = get_order(mem_cc_shared_granule_size());
+ pool_size = mem_cc_align_to_shared_granule(pool_size);
/* Cannot allocate larger than MAX_PAGE_ORDER */
order = min(get_order(pool_size), MAX_PAGE_ORDER);
@@ -102,7 +104,7 @@ static int atomic_pool_expand(struct dma_gen_pool *dma_pool, size_t pool_size,
order, false);
if (!page)
page = alloc_pages(gfp | __GFP_NOWARN, order);
- } while (!page && order-- > 0);
+ } while (!page && order-- > min_encrypt_order);
if (!page)
goto out;
--
2.43.0