Skip to content

Commit 81e9d89

Browse files
Nicolas Saenz JulienneChristoph Hellwig
authored andcommitted
dma-pool: make sure atomic pool suits device
When allocating DMA memory from a pool, the core can only guess which atomic pool will fit a device's constraints. If it doesn't, get a safer atomic pool and try again. Fixes: c84dc6e ("dma-pool: add additional coherent pools to map to gfp mask") Reported-by: Jeremy Linton <[email protected]> Suggested-by: Robin Murphy <[email protected]> Signed-off-by: Nicolas Saenz Julienne <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 48b6703 commit 81e9d89

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

kernel/dma/pool.c

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -240,39 +240,56 @@ static inline struct gen_pool *dma_guess_pool(struct device *dev,
240240
void *dma_alloc_from_pool(struct device *dev, size_t size,
241241
struct page **ret_page, gfp_t flags)
242242
{
243-
struct gen_pool *pool = dma_guess_pool(dev, NULL);
244-
unsigned long val;
243+
struct gen_pool *pool = NULL;
244+
unsigned long val = 0;
245245
void *ptr = NULL;
246-
247-
if (!pool) {
248-
WARN(1, "%pGg atomic pool not initialised!\n", &flags);
249-
return NULL;
246+
phys_addr_t phys;
247+
248+
while (1) {
249+
pool = dma_guess_pool(dev, pool);
250+
if (!pool) {
251+
WARN(1, "Failed to get suitable pool for %s\n",
252+
dev_name(dev));
253+
break;
254+
}
255+
256+
val = gen_pool_alloc(pool, size);
257+
if (!val)
258+
continue;
259+
260+
phys = gen_pool_virt_to_phys(pool, val);
261+
if (dma_coherent_ok(dev, phys, size))
262+
break;
263+
264+
gen_pool_free(pool, val, size);
265+
val = 0;
250266
}
251267

252-
val = gen_pool_alloc(pool, size);
253-
if (likely(val)) {
254-
phys_addr_t phys = gen_pool_virt_to_phys(pool, val);
255268

269+
if (val) {
256270
*ret_page = pfn_to_page(__phys_to_pfn(phys));
257271
ptr = (void *)val;
258272
memset(ptr, 0, size);
259-
} else {
260-
WARN_ONCE(1, "DMA coherent pool depleted, increase size "
261-
"(recommended min coherent_pool=%zuK)\n",
262-
gen_pool_size(pool) >> 9);
273+
274+
if (gen_pool_avail(pool) < atomic_pool_size)
275+
schedule_work(&atomic_pool_work);
263276
}
264-
if (gen_pool_avail(pool) < atomic_pool_size)
265-
schedule_work(&atomic_pool_work);
266277

267278
return ptr;
268279
}
269280

270281
bool dma_free_from_pool(struct device *dev, void *start, size_t size)
271282
{
272-
struct gen_pool *pool = dma_guess_pool(dev, NULL);
283+
struct gen_pool *pool = NULL;
273284

274-
if (!pool || !gen_pool_has_addr(pool, (unsigned long)start, size))
275-
return false;
276-
gen_pool_free(pool, (unsigned long)start, size);
277-
return true;
285+
while (1) {
286+
pool = dma_guess_pool(dev, pool);
287+
if (!pool)
288+
return false;
289+
290+
if (gen_pool_has_addr(pool, (unsigned long)start, size)) {
291+
gen_pool_free(pool, (unsigned long)start, size);
292+
return true;
293+
}
294+
}
278295
}

0 commit comments

Comments
 (0)