@@ -23,6 +23,7 @@ config DRM_I915_DEBUG
select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks)
select DRM_DEBUG_MM if DRM=y
select DRM_I915_SW_FENCE_DEBUG_OBJECTS if DRM_I915=y
+ select DRM_I915_SELFTEST
default n
help
Choose this option to turn on extra driver debugging that may affect
@@ -56,3 +57,17 @@ config DRM_I915_SW_FENCE_DEBUG_OBJECTS
Recommended for driver developers only.
If in doubt, say "N".
+
+config DRM_I915_SELFTEST
+ bool "Enable selftests upon driver load"
+ depends on DRM_I915
+ default n
+ help
+ Choose this option to allow the driver to perform selftests upon
+ loading; also requires the i915.selftest=1 module parameter. To
+ exit the module after running the selftests (i.e. to prevent normal
+ module initialisation afterwards) use i915.selftest=-1.
+
+ Recommended for driver developers only.
+
+ If in doubt, say "N".
@@ -114,6 +114,7 @@ i915-y += dvo_ch7017.o \
# Post-mortem debug and GPU hang state capture
i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
+i915-$(CONFIG_DRM_I915_SELFTEST) += i915_selftest.o
# virtual gpu code
i915-y += i915_vgpu.o
@@ -243,3 +243,8 @@ MODULE_PARM_DESC(enable_dpcd_backlight,
module_param_named(enable_gvt, i915.enable_gvt, bool, 0400);
MODULE_PARM_DESC(enable_gvt,
"Enable support for Intel GVT-g graphics virtualization host support(default:false)");
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+module_param_named_unsafe(selftest, i915.selftest, int, 0400);
+MODULE_PARM_DESC(selftest, "Run selftests when loading (0:disabled [default], 1 run tests then load module, -1 run tests then exit module)");
+#endif
@@ -28,6 +28,9 @@
#include <linux/cache.h> /* for __read_mostly */
struct i915_params {
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+ int selftest;
+#endif
int modeset;
int panel_ignore_lid;
int semaphores;
@@ -27,6 +27,7 @@
#include <linux/vga_switcheroo.h>
#include "i915_drv.h"
+#include "i915_selftest.h"
#define GEN_DEFAULT_PIPEOFFSETS \
.pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \
@@ -496,6 +497,11 @@ static struct pci_driver i915_pci_driver = {
static int __init i915_init(void)
{
bool use_kms = true;
+ int ret;
+
+ ret = i915_selftest();
+ if (ret)
+ return ret;
/*
* Enable KMS by default, unless explicitly overriden by
new file mode 100644
@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "i915_drv.h"
+#include "i915_selftest.h"
+
+int i915_selftest_sanitycheck(void)
+{
+ pr_info("i915: %s() - ok!\n", __func__);
+ return 0;
+}
+
+#define selftest(name, func) name,
+enum {
+#include "i915_selftests.h"
+};
+#undef selftest
+
+#define selftest(name, func) [name] = { #name, func },
+static struct i915_selftest_subtest {
+ const char *name;
+ int (*func)(void);
+ bool enabled;
+} i915_selftests[] = {
+#include "i915_selftests.h"
+};
+#undef selftest
+
+#define selftest(name, func) \
+module_param_named(subtest__##name, i915_selftests[name].enabled, bool, 0400);
+#include "i915_selftests.h"
+#undef selftest
+
+static void set_default_test_all(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(i915_selftests); i++)
+ if (i915_selftests[i].enabled)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(i915_selftests); i++)
+ i915_selftests[i].enabled = true;
+}
+
+int i915_selftest(void)
+{
+ int i;
+
+ if (!i915.selftest)
+ return 0;
+
+ pr_info("i915: Performing selftests\n");
+ set_default_test_all();
+
+ for (i = 0; i < ARRAY_SIZE(i915_selftests); i++) {
+ int err;
+
+ if (!i915_selftests[i].enabled)
+ continue;
+
+ pr_debug("Runnin %s\n", i915_selftests[i].name);
+ err = i915_selftests[i].func();
+ if (err)
+ return err;
+ }
+
+ if (i915.selftest < 0)
+ return -ENOTTY;
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __I915_SELFTEST_H__
+#define __I915_SELFTEST_H__
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+int i915_selftest(void);
+#else
+static inline int i915_selftest(void) { return 0; }
+#endif
+
+/* We extract the function declarations from i915_selftests.h.
+ * Add your unit tests there!
+ */
+#define selftest(name, func) int func(void);
+#include "i915_selftests.h"
+#undef selftest
+
+#endif /* __I915_SELFTEST_H__ */
new file mode 100644
@@ -0,0 +1,11 @@
+/* List each unit test as selftest(name, function)
+ *
+ * The name is used as both an enum and expanded as subtest__name to create
+ * a module parameter. It must be unique and legal for a C identifier.
+ *
+ * The function should be of type int function(void). It may be conditionally
+ * compiled using #if IS_ENABLED(DRM_I915_SELFTEST).
+ *
+ * Tests are executed in reverse order by igt/drv_selftest
+ */
+selftest(sanitycheck, i915_selftest_sanitycheck) /* keep last */
Some pieces of code are independent of hardware but are very tricky to exercise through the normal userspace ABI or via debugfs hooks. Being able to create mock unit tests and execute them through CI is vital. Start by adding a central point where we can execute unit tests from and a parameter to enable them. This is disabled by default as the expectation is that these tests will occasionally explode. To facilitate integration with igt, any parameter beginning with i915.subtest__ is interpreted as a selftest subtest executable independently via igt/drv_selftest. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/Kconfig.debug | 15 ++++++ drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_params.c | 5 ++ drivers/gpu/drm/i915/i915_params.h | 3 ++ drivers/gpu/drm/i915/i915_pci.c | 6 +++ drivers/gpu/drm/i915/i915_selftest.c | 92 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_selftest.h | 40 +++++++++++++++ drivers/gpu/drm/i915/i915_selftests.h | 11 +++++ 8 files changed, 173 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_selftest.c create mode 100644 drivers/gpu/drm/i915/i915_selftest.h create mode 100644 drivers/gpu/drm/i915/i915_selftests.h