/* SPDX-License-Identifier: MIT */ /* * Copyright © 2019 Intel Corporation */ #include #include #include #include #include #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");