diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
commit | c6da2cfeb05178a11c6d062a06f8078150ee492f (patch) | |
tree | f3b4021d252c52d6463a9b3c1bb7245e399b009c /arch/arm/plat-samsung/dma_m2m_test.c | |
parent | c6d7c4dbff353eac7919342ae6b3299a378160a6 (diff) | |
download | kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2 |
samsung update 1
Diffstat (limited to 'arch/arm/plat-samsung/dma_m2m_test.c')
-rw-r--r-- | arch/arm/plat-samsung/dma_m2m_test.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/arch/arm/plat-samsung/dma_m2m_test.c b/arch/arm/plat-samsung/dma_m2m_test.c new file mode 100644 index 0000000..b1ca128 --- /dev/null +++ b/arch/arm/plat-samsung/dma_m2m_test.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2010 Samsung Electronics Co. Ltd. + * Jaswinder Singh <jassi.brar@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * MemToMem DMA Xfer Test Driver for S3C DMA API + * + */ +#include <linux/init.h> +#include <linux/kthread.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/wait.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> + +#include <mach/dma.h> + +#define XFER_UNIT 1024 + +static unsigned int xfer_size = 256; +module_param(xfer_size, uint, S_IRUGO); +MODULE_PARM_DESC(xfer_size, "Size of each DMA enqueue request in KB"); + +#define DMATEST_BRSTSZ 1 +static unsigned short burst = 1; +module_param(burst, ushort, S_IRUGO); +MODULE_PARM_DESC(burst, "For which parts of API to calc performance"); + +static unsigned short perf_test = 1; +module_param(perf_test, ushort, S_IRUGO); +MODULE_PARM_DESC(perf_test, "For which parts of API to calc performance"); + +static unsigned int sec = 60 * 60; /* 1 hour by default */ +module_param(sec, uint, S_IRUGO); +MODULE_PARM_DESC(sec, "Number of seconds to run the test (default: 24hr)"); + +static unsigned int channels = 10000; /* Use all channels by default */ +module_param(channels, uint, S_IRUGO); +MODULE_PARM_DESC(channels, "Number of channels to test (default: 8)"); + +struct s3cdma_thread { + unsigned id; /* For Channel index */ + struct task_struct *task; +#define SRC 0 +#define DST 1 + void *buff_cpu[2]; /* CPU address of the Source & Destination buffer */ + dma_addr_t buff_phys[2]; /* Physical address of the Source & Destination buffer */ + unsigned long jiffies; + int stopped; + enum s3c2410_dma_buffresult res; + int size; + unsigned done; + struct s3c2410_dma_client cl; + struct completion xfer_cmplt; + struct list_head node; +}; + +static unsigned int delta; +static unsigned long cycles, maxtime; +static LIST_HEAD(channel_list); + +void s3cdma_cb(struct s3c2410_dma_chan *chan, void *buf_id, + int size, enum s3c2410_dma_buffresult res) +{ + struct s3cdma_thread *thread = buf_id; + + thread->res = res; + thread->size = size; + + complete(&thread->xfer_cmplt); +} + +static void dmatest_init_buf(u32 buf[], int clr, unsigned int bytes) +{ + unsigned int i; + + for (i = 0; i < bytes / 4; i++) + buf[i] = clr ? 0 : i; +} + +static bool dmatest_buf_same(u32 src[], u32 dst[], unsigned int bytes) +{ + unsigned int i; + + for (i = 0; i < (bytes - delta) / 4; i++) + if (src[i] != dst[i]) + return false; + + for (; i < bytes / 4; i++) + if (dst[i]) + return false; + + return true; +} + +static int dmatest_func(void *data) +{ + struct s3cdma_thread *thread = data; + enum dma_ch chan = DMACH_MTOM_0 + thread->id; + unsigned long tout = jiffies + msecs_to_jiffies(sec * 1000); + int src_idx = 0; + unsigned val; + + thread->jiffies = jiffies; + thread->done = 0; + + while (!kthread_should_stop() && time_before(jiffies, tout)) { + + u32 *srcbuf = thread->buff_cpu[src_idx]; + u32 *dstbuf = thread->buff_cpu[1 - src_idx]; + + if (!perf_test) { + dmatest_init_buf(srcbuf, 0, xfer_size); + dmatest_init_buf(dstbuf, 1, xfer_size); + delta = 1024; + } + + s3c2410_dma_devconfig(chan, S3C_DMA_MEM2MEM, + thread->buff_phys[src_idx]); + + s3c2410_dma_enqueue(chan, (void *)thread, + thread->buff_phys[1 - src_idx], xfer_size - delta); + + s3c2410_dma_ctrl(chan, S3C2410_DMAOP_START); + + val = wait_for_completion_timeout(&thread->xfer_cmplt, msecs_to_jiffies(5*1000)); + if (!val) { + dma_addr_t src, dst; + s3c2410_dma_getposition(DMACH_MTOM_0 + thread->id, + &src, &dst); + + printk("\n%s:%d Thrd-%u Done-%u <%x,%x>/<%x,%x>\n", + __func__, __LINE__, thread->id, thread->done, + src, dst, thread->buff_phys[src_idx], thread->buff_phys[1 - src_idx]); + break; + } + + if (thread->res != S3C2410_RES_OK + || thread->size != xfer_size - delta) { + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%u: Cycle-%u Res-%u Xfer_size-%d!\n", + thread->id, thread->done, thread->res, thread->size); + } else { + thread->done++; + } + + if (!perf_test && + !dmatest_buf_same(srcbuf, dstbuf, xfer_size)) { + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%u: Cycle-%u Xfer_cmp failed!\n", + thread->id, thread->done); + break; + } + + src_idx = 1 - src_idx; + } + + thread->jiffies = jiffies - thread->jiffies; + + thread->stopped = 1; + + return 0; +} + +static int __init dmatest_init(void) +{ + struct s3cdma_thread *thread; + int ret, i = 0; + + xfer_size *= XFER_UNIT; + + if (sec < 5) { + sec = 5; + printk(KERN_INFO "S3C DMA M2M Test: Using 5secs test time\n"); + } + + while (i < 10) { + if (burst == (1 << i)) + break; + i++; + } + /* If invalid burst value provided */ + if (i == 10) { + burst = 1; + printk(KERN_INFO "S3C DMA M2M Test: Using 1 burst size\n"); + } + + for (i = 0; i < channels; i++) { + thread = kzalloc(sizeof(struct s3cdma_thread), GFP_KERNEL); + if (!thread) { + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%u No memory for channel\n", i); + goto thrd_alloc_err; + } + + thread->buff_cpu[SRC] = dma_alloc_coherent(NULL, xfer_size, + &thread->buff_phys[SRC], GFP_KERNEL); + if (!thread->buff_cpu[SRC]) { + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%u No memory for src buff\n", i); + goto src_alloc_err; + } + + thread->buff_cpu[DST] = dma_alloc_coherent(NULL, xfer_size, + &thread->buff_phys[DST], GFP_KERNEL); + if (!thread->buff_cpu[DST]) { + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%u No memory for dst buff\n", i); + goto dst_alloc_err; + } + + dmatest_init_buf(thread->buff_cpu[SRC], 0, xfer_size); + dmatest_init_buf(thread->buff_cpu[DST], 1, xfer_size); + + thread->id = i; + thread->cl.name = (char *) thread; + thread->stopped = 0; + + init_completion(&thread->xfer_cmplt); + + ret = s3c2410_dma_request(DMACH_MTOM_0 + thread->id, + &thread->cl, NULL); + if (ret) { + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%d acq(%d)\n", i, ret); + goto thrd_dma_acq_err; + } + + s3c2410_dma_set_buffdone_fn(DMACH_MTOM_0 + thread->id, s3cdma_cb); + + ret = s3c2410_dma_config(DMACH_MTOM_0 + thread->id, burst); + if (ret) { + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%d config(%d)\n", i, ret); + goto thrd_dma_cfg_err; + } + + thread->task = kthread_run(dmatest_func, thread, + "dma-m2m-test%u", i); + if (IS_ERR(thread->task)) { + printk(KERN_INFO "S3C DMA M2M Test: Failed to run thread dma-m2m-test%u\n", i); + goto thrd_run_err; + } + + list_add_tail(&thread->node, &channel_list); + + continue; + +thrd_run_err: +thrd_dma_cfg_err: + s3c2410_dma_free(DMACH_MTOM_0 + thread->id, &thread->cl); +thrd_dma_acq_err: + dma_free_coherent(NULL, xfer_size, + thread->buff_cpu[DST], thread->buff_phys[DST]); +dst_alloc_err: + dma_free_coherent(NULL, xfer_size, + thread->buff_cpu[SRC], thread->buff_phys[SRC]); +src_alloc_err: + kfree(thread); +thrd_alloc_err: + break; + } + + printk(KERN_INFO "S3C DMA M2M Test: Testing with %u Channels\n", i); + + return 0; +} +module_init(dmatest_init); + +static void __exit dmatest_exit(void) +{ + struct s3cdma_thread *thread; + + while (!list_empty(&channel_list)) { + thread = list_entry(channel_list.next, + struct s3cdma_thread, node); + + list_del(&thread->node); + + if (perf_test && !dmatest_buf_same(thread->buff_cpu[SRC], + thread->buff_cpu[DST], xfer_size)) + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%u: Xfer_cmp failed!\n", thread->id); + + if (!thread->stopped) + kthread_stop(thread->task); + + if (jiffies_to_msecs(thread->jiffies) > maxtime) + maxtime = jiffies_to_msecs(thread->jiffies); + + cycles += thread->done; + + printk(KERN_INFO "S3C DMA M2M Test: Thrd-%u %ux%u Kb in %ums\n", + thread->id, thread->done, xfer_size / XFER_UNIT, + jiffies_to_msecs(thread->jiffies)); + + s3c2410_dma_free(DMACH_MTOM_0 + thread->id, &thread->cl); + + dma_free_coherent(NULL, xfer_size, + thread->buff_cpu[DST], thread->buff_phys[DST]); + + dma_free_coherent(NULL, xfer_size, + thread->buff_cpu[SRC], thread->buff_phys[SRC]); + + kfree(thread); + } + + printk(KERN_INFO "S3C DMA M2M Test: Overall %lux%u Kb in %lums\n", + cycles, xfer_size / XFER_UNIT, maxtime); + printk(KERN_INFO "S3C DMA M2M Test: %lu MB/Sec\n", + cycles * 1000 / maxtime * xfer_size / XFER_UNIT / 1024); +} +module_exit(dmatest_exit); + +MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>"); +MODULE_DESCRIPTION("S3C DMA MemToMem Test Driver"); +MODULE_LICENSE("GPL"); |