Skip to content

Commit c7f5d2e

Browse files
detulepopcornmix
authored andcommitted
vchiq_2835_arm: Implement a DMA pool for small bulk transfers (#2699)
During a bulk transfer we request a DMA allocation to hold the scatter-gather list. Most of the time, this allocation is small (<< PAGE_SIZE), however it can be requested at a high enough frequency to cause fragmentation and/or stress the CMA allocator (think time spent in compaction here, or during allocations elsewhere). Implement a pool to serve up small DMA allocations, falling back to a coherent allocation if the request is greater than VCHIQ_DMA_POOL_SIZE. Signed-off-by: Oliver Gjoneski <[email protected]>
1 parent 8847888 commit c7f5d2e

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/interrupt.h>
88
#include <linux/pagemap.h>
99
#include <linux/dma-mapping.h>
10+
#include <linux/dmapool.h>
1011
#include <linux/io.h>
1112
#include <linux/platform_device.h>
1213
#include <linux/uaccess.h>
@@ -29,6 +30,8 @@
2930
#define BELL0 0x00
3031
#define BELL2 0x08
3132

33+
#define VCHIQ_DMA_POOL_SIZE PAGE_SIZE
34+
3235
struct vchiq_2835_state {
3336
int inited;
3437
struct vchiq_arm_state arm_state;
@@ -38,6 +41,7 @@ struct vchiq_pagelist_info {
3841
struct pagelist *pagelist;
3942
size_t pagelist_buffer_size;
4043
dma_addr_t dma_addr;
44+
bool is_from_pool;
4145
enum dma_data_direction dma_dir;
4246
unsigned int num_pages;
4347
unsigned int pages_need_release;
@@ -58,6 +62,7 @@ static void __iomem *g_regs;
5862
* of 32.
5963
*/
6064
static unsigned int g_cache_line_size = 32;
65+
static struct dma_pool *g_dma_pool;
6166
static unsigned int g_use_36bit_addrs = 0;
6267
static unsigned int g_fragments_size;
6368
static char *g_fragments_base;
@@ -182,6 +187,13 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
182187

183188
g_dev = dev;
184189
g_dma_dev = dma_dev ?: dev;
190+
g_dma_pool = dmam_pool_create("vchiq_scatter_pool", dev,
191+
VCHIQ_DMA_POOL_SIZE, g_cache_line_size,
192+
0);
193+
if (!g_dma_pool) {
194+
dev_err(dev, "failed to create dma pool");
195+
return -ENOMEM;
196+
}
185197

186198
vchiq_log_info(vchiq_arm_log_level,
187199
"vchiq_init - done (slots %pK, phys %pad)",
@@ -314,8 +326,14 @@ cleanup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo)
314326
if (pagelistinfo->pages_need_release)
315327
unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages);
316328

317-
dma_free_coherent(g_dev, pagelistinfo->pagelist_buffer_size,
318-
pagelistinfo->pagelist, pagelistinfo->dma_addr);
329+
if (pagelistinfo->is_from_pool) {
330+
dma_pool_free(g_dma_pool, pagelistinfo->pagelist,
331+
pagelistinfo->dma_addr);
332+
} else {
333+
dma_free_coherent(g_dev, pagelistinfo->pagelist_buffer_size,
334+
pagelistinfo->pagelist,
335+
pagelistinfo->dma_addr);
336+
}
319337
}
320338

321339
/* There is a potential problem with partial cache lines (pages?)
@@ -336,6 +354,7 @@ create_pagelist(char *buf, char __user *ubuf,
336354
u32 *addrs;
337355
unsigned int num_pages, offset, i, k;
338356
int actual_pages;
357+
bool is_from_pool;
339358
size_t pagelist_size;
340359
struct scatterlist *scatterlist, *sg;
341360
int dma_buffers;
@@ -365,8 +384,16 @@ create_pagelist(char *buf, char __user *ubuf,
365384
/* Allocate enough storage to hold the page pointers and the page
366385
* list
367386
*/
368-
pagelist = dma_alloc_coherent(g_dev, pagelist_size, &dma_addr,
369-
GFP_KERNEL);
387+
if (pagelist_size > VCHIQ_DMA_POOL_SIZE) {
388+
pagelist = dma_alloc_coherent(g_dev,
389+
pagelist_size,
390+
&dma_addr,
391+
GFP_KERNEL);
392+
is_from_pool = false;
393+
} else {
394+
pagelist = dma_pool_alloc(g_dma_pool, GFP_KERNEL, &dma_addr);
395+
is_from_pool = true;
396+
}
370397

371398
vchiq_log_trace(vchiq_arm_log_level, "%s - %pK", __func__, pagelist);
372399

@@ -387,6 +414,7 @@ create_pagelist(char *buf, char __user *ubuf,
387414
pagelistinfo->pagelist = pagelist;
388415
pagelistinfo->pagelist_buffer_size = pagelist_size;
389416
pagelistinfo->dma_addr = dma_addr;
417+
pagelistinfo->is_from_pool = is_from_pool;
390418
pagelistinfo->dma_dir = (type == PAGELIST_WRITE) ?
391419
DMA_TO_DEVICE : DMA_FROM_DEVICE;
392420
pagelistinfo->num_pages = num_pages;

0 commit comments

Comments
 (0)