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 36 static inline int nr_blocks(int size) 37 { 38 return clamp_t(int, (PAGE_SIZE / size) * 512, 1024, 8192); 39 } 40 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 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 = kcalloc(blocks, sizeof(*p), GFP_KERNEL); 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 102 static void dmapool_test_release(struct device *dev) 103 { 104 } 105 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 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