Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

authored by

Qinxin Xia and committed by
Marek Szyprowski
9cc60ec4 6de23f81

+115 -24
+7 -1
include/uapi/linux/map_benchmark.h
··· 17 17 #define DMA_MAP_TO_DEVICE 1 18 18 #define DMA_MAP_FROM_DEVICE 2 19 19 20 + enum { 21 + DMA_MAP_BENCH_SINGLE_MODE, 22 + DMA_MAP_BENCH_MODE_MAX 23 + }; 24 + 20 25 struct map_benchmark { 21 26 __u64 avg_map_100ns; /* average map latency in 100ns */ 22 27 __u64 map_stddev; /* standard deviation of map latency */ ··· 34 29 __u32 dma_dir; /* DMA data direction */ 35 30 __u32 dma_trans_ns; /* time for DMA transmission in ns */ 36 31 __u32 granule; /* how many PAGE_SIZE will do map/unmap once a time */ 37 - __u8 expansion[76]; /* For future use */ 32 + __u8 map_mode; /* the mode of dma map */ 33 + __u8 expansion[75]; /* For future use */ 38 34 }; 39 35 40 36 #endif /* _UAPI_DMA_BENCHMARK_H */
+108 -23
kernel/dma/map_benchmark.c
··· 5 5 6 6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 7 8 + #include <linux/cleanup.h> 8 9 #include <linux/debugfs.h> 9 10 #include <linux/delay.h> 10 11 #include <linux/device.h> ··· 32 31 atomic64_t loops; 33 32 }; 34 33 34 + struct map_benchmark_ops { 35 + void *(*prepare)(struct map_benchmark_data *map); 36 + void (*unprepare)(void *mparam); 37 + void (*initialize_data)(void *mparam); 38 + int (*do_map)(void *mparam); 39 + void (*do_unmap)(void *mparam); 40 + }; 41 + 42 + struct dma_single_map_param { 43 + struct device *dev; 44 + dma_addr_t addr; 45 + void *xbuf; 46 + u32 npages; 47 + u32 dma_dir; 48 + }; 49 + 50 + static void *dma_single_map_benchmark_prepare(struct map_benchmark_data *map) 51 + { 52 + struct dma_single_map_param *params __free(kfree) = kzalloc(sizeof(*params), 53 + GFP_KERNEL); 54 + if (!params) 55 + return NULL; 56 + 57 + params->npages = map->bparam.granule; 58 + params->dma_dir = map->bparam.dma_dir; 59 + params->dev = map->dev; 60 + params->xbuf = alloc_pages_exact(params->npages * PAGE_SIZE, GFP_KERNEL); 61 + if (!params->xbuf) 62 + return NULL; 63 + 64 + return_ptr(params); 65 + } 66 + 67 + static void dma_single_map_benchmark_unprepare(void *mparam) 68 + { 69 + struct dma_single_map_param *params = mparam; 70 + 71 + free_pages_exact(params->xbuf, params->npages * PAGE_SIZE); 72 + kfree(params); 73 + } 74 + 75 + static void dma_single_map_benchmark_initialize_data(void *mparam) 76 + { 77 + struct dma_single_map_param *params = mparam; 78 + 79 + /* 80 + * for a non-coherent device, if we don't stain them in the 81 + * cache, this will give an underestimate of the real-world 82 + * overhead of BIDIRECTIONAL or TO_DEVICE mappings; 83 + * 66 means everything goes well! 66 is lucky. 84 + */ 85 + if (params->dma_dir != DMA_FROM_DEVICE) 86 + memset(params->xbuf, 0x66, params->npages * PAGE_SIZE); 87 + } 88 + 89 + static int dma_single_map_benchmark_do_map(void *mparam) 90 + { 91 + struct dma_single_map_param *params = mparam; 92 + 93 + params->addr = dma_map_single(params->dev, params->xbuf, 94 + params->npages * PAGE_SIZE, params->dma_dir); 95 + if (unlikely(dma_mapping_error(params->dev, params->addr))) { 96 + pr_err("dma_map_single failed on %s\n", dev_name(params->dev)); 97 + return -ENOMEM; 98 + } 99 + 100 + return 0; 101 + } 102 + 103 + static void dma_single_map_benchmark_do_unmap(void *mparam) 104 + { 105 + struct dma_single_map_param *params = mparam; 106 + 107 + dma_unmap_single(params->dev, params->addr, 108 + params->npages * PAGE_SIZE, params->dma_dir); 109 + } 110 + 111 + static struct map_benchmark_ops dma_single_map_benchmark_ops = { 112 + .prepare = dma_single_map_benchmark_prepare, 113 + .unprepare = dma_single_map_benchmark_unprepare, 114 + .initialize_data = dma_single_map_benchmark_initialize_data, 115 + .do_map = dma_single_map_benchmark_do_map, 116 + .do_unmap = dma_single_map_benchmark_do_unmap, 117 + }; 118 + 119 + static struct map_benchmark_ops *dma_map_benchmark_ops[DMA_MAP_BENCH_MODE_MAX] = { 120 + [DMA_MAP_BENCH_SINGLE_MODE] = &dma_single_map_benchmark_ops, 121 + }; 122 + 35 123 static int map_benchmark_thread(void *data) 36 124 { 37 - void *buf; 38 - dma_addr_t dma_addr; 39 125 struct map_benchmark_data *map = data; 40 - int npages = map->bparam.granule; 41 - u64 size = npages * PAGE_SIZE; 126 + __u8 map_mode = map->bparam.map_mode; 42 127 int ret = 0; 43 128 44 - buf = alloc_pages_exact(size, GFP_KERNEL); 45 - if (!buf) 129 + struct map_benchmark_ops *mb_ops = dma_map_benchmark_ops[map_mode]; 130 + void *mparam = mb_ops->prepare(map); 131 + 132 + if (!mparam) 46 133 return -ENOMEM; 47 134 48 135 while (!kthread_should_stop()) { ··· 138 49 ktime_t map_stime, map_etime, unmap_stime, unmap_etime; 139 50 ktime_t map_delta, unmap_delta; 140 51 141 - /* 142 - * for a non-coherent device, if we don't stain them in the 143 - * cache, this will give an underestimate of the real-world 144 - * overhead of BIDIRECTIONAL or TO_DEVICE mappings; 145 - * 66 means evertything goes well! 66 is lucky. 146 - */ 147 - if (map->dir != DMA_FROM_DEVICE) 148 - memset(buf, 0x66, size); 149 - 52 + mb_ops->initialize_data(mparam); 150 53 map_stime = ktime_get(); 151 - dma_addr = dma_map_single(map->dev, buf, size, map->dir); 152 - if (unlikely(dma_mapping_error(map->dev, dma_addr))) { 153 - pr_err("dma_map_single failed on %s\n", 154 - dev_name(map->dev)); 155 - ret = -ENOMEM; 54 + ret = mb_ops->do_map(mparam); 55 + if (ret) 156 56 goto out; 157 - } 57 + 158 58 map_etime = ktime_get(); 159 59 map_delta = ktime_sub(map_etime, map_stime); 160 60 ··· 151 73 ndelay(map->bparam.dma_trans_ns); 152 74 153 75 unmap_stime = ktime_get(); 154 - dma_unmap_single(map->dev, dma_addr, size, map->dir); 76 + mb_ops->do_unmap(mparam); 77 + 155 78 unmap_etime = ktime_get(); 156 79 unmap_delta = ktime_sub(unmap_etime, unmap_stime); 157 80 ··· 187 108 } 188 109 189 110 out: 190 - free_pages_exact(buf, size); 111 + mb_ops->unprepare(mparam); 191 112 return ret; 192 113 } 193 114 ··· 288 209 289 210 switch (cmd) { 290 211 case DMA_MAP_BENCHMARK: 212 + if (map->bparam.map_mode < 0 || 213 + map->bparam.map_mode >= DMA_MAP_BENCH_MODE_MAX) { 214 + pr_err("invalid map mode\n"); 215 + return -EINVAL; 216 + } 217 + 291 218 if (map->bparam.threads == 0 || 292 219 map->bparam.threads > DMA_MAP_MAX_THREADS) { 293 220 pr_err("invalid thread number\n");