xref: /kernel/linux/linux-6.6/mm/dmapool_test.c (revision 62306a36)
162306a36Sopenharmony_ci#include <linux/device.h>
262306a36Sopenharmony_ci#include <linux/dma-map-ops.h>
362306a36Sopenharmony_ci#include <linux/dma-mapping.h>
462306a36Sopenharmony_ci#include <linux/dmapool.h>
562306a36Sopenharmony_ci#include <linux/kernel.h>
662306a36Sopenharmony_ci#include <linux/ktime.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define NR_TESTS (100)
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistruct dma_pool_pair {
1262306a36Sopenharmony_ci	dma_addr_t dma;
1362306a36Sopenharmony_ci	void *v;
1462306a36Sopenharmony_ci};
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct dmapool_parms {
1762306a36Sopenharmony_ci	size_t size;
1862306a36Sopenharmony_ci	size_t align;
1962306a36Sopenharmony_ci	size_t boundary;
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic const struct dmapool_parms pool_parms[] = {
2362306a36Sopenharmony_ci	{ .size = 16, .align = 16, .boundary = 0 },
2462306a36Sopenharmony_ci	{ .size = 64, .align = 64, .boundary = 0 },
2562306a36Sopenharmony_ci	{ .size = 256, .align = 256, .boundary = 0 },
2662306a36Sopenharmony_ci	{ .size = 1024, .align = 1024, .boundary = 0 },
2762306a36Sopenharmony_ci	{ .size = 4096, .align = 4096, .boundary = 0 },
2862306a36Sopenharmony_ci	{ .size = 68, .align = 32, .boundary = 4096 },
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic struct dma_pool *pool;
3262306a36Sopenharmony_cistatic struct device test_dev;
3362306a36Sopenharmony_cistatic u64 dma_mask;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic inline int nr_blocks(int size)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	return clamp_t(int, (PAGE_SIZE / size) * 512, 1024, 8192);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic int dmapool_test_alloc(struct dma_pool_pair *p, int blocks)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	int i;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	for (i = 0; i < blocks; i++) {
4562306a36Sopenharmony_ci		p[i].v = dma_pool_alloc(pool, GFP_KERNEL,
4662306a36Sopenharmony_ci					&p[i].dma);
4762306a36Sopenharmony_ci		if (!p[i].v)
4862306a36Sopenharmony_ci			goto pool_fail;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	for (i = 0; i < blocks; i++)
5262306a36Sopenharmony_ci		dma_pool_free(pool, p[i].v, p[i].dma);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return 0;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cipool_fail:
5762306a36Sopenharmony_ci	for (--i; i >= 0; i--)
5862306a36Sopenharmony_ci		dma_pool_free(pool, p[i].v, p[i].dma);
5962306a36Sopenharmony_ci	return -ENOMEM;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int dmapool_test_block(const struct dmapool_parms *parms)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	int blocks = nr_blocks(parms->size);
6562306a36Sopenharmony_ci	ktime_t start_time, end_time;
6662306a36Sopenharmony_ci	struct dma_pool_pair *p;
6762306a36Sopenharmony_ci	int i, ret;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	p = kcalloc(blocks, sizeof(*p), GFP_KERNEL);
7062306a36Sopenharmony_ci	if (!p)
7162306a36Sopenharmony_ci		return -ENOMEM;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	pool = dma_pool_create("test pool", &test_dev, parms->size,
7462306a36Sopenharmony_ci			       parms->align, parms->boundary);
7562306a36Sopenharmony_ci	if (!pool) {
7662306a36Sopenharmony_ci		ret = -ENOMEM;
7762306a36Sopenharmony_ci		goto free_pairs;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	start_time = ktime_get();
8162306a36Sopenharmony_ci	for (i = 0; i < NR_TESTS; i++) {
8262306a36Sopenharmony_ci		ret = dmapool_test_alloc(p, blocks);
8362306a36Sopenharmony_ci		if (ret)
8462306a36Sopenharmony_ci			goto free_pool;
8562306a36Sopenharmony_ci		if (need_resched())
8662306a36Sopenharmony_ci			cond_resched();
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci	end_time = ktime_get();
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	printk("dmapool test: size:%-4zu align:%-4zu blocks:%-4d time:%llu\n",
9162306a36Sopenharmony_ci		parms->size, parms->align, blocks,
9262306a36Sopenharmony_ci		ktime_us_delta(end_time, start_time));
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cifree_pool:
9562306a36Sopenharmony_ci	dma_pool_destroy(pool);
9662306a36Sopenharmony_cifree_pairs:
9762306a36Sopenharmony_ci	kfree(p);
9862306a36Sopenharmony_ci	return ret;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void dmapool_test_release(struct device *dev)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int dmapool_checks(void)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	int i, ret;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	ret = dev_set_name(&test_dev, "dmapool-test");
11062306a36Sopenharmony_ci	if (ret)
11162306a36Sopenharmony_ci		return ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ret = device_register(&test_dev);
11462306a36Sopenharmony_ci	if (ret) {
11562306a36Sopenharmony_ci		printk("%s: register failed:%d\n", __func__, ret);
11662306a36Sopenharmony_ci		goto put_device;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	test_dev.release = dmapool_test_release;
12062306a36Sopenharmony_ci	set_dma_ops(&test_dev, NULL);
12162306a36Sopenharmony_ci	test_dev.dma_mask = &dma_mask;
12262306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(&test_dev, DMA_BIT_MASK(64));
12362306a36Sopenharmony_ci	if (ret) {
12462306a36Sopenharmony_ci		printk("%s: mask failed:%d\n", __func__, ret);
12562306a36Sopenharmony_ci		goto del_device;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pool_parms); i++) {
12962306a36Sopenharmony_ci		ret = dmapool_test_block(&pool_parms[i]);
13062306a36Sopenharmony_ci		if (ret)
13162306a36Sopenharmony_ci			break;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cidel_device:
13562306a36Sopenharmony_ci	device_del(&test_dev);
13662306a36Sopenharmony_ciput_device:
13762306a36Sopenharmony_ci	put_device(&test_dev);
13862306a36Sopenharmony_ci	return ret;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic void dmapool_exit(void)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cimodule_init(dmapool_checks);
14662306a36Sopenharmony_cimodule_exit(dmapool_exit);
14762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
148