Skip to content

Commit d7e673e

Browse files
Nicolas Saenz JulienneChristoph Hellwig
authored andcommitted
dma-pool: Only allocate from CMA when in same memory zone
There is no guarantee to CMA's placement, so allocating a zone specific atomic pool from CMA might return memory from a completely different memory zone. To get around this double check CMA's placement before allocating from it. Signed-off-by: Nicolas Saenz Julienne <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 9420139 commit d7e673e

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

kernel/dma/pool.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
* Copyright (C) 2012 ARM Ltd.
44
* Copyright (C) 2020 Google LLC
55
*/
6+
#include <linux/cma.h>
67
#include <linux/debugfs.h>
8+
#include <linux/dma-contiguous.h>
79
#include <linux/dma-direct.h>
810
#include <linux/dma-noncoherent.h>
911
#include <linux/init.h>
@@ -55,6 +57,29 @@ static void dma_atomic_pool_size_add(gfp_t gfp, size_t size)
5557
pool_size_kernel += size;
5658
}
5759

60+
static bool cma_in_zone(gfp_t gfp)
61+
{
62+
unsigned long size;
63+
phys_addr_t end;
64+
struct cma *cma;
65+
66+
cma = dev_get_cma_area(NULL);
67+
if (!cma)
68+
return false;
69+
70+
size = cma_get_size(cma);
71+
if (!size)
72+
return false;
73+
74+
/* CMA can't cross zone boundaries, see cma_activate_area() */
75+
end = cma_get_base(cma) + size - 1;
76+
if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
77+
return end <= DMA_BIT_MASK(zone_dma_bits);
78+
if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
79+
return end <= DMA_BIT_MASK(32);
80+
return true;
81+
}
82+
5883
static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
5984
gfp_t gfp)
6085
{
@@ -68,7 +93,11 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
6893

6994
do {
7095
pool_size = 1 << (PAGE_SHIFT + order);
71-
page = alloc_pages(gfp, order);
96+
if (cma_in_zone(gfp))
97+
page = dma_alloc_from_contiguous(NULL, 1 << order,
98+
order, false);
99+
if (!page)
100+
page = alloc_pages(gfp, order);
72101
} while (!page && order-- > 0);
73102
if (!page)
74103
goto out;

0 commit comments

Comments
 (0)