All of lore.kernel.org
 help / color / mirror / Atom feed
* Selftests
@ 2017-01-11 21:09 Chris Wilson
  2017-01-11 21:09 ` [PATCH 01/37] drm: Provide a driver hook for drm_dev_release() Chris Wilson
                   ` (37 more replies)
  0 siblings, 38 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

A small smattering of selftests. Coverage is getting better, but still a
long way from providing coverage of every path I have planned. :|
The tests we do have do nicely demonstrated the ease at which some
in-depth testing can be done in the kernel, some that would be
impossible from userspace. (But uabi still requires thorough testing of
its own, ofc.) 
-Chris

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* [PATCH 01/37] drm: Provide a driver hook for drm_dev_release()
  2017-01-11 21:09 Selftests Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 02/37] drm/i915: Provide a hook for selftests Chris Wilson
                   ` (36 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Some state is coupled into the device lifetime outside of the
load/unload timeframe and requires teardown during final unreference
from drm_dev_release(). For example, dmabufs hold both a device and
module reference and may live longer than expected (i.e. the current
pattern of the driver tearing down its state and then releasing a
reference to the drm device) and yet touch driver private state when
destroyed.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/drm_drv.c | 3 +++
 include/drm/drm_drv.h     | 9 +++++++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 1b11ab628da7..a150f0c6a299 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -598,6 +598,9 @@ static void drm_dev_release(struct kref *ref)
 {
 	struct drm_device *dev = container_of(ref, struct drm_device, ref);
 
+	if (dev->driver->release)
+		dev->driver->release(dev);
+
 	if (drm_core_check_feature(dev, DRIVER_GEM))
 		drm_gem_destroy(dev);
 
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 34ece393c639..dfddd8c15b62 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -103,6 +103,15 @@ struct drm_driver {
 	 *
 	 */
 	void (*unload) (struct drm_device *);
+
+	/**
+	 * @release:
+	 *
+	 * Optional callback for destroying device state after the final
+	 * reference is released, i.e. the device is being destroyed.
+	 */
+	void (*release) (struct drm_device *);
+
 	int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
 	int (*dma_quiescent) (struct drm_device *);
 	int (*context_dtor) (struct drm_device *dev, int context);
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 02/37] drm/i915: Provide a hook for selftests
  2017-01-11 21:09 Selftests Chris Wilson
  2017-01-11 21:09 ` [PATCH 01/37] drm: Provide a driver hook for drm_dev_release() Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12  7:29   ` Tvrtko Ursulin
  2017-01-13  8:31   ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 03/37] drm/i915: Add some selftests for sg_table manipulation Chris Wilson
                   ` (35 subsequent siblings)
  37 siblings, 2 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

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 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.igt__ is interpreted as a subtest executable independently via
igt/drv_selftest.

Two classes of selftests are recognised: mock unit tests and integration
tests. Mock unit tests are run as soon as the module is loaded, before
the device is probed. At that point there is no driver instantiated and
all hw interactions must be "mocked". This is very useful for writing
universal tests to exercise code not typically run on a broad range of
architectures. Alternatively, you can hook into the live selftests and
run when the device has been instantiated - hw interactions are real.

v2: Add a macro for compiling conditional code for mock objects inside
real objects.
v3: Differentiate between mock unit tests and late integration test.
v4: List the tests in natural order, use igt to sort after modparam.
v5: s/late/live/
v6: s/unsigned long/unsigned int/

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> #v1
---
 drivers/gpu/drm/i915/Kconfig.debug                 |  16 ++
 drivers/gpu/drm/i915/Makefile                      |   3 +
 drivers/gpu/drm/i915/i915_pci.c                    |  19 +-
 drivers/gpu/drm/i915/i915_selftest.h               |  91 +++++++++
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |  11 +
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |  11 +
 drivers/gpu/drm/i915/selftests/i915_selftest.c     | 226 +++++++++++++++++++++
 tools/testing/selftests/drivers/gpu/i915.sh        |   1 +
 8 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/i915_selftest.h
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_live_selftests.h
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_selftest.c

diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
index 598551dbf62c..a4d8cfd77c3c 100644
--- a/drivers/gpu/drm/i915/Kconfig.debug
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -26,6 +26,7 @@ config DRM_I915_DEBUG
         select DRM_DEBUG_MM if DRM=y
 	select DRM_DEBUG_MM_SELFTEST
 	select DRM_I915_SW_FENCE_DEBUG_OBJECTS
+	select DRM_I915_SELFTEST
         default n
         help
           Choose this option to turn on extra driver debugging that may affect
@@ -59,3 +60,18 @@ 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
+	select PRIME_NUMBERS
+	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".
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 5196509e71cf..c9d1554de35d 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -3,6 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 subdir-ccflags-$(CONFIG_DRM_I915_WERROR) := -Werror
+subdir-ccflags-$(CONFIG_DRM_I915_SELFTEST) += -I$(src) -I$(src)/selftests
 subdir-ccflags-y += \
 	$(call as-instr,movntdqa (%eax)$(comma)%xmm0,-DCONFIG_AS_MOVNTDQA)
 
@@ -114,6 +115,8 @@ 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) += \
+	selftests/i915_selftest.o
 
 # virtual gpu code
 i915-y += i915_vgpu.o
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index ecb487b5356f..b3bf9474f081 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -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, \
@@ -476,6 +477,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct intel_device_info *intel_info =
 		(struct intel_device_info *) ent->driver_data;
+	int err;
 
 	if (IS_ALPHA_SUPPORT(intel_info) && !i915.alpha_support) {
 		DRM_INFO("The driver support for your hardware in this kernel version is alpha quality\n"
@@ -499,7 +501,17 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (vga_switcheroo_client_probe_defer(pdev))
 		return -EPROBE_DEFER;
 
-	return i915_driver_load(pdev, ent);
+	err = i915_driver_load(pdev, ent);
+	if (err)
+		return err;
+
+	err = i915_live_selftests(pdev);
+	if (err) {
+		i915_driver_unload(pci_get_drvdata(pdev));
+		return err > 0 ? -ENOTTY : err;
+	}
+
+	return 0;
 }
 
 static void i915_pci_remove(struct pci_dev *pdev)
@@ -521,6 +533,11 @@ static struct pci_driver i915_pci_driver = {
 static int __init i915_init(void)
 {
 	bool use_kms = true;
+	int err;
+
+	err = i915_mock_selftests();
+	if (err)
+		return err > 0 ? 0 : err;
 
 	/*
 	 * Enable KMS by default, unless explicitly overriden by
diff --git a/drivers/gpu/drm/i915/i915_selftest.h b/drivers/gpu/drm/i915/i915_selftest.h
new file mode 100644
index 000000000000..4ec96cac2203
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_selftest.h
@@ -0,0 +1,91 @@
+/*
+ * 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__
+
+struct pci_dev;
+struct drm_i915_private;
+
+struct i915_selftest {
+	unsigned long timeout_jiffies;
+	unsigned int timeout_ms;
+	unsigned int random_seed;
+	int mock;
+	int live;
+};
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+extern struct i915_selftest i915_selftest;
+
+int i915_mock_selftests(void);
+int i915_live_selftests(struct pci_dev *pdev);
+
+/* We extract the function declarations from i915_mock_selftests.h and
+ * i915_live_selftests.h Add your unit test declarations there!
+ *
+ * Mock unit tests are run very early upon module load, before the driver
+ * is probed. All hardware interactions, as well as other subsystems, must
+ * be "mocked".
+ *
+ * Live unit tests are run after the driver is loaded - all hardware
+ * interactions are real.
+ */
+#define selftest(name, func) int func(void);
+#include "i915_mock_selftests.h"
+#undef selftest
+#define selftest(name, func) int func(struct drm_i915_private *i915);
+#include "i915_live_selftests.h"
+#undef selftest
+
+struct i915_subtest {
+	int (*func)(void *data);
+	const char *name;
+};
+
+int __i915_subtests(const char *caller,
+		    const struct i915_subtest *st,
+		    unsigned int count,
+		    void *data);
+#define i915_subtests(T, data) \
+	__i915_subtests(__func__, T, ARRAY_SIZE(T), data)
+
+#define SUBTEST(x) { x, #x }
+
+#define I915_SELFTEST_DECLARE(x) x
+#define I915_SELFTEST_ONLY(x) unlikely(x)
+
+#else /* !IS_ENABLED(CONFIG_DRM_I915_SELFTEST) */
+
+static inline int i915_mock_selftests(void) { return 0; }
+static inline int i915_live_selftests(struct pci_dev *pdev) { return 0; }
+
+#define I915_SELFTEST_DECLARE(x)
+#define I915_SELFTEST_ONLY(x) 0
+
+#endif
+
+#define I915_SELFTEST_TIMEOUT(name__) \
+	unsigned long name__ = jiffies + i915_selftest.timeout_jiffies
+
+#endif /* !__I915_SELFTEST_H__ */
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
new file mode 100644
index 000000000000..f3e17cb10e05
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -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 order by igt/drv_selftest
+ */
+selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
new file mode 100644
index 000000000000..69e97a2ba4a6
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -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 order by igt/drv_selftest
+ */
+selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
diff --git a/drivers/gpu/drm/i915/selftests/i915_selftest.c b/drivers/gpu/drm/i915/selftests/i915_selftest.c
new file mode 100644
index 000000000000..66928eead3a9
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_selftest.c
@@ -0,0 +1,226 @@
+/*
+ * 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 <linux/random.h>
+
+#include "i915_drv.h"
+#include "i915_selftest.h"
+
+struct i915_selftest i915_selftest __read_mostly = {
+	.timeout_ms = 1000,
+};
+
+int i915_mock_sanitycheck(void)
+{
+	pr_info("i915: %s() - ok!\n", __func__);
+	return 0;
+}
+
+int i915_live_sanitycheck(struct drm_i915_private *i915)
+{
+	pr_info("%s: %s() - ok!\n", i915->drm.driver->name, __func__);
+	return 0;
+}
+
+enum {
+#define selftest(name, func) mock_##name,
+#include "i915_mock_selftests.h"
+#undef selftest
+};
+enum {
+#define selftest(name, func) live_##name,
+#include "i915_live_selftests.h"
+#undef selftest
+};
+
+struct selftest {
+	bool enabled;
+	const char *name;
+	union {
+		int (*mock)(void);
+		int (*live)(struct drm_i915_private *);
+	};
+};
+
+#define selftest(n, f) [mock_##n] = { .name = #n, .mock = f },
+static struct selftest mock_selftests[] = {
+#include "i915_mock_selftests.h"
+};
+#undef selftest
+
+#define selftest(n, f) [live_##n] = { .name = #n, .live = f },
+static struct selftest live_selftests[] = {
+#include "i915_live_selftests.h"
+};
+#undef selftest
+
+/* Embed the line number into the parameter name so that we can order tests */
+#define selftest(n, func) selftest_0(n, func, param(n))
+#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), mock_##n))
+#define selftest_0(n, func, id) \
+module_param_named(id, mock_selftests[mock_##n].enabled, bool, 0400);
+#include "i915_mock_selftests.h"
+#undef selftest_0
+#undef param
+
+#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), live_##n))
+#define selftest_0(n, func, id) \
+module_param_named(id, live_selftests[live_##n].enabled, bool, 0400);
+#include "i915_live_selftests.h"
+#undef selftest_0
+#undef param
+#undef selftest
+
+static void set_default_test_all(struct selftest *st, unsigned int count)
+{
+	unsigned int 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(const char *name,
+			 struct selftest *st,
+			 unsigned int count,
+			 void *data)
+{
+	int err = 0;
+
+	while (!i915_selftest.random_seed)
+		i915_selftest.random_seed = get_random_int();
+
+	i915_selftest.timeout_jiffies =
+		i915_selftest.timeout_ms ?
+		msecs_to_jiffies_timeout(i915_selftest.timeout_ms) :
+		MAX_SCHEDULE_TIMEOUT;
+
+	set_default_test_all(st, count);
+
+	pr_info("i915: Performing %s selftests with st_random_seed=0x%x st_timeout=%u\n",
+		name, i915_selftest.random_seed, i915_selftest.timeout_ms);
+
+	/* Tests are listed in order in i915_*_selftests.h */
+	for (; count--; st++) {
+		if (!st->enabled)
+			continue;
+
+		cond_resched();
+		if (signal_pending(current))
+			return -EINTR;
+
+		pr_debug("i915: Running %s\n", st->name);
+		if (data)
+			err = st->live(data);
+		else
+			err = st->mock();
+		if (err)
+			break;
+	}
+
+	if (WARN(err > 0 || err == -ENOTTY,
+		 "%s returned %d, conflicting with selftest's magic values!\n",
+		 st->name, err))
+		err = -1;
+
+	rcu_barrier();
+	return err;
+}
+
+#define run_selftests(x, data) \
+	(run_selftests)(#x, x##_selftests, ARRAY_SIZE(x##_selftests), data)
+
+int i915_mock_selftests(void)
+{
+	int err;
+
+	if (!i915_selftest.mock)
+		return 0;
+
+	err = run_selftests(mock, NULL);
+	if (err)
+		return err;
+
+	if (i915_selftest.mock < 0)
+		return 1;
+
+	return 0;
+}
+
+int i915_live_selftests(struct pci_dev *pdev)
+{
+	int err;
+
+	if (!i915_selftest.live)
+		return 0;
+
+	err = run_selftests(live, to_i915(pci_get_drvdata(pdev)));
+	if (err) {
+		i915_selftest.live = err;
+		return err;
+	}
+
+	if (i915_selftest.live < 0) {
+		i915_selftest.live = -ENOTTY;
+		return 1;
+	}
+
+	return 0;
+}
+
+int __i915_subtests(const char *caller,
+		    const struct i915_subtest *st,
+		    unsigned int count,
+		    void *data)
+{
+	int err;
+
+	for (; count--; st++) {
+		cond_resched();
+		if (signal_pending(current))
+			return -EINTR;
+
+		pr_debug("i915: Running %s/%s\n", caller, st->name);
+		err = st->func(data);
+		if (err) {
+			if (err != -EINTR)
+				pr_err("i915/%s: %s failed with error %d\n",
+				       caller, st->name, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+module_param_named(st_random_seed, i915_selftest.random_seed, uint, 0400);
+module_param_named(st_timeout, i915_selftest.timeout_ms, uint, 0400);
+
+module_param_named_unsafe(mock_selftests, i915_selftest.mock, int, 0400);
+MODULE_PARM_DESC(mock_selftests, "Run selftests before loading, using mock hardware (0:disabled [default], 1:run tests then load driver, -1:run tests then exit module)");
+
+module_param_named_unsafe(live_selftests, i915_selftest.live, int, 0400);
+MODULE_PARM_DESC(live_selftests, "Run selftests after driver initialisation on the live system (0:disabled [default], 1:run tests then continue, -1:run tests then exit module)");
diff --git a/tools/testing/selftests/drivers/gpu/i915.sh b/tools/testing/selftests/drivers/gpu/i915.sh
index d407f0fa1e3a..c06d6e8a8dcc 100755
--- a/tools/testing/selftests/drivers/gpu/i915.sh
+++ b/tools/testing/selftests/drivers/gpu/i915.sh
@@ -7,6 +7,7 @@ if ! /sbin/modprobe -q -r i915; then
 fi
 
 if /sbin/modprobe -q i915 mock_selftests=-1; then
+	/sbin/modprobe -q -r i915
 	echo "drivers/gpu/i915: ok"
 else
 	echo "drivers/gpu/i915: [FAIL]"
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 03/37] drm/i915: Add some selftests for sg_table manipulation
  2017-01-11 21:09 Selftests Chris Wilson
  2017-01-11 21:09 ` [PATCH 01/37] drm: Provide a driver hook for drm_dev_release() Chris Wilson
  2017-01-11 21:09 ` [PATCH 02/37] drm/i915: Provide a hook for selftests Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 10:56   ` Tvrtko Ursulin
  2017-01-11 21:09 ` [PATCH 04/37] drm/i915: Add unit tests for the breadcrumb rbtree, insert/remove Chris Wilson
                   ` (34 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Start exercising the scattergather lists, especially looking at
iteration after coalescing.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_gem.c                    |  11 +-
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |   1 +
 drivers/gpu/drm/i915/selftests/scatterlist.c       | 255 +++++++++++++++++++++
 3 files changed, 264 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/selftests/scatterlist.c

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4c6d40e28cf5..e88541b5b72b 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2219,17 +2219,17 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
 	mutex_unlock(&obj->mm.lock);
 }
 
-static void i915_sg_trim(struct sg_table *orig_st)
+static bool i915_sg_trim(struct sg_table *orig_st)
 {
 	struct sg_table new_st;
 	struct scatterlist *sg, *new_sg;
 	unsigned int i;
 
 	if (orig_st->nents == orig_st->orig_nents)
-		return;
+		return false;
 
 	if (sg_alloc_table(&new_st, orig_st->nents, GFP_KERNEL | __GFP_NOWARN))
-		return;
+		return false;
 
 	new_sg = new_st.sgl;
 	for_each_sg(orig_st->sgl, sg, orig_st->nents, i) {
@@ -2242,6 +2242,7 @@ static void i915_sg_trim(struct sg_table *orig_st)
 	sg_free_table(orig_st);
 
 	*orig_st = new_st;
+	return true;
 }
 
 static struct sg_table *
@@ -4892,3 +4893,7 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
 	sg = i915_gem_object_get_sg(obj, n, &offset);
 	return sg_dma_address(sg) + (offset << PAGE_SHIFT);
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/scatterlist.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 69e97a2ba4a6..5f0bdda42ed8 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -9,3 +9,4 @@
  * Tests are executed in order by igt/drv_selftest
  */
 selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
+selftest(scatterlist, scatterlist_mock_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/scatterlist.c b/drivers/gpu/drm/i915/selftests/scatterlist.c
new file mode 100644
index 000000000000..1573be8961bf
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/scatterlist.c
@@ -0,0 +1,255 @@
+/*
+ * 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 <linux/prime_numbers.h>
+
+#include "i915_selftest.h"
+
+#define PFN_BIAS (1 << 10)
+
+struct pfn_table {
+	struct sg_table st;
+	unsigned long start, end;
+};
+
+static noinline int expect_pfn_sg(struct pfn_table *pt, const char *who)
+{
+	struct scatterlist *sg;
+	unsigned long pfn, n;
+
+	pfn = pt->start;
+	for_each_sg(pt->st.sgl, sg, pt->st.nents, n) {
+		struct page *page = sg_page(sg);
+
+		if (page_to_pfn(page) != pfn) {
+			pr_err("%s left pages out of order, expected pfn %lu, found pfn %lu (using for_each_sg)\n",
+			       who, pfn, page_to_pfn(page));
+			return -EINVAL;
+		}
+
+		if (sg->length != (n + 1) * PAGE_SIZE) {
+			pr_err("%s: %s copied wrong sg length, expected size %lu, found %u (using for_each_sg)\n",
+			       __func__, who, (n + 1) * PAGE_SIZE, sg->length);
+			return -EINVAL;
+		}
+
+		cond_resched();
+		if (signal_pending(current))
+			return -EINTR;
+
+		pfn += n + 1;
+	}
+	if (pfn != pt->end) {
+		pr_err("%s: %s finished on wrong pfn, expected %lu, found %lu\n",
+		       __func__, who, pt->end, pfn);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static noinline int expect_pfn_sg_page_iter(struct pfn_table *pt, const char *who)
+{
+	struct sg_page_iter sgiter;
+	unsigned long pfn;
+
+	pfn = pt->start;
+	for_each_sg_page(pt->st.sgl, &sgiter, pt->st.nents, 0) {
+		struct page *page = sg_page_iter_page(&sgiter);
+
+		if (page != pfn_to_page(pfn)) {
+			pr_err("%s: %s left pages out of order, expected pfn %lu, found pfn %lu (using for_each_sg_page)\n",
+			       __func__, who, pfn, page_to_pfn(page));
+			return -EINVAL;
+		}
+
+		cond_resched();
+		if (signal_pending(current))
+			return -EINTR;
+
+		pfn++;
+	}
+	if (pfn != pt->end) {
+		pr_err("%s: %s finished on wrong pfn, expected %lu, found %lu\n",
+		       __func__, who, pt->end, pfn);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static noinline int expect_pfn_sgtiter(struct pfn_table *pt, const char *who)
+{
+	struct sgt_iter sgt;
+	struct page *page;
+	unsigned long pfn;
+
+	pfn = pt->start;
+	for_each_sgt_page(page, sgt, &pt->st) {
+		if (page != pfn_to_page(pfn)) {
+			pr_err("%s: %s left pages out of order, expected pfn %lu, found pfn %lu (using for_each_sgt_page)\n",
+			       __func__, who, pfn, page_to_pfn(page));
+			return -EINVAL;
+		}
+
+		cond_resched();
+		if (signal_pending(current))
+			return -EINTR;
+
+		pfn++;
+	}
+	if (pfn != pt->end) {
+		pr_err("%s: %s finished on wrong pfn, expected %lu, found %lu\n",
+		       __func__, who, pt->end, pfn);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int expect_pfn_sgtable(struct pfn_table *pt, const char *who)
+{
+	int err;
+
+	err = expect_pfn_sg(pt, who);
+	if (err)
+		return err;
+
+	err = expect_pfn_sg_page_iter(pt, who);
+	if (err)
+		return err;
+
+	err = expect_pfn_sgtiter(pt, who);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static bool alloc_table(struct pfn_table *pt,
+			unsigned long count,
+			unsigned long max)
+{
+	struct scatterlist *sg;
+	unsigned long n, pfn;
+
+	if (sg_alloc_table(&pt->st, max,
+			   GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN))
+		return false;
+
+	pt->start = PFN_BIAS;
+	pfn = pt->start;
+	sg = pt->st.sgl;
+	for (n = 0; n < count; n++) {
+		if (n)
+			sg = sg_next(sg);
+		sg_set_page(sg, pfn_to_page(pfn), (n + 1)*PAGE_SIZE, 0);
+		pfn += n + 1;
+	}
+	sg_mark_end(sg);
+	pt->st.nents = n;
+	pt->end = pfn;
+
+	return true;
+}
+
+static int igt_sg_alloc(void *ignored)
+{
+	I915_SELFTEST_TIMEOUT(end_time);
+	const unsigned long max_order = 20; /* approximating a 4GiB object */
+	unsigned long prime;
+
+	for_each_prime_number(prime, max_order) {
+		unsigned long size = BIT(prime);
+		int offset;
+
+		for (offset = -1; offset <= 1; offset++) {
+			struct pfn_table pt;
+			int err;
+
+			if (!alloc_table(&pt, size + offset, size + offset))
+				return 0; /* out of memory, give up */
+
+			err = expect_pfn_sgtable(&pt, "sg_alloc_table");
+			sg_free_table(&pt.st);
+			if (err)
+				return err;
+
+			if (time_after(jiffies, end_time)) {
+				pr_warn("%s timed out: last table size %lu\n",
+					__func__, size + offset);
+				return 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int igt_sg_trim(void *ignored)
+{
+	I915_SELFTEST_TIMEOUT(end_time);
+	const unsigned long max = PAGE_SIZE; /* not prime! */
+	struct pfn_table pt;
+	unsigned long prime;
+
+	for_each_prime_number(prime, max) {
+		int err;
+
+		if (!alloc_table(&pt, prime, max))
+			return 0; /* out of memory, give up */
+
+		err = 0;
+		if (i915_sg_trim(&pt.st)) {
+			if (pt.st.orig_nents != prime ||
+			    pt.st.nents != prime) {
+				pr_err("i915_sg_trim failed (nents %u, orig_nents %u), expected %lu\n",
+				       pt.st.nents, pt.st.orig_nents, prime);
+				err = -EINVAL;
+			} else {
+				err = expect_pfn_sgtable(&pt, "i915_sg_trim");
+			}
+		}
+		sg_free_table(&pt.st);
+		if (err)
+			return err;
+
+		if (time_after(jiffies, end_time)) {
+			pr_warn("%s timed out: last trim size %lu/%lu\n",
+				__func__, prime, max);
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+int scatterlist_mock_selftests(void)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_sg_alloc),
+		SUBTEST(igt_sg_trim),
+	};
+
+	return i915_subtests(tests, NULL);
+}
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 04/37] drm/i915: Add unit tests for the breadcrumb rbtree, insert/remove
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (2 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 03/37] drm/i915: Add some selftests for sg_table manipulation Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 05/37] drm/i915: Add unit tests for the breadcrumb rbtree, completion Chris Wilson
                   ` (33 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

First retroactive test, make sure that the waiters are in global seqno
order after random inserts and removals.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/Makefile                      |   1 +
 drivers/gpu/drm/i915/intel_breadcrumbs.c           |  21 +++
 drivers/gpu/drm/i915/intel_engine_cs.c             |   4 +
 drivers/gpu/drm/i915/intel_ringbuffer.h            |   2 +
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |   1 +
 drivers/gpu/drm/i915/selftests/i915_random.c       |  63 ++++++++
 drivers/gpu/drm/i915/selftests/i915_random.h       |  47 ++++++
 drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c | 176 +++++++++++++++++++++
 drivers/gpu/drm/i915/selftests/mock_engine.c       |  55 +++++++
 drivers/gpu/drm/i915/selftests/mock_engine.h       |  32 ++++
 10 files changed, 402 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_random.c
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_random.h
 create mode 100644 drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_engine.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_engine.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index c9d1554de35d..b5da9aa98764 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -116,6 +116,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) += \
+	selftests/i915_random.o \
 	selftests/i915_selftest.o
 
 # virtual gpu code
diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c
index fcfa423d08bd..5682c8aa8064 100644
--- a/drivers/gpu/drm/i915/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c
@@ -109,6 +109,18 @@ static void __intel_breadcrumbs_enable_irq(struct intel_breadcrumbs *b)
 	if (b->rpm_wakelock)
 		return;
 
+	if (I915_SELFTEST_ONLY(b->mock)) {
+		/* For our mock objects we want to avoid interaction
+		 * with the real hardware (which is not set up). So
+		 * we simply pretend we have enabled the powerwell
+		 * and the irq, and leave it up to the mock
+		 * implementation to call intel_engine_wakeup()
+		 * itself when it wants to simulate a user interrupt,
+		 */
+		b->rpm_wakelock = true;
+		return;
+	}
+
 	/* Since we are waiting on a request, the GPU should be busy
 	 * and should have its own rpm reference. For completeness,
 	 * record an rpm reference for ourselves to cover the
@@ -143,6 +155,11 @@ static void __intel_breadcrumbs_disable_irq(struct intel_breadcrumbs *b)
 	if (!b->rpm_wakelock)
 		return;
 
+	if (I915_SELFTEST_ONLY(b->mock)) {
+		b->rpm_wakelock = false;
+		return;
+	}
+
 	if (b->irq_enabled) {
 		irq_disable(engine);
 		b->irq_enabled = false;
@@ -661,3 +678,7 @@ unsigned int intel_breadcrumbs_busy(struct drm_i915_private *i915)
 
 	return mask;
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/intel_breadcrumbs.c"
+#endif
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index 97bbbc3d6aa8..c6332096d870 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -482,3 +482,7 @@ void intel_engine_get_instdone(struct intel_engine_cs *engine,
 		break;
 	}
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/mock_engine.c"
+#endif
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 79c2b8d72322..eba238095497 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -5,6 +5,7 @@
 #include "i915_gem_batch_pool.h"
 #include "i915_gem_request.h"
 #include "i915_gem_timeline.h"
+#include "i915_selftest.h"
 
 #define I915_CMD_HASH_ORDER 9
 
@@ -244,6 +245,7 @@ struct intel_engine_cs {
 
 		bool irq_enabled : 1;
 		bool rpm_wakelock : 1;
+		I915_SELFTEST_DECLARE(bool mock : 1);
 	} breadcrumbs;
 
 	/*
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 5f0bdda42ed8..80458e2a2b04 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -10,3 +10,4 @@
  */
 selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
 selftest(scatterlist, scatterlist_mock_selftests)
+selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/i915_random.c b/drivers/gpu/drm/i915/selftests/i915_random.c
new file mode 100644
index 000000000000..606a237fed17
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_random.c
@@ -0,0 +1,63 @@
+/*
+ * 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 <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "i915_random.h"
+
+static inline u32 i915_prandom_u32_max_state(u32 ep_ro, struct rnd_state *state)
+{
+	return upper_32_bits((u64)prandom_u32_state(state) * ep_ro);
+}
+
+void i915_random_reorder(unsigned int *order, unsigned int count,
+			 struct rnd_state *state)
+{
+	unsigned int i, j;
+
+	for (i = 0; i < count; ++i) {
+		BUILD_BUG_ON(sizeof(unsigned int) > sizeof(u32));
+		j = i915_prandom_u32_max_state(count, state);
+		swap(order[i], order[j]);
+	}
+}
+
+unsigned int *i915_random_order(unsigned int count, struct rnd_state *state)
+{
+	unsigned int *order, i;
+
+	order = kmalloc_array(count, sizeof(*order), GFP_TEMPORARY);
+	if (!order)
+		return order;
+
+	for (i = 0; i < count; i++)
+		order[i] = i;
+
+	i915_random_reorder(order, count, state);
+	return order;
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_random.h b/drivers/gpu/drm/i915/selftests/i915_random.h
new file mode 100644
index 000000000000..bc8a48d4172c
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_random.h
@@ -0,0 +1,47 @@
+/*
+ * 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_SELFTESTS_RANDOM_H__
+#define __I915_SELFTESTS_RANDOM_H__
+
+#include <linux/random.h>
+
+#include "i915_selftest.h"
+
+#define I915_RND_STATE_INITIALIZER() ({					\
+	struct rnd_state state__;					\
+	prandom_seed_state(&state__, i915_selftest.random_seed);	\
+	state__;							\
+})
+
+#define I915_RND_STATE(name__) \
+	struct rnd_state name__ = I915_RND_STATE_INITIALIZER()
+
+unsigned int *i915_random_order(unsigned int count,
+				struct rnd_state *state);
+void i915_random_reorder(unsigned int *order,
+			 unsigned int count,
+			 struct rnd_state *state);
+
+#endif /* !__I915_SELFTESTS_RANDOM_H__ */
diff --git a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
new file mode 100644
index 000000000000..23b09fd5d3aa
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
@@ -0,0 +1,176 @@
+/*
+ * 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_random.h"
+#include "i915_selftest.h"
+
+#include "mock_engine.h"
+
+static int check_rbtree(struct intel_engine_cs *engine,
+			const unsigned long *bitmap,
+			const struct intel_wait *waiters,
+			const int count)
+{
+	struct intel_breadcrumbs *b = &engine->breadcrumbs;
+	struct rb_node *rb;
+	int n;
+
+	if (&b->first_wait->node != rb_first(&b->waiters)) {
+		pr_err("First waiter does not match first element of wait-tree\n");
+		return -EINVAL;
+	}
+
+	n = find_first_bit(bitmap, count);
+	for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
+		struct intel_wait *w = container_of(rb, typeof(*w), node);
+		int idx = w - waiters;
+
+		if (!test_bit(idx, bitmap)) {
+			pr_err("waiter[%d, seqno=%d] removed but still in wait-tree\n",
+			       idx, w->seqno);
+			return -EINVAL;
+		}
+
+		if (n != idx) {
+			pr_err("waiter[%d, seqno=%d] does not match expected next element in tree [%d]\n",
+			       idx, w->seqno, n);
+			return -EINVAL;
+		}
+
+		n = find_next_bit(bitmap, count, n + 1);
+	}
+
+	return 0;
+}
+
+static int check_rbtree_empty(struct intel_engine_cs *engine)
+{
+	struct intel_breadcrumbs *b = &engine->breadcrumbs;
+
+	if (b->first_wait) {
+		pr_err("Empty breadcrumbs still has a waiter\n");
+		return -EINVAL;
+	}
+
+	if (!RB_EMPTY_ROOT(&b->waiters)) {
+		pr_err("Empty breadcrumbs, but wait-tree not empty\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int igt_random_insert_remove(void *arg)
+{
+	const u32 seqno_bias = 0x1000;
+	I915_RND_STATE(prng);
+	struct intel_engine_cs *engine = arg;
+	struct intel_wait *waiters;
+	const int count = 4096;
+	int *in_order, *out_order;
+	unsigned long *bitmap;
+	int err = -ENOMEM;
+	int n;
+
+	mock_engine_reset(engine);
+
+	waiters = drm_malloc_gfp(count, sizeof(*waiters), GFP_TEMPORARY);
+	if (!waiters)
+		goto out_engines;
+
+	bitmap = kcalloc(DIV_ROUND_UP(count, BITS_PER_LONG), sizeof(*bitmap),
+			 GFP_TEMPORARY);
+	if (!bitmap)
+		goto out_waiters;
+
+	in_order = i915_random_order(count, &prng);
+	if (!in_order)
+		goto out_bitmap;
+
+	out_order = i915_random_order(count, &prng);
+	if (!out_order)
+		goto out_order;
+
+	for (n = 0; n < count; n++)
+		intel_wait_init(&waiters[n], seqno_bias + n);
+
+	err = check_rbtree(engine, bitmap, waiters, count);
+	if (err)
+		goto err;
+
+	/* Add and remove waiters into the rbtree in random order. At each
+	 * step, we verifying that the rbtree is correctly ordered.
+	 */
+	for (n = 0; n < count; n++) {
+		int i = in_order[n];
+
+		intel_engine_add_wait(engine, &waiters[i]);
+		__set_bit(i, bitmap);
+
+		err = check_rbtree(engine, bitmap, waiters, count);
+		if (err)
+			goto err;
+	}
+	for (n = 0; n < count; n++) {
+		int i = out_order[n];
+
+		intel_engine_remove_wait(engine, &waiters[i]);
+		__clear_bit(i, bitmap);
+
+		err = check_rbtree(engine, bitmap, waiters, count);
+		if (err)
+			goto err;
+	}
+
+	err = check_rbtree_empty(engine);
+err:
+	kfree(out_order);
+out_order:
+	kfree(in_order);
+out_bitmap:
+	kfree(bitmap);
+out_waiters:
+	drm_free_large(waiters);
+out_engines:
+	mock_engine_flush(engine);
+	return err;
+}
+
+int intel_breadcrumbs_mock_selftests(void)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_random_insert_remove),
+	};
+	struct intel_engine_cs *engine;
+	int err;
+
+	engine = mock_engine("mock");
+	if (!engine)
+		return -ENOMEM;
+
+	err = i915_subtests(tests, engine);
+	kfree(engine);
+
+	return err;
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
new file mode 100644
index 000000000000..085d611ed56b
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
@@ -0,0 +1,55 @@
+/*
+ * 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 "mock_engine.h"
+
+struct intel_engine_cs *mock_engine(const char *name)
+{
+	struct intel_engine_cs *engine;
+	static int id;
+
+	engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_TEMPORARY);
+	if (!engine)
+		return NULL;
+
+	/* minimal engine setup for seqno */
+	engine->name = name;
+	engine->id = id++;
+	engine->status_page.page_addr = (void *)(engine + 1);
+
+	/* minimal breadcrumbs init */
+	spin_lock_init(&engine->breadcrumbs.lock);
+	engine->breadcrumbs.mock = true;
+
+	return engine;
+}
+
+void mock_engine_flush(struct intel_engine_cs *engine)
+{
+}
+
+void mock_engine_reset(struct intel_engine_cs *engine)
+{
+	intel_write_status_page(engine, I915_GEM_HWS_INDEX, 0);
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.h b/drivers/gpu/drm/i915/selftests/mock_engine.h
new file mode 100644
index 000000000000..0ae9a94aaa1e
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.h
@@ -0,0 +1,32 @@
+/*
+ * 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 __MOCK_ENGINE_H__
+#define __MOCK_ENGINE_H__
+
+struct intel_engine_cs *mock_engine(const char *name);
+void mock_engine_flush(struct intel_engine_cs *engine);
+void mock_engine_reset(struct intel_engine_cs *engine);
+
+#endif /* !__MOCK_ENGINE_H__ */
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 05/37] drm/i915: Add unit tests for the breadcrumb rbtree, completion
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (3 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 04/37] drm/i915: Add unit tests for the breadcrumb rbtree, insert/remove Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 06/37] drm/i915: Add unit tests for the breadcrumb rbtree, wakeups Chris Wilson
                   ` (32 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Second retroactive test, make sure that the waiters are removed from the
global wait-tree when their seqno completes.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c | 107 +++++++++++++++++++++
 drivers/gpu/drm/i915/selftests/mock_engine.h       |   6 ++
 2 files changed, 113 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
index 23b09fd5d3aa..e9dff6eee323 100644
--- a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
@@ -64,6 +64,27 @@ static int check_rbtree(struct intel_engine_cs *engine,
 	return 0;
 }
 
+static int check_completion(struct intel_engine_cs *engine,
+			    const unsigned long *bitmap,
+			    const struct intel_wait *waiters,
+			    const int count)
+{
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (intel_wait_complete(&waiters[n]) != !!test_bit(n, bitmap))
+			continue;
+
+		pr_err("waiter[%d, seqno=%d] is %s, but expected %s\n",
+		       n, waiters[n].seqno,
+		       intel_wait_complete(&waiters[n]) ? "complete" : "active",
+		       test_bit(n, bitmap) ? "active" : "complete");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int check_rbtree_empty(struct intel_engine_cs *engine)
 {
 	struct intel_breadcrumbs *b = &engine->breadcrumbs;
@@ -157,10 +178,96 @@ static int igt_random_insert_remove(void *arg)
 	return err;
 }
 
+static int igt_insert_complete(void *arg)
+{
+	const u32 seqno_bias = 0x1000;
+	struct intel_engine_cs *engine = arg;
+	struct intel_wait *waiters;
+	const int count = 4096;
+	unsigned long *bitmap;
+	int err = -ENOMEM;
+	int n, m;
+
+	mock_engine_reset(engine);
+
+	waiters = drm_malloc_gfp(count, sizeof(*waiters), GFP_TEMPORARY);
+	if (!waiters)
+		goto out_engines;
+
+	bitmap = kcalloc(DIV_ROUND_UP(count, BITS_PER_LONG), sizeof(*bitmap),
+			 GFP_TEMPORARY);
+	if (!bitmap)
+		goto out_waiters;
+
+	for (n = 0; n < count; n++) {
+		intel_wait_init(&waiters[n], n + seqno_bias);
+		intel_engine_add_wait(engine, &waiters[n]);
+		__set_bit(n, bitmap);
+	}
+	err = check_rbtree(engine, bitmap, waiters, count);
+	if (err)
+		goto err;
+
+	/* On each step, we advance the seqno so that several waiters are then
+	 * complete (we increase the seqno by increasingly larger values to
+	 * retire more and more waiters at once). All retired waiters should
+	 * be woken and removed from the rbtree, and so that we check.
+	 */
+	for (n = 0; n < count; n = m) {
+		int seqno = 2 * n;
+
+		GEM_BUG_ON(find_first_bit(bitmap, count) != n);
+
+		if (intel_wait_complete(&waiters[n])) {
+			pr_err("waiter[%d, seqno=%d] completed too early\n",
+			       n, waiters[n].seqno);
+			err = -EINVAL;
+			goto err;
+		}
+
+		/* complete the following waiters */
+		mock_seqno_advance(engine, seqno + seqno_bias);
+		for (m = n; m <= seqno; m++) {
+			if (m == count)
+				break;
+
+			GEM_BUG_ON(!test_bit(m, bitmap));
+			__clear_bit(m, bitmap);
+		}
+
+		intel_engine_remove_wait(engine, &waiters[n]);
+		RB_CLEAR_NODE(&waiters[n].node);
+
+		err = check_rbtree(engine, bitmap, waiters, count);
+		if (err) {
+			pr_err("rbtree corrupt after seqno advance to %d\n",
+			       seqno + seqno_bias);
+			goto err;
+		}
+
+		err = check_completion(engine, bitmap, waiters, count);
+		if (err) {
+			pr_err("completions after seqno advance to %d failed\n",
+			       seqno + seqno_bias);
+			goto err;
+		}
+	}
+
+	err = check_rbtree_empty(engine);
+err:
+	kfree(bitmap);
+out_waiters:
+	drm_free_large(waiters);
+out_engines:
+	mock_engine_flush(engine);
+	return err;
+}
+
 int intel_breadcrumbs_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_random_insert_remove),
+		SUBTEST(igt_insert_complete),
 	};
 	struct intel_engine_cs *engine;
 	int err;
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.h b/drivers/gpu/drm/i915/selftests/mock_engine.h
index 0ae9a94aaa1e..9cfe9671f860 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.h
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.h
@@ -29,4 +29,10 @@ struct intel_engine_cs *mock_engine(const char *name);
 void mock_engine_flush(struct intel_engine_cs *engine);
 void mock_engine_reset(struct intel_engine_cs *engine);
 
+static inline void mock_seqno_advance(struct intel_engine_cs *engine, u32 seqno)
+{
+	intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
+	intel_engine_wakeup(engine);
+}
+
 #endif /* !__MOCK_ENGINE_H__ */
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 06/37] drm/i915: Add unit tests for the breadcrumb rbtree, wakeups
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (4 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 05/37] drm/i915: Add unit tests for the breadcrumb rbtree, completion Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 11:11   ` Tvrtko Ursulin
  2017-01-11 21:09 ` [PATCH 07/37] drm/i915: Mock the GEM device for self-testing Chris Wilson
                   ` (31 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Third retroactive test, make sure that the seqno waiters are woken.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c | 171 +++++++++++++++++++++
 1 file changed, 171 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
index e9dff6eee323..bee86470a91d 100644
--- a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
@@ -263,11 +263,182 @@ static int igt_insert_complete(void *arg)
 	return err;
 }
 
+struct igt_wakeup {
+	struct task_struct *tsk;
+	atomic_t *ready, *set, *done;
+	struct intel_engine_cs *engine;
+	unsigned long flags;
+	wait_queue_head_t *wq;
+	u32 seqno;
+};
+
+static int wait_atomic(atomic_t *p)
+{
+	schedule();
+	return 0;
+}
+
+static int wait_atomic_timeout(atomic_t *p)
+{
+	return schedule_timeout(10 * HZ) ? 0 : -ETIMEDOUT;
+}
+
+static int igt_wakeup_thread(void *arg)
+{
+	struct igt_wakeup *w = arg;
+	struct intel_wait wait;
+
+	while (!kthread_should_stop()) {
+		DEFINE_WAIT(ready);
+
+		for (;;) {
+			prepare_to_wait(w->wq, &ready, TASK_INTERRUPTIBLE);
+			if (atomic_read(w->ready) == 0)
+				break;
+
+			schedule();
+		}
+		finish_wait(w->wq, &ready);
+		if (atomic_dec_and_test(w->set))
+			wake_up_atomic_t(w->set);
+
+		if (test_bit(0, &w->flags))
+			break;
+
+		intel_wait_init(&wait, w->seqno);
+		intel_engine_add_wait(w->engine, &wait);
+		for (;;) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			if (i915_seqno_passed(intel_engine_get_seqno(w->engine),
+					      w->seqno))
+				break;
+
+			schedule();
+		}
+		intel_engine_remove_wait(w->engine, &wait);
+		__set_current_state(TASK_RUNNING);
+
+		if (atomic_dec_and_test(w->done))
+			wake_up_atomic_t(w->done);
+	}
+
+	if (atomic_dec_and_test(w->done))
+		wake_up_atomic_t(w->done);
+	return 0;
+}
+
+static void igt_wake_all_sync(atomic_t *ready,
+			      atomic_t *set,
+			      atomic_t *done,
+			      wait_queue_head_t *wq,
+			      int count)
+{
+	atomic_set(set, count);
+	atomic_set(done, count);
+
+	atomic_set(ready, 0);
+	wake_up_all(wq);
+
+	wait_on_atomic_t(set, wait_atomic, TASK_UNINTERRUPTIBLE);
+	atomic_set(ready, count);
+}
+
+static int igt_wakeup(void *arg)
+{
+	const int state = TASK_UNINTERRUPTIBLE;
+	struct intel_engine_cs *engine = arg;
+	struct igt_wakeup *waiters;
+	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
+	const int count = 4096;
+	const u32 max_seqno = count / 4;
+	atomic_t ready, set, done;
+	int err = -ENOMEM;
+	int n, step;
+
+	mock_engine_reset(engine);
+
+	waiters = drm_malloc_gfp(count, sizeof(*waiters), GFP_TEMPORARY);
+	if (!waiters)
+		goto out_engines;
+
+	/* Create a large number of threads, each waiting on a random seqno.
+	 * Multiple waiters will be waiting for the same seqno.
+	 */
+	atomic_set(&ready, count);
+	for (n = 0; n < count; n++) {
+		waiters[n].wq = &wq;
+		waiters[n].ready = &ready;
+		waiters[n].set = &set;
+		waiters[n].done = &done;
+		waiters[n].engine = engine;
+		waiters[n].flags = 0;
+
+		waiters[n].tsk = kthread_run(igt_wakeup_thread, &waiters[n],
+					     "i915/igt:%d", n);
+		if (IS_ERR(waiters[n].tsk))
+			goto out_waiters;
+
+		get_task_struct(waiters[n].tsk);
+	}
+
+	for (step = 1; step <= max_seqno; step <<= 1) {
+		u32 seqno;
+
+		for (n = 0; n < count; n++)
+			waiters[n].seqno = 1 + get_random_int() % max_seqno;
+
+		mock_seqno_advance(engine, 0);
+		igt_wake_all_sync(&ready, &set, &done, &wq, count);
+
+		for (seqno = 1; seqno <= max_seqno + step; seqno += step) {
+			usleep_range(50, 500);
+			mock_seqno_advance(engine, seqno);
+		}
+		GEM_BUG_ON(intel_engine_get_seqno(engine) < 1 + max_seqno);
+
+		err = wait_on_atomic_t(&done, wait_atomic_timeout, state);
+		if (err) {
+			pr_err("Timed out waiting for %d remaining waiters\n",
+			       atomic_read(&done));
+			break;
+		}
+
+		err = check_rbtree_empty(engine);
+		if (err)
+			break;
+	}
+
+out_waiters:
+	for (n = 0; n < count; n++) {
+		if (IS_ERR(waiters[n].tsk))
+			break;
+
+		set_bit(0, &waiters[n].flags);
+	}
+
+	igt_wake_all_sync(&ready, &set, &done, &wq, n);
+	wait_on_atomic_t(&done, wait_atomic, state);
+
+	for (n = 0; n < count; n++) {
+		if (IS_ERR(waiters[n].tsk))
+			break;
+
+		kthread_stop(waiters[n].tsk);
+		put_task_struct(waiters[n].tsk);
+	}
+
+	drm_free_large(waiters);
+out_engines:
+	mock_engine_flush(engine);
+	return err;
+}
+
 int intel_breadcrumbs_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_random_insert_remove),
 		SUBTEST(igt_insert_complete),
+		SUBTEST(igt_wakeup),
 	};
 	struct intel_engine_cs *engine;
 	int err;
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 07/37] drm/i915: Mock the GEM device for self-testing
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (5 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 06/37] drm/i915: Add unit tests for the breadcrumb rbtree, wakeups Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 08/37] drm/i915: Mock a GGTT " Chris Wilson
                   ` (30 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

A simulacrum of drm_i915_private to let us pretend interactions with the
device.

v2: Tidy init error paths

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c                  |   4 +
 drivers/gpu/drm/i915/i915_gem.c                  |   1 +
 drivers/gpu/drm/i915/selftests/fake_drm.c        |  54 ++++++++++++
 drivers/gpu/drm/i915/selftests/fake_drm.h        |  31 +++++++
 drivers/gpu/drm/i915/selftests/mock_gem_device.c | 106 +++++++++++++++++++++++
 drivers/gpu/drm/i915/selftests/mock_gem_device.h |   8 ++
 drivers/gpu/drm/i915/selftests/mock_gem_object.h |   8 ++
 7 files changed, 212 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/fake_drm.c
 create mode 100644 drivers/gpu/drm/i915/selftests/fake_drm.h
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_gem_device.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_gem_device.h
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_gem_object.h

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index aefab9a1a68e..41bf81bdae4e 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -2604,3 +2604,7 @@ static struct drm_driver driver = {
 	.minor = DRIVER_MINOR,
 	.patchlevel = DRIVER_PATCHLEVEL,
 };
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/fake_drm.c"
+#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index e88541b5b72b..ddc85a7c8d82 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4896,4 +4896,5 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
 
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftests/scatterlist.c"
+#include "selftests/mock_gem_device.c"
 #endif
diff --git a/drivers/gpu/drm/i915/selftests/fake_drm.c b/drivers/gpu/drm/i915/selftests/fake_drm.c
new file mode 100644
index 000000000000..76af50d2cbaf
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/fake_drm.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2017 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 "fake_drm.h"
+
+static inline struct inode fake_inode(struct drm_i915_private *i915)
+{
+	return (struct inode){ .i_rdev = i915->drm.primary->index };
+}
+
+struct drm_file *fake_file(struct drm_i915_private *i915)
+{
+	struct inode inode = fake_inode(i915);
+	struct file filp = {};
+	struct drm_file *file;
+	int err;
+
+	err = drm_open(&inode, &filp);
+	if (unlikely(err))
+		return ERR_PTR(err);
+
+	file = filp.private_data;
+	file->authenticated = true;
+	return file;
+}
+
+void fake_file_free(struct drm_i915_private *i915, struct drm_file *file)
+{
+	struct inode inode = fake_inode(i915);
+	struct file filp = { .private_data = file };
+
+	drm_release(&inode, &filp);
+}
diff --git a/drivers/gpu/drm/i915/selftests/fake_drm.h b/drivers/gpu/drm/i915/selftests/fake_drm.h
new file mode 100644
index 000000000000..5e1975084959
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/fake_drm.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2017 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 __FAKE_DRM_H
+#define __FAKE_DRM_H
+
+struct drm_file *fake_file(struct drm_i915_private *i915);
+void fake_file_free(struct drm_i915_private *i915, struct drm_file *file);
+
+#endif /* !__FAKE_DRM_H */
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
new file mode 100644
index 000000000000..0d5484467a4b
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -0,0 +1,106 @@
+/*
+ * 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 <linux/pm_runtime.h>
+
+#include "mock_gem_device.h"
+#include "mock_gem_object.h"
+
+static void mock_device_release(struct drm_device *dev)
+{
+	struct drm_i915_private *i915 = to_i915(dev);
+
+	i915_gem_drain_freed_objects(i915);
+
+	kmem_cache_destroy(i915->objects);
+	put_device(&i915->drm.pdev->dev);
+}
+
+static struct drm_driver mock_driver = {
+	.name = "mock",
+	.driver_features = DRIVER_GEM,
+	.release = mock_device_release,
+
+	.gem_close_object = i915_gem_close_object,
+	.gem_free_object_unlocked = i915_gem_free_object,
+};
+
+static void release_dev(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	kfree(pdev);
+}
+
+struct drm_i915_private *mock_gem_device(void)
+{
+	struct drm_i915_private *i915;
+	struct pci_dev *pdev;
+	int err;
+
+	i915 = kzalloc(sizeof(*i915), GFP_TEMPORARY);
+	if (!i915)
+		goto err;
+
+	pdev = kzalloc(sizeof(*pdev), GFP_TEMPORARY);
+	if (!pdev)
+		goto free_device;
+
+	device_initialize(&pdev->dev);
+	pdev->dev.release = release_dev;
+	dev_set_name(&pdev->dev, "mock");
+	dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	pci_set_drvdata(pdev, i915);
+
+	err = drm_dev_init(&i915->drm, &mock_driver, &pdev->dev);
+	if (err) {
+		pr_err("Failed to initialise mock GEM device: err=%d\n", err);
+		goto put_device;
+	}
+	i915->drm.pdev = pdev;
+	i915->drm.dev_private = i915;
+
+	mkwrite_device_info(i915)->gen = -1;
+
+	spin_lock_init(&i915->mm.object_stat_lock);
+
+	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
+	init_llist_head(&i915->mm.free_list);
+
+	i915->objects = KMEM_CACHE(mock_object, SLAB_HWCACHE_ALIGN);
+	if (!i915->objects)
+		goto put_device;
+
+	return i915;
+
+put_device:
+	put_device(&pdev->dev);
+free_device:
+	kfree(i915);
+err:
+	return NULL;
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.h b/drivers/gpu/drm/i915/selftests/mock_gem_device.h
new file mode 100644
index 000000000000..7ff7c848f731
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.h
@@ -0,0 +1,8 @@
+#ifndef __MOCK_GEM_DEVICE_H__
+#define __MOCK_GEM_DEVICE_H__
+
+#include "i915_drv.h"
+
+struct drm_i915_private *mock_gem_device(void);
+
+#endif /* !__MOCK_GEM_DEVICE_H__ */
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_object.h b/drivers/gpu/drm/i915/selftests/mock_gem_object.h
new file mode 100644
index 000000000000..9fbf67321662
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_object.h
@@ -0,0 +1,8 @@
+#ifndef __MOCK_GEM_OBJECT_H__
+#define __MOCK_GEM_OBJECT_H__
+
+struct mock_object {
+	struct drm_i915_gem_object base;
+};
+
+#endif /* !__MOCK_GEM_OBJECT_H__ */
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 08/37] drm/i915: Mock a GGTT for self-testing
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (6 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 07/37] drm/i915: Mock the GEM device for self-testing Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 09/37] drm/i915: Mock infrastructure for request emission Chris Wilson
                   ` (29 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

A very simple mockery, just a random manager and timeline. Useful for
inserting objects and ordering retirement; and not much else.

v2: mock_fini_ggtt() to complement mock_init_ggtt().

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_gtt.c              |   4 +
 drivers/gpu/drm/i915/selftests/mock_gem_device.c |  31 +++++
 drivers/gpu/drm/i915/selftests/mock_gtt.c        | 138 +++++++++++++++++++++++
 drivers/gpu/drm/i915/selftests/mock_gtt.h        |  35 ++++++
 4 files changed, 208 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_gtt.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_gtt.h

diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index e505de295848..f0057b812337 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -3764,3 +3764,7 @@ int i915_gem_gtt_insert(struct i915_address_space *vm,
 					   size, alignment, color,
 					   start, end, DRM_MM_INSERT_EVICT);
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/mock_gtt.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index 0d5484467a4b..8f5fbc18a607 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -26,13 +26,20 @@
 
 #include "mock_gem_device.h"
 #include "mock_gem_object.h"
+#include "mock_gtt.h"
 
 static void mock_device_release(struct drm_device *dev)
 {
 	struct drm_i915_private *i915 = to_i915(dev);
 
+	mutex_lock(&i915->drm.struct_mutex);
+	mock_fini_ggtt(i915);
+	i915_gem_timeline_fini(&i915->gt.global_timeline);
+	mutex_unlock(&i915->drm.struct_mutex);
+
 	i915_gem_drain_freed_objects(i915);
 
+	kmem_cache_destroy(i915->vmas);
 	kmem_cache_destroy(i915->objects);
 	put_device(&i915->drm.pdev->dev);
 }
@@ -84,19 +91,43 @@ struct drm_i915_private *mock_gem_device(void)
 	i915->drm.pdev = pdev;
 	i915->drm.dev_private = i915;
 
+	/* Using the global GTT may ask questions about KMS users, so prepare */
+	drm_mode_config_init(&i915->drm);
+
 	mkwrite_device_info(i915)->gen = -1;
 
 	spin_lock_init(&i915->mm.object_stat_lock);
 
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
 	init_llist_head(&i915->mm.free_list);
+	INIT_LIST_HEAD(&i915->mm.unbound_list);
+	INIT_LIST_HEAD(&i915->mm.bound_list);
 
 	i915->objects = KMEM_CACHE(mock_object, SLAB_HWCACHE_ALIGN);
 	if (!i915->objects)
 		goto put_device;
 
+	i915->vmas = KMEM_CACHE(i915_vma, SLAB_HWCACHE_ALIGN);
+	if (!i915->vmas)
+		goto err_objects;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	INIT_LIST_HEAD(&i915->gt.timelines);
+	err = i915_gem_timeline_init__global(i915);
+	if (err) {
+		mutex_unlock(&i915->drm.struct_mutex);
+		goto err_vmas;
+	}
+
+	mock_init_ggtt(i915);
+	mutex_unlock(&i915->drm.struct_mutex);
+
 	return i915;
 
+err_vmas:
+	kmem_cache_destroy(i915->vmas);
+err_objects:
+	kmem_cache_destroy(i915->objects);
 put_device:
 	put_device(&pdev->dev);
 free_device:
diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c
new file mode 100644
index 000000000000..e176a04f482b
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c
@@ -0,0 +1,138 @@
+/*
+ * 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 "mock_gtt.h"
+
+static void mock_insert_page(struct i915_address_space *vm,
+			     dma_addr_t addr,
+			     uint64_t offset,
+			     enum i915_cache_level level,
+			     u32 flags)
+{
+}
+
+static void mock_insert_entries(struct i915_address_space *vm,
+				struct sg_table *st,
+				uint64_t start,
+				enum i915_cache_level level, u32 flags)
+{
+}
+
+static int mock_bind_ppgtt(struct i915_vma *vma,
+			   enum i915_cache_level cache_level,
+			   u32 flags)
+{
+	GEM_BUG_ON(flags & I915_VMA_GLOBAL_BIND);
+	vma->pages = vma->obj->mm.pages;
+	vma->flags |= I915_VMA_LOCAL_BIND;
+	return 0;
+}
+
+static void mock_unbind_ppgtt(struct i915_vma *vma)
+{
+}
+
+static void mock_cleanup(struct i915_address_space *vm)
+{
+}
+
+struct i915_hw_ppgtt *
+mock_ppgtt(struct drm_i915_private *i915,
+	   const char *name)
+{
+	struct i915_hw_ppgtt *ppgtt;
+
+	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+	if (!ppgtt)
+		return NULL;
+
+	kref_init(&ppgtt->ref);
+	ppgtt->base.i915 = i915;
+	ppgtt->base.total = round_down(U64_MAX, PAGE_SIZE);
+	ppgtt->base.file = ERR_PTR(-ENODEV);
+
+	INIT_LIST_HEAD(&ppgtt->base.active_list);
+	INIT_LIST_HEAD(&ppgtt->base.inactive_list);
+	INIT_LIST_HEAD(&ppgtt->base.unbound_list);
+
+	INIT_LIST_HEAD(&ppgtt->base.global_link);
+	drm_mm_init(&ppgtt->base.mm, 0, ppgtt->base.total);
+	i915_gem_timeline_init(i915, &ppgtt->base.timeline, name);
+
+	ppgtt->base.clear_range = nop_clear_range;
+	ppgtt->base.insert_page = mock_insert_page;
+	ppgtt->base.insert_entries = mock_insert_entries;
+	ppgtt->base.bind_vma = mock_bind_ppgtt;
+	ppgtt->base.unbind_vma = mock_unbind_ppgtt;
+	ppgtt->base.cleanup = mock_cleanup;
+
+	return ppgtt;
+}
+
+static int mock_bind_ggtt(struct i915_vma *vma,
+			  enum i915_cache_level cache_level,
+			  u32 flags)
+{
+	int err;
+
+	err = i915_get_ggtt_vma_pages(vma);
+	if (err)
+		return err;
+
+	vma->flags |= I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND;
+	return 0;
+}
+
+static void mock_unbind_ggtt(struct i915_vma *vma)
+{
+}
+
+void mock_init_ggtt(struct drm_i915_private *i915)
+{
+	struct i915_ggtt *ggtt = &i915->ggtt;
+
+	INIT_LIST_HEAD(&i915->vm_list);
+
+	ggtt->base.i915 = i915;
+
+	ggtt->mappable_base = 0;
+	ggtt->mappable_end = 2048 * PAGE_SIZE;
+	ggtt->base.total = 4096 * PAGE_SIZE;
+
+	ggtt->base.clear_range = nop_clear_range;
+	ggtt->base.insert_page = mock_insert_page;
+	ggtt->base.insert_entries = mock_insert_entries;
+	ggtt->base.bind_vma = mock_bind_ggtt;
+	ggtt->base.unbind_vma = mock_unbind_ggtt;
+	ggtt->base.cleanup = mock_cleanup;
+
+	i915_address_space_init(&ggtt->base, i915, "global");
+}
+
+void mock_fini_ggtt(struct drm_i915_private *i915)
+{
+	struct i915_ggtt *ggtt = &i915->ggtt;
+
+	i915_address_space_fini(&ggtt->base);
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.h b/drivers/gpu/drm/i915/selftests/mock_gtt.h
new file mode 100644
index 000000000000..9a0a833bb545
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_gtt.h
@@ -0,0 +1,35 @@
+/*
+ * 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 __MOCK_GTT_H
+#define __MOCK_GTT_H
+
+void mock_init_ggtt(struct drm_i915_private *i915);
+void mock_fini_ggtt(struct drm_i915_private *i915);
+
+struct i915_hw_ppgtt *
+mock_ppgtt(struct drm_i915_private *i915,
+	   const char *name);
+
+#endif /* !__MOCK_GTT_H */
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 09/37] drm/i915: Mock infrastructure for request emission
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (7 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 08/37] drm/i915: Mock a GGTT " Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 13:11   ` Tvrtko Ursulin
  2017-01-11 21:09 ` [PATCH 10/37] drm/i915: Create a fake object for testing huge allocations Chris Wilson
                   ` (28 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Create a fake engine that runs requests using a timer to simulate hw.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem_context.c            |   4 +
 drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c |  11 +-
 drivers/gpu/drm/i915/selftests/mock_context.c      |  70 +++++++++
 drivers/gpu/drm/i915/selftests/mock_context.h      |  34 ++++
 drivers/gpu/drm/i915/selftests/mock_engine.c       | 172 +++++++++++++++++++--
 drivers/gpu/drm/i915/selftests/mock_engine.h       |  18 ++-
 drivers/gpu/drm/i915/selftests/mock_gem_device.c   |  95 +++++++++++-
 drivers/gpu/drm/i915/selftests/mock_gem_device.h   |   1 +
 drivers/gpu/drm/i915/selftests/mock_request.c      |  44 ++++++
 drivers/gpu/drm/i915/selftests/mock_request.h      |  44 ++++++
 10 files changed, 475 insertions(+), 18 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_context.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_context.h
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_request.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_request.h

diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index fbd3b8ecbe20..91551b01a62c 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -1185,3 +1185,7 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 
 	return 0;
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/mock_context.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
index bee86470a91d..2742103247c0 100644
--- a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
@@ -25,6 +25,7 @@
 #include "i915_random.h"
 #include "i915_selftest.h"
 
+#include "mock_gem_device.h"
 #include "mock_engine.h"
 
 static int check_rbtree(struct intel_engine_cs *engine,
@@ -440,15 +441,15 @@ int intel_breadcrumbs_mock_selftests(void)
 		SUBTEST(igt_insert_complete),
 		SUBTEST(igt_wakeup),
 	};
-	struct intel_engine_cs *engine;
+	struct drm_i915_private *i915;
 	int err;
 
-	engine = mock_engine("mock");
-	if (!engine)
+	i915 = mock_gem_device();
+	if (!i915)
 		return -ENOMEM;
 
-	err = i915_subtests(tests, engine);
-	kfree(engine);
+	err = i915_subtests(tests, i915->engine[RCS]);
+	drm_dev_unref(&i915->drm);
 
 	return err;
 }
diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c
new file mode 100644
index 000000000000..5098dbbc81d5
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_context.c
@@ -0,0 +1,70 @@
+/*
+ * 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 "mock_context.h"
+#include "mock_gtt.h"
+
+struct i915_gem_context *
+mock_context(struct drm_i915_private *i915,
+	     const char *name)
+{
+	struct i915_gem_context *ctx;
+	int ret;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return NULL;
+
+	kref_init(&ctx->ref);
+	INIT_LIST_HEAD(&ctx->link);
+	ctx->name = name ? kstrdup(name, GFP_KERNEL) : NULL;
+	ctx->i915 = i915;
+
+	ret = ida_simple_get(&i915->context_hw_ida,
+			     0, MAX_CONTEXT_HW_ID, GFP_KERNEL);
+	if (ret < 0) {
+		kfree(ctx);
+		return NULL;
+	}
+	ctx->hw_id = ret;
+
+	if (name) {
+		ctx->ppgtt = mock_ppgtt(i915, name);
+		if (!ctx->ppgtt) {
+			kfree(ctx);
+			return NULL;
+		}
+	}
+
+	return ctx;
+}
+
+void mock_context_close(struct i915_gem_context *ctx)
+{
+	i915_gem_context_set_closed(ctx);
+
+	i915_ppgtt_close(&ctx->ppgtt->base);
+
+	i915_gem_context_put(ctx);
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_context.h b/drivers/gpu/drm/i915/selftests/mock_context.h
new file mode 100644
index 000000000000..2427e5c0916a
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_context.h
@@ -0,0 +1,34 @@
+/*
+ * 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 __MOCK_CONTEXT_H
+#define __MOCK_CONTEXT_H
+
+struct i915_gem_context *
+mock_context(struct drm_i915_private *i915,
+	     const char *name);
+
+void mock_context_close(struct i915_gem_context *ctx);
+
+#endif /* !__MOCK_CONTEXT_H */
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
index 085d611ed56b..b4b96d247a67 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.c
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
@@ -23,33 +23,185 @@
  */
 
 #include "mock_engine.h"
+#include "mock_request.h"
 
-struct intel_engine_cs *mock_engine(const char *name)
+static struct mock_request *first_request(struct mock_engine *engine)
 {
-	struct intel_engine_cs *engine;
+	return list_first_entry_or_null(&engine->hw_queue,
+					struct mock_request,
+					link);
+}
+
+static void hw_delay_complete(unsigned long data)
+{
+	struct mock_engine *engine = (typeof(engine))data;
+	struct mock_request *request;
+
+	spin_lock(&engine->hw_lock);
+
+	request = first_request(engine);
+	if (request) {
+		list_del_init(&request->link);
+		mock_seqno_advance(&engine->base, request->base.global_seqno);
+	}
+
+	request = first_request(engine);
+	if (request)
+		mod_timer(&engine->hw_delay, jiffies + request->delay);
+
+	spin_unlock(&engine->hw_lock);
+}
+
+static int mock_context_pin(struct intel_engine_cs *engine,
+			    struct i915_gem_context *ctx)
+{
+	i915_gem_context_get(ctx);
+	return 0;
+}
+
+static void mock_context_unpin(struct intel_engine_cs *engine,
+			       struct i915_gem_context *ctx)
+{
+	i915_gem_context_put(ctx);
+}
+
+static int mock_request_alloc(struct drm_i915_gem_request *request)
+{
+	struct mock_request *mock = container_of(request, typeof(*mock), base);
+
+	INIT_LIST_HEAD(&mock->link);
+	mock->delay = 0;
+
+	request->ring = request->engine->buffer;
+	return 0;
+}
+
+static int mock_emit_flush(struct drm_i915_gem_request *request,
+			   unsigned int flags)
+{
+	return 0;
+}
+
+static void mock_emit_breadcrumb(struct drm_i915_gem_request *request,
+				 u32 *flags)
+{
+}
+
+static void mock_submit_request(struct drm_i915_gem_request *request)
+{
+	struct mock_request *mock = container_of(request, typeof(*mock), base);
+	struct mock_engine *engine =
+		container_of(request->engine, typeof(*engine), base);
+
+	i915_gem_request_submit(request);
+	GEM_BUG_ON(!request->global_seqno);
+
+	spin_lock_irq(&engine->hw_lock);
+	list_add_tail(&mock->link, &engine->hw_queue);
+	if (mock->link.prev == &engine->hw_queue)
+		mod_timer(&engine->hw_delay, jiffies + mock->delay);
+	spin_unlock_irq(&engine->hw_lock);
+}
+
+static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
+{
+	const unsigned long sz = roundup_pow_of_two(sizeof(struct intel_ring));
+	struct intel_ring *ring;
+
+	ring = kzalloc(sizeof(*ring) + sz, GFP_TEMPORARY);
+	if (!ring)
+		return NULL;
+
+	ring->engine = engine;
+	ring->size = sz;
+	ring->effective_size = sz;
+	ring->vaddr = (void *)(ring + 1);
+
+	INIT_LIST_HEAD(&ring->request_list);
+	ring->last_retired_head = -1;
+	intel_ring_update_space(ring);
+
+	return ring;
+}
+
+struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
+				    const char *name)
+{
+	struct mock_engine *engine;
 	static int id;
 
 	engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_TEMPORARY);
 	if (!engine)
 		return NULL;
 
-	/* minimal engine setup for seqno */
-	engine->name = name;
-	engine->id = id++;
-	engine->status_page.page_addr = (void *)(engine + 1);
+	engine->base.buffer = mock_ring(&engine->base);
+	if (!engine->base.buffer) {
+		kfree(engine);
+		return NULL;
+	}
 
-	/* minimal breadcrumbs init */
-	spin_lock_init(&engine->breadcrumbs.lock);
-	engine->breadcrumbs.mock = true;
+	/* minimal engine setup for requests */
+	engine->base.i915 = i915;
+	engine->base.name = name;
+	engine->base.id = id++;
+	engine->base.status_page.page_addr = (void *)(engine + 1);
 
-	return engine;
+	engine->base.context_pin = mock_context_pin;
+	engine->base.context_unpin = mock_context_unpin;
+	engine->base.request_alloc = mock_request_alloc;
+	engine->base.emit_flush = mock_emit_flush;
+	engine->base.emit_breadcrumb = mock_emit_breadcrumb;
+	engine->base.submit_request = mock_submit_request;
+
+	engine->base.timeline =
+		&i915->gt.global_timeline.engine[engine->base.id];
+
+	intel_engine_init_breadcrumbs(&engine->base);
+	engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
+
+	/* fake hw queue */
+	spin_lock_init(&engine->hw_lock);
+	setup_timer(&engine->hw_delay,
+		    hw_delay_complete,
+		    (unsigned long)engine);
+	INIT_LIST_HEAD(&engine->hw_queue);
+
+	return &engine->base;
 }
 
 void mock_engine_flush(struct intel_engine_cs *engine)
 {
+	struct mock_engine *mock =
+		container_of(engine, typeof(*mock), base);
+	struct mock_request *request, *rn;
+
+	del_timer_sync(&mock->hw_delay);
+
+	spin_lock_irq(&mock->hw_lock);
+	list_for_each_entry_safe(request, rn, &mock->hw_queue, link) {
+		list_del_init(&request->link);
+		mock_seqno_advance(&mock->base, request->base.global_seqno);
+	}
+	spin_unlock_irq(&mock->hw_lock);
 }
 
 void mock_engine_reset(struct intel_engine_cs *engine)
 {
 	intel_write_status_page(engine, I915_GEM_HWS_INDEX, 0);
 }
+
+void mock_engine_free(struct intel_engine_cs *engine)
+{
+	struct mock_engine *mock =
+		container_of(engine, typeof(*mock), base);
+
+	GEM_BUG_ON(timer_pending(&mock->hw_delay));
+
+	if (engine->last_retired_context)
+		engine->context_unpin(engine, engine->last_retired_context);
+
+	intel_engine_fini_breadcrumbs(engine);
+
+	kfree(engine->buffer);
+	kfree(engine);
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.h b/drivers/gpu/drm/i915/selftests/mock_engine.h
index 9cfe9671f860..d080d0a10a4f 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.h
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.h
@@ -25,9 +25,25 @@
 #ifndef __MOCK_ENGINE_H__
 #define __MOCK_ENGINE_H__
 
-struct intel_engine_cs *mock_engine(const char *name);
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+
+#include "intel_ringbuffer.h"
+
+struct mock_engine {
+	struct intel_engine_cs base;
+
+	spinlock_t hw_lock;
+	struct list_head hw_queue;
+	struct timer_list hw_delay;
+};
+
+struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
+				    const char *name);
 void mock_engine_flush(struct intel_engine_cs *engine);
 void mock_engine_reset(struct intel_engine_cs *engine);
+void mock_engine_free(struct intel_engine_cs *engine);
 
 static inline void mock_seqno_advance(struct intel_engine_cs *engine, u32 seqno)
 {
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index 8f5fbc18a607..7ce86ed71764 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -24,21 +24,57 @@
 
 #include <linux/pm_runtime.h>
 
+#include "mock_engine.h"
+#include "mock_context.h"
+#include "mock_request.h"
 #include "mock_gem_device.h"
 #include "mock_gem_object.h"
 #include "mock_gtt.h"
 
+void mock_device_flush(struct drm_i915_private *i915)
+{
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+
+	lockdep_assert_held(&i915->drm.struct_mutex);
+
+	for_each_engine(engine, i915, id)
+		mock_engine_flush(engine);
+
+	i915_gem_retire_requests(i915);
+}
+
 static void mock_device_release(struct drm_device *dev)
 {
 	struct drm_i915_private *i915 = to_i915(dev);
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
 
 	mutex_lock(&i915->drm.struct_mutex);
+	mock_device_flush(i915);
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	cancel_delayed_work_sync(&i915->gt.retire_work);
+	cancel_delayed_work_sync(&i915->gt.idle_work);
+
+	mutex_lock(&i915->drm.struct_mutex);
+	for_each_engine(engine, i915, id)
+		mock_engine_free(engine);
+
+	i915_gem_context_fini(i915);
+
 	mock_fini_ggtt(i915);
 	i915_gem_timeline_fini(&i915->gt.global_timeline);
 	mutex_unlock(&i915->drm.struct_mutex);
 
+	drain_workqueue(i915->wq);
+
 	i915_gem_drain_freed_objects(i915);
 
+	destroy_workqueue(i915->wq);
+
+	kmem_cache_destroy(i915->dependencies);
+	kmem_cache_destroy(i915->requests);
 	kmem_cache_destroy(i915->vmas);
 	kmem_cache_destroy(i915->objects);
 	put_device(&i915->drm.pdev->dev);
@@ -60,9 +96,19 @@ static void release_dev(struct device *dev)
 	kfree(pdev);
 }
 
+static void mock_retire_work_handler(struct work_struct *work)
+{
+}
+
+static void mock_idle_work_handler(struct work_struct *work)
+{
+}
+
 struct drm_i915_private *mock_gem_device(void)
 {
 	struct drm_i915_private *i915;
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
 	struct pci_dev *pdev;
 	int err;
 
@@ -98,36 +144,81 @@ struct drm_i915_private *mock_gem_device(void)
 
 	spin_lock_init(&i915->mm.object_stat_lock);
 
+	init_waitqueue_head(&i915->gpu_error.wait_queue);
+	init_waitqueue_head(&i915->gpu_error.reset_queue);
+
+	i915->wq = alloc_ordered_workqueue("mock", 0);
+	if (!i915->wq)
+		goto put_device;
+
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
 	init_llist_head(&i915->mm.free_list);
 	INIT_LIST_HEAD(&i915->mm.unbound_list);
 	INIT_LIST_HEAD(&i915->mm.bound_list);
 
+	ida_init(&i915->context_hw_ida);
+
+	INIT_DELAYED_WORK(&i915->gt.retire_work, mock_retire_work_handler);
+	INIT_DELAYED_WORK(&i915->gt.idle_work, mock_idle_work_handler);
+
+	i915->gt.awake = true;
+
 	i915->objects = KMEM_CACHE(mock_object, SLAB_HWCACHE_ALIGN);
 	if (!i915->objects)
-		goto put_device;
+		goto err_wq;
 
 	i915->vmas = KMEM_CACHE(i915_vma, SLAB_HWCACHE_ALIGN);
 	if (!i915->vmas)
 		goto err_objects;
 
+	i915->requests = KMEM_CACHE(mock_request,
+				    SLAB_HWCACHE_ALIGN |
+				    SLAB_RECLAIM_ACCOUNT |
+				    SLAB_DESTROY_BY_RCU);
+	if (!i915->requests)
+		goto err_vmas;
+
+	i915->dependencies = KMEM_CACHE(i915_dependency,
+					SLAB_HWCACHE_ALIGN |
+					SLAB_RECLAIM_ACCOUNT);
+	if (!i915->dependencies)
+		goto err_requests;
+
 	mutex_lock(&i915->drm.struct_mutex);
 	INIT_LIST_HEAD(&i915->gt.timelines);
 	err = i915_gem_timeline_init__global(i915);
 	if (err) {
 		mutex_unlock(&i915->drm.struct_mutex);
-		goto err_vmas;
+		goto err_dependencies;
 	}
 
 	mock_init_ggtt(i915);
 	mutex_unlock(&i915->drm.struct_mutex);
 
+	mkwrite_device_info(i915)->ring_mask = BIT(0);
+	i915->engine[RCS] = mock_engine(i915, "mock");
+	if (!i915->engine[RCS])
+		goto err_dependencies;
+
+	i915->kernel_context = mock_context(i915, NULL);
+	if (!i915->kernel_context)
+		goto err_engine;
+
 	return i915;
 
+err_engine:
+	for_each_engine(engine, i915, id)
+		mock_engine_free(engine);
+err_dependencies:
+	kmem_cache_destroy(i915->dependencies);
+err_requests:
+	kmem_cache_destroy(i915->requests);
 err_vmas:
 	kmem_cache_destroy(i915->vmas);
 err_objects:
 	kmem_cache_destroy(i915->objects);
+err_wq:
+	destroy_workqueue(i915->wq);
 put_device:
 	put_device(&pdev->dev);
 free_device:
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.h b/drivers/gpu/drm/i915/selftests/mock_gem_device.h
index 7ff7c848f731..7eceff766957 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.h
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.h
@@ -4,5 +4,6 @@
 #include "i915_drv.h"
 
 struct drm_i915_private *mock_gem_device(void);
+void mock_device_flush(struct drm_i915_private *i915);
 
 #endif /* !__MOCK_GEM_DEVICE_H__ */
diff --git a/drivers/gpu/drm/i915/selftests/mock_request.c b/drivers/gpu/drm/i915/selftests/mock_request.c
new file mode 100644
index 000000000000..e23242d1b88a
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_request.c
@@ -0,0 +1,44 @@
+/*
+ * 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 "mock_request.h"
+
+struct drm_i915_gem_request *
+mock_request(struct intel_engine_cs *engine,
+	     struct i915_gem_context *context,
+	     unsigned long delay)
+{
+	struct drm_i915_gem_request *request;
+	struct mock_request *mock;
+
+	/* NB the i915->requests slab cache is enlarged to fit mock_request */
+	request = i915_gem_request_alloc(engine, context);
+	if (!request)
+		return NULL;
+
+	mock = container_of(request, typeof(*mock), base);
+	mock->delay = delay;
+
+	return &mock->base;
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_request.h b/drivers/gpu/drm/i915/selftests/mock_request.h
new file mode 100644
index 000000000000..9c739125cab5
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_request.h
@@ -0,0 +1,44 @@
+/*
+ * 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 __MOCK_REQUEST__
+#define __MOCK_REQUEST__
+
+#include <linux/list.h>
+
+#include "i915_gem_request.h"
+
+struct mock_request {
+	struct drm_i915_gem_request base;
+
+	struct list_head link;
+	unsigned long delay;
+};
+
+struct drm_i915_gem_request *
+mock_request(struct intel_engine_cs *engine,
+	     struct i915_gem_context *context,
+	     unsigned long delay);
+
+#endif /* !__MOCK_REQUEST__ */
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 10/37] drm/i915: Create a fake object for testing huge allocations
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (8 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 09/37] drm/i915: Mock infrastructure for request emission Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 10:56   ` Matthew Auld
  2017-01-11 21:09 ` [PATCH 11/37] drm/i915: Add selftests for i915_gem_request Chris Wilson
                   ` (27 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

We would like to be able to exercise huge allocations even on memory
constrained devices. To do this we create an object that allocates only
a few pages and remaps them across its whole range - each page is reused
multiple times. We can therefore pretend we are rendering into a much
larger object.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem.c                  |   1 +
 drivers/gpu/drm/i915/i915_gem_object.h           |  20 ++--
 drivers/gpu/drm/i915/selftests/huge_gem_object.c | 130 +++++++++++++++++++++++
 drivers/gpu/drm/i915/selftests/huge_gem_object.h |  33 ++++++
 4 files changed, 176 insertions(+), 8 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/selftests/huge_gem_object.c
 create mode 100644 drivers/gpu/drm/i915/selftests/huge_gem_object.h

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index ddc85a7c8d82..07b4ba3df94c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4897,4 +4897,5 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftests/scatterlist.c"
 #include "selftests/mock_gem_device.c"
+#include "selftests/huge_gem_object.c"
 #endif
diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h
index 290eaa7fc9eb..4114cc8a0b9b 100644
--- a/drivers/gpu/drm/i915/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/i915_gem_object.h
@@ -167,14 +167,18 @@ struct drm_i915_gem_object {
 	/** Record of address bit 17 of each page at last unbind. */
 	unsigned long *bit_17;
 
-	struct i915_gem_userptr {
-		uintptr_t ptr;
-		unsigned read_only :1;
-
-		struct i915_mm_struct *mm;
-		struct i915_mmu_object *mmu_object;
-		struct work_struct *work;
-	} userptr;
+	union {
+		struct i915_gem_userptr {
+			uintptr_t ptr;
+			unsigned read_only :1;
+
+			struct i915_mm_struct *mm;
+			struct i915_mmu_object *mmu_object;
+			struct work_struct *work;
+		} userptr;
+
+		unsigned long scratch;
+	};
 
 	/** for phys allocated objects */
 	struct drm_dma_handle *phys_handle;
diff --git a/drivers/gpu/drm/i915/selftests/huge_gem_object.c b/drivers/gpu/drm/i915/selftests/huge_gem_object.c
new file mode 100644
index 000000000000..df00e14ce8bc
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/huge_gem_object.c
@@ -0,0 +1,130 @@
+/*
+ * 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 "huge_gem_object.h"
+
+static void huge_free_pages(struct drm_i915_gem_object *obj,
+			    struct sg_table *pages)
+{
+	unsigned long nreal = obj->scratch / PAGE_SIZE;
+	struct scatterlist *sg;
+
+	for (sg = pages->sgl; sg && nreal--; sg = ____sg_next(sg))
+		__free_page(sg_page(sg));
+
+	sg_free_table(pages);
+	kfree(pages);
+}
+
+static struct sg_table *
+huge_get_pages(struct drm_i915_gem_object *obj)
+{
+#define GFP (GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY)
+	const unsigned long nreal = obj->scratch / PAGE_SIZE;
+	const unsigned long npages = obj->base.size / PAGE_SIZE;
+	struct scatterlist *sg, *src, *end;
+	struct sg_table *pages;
+	unsigned long n;
+
+	pages = kmalloc(sizeof(*pages), GFP);
+	if (!pages)
+		return ERR_PTR(-ENOMEM);
+
+	if (sg_alloc_table(pages, npages, GFP)) {
+		kfree(pages);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sg = pages->sgl;
+	for (n = 0; n < nreal; n++) {
+		struct page *page;
+
+		page = alloc_page(GFP | __GFP_HIGHMEM);
+		if (!page) {
+			sg_mark_end(sg);
+			goto err;
+		}
+
+		sg_set_page(sg, page, PAGE_SIZE, 0);
+		sg = ____sg_next(sg);
+	}
+	if (nreal < npages) {
+		for (end = sg, src = pages->sgl; sg; sg = __sg_next(sg)) {
+			sg_set_page(sg, sg_page(src), PAGE_SIZE, 0);
+			src = ____sg_next(src);
+			if (src == end)
+				src = pages->sgl;
+		}
+	}
+
+	if (i915_gem_gtt_prepare_pages(obj, pages))
+		goto err;
+
+	return pages;
+
+err:
+	huge_free_pages(obj, pages);
+	return ERR_PTR(-ENOMEM);
+#undef GFP
+}
+
+static void huge_put_pages(struct drm_i915_gem_object *obj,
+			   struct sg_table *pages)
+{
+	i915_gem_gtt_finish_pages(obj, pages);
+	huge_free_pages(obj, pages);
+
+	obj->mm.dirty = false;
+}
+
+static const struct drm_i915_gem_object_ops huge_ops = {
+	.flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE |
+		 I915_GEM_OBJECT_IS_SHRINKABLE,
+	.get_pages = huge_get_pages,
+	.put_pages = huge_put_pages,
+};
+
+struct drm_i915_gem_object *
+huge_gem_object(struct drm_i915_private *i915,
+		unsigned long real_size,
+		unsigned long total_size)
+{
+	struct drm_i915_gem_object *obj;
+
+	GEM_BUG_ON(!real_size || real_size > total_size);
+
+	obj = i915_gem_object_alloc(i915);
+	if (!obj)
+		return ERR_PTR(-ENOMEM);
+
+	drm_gem_private_object_init(&i915->drm, &obj->base, total_size);
+	i915_gem_object_init(obj, &huge_ops);
+
+	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
+	obj->cache_level = HAS_LLC(i915) ? I915_CACHE_LLC : I915_CACHE_NONE;
+	obj->scratch = real_size;
+
+	return obj;
+}
diff --git a/drivers/gpu/drm/i915/selftests/huge_gem_object.h b/drivers/gpu/drm/i915/selftests/huge_gem_object.h
new file mode 100644
index 000000000000..0d80f0f70bbc
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/huge_gem_object.h
@@ -0,0 +1,33 @@
+/*
+ * 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 __HUGE_GEM_OBJECT_H
+#define __HUGE_GEM_OBJECT_H
+
+struct drm_i915_gem_object *
+huge_gem_object(struct drm_i915_private *i915,
+		unsigned long real_size,
+		unsigned long total_size);
+
+#endif /* !__HUGE_GEM_OBJECT_H */
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 11/37] drm/i915: Add selftests for i915_gem_request
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (9 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 10/37] drm/i915: Create a fake object for testing huge allocations Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 11:20   ` Tvrtko Ursulin
  2017-01-11 21:09 ` [PATCH 12/37] drm/i915: Add a simple request selftest for waiting Chris Wilson
                   ` (26 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Simple starting point for adding seltests for i915_gem_request, first
mock a device (with engines and contexts) that allows us to construct
and execute a request, along with waiting for the request to complete.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem_request.c            |  5 ++
 drivers/gpu/drm/i915/selftests/i915_gem_request.c  | 66 ++++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |  1 +
 3 files changed, 72 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_request.c

diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
index 72b7f7d9461d..bd2aeb290cad 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/i915_gem_request.c
@@ -1193,3 +1193,8 @@ void i915_gem_retire_requests(struct drm_i915_private *dev_priv)
 	for_each_engine(engine, dev_priv, id)
 		engine_retire_requests(engine);
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/mock_request.c"
+#include "selftests/i915_gem_request.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
new file mode 100644
index 000000000000..233c0bdb9e82
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
@@ -0,0 +1,66 @@
+/*
+ * 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_selftest.h"
+
+#include "mock_gem_device.h"
+
+static int igt_add_request(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_request *request;
+	int err = -ENOMEM;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	request = mock_request(i915->engine[RCS],
+			       i915->kernel_context,
+			       HZ / 10);
+	if (!request)
+		goto out_unlock;
+
+	i915_add_request(request);
+
+	err = 0;
+out_unlock:
+	mutex_unlock(&i915->drm.struct_mutex);
+	return err;
+}
+
+int i915_gem_request_mock_selftests(void)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_add_request),
+	};
+	struct drm_i915_private *i915;
+	int err;
+
+	i915 = mock_gem_device();
+	if (!i915)
+		return -ENOMEM;
+
+	err = i915_subtests(tests, i915);
+	drm_dev_unref(&i915->drm);
+
+	return err;
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 80458e2a2b04..bda982404ad3 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -11,3 +11,4 @@
 selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
 selftest(scatterlist, scatterlist_mock_selftests)
 selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
+selftest(requests, i915_gem_request_mock_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 12/37] drm/i915: Add a simple request selftest for waiting
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (10 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 11/37] drm/i915: Add selftests for i915_gem_request Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 11:25   ` Tvrtko Ursulin
  2017-01-11 21:09 ` [PATCH 13/37] drm/i915: Add a simple fence selftest to i915_gem_request Chris Wilson
                   ` (25 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

A trivial kselftest to submit a request and wait upon it.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_request.c | 44 +++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
index 233c0bdb9e82..ef72b32f9bc3 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
@@ -47,10 +47,54 @@ static int igt_add_request(void *arg)
 	return err;
 }
 
+static int igt_wait_request(void *arg)
+{
+	const long T = HZ / 4;
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_request *request;
+	int err = -EINVAL;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	request = mock_request(i915->engine[RCS], i915->kernel_context, T);
+	if (!request) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+
+	i915_add_request(request);
+
+	if (i915_gem_request_completed(request)) {
+		pr_err("request completed immediately!\n");
+		goto out_unlock;
+	}
+
+	if (i915_wait_request(request, I915_WAIT_LOCKED, T / 2) != -ETIME) {
+		pr_err("request wait succeeded (expected tiemout!)\n");
+		goto out_unlock;
+	}
+
+	if (i915_wait_request(request, I915_WAIT_LOCKED, T) == -ETIME) {
+		pr_err("request wait timed out!\n");
+		goto out_unlock;
+	}
+
+	if (!i915_gem_request_completed(request)) {
+		pr_err("request not complete after waiting!\n");
+		goto out_unlock;
+	}
+
+	err = 0;
+out_unlock:
+	mock_device_flush(i915);
+	mutex_unlock(&i915->drm.struct_mutex);
+	return err;
+}
+
 int i915_gem_request_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_add_request),
+		SUBTEST(igt_wait_request),
 	};
 	struct drm_i915_private *i915;
 	int err;
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 13/37] drm/i915: Add a simple fence selftest to i915_gem_request
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (11 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 12/37] drm/i915: Add a simple request selftest for waiting Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 14/37] drm/i915: Simple selftest to exercise live requests Chris Wilson
                   ` (24 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Do a quick selftest on in the interoperability of dma_fence_wait on a
i915_gem_request.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/selftests/i915_gem_request.c | 47 +++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
index ef72b32f9bc3..f348f5f81351 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
@@ -90,11 +90,58 @@ static int igt_wait_request(void *arg)
 	return err;
 }
 
+static int igt_fence_wait(void *arg)
+{
+	const long T = HZ / 4;
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_request *request;
+	int err = -EINVAL;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	request = mock_request(i915->engine[RCS], i915->kernel_context, T);
+	if (!request) {
+		err = -ENOMEM;
+		goto out_locked;
+	}
+
+	i915_add_request(request);
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	if (dma_fence_is_signaled(&request->fence)) {
+		pr_err("fence signaled immediately!\n");
+		goto out_device;
+	}
+
+	if (dma_fence_wait_timeout(&request->fence, false, T / 2) != -ETIME) {
+		pr_err("fence wait success after submit (expected timeout)!\n");
+		goto out_device;
+	}
+
+	if (dma_fence_wait_timeout(&request->fence, false, T) <= 0) {
+		pr_err("fence wait timed out (expected success)!\n");
+		goto out_device;
+	}
+
+	if (!dma_fence_is_signaled(&request->fence)) {
+		pr_err("fence unsignaled after waiting!\n");
+		goto out_device;
+	}
+
+	err = 0;
+out_device:
+	mutex_lock(&i915->drm.struct_mutex);
+out_locked:
+	mock_device_flush(i915);
+	mutex_unlock(&i915->drm.struct_mutex);
+	return err;
+}
+
 int i915_gem_request_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_add_request),
 		SUBTEST(igt_wait_request),
+		SUBTEST(igt_fence_wait),
 	};
 	struct drm_i915_private *i915;
 	int err;
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 14/37] drm/i915: Simple selftest to exercise live requests
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (12 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 13/37] drm/i915: Add a simple fence selftest to i915_gem_request Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 12:10   ` Tvrtko Ursulin
  2017-01-11 21:09 ` [PATCH 15/37] drm/i915: Add selftests for object allocation, phys Chris Wilson
                   ` (23 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Just create several batches of requests and expect it to not fall over!

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_request.c  | 78 ++++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |  1 +
 2 files changed, 79 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
index f348f5f81351..63e69d360764 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
@@ -22,6 +22,8 @@
  *
  */
 
+#include <linux/prime_numbers.h>
+
 #include "i915_selftest.h"
 
 #include "mock_gem_device.h"
@@ -155,3 +157,79 @@ int i915_gem_request_mock_selftests(void)
 
 	return err;
 }
+
+static int live_nop_request(void *arg)
+{
+	I915_SELFTEST_TIMEOUT(end_time);
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_request *request;
+	unsigned int reset_count = i915_reset_count(&i915->gpu_error);
+	unsigned long n, prime;
+	ktime_t times[2] = {};
+	int err;
+
+	mutex_lock(&i915->drm.struct_mutex);
+
+	err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
+	if (err) {
+		pr_err("Failed to idle GPU before %s\n", __func__);
+		goto out_unlock;
+	}
+
+	i915->gpu_error.missed_irq_rings = 0;
+
+	for_each_prime_number_from(prime, 1, 8192) {
+		times[1] = ktime_get_raw();
+
+		for (n = 0; n < prime; n++) {
+			request = i915_gem_request_alloc(i915->engine[RCS],
+							 i915->kernel_context);
+			if (IS_ERR(request)) {
+				err = PTR_ERR(request);
+				goto out_unlock;
+			}
+
+			i915_add_request(request);
+		}
+		i915_wait_request(request, I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT);
+		times[1] = ktime_sub(ktime_get_raw(), times[1]);
+		if (prime == 1)
+			times[0] = times[1];
+
+		if (time_after(jiffies, end_time)) {
+			pr_warn("%s timed out: last batch size %lu\n",
+				__func__, prime);
+			break;
+		}
+	}
+
+	if (reset_count != i915_reset_count(&i915->gpu_error)) {
+		pr_err("GPU was reset %d times!\n",
+		       i915_reset_count(&i915->gpu_error) - reset_count);
+		err = -EIO;
+		goto out_unlock;
+	}
+
+	if (i915->gpu_error.missed_irq_rings) {
+		pr_err("Missed interrupts on rings %lx\n",
+		       i915->gpu_error.missed_irq_rings);
+		err = -EIO;
+		goto out_unlock;
+	}
+
+	pr_info("Request latencies: 1 = %lluns, %lu = %lluns\n",
+	       ktime_to_ns(times[0]),
+	       prime, div64_u64(ktime_to_ns(times[1]), prime));
+
+out_unlock:
+	mutex_unlock(&i915->drm.struct_mutex);
+	return err;
+}
+
+int i915_gem_request_live_selftests(struct drm_i915_private *i915)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(live_nop_request),
+	};
+	return i915_subtests(tests, i915);
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
index f3e17cb10e05..09bf538826df 100644
--- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -9,3 +9,4 @@
  * Tests are executed in order by igt/drv_selftest
  */
 selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
+selftest(requests, i915_gem_request_live_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 15/37] drm/i915: Add selftests for object allocation, phys
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (13 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 14/37] drm/i915: Simple selftest to exercise live requests Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 16/37] drm/i915: Add a live seftest for GEM objects Chris Wilson
                   ` (22 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

The phys object is a rarely used device (only very old machines require
a chunk of physically contiguous pages for a few hardware interactions).
As such, it is not exercised by CI and to combat that we want to add a
test that exercises the phys object on all platforms.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_gem.c                    |   1 +
 drivers/gpu/drm/i915/selftests/i915_gem_object.c   | 114 +++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |   1 +
 3 files changed, 116 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_object.c

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 07b4ba3df94c..4a52c5872898 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4898,4 +4898,5 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
 #include "selftests/scatterlist.c"
 #include "selftests/mock_gem_device.c"
 #include "selftests/huge_gem_object.c"
+#include "selftests/i915_gem_object.c"
 #endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
new file mode 100644
index 000000000000..f243d4e73d7b
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
@@ -0,0 +1,114 @@
+/*
+ * 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_selftest.h"
+
+#include "mock_gem_device.h"
+
+static int igt_gem_object(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	int err = -ENOMEM;
+
+	obj = i915_gem_object_create(i915, PAGE_SIZE);
+	if (IS_ERR(obj)) {
+		err = PTR_ERR(obj);
+		pr_err("i915_gem_object_create failed, err=%d\n", err);
+		goto out;
+	}
+
+	err = 0;
+	i915_gem_object_put(obj);
+out:
+	return err;
+}
+
+static int igt_phys_object(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	int err = -ENOMEM;
+
+	obj = i915_gem_object_create(i915, PAGE_SIZE);
+	if (IS_ERR(obj)) {
+		err = PTR_ERR(obj);
+		pr_err("i915_gem_object_create failed, err=%d\n", err);
+		goto out;
+	}
+
+	err = -EINVAL;
+	mutex_lock(&i915->drm.struct_mutex);
+	err = i915_gem_object_attach_phys(obj, PAGE_SIZE);
+	mutex_unlock(&i915->drm.struct_mutex);
+	if (err) {
+		pr_err("i915_gem_object_attach_phys failed, err=%d\n", err);
+		goto err;
+	}
+
+	if (obj->ops != &i915_gem_phys_ops) {
+		pr_err("i915_gem_object_attach_phys did not create a phys object\n");
+		goto err;
+	}
+
+	if (!atomic_read(&obj->mm.pages_pin_count)) {
+		pr_err("i915_gem_object_attach_phys did not pin its phys pages\n");
+		goto err;
+	}
+
+	/* Make the object dirty so that put_pages must do copy back the data */
+	mutex_lock(&i915->drm.struct_mutex);
+	err = i915_gem_object_set_to_gtt_domain(obj, true);
+	mutex_unlock(&i915->drm.struct_mutex);
+	if (err) {
+		pr_err("i915_gem_object_set_to_gtt_domain failed with err=%d\n",
+		       err);
+		goto err;
+	}
+
+	err = 0;
+err:
+	i915_gem_object_put(obj);
+out:
+	return err;
+}
+
+int i915_gem_object_mock_selftests(void)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_gem_object),
+		SUBTEST(igt_phys_object),
+	};
+	struct drm_i915_private *i915;
+	int err;
+
+	i915 = mock_gem_device();
+	if (!i915)
+		return -ENOMEM;
+
+	err = i915_subtests(tests, i915);
+
+	drm_dev_unref(&i915->drm);
+	return err;
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index bda982404ad3..2ed94e3a71b7 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -12,3 +12,4 @@ selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
 selftest(scatterlist, scatterlist_mock_selftests)
 selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
 selftest(requests, i915_gem_request_mock_selftests)
+selftest(objects, i915_gem_object_mock_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 16/37] drm/i915: Add a live seftest for GEM objects
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (14 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 15/37] drm/i915: Add selftests for object allocation, phys Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 11:17   ` Matthew Auld
  2017-01-11 21:09 ` [PATCH 17/37] drm/i915: Test partial mappings Chris Wilson
                   ` (21 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Starting with a placeholder test just to reassure that we can create a
test object,

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_object.c   | 47 ++++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |  1 +
 2 files changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
index f243d4e73d7b..08e6b49b1e77 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
@@ -94,6 +94,44 @@ static int igt_phys_object(void *arg)
 	return err;
 }
 
+static int igt_gem_huge(void *arg)
+{
+	const unsigned int nreal = 509; /* just to be awkward */
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	unsigned int n;
+	int err;
+
+	obj = huge_gem_object(i915,
+			      nreal * PAGE_SIZE,
+			      i915->ggtt.base.total + PAGE_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	err = i915_gem_object_pin_pages(obj);
+	if (err) {
+		pr_err("Failed to allocate %u pages (%zu total), err=%d\n",
+		       nreal, obj->base.size / PAGE_SIZE, err);
+		goto err;
+	}
+
+	for (n = 0; n < obj->base.size / PAGE_SIZE; n++) {
+		if (i915_gem_object_get_page(obj, n) !=
+		    i915_gem_object_get_page(obj, n % nreal)) {
+			pr_err("Page lookup mismatch at index %u [%u]\n",
+			       n, n % nreal);
+			err = -EINVAL;
+			goto err_unpin;
+		}
+	}
+
+err_unpin:
+	i915_gem_object_unpin_pages(obj);
+err:
+	i915_gem_object_put(obj);
+	return err;
+}
+
 int i915_gem_object_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
@@ -112,3 +150,12 @@ int i915_gem_object_mock_selftests(void)
 	drm_dev_unref(&i915->drm);
 	return err;
 }
+
+int i915_gem_object_live_selftests(struct drm_i915_private *i915)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_gem_huge),
+	};
+
+	return i915_subtests(tests, i915);
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
index 09bf538826df..1822ac99d577 100644
--- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -10,3 +10,4 @@
  */
 selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
 selftest(requests, i915_gem_request_live_selftests)
+selftest(object, i915_gem_object_live_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 17/37] drm/i915: Test partial mappings
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (15 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 16/37] drm/i915: Add a live seftest for GEM objects Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-16 22:05   ` Matthew Auld
  2017-01-17 12:12   ` Matthew Auld
  2017-01-11 21:09 ` [PATCH 18/37] drm/i915: Test exhaustion of the mmap space Chris Wilson
                   ` (20 subsequent siblings)
  37 siblings, 2 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Create partial mappings to cover a large object, investigating tiling
(fenced regions) and VMA reuse.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_object.c | 252 +++++++++++++++++++++++
 1 file changed, 252 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
index 08e6b49b1e77..df3625f551aa 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
@@ -132,6 +132,257 @@ static int igt_gem_huge(void *arg)
 	return err;
 }
 
+struct tile {
+	unsigned int width;
+	unsigned int height;
+	unsigned int stride;
+	unsigned int size;
+	unsigned int tiling;
+	unsigned int swizzle;
+};
+
+static u64 swizzle_bit(unsigned bit, u64 offset)
+{
+	return (offset & BIT_ULL(bit)) >> (bit - 6);
+}
+
+static u64 tiled_offset(const struct tile *tile, u64 v)
+{
+	u64 x, y;
+
+	if (tile->tiling == I915_TILING_NONE)
+		return v;
+
+	switch (tile->swizzle) {
+	case I915_BIT_6_SWIZZLE_9:
+		v ^= swizzle_bit(9, v);
+		break;
+	case I915_BIT_6_SWIZZLE_9_10:
+		v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v);
+		break;
+	case I915_BIT_6_SWIZZLE_9_11:
+		v ^= swizzle_bit(9, v) ^ swizzle_bit(11, v);
+		break;
+	case I915_BIT_6_SWIZZLE_9_10_11:
+		v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v) ^ swizzle_bit(11, v);
+		break;
+	}
+
+	y = div64_u64_rem(v, tile->stride, &x);
+	v = div64_u64_rem(y, tile->height, &y) * tile->stride * tile->height;
+
+	if (tile->tiling == I915_TILING_X) {
+		v += y * tile->width;
+		v += div64_u64_rem(x, tile->width, &x) << tile->size;
+		v += x;
+	} else {
+		const unsigned int ytile_span = 16;
+		const unsigned int ytile_height = 32 * ytile_span;
+
+		v += y * ytile_span;
+		v += div64_u64_rem(x, ytile_span, &x) * ytile_height;
+		v += x;
+	}
+
+	return v;
+}
+
+static int check_partial_mapping(struct drm_i915_gem_object *obj,
+				 const struct tile *tile)
+{
+	const unsigned int nreal = obj->scratch / PAGE_SIZE;
+	const unsigned long npages = obj->base.size / PAGE_SIZE;
+	struct i915_vma *vma;
+	unsigned long page;
+	int err;
+
+	cond_resched();
+	if (signal_pending(current))
+		return -EINTR;
+
+	err = i915_gem_object_set_tiling(obj, tile->tiling, tile->stride);
+	if (err)
+		return err;
+
+	GEM_BUG_ON(i915_gem_object_get_tiling(obj) != tile->tiling);
+	GEM_BUG_ON(i915_gem_object_get_stride(obj) != tile->stride);
+
+	for_each_prime_number_from(page, 1, npages) {
+		struct i915_ggtt_view view =
+			compute_partial_view(obj, page, MIN_CHUNK_PAGES);
+		u32 __iomem *io;
+		struct page *p;
+		unsigned int n;
+		u64 offset;
+		u32 *cpu;
+
+		GEM_BUG_ON(intel_partial_get_page_count(&view.partial) > nreal);
+
+		err = i915_gem_object_set_to_gtt_domain(obj, true);
+		if (err)
+			return err;
+
+		vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
+		if (IS_ERR(vma)) {
+			pr_err("Failed to pin partial view: offset=%lu\n",
+			       page);
+			return PTR_ERR(vma);
+		}
+
+		n = page - intel_partial_get_page_offset(&view.partial);
+		GEM_BUG_ON(n >= intel_partial_get_page_count(&view.partial));
+
+		io = i915_vma_pin_iomap(vma);
+		i915_vma_unpin(vma);
+		if (IS_ERR(io)) {
+			pr_err("Failed to iomap partial view: offset=%lu\n",
+			       page);
+			return PTR_ERR(io);
+		}
+
+		err = i915_vma_get_fence(vma);
+		if (err) {
+			pr_err("Failed to get fence for partial view: offset=%lu\n",
+			       page);
+			i915_vma_unpin_iomap(vma);
+			return PTR_ERR(io);
+		}
+
+		iowrite32(page, io + n * PAGE_SIZE/sizeof(*io));
+		i915_vma_unpin_iomap(vma);
+
+		offset = tiled_offset(tile, page << PAGE_SHIFT);
+		if (offset >= obj->base.size)
+			continue;
+
+		i915_gem_object_flush_gtt_write_domain(obj);
+
+		p = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT);
+		cpu = kmap(p) + offset_in_page(offset);
+		drm_clflush_virt_range(cpu, sizeof(*cpu));
+		if (*cpu != (u32)page) {
+			pr_err("Partial view for %lu [%u] (offset=%llu, size=%u [%llu, row size %u], fence=%d, tiling=%d, stride=%d) misalignment, expected write to page (%llu + %u [0x%llx]) of 0x%x, found 0x%x\n",
+			       page, n,
+			       intel_partial_get_page_offset(&view.partial),
+			       intel_partial_get_page_count(&view.partial),
+			       vma->size >> PAGE_SHIFT,
+			       tile_row_pages(obj),
+			       vma->fence ? vma->fence->id : -1, tile->tiling, tile->stride,
+			       offset >> PAGE_SHIFT,
+			       (unsigned int)offset_in_page(offset),
+			       offset,
+			       (u32)page, *cpu);
+			err = -EINVAL;
+		}
+		*cpu = 0;
+		drm_clflush_virt_range(cpu, sizeof(*cpu));
+		kunmap(p);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int igt_partial_tiling(void *arg)
+{
+	const unsigned int nreal = 1 << 12; /* largest tile row x2 */
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct tile tile;
+	int err;
+
+	obj = huge_gem_object(i915,
+			      nreal << PAGE_SHIFT,
+			      (1 + next_prime_number(i915->ggtt.base.total >> PAGE_SHIFT)) << PAGE_SHIFT);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	err = i915_gem_object_pin_pages(obj);
+	if (err) {
+		pr_err("Failed to allocate %u pages (%zu total), err=%d\n",
+		       nreal, obj->base.size / PAGE_SIZE, err);
+		goto err;
+	}
+
+	tile.height = 1;
+	tile.width = 1;
+	tile.size = 0;
+	tile.stride = 0;
+	tile.swizzle = I915_BIT_6_SWIZZLE_NONE;
+	tile.tiling = I915_TILING_NONE;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	err = check_partial_mapping(obj, &tile);
+	if (err)
+		goto err_unlock;
+
+	for (tile.tiling = I915_TILING_X;
+	     tile.tiling <= I915_TILING_Y;
+	     tile.tiling++) {
+		unsigned int max_pitch;
+		unsigned int pitch;
+
+		switch (tile.tiling) {
+		case I915_TILING_X:
+			tile.swizzle = i915->mm.bit_6_swizzle_x;
+			break;
+		case I915_TILING_Y:
+			tile.swizzle = i915->mm.bit_6_swizzle_y;
+			break;
+		}
+
+		if (tile.swizzle == I915_BIT_6_SWIZZLE_UNKNOWN ||
+		    tile.swizzle == I915_BIT_6_SWIZZLE_9_10_17)
+			continue;
+
+		if (INTEL_GEN(i915) <= 2) {
+			tile.height = 16;
+			tile.width = 128;
+			tile.size = 11;
+		} else if (tile.tiling == I915_TILING_Y &&
+			   HAS_128_BYTE_Y_TILING(i915)) {
+			tile.height = 32;
+			tile.width = 128;
+			tile.size = 12;
+		} else {
+			tile.height = 8;
+			tile.width = 512;
+			tile.size = 12;
+		}
+
+		if (INTEL_GEN(i915) < 4)
+			max_pitch = 8192 / tile.width;
+		else if (INTEL_GEN(i915) < 7)
+			max_pitch = 128 * I965_FENCE_MAX_PITCH_VAL / tile.width;
+		else
+			max_pitch = 128 * GEN7_FENCE_MAX_PITCH_VAL / tile.width;
+
+		for (pitch = 1; pitch <= max_pitch; pitch <<= 1) {
+			tile.stride = tile.width * pitch;
+			err = check_partial_mapping(obj, &tile);
+			if (err)
+				goto err_unlock;
+		}
+
+		if (INTEL_GEN(i915) >= 4) {
+			for_each_prime_number(pitch, max_pitch) {
+				tile.stride = tile.width * pitch;
+				err = check_partial_mapping(obj, &tile);
+				if (err)
+					goto err_unlock;
+			}
+		}
+	}
+
+err_unlock:
+	mutex_unlock(&i915->drm.struct_mutex);
+	i915_gem_object_unpin_pages(obj);
+err:
+	i915_gem_object_put(obj);
+	return err;
+}
+
 int i915_gem_object_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
@@ -155,6 +406,7 @@ int i915_gem_object_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_gem_huge),
+		SUBTEST(igt_partial_tiling),
 	};
 
 	return i915_subtests(tests, i915);
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 18/37] drm/i915: Test exhaustion of the mmap space
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (16 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 17/37] drm/i915: Test partial mappings Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 17:29   ` Matthew Auld
  2017-01-11 21:09 ` [PATCH 19/37] drm/i915: Test coherency of and barriers between cache domains Chris Wilson
                   ` (19 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

An unlikely error condition that we can simulate by stealing the most of
the range before trying to insert new objects.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_object.c | 137 +++++++++++++++++++++++
 1 file changed, 137 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
index df3625f551aa..46512a67877d 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
@@ -25,6 +25,7 @@
 #include "i915_selftest.h"
 
 #include "mock_gem_device.h"
+#include "huge_gem_object.h"
 
 static int igt_gem_object(void *arg)
 {
@@ -383,6 +384,141 @@ static int igt_partial_tiling(void *arg)
 	return err;
 }
 
+static int make_obj_busy(struct drm_i915_gem_object *obj)
+{
+	struct drm_i915_private *i915 = to_i915(obj->base.dev);
+	struct drm_i915_gem_request *rq;
+	struct i915_vma *vma;
+	int err;
+
+	vma = i915_gem_obj_lookup_or_create_vma(obj, &i915->ggtt.base, NULL);
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	err = i915_vma_pin(vma, 0, 0, PIN_USER);
+	if (err)
+		return err;
+
+	rq = i915_gem_request_alloc(i915->engine[RCS], i915->kernel_context);
+	if (IS_ERR(rq)) {
+		i915_vma_unpin(vma);
+		return PTR_ERR(rq);
+	}
+
+	i915_vma_move_to_active(vma, rq, 0);
+	i915_add_request(rq);
+
+	i915_gem_object_set_active_reference(obj);
+	i915_vma_unpin(vma);
+	return 0;
+}
+
+static bool assert_mmap_offset(struct drm_i915_private *i915,
+			       unsigned long size,
+			       int expected)
+{
+	struct drm_i915_gem_object *obj;
+	int err;
+
+	obj = i915_gem_object_create_internal(i915, size);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	err = i915_gem_object_create_mmap_offset(obj);
+	i915_gem_object_put(obj);
+
+	return err == expected;
+}
+
+static int igt_mmap_offset_exhaustion(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_mm *mm = &i915->drm.vma_offset_manager->vm_addr_space_mm;
+	struct drm_i915_gem_object *obj;
+	struct drm_mm_node resv, *hole;
+	u64 hole_start, hole_end;
+	int loop, err;
+
+	/* Trim the VMA mmap space to only a page */
+	memset(&resv, 0, sizeof(resv));
+	drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
+		resv.start = hole_start;
+		resv.size = hole_end - hole_start - 1; /* PAGE_SIZE units */
+		err = drm_mm_reserve_node(mm, &resv);
+		if (err) {
+			pr_err("Failed to trim VMA manager, err=%d\n", err);
+			return err;
+		}
+		break;
+	}
+
+	/* Just fits! */
+	if (!assert_mmap_offset(i915, PAGE_SIZE, 0)) {
+		pr_err("Unable to insert object into single page hole\n");
+		err = -EINVAL;
+		goto err;
+	}
+
+	/* Too large */
+	if (!assert_mmap_offset(i915, 2*PAGE_SIZE, -ENOSPC)) {
+		pr_err("Unexpectedly succeded in inserting too large object into single page hole\n");
+		err = -EINVAL;
+		goto err;
+	}
+
+	/* Fill the hole, should then fail */
+	obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(obj)) {
+		err = PTR_ERR(obj);
+		goto err;
+	}
+
+	err = i915_gem_object_create_mmap_offset(obj);
+	if (err) {
+		pr_err("Unable to insert object into reclaimed hole\n");
+		goto err_obj;
+	}
+
+	if (!assert_mmap_offset(i915, PAGE_SIZE, -ENOSPC)) {
+		pr_err("Unexpectedly succeded in inserting object into no holes!\n");
+		err = -EINVAL;
+		goto err_obj;
+	}
+
+	i915_gem_object_put(obj);
+
+	/* Now fill with busy dead objects that we expect to reap */
+	for (loop = 0; loop < 3; loop++) {
+		obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+		if (IS_ERR(obj)) {
+			err = PTR_ERR(obj);
+			goto err;
+		}
+
+		mutex_lock(&i915->drm.struct_mutex);
+		err = make_obj_busy(obj);
+		mutex_unlock(&i915->drm.struct_mutex);
+		if (err) {
+			pr_err("[loop %d] Failed to busy the object\n", loop);
+			goto err_obj;
+		}
+
+		err = i915_gem_object_create_mmap_offset(obj);
+		if (err) {
+			pr_err("[loop %d] i915_gem_object_create_mmap_offset failed with err=%d\n",
+			       loop, err);
+			goto err;
+		}
+	}
+
+err:
+	drm_mm_remove_node(&resv);
+	return err;
+err_obj:
+	i915_gem_object_put(obj);
+	goto err;
+}
+
 int i915_gem_object_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
@@ -407,6 +543,7 @@ int i915_gem_object_live_selftests(struct drm_i915_private *i915)
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_gem_huge),
 		SUBTEST(igt_partial_tiling),
+		SUBTEST(igt_mmap_offset_exhaustion),
 	};
 
 	return i915_subtests(tests, i915);
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 19/37] drm/i915: Test coherency of and barriers between cache domains
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (17 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 18/37] drm/i915: Test exhaustion of the mmap space Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-13 11:44   ` Matthew Auld
  2017-01-11 21:09 ` [PATCH 20/37] drm/i915: Move uncore selfchecks to live selftest infrastructure Chris Wilson
                   ` (18 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Write into an object using WB, WC, GTT, and GPU paths and make sure that
our internal API is sufficient to ensure coherent reads and writes.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem.c                    |   1 +
 .../gpu/drm/i915/selftests/i915_gem_coherency.c    | 355 +++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |   1 +
 3 files changed, 357 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_coherency.c

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4a52c5872898..242d894b356e 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4899,4 +4899,5 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
 #include "selftests/mock_gem_device.c"
 #include "selftests/huge_gem_object.c"
 #include "selftests/i915_gem_object.c"
+#include "selftests/i915_gem_coherency.c"
 #endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
new file mode 100644
index 000000000000..3e57b7a3c73f
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright © 2017 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 <linux/prime_numbers.h>
+
+#include "i915_selftest.h"
+#include "i915_random.h"
+
+static int cpu_set(struct drm_i915_gem_object *obj,
+		   unsigned long offset,
+		   u32 v)
+{
+	unsigned int needs_clflush;
+	struct page *page;
+	typeof(v) *map;
+	int err;
+
+	err = i915_gem_obj_prepare_shmem_write(obj, &needs_clflush);
+	if (err)
+		return err;
+
+	page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT);
+	map = kmap_atomic(page);
+	if (needs_clflush & CLFLUSH_BEFORE)
+		clflush(map+offset_in_page(offset) / sizeof(*map));
+	map[offset_in_page(offset) / sizeof(*map)] = v;
+	if (needs_clflush & CLFLUSH_AFTER)
+		clflush(map+offset_in_page(offset) / sizeof(*map));
+	kunmap_atomic(map);
+
+	i915_gem_obj_finish_shmem_access(obj);
+	return 0;
+}
+
+static int cpu_get(struct drm_i915_gem_object *obj,
+		   unsigned long offset,
+		   u32 *v)
+{
+	unsigned int needs_clflush;
+	struct page *page;
+	typeof(v) map;
+	int err;
+
+	err = i915_gem_obj_prepare_shmem_read(obj, &needs_clflush);
+	if (err)
+		return err;
+
+	page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT);
+	map = kmap_atomic(page);
+	if (needs_clflush & CLFLUSH_BEFORE)
+		clflush(map+offset_in_page(offset) / sizeof(*map));
+	*v = map[offset_in_page(offset) / sizeof(*map)];
+	kunmap_atomic(map);
+
+	i915_gem_obj_finish_shmem_access(obj);
+	return 0;
+}
+
+static int gtt_set(struct drm_i915_gem_object *obj,
+		   unsigned long offset,
+		   u32 v)
+{
+	struct i915_vma *vma;
+	typeof(v) *map;
+	int err;
+
+	err = i915_gem_object_set_to_gtt_domain(obj, true);
+	if (err)
+		return err;
+
+	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	map = i915_vma_pin_iomap(vma);
+	i915_vma_unpin(vma);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	map[offset / sizeof(*map)] = v;
+	i915_vma_unpin_iomap(vma);
+
+	return 0;
+}
+
+static int gtt_get(struct drm_i915_gem_object *obj,
+		   unsigned long offset,
+		   u32 *v)
+{
+	struct i915_vma *vma;
+	typeof(v) map;
+	int err;
+
+	err = i915_gem_object_set_to_gtt_domain(obj, false);
+	if (err)
+		return err;
+
+	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	map = i915_vma_pin_iomap(vma);
+	i915_vma_unpin(vma);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	*v = map[offset / sizeof(*map)];
+	i915_vma_unpin_iomap(vma);
+
+	return 0;
+}
+
+static int wc_set(struct drm_i915_gem_object *obj,
+		  unsigned long offset,
+		  u32 v)
+{
+	typeof(v) *map;
+	int err;
+
+	/* XXX GTT write followed by WC write go missing */
+	i915_gem_object_flush_gtt_write_domain(obj);
+
+	err = i915_gem_object_set_to_gtt_domain(obj, true);
+	if (err)
+		return err;
+
+	map = i915_gem_object_pin_map(obj, I915_MAP_WC);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	map[offset / sizeof(*map)] = v;
+	i915_gem_object_unpin_map(obj);
+
+	return 0;
+}
+
+static int wc_get(struct drm_i915_gem_object *obj,
+		  unsigned long offset,
+		  u32 *v)
+{
+	typeof(v) map;
+	int err;
+
+	/* XXX WC write followed by GTT write go missing */
+	i915_gem_object_flush_gtt_write_domain(obj);
+
+	err = i915_gem_object_set_to_gtt_domain(obj, false);
+	if (err)
+		return err;
+
+	map = i915_gem_object_pin_map(obj, I915_MAP_WC);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	*v = map[offset / sizeof(*map)];
+	i915_gem_object_unpin_map(obj);
+
+	return 0;
+}
+
+static int gpu_set(struct drm_i915_gem_object *obj,
+		   unsigned long offset,
+		   u32 v)
+{
+	struct drm_i915_private *i915 = to_i915(obj->base.dev);
+	struct drm_i915_gem_request *rq;
+	struct i915_vma *vma;
+	int err;
+
+	err = i915_gem_object_set_to_gtt_domain(obj, true);
+	if (err)
+		return err;
+
+	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	rq = i915_gem_request_alloc(i915->engine[RCS], i915->kernel_context);
+	if (IS_ERR(rq)) {
+		i915_vma_unpin(vma);
+		return PTR_ERR(rq);
+	}
+
+	err = intel_ring_begin(rq, 4);
+	if (err) {
+		__i915_add_request(rq, false);
+		i915_vma_unpin(vma);
+		return err;
+	}
+
+	if (INTEL_GEN(i915) >= 8) {
+		intel_ring_emit(rq->ring, MI_STORE_DWORD_IMM_GEN4 | 1 << 22);
+		intel_ring_emit(rq->ring, lower_32_bits(i915_ggtt_offset(vma) + offset));
+		intel_ring_emit(rq->ring, upper_32_bits(i915_ggtt_offset(vma) + offset));
+		intel_ring_emit(rq->ring, v);
+	} else if (INTEL_GEN(i915) >= 4) {
+		intel_ring_emit(rq->ring, MI_STORE_DWORD_IMM_GEN4 | 1 << 22);
+		intel_ring_emit(rq->ring, 0);
+		intel_ring_emit(rq->ring, i915_ggtt_offset(vma) + offset);
+		intel_ring_emit(rq->ring, v);
+	} else {
+		intel_ring_emit(rq->ring, MI_STORE_DWORD_IMM | 1 << 22);
+		intel_ring_emit(rq->ring, i915_ggtt_offset(vma) + offset);
+		intel_ring_emit(rq->ring, v);
+		intel_ring_emit(rq->ring, MI_NOOP);
+	}
+	intel_ring_advance(rq->ring);
+
+	i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+	i915_vma_unpin(vma);
+
+	ww_mutex_lock(&obj->resv->lock, NULL);
+	reservation_object_add_excl_fence(obj->resv, &rq->fence);
+	ww_mutex_unlock(&obj->resv->lock);
+
+	__i915_add_request(rq, true);
+
+	return 0;
+}
+
+static const struct igt_coherency_mode {
+	const char *name;
+	int (*set)(struct drm_i915_gem_object *, unsigned long offset, u32 v);
+	int (*get)(struct drm_i915_gem_object *, unsigned long offset, u32 *v);
+} igt_coherency_mode[] = {
+	{ "cpu", cpu_set, cpu_get },
+	{ "gtt", gtt_set, gtt_get },
+	{ "wc", wc_set, wc_get },
+	{ "gpu", gpu_set, NULL },
+	{ },
+};
+
+static int igt_gem_coherency(void *arg)
+{
+	const unsigned int ncachelines = PAGE_SIZE/64;
+	I915_RND_STATE(prng);
+	struct drm_i915_private *i915 = arg;
+	const struct igt_coherency_mode *read, *write, *over;
+	struct drm_i915_gem_object *obj;
+	unsigned long count, n;
+	u32 *offsets, *values;
+	int err;
+
+	offsets = kmalloc_array(ncachelines, 2*sizeof(u32), GFP_KERNEL);
+	if (!offsets)
+		return -ENOMEM;
+	for (count = 0; count < ncachelines; count++)
+		offsets[count] = count * 64 + 4 * (count % 16);
+
+	values = offsets + ncachelines;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	for (over = igt_coherency_mode; over->name; over++) {
+		if (!over->set)
+			continue;
+
+		for (write = igt_coherency_mode; write->name; write++) {
+			if (!write->set)
+				continue;
+
+			for (read = igt_coherency_mode; read->name; read++) {
+				if (!read->get)
+					continue;
+
+				for_each_prime_number_from(count, 1, ncachelines) {
+					obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+					if (IS_ERR(obj))
+						goto unlock;
+
+					i915_random_reorder(offsets, ncachelines, &prng);
+					for (n = 0; n < count; n++)
+						values[n] = prandom_u32_state(&prng);
+
+					for (n = 0; n < count; n++) {
+						err = over->set(obj, offsets[n], ~values[n]);
+						if (err) {
+							pr_err("Failed to set stale value[%ld/%ld] in object using %s, err=%d\n",
+							       n, count, over->name, err);
+							goto unlock;
+						}
+					}
+
+					for (n = 0; n < count; n++) {
+						err = write->set(obj, offsets[n], values[n]);
+						if (err) {
+							pr_err("Failed to set value[%ld/%ld] in object using %s, err=%d\n",
+							       n, count, write->name, err);
+							goto unlock;
+						}
+					}
+
+					for (n = 0; n < count; n++) {
+						u32 found;
+
+						err = read->get(obj, offsets[n], &found);
+						if (err) {
+							pr_err("Failed to get value[%ld/%ld] in object using %s, err=%d\n",
+							       n, count, read->name, err);
+							goto unlock;
+						}
+
+						if (found != values[n]) {
+							pr_err("Value[%ld/%ld] mismatch, (overwrite with %s) wrote [%s] %x read [%s] %x (inverse %x), at offset %x\n",
+							       n, count, over->name,
+							       write->name, values[n],
+							       read->name, found,
+							       ~values[n], offsets[n]);
+							err = -EINVAL;
+							goto unlock;
+						}
+					}
+
+					__i915_gem_object_release_unless_active(obj);
+					obj = NULL;
+				}
+			}
+		}
+	}
+unlock:
+	if (obj)
+		__i915_gem_object_release_unless_active(obj);
+	mutex_unlock(&i915->drm.struct_mutex);
+	kfree(offsets);
+	return err;
+}
+
+int i915_gem_coherency_live_selftests(struct drm_i915_private *i915)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_gem_coherency),
+	};
+
+	return i915_subtests(tests, i915);
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
index 1822ac99d577..fde9ef22cfe8 100644
--- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -11,3 +11,4 @@
 selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
 selftest(requests, i915_gem_request_live_selftests)
 selftest(object, i915_gem_object_live_selftests)
+selftest(coherency, i915_gem_coherency_live_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 20/37] drm/i915: Move uncore selfchecks to live selftest infrastructure
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (18 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 19/37] drm/i915: Test coherency of and barriers between cache domains Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 21/37] drm/i915: Test all fw tables during mock selftests Chris Wilson
                   ` (17 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Now that the kselftest infrastructure exists, put it to use and add to
it the existing consistency checks on the fw register lookup tables.

v2: s/tabke/table/

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/intel_uncore.c                | 52 +-----------
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |  1 +
 drivers/gpu/drm/i915/selftests/intel_uncore.c      | 99 ++++++++++++++++++++++
 3 files changed, 104 insertions(+), 48 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/selftests/intel_uncore.c

diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index abe08885a5ba..b6ce8de2cc86 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -635,33 +635,6 @@ find_fw_domain(struct drm_i915_private *dev_priv, u32 offset)
 	return entry->domains;
 }
 
-static void
-intel_fw_table_check(struct drm_i915_private *dev_priv)
-{
-	const struct intel_forcewake_range *ranges;
-	unsigned int num_ranges;
-	s32 prev;
-	unsigned int i;
-
-	if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG))
-		return;
-
-	ranges = dev_priv->uncore.fw_domains_table;
-	if (!ranges)
-		return;
-
-	num_ranges = dev_priv->uncore.fw_domains_table_entries;
-
-	for (i = 0, prev = -1; i < num_ranges; i++, ranges++) {
-		WARN_ON_ONCE(IS_GEN9(dev_priv) &&
-			     (prev + 1) != (s32)ranges->start);
-		WARN_ON_ONCE(prev >= (s32)ranges->start);
-		prev = ranges->start;
-		WARN_ON_ONCE(prev >= (s32)ranges->end);
-		prev = ranges->end;
-	}
-}
-
 #define GEN_FW_RANGE(s, e, d) \
 	{ .start = (s), .end = (e), .domains = (d) }
 
@@ -700,23 +673,6 @@ static const i915_reg_t gen8_shadowed_regs[] = {
 	/* TODO: Other registers are not yet used */
 };
 
-static void intel_shadow_table_check(void)
-{
-	const i915_reg_t *reg = gen8_shadowed_regs;
-	s32 prev;
-	u32 offset;
-	unsigned int i;
-
-	if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG))
-		return;
-
-	for (i = 0, prev = -1; i < ARRAY_SIZE(gen8_shadowed_regs); i++, reg++) {
-		offset = i915_mmio_reg_offset(*reg);
-		WARN_ON_ONCE(prev >= (s32)offset);
-		prev = offset;
-	}
-}
-
 static int mmio_reg_cmp(u32 key, const i915_reg_t *reg)
 {
 	u32 offset = i915_mmio_reg_offset(*reg);
@@ -1445,10 +1401,6 @@ void intel_uncore_init(struct drm_i915_private *dev_priv)
 		break;
 	}
 
-	intel_fw_table_check(dev_priv);
-	if (INTEL_GEN(dev_priv) >= 8)
-		intel_shadow_table_check();
-
 	if (intel_vgpu_active(dev_priv)) {
 		ASSIGN_WRITE_MMIO_VFUNCS(vgpu);
 		ASSIGN_READ_MMIO_VFUNCS(vgpu);
@@ -1971,3 +1923,7 @@ intel_uncore_forcewake_for_reg(struct drm_i915_private *dev_priv,
 
 	return fw_domains;
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/intel_uncore.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
index fde9ef22cfe8..c060bf24928e 100644
--- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -9,6 +9,7 @@
  * Tests are executed in order by igt/drv_selftest
  */
 selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
+selftest(uncore, intel_uncore_live_selftests)
 selftest(requests, i915_gem_request_live_selftests)
 selftest(object, i915_gem_object_live_selftests)
 selftest(coherency, i915_gem_coherency_live_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c
new file mode 100644
index 000000000000..0ac467940a4f
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c
@@ -0,0 +1,99 @@
+/*
+ * 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_selftest.h"
+
+static int intel_fw_table_check(struct drm_i915_private *i915)
+{
+	const struct intel_forcewake_range *ranges;
+	unsigned int num_ranges, i;
+	s32 prev;
+
+	ranges = i915->uncore.fw_domains_table;
+	if (!ranges)
+		return 0;
+
+	num_ranges = i915->uncore.fw_domains_table_entries;
+	for (i = 0, prev = -1; i < num_ranges; i++, ranges++) {
+		/* Check that the table is watertight */
+		if (IS_GEN9(i915) && (prev + 1) != (s32)ranges->start) {
+			pr_err("%s: entry[%d]:(%x, %x) is not watertight to previous (%x)\n",
+			       __func__, i, ranges->start, ranges->end, prev);
+			return -EINVAL;
+		}
+
+		/* Check that the table never goes backwards */
+		if (prev >= (s32)ranges->start) {
+			pr_err("%s: entry[%d]:(%x, %x) is less than the previous (%x)\n",
+			       __func__, i, ranges->start, ranges->end, prev);
+			return -EINVAL;
+		}
+
+		/* Check that the entry is valid */
+		if (ranges->start >= ranges->end) {
+			pr_err("%s: entry[%d]:(%x, %x) has negative length\n",
+			       __func__, i, ranges->start, ranges->end);
+			return -EINVAL;
+		}
+
+		prev = ranges->end;
+	}
+
+	return 0;
+}
+
+static int intel_shadow_table_check(void)
+{
+	const i915_reg_t *reg = gen8_shadowed_regs;
+	unsigned int i;
+	s32 prev;
+
+	for (i = 0, prev = -1; i < ARRAY_SIZE(gen8_shadowed_regs); i++, reg++) {
+		u32 offset = i915_mmio_reg_offset(*reg);
+		if (prev >= (s32)offset) {
+			pr_err("%s: entry[%d]:(%x) is before previous (%x)\n",
+			       __func__, i, offset, prev);
+			return -EINVAL;
+		}
+
+		prev = offset;
+	}
+
+	return 0;
+}
+
+int intel_uncore_live_selftests(struct drm_i915_private *i915)
+{
+	int err;
+
+	err = intel_fw_table_check(i915);
+	if (err)
+		return err;
+
+	err = intel_shadow_table_check();
+	if (err)
+		return err;
+
+	return 0;
+}
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 21/37] drm/i915: Test all fw tables during mock selftests
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (19 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 20/37] drm/i915: Move uncore selfchecks to live selftest infrastructure Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 22/37] drm/i915: Sanity check all registers for matching fw domains Chris Wilson
                   ` (16 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

In addition to just testing the fw table we load, during the initial
mock testing we can test that all tables are valid (so the testing is
not limited to just the platforms that load that particular table).

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |  1 +
 drivers/gpu/drm/i915/selftests/intel_uncore.c      | 49 ++++++++++++++++------
 2 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 2ed94e3a71b7..c61e08de7913 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -10,6 +10,7 @@
  */
 selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
 selftest(scatterlist, scatterlist_mock_selftests)
+selftest(uncore, intel_uncore_mock_selftests)
 selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
 selftest(requests, i915_gem_request_mock_selftests)
 selftest(objects, i915_gem_object_mock_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c
index 0ac467940a4f..c18fddb12d00 100644
--- a/drivers/gpu/drm/i915/selftests/intel_uncore.c
+++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c
@@ -24,20 +24,16 @@
 
 #include "i915_selftest.h"
 
-static int intel_fw_table_check(struct drm_i915_private *i915)
+static int intel_fw_table_check(const struct intel_forcewake_range *ranges,
+				unsigned int num_ranges,
+				bool is_watertight)
 {
-	const struct intel_forcewake_range *ranges;
-	unsigned int num_ranges, i;
+	unsigned int i;
 	s32 prev;
 
-	ranges = i915->uncore.fw_domains_table;
-	if (!ranges)
-		return 0;
-
-	num_ranges = i915->uncore.fw_domains_table_entries;
 	for (i = 0, prev = -1; i < num_ranges; i++, ranges++) {
 		/* Check that the table is watertight */
-		if (IS_GEN9(i915) && (prev + 1) != (s32)ranges->start) {
+		if (is_watertight && (prev + 1) != (s32)ranges->start) {
 			pr_err("%s: entry[%d]:(%x, %x) is not watertight to previous (%x)\n",
 			       __func__, i, ranges->start, ranges->end, prev);
 			return -EINVAL;
@@ -83,15 +79,42 @@ static int intel_shadow_table_check(void)
 	return 0;
 }
 
-int intel_uncore_live_selftests(struct drm_i915_private *i915)
+int intel_uncore_mock_selftests(void)
 {
-	int err;
+	struct {
+		const struct intel_forcewake_range *ranges;
+		unsigned int num_ranges;
+		bool is_watertight;
+	} fw[] = {
+		{ __vlv_fw_ranges, ARRAY_SIZE(__vlv_fw_ranges), false },
+		{ __chv_fw_ranges, ARRAY_SIZE(__chv_fw_ranges), false },
+		{ __gen9_fw_ranges, ARRAY_SIZE(__gen9_fw_ranges), true },
+	};
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(fw); i++) {
+		err = intel_fw_table_check(fw[i].ranges,
+					   fw[i].num_ranges,
+					   fw[i].is_watertight);
+		if (err)
+			return err;
+	}
 
-	err = intel_fw_table_check(i915);
+	err = intel_shadow_table_check();
 	if (err)
 		return err;
 
-	err = intel_shadow_table_check();
+	return 0;
+}
+
+int intel_uncore_live_selftests(struct drm_i915_private *i915)
+{
+	int err;
+
+	/* Confirm the table we load is still valid */
+	err = intel_fw_table_check(i915->uncore.fw_domains_table,
+				   i915->uncore.fw_domains_table_entries,
+				   INTEL_GEN(i915) >= 9);
 	if (err)
 		return err;
 
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 22/37] drm/i915: Sanity check all registers for matching fw domains
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (20 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 21/37] drm/i915: Test all fw tables during mock selftests Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 23/37] drm/i915: Add some mock tests for dmabuf interop Chris Wilson
                   ` (15 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Add a late selftest that walks over all forcewake registers (those below
0x40000) and uses the mmio debug register to check to see if any are
unclaimed. This is possible if we fail to wake the appropriate
powerwells for the register.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/selftests/intel_uncore.c | 48 +++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c
index c18fddb12d00..fba76fef4d55 100644
--- a/drivers/gpu/drm/i915/selftests/intel_uncore.c
+++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c
@@ -107,6 +107,50 @@ int intel_uncore_mock_selftests(void)
 	return 0;
 }
 
+static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_priv)
+{
+#define FW_RANGE 0x40000
+	unsigned long *valid;
+	u32 offset;
+	int err;
+
+	valid = kzalloc(BITS_TO_LONGS(FW_RANGE) * sizeof(*valid),
+			GFP_TEMPORARY);
+	if (!valid)
+		return -ENOMEM;
+
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+	check_for_unclaimed_mmio(dev_priv);
+	for (offset = 0; offset < FW_RANGE; offset += 4) {
+		i915_reg_t reg = { offset };
+
+		(void)I915_READ_FW(reg);
+		if (!check_for_unclaimed_mmio(dev_priv))
+			set_bit(offset, valid);
+	}
+
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
+	err = 0;
+	for_each_set_bit(offset, valid, FW_RANGE) {
+		i915_reg_t reg = { offset };
+
+		intel_uncore_forcewake_reset(dev_priv, false);
+		check_for_unclaimed_mmio(dev_priv);
+
+		(void)I915_READ(reg);
+		if (check_for_unclaimed_mmio(dev_priv)) {
+			pr_err("Unclaimed mmio read to register 0x%04x\n",
+			       offset);
+			err = -EINVAL;
+		}
+	}
+
+	kfree(valid);
+	return err;
+}
+
 int intel_uncore_live_selftests(struct drm_i915_private *i915)
 {
 	int err;
@@ -118,5 +162,9 @@ int intel_uncore_live_selftests(struct drm_i915_private *i915)
 	if (err)
 		return err;
 
+	err = intel_uncore_check_forcewake_domains(i915);
+	if (err)
+		return err;
+
 	return 0;
 }
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 23/37] drm/i915: Add some mock tests for dmabuf interop
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (21 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 22/37] drm/i915: Sanity check all registers for matching fw domains Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 24/37] drm/i915: Add initial selftests for i915_gem_gtt Chris Wilson
                   ` (14 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Check that we can create both dmabuf and objects from dmabuf.

v2: Cleanups, correct include, fix unpin on dead path and prevent
explosion on dmabuf init failure

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_dmabuf.c             |   5 +
 drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c   | 298 +++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |   1 +
 drivers/gpu/drm/i915/selftests/mock_dmabuf.c       | 176 ++++++++++++
 drivers/gpu/drm/i915/selftests/mock_dmabuf.h       |  41 +++
 5 files changed, 521 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_dmabuf.c
 create mode 100644 drivers/gpu/drm/i915/selftests/mock_dmabuf.h

diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index d037adcda6f2..3e276eee0450 100644
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -307,3 +307,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 
 	return ERR_PTR(ret);
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/mock_dmabuf.c"
+#include "selftests/i915_gem_dmabuf.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
new file mode 100644
index 000000000000..75187a06bcb6
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
@@ -0,0 +1,298 @@
+/*
+ * 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_selftest.h"
+
+#include "mock_gem_device.h"
+#include "mock_dmabuf.h"
+
+static int igt_dmabuf_export(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct dma_buf *dmabuf;
+	int err;
+
+	obj = i915_gem_object_create(i915, PAGE_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
+	if (IS_ERR(dmabuf)) {
+		pr_err("i915_gem_prime_export failed with err=%d\n",
+		       (int)PTR_ERR(dmabuf));
+		err = PTR_ERR(dmabuf);
+		goto err;
+	}
+
+	err = 0;
+	dma_buf_put(dmabuf);
+err:
+	i915_gem_object_put(obj);
+	return err;
+}
+
+static int igt_dmabuf_import_self(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct drm_gem_object *import;
+	struct dma_buf *dmabuf;
+	int err;
+
+	obj = i915_gem_object_create(i915, PAGE_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
+	if (IS_ERR(dmabuf)) {
+		pr_err("i915_gem_prime_export failed with err=%d\n",
+		       (int)PTR_ERR(dmabuf));
+		err = PTR_ERR(dmabuf);
+		goto err;
+	}
+
+	import = i915_gem_prime_import(&i915->drm, dmabuf);
+	if (IS_ERR(import)) {
+		pr_err("i915_gem_prime_import failed with err=%d\n",
+		       (int)PTR_ERR(import));
+		err = PTR_ERR(import);
+		goto err_dmabuf;
+	}
+
+	if (import != &obj->base) {
+		pr_err("i915_gem_prime_import created a new object!\n");
+		err = -EINVAL;
+		goto err_import;
+	}
+
+	err = 0;
+err_import:
+	i915_gem_object_put(to_intel_bo(import));
+err_dmabuf:
+	dma_buf_put(dmabuf);
+err:
+	i915_gem_object_put(obj);
+	return err;
+}
+
+static int igt_dmabuf_import(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct dma_buf *dmabuf;
+	void *obj_map, *dma_map;
+	u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff };
+	int err, i;
+
+	dmabuf = mock_dmabuf(1);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
+	if (IS_ERR(obj)) {
+		pr_err("i915_gem_prime_import failed with err=%d\n",
+		       (int)PTR_ERR(obj));
+		err = PTR_ERR(obj);
+		goto err_dmabuf;
+	}
+
+	if (obj->base.dev != &i915->drm) {
+		pr_err("i915_gem_prime_import created a non-i915 object!\n");
+		err = -EINVAL;
+		goto err_obj;
+	}
+
+	if (obj->base.size != PAGE_SIZE) {
+		pr_err("i915_gem_prime_import is wrong size found %lld, expected %ld\n",
+		       (long long)obj->base.size, PAGE_SIZE);
+		err = -EINVAL;
+		goto err_obj;
+	}
+
+	dma_map = dma_buf_vmap(dmabuf);
+	if (!dma_map) {
+		pr_err("dma_buf_vmap failed\n");
+		err = -ENOMEM;
+		goto err_obj;
+	}
+
+	if (0) { /* Can not yet map dmabuf */
+		obj_map = i915_gem_object_pin_map(obj, I915_MAP_WB);
+		if (IS_ERR(obj_map)) {
+			err = PTR_ERR(obj_map);
+			pr_err("i915_gem_object_pin_map failed with err=%d\n", err);
+			goto err_dma_map;
+		}
+
+		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
+			memset(dma_map, pattern[i], PAGE_SIZE);
+			if (memchr_inv(obj_map, pattern[i], PAGE_SIZE)) {
+				err = -EINVAL;
+				pr_err("imported vmap not all set to %x!\n", pattern[i]);
+				i915_gem_object_unpin_map(obj);
+				goto err_dma_map;
+			}
+		}
+
+		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
+			memset(obj_map, pattern[i], PAGE_SIZE);
+			if (memchr_inv(dma_map, pattern[i], PAGE_SIZE)) {
+				err = -EINVAL;
+				pr_err("exported vmap not all set to %x!\n", pattern[i]);
+				i915_gem_object_unpin_map(obj);
+				goto err_dma_map;
+			}
+		}
+
+		i915_gem_object_unpin_map(obj);
+	}
+
+	err = 0;
+err_dma_map:
+	dma_buf_vunmap(dmabuf, dma_map);
+err_obj:
+	i915_gem_object_put(obj);
+err_dmabuf:
+	dma_buf_put(dmabuf);
+	return err;
+}
+
+static int igt_dmabuf_import_ownership(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct dma_buf *dmabuf;
+	void *ptr;
+	int err;
+
+	dmabuf = mock_dmabuf(1);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	ptr = dma_buf_vmap(dmabuf);
+	if (!ptr) {
+		pr_err("dma_buf_vmap failed\n");
+		err = -ENOMEM;
+		goto err_dmabuf;
+	}
+
+	memset(ptr, 0xc5, PAGE_SIZE);
+	dma_buf_vunmap(dmabuf, ptr);
+
+	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
+	if (IS_ERR(obj)) {
+		pr_err("i915_gem_prime_import failed with err=%d\n",
+		       (int)PTR_ERR(obj));
+		err = PTR_ERR(obj);
+		goto err_dmabuf;
+	}
+
+	dma_buf_put(dmabuf);
+
+	err = i915_gem_object_pin_pages(obj);
+	if (err) {
+		pr_err("i915_gem_object_pin_pages failed with err=%d\n", err);
+		goto err_obj;
+	}
+
+	err = 0;
+	i915_gem_object_unpin_pages(obj);
+err_obj:
+	i915_gem_object_put(obj);
+	return err;
+
+err_dmabuf:
+	dma_buf_put(dmabuf);
+	return err;
+}
+
+static int igt_dmabuf_export_vmap(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct dma_buf *dmabuf;
+	void *ptr;
+	int err;
+
+	obj = i915_gem_object_create(i915, PAGE_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
+	if (IS_ERR(dmabuf)) {
+		pr_err("i915_gem_prime_export failed with err=%d\n",
+		       (int)PTR_ERR(dmabuf));
+		err = PTR_ERR(dmabuf);
+		goto err_obj;
+	}
+	i915_gem_object_put(obj);
+
+	ptr = dma_buf_vmap(dmabuf);
+	if (IS_ERR(ptr)) {
+		err = PTR_ERR(ptr);
+		pr_err("dma_buf_vmap failed with err=%d\n", err);
+		goto err;
+	}
+
+	if(memchr_inv(ptr, 0, dmabuf->size)) {
+		pr_err("Exported object not initialiased to zero!\n");
+		err = -EINVAL;
+		goto err;
+	}
+
+	memset(ptr, 0xc5, dmabuf->size);
+
+	err = 0;
+	dma_buf_vunmap(dmabuf, ptr);
+err:
+	dma_buf_put(dmabuf);
+	return err;
+
+err_obj:
+	i915_gem_object_put(obj);
+	return err;
+}
+
+int i915_gem_dmabuf_mock_selftests(void)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_dmabuf_export),
+		SUBTEST(igt_dmabuf_import_self),
+		SUBTEST(igt_dmabuf_import),
+		SUBTEST(igt_dmabuf_import_ownership),
+		SUBTEST(igt_dmabuf_export_vmap),
+	};
+	struct drm_i915_private *i915;
+	int err;
+
+	i915 = mock_gem_device();
+	if (!i915)
+		return -ENOMEM;
+
+	err = i915_subtests(tests, i915);
+
+	drm_dev_unref(&i915->drm);
+	return err;
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index c61e08de7913..955a4d6ccdaf 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -14,3 +14,4 @@ selftest(uncore, intel_uncore_mock_selftests)
 selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
 selftest(requests, i915_gem_request_mock_selftests)
 selftest(objects, i915_gem_object_mock_selftests)
+selftest(dmabuf, i915_gem_dmabuf_mock_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c
new file mode 100644
index 000000000000..99da8f4ef497
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c
@@ -0,0 +1,176 @@
+/*
+ * 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 "mock_dmabuf.h"
+
+static struct sg_table *mock_map_dma_buf(struct dma_buf_attachment *attachment,
+					 enum dma_data_direction dir)
+{
+	struct mock_dmabuf *mock = to_mock(attachment->dmabuf);
+	struct sg_table *st;
+	struct scatterlist *sg;
+	int i, err;
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	err = sg_alloc_table(st, mock->npages, GFP_KERNEL);
+	if (err)
+		goto err_free;
+
+	sg = st->sgl;
+	for (i = 0; i < mock->npages; i++) {
+		sg_set_page(sg, mock->pages[i], PAGE_SIZE, 0);
+		sg = sg_next(sg);
+	}
+
+	if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
+		err = -ENOMEM;
+		goto err_st;
+	}
+
+	return st;
+
+err_st:
+	sg_free_table(st);
+err_free:
+	kfree(st);
+	return ERR_PTR(err);
+}
+
+static void mock_unmap_dma_buf(struct dma_buf_attachment *attachment,
+			       struct sg_table *st,
+			       enum dma_data_direction dir)
+{
+	dma_unmap_sg(attachment->dev, st->sgl, st->nents, dir);
+	sg_free_table(st);
+	kfree(st);
+}
+
+static void mock_dmabuf_release(struct dma_buf *dma_buf)
+{
+	struct mock_dmabuf *mock = to_mock(dma_buf);
+	int i;
+
+	for (i = 0; i < mock->npages; i++)
+		put_page(mock->pages[i]);
+
+	kfree(mock);
+}
+
+static void *mock_dmabuf_vmap(struct dma_buf *dma_buf)
+{
+	struct mock_dmabuf *mock = to_mock(dma_buf);
+
+	return vm_map_ram(mock->pages, mock->npages, 0, PAGE_KERNEL);
+}
+
+static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
+{
+	struct mock_dmabuf *mock = to_mock(dma_buf);
+
+	vm_unmap_ram(vaddr, mock->npages);
+}
+
+static void *mock_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
+{
+	struct mock_dmabuf *mock = to_mock(dma_buf);
+
+	return kmap_atomic(mock->pages[page_num]);
+}
+
+static void mock_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+	kunmap_atomic(addr);
+}
+
+static void *mock_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
+{
+	struct mock_dmabuf *mock = to_mock(dma_buf);
+
+	return kmap(mock->pages[page_num]);
+}
+
+static void mock_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+	struct mock_dmabuf *mock = to_mock(dma_buf);
+
+	return kunmap(mock->pages[page_num]);
+}
+
+static int mock_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static const struct dma_buf_ops mock_dmabuf_ops =  {
+	.map_dma_buf = mock_map_dma_buf,
+	.unmap_dma_buf = mock_unmap_dma_buf,
+	.release = mock_dmabuf_release,
+	.kmap = mock_dmabuf_kmap,
+	.kmap_atomic = mock_dmabuf_kmap_atomic,
+	.kunmap = mock_dmabuf_kunmap,
+	.kunmap_atomic = mock_dmabuf_kunmap_atomic,
+	.mmap = mock_dmabuf_mmap,
+	.vmap = mock_dmabuf_vmap,
+	.vunmap = mock_dmabuf_vunmap,
+};
+
+static struct dma_buf *mock_dmabuf(int npages)
+{
+	struct mock_dmabuf *mock;
+	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+	struct dma_buf *dmabuf;
+	int i;
+
+	mock = kmalloc(sizeof(*mock) + npages * sizeof(struct page *),
+		       GFP_KERNEL);
+	if (!mock)
+		return ERR_PTR(-ENOMEM);
+
+	mock->npages = npages;
+	for (i = 0; i < npages; i++) {
+		mock->pages[i] = alloc_page(GFP_KERNEL);
+		if (!mock->pages[i])
+			goto err;
+	}
+
+	exp_info.ops = &mock_dmabuf_ops;
+	exp_info.size = npages * PAGE_SIZE;
+	exp_info.flags = O_CLOEXEC;
+	exp_info.priv = mock;
+
+	dmabuf = dma_buf_export(&exp_info);
+	if (IS_ERR(dmabuf))
+		goto err;
+
+	return dmabuf;
+
+err:
+	while (i--)
+		put_page(mock->pages[i]);
+	kfree(mock);
+	return ERR_PTR(-ENOMEM);
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_dmabuf.h b/drivers/gpu/drm/i915/selftests/mock_dmabuf.h
new file mode 100644
index 000000000000..ec80613159b9
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/mock_dmabuf.h
@@ -0,0 +1,41 @@
+
+/*
+ * 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 __MOCK_DMABUF_H__
+#define __MOCK_DMABUF_H__
+
+#include <linux/dma-buf.h>
+
+struct mock_dmabuf {
+	int npages;
+	struct page *pages[];
+};
+
+static struct mock_dmabuf *to_mock(struct dma_buf *buf)
+{
+	return buf->priv;
+}
+
+#endif /* !__MOCK_DMABUF_H__ */
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 24/37] drm/i915: Add initial selftests for i915_gem_gtt
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (22 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 23/37] drm/i915: Add some mock tests for dmabuf interop Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 25/37] drm/i915: Move i915_ppgtt_close() into i915_gem_gtt.c Chris Wilson
                   ` (13 subsequent siblings)
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Simple starting point for adding selftests for i915_gem_gtt, first
try creating a ppGTT and filling it.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_gtt.c                |  1 +
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c      | 95 ++++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |  1 +
 3 files changed, 97 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c

diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index f0057b812337..5f30d81e842e 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -3767,4 +3767,5 @@ int i915_gem_gtt_insert(struct i915_address_space *vm,
 
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftests/mock_gtt.c"
+#include "selftests/i915_gem_gtt.c"
 #endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
new file mode 100644
index 000000000000..97b55e9726d8
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -0,0 +1,95 @@
+/*
+ * 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_selftest.h"
+
+static int igt_ppgtt_alloc(void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	struct i915_hw_ppgtt *ppgtt;
+	u64 size, last;
+	int err;
+
+	if (!USES_PPGTT(dev_priv))
+		return 0;
+
+	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+	if (!ppgtt)
+		return -ENOMEM;
+
+	err = __hw_ppgtt_init(ppgtt, dev_priv);
+	if (err)
+		goto err_ppgtt;
+
+	if (!ppgtt->base.allocate_va_range)
+		goto err_ppgtt_cleanup;
+
+	/* Check we can allocate the entire range */
+	for (size = 4096;
+	     size <= ppgtt->base.total;
+	     size <<= 2) {
+		err = ppgtt->base.allocate_va_range(&ppgtt->base, 0, size);
+		if (err) {
+			if (err == -ENOMEM) {
+				pr_info("[1] Ran out of memory for va_range [0 + %llx] [bit %d]\n",
+					size, ilog2(size));
+				err = 0; /* virtual space too large! */
+			}
+			goto err_ppgtt_cleanup;
+		}
+
+		ppgtt->base.clear_range(&ppgtt->base, 0, size);
+	}
+
+	/* Check we can incrementally allocate the entire range */
+	for (last = 0, size = 4096;
+	     size <= ppgtt->base.total;
+	     last = size, size <<= 2) {
+		err = ppgtt->base.allocate_va_range(&ppgtt->base,
+						    last, size - last);
+		if (err) {
+			if (err == -ENOMEM) {
+				pr_info("[2] Ran out of memory for va_range [%llx + %llx] [bit %d]\n",
+					last, size - last, ilog2(size));
+				err = 0; /* virtual space too large! */
+			}
+			goto err_ppgtt_cleanup;
+		}
+	}
+
+err_ppgtt_cleanup:
+	ppgtt->base.cleanup(&ppgtt->base);
+err_ppgtt:
+	kfree(ppgtt);
+	return err;
+}
+
+int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_ppgtt_alloc),
+	};
+
+	return i915_subtests(tests, i915);
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
index c060bf24928e..94517ad6dbd1 100644
--- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -13,3 +13,4 @@ selftest(uncore, intel_uncore_live_selftests)
 selftest(requests, i915_gem_request_live_selftests)
 selftest(object, i915_gem_object_live_selftests)
 selftest(coherency, i915_gem_coherency_live_selftests)
+selftest(gtt, i915_gem_gtt_live_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 25/37] drm/i915: Move i915_ppgtt_close() into i915_gem_gtt.c
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (23 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 24/37] drm/i915: Add initial selftests for i915_gem_gtt Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 12:43   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 26/37] drm/i915: Assert that we have allocated the drm_mm_node upon pinning Chris Wilson
                   ` (12 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Move it alongside its ppgtt counterparts, in order to make it available
for the ppgtt selftests.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem_context.c | 21 ---------------------
 drivers/gpu/drm/i915/i915_gem_gtt.c     | 21 +++++++++++++++++++++
 drivers/gpu/drm/i915/i915_gem_gtt.h     |  1 +
 3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 91551b01a62c..6fcb35ecd6a7 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -205,27 +205,6 @@ alloc_context_obj(struct drm_i915_private *dev_priv, u64 size)
 	return obj;
 }
 
-static void i915_ppgtt_close(struct i915_address_space *vm)
-{
-	struct list_head *phases[] = {
-		&vm->active_list,
-		&vm->inactive_list,
-		&vm->unbound_list,
-		NULL,
-	}, **phase;
-
-	GEM_BUG_ON(vm->closed);
-	vm->closed = true;
-
-	for (phase = phases; *phase; phase++) {
-		struct i915_vma *vma, *vn;
-
-		list_for_each_entry_safe(vma, vn, *phase, vm_link)
-			if (!i915_vma_is_closed(vma))
-				i915_vma_close(vma);
-	}
-}
-
 static void context_close(struct i915_gem_context *ctx)
 {
 	i915_gem_context_set_closed(ctx);
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 5f30d81e842e..5bbaa24d8a91 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2260,6 +2260,27 @@ i915_ppgtt_create(struct drm_i915_private *dev_priv,
 	return ppgtt;
 }
 
+void i915_ppgtt_close(struct i915_address_space *vm)
+{
+	struct list_head *phases[] = {
+		&vm->active_list,
+		&vm->inactive_list,
+		&vm->unbound_list,
+		NULL,
+	}, **phase;
+
+	GEM_BUG_ON(vm->closed);
+	vm->closed = true;
+
+	for (phase = phases; *phase; phase++) {
+		struct i915_vma *vma, *vn;
+
+		list_for_each_entry_safe(vma, vn, *phase, vm_link)
+			if (!i915_vma_is_closed(vma))
+				i915_vma_close(vma);
+	}
+}
+
 void i915_ppgtt_release(struct kref *kref)
 {
 	struct i915_hw_ppgtt *ppgtt =
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 7ce4e2aaa159..28a3eca17b39 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -535,6 +535,7 @@ void i915_ppgtt_release(struct kref *kref);
 struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_i915_private *dev_priv,
 					struct drm_i915_file_private *fpriv,
 					const char *name);
+void i915_ppgtt_close(struct i915_address_space *vm);
 static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt)
 {
 	if (ppgtt)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 26/37] drm/i915: Assert that we have allocated the drm_mm_node upon pinning
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (24 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 25/37] drm/i915: Move i915_ppgtt_close() into i915_gem_gtt.c Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 12:45   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 27/37] drm/i915: Exercising filling the top/bottom portions of the ppgtt Chris Wilson
                   ` (11 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

We currently check after the slow path that the vma is bound correctly,
but we don't currently check after the fast path. This is important in
case we accidentally take the fast path and leave the vma misplaced.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_vma.c | 1 +
 drivers/gpu/drm/i915/i915_vma.h | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 2307e1610743..6424352a69b2 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -474,6 +474,7 @@ int __i915_vma_do_pin(struct i915_vma *vma,
 	if ((bound ^ vma->flags) & I915_VMA_GLOBAL_BIND)
 		__i915_vma_set_map_and_fenceable(vma);
 
+	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
 	GEM_BUG_ON(i915_vma_misplaced(vma, size, alignment, flags));
 	return 0;
 
diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
index 9d6913b10f30..47b5ceb386c4 100644
--- a/drivers/gpu/drm/i915/i915_vma.h
+++ b/drivers/gpu/drm/i915/i915_vma.h
@@ -237,8 +237,11 @@ i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
 	/* Pin early to prevent the shrinker/eviction logic from destroying
 	 * our vma as we insert and bind.
 	 */
-	if (likely(((++vma->flags ^ flags) & I915_VMA_BIND_MASK) == 0))
+	if (likely(((++vma->flags ^ flags) & I915_VMA_BIND_MASK) == 0)) {
+		GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+		GEM_BUG_ON(i915_vma_misplaced(vma, size, alignment, flags));
 		return 0;
+	}
 
 	return __i915_vma_do_pin(vma, size, alignment, flags);
 }
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 27/37] drm/i915: Exercising filling the top/bottom portions of the ppgtt
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (25 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 26/37] drm/i915: Assert that we have allocated the drm_mm_node upon pinning Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 13:32   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 28/37] drm/i915: Exercising filling the top/bottom portions of the global GTT Chris Wilson
                   ` (10 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Allocate objects with varying number of pages (which should hopefully
consist of a mixture of contiguous page chunks and so coalesced sg
lists) and check that the sg walkers in insert_pages cope.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h               |   2 +-
 drivers/gpu/drm/i915/i915_gem_internal.c      |   4 +-
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 159 ++++++++++++++++++++++++++
 3 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index b84c1d1fa12c..65298edc0e9c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3506,7 +3506,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
 /* i915_gem_internal.c */
 struct drm_i915_gem_object *
 i915_gem_object_create_internal(struct drm_i915_private *dev_priv,
-				unsigned int size);
+				unsigned long size);
 
 /* i915_gem_shrinker.c */
 unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/i915_gem_internal.c b/drivers/gpu/drm/i915/i915_gem_internal.c
index 2222863e505f..92f66e959a9f 100644
--- a/drivers/gpu/drm/i915/i915_gem_internal.c
+++ b/drivers/gpu/drm/i915/i915_gem_internal.c
@@ -151,10 +151,12 @@ static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = {
  */
 struct drm_i915_gem_object *
 i915_gem_object_create_internal(struct drm_i915_private *i915,
-				unsigned int size)
+				unsigned long size)
 {
 	struct drm_i915_gem_object *obj;
 
+	GEM_BUG_ON(!size);
+
 	obj = i915_gem_object_alloc(i915);
 	if (!obj)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index 97b55e9726d8..5d0e6f60bea7 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -22,7 +22,10 @@
  *
  */
 
+#include <linux/prime_numbers.h>
+
 #include "i915_selftest.h"
+#include "huge_gem_object.h"
 
 static int igt_ppgtt_alloc(void *arg)
 {
@@ -85,10 +88,166 @@ static int igt_ppgtt_alloc(void *arg)
 	return err;
 }
 
+static struct i915_vma *vma_lookup(struct drm_i915_gem_object *obj,
+				   struct i915_address_space *vm)
+{
+	return i915_gem_obj_lookup_or_create_vma(obj, vm, NULL);
+}
+
+static int igt_ppgtt_fill(void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	unsigned long npages, max_pages = 1 << 20, prime;
+	struct drm_i915_gem_object *obj, *on;
+	struct i915_hw_ppgtt *ppgtt;
+	struct i915_vma *vma;
+	LIST_HEAD(objects);
+	int err = 0;
+
+	if (!USES_FULL_PPGTT(dev_priv))
+		return 0;
+
+	mutex_lock(&dev_priv->drm.struct_mutex);
+	ppgtt = i915_ppgtt_create(dev_priv, NULL, "mock");
+	if (IS_ERR(ppgtt)) {
+		err = PTR_ERR(ppgtt);
+		goto err_unlock;
+	}
+	GEM_BUG_ON(ppgtt->base.total & ~PAGE_MASK);
+
+	max_pages = min_t(u64, max_pages, ppgtt->base.total/2 >> PAGE_SHIFT);
+
+	for_each_prime_number_from(prime, 2, 13) {
+		for (npages = 1; npages <= max_pages; npages *= prime) {
+			u64 flags;
+
+			GEM_BUG_ON(!npages);
+			obj = huge_gem_object(dev_priv,
+					      PAGE_SIZE,
+					      npages << PAGE_SHIFT);
+			if (IS_ERR(obj))
+				break;
+
+			list_add(&obj->batch_pool_link, &objects);
+
+			/* Fill the GTT top down - hope we don't overstep the end */
+			flags = ppgtt->base.total | PIN_OFFSET_FIXED | PIN_USER;
+			list_for_each_entry(obj, &objects, batch_pool_link) {
+				vma = vma_lookup(obj, &ppgtt->base);
+				if (IS_ERR(vma))
+					continue;
+
+				flags -= obj->base.size;
+				err = i915_vma_pin(vma, 0, 0, flags);
+				if (err) {
+					pr_err("Fill top-down failed with err=%d on size=%lu pages (prime=%lu)\n", err, npages, prime);
+					goto err;
+				}
+
+				i915_vma_unpin(vma);
+			}
+
+			flags = ppgtt->base.total | PIN_OFFSET_FIXED | PIN_USER;
+			list_for_each_entry(obj, &objects, batch_pool_link) {
+				vma = vma_lookup(obj, &ppgtt->base);
+				if (IS_ERR(vma))
+					continue;
+
+				flags -= obj->base.size;
+				if (!drm_mm_node_allocated(&vma->node) ||
+				    i915_vma_misplaced(vma, 0, 0, flags)) {
+					pr_err("Fill top-down moved vma.node=%llx + %llx, expected offset %llx\n",
+					       vma->node.start, vma->node.size,
+					       flags & PAGE_MASK);
+					err = -EINVAL;
+					goto err;
+				}
+
+				err = i915_vma_unbind(vma);
+				if (err) {
+					pr_err("Fill top-down unbind of vma.node=%llx + %llx failed with err=%d\n",
+					       vma->node.start, vma->node.size,
+					       err);
+					goto err;
+				}
+			}
+
+			/* And again from the bottom */
+			flags = PIN_OFFSET_FIXED | PIN_USER;
+			list_for_each_entry(obj, &objects, batch_pool_link) {
+				vma = vma_lookup(obj, &ppgtt->base);
+				if (IS_ERR(vma))
+					continue;
+
+				err = i915_vma_pin(vma, 0, 0, flags);
+				if (err) {
+					pr_err("Fill bottom-up failed with err=%d on size=%lu pages (prime=%lu)\n", err, npages, prime);
+					goto err;
+				}
+
+				i915_vma_unpin(vma);
+				flags += obj->base.size;
+			}
+
+			flags = PIN_OFFSET_FIXED | PIN_USER;
+			list_for_each_entry(obj, &objects, batch_pool_link) {
+				vma = vma_lookup(obj, &ppgtt->base);
+				if (IS_ERR(vma))
+					continue;
+
+				if (!drm_mm_node_allocated(&vma->node) ||
+				    i915_vma_misplaced(vma, 0, 0, flags)) {
+					pr_err("Fill top-down moved vma.node=%llx + %llx, expected offset %llx\n",
+					       vma->node.start, vma->node.size,
+					       flags & PAGE_MASK);
+					err = -EINVAL;
+					goto err;
+				}
+
+				err = i915_vma_unbind(vma);
+				if (err) {
+					pr_err("Fill top-down unbind of vma.node=%llx + %llx failed with err=%d\n",
+					       vma->node.start, vma->node.size,
+					       err);
+					goto err;
+				}
+
+				flags += obj->base.size;
+			}
+		}
+
+		list_for_each_entry_safe(obj, on, &objects, batch_pool_link) {
+			list_del(&obj->batch_pool_link);
+			vma = vma_lookup(obj, &ppgtt->base);
+			if (!IS_ERR(vma))
+				i915_vma_close(vma);
+
+			i915_gem_object_put(obj);
+		}
+	}
+err:
+
+	list_for_each_entry_safe(obj, on, &objects, batch_pool_link) {
+		list_del(&obj->batch_pool_link);
+		vma = vma_lookup(obj, &ppgtt->base);
+		if (!IS_ERR(vma))
+			i915_vma_close(vma);
+
+		i915_gem_object_put(obj);
+	}
+
+	i915_ppgtt_close(&ppgtt->base);
+	i915_ppgtt_put(ppgtt);
+err_unlock:
+	mutex_unlock(&dev_priv->drm.struct_mutex);
+	return err;
+}
+
 int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_ppgtt_alloc),
+		SUBTEST(igt_ppgtt_fill),
 	};
 
 	return i915_subtests(tests, i915);
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 28/37] drm/i915: Exercising filling the top/bottom portions of the global GTT
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (26 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 27/37] drm/i915: Exercising filling the top/bottom portions of the ppgtt Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 14:05   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 29/37] drm/i915: Fill different pages of the GTT Chris Wilson
                   ` (9 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Same test as previously for the per-process GTT instead applied to the
global GTT.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 118 +++++++++++++++++++-------
 1 file changed, 88 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index 5d0e6f60bea7..8ed88f438eef 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -25,6 +25,7 @@
 #include <linux/prime_numbers.h>
 
 #include "i915_selftest.h"
+#include "fake_drm.h"
 #include "huge_gem_object.h"
 
 static int igt_ppgtt_alloc(void *arg)
@@ -94,35 +95,25 @@ static struct i915_vma *vma_lookup(struct drm_i915_gem_object *obj,
 	return i915_gem_obj_lookup_or_create_vma(obj, vm, NULL);
 }
 
-static int igt_ppgtt_fill(void *arg)
+static int fill_hole(struct drm_i915_private *i915,
+		     struct i915_address_space *vm,
+		     u64 hole_start, u64 hole_end)
 {
-	struct drm_i915_private *dev_priv = arg;
 	unsigned long npages, max_pages = 1 << 20, prime;
+	u64 hole_size = hole_end - hole_start;
 	struct drm_i915_gem_object *obj, *on;
-	struct i915_hw_ppgtt *ppgtt;
 	struct i915_vma *vma;
 	LIST_HEAD(objects);
-	int err = 0;
-
-	if (!USES_FULL_PPGTT(dev_priv))
-		return 0;
-
-	mutex_lock(&dev_priv->drm.struct_mutex);
-	ppgtt = i915_ppgtt_create(dev_priv, NULL, "mock");
-	if (IS_ERR(ppgtt)) {
-		err = PTR_ERR(ppgtt);
-		goto err_unlock;
-	}
-	GEM_BUG_ON(ppgtt->base.total & ~PAGE_MASK);
+	int err;
 
-	max_pages = min_t(u64, max_pages, ppgtt->base.total/2 >> PAGE_SHIFT);
+	max_pages = min_t(u64, max_pages, hole_size/2 >> PAGE_SHIFT);
 
 	for_each_prime_number_from(prime, 2, 13) {
 		for (npages = 1; npages <= max_pages; npages *= prime) {
 			u64 flags;
 
 			GEM_BUG_ON(!npages);
-			obj = huge_gem_object(dev_priv,
+			obj = huge_gem_object(i915,
 					      PAGE_SIZE,
 					      npages << PAGE_SHIFT);
 			if (IS_ERR(obj))
@@ -131,9 +122,9 @@ static int igt_ppgtt_fill(void *arg)
 			list_add(&obj->batch_pool_link, &objects);
 
 			/* Fill the GTT top down - hope we don't overstep the end */
-			flags = ppgtt->base.total | PIN_OFFSET_FIXED | PIN_USER;
+			flags = hole_end | PIN_OFFSET_FIXED | PIN_USER;
 			list_for_each_entry(obj, &objects, batch_pool_link) {
-				vma = vma_lookup(obj, &ppgtt->base);
+				vma = vma_lookup(obj, vm);
 				if (IS_ERR(vma))
 					continue;
 
@@ -147,9 +138,9 @@ static int igt_ppgtt_fill(void *arg)
 				i915_vma_unpin(vma);
 			}
 
-			flags = ppgtt->base.total | PIN_OFFSET_FIXED | PIN_USER;
+			flags = hole_end | PIN_OFFSET_FIXED | PIN_USER;
 			list_for_each_entry(obj, &objects, batch_pool_link) {
-				vma = vma_lookup(obj, &ppgtt->base);
+				vma = vma_lookup(obj, vm);
 				if (IS_ERR(vma))
 					continue;
 
@@ -173,9 +164,9 @@ static int igt_ppgtt_fill(void *arg)
 			}
 
 			/* And again from the bottom */
-			flags = PIN_OFFSET_FIXED | PIN_USER;
+			flags = hole_start | PIN_OFFSET_FIXED | PIN_USER;
 			list_for_each_entry(obj, &objects, batch_pool_link) {
-				vma = vma_lookup(obj, &ppgtt->base);
+				vma = vma_lookup(obj, vm);
 				if (IS_ERR(vma))
 					continue;
 
@@ -189,9 +180,9 @@ static int igt_ppgtt_fill(void *arg)
 				flags += obj->base.size;
 			}
 
-			flags = PIN_OFFSET_FIXED | PIN_USER;
+			flags = hole_start | PIN_OFFSET_FIXED | PIN_USER;
 			list_for_each_entry(obj, &objects, batch_pool_link) {
-				vma = vma_lookup(obj, &ppgtt->base);
+				vma = vma_lookup(obj, vm);
 				if (IS_ERR(vma))
 					continue;
 
@@ -218,28 +209,94 @@ static int igt_ppgtt_fill(void *arg)
 
 		list_for_each_entry_safe(obj, on, &objects, batch_pool_link) {
 			list_del(&obj->batch_pool_link);
-			vma = vma_lookup(obj, &ppgtt->base);
-			if (!IS_ERR(vma))
+			vma = vma_lookup(obj, vm);
+			if (!IS_ERR(vma) && !i915_vma_is_ggtt(vma))
 				i915_vma_close(vma);
 
 			i915_gem_object_put(obj);
 		}
 	}
-err:
 
+	return 0;
+
+err:
 	list_for_each_entry_safe(obj, on, &objects, batch_pool_link) {
 		list_del(&obj->batch_pool_link);
-		vma = vma_lookup(obj, &ppgtt->base);
-		if (!IS_ERR(vma))
+		vma = vma_lookup(obj, vm);
+		if (!IS_ERR(vma) && !i915_vma_is_ggtt(vma))
 			i915_vma_close(vma);
 
 		i915_gem_object_put(obj);
 	}
+	return err;
+}
+
+static int igt_ppgtt_fill(void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	struct drm_file *file;
+	struct i915_hw_ppgtt *ppgtt;
+	int err;
+
+	if (!USES_FULL_PPGTT(dev_priv))
+		return 0;
+
+	file = fake_file(dev_priv);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	mutex_lock(&dev_priv->drm.struct_mutex);
+	ppgtt = i915_ppgtt_create(dev_priv, file->driver_priv, "mock");
+	if (IS_ERR(ppgtt)) {
+		err = PTR_ERR(ppgtt);
+		goto err_unlock;
+	}
+	GEM_BUG_ON(ppgtt->base.total & ~PAGE_MASK);
+
+	err = fill_hole(dev_priv, &ppgtt->base, 0, ppgtt->base.total);
 
 	i915_ppgtt_close(&ppgtt->base);
 	i915_ppgtt_put(ppgtt);
 err_unlock:
 	mutex_unlock(&dev_priv->drm.struct_mutex);
+
+	fake_file_free(dev_priv, file);
+	return err;
+}
+
+static int igt_ggtt_fill(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 hole_start = U64_MAX, hole_end = 0, hole_size = 0;
+	u64 this_start, this_end;
+	struct drm_mm_node *node;
+	int err;
+
+	GEM_BUG_ON(ggtt->base.total & ~PAGE_MASK);
+
+	mutex_lock(&i915->drm.struct_mutex);
+	drm_mm_for_each_hole(node, &ggtt->base.mm, this_start, this_end) {
+		u64 this_size;
+
+		if (ggtt->base.mm.color_adjust)
+			ggtt->base. mm.color_adjust(node, 0,
+						    &this_start, &this_end);
+
+		this_size = this_end - this_start;
+		if (this_size > hole_size) {
+			hole_size = this_size;
+			hole_start = this_start;
+			hole_end = this_end;
+		}
+	}
+	pr_info("Found GGTT hole [%llx, %llx], size %llx\n",
+		hole_start, hole_end, hole_size);
+	GEM_BUG_ON(hole_start >= hole_end);
+
+	err = fill_hole(i915, &ggtt->base, hole_start, hole_end);
+	mutex_unlock(&i915->drm.struct_mutex);
+
 	return err;
 }
 
@@ -248,6 +305,7 @@ int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_ppgtt_alloc),
 		SUBTEST(igt_ppgtt_fill),
+		SUBTEST(igt_ggtt_fill),
 	};
 
 	return i915_subtests(tests, i915);
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 29/37] drm/i915: Fill different pages of the GTT
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (27 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 28/37] drm/i915: Exercising filling the top/bottom portions of the global GTT Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-13  7:47   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 30/37] drm/i915: Exercise filling and removing random ranges from the live GTT Chris Wilson
                   ` (8 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Exercise filling different pages of the GTT

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 130 ++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index 8ed88f438eef..68f7bfb7502e 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -231,6 +231,65 @@ static int fill_hole(struct drm_i915_private *i915,
 	return err;
 }
 
+static int walk_hole(struct drm_i915_private *i915,
+		     struct i915_address_space *vm,
+		     u64 hole_start, u64 hole_end)
+{
+	I915_SELFTEST_TIMEOUT(end_time);
+	struct drm_i915_gem_object *obj;
+	struct i915_vma *vma;
+	u64 addr;
+	int err;
+
+	obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	vma = vma_lookup(obj, vm);
+	if (IS_ERR(vma)) {
+		err = PTR_ERR(vma);
+		goto err;
+	}
+
+	for (addr = hole_start; addr < hole_end; addr += PAGE_SIZE) {
+		cond_resched();
+
+		err = i915_vma_pin(vma, 0, 0,
+				   addr | PIN_OFFSET_FIXED | PIN_USER);
+		if (err) {
+			pr_err("Walk bind failed at %llx with err=%d\n",
+			       addr, err);
+			break;
+		}
+		i915_vma_unpin(vma);
+
+		if (!drm_mm_node_allocated(&vma->node) ||
+		    i915_vma_misplaced(vma, 0, 0, addr | PIN_OFFSET_FIXED)) {
+			pr_err("Walk incorrect at %llx\n", addr);
+			err = -EINVAL;
+			break;
+		}
+
+		err = i915_vma_unbind(vma);
+		if (err) {
+			pr_err("Walk unbind failed at %llx with err=%d\n",
+			       addr, err);
+			break;
+		}
+
+		if (time_after(jiffies, end_time)) {
+			pr_warn("Walk timed out at %llx\n", addr);
+			break;
+		}
+	}
+
+	if (!i915_vma_is_ggtt(vma))
+		i915_vma_close(vma);
+err:
+	i915_gem_object_put(obj);
+	return err;
+}
+
 static int igt_ppgtt_fill(void *arg)
 {
 	struct drm_i915_private *dev_priv = arg;
@@ -264,6 +323,39 @@ static int igt_ppgtt_fill(void *arg)
 	return err;
 }
 
+static int igt_ppgtt_walk(void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	struct drm_file *file;
+	struct i915_hw_ppgtt *ppgtt;
+	int err;
+
+	if (!USES_FULL_PPGTT(dev_priv))
+		return 0;
+
+	file = fake_file(dev_priv);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	mutex_lock(&dev_priv->drm.struct_mutex);
+	ppgtt = i915_ppgtt_create(dev_priv, file->driver_priv, "mock");
+	if (IS_ERR(ppgtt)) {
+		err = PTR_ERR(ppgtt);
+		goto err_unlock;
+	}
+	GEM_BUG_ON(ppgtt->base.total & ~PAGE_MASK);
+
+	err = walk_hole(dev_priv, &ppgtt->base, 0, ppgtt->base.total);
+
+	i915_ppgtt_close(&ppgtt->base);
+	i915_ppgtt_put(ppgtt);
+err_unlock:
+	mutex_unlock(&dev_priv->drm.struct_mutex);
+
+	fake_file_free(dev_priv, file);
+	return err;
+}
+
 static int igt_ggtt_fill(void *arg)
 {
 	struct drm_i915_private *i915 = arg;
@@ -300,11 +392,49 @@ static int igt_ggtt_fill(void *arg)
 	return err;
 }
 
+static int igt_ggtt_walk(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 hole_start = U64_MAX, hole_end = 0, hole_size = 0;
+	u64 this_start, this_end;
+	struct drm_mm_node *node;
+	int err;
+
+	GEM_BUG_ON(ggtt->base.total & ~PAGE_MASK);
+
+	mutex_lock(&i915->drm.struct_mutex);
+	drm_mm_for_each_hole(node, &ggtt->base.mm, this_start, this_end) {
+		u64 this_size;
+
+		if (ggtt->base.mm.color_adjust)
+			ggtt->base. mm.color_adjust(node, 0,
+						    &this_start, &this_end);
+
+		this_size = this_end - this_start;
+		if (this_size > hole_size) {
+			hole_size = this_size;
+			hole_start = this_start;
+			hole_end = this_end;
+		}
+	}
+	pr_info("Found GGTT hole [%llx, %llx], size %llx\n",
+		hole_start, hole_end, hole_size);
+	GEM_BUG_ON(hole_start >= hole_end);
+
+	err = walk_hole(i915, &ggtt->base, hole_start, hole_end);
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	return err;
+}
+
 int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_ppgtt_alloc),
+		SUBTEST(igt_ppgtt_walk),
 		SUBTEST(igt_ppgtt_fill),
+		SUBTEST(igt_ggtt_walk),
 		SUBTEST(igt_ggtt_fill),
 	};
 
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 30/37] drm/i915: Exercise filling and removing random ranges from the live GTT
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (28 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 29/37] drm/i915: Fill different pages of the GTT Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-13  8:59   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 31/37] drm/i915: Test creation of VMA Chris Wilson
                   ` (7 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Test the low-level i915_address_space interfaces to sanity check the
live insertion/removal of address ranges.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 140 ++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index 68f7bfb7502e..b20406631120 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -25,6 +25,7 @@
 #include <linux/prime_numbers.h>
 
 #include "i915_selftest.h"
+#include "i915_random.h"
 #include "fake_drm.h"
 #include "huge_gem_object.h"
 
@@ -290,6 +291,74 @@ static int walk_hole(struct drm_i915_private *i915,
 	return err;
 }
 
+static u64 scale(u64 offset, unsigned int shift)
+{
+	return offset << shift;
+}
+
+static int random_hole(struct drm_i915_private *i915,
+		       struct i915_address_space *vm,
+		       u64 hole_start, u64 hole_end)
+{
+	I915_RND_STATE(prng);
+	unsigned int size;
+
+	for (size = 12; (hole_end - hole_start) >> (size + 2); size++) {
+		I915_SELFTEST_TIMEOUT(end_time);
+		struct drm_i915_gem_object *obj;
+		unsigned int *order, count, n;
+		u64 hole_size;
+
+		hole_size = (hole_end - hole_start) >> size;
+		if (hole_size > KMALLOC_MAX_SIZE / sizeof(u32))
+			hole_size = KMALLOC_MAX_SIZE / sizeof(u32);
+		count = hole_size;
+		do {
+			count >>= 1;
+			order = i915_random_order(count, &prng);
+		} while (!order && count);
+
+		obj = huge_gem_object(i915, PAGE_SIZE, scale(1, size));
+		if (IS_ERR(obj))
+			break;
+
+		GEM_BUG_ON(obj->base.size != scale(1, size));
+
+		if (i915_gem_object_pin_pages(obj)) {
+			i915_gem_object_put(obj);
+			break;
+		}
+
+		for (n = 0; n < count; n++) {
+			if (vm->allocate_va_range &&
+			    vm->allocate_va_range(vm,
+						  scale(order[n], size),
+						  scale(1, size)))
+				break;
+
+			vm->insert_entries(vm, obj->mm.pages,
+					   scale(order[n], size),
+					   I915_CACHE_NONE, 0);
+			if (time_after(jiffies, end_time))
+				break;
+		}
+		count = n;
+
+		i915_random_reorder(order, count, &prng);
+		for (n = 0; n < count; n++)
+			vm->clear_range(vm,
+					scale(order[n], size),
+					scale(1, size));
+
+		i915_gem_object_unpin_pages(obj);
+		i915_gem_object_put(obj);
+
+		kfree(order);
+	}
+
+	return 0;
+}
+
 static int igt_ppgtt_fill(void *arg)
 {
 	struct drm_i915_private *dev_priv = arg;
@@ -356,6 +425,39 @@ static int igt_ppgtt_walk(void *arg)
 	return err;
 }
 
+static int igt_ppgtt_drunk(void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	struct drm_file *file;
+	struct i915_hw_ppgtt *ppgtt;
+	int err;
+
+	if (!USES_FULL_PPGTT(dev_priv))
+		return 0;
+
+	file = fake_file(dev_priv);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	mutex_lock(&dev_priv->drm.struct_mutex);
+	ppgtt = i915_ppgtt_create(dev_priv, file->driver_priv, "mock");
+	if (IS_ERR(ppgtt)) {
+		err = PTR_ERR(ppgtt);
+		goto err_unlock;
+	}
+	GEM_BUG_ON(ppgtt->base.total & ~PAGE_MASK);
+
+	err = random_hole(dev_priv, &ppgtt->base, 0, ppgtt->base.total);
+
+	i915_ppgtt_close(&ppgtt->base);
+	i915_ppgtt_put(ppgtt);
+err_unlock:
+	mutex_unlock(&dev_priv->drm.struct_mutex);
+
+	fake_file_free(dev_priv, file);
+	return err;
+}
+
 static int igt_ggtt_fill(void *arg)
 {
 	struct drm_i915_private *i915 = arg;
@@ -428,12 +530,50 @@ static int igt_ggtt_walk(void *arg)
 	return err;
 }
 
+static int igt_ggtt_drunk(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 hole_start = U64_MAX, hole_end = 0, hole_size = 0;
+	u64 this_start, this_end;
+	struct drm_mm_node *node;
+	int err;
+
+	GEM_BUG_ON(ggtt->base.total & ~PAGE_MASK);
+
+	mutex_lock(&i915->drm.struct_mutex);
+	drm_mm_for_each_hole(node, &ggtt->base.mm, this_start, this_end) {
+		u64 this_size;
+
+		if (ggtt->base.mm.color_adjust)
+			ggtt->base. mm.color_adjust(node, 0,
+						    &this_start, &this_end);
+
+		this_size = this_end - this_start;
+		if (this_size > hole_size) {
+			hole_size = this_size;
+			hole_start = this_start;
+			hole_end = this_end;
+		}
+	}
+	pr_info("Found GGTT hole [%llx, %llx], size %llx\n",
+		hole_start, hole_end, hole_size);
+	GEM_BUG_ON(hole_start >= hole_end);
+
+	err = random_hole(i915, &ggtt->base, hole_start, hole_end);
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	return err;
+}
+
 int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_ppgtt_alloc),
+		SUBTEST(igt_ppgtt_drunk),
 		SUBTEST(igt_ppgtt_walk),
 		SUBTEST(igt_ppgtt_fill),
+		SUBTEST(igt_ggtt_drunk),
 		SUBTEST(igt_ggtt_walk),
 		SUBTEST(igt_ggtt_fill),
 	};
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 31/37] drm/i915: Test creation of VMA
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (29 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 30/37] drm/i915: Exercise filling and removing random ranges from the live GTT Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-13 12:28   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 32/37] drm/i915: Exercise i915_vma_pin/i915_vma_insert Chris Wilson
                   ` (6 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Simple test to exercise creation and lookup of VMA within an object.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_vma.c                    |   3 +
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |   1 +
 drivers/gpu/drm/i915/selftests/i915_vma.c          | 176 +++++++++++++++++++++
 3 files changed, 180 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_vma.c

diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 6424352a69b2..af8738a84a85 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -621,3 +621,6 @@ int i915_vma_unbind(struct i915_vma *vma)
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/i915_vma.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 955a4d6ccdaf..b450eab7e6e1 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -15,3 +15,4 @@ selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
 selftest(requests, i915_gem_request_mock_selftests)
 selftest(objects, i915_gem_object_mock_selftests)
 selftest(dmabuf, i915_gem_dmabuf_mock_selftests)
+selftest(vma, i915_vma_mock_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c
new file mode 100644
index 000000000000..ebd200245f88
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_vma.c
@@ -0,0 +1,176 @@
+/*
+ * 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 <linux/prime_numbers.h>
+
+#include "i915_selftest.h"
+
+#include "mock_gem_device.h"
+#include "mock_context.h"
+
+static bool assert_vma(struct i915_vma *vma,
+		       struct drm_i915_gem_object *obj,
+		       struct i915_gem_context *ctx)
+{
+	if (vma->vm != &ctx->ppgtt->base) {
+		pr_err("VMA created with wrong VM\n");
+		return false;
+	}
+
+	if (vma->size != obj->base.size) {
+		pr_err("VMA created with wrong size, found %llu, expected %zu\n",
+		       vma->size, obj->base.size);
+		return false;
+	}
+
+	if (vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) {
+		pr_err("VMA created with wrong type [%d]\n",
+		       vma->ggtt_view.type);
+		return false;
+	}
+
+	return true;
+}
+
+static int vma_create(struct drm_i915_private *i915,
+		      struct list_head *objects,
+		      struct list_head *contexts)
+{
+	struct drm_i915_gem_object *obj;
+	struct i915_gem_context *ctx;
+	int pinned;
+
+	list_for_each_entry(obj, objects, batch_pool_link) {
+		for (pinned = 0; pinned <= 1; pinned++) {
+			list_for_each_entry(ctx, contexts, link) {
+				struct i915_vma *vma;
+				int err;
+
+				vma = i915_gem_obj_lookup_or_create_vma(obj, &ctx->ppgtt->base, NULL);
+				if (IS_ERR(vma))
+					return PTR_ERR(vma);
+
+				if (!assert_vma(vma, obj, ctx)) {
+					pr_err("VMA lookup/create failed\n");
+					return -EINVAL;
+				}
+
+				if (!pinned) {
+					err = i915_vma_pin(vma, 0, 0, PIN_USER);
+					if (err) {
+						pr_err("Failed to pin VMA\n");
+						return err;
+					}
+				} else {
+					i915_vma_unpin(vma);
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int igt_vma_create(void *arg)
+{
+	I915_SELFTEST_TIMEOUT(end_time);
+	LIST_HEAD(objects);
+	LIST_HEAD(contexts);
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj, *on;
+	struct i915_gem_context *ctx, *cn;
+	unsigned long num_obj, num_ctx;
+	unsigned long no, nc;
+	int err;
+
+	no = 0;
+	for_each_prime_number(num_obj, 8192) {
+		for (; no < num_obj; no++) {
+			obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+			if (IS_ERR(obj))
+				goto err;
+
+			list_add(&obj->batch_pool_link, &objects);
+		}
+
+		list_for_each_entry_safe(ctx, cn, &contexts, link)
+			mock_context_close(ctx);
+
+		nc = 0;
+		for_each_prime_number(num_ctx, 8192) {
+			cond_resched();
+			if (signal_pending(current)) {
+				err = -EINTR;
+				goto err;
+			}
+
+			for (; nc < num_ctx; nc++) {
+				ctx = mock_context(i915, "mock");
+				if (!ctx)
+					goto err;
+
+				list_move(&ctx->link, &contexts);
+			}
+
+			err = vma_create(i915, &objects, &contexts);
+			if (err)
+				goto err;
+		}
+
+		if (time_after(jiffies, end_time)) {
+			pr_warn("%s timed out: after %lu objects\n", __func__, no);
+			break;
+		}
+	}
+
+	/* Final pass to lookup all created contexts */
+	err = vma_create(i915, &objects, &contexts);
+err:
+	list_for_each_entry_safe(ctx, cn, &contexts, link)
+		mock_context_close(ctx);
+
+	list_for_each_entry_safe(obj, on, &objects, batch_pool_link)
+		i915_gem_object_put(obj);
+	return err;
+}
+
+int i915_vma_mock_selftests(void)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_vma_create),
+	};
+	struct drm_i915_private *i915;
+	int err;
+
+	i915 = mock_gem_device();
+	if (!i915)
+		return -ENOMEM;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	err = i915_subtests(tests, i915);
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	return err;
+}
+
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 32/37] drm/i915: Exercise i915_vma_pin/i915_vma_insert
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (30 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 31/37] drm/i915: Test creation of VMA Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-13 12:49   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 33/37] drm/i915: Verify page layout for rotated VMA Chris Wilson
                   ` (5 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

High-level testing of the struct drm_mm by verifying our handling of
weird requests to i915_vma_pin.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_vma.c           |   4 +-
 drivers/gpu/drm/i915/i915_vma.h           |   4 +-
 drivers/gpu/drm/i915/selftests/i915_vma.c | 133 ++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index af8738a84a85..38c5f1039569 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -259,8 +259,8 @@ void i915_vma_unpin_and_release(struct i915_vma **p_vma)
 	__i915_gem_object_release_unless_active(obj);
 }
 
-bool
-i915_vma_misplaced(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
+bool i915_vma_misplaced(const struct i915_vma *vma,
+			u64 size, u64 alignment, u64 flags)
 {
 	if (!drm_mm_node_allocated(&vma->node))
 		return false;
diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
index 47b5ceb386c4..7211c9bef637 100644
--- a/drivers/gpu/drm/i915/i915_vma.h
+++ b/drivers/gpu/drm/i915/i915_vma.h
@@ -218,8 +218,8 @@ i915_vma_compare(struct i915_vma *vma,
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
 		  u32 flags);
 bool i915_gem_valid_gtt_space(struct i915_vma *vma, unsigned long cache_level);
-bool
-i915_vma_misplaced(struct i915_vma *vma, u64 size, u64 alignment, u64 flags);
+bool i915_vma_misplaced(const struct i915_vma *vma,
+			u64 size, u64 alignment, u64 flags);
 void __i915_vma_set_map_and_fenceable(struct i915_vma *vma);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
 void i915_vma_close(struct i915_vma *vma);
diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c
index ebd200245f88..d229adabc5f8 100644
--- a/drivers/gpu/drm/i915/selftests/i915_vma.c
+++ b/drivers/gpu/drm/i915/selftests/i915_vma.c
@@ -155,10 +155,143 @@ static int igt_vma_create(void *arg)
 	return err;
 }
 
+struct pin_mode {
+	u64 size;
+	u64 flags;
+	bool (*assert)(const struct i915_vma *,
+		       const struct pin_mode *mode,
+		       int result);
+};
+
+static bool assert_pin_valid(const struct i915_vma *vma,
+			     const struct pin_mode *mode,
+			     int result)
+{
+	if (result)
+		return false;
+
+	if (i915_vma_misplaced(vma, mode->size, 0, mode->flags))
+		return false;
+
+	return true;
+}
+
+__maybe_unused
+static bool assert_pin_e2big(const struct i915_vma *vma,
+			     const struct pin_mode *mode,
+			     int result)
+{
+	return result == -E2BIG;
+}
+
+__maybe_unused
+static bool assert_pin_enospc(const struct i915_vma *vma,
+			      const struct pin_mode *mode,
+			      int result)
+{
+	return result == -ENOSPC;
+}
+
+__maybe_unused
+static bool assert_pin_einval(const struct i915_vma *vma,
+			      const struct pin_mode *mode,
+			      int result)
+{
+	return result == -EINVAL;
+}
+
+static int igt_vma_pin1(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	const struct pin_mode modes[] = {
+		[0] = { 0, PIN_GLOBAL, assert_pin_valid },
+		[1] = { 0, PIN_GLOBAL | PIN_MAPPABLE, assert_pin_valid },
+
+		[2] = { 0, PIN_GLOBAL | PIN_OFFSET_BIAS | 4096, assert_pin_valid },
+		[3] = { 0, PIN_GLOBAL | PIN_OFFSET_BIAS | 8192, assert_pin_valid },
+		[4] = { 0, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096), assert_pin_valid },
+		[5] = { 0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096), assert_pin_valid },
+		[6] = { 0, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.base.total - 4096), assert_pin_valid },
+
+		[7] = { 0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (i915->ggtt.mappable_end - 4096), assert_pin_valid },
+		[8] = { 0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | i915->ggtt.mappable_end, assert_pin_einval },
+		[9] = { 0, PIN_GLOBAL | PIN_OFFSET_FIXED | (i915->ggtt.base.total - 4096), assert_pin_valid },
+		[10] = { 0, PIN_GLOBAL | PIN_OFFSET_FIXED | i915->ggtt.base.total, assert_pin_einval },
+		[11] = { 0, PIN_GLOBAL | PIN_OFFSET_FIXED | round_down(U64_MAX, PAGE_SIZE), assert_pin_einval },
+
+		[12] = { 4096, PIN_GLOBAL, assert_pin_valid },
+		[13] = { 8192, PIN_GLOBAL, assert_pin_valid },
+		[14] = { i915->ggtt.mappable_end - 4096, PIN_GLOBAL | PIN_MAPPABLE, assert_pin_valid },
+		[15] = { i915->ggtt.mappable_end, PIN_GLOBAL | PIN_MAPPABLE, assert_pin_valid },
+		[16] = { i915->ggtt.mappable_end + 4096, PIN_GLOBAL | PIN_MAPPABLE, assert_pin_e2big },
+		[17] = { i915->ggtt.base.total - 4096, PIN_GLOBAL, assert_pin_valid },
+		[18] = { i915->ggtt.base.total, PIN_GLOBAL, assert_pin_valid },
+		[19] = { i915->ggtt.base.total + 4096, PIN_GLOBAL, assert_pin_e2big },
+		[20] = { round_down(U64_MAX, PAGE_SIZE), PIN_GLOBAL, assert_pin_e2big },
+		[21] = { 8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (i915->ggtt.mappable_end - 4096), assert_pin_einval },
+		[22] = { 8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (i915->ggtt.base.total - 4096), assert_pin_einval },
+		[23] = { 8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (round_down(U64_MAX, PAGE_SIZE) - 4096), assert_pin_einval },
+
+		[24] = { 8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096), assert_pin_valid },
+
+#if !IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
+		/* Misusing BIAS is a programming error (it is not controllable
+		 * from userspace) so when debugging is enabled, it explodes.
+		 * However, the tests are still quite interesting for checking
+		 * variable start, end and size.
+		 */
+		[25] = { 0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | i915->ggtt.mappable_end, assert_pin_enospc },
+		[26] = { 0, PIN_GLOBAL | PIN_OFFSET_BIAS | i915->ggtt.base.total, assert_pin_enospc },
+		[27] = { 8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096), assert_pin_enospc },
+		[28] = { 8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.base.total - 4096), assert_pin_enospc },
+#endif
+		{ },
+	}, *m;
+	struct drm_i915_gem_object *obj;
+	struct i915_vma *vma;
+	int err = -EINVAL;
+
+	GEM_BUG_ON(!drm_mm_clean(&i915->ggtt.base.mm));
+
+	obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	vma = i915_gem_obj_lookup_or_create_vma(obj, &i915->ggtt.base, NULL);
+	if (IS_ERR(vma))
+		goto err;
+
+	for (m = modes; m->assert; m++) {
+		err = i915_vma_pin(vma, m->size, 0, m->flags);
+		if (!m->assert(vma, m, err)) {
+			pr_err("%s to pin single page into GGTT with mode[%ld]: size=%llx flags=%llx, err=%d\n",
+			       m->assert == assert_pin_valid ? "Failed" : "Unexpectedly succeeded",
+			       m - modes, m->size, m->flags, err);
+			err = -EINVAL;
+			goto err;
+		}
+
+		if (!err) {
+			i915_vma_unpin(vma);
+			err = i915_vma_unbind(vma);
+			if (err) {
+				pr_err("Failed to unbind single page from GGTT, err=%d\n", err);
+				goto err;
+			}
+		}
+	}
+
+	err = 0;
+err:
+	i915_gem_object_put(obj);
+	return err;
+}
+
 int i915_vma_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_vma_create),
+		SUBTEST(igt_vma_pin1),
 	};
 	struct drm_i915_private *i915;
 	int err;
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 33/37] drm/i915: Verify page layout for rotated VMA
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (31 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 32/37] drm/i915: Exercise i915_vma_pin/i915_vma_insert Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-12 17:41   ` Tvrtko Ursulin
  2017-01-11 21:09 ` [PATCH 34/37] drm/i915: Test creation of partial VMA Chris Wilson
                   ` (4 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Exercise creating rotated VMA and checking the page order within.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_vma.c | 130 ++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c
index d229adabc5f8..95c5db2b0881 100644
--- a/drivers/gpu/drm/i915/selftests/i915_vma.c
+++ b/drivers/gpu/drm/i915/selftests/i915_vma.c
@@ -287,11 +287,141 @@ static int igt_vma_pin1(void *arg)
 	return err;
 }
 
+static unsigned long rotated_index(const struct intel_rotation_info *r,
+				   unsigned int n,
+				   unsigned int x,
+				   unsigned int y)
+{
+	return r->plane[n].stride * (r->plane[n].height - y - 1) + x;
+}
+
+static struct scatterlist *
+assert_rotated(struct drm_i915_gem_object *obj,
+	       const struct intel_rotation_info *r, unsigned int n,
+	       struct scatterlist *sg)
+{
+	unsigned int x, y;
+
+	for (x = 0; x < r->plane[n].width; x++) {
+		for (y = 0; y < r->plane[n].height; y++) {
+			unsigned long src_idx;
+			dma_addr_t src;
+
+			src_idx = rotated_index(r, n, x, y);
+			src = i915_gem_object_get_dma_address(obj, src_idx);
+
+			if (sg_dma_len(sg) != PAGE_SIZE) {
+				pr_err("Invalid sg.length, found %d, expected %lu for rotated page (%d, %d) [src index %lu]\n",
+				       sg_dma_len(sg), PAGE_SIZE,
+				       x, y, src_idx);
+				return NULL;
+			}
+
+			if (sg_dma_address(sg) != src) {
+				pr_err("Invalid address for rotated page (%d, %d) [src index %lu]\n",
+				       x, y, src_idx);
+				return NULL;
+			}
+
+			sg = ____sg_next(sg);
+		}
+	}
+
+	return sg;
+}
+
+static int igt_vma_rotate(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	const unsigned int width = 6;
+	const unsigned int height = 4;
+	const unsigned int npages = 24;
+	struct i915_vma *vma;
+	struct i915_ggtt_view view;
+	struct scatterlist *sg;
+	unsigned int n;
+	int err = -ENOMEM;
+
+	obj = i915_gem_object_create_internal(i915, npages*PAGE_SIZE);
+	if (IS_ERR(obj))
+		goto err;
+
+	view.type = I915_GGTT_VIEW_ROTATED;
+	view.rotated.plane[0].offset = 0;
+	view.rotated.plane[0].width = width;
+	view.rotated.plane[0].height = height;
+	view.rotated.plane[0].stride = width;
+
+	view.rotated.plane[1].offset = 0;
+	view.rotated.plane[1].width = height;
+	view.rotated.plane[1].height = width;
+	view.rotated.plane[1].stride = height;
+
+	vma = i915_gem_obj_lookup_or_create_vma(obj, &i915->ggtt.base, &view);
+	if (IS_ERR(vma)) {
+		err = PTR_ERR(vma);
+		goto err_object;
+	}
+
+	if (!i915_vma_is_ggtt(vma)) {
+		pr_err("VMA is not in the GGTT!\n");
+		err = -EINVAL;
+		goto err_object;
+	}
+
+	err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
+	if (err)
+		goto err_object;
+
+	if (memcmp(&vma->ggtt_view, &view, sizeof(view))) {
+		pr_err("VMA mismatch upon creation!\n");
+		err = -EINVAL;
+		goto err_object;
+	}
+
+	if (vma->size != 2*npages*PAGE_SIZE) {
+		pr_err("VMA is wrong size, expected %lu, found %llu\n",
+		       2*npages*PAGE_SIZE, vma->size);
+		err = -EINVAL;
+		goto err_object;
+	}
+
+	if (vma->node.size < vma->size) {
+		pr_err("VMA binding too small, expected %llu, found %llu\n",
+		       vma->size, vma->node.size);
+		err = -EINVAL;
+		goto err_object;
+	}
+
+	if (vma->pages == obj->mm.pages) {
+		pr_err("VMA using unrotated object pages!\n");
+		err = -EINVAL;
+		goto err_object;
+	}
+
+	sg = vma->pages->sgl;
+	for (n = 0; n < ARRAY_SIZE(view.rotated.plane); n++) {
+		sg = assert_rotated(obj, &view.rotated, n, sg);
+		if (!sg) {
+			pr_err("Inconsistent VMA pages for plane %d\n", n);
+			err = -EINVAL;
+			goto err_object;
+		}
+	}
+
+err_object:
+	i915_gem_object_put(obj);
+err:
+	return err;
+}
+
 int i915_vma_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_vma_create),
 		SUBTEST(igt_vma_pin1),
+		SUBTEST(igt_vma_rotate),
 	};
 	struct drm_i915_private *i915;
 	int err;
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 34/37] drm/i915: Test creation of partial VMA
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (32 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 33/37] drm/i915: Verify page layout for rotated VMA Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-13 13:10   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 35/37] drm/i915: Live testing for context execution Chris Wilson
                   ` (3 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Mock testing to ensure we can create and lookup partial VMA.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_vma.c | 179 ++++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)

diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c
index 95c5db2b0881..7511f383868c 100644
--- a/drivers/gpu/drm/i915/selftests/i915_vma.c
+++ b/drivers/gpu/drm/i915/selftests/i915_vma.c
@@ -416,12 +416,191 @@ static int igt_vma_rotate(void *arg)
 	return err;
 }
 
+static bool assert_partial(struct drm_i915_gem_object *obj,
+			   struct i915_vma *vma,
+			   unsigned long offset,
+			   unsigned long size)
+{
+	struct sgt_iter sgt;
+	dma_addr_t dma;
+
+	for_each_sgt_dma(dma, sgt, vma->pages) {
+		dma_addr_t src;
+
+		if (!size) {
+			pr_err("Partial scattergather list too long\n");
+			return false;
+		}
+
+		src = i915_gem_object_get_dma_address(obj, offset);
+		if (src != dma) {
+			pr_err("DMA mismatch for partial page offset %lu\n",
+			       offset);
+			return false;
+		}
+
+		offset++;
+		size--;
+	}
+
+	return true;
+}
+
+static int igt_vma_partial(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	const unsigned int npages = 1021; /* prime! */
+	struct drm_i915_gem_object *obj;
+	unsigned int sz, offset, loop;
+	struct i915_vma *vma;
+	int err = -ENOMEM;
+
+	obj = i915_gem_object_create_internal(i915, npages*PAGE_SIZE);
+	if (IS_ERR(obj))
+		goto err;
+
+	for (loop = 0; loop <= 1; loop++) { /* exercise both create/lookup */
+		unsigned int count, nvma;
+
+		nvma = loop;
+		for_each_prime_number_from(sz, 1, npages) {
+			for_each_prime_number_from(offset, 0, npages - sz) {
+				struct i915_ggtt_view view;
+
+				view.type = I915_GGTT_VIEW_PARTIAL;
+				view.partial.offset_size =
+					offset << INTEL_PARTIAL_SIZE_BITS | (sz - 1);
+
+				if (sz == npages)
+					view.type = I915_GGTT_VIEW_NORMAL;
+
+				vma = i915_gem_obj_lookup_or_create_vma(obj, &i915->ggtt.base, &view);
+				if (IS_ERR(vma)) {
+					err = PTR_ERR(vma);
+					goto err_object;
+				}
+
+				if (!i915_vma_is_ggtt(vma)) {
+					pr_err("VMA is not in the GGTT!\n");
+					err = -EINVAL;
+					goto err_object;
+				}
+
+				err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
+				if (err)
+					goto err_object;
+
+				if (vma->size != sz*PAGE_SIZE) {
+					pr_err("VMA is wrong size, expected %lu, found %llu\n",
+					       sz*PAGE_SIZE, vma->size);
+					err = -EINVAL;
+					goto err_object;
+				}
+
+				if (vma->node.size < vma->size) {
+					pr_err("VMA binding too small, expected %llu, found %llu\n",
+					       vma->size, vma->node.size);
+					err = -EINVAL;
+					goto err_object;
+				}
+
+				if (view.type != I915_GGTT_VIEW_NORMAL) {
+					if (memcmp(&vma->ggtt_view, &view, sizeof(view))) {
+						pr_err("VMA mismatch upon creation!\n");
+						err = -EINVAL;
+						goto err_object;
+					}
+
+					if (vma->pages == obj->mm.pages) {
+						pr_err("VMA using unrotated object pages!\n");
+						err = -EINVAL;
+						goto err_object;
+					}
+				}
+
+				if (!assert_partial(obj, vma, offset, sz)) {
+					pr_err("Inconsistent partial pages for (offset=%d, size=%d)\n", offset, sz);
+					err = -EINVAL;
+					goto err_object;
+				}
+
+				i915_vma_unpin(vma);
+				nvma++;
+			}
+		}
+
+		count = loop;
+		list_for_each_entry(vma, &obj->vma_list, obj_link)
+			count++;
+		if (count != nvma) {
+			pr_err("All partial vma were not recorded on the obj->vma_list: found %u, expected %u\n",
+			       count, nvma);
+			err = -EINVAL;
+			goto err_object;
+		}
+
+		/* Create a mapping for the entire object, just for extra fun */
+		vma = i915_gem_obj_lookup_or_create_vma(obj,
+							&i915->ggtt.base,
+							NULL);
+		if (IS_ERR(vma)) {
+			err = PTR_ERR(vma);
+			goto err_object;
+		}
+
+		if (!i915_vma_is_ggtt(vma)) {
+			pr_err("VMA is not in the GGTT!\n");
+			err = -EINVAL;
+			goto err_object;
+		}
+
+		err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
+		if (err)
+			goto err_object;
+
+		if (vma->size != obj->base.size) {
+			pr_err("VMA is wrong size, expected %lu, found %llu\n",
+			       sz*PAGE_SIZE, vma->size);
+			err = -EINVAL;
+			goto err_object;
+		}
+
+		if (vma->node.size < vma->size) {
+			pr_err("VMA binding too small, expected %llu, found %llu\n",
+			       vma->size, vma->node.size);
+			err = -EINVAL;
+			goto err_object;
+		}
+
+		if (vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) {
+			pr_err("Not the normal ggtt view! Found %d\n",
+			       vma->ggtt_view.type);
+			err = -EINVAL;
+			goto err_object;
+		}
+
+		if (vma->pages != obj->mm.pages) {
+			pr_err("VMA not using object pages!\n");
+			err = -EINVAL;
+			goto err_object;
+		}
+
+		i915_vma_unpin(vma);
+	}
+
+err_object:
+	i915_gem_object_put(obj);
+err:
+	return err;
+}
+
 int i915_vma_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_vma_create),
 		SUBTEST(igt_vma_pin1),
 		SUBTEST(igt_vma_rotate),
+		SUBTEST(igt_vma_partial),
 	};
 	struct drm_i915_private *i915;
 	int err;
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 35/37] drm/i915: Live testing for context execution
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (33 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 34/37] drm/i915: Test creation of partial VMA Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-13 14:28   ` Joonas Lahtinen
  2017-01-11 21:09 ` [PATCH 36/37] drm/i915: Initial selftests for exercising eviction Chris Wilson
                   ` (2 subsequent siblings)
  37 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Check we can create and execution within a context.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem_context.c            |   1 +
 drivers/gpu/drm/i915/selftests/i915_gem_context.c  | 302 +++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |   1 +
 3 files changed, 304 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_context.c

diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 6fcb35ecd6a7..9966dfd56a1b 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -1167,4 +1167,5 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftests/mock_context.c"
+#include "selftests/i915_gem_context.c"
 #endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c
new file mode 100644
index 000000000000..53951dce67e9
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2017 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_selftest.h"
+#include "fake_drm.h"
+#include "huge_gem_object.h"
+
+static struct i915_vma *vma_lookup(struct drm_i915_gem_object *obj,
+				   struct i915_address_space *vm)
+{
+	return i915_gem_obj_lookup_or_create_vma(obj, vm, NULL);
+}
+
+static struct i915_vma *
+gpu_fill_pages(struct i915_vma *vma,
+	       unsigned long first_page,
+	       unsigned int offset_in_page,
+	       unsigned long count,
+	       u32 value)
+{
+	struct drm_i915_gem_object *obj;
+	const int gen = INTEL_GEN(vma->vm->i915);
+	unsigned long sz = (4*count + 1)*sizeof(u32);
+	u64 offset;
+	u32 *cmd;
+	int err;
+
+	GEM_BUG_ON(offset_in_page >= PAGE_SIZE);
+
+	obj = i915_gem_object_create_internal(vma->vm->i915,
+					      round_up(sz, PAGE_SIZE));
+	if (IS_ERR(obj))
+		return ERR_CAST(obj);
+
+	cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
+	if (IS_ERR(cmd)) {
+		i915_gem_object_put(obj);
+		return ERR_CAST(cmd);
+	}
+
+	offset = PAGE_SIZE * first_page + offset_in_page;
+	offset += vma->node.start;
+	for (sz = 0; sz < count; sz++) {
+		if (gen >= 8) {
+			*cmd++ = MI_STORE_DWORD_IMM_GEN4;
+			*cmd++ = lower_32_bits(offset);
+			*cmd++ = upper_32_bits(offset);
+			*cmd++ = value;
+		} else if (gen >= 6) {
+			*cmd++ = MI_STORE_DWORD_IMM_GEN4;
+			*cmd++ = 0;
+			*cmd++ = offset;
+			*cmd++ = value;
+		} else if (gen >= 4) {
+			*cmd++ = MI_STORE_DWORD_IMM_GEN4 | 1 << 22;
+			*cmd++ = 0;
+			*cmd++ = offset;
+			*cmd++ = value;
+		} else {
+			*cmd++ = MI_STORE_DWORD_IMM | 1 << 22;
+			*cmd++ = offset;
+			*cmd++ = value;
+		}
+		offset += PAGE_SIZE;
+	}
+	*cmd = MI_BATCH_BUFFER_END;
+	i915_gem_object_unpin_map(obj);
+
+	err = i915_gem_object_set_to_gtt_domain(obj, false);
+	if (err) {
+		i915_gem_object_put(obj);
+		return ERR_PTR(err);
+	}
+
+	vma = vma_lookup(obj, vma->vm);
+	if (IS_ERR(vma)) {
+		i915_gem_object_put(obj);
+		return vma;
+	}
+
+	err = i915_vma_pin(vma, 0, 0, PIN_USER);
+	if (err) {
+		i915_gem_object_put(obj);
+		return ERR_PTR(err);
+	}
+
+	return vma;
+}
+
+static int gpu_fill(struct drm_i915_gem_object *obj,
+		    struct i915_gem_context *ctx)
+{
+	struct drm_i915_private *i915 = to_i915(obj->base.dev);
+	const unsigned long npages = obj->base.size >> PAGE_SHIFT;
+	struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;
+	struct intel_engine_cs *engine = i915->engine[RCS];
+	struct i915_vma *vma;
+	unsigned long page;
+	int err;
+
+	vma = vma_lookup(obj, vm);
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	err = i915_gem_object_set_to_gtt_domain(obj, false);
+	if (err)
+		return err;
+
+	err = i915_vma_pin(vma, 0, 0, PIN_USER);
+	if (err)
+		return err;
+
+	GEM_BUG_ON(!IS_ALIGNED(npages, 1024));
+	for (page = 0; page < npages; page += 1024) {
+		unsigned int v = page / 1024;
+		struct drm_i915_gem_request *rq;
+		struct i915_vma *batch;
+
+		batch = gpu_fill_pages(vma, page, v*sizeof(u32), 1024, v);
+		if (IS_ERR(batch)) {
+			i915_vma_unpin(vma);
+			return PTR_ERR(batch);
+		}
+
+		rq = i915_gem_request_alloc(engine, ctx);
+		if (IS_ERR(rq)) {
+			i915_vma_unpin(batch);
+			i915_vma_unpin(vma);
+			return PTR_ERR(rq);
+		}
+
+		i915_switch_context(rq);
+		engine->emit_bb_start(rq,
+				      batch->node.start, batch->node.size, 0);
+
+		i915_vma_move_to_active(batch, rq, 0);
+		i915_gem_object_set_active_reference(batch->obj);
+		i915_vma_unpin(batch);
+		i915_vma_close(batch);
+
+		i915_vma_move_to_active(vma, rq, 0);
+
+		ww_mutex_lock(&obj->resv->lock, NULL);
+		reservation_object_add_excl_fence(obj->resv, &rq->fence);
+		ww_mutex_unlock(&obj->resv->lock);
+
+		__i915_add_request(rq, true);
+	}
+	i915_vma_unpin(vma);
+
+	return 0;
+}
+
+static int cpu_fill(struct drm_i915_gem_object *obj, u32 value)
+{
+	const bool has_llc = HAS_LLC(to_i915(obj->base.dev));
+	unsigned int n, m;
+	unsigned int need_flush;
+	int err;
+
+	err = i915_gem_obj_prepare_shmem_write(obj, &need_flush);
+	if (err)
+		return err;
+
+	for (n = 0; n < 1024; n++) {
+		u32 *map;
+
+		map = kmap_atomic(i915_gem_object_get_page(obj, n));
+		for (m = 0; m < 1024; m++)
+			map[m] = value;
+		if (!has_llc)
+			drm_clflush_virt_range(map, PAGE_SIZE);
+		kunmap_atomic(map);
+	}
+
+	i915_gem_obj_finish_shmem_access(obj);
+	obj->base.read_domains = I915_GEM_DOMAIN_GTT | I915_GEM_DOMAIN_CPU;
+	obj->base.write_domain = 0;
+	return 0;
+}
+
+static int cpu_check(struct drm_i915_gem_object *obj,
+		     unsigned long num)
+{
+	unsigned int n, m, max = (obj->base.size >> PAGE_SHIFT) / 1024;
+	unsigned int needs_flush;
+	int err;
+
+	err = i915_gem_obj_prepare_shmem_read(obj, &needs_flush);
+	if (err)
+		return err;
+
+	for (n = 0; !err && n < 1024; n++) {
+		u32 *map;
+
+		map = kmap_atomic(i915_gem_object_get_page(obj, n));
+		if (needs_flush & CLFLUSH_BEFORE)
+			drm_clflush_virt_range(map, sizeof(u32)*max);
+		for (m = 0; !err && m < max; m++) {
+			if (map[m] != m) {
+				pr_err("Invalid value in object %lu at page %d, offset %d: found %x expected %x\n",
+				       num, n, m, map[m], m);
+				err = -EINVAL;
+			}
+		}
+		kunmap_atomic(map);
+	}
+
+	i915_gem_obj_finish_shmem_access(obj);
+	return err;
+}
+
+static int igt_ctx_exec(void *arg)
+{
+	I915_SELFTEST_TIMEOUT(end_time);
+	LIST_HEAD(objects);
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct drm_file *file = fake_file(i915);
+	unsigned int count = 0;
+	int err = 0;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	while (!time_after(jiffies, end_time)) {
+		struct i915_gem_context *ctx;
+		struct i915_address_space *vm;
+		u64 npages;
+		u32 ignored;
+
+		ctx = i915_gem_create_context(i915, file->driver_priv);
+		if (IS_ERR(ctx))
+			break;
+
+		vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;
+		npages = min(vm->total / 2, 1024ull * 1024 * PAGE_SIZE);
+		npages >>= PAGE_SHIFT + 10;
+		npages <<= PAGE_SHIFT + 10;
+		obj = huge_gem_object(i915, 1024 * PAGE_SIZE, npages);
+		if (IS_ERR(obj))
+			break;
+
+		/* tie the handle to the drm_file for easy reaping */
+		err = drm_gem_handle_create(file, &obj->base, &ignored);
+		if (err) {
+			i915_gem_object_put(obj);
+			break;
+		}
+
+		err = cpu_fill(obj, 0xdeadbeef);
+		if (!err)
+			err = gpu_fill(obj, ctx);
+		if (err) {
+			pr_err("Failed to fill object, err=%d\n", err);
+			break;
+		}
+
+		list_add_tail(&obj->batch_pool_link, &objects);
+		count++;
+	}
+	pr_info("Submitted %d contexts\n", count);
+
+	count = 0;
+	list_for_each_entry(obj, &objects, batch_pool_link) {
+		if (!err)
+			err = cpu_check(obj, count);
+		count++;
+	}
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	fake_file_free(i915, file);
+	return err;
+}
+
+int i915_gem_context_live_selftests(struct drm_i915_private *i915)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_ctx_exec),
+	};
+
+	return i915_subtests(tests, i915);
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
index 94517ad6dbd1..0c925f17b445 100644
--- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -14,3 +14,4 @@ selftest(requests, i915_gem_request_live_selftests)
 selftest(object, i915_gem_object_live_selftests)
 selftest(coherency, i915_gem_coherency_live_selftests)
 selftest(gtt, i915_gem_gtt_live_selftests)
+selftest(context, i915_gem_context_live_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 36/37] drm/i915: Initial selftests for exercising eviction
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (34 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 35/37] drm/i915: Live testing for context execution Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 21:09 ` [PATCH 37/37] drm/i915: Add initial selftests for hang detection and resets Chris Wilson
  2017-01-11 22:23 ` ✓ Fi.CI.BAT: success for series starting with [01/37] drm: Provide a driver hook for drm_dev_release() Patchwork
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Very simple tests to just ask eviction to find some free space in a full
GTT and one with some available space.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_evict.c              |   4 +
 drivers/gpu/drm/i915/selftests/i915_gem_evict.c    | 232 +++++++++++++++++++++
 .../gpu/drm/i915/selftests/i915_mock_selftests.h   |   1 +
 3 files changed, 237 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_evict.c

diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index c181b1bb3d2c..609a8fcb48ca 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -387,3 +387,7 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
 
 	return 0;
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/i915_gem_evict.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c
new file mode 100644
index 000000000000..f3730abac5fb
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c
@@ -0,0 +1,232 @@
+/*
+ * 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_selftest.h"
+
+#include "mock_gem_device.h"
+
+static int populate_ggtt(struct drm_i915_private *i915)
+{
+	struct drm_i915_gem_object *obj;
+	u64 size;
+
+	for (size = 0; size < i915->ggtt.base.total; size += PAGE_SIZE) {
+		struct i915_vma *vma;
+
+		obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+		if (IS_ERR(obj))
+			return PTR_ERR(obj);
+
+		vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
+		if (IS_ERR(vma))
+			return PTR_ERR(vma);
+	}
+
+	if (!list_empty(&i915->mm.unbound_list)) {
+		size = 0;
+		list_for_each_entry(obj, &i915->mm.unbound_list, global_link)
+			size++;
+
+		pr_err("Found %lld objects unbound!\n", size);
+		return -EINVAL;
+	}
+
+	if (list_empty(&i915->ggtt.base.inactive_list)) {
+		pr_err("No objects on the GGTT inactive list!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void unpin_ggtt(struct drm_i915_private *i915)
+{
+	struct i915_vma *vma;
+
+	list_for_each_entry(vma, &i915->ggtt.base.inactive_list, vm_link)
+		i915_vma_unpin(vma);
+}
+
+static void cleanup_objects(struct drm_i915_private *i915)
+{
+	struct drm_i915_gem_object *obj, *on;
+
+	list_for_each_entry_safe(obj, on, &i915->mm.unbound_list, global_link)
+		i915_gem_object_put(obj);
+
+	list_for_each_entry_safe(obj, on, &i915->mm.bound_list, global_link)
+		i915_gem_object_put(obj);
+
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	i915_gem_drain_freed_objects(i915);
+
+	mutex_lock(&i915->drm.struct_mutex);
+}
+
+static int igt_evict_something(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	int err;
+
+	err = populate_ggtt(i915);
+	if (err)
+		goto cleanup;
+
+	err = i915_gem_evict_something(&ggtt->base,
+				       PAGE_SIZE, 0, 0,
+				       0, U64_MAX,
+				       0);
+	if (err != -ENOSPC) {
+		pr_err("i915_gem_evict_something failed on a full GGTT with err=%d\n",
+		       err);
+		goto cleanup;
+	}
+
+	unpin_ggtt(i915);
+
+	err = i915_gem_evict_something(&ggtt->base,
+				       PAGE_SIZE, 0, 0,
+				       0, U64_MAX,
+				       0);
+	if (err) {
+		pr_err("i915_gem_evict_something failed on a full GGTT with err=%d\n",
+		       err);
+		goto cleanup;
+	}
+
+cleanup:
+	cleanup_objects(i915);
+	return err;
+}
+
+static int igt_overcommit(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_object *obj;
+	struct i915_vma *vma;
+	int err;
+
+	err = populate_ggtt(i915);
+	if (err)
+		goto cleanup;
+
+	obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(obj)) {
+		err = PTR_ERR(obj);
+		goto cleanup;
+	}
+
+	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
+	if (IS_ERR(vma) && PTR_ERR(vma) != -ENOSPC) {
+		pr_err("Failed to evict+insert, i915_gem_object_ggtt_pin returned err=%d\n", (int)PTR_ERR(vma));
+		err = PTR_ERR(vma);
+		goto cleanup;
+	}
+
+cleanup:
+	cleanup_objects(i915);
+	return err;
+}
+
+static int igt_evict_for_vma(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	struct drm_mm_node target = {
+		.start = 0,
+		.size = 4096,
+	};
+	int err;
+
+	err = populate_ggtt(i915);
+	if (err)
+		goto cleanup;
+
+	err = i915_gem_evict_for_node(&ggtt->base, &target, 0);
+	if (err != -ENOSPC) {
+		pr_err("i915_gem_evict_for_node on a full GGTT returned err=%d\n",
+		       err);
+		goto cleanup;
+	}
+
+	unpin_ggtt(i915);
+
+	err = i915_gem_evict_for_node(&ggtt->base, &target, 0);
+	if (err) {
+		pr_err("i915_gem_evict_for_node returned err=%d\n",
+		       err);
+		goto cleanup;
+	}
+
+cleanup:
+	cleanup_objects(i915);
+	return err;
+}
+
+static int igt_evict_vm(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	int err;
+
+	err = populate_ggtt(i915);
+	if (err)
+		goto cleanup;
+
+	err = i915_gem_evict_vm(&ggtt->base, false);
+	if (err) {
+		pr_err("i915_gem_evict_vm on a full GGTT returned err=%d]\n",
+		       err);
+		goto cleanup;
+	}
+
+cleanup:
+	cleanup_objects(i915);
+	return err;
+}
+
+int i915_gem_evict_mock_selftests(void)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_evict_something),
+		SUBTEST(igt_evict_for_vma),
+		SUBTEST(igt_evict_vm),
+		SUBTEST(igt_overcommit),
+	};
+	struct drm_i915_private *i915;
+	int err;
+
+	i915 = mock_gem_device();
+	if (!i915)
+		return -ENOMEM;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	err = i915_subtests(tests, i915);
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	drm_dev_unref(&i915->drm);
+	return err;
+}
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index b450eab7e6e1..cfbd3f5486ae 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -16,3 +16,4 @@ selftest(requests, i915_gem_request_mock_selftests)
 selftest(objects, i915_gem_object_mock_selftests)
 selftest(dmabuf, i915_gem_dmabuf_mock_selftests)
 selftest(vma, i915_vma_mock_selftests)
+selftest(evict, i915_gem_evict_mock_selftests)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* [PATCH 37/37] drm/i915: Add initial selftests for hang detection and resets
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (35 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 36/37] drm/i915: Initial selftests for exercising eviction Chris Wilson
@ 2017-01-11 21:09 ` Chris Wilson
  2017-01-11 22:23 ` ✓ Fi.CI.BAT: success for series starting with [01/37] drm: Provide a driver hook for drm_dev_release() Patchwork
  37 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-11 21:09 UTC (permalink / raw)
  To: intel-gfx

Check that we can reset the GPU and continue executing from the next
request.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_hangcheck.c             |   4 +
 .../gpu/drm/i915/selftests/i915_live_selftests.h   |   1 +
 drivers/gpu/drm/i915/selftests/intel_hangcheck.c   | 455 +++++++++++++++++++++
 3 files changed, 460 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/selftests/intel_hangcheck.c

diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c
index f05971f5586f..dce742243ba6 100644
--- a/drivers/gpu/drm/i915/intel_hangcheck.c
+++ b/drivers/gpu/drm/i915/intel_hangcheck.c
@@ -480,3 +480,7 @@ void intel_hangcheck_init(struct drm_i915_private *i915)
 	INIT_DELAYED_WORK(&i915->gpu_error.hangcheck_work,
 			  i915_hangcheck_elapsed);
 }
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/intel_hangcheck.c"
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
index 0c925f17b445..e6699c59f244 100644
--- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
@@ -15,3 +15,4 @@ selftest(object, i915_gem_object_live_selftests)
 selftest(coherency, i915_gem_coherency_live_selftests)
 selftest(gtt, i915_gem_gtt_live_selftests)
 selftest(context, i915_gem_context_live_selftests)
+selftest(hangcheck, intel_hangcheck_live_selftests)
diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c
new file mode 100644
index 000000000000..6d2741624f81
--- /dev/null
+++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c
@@ -0,0 +1,455 @@
+/*
+ * 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_selftest.h"
+
+struct hang {
+	struct drm_i915_private *i915;
+	struct drm_i915_gem_object *hws;
+	struct drm_i915_gem_object *obj;
+	u32 *seqno;
+	u32 *batch;
+};
+
+static int hang_init(struct hang *h, struct drm_i915_private *i915)
+{
+	void *vaddr;
+
+	memset(h, 0, sizeof(*h));
+	h->i915 = i915;
+
+	h->hws = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(h->hws))
+		return PTR_ERR(h->hws);
+
+	h->obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+	if (IS_ERR(h->obj)) {
+		i915_gem_object_put(h->obj);
+		return PTR_ERR(h->obj);
+	}
+
+	i915_gem_object_set_cache_level(h->hws, I915_CACHE_LLC);
+	vaddr = i915_gem_object_pin_map(h->hws, I915_MAP_WB);
+	if (IS_ERR(vaddr)) {
+		i915_gem_object_put(h->hws);
+		i915_gem_object_put(h->obj);
+		return PTR_ERR(vaddr);
+	}
+	h->seqno = memset(vaddr, 0xff, PAGE_SIZE);
+
+	vaddr = i915_gem_object_pin_map(h->obj,
+					HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC);
+	if (IS_ERR(vaddr)) {
+		i915_gem_object_unpin_map(h->hws);
+		i915_gem_object_put(h->hws);
+		i915_gem_object_put(h->obj);
+		return PTR_ERR(vaddr);
+	}
+	h->batch = vaddr;
+
+	return 0;
+}
+
+static u64 hws_address(const struct i915_vma *hws,
+		       const struct drm_i915_gem_request *rq)
+{
+	return hws->node.start + offset_in_page(sizeof(u32)*rq->fence.context);
+}
+
+static int emit_recurse_batch(struct hang *h,
+			      struct drm_i915_gem_request *rq)
+{
+	struct drm_i915_private *i915 = h->i915;
+	struct i915_address_space *vm = rq->ctx->ppgtt ? &rq->ctx->ppgtt->base : &i915->ggtt.base;
+	struct i915_vma *hws, *vma;
+	u32 *batch;
+	int err;
+
+	vma = i915_gem_obj_lookup_or_create_vma(h->obj, vm, NULL);
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	hws = i915_gem_obj_lookup_or_create_vma(h->hws, vm, NULL);
+	if (IS_ERR(hws))
+		return PTR_ERR(hws);
+
+	err = i915_vma_pin(vma, 0, 0, PIN_USER);
+	if (err)
+		return err;
+
+	err = i915_vma_pin(hws, 0, 0, PIN_USER);
+	if (err)
+		goto unpin_vma;
+
+	i915_vma_move_to_active(vma, rq, 0);
+	i915_vma_move_to_active(hws, rq, 0);
+
+	batch = h->batch;
+	if (INTEL_GEN(i915) >= 8) {
+		*batch++ = MI_STORE_DWORD_IMM_GEN4;
+		*batch++ = lower_32_bits(hws_address(hws, rq));
+		*batch++ = upper_32_bits(hws_address(hws, rq));
+		*batch++ = rq->fence.seqno;
+		*batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+		*batch++ = lower_32_bits(vma->node.start);
+		*batch++ = upper_32_bits(vma->node.start);
+	} else if (INTEL_GEN(i915) >= 6) {
+		*batch++ = MI_STORE_DWORD_IMM_GEN4;
+		*batch++ = 0;
+		*batch++ = lower_32_bits(hws_address(hws, rq));
+		*batch++ = rq->fence.seqno;
+		*batch++ = MI_BATCH_BUFFER_START | 1 << 8;
+		*batch++ = lower_32_bits(vma->node.start);
+	} else if (INTEL_GEN(i915) >= 4) {
+		*batch++ = MI_STORE_DWORD_IMM_GEN4;
+		*batch++ = 0;
+		*batch++ = lower_32_bits(hws_address(hws, rq));
+		*batch++ = rq->fence.seqno;
+		*batch++ = MI_BATCH_BUFFER_START | 2 << 6;
+		*batch++ = lower_32_bits(vma->node.start);
+	} else {
+		*batch++ = MI_STORE_DWORD_IMM;
+		*batch++ = lower_32_bits(hws_address(hws, rq));
+		*batch++ = rq->fence.seqno;
+		*batch++ = MI_BATCH_BUFFER_START | 2 << 6 | 1;
+		*batch++ = lower_32_bits(vma->node.start);
+	}
+
+	err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0);
+
+	i915_vma_unpin(hws);
+unpin_vma:
+	i915_vma_unpin(vma);
+	return err;
+}
+
+static struct drm_i915_gem_request *
+hang_create_request(struct hang *h,
+		    struct intel_engine_cs *engine,
+		    struct i915_gem_context *ctx)
+{
+	struct drm_i915_gem_request *rq;
+	int err;
+
+	if (i915_gem_object_is_active(h->obj)) {
+		struct drm_i915_gem_object *obj;
+		void *vaddr;
+
+		obj = i915_gem_object_create_internal(h->i915, PAGE_SIZE);
+		if (IS_ERR(obj))
+			return ERR_CAST(obj);
+
+		vaddr = i915_gem_object_pin_map(obj,
+						HAS_LLC(h->i915) ? I915_MAP_WB : I915_MAP_WC);
+		if (IS_ERR(vaddr)) {
+			i915_gem_object_put(obj);
+			return ERR_CAST(vaddr);
+		}
+
+		i915_gem_object_unpin_map(h->obj);
+		__i915_gem_object_release_unless_active(h->obj);
+
+		h->obj = obj;
+		h->batch = vaddr;
+	}
+
+	rq = i915_gem_request_alloc(engine, ctx);
+	if (IS_ERR(rq))
+		return rq;
+
+	err = emit_recurse_batch(h, rq);
+	if (err) {
+		__i915_add_request(rq, false);
+		return ERR_PTR(err);
+	}
+
+	return rq;
+}
+
+static u32 hws_seqno(const struct hang *h,
+		     const struct drm_i915_gem_request *rq)
+{
+	return READ_ONCE(h->seqno[rq->fence.context % (PAGE_SIZE/sizeof(u32))]);
+}
+
+static void hang_fini(struct hang *h)
+{
+	*h->batch = MI_BATCH_BUFFER_END;
+
+	i915_gem_object_unpin_map(h->obj);
+	__i915_gem_object_release_unless_active(h->obj);
+
+	i915_gem_object_unpin_map(h->hws);
+	__i915_gem_object_release_unless_active(h->hws);
+}
+
+static int igt_hang_sanitycheck(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_request *rq;
+	struct hang h;
+	int err;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	err = hang_init(&h, i915);
+	if (err)
+		goto unlock;
+
+	rq = hang_create_request(&h, i915->engine[RCS], i915->kernel_context);
+	if (IS_ERR(rq)) {
+		err = PTR_ERR(rq);
+		goto fini;
+	}
+
+	i915_gem_request_get(rq);
+
+	*h.batch = MI_BATCH_BUFFER_END;
+	__i915_add_request(rq, true);
+
+	i915_wait_request(rq, I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT);
+	i915_gem_request_put(rq);
+
+fini:
+	hang_fini(&h);
+unlock:
+	mutex_unlock(&i915->drm.struct_mutex);
+	return err;
+}
+
+static int igt_global_reset(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	unsigned int reset_count;
+	int err = 0;
+
+	if (!intel_has_gpu_reset(i915))
+		return 0;
+
+	set_bit(I915_RESET_IN_PROGRESS, &i915->gpu_error.flags);
+
+	mutex_lock(&i915->drm.struct_mutex);
+	reset_count = i915_reset_count(&i915->gpu_error);
+
+	i915_reset(i915);
+
+	if (i915_reset_count(&i915->gpu_error) == reset_count) {
+		pr_err("No GPU reset recorded!\n");
+		err = -EINVAL;
+	}
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	GEM_BUG_ON(test_bit(I915_RESET_IN_PROGRESS, &i915->gpu_error.flags));
+	if (i915_terminally_wedged(&i915->gpu_error))
+		err = -EIO;
+
+	return err;
+}
+
+static u32 fake_hangcheck(struct drm_i915_gem_request *rq)
+{
+	u32 reset_count;
+
+	rq->engine->hangcheck.stalled = true;
+	rq->engine->hangcheck.seqno = intel_engine_get_seqno(rq->engine);
+
+	reset_count = i915_reset_count(&rq->i915->gpu_error);
+
+	set_bit(I915_RESET_IN_PROGRESS, &rq->i915->gpu_error.flags);
+	wake_up_all(&rq->i915->gpu_error.wait_queue);
+
+	return reset_count;
+}
+
+static bool wait_for_hang(struct hang *h, struct drm_i915_gem_request *rq)
+{
+	return !(wait_for_us(i915_seqno_passed(hws_seqno(h, rq),
+					       rq->fence.seqno),
+			     10) &&
+		 wait_for(i915_seqno_passed(hws_seqno(h, rq),
+					    rq->fence.seqno),
+			  1000));
+}
+
+static int igt_wait_reset(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_request *rq;
+	unsigned int reset_count;
+	struct hang h;
+	long timeout;
+	int err;
+
+	if (!intel_has_gpu_reset(i915))
+		return 0;
+
+	set_bit(I915_RESET_IN_PROGRESS, &i915->gpu_error.flags);
+
+	mutex_lock(&i915->drm.struct_mutex);
+	err = hang_init(&h, i915);
+	if (err)
+		goto unlock;
+
+	rq = hang_create_request(&h, i915->engine[RCS], i915->kernel_context);
+	if (IS_ERR(rq)) {
+		err = PTR_ERR(rq);
+		goto fini;
+	}
+
+	i915_gem_request_get(rq);
+	__i915_add_request(rq, true);
+
+	if (!wait_for_hang(&h, rq)) {
+		pr_err("Failed to start request %x\n", rq->fence.seqno);
+		err = -EIO;
+		goto fini;
+	}
+
+	reset_count = fake_hangcheck(rq);
+
+	timeout = i915_wait_request(rq, I915_WAIT_LOCKED, 10);
+	if (timeout < 0) {
+		pr_err("i915_wait_request failed on a stuck request: err=%ld\n",
+		       timeout);
+		err = timeout;
+		goto fini;
+	}
+	GEM_BUG_ON(test_bit(I915_RESET_IN_PROGRESS, &i915->gpu_error.flags));
+
+	if (i915_reset_count(&i915->gpu_error) == reset_count) {
+		pr_err("No GPU reset recorded!\n");
+		err = -EINVAL;
+		goto fini;
+	}
+
+fini:
+	hang_fini(&h);
+unlock:
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	if (i915_terminally_wedged(&i915->gpu_error))
+		return -EIO;
+
+	return err;
+}
+
+static int igt_reset_queue(void *arg)
+{
+	I915_SELFTEST_TIMEOUT(end_time);
+	struct drm_i915_private *i915 = arg;
+	struct drm_i915_gem_request *prev;
+	unsigned int count;
+	struct hang h;
+	int err;
+
+	if (!intel_has_gpu_reset(i915))
+		return 0;
+
+	mutex_lock(&i915->drm.struct_mutex);
+	err = hang_init(&h, i915);
+	if (err)
+		goto unlock;
+
+	prev = hang_create_request(&h, i915->engine[RCS], i915->kernel_context);
+	if (IS_ERR(prev)) {
+		err = PTR_ERR(prev);
+		goto fini;
+	}
+
+	i915_gem_request_get(prev);
+	__i915_add_request(prev, true);
+
+	count = 0;
+	do {
+		struct drm_i915_gem_request *rq;
+		unsigned int reset_count;
+
+		rq = hang_create_request(&h, i915->engine[RCS], i915->kernel_context);
+		if (IS_ERR(rq)) {
+			err = PTR_ERR(rq);
+			goto fini;
+		}
+
+		i915_gem_request_get(rq);
+		__i915_add_request(rq, true);
+
+		if (!wait_for_hang(&h, prev)) {
+			pr_err("Failed to start request %x\n",
+			       prev->fence.seqno);
+			err = -EIO;
+			goto fini;
+		}
+
+		reset_count = fake_hangcheck(prev);
+
+		i915_reset(i915);
+
+		GEM_BUG_ON(test_bit(I915_RESET_IN_PROGRESS, &i915->gpu_error.flags));
+		if (prev->fence.error != -EIO) {
+			pr_err("GPU reset not recorded on hanging request [fence.error=%d]!\n",
+			       prev->fence.error);
+			err = -EINVAL;
+			goto fini;
+		}
+
+		if (rq->fence.error) {
+			pr_err("Fence error status not zero [%d] after unrelated reset\n",
+			       rq->fence.error);
+			err = -EINVAL;
+			goto fini;
+		}
+
+		if (i915_reset_count(&i915->gpu_error) == reset_count) {
+			pr_err("No GPU reset recorded!\n");
+			err = -EINVAL;
+			goto fini;
+		}
+
+		i915_gem_request_put(prev);
+		prev = rq;
+		count++;
+	} while (time_before(jiffies, end_time));
+	pr_info("Completed %d resets\n", count);
+	i915_gem_request_put(prev);
+
+fini:
+	hang_fini(&h);
+unlock:
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	if (i915_terminally_wedged(&i915->gpu_error))
+		return -EIO;
+
+	return err;
+}
+
+int intel_hangcheck_live_selftests(struct drm_i915_private *i915)
+{
+	static const struct i915_subtest tests[] = {
+		SUBTEST(igt_hang_sanitycheck),
+		SUBTEST(igt_global_reset),
+		SUBTEST(igt_wait_reset),
+		SUBTEST(igt_reset_queue),
+	};
+	return i915_subtests(tests, i915);
+}
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 81+ messages in thread

* ✓ Fi.CI.BAT: success for series starting with [01/37] drm: Provide a driver hook for drm_dev_release()
  2017-01-11 21:09 Selftests Chris Wilson
                   ` (36 preceding siblings ...)
  2017-01-11 21:09 ` [PATCH 37/37] drm/i915: Add initial selftests for hang detection and resets Chris Wilson
@ 2017-01-11 22:23 ` Patchwork
  37 siblings, 0 replies; 81+ messages in thread
From: Patchwork @ 2017-01-11 22:23 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

Series: series starting with [01/37] drm: Provide a driver hook for drm_dev_release()
URL   : https://patchwork.freedesktop.org/series/17852/
State : success

== Summary ==

Series 17852v1 Series without cover letter
https://patchwork.freedesktop.org/api/1.0/series/17852/revisions/1/mbox/


fi-bdw-5557u     total:246  pass:232  dwarn:0   dfail:0   fail:0   skip:14 
fi-bsw-n3050     total:246  pass:207  dwarn:0   dfail:0   fail:0   skip:39 
fi-bxt-j4205     total:246  pass:224  dwarn:0   dfail:0   fail:0   skip:22 
fi-bxt-t5700     total:82   pass:69   dwarn:0   dfail:0   fail:0   skip:12 
fi-byt-j1900     total:246  pass:219  dwarn:0   dfail:0   fail:0   skip:27 
fi-byt-n2820     total:246  pass:215  dwarn:0   dfail:0   fail:0   skip:31 
fi-hsw-4770      total:246  pass:227  dwarn:0   dfail:0   fail:0   skip:19 
fi-hsw-4770r     total:246  pass:227  dwarn:0   dfail:0   fail:0   skip:19 
fi-ivb-3520m     total:246  pass:225  dwarn:0   dfail:0   fail:0   skip:21 
fi-ivb-3770      total:246  pass:225  dwarn:0   dfail:0   fail:0   skip:21 
fi-kbl-7500u     total:246  pass:225  dwarn:0   dfail:0   fail:0   skip:21 
fi-skl-6260u     total:246  pass:233  dwarn:0   dfail:0   fail:0   skip:13 
fi-skl-6700hq    total:246  pass:226  dwarn:0   dfail:0   fail:0   skip:20 
fi-skl-6700k     total:246  pass:222  dwarn:3   dfail:0   fail:0   skip:21 
fi-skl-6770hq    total:246  pass:233  dwarn:0   dfail:0   fail:0   skip:13 
fi-snb-2520m     total:246  pass:215  dwarn:0   dfail:0   fail:0   skip:31 
fi-snb-2600      total:246  pass:214  dwarn:0   dfail:0   fail:0   skip:32 

60f8884d35facd41e1b085a19444205ec13a5da0 drm-tip: 2017y-01m-11d-20h-53m-23s UTC integration manifest
5ec6412 drm/i915: Mock the GEM device for self-testing
27489f4 drm/i915: Add unit tests for the breadcrumb rbtree, wakeups
df115da drm/i915: Add unit tests for the breadcrumb rbtree, completion
e571095 drm/i915: Add unit tests for the breadcrumb rbtree, insert/remove
0af4db2 drm/i915: Add some selftests for sg_table manipulation
ab6bcab drm/i915: Provide a hook for selftests
ff83217 drm: Provide a driver hook for drm_dev_release()

== Logs ==

For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_3490/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 02/37] drm/i915: Provide a hook for selftests
  2017-01-11 21:09 ` [PATCH 02/37] drm/i915: Provide a hook for selftests Chris Wilson
@ 2017-01-12  7:29   ` Tvrtko Ursulin
  2017-01-12  7:40     ` Chris Wilson
  2017-01-13  8:31   ` Chris Wilson
  1 sibling, 1 reply; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12  7:29 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> 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 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.igt__ is interpreted as a subtest executable independently via
> igt/drv_selftest.
>
> Two classes of selftests are recognised: mock unit tests and integration
> tests. Mock unit tests are run as soon as the module is loaded, before
> the device is probed. At that point there is no driver instantiated and
> all hw interactions must be "mocked". This is very useful for writing
> universal tests to exercise code not typically run on a broad range of
> architectures. Alternatively, you can hook into the live selftests and
> run when the device has been instantiated - hw interactions are real.
>
> v2: Add a macro for compiling conditional code for mock objects inside
> real objects.
> v3: Differentiate between mock unit tests and late integration test.
> v4: List the tests in natural order, use igt to sort after modparam.
> v5: s/late/live/
> v6: s/unsigned long/unsigned int/
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> #v1
> ---
>  drivers/gpu/drm/i915/Kconfig.debug                 |  16 ++
>  drivers/gpu/drm/i915/Makefile                      |   3 +
>  drivers/gpu/drm/i915/i915_pci.c                    |  19 +-
>  drivers/gpu/drm/i915/i915_selftest.h               |  91 +++++++++
>  .../gpu/drm/i915/selftests/i915_live_selftests.h   |  11 +
>  .../gpu/drm/i915/selftests/i915_mock_selftests.h   |  11 +
>  drivers/gpu/drm/i915/selftests/i915_selftest.c     | 226 +++++++++++++++++++++
>  tools/testing/selftests/drivers/gpu/i915.sh        |   1 +
>  8 files changed, 377 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/i915/i915_selftest.h
>  create mode 100644 drivers/gpu/drm/i915/selftests/i915_live_selftests.h
>  create mode 100644 drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
>  create mode 100644 drivers/gpu/drm/i915/selftests/i915_selftest.c
>
> diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
> index 598551dbf62c..a4d8cfd77c3c 100644
> --- a/drivers/gpu/drm/i915/Kconfig.debug
> +++ b/drivers/gpu/drm/i915/Kconfig.debug
> @@ -26,6 +26,7 @@ config DRM_I915_DEBUG
>          select DRM_DEBUG_MM if DRM=y
>  	select DRM_DEBUG_MM_SELFTEST
>  	select DRM_I915_SW_FENCE_DEBUG_OBJECTS
> +	select DRM_I915_SELFTEST
>          default n
>          help
>            Choose this option to turn on extra driver debugging that may affect
> @@ -59,3 +60,18 @@ 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
> +	select PRIME_NUMBERS
> +	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".
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 5196509e71cf..c9d1554de35d 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -3,6 +3,7 @@
>  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
>
>  subdir-ccflags-$(CONFIG_DRM_I915_WERROR) := -Werror
> +subdir-ccflags-$(CONFIG_DRM_I915_SELFTEST) += -I$(src) -I$(src)/selftests
>  subdir-ccflags-y += \
>  	$(call as-instr,movntdqa (%eax)$(comma)%xmm0,-DCONFIG_AS_MOVNTDQA)
>
> @@ -114,6 +115,8 @@ 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) += \
> +	selftests/i915_selftest.o
>
>  # virtual gpu code
>  i915-y += i915_vgpu.o
> diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
> index ecb487b5356f..b3bf9474f081 100644
> --- a/drivers/gpu/drm/i915/i915_pci.c
> +++ b/drivers/gpu/drm/i915/i915_pci.c
> @@ -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, \
> @@ -476,6 +477,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  {
>  	struct intel_device_info *intel_info =
>  		(struct intel_device_info *) ent->driver_data;
> +	int err;
>
>  	if (IS_ALPHA_SUPPORT(intel_info) && !i915.alpha_support) {
>  		DRM_INFO("The driver support for your hardware in this kernel version is alpha quality\n"
> @@ -499,7 +501,17 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  	if (vga_switcheroo_client_probe_defer(pdev))
>  		return -EPROBE_DEFER;
>
> -	return i915_driver_load(pdev, ent);
> +	err = i915_driver_load(pdev, ent);
> +	if (err)
> +		return err;
> +
> +	err = i915_live_selftests(pdev);
> +	if (err) {
> +		i915_driver_unload(pci_get_drvdata(pdev));
> +		return err > 0 ? -ENOTTY : err;
> +	}
> +
> +	return 0;
>  }
>
>  static void i915_pci_remove(struct pci_dev *pdev)
> @@ -521,6 +533,11 @@ static struct pci_driver i915_pci_driver = {
>  static int __init i915_init(void)
>  {
>  	bool use_kms = true;
> +	int err;
> +
> +	err = i915_mock_selftests();
> +	if (err)
> +		return err > 0 ? 0 : err;
>
>  	/*
>  	 * Enable KMS by default, unless explicitly overriden by
> diff --git a/drivers/gpu/drm/i915/i915_selftest.h b/drivers/gpu/drm/i915/i915_selftest.h
> new file mode 100644
> index 000000000000..4ec96cac2203
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/i915_selftest.h
> @@ -0,0 +1,91 @@
> +/*
> + * 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__
> +
> +struct pci_dev;
> +struct drm_i915_private;
> +
> +struct i915_selftest {
> +	unsigned long timeout_jiffies;
> +	unsigned int timeout_ms;
> +	unsigned int random_seed;
> +	int mock;
> +	int live;
> +};
> +
> +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> +extern struct i915_selftest i915_selftest;
> +
> +int i915_mock_selftests(void);
> +int i915_live_selftests(struct pci_dev *pdev);
> +
> +/* We extract the function declarations from i915_mock_selftests.h and
> + * i915_live_selftests.h Add your unit test declarations there!
> + *
> + * Mock unit tests are run very early upon module load, before the driver
> + * is probed. All hardware interactions, as well as other subsystems, must
> + * be "mocked".
> + *
> + * Live unit tests are run after the driver is loaded - all hardware
> + * interactions are real.
> + */
> +#define selftest(name, func) int func(void);
> +#include "i915_mock_selftests.h"
> +#undef selftest
> +#define selftest(name, func) int func(struct drm_i915_private *i915);
> +#include "i915_live_selftests.h"
> +#undef selftest
> +
> +struct i915_subtest {
> +	int (*func)(void *data);
> +	const char *name;
> +};
> +
> +int __i915_subtests(const char *caller,
> +		    const struct i915_subtest *st,
> +		    unsigned int count,
> +		    void *data);
> +#define i915_subtests(T, data) \
> +	__i915_subtests(__func__, T, ARRAY_SIZE(T), data)
> +
> +#define SUBTEST(x) { x, #x }
> +
> +#define I915_SELFTEST_DECLARE(x) x
> +#define I915_SELFTEST_ONLY(x) unlikely(x)
> +
> +#else /* !IS_ENABLED(CONFIG_DRM_I915_SELFTEST) */
> +
> +static inline int i915_mock_selftests(void) { return 0; }
> +static inline int i915_live_selftests(struct pci_dev *pdev) { return 0; }
> +
> +#define I915_SELFTEST_DECLARE(x)
> +#define I915_SELFTEST_ONLY(x) 0
> +
> +#endif
> +
> +#define I915_SELFTEST_TIMEOUT(name__) \
> +	unsigned long name__ = jiffies + i915_selftest.timeout_jiffies
> +
> +#endif /* !__I915_SELFTEST_H__ */
> diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
> new file mode 100644
> index 000000000000..f3e17cb10e05
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
> @@ -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 order by igt/drv_selftest
> + */
> +selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
> diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> new file mode 100644
> index 000000000000..69e97a2ba4a6
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> @@ -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 order by igt/drv_selftest
> + */
> +selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
> diff --git a/drivers/gpu/drm/i915/selftests/i915_selftest.c b/drivers/gpu/drm/i915/selftests/i915_selftest.c
> new file mode 100644
> index 000000000000..66928eead3a9
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/i915_selftest.c
> @@ -0,0 +1,226 @@
> +/*
> + * 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 <linux/random.h>
> +
> +#include "i915_drv.h"
> +#include "i915_selftest.h"
> +
> +struct i915_selftest i915_selftest __read_mostly = {
> +	.timeout_ms = 1000,
> +};
> +
> +int i915_mock_sanitycheck(void)
> +{
> +	pr_info("i915: %s() - ok!\n", __func__);
> +	return 0;
> +}
> +
> +int i915_live_sanitycheck(struct drm_i915_private *i915)
> +{
> +	pr_info("%s: %s() - ok!\n", i915->drm.driver->name, __func__);
> +	return 0;
> +}
> +
> +enum {
> +#define selftest(name, func) mock_##name,
> +#include "i915_mock_selftests.h"
> +#undef selftest
> +};
> +enum {
> +#define selftest(name, func) live_##name,
> +#include "i915_live_selftests.h"
> +#undef selftest
> +};
> +
> +struct selftest {
> +	bool enabled;
> +	const char *name;
> +	union {
> +		int (*mock)(void);
> +		int (*live)(struct drm_i915_private *);
> +	};
> +};
> +
> +#define selftest(n, f) [mock_##n] = { .name = #n, .mock = f },
> +static struct selftest mock_selftests[] = {
> +#include "i915_mock_selftests.h"
> +};
> +#undef selftest
> +
> +#define selftest(n, f) [live_##n] = { .name = #n, .live = f },
> +static struct selftest live_selftests[] = {
> +#include "i915_live_selftests.h"
> +};
> +#undef selftest
> +
> +/* Embed the line number into the parameter name so that we can order tests */
> +#define selftest(n, func) selftest_0(n, func, param(n))
> +#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), mock_##n))
> +#define selftest_0(n, func, id) \
> +module_param_named(id, mock_selftests[mock_##n].enabled, bool, 0400);
> +#include "i915_mock_selftests.h"
> +#undef selftest_0
> +#undef param
> +
> +#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), live_##n))
> +#define selftest_0(n, func, id) \
> +module_param_named(id, live_selftests[live_##n].enabled, bool, 0400);
> +#include "i915_live_selftests.h"
> +#undef selftest_0
> +#undef param
> +#undef selftest
> +
> +static void set_default_test_all(struct selftest *st, unsigned int count)
> +{
> +	unsigned int 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(const char *name,
> +			 struct selftest *st,
> +			 unsigned int count,
> +			 void *data)
> +{
> +	int err = 0;
> +
> +	while (!i915_selftest.random_seed)
> +		i915_selftest.random_seed = get_random_int();
> +
> +	i915_selftest.timeout_jiffies =
> +		i915_selftest.timeout_ms ?
> +		msecs_to_jiffies_timeout(i915_selftest.timeout_ms) :
> +		MAX_SCHEDULE_TIMEOUT;
> +
> +	set_default_test_all(st, count);
> +
> +	pr_info("i915: Performing %s selftests with st_random_seed=0x%x st_timeout=%u\n",
> +		name, i915_selftest.random_seed, i915_selftest.timeout_ms);
> +
> +	/* Tests are listed in order in i915_*_selftests.h */
> +	for (; count--; st++) {
> +		if (!st->enabled)
> +			continue;
> +
> +		cond_resched();
> +		if (signal_pending(current))
> +			return -EINTR;
> +
> +		pr_debug("i915: Running %s\n", st->name);
> +		if (data)
> +			err = st->live(data);
> +		else
> +			err = st->mock();
> +		if (err)
> +			break;
> +	}
> +
> +	if (WARN(err > 0 || err == -ENOTTY,
> +		 "%s returned %d, conflicting with selftest's magic values!\n",
> +		 st->name, err))
> +		err = -1;
> +
> +	rcu_barrier();
> +	return err;
> +}
> +
> +#define run_selftests(x, data) \
> +	(run_selftests)(#x, x##_selftests, ARRAY_SIZE(x##_selftests), data)
> +
> +int i915_mock_selftests(void)
> +{
> +	int err;
> +
> +	if (!i915_selftest.mock)
> +		return 0;
> +
> +	err = run_selftests(mock, NULL);
> +	if (err)
> +		return err;
> +
> +	if (i915_selftest.mock < 0)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +int i915_live_selftests(struct pci_dev *pdev)
> +{
> +	int err;
> +
> +	if (!i915_selftest.live)
> +		return 0;
> +
> +	err = run_selftests(live, to_i915(pci_get_drvdata(pdev)));
> +	if (err) {
> +		i915_selftest.live = err;
> +		return err;
> +	}
> +
> +	if (i915_selftest.live < 0) {
> +		i915_selftest.live = -ENOTTY;
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int __i915_subtests(const char *caller,
> +		    const struct i915_subtest *st,
> +		    unsigned int count,
> +		    void *data)
> +{
> +	int err;
> +
> +	for (; count--; st++) {
> +		cond_resched();
> +		if (signal_pending(current))
> +			return -EINTR;
> +
> +		pr_debug("i915: Running %s/%s\n", caller, st->name);
> +		err = st->func(data);
> +		if (err) {
> +			if (err != -EINTR)
> +				pr_err("i915/%s: %s failed with error %d\n",
> +				       caller, st->name, err);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +module_param_named(st_random_seed, i915_selftest.random_seed, uint, 0400);
> +module_param_named(st_timeout, i915_selftest.timeout_ms, uint, 0400);
> +
> +module_param_named_unsafe(mock_selftests, i915_selftest.mock, int, 0400);
> +MODULE_PARM_DESC(mock_selftests, "Run selftests before loading, using mock hardware (0:disabled [default], 1:run tests then load driver, -1:run tests then exit module)");
> +
> +module_param_named_unsafe(live_selftests, i915_selftest.live, int, 0400);
> +MODULE_PARM_DESC(live_selftests, "Run selftests after driver initialisation on the live system (0:disabled [default], 1:run tests then continue, -1:run tests then exit module)");
> diff --git a/tools/testing/selftests/drivers/gpu/i915.sh b/tools/testing/selftests/drivers/gpu/i915.sh
> index d407f0fa1e3a..c06d6e8a8dcc 100755
> --- a/tools/testing/selftests/drivers/gpu/i915.sh
> +++ b/tools/testing/selftests/drivers/gpu/i915.sh
> @@ -7,6 +7,7 @@ if ! /sbin/modprobe -q -r i915; then
>  fi
>
>  if /sbin/modprobe -q i915 mock_selftests=-1; then
> +	/sbin/modprobe -q -r i915
>  	echo "drivers/gpu/i915: ok"
>  else
>  	echo "drivers/gpu/i915: [FAIL]"
>

Oh, how did the last bit happen?

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 02/37] drm/i915: Provide a hook for selftests
  2017-01-12  7:29   ` Tvrtko Ursulin
@ 2017-01-12  7:40     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-12  7:40 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx

On Thu, Jan 12, 2017 at 07:29:59AM +0000, Tvrtko Ursulin wrote:
> 
> On 11/01/2017 21:09, Chris Wilson wrote:
> >diff --git a/tools/testing/selftests/drivers/gpu/i915.sh b/tools/testing/selftests/drivers/gpu/i915.sh
> >index d407f0fa1e3a..c06d6e8a8dcc 100755
> >--- a/tools/testing/selftests/drivers/gpu/i915.sh
> >+++ b/tools/testing/selftests/drivers/gpu/i915.sh
> >@@ -7,6 +7,7 @@ if ! /sbin/modprobe -q -r i915; then
> > fi
> >
> > if /sbin/modprobe -q i915 mock_selftests=-1; then
> >+	/sbin/modprobe -q -r i915
> > 	echo "drivers/gpu/i915: ok"
> > else
> > 	echo "drivers/gpu/i915: [FAIL]"
> >
> 
> Oh, how did the last bit happen?

Since the backmerge around Christmas the kselftest.sh was upstreamed
(after RCFv2) and so I squashed in the fixup I had.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 10/37] drm/i915: Create a fake object for testing huge allocations
  2017-01-11 21:09 ` [PATCH 10/37] drm/i915: Create a fake object for testing huge allocations Chris Wilson
@ 2017-01-12 10:56   ` Matthew Auld
  0 siblings, 0 replies; 81+ messages in thread
From: Matthew Auld @ 2017-01-12 10:56 UTC (permalink / raw)
  To: Chris Wilson; +Cc: Intel Graphics Development

On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> We would like to be able to exercise huge allocations even on memory
> constrained devices. To do this we create an object that allocates only
> a few pages and remaps them across its whole range - each page is reused
> multiple times. We can therefore pretend we are rendering into a much
> larger object.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 03/37] drm/i915: Add some selftests for sg_table manipulation
  2017-01-11 21:09 ` [PATCH 03/37] drm/i915: Add some selftests for sg_table manipulation Chris Wilson
@ 2017-01-12 10:56   ` Tvrtko Ursulin
  2017-01-12 11:14     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12 10:56 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> Start exercising the scattergather lists, especially looking at
> iteration after coalescing.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_gem.c                    |  11 +-
>  .../gpu/drm/i915/selftests/i915_mock_selftests.h   |   1 +
>  drivers/gpu/drm/i915/selftests/scatterlist.c       | 255 +++++++++++++++++++++
>  3 files changed, 264 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/selftests/scatterlist.c
>
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 4c6d40e28cf5..e88541b5b72b 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2219,17 +2219,17 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
>  	mutex_unlock(&obj->mm.lock);
>  }
>
> -static void i915_sg_trim(struct sg_table *orig_st)
> +static bool i915_sg_trim(struct sg_table *orig_st)
>  {
>  	struct sg_table new_st;
>  	struct scatterlist *sg, *new_sg;
>  	unsigned int i;
>
>  	if (orig_st->nents == orig_st->orig_nents)
> -		return;
> +		return false;
>
>  	if (sg_alloc_table(&new_st, orig_st->nents, GFP_KERNEL | __GFP_NOWARN))
> -		return;
> +		return false;
>
>  	new_sg = new_st.sgl;
>  	for_each_sg(orig_st->sgl, sg, orig_st->nents, i) {
> @@ -2242,6 +2242,7 @@ static void i915_sg_trim(struct sg_table *orig_st)
>  	sg_free_table(orig_st);
>
>  	*orig_st = new_st;
> +	return true;
>  }
>
>  static struct sg_table *
> @@ -4892,3 +4893,7 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
>  	sg = i915_gem_object_get_sg(obj, n, &offset);
>  	return sg_dma_address(sg) + (offset << PAGE_SHIFT);
>  }
> +
> +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> +#include "selftests/scatterlist.c"
> +#endif
> diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> index 69e97a2ba4a6..5f0bdda42ed8 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> @@ -9,3 +9,4 @@
>   * Tests are executed in order by igt/drv_selftest
>   */
>  selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
> +selftest(scatterlist, scatterlist_mock_selftests)
> diff --git a/drivers/gpu/drm/i915/selftests/scatterlist.c b/drivers/gpu/drm/i915/selftests/scatterlist.c
> new file mode 100644
> index 000000000000..1573be8961bf
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/scatterlist.c
> @@ -0,0 +1,255 @@
> +/*
> + * 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 <linux/prime_numbers.h>
> +
> +#include "i915_selftest.h"
> +
> +#define PFN_BIAS (1 << 10)
> +
> +struct pfn_table {
> +	struct sg_table st;
> +	unsigned long start, end;
> +};
> +
> +static noinline int expect_pfn_sg(struct pfn_table *pt, const char *who)
> +{
> +	struct scatterlist *sg;
> +	unsigned long pfn, n;
> +
> +	pfn = pt->start;
> +	for_each_sg(pt->st.sgl, sg, pt->st.nents, n) {
> +		struct page *page = sg_page(sg);
> +
> +		if (page_to_pfn(page) != pfn) {
> +			pr_err("%s left pages out of order, expected pfn %lu, found pfn %lu (using for_each_sg)\n",
> +			       who, pfn, page_to_pfn(page));
> +			return -EINVAL;
> +		}
> +
> +		if (sg->length != (n + 1) * PAGE_SIZE) {
> +			pr_err("%s: %s copied wrong sg length, expected size %lu, found %u (using for_each_sg)\n",
> +			       __func__, who, (n + 1) * PAGE_SIZE, sg->length);
> +			return -EINVAL;
> +		}
> +
> +		cond_resched();
> +		if (signal_pending(current))
> +			return -EINTR;
> +
> +		pfn += n + 1;
> +	}
> +	if (pfn != pt->end) {
> +		pr_err("%s: %s finished on wrong pfn, expected %lu, found %lu\n",
> +		       __func__, who, pt->end, pfn);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static noinline int expect_pfn_sg_page_iter(struct pfn_table *pt, const char *who)
> +{
> +	struct sg_page_iter sgiter;
> +	unsigned long pfn;
> +
> +	pfn = pt->start;
> +	for_each_sg_page(pt->st.sgl, &sgiter, pt->st.nents, 0) {
> +		struct page *page = sg_page_iter_page(&sgiter);
> +
> +		if (page != pfn_to_page(pfn)) {
> +			pr_err("%s: %s left pages out of order, expected pfn %lu, found pfn %lu (using for_each_sg_page)\n",
> +			       __func__, who, pfn, page_to_pfn(page));
> +			return -EINVAL;
> +		}
> +
> +		cond_resched();
> +		if (signal_pending(current))
> +			return -EINTR;
> +
> +		pfn++;
> +	}
> +	if (pfn != pt->end) {
> +		pr_err("%s: %s finished on wrong pfn, expected %lu, found %lu\n",
> +		       __func__, who, pt->end, pfn);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static noinline int expect_pfn_sgtiter(struct pfn_table *pt, const char *who)
> +{
> +	struct sgt_iter sgt;
> +	struct page *page;
> +	unsigned long pfn;
> +
> +	pfn = pt->start;
> +	for_each_sgt_page(page, sgt, &pt->st) {
> +		if (page != pfn_to_page(pfn)) {
> +			pr_err("%s: %s left pages out of order, expected pfn %lu, found pfn %lu (using for_each_sgt_page)\n",
> +			       __func__, who, pfn, page_to_pfn(page));
> +			return -EINVAL;
> +		}
> +
> +		cond_resched();
> +		if (signal_pending(current))
> +			return -EINTR;
> +
> +		pfn++;
> +	}
> +	if (pfn != pt->end) {
> +		pr_err("%s: %s finished on wrong pfn, expected %lu, found %lu\n",
> +		       __func__, who, pt->end, pfn);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int expect_pfn_sgtable(struct pfn_table *pt, const char *who)
> +{
> +	int err;
> +
> +	err = expect_pfn_sg(pt, who);
> +	if (err)
> +		return err;
> +
> +	err = expect_pfn_sg_page_iter(pt, who);
> +	if (err)
> +		return err;
> +
> +	err = expect_pfn_sgtiter(pt, who);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static bool alloc_table(struct pfn_table *pt,
> +			unsigned long count,
> +			unsigned long max)
> +{
> +	struct scatterlist *sg;
> +	unsigned long n, pfn;
> +
> +	if (sg_alloc_table(&pt->st, max,
> +			   GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN))
> +		return false;
> +
> +	pt->start = PFN_BIAS;
> +	pfn = pt->start;
> +	sg = pt->st.sgl;
> +	for (n = 0; n < count; n++) {
> +		if (n)
> +			sg = sg_next(sg);
> +		sg_set_page(sg, pfn_to_page(pfn), (n + 1)*PAGE_SIZE, 0);

For count = BIT(max_order) (== 1M) the last sg entry will have a size of 
4GiB which would overflow sg->length, no? Especially with size + offset 
below. Unless for_each_prime_number stops below max_order. But where?

> +		pfn += n + 1;

Please describe what kind of table and why you are building with a 
comment. If tests have no comments and do, on the first look, not fully 
obvious things, then it is a lot of effort in the future to work on 
fixes and/or maintain the code.

> +	}
> +	sg_mark_end(sg);
> +	pt->st.nents = n;
> +	pt->end = pfn;
> +
> +	return true;
> +}
> +
> +static int igt_sg_alloc(void *ignored)
> +{
> +	I915_SELFTEST_TIMEOUT(end_time);
> +	const unsigned long max_order = 20; /* approximating a 4GiB object */
> +	unsigned long prime;
> +
> +	for_each_prime_number(prime, max_order) {
> +		unsigned long size = BIT(prime);
> +		int offset;
> +
> +		for (offset = -1; offset <= 1; offset++) {
> +			struct pfn_table pt;
> +			int err;
> +
> +			if (!alloc_table(&pt, size + offset, size + offset))
> +				return 0; /* out of memory, give up */
> +
> +			err = expect_pfn_sgtable(&pt, "sg_alloc_table");
> +			sg_free_table(&pt.st);
> +			if (err)
> +				return err;
> +
> +			if (time_after(jiffies, end_time)) {
> +				pr_warn("%s timed out: last table size %lu\n",
> +					__func__, size + offset);
> +				return 0;
> +			}

Maybe a fmt+vaarg timeout helper since I expect there'll be a lot of 
this. Like:

if (i915_selftest_timeout(end_time, "fmt %s", arg))
	return 0;

It is slightly tidier.

> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int igt_sg_trim(void *ignored)
> +{
> +	I915_SELFTEST_TIMEOUT(end_time);
> +	const unsigned long max = PAGE_SIZE; /* not prime! */
> +	struct pfn_table pt;
> +	unsigned long prime;
> +
> +	for_each_prime_number(prime, max) {
> +		int err;
> +
> +		if (!alloc_table(&pt, prime, max))
> +			return 0; /* out of memory, give up */
> +
> +		err = 0;
> +		if (i915_sg_trim(&pt.st)) {
> +			if (pt.st.orig_nents != prime ||
> +			    pt.st.nents != prime) {
> +				pr_err("i915_sg_trim failed (nents %u, orig_nents %u), expected %lu\n",
> +				       pt.st.nents, pt.st.orig_nents, prime);
> +				err = -EINVAL;
> +			} else {
> +				err = expect_pfn_sgtable(&pt, "i915_sg_trim");
> +			}
> +		}
> +		sg_free_table(&pt.st);
> +		if (err)
> +			return err;
> +
> +		if (time_after(jiffies, end_time)) {
> +			pr_warn("%s timed out: last trim size %lu/%lu\n",
> +				__func__, prime, max);
> +			return 0;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int scatterlist_mock_selftests(void)
> +{
> +	static const struct i915_subtest tests[] = {
> +		SUBTEST(igt_sg_alloc),
> +		SUBTEST(igt_sg_trim),
> +	};
> +
> +	return i915_subtests(tests, NULL);
> +}
>

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 06/37] drm/i915: Add unit tests for the breadcrumb rbtree, wakeups
  2017-01-11 21:09 ` [PATCH 06/37] drm/i915: Add unit tests for the breadcrumb rbtree, wakeups Chris Wilson
@ 2017-01-12 11:11   ` Tvrtko Ursulin
  2017-01-12 14:37     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12 11:11 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> Third retroactive test, make sure that the seqno waiters are woken.

There are some open questions from the previous round (early December), 
not least of which is that I think we really need good comments in 
tests. Especially ones like this one which is pretty advanced. We need 
an overall description and some commentary on the stages. It is not 
straightforward to reverse engineer this, so doing it every time this 
code will need some attention for one reason or the other will be a PITA.

Regards,

Tvrtko

>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c | 171 +++++++++++++++++++++
>  1 file changed, 171 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
> index e9dff6eee323..bee86470a91d 100644
> --- a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
> +++ b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
> @@ -263,11 +263,182 @@ static int igt_insert_complete(void *arg)
>  	return err;
>  }
>
> +struct igt_wakeup {
> +	struct task_struct *tsk;
> +	atomic_t *ready, *set, *done;
> +	struct intel_engine_cs *engine;
> +	unsigned long flags;
> +	wait_queue_head_t *wq;
> +	u32 seqno;
> +};
> +
> +static int wait_atomic(atomic_t *p)
> +{
> +	schedule();
> +	return 0;
> +}
> +
> +static int wait_atomic_timeout(atomic_t *p)
> +{
> +	return schedule_timeout(10 * HZ) ? 0 : -ETIMEDOUT;
> +}
> +
> +static int igt_wakeup_thread(void *arg)
> +{
> +	struct igt_wakeup *w = arg;
> +	struct intel_wait wait;
> +
> +	while (!kthread_should_stop()) {
> +		DEFINE_WAIT(ready);
> +
> +		for (;;) {
> +			prepare_to_wait(w->wq, &ready, TASK_INTERRUPTIBLE);
> +			if (atomic_read(w->ready) == 0)
> +				break;
> +
> +			schedule();
> +		}
> +		finish_wait(w->wq, &ready);
> +		if (atomic_dec_and_test(w->set))
> +			wake_up_atomic_t(w->set);
> +
> +		if (test_bit(0, &w->flags))
> +			break;
> +
> +		intel_wait_init(&wait, w->seqno);
> +		intel_engine_add_wait(w->engine, &wait);
> +		for (;;) {
> +			set_current_state(TASK_UNINTERRUPTIBLE);
> +			if (i915_seqno_passed(intel_engine_get_seqno(w->engine),
> +					      w->seqno))
> +				break;
> +
> +			schedule();
> +		}
> +		intel_engine_remove_wait(w->engine, &wait);
> +		__set_current_state(TASK_RUNNING);
> +
> +		if (atomic_dec_and_test(w->done))
> +			wake_up_atomic_t(w->done);
> +	}
> +
> +	if (atomic_dec_and_test(w->done))
> +		wake_up_atomic_t(w->done);
> +	return 0;
> +}
> +
> +static void igt_wake_all_sync(atomic_t *ready,
> +			      atomic_t *set,
> +			      atomic_t *done,
> +			      wait_queue_head_t *wq,
> +			      int count)
> +{
> +	atomic_set(set, count);
> +	atomic_set(done, count);
> +
> +	atomic_set(ready, 0);
> +	wake_up_all(wq);
> +
> +	wait_on_atomic_t(set, wait_atomic, TASK_UNINTERRUPTIBLE);
> +	atomic_set(ready, count);
> +}
> +
> +static int igt_wakeup(void *arg)
> +{
> +	const int state = TASK_UNINTERRUPTIBLE;
> +	struct intel_engine_cs *engine = arg;
> +	struct igt_wakeup *waiters;
> +	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
> +	const int count = 4096;
> +	const u32 max_seqno = count / 4;
> +	atomic_t ready, set, done;
> +	int err = -ENOMEM;
> +	int n, step;
> +
> +	mock_engine_reset(engine);
> +
> +	waiters = drm_malloc_gfp(count, sizeof(*waiters), GFP_TEMPORARY);
> +	if (!waiters)
> +		goto out_engines;
> +
> +	/* Create a large number of threads, each waiting on a random seqno.
> +	 * Multiple waiters will be waiting for the same seqno.
> +	 */
> +	atomic_set(&ready, count);
> +	for (n = 0; n < count; n++) {
> +		waiters[n].wq = &wq;
> +		waiters[n].ready = &ready;
> +		waiters[n].set = &set;
> +		waiters[n].done = &done;
> +		waiters[n].engine = engine;
> +		waiters[n].flags = 0;
> +
> +		waiters[n].tsk = kthread_run(igt_wakeup_thread, &waiters[n],
> +					     "i915/igt:%d", n);
> +		if (IS_ERR(waiters[n].tsk))
> +			goto out_waiters;
> +
> +		get_task_struct(waiters[n].tsk);
> +	}
> +
> +	for (step = 1; step <= max_seqno; step <<= 1) {
> +		u32 seqno;
> +
> +		for (n = 0; n < count; n++)
> +			waiters[n].seqno = 1 + get_random_int() % max_seqno;
> +
> +		mock_seqno_advance(engine, 0);
> +		igt_wake_all_sync(&ready, &set, &done, &wq, count);
> +
> +		for (seqno = 1; seqno <= max_seqno + step; seqno += step) {
> +			usleep_range(50, 500);
> +			mock_seqno_advance(engine, seqno);
> +		}
> +		GEM_BUG_ON(intel_engine_get_seqno(engine) < 1 + max_seqno);
> +
> +		err = wait_on_atomic_t(&done, wait_atomic_timeout, state);
> +		if (err) {
> +			pr_err("Timed out waiting for %d remaining waiters\n",
> +			       atomic_read(&done));
> +			break;
> +		}
> +
> +		err = check_rbtree_empty(engine);
> +		if (err)
> +			break;
> +	}
> +
> +out_waiters:
> +	for (n = 0; n < count; n++) {
> +		if (IS_ERR(waiters[n].tsk))
> +			break;
> +
> +		set_bit(0, &waiters[n].flags);
> +	}
> +
> +	igt_wake_all_sync(&ready, &set, &done, &wq, n);
> +	wait_on_atomic_t(&done, wait_atomic, state);
> +
> +	for (n = 0; n < count; n++) {
> +		if (IS_ERR(waiters[n].tsk))
> +			break;
> +
> +		kthread_stop(waiters[n].tsk);
> +		put_task_struct(waiters[n].tsk);
> +	}
> +
> +	drm_free_large(waiters);
> +out_engines:
> +	mock_engine_flush(engine);
> +	return err;
> +}
> +
>  int intel_breadcrumbs_mock_selftests(void)
>  {
>  	static const struct i915_subtest tests[] = {
>  		SUBTEST(igt_random_insert_remove),
>  		SUBTEST(igt_insert_complete),
> +		SUBTEST(igt_wakeup),
>  	};
>  	struct intel_engine_cs *engine;
>  	int err;
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 03/37] drm/i915: Add some selftests for sg_table manipulation
  2017-01-12 10:56   ` Tvrtko Ursulin
@ 2017-01-12 11:14     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-12 11:14 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx

On Thu, Jan 12, 2017 at 10:56:42AM +0000, Tvrtko Ursulin wrote:
> 
> On 11/01/2017 21:09, Chris Wilson wrote:
> >+static bool alloc_table(struct pfn_table *pt,
> >+			unsigned long count,
> >+			unsigned long max)
> >+{
> >+	struct scatterlist *sg;
> >+	unsigned long n, pfn;
> >+
> >+	if (sg_alloc_table(&pt->st, max,
> >+			   GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN))
> >+		return false;
> >+
> >+	pt->start = PFN_BIAS;
> >+	pfn = pt->start;
> >+	sg = pt->st.sgl;
> >+	for (n = 0; n < count; n++) {
> >+		if (n)
> >+			sg = sg_next(sg);
> >+		sg_set_page(sg, pfn_to_page(pfn), (n + 1)*PAGE_SIZE, 0);
> 
> For count = BIT(max_order) (== 1M) the last sg entry will have a
> size of 4GiB which would overflow sg->length, no? Especially with
> size + offset below. Unless for_each_prime_number stops below
> max_order. But where?

Stops at the last prime number less than 20, 19. A GEM_BUG_ON() would
clarify that.
> 
> >+		pfn += n + 1;
> 
> Please describe what kind of table and why you are building with a
> comment. If tests have no comments and do, on the first look, not
> fully obvious things, then it is a lot of effort in the future to
> work on fixes and/or maintain the code.

Creative block? If I start along those lines, I'll end up adding more
tests... Oh well.

> >+	}
> >+	sg_mark_end(sg);
> >+	pt->st.nents = n;
> >+	pt->end = pfn;
> >+
> >+	return true;
> >+}
> >+
> >+static int igt_sg_alloc(void *ignored)
> >+{
> >+	I915_SELFTEST_TIMEOUT(end_time);
> >+	const unsigned long max_order = 20; /* approximating a 4GiB object */
> >+	unsigned long prime;
> >+
> >+	for_each_prime_number(prime, max_order) {
> >+		unsigned long size = BIT(prime);
> >+		int offset;
> >+
> >+		for (offset = -1; offset <= 1; offset++) {
> >+			struct pfn_table pt;
> >+			int err;
> >+
> >+			if (!alloc_table(&pt, size + offset, size + offset))
> >+				return 0; /* out of memory, give up */
> >+
> >+			err = expect_pfn_sgtable(&pt, "sg_alloc_table");
> >+			sg_free_table(&pt.st);
> >+			if (err)
> >+				return err;
> >+
> >+			if (time_after(jiffies, end_time)) {
> >+				pr_warn("%s timed out: last table size %lu\n",
> >+					__func__, size + offset);
> >+				return 0;
> >+			}
> 
> Maybe a fmt+vaarg timeout helper since I expect there'll be a lot of
> this. Like:
> 
> if (i915_selftest_timeout(end_time, "fmt %s", arg))
> 	return 0;
> 
> It is slightly tidier.

Nice.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 16/37] drm/i915: Add a live seftest for GEM objects
  2017-01-11 21:09 ` [PATCH 16/37] drm/i915: Add a live seftest for GEM objects Chris Wilson
@ 2017-01-12 11:17   ` Matthew Auld
  0 siblings, 0 replies; 81+ messages in thread
From: Matthew Auld @ 2017-01-12 11:17 UTC (permalink / raw)
  To: Chris Wilson; +Cc: Intel Graphics Development

On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> Starting with a placeholder test just to reassure that we can create a
> test object,
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 11/37] drm/i915: Add selftests for i915_gem_request
  2017-01-11 21:09 ` [PATCH 11/37] drm/i915: Add selftests for i915_gem_request Chris Wilson
@ 2017-01-12 11:20   ` Tvrtko Ursulin
  2017-01-12 11:32     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12 11:20 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> Simple starting point for adding seltests for i915_gem_request, first
> mock a device (with engines and contexts) that allows us to construct
> and execute a request, along with waiting for the request to complete.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

AFAICT I r-b this one in the previous round.

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko

> ---
>  drivers/gpu/drm/i915/i915_gem_request.c            |  5 ++
>  drivers/gpu/drm/i915/selftests/i915_gem_request.c  | 66 ++++++++++++++++++++++
>  .../gpu/drm/i915/selftests/i915_mock_selftests.h   |  1 +
>  3 files changed, 72 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_request.c
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
> index 72b7f7d9461d..bd2aeb290cad 100644
> --- a/drivers/gpu/drm/i915/i915_gem_request.c
> +++ b/drivers/gpu/drm/i915/i915_gem_request.c
> @@ -1193,3 +1193,8 @@ void i915_gem_retire_requests(struct drm_i915_private *dev_priv)
>  	for_each_engine(engine, dev_priv, id)
>  		engine_retire_requests(engine);
>  }
> +
> +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> +#include "selftests/mock_request.c"
> +#include "selftests/i915_gem_request.c"
> +#endif
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> new file mode 100644
> index 000000000000..233c0bdb9e82
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> @@ -0,0 +1,66 @@
> +/*
> + * 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_selftest.h"
> +
> +#include "mock_gem_device.h"
> +
> +static int igt_add_request(void *arg)
> +{
> +	struct drm_i915_private *i915 = arg;
> +	struct drm_i915_gem_request *request;
> +	int err = -ENOMEM;
> +
> +	mutex_lock(&i915->drm.struct_mutex);
> +	request = mock_request(i915->engine[RCS],
> +			       i915->kernel_context,
> +			       HZ / 10);
> +	if (!request)
> +		goto out_unlock;
> +
> +	i915_add_request(request);
> +
> +	err = 0;
> +out_unlock:
> +	mutex_unlock(&i915->drm.struct_mutex);
> +	return err;
> +}
> +
> +int i915_gem_request_mock_selftests(void)
> +{
> +	static const struct i915_subtest tests[] = {
> +		SUBTEST(igt_add_request),
> +	};
> +	struct drm_i915_private *i915;
> +	int err;
> +
> +	i915 = mock_gem_device();
> +	if (!i915)
> +		return -ENOMEM;
> +
> +	err = i915_subtests(tests, i915);
> +	drm_dev_unref(&i915->drm);
> +
> +	return err;
> +}
> diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> index 80458e2a2b04..bda982404ad3 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> @@ -11,3 +11,4 @@
>  selftest(sanitycheck, i915_mock_sanitycheck) /* keep first (igt selfcheck) */
>  selftest(scatterlist, scatterlist_mock_selftests)
>  selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
> +selftest(requests, i915_gem_request_mock_selftests)
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 12/37] drm/i915: Add a simple request selftest for waiting
  2017-01-11 21:09 ` [PATCH 12/37] drm/i915: Add a simple request selftest for waiting Chris Wilson
@ 2017-01-12 11:25   ` Tvrtko Ursulin
  0 siblings, 0 replies; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12 11:25 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> A trivial kselftest to submit a request and wait upon it.

Hm this should have been a v2!

> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/selftests/i915_gem_request.c | 44 +++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> index 233c0bdb9e82..ef72b32f9bc3 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> @@ -47,10 +47,54 @@ static int igt_add_request(void *arg)
>  	return err;
>  }
>
> +static int igt_wait_request(void *arg)
> +{
> +	const long T = HZ / 4;
> +	struct drm_i915_private *i915 = arg;
> +	struct drm_i915_gem_request *request;
> +	int err = -EINVAL;
> +
> +	mutex_lock(&i915->drm.struct_mutex);
> +	request = mock_request(i915->engine[RCS], i915->kernel_context, T);
> +	if (!request) {
> +		err = -ENOMEM;
> +		goto out_unlock;
> +	}
> +
> +	i915_add_request(request);
> +
> +	if (i915_gem_request_completed(request)) {
> +		pr_err("request completed immediately!\n");
> +		goto out_unlock;
> +	}
> +
> +	if (i915_wait_request(request, I915_WAIT_LOCKED, T / 2) != -ETIME) {
> +		pr_err("request wait succeeded (expected tiemout!)\n");
> +		goto out_unlock;
> +	}
> +
> +	if (i915_wait_request(request, I915_WAIT_LOCKED, T) == -ETIME) {
> +		pr_err("request wait timed out!\n");
> +		goto out_unlock;
> +	}
> +
> +	if (!i915_gem_request_completed(request)) {
> +		pr_err("request not complete after waiting!\n");
> +		goto out_unlock;
> +	}
> +
> +	err = 0;
> +out_unlock:
> +	mock_device_flush(i915);
> +	mutex_unlock(&i915->drm.struct_mutex);
> +	return err;
> +}
> +
>  int i915_gem_request_mock_selftests(void)
>  {
>  	static const struct i915_subtest tests[] = {
>  		SUBTEST(igt_add_request),
> +		SUBTEST(igt_wait_request),
>  	};
>  	struct drm_i915_private *i915;
>  	int err;
>

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 11/37] drm/i915: Add selftests for i915_gem_request
  2017-01-12 11:20   ` Tvrtko Ursulin
@ 2017-01-12 11:32     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-12 11:32 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx

On Thu, Jan 12, 2017 at 11:20:43AM +0000, Tvrtko Ursulin wrote:
> 
> On 11/01/2017 21:09, Chris Wilson wrote:
> >Simple starting point for adding seltests for i915_gem_request, first
> >mock a device (with engines and contexts) that allows us to construct
> >and execute a request, along with waiting for the request to complete.
> >
> >Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> 
> AFAICT I r-b this one in the previous round.

Previous? Didn't see it sorry. I dropped the oldest r-bs for where the
patches no longered resembled the originals - this being one where all
the infrastructure was pulled out into preamble iirc.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 14/37] drm/i915: Simple selftest to exercise live requests
  2017-01-11 21:09 ` [PATCH 14/37] drm/i915: Simple selftest to exercise live requests Chris Wilson
@ 2017-01-12 12:10   ` Tvrtko Ursulin
  2017-01-12 12:20     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12 12:10 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> Just create several batches of requests and expect it to not fall over!
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/selftests/i915_gem_request.c  | 78 ++++++++++++++++++++++
>  .../gpu/drm/i915/selftests/i915_live_selftests.h   |  1 +
>  2 files changed, 79 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> index f348f5f81351..63e69d360764 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> @@ -22,6 +22,8 @@
>   *
>   */
>
> +#include <linux/prime_numbers.h>
> +
>  #include "i915_selftest.h"
>
>  #include "mock_gem_device.h"
> @@ -155,3 +157,79 @@ int i915_gem_request_mock_selftests(void)
>
>  	return err;
>  }
> +
> +static int live_nop_request(void *arg)
> +{
> +	I915_SELFTEST_TIMEOUT(end_time);
> +	struct drm_i915_private *i915 = arg;
> +	struct drm_i915_gem_request *request;
> +	unsigned int reset_count = i915_reset_count(&i915->gpu_error);
> +	unsigned long n, prime;
> +	ktime_t times[2] = {};
> +	int err;
> +
> +	mutex_lock(&i915->drm.struct_mutex);
> +
> +	err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
> +	if (err) {
> +		pr_err("Failed to idle GPU before %s\n", __func__);
> +		goto out_unlock;
> +	}
> +
> +	i915->gpu_error.missed_irq_rings = 0;
> +
> +	for_each_prime_number_from(prime, 1, 8192) {

Feels like an overuse of primes. Wouldn't an exponential sequence make 
more sense here? Like 1, 10, 100, 1000, if not even 100 would be enough.

Also since it is a live test, might be cool to loop over the engines.

> +		times[1] = ktime_get_raw();
> +
> +		for (n = 0; n < prime; n++) {
> +			request = i915_gem_request_alloc(i915->engine[RCS],
> +							 i915->kernel_context);
> +			if (IS_ERR(request)) {
> +				err = PTR_ERR(request);
> +				goto out_unlock;
> +			}
> +
> +			i915_add_request(request);
> +		}
> +		i915_wait_request(request, I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT);
> +		times[1] = ktime_sub(ktime_get_raw(), times[1]);
> +		if (prime == 1)
> +			times[0] = times[1];
> +
> +		if (time_after(jiffies, end_time)) {
> +			pr_warn("%s timed out: last batch size %lu\n",
> +				__func__, prime);
> +			break;
> +		}
> +	}
> +
> +	if (reset_count != i915_reset_count(&i915->gpu_error)) {
> +		pr_err("GPU was reset %d times!\n",
> +		       i915_reset_count(&i915->gpu_error) - reset_count);
> +		err = -EIO;
> +		goto out_unlock;
> +	}
> +
> +	if (i915->gpu_error.missed_irq_rings) {
> +		pr_err("Missed interrupts on rings %lx\n",
> +		       i915->gpu_error.missed_irq_rings);
> +		err = -EIO;
> +		goto out_unlock;
> +	}
> +
> +	pr_info("Request latencies: 1 = %lluns, %lu = %lluns\n",
> +	       ktime_to_ns(times[0]),
> +	       prime, div64_u64(ktime_to_ns(times[1]), prime));
> +
> +out_unlock:
> +	mutex_unlock(&i915->drm.struct_mutex);
> +	return err;
> +}
> +
> +int i915_gem_request_live_selftests(struct drm_i915_private *i915)
> +{
> +	static const struct i915_subtest tests[] = {
> +		SUBTEST(live_nop_request),
> +	};
> +	return i915_subtests(tests, i915);
> +}
> diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
> index f3e17cb10e05..09bf538826df 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
> +++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h
> @@ -9,3 +9,4 @@
>   * Tests are executed in order by igt/drv_selftest
>   */
>  selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
> +selftest(requests, i915_gem_request_live_selftests)
>

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 14/37] drm/i915: Simple selftest to exercise live requests
  2017-01-12 12:10   ` Tvrtko Ursulin
@ 2017-01-12 12:20     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-12 12:20 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx

On Thu, Jan 12, 2017 at 12:10:08PM +0000, Tvrtko Ursulin wrote:
> 
> On 11/01/2017 21:09, Chris Wilson wrote:
> >Just create several batches of requests and expect it to not fall over!
> >
> >Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> >---
> > drivers/gpu/drm/i915/selftests/i915_gem_request.c  | 78 ++++++++++++++++++++++
> > .../gpu/drm/i915/selftests/i915_live_selftests.h   |  1 +
> > 2 files changed, 79 insertions(+)
> >
> >diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> >index f348f5f81351..63e69d360764 100644
> >--- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> >+++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c
> >@@ -22,6 +22,8 @@
> >  *
> >  */
> >
> >+#include <linux/prime_numbers.h>
> >+
> > #include "i915_selftest.h"
> >
> > #include "mock_gem_device.h"
> >@@ -155,3 +157,79 @@ int i915_gem_request_mock_selftests(void)
> >
> > 	return err;
> > }
> >+
> >+static int live_nop_request(void *arg)
> >+{
> >+	I915_SELFTEST_TIMEOUT(end_time);
> >+	struct drm_i915_private *i915 = arg;
> >+	struct drm_i915_gem_request *request;
> >+	unsigned int reset_count = i915_reset_count(&i915->gpu_error);
> >+	unsigned long n, prime;
> >+	ktime_t times[2] = {};
> >+	int err;
> >+
> >+	mutex_lock(&i915->drm.struct_mutex);
> >+
> >+	err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
> >+	if (err) {
> >+		pr_err("Failed to idle GPU before %s\n", __func__);
> >+		goto out_unlock;
> >+	}
> >+
> >+	i915->gpu_error.missed_irq_rings = 0;
> >+
> >+	for_each_prime_number_from(prime, 1, 8192) {
> 
> Feels like an overuse of primes. Wouldn't an exponential sequence
> make more sense here? Like 1, 10, 100, 1000, if not even 100 would
> be enough.

Heh, everything is a nail right! I do like testing with primes though,
since powers-of-two are frequently optimised (I don't claim we should
hit any on this path). It just feels more likely to find issues by
avoiding testing with "simple" values, and the goal is find bugs in next
year's patches so serendipity rules.
 
> Also since it is a live test, might be cool to loop over the engines.

Good idea.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 25/37] drm/i915: Move i915_ppgtt_close() into i915_gem_gtt.c
  2017-01-11 21:09 ` [PATCH 25/37] drm/i915: Move i915_ppgtt_close() into i915_gem_gtt.c Chris Wilson
@ 2017-01-12 12:43   ` Joonas Lahtinen
  0 siblings, 0 replies; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-12 12:43 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Move it alongside its ppgtt counterparts, in order to make it available
> for the ppgtt selftests.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

Positive side-effects.

Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 26/37] drm/i915: Assert that we have allocated the drm_mm_node upon pinning
  2017-01-11 21:09 ` [PATCH 26/37] drm/i915: Assert that we have allocated the drm_mm_node upon pinning Chris Wilson
@ 2017-01-12 12:45   ` Joonas Lahtinen
  0 siblings, 0 replies; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-12 12:45 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> We currently check after the slow path that the vma is bound correctly,
> but we don't currently check after the fast path. This is important in
> case we accidentally take the fast path and leave the vma misplaced.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 09/37] drm/i915: Mock infrastructure for request emission
  2017-01-11 21:09 ` [PATCH 09/37] drm/i915: Mock infrastructure for request emission Chris Wilson
@ 2017-01-12 13:11   ` Tvrtko Ursulin
  2017-01-12 13:27     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12 13:11 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> Create a fake engine that runs requests using a timer to simulate hw.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/i915_gem_context.c            |   4 +
>  drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c |  11 +-
>  drivers/gpu/drm/i915/selftests/mock_context.c      |  70 +++++++++
>  drivers/gpu/drm/i915/selftests/mock_context.h      |  34 ++++
>  drivers/gpu/drm/i915/selftests/mock_engine.c       | 172 +++++++++++++++++++--
>  drivers/gpu/drm/i915/selftests/mock_engine.h       |  18 ++-
>  drivers/gpu/drm/i915/selftests/mock_gem_device.c   |  95 +++++++++++-
>  drivers/gpu/drm/i915/selftests/mock_gem_device.h   |   1 +
>  drivers/gpu/drm/i915/selftests/mock_request.c      |  44 ++++++
>  drivers/gpu/drm/i915/selftests/mock_request.h      |  44 ++++++
>  10 files changed, 475 insertions(+), 18 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/selftests/mock_context.c
>  create mode 100644 drivers/gpu/drm/i915/selftests/mock_context.h
>  create mode 100644 drivers/gpu/drm/i915/selftests/mock_request.c
>  create mode 100644 drivers/gpu/drm/i915/selftests/mock_request.h
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index fbd3b8ecbe20..91551b01a62c 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -1185,3 +1185,7 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
>
>  	return 0;
>  }
> +
> +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> +#include "selftests/mock_context.c"
> +#endif
> diff --git a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
> index bee86470a91d..2742103247c0 100644
> --- a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
> +++ b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
> @@ -25,6 +25,7 @@
>  #include "i915_random.h"
>  #include "i915_selftest.h"
>
> +#include "mock_gem_device.h"
>  #include "mock_engine.h"
>
>  static int check_rbtree(struct intel_engine_cs *engine,
> @@ -440,15 +441,15 @@ int intel_breadcrumbs_mock_selftests(void)
>  		SUBTEST(igt_insert_complete),
>  		SUBTEST(igt_wakeup),
>  	};
> -	struct intel_engine_cs *engine;
> +	struct drm_i915_private *i915;
>  	int err;
>
> -	engine = mock_engine("mock");
> -	if (!engine)
> +	i915 = mock_gem_device();
> +	if (!i915)
>  		return -ENOMEM;
>
> -	err = i915_subtests(tests, engine);
> -	kfree(engine);
> +	err = i915_subtests(tests, i915->engine[RCS]);
> +	drm_dev_unref(&i915->drm);
>
>  	return err;
>  }
> diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c
> new file mode 100644
> index 000000000000..5098dbbc81d5
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/mock_context.c
> @@ -0,0 +1,70 @@
> +/*
> + * 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 "mock_context.h"
> +#include "mock_gtt.h"
> +
> +struct i915_gem_context *
> +mock_context(struct drm_i915_private *i915,
> +	     const char *name)
> +{
> +	struct i915_gem_context *ctx;
> +	int ret;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return NULL;
> +
> +	kref_init(&ctx->ref);
> +	INIT_LIST_HEAD(&ctx->link);
> +	ctx->name = name ? kstrdup(name, GFP_KERNEL) : NULL;

Care or not whether allocation worked?

> +	ctx->i915 = i915;
> +
> +	ret = ida_simple_get(&i915->context_hw_ida,
> +			     0, MAX_CONTEXT_HW_ID, GFP_KERNEL);
> +	if (ret < 0) {

if (name && name != ctx->name)
	kfree(ctx->name);

> +		kfree(ctx);
> +		return NULL;
> +	}
> +	ctx->hw_id = ret;
> +
> +	if (name) {
> +		ctx->ppgtt = mock_ppgtt(i915, name);
> +		if (!ctx->ppgtt) {

Ditto.

> +			kfree(ctx);
> +			return NULL;
> +		}
> +	}
> +
> +	return ctx;
> +}
> +
> +void mock_context_close(struct i915_gem_context *ctx)
> +{
> +	i915_gem_context_set_closed(ctx);
> +
> +	i915_ppgtt_close(&ctx->ppgtt->base);
> +
> +	i915_gem_context_put(ctx);
> +}
> diff --git a/drivers/gpu/drm/i915/selftests/mock_context.h b/drivers/gpu/drm/i915/selftests/mock_context.h
> new file mode 100644
> index 000000000000..2427e5c0916a
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/mock_context.h
> @@ -0,0 +1,34 @@
> +/*
> + * 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 __MOCK_CONTEXT_H
> +#define __MOCK_CONTEXT_H
> +
> +struct i915_gem_context *
> +mock_context(struct drm_i915_private *i915,
> +	     const char *name);
> +
> +void mock_context_close(struct i915_gem_context *ctx);
> +
> +#endif /* !__MOCK_CONTEXT_H */
> diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
> index 085d611ed56b..b4b96d247a67 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_engine.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
> @@ -23,33 +23,185 @@
>   */
>
>  #include "mock_engine.h"
> +#include "mock_request.h"
>
> -struct intel_engine_cs *mock_engine(const char *name)
> +static struct mock_request *first_request(struct mock_engine *engine)
>  {
> -	struct intel_engine_cs *engine;
> +	return list_first_entry_or_null(&engine->hw_queue,
> +					struct mock_request,
> +					link);
> +}
> +
> +static void hw_delay_complete(unsigned long data)
> +{
> +	struct mock_engine *engine = (typeof(engine))data;
> +	struct mock_request *request;
> +
> +	spin_lock(&engine->hw_lock);
> +
> +	request = first_request(engine);
> +	if (request) {
> +		list_del_init(&request->link);
> +		mock_seqno_advance(&engine->base, request->base.global_seqno);
> +	}
> +
> +	request = first_request(engine);
> +	if (request)
> +		mod_timer(&engine->hw_delay, jiffies + request->delay);
> +
> +	spin_unlock(&engine->hw_lock);
> +}
> +
> +static int mock_context_pin(struct intel_engine_cs *engine,
> +			    struct i915_gem_context *ctx)
> +{
> +	i915_gem_context_get(ctx);
> +	return 0;
> +}
> +
> +static void mock_context_unpin(struct intel_engine_cs *engine,
> +			       struct i915_gem_context *ctx)
> +{
> +	i915_gem_context_put(ctx);
> +}
> +
> +static int mock_request_alloc(struct drm_i915_gem_request *request)
> +{
> +	struct mock_request *mock = container_of(request, typeof(*mock), base);
> +
> +	INIT_LIST_HEAD(&mock->link);
> +	mock->delay = 0;
> +
> +	request->ring = request->engine->buffer;
> +	return 0;
> +}
> +
> +static int mock_emit_flush(struct drm_i915_gem_request *request,
> +			   unsigned int flags)
> +{
> +	return 0;
> +}
> +
> +static void mock_emit_breadcrumb(struct drm_i915_gem_request *request,
> +				 u32 *flags)
> +{
> +}
> +
> +static void mock_submit_request(struct drm_i915_gem_request *request)
> +{
> +	struct mock_request *mock = container_of(request, typeof(*mock), base);
> +	struct mock_engine *engine =
> +		container_of(request->engine, typeof(*engine), base);
> +
> +	i915_gem_request_submit(request);
> +	GEM_BUG_ON(!request->global_seqno);
> +
> +	spin_lock_irq(&engine->hw_lock);
> +	list_add_tail(&mock->link, &engine->hw_queue);
> +	if (mock->link.prev == &engine->hw_queue)
> +		mod_timer(&engine->hw_delay, jiffies + mock->delay);
> +	spin_unlock_irq(&engine->hw_lock);
> +}
> +
> +static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
> +{
> +	const unsigned long sz = roundup_pow_of_two(sizeof(struct intel_ring));

You certainly like your longs. Never mind. :)

> +	struct intel_ring *ring;
> +
> +	ring = kzalloc(sizeof(*ring) + sz, GFP_TEMPORARY);

Why GFP_TEMPORARY, the mocked context & co are not?

> +	if (!ring)
> +		return NULL;
> +
> +	ring->engine = engine;
> +	ring->size = sz;
> +	ring->effective_size = sz;
> +	ring->vaddr = (void *)(ring + 1);
> +
> +	INIT_LIST_HEAD(&ring->request_list);
> +	ring->last_retired_head = -1;
> +	intel_ring_update_space(ring);
> +
> +	return ring;
> +}
> +
> +struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
> +				    const char *name)
> +{
> +	struct mock_engine *engine;
>  	static int id;
>
>  	engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_TEMPORARY);
>  	if (!engine)
>  		return NULL;
>
> -	/* minimal engine setup for seqno */
> -	engine->name = name;
> -	engine->id = id++;
> -	engine->status_page.page_addr = (void *)(engine + 1);
> +	engine->base.buffer = mock_ring(&engine->base);
> +	if (!engine->base.buffer) {
> +		kfree(engine);
> +		return NULL;
> +	}
>
> -	/* minimal breadcrumbs init */
> -	spin_lock_init(&engine->breadcrumbs.lock);
> -	engine->breadcrumbs.mock = true;
> +	/* minimal engine setup for requests */
> +	engine->base.i915 = i915;
> +	engine->base.name = name;
> +	engine->base.id = id++;
> +	engine->base.status_page.page_addr = (void *)(engine + 1);
>
> -	return engine;
> +	engine->base.context_pin = mock_context_pin;
> +	engine->base.context_unpin = mock_context_unpin;
> +	engine->base.request_alloc = mock_request_alloc;
> +	engine->base.emit_flush = mock_emit_flush;
> +	engine->base.emit_breadcrumb = mock_emit_breadcrumb;
> +	engine->base.submit_request = mock_submit_request;
> +
> +	engine->base.timeline =
> +		&i915->gt.global_timeline.engine[engine->base.id];
> +
> +	intel_engine_init_breadcrumbs(&engine->base);
> +	engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
> +
> +	/* fake hw queue */
> +	spin_lock_init(&engine->hw_lock);
> +	setup_timer(&engine->hw_delay,
> +		    hw_delay_complete,
> +		    (unsigned long)engine);
> +	INIT_LIST_HEAD(&engine->hw_queue);
> +
> +	return &engine->base;
>  }
>
>  void mock_engine_flush(struct intel_engine_cs *engine)
>  {
> +	struct mock_engine *mock =
> +		container_of(engine, typeof(*mock), base);
> +	struct mock_request *request, *rn;
> +
> +	del_timer_sync(&mock->hw_delay);
> +
> +	spin_lock_irq(&mock->hw_lock);
> +	list_for_each_entry_safe(request, rn, &mock->hw_queue, link) {
> +		list_del_init(&request->link);
> +		mock_seqno_advance(&mock->base, request->base.global_seqno);
> +	}
> +	spin_unlock_irq(&mock->hw_lock);
>  }
>
>  void mock_engine_reset(struct intel_engine_cs *engine)
>  {
>  	intel_write_status_page(engine, I915_GEM_HWS_INDEX, 0);
>  }
> +
> +void mock_engine_free(struct intel_engine_cs *engine)
> +{
> +	struct mock_engine *mock =
> +		container_of(engine, typeof(*mock), base);
> +
> +	GEM_BUG_ON(timer_pending(&mock->hw_delay));
> +
> +	if (engine->last_retired_context)
> +		engine->context_unpin(engine, engine->last_retired_context);
> +
> +	intel_engine_fini_breadcrumbs(engine);
> +
> +	kfree(engine->buffer);
> +	kfree(engine);
> +}
> diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.h b/drivers/gpu/drm/i915/selftests/mock_engine.h
> index 9cfe9671f860..d080d0a10a4f 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_engine.h
> +++ b/drivers/gpu/drm/i915/selftests/mock_engine.h
> @@ -25,9 +25,25 @@
>  #ifndef __MOCK_ENGINE_H__
>  #define __MOCK_ENGINE_H__
>
> -struct intel_engine_cs *mock_engine(const char *name);
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/timer.h>
> +
> +#include "intel_ringbuffer.h"
> +
> +struct mock_engine {
> +	struct intel_engine_cs base;
> +
> +	spinlock_t hw_lock;
> +	struct list_head hw_queue;
> +	struct timer_list hw_delay;
> +};
> +
> +struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
> +				    const char *name);
>  void mock_engine_flush(struct intel_engine_cs *engine);
>  void mock_engine_reset(struct intel_engine_cs *engine);
> +void mock_engine_free(struct intel_engine_cs *engine);
>
>  static inline void mock_seqno_advance(struct intel_engine_cs *engine, u32 seqno)
>  {
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> index 8f5fbc18a607..7ce86ed71764 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> @@ -24,21 +24,57 @@
>
>  #include <linux/pm_runtime.h>
>
> +#include "mock_engine.h"
> +#include "mock_context.h"
> +#include "mock_request.h"
>  #include "mock_gem_device.h"
>  #include "mock_gem_object.h"
>  #include "mock_gtt.h"
>
> +void mock_device_flush(struct drm_i915_private *i915)
> +{
> +	struct intel_engine_cs *engine;
> +	enum intel_engine_id id;
> +
> +	lockdep_assert_held(&i915->drm.struct_mutex);
> +
> +	for_each_engine(engine, i915, id)
> +		mock_engine_flush(engine);
> +
> +	i915_gem_retire_requests(i915);
> +}
> +
>  static void mock_device_release(struct drm_device *dev)
>  {
>  	struct drm_i915_private *i915 = to_i915(dev);
> +	struct intel_engine_cs *engine;
> +	enum intel_engine_id id;
>
>  	mutex_lock(&i915->drm.struct_mutex);
> +	mock_device_flush(i915);
> +	mutex_unlock(&i915->drm.struct_mutex);
> +
> +	cancel_delayed_work_sync(&i915->gt.retire_work);
> +	cancel_delayed_work_sync(&i915->gt.idle_work);
> +
> +	mutex_lock(&i915->drm.struct_mutex);
> +	for_each_engine(engine, i915, id)
> +		mock_engine_free(engine);
> +
> +	i915_gem_context_fini(i915);
> +
>  	mock_fini_ggtt(i915);
>  	i915_gem_timeline_fini(&i915->gt.global_timeline);
>  	mutex_unlock(&i915->drm.struct_mutex);
>
> +	drain_workqueue(i915->wq);
> +
>  	i915_gem_drain_freed_objects(i915);
>
> +	destroy_workqueue(i915->wq);
> +
> +	kmem_cache_destroy(i915->dependencies);
> +	kmem_cache_destroy(i915->requests);
>  	kmem_cache_destroy(i915->vmas);
>  	kmem_cache_destroy(i915->objects);
>  	put_device(&i915->drm.pdev->dev);
> @@ -60,9 +96,19 @@ static void release_dev(struct device *dev)
>  	kfree(pdev);
>  }
>
> +static void mock_retire_work_handler(struct work_struct *work)
> +{
> +}
> +
> +static void mock_idle_work_handler(struct work_struct *work)
> +{
> +}
> +
>  struct drm_i915_private *mock_gem_device(void)
>  {
>  	struct drm_i915_private *i915;
> +	struct intel_engine_cs *engine;
> +	enum intel_engine_id id;
>  	struct pci_dev *pdev;
>  	int err;
>
> @@ -98,36 +144,81 @@ struct drm_i915_private *mock_gem_device(void)
>
>  	spin_lock_init(&i915->mm.object_stat_lock);
>
> +	init_waitqueue_head(&i915->gpu_error.wait_queue);
> +	init_waitqueue_head(&i915->gpu_error.reset_queue);
> +
> +	i915->wq = alloc_ordered_workqueue("mock", 0);
> +	if (!i915->wq)
> +		goto put_device;
> +
>  	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
>  	init_llist_head(&i915->mm.free_list);
>  	INIT_LIST_HEAD(&i915->mm.unbound_list);
>  	INIT_LIST_HEAD(&i915->mm.bound_list);
>
> +	ida_init(&i915->context_hw_ida);
> +
> +	INIT_DELAYED_WORK(&i915->gt.retire_work, mock_retire_work_handler);
> +	INIT_DELAYED_WORK(&i915->gt.idle_work, mock_idle_work_handler);
> +
> +	i915->gt.awake = true;
> +
>  	i915->objects = KMEM_CACHE(mock_object, SLAB_HWCACHE_ALIGN);
>  	if (!i915->objects)
> -		goto put_device;
> +		goto err_wq;
>
>  	i915->vmas = KMEM_CACHE(i915_vma, SLAB_HWCACHE_ALIGN);
>  	if (!i915->vmas)
>  		goto err_objects;
>
> +	i915->requests = KMEM_CACHE(mock_request,
> +				    SLAB_HWCACHE_ALIGN |
> +				    SLAB_RECLAIM_ACCOUNT |
> +				    SLAB_DESTROY_BY_RCU);
> +	if (!i915->requests)
> +		goto err_vmas;
> +
> +	i915->dependencies = KMEM_CACHE(i915_dependency,
> +					SLAB_HWCACHE_ALIGN |
> +					SLAB_RECLAIM_ACCOUNT);
> +	if (!i915->dependencies)
> +		goto err_requests;
> +
>  	mutex_lock(&i915->drm.struct_mutex);
>  	INIT_LIST_HEAD(&i915->gt.timelines);
>  	err = i915_gem_timeline_init__global(i915);
>  	if (err) {
>  		mutex_unlock(&i915->drm.struct_mutex);
> -		goto err_vmas;
> +		goto err_dependencies;
>  	}
>
>  	mock_init_ggtt(i915);
>  	mutex_unlock(&i915->drm.struct_mutex);
>
> +	mkwrite_device_info(i915)->ring_mask = BIT(0);
> +	i915->engine[RCS] = mock_engine(i915, "mock");
> +	if (!i915->engine[RCS])
> +		goto err_dependencies;
> +
> +	i915->kernel_context = mock_context(i915, NULL);
> +	if (!i915->kernel_context)
> +		goto err_engine;
> +
>  	return i915;
>
> +err_engine:
> +	for_each_engine(engine, i915, id)
> +		mock_engine_free(engine);
> +err_dependencies:
> +	kmem_cache_destroy(i915->dependencies);
> +err_requests:
> +	kmem_cache_destroy(i915->requests);
>  err_vmas:
>  	kmem_cache_destroy(i915->vmas);
>  err_objects:
>  	kmem_cache_destroy(i915->objects);
> +err_wq:
> +	destroy_workqueue(i915->wq);
>  put_device:
>  	put_device(&pdev->dev);
>  free_device:
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.h b/drivers/gpu/drm/i915/selftests/mock_gem_device.h
> index 7ff7c848f731..7eceff766957 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.h
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.h
> @@ -4,5 +4,6 @@
>  #include "i915_drv.h"
>
>  struct drm_i915_private *mock_gem_device(void);
> +void mock_device_flush(struct drm_i915_private *i915);
>
>  #endif /* !__MOCK_GEM_DEVICE_H__ */
> diff --git a/drivers/gpu/drm/i915/selftests/mock_request.c b/drivers/gpu/drm/i915/selftests/mock_request.c
> new file mode 100644
> index 000000000000..e23242d1b88a
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/mock_request.c
> @@ -0,0 +1,44 @@
> +/*
> + * 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 "mock_request.h"
> +
> +struct drm_i915_gem_request *
> +mock_request(struct intel_engine_cs *engine,
> +	     struct i915_gem_context *context,
> +	     unsigned long delay)
> +{
> +	struct drm_i915_gem_request *request;
> +	struct mock_request *mock;
> +
> +	/* NB the i915->requests slab cache is enlarged to fit mock_request */
> +	request = i915_gem_request_alloc(engine, context);
> +	if (!request)
> +		return NULL;
> +
> +	mock = container_of(request, typeof(*mock), base);
> +	mock->delay = delay;
> +
> +	return &mock->base;
> +}
> diff --git a/drivers/gpu/drm/i915/selftests/mock_request.h b/drivers/gpu/drm/i915/selftests/mock_request.h
> new file mode 100644
> index 000000000000..9c739125cab5
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/mock_request.h
> @@ -0,0 +1,44 @@
> +/*
> + * 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 __MOCK_REQUEST__
> +#define __MOCK_REQUEST__
> +
> +#include <linux/list.h>
> +
> +#include "i915_gem_request.h"
> +
> +struct mock_request {
> +	struct drm_i915_gem_request base;
> +
> +	struct list_head link;
> +	unsigned long delay;
> +};
> +
> +struct drm_i915_gem_request *
> +mock_request(struct intel_engine_cs *engine,
> +	     struct i915_gem_context *context,
> +	     unsigned long delay);
> +
> +#endif /* !__MOCK_REQUEST__ */
>

Looks reasonable. I say we run with and if I missed something fix it in 
the fly. With the name leak and GFP flags tidy:

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 09/37] drm/i915: Mock infrastructure for request emission
  2017-01-12 13:11   ` Tvrtko Ursulin
@ 2017-01-12 13:27     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-12 13:27 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx

On Thu, Jan 12, 2017 at 01:11:50PM +0000, Tvrtko Ursulin wrote:
> 
> On 11/01/2017 21:09, Chris Wilson wrote:
> >+struct i915_gem_context *
> >+mock_context(struct drm_i915_private *i915,
> >+	     const char *name)
> >+{
> >+	struct i915_gem_context *ctx;
> >+	int ret;
> >+
> >+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> >+	if (!ctx)
> >+		return NULL;
> >+
> >+	kref_init(&ctx->ref);
> >+	INIT_LIST_HEAD(&ctx->link);
> >+	ctx->name = name ? kstrdup(name, GFP_KERNEL) : NULL;
> 
> Care or not whether allocation worked?

Not really, ctx->name is a hint. But not checking is just asking for
trouble later.

> >+static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
> >+{
> >+	const unsigned long sz = roundup_pow_of_two(sizeof(struct intel_ring));
> 
> You certainly like your longs. Never mind. :)

We have a habit of growing our structs. Consider this future proofing
;)

> >+	struct intel_ring *ring;
> >+
> >+	ring = kzalloc(sizeof(*ring) + sz, GFP_TEMPORARY);
> 
> Why GFP_TEMPORARY, the mocked context & co are not?

Depends on the phase I was writing the patch. The first tests were fast,
and so GFP_TEMPORARY seemed appropriate, and I used it everywhere I
remembered. With some tests being deliberately slow and others
deliberately using all memory, GFP_TEMPORARY seems more like misuse.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 27/37] drm/i915: Exercising filling the top/bottom portions of the ppgtt
  2017-01-11 21:09 ` [PATCH 27/37] drm/i915: Exercising filling the top/bottom portions of the ppgtt Chris Wilson
@ 2017-01-12 13:32   ` Joonas Lahtinen
  0 siblings, 0 replies; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-12 13:32 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Allocate objects with varying number of pages (which should hopefully
> consist of a mixture of contiguous page chunks and so coalesced sg
> lists) and check that the sg walkers in insert_pages cope.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

>  struct drm_i915_gem_object *
>  i915_gem_object_create_internal(struct drm_i915_private *dev_priv,
> -				unsigned int size);
> +				unsigned long size);

As discussed in IRC, phys_size_t would be more documenting why it
deviates from u64.
 
> +static struct i915_vma *vma_lookup(struct drm_i915_gem_object *obj,
> +				   struct i915_address_space *vm)
> +{
> +	return i915_gem_obj_lookup_or_create_vma(obj, vm, NULL);
> +}

How about finally renaming the original function itself? 'vma_lookup'
is tad confusing, maybe 'vma_instance'? Lookup has strong implication
that it'll just look for existance. The name could be even better.

> +
> +static int igt_ppgtt_fill(void *arg)
> +{
> +	struct drm_i915_private *dev_priv = arg;
> +	unsigned long npages, max_pages = 1 << 20, prime;

Naww, assignment to it's own line (or rather, embed it to the min_t
expression). If you plan on making it a parameter, do so :P

> +	struct drm_i915_gem_object *obj, *on;
> +	struct i915_hw_ppgtt *ppgtt;
> +	struct i915_vma *vma;
> +	LIST_HEAD(objects);
> +	int err = 0;
> +
> +	if (!USES_FULL_PPGTT(dev_priv))
> +		return 0;

This calls for return -ENXIO (or something else we're not using under
DRM and i915) and handling in the callchain.

> +
> +	mutex_lock(&dev_priv->drm.struct_mutex);
> +	ppgtt = i915_ppgtt_create(dev_priv, NULL, "mock");
> +	if (IS_ERR(ppgtt)) {
> +		err = PTR_ERR(ppgtt);
> +		goto err_unlock;
> +	}
> +	GEM_BUG_ON(ppgtt->base.total & ~PAGE_MASK);

IS_ALIGNED or offset_in_page

> +	for_each_prime_number_from(prime, 2, 13) {
> +		for (npages = 1; npages <= max_pages; npages *= prime) {
> +			u64 flags;
> +
> +			GEM_BUG_ON(!npages);
> +			obj = huge_gem_object(dev_priv,
> +					      PAGE_SIZE,
> +					      npages << PAGE_SHIFT);
> +			if (IS_ERR(obj))
> +				break;
> +
> +			list_add(&obj->batch_pool_link, &objects);

Urgh... anonymous union?

> +
> +			/* Fill the GTT top down - hope we don't overstep the end */
> +			flags = ppgtt->base.total | PIN_OFFSET_FIXED | PIN_USER;
> +			list_for_each_entry(obj, &objects, batch_pool_link) {
> +				vma = vma_lookup(obj, &ppgtt->base);
> +				if (IS_ERR(vma))
> +					continue;
> +

GEM_BUG_ON(flags & I915_GTT_PAGE_SIZE < obj->base.size);

> +				flags -= obj->base.size;
> +				err = i915_vma_pin(vma, 0, 0, flags);
> +				if (err) {
> +					pr_err("Fill top-down failed with err=%d on size=%lu pages (prime=%lu)\n", err, npages, prime);

Alternatively dump flags in here so it's obvious from log.

> +					goto err;
> +				}
> +
> +				i915_vma_unpin(vma);
> +			}
> +
> +			flags = ppgtt->base.total | PIN_OFFSET_FIXED | PIN_USER;
> +			list_for_each_entry(obj, &objects, batch_pool_link) {
> +				vma = vma_lookup(obj, &ppgtt->base);
> +				if (IS_ERR(vma))
> +					continue;
> +
> +				flags -= obj->base.size;
> +				if (!drm_mm_node_allocated(&vma->node) ||
> +				    i915_vma_misplaced(vma, 0, 0, flags)) {
> +					pr_err("Fill top-down moved vma.node=%llx + %llx, expected offset %llx\n",
> +					       vma->node.start, vma->node.size,
> +					       flags & PAGE_MASK);
> +					err = -EINVAL;
> +					goto err;
> +				}
> +
> +				err = i915_vma_unbind(vma);
> +				if (err) {
> +					pr_err("Fill top-down unbind of vma.node=%llx + %llx failed with err=%d\n",
> +					       vma->node.start, vma->node.size,
> +					       err);
> +					goto err;
> +				}
> +			}
> +

Maybe convert above into traditional phase[] array to dedup code from
this point on?

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 28/37] drm/i915: Exercising filling the top/bottom portions of the global GTT
  2017-01-11 21:09 ` [PATCH 28/37] drm/i915: Exercising filling the top/bottom portions of the global GTT Chris Wilson
@ 2017-01-12 14:05   ` Joonas Lahtinen
  0 siblings, 0 replies; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-12 14:05 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Same test as previously for the per-process GTT instead applied to the
> global GTT.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> @@ -218,28 +209,94 @@ static int igt_ppgtt_fill(void *arg)
>  
>  		list_for_each_entry_safe(obj, on, &objects, batch_pool_link) {
>  			list_del(&obj->batch_pool_link);
> -			vma = vma_lookup(obj, &ppgtt->base);
> -			if (!IS_ERR(vma))
> +			vma = vma_lookup(obj, vm);
> +			if (!IS_ERR(vma) && !i915_vma_is_ggtt(vma))

Reasoning is worthy a commenting here as discussed in IRC.

>  				i915_vma_close(vma);
>  
>  			i915_gem_object_put(obj);
>  		}
>  	}
> -err:

<SNIP>

> +static int igt_ggtt_fill(void *arg)
> +{

<SNIP>

> +	mutex_lock(&i915->drm.struct_mutex);
> +	drm_mm_for_each_hole(node, &ggtt->base.mm, this_start, this_end) {
> +		u64 this_size;
> +
> +		if (ggtt->base.mm.color_adjust)
> +			ggtt->base. mm.color_adjust(node, 0,

You somehow managed to add space --^ 

Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 06/37] drm/i915: Add unit tests for the breadcrumb rbtree, wakeups
  2017-01-12 11:11   ` Tvrtko Ursulin
@ 2017-01-12 14:37     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-12 14:37 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx

On Thu, Jan 12, 2017 at 11:11:20AM +0000, Tvrtko Ursulin wrote:
> 
> On 11/01/2017 21:09, Chris Wilson wrote:
> >Third retroactive test, make sure that the seqno waiters are woken.
> 
> There are some open questions from the previous round (early
> December), not least of which is that I think we really need good
> comments in tests. Especially ones like this one which is pretty
> advanced. We need an overall description and some commentary on the
> stages. It is not straightforward to reverse engineer this, so doing
> it every time this code will need some attention for one reason or
> the other will be a PITA.

I added that comment!
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 18/37] drm/i915: Test exhaustion of the mmap space
  2017-01-11 21:09 ` [PATCH 18/37] drm/i915: Test exhaustion of the mmap space Chris Wilson
@ 2017-01-12 17:29   ` Matthew Auld
  0 siblings, 0 replies; 81+ messages in thread
From: Matthew Auld @ 2017-01-12 17:29 UTC (permalink / raw)
  To: Chris Wilson; +Cc: Intel Graphics Development

On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> An unlikely error condition that we can simulate by stealing the most of
s/the most/most/

> the range before trying to insert new objects.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/selftests/i915_gem_object.c | 137 +++++++++++++++++++++++
>  1 file changed, 137 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> index df3625f551aa..46512a67877d 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> @@ -25,6 +25,7 @@
>  #include "i915_selftest.h"
>
>  #include "mock_gem_device.h"
> +#include "huge_gem_object.h"
>
>  static int igt_gem_object(void *arg)
>  {
> @@ -383,6 +384,141 @@ static int igt_partial_tiling(void *arg)
>         return err;
>  }
>
> +static int make_obj_busy(struct drm_i915_gem_object *obj)
> +{
> +       struct drm_i915_private *i915 = to_i915(obj->base.dev);
> +       struct drm_i915_gem_request *rq;
> +       struct i915_vma *vma;
> +       int err;
> +
> +       vma = i915_gem_obj_lookup_or_create_vma(obj, &i915->ggtt.base, NULL);
> +       if (IS_ERR(vma))
> +               return PTR_ERR(vma);
> +
> +       err = i915_vma_pin(vma, 0, 0, PIN_USER);
> +       if (err)
> +               return err;
> +
> +       rq = i915_gem_request_alloc(i915->engine[RCS], i915->kernel_context);
> +       if (IS_ERR(rq)) {
> +               i915_vma_unpin(vma);
> +               return PTR_ERR(rq);
> +       }
> +
> +       i915_vma_move_to_active(vma, rq, 0);
> +       i915_add_request(rq);
> +
> +       i915_gem_object_set_active_reference(obj);
> +       i915_vma_unpin(vma);
> +       return 0;
> +}
> +
> +static bool assert_mmap_offset(struct drm_i915_private *i915,
> +                              unsigned long size,
> +                              int expected)
> +{
> +       struct drm_i915_gem_object *obj;
> +       int err;
> +
> +       obj = i915_gem_object_create_internal(i915, size);
> +       if (IS_ERR(obj))
> +               return PTR_ERR(obj);
> +
> +       err = i915_gem_object_create_mmap_offset(obj);
> +       i915_gem_object_put(obj);
> +
> +       return err == expected;
> +}
> +
> +static int igt_mmap_offset_exhaustion(void *arg)
> +{
> +       struct drm_i915_private *i915 = arg;
> +       struct drm_mm *mm = &i915->drm.vma_offset_manager->vm_addr_space_mm;
> +       struct drm_i915_gem_object *obj;
> +       struct drm_mm_node resv, *hole;
> +       u64 hole_start, hole_end;
> +       int loop, err;
> +
> +       /* Trim the VMA mmap space to only a page */
> +       memset(&resv, 0, sizeof(resv));
> +       drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
> +               resv.start = hole_start;
> +               resv.size = hole_end - hole_start - 1; /* PAGE_SIZE units */
> +               err = drm_mm_reserve_node(mm, &resv);
> +               if (err) {
> +                       pr_err("Failed to trim VMA manager, err=%d\n", err);
> +                       return err;
> +               }
> +               break;
> +       }
> +
> +       /* Just fits! */
> +       if (!assert_mmap_offset(i915, PAGE_SIZE, 0)) {
> +               pr_err("Unable to insert object into single page hole\n");
> +               err = -EINVAL;
> +               goto err;
> +       }
> +
> +       /* Too large */
> +       if (!assert_mmap_offset(i915, 2*PAGE_SIZE, -ENOSPC)) {
> +               pr_err("Unexpectedly succeded in inserting too large object into single page hole\n");
s/succeded/succeeded

> +               err = -EINVAL;
> +               goto err;
> +       }
> +
> +       /* Fill the hole, should then fail */
Fill the hole, further attempts should then fail; less confusing imo.

Reviewed-by: Matthew Auld <matthew.auld@intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 33/37] drm/i915: Verify page layout for rotated VMA
  2017-01-11 21:09 ` [PATCH 33/37] drm/i915: Verify page layout for rotated VMA Chris Wilson
@ 2017-01-12 17:41   ` Tvrtko Ursulin
  0 siblings, 0 replies; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-12 17:41 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 11/01/2017 21:09, Chris Wilson wrote:
> Exercise creating rotated VMA and checking the page order within.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/selftests/i915_vma.c | 130 ++++++++++++++++++++++++++++++
>  1 file changed, 130 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c
> index d229adabc5f8..95c5db2b0881 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_vma.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_vma.c
> @@ -287,11 +287,141 @@ static int igt_vma_pin1(void *arg)
>  	return err;
>  }
>
> +static unsigned long rotated_index(const struct intel_rotation_info *r,
> +				   unsigned int n,
> +				   unsigned int x,
> +				   unsigned int y)
> +{
> +	return r->plane[n].stride * (r->plane[n].height - y - 1) + x;
> +}
> +
> +static struct scatterlist *
> +assert_rotated(struct drm_i915_gem_object *obj,
> +	       const struct intel_rotation_info *r, unsigned int n,
> +	       struct scatterlist *sg)
> +{
> +	unsigned int x, y;
> +
> +	for (x = 0; x < r->plane[n].width; x++) {
> +		for (y = 0; y < r->plane[n].height; y++) {
> +			unsigned long src_idx;
> +			dma_addr_t src;
> +
> +			src_idx = rotated_index(r, n, x, y);
> +			src = i915_gem_object_get_dma_address(obj, src_idx);

Right, this is actually more like unrotate, from rotated coords to 
unrotated index. I'll assume the formula is correct if it passes. :)

> +
> +			if (sg_dma_len(sg) != PAGE_SIZE) {
> +				pr_err("Invalid sg.length, found %d, expected %lu for rotated page (%d, %d) [src index %lu]\n",
> +				       sg_dma_len(sg), PAGE_SIZE,
> +				       x, y, src_idx);
> +				return NULL;
> +			}
> +
> +			if (sg_dma_address(sg) != src) {
> +				pr_err("Invalid address for rotated page (%d, %d) [src index %lu]\n",
> +				       x, y, src_idx);
> +				return NULL;
> +			}
> +
> +			sg = ____sg_next(sg);
> +		}
> +	}
> +
> +	return sg;
> +}
> +
> +static int igt_vma_rotate(void *arg)
> +{
> +	struct drm_i915_private *i915 = arg;
> +	struct drm_i915_gem_object *obj;
> +	const unsigned int width = 6;
> +	const unsigned int height = 4;
> +	const unsigned int npages = 24;
> +	struct i915_vma *vma;
> +	struct i915_ggtt_view view;
> +	struct scatterlist *sg;
> +	unsigned int n;
> +	int err = -ENOMEM;
> +
> +	obj = i915_gem_object_create_internal(i915, npages*PAGE_SIZE);
> +	if (IS_ERR(obj))
> +		goto err;
> +
> +	view.type = I915_GGTT_VIEW_ROTATED;
> +	view.rotated.plane[0].offset = 0;
> +	view.rotated.plane[0].width = width;
> +	view.rotated.plane[0].height = height;
> +	view.rotated.plane[0].stride = width;
> +
> +	view.rotated.plane[1].offset = 0;
> +	view.rotated.plane[1].width = height;
> +	view.rotated.plane[1].height = width;
> +	view.rotated.plane[1].stride = height;

Ahem, why are the width & height assignments different between the 
planes and how can a single assert possibly work with this? Perhaps it 
all works totally differently after Ville's rewrite, I don't know any 
more obviously.

> +
> +	vma = i915_gem_obj_lookup_or_create_vma(obj, &i915->ggtt.base, &view);
> +	if (IS_ERR(vma)) {
> +		err = PTR_ERR(vma);
> +		goto err_object;
> +	}
> +
> +	if (!i915_vma_is_ggtt(vma)) {
> +		pr_err("VMA is not in the GGTT!\n");
> +		err = -EINVAL;
> +		goto err_object;
> +	}
> +
> +	err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
> +	if (err)
> +		goto err_object;

Log message would be good.

> +
> +	if (memcmp(&vma->ggtt_view, &view, sizeof(view))) {
> +		pr_err("VMA mismatch upon creation!\n");
> +		err = -EINVAL;
> +		goto err_object;
> +	}

i915_vma_compare to cover any future tweaking in that area?

> +
> +	if (vma->size != 2*npages*PAGE_SIZE) {
> +		pr_err("VMA is wrong size, expected %lu, found %llu\n",
> +		       2*npages*PAGE_SIZE, vma->size);
> +		err = -EINVAL;
> +		goto err_object;
> +	}

Wait a minute, how can rotated view be bigger than the object?!

[after some head scratching and bringing up the code]

Right, you are playing tricks with pretend two planes. It would be good 
to split the test into one plane only first, and then the two-plane 
configuration. Probably with a "real" backing store, I mean object with 
enough pages for both planes and a proper offset.

> +
> +	if (vma->node.size < vma->size) {
> +		pr_err("VMA binding too small, expected %llu, found %llu\n",
> +		       vma->size, vma->node.size);
> +		err = -EINVAL;
> +		goto err_object;
> +	}
> +
> +	if (vma->pages == obj->mm.pages) {
> +		pr_err("VMA using unrotated object pages!\n");
> +		err = -EINVAL;
> +		goto err_object;
> +	}
> +
> +	sg = vma->pages->sgl;
> +	for (n = 0; n < ARRAY_SIZE(view.rotated.plane); n++) {
> +		sg = assert_rotated(obj, &view.rotated, n, sg);
> +		if (!sg) {
> +			pr_err("Inconsistent VMA pages for plane %d\n", n);
> +			err = -EINVAL;
> +			goto err_object;
> +		}
> +	}
> +
> +err_object:
> +	i915_gem_object_put(obj);
> +err:
> +	return err;
> +}
> +
>  int i915_vma_mock_selftests(void)
>  {
>  	static const struct i915_subtest tests[] = {
>  		SUBTEST(igt_vma_create),
>  		SUBTEST(igt_vma_pin1),
> +		SUBTEST(igt_vma_rotate),
>  	};
>  	struct drm_i915_private *i915;
>  	int err;
>

Regards,

Tvrtko

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 29/37] drm/i915: Fill different pages of the GTT
  2017-01-11 21:09 ` [PATCH 29/37] drm/i915: Fill different pages of the GTT Chris Wilson
@ 2017-01-13  7:47   ` Joonas Lahtinen
  2017-01-13 20:45     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-13  7:47 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Exercise filling different pages of the GTT
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> +static int walk_hole(struct drm_i915_private *i915,
> > +		     struct i915_address_space *vm,
> > +		     u64 hole_start, u64 hole_end)
> +{

<SNIP>

> +	for (addr = hole_start; addr < hole_end; addr += PAGE_SIZE)
{
> +		cond_resched();

Maybe this should be in the previous tests too that fill the GTT (one
would imagine it to take a lot longer than just walking with single
vma).

> +static int igt_ppgtt_walk(void *arg)
> +{

<SNIP>

> +
> +	i915_ppgtt_close(&ppgtt->base);
> +	i915_ppgtt_put(ppgtt);
> +err_unlock:

traditionally called out_unlock; Or being sole label, just out:

> +	mutex_unlock(&dev_priv->drm.struct_mutex);
> +
> +	fake_file_free(dev_priv, file);
> +	return err;
> +}
> +

<SNIP>

> +static int igt_ggtt_walk(void *arg)
> +{
> +	struct drm_i915_private *i915 = arg;
> +	struct i915_ggtt *ggtt = &i915->ggtt;
> +	u64 hole_start = U64_MAX, hole_end = 0, hole_size = 0;

I think I missed this in the ppgtt, but; single assignment per line as
per CodingStyle. This is not obfuscation contest.

> +	u64 this_start, this_end;
> +	struct drm_mm_node *node;
> +	int err;
> +
> +	GEM_BUG_ON(ggtt->base.total & ~PAGE_MASK);

I think single instance of this somewhere early should be enough?

> +
> +	mutex_lock(&i915->drm.struct_mutex);
> +	drm_mm_for_each_hole(node, &ggtt->base.mm, this_start, this_end) {
> +		u64 this_size;
> +
> +		if (ggtt->base.mm.color_adjust)
> +			ggtt->base. mm.color_adjust(node, 0,
> +						    &this_start, &this_end);
> +
> +		this_size = this_end - this_start;
> +		if (this_size > hole_size) {
> +			hole_size = this_size;
> +			hole_start = this_start;
> +			hole_end = this_end;
> +		}
> +	}
> +	pr_info("Found GGTT hole [%llx, %llx], size %llx\n",
> +		hole_start, hole_end, hole_size);
> +	GEM_BUG_ON(hole_start >= hole_end);
> +

Why not just walk all the holes big enough to accommodate GTT_PAGE_SIZE
for better coverage? But for just one hole, with above;

Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 02/37] drm/i915: Provide a hook for selftests
  2017-01-11 21:09 ` [PATCH 02/37] drm/i915: Provide a hook for selftests Chris Wilson
  2017-01-12  7:29   ` Tvrtko Ursulin
@ 2017-01-13  8:31   ` Chris Wilson
  2017-01-13 10:12     ` Tvrtko Ursulin
  1 sibling, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-13  8:31 UTC (permalink / raw)
  To: intel-gfx

On Wed, Jan 11, 2017 at 09:09:02PM +0000, Chris Wilson wrote:
> 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 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.igt__ is interpreted as a subtest executable independently via
> igt/drv_selftest.
> 
> Two classes of selftests are recognised: mock unit tests and integration
> tests. Mock unit tests are run as soon as the module is loaded, before
> the device is probed. At that point there is no driver instantiated and
> all hw interactions must be "mocked". This is very useful for writing
> universal tests to exercise code not typically run on a broad range of
> architectures. Alternatively, you can hook into the live selftests and
> run when the device has been instantiated - hw interactions are real.

One problem I'm running into is that i915_selftest_ is a long prefix,
especially when we get to something like i915_selftest_timeout(jiffies,
							       "format",
							       args);

I'm tempted by /i915_selftest_/igt_/. Thoughts?
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 30/37] drm/i915: Exercise filling and removing random ranges from the live GTT
  2017-01-11 21:09 ` [PATCH 30/37] drm/i915: Exercise filling and removing random ranges from the live GTT Chris Wilson
@ 2017-01-13  8:59   ` Joonas Lahtinen
  2017-01-13  9:08     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-13  8:59 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Test the low-level i915_address_space interfaces to sanity check the
> live insertion/removal of address ranges.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> +static u64 scale(u64 offset, unsigned int shift)
> +{
> +	return offset << shift;
> +}

BIT_ULL is your friend.

> +static int random_hole(struct drm_i915_private *i915,

fill_random_hole?

> +		       struct i915_address_space *vm,
> +		       u64 hole_start, u64 hole_end)
> +{
> +	I915_RND_STATE(prng);

Just to remind that this prng should be seeded from the user seed to
maintain repeatability. I kinda assume it's so.

> +	unsigned int size;
> +
> +	for (size = 12; (hole_end - hole_start) >> (size + 2); size++) {

This criteria is not obvious to me. Maybe write a comment above.

You could add a variable BIT_ULL(1, size) here too.

<SNIP>

Put a one line comment what each test achieves, again you have some of
it in the commit messages already.

> +static int igt_ppgtt_drunk(void *arg)

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 30/37] drm/i915: Exercise filling and removing random ranges from the live GTT
  2017-01-13  8:59   ` Joonas Lahtinen
@ 2017-01-13  9:08     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-13  9:08 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: intel-gfx

On Fri, Jan 13, 2017 at 10:59:52AM +0200, Joonas Lahtinen wrote:
> On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> > +		       struct i915_address_space *vm,
> > +		       u64 hole_start, u64 hole_end)
> > +{
> > +	I915_RND_STATE(prng);
> 
> Just to remind that this prng should be seeded from the user seed to
> maintain repeatability. I kinda assume it's so.

I915_RND_STATE() does the initialisation from the user seed. But as we
were discussing on IRC, since the inner loop has variable length (due to
each being limited by the user timeout), we need to reseed at the
beginning of each loop. As the loops are fairly uniform, we want to
reseed using the prng(user_seed) to try and avoid falling into the trap
of pattern repetition.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 02/37] drm/i915: Provide a hook for selftests
  2017-01-13  8:31   ` Chris Wilson
@ 2017-01-13 10:12     ` Tvrtko Ursulin
  2017-01-13 10:22       ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-13 10:12 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 13/01/2017 08:31, Chris Wilson wrote:
> On Wed, Jan 11, 2017 at 09:09:02PM +0000, Chris Wilson wrote:
>> 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 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.igt__ is interpreted as a subtest executable independently via
>> igt/drv_selftest.
>>
>> Two classes of selftests are recognised: mock unit tests and integration
>> tests. Mock unit tests are run as soon as the module is loaded, before
>> the device is probed. At that point there is no driver instantiated and
>> all hw interactions must be "mocked". This is very useful for writing
>> universal tests to exercise code not typically run on a broad range of
>> architectures. Alternatively, you can hook into the live selftests and
>> run when the device has been instantiated - hw interactions are real.
>
> One problem I'm running into is that i915_selftest_ is a long prefix,
> especially when we get to something like i915_selftest_timeout(jiffies,
> 							       "format",
> 							       args);
>
> I'm tempted by /i915_selftest_/igt_/. Thoughts?

Like an overall rename presumably and not just this helper? I thinks 
that's fine.

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 02/37] drm/i915: Provide a hook for selftests
  2017-01-13 10:12     ` Tvrtko Ursulin
@ 2017-01-13 10:22       ` Chris Wilson
  2017-01-13 10:42         ` Tvrtko Ursulin
  0 siblings, 1 reply; 81+ messages in thread
From: Chris Wilson @ 2017-01-13 10:22 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx

On Fri, Jan 13, 2017 at 10:12:16AM +0000, Tvrtko Ursulin wrote:
> 
> On 13/01/2017 08:31, Chris Wilson wrote:
> >On Wed, Jan 11, 2017 at 09:09:02PM +0000, Chris Wilson wrote:
> >>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 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.igt__ is interpreted as a subtest executable independently via
> >>igt/drv_selftest.
> >>
> >>Two classes of selftests are recognised: mock unit tests and integration
> >>tests. Mock unit tests are run as soon as the module is loaded, before
> >>the device is probed. At that point there is no driver instantiated and
> >>all hw interactions must be "mocked". This is very useful for writing
> >>universal tests to exercise code not typically run on a broad range of
> >>architectures. Alternatively, you can hook into the live selftests and
> >>run when the device has been instantiated - hw interactions are real.
> >
> >One problem I'm running into is that i915_selftest_ is a long prefix,
> >especially when we get to something like i915_selftest_timeout(jiffies,
> >							       "format",
> >							       args);
> >
> >I'm tempted by /i915_selftest_/igt_/. Thoughts?
> 
> Like an overall rename presumably and not just this helper? I thinks
> that's fine.

I think .../drm/i915/selftests/ is ok (and so i915_selftest.h), I was
thinking of all the helpers like igt_timeout(), igt_subtests()

Hmm. Otoh, if i915_selftest.h talks all about igt_foo that seems wrong.
.../drm/i915/igt/ ?  Then we'd have #include "igt/i915_gem_object.c"
Not sure if that is as clear as #include "selftests/i915_gem_object.c"

So just the helpers, imo, should be igt_foo(). And maybe split
i915_selftest.h between the test boilerplate and the igt helpers.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 02/37] drm/i915: Provide a hook for selftests
  2017-01-13 10:22       ` Chris Wilson
@ 2017-01-13 10:42         ` Tvrtko Ursulin
  0 siblings, 0 replies; 81+ messages in thread
From: Tvrtko Ursulin @ 2017-01-13 10:42 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 13/01/2017 10:22, Chris Wilson wrote:
> On Fri, Jan 13, 2017 at 10:12:16AM +0000, Tvrtko Ursulin wrote:
>>
>> On 13/01/2017 08:31, Chris Wilson wrote:
>>> On Wed, Jan 11, 2017 at 09:09:02PM +0000, Chris Wilson wrote:
>>>> 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 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.igt__ is interpreted as a subtest executable independently via
>>>> igt/drv_selftest.
>>>>
>>>> Two classes of selftests are recognised: mock unit tests and integration
>>>> tests. Mock unit tests are run as soon as the module is loaded, before
>>>> the device is probed. At that point there is no driver instantiated and
>>>> all hw interactions must be "mocked". This is very useful for writing
>>>> universal tests to exercise code not typically run on a broad range of
>>>> architectures. Alternatively, you can hook into the live selftests and
>>>> run when the device has been instantiated - hw interactions are real.
>>>
>>> One problem I'm running into is that i915_selftest_ is a long prefix,
>>> especially when we get to something like i915_selftest_timeout(jiffies,
>>> 							       "format",
>>> 							       args);
>>>
>>> I'm tempted by /i915_selftest_/igt_/. Thoughts?
>>
>> Like an overall rename presumably and not just this helper? I thinks
>> that's fine.
>
> I think .../drm/i915/selftests/ is ok (and so i915_selftest.h), I was
> thinking of all the helpers like igt_timeout(), igt_subtests()
>
> Hmm. Otoh, if i915_selftest.h talks all about igt_foo that seems wrong.
> .../drm/i915/igt/ ?  Then we'd have #include "igt/i915_gem_object.c"
> Not sure if that is as clear as #include "selftests/i915_gem_object.c"
>
> So just the helpers, imo, should be igt_foo(). And maybe split
> i915_selftest.h between the test boilerplate and the igt helpers.

Just the helpers sounds fine. i915_selftest.h is small enough I think to 
keep everything in there.

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 19/37] drm/i915: Test coherency of and barriers between cache domains
  2017-01-11 21:09 ` [PATCH 19/37] drm/i915: Test coherency of and barriers between cache domains Chris Wilson
@ 2017-01-13 11:44   ` Matthew Auld
  2017-01-13 14:13     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Matthew Auld @ 2017-01-13 11:44 UTC (permalink / raw)
  To: Chris Wilson; +Cc: Intel Graphics Development

On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> Write into an object using WB, WC, GTT, and GPU paths and make sure that
> our internal API is sufficient to ensure coherent reads and writes.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/i915_gem.c                    |   1 +
>  .../gpu/drm/i915/selftests/i915_gem_coherency.c    | 355 +++++++++++++++++++++
>  .../gpu/drm/i915/selftests/i915_live_selftests.h   |   1 +
>  3 files changed, 357 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
>
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 4a52c5872898..242d894b356e 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -4899,4 +4899,5 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
>  #include "selftests/mock_gem_device.c"
>  #include "selftests/huge_gem_object.c"
>  #include "selftests/i915_gem_object.c"
> +#include "selftests/i915_gem_coherency.c"
>  #endif
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
> new file mode 100644
> index 000000000000..3e57b7a3c73f
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
> @@ -0,0 +1,355 @@
> +/*
> + * Copyright © 2017 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 <linux/prime_numbers.h>
> +
> +#include "i915_selftest.h"
> +#include "i915_random.h"
> +
> +static int cpu_set(struct drm_i915_gem_object *obj,
> +                  unsigned long offset,
> +                  u32 v)
> +{
> +       unsigned int needs_clflush;
> +       struct page *page;
> +       typeof(v) *map;
Are you expecting typeof v to change, so less churn ?

> +       int err;
> +
> +       err = i915_gem_obj_prepare_shmem_write(obj, &needs_clflush);
> +       if (err)
> +               return err;
> +
> +       page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT);
> +       map = kmap_atomic(page);
> +       if (needs_clflush & CLFLUSH_BEFORE)
> +               clflush(map+offset_in_page(offset) / sizeof(*map));
> +       map[offset_in_page(offset) / sizeof(*map)] = v;
> +       if (needs_clflush & CLFLUSH_AFTER)
> +               clflush(map+offset_in_page(offset) / sizeof(*map));
> +       kunmap_atomic(map);
> +
> +       i915_gem_obj_finish_shmem_access(obj);
> +       return 0;
> +}
> +
> +static int cpu_get(struct drm_i915_gem_object *obj,
> +                  unsigned long offset,
> +                  u32 *v)
> +{
> +       unsigned int needs_clflush;
> +       struct page *page;
> +       typeof(v) map;
> +       int err;
> +
> +       err = i915_gem_obj_prepare_shmem_read(obj, &needs_clflush);
> +       if (err)
> +               return err;
> +
> +       page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT);
> +       map = kmap_atomic(page);
> +       if (needs_clflush & CLFLUSH_BEFORE)
> +               clflush(map+offset_in_page(offset) / sizeof(*map));
> +       *v = map[offset_in_page(offset) / sizeof(*map)];
> +       kunmap_atomic(map);
> +
> +       i915_gem_obj_finish_shmem_access(obj);
> +       return 0;
> +}
> +
> +static int gtt_set(struct drm_i915_gem_object *obj,
> +                  unsigned long offset,
> +                  u32 v)
> +{
> +       struct i915_vma *vma;
> +       typeof(v) *map;
> +       int err;
> +
> +       err = i915_gem_object_set_to_gtt_domain(obj, true);
> +       if (err)
> +               return err;
> +
> +       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
> +       if (IS_ERR(vma))
> +               return PTR_ERR(vma);
> +
> +       map = i915_vma_pin_iomap(vma);
> +       i915_vma_unpin(vma);
> +       if (IS_ERR(map))
> +               return PTR_ERR(map);
> +
> +       map[offset / sizeof(*map)] = v;
> +       i915_vma_unpin_iomap(vma);
> +
> +       return 0;
> +}
> +
> +static int gtt_get(struct drm_i915_gem_object *obj,
> +                  unsigned long offset,
> +                  u32 *v)
> +{
> +       struct i915_vma *vma;
> +       typeof(v) map;
> +       int err;
> +
> +       err = i915_gem_object_set_to_gtt_domain(obj, false);
> +       if (err)
> +               return err;
> +
> +       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
> +       if (IS_ERR(vma))
> +               return PTR_ERR(vma);
> +
> +       map = i915_vma_pin_iomap(vma);
> +       i915_vma_unpin(vma);
> +       if (IS_ERR(map))
> +               return PTR_ERR(map);
> +
> +       *v = map[offset / sizeof(*map)];
> +       i915_vma_unpin_iomap(vma);
> +
> +       return 0;
> +}
> +
> +static int wc_set(struct drm_i915_gem_object *obj,
> +                 unsigned long offset,
> +                 u32 v)
> +{
> +       typeof(v) *map;
> +       int err;
> +
> +       /* XXX GTT write followed by WC write go missing */
> +       i915_gem_object_flush_gtt_write_domain(obj);
> +
> +       err = i915_gem_object_set_to_gtt_domain(obj, true);
> +       if (err)
> +               return err;
> +
> +       map = i915_gem_object_pin_map(obj, I915_MAP_WC);
> +       if (IS_ERR(map))
> +               return PTR_ERR(map);
> +
> +       map[offset / sizeof(*map)] = v;
> +       i915_gem_object_unpin_map(obj);
> +
> +       return 0;
> +}
> +
> +static int wc_get(struct drm_i915_gem_object *obj,
> +                 unsigned long offset,
> +                 u32 *v)
> +{
> +       typeof(v) map;
> +       int err;
> +
> +       /* XXX WC write followed by GTT write go missing */
> +       i915_gem_object_flush_gtt_write_domain(obj);
> +
> +       err = i915_gem_object_set_to_gtt_domain(obj, false);
> +       if (err)
> +               return err;
> +
> +       map = i915_gem_object_pin_map(obj, I915_MAP_WC);
> +       if (IS_ERR(map))
> +               return PTR_ERR(map);
> +
> +       *v = map[offset / sizeof(*map)];
> +       i915_gem_object_unpin_map(obj);
> +
> +       return 0;
> +}
> +
> +static int gpu_set(struct drm_i915_gem_object *obj,
> +                  unsigned long offset,
> +                  u32 v)
> +{
> +       struct drm_i915_private *i915 = to_i915(obj->base.dev);
> +       struct drm_i915_gem_request *rq;
> +       struct i915_vma *vma;
> +       int err;
> +
> +       err = i915_gem_object_set_to_gtt_domain(obj, true);
> +       if (err)
> +               return err;
> +
> +       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
> +       if (IS_ERR(vma))
> +               return PTR_ERR(vma);
> +
> +       rq = i915_gem_request_alloc(i915->engine[RCS], i915->kernel_context);
> +       if (IS_ERR(rq)) {
> +               i915_vma_unpin(vma);
> +               return PTR_ERR(rq);
> +       }
> +
> +       err = intel_ring_begin(rq, 4);
> +       if (err) {
> +               __i915_add_request(rq, false);
> +               i915_vma_unpin(vma);
> +               return err;
> +       }
> +
> +       if (INTEL_GEN(i915) >= 8) {
> +               intel_ring_emit(rq->ring, MI_STORE_DWORD_IMM_GEN4 | 1 << 22);
> +               intel_ring_emit(rq->ring, lower_32_bits(i915_ggtt_offset(vma) + offset));
> +               intel_ring_emit(rq->ring, upper_32_bits(i915_ggtt_offset(vma) + offset));
> +               intel_ring_emit(rq->ring, v);
> +       } else if (INTEL_GEN(i915) >= 4) {
> +               intel_ring_emit(rq->ring, MI_STORE_DWORD_IMM_GEN4 | 1 << 22);
> +               intel_ring_emit(rq->ring, 0);
> +               intel_ring_emit(rq->ring, i915_ggtt_offset(vma) + offset);
> +               intel_ring_emit(rq->ring, v);
> +       } else {
> +               intel_ring_emit(rq->ring, MI_STORE_DWORD_IMM | 1 << 22);
> +               intel_ring_emit(rq->ring, i915_ggtt_offset(vma) + offset);
> +               intel_ring_emit(rq->ring, v);
> +               intel_ring_emit(rq->ring, MI_NOOP);
> +       }
> +       intel_ring_advance(rq->ring);
> +
> +       i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
> +       i915_vma_unpin(vma);
> +
> +       ww_mutex_lock(&obj->resv->lock, NULL);
> +       reservation_object_add_excl_fence(obj->resv, &rq->fence);
> +       ww_mutex_unlock(&obj->resv->lock);
> +
> +       __i915_add_request(rq, true);
> +
> +       return 0;
> +}
> +
> +static const struct igt_coherency_mode {
> +       const char *name;
> +       int (*set)(struct drm_i915_gem_object *, unsigned long offset, u32 v);
> +       int (*get)(struct drm_i915_gem_object *, unsigned long offset, u32 *v);
> +} igt_coherency_mode[] = {
> +       { "cpu", cpu_set, cpu_get },
> +       { "gtt", gtt_set, gtt_get },
> +       { "wc", wc_set, wc_get },
> +       { "gpu", gpu_set, NULL },
> +       { },
> +};
> +
> +static int igt_gem_coherency(void *arg)
> +{
> +       const unsigned int ncachelines = PAGE_SIZE/64;
> +       I915_RND_STATE(prng);
> +       struct drm_i915_private *i915 = arg;
> +       const struct igt_coherency_mode *read, *write, *over;
> +       struct drm_i915_gem_object *obj;
> +       unsigned long count, n;
> +       u32 *offsets, *values;
> +       int err;
> +
> +       offsets = kmalloc_array(ncachelines, 2*sizeof(u32), GFP_KERNEL);
> +       if (!offsets)
> +               return -ENOMEM;
> +       for (count = 0; count < ncachelines; count++)
> +               offsets[count] = count * 64 + 4 * (count % 16);
> +
> +       values = offsets + ncachelines;
> +
> +       mutex_lock(&i915->drm.struct_mutex);
> +       for (over = igt_coherency_mode; over->name; over++) {
> +               if (!over->set)
> +                       continue;
> +
> +               for (write = igt_coherency_mode; write->name; write++) {
> +                       if (!write->set)
> +                               continue;
> +
> +                       for (read = igt_coherency_mode; read->name; read++) {
> +                               if (!read->get)
> +                                       continue;
> +
> +                               for_each_prime_number_from(count, 1, ncachelines) {
> +                                       obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
> +                                       if (IS_ERR(obj))
This looks a little nasty, err may be uninitialised, and even worse it
looks like the if (obj) check will pass.

Otherwise:
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 31/37] drm/i915: Test creation of VMA
  2017-01-11 21:09 ` [PATCH 31/37] drm/i915: Test creation of VMA Chris Wilson
@ 2017-01-13 12:28   ` Joonas Lahtinen
  2017-01-13 12:50     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-13 12:28 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Simple test to exercise creation and lookup of VMA within an object.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> +static int vma_create(struct drm_i915_private *i915,
> +		      struct list_head *objects,
> +		      struct list_head *contexts)

create_vmas?

<SNIP>

> +static int igt_vma_create(void *arg)
> +{
> +	I915_SELFTEST_TIMEOUT(end_time);
> +	LIST_HEAD(objects);
> +	LIST_HEAD(contexts);

Looks aesthetically dispelasing ~ messy, LIST_HEADs could go just
before "int err" as they're not that special?

> +	struct drm_i915_private *i915 = arg;
> +	struct drm_i915_gem_object *obj, *on;
> +	struct i915_gem_context *ctx, *cn;
> +	unsigned long num_obj, num_ctx;
> +	unsigned long no, nc;
> +	int err;
> +
> +	no = 0;
> +	for_each_prime_number(num_obj, 8192) {

max_prime

> +		for (; no < num_obj; no++) {
> +			obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
> +			if (IS_ERR(obj))
> +				goto err;
> +
> +			list_add(&obj->batch_pool_link, &objects);

grumble...

> +		}
> +
> +		list_for_each_entry_safe(ctx, cn, &contexts, link)
> +			mock_context_close(ctx);

I'm unsure why exactly here? On the first round it's empty.

> +
> +		nc = 0;
> +		for_each_prime_number(num_ctx, 8192) {
> +			cond_resched();
> +			if (signal_pending(current)) {
> +				err = -EINTR;
> +				goto err;
> +			}

Again something that could be made into a helper maybe, and then used
in many points? if (igt_exit_point_or_so) return/goto...

> +		if (time_after(jiffies, end_time)) {
> +			pr_warn("%s timed out: after %lu objects\n", __func__, no);
> +			break;
> +		}

Helper too, because it's not important for the testing itself.

<SNIP>

> +int i915_vma_mock_selftests(void)
> +{
> +	static const struct i915_subtest tests[] = {
> +		SUBTEST(igt_vma_create),
> +	};
> +	struct drm_i915_private *i915;
> +	int err;
> +
> +	i915 = mock_gem_device();
> +	if (!i915)
> +		return -ENOMEM;
> +
> +	mutex_lock(&i915->drm.struct_mutex);
> +	err = i915_subtests(tests, i915);
> +	mutex_unlock(&i915->drm.struct_mutex);
> +

I'm unclear if i915 should be released, I feel like it should. If not,
consider renaming mock_gem_device into getterish (but not gibberish).

> +	return err;
> +}
> +
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 32/37] drm/i915: Exercise i915_vma_pin/i915_vma_insert
  2017-01-11 21:09 ` [PATCH 32/37] drm/i915: Exercise i915_vma_pin/i915_vma_insert Chris Wilson
@ 2017-01-13 12:49   ` Joonas Lahtinen
  2017-01-13 12:57     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-13 12:49 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> High-level testing of the struct drm_mm by verifying our handling of
> weird requests to i915_vma_pin.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> +static int igt_vma_pin1(void *arg)
> +{
> +	struct drm_i915_private *i915 = arg;
> +	const struct pin_mode modes[] = {
> +		[0] = { 0, PIN_GLOBAL, assert_pin_valid },

Now that pin_mode is introduced far, use named initializers (especially
when the array starts with plenty of zeros in the first column). Or at
the least, make a comment /* size, flags, assert_func */

<SNIP>

> +
> +		[24] = { 8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096), assert_pin_valid },
> +
> +#if !IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)

Better drop the unnecessarily verbose [NN] =, if an another #if section
is added, it'll be bad. And no real benefit either, inserting a test in
the middle will be bad too, it's not like we never forget something
from first iteration.

> +		/* Misusing BIAS is a programming error (it is not controllable
> +		 * from userspace) so when debugging is enabled, it explodes.
> +		 * However, the tests are still quite interesting for checking
> +		 * variable start, end and size.
> +		 */

Are they ever run? I'd imagine not in the CI at least. Should not hurt
with explanation.

With the array sanitized;

Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 31/37] drm/i915: Test creation of VMA
  2017-01-13 12:28   ` Joonas Lahtinen
@ 2017-01-13 12:50     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-13 12:50 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: intel-gfx

On Fri, Jan 13, 2017 at 02:28:54PM +0200, Joonas Lahtinen wrote:
> On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> > Simple test to exercise creation and lookup of VMA within an object.
> > 
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> 
> <SNIP>
> 
> > +static int vma_create(struct drm_i915_private *i915,
> > +		      struct list_head *objects,
> > +		      struct list_head *contexts)
> 
> create_vmas?
> 
> <SNIP>
> 
> > +static int igt_vma_create(void *arg)
> > +{
> > +	I915_SELFTEST_TIMEOUT(end_time);
> > +	LIST_HEAD(objects);
> > +	LIST_HEAD(contexts);
> 
> Looks aesthetically dispelasing ~ messy, LIST_HEADs could go just
> before "int err" as they're not that special?
> 
> > +	struct drm_i915_private *i915 = arg;
> > +	struct drm_i915_gem_object *obj, *on;
> > +	struct i915_gem_context *ctx, *cn;
> > +	unsigned long num_obj, num_ctx;
> > +	unsigned long no, nc;
> > +	int err;
> > +
> > +	no = 0;
> > +	for_each_prime_number(num_obj, 8192) {
> 
> max_prime

s/8192/ULONG_MAX/ are you serious! ;)

> > +		for (; no < num_obj; no++) {
> > +			obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
> > +			if (IS_ERR(obj))
> > +				goto err;
> > +
> > +			list_add(&obj->batch_pool_link, &objects);
> 
> grumble...

Just put on the rose tinted glasses.
 
> > +		}
> > +
> > +		list_for_each_entry_safe(ctx, cn, &contexts, link)
> > +			mock_context_close(ctx);
> 
> I'm unsure why exactly here? On the first round it's empty.

Just the order in which I wrote the test and there was no reason to move
it...

> > +
> > +		nc = 0;
> > +		for_each_prime_number(num_ctx, 8192) {
> > +			cond_resched();
> > +			if (signal_pending(current)) {
> > +				err = -EINTR;
> > +				goto err;
> > +			}
> 
> Again something that could be made into a helper maybe, and then used
> in many points? if (igt_exit_point_or_so) return/goto...

> > +		if (time_after(jiffies, end_time)) {
> > +			pr_warn("%s timed out: after %lu objects\n", __func__, no);
> > +			break;
> > +		}
> 
> Helper too, because it's not important for the testing itself.

Already igt_timeout(timeout, fmt, ...)

I've been contemplating putting the cond_resched/interruptible check
here. The complaint above is good enough justification.

> <SNIP>
> 
> > +int i915_vma_mock_selftests(void)
> > +{
> > +	static const struct i915_subtest tests[] = {
> > +		SUBTEST(igt_vma_create),
> > +	};
> > +	struct drm_i915_private *i915;
> > +	int err;
> > +
> > +	i915 = mock_gem_device();
> > +	if (!i915)
> > +		return -ENOMEM;
> > +
> > +	mutex_lock(&i915->drm.struct_mutex);
> > +	err = i915_subtests(tests, i915);
> > +	mutex_unlock(&i915->drm.struct_mutex);
> > +
> 
> I'm unclear if i915 should be released, I feel like it should. If not,
> consider renaming mock_gem_device into getterish (but not gibberish).

It was a mistake, i.e. I forgot drm_dev_unref(&i915->drm) here.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 32/37] drm/i915: Exercise i915_vma_pin/i915_vma_insert
  2017-01-13 12:49   ` Joonas Lahtinen
@ 2017-01-13 12:57     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-13 12:57 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: intel-gfx

On Fri, Jan 13, 2017 at 02:49:49PM +0200, Joonas Lahtinen wrote:
> On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> > High-level testing of the struct drm_mm by verifying our handling of
> > weird requests to i915_vma_pin.
> > 
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> 
> <SNIP>
> 
> > +static int igt_vma_pin1(void *arg)
> > +{
> > +	struct drm_i915_private *i915 = arg;
> > +	const struct pin_mode modes[] = {
> > +		[0] = { 0, PIN_GLOBAL, assert_pin_valid },
> 
> Now that pin_mode is introduced far, use named initializers (especially
> when the array starts with plenty of zeros in the first column). Or at
> the least, make a comment /* size, flags, assert_func */
> 
> <SNIP>
> 
> > +
> > +		[24] = { 8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096), assert_pin_valid },
> > +
> > +#if !IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
> 
> Better drop the unnecessarily verbose [NN] =, if an another #if section
> is added, it'll be bad. And no real benefit either, inserting a test in
> the middle will be bad too, it's not like we never forget something
> from first iteration.

It was providing some information in the error report, and I was too
lazy to include the appropriate string. Why do you never let me be lazy!
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 34/37] drm/i915: Test creation of partial VMA
  2017-01-11 21:09 ` [PATCH 34/37] drm/i915: Test creation of partial VMA Chris Wilson
@ 2017-01-13 13:10   ` Joonas Lahtinen
  0 siblings, 0 replies; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-13 13:10 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Mock testing to ensure we can create and lookup partial VMA.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> +static int igt_vma_partial(void *arg)
> +{
> +	struct drm_i915_private *i915 = arg;
> +	const unsigned int npages = 1021; /* prime! */

Yes, but why this prime?

<SNIP>

> +	for (loop = 0; loop <= 1; loop++) { /* exercise both create/lookup */

create_not_lookup, no need for comments

> +		unsigned int count, nvma;
> +
> +		nvma = loop;

nvma = create_not_lookup ? 0 : 1; would make this less cryptic to read.
Compiler shall optimize then.

> +		for_each_prime_number_from(sz, 1, npages) {
> +			for_each_prime_number_from(offset, 0, npages - sz) {
> +				struct i915_ggtt_view view;
> +
> +				view.type = I915_GGTT_VIEW_PARTIAL;
> +				view.partial.offset_size =
> +					offset << INTEL_PARTIAL_SIZE_BITS | (sz - 1);

Could initialize in named manner when declaring?

> +
> +				if (sz == npages)
> +					view.type = I915_GGTT_VIEW_NORMAL;
> +
> +				vma = i915_gem_obj_lookup_or_create_vma(obj, &i915->ggtt.base, &view);
> +				if (IS_ERR(vma)) {
> +					err = PTR_ERR(vma);
> +					goto err_object;
> +				}
> +
> +				if (!i915_vma_is_ggtt(vma)) {
> +					pr_err("VMA is not in the GGTT!\n");
> +					err = -EINVAL;
> +					goto err_object;
> +				}
> +
> +				err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
> +				if (err)
> +					goto err_object;
> +
> +				if (vma->size != sz*PAGE_SIZE) {

Why do you delay this check after pinning?

> +				if (view.type != I915_GGTT_VIEW_NORMAL) {
> +					if (memcmp(&vma->ggtt_view, &view, sizeof(view))) {
> +						pr_err("VMA mismatch upon creation!\n");

Maybe here.

> +						err = -EINVAL;
> +						goto err_object;
> +					}
> +
> +					if (vma->pages == obj->mm.pages) {
> +						pr_err("VMA using unrotated object pages!\n");

At least here speak of "partial VMA", not rotated/regular VMA.

> +				i915_vma_unpin(vma);
> +				nvma++;

num_vma would not be that much worse to type?

<SNIP>

From here;

> +		if (vma->size != obj->base.size) {
> +			pr_err("VMA is wrong size, expected %lu, found %llu\n",
> +			       sz*PAGE_SIZE, vma->size);
> +			err = -EINVAL;
> +			goto err_object;
> +		}
> +
> +		if (vma->node.size < vma->size) {
> +			pr_err("VMA binding too small, expected %llu, found %llu\n",
> +			       vma->size, vma->node.size);
> +			err = -EINVAL;
> +			goto err_object;
> +		}
> +
> +		if (vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) {
> +			pr_err("Not the normal ggtt view! Found %d\n",
> +			       vma->ggtt_view.type);
> +			err = -EINVAL;
> +			goto err_object;
> +		}
> +
> +		if (vma->pages != obj->mm.pages) {
> +			pr_err("VMA not using object pages!\n");
> +			err = -EINVAL;
> +			goto err_object;
> +		}

One big helper function?

Regards, Joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 19/37] drm/i915: Test coherency of and barriers between cache domains
  2017-01-13 11:44   ` Matthew Auld
@ 2017-01-13 14:13     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-13 14:13 UTC (permalink / raw)
  To: Matthew Auld; +Cc: Intel Graphics Development

On Fri, Jan 13, 2017 at 11:44:23AM +0000, Matthew Auld wrote:
> On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > Write into an object using WB, WC, GTT, and GPU paths and make sure that
> > our internal API is sufficient to ensure coherent reads and writes.
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > ---
> >  drivers/gpu/drm/i915/i915_gem.c                    |   1 +
> >  .../gpu/drm/i915/selftests/i915_gem_coherency.c    | 355 +++++++++++++++++++++
> >  .../gpu/drm/i915/selftests/i915_live_selftests.h   |   1 +
> >  3 files changed, 357 insertions(+)
> >  create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
> >
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > index 4a52c5872898..242d894b356e 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -4899,4 +4899,5 @@ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
> >  #include "selftests/mock_gem_device.c"
> >  #include "selftests/huge_gem_object.c"
> >  #include "selftests/i915_gem_object.c"
> > +#include "selftests/i915_gem_coherency.c"
> >  #endif
> > diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
> > new file mode 100644
> > index 000000000000..3e57b7a3c73f
> > --- /dev/null
> > +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
> > @@ -0,0 +1,355 @@
> > +/*
> > + * Copyright © 2017 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 <linux/prime_numbers.h>
> > +
> > +#include "i915_selftest.h"
> > +#include "i915_random.h"
> > +
> > +static int cpu_set(struct drm_i915_gem_object *obj,
> > +                  unsigned long offset,
> > +                  u32 v)
> > +{
> > +       unsigned int needs_clflush;
> > +       struct page *page;
> > +       typeof(v) *map;
> Are you expecting typeof v to change, so less churn ?

A few times in writing. Mainly my intent was to document that map is the
same type as v to avoid any implicit conversion.

> > +       mutex_lock(&i915->drm.struct_mutex);
> > +       for (over = igt_coherency_mode; over->name; over++) {
> > +               if (!over->set)
> > +                       continue;
> > +
> > +               for (write = igt_coherency_mode; write->name; write++) {
> > +                       if (!write->set)
> > +                               continue;
> > +
> > +                       for (read = igt_coherency_mode; read->name; read++) {
> > +                               if (!read->get)
> > +                                       continue;
> > +
> > +                               for_each_prime_number_from(count, 1, ncachelines) {
> > +                                       obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
> > +                                       if (IS_ERR(obj))
> This looks a little nasty, err may be uninitialised, and even worse it
> looks like the if (obj) check will pass.

I forgot about err being unset. I did mean that if we ran out of memory
here, we just give up. That's probably a bit silly, reporting ENOMEM as
an indication that we didn't actually run all phases and so didn't
complete the test is sensible. It was from the time before it looped
over all combinations of modes, thinking that they would be seperate
tests and this was just a memory exhaustion stopping a repeated test.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 35/37] drm/i915: Live testing for context execution
  2017-01-11 21:09 ` [PATCH 35/37] drm/i915: Live testing for context execution Chris Wilson
@ 2017-01-13 14:28   ` Joonas Lahtinen
  2017-01-13 18:35     ` Chris Wilson
  0 siblings, 1 reply; 81+ messages in thread
From: Joonas Lahtinen @ 2017-01-13 14:28 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx

On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Check we can create and execution within a context.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> +static struct i915_vma *
> +gpu_fill_pages(struct i915_vma *vma,
> +	       unsigned long first_page,
> +	       unsigned int offset_in_page,
> +	       unsigned long count,
> +	       u32 value)
> +{
> +	struct drm_i915_gem_object *obj;
> +	const int gen = INTEL_GEN(vma->vm->i915);
> +	unsigned long sz = (4*count + 1)*sizeof(u32);
> +	u64 offset;
> +	u32 *cmd;
> +	int err;
> +
> +	GEM_BUG_ON(offset_in_page >= PAGE_SIZE);

offset_in_page is a function too...

<SNIP>

For future synchronization purposes, maybe document where the below was
cloned from?

> +	offset = PAGE_SIZE * first_page + offset_in_page;
> +	offset += vma->node.start;
> +	for (sz = 0; sz < count; sz++) {
> +		if (gen >= 8) {
> +			*cmd++ = MI_STORE_DWORD_IMM_GEN4;
> +			*cmd++ = lower_32_bits(offset);
> +			*cmd++ = upper_32_bits(offset);
> +			*cmd++ = value;
> +		} else if (gen >= 6) {
> +			*cmd++ = MI_STORE_DWORD_IMM_GEN4;
> +			*cmd++ = 0;
> +			*cmd++ = offset;

GEM_BUG_ON on overflows and so on. In the following branches too. And
maybe be explicit and "= lower_32_bits(offset);"?

> +			*cmd++ = value;
> +		} else if (gen >= 4) {
> +			*cmd++ = MI_STORE_DWORD_IMM_GEN4 | 1 << 22;
> +			*cmd++ = 0;
> +			*cmd++ = offset;
> +			*cmd++ = value;
> +		} else {
> +			*cmd++ = MI_STORE_DWORD_IMM | 1 << 22;
> +			*cmd++ = offset;
> +			*cmd++ = value;
> +		}
> +		offset += PAGE_SIZE;
> +	}

<SNIP>

> 
> +static int gpu_fill(struct drm_i915_gem_object *obj,
> +		    struct i915_gem_context *ctx)
> +{
> +	struct drm_i915_private *i915 = to_i915(obj->base.dev);
> +	const unsigned long npages = obj->base.size >> PAGE_SHIFT;
> +	struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;

vm = &(ctx->ppgtt ?: &i915->ggtt)->base? Or does GCC bork up.

Long line anyway.

> +	struct intel_engine_cs *engine = i915->engine[RCS];

rcs_fill as function name (rcs_fill_pages too)?

> +	err = i915_gem_object_set_to_gtt_domain(obj, false);

Isn't the object most definitely going to be written by GPU?

> +
> +	err = i915_vma_pin(vma, 0, 0, PIN_USER);
> +	if (err)
> +		return err;
> +
> +	GEM_BUG_ON(!IS_ALIGNED(npages, 1024));

Ok, #define time 1024 is a very magicy.

> +	for (page = 0; page < npages; page += 1024) {
> +		unsigned int v = page / 1024;
> +		struct drm_i915_gem_request *rq;
> +		struct i915_vma *batch;
> +
> +		batch = gpu_fill_pages(vma, page, v*sizeof(u32), 1024, v);
> +		if (IS_ERR(batch)) {

err = PTR_ERR(batch);
goto out_unpin;

> +			i915_vma_unpin(vma);
> +			return PTR_ERR(batch);
> +		}
> +
> +		rq = i915_gem_request_alloc(engine, ctx);
> +		if (IS_ERR(rq)) {
> +			i915_vma_unpin(batch);
> +			i915_vma_unpin(vma);
> +			return PTR_ERR(rq);

goto out_unpin:

> +		}
> +
> +		i915_switch_context(rq);

GEM_BUG_ON(rq->engine != engine) to help readability.

This all makes me think how strange our internal API actually is.

> +
> +		ww_mutex_lock(&obj->resv->lock, NULL);
> +		reservation_object_add_excl_fence(obj->resv, &rq->fence);

Wasn't there a patch not to mess with the reservation internals (aka,
wrap it?)

> +		ww_mutex_unlock(&obj->resv->lock);
> +
> +		__i915_add_request(rq, true);
> +	}

I imagine this work submission helper might come in handy as a separate
thing?

> +static int cpu_fill(struct drm_i915_gem_object *obj, u32 value)
> +{
> +	const bool has_llc = HAS_LLC(to_i915(obj->base.dev));

I'm not sure what's the benefit compared to having 'i915' here and
HAS_LLC(i915) later. Except making cocci script more complex when we
i915->has_llc.

> +	unsigned int n, m;
> +	unsigned int need_flush;
> +	int err;
> +
> +	err = i915_gem_obj_prepare_shmem_write(obj, &need_flush);

I wonder why we've not changed to bool.</ponder>

> +	if (err)
> > +		return err;
> +
> > +	for (n = 0; n < 1024; n++) {
> > +		u32 *map;
> +
> > +		map = kmap_atomic(i915_gem_object_get_page(obj, n));
> > +		for (m = 0; m < 1024; m++)
> > +			map[m] = value;
> > +		if (!has_llc)
> > +			drm_clflush_virt_range(map, PAGE_SIZE);
> > +		kunmap_atomic(map);
> > +	}
> +
> > +	i915_gem_obj_finish_shmem_access(obj);
> > +	obj->base.read_domains = I915_GEM_DOMAIN_GTT | I915_GEM_DOMAIN_CPU;
> > +	obj->base.write_domain = 0;
> > +	return 0;
> +}
> +
> +static int cpu_check(struct drm_i915_gem_object *obj,
> > +		     unsigned long num)
> +{
> +	unsigned int n, m, max = (obj->base.size >> PAGE_SHIFT) / 1024;

Split assignment to different line, also, meaningful variable names
would be great.

> +	unsigned int needs_flush;
> +	int err;
> +
> +	err = i915_gem_obj_prepare_shmem_read(obj, &needs_flush);
> +	if (err)
> +		return err;
> +
> +	for (n = 0; !err && n < 1024; n++) {
> +		u32 *map;
> +
> +		map = kmap_atomic(i915_gem_object_get_page(obj, n));

Does some test check the kmap works?

> +static int igt_ctx_exec(void *arg)
> +{

<SNIP>

> +	mutex_lock(&i915->drm.struct_mutex);
> +	while (!time_after(jiffies, end_time)) {

Time budgeted function?

> +		vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;
> +		npages = min(vm->total / 2, 1024ull * 1024 * PAGE_SIZE);
> +		npages >>= PAGE_SHIFT + 10;
> +		npages <<= PAGE_SHIFT + 10;

What? Comment please.

> +		obj = huge_gem_object(i915, 1024 * PAGE_SIZE, npages);
> > +		if (IS_ERR(obj))
> > +			break;
> +
> > +		/* tie the handle to the drm_file for easy reaping */
> > +		err = drm_gem_handle_create(file, &obj->base, &ignored);
> > +		if (err) {
> > +			i915_gem_object_put(obj);
> > +			break;
> > +		}
> +
> > +		err = cpu_fill(obj, 0xdeadbeef);
> > +		if (!err)
> > +			err = gpu_fill(obj, ctx);
> > +		if (err) {
> +			pr_err("Failed to fill object, err=%d\n", err);

Might be informative if it was GPU or CPU? The functions themselves are
silent.

> +			break;
> +		}
> +
> +		list_add_tail(&obj->batch_pool_link, &objects);
> +		count++;
> +	}
> +	pr_info("Submitted %d contexts\n", count);
> +
> +	count = 0;
> +	list_for_each_entry(obj, &objects, batch_pool_link) {
> +		if (!err)
> +			err = cpu_check(obj, count);

break; count is not used after this point, so why does it matter after?

> +		count++;
> +	}

Regards, joonas
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 35/37] drm/i915: Live testing for context execution
  2017-01-13 14:28   ` Joonas Lahtinen
@ 2017-01-13 18:35     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-13 18:35 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: intel-gfx

On Fri, Jan 13, 2017 at 04:28:58PM +0200, Joonas Lahtinen wrote:
> On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> <SNIP>
> 
> For future synchronization purposes, maybe document where the below was
> cloned from?

It is a routine I've written many times.

> > +	offset = PAGE_SIZE * first_page + offset_in_page;
> > +	offset += vma->node.start;
> > +	for (sz = 0; sz < count; sz++) {
> > +		if (gen >= 8) {
> > +			*cmd++ = MI_STORE_DWORD_IMM_GEN4;
> > +			*cmd++ = lower_32_bits(offset);
> > +			*cmd++ = upper_32_bits(offset);
> > +			*cmd++ = value;
> > +		} else if (gen >= 6) {
> > +			*cmd++ = MI_STORE_DWORD_IMM_GEN4;
> > +			*cmd++ = 0;
> > +			*cmd++ = offset;

> > +static int gpu_fill(struct drm_i915_gem_object *obj,
> > +		    struct i915_gem_context *ctx)
> > +{
> > +	struct drm_i915_private *i915 = to_i915(obj->base.dev);
> > +	const unsigned long npages = obj->base.size >> PAGE_SHIFT;
> > +	struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;
> 
> vm = &(ctx->ppgtt ?: &i915->ggtt)->base? Or does GCC bork up.

Different types, gcc doesn't like them inside the ternary.
 
> Long line anyway.
> 
> > +	struct intel_engine_cs *engine = i915->engine[RCS];
> 
> rcs_fill as function name (rcs_fill_pages too)?

Now using all engines. Just let me be lazy, just once?

> > +	err = i915_gem_object_set_to_gtt_domain(obj, false);
> 
> Isn't the object most definitely going to be written by GPU?

Yes. But, before we begin I want any CPU writes to be flushed to memory
(if not LLC).
 
> > +
> > +	err = i915_vma_pin(vma, 0, 0, PIN_USER);
> > +	if (err)
> > +		return err;
> > +
> > +	GEM_BUG_ON(!IS_ALIGNED(npages, 1024));
> 
> Ok, #define time 1024 is a very magicy.

You're going to love the replacement magic. No spoilers I'm afraid.
 
> > +		}
> > +
> > +		i915_switch_context(rq);
> 
> GEM_BUG_ON(rq->engine != engine) to help readability.

Don't see how that helps readibility. That's a check that should in the
earlier request construction tests.
 
> This all makes me think how strange our internal API actually is.

Yes.
 
> > +
> > +		ww_mutex_lock(&obj->resv->lock, NULL);
> > +		reservation_object_add_excl_fence(obj->resv, &rq->fence);
> 
> Wasn't there a patch not to mess with the reservation internals (aka,
> wrap it?)

My bad, I keep thinking that it is still private to my tree.
 
> > +		ww_mutex_unlock(&obj->resv->lock);
> > +
> > +		__i915_add_request(rq, true);
> > +	}
> 
> I imagine this work submission helper might come in handy as a separate
> thing?

Not quite yet. But something like this. Kind of waiting for more users
plus. There are some quirks that need some care to avoid upsetting
random tests.
 
> > +	for (n = 0; !err && n < 1024; n++) {
> > +		u32 *map;
> > +
> > +		map = kmap_atomic(i915_gem_object_get_page(obj, n));
> 
> Does some test check the kmap works?

No, it's documented as "just works". So if it doesn't we have plenty of
explosions every where.

> > +static int igt_ctx_exec(void *arg)
> > +{
> 
> <SNIP>
> 
> > +	mutex_lock(&i915->drm.struct_mutex);
> > +	while (!time_after(jiffies, end_time)) {
> 
> Time budgeted function?
> 
> > +		vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;
> > +		npages = min(vm->total / 2, 1024ull * 1024 * PAGE_SIZE);
> > +		npages >>= PAGE_SHIFT + 10;
> > +		npages <<= PAGE_SHIFT + 10;
> 
> What? Comment please.

Drop the low 22 bits. What, you'd rather have round_down()? Heresy!

> > +	count = 0;
> > +	list_for_each_entry(obj, &objects, batch_pool_link) {
> > +		if (!err)
> > +			err = cpu_check(obj, count);
> 
> break; count is not used after this point, so why does it matter after?

It was freeing objects until the fake_file trick.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 29/37] drm/i915: Fill different pages of the GTT
  2017-01-13  7:47   ` Joonas Lahtinen
@ 2017-01-13 20:45     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-13 20:45 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: intel-gfx

On Fri, Jan 13, 2017 at 09:47:08AM +0200, Joonas Lahtinen wrote:
> On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> > +
> > +	mutex_lock(&i915->drm.struct_mutex);
> > +	drm_mm_for_each_hole(node, &ggtt->base.mm, this_start, this_end) {
> > +		u64 this_size;
> > +
> > +		if (ggtt->base.mm.color_adjust)
> > +			ggtt->base. mm.color_adjust(node, 0,
> > +						    &this_start, &this_end);
> > +
> > +		this_size = this_end - this_start;
> > +		if (this_size > hole_size) {
> > +			hole_size = this_size;
> > +			hole_start = this_start;
> > +			hole_end = this_end;
> > +		}
> > +	}
> > +	pr_info("Found GGTT hole [%llx, %llx], size %llx\n",
> > +		hole_start, hole_end, hole_size);
> > +	GEM_BUG_ON(hole_start >= hole_end);
> > +
> 
> Why not just walk all the holes big enough to accommodate GTT_PAGE_SIZE
> for better coverage? But for just one hole, with above;

My interest in test was focused on what happens at the edges. The test
tries to put objects of different sizes next to the edge, and see if we
overstepped in the PTE insertion. Looking at the object next below that
was to try and hit different pagetable boundaries, as the pattern is
slightly different to the earlier tests. In particular I'm trying to
reproduce the NULL pointer dereferences seen in gen8_ppgtt_insert_pte and
gen6_ppgtt_insert_pte, but unsucessfully so far.

Anyway, in regards to this test I was looking for multiple pages, but
that is no reason not to use all holes and just timeout.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 17/37] drm/i915: Test partial mappings
  2017-01-11 21:09 ` [PATCH 17/37] drm/i915: Test partial mappings Chris Wilson
@ 2017-01-16 22:05   ` Matthew Auld
  2017-01-16 22:25     ` Chris Wilson
  2017-01-17 12:12   ` Matthew Auld
  1 sibling, 1 reply; 81+ messages in thread
From: Matthew Auld @ 2017-01-16 22:05 UTC (permalink / raw)
  To: Chris Wilson; +Cc: Intel Graphics Development

On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> Create partial mappings to cover a large object, investigating tiling
> (fenced regions) and VMA reuse.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/selftests/i915_gem_object.c | 252 +++++++++++++++++++++++
>  1 file changed, 252 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> index 08e6b49b1e77..df3625f551aa 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> @@ -132,6 +132,257 @@ static int igt_gem_huge(void *arg)
>         return err;
>  }
>
> +struct tile {
> +       unsigned int width;
> +       unsigned int height;
> +       unsigned int stride;
> +       unsigned int size;
> +       unsigned int tiling;
> +       unsigned int swizzle;
> +};
> +
> +static u64 swizzle_bit(unsigned bit, u64 offset)
> +{
> +       return (offset & BIT_ULL(bit)) >> (bit - 6);
> +}
> +
> +static u64 tiled_offset(const struct tile *tile, u64 v)
> +{
> +       u64 x, y;
> +
> +       if (tile->tiling == I915_TILING_NONE)
> +               return v;
> +
> +       switch (tile->swizzle) {
> +       case I915_BIT_6_SWIZZLE_9:
> +               v ^= swizzle_bit(9, v);
> +               break;
> +       case I915_BIT_6_SWIZZLE_9_10:
> +               v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v);
> +               break;
> +       case I915_BIT_6_SWIZZLE_9_11:
> +               v ^= swizzle_bit(9, v) ^ swizzle_bit(11, v);
> +               break;
> +       case I915_BIT_6_SWIZZLE_9_10_11:
> +               v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v) ^ swizzle_bit(11, v);
> +               break;
> +       }
> +
> +       y = div64_u64_rem(v, tile->stride, &x);
> +       v = div64_u64_rem(y, tile->height, &y) * tile->stride * tile->height;
> +
> +       if (tile->tiling == I915_TILING_X) {
> +               v += y * tile->width;
> +               v += div64_u64_rem(x, tile->width, &x) << tile->size;
> +               v += x;
> +       } else {
> +               const unsigned int ytile_span = 16;
> +               const unsigned int ytile_height = 32 * ytile_span;
I don't follow this part, is this a smaller tile within a tile ?
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 17/37] drm/i915: Test partial mappings
  2017-01-16 22:05   ` Matthew Auld
@ 2017-01-16 22:25     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-16 22:25 UTC (permalink / raw)
  To: Matthew Auld; +Cc: Intel Graphics Development

On Mon, Jan 16, 2017 at 10:05:21PM +0000, Matthew Auld wrote:
> On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > Create partial mappings to cover a large object, investigating tiling
> > (fenced regions) and VMA reuse.
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > ---
> >  drivers/gpu/drm/i915/selftests/i915_gem_object.c | 252 +++++++++++++++++++++++
> >  1 file changed, 252 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> > index 08e6b49b1e77..df3625f551aa 100644
> > --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> > +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> > @@ -132,6 +132,257 @@ static int igt_gem_huge(void *arg)
> >         return err;
> >  }
> >
> > +struct tile {
> > +       unsigned int width;
> > +       unsigned int height;
> > +       unsigned int stride;
> > +       unsigned int size;
> > +       unsigned int tiling;
> > +       unsigned int swizzle;
> > +};
> > +
> > +static u64 swizzle_bit(unsigned bit, u64 offset)
> > +{
> > +       return (offset & BIT_ULL(bit)) >> (bit - 6);
> > +}
> > +
> > +static u64 tiled_offset(const struct tile *tile, u64 v)
> > +{
> > +       u64 x, y;
> > +
> > +       if (tile->tiling == I915_TILING_NONE)
> > +               return v;
> > +
> > +       switch (tile->swizzle) {
> > +       case I915_BIT_6_SWIZZLE_9:
> > +               v ^= swizzle_bit(9, v);
> > +               break;
> > +       case I915_BIT_6_SWIZZLE_9_10:
> > +               v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v);
> > +               break;
> > +       case I915_BIT_6_SWIZZLE_9_11:
> > +               v ^= swizzle_bit(9, v) ^ swizzle_bit(11, v);
> > +               break;
> > +       case I915_BIT_6_SWIZZLE_9_10_11:
> > +               v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v) ^ swizzle_bit(11, v);
> > +               break;
> > +       }
> > +
> > +       y = div64_u64_rem(v, tile->stride, &x);
> > +       v = div64_u64_rem(y, tile->height, &y) * tile->stride * tile->height;
> > +
> > +       if (tile->tiling == I915_TILING_X) {
> > +               v += y * tile->width;
> > +               v += div64_u64_rem(x, tile->width, &x) << tile->size;
> > +               v += x;
> > +       } else {
> > +               const unsigned int ytile_span = 16;
> > +               const unsigned int ytile_height = 32 * ytile_span;
> I don't follow this part, is this a smaller tile within a tile ?

Yes, that is one way of thinking about y-tiling, cacheline tiles within
page tiles.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 17/37] drm/i915: Test partial mappings
  2017-01-11 21:09 ` [PATCH 17/37] drm/i915: Test partial mappings Chris Wilson
  2017-01-16 22:05   ` Matthew Auld
@ 2017-01-17 12:12   ` Matthew Auld
  2017-01-17 12:29     ` Chris Wilson
  1 sibling, 1 reply; 81+ messages in thread
From: Matthew Auld @ 2017-01-17 12:12 UTC (permalink / raw)
  To: Chris Wilson; +Cc: Intel Graphics Development

On 11 January 2017 at 21:09, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> Create partial mappings to cover a large object, investigating tiling
> (fenced regions) and VMA reuse.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/selftests/i915_gem_object.c | 252 +++++++++++++++++++++++
>  1 file changed, 252 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> index 08e6b49b1e77..df3625f551aa 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> @@ -132,6 +132,257 @@ static int igt_gem_huge(void *arg)
>         return err;
>  }
>
> +struct tile {
> +       unsigned int width;
> +       unsigned int height;
> +       unsigned int stride;
> +       unsigned int size;
> +       unsigned int tiling;
> +       unsigned int swizzle;
> +};
> +
> +static u64 swizzle_bit(unsigned bit, u64 offset)
> +{
> +       return (offset & BIT_ULL(bit)) >> (bit - 6);
> +}
> +
> +static u64 tiled_offset(const struct tile *tile, u64 v)
> +{
> +       u64 x, y;
> +
> +       if (tile->tiling == I915_TILING_NONE)
> +               return v;
> +
> +       switch (tile->swizzle) {
> +       case I915_BIT_6_SWIZZLE_9:
> +               v ^= swizzle_bit(9, v);
> +               break;
> +       case I915_BIT_6_SWIZZLE_9_10:
> +               v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v);
> +               break;
> +       case I915_BIT_6_SWIZZLE_9_11:
> +               v ^= swizzle_bit(9, v) ^ swizzle_bit(11, v);
> +               break;
> +       case I915_BIT_6_SWIZZLE_9_10_11:
> +               v ^= swizzle_bit(9, v) ^ swizzle_bit(10, v) ^ swizzle_bit(11, v);
> +               break;
> +       }
> +
> +       y = div64_u64_rem(v, tile->stride, &x);
> +       v = div64_u64_rem(y, tile->height, &y) * tile->stride * tile->height;
> +
> +       if (tile->tiling == I915_TILING_X) {
> +               v += y * tile->width;
> +               v += div64_u64_rem(x, tile->width, &x) << tile->size;
> +               v += x;
> +       } else {
> +               const unsigned int ytile_span = 16;
> +               const unsigned int ytile_height = 32 * ytile_span;
> +
> +               v += y * ytile_span;
> +               v += div64_u64_rem(x, ytile_span, &x) * ytile_height;
> +               v += x;
> +       }
> +
> +       return v;
> +}
> +
> +static int check_partial_mapping(struct drm_i915_gem_object *obj,
> +                                const struct tile *tile)
> +{
> +       const unsigned int nreal = obj->scratch / PAGE_SIZE;
> +       const unsigned long npages = obj->base.size / PAGE_SIZE;
> +       struct i915_vma *vma;
> +       unsigned long page;
> +       int err;
> +
> +       cond_resched();
> +       if (signal_pending(current))
> +               return -EINTR;
> +
> +       err = i915_gem_object_set_tiling(obj, tile->tiling, tile->stride);
> +       if (err)
> +               return err;
> +
> +       GEM_BUG_ON(i915_gem_object_get_tiling(obj) != tile->tiling);
> +       GEM_BUG_ON(i915_gem_object_get_stride(obj) != tile->stride);
> +
> +       for_each_prime_number_from(page, 1, npages) {
> +               struct i915_ggtt_view view =
> +                       compute_partial_view(obj, page, MIN_CHUNK_PAGES);
> +               u32 __iomem *io;
> +               struct page *p;
> +               unsigned int n;
> +               u64 offset;
> +               u32 *cpu;
> +
> +               GEM_BUG_ON(intel_partial_get_page_count(&view.partial) > nreal);
> +
> +               err = i915_gem_object_set_to_gtt_domain(obj, true);
> +               if (err)
> +                       return err;
> +
> +               vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
> +               if (IS_ERR(vma)) {
> +                       pr_err("Failed to pin partial view: offset=%lu\n",
> +                              page);
> +                       return PTR_ERR(vma);
> +               }
> +
> +               n = page - intel_partial_get_page_offset(&view.partial);
> +               GEM_BUG_ON(n >= intel_partial_get_page_count(&view.partial));
> +
> +               io = i915_vma_pin_iomap(vma);
> +               i915_vma_unpin(vma);
> +               if (IS_ERR(io)) {
> +                       pr_err("Failed to iomap partial view: offset=%lu\n",
> +                              page);
> +                       return PTR_ERR(io);
> +               }
> +
> +               err = i915_vma_get_fence(vma);
> +               if (err) {
> +                       pr_err("Failed to get fence for partial view: offset=%lu\n",
> +                              page);
> +                       i915_vma_unpin_iomap(vma);
> +                       return PTR_ERR(io);
An odd error code ;)

> +               }
> +
> +               iowrite32(page, io + n * PAGE_SIZE/sizeof(*io));
> +               i915_vma_unpin_iomap(vma);
> +
> +               offset = tiled_offset(tile, page << PAGE_SHIFT);
> +               if (offset >= obj->base.size)
> +                       continue;
> +
> +               i915_gem_object_flush_gtt_write_domain(obj);
> +
> +               p = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT);
> +               cpu = kmap(p) + offset_in_page(offset);
> +               drm_clflush_virt_range(cpu, sizeof(*cpu));
> +               if (*cpu != (u32)page) {
> +                       pr_err("Partial view for %lu [%u] (offset=%llu, size=%u [%llu, row size %u], fence=%d, tiling=%d, stride=%d) misalignment, expected write to page (%llu + %u [0x%llx]) of 0x%x, found 0x%x\n",
> +                              page, n,
> +                              intel_partial_get_page_offset(&view.partial),
> +                              intel_partial_get_page_count(&view.partial),
> +                              vma->size >> PAGE_SHIFT,
> +                              tile_row_pages(obj),
> +                              vma->fence ? vma->fence->id : -1, tile->tiling, tile->stride,
> +                              offset >> PAGE_SHIFT,
> +                              (unsigned int)offset_in_page(offset),
> +                              offset,
> +                              (u32)page, *cpu);
> +                       err = -EINVAL;
> +               }
> +               *cpu = 0;
> +               drm_clflush_virt_range(cpu, sizeof(*cpu));
> +               kunmap(p);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return 0;
> +}
> +
> +static int igt_partial_tiling(void *arg)
> +{
> +       const unsigned int nreal = 1 << 12; /* largest tile row x2 */
> +       struct drm_i915_private *i915 = arg;
> +       struct drm_i915_gem_object *obj;
> +       struct tile tile;
> +       int err;
> +
> +       obj = huge_gem_object(i915,
> +                             nreal << PAGE_SHIFT,
> +                             (1 + next_prime_number(i915->ggtt.base.total >> PAGE_SHIFT)) << PAGE_SHIFT);
> +       if (IS_ERR(obj))
> +               return PTR_ERR(obj);
> +
> +       err = i915_gem_object_pin_pages(obj);
> +       if (err) {
> +               pr_err("Failed to allocate %u pages (%zu total), err=%d\n",
> +                      nreal, obj->base.size / PAGE_SIZE, err);
> +               goto err;
> +       }
> +
> +       tile.height = 1;
> +       tile.width = 1;
> +       tile.size = 0;
> +       tile.stride = 0;
> +       tile.swizzle = I915_BIT_6_SWIZZLE_NONE;
> +       tile.tiling = I915_TILING_NONE;
> +
> +       mutex_lock(&i915->drm.struct_mutex);
> +       err = check_partial_mapping(obj, &tile);
> +       if (err)
> +               goto err_unlock;
> +
> +       for (tile.tiling = I915_TILING_X;
> +            tile.tiling <= I915_TILING_Y;
> +            tile.tiling++) {
> +               unsigned int max_pitch;
> +               unsigned int pitch;
> +
> +               switch (tile.tiling) {
> +               case I915_TILING_X:
> +                       tile.swizzle = i915->mm.bit_6_swizzle_x;
> +                       break;
> +               case I915_TILING_Y:
> +                       tile.swizzle = i915->mm.bit_6_swizzle_y;
> +                       break;
> +               }
> +
> +               if (tile.swizzle == I915_BIT_6_SWIZZLE_UNKNOWN ||
> +                   tile.swizzle == I915_BIT_6_SWIZZLE_9_10_17)
> +                       continue;
> +
> +               if (INTEL_GEN(i915) <= 2) {
> +                       tile.height = 16;
> +                       tile.width = 128;
> +                       tile.size = 11;
> +               } else if (tile.tiling == I915_TILING_Y &&
> +                          HAS_128_BYTE_Y_TILING(i915)) {
> +                       tile.height = 32;
> +                       tile.width = 128;
> +                       tile.size = 12;
> +               } else {
> +                       tile.height = 8;
> +                       tile.width = 512;
> +                       tile.size = 12;
> +               }
> +
> +               if (INTEL_GEN(i915) < 4)
> +                       max_pitch = 8192 / tile.width;
> +               else if (INTEL_GEN(i915) < 7)
> +                       max_pitch = 128 * I965_FENCE_MAX_PITCH_VAL / tile.width;
> +               else
> +                       max_pitch = 128 * GEN7_FENCE_MAX_PITCH_VAL / tile.width;
> +
> +               for (pitch = 1; pitch <= max_pitch; pitch <<= 1) {
> +                       tile.stride = tile.width * pitch;
> +                       err = check_partial_mapping(obj, &tile);
> +                       if (err)
> +                               goto err_unlock;
> +               }
> +
> +               if (INTEL_GEN(i915) >= 4) {
Why do we need this restriction, not enough primes ?

Otherwise seems reasonable:
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: [PATCH 17/37] drm/i915: Test partial mappings
  2017-01-17 12:12   ` Matthew Auld
@ 2017-01-17 12:29     ` Chris Wilson
  0 siblings, 0 replies; 81+ messages in thread
From: Chris Wilson @ 2017-01-17 12:29 UTC (permalink / raw)
  To: Matthew Auld; +Cc: Intel Graphics Development

On Tue, Jan 17, 2017 at 12:12:50PM +0000, Matthew Auld wrote:
> > +               for (pitch = 1; pitch <= max_pitch; pitch <<= 1) {
> > +                       tile.stride = tile.width * pitch;
> > +                       err = check_partial_mapping(obj, &tile);
> > +                       if (err)
> > +                               goto err_unlock;
> > +               }
> > +
> > +               if (INTEL_GEN(i915) >= 4) {
> Why do we need this restriction, not enough primes ?

Hardware restrictions (old gen only have power-of-two fence strides). We
are a doing a test using the GTT and real fence registers. It doesn't work
if we program them wrong ;)
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 81+ messages in thread

end of thread, other threads:[~2017-01-17 12:29 UTC | newest]

Thread overview: 81+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-11 21:09 Selftests Chris Wilson
2017-01-11 21:09 ` [PATCH 01/37] drm: Provide a driver hook for drm_dev_release() Chris Wilson
2017-01-11 21:09 ` [PATCH 02/37] drm/i915: Provide a hook for selftests Chris Wilson
2017-01-12  7:29   ` Tvrtko Ursulin
2017-01-12  7:40     ` Chris Wilson
2017-01-13  8:31   ` Chris Wilson
2017-01-13 10:12     ` Tvrtko Ursulin
2017-01-13 10:22       ` Chris Wilson
2017-01-13 10:42         ` Tvrtko Ursulin
2017-01-11 21:09 ` [PATCH 03/37] drm/i915: Add some selftests for sg_table manipulation Chris Wilson
2017-01-12 10:56   ` Tvrtko Ursulin
2017-01-12 11:14     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 04/37] drm/i915: Add unit tests for the breadcrumb rbtree, insert/remove Chris Wilson
2017-01-11 21:09 ` [PATCH 05/37] drm/i915: Add unit tests for the breadcrumb rbtree, completion Chris Wilson
2017-01-11 21:09 ` [PATCH 06/37] drm/i915: Add unit tests for the breadcrumb rbtree, wakeups Chris Wilson
2017-01-12 11:11   ` Tvrtko Ursulin
2017-01-12 14:37     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 07/37] drm/i915: Mock the GEM device for self-testing Chris Wilson
2017-01-11 21:09 ` [PATCH 08/37] drm/i915: Mock a GGTT " Chris Wilson
2017-01-11 21:09 ` [PATCH 09/37] drm/i915: Mock infrastructure for request emission Chris Wilson
2017-01-12 13:11   ` Tvrtko Ursulin
2017-01-12 13:27     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 10/37] drm/i915: Create a fake object for testing huge allocations Chris Wilson
2017-01-12 10:56   ` Matthew Auld
2017-01-11 21:09 ` [PATCH 11/37] drm/i915: Add selftests for i915_gem_request Chris Wilson
2017-01-12 11:20   ` Tvrtko Ursulin
2017-01-12 11:32     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 12/37] drm/i915: Add a simple request selftest for waiting Chris Wilson
2017-01-12 11:25   ` Tvrtko Ursulin
2017-01-11 21:09 ` [PATCH 13/37] drm/i915: Add a simple fence selftest to i915_gem_request Chris Wilson
2017-01-11 21:09 ` [PATCH 14/37] drm/i915: Simple selftest to exercise live requests Chris Wilson
2017-01-12 12:10   ` Tvrtko Ursulin
2017-01-12 12:20     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 15/37] drm/i915: Add selftests for object allocation, phys Chris Wilson
2017-01-11 21:09 ` [PATCH 16/37] drm/i915: Add a live seftest for GEM objects Chris Wilson
2017-01-12 11:17   ` Matthew Auld
2017-01-11 21:09 ` [PATCH 17/37] drm/i915: Test partial mappings Chris Wilson
2017-01-16 22:05   ` Matthew Auld
2017-01-16 22:25     ` Chris Wilson
2017-01-17 12:12   ` Matthew Auld
2017-01-17 12:29     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 18/37] drm/i915: Test exhaustion of the mmap space Chris Wilson
2017-01-12 17:29   ` Matthew Auld
2017-01-11 21:09 ` [PATCH 19/37] drm/i915: Test coherency of and barriers between cache domains Chris Wilson
2017-01-13 11:44   ` Matthew Auld
2017-01-13 14:13     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 20/37] drm/i915: Move uncore selfchecks to live selftest infrastructure Chris Wilson
2017-01-11 21:09 ` [PATCH 21/37] drm/i915: Test all fw tables during mock selftests Chris Wilson
2017-01-11 21:09 ` [PATCH 22/37] drm/i915: Sanity check all registers for matching fw domains Chris Wilson
2017-01-11 21:09 ` [PATCH 23/37] drm/i915: Add some mock tests for dmabuf interop Chris Wilson
2017-01-11 21:09 ` [PATCH 24/37] drm/i915: Add initial selftests for i915_gem_gtt Chris Wilson
2017-01-11 21:09 ` [PATCH 25/37] drm/i915: Move i915_ppgtt_close() into i915_gem_gtt.c Chris Wilson
2017-01-12 12:43   ` Joonas Lahtinen
2017-01-11 21:09 ` [PATCH 26/37] drm/i915: Assert that we have allocated the drm_mm_node upon pinning Chris Wilson
2017-01-12 12:45   ` Joonas Lahtinen
2017-01-11 21:09 ` [PATCH 27/37] drm/i915: Exercising filling the top/bottom portions of the ppgtt Chris Wilson
2017-01-12 13:32   ` Joonas Lahtinen
2017-01-11 21:09 ` [PATCH 28/37] drm/i915: Exercising filling the top/bottom portions of the global GTT Chris Wilson
2017-01-12 14:05   ` Joonas Lahtinen
2017-01-11 21:09 ` [PATCH 29/37] drm/i915: Fill different pages of the GTT Chris Wilson
2017-01-13  7:47   ` Joonas Lahtinen
2017-01-13 20:45     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 30/37] drm/i915: Exercise filling and removing random ranges from the live GTT Chris Wilson
2017-01-13  8:59   ` Joonas Lahtinen
2017-01-13  9:08     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 31/37] drm/i915: Test creation of VMA Chris Wilson
2017-01-13 12:28   ` Joonas Lahtinen
2017-01-13 12:50     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 32/37] drm/i915: Exercise i915_vma_pin/i915_vma_insert Chris Wilson
2017-01-13 12:49   ` Joonas Lahtinen
2017-01-13 12:57     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 33/37] drm/i915: Verify page layout for rotated VMA Chris Wilson
2017-01-12 17:41   ` Tvrtko Ursulin
2017-01-11 21:09 ` [PATCH 34/37] drm/i915: Test creation of partial VMA Chris Wilson
2017-01-13 13:10   ` Joonas Lahtinen
2017-01-11 21:09 ` [PATCH 35/37] drm/i915: Live testing for context execution Chris Wilson
2017-01-13 14:28   ` Joonas Lahtinen
2017-01-13 18:35     ` Chris Wilson
2017-01-11 21:09 ` [PATCH 36/37] drm/i915: Initial selftests for exercising eviction Chris Wilson
2017-01-11 21:09 ` [PATCH 37/37] drm/i915: Add initial selftests for hang detection and resets Chris Wilson
2017-01-11 22:23 ` ✓ Fi.CI.BAT: success for series starting with [01/37] drm: Provide a driver hook for drm_dev_release() Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.