blob: c1ac55df9063805a060f84419c6c680ab7e1d142 [file] [log] [blame]
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <unistd.h>
#define OCMEM_KERNEL_TEST_MAGIC 0xc1
#define OCMEM_TEST_TYPE_NOMINAL \
_IO(OCMEM_KERNEL_TEST_MAGIC, 1)
#define OCMEM_TEST_TYPE_ADVERSARIAL \
_IO(OCMEM_KERNEL_TEST_MAGIC, 2)
#define OCMEM_TEST_TYPE_STRESS \
_IO(OCMEM_KERNEL_TEST_MAGIC, 3)
#define OCMEM_TEST_VERBOSE_MODE \
_IO(OCMEM_KERNEL_TEST_MAGIC, 4)
#define OCMEM_TEST_DEBUG_MODE \
_IO(OCMEM_KERNEL_TEST_MAGIC, 5)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
#define NUM_ITERATIONS (10)
static int ocmem_dev_fd;
static int iterations;
static int verbosity;
#define pr_debug(msg, args...) do { \
if (verbosity) \
printf("\n"msg, ##args);\
} while (0)
#define pr_err(msg, args...) do { \
fprintf(stderr, "\n"msg, ##args);\
} while (0)
enum test_types {
NOMINAL,
ADVERSARIAL,
STRESS,
REPEAT,
};
struct option testopts[] = {
{"Nominal", no_argument, NULL, 'n'},
{"Adversarial", no_argument, NULL, 'a'},
{"Stress", no_argument, NULL, 's'},
{"Repeatability", required_argument, NULL, 'r'},
{"Verbose", no_argument, NULL, 'v'},
{"Help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0},
};
static void usage(int ret)
{
printf("Usage: ocmem_test [OPTIONS] [TEST_TYPE]...\n"
"Runs the kernel mode ocmem tests specified by the TEST_TYPE\n"
"parameter. If no TEST_TYPE is specified, then the nominal\n"
" test is run.\n"
"\n"
"OPTIONS can be:\n"
" -v, --verbose run with debug messages enabled\n"
"\n"
"TEST_TYPE can be:\n"
" -n, --nominal run standard functionality tests\n"
" -a, --adversarial run tests that try to break the\n"
" driver\n"
" -s, --stress run tests that try to maximize the\n"
" capacity of the driver\n"
" -r, --repeatability run specified iterations of both the\n"
" nominal and adversarial tests\n");
exit(ret);
}
static unsigned int parse_command(int argc, char *const argv[])
{
int command;
unsigned ret = 0;
while ((command = getopt_long(argc, argv, "vnashr:", testopts,
NULL)) != -1) {
switch (command) {
case 'v':
verbosity = 1;
break;
case 'n':
ret |= 1 << NOMINAL;
break;
case 'a':
ret |= 1 << ADVERSARIAL;
break;
case 's':
ret |= 1 << STRESS;
break;
case 'r':
ret |= 1 << REPEAT;
if (optarg) {
iterations = atoi(optarg);
if (iterations <= 0)
iterations = NUM_ITERATIONS;
printf("Iterations: %d\n\n", iterations);
} else {
iterations = NUM_ITERATIONS;
printf("Using default iterations: %d\n",
iterations);
}
break;
case 'h':
usage(0);
default:
usage(-1);
}
}
return ret;
}
static int nominal_test(void)
{
int errors = 0;
int ret = 0;
pr_debug("OCMEM nominal test iocl invoked\n");
ret = ioctl(ocmem_dev_fd, OCMEM_TEST_TYPE_NOMINAL);
if (ret == -ENOTTY || ret == -EFAULT || ret == -EINVAL) {
pr_err("Failed to invoke ioctl (errno:%d)\n", ret);
exit(-1);
}
if (ret < 0) {
pr_err("OCMEM nominal test FAILED; failures %d\n", ret);
errors++;
}
return errors;
}
static int stress_test(void)
{
int errors = 0;
int ret = 0;
pr_debug("OCMEM nominal test ioctl invoked\n");
ret = ioctl(ocmem_dev_fd, OCMEM_TEST_TYPE_STRESS);
if (ret == -ENOTTY || ret == -EFAULT || ret == -EINVAL) {
pr_err("Failed to invoke ioctl (errno:%d)\n", ret);
exit(-1);
}
if (ret < 0) {
pr_err("OCMEM stress test FAILED; failures %d\n", ret);
errors++;
}
return errors;
}
static int adversarial_test(void)
{
int errors = 0;
int ret = 0;
pr_debug("OCMEM adversarial test ioctl invoked\n");
ret = ioctl(ocmem_dev_fd, OCMEM_TEST_TYPE_ADVERSARIAL);
if (ret == -ENOTTY || ret == -EFAULT || ret == -EINVAL) {
pr_err("Failed to invoke ioctl (errno:%d)\n", ret);
exit(-1);
}
if (ret < 0) {
pr_err("OCMEM adversarial test FAILED; failures %d\n", ret);
errors++;
}
return errors;
}
static int repeat_test(void)
{
unsigned int i = 0;
int errors = 0;
pr_debug("OCMEM repeat test invoked for %d iterations\n", iterations);
for (i = 0; i < iterations; i++) {
pr_debug("Repeat test iteration %d\n", i);
errors += nominal_test();
errors += stress_test();
}
return errors;
}
static int (*test_func[]) () = {
[NOMINAL] = nominal_test,
[ADVERSARIAL] = adversarial_test,
[STRESS] = stress_test,
[REPEAT] = repeat_test,
};
int main(int argc, char **argv)
{
int rc = -1;
int num_failures = 0;
unsigned int i = 0;
unsigned int test_mask = parse_command(argc, argv);
ocmem_dev_fd = open("/dev/ocmemtest", O_RDWR | O_SYNC);
if (ocmem_dev_fd < 0) {
pr_err("Failed to open OCMEM device\n");
return rc;
}
pr_debug("OCMEM opened ocmem_dev_fd (%d) successfully\n",
ocmem_dev_fd);
if (verbosity) {
if (ioctl(ocmem_dev_fd, OCMEM_TEST_VERBOSE_MODE,
&verbosity) < 0)
pr_err("Failed to set verbose mode in DLKM\n");
}
for (i = 0; i < (int)ARRAY_SIZE(test_func); i++) {
/* Look for the test that was selected */
if (!(test_mask & (1U << i)))
continue;
/* This test was selected, so run it */
rc = test_func[i]();
if (rc) {
pr_err("%s test case FAILED! rc:%d\n",
testopts[i].name, rc);
num_failures += rc;
}
}
if (num_failures)
pr_err("OCMEM: NUMBER OF TESTS FAILED: %d\n", num_failures);
close(ocmem_dev_fd);
pr_debug("OCMEM test exiting with %d failures\n", num_failures);
return -num_failures;
}