From b1f9107e1b251b2cbd413062fad3636570d2ea20 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 Oct 2017 23:08:54 +0100 Subject: drm/i915/selftests: Don't try to queue a request with zero delay Instead of trying to create a timer with zero delay (i.e. with expires set to the current jiffies and not the future, an already expired timer), execute that request immediately. v2: Refactor list_del_init+signal into its own little function. v3: Reorder testing so as not to immediately signal a delayed request. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20171024220855.30155-1-chris@chris-wilson.co.uk Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/selftests/mock_engine.c | 37 +++++++++++++++++++++------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index 331c2b09869e..0aafa8a105b8 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -32,6 +32,13 @@ static struct mock_request *first_request(struct mock_engine *engine) link); } +static void advance(struct mock_engine *engine, + struct mock_request *request) +{ + list_del_init(&request->link); + mock_seqno_advance(&engine->base, request->base.global_seqno); +} + static void hw_delay_complete(struct timer_list *t) { struct mock_engine *engine = from_timer(engine, t, hw_delay); @@ -39,15 +46,23 @@ static void hw_delay_complete(struct timer_list *t) 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); - } - + /* Timer fired, first request is complete */ request = first_request(engine); if (request) - mod_timer(&engine->hw_delay, jiffies + request->delay); + advance(engine, request); + + /* + * Also immediately signal any subsequent 0-delay requests, but + * requeue the timer for the next delayed request. + */ + while ((request = first_request(engine))) { + if (request->delay) { + mod_timer(&engine->hw_delay, jiffies + request->delay); + break; + } + + advance(engine, request); + } spin_unlock(&engine->hw_lock); } @@ -98,8 +113,12 @@ static void mock_submit_request(struct drm_i915_gem_request *request) 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); + if (mock->link.prev == &engine->hw_queue) { + if (mock->delay) + mod_timer(&engine->hw_delay, jiffies + mock->delay); + else + advance(engine, mock); + } spin_unlock_irq(&engine->hw_lock); } -- cgit From 6d0dbd309687113009a276886628c7c74c848d3c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 08:13:44 -0700 Subject: drm/i915/selftests: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: David Airlie Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Kees Cook Link: https://patchwork.freedesktop.org/patch/msgid/20171024151344.GA104417@beast Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/selftests/lib_sw_fence.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/lib_sw_fence.c b/drivers/gpu/drm/i915/selftests/lib_sw_fence.c index 3790fdf44a1a..b26f07b55d86 100644 --- a/drivers/gpu/drm/i915/selftests/lib_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/lib_sw_fence.c @@ -49,9 +49,9 @@ void onstack_fence_fini(struct i915_sw_fence *fence) i915_sw_fence_fini(fence); } -static void timed_fence_wake(unsigned long data) +static void timed_fence_wake(struct timer_list *t) { - struct timed_fence *tf = (struct timed_fence *)data; + struct timed_fence *tf = from_timer(tf, t, timer); i915_sw_fence_commit(&tf->fence); } @@ -60,7 +60,7 @@ void timed_fence_init(struct timed_fence *tf, unsigned long expires) { onstack_fence_init(&tf->fence); - setup_timer_on_stack(&tf->timer, timed_fence_wake, (unsigned long)tf); + timer_setup_on_stack(&tf->timer, timed_fence_wake, 0); if (time_after(expires, jiffies)) mod_timer(&tf->timer, expires); -- cgit From 02a1ca45cf33d23c7540b572aed5bf624ba968fe Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Oct 2017 14:13:36 +0100 Subject: Revert "drm/i915/selftests: Convert timers to use timer_setup()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6d0dbd309687113009a276886628c7c74c848d3c. timer_setup_on_stack() does not yet exist: In file included from drivers/gpu/drm/i915/i915_sw_fence.c:517:0: drivers/gpu/drm/i915/selftests/lib_sw_fence.c: In function ‘timed_fence_init’: drivers/gpu/drm/i915/selftests/lib_sw_fence.c:63:2: error: implicit declaration of function ‘timer_setup_on_stack’; did you mean ‘hrtimer_init_on_stack’? [-Werror=implicit-function-declaration] timer_setup_on_stack(&tf->timer, timed_fence_wake, 0); Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20171025131336.2584-1-chris@chris-wilson.co.uk Acked-by: Joonas Lahtinen --- drivers/gpu/drm/i915/selftests/lib_sw_fence.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/lib_sw_fence.c b/drivers/gpu/drm/i915/selftests/lib_sw_fence.c index b26f07b55d86..3790fdf44a1a 100644 --- a/drivers/gpu/drm/i915/selftests/lib_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/lib_sw_fence.c @@ -49,9 +49,9 @@ void onstack_fence_fini(struct i915_sw_fence *fence) i915_sw_fence_fini(fence); } -static void timed_fence_wake(struct timer_list *t) +static void timed_fence_wake(unsigned long data) { - struct timed_fence *tf = from_timer(tf, t, timer); + struct timed_fence *tf = (struct timed_fence *)data; i915_sw_fence_commit(&tf->fence); } @@ -60,7 +60,7 @@ void timed_fence_init(struct timed_fence *tf, unsigned long expires) { onstack_fence_init(&tf->fence); - timer_setup_on_stack(&tf->timer, timed_fence_wake, 0); + setup_timer_on_stack(&tf->timer, timed_fence_wake, (unsigned long)tf); if (time_after(expires, jiffies)) mod_timer(&tf->timer, expires); -- cgit From 69ea47a5a98b198c9d36fe157a3986748a9e2554 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Oct 2017 16:32:07 +0100 Subject: drm/i915/selftests: Hide dangerous tests Some tests are designed to exercise the limits of the HW and may trigger unintended side-effects making the machine unusable. This should not be executed by default, but are still useful for early platform validation. References: https://bugs.freedesktop.org/show_bug.cgi?id=103453 Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20171025153207.9589-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/selftests/intel_uncore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index 3cac22eb47ce..f52a4ab9aa98 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -120,10 +120,10 @@ static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_pri !IS_CHERRYVIEW(dev_priv)) return 0; - if (IS_VALLEYVIEW(dev_priv)) /* XXX system lockup! */ - return 0; - - if (IS_BROADWELL(dev_priv)) /* XXX random GPU hang afterwards! */ + /* + * This test may lockup the machine or cause GPU hangs afterwards. + */ + if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN)) return 0; valid = kzalloc(BITS_TO_LONGS(FW_RANGE) * sizeof(*valid), -- cgit From f6d03042b9ad514077175b5cc53069e0a364d0ec Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Nov 2017 11:05:59 +0000 Subject: drm/i915/selftests: Skip mixed page exhaustion if only small pages available If we only have 4k pages, we can't mix together different combinations of hugepages to see if the world burns. However, as the loops did nothing, we never set err to 0 and reported ENODEV aborting the test. Teach the test to skip instead. Signed-off-by: Chris Wilson Cc: Matthew Auld Cc: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20171107110559.6098-1-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld --- drivers/gpu/drm/i915/selftests/huge_pages.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 5cc8101bb2b1..01af540b6ef9 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -1159,6 +1159,9 @@ static int igt_ppgtt_exhaust_huge(void *arg) int n, i; int err = -ENODEV; + if (supported == I915_GTT_PAGE_SIZE_4K) + return 0; + /* * Sanity check creating objects with a varying mix of page sizes -- * ensuring that our writes lands in the right place. -- cgit From c29ccb9f426e6e4e91c9901bb6ee8dbe6abc48eb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Nov 2017 11:40:51 +0000 Subject: drm/i915/selftests: Take rpm wakeref around GGTT lowlevel tests The vma routines are responsible for acquiring the device rpm wakeref before they poke the HW. However, some of the selftests bypass the higher level vma routines in order to poke directly at the lowlevel GGTT functions; these are then responsible for managing rpm themselves. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20171107114051.10583-1-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 9da0c9f99916..581296860539 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -267,7 +267,9 @@ static int lowlevel_hole(struct drm_i915_private *i915, mock_vma.node.size = BIT_ULL(size); mock_vma.node.start = addr; + intel_runtime_pm_get(i915); vm->insert_entries(vm, &mock_vma, I915_CACHE_NONE, 0); + intel_runtime_pm_put(i915); } count = n; @@ -1047,6 +1049,7 @@ static int igt_ggtt_page(void *arg) goto out_remove; } + intel_runtime_pm_get(i915); for (n = 0; n < count; n++) { u64 offset = tmp.start + order[n] * PAGE_SIZE; u32 __iomem *vaddr; @@ -1086,6 +1089,7 @@ static int igt_ggtt_page(void *arg) break; } } + intel_runtime_pm_put(i915); kfree(order); out_remove: -- cgit From 693b1ccabe43d96a1eb57716ac032632882de20f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Nov 2017 11:56:53 +0000 Subject: drm/i915/selftests: Take rpm wakeref around partial tiling tests Since the partial tiling tests are poking into the GGTT to watch the fence registers in operation, it itself needs the device rpm wakeref in order for the GGTT to remain accessible. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20171107115653.10716-1-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 1b8774a42e48..f32aa6bb79e2 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -317,6 +317,7 @@ static int igt_partial_tiling(void *arg) } mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); if (1) { IGT_TIMEOUT(end); @@ -418,6 +419,7 @@ next_tiling: ; } out_unlock: + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); i915_gem_object_unpin_pages(obj); out: -- cgit From a5266db4d31410fbfb4f40118e58085994e83dbc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 19 Oct 2017 13:16:20 +0200 Subject: drm/i915: Acquire PUNIT->PMIC bus for intel_uncore_forcewake_reset() intel_uncore_forcewake_reset() does forcewake puts and gets as such we need to make sure that no-one tries to access the PUNIT->PMIC bus (on systems where this bus is shared) while it runs, otherwise bad things happen. Normally this is taken care of by the i915_pmic_bus_access_notifier() which does an intel_uncore_forcewake_get(FORCEWAKE_ALL) when some other driver tries to access the PMIC bus, so that later forcewake gets are no-ops (for the duration of the bus access). But intel_uncore_forcewake_reset gets called in 3 cases: 1) Before registering the pmic_bus_access_notifier 2) After unregistering the pmic_bus_access_notifier 3) To reset forcewake state on a GPU reset In all 3 cases the i915_pmic_bus_access_notifier() protection is insufficient. This commit fixes this race by calling iosf_mbi_punit_acquire() before calling intel_uncore_forcewake_reset(). In the case where it is called directly after unregistering the pmic_bus_access_notifier, we need to hold the punit-lock over both calls to avoid a race where intel_uncore_fw_release_timer() may execute between the 2 calls. Reviewed-by: Imre Deak Acked-by: Ingo Molnar Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20171019111620.26761-3-hdegoede@redhat.com --- drivers/gpu/drm/i915/selftests/intel_uncore.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index f52a4ab9aa98..2f6367643171 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -148,7 +148,10 @@ static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_pri for_each_set_bit(offset, valid, FW_RANGE) { i915_reg_t reg = { offset }; + iosf_mbi_punit_acquire(); intel_uncore_forcewake_reset(dev_priv, false); + iosf_mbi_punit_release(); + check_for_unclaimed_mmio(dev_priv); (void)I915_READ(reg); -- cgit From 9511ce1ce7299029acc985ce5f96a1e2e703f084 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 10 Nov 2017 15:19:19 +0000 Subject: drm/i915/selftests: Initialise mock_i915->mm.obj_lock lockdep spotted that the mock tests were using the i915->mm.obj_lock without first initialiasing it: >[ 1303.217043] [IGT] drv_selftest: starting subtest mock_objects <4>[ 1303.240898] Setting dangerous option mock_selftests - tainting kernel <6>[ 1303.253665] i915: Performing mock selftests with st_random_seed=0xd87ea6c6 st_timeout=1000 <4>[ 1303.254812] INFO: trying to register non-static key. <4>[ 1303.254816] the code is fine but needs lockdep annotation. <4>[ 1303.254818] turning off the locking correctness validator. <4>[ 1303.254820] CPU: 4 PID: 13112 Comm: drv_selftest Tainted: G U W 4.14.0-rc8-CI-Patchwork_7058+ #1 <4>[ 1303.254823] Hardware name: MSI MS-7924/Z97M-G43(MS-7924), BIOS V1.12 02/15/2016 <4>[ 1303.254825] Call Trace: <4>[ 1303.254829] dump_stack+0x68/0x9f <4>[ 1303.254832] register_lock_class+0x3fd/0x580 <4>[ 1303.254835] ? ___slab_alloc.constprop.29+0x157/0x3d0 <4>[ 1303.254837] ? ___slab_alloc.constprop.29+0x157/0x3d0 <4>[ 1303.254840] ? sg_kmalloc+0x1e/0x50 <4>[ 1303.254842] ? debug_smp_processor_id+0x17/0x20 <4>[ 1303.254845] __lock_acquire+0xa4/0x1b00 <4>[ 1303.254884] ? __i915_gem_object_set_pages+0x116/0x1f0 [i915] <4>[ 1303.254887] ? __this_cpu_preempt_check+0x13/0x20 <4>[ 1303.254889] ? sg_kmalloc+0x1e/0x50 <4>[ 1303.254891] lock_acquire+0xb0/0x200 <4>[ 1303.254893] ? lock_acquire+0xb0/0x200 <4>[ 1303.254917] ? __i915_gem_object_set_pages+0x116/0x1f0 [i915] <4>[ 1303.254920] _raw_spin_lock+0x32/0x50 <4>[ 1303.254944] ? __i915_gem_object_set_pages+0x116/0x1f0 [i915] <4>[ 1303.254967] __i915_gem_object_set_pages+0x116/0x1f0 [i915] <4>[ 1303.254991] i915_gem_object_get_pages_phys+0x286/0x2b0 [i915] <4>[ 1303.255015] ____i915_gem_object_get_pages+0x20/0x60 [i915] <4>[ 1303.255039] i915_gem_object_attach_phys+0x137/0x1a0 [i915] <4>[ 1303.255063] igt_phys_object+0x45/0x120 [i915] <4>[ 1303.255094] __i915_subtests+0x40/0xd0 [i915] <4>[ 1303.255099] ? work_on_cpu_safe+0x60/0x60 <4>[ 1303.255131] i915_gem_object_mock_selftests+0x34/0x50 [i915] Signed-off-by: Chris Wilson Cc: Matthew Auld Cc: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20171110151919.18451-1-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/selftests/mock_gem_device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 04eb9362f4f8..d2bf2729c331 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -180,6 +180,7 @@ struct drm_i915_private *mock_gem_device(void) I915_GTT_PAGE_SIZE_2M; spin_lock_init(&i915->mm.object_stat_lock); + spin_lock_init(&i915->mm.obj_lock); mock_uncore_init(i915); init_waitqueue_head(&i915->gpu_error.wait_queue); -- cgit From 9c52d1c816baa5b8c97485b20d95af29c98d26ee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 10 Nov 2017 23:24:47 +0000 Subject: drm/i915/selftests: Yet another forgotten mock_i915->mm initialiser Move all of the i915->mm initialisation to a private function that can be reused by the mock i915 device to save forgetting any more steps. For example, <7>[ 1542.046332] [IGT] drv_selftest: starting subtest mock_objects <4>[ 1542.123924] Setting dangerous option mock_selftests - tainting kernel <6>[ 1542.167941] i915: Performing mock selftests with st_random_seed=0x246f5ab5 st_timeout=1000 <4>[ 1542.178012] INFO: trying to register non-static key. <4>[ 1542.178027] the code is fine but needs lockdep annotation. <4>[ 1542.178032] turning off the locking correctness validator. <4>[ 1542.178041] CPU: 3 PID: 6008 Comm: kworker/3:7 Tainted: G U 4.14.0-rc8-CI-CI_DRM_3332+ #1 <4>[ 1542.178049] Hardware name: /NUC6CAYB, BIOS AYAPLCEL.86A.0040.2017.0619.1722 06/19/2017 <4>[ 1542.178144] Workqueue: events __i915_gem_free_work [i915] <4>[ 1542.178152] Call Trace: <4>[ 1542.178163] dump_stack+0x68/0x9f <4>[ 1542.178170] register_lock_class+0x3fd/0x580 <4>[ 1542.178177] ? unwind_next_frame+0x14/0x20 <4>[ 1542.178184] ? __save_stack_trace+0x73/0xd0 <4>[ 1542.178191] __lock_acquire+0xa4/0x1b00 <4>[ 1542.178254] ? __i915_gem_free_work+0x28/0xa0 [i915] <4>[ 1542.178261] ? __lock_acquire+0x4ab/0x1b00 <4>[ 1542.178268] lock_acquire+0xb0/0x200 <4>[ 1542.178273] ? lock_acquire+0xb0/0x200 <4>[ 1542.178336] ? __i915_gem_free_work+0x28/0xa0 [i915] <4>[ 1542.178344] _raw_spin_lock+0x32/0x50 <4>[ 1542.178405] ? __i915_gem_free_work+0x28/0xa0 [i915] <4>[ 1542.178468] __i915_gem_free_work+0x28/0xa0 [i915] <4>[ 1542.178476] process_one_work+0x221/0x650 <4>[ 1542.178483] worker_thread+0x4e/0x3c0 <4>[ 1542.178489] kthread+0x114/0x150 <4>[ 1542.178494] ? process_one_work+0x650/0x650 <4>[ 1542.178499] ? kthread_create_on_node+0x40/0x40 <4>[ 1542.178506] ret_from_fork+0x27/0x40 v2: Fish out i915->mm.object_stat_lock which was being inited over in i915_drv.c (Matthew) Signed-off-by: Chris Wilson Cc: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20171110232447.21618-1-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld --- drivers/gpu/drm/i915/selftests/mock_gem_device.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index d2bf2729c331..80f152aaedf9 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -179,9 +179,8 @@ struct drm_i915_private *mock_gem_device(void) I915_GTT_PAGE_SIZE_64K | I915_GTT_PAGE_SIZE_2M; - spin_lock_init(&i915->mm.object_stat_lock); - spin_lock_init(&i915->mm.obj_lock); mock_uncore_init(i915); + i915_gem_init__mm(i915); init_waitqueue_head(&i915->gpu_error.wait_queue); init_waitqueue_head(&i915->gpu_error.reset_queue); @@ -190,11 +189,6 @@ struct drm_i915_private *mock_gem_device(void) 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); - mock_init_contexts(i915); INIT_DELAYED_WORK(&i915->gt.retire_work, mock_retire_work_handler); -- cgit From 6e1281412ab9e6772d8f6c26e592181fcdd2ae0c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Nov 2017 22:33:46 +0000 Subject: drm/i915/selftests: Always initialise err smatch does not track initialised values as well as gcc, and this triggers many warnings by smatch not presented by gcc. Silence smatch by initialising the error values to -ENODEV, which we use to denote internal errors. (If we see a selftest fail with a silent -ENODEV, we know smatch was right!) v2: smatch was right about igt_create_vma(), it may unlikely fail on the first object allocation which we want to be loud about. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20171114223346.25958-1-chris@chris-wilson.co.uk Reviewed-by: Dhinakaran Pandiyan --- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 8 ++++---- drivers/gpu/drm/i915/selftests/i915_gem_request.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_timeline.c | 2 +- drivers/gpu/drm/i915/selftests/i915_syncmap.c | 6 +++--- drivers/gpu/drm/i915/selftests/i915_vma.c | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index def5052862ae..c82780a9d455 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -325,7 +325,7 @@ static int igt_ctx_exec(void *arg) LIST_HEAD(objects); unsigned long ncontexts, ndwords, dw; bool first_shared_gtt = true; - int err; + int err = -ENODEV; /* Create a few different contexts (with different mm) and write * through each ctx/mm using the GPU making sure those writes end diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 581296860539..d9560d8a6cc8 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -699,7 +699,7 @@ static int drunk_hole(struct drm_i915_private *i915, unsigned int *order, count, n; struct i915_vma *vma; u64 hole_size; - int err; + int err = -ENODEV; hole_size = (hole_end - hole_start) >> size; if (hole_size > KMALLOC_MAX_SIZE / sizeof(u32)) @@ -958,7 +958,7 @@ static int exercise_ggtt(struct drm_i915_private *i915, u64 hole_start, hole_end, last = 0; struct drm_mm_node *node; IGT_TIMEOUT(end_time); - int err; + int err = -ENODEV; mutex_lock(&i915->drm.struct_mutex); restart: @@ -1164,7 +1164,7 @@ static int igt_gtt_reserve(void *arg) struct drm_i915_gem_object *obj, *on; LIST_HEAD(objects); u64 total; - int err; + int err = -ENODEV; /* i915_gem_gtt_reserve() tries to reserve the precise range * for the node, and evicts if it has to. So our test checks that @@ -1355,7 +1355,7 @@ static int igt_gtt_insert(void *arg) }, *ii; LIST_HEAD(objects); u64 total; - int err; + int err = -ENODEV; /* i915_gem_gtt_insert() tries to allocate some free space in the GTT * to the node, evicting if required. diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c index a999161e8db1..6bce99050e94 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c @@ -332,7 +332,7 @@ static int live_nop_request(void *arg) struct intel_engine_cs *engine; struct live_test t; unsigned int id; - int err; + int err = -ENODEV; /* Submit various sized batches of empty requests, to each engine * (individually), and wait for the batch to complete. We can check diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c b/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c index 4795877abe56..3000e6a7d82d 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c @@ -79,7 +79,7 @@ static int igt_sync(void *arg) }, *p; struct intel_timeline *tl; int order, offset; - int ret; + int ret = -ENODEV; tl = mock_timeline(0); if (!tl) diff --git a/drivers/gpu/drm/i915/selftests/i915_syncmap.c b/drivers/gpu/drm/i915/selftests/i915_syncmap.c index bcab3d00a785..47f4ae18a1ef 100644 --- a/drivers/gpu/drm/i915/selftests/i915_syncmap.c +++ b/drivers/gpu/drm/i915/selftests/i915_syncmap.c @@ -333,7 +333,7 @@ static int igt_syncmap_join_below(void *arg) { struct i915_syncmap *sync; unsigned int step, order, idx; - int err; + int err = -ENODEV; i915_syncmap_init(&sync); @@ -402,7 +402,7 @@ static int igt_syncmap_neighbours(void *arg) I915_RND_STATE(prng); IGT_TIMEOUT(end_time); struct i915_syncmap *sync; - int err; + int err = -ENODEV; /* * Each leaf holds KSYNCMAP seqno. Check that when we create KSYNCMAP @@ -447,7 +447,7 @@ static int igt_syncmap_compact(void *arg) { struct i915_syncmap *sync; unsigned int idx, order; - int err; + int err = -ENODEV; i915_syncmap_init(&sync); diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c index 2e86ec136b35..eb89e301b602 100644 --- a/drivers/gpu/drm/i915/selftests/i915_vma.c +++ b/drivers/gpu/drm/i915/selftests/i915_vma.c @@ -150,7 +150,7 @@ static int igt_vma_create(void *arg) IGT_TIMEOUT(end_time); LIST_HEAD(contexts); LIST_HEAD(objects); - int err; + int err = -ENOMEM; /* Exercise creating many vma amonst many objections, checking the * vma creation and lookup routines. -- cgit From fb4e14860b5e24645926ff46d3fe7237e97acc0f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Nov 2017 19:18:42 +0000 Subject: drm/i915/selftests: Markup __iomem for igt_gem_coherency Silence sparse warnings by using __iomem markup and io accessors. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20171114191842.19063-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_coherency.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index 35d778d70626..7a0d1e17c1ad 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -33,7 +33,7 @@ static int cpu_set(struct drm_i915_gem_object *obj, { unsigned int needs_clflush; struct page *page; - typeof(v) *map; + u32 *map; int err; err = i915_gem_obj_prepare_shmem_write(obj, &needs_clflush); @@ -59,7 +59,7 @@ static int cpu_get(struct drm_i915_gem_object *obj, { unsigned int needs_clflush; struct page *page; - typeof(v) map; + u32 *map; int err; err = i915_gem_obj_prepare_shmem_read(obj, &needs_clflush); @@ -82,7 +82,7 @@ static int gtt_set(struct drm_i915_gem_object *obj, u32 v) { struct i915_vma *vma; - typeof(v) *map; + u32 __iomem *map; int err; err = i915_gem_object_set_to_gtt_domain(obj, true); @@ -98,7 +98,7 @@ static int gtt_set(struct drm_i915_gem_object *obj, if (IS_ERR(map)) return PTR_ERR(map); - map[offset / sizeof(*map)] = v; + iowrite32(v, &map[offset / sizeof(*map)]); i915_vma_unpin_iomap(vma); return 0; @@ -109,7 +109,7 @@ static int gtt_get(struct drm_i915_gem_object *obj, u32 *v) { struct i915_vma *vma; - typeof(v) map; + u32 __iomem *map; int err; err = i915_gem_object_set_to_gtt_domain(obj, false); @@ -125,7 +125,7 @@ static int gtt_get(struct drm_i915_gem_object *obj, if (IS_ERR(map)) return PTR_ERR(map); - *v = map[offset / sizeof(*map)]; + *v = ioread32(&map[offset / sizeof(*map)]); i915_vma_unpin_iomap(vma); return 0; @@ -135,7 +135,7 @@ static int wc_set(struct drm_i915_gem_object *obj, unsigned long offset, u32 v) { - typeof(v) *map; + u32 *map; int err; err = i915_gem_object_set_to_wc_domain(obj, true); @@ -156,7 +156,7 @@ static int wc_get(struct drm_i915_gem_object *obj, unsigned long offset, u32 *v) { - typeof(v) map; + u32 *map; int err; err = i915_gem_object_set_to_wc_domain(obj, false); -- cgit From 24fd018aaeaecdba79f85e2232ca37a412e2754b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Nov 2017 15:12:03 +0000 Subject: drm/i915/selftests: Increase size for mock ringbuffer We don't actually emit any commands into the ringbuffer, so we set it very small. However, an upcoming change centralises the wait-for-space into i915_gem_request_alloc() and that imposes a minimum size upon all ringbuffers (mock or real) of MIN_SPACE_FOR_ADD_REQUEST. Grow the mock ringbuffer such that we allocate a single page for the struct+buffer, satisfying the new condition without wasting too much space. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20171115151204.8105-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/mock_engine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index 0aafa8a105b8..55c0e2c15782 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -124,9 +124,11 @@ static void mock_submit_request(struct drm_i915_gem_request *request) static struct intel_ring *mock_ring(struct intel_engine_cs *engine) { - const unsigned long sz = roundup_pow_of_two(sizeof(struct intel_ring)); + const unsigned long sz = PAGE_SIZE / 2; struct intel_ring *ring; + BUILD_BUG_ON(MIN_SPACE_FOR_ADD_REQUEST > sz); + ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL); if (!ring) return NULL; -- cgit From 4fe95b042d9d36744f6848069a92759c10dd2a0e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Nov 2017 15:25:58 +0000 Subject: drm/i915/selftests: exercise_ggtt may have nothing to do When operating on the live_ggtt we have to find a usuable hole for our test. It is possible for there to be no hole we can use, so initialise the err to 0 for the early exit. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20171115152558.31252-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index d9560d8a6cc8..3dcf886a2802 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -958,7 +958,7 @@ static int exercise_ggtt(struct drm_i915_private *i915, u64 hole_start, hole_end, last = 0; struct drm_mm_node *node; IGT_TIMEOUT(end_time); - int err = -ENODEV; + int err = 0; mutex_lock(&i915->drm.struct_mutex); restart: -- cgit From 55bd6bd75717ca67b790cc1a457cab92adcce148 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 16 Nov 2017 14:06:31 -0800 Subject: drm/i915/selftests: Add a GuC doorbells selftest The first test aims to check guc_init_doorbell_hw, changing the existing guc clients and doorbells state before calling it. The second test tries to create as many clients as it is currently possible (currently limited to max number of doorbells) and exercise the doorbell alloc/dealloc code. Since our usage mode require very few clients/doorbells, this code has been exercised very lightly and it's good to have a simple test for it. As reference, this test already helped identify the bug fixed by commit 7f1ea2ac3017 ("drm/i915/guc: Fix doorbell id selection"). v2: Extend number of clients; check for client allocation failure when number of doorbells is exceeded; validate client properties; reuse guc_init_doorbell_hw (Chris). v3: guc_init_doorbell_hw test added per Chris suggestion. v4: Try to explain why guc_init_doorbell_hw exist and comment some details in the subtest. v5: Remove redundant pr_info at the beginning of each subtest (Chris); rebase (s/i915_guc_client/intel_guc_client/). Signed-off-by: Michel Thierry Cc: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Chris Wilson Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20171116220632.1909-1-michel.thierry@intel.com Signed-off-by: Chris Wilson --- .../gpu/drm/i915/selftests/i915_live_selftests.h | 1 + drivers/gpu/drm/i915/selftests/intel_guc.c | 367 +++++++++++++++++++++ 2 files changed, 368 insertions(+) create mode 100644 drivers/gpu/drm/i915/selftests/intel_guc.c (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h index 54a73534b37e..1b750e92dd08 100644 --- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h +++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h @@ -19,3 +19,4 @@ selftest(evict, i915_gem_evict_live_selftests) selftest(hugepages, i915_gem_huge_page_live_selftests) selftest(contexts, i915_gem_context_live_selftests) selftest(hangcheck, intel_hangcheck_live_selftests) +selftest(guc, intel_guc_live_selftest) diff --git a/drivers/gpu/drm/i915/selftests/intel_guc.c b/drivers/gpu/drm/i915/selftests/intel_guc.c new file mode 100644 index 000000000000..f10029e18820 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/intel_guc.c @@ -0,0 +1,367 @@ +/* + * 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" + +/* max doorbell number + negative test for each client type */ +#define ATTEMPTS (GUC_NUM_DOORBELLS + GUC_CLIENT_PRIORITY_NUM) + +struct intel_guc_client *clients[ATTEMPTS]; + +static bool available_dbs(struct intel_guc *guc, u32 priority) +{ + unsigned long offset; + unsigned long end; + u16 id; + + /* first half is used for normal priority, second half for high */ + offset = 0; + end = GUC_NUM_DOORBELLS / 2; + if (priority <= GUC_CLIENT_PRIORITY_HIGH) { + offset = end; + end += offset; + } + + id = find_next_zero_bit(guc->doorbell_bitmap, end, offset); + if (id < end) + return true; + + return false; +} + +static int check_all_doorbells(struct intel_guc *guc) +{ + u16 db_id; + + pr_info_once("Max number of doorbells: %d", GUC_NUM_DOORBELLS); + for (db_id = 0; db_id < GUC_NUM_DOORBELLS; ++db_id) { + if (!doorbell_ok(guc, db_id)) { + pr_err("doorbell %d, not ok\n", db_id); + return -EIO; + } + } + + return 0; +} + +/* + * Basic client sanity check, handy to validate create_clients. + */ +static int validate_client(struct intel_guc_client *client, + int client_priority, + bool is_preempt_client) +{ + struct drm_i915_private *dev_priv = guc_to_i915(client->guc); + struct i915_gem_context *ctx_owner = is_preempt_client ? + dev_priv->preempt_context : dev_priv->kernel_context; + + if (client->owner != ctx_owner || + client->engines != INTEL_INFO(dev_priv)->ring_mask || + client->priority != client_priority || + client->doorbell_id == GUC_DOORBELL_INVALID) + return -EINVAL; + else + return 0; +} + +/* + * Check that guc_init_doorbell_hw is doing what it should. + * + * During GuC submission enable, we create GuC clients and their doorbells, + * but after resetting the microcontroller (resume & gpu reset), these + * GuC clients are still around, but the status of their doorbells may be + * incorrect. This is the reason behind validating that the doorbells status + * expected by the driver matches what the GuC/HW have. + */ +static int igt_guc_init_doorbell_hw(void *args) +{ + struct drm_i915_private *dev_priv = args; + struct intel_guc *guc; + DECLARE_BITMAP(db_bitmap_bk, GUC_NUM_DOORBELLS); + int i, err = 0; + + GEM_BUG_ON(!HAS_GUC(dev_priv)); + mutex_lock(&dev_priv->drm.struct_mutex); + + guc = &dev_priv->guc; + if (!guc) { + pr_err("No guc object!\n"); + err = -EINVAL; + goto unlock; + } + + err = check_all_doorbells(guc); + if (err) + goto unlock; + + /* + * Get rid of clients created during driver load because the test will + * recreate them. + */ + guc_clients_destroy(guc); + if (guc->execbuf_client || guc->preempt_client) { + pr_err("guc_clients_destroy lied!\n"); + err = -EINVAL; + goto unlock; + } + + err = guc_clients_create(guc); + if (err) { + pr_err("Failed to create clients\n"); + goto unlock; + } + + err = validate_client(guc->execbuf_client, + GUC_CLIENT_PRIORITY_KMD_NORMAL, false); + if (err) { + pr_err("execbug client validation failed\n"); + goto out; + } + + err = validate_client(guc->preempt_client, + GUC_CLIENT_PRIORITY_KMD_HIGH, true); + if (err) { + pr_err("preempt client validation failed\n"); + goto out; + } + + /* each client should have received a doorbell during alloc */ + if (!has_doorbell(guc->execbuf_client) || + !has_doorbell(guc->preempt_client)) { + pr_err("guc_clients_create didn't create doorbells\n"); + err = -EINVAL; + goto out; + } + + /* + * Basic test - an attempt to reallocate a valid doorbell to the + * client it is currently assigned should not cause a failure. + */ + err = guc_init_doorbell_hw(guc); + if (err) + goto out; + + /* + * Negative test - a client with no doorbell (invalid db id). + * Each client gets a doorbell when it is created, after destroying + * the doorbell, the db id is changed to GUC_DOORBELL_INVALID and the + * firmware will reject any attempt to allocate a doorbell with an + * invalid id (db has to be reserved before allocation). + */ + destroy_doorbell(guc->execbuf_client); + if (has_doorbell(guc->execbuf_client)) { + pr_err("destroy db did not work\n"); + err = -EINVAL; + goto out; + } + + err = guc_init_doorbell_hw(guc); + if (err != -EIO) { + pr_err("unexpected (err = %d)", err); + goto out; + } + + if (!available_dbs(guc, guc->execbuf_client->priority)) { + pr_err("doorbell not available when it should\n"); + err = -EIO; + goto out; + } + + /* clean after test */ + err = create_doorbell(guc->execbuf_client); + if (err) { + pr_err("recreate doorbell failed\n"); + goto out; + } + + /* + * Negative test - doorbell_bitmap out of sync, will trigger a few of + * WARN_ON(!doorbell_ok(guc, db_id)) but that's ok as long as the + * doorbells from our clients don't fail. + */ + bitmap_copy(db_bitmap_bk, guc->doorbell_bitmap, GUC_NUM_DOORBELLS); + for (i = 0; i < GUC_NUM_DOORBELLS; i++) + if (i % 2) + test_and_change_bit(i, guc->doorbell_bitmap); + + err = guc_init_doorbell_hw(guc); + if (err) { + pr_err("out of sync doorbell caused an error\n"); + goto out; + } + + /* restore 'correct' db bitmap */ + bitmap_copy(guc->doorbell_bitmap, db_bitmap_bk, GUC_NUM_DOORBELLS); + err = guc_init_doorbell_hw(guc); + if (err) { + pr_err("restored doorbell caused an error\n"); + goto out; + } + +out: + /* + * Leave clean state for other test, plus the driver always destroy the + * clients during unload. + */ + guc_clients_destroy(guc); + guc_clients_create(guc); +unlock: + mutex_unlock(&dev_priv->drm.struct_mutex); + return err; +} + +/* + * Create as many clients as number of doorbells. Note that there's already + * client(s)/doorbell(s) created during driver load, but this test creates + * its own and do not interact with the existing ones. + */ +static int igt_guc_doorbells(void *arg) +{ + struct drm_i915_private *dev_priv = arg; + struct intel_guc *guc; + int i, err = 0; + u16 db_id; + + GEM_BUG_ON(!HAS_GUC(dev_priv)); + mutex_lock(&dev_priv->drm.struct_mutex); + + guc = &dev_priv->guc; + if (!guc) { + pr_err("No guc object!\n"); + err = -EINVAL; + goto unlock; + } + + err = check_all_doorbells(guc); + if (err) + goto unlock; + + for (i = 0; i < ATTEMPTS; i++) { + clients[i] = guc_client_alloc(dev_priv, + INTEL_INFO(dev_priv)->ring_mask, + i % GUC_CLIENT_PRIORITY_NUM, + dev_priv->kernel_context); + + if (!clients[i]) { + pr_err("[%d] No guc client\n", i); + err = -EINVAL; + goto out; + } + + if (IS_ERR(clients[i])) { + if (PTR_ERR(clients[i]) != -ENOSPC) { + pr_err("[%d] unexpected error\n", i); + err = PTR_ERR(clients[i]); + goto out; + } + + if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) { + pr_err("[%d] non-db related alloc fail\n", i); + err = -EINVAL; + goto out; + } + + /* expected, ran out of dbs for this client type */ + continue; + } + + /* + * The check below is only valid because we keep a doorbell + * assigned during the whole life of the client. + */ + if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) { + pr_err("[%d] more clients than doorbells (%d >= %d)\n", + i, clients[i]->stage_id, GUC_NUM_DOORBELLS); + err = -EINVAL; + goto out; + } + + err = validate_client(clients[i], + i % GUC_CLIENT_PRIORITY_NUM, false); + if (err) { + pr_err("[%d] client_alloc sanity check failed!\n", i); + err = -EINVAL; + goto out; + } + + db_id = clients[i]->doorbell_id; + + /* + * Client alloc gives us a doorbell, but we want to exercise + * this ourselves (this resembles guc_init_doorbell_hw) + */ + destroy_doorbell(clients[i]); + if (clients[i]->doorbell_id != GUC_DOORBELL_INVALID) { + pr_err("[%d] destroy db did not work!\n", i); + err = -EINVAL; + goto out; + } + + err = __reserve_doorbell(clients[i]); + if (err) { + pr_err("[%d] Failed to reserve a doorbell\n", i); + goto out; + } + + __update_doorbell_desc(clients[i], clients[i]->doorbell_id); + err = __create_doorbell(clients[i]); + if (err) { + pr_err("[%d] Failed to create a doorbell\n", i); + goto out; + } + + /* doorbell id shouldn't change, we are holding the mutex */ + if (db_id != clients[i]->doorbell_id) { + pr_err("[%d] doorbell id changed (%d != %d)\n", + i, db_id, clients[i]->doorbell_id); + err = -EINVAL; + goto out; + } + + err = check_all_doorbells(guc); + if (err) + goto out; + } + +out: + for (i = 0; i < ATTEMPTS; i++) + if (!IS_ERR_OR_NULL(clients[i])) + guc_client_free(clients[i]); +unlock: + mutex_unlock(&dev_priv->drm.struct_mutex); + return err; +} + +int intel_guc_live_selftest(struct drm_i915_private *dev_priv) +{ + static const struct i915_subtest tests[] = { + SUBTEST(igt_guc_init_doorbell_hw), + SUBTEST(igt_guc_doorbells), + }; + + if (!i915_modparams.enable_guc_submission) + return 0; + + return i915_subtests(tests, dev_priv); +} -- cgit From 223c73a3667a5afe33245d423f867f4c4b1b39ea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Nov 2017 16:29:45 +0000 Subject: drm/i915/selftests: Report ENOMEM clearly for an allocation failure If we can not run the drunk_hole test because we couldn't allocate the memory for the permutation array (even after we tried trimming the size), report a clear ENOMEM. Similary, if we are asked to operate on a hole too small for ourselves, make it skip quietly. v2: Avoid malloc(0) since that returns ZERO_SIZE_PTR not NULL. v3: Fixup similar construction for lowlevel_hole v4: Use u64 >> 1 to avoid 64b div. Signed-off-by: Chris Wilson Cc: Matthew Auld Cc: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20171117101732.4335-1-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20171117162945.16390-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 36 +++++++++++++++++++-------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915/selftests') diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 3dcf886a2802..6491cf0a4f46 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -216,13 +216,21 @@ static int lowlevel_hole(struct drm_i915_private *i915, 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; + count = hole_size >> 1; + if (!count) { + pr_debug("%s: hole is too small [%llx - %llx] >> %d: %lld\n", + __func__, hole_start, hole_end, size, hole_size); + break; + } + do { - count >>= 1; order = i915_random_order(count, &prng); - } while (!order && count); - if (!order) - break; + if (order) + break; + } while (count >>= 1); + if (!count) + return -ENOMEM; + GEM_BUG_ON(!order); GEM_BUG_ON(count * BIT_ULL(size) > vm->total); GEM_BUG_ON(hole_start + count * BIT_ULL(size) > hole_end); @@ -704,13 +712,21 @@ static int drunk_hole(struct drm_i915_private *i915, 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; + count = hole_size >> 1; + if (!count) { + pr_debug("%s: hole is too small [%llx - %llx] >> %d: %lld\n", + __func__, hole_start, hole_end, size, hole_size); + break; + } + do { - count >>= 1; order = i915_random_order(count, &prng); - } while (!order && count); - if (!order) - break; + if (order) + break; + } while (count >>= 1); + if (!count) + return -ENOMEM; + GEM_BUG_ON(!order); /* Ignore allocation failures (i.e. don't report them as * a test failure) as we are purposefully allocating very -- cgit