287 lines
7.1 KiB
C
287 lines
7.1 KiB
C
/*
|
|
* 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;
|
|
}
|