msm: ipa: Add support for IPA unit-test framework

Add IPA unit-test framework. The framework supports
definition and execution of tests that are grouped
into suites according to IPA functional blocks.
Debugfs file system is being used as a user interface.
An example test suite is added for reference.

Change-Id: Ide4ed54970c62f6485809c3bd63960536b4ace4f
CRs-Fixed: 1040200
Signed-off-by: Ghanim Fodi <gfodi@codeaurora.org>
This commit is contained in:
Ghanim Fodi 2016-08-04 12:08:25 +03:00
parent e94b446eac
commit 699fd2ab7f
12 changed files with 1476 additions and 1 deletions

View file

@ -114,7 +114,6 @@ config IPA3
Kernel and user-space processes can call the IPA driver
to configure IPA core.
config RMNET_IPA3
tristate "IPA3 RMNET WWAN Network Device"
depends on IPA3 && MSM_QMI_INTERFACE
@ -124,6 +123,16 @@ config RMNET_IPA3
for RmNet Data Driver and also exchange of QMI messages between
A7 and Q6 IPA-driver.
config IPA_UT
tristate "IPA Unit-Test Framework and Test Suites"
depends on IPA3 && DEBUG_FS
help
This Module implements IPA in-kernel test framework.
The framework supports defining and running tests, grouped
into suites according to the sub-unit of the IPA being tested.
The user interface to run and control the tests is debugfs file
system.
config SSM
tristate "QTI Secure Service Module"
depends on QSEECOM

View file

@ -1,4 +1,5 @@
obj-$(CONFIG_IPA) += ipa_v2/ ipa_clients/ ipa_common
obj-$(CONFIG_IPA3) += ipa_v3/ ipa_clients/ ipa_common
obj-$(CONFIG_IPA_UT) += test/
ipa_common += ipa_api.o ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o

View file

@ -2533,6 +2533,50 @@ int ipa_stop_gsi_channel(u32 clnt_hdl)
}
EXPORT_SYMBOL(ipa_stop_gsi_channel);
/**
* ipa_get_version_string() - Get string representation of IPA version
* @ver: IPA version
*
* Return: Constant string representation
*/
const char *ipa_get_version_string(enum ipa_hw_type ver)
{
const char *str;
switch (ver) {
case IPA_HW_v1_0:
str = "1.0";
break;
case IPA_HW_v1_1:
str = "1.1";
break;
case IPA_HW_v2_0:
str = "2.0";
break;
case IPA_HW_v2_1:
str = "2.1";
break;
case IPA_HW_v2_5:
str = "2.5/2.6";
break;
case IPA_HW_v2_6L:
str = "2.6L";
break;
case IPA_HW_v3_0:
str = "3.0";
break;
case IPA_HW_v3_1:
str = "3.1";
break;
default:
str = "Invalid version";
break;
}
return str;
}
EXPORT_SYMBOL(ipa_get_version_string);
static struct of_device_id ipa_plat_drv_match[] = {
{ .compatible = "qcom,ipa", },
{ .compatible = "qcom,ipa-smmu-ap-cb", },

View file

@ -355,5 +355,6 @@ u8 *ipa_write_16(u16 hw, u8 *dest);
u8 *ipa_write_8(u8 b, u8 *dest);
u8 *ipa_pad_to_64(u8 *dest);
u8 *ipa_pad_to_32(u8 *dest);
const char *ipa_get_version_string(enum ipa_hw_type ver);
#endif /* _IPA_COMMON_I_H_ */

View file

@ -2131,6 +2131,12 @@ void ipa3_debugfs_remove(void)
debugfs_remove_recursive(dent);
}
struct dentry *ipa_debugfs_get_root(void)
{
return dent;
}
EXPORT_SYMBOL(ipa_debugfs_get_root);
#else /* !CONFIG_DEBUG_FS */
void ipa3_debugfs_init(void) {}
void ipa3_debugfs_remove(void) {}

View file

@ -2012,4 +2012,5 @@ int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr,
u32 size, bool map);
int ipa3_ntn_init(void);
int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats);
struct dentry *ipa_debugfs_get_root(void);
#endif /* _IPA3_I_H_ */

View file

@ -0,0 +1,2 @@
obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o
ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o

View file

@ -0,0 +1,99 @@
/* Copyright (c) 2016, 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 "ipa_ut_framework.h"
/**
* Example IPA Unit-test suite
* To be a reference for writing new suites and tests.
* This suite is also used as unit-test for the testing framework itself.
* Structure:
* 1- Define the setup and teardown functions
* Not Mandatory. Null may be used as well
* 2- For each test, define its Run() function
* 3- Use IPA_UT_DEFINE_SUITE_START() to start defining the suite
* 4- use IPA_UT_ADD_TEST() for adding tests within
* the suite definition block
* 5- IPA_UT_DEFINE_SUITE_END() close the suite definition
*/
static int ipa_test_example_dummy;
static int ipa_test_example_suite_setup(void **ppriv)
{
IPA_UT_DBG("Start Setup - set 0x1234F\n");
ipa_test_example_dummy = 0x1234F;
*ppriv = (void *)&ipa_test_example_dummy;
return 0;
}
static int ipa_test_example_teardown(void *priv)
{
IPA_UT_DBG("Start Teardown\n");
IPA_UT_DBG("priv=0x%p - value=0x%x\n", priv, *((int *)priv));
return 0;
}
static int ipa_test_example_test1(void *priv)
{
IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv));
ipa_test_example_dummy++;
return 0;
}
static int ipa_test_example_test2(void *priv)
{
IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv));
ipa_test_example_dummy++;
return 0;
}
static int ipa_test_example_test3(void *priv)
{
IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv));
ipa_test_example_dummy++;
return 0;
}
static int ipa_test_example_test4(void *priv)
{
IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv));
ipa_test_example_dummy++;
IPA_UT_TEST_FAIL_REPORT("failed on test");
return -EFAULT;
}
/* Suite definition block */
IPA_UT_DEFINE_SUITE_START(example, "Example suite",
ipa_test_example_suite_setup, ipa_test_example_teardown)
{
IPA_UT_ADD_TEST(test1, "This is test number 1",
ipa_test_example_test1, false, IPA_HW_v1_0, IPA_HW_MAX),
IPA_UT_ADD_TEST(test2, "This is test number 2",
ipa_test_example_test2, false, IPA_HW_v1_0, IPA_HW_MAX),
IPA_UT_ADD_TEST(test3, "This is test number 3",
ipa_test_example_test3, false, IPA_HW_v1_1, IPA_HW_v2_6),
IPA_UT_ADD_TEST(test4, "This is test number 4",
ipa_test_example_test4, false, IPA_HW_v1_1, IPA_HW_MAX),
} IPA_UT_DEFINE_SUITE_END(example);

View file

@ -0,0 +1,969 @@
/* Copyright (c) 2016, 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/mutex.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/ipa.h>
#include "../ipa_v3/ipa_i.h"
#include "ipa_ut_framework.h"
#include "ipa_ut_suite_list.h"
#include "ipa_ut_i.h"
#define IPA_UT_DEBUG_WRITE_BUF_SIZE 256
#define IPA_UT_DEBUG_READ_BUF_SIZE 1024
#define IPA_UT_READ_WRITE_DBG_FILE_MODE \
(S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP)
/**
* struct ipa_ut_context - I/S context
* @inited: Will wait till IPA is ready. Will create the enable file
* @enabled: All tests and suite debugfs files are created
* @lock: Lock for mutual exclustion
* @ipa_dbgfs_root: IPA root debugfs folder
* @test_dbgfs_root: UT root debugfs folder. Sub-folder of IPA root
* @test_dbgfs_suites: Suites root debugfs folder. Sub-folder of UT root
*/
struct ipa_ut_context {
bool inited;
bool enabled;
struct mutex lock;
struct dentry *ipa_dbgfs_root;
struct dentry *test_dbgfs_root;
struct dentry *test_dbgfs_suites;
};
static ssize_t ipa_ut_dbgfs_enable_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t ipa_ut_dbgfs_enable_write(struct file *file,
const char __user *buf, size_t count, loff_t *ppos);
static ssize_t ipa_ut_dbgfs_test_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t ipa_ut_dbgfs_test_write(struct file *file,
const char __user *buf, size_t count, loff_t *ppos);
static int ipa_ut_dbgfs_all_test_open(struct inode *inode,
struct file *filp);
static int ipa_ut_dbgfs_regression_test_open(struct inode *inode,
struct file *filp);
static ssize_t ipa_ut_dbgfs_meta_test_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t ipa_ut_dbgfs_meta_test_write(struct file *file,
const char __user *buf, size_t count, loff_t *ppos);
static const struct file_operations ipa_ut_dbgfs_enable_fops = {
.read = ipa_ut_dbgfs_enable_read,
.write = ipa_ut_dbgfs_enable_write,
};
static const struct file_operations ipa_ut_dbgfs_test_fops = {
.read = ipa_ut_dbgfs_test_read,
.write = ipa_ut_dbgfs_test_write,
};
static const struct file_operations ipa_ut_dbgfs_all_test_fops = {
.open = ipa_ut_dbgfs_all_test_open,
.read = ipa_ut_dbgfs_meta_test_read,
.write = ipa_ut_dbgfs_meta_test_write,
};
static const struct file_operations ipa_ut_dbgfs_regression_test_fops = {
.open = ipa_ut_dbgfs_regression_test_open,
.read = ipa_ut_dbgfs_meta_test_read,
.write = ipa_ut_dbgfs_meta_test_write,
};
static struct ipa_ut_context *ipa_ut_ctx;
char *_IPA_UT_TEST_LOG_BUF_NAME;
struct ipa_ut_tst_fail_report _IPA_UT_TEST_FAIL_REPORT_DATA;
/**
* ipa_ut_show_suite_exec_summary() - Show tests run summary
* @suite: suite to print its running summary
*
* Print list of succeeded tests, failed tests and skipped tests
*
* Note: Assumes lock acquired
*/
static void ipa_ut_show_suite_exec_summary(const struct ipa_ut_suite *suite)
{
int i;
IPA_UT_DBG("Entry\n");
ipa_assert_on(!suite);
pr_info("\n\n");
pr_info("\t Suite '%s' summary\n", suite->meta_data->name);
pr_info("===========================\n");
pr_info("Successful tests\n");
pr_info("----------------\n");
for (i = 0 ; i < suite->tests_cnt ; i++) {
if (suite->tests[i].res != IPA_UT_TEST_RES_SUCCESS)
continue;
pr_info("\t%s\n", suite->tests[i].name);
}
pr_info("\nFailed tests\n");
pr_info("------------\n");
for (i = 0 ; i < suite->tests_cnt ; i++) {
if (suite->tests[i].res != IPA_UT_TEST_RES_FAIL)
continue;
pr_info("\t%s\n", suite->tests[i].name);
}
pr_info("\nSkipped tests\n");
pr_info("-------------\n");
for (i = 0 ; i < suite->tests_cnt ; i++) {
if (suite->tests[i].res != IPA_UT_TEST_RES_SKIP)
continue;
pr_info("\t%s\n", suite->tests[i].name);
}
pr_info("\n");
}
/**
* ipa_ut_dbgfs_meta_test_write() - Debugfs write func for a for a meta test
* @params: write fops
*
* Used to run all/regression tests in a suite
* Create log buffer that the test can use to store ongoing logs
* IPA clocks need to be voted.
* Run setup() once before running the tests and teardown() once after
* If no such call-backs then ignore it; if failed then fail the suite
* Print tests progress during running
* Test log and fail report will be showed only if the test failed.
* Finally show Summary of the suite tests running
*
* Note: If test supported IPA H/W version mismatch, skip it
* If a test lack run function, skip it
* If test doesn't belong to regression and it is regression run, skip it
* Note: Running mode: Do not stop running on failure
*
* Return: Negative in failure, given characters amount in success
*/
static ssize_t ipa_ut_dbgfs_meta_test_write(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
struct ipa_ut_suite *suite;
int i;
enum ipa_hw_type ipa_ver;
int rc = 0;
long meta_type;
bool tst_fail = false;
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
suite = file->f_inode->i_private;
ipa_assert_on(!suite);
meta_type = (long)(file->private_data);
IPA_UT_DBG("Meta test type %ld\n", meta_type);
_IPA_UT_TEST_LOG_BUF_NAME = kzalloc(_IPA_UT_TEST_LOG_BUF_SIZE,
GFP_KERNEL);
if (!_IPA_UT_TEST_LOG_BUF_NAME) {
IPA_UT_ERR("failed to allocate %d bytes\n",
_IPA_UT_TEST_LOG_BUF_SIZE);
rc = -ENOMEM;
goto unlock_mutex;
}
if (!suite->tests_cnt || !suite->tests) {
pr_info("No tests for suite '%s'\n", suite->meta_data->name);
goto free_mem;
}
ipa_ver = ipa_get_hw_type();
IPA_ACTIVE_CLIENTS_INC_SPECIAL("IPA_UT");
if (suite->meta_data->setup) {
pr_info("*** Suite '%s': Run setup ***\n",
suite->meta_data->name);
rc = suite->meta_data->setup(&suite->meta_data->priv);
if (rc) {
IPA_UT_ERR("Setup failed for suite %s\n",
suite->meta_data->name);
rc = -EFAULT;
goto release_clock;
}
} else {
pr_info("*** Suite '%s': No Setup ***\n",
suite->meta_data->name);
}
pr_info("*** Suite '%s': Run %s tests ***\n\n",
suite->meta_data->name,
meta_type == IPA_UT_META_TEST_REGRESSION ? "regression" : "all"
);
for (i = 0 ; i < suite->tests_cnt ; i++) {
if (meta_type == IPA_UT_META_TEST_REGRESSION &&
!suite->tests[i].run_in_regression) {
pr_info(
"*** Test '%s': Skip - Not in regression ***\n\n"
, suite->tests[i].name);
suite->tests[i].res = IPA_UT_TEST_RES_SKIP;
continue;
}
if (suite->tests[i].min_ipa_hw_ver > ipa_ver ||
suite->tests[i].max_ipa_hw_ver < ipa_ver) {
pr_info(
"*** Test '%s': Skip - IPA VER mismatch ***\n\n"
, suite->tests[i].name);
suite->tests[i].res = IPA_UT_TEST_RES_SKIP;
continue;
}
if (!suite->tests[i].run) {
pr_info(
"*** Test '%s': Skip - No Run function ***\n\n"
, suite->tests[i].name);
suite->tests[i].res = IPA_UT_TEST_RES_SKIP;
continue;
}
_IPA_UT_TEST_LOG_BUF_NAME[0] = '\0';
_IPA_UT_TEST_FAIL_REPORT_DATA.valid = false;
pr_info("*** Test '%s': Running... ***\n",
suite->tests[i].name);
rc = suite->tests[i].run(suite->meta_data->priv);
if (rc) {
tst_fail = true;
suite->tests[i].res = IPA_UT_TEST_RES_FAIL;
pr_info("%s", _IPA_UT_TEST_LOG_BUF_NAME);
} else {
suite->tests[i].res = IPA_UT_TEST_RES_SUCCESS;
}
pr_info(">>>>>>**** TEST '%s': %s ****<<<<<<\n",
suite->tests[i].name, tst_fail ? "FAIL" : "SUCCESS");
if (tst_fail && _IPA_UT_TEST_FAIL_REPORT_DATA.valid) {
pr_info("*** FAIL INFO:\n");
pr_info("\tFILE = %s\n\tFUNC = %s()\n\tLINE = %d\n",
_IPA_UT_TEST_FAIL_REPORT_DATA.file,
_IPA_UT_TEST_FAIL_REPORT_DATA.func,
_IPA_UT_TEST_FAIL_REPORT_DATA.line);
pr_info("\t%s\n", _IPA_UT_TEST_FAIL_REPORT_DATA.info);
}
pr_info("\n");
}
if (suite->meta_data->teardown) {
pr_info("*** Suite '%s': Run Teardown ***\n",
suite->meta_data->name);
rc = suite->meta_data->teardown(suite->meta_data->priv);
if (rc) {
IPA_UT_ERR("Teardown failed for suite %s\n",
suite->meta_data->name);
rc = -EFAULT;
goto release_clock;
}
} else {
pr_info("*** Suite '%s': No Teardown ***\n",
suite->meta_data->name);
}
ipa_ut_show_suite_exec_summary(suite);
release_clock:
IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IPA_UT");
free_mem:
kfree(_IPA_UT_TEST_LOG_BUF_NAME);
unlock_mutex:
mutex_unlock(&ipa_ut_ctx->lock);
return ((!rc && !tst_fail) ? count : -EFAULT);
}
/**
* ipa_ut_dbgfs_meta_test_read() - Debugfs read func for a meta test
* @params: read fops
*
* Meta test, is a test that describes other test or bunch of tests.
* for example, the 'all' test. Running this test will run all
* the tests in the suite.
*
* Show information regard the suite. E.g. name and description
* If regression - List the regression tests names
*
* Return: Amount of characters written to user space buffer
*/
static ssize_t ipa_ut_dbgfs_meta_test_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
char *buf;
struct ipa_ut_suite *suite;
int nbytes;
ssize_t cnt;
long meta_type;
int i;
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
suite = file->f_inode->i_private;
ipa_assert_on(!suite);
meta_type = (long)(file->private_data);
IPA_UT_DBG("Meta test type %ld\n", meta_type);
buf = kmalloc(IPA_UT_DEBUG_READ_BUF_SIZE, GFP_KERNEL);
if (!buf) {
IPA_UT_ERR("failed to allocate %d bytes\n",
IPA_UT_DEBUG_READ_BUF_SIZE);
cnt = 0;
goto unlock_mutex;
}
if (meta_type == IPA_UT_META_TEST_ALL) {
nbytes = scnprintf(buf, IPA_UT_DEBUG_READ_BUF_SIZE,
"\tMeta-test running all the tests in the suite:\n"
"\tSuite Name: %s\n"
"\tDescription: %s\n"
"\tNumber of test in suite: %zu\n",
suite->meta_data->name,
suite->meta_data->desc ?: "",
suite->tests_cnt);
} else {
nbytes = scnprintf(buf, IPA_UT_DEBUG_READ_BUF_SIZE,
"\tMeta-test running regression tests in the suite:\n"
"\tSuite Name: %s\n"
"\tDescription: %s\n"
"\tRegression tests:\n",
suite->meta_data->name,
suite->meta_data->desc ?: "");
for (i = 0 ; i < suite->tests_cnt ; i++) {
if (!suite->tests[i].run_in_regression)
continue;
nbytes += scnprintf(buf + nbytes,
IPA_UT_DEBUG_READ_BUF_SIZE - nbytes,
"\t\t%s\n", suite->tests[i].name);
}
}
cnt = simple_read_from_buffer(ubuf, count, ppos, buf, nbytes);
kfree(buf);
unlock_mutex:
mutex_unlock(&ipa_ut_ctx->lock);
return cnt;
}
/**
* ipa_ut_dbgfs_regression_test_open() - Debugfs open function for
* 'regression' tests
* @params: open fops
*
* Mark "Regression tests" for meta-tests later operations.
*
* Return: Zero (always success).
*/
static int ipa_ut_dbgfs_regression_test_open(struct inode *inode,
struct file *filp)
{
IPA_UT_DBG("Entry\n");
filp->private_data = (void *)(IPA_UT_META_TEST_REGRESSION);
return 0;
}
/**
* ipa_ut_dbgfs_all_test_open() - Debugfs open function for 'all' tests
* @params: open fops
*
* Mark "All tests" for meta-tests later operations.
*
* Return: Zero (always success).
*/
static int ipa_ut_dbgfs_all_test_open(struct inode *inode,
struct file *filp)
{
IPA_UT_DBG("Entry\n");
filp->private_data = (void *)(IPA_UT_META_TEST_ALL);
return 0;
}
/**
* ipa_ut_dbgfs_test_write() - Debugfs write function for a test
* @params: write fops
*
* Used to run a test.
* Create log buffer that the test can use to store ongoing logs
* IPA clocks need to be voted.
* Run setup() before the test and teardown() after the tests.
* If no such call-backs then ignore it; if failed then fail the test
* If all succeeds, no printing to user
* If failed, test logs and failure report will be printed to user
*
* Note: Test must has run function and it's supported IPA H/W version
* must be matching. Otherwise test will fail.
*
* Return: Negative in failure, given characters amount in success
*/
static ssize_t ipa_ut_dbgfs_test_write(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
struct ipa_ut_test *test;
struct ipa_ut_suite *suite;
bool tst_fail = false;
int rc = 0;
enum ipa_hw_type ipa_ver;
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
test = file->f_inode->i_private;
ipa_assert_on(!test);
_IPA_UT_TEST_LOG_BUF_NAME = kzalloc(_IPA_UT_TEST_LOG_BUF_SIZE,
GFP_KERNEL);
if (!_IPA_UT_TEST_LOG_BUF_NAME) {
IPA_UT_ERR("failed to allocate %d bytes\n",
_IPA_UT_TEST_LOG_BUF_SIZE);
rc = -ENOMEM;
goto unlock_mutex;
}
if (!test->run) {
IPA_UT_ERR("*** Test %s - No run func ***\n",
test->name);
rc = -EFAULT;
goto free_mem;
}
ipa_ver = ipa_get_hw_type();
if (test->min_ipa_hw_ver > ipa_ver ||
test->max_ipa_hw_ver < ipa_ver) {
IPA_UT_ERR("Cannot run test %s on IPA HW Ver %s\n",
test->name, ipa_get_version_string(ipa_ver));
rc = -EFAULT;
goto free_mem;
}
IPA_ACTIVE_CLIENTS_INC_SPECIAL("IPA_UT");
suite = test->suite;
if (suite && suite->meta_data->setup) {
IPA_UT_DBG("*** Suite '%s': Run setup ***\n",
suite->meta_data->name);
rc = suite->meta_data->setup(&suite->meta_data->priv);
if (rc) {
IPA_UT_ERR("Setup failed for suite %s\n",
suite->meta_data->name);
rc = -EFAULT;
goto release_clock;
}
} else {
IPA_UT_DBG("*** Suite '%s': No Setup ***\n",
suite->meta_data->name);
}
IPA_UT_DBG("*** Test '%s': Running... ***\n", test->name);
_IPA_UT_TEST_FAIL_REPORT_DATA.valid = false;
rc = test->run(suite->meta_data->priv);
if (rc)
tst_fail = true;
IPA_UT_DBG("*** Test %s - ***\n", tst_fail ? "FAIL" : "SUCCESS");
if (tst_fail) {
pr_info("=================>>>>>>>>>>>\n");
pr_info("%s\n", _IPA_UT_TEST_LOG_BUF_NAME);
pr_info("**** TEST %s FAILED ****\n", test->name);
if (_IPA_UT_TEST_FAIL_REPORT_DATA.valid) {
pr_info("*** FAIL INFO:\n");
pr_info("\tFILE = %s\n\tFUNC = %s()\n\tLINE = %d\n",
_IPA_UT_TEST_FAIL_REPORT_DATA.file,
_IPA_UT_TEST_FAIL_REPORT_DATA.func,
_IPA_UT_TEST_FAIL_REPORT_DATA.line);
pr_info("\t%s\n", _IPA_UT_TEST_FAIL_REPORT_DATA.info);
}
pr_info("<<<<<<<<<<<=================\n");
}
if (suite && suite->meta_data->teardown) {
IPA_UT_DBG("*** Suite '%s': Run Teardown ***\n",
suite->meta_data->name);
rc = suite->meta_data->teardown(suite->meta_data->priv);
if (rc) {
IPA_UT_ERR("Teardown failed for suite %s\n",
suite->meta_data->name);
rc = -EFAULT;
goto release_clock;
}
} else {
IPA_UT_DBG("*** Suite '%s': No Teardown ***\n",
suite->meta_data->name);
}
release_clock:
IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IPA_UT");
free_mem:
kfree(_IPA_UT_TEST_LOG_BUF_NAME);
unlock_mutex:
mutex_unlock(&ipa_ut_ctx->lock);
return ((!rc && !tst_fail) ? count : -EFAULT);
}
/**
* ipa_ut_dbgfs_test_read() - Debugfs read function for a test
* @params: read fops
*
* print information regard the test. E.g. name and description
*
* Return: Amount of characters written to user space buffer
*/
static ssize_t ipa_ut_dbgfs_test_read(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
char *buf;
struct ipa_ut_test *test;
int nbytes;
ssize_t cnt;
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
test = file->f_inode->i_private;
ipa_assert_on(!test);
buf = kmalloc(IPA_UT_DEBUG_READ_BUF_SIZE, GFP_KERNEL);
if (!buf) {
IPA_UT_ERR("failed to allocate %d bytes\n",
IPA_UT_DEBUG_READ_BUF_SIZE);
cnt = 0;
goto unlock_mutex;
}
nbytes = scnprintf(buf, IPA_UT_DEBUG_READ_BUF_SIZE,
"\t Test Name: %s\n"
"\t Description: %s\n"
"\t Suite Name: %s\n"
"\t Run In Regression: %s\n"
"\t Supported IPA versions: [%s -> %s]\n",
test->name, test->desc ?: "", test->suite->meta_data->name,
test->run_in_regression ? "Yes" : "No",
ipa_get_version_string(test->min_ipa_hw_ver),
test->max_ipa_hw_ver == IPA_HW_MAX ? "MAX" :
ipa_get_version_string(test->max_ipa_hw_ver));
if (nbytes > count)
IPA_UT_ERR("User buf too small - return partial info\n");
cnt = simple_read_from_buffer(ubuf, count, ppos, buf, nbytes);
kfree(buf);
unlock_mutex:
mutex_unlock(&ipa_ut_ctx->lock);
return cnt;
}
/**
* ipa_ut_framework_load_suites() - Load tests and expose them to user space
*
* Creates debugfs folder for each suite and then file for each test in it.
* Create debugfs "all" file for each suite for meta-test to run all tests.
*
* Note: Assumes lock acquired
*
* Return: Zero in success, otherwise in failure
*/
int ipa_ut_framework_load_suites(void)
{
int suite_idx;
int tst_idx;
struct ipa_ut_suite *suite;
struct dentry *s_dent;
struct dentry *f_dent;
IPA_UT_DBG("Entry\n");
for (suite_idx = IPA_UT_SUITE_FIRST_INDEX;
suite_idx < IPA_UT_SUITES_COUNT; suite_idx++) {
suite = IPA_UT_GET_SUITE(suite_idx);
if (!suite->meta_data->name) {
IPA_UT_ERR("No suite name\n");
return -EFAULT;
}
s_dent = debugfs_create_dir(suite->meta_data->name,
ipa_ut_ctx->test_dbgfs_suites);
if (!s_dent || IS_ERR(s_dent)) {
IPA_UT_ERR("fail create dbg entry - suite %s\n",
suite->meta_data->name);
return -EFAULT;
}
for (tst_idx = 0; tst_idx < suite->tests_cnt ; tst_idx++) {
if (!suite->tests[tst_idx].name) {
IPA_UT_ERR("No test name on suite %s\n",
suite->meta_data->name);
return -EFAULT;
}
f_dent = debugfs_create_file(
suite->tests[tst_idx].name,
IPA_UT_READ_WRITE_DBG_FILE_MODE, s_dent,
&suite->tests[tst_idx],
&ipa_ut_dbgfs_test_fops);
if (!f_dent || IS_ERR(f_dent)) {
IPA_UT_ERR("fail create dbg entry - tst %s\n",
suite->tests[tst_idx].name);
return -EFAULT;
}
}
/* entry for meta-test all to run all tests in suites */
f_dent = debugfs_create_file(_IPA_UT_RUN_ALL_TEST_NAME,
IPA_UT_READ_WRITE_DBG_FILE_MODE, s_dent,
suite, &ipa_ut_dbgfs_all_test_fops);
if (!f_dent || IS_ERR(f_dent)) {
IPA_UT_ERR("fail to create dbg entry - %s\n",
_IPA_UT_RUN_ALL_TEST_NAME);
return -EFAULT;
}
/*
* entry for meta-test regression to run all regression
* tests in suites
*/
f_dent = debugfs_create_file(_IPA_UT_RUN_REGRESSION_TEST_NAME,
IPA_UT_READ_WRITE_DBG_FILE_MODE, s_dent,
suite, &ipa_ut_dbgfs_regression_test_fops);
if (!f_dent || IS_ERR(f_dent)) {
IPA_UT_ERR("fail to create dbg entry - %s\n",
_IPA_UT_RUN_ALL_TEST_NAME);
return -EFAULT;
}
}
return 0;
}
/**
* ipa_ut_framework_enable() - Enable the framework
*
* Creates the tests and suites debugfs entries and load them.
* This will expose the tests to user space.
*
* Return: Zero in success, otherwise in failure
*/
static int ipa_ut_framework_enable(void)
{
int ret = 0;
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
if (ipa_ut_ctx->enabled) {
IPA_UT_ERR("Already enabled\n");
goto unlock_mutex;
}
ipa_ut_ctx->test_dbgfs_suites = debugfs_create_dir("suites",
ipa_ut_ctx->test_dbgfs_root);
if (!ipa_ut_ctx->test_dbgfs_suites ||
IS_ERR(ipa_ut_ctx->test_dbgfs_suites)) {
IPA_UT_ERR("failed to create suites debugfs dir\n");
ret = -EFAULT;
goto unlock_mutex;
}
if (ipa_ut_framework_load_suites()) {
IPA_UT_ERR("failed to load the suites into debugfs\n");
ret = -EFAULT;
goto fail_clean_suites_dbgfs;
}
ipa_ut_ctx->enabled = true;
goto unlock_mutex;
fail_clean_suites_dbgfs:
debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_suites);
unlock_mutex:
mutex_unlock(&ipa_ut_ctx->lock);
return ret;
}
/**
* ipa_ut_framework_disable() - Disable the framework
*
* Remove the tests and suites debugfs exposure.
*
* Return: Zero in success, otherwise in failure
*/
static int ipa_ut_framework_disable(void)
{
int ret = 0;
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
if (!ipa_ut_ctx->enabled) {
IPA_UT_ERR("Already disabled\n");
goto unlock_mutex;
}
debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_suites);
ipa_ut_ctx->enabled = false;
unlock_mutex:
mutex_unlock(&ipa_ut_ctx->lock);
return ret;
}
/**
* ipa_ut_dbgfs_enable_write() - Debugfs enable file write fops
* @params: write fops
*
* Input should be number. If 0, then disable. Otherwise enable.
*
* Return: if failed then negative value, if succeeds, amount of given chars
*/
static ssize_t ipa_ut_dbgfs_enable_write(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
char lcl_buf[IPA_UT_DEBUG_WRITE_BUF_SIZE];
s8 option = 0;
int ret;
IPA_UT_DBG("Entry\n");
if (sizeof(lcl_buf) < count + 1) {
IPA_UT_ERR("No enough space\n");
return -E2BIG;
}
if (copy_from_user(lcl_buf, buf, count)) {
IPA_UT_ERR("fail to copy buf from user space\n");
return -EFAULT;
}
lcl_buf[count] = '\0';
if (kstrtos8(lcl_buf, 0, &option)) {
IPA_UT_ERR("fail convert str to s8\n");
return -EINVAL;
}
if (option == 0)
ret = ipa_ut_framework_disable();
else
ret = ipa_ut_framework_enable();
return ret ?: count;
}
/**
* ipa_ut_dbgfs_enable_read() - Debugfs enable file read fops
* @params: read fops
*
* To show to user space if the I/S is enabled or disabled.
*
* Return: amount of characters returned to user space
*/
static ssize_t ipa_ut_dbgfs_enable_read(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
const char *status;
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
status = ipa_ut_ctx->enabled ?
"Enabled - Write 0 to disable\n" :
"Disabled - Write 1 to enable\n";
mutex_unlock(&ipa_ut_ctx->lock);
return simple_read_from_buffer(ubuf, count, ppos,
status, strlen(status));
}
/**
* ipa_ut_framework_init() - Unit-tests framework initialization
*
* Complete tests initialization: Each tests needs to point to it's
* corresponing suite.
* Creates the framework debugfs root directory under IPA directory.
* Create enable debugfs file - to enable/disable the framework.
*
* Return: Zero in success, otherwise in failure
*/
static int ipa_ut_framework_init(void)
{
struct dentry *dfile_enable;
int ret;
int suite_idx;
int test_idx;
struct ipa_ut_suite *suite;
IPA_UT_DBG("Entry\n");
ipa_assert_on(!ipa_ut_ctx);
ipa_ut_ctx->ipa_dbgfs_root = ipa_debugfs_get_root();
if (!ipa_ut_ctx->ipa_dbgfs_root) {
IPA_UT_ERR("No IPA debugfs root entry\n");
return -EFAULT;
}
mutex_lock(&ipa_ut_ctx->lock);
/* tests needs to point to their corresponding suites structures */
for (suite_idx = IPA_UT_SUITE_FIRST_INDEX;
suite_idx < IPA_UT_SUITES_COUNT; suite_idx++) {
suite = IPA_UT_GET_SUITE(suite_idx);
ipa_assert_on(!suite);
if (!suite->tests) {
IPA_UT_DBG("No tests for suite %s\n",
suite->meta_data->name);
continue;
}
for (test_idx = 0; test_idx < suite->tests_cnt; test_idx++) {
suite->tests[test_idx].suite = suite;
IPA_UT_DBG("Updating test %s info for suite %s\n",
suite->tests[test_idx].name,
suite->meta_data->name);
}
}
ipa_ut_ctx->test_dbgfs_root = debugfs_create_dir("test",
ipa_ut_ctx->ipa_dbgfs_root);
if (!ipa_ut_ctx->test_dbgfs_root ||
IS_ERR(ipa_ut_ctx->test_dbgfs_root)) {
IPA_UT_ERR("failed to create test debugfs dir\n");
ret = -EFAULT;
goto unlock_mutex;
}
dfile_enable = debugfs_create_file("enable",
IPA_UT_READ_WRITE_DBG_FILE_MODE,
ipa_ut_ctx->test_dbgfs_root, 0, &ipa_ut_dbgfs_enable_fops);
if (!dfile_enable || IS_ERR(dfile_enable)) {
IPA_UT_ERR("failed to create enable debugfs file\n");
ret = -EFAULT;
goto fail_clean_dbgfs;
}
ipa_ut_ctx->inited = true;
IPA_UT_DBG("Done\n");
ret = 0;
goto unlock_mutex;
fail_clean_dbgfs:
debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_root);
unlock_mutex:
mutex_unlock(&ipa_ut_ctx->lock);
return ret;
}
/**
* ipa_ut_framework_destroy() - Destroy the UT framework info
*
* Disable it if enabled.
* Remove the debugfs entries using the root entry
*/
static void ipa_ut_framework_destroy(void)
{
IPA_UT_DBG("Entry\n");
mutex_lock(&ipa_ut_ctx->lock);
if (ipa_ut_ctx->enabled)
ipa_ut_framework_disable();
if (ipa_ut_ctx->inited)
debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_root);
mutex_unlock(&ipa_ut_ctx->lock);
}
/**
* ipa_ut_ipa_ready_cb() - IPA ready CB
*
* Once IPA is ready starting initializing the unit-test framework
*/
static void ipa_ut_ipa_ready_cb(void *user_data)
{
IPA_UT_DBG("Entry\n");
(void)ipa_ut_framework_init();
}
/**
* ipa_ut_module_init() - Module init
*
* Create the framework context, wait for IPA driver readiness
* and Initialize it.
* If IPA driver already ready, continue initialization immediately.
* if not, wait for IPA ready notification by IPA driver context
*/
static int __init ipa_ut_module_init(void)
{
int ret;
IPA_UT_INFO("Loading IPA test module...\n");
ipa_ut_ctx = kzalloc(sizeof(struct ipa_ut_context), GFP_KERNEL);
if (!ipa_ut_ctx) {
IPA_UT_ERR("Failed to allocate ctx\n");
return -ENOMEM;
}
mutex_init(&ipa_ut_ctx->lock);
if (!ipa_is_ready()) {
IPA_UT_DBG("IPA driver not ready, registering callback\n");
ret = ipa_register_ipa_ready_cb(ipa_ut_ipa_ready_cb, NULL);
/*
* If we received -EEXIST, IPA has initialized. So we need
* to continue the initing process.
*/
if (ret != -EEXIST) {
if (ret) {
IPA_UT_ERR("IPA CB reg failed - %d\n", ret);
kfree(ipa_ut_ctx);
ipa_ut_ctx = NULL;
}
return ret;
}
}
ret = ipa_ut_framework_init();
if (ret) {
IPA_UT_ERR("framework init failed\n");
kfree(ipa_ut_ctx);
ipa_ut_ctx = NULL;
}
return ret;
}
/**
* ipa_ut_module_exit() - Module exit function
*
* Destroys the Framework and removes its context
*/
static void ipa_ut_module_exit(void)
{
IPA_UT_DBG("Entry\n");
if (!ipa_ut_ctx)
return;
ipa_ut_framework_destroy();
kfree(ipa_ut_ctx);
ipa_ut_ctx = NULL;
}
module_init(ipa_ut_module_init);
module_exit(ipa_ut_module_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("IPA Unit Test module");

View file

@ -0,0 +1,222 @@
/* Copyright (c) 2016, 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.
*/
#ifndef _IPA_UT_FRAMEWORK_H_
#define _IPA_UT_FRAMEWORK_H_
#include <linux/kernel.h>
#include "../ipa_common_i.h"
#include "ipa_ut_i.h"
#define IPA_UT_DRV_NAME "ipa_ut"
#define IPA_UT_DBG(fmt, args...) \
do { \
pr_debug(IPA_UT_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_UT_DBG_LOW(fmt, args...) \
do { \
pr_debug(IPA_UT_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_UT_ERR(fmt, args...) \
do { \
pr_err(IPA_UT_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_UT_INFO(fmt, args...) \
do { \
pr_info(IPA_UT_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
/**
* struct ipa_ut_tst_fail_report - Information on test failure
* @valid: When a test posts a report, valid will be marked true
* @file: File name containing the failed test.
* @line: Number of line in the file where the test failed.
* @func: Function where the test failed in.
* @info: Information about the failure.
*/
struct ipa_ut_tst_fail_report {
bool valid;
const char *file;
int line;
const char *func;
const char *info;
};
/**
* Report on test failure
* To be used by tests.
*/
#define IPA_UT_TEST_FAIL_REPORT(__info) \
do { \
extern struct ipa_ut_tst_fail_report \
_IPA_UT_TEST_FAIL_REPORT_DATA; \
_IPA_UT_TEST_FAIL_REPORT_DATA.valid = true; \
_IPA_UT_TEST_FAIL_REPORT_DATA.file = __FILENAME__; \
_IPA_UT_TEST_FAIL_REPORT_DATA.line = __LINE__; \
_IPA_UT_TEST_FAIL_REPORT_DATA.func = __func__; \
if (__info) \
_IPA_UT_TEST_FAIL_REPORT_DATA.info = __info; \
else \
_IPA_UT_TEST_FAIL_REPORT_DATA.info = ""; \
} while (0)
/**
* To be used by tests to log progress and ongoing information
* Logs are not printed to user, but saved to a buffer.
* I/S shall print the buffer at different occasions - e.g. in test failure
*/
#define IPA_UT_LOG(fmt, args...) \
do { \
extern char *_IPA_UT_TEST_LOG_BUF_NAME; \
char __buf[512]; \
IPA_UT_DBG(fmt, args); \
scnprintf(__buf, sizeof(__buf), \
fmt, args); \
strlcat(_IPA_UT_TEST_LOG_BUF_NAME, __buf, sizeof(__buf)); \
} while (0)
/**
* struct ipa_ut_suite_meta - Suite meta-data
* @name: Suite unique name
* @desc: Suite description
* @setup: Setup Call-back of the suite
* @teardown: Teardown Call-back of the suite
* @priv: Private pointer of the suite
*
* Setup/Teardown will be called once for the suite when running a tests of it.
* priv field is shared between the Setup/Teardown and the tests
*/
struct ipa_ut_suite_meta {
char *name;
char *desc;
int (*setup)(void **ppriv);
int (*teardown)(void *priv);
void *priv;
};
/* Test suite data structure declaration */
struct ipa_ut_suite;
/**
* struct ipa_ut_test - Test information
* @name: Test name
* @desc: Test description
* @run: Test execution call-back
* @run_in_regression: To run this test as part of regression?
* @min_ipa_hw_ver: Minimum IPA H/W version where the test is supported?
* @max_ipa_hw_ver: Maximum IPA H/W version where the test is supported?
* @suite: Pointer to suite containing this test
* @res: Test execution result. Will be updated after running a test as part
* of suite tests run
*/
struct ipa_ut_test {
char *name;
char *desc;
int (*run)(void *priv);
bool run_in_regression;
int min_ipa_hw_ver;
int max_ipa_hw_ver;
struct ipa_ut_suite *suite;
enum ipa_ut_test_result res;
};
/**
* struct ipa_ut_suite - Suite information
* @meta_data: Pointer to meta-data structure of the suite
* @tests: Pointer to array of tests belongs to the suite
* @tests_cnt: Number of tests
*/
struct ipa_ut_suite {
struct ipa_ut_suite_meta *meta_data;
struct ipa_ut_test *tests;
size_t tests_cnt;
};
/**
* Add a test to a suite.
* Will add entry to tests array and update its info with
* the given info, thus adding new test.
*/
#define IPA_UT_ADD_TEST(__name, __desc, __run, __run_in_regression, \
__min_ipa_hw_ver, __max_ipa__hw_ver) \
{ \
.name = #__name, \
.desc = __desc, \
.run = __run, \
.run_in_regression = __run_in_regression, \
.min_ipa_hw_ver = __min_ipa_hw_ver, \
.max_ipa_hw_ver = __max_ipa__hw_ver, \
.suite = NULL, \
}
/**
* Declare a suite
* Every suite need to be declared before it is registered.
*/
#define IPA_UT_DECLARE_SUITE(__name) \
extern struct ipa_ut_suite _IPA_UT_SUITE_DATA(__name)
/**
* Register a suite
* Registering a suite is mandatory so it will be considered.
*/
#define IPA_UT_REGISTER_SUITE(__name) \
(&_IPA_UT_SUITE_DATA(__name))
/**
* Start/End suite definition
* Will create the suite global structures and adds adding tests to it.
* Use IPA_UT_ADD_TEST() with these macros to add tests when defining
* a suite
*/
#define IPA_UT_DEFINE_SUITE_START(__name, __desc, __setup, __teardown) \
static struct ipa_ut_suite_meta _IPA_UT_SUITE_META_DATA(__name) = \
{ \
.name = #__name, \
.desc = __desc, \
.setup = __setup, \
.teardown = __teardown, \
}; \
static struct ipa_ut_test _IPA_UT_SUITE_TESTS(__name)[] =
#define IPA_UT_DEFINE_SUITE_END(__name) \
; \
struct ipa_ut_suite _IPA_UT_SUITE_DATA(__name) = \
{ \
.meta_data = &_IPA_UT_SUITE_META_DATA(__name), \
.tests = _IPA_UT_SUITE_TESTS(__name), \
.tests_cnt = ARRAY_SIZE(_IPA_UT_SUITE_TESTS(__name)), \
}
#endif /* _IPA_UT_FRAMEWORK_H_ */

View file

@ -0,0 +1,86 @@
/* Copyright (c) 2016, 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.
*/
#ifndef _IPA_UT_I_H_
#define _IPA_UT_I_H_
/* Suite data global structure name */
#define _IPA_UT_SUITE_DATA(__name) ipa_ut_ ##__name ##_data
/* Suite meta-data global structure name */
#define _IPA_UT_SUITE_META_DATA(__name) ipa_ut_ ##__name ##_meta_data
/* Suite global array of tests */
#define _IPA_UT_SUITE_TESTS(__name) ipa_ut_ ##__name ##_tests
/* Global array of all suites */
#define _IPA_UT_ALL_SUITES ipa_ut_all_suites_data
/* Meta-test "all" name - test to run all tests in given suite */
#define _IPA_UT_RUN_ALL_TEST_NAME "all"
/**
* Meta-test "regression" name -
* test to run all regression tests in given suite
*/
#define _IPA_UT_RUN_REGRESSION_TEST_NAME "regression"
/* Test Log buffer name and size */
#define _IPA_UT_TEST_LOG_BUF_NAME ipa_ut_tst_log_buf
#define _IPA_UT_TEST_LOG_BUF_SIZE 2048
/* Global structure for test fail execution result information */
#define _IPA_UT_TEST_FAIL_REPORT_DATA ipa_ut_tst_fail_report_data
/* Start/End definitions of the array of suites */
#define IPA_UT_DEFINE_ALL_SUITES_START \
static struct ipa_ut_suite *_IPA_UT_ALL_SUITES[] =
#define IPA_UT_DEFINE_ALL_SUITES_END
/**
* Suites iterator - Array-like container
* First index, number of elements and element fetcher
*/
#define IPA_UT_SUITE_FIRST_INDEX 0
#define IPA_UT_SUITES_COUNT \
ARRAY_SIZE(_IPA_UT_ALL_SUITES)
#define IPA_UT_GET_SUITE(__index) \
_IPA_UT_ALL_SUITES[__index]
/**
* enum ipa_ut_test_result - Test execution result
* @IPA_UT_TEST_RES_FAIL: Test executed and failed
* @IPA_UT_TEST_RES_SUCCESS: Test executed and succeeded
* @IPA_UT_TEST_RES_SKIP: Test was not executed.
*
* When running all tests in a suite, a specific test could
* be skipped and not executed. For example due to mismatch of
* IPA H/W version.
*/
enum ipa_ut_test_result {
IPA_UT_TEST_RES_FAIL,
IPA_UT_TEST_RES_SUCCESS,
IPA_UT_TEST_RES_SKIP,
};
/**
* enum ipa_ut_meta_test_type - Type of suite meta-test
* @IPA_UT_META_TEST_ALL: Represents all tests in suite
* @IPA_UT_META_TEST_REGRESSION: Represents all regression tests in suite
*/
enum ipa_ut_meta_test_type {
IPA_UT_META_TEST_ALL,
IPA_UT_META_TEST_REGRESSION,
};
#endif /* _IPA_UT_I_H_ */

View file

@ -0,0 +1,35 @@
/* Copyright (c) 2016, 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.
*/
#ifndef _IPA_UT_SUITE_LIST_H_
#define _IPA_UT_SUITE_LIST_H_
#include "ipa_ut_framework.h"
#include "ipa_ut_i.h"
/**
* Declare every suite here so that it will be found later below
* No importance for order.
*/
IPA_UT_DECLARE_SUITE(example);
/**
* Register every suite inside the below block.
* Unregistered suites will be ignored
*/
IPA_UT_DEFINE_ALL_SUITES_START
{
IPA_UT_REGISTER_SUITE(example),
} IPA_UT_DEFINE_ALL_SUITES_END;
#endif /* _IPA_UT_SUITE_LIST_H_ */