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: add support for dma_map_sg

Support for dma scatter-gather mapping and is intended for testing
mapping performance. It achieves by introducing the dma_sg_map_param
structure and related functions, which enable the implementation of
scatter-gather mapping preparation, mapping, and unmapping operations.
Additionally, the dma_map_benchmark_ops array is updated to include
operations for scatter-gather mapping. This commit aims to provide
a wider range of mapping performance test to cater to different scenarios.

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-3-xiaqinxin@huawei.com

authored by

Qinxin Xia and committed by
Marek Szyprowski
a8d14dd6 9cc60ec4

+119 -1
+4 -1
include/uapi/linux/map_benchmark.h
··· 19 19 20 20 enum { 21 21 DMA_MAP_BENCH_SINGLE_MODE, 22 + DMA_MAP_BENCH_SG_MODE, 22 23 DMA_MAP_BENCH_MODE_MAX 23 24 }; 24 25 ··· 34 33 __u32 dma_bits; /* DMA addressing capability */ 35 34 __u32 dma_dir; /* DMA data direction */ 36 35 __u32 dma_trans_ns; /* time for DMA transmission in ns */ 37 - __u32 granule; /* how many PAGE_SIZE will do map/unmap once a time */ 36 + __u32 granule; /* - SINGLE_MODE: number of pages mapped/unmapped per operation 37 + * - SG_MODE: number of scatterlist entries (each maps one page) 38 + */ 38 39 __u8 map_mode; /* the mode of dma map */ 39 40 __u8 expansion[75]; /* For future use */ 40 41 };
+115
kernel/dma/map_benchmark.c
··· 16 16 #include <linux/module.h> 17 17 #include <linux/pci.h> 18 18 #include <linux/platform_device.h> 19 + #include <linux/scatterlist.h> 19 20 #include <linux/slab.h> 20 21 #include <linux/timekeeping.h> 21 22 #include <uapi/linux/map_benchmark.h> ··· 118 117 .do_unmap = dma_single_map_benchmark_do_unmap, 119 118 }; 120 119 120 + struct dma_sg_map_param { 121 + struct sg_table sgt; 122 + struct device *dev; 123 + void **buf; 124 + u32 npages; 125 + u32 dma_dir; 126 + }; 127 + 128 + static void *dma_sg_map_benchmark_prepare(struct map_benchmark_data *map) 129 + { 130 + struct scatterlist *sg; 131 + int i; 132 + 133 + struct dma_sg_map_param *params = kzalloc(sizeof(*params), GFP_KERNEL); 134 + 135 + if (!params) 136 + return NULL; 137 + /* 138 + * Set the number of scatterlist entries based on the granule. 139 + * In SG mode, 'granule' represents the number of scatterlist entries. 140 + * Each scatterlist entry corresponds to a single page. 141 + */ 142 + params->npages = map->bparam.granule; 143 + params->dma_dir = map->bparam.dma_dir; 144 + params->dev = map->dev; 145 + params->buf = kmalloc_array(params->npages, sizeof(*params->buf), 146 + GFP_KERNEL); 147 + if (!params->buf) 148 + goto out; 149 + 150 + if (sg_alloc_table(&params->sgt, params->npages, GFP_KERNEL)) 151 + goto free_buf; 152 + 153 + for_each_sgtable_sg(&params->sgt, sg, i) { 154 + params->buf[i] = (void *)__get_free_page(GFP_KERNEL); 155 + if (!params->buf[i]) 156 + goto free_page; 157 + 158 + sg_set_buf(sg, params->buf[i], PAGE_SIZE); 159 + } 160 + 161 + return params; 162 + 163 + free_page: 164 + while (i-- > 0) 165 + free_page((unsigned long)params->buf[i]); 166 + 167 + sg_free_table(&params->sgt); 168 + free_buf: 169 + kfree(params->buf); 170 + out: 171 + kfree(params); 172 + return NULL; 173 + } 174 + 175 + static void dma_sg_map_benchmark_unprepare(void *mparam) 176 + { 177 + struct dma_sg_map_param *params = mparam; 178 + int i; 179 + 180 + for (i = 0; i < params->npages; i++) 181 + free_page((unsigned long)params->buf[i]); 182 + 183 + sg_free_table(&params->sgt); 184 + 185 + kfree(params->buf); 186 + kfree(params); 187 + } 188 + 189 + static void dma_sg_map_benchmark_initialize_data(void *mparam) 190 + { 191 + struct dma_sg_map_param *params = mparam; 192 + struct scatterlist *sg; 193 + int i = 0; 194 + 195 + if (params->dma_dir == DMA_FROM_DEVICE) 196 + return; 197 + 198 + for_each_sgtable_sg(&params->sgt, sg, i) 199 + memset(params->buf[i], 0x66, PAGE_SIZE); 200 + } 201 + 202 + static int dma_sg_map_benchmark_do_map(void *mparam) 203 + { 204 + struct dma_sg_map_param *params = mparam; 205 + int ret = 0; 206 + 207 + int sg_mapped = dma_map_sg(params->dev, params->sgt.sgl, 208 + params->npages, params->dma_dir); 209 + if (!sg_mapped) { 210 + pr_err("dma_map_sg failed on %s\n", dev_name(params->dev)); 211 + ret = -ENOMEM; 212 + } 213 + 214 + return ret; 215 + } 216 + 217 + static void dma_sg_map_benchmark_do_unmap(void *mparam) 218 + { 219 + struct dma_sg_map_param *params = mparam; 220 + 221 + dma_unmap_sg(params->dev, params->sgt.sgl, params->npages, 222 + params->dma_dir); 223 + } 224 + 225 + static struct map_benchmark_ops dma_sg_map_benchmark_ops = { 226 + .prepare = dma_sg_map_benchmark_prepare, 227 + .unprepare = dma_sg_map_benchmark_unprepare, 228 + .initialize_data = dma_sg_map_benchmark_initialize_data, 229 + .do_map = dma_sg_map_benchmark_do_map, 230 + .do_unmap = dma_sg_map_benchmark_do_unmap, 231 + }; 232 + 121 233 static struct map_benchmark_ops *dma_map_benchmark_ops[DMA_MAP_BENCH_MODE_MAX] = { 122 234 [DMA_MAP_BENCH_SINGLE_MODE] = &dma_single_map_benchmark_ops, 235 + [DMA_MAP_BENCH_SG_MODE] = &dma_sg_map_benchmark_ops, 123 236 }; 124 237 125 238 static int map_benchmark_thread(void *data)