/* * 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 #include #include #include #include #include #include #include #include #include #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; }