Loading drivers/platform/msm/ipa/test/Makefile +1 −1 Original line number Diff line number Diff line obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o drivers/platform/msm/ipa/test/ipa_test_dma.c 0 → 100644 +931 −0 Original line number Diff line number Diff line /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * 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. */ #include <linux/ipa.h> #include "../ipa_v3/ipa_i.h" #include "ipa_ut_framework.h" #define IPA_TEST_DMA_WQ_NAME_BUFF_SZ 64 #define IPA_TEST_DMA_MT_TEST_NUM_WQ 500 #define IPA_TEST_DMA_MEMCPY_BUFF_SIZE 16384 #define IPA_TEST_DMA_MAX_PKT_SIZE 0xFF00 #define IPA_DMA_TEST_LOOP_NUM 1000 #define IPA_DMA_TEST_INT_LOOP_NUM 50 #define IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM 128 #define IPA_DMA_RUN_TEST_UNIT_IN_LOOP(test_unit, iters, rc, args...) \ do { \ int __i; \ for (__i = 0; __i < iters; __i++) { \ IPA_UT_LOG(#test_unit " START iter %d\n", __i); \ rc = test_unit(args); \ if (!rc) \ continue; \ IPA_UT_LOG(#test_unit " failed %d\n", rc); \ break; \ } \ } while (0) /** * struct ipa_test_dma_async_user_data - user_data structure for async memcpy * @src_mem: source memory buffer * @dest_mem: destination memory buffer * @call_serial_number: Id of the caller * @copy_done: Completion object */ struct ipa_test_dma_async_user_data { struct ipa_mem_buffer src_mem; struct ipa_mem_buffer dest_mem; int call_serial_number; struct completion copy_done; }; /** * ipa_test_dma_setup() - Suite setup function */ static int ipa_test_dma_setup(void **ppriv) { int rc; IPA_UT_DBG("Start Setup\n"); if (!ipa3_ctx) { IPA_UT_ERR("No IPA ctx\n"); return -EINVAL; } rc = ipa_dma_init(); if (rc) IPA_UT_ERR("Fail to init ipa_dma - return code %d\n", rc); else IPA_UT_DBG("ipa_dma_init() Completed successfully!\n"); *ppriv = NULL; return rc; } /** * ipa_test_dma_teardown() - Suite teardown function */ static int ipa_test_dma_teardown(void *priv) { IPA_UT_DBG("Start Teardown\n"); ipa_dma_destroy(); return 0; } static int ipa_test_dma_alloc_buffs(struct ipa_mem_buffer *src, struct ipa_mem_buffer *dest, int size) { int i; static int val = 1; int rc; val++; src->size = size; src->base = dma_alloc_coherent(ipa3_ctx->pdev, src->size, &src->phys_base, GFP_KERNEL); if (!src->base) { IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); return -ENOMEM; } dest->size = size; dest->base = dma_alloc_coherent(ipa3_ctx->pdev, dest->size, &dest->phys_base, GFP_KERNEL); if (!dest->base) { IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); rc = -ENOMEM; goto fail_alloc_dest; } memset(dest->base, 0, dest->size); for (i = 0; i < src->size; i++) memset(src->base + i, (val + i) & 0xFF, 1); rc = memcmp(dest->base, src->base, dest->size); if (rc == 0) { IPA_UT_LOG("dest & src buffers are equal\n"); IPA_UT_TEST_FAIL_REPORT("dest & src buffers are equal"); rc = -EFAULT; goto fail_buf_cmp; } return 0; fail_buf_cmp: dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, dest->phys_base); fail_alloc_dest: dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, src->phys_base); return rc; } static void ipa_test_dma_destroy_buffs(struct ipa_mem_buffer *src, struct ipa_mem_buffer *dest) { dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, src->phys_base); dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, dest->phys_base); } /** * ipa_test_dma_memcpy_sync() - memcpy in sync mode * * @size: buffer size * @expect_fail: test expects the memcpy to fail * * To be run during tests * 1. Alloc src and dst buffers * 2. sync memcpy src to dst via dma * 3. compare src and dts if memcpy succeeded as expected */ static int ipa_test_dma_memcpy_sync(int size, bool expect_fail) { int rc = 0; int i; struct ipa_mem_buffer src_mem; struct ipa_mem_buffer dest_mem; u8 *src; u8 *dest; rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); if (rc) { IPA_UT_LOG("fail to alloc buffers\n"); IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); return rc; } rc = ipa_dma_sync_memcpy(dest_mem.phys_base, src_mem.phys_base, size); if (!expect_fail && rc) { IPA_UT_LOG("fail to sync memcpy - rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); goto free_buffs; } if (expect_fail && !rc) { IPA_UT_LOG("sync memcpy succeeded while expected to fail\n"); IPA_UT_TEST_FAIL_REPORT( "sync memcpy succeeded while expected to fail"); rc = -EFAULT; goto free_buffs; } if (!rc) { /* if memcpy succeeded, compare the buffers */ rc = memcmp(dest_mem.base, src_mem.base, size); if (rc) { IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); IPA_UT_TEST_FAIL_REPORT( "BAD memcpy - buffs are not equals"); src = src_mem.base; dest = dest_mem.base; for (i = 0; i < size; i++) { if (*(src + i) != *(dest + i)) { IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", i, *(src + i), *(dest + i)); } } } } else { /* if memcpy failed as expected, update the rc */ rc = 0; } free_buffs: ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); return rc; } static void ipa_test_dma_async_memcpy_cb(void *comp_obj) { struct completion *xfer_done; if (!comp_obj) { IPA_UT_ERR("Invalid Input\n"); return; } xfer_done = (struct completion *)comp_obj; complete(xfer_done); } static void ipa_test_dma_async_memcpy_cb_user_data(void *user_param) { int rc; int i; u8 *src; u8 *dest; struct ipa_test_dma_async_user_data *udata = (struct ipa_test_dma_async_user_data *)user_param; if (!udata) { IPA_UT_ERR("Invalid user param\n"); return; } rc = memcmp(udata->dest_mem.base, udata->src_mem.base, udata->src_mem.size); if (rc) { IPA_UT_LOG("BAD memcpy - buffs are not equal sn=%d\n", udata->call_serial_number); IPA_UT_TEST_FAIL_REPORT( "BAD memcpy - buffs are not equal"); src = udata->src_mem.base; dest = udata->dest_mem.base; for (i = 0; i < udata->src_mem.size; i++) { if (*(src + i) != *(dest + i)) { IPA_UT_ERR("byte: %d 0x%x != 0x%x\n", i, *(src + i), *(dest + i)); } } return; } IPA_UT_LOG("Notify on async memcopy sn=%d\n", udata->call_serial_number); complete(&(udata->copy_done)); } /** * ipa_test_dma_memcpy_async() - memcpy in async mode * * @size: buffer size * @expect_fail: test expected the memcpy to fail * * To be run during tests * 1. Alloc src and dst buffers * 2. async memcpy src to dst via dma and wait for completion * 3. compare src and dts if memcpy succeeded as expected */ static int ipa_test_dma_memcpy_async(int size, bool expect_fail) { int rc = 0; int i; struct ipa_mem_buffer src_mem; struct ipa_mem_buffer dest_mem; u8 *src; u8 *dest; struct completion xfer_done; rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); if (rc) { IPA_UT_LOG("fail to alloc buffers\n"); IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); return rc; } init_completion(&xfer_done); rc = ipa_dma_async_memcpy(dest_mem.phys_base, src_mem.phys_base, size, ipa_test_dma_async_memcpy_cb, &xfer_done); if (!expect_fail && rc) { IPA_UT_LOG("fail to initiate async memcpy - rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("async memcpy initiate failed"); goto free_buffs; } if (expect_fail && !rc) { IPA_UT_LOG("async memcpy succeeded while expected to fail\n"); IPA_UT_TEST_FAIL_REPORT( "async memcpy succeeded while expected to fail"); rc = -EFAULT; goto free_buffs; } if (!rc) { /* if memcpy succeeded, compare the buffers */ wait_for_completion(&xfer_done); rc = memcmp(dest_mem.base, src_mem.base, size); if (rc) { IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); IPA_UT_TEST_FAIL_REPORT( "BAD memcpy - buffs are not equals"); src = src_mem.base; dest = dest_mem.base; for (i = 0; i < size; i++) { if (*(src + i) != *(dest + i)) { IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", i, *(src + i), *(dest + i)); } } } } else { /* if memcpy failed as expected, update the rc */ rc = 0; } free_buffs: ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); return rc; } /** * ipa_test_dma_sync_async_memcpy() - memcpy in sync and then async mode * * @size: buffer size * * To be run during tests * 1. several sync memcopy in row * 2. several async memcopy - * back-to-back (next async try initiated after prev is completed) */ static int ipa_test_dma_sync_async_memcpy(int size) { int rc; IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); if (rc) { IPA_UT_LOG("sync memcopy fail rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcopy fail"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); if (rc) { IPA_UT_LOG("async memcopy fail rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("async memcopy fail"); return rc; } return 0; } /** * TEST: test control API - enable/disable dma * 1. enable dma * 2. disable dma */ static int ipa_test_dma_control_api(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: memcpy before dma enable * * 1. sync memcpy - should fail * 2. async memcpy - should fail */ static int ipa_test_dma_memcpy_before_enable(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); if (rc) { IPA_UT_LOG("sync memcpy succeeded unexpectedly rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); return rc; } rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); if (rc) { IPA_UT_LOG("async memcpy succeeded unexpectedly rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); return rc; } return 0; } /** * TEST: Sync memory copy * * 1. dma enable * 2. sync memcpy * 3. dma disable */ static int ipa_test_dma_sync_memcpy(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Async memory copy * * 1. dma enable * 2. async memcpy * 3. dma disable */ static int ipa_test_dma_async_memcpy(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("async memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("async memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Iteration of sync memory copy * * 1. dma enable * 2. sync memcpy in loop - in row * 3. dma disable */ static int ipa_test_dma_sync_memcpy_in_loop(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, IPA_DMA_TEST_LOOP_NUM, rc, IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("Iterations of sync memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("Iterations of sync memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Iteration of async memory copy * * 1. dma enable * 2. async memcpy in loop - back-to-back * next async copy is initiated once previous one completed * 3. dma disable */ static int ipa_test_dma_async_memcpy_in_loop(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, IPA_DMA_TEST_LOOP_NUM, rc, IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("Iterations of async memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("Iterations of async memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Iteration of interleaved sync and async memory copy * * 1. dma enable * 2. sync and async memcpy in loop - interleaved * 3. dma disable */ static int ipa_test_dma_interleaved_sync_async_memcpy_in_loop(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_sync_async_memcpy, IPA_DMA_TEST_INT_LOOP_NUM, rc, IPA_TEST_DMA_MEMCPY_BUFF_SIZE); if (rc) { IPA_UT_LOG( "Iterations of interleaved sync async memcpy failed rc=%d\n" , rc); IPA_UT_TEST_FAIL_REPORT( "Iterations of interleaved sync async memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } static atomic_t ipa_test_dma_mt_test_pass; static void ipa_test_dma_wrapper_test_one_sync(struct work_struct *work) { int rc; rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("fail sync memcpy from thread rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail sync memcpy from thread"); return; } atomic_inc(&ipa_test_dma_mt_test_pass); } static void ipa_test_dma_wrapper_test_one_async(struct work_struct *work) { int rc; rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("fail async memcpy from thread rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail async memcpy from thread"); return; } atomic_inc(&ipa_test_dma_mt_test_pass); } /** * TEST: Multiple threads running sync and sync mem copy * * 1. dma enable * 2. In-loop * 2.1 create wq for sync memcpy * 2.2 create wq for async memcpy * 2.3 queue sync memcpy work * 2.4 queue async memcoy work * 3. In-loop * 3.1 flush and destroy wq sync * 3.2 flush and destroy wq async * 3. dma disable */ static int ipa_test_dma_mt_sync_async(void *priv) { int rc; int i; static struct workqueue_struct *wq_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; static struct workqueue_struct *wq_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; static struct work_struct work_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; static struct work_struct work_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; char buff[IPA_TEST_DMA_WQ_NAME_BUFF_SZ]; memset(wq_sync, 0, sizeof(wq_sync)); memset(wq_sync, 0, sizeof(wq_async)); memset(work_async, 0, sizeof(work_async)); memset(work_sync, 0, sizeof(work_sync)); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } atomic_set(&ipa_test_dma_mt_test_pass, 0); for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { snprintf(buff, sizeof(buff), "ipa_test_dmaSwq%d", i); wq_sync[i] = create_singlethread_workqueue(buff); if (!wq_sync[i]) { IPA_UT_ERR("failed to create sync wq#%d\n", i); rc = -EFAULT; goto fail_create_wq; } snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipa_test_dmaAwq%d", i); wq_async[i] = create_singlethread_workqueue(buff); if (!wq_async[i]) { IPA_UT_ERR("failed to create async wq#%d\n", i); rc = -EFAULT; goto fail_create_wq; } INIT_WORK(&work_sync[i], ipa_test_dma_wrapper_test_one_sync); queue_work(wq_sync[i], &work_sync[i]); INIT_WORK(&work_async[i], ipa_test_dma_wrapper_test_one_async); queue_work(wq_async[i], &work_async[i]); } for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { flush_workqueue(wq_sync[i]); destroy_workqueue(wq_sync[i]); flush_workqueue(wq_async[i]); destroy_workqueue(wq_async[i]); } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } if ((2 * IPA_TEST_DMA_MT_TEST_NUM_WQ) != atomic_read(&ipa_test_dma_mt_test_pass)) { IPA_UT_LOG( "Multi-threaded sync/async memcopy failed passed=%d\n" , atomic_read(&ipa_test_dma_mt_test_pass)); IPA_UT_TEST_FAIL_REPORT( "Multi-threaded sync/async memcopy failed"); return -EFAULT; } return 0; fail_create_wq: (void)ipa_dma_disable(); for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { if (wq_sync[i]) destroy_workqueue(wq_sync[i]); if (wq_async[i]) destroy_workqueue(wq_async[i]); } return rc; } /** * TEST: Several parallel async memory copy iterations * * 1. create several user_data structures - one per iteration * 2. allocate buffs. Give slice for each iteration * 3. iterations of async mem copy * 4. wait for all to complete * 5. dma disable */ static int ipa_test_dma_parallel_async_memcpy_in_loop(void *priv) { int rc; struct ipa_test_dma_async_user_data *udata; struct ipa_mem_buffer all_src_mem; struct ipa_mem_buffer all_dest_mem; int i; bool is_fail = false; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } udata = kzalloc(IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM * sizeof(struct ipa_test_dma_async_user_data), GFP_KERNEL); if (!udata) { IPA_UT_ERR("fail allocate user_data array\n"); (void)ipa_dma_disable(); return -ENOMEM; } rc = ipa_test_dma_alloc_buffs(&all_src_mem, &all_dest_mem, IPA_TEST_DMA_MEMCPY_BUFF_SIZE); if (rc) { IPA_UT_LOG("fail to alloc buffers\n"); IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); kfree(udata); (void)ipa_dma_disable(); return rc; } for (i = 0 ; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) { udata[i].src_mem.size = IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM; udata[i].src_mem.base = all_src_mem.base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].src_mem.phys_base = all_src_mem.phys_base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].dest_mem.size = (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].dest_mem.base = all_dest_mem.base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].dest_mem.phys_base = all_dest_mem.phys_base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].call_serial_number = i + 1; init_completion(&(udata[i].copy_done)); rc = ipa_dma_async_memcpy(udata[i].dest_mem.phys_base, udata[i].src_mem.phys_base, (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM), ipa_test_dma_async_memcpy_cb_user_data, &udata[i]); if (rc) { IPA_UT_LOG("async memcpy initiation fail i=%d rc=%d\n", i, rc); is_fail = true; } } for (i = 0; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) wait_for_completion(&udata[i].copy_done); ipa_test_dma_destroy_buffs(&all_src_mem, &all_dest_mem); kfree(udata); rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } if (is_fail) { IPA_UT_LOG("async memcopy failed\n"); IPA_UT_TEST_FAIL_REPORT("async memcopy failed"); return -EFAULT; } return 0; } /** * TEST: Sync memory copy * * 1. dma enable * 2. sync memcpy with max packet size * 3. dma disable */ static int ipa_test_dma_sync_memcpy_max_pkt_size(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MAX_PKT_SIZE, false); if (rc) { IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /* Suite definition block */ IPA_UT_DEFINE_SUITE_START(dma, "DMA for GSI", ipa_test_dma_setup, ipa_test_dma_teardown) { IPA_UT_ADD_TEST(control_api, "Control API", ipa_test_dma_control_api, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(memcpy_before_enable, "Call memcpy before dma enable and expect it to fail", ipa_test_dma_memcpy_before_enable, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(sync_memcpy, "Sync memory copy", ipa_test_dma_sync_memcpy, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(async_memcpy, "Async memory copy", ipa_test_dma_async_memcpy, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(sync_memcpy_in_loop, "Several sync memory copy iterations", ipa_test_dma_sync_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(async_memcpy_in_loop, "Several async memory copy iterations", ipa_test_dma_async_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(interleaved_sync_async_memcpy_in_loop, "Several interleaved sync and async memory copy iterations", ipa_test_dma_interleaved_sync_async_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(multi_threaded_multiple_sync_async_memcpy, "Several multi-threaded sync and async memory copy iterations", ipa_test_dma_mt_sync_async, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(parallel_async_memcpy_in_loop, "Several parallel async memory copy iterations", ipa_test_dma_parallel_async_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(sync_memcpy_max_pkt_size, "Sync memory copy with max packet size", ipa_test_dma_sync_memcpy_max_pkt_size, true, IPA_HW_v3_0, IPA_HW_MAX), } IPA_UT_DEFINE_SUITE_END(dma); drivers/platform/msm/ipa/test/ipa_ut_suite_list.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -21,6 +21,7 @@ * No importance for order. */ IPA_UT_DECLARE_SUITE(mhi); IPA_UT_DECLARE_SUITE(dma); IPA_UT_DECLARE_SUITE(example); Loading @@ -31,6 +32,7 @@ IPA_UT_DECLARE_SUITE(example); IPA_UT_DEFINE_ALL_SUITES_START { IPA_UT_REGISTER_SUITE(mhi), IPA_UT_REGISTER_SUITE(dma), IPA_UT_REGISTER_SUITE(example), } IPA_UT_DEFINE_ALL_SUITES_END; Loading Loading
drivers/platform/msm/ipa/test/Makefile +1 −1 Original line number Diff line number Diff line obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o ipa_test_mhi.o ipa_test_dma.o
drivers/platform/msm/ipa/test/ipa_test_dma.c 0 → 100644 +931 −0 Original line number Diff line number Diff line /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * 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. */ #include <linux/ipa.h> #include "../ipa_v3/ipa_i.h" #include "ipa_ut_framework.h" #define IPA_TEST_DMA_WQ_NAME_BUFF_SZ 64 #define IPA_TEST_DMA_MT_TEST_NUM_WQ 500 #define IPA_TEST_DMA_MEMCPY_BUFF_SIZE 16384 #define IPA_TEST_DMA_MAX_PKT_SIZE 0xFF00 #define IPA_DMA_TEST_LOOP_NUM 1000 #define IPA_DMA_TEST_INT_LOOP_NUM 50 #define IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM 128 #define IPA_DMA_RUN_TEST_UNIT_IN_LOOP(test_unit, iters, rc, args...) \ do { \ int __i; \ for (__i = 0; __i < iters; __i++) { \ IPA_UT_LOG(#test_unit " START iter %d\n", __i); \ rc = test_unit(args); \ if (!rc) \ continue; \ IPA_UT_LOG(#test_unit " failed %d\n", rc); \ break; \ } \ } while (0) /** * struct ipa_test_dma_async_user_data - user_data structure for async memcpy * @src_mem: source memory buffer * @dest_mem: destination memory buffer * @call_serial_number: Id of the caller * @copy_done: Completion object */ struct ipa_test_dma_async_user_data { struct ipa_mem_buffer src_mem; struct ipa_mem_buffer dest_mem; int call_serial_number; struct completion copy_done; }; /** * ipa_test_dma_setup() - Suite setup function */ static int ipa_test_dma_setup(void **ppriv) { int rc; IPA_UT_DBG("Start Setup\n"); if (!ipa3_ctx) { IPA_UT_ERR("No IPA ctx\n"); return -EINVAL; } rc = ipa_dma_init(); if (rc) IPA_UT_ERR("Fail to init ipa_dma - return code %d\n", rc); else IPA_UT_DBG("ipa_dma_init() Completed successfully!\n"); *ppriv = NULL; return rc; } /** * ipa_test_dma_teardown() - Suite teardown function */ static int ipa_test_dma_teardown(void *priv) { IPA_UT_DBG("Start Teardown\n"); ipa_dma_destroy(); return 0; } static int ipa_test_dma_alloc_buffs(struct ipa_mem_buffer *src, struct ipa_mem_buffer *dest, int size) { int i; static int val = 1; int rc; val++; src->size = size; src->base = dma_alloc_coherent(ipa3_ctx->pdev, src->size, &src->phys_base, GFP_KERNEL); if (!src->base) { IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); return -ENOMEM; } dest->size = size; dest->base = dma_alloc_coherent(ipa3_ctx->pdev, dest->size, &dest->phys_base, GFP_KERNEL); if (!dest->base) { IPA_UT_LOG("fail to alloc dma mem %d bytes\n", size); IPA_UT_TEST_FAIL_REPORT("fail to alloc dma mem"); rc = -ENOMEM; goto fail_alloc_dest; } memset(dest->base, 0, dest->size); for (i = 0; i < src->size; i++) memset(src->base + i, (val + i) & 0xFF, 1); rc = memcmp(dest->base, src->base, dest->size); if (rc == 0) { IPA_UT_LOG("dest & src buffers are equal\n"); IPA_UT_TEST_FAIL_REPORT("dest & src buffers are equal"); rc = -EFAULT; goto fail_buf_cmp; } return 0; fail_buf_cmp: dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, dest->phys_base); fail_alloc_dest: dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, src->phys_base); return rc; } static void ipa_test_dma_destroy_buffs(struct ipa_mem_buffer *src, struct ipa_mem_buffer *dest) { dma_free_coherent(ipa3_ctx->pdev, src->size, src->base, src->phys_base); dma_free_coherent(ipa3_ctx->pdev, dest->size, dest->base, dest->phys_base); } /** * ipa_test_dma_memcpy_sync() - memcpy in sync mode * * @size: buffer size * @expect_fail: test expects the memcpy to fail * * To be run during tests * 1. Alloc src and dst buffers * 2. sync memcpy src to dst via dma * 3. compare src and dts if memcpy succeeded as expected */ static int ipa_test_dma_memcpy_sync(int size, bool expect_fail) { int rc = 0; int i; struct ipa_mem_buffer src_mem; struct ipa_mem_buffer dest_mem; u8 *src; u8 *dest; rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); if (rc) { IPA_UT_LOG("fail to alloc buffers\n"); IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); return rc; } rc = ipa_dma_sync_memcpy(dest_mem.phys_base, src_mem.phys_base, size); if (!expect_fail && rc) { IPA_UT_LOG("fail to sync memcpy - rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); goto free_buffs; } if (expect_fail && !rc) { IPA_UT_LOG("sync memcpy succeeded while expected to fail\n"); IPA_UT_TEST_FAIL_REPORT( "sync memcpy succeeded while expected to fail"); rc = -EFAULT; goto free_buffs; } if (!rc) { /* if memcpy succeeded, compare the buffers */ rc = memcmp(dest_mem.base, src_mem.base, size); if (rc) { IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); IPA_UT_TEST_FAIL_REPORT( "BAD memcpy - buffs are not equals"); src = src_mem.base; dest = dest_mem.base; for (i = 0; i < size; i++) { if (*(src + i) != *(dest + i)) { IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", i, *(src + i), *(dest + i)); } } } } else { /* if memcpy failed as expected, update the rc */ rc = 0; } free_buffs: ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); return rc; } static void ipa_test_dma_async_memcpy_cb(void *comp_obj) { struct completion *xfer_done; if (!comp_obj) { IPA_UT_ERR("Invalid Input\n"); return; } xfer_done = (struct completion *)comp_obj; complete(xfer_done); } static void ipa_test_dma_async_memcpy_cb_user_data(void *user_param) { int rc; int i; u8 *src; u8 *dest; struct ipa_test_dma_async_user_data *udata = (struct ipa_test_dma_async_user_data *)user_param; if (!udata) { IPA_UT_ERR("Invalid user param\n"); return; } rc = memcmp(udata->dest_mem.base, udata->src_mem.base, udata->src_mem.size); if (rc) { IPA_UT_LOG("BAD memcpy - buffs are not equal sn=%d\n", udata->call_serial_number); IPA_UT_TEST_FAIL_REPORT( "BAD memcpy - buffs are not equal"); src = udata->src_mem.base; dest = udata->dest_mem.base; for (i = 0; i < udata->src_mem.size; i++) { if (*(src + i) != *(dest + i)) { IPA_UT_ERR("byte: %d 0x%x != 0x%x\n", i, *(src + i), *(dest + i)); } } return; } IPA_UT_LOG("Notify on async memcopy sn=%d\n", udata->call_serial_number); complete(&(udata->copy_done)); } /** * ipa_test_dma_memcpy_async() - memcpy in async mode * * @size: buffer size * @expect_fail: test expected the memcpy to fail * * To be run during tests * 1. Alloc src and dst buffers * 2. async memcpy src to dst via dma and wait for completion * 3. compare src and dts if memcpy succeeded as expected */ static int ipa_test_dma_memcpy_async(int size, bool expect_fail) { int rc = 0; int i; struct ipa_mem_buffer src_mem; struct ipa_mem_buffer dest_mem; u8 *src; u8 *dest; struct completion xfer_done; rc = ipa_test_dma_alloc_buffs(&src_mem, &dest_mem, size); if (rc) { IPA_UT_LOG("fail to alloc buffers\n"); IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); return rc; } init_completion(&xfer_done); rc = ipa_dma_async_memcpy(dest_mem.phys_base, src_mem.phys_base, size, ipa_test_dma_async_memcpy_cb, &xfer_done); if (!expect_fail && rc) { IPA_UT_LOG("fail to initiate async memcpy - rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("async memcpy initiate failed"); goto free_buffs; } if (expect_fail && !rc) { IPA_UT_LOG("async memcpy succeeded while expected to fail\n"); IPA_UT_TEST_FAIL_REPORT( "async memcpy succeeded while expected to fail"); rc = -EFAULT; goto free_buffs; } if (!rc) { /* if memcpy succeeded, compare the buffers */ wait_for_completion(&xfer_done); rc = memcmp(dest_mem.base, src_mem.base, size); if (rc) { IPA_UT_LOG("BAD memcpy - buffs are not equals\n"); IPA_UT_TEST_FAIL_REPORT( "BAD memcpy - buffs are not equals"); src = src_mem.base; dest = dest_mem.base; for (i = 0; i < size; i++) { if (*(src + i) != *(dest + i)) { IPA_UT_LOG("byte: %d 0x%x != 0x%x\n", i, *(src + i), *(dest + i)); } } } } else { /* if memcpy failed as expected, update the rc */ rc = 0; } free_buffs: ipa_test_dma_destroy_buffs(&src_mem, &dest_mem); return rc; } /** * ipa_test_dma_sync_async_memcpy() - memcpy in sync and then async mode * * @size: buffer size * * To be run during tests * 1. several sync memcopy in row * 2. several async memcopy - * back-to-back (next async try initiated after prev is completed) */ static int ipa_test_dma_sync_async_memcpy(int size) { int rc; IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); if (rc) { IPA_UT_LOG("sync memcopy fail rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcopy fail"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, IPA_DMA_TEST_INT_LOOP_NUM, rc, size, false); if (rc) { IPA_UT_LOG("async memcopy fail rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("async memcopy fail"); return rc; } return 0; } /** * TEST: test control API - enable/disable dma * 1. enable dma * 2. disable dma */ static int ipa_test_dma_control_api(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: memcpy before dma enable * * 1. sync memcpy - should fail * 2. async memcpy - should fail */ static int ipa_test_dma_memcpy_before_enable(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); if (rc) { IPA_UT_LOG("sync memcpy succeeded unexpectedly rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); return rc; } rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, true); if (rc) { IPA_UT_LOG("async memcpy succeeded unexpectedly rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy succeeded unexpectedly"); return rc; } return 0; } /** * TEST: Sync memory copy * * 1. dma enable * 2. sync memcpy * 3. dma disable */ static int ipa_test_dma_sync_memcpy(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Async memory copy * * 1. dma enable * 2. async memcpy * 3. dma disable */ static int ipa_test_dma_async_memcpy(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("async memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("async memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Iteration of sync memory copy * * 1. dma enable * 2. sync memcpy in loop - in row * 3. dma disable */ static int ipa_test_dma_sync_memcpy_in_loop(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_sync, IPA_DMA_TEST_LOOP_NUM, rc, IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("Iterations of sync memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("Iterations of sync memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Iteration of async memory copy * * 1. dma enable * 2. async memcpy in loop - back-to-back * next async copy is initiated once previous one completed * 3. dma disable */ static int ipa_test_dma_async_memcpy_in_loop(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_memcpy_async, IPA_DMA_TEST_LOOP_NUM, rc, IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("Iterations of async memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("Iterations of async memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /** * TEST: Iteration of interleaved sync and async memory copy * * 1. dma enable * 2. sync and async memcpy in loop - interleaved * 3. dma disable */ static int ipa_test_dma_interleaved_sync_async_memcpy_in_loop(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } IPA_DMA_RUN_TEST_UNIT_IN_LOOP(ipa_test_dma_sync_async_memcpy, IPA_DMA_TEST_INT_LOOP_NUM, rc, IPA_TEST_DMA_MEMCPY_BUFF_SIZE); if (rc) { IPA_UT_LOG( "Iterations of interleaved sync async memcpy failed rc=%d\n" , rc); IPA_UT_TEST_FAIL_REPORT( "Iterations of interleaved sync async memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } static atomic_t ipa_test_dma_mt_test_pass; static void ipa_test_dma_wrapper_test_one_sync(struct work_struct *work) { int rc; rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("fail sync memcpy from thread rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail sync memcpy from thread"); return; } atomic_inc(&ipa_test_dma_mt_test_pass); } static void ipa_test_dma_wrapper_test_one_async(struct work_struct *work) { int rc; rc = ipa_test_dma_memcpy_async(IPA_TEST_DMA_MEMCPY_BUFF_SIZE, false); if (rc) { IPA_UT_LOG("fail async memcpy from thread rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail async memcpy from thread"); return; } atomic_inc(&ipa_test_dma_mt_test_pass); } /** * TEST: Multiple threads running sync and sync mem copy * * 1. dma enable * 2. In-loop * 2.1 create wq for sync memcpy * 2.2 create wq for async memcpy * 2.3 queue sync memcpy work * 2.4 queue async memcoy work * 3. In-loop * 3.1 flush and destroy wq sync * 3.2 flush and destroy wq async * 3. dma disable */ static int ipa_test_dma_mt_sync_async(void *priv) { int rc; int i; static struct workqueue_struct *wq_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; static struct workqueue_struct *wq_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; static struct work_struct work_async[IPA_TEST_DMA_MT_TEST_NUM_WQ]; static struct work_struct work_sync[IPA_TEST_DMA_MT_TEST_NUM_WQ]; char buff[IPA_TEST_DMA_WQ_NAME_BUFF_SZ]; memset(wq_sync, 0, sizeof(wq_sync)); memset(wq_sync, 0, sizeof(wq_async)); memset(work_async, 0, sizeof(work_async)); memset(work_sync, 0, sizeof(work_sync)); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } atomic_set(&ipa_test_dma_mt_test_pass, 0); for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { snprintf(buff, sizeof(buff), "ipa_test_dmaSwq%d", i); wq_sync[i] = create_singlethread_workqueue(buff); if (!wq_sync[i]) { IPA_UT_ERR("failed to create sync wq#%d\n", i); rc = -EFAULT; goto fail_create_wq; } snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipa_test_dmaAwq%d", i); wq_async[i] = create_singlethread_workqueue(buff); if (!wq_async[i]) { IPA_UT_ERR("failed to create async wq#%d\n", i); rc = -EFAULT; goto fail_create_wq; } INIT_WORK(&work_sync[i], ipa_test_dma_wrapper_test_one_sync); queue_work(wq_sync[i], &work_sync[i]); INIT_WORK(&work_async[i], ipa_test_dma_wrapper_test_one_async); queue_work(wq_async[i], &work_async[i]); } for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { flush_workqueue(wq_sync[i]); destroy_workqueue(wq_sync[i]); flush_workqueue(wq_async[i]); destroy_workqueue(wq_async[i]); } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } if ((2 * IPA_TEST_DMA_MT_TEST_NUM_WQ) != atomic_read(&ipa_test_dma_mt_test_pass)) { IPA_UT_LOG( "Multi-threaded sync/async memcopy failed passed=%d\n" , atomic_read(&ipa_test_dma_mt_test_pass)); IPA_UT_TEST_FAIL_REPORT( "Multi-threaded sync/async memcopy failed"); return -EFAULT; } return 0; fail_create_wq: (void)ipa_dma_disable(); for (i = 0; i < IPA_TEST_DMA_MT_TEST_NUM_WQ; i++) { if (wq_sync[i]) destroy_workqueue(wq_sync[i]); if (wq_async[i]) destroy_workqueue(wq_async[i]); } return rc; } /** * TEST: Several parallel async memory copy iterations * * 1. create several user_data structures - one per iteration * 2. allocate buffs. Give slice for each iteration * 3. iterations of async mem copy * 4. wait for all to complete * 5. dma disable */ static int ipa_test_dma_parallel_async_memcpy_in_loop(void *priv) { int rc; struct ipa_test_dma_async_user_data *udata; struct ipa_mem_buffer all_src_mem; struct ipa_mem_buffer all_dest_mem; int i; bool is_fail = false; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } udata = kzalloc(IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM * sizeof(struct ipa_test_dma_async_user_data), GFP_KERNEL); if (!udata) { IPA_UT_ERR("fail allocate user_data array\n"); (void)ipa_dma_disable(); return -ENOMEM; } rc = ipa_test_dma_alloc_buffs(&all_src_mem, &all_dest_mem, IPA_TEST_DMA_MEMCPY_BUFF_SIZE); if (rc) { IPA_UT_LOG("fail to alloc buffers\n"); IPA_UT_TEST_FAIL_REPORT("fail to alloc buffers"); kfree(udata); (void)ipa_dma_disable(); return rc; } for (i = 0 ; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) { udata[i].src_mem.size = IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM; udata[i].src_mem.base = all_src_mem.base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].src_mem.phys_base = all_src_mem.phys_base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].dest_mem.size = (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].dest_mem.base = all_dest_mem.base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].dest_mem.phys_base = all_dest_mem.phys_base + i * (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM); udata[i].call_serial_number = i + 1; init_completion(&(udata[i].copy_done)); rc = ipa_dma_async_memcpy(udata[i].dest_mem.phys_base, udata[i].src_mem.phys_base, (IPA_TEST_DMA_MEMCPY_BUFF_SIZE / IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM), ipa_test_dma_async_memcpy_cb_user_data, &udata[i]); if (rc) { IPA_UT_LOG("async memcpy initiation fail i=%d rc=%d\n", i, rc); is_fail = true; } } for (i = 0; i < IPA_DMA_TEST_ASYNC_PARALLEL_LOOP_NUM ; i++) wait_for_completion(&udata[i].copy_done); ipa_test_dma_destroy_buffs(&all_src_mem, &all_dest_mem); kfree(udata); rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } if (is_fail) { IPA_UT_LOG("async memcopy failed\n"); IPA_UT_TEST_FAIL_REPORT("async memcopy failed"); return -EFAULT; } return 0; } /** * TEST: Sync memory copy * * 1. dma enable * 2. sync memcpy with max packet size * 3. dma disable */ static int ipa_test_dma_sync_memcpy_max_pkt_size(void *priv) { int rc; IPA_UT_LOG("Test Start\n"); rc = ipa_dma_enable(); if (rc) { IPA_UT_LOG("DMA enable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail enable dma"); return rc; } rc = ipa_test_dma_memcpy_sync(IPA_TEST_DMA_MAX_PKT_SIZE, false); if (rc) { IPA_UT_LOG("sync memcpy failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("sync memcpy failed"); (void)ipa_dma_disable(); return rc; } rc = ipa_dma_disable(); if (rc) { IPA_UT_LOG("DMA disable failed rc=%d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail disable dma"); return rc; } return 0; } /* Suite definition block */ IPA_UT_DEFINE_SUITE_START(dma, "DMA for GSI", ipa_test_dma_setup, ipa_test_dma_teardown) { IPA_UT_ADD_TEST(control_api, "Control API", ipa_test_dma_control_api, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(memcpy_before_enable, "Call memcpy before dma enable and expect it to fail", ipa_test_dma_memcpy_before_enable, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(sync_memcpy, "Sync memory copy", ipa_test_dma_sync_memcpy, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(async_memcpy, "Async memory copy", ipa_test_dma_async_memcpy, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(sync_memcpy_in_loop, "Several sync memory copy iterations", ipa_test_dma_sync_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(async_memcpy_in_loop, "Several async memory copy iterations", ipa_test_dma_async_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(interleaved_sync_async_memcpy_in_loop, "Several interleaved sync and async memory copy iterations", ipa_test_dma_interleaved_sync_async_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(multi_threaded_multiple_sync_async_memcpy, "Several multi-threaded sync and async memory copy iterations", ipa_test_dma_mt_sync_async, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(parallel_async_memcpy_in_loop, "Several parallel async memory copy iterations", ipa_test_dma_parallel_async_memcpy_in_loop, true, IPA_HW_v3_0, IPA_HW_MAX), IPA_UT_ADD_TEST(sync_memcpy_max_pkt_size, "Sync memory copy with max packet size", ipa_test_dma_sync_memcpy_max_pkt_size, true, IPA_HW_v3_0, IPA_HW_MAX), } IPA_UT_DEFINE_SUITE_END(dma);
drivers/platform/msm/ipa/test/ipa_ut_suite_list.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -21,6 +21,7 @@ * No importance for order. */ IPA_UT_DECLARE_SUITE(mhi); IPA_UT_DECLARE_SUITE(dma); IPA_UT_DECLARE_SUITE(example); Loading @@ -31,6 +32,7 @@ IPA_UT_DECLARE_SUITE(example); IPA_UT_DEFINE_ALL_SUITES_START { IPA_UT_REGISTER_SUITE(mhi), IPA_UT_REGISTER_SUITE(dma), IPA_UT_REGISTER_SUITE(example), } IPA_UT_DEFINE_ALL_SUITES_END; Loading