|  | /* SPDX-License-Identifier: MIT */ | 
|  |  | 
|  | /* | 
|  | * Copyright © 2019 Intel Corporation | 
|  | */ | 
|  |  | 
|  | #include <linux/compiler.h> | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/module.h> | 
|  | #include <linux/sched/signal.h> | 
|  | #include <linux/slab.h> | 
|  |  | 
|  | #include "selftest.h" | 
|  |  | 
|  | enum { | 
|  | #define selftest(n, func) __idx_##n, | 
|  | #include "selftests.h" | 
|  | #undef selftest | 
|  | }; | 
|  |  | 
|  | #define selftest(n, f) [__idx_##n] = { .name = #n, .func = f }, | 
|  | static struct selftest { | 
|  | bool enabled; | 
|  | const char *name; | 
|  | int (*func)(void); | 
|  | } selftests[] = { | 
|  | #include "selftests.h" | 
|  | }; | 
|  | #undef selftest | 
|  |  | 
|  | /* Embed the line number into the parameter name so that we can order tests */ | 
|  | #define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n)) | 
|  | #define selftest_0(n, func, id) \ | 
|  | module_param_named(id, selftests[__idx_##n].enabled, bool, 0400); | 
|  | #define selftest(n, func) selftest_0(n, func, param(n)) | 
|  | #include "selftests.h" | 
|  | #undef selftest | 
|  |  | 
|  | int __sanitycheck__(void) | 
|  | { | 
|  | pr_debug("Hello World!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static char *__st_filter; | 
|  |  | 
|  | static bool apply_subtest_filter(const char *caller, const char *name) | 
|  | { | 
|  | char *filter, *sep, *tok; | 
|  | bool result = true; | 
|  |  | 
|  | filter = kstrdup(__st_filter, GFP_KERNEL); | 
|  | for (sep = filter; (tok = strsep(&sep, ","));) { | 
|  | bool allow = true; | 
|  | char *sl; | 
|  |  | 
|  | if (*tok == '!') { | 
|  | allow = false; | 
|  | tok++; | 
|  | } | 
|  |  | 
|  | if (*tok == '\0') | 
|  | continue; | 
|  |  | 
|  | sl = strchr(tok, '/'); | 
|  | if (sl) { | 
|  | *sl++ = '\0'; | 
|  | if (strcmp(tok, caller)) { | 
|  | if (allow) | 
|  | result = false; | 
|  | continue; | 
|  | } | 
|  | tok = sl; | 
|  | } | 
|  |  | 
|  | if (strcmp(tok, name)) { | 
|  | if (allow) | 
|  | result = false; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | result = allow; | 
|  | break; | 
|  | } | 
|  | kfree(filter); | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | int | 
|  | __subtests(const char *caller, const struct subtest *st, int count, void *data) | 
|  | { | 
|  | int err; | 
|  |  | 
|  | for (; count--; st++) { | 
|  | cond_resched(); | 
|  | if (signal_pending(current)) | 
|  | return -EINTR; | 
|  |  | 
|  | if (!apply_subtest_filter(caller, st->name)) | 
|  | continue; | 
|  |  | 
|  | pr_info("dma-buf: Running %s/%s\n", caller, st->name); | 
|  |  | 
|  | err = st->func(data); | 
|  | if (err && err != -EINTR) { | 
|  | pr_err("dma-buf/%s: %s failed with error %d\n", | 
|  | caller, st->name, err); | 
|  | return err; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void set_default_test_all(struct selftest *st, unsigned long count) | 
|  | { | 
|  | unsigned long i; | 
|  |  | 
|  | for (i = 0; i < count; i++) | 
|  | if (st[i].enabled) | 
|  | return; | 
|  |  | 
|  | for (i = 0; i < count; i++) | 
|  | st[i].enabled = true; | 
|  | } | 
|  |  | 
|  | static int run_selftests(struct selftest *st, unsigned long count) | 
|  | { | 
|  | int err = 0; | 
|  |  | 
|  | set_default_test_all(st, count); | 
|  |  | 
|  | /* Tests are listed in natural order in selftests.h */ | 
|  | for (; count--; st++) { | 
|  | if (!st->enabled) | 
|  | continue; | 
|  |  | 
|  | pr_info("dma-buf: Running %s\n", st->name); | 
|  | err = st->func(); | 
|  | if (err) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (WARN(err > 0 || err == -ENOTTY, | 
|  | "%s returned %d, conflicting with selftest's magic values!\n", | 
|  | st->name, err)) | 
|  | err = -1; | 
|  |  | 
|  | return err; | 
|  | } | 
|  |  | 
|  | static int __init st_init(void) | 
|  | { | 
|  | return run_selftests(selftests, ARRAY_SIZE(selftests)); | 
|  | } | 
|  |  | 
|  | static void __exit st_exit(void) | 
|  | { | 
|  | } | 
|  |  | 
|  | module_param_named(st_filter, __st_filter, charp, 0400); | 
|  | module_init(st_init); | 
|  | module_exit(st_exit); | 
|  |  | 
|  | MODULE_DESCRIPTION("Self-test harness for dma-buf"); | 
|  | MODULE_LICENSE("GPL and additional rights"); |