1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/device.h>
3 #include <linux/dma-map-ops.h>
4 #include <linux/dma-mapping.h>
5 #include <linux/dmapool.h>
6 #include <linux/kernel.h>
7 #include <linux/ktime.h>
8 #include <linux/module.h>
9
10 #define NR_TESTS (100)
11
12 struct dma_pool_pair {
13 dma_addr_t dma;
14 void *v;
15 };
16
17 struct dmapool_parms {
18 size_t size;
19 size_t align;
20 size_t boundary;
21 };
22
23 static const struct dmapool_parms pool_parms[] = {
24 { .size = 16, .align = 16, .boundary = 0 },
25 { .size = 64, .align = 64, .boundary = 0 },
26 { .size = 256, .align = 256, .boundary = 0 },
27 { .size = 1024, .align = 1024, .boundary = 0 },
28 { .size = 4096, .align = 4096, .boundary = 0 },
29 { .size = 68, .align = 32, .boundary = 4096 },
30 };
31
32 static struct dma_pool *pool;
33 static struct device test_dev;
34 static u64 dma_mask;
35
nr_blocks(int size)36 static inline int nr_blocks(int size)
37 {
38 return clamp_t(int, (PAGE_SIZE / size) * 512, 1024, 8192);
39 }
40
dmapool_test_alloc(struct dma_pool_pair * p,int blocks)41 static int dmapool_test_alloc(struct dma_pool_pair *p, int blocks)
42 {
43 int i;
44
45 for (i = 0; i < blocks; i++) {
46 p[i].v = dma_pool_alloc(pool, GFP_KERNEL,
47 &p[i].dma);
48 if (!p[i].v)
49 goto pool_fail;
50 }
51
52 for (i = 0; i < blocks; i++)
53 dma_pool_free(pool, p[i].v, p[i].dma);
54
55 return 0;
56
57 pool_fail:
58 for (--i; i >= 0; i--)
59 dma_pool_free(pool, p[i].v, p[i].dma);
60 return -ENOMEM;
61 }
62
dmapool_test_block(const struct dmapool_parms * parms)63 static int dmapool_test_block(const struct dmapool_parms *parms)
64 {
65 int blocks = nr_blocks(parms->size);
66 ktime_t start_time, end_time;
67 struct dma_pool_pair *p;
68 int i, ret;
69
70 p = kzalloc_objs(*p, blocks);
71 if (!p)
72 return -ENOMEM;
73
74 pool = dma_pool_create("test pool", &test_dev, parms->size,
75 parms->align, parms->boundary);
76 if (!pool) {
77 ret = -ENOMEM;
78 goto free_pairs;
79 }
80
81 start_time = ktime_get();
82 for (i = 0; i < NR_TESTS; i++) {
83 ret = dmapool_test_alloc(p, blocks);
84 if (ret)
85 goto free_pool;
86 if (need_resched())
87 cond_resched();
88 }
89 end_time = ktime_get();
90
91 printk("dmapool test: size:%-4zu align:%-4zu blocks:%-4d time:%llu\n",
92 parms->size, parms->align, blocks,
93 ktime_us_delta(end_time, start_time));
94
95 free_pool:
96 dma_pool_destroy(pool);
97 free_pairs:
98 kfree(p);
99 return ret;
100 }
101
dmapool_test_release(struct device * dev)102 static void dmapool_test_release(struct device *dev)
103 {
104 }
105
dmapool_checks(void)106 static int dmapool_checks(void)
107 {
108 int i, ret;
109
110 ret = dev_set_name(&test_dev, "dmapool-test");
111 if (ret)
112 return ret;
113
114 ret = device_register(&test_dev);
115 if (ret) {
116 printk("%s: register failed:%d\n", __func__, ret);
117 goto put_device;
118 }
119
120 test_dev.release = dmapool_test_release;
121 set_dma_ops(&test_dev, NULL);
122 test_dev.dma_mask = &dma_mask;
123 ret = dma_set_mask_and_coherent(&test_dev, DMA_BIT_MASK(64));
124 if (ret) {
125 printk("%s: mask failed:%d\n", __func__, ret);
126 goto del_device;
127 }
128
129 for (i = 0; i < ARRAY_SIZE(pool_parms); i++) {
130 ret = dmapool_test_block(&pool_parms[i]);
131 if (ret)
132 break;
133 }
134
135 del_device:
136 device_del(&test_dev);
137 put_device:
138 put_device(&test_dev);
139 return ret;
140 }
141
dmapool_exit(void)142 static void dmapool_exit(void)
143 {
144 }
145
146 module_init(dmapool_checks);
147 module_exit(dmapool_exit);
148 MODULE_DESCRIPTION("dma_pool timing test");
149 MODULE_LICENSE("GPL");
150