Skip to content

Commit 9420139

Browse files
author
Christoph Hellwig
committed
dma-pool: fix coherent pool allocations for IOMMU mappings
When allocating coherent pool memory for an IOMMU mapping we don't care about the DMA mask. Move the guess for the initial GFP mask into the dma_direct_alloc_pages and pass dma_coherent_ok as a function pointer argument so that it doesn't get applied to the IOMMU case. Signed-off-by: Christoph Hellwig <[email protected]> Tested-by: Amit Pundir <[email protected]>
1 parent a1d2108 commit 9420139

File tree

5 files changed

+62
-77
lines changed

5 files changed

+62
-77
lines changed

drivers/iommu/dma-iommu.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,8 +1035,8 @@ static void *iommu_dma_alloc(struct device *dev, size_t size,
10351035

10361036
if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
10371037
!gfpflags_allow_blocking(gfp) && !coherent)
1038-
cpu_addr = dma_alloc_from_pool(dev, PAGE_ALIGN(size), &page,
1039-
gfp);
1038+
page = dma_alloc_from_pool(dev, PAGE_ALIGN(size), &cpu_addr,
1039+
gfp, NULL);
10401040
else
10411041
cpu_addr = iommu_dma_alloc_pages(dev, size, &page, gfp, attrs);
10421042
if (!cpu_addr)

include/linux/dma-direct.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size,
7373
}
7474

7575
u64 dma_direct_get_required_mask(struct device *dev);
76-
gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
77-
u64 *phys_mask);
78-
bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size);
7976
void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
8077
gfp_t gfp, unsigned long attrs);
8178
void dma_direct_free(struct device *dev, size_t size, void *cpu_addr,

include/linux/dma-mapping.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,9 @@ void *dma_common_pages_remap(struct page **pages, size_t size,
522522
pgprot_t prot, const void *caller);
523523
void dma_common_free_remap(void *cpu_addr, size_t size);
524524

525-
void *dma_alloc_from_pool(struct device *dev, size_t size,
526-
struct page **ret_page, gfp_t flags);
525+
struct page *dma_alloc_from_pool(struct device *dev, size_t size,
526+
void **cpu_addr, gfp_t flags,
527+
bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t));
527528
bool dma_free_from_pool(struct device *dev, void *start, size_t size);
528529

529530
int

kernel/dma/direct.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ u64 dma_direct_get_required_mask(struct device *dev)
4343
return (1ULL << (fls64(max_dma) - 1)) * 2 - 1;
4444
}
4545

46-
gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
46+
static gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
4747
u64 *phys_limit)
4848
{
4949
u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit);
@@ -68,7 +68,7 @@ gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
6868
return 0;
6969
}
7070

71-
bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
71+
static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
7272
{
7373
return phys_to_dma_direct(dev, phys) + size - 1 <=
7474
min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit);
@@ -161,8 +161,13 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
161161
size = PAGE_ALIGN(size);
162162

163163
if (dma_should_alloc_from_pool(dev, gfp, attrs)) {
164-
ret = dma_alloc_from_pool(dev, size, &page, gfp);
165-
if (!ret)
164+
u64 phys_mask;
165+
166+
gfp |= dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
167+
&phys_mask);
168+
page = dma_alloc_from_pool(dev, size, &ret, gfp,
169+
dma_coherent_ok);
170+
if (!page)
166171
return NULL;
167172
goto done;
168173
}

kernel/dma/pool.c

Lines changed: 48 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -196,93 +196,75 @@ static int __init dma_atomic_pool_init(void)
196196
}
197197
postcore_initcall(dma_atomic_pool_init);
198198

199-
static inline struct gen_pool *dma_guess_pool_from_device(struct device *dev)
199+
static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp)
200200
{
201-
u64 phys_mask;
202-
gfp_t gfp;
203-
204-
gfp = dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
205-
&phys_mask);
206-
if (IS_ENABLED(CONFIG_ZONE_DMA) && gfp == GFP_DMA)
201+
if (prev == NULL) {
202+
if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
203+
return atomic_pool_dma32;
204+
if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
205+
return atomic_pool_dma;
206+
return atomic_pool_kernel;
207+
}
208+
if (prev == atomic_pool_kernel)
209+
return atomic_pool_dma32 ? atomic_pool_dma32 : atomic_pool_dma;
210+
if (prev == atomic_pool_dma32)
207211
return atomic_pool_dma;
208-
if (IS_ENABLED(CONFIG_ZONE_DMA32) && gfp == GFP_DMA32)
209-
return atomic_pool_dma32;
210-
return atomic_pool_kernel;
212+
return NULL;
211213
}
212214

213-
static inline struct gen_pool *dma_get_safer_pool(struct gen_pool *bad_pool)
215+
static struct page *__dma_alloc_from_pool(struct device *dev, size_t size,
216+
struct gen_pool *pool, void **cpu_addr,
217+
bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
214218
{
215-
if (bad_pool == atomic_pool_kernel)
216-
return atomic_pool_dma32 ? : atomic_pool_dma;
219+
unsigned long addr;
220+
phys_addr_t phys;
217221

218-
if (bad_pool == atomic_pool_dma32)
219-
return atomic_pool_dma;
222+
addr = gen_pool_alloc(pool, size);
223+
if (!addr)
224+
return NULL;
220225

221-
return NULL;
222-
}
226+
phys = gen_pool_virt_to_phys(pool, addr);
227+
if (phys_addr_ok && !phys_addr_ok(dev, phys, size)) {
228+
gen_pool_free(pool, addr, size);
229+
return NULL;
230+
}
223231

224-
static inline struct gen_pool *dma_guess_pool(struct device *dev,
225-
struct gen_pool *bad_pool)
226-
{
227-
if (bad_pool)
228-
return dma_get_safer_pool(bad_pool);
232+
if (gen_pool_avail(pool) < atomic_pool_size)
233+
schedule_work(&atomic_pool_work);
229234

230-
return dma_guess_pool_from_device(dev);
235+
*cpu_addr = (void *)addr;
236+
memset(*cpu_addr, 0, size);
237+
return pfn_to_page(__phys_to_pfn(phys));
231238
}
232239

233-
void *dma_alloc_from_pool(struct device *dev, size_t size,
234-
struct page **ret_page, gfp_t flags)
240+
struct page *dma_alloc_from_pool(struct device *dev, size_t size,
241+
void **cpu_addr, gfp_t gfp,
242+
bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
235243
{
236244
struct gen_pool *pool = NULL;
237-
unsigned long val = 0;
238-
void *ptr = NULL;
239-
phys_addr_t phys;
240-
241-
while (1) {
242-
pool = dma_guess_pool(dev, pool);
243-
if (!pool) {
244-
WARN(1, "Failed to get suitable pool for %s\n",
245-
dev_name(dev));
246-
break;
247-
}
248-
249-
val = gen_pool_alloc(pool, size);
250-
if (!val)
251-
continue;
252-
253-
phys = gen_pool_virt_to_phys(pool, val);
254-
if (dma_coherent_ok(dev, phys, size))
255-
break;
256-
257-
gen_pool_free(pool, val, size);
258-
val = 0;
259-
}
260-
261-
262-
if (val) {
263-
*ret_page = pfn_to_page(__phys_to_pfn(phys));
264-
ptr = (void *)val;
265-
memset(ptr, 0, size);
245+
struct page *page;
266246

267-
if (gen_pool_avail(pool) < atomic_pool_size)
268-
schedule_work(&atomic_pool_work);
247+
while ((pool = dma_guess_pool(pool, gfp))) {
248+
page = __dma_alloc_from_pool(dev, size, pool, cpu_addr,
249+
phys_addr_ok);
250+
if (page)
251+
return page;
269252
}
270253

271-
return ptr;
254+
WARN(1, "Failed to get suitable pool for %s\n", dev_name(dev));
255+
return NULL;
272256
}
273257

274258
bool dma_free_from_pool(struct device *dev, void *start, size_t size)
275259
{
276260
struct gen_pool *pool = NULL;
277261

278-
while (1) {
279-
pool = dma_guess_pool(dev, pool);
280-
if (!pool)
281-
return false;
282-
283-
if (gen_pool_has_addr(pool, (unsigned long)start, size)) {
284-
gen_pool_free(pool, (unsigned long)start, size);
285-
return true;
286-
}
262+
while ((pool = dma_guess_pool(pool, 0))) {
263+
if (!gen_pool_has_addr(pool, (unsigned long)start, size))
264+
continue;
265+
gen_pool_free(pool, (unsigned long)start, size);
266+
return true;
287267
}
268+
269+
return false;
288270
}

0 commit comments

Comments
 (0)