mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
dma-mapping: benchmark: modify the framework to adapt to more map modes
This patch adjusts the DMA map benchmark framework to make the DMA map benchmark framework more flexible and adaptable to other mapping modes in the future. By abstracting the framework into five interfaces: prepare, unprepare, initialize_data, do_map, and do_unmap. The new map schema can be introduced more easily without major modifications to the existing code structure. Reviewed-by: Barry Song <baohua@kernel.org> Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Link: https://lore.kernel.org/r/20260225093800.3625054-2-xiaqinxin@huawei.com
This commit is contained in:
committed by
Marek Szyprowski
parent
6de23f81a5
commit
9cc60ec453
@@ -5,6 +5,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
@@ -31,17 +32,105 @@ struct map_benchmark_data {
|
||||
atomic64_t loops;
|
||||
};
|
||||
|
||||
struct map_benchmark_ops {
|
||||
void *(*prepare)(struct map_benchmark_data *map);
|
||||
void (*unprepare)(void *mparam);
|
||||
void (*initialize_data)(void *mparam);
|
||||
int (*do_map)(void *mparam);
|
||||
void (*do_unmap)(void *mparam);
|
||||
};
|
||||
|
||||
struct dma_single_map_param {
|
||||
struct device *dev;
|
||||
dma_addr_t addr;
|
||||
void *xbuf;
|
||||
u32 npages;
|
||||
u32 dma_dir;
|
||||
};
|
||||
|
||||
static void *dma_single_map_benchmark_prepare(struct map_benchmark_data *map)
|
||||
{
|
||||
struct dma_single_map_param *params __free(kfree) = kzalloc(sizeof(*params),
|
||||
GFP_KERNEL);
|
||||
if (!params)
|
||||
return NULL;
|
||||
|
||||
params->npages = map->bparam.granule;
|
||||
params->dma_dir = map->bparam.dma_dir;
|
||||
params->dev = map->dev;
|
||||
params->xbuf = alloc_pages_exact(params->npages * PAGE_SIZE, GFP_KERNEL);
|
||||
if (!params->xbuf)
|
||||
return NULL;
|
||||
|
||||
return_ptr(params);
|
||||
}
|
||||
|
||||
static void dma_single_map_benchmark_unprepare(void *mparam)
|
||||
{
|
||||
struct dma_single_map_param *params = mparam;
|
||||
|
||||
free_pages_exact(params->xbuf, params->npages * PAGE_SIZE);
|
||||
kfree(params);
|
||||
}
|
||||
|
||||
static void dma_single_map_benchmark_initialize_data(void *mparam)
|
||||
{
|
||||
struct dma_single_map_param *params = mparam;
|
||||
|
||||
/*
|
||||
* for a non-coherent device, if we don't stain them in the
|
||||
* cache, this will give an underestimate of the real-world
|
||||
* overhead of BIDIRECTIONAL or TO_DEVICE mappings;
|
||||
* 66 means everything goes well! 66 is lucky.
|
||||
*/
|
||||
if (params->dma_dir != DMA_FROM_DEVICE)
|
||||
memset(params->xbuf, 0x66, params->npages * PAGE_SIZE);
|
||||
}
|
||||
|
||||
static int dma_single_map_benchmark_do_map(void *mparam)
|
||||
{
|
||||
struct dma_single_map_param *params = mparam;
|
||||
|
||||
params->addr = dma_map_single(params->dev, params->xbuf,
|
||||
params->npages * PAGE_SIZE, params->dma_dir);
|
||||
if (unlikely(dma_mapping_error(params->dev, params->addr))) {
|
||||
pr_err("dma_map_single failed on %s\n", dev_name(params->dev));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dma_single_map_benchmark_do_unmap(void *mparam)
|
||||
{
|
||||
struct dma_single_map_param *params = mparam;
|
||||
|
||||
dma_unmap_single(params->dev, params->addr,
|
||||
params->npages * PAGE_SIZE, params->dma_dir);
|
||||
}
|
||||
|
||||
static struct map_benchmark_ops dma_single_map_benchmark_ops = {
|
||||
.prepare = dma_single_map_benchmark_prepare,
|
||||
.unprepare = dma_single_map_benchmark_unprepare,
|
||||
.initialize_data = dma_single_map_benchmark_initialize_data,
|
||||
.do_map = dma_single_map_benchmark_do_map,
|
||||
.do_unmap = dma_single_map_benchmark_do_unmap,
|
||||
};
|
||||
|
||||
static struct map_benchmark_ops *dma_map_benchmark_ops[DMA_MAP_BENCH_MODE_MAX] = {
|
||||
[DMA_MAP_BENCH_SINGLE_MODE] = &dma_single_map_benchmark_ops,
|
||||
};
|
||||
|
||||
static int map_benchmark_thread(void *data)
|
||||
{
|
||||
void *buf;
|
||||
dma_addr_t dma_addr;
|
||||
struct map_benchmark_data *map = data;
|
||||
int npages = map->bparam.granule;
|
||||
u64 size = npages * PAGE_SIZE;
|
||||
__u8 map_mode = map->bparam.map_mode;
|
||||
int ret = 0;
|
||||
|
||||
buf = alloc_pages_exact(size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
struct map_benchmark_ops *mb_ops = dma_map_benchmark_ops[map_mode];
|
||||
void *mparam = mb_ops->prepare(map);
|
||||
|
||||
if (!mparam)
|
||||
return -ENOMEM;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
@@ -49,23 +138,12 @@ static int map_benchmark_thread(void *data)
|
||||
ktime_t map_stime, map_etime, unmap_stime, unmap_etime;
|
||||
ktime_t map_delta, unmap_delta;
|
||||
|
||||
/*
|
||||
* for a non-coherent device, if we don't stain them in the
|
||||
* cache, this will give an underestimate of the real-world
|
||||
* overhead of BIDIRECTIONAL or TO_DEVICE mappings;
|
||||
* 66 means evertything goes well! 66 is lucky.
|
||||
*/
|
||||
if (map->dir != DMA_FROM_DEVICE)
|
||||
memset(buf, 0x66, size);
|
||||
|
||||
mb_ops->initialize_data(mparam);
|
||||
map_stime = ktime_get();
|
||||
dma_addr = dma_map_single(map->dev, buf, size, map->dir);
|
||||
if (unlikely(dma_mapping_error(map->dev, dma_addr))) {
|
||||
pr_err("dma_map_single failed on %s\n",
|
||||
dev_name(map->dev));
|
||||
ret = -ENOMEM;
|
||||
ret = mb_ops->do_map(mparam);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
map_etime = ktime_get();
|
||||
map_delta = ktime_sub(map_etime, map_stime);
|
||||
|
||||
@@ -73,7 +151,8 @@ static int map_benchmark_thread(void *data)
|
||||
ndelay(map->bparam.dma_trans_ns);
|
||||
|
||||
unmap_stime = ktime_get();
|
||||
dma_unmap_single(map->dev, dma_addr, size, map->dir);
|
||||
mb_ops->do_unmap(mparam);
|
||||
|
||||
unmap_etime = ktime_get();
|
||||
unmap_delta = ktime_sub(unmap_etime, unmap_stime);
|
||||
|
||||
@@ -108,7 +187,7 @@ static int map_benchmark_thread(void *data)
|
||||
}
|
||||
|
||||
out:
|
||||
free_pages_exact(buf, size);
|
||||
mb_ops->unprepare(mparam);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -209,6 +288,12 @@ static long map_benchmark_ioctl(struct file *file, unsigned int cmd,
|
||||
|
||||
switch (cmd) {
|
||||
case DMA_MAP_BENCHMARK:
|
||||
if (map->bparam.map_mode < 0 ||
|
||||
map->bparam.map_mode >= DMA_MAP_BENCH_MODE_MAX) {
|
||||
pr_err("invalid map mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map->bparam.threads == 0 ||
|
||||
map->bparam.threads > DMA_MAP_MAX_THREADS) {
|
||||
pr_err("invalid thread number\n");
|
||||
|
||||
Reference in New Issue
Block a user