162306a36Sopenharmony_ci/* SPDX-License-Identifier: MIT */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/compiler.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/sched/signal.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "selftest.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cienum { 1662306a36Sopenharmony_ci#define selftest(n, func) __idx_##n, 1762306a36Sopenharmony_ci#include "selftests.h" 1862306a36Sopenharmony_ci#undef selftest 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f }, 2262306a36Sopenharmony_cistatic struct selftest { 2362306a36Sopenharmony_ci bool enabled; 2462306a36Sopenharmony_ci const char *name; 2562306a36Sopenharmony_ci int (*func)(void); 2662306a36Sopenharmony_ci} selftests[] = { 2762306a36Sopenharmony_ci#include "selftests.h" 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci#undef selftest 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Embed the line number into the parameter name so that we can order tests */ 3262306a36Sopenharmony_ci#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n)) 3362306a36Sopenharmony_ci#define selftest_0(n, func, id) \ 3462306a36Sopenharmony_cimodule_param_named(id, selftests[__idx_##n].enabled, bool, 0400); 3562306a36Sopenharmony_ci#define selftest(n, func) selftest_0(n, func, param(n)) 3662306a36Sopenharmony_ci#include "selftests.h" 3762306a36Sopenharmony_ci#undef selftest 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciint __sanitycheck__(void) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci pr_debug("Hello World!\n"); 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic char *__st_filter; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic bool apply_subtest_filter(const char *caller, const char *name) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci char *filter, *sep, *tok; 5062306a36Sopenharmony_ci bool result = true; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci filter = kstrdup(__st_filter, GFP_KERNEL); 5362306a36Sopenharmony_ci for (sep = filter; (tok = strsep(&sep, ","));) { 5462306a36Sopenharmony_ci bool allow = true; 5562306a36Sopenharmony_ci char *sl; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (*tok == '!') { 5862306a36Sopenharmony_ci allow = false; 5962306a36Sopenharmony_ci tok++; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (*tok == '\0') 6362306a36Sopenharmony_ci continue; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci sl = strchr(tok, '/'); 6662306a36Sopenharmony_ci if (sl) { 6762306a36Sopenharmony_ci *sl++ = '\0'; 6862306a36Sopenharmony_ci if (strcmp(tok, caller)) { 6962306a36Sopenharmony_ci if (allow) 7062306a36Sopenharmony_ci result = false; 7162306a36Sopenharmony_ci continue; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci tok = sl; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (strcmp(tok, name)) { 7762306a36Sopenharmony_ci if (allow) 7862306a36Sopenharmony_ci result = false; 7962306a36Sopenharmony_ci continue; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci result = allow; 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci kfree(filter); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return result; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciint 9162306a36Sopenharmony_ci__subtests(const char *caller, const struct subtest *st, int count, void *data) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci int err; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (; count--; st++) { 9662306a36Sopenharmony_ci cond_resched(); 9762306a36Sopenharmony_ci if (signal_pending(current)) 9862306a36Sopenharmony_ci return -EINTR; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (!apply_subtest_filter(caller, st->name)) 10162306a36Sopenharmony_ci continue; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci pr_info("dma-buf: Running %s/%s\n", caller, st->name); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci err = st->func(data); 10662306a36Sopenharmony_ci if (err && err != -EINTR) { 10762306a36Sopenharmony_ci pr_err("dma-buf/%s: %s failed with error %d\n", 10862306a36Sopenharmony_ci caller, st->name, err); 10962306a36Sopenharmony_ci return err; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void set_default_test_all(struct selftest *st, unsigned long count) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci unsigned long i; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci for (i = 0; i < count; i++) 12162306a36Sopenharmony_ci if (st[i].enabled) 12262306a36Sopenharmony_ci return; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci for (i = 0; i < count; i++) 12562306a36Sopenharmony_ci st[i].enabled = true; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int run_selftests(struct selftest *st, unsigned long count) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci int err = 0; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci set_default_test_all(st, count); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* Tests are listed in natural order in selftests.h */ 13562306a36Sopenharmony_ci for (; count--; st++) { 13662306a36Sopenharmony_ci if (!st->enabled) 13762306a36Sopenharmony_ci continue; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci pr_info("dma-buf: Running %s\n", st->name); 14062306a36Sopenharmony_ci err = st->func(); 14162306a36Sopenharmony_ci if (err) 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (WARN(err > 0 || err == -ENOTTY, 14662306a36Sopenharmony_ci "%s returned %d, conflicting with selftest's magic values!\n", 14762306a36Sopenharmony_ci st->name, err)) 14862306a36Sopenharmony_ci err = -1; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return err; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int __init st_init(void) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci return run_selftests(selftests, ARRAY_SIZE(selftests)); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void __exit st_exit(void) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cimodule_param_named(st_filter, __st_filter, charp, 0400); 16362306a36Sopenharmony_cimodule_init(st_init); 16462306a36Sopenharmony_cimodule_exit(st_exit); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciMODULE_DESCRIPTION("Self-test harness for dma-buf"); 16762306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 168