xref: /openbmc/linux/drivers/gpu/drm/i915/selftests/i915_gem_evict.c (revision 0791faebfe750292a8a842b64795a390ca4a3b51)
1f40a7b75SChris Wilson /*
2f40a7b75SChris Wilson  * Copyright © 2016 Intel Corporation
3f40a7b75SChris Wilson  *
4f40a7b75SChris Wilson  * Permission is hereby granted, free of charge, to any person obtaining a
5f40a7b75SChris Wilson  * copy of this software and associated documentation files (the "Software"),
6f40a7b75SChris Wilson  * to deal in the Software without restriction, including without limitation
7f40a7b75SChris Wilson  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8f40a7b75SChris Wilson  * and/or sell copies of the Software, and to permit persons to whom the
9f40a7b75SChris Wilson  * Software is furnished to do so, subject to the following conditions:
10f40a7b75SChris Wilson  *
11f40a7b75SChris Wilson  * The above copyright notice and this permission notice (including the next
12f40a7b75SChris Wilson  * paragraph) shall be included in all copies or substantial portions of the
13f40a7b75SChris Wilson  * Software.
14f40a7b75SChris Wilson  *
15f40a7b75SChris Wilson  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16f40a7b75SChris Wilson  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17f40a7b75SChris Wilson  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18f40a7b75SChris Wilson  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19f40a7b75SChris Wilson  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20f40a7b75SChris Wilson  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21f40a7b75SChris Wilson  * IN THE SOFTWARE.
22f40a7b75SChris Wilson  *
23f40a7b75SChris Wilson  */
24f40a7b75SChris Wilson 
25b508d01fSJani Nikula #include "gem/i915_gem_internal.h"
2610be98a7SChris Wilson #include "gem/i915_gem_pm.h"
2710be98a7SChris Wilson #include "gem/selftests/igt_gem_utils.h"
2810be98a7SChris Wilson #include "gem/selftests/mock_context.h"
29cb823ed9SChris Wilson #include "gt/intel_gt.h"
30725859b9STejas Upadhyay #include "gt/intel_gt_print.h"
31f40a7b75SChris Wilson 
3210be98a7SChris Wilson #include "i915_selftest.h"
3310be98a7SChris Wilson 
341422768fSChris Wilson #include "igt_flush_test.h"
359c1477e8SChris Wilson #include "lib_sw_fence.h"
369c1477e8SChris Wilson #include "mock_drm.h"
37f40a7b75SChris Wilson #include "mock_gem_device.h"
38f40a7b75SChris Wilson 
quirk_add(struct drm_i915_gem_object * obj,struct list_head * objects)39480cd6ddSChris Wilson static void quirk_add(struct drm_i915_gem_object *obj,
40480cd6ddSChris Wilson 		      struct list_head *objects)
41f40a7b75SChris Wilson {
42480cd6ddSChris Wilson 	/* quirk is only for live tiled objects, use it to declare ownership */
430175969eSChris Wilson 	GEM_BUG_ON(i915_gem_object_has_tiling_quirk(obj));
440175969eSChris Wilson 	i915_gem_object_set_tiling_quirk(obj);
45480cd6ddSChris Wilson 	list_add(&obj->st_link, objects);
46480cd6ddSChris Wilson }
47480cd6ddSChris Wilson 
populate_ggtt(struct i915_ggtt * ggtt,struct list_head * objects)482271a223STvrtko Ursulin static int populate_ggtt(struct i915_ggtt *ggtt, struct list_head *objects)
49480cd6ddSChris Wilson {
50480cd6ddSChris Wilson 	struct drm_i915_gem_object *obj;
519da0ea09SChris Wilson 	unsigned long count;
5271fc448cSChris Wilson 
5371fc448cSChris Wilson 	count = 0;
5475d0a7f3SChris Wilson 	do {
55f40a7b75SChris Wilson 		struct i915_vma *vma;
56f40a7b75SChris Wilson 
572271a223STvrtko Ursulin 		obj = i915_gem_object_create_internal(ggtt->vm.i915,
582271a223STvrtko Ursulin 						      I915_GTT_PAGE_SIZE);
59480cd6ddSChris Wilson 		if (IS_ERR(obj))
60480cd6ddSChris Wilson 			return PTR_ERR(obj);
61480cd6ddSChris Wilson 
6271fc448cSChris Wilson 		vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
6375d0a7f3SChris Wilson 		if (IS_ERR(vma)) {
6475d0a7f3SChris Wilson 			i915_gem_object_put(obj);
6575d0a7f3SChris Wilson 			if (vma == ERR_PTR(-ENOSPC))
6675d0a7f3SChris Wilson 				break;
67f40a7b75SChris Wilson 
6875d0a7f3SChris Wilson 			return PTR_ERR(vma);
6971fc448cSChris Wilson 		}
7071fc448cSChris Wilson 
7175d0a7f3SChris Wilson 		quirk_add(obj, objects);
7275d0a7f3SChris Wilson 		count++;
7375d0a7f3SChris Wilson 	} while (1);
7475d0a7f3SChris Wilson 	pr_debug("Filled GGTT with %lu pages [%llu total]\n",
752271a223STvrtko Ursulin 		 count, ggtt->vm.total / PAGE_SIZE);
7675d0a7f3SChris Wilson 
772271a223STvrtko Ursulin 	if (list_empty(&ggtt->vm.bound_list)) {
78f40a7b75SChris Wilson 		pr_err("No objects on the GGTT inactive list!\n");
79f40a7b75SChris Wilson 		return -EINVAL;
80f40a7b75SChris Wilson 	}
81f40a7b75SChris Wilson 
82f40a7b75SChris Wilson 	return 0;
83f40a7b75SChris Wilson }
84f40a7b75SChris Wilson 
unpin_ggtt(struct i915_ggtt * ggtt)852271a223STvrtko Ursulin static void unpin_ggtt(struct i915_ggtt *ggtt)
86f40a7b75SChris Wilson {
87f40a7b75SChris Wilson 	struct i915_vma *vma;
88f40a7b75SChris Wilson 
892271a223STvrtko Ursulin 	list_for_each_entry(vma, &ggtt->vm.bound_list, vm_link)
900175969eSChris Wilson 		if (i915_gem_object_has_tiling_quirk(vma->obj))
91f40a7b75SChris Wilson 			i915_vma_unpin(vma);
92f40a7b75SChris Wilson }
93f40a7b75SChris Wilson 
cleanup_objects(struct i915_ggtt * ggtt,struct list_head * list)942271a223STvrtko Ursulin static void cleanup_objects(struct i915_ggtt *ggtt, struct list_head *list)
95f40a7b75SChris Wilson {
96f40a7b75SChris Wilson 	struct drm_i915_gem_object *obj, *on;
97f40a7b75SChris Wilson 
98480cd6ddSChris Wilson 	list_for_each_entry_safe(obj, on, list, st_link) {
990175969eSChris Wilson 		GEM_BUG_ON(!i915_gem_object_has_tiling_quirk(obj));
1000175969eSChris Wilson 		i915_gem_object_set_tiling_quirk(obj);
101f40a7b75SChris Wilson 		i915_gem_object_put(obj);
102480cd6ddSChris Wilson 	}
103f40a7b75SChris Wilson 
1042271a223STvrtko Ursulin 	i915_gem_drain_freed_objects(ggtt->vm.i915);
105f40a7b75SChris Wilson }
106f40a7b75SChris Wilson 
igt_evict_something(void * arg)107f40a7b75SChris Wilson static int igt_evict_something(void *arg)
108f40a7b75SChris Wilson {
1092271a223STvrtko Ursulin 	struct intel_gt *gt = arg;
1102271a223STvrtko Ursulin 	struct i915_ggtt *ggtt = gt->ggtt;
111480cd6ddSChris Wilson 	LIST_HEAD(objects);
112f40a7b75SChris Wilson 	int err;
113f40a7b75SChris Wilson 
114f40a7b75SChris Wilson 	/* Fill the GGTT with pinned objects and try to evict one. */
115f40a7b75SChris Wilson 
1162271a223STvrtko Ursulin 	err = populate_ggtt(ggtt, &objects);
117f40a7b75SChris Wilson 	if (err)
118f40a7b75SChris Wilson 		goto cleanup;
119f40a7b75SChris Wilson 
120f40a7b75SChris Wilson 	/* Everything is pinned, nothing should happen */
1212850748eSChris Wilson 	mutex_lock(&ggtt->vm.mutex);
1227e00897bSMaarten Lankhorst 	err = i915_gem_evict_something(&ggtt->vm, NULL,
123f40a7b75SChris Wilson 				       I915_GTT_PAGE_SIZE, 0, 0,
124f40a7b75SChris Wilson 				       0, U64_MAX,
125f40a7b75SChris Wilson 				       0);
1262850748eSChris Wilson 	mutex_unlock(&ggtt->vm.mutex);
127f40a7b75SChris Wilson 	if (err != -ENOSPC) {
128f40a7b75SChris Wilson 		pr_err("i915_gem_evict_something failed on a full GGTT with err=%d\n",
129f40a7b75SChris Wilson 		       err);
130f40a7b75SChris Wilson 		goto cleanup;
131f40a7b75SChris Wilson 	}
132f40a7b75SChris Wilson 
1332271a223STvrtko Ursulin 	unpin_ggtt(ggtt);
134f40a7b75SChris Wilson 
135f40a7b75SChris Wilson 	/* Everything is unpinned, we should be able to evict something */
1362850748eSChris Wilson 	mutex_lock(&ggtt->vm.mutex);
1377e00897bSMaarten Lankhorst 	err = i915_gem_evict_something(&ggtt->vm, NULL,
138f40a7b75SChris Wilson 				       I915_GTT_PAGE_SIZE, 0, 0,
139f40a7b75SChris Wilson 				       0, U64_MAX,
140f40a7b75SChris Wilson 				       0);
1412850748eSChris Wilson 	mutex_unlock(&ggtt->vm.mutex);
142f40a7b75SChris Wilson 	if (err) {
143f40a7b75SChris Wilson 		pr_err("i915_gem_evict_something failed on a full GGTT with err=%d\n",
144f40a7b75SChris Wilson 		       err);
145f40a7b75SChris Wilson 		goto cleanup;
146f40a7b75SChris Wilson 	}
147f40a7b75SChris Wilson 
148f40a7b75SChris Wilson cleanup:
1492271a223STvrtko Ursulin 	cleanup_objects(ggtt, &objects);
150f40a7b75SChris Wilson 	return err;
151f40a7b75SChris Wilson }
152f40a7b75SChris Wilson 
igt_overcommit(void * arg)153f40a7b75SChris Wilson static int igt_overcommit(void *arg)
154f40a7b75SChris Wilson {
1552271a223STvrtko Ursulin 	struct intel_gt *gt = arg;
1562271a223STvrtko Ursulin 	struct i915_ggtt *ggtt = gt->ggtt;
157f40a7b75SChris Wilson 	struct drm_i915_gem_object *obj;
158f40a7b75SChris Wilson 	struct i915_vma *vma;
159480cd6ddSChris Wilson 	LIST_HEAD(objects);
160f40a7b75SChris Wilson 	int err;
161f40a7b75SChris Wilson 
162f40a7b75SChris Wilson 	/* Fill the GGTT with pinned objects and then try to pin one more.
163f40a7b75SChris Wilson 	 * We expect it to fail.
164f40a7b75SChris Wilson 	 */
165f40a7b75SChris Wilson 
1662271a223STvrtko Ursulin 	err = populate_ggtt(ggtt, &objects);
167f40a7b75SChris Wilson 	if (err)
168f40a7b75SChris Wilson 		goto cleanup;
169f40a7b75SChris Wilson 
1702271a223STvrtko Ursulin 	obj = i915_gem_object_create_internal(gt->i915, I915_GTT_PAGE_SIZE);
171f40a7b75SChris Wilson 	if (IS_ERR(obj)) {
172f40a7b75SChris Wilson 		err = PTR_ERR(obj);
173f40a7b75SChris Wilson 		goto cleanup;
174f40a7b75SChris Wilson 	}
175f40a7b75SChris Wilson 
176480cd6ddSChris Wilson 	quirk_add(obj, &objects);
177480cd6ddSChris Wilson 
178f40a7b75SChris Wilson 	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
179e6689501SChris Wilson 	if (vma != ERR_PTR(-ENOSPC)) {
180e6689501SChris Wilson 		pr_err("Failed to evict+insert, i915_gem_object_ggtt_pin returned err=%d\n", (int)PTR_ERR_OR_ZERO(vma));
181f40a7b75SChris Wilson 		err = -EINVAL;
182f40a7b75SChris Wilson 		goto cleanup;
183f40a7b75SChris Wilson 	}
184f40a7b75SChris Wilson 
185f40a7b75SChris Wilson cleanup:
1862271a223STvrtko Ursulin 	cleanup_objects(ggtt, &objects);
187f40a7b75SChris Wilson 	return err;
188f40a7b75SChris Wilson }
189f40a7b75SChris Wilson 
igt_evict_for_vma(void * arg)190f40a7b75SChris Wilson static int igt_evict_for_vma(void *arg)
191f40a7b75SChris Wilson {
1922271a223STvrtko Ursulin 	struct intel_gt *gt = arg;
1932271a223STvrtko Ursulin 	struct i915_ggtt *ggtt = gt->ggtt;
194f40a7b75SChris Wilson 	struct drm_mm_node target = {
195f40a7b75SChris Wilson 		.start = 0,
196f40a7b75SChris Wilson 		.size = 4096,
197f40a7b75SChris Wilson 	};
198480cd6ddSChris Wilson 	LIST_HEAD(objects);
199f40a7b75SChris Wilson 	int err;
200f40a7b75SChris Wilson 
201f40a7b75SChris Wilson 	/* Fill the GGTT with pinned objects and try to evict a range. */
202f40a7b75SChris Wilson 
2032271a223STvrtko Ursulin 	err = populate_ggtt(ggtt, &objects);
204f40a7b75SChris Wilson 	if (err)
205f40a7b75SChris Wilson 		goto cleanup;
206f40a7b75SChris Wilson 
207f40a7b75SChris Wilson 	/* Everything is pinned, nothing should happen */
2082850748eSChris Wilson 	mutex_lock(&ggtt->vm.mutex);
2097e00897bSMaarten Lankhorst 	err = i915_gem_evict_for_node(&ggtt->vm, NULL, &target, 0);
2102850748eSChris Wilson 	mutex_unlock(&ggtt->vm.mutex);
211f40a7b75SChris Wilson 	if (err != -ENOSPC) {
212f40a7b75SChris Wilson 		pr_err("i915_gem_evict_for_node on a full GGTT returned err=%d\n",
213f40a7b75SChris Wilson 		       err);
214f40a7b75SChris Wilson 		goto cleanup;
215f40a7b75SChris Wilson 	}
216f40a7b75SChris Wilson 
2172271a223STvrtko Ursulin 	unpin_ggtt(ggtt);
218f40a7b75SChris Wilson 
219f40a7b75SChris Wilson 	/* Everything is unpinned, we should be able to evict the node */
2202850748eSChris Wilson 	mutex_lock(&ggtt->vm.mutex);
2217e00897bSMaarten Lankhorst 	err = i915_gem_evict_for_node(&ggtt->vm, NULL, &target, 0);
2222850748eSChris Wilson 	mutex_unlock(&ggtt->vm.mutex);
223f40a7b75SChris Wilson 	if (err) {
224f40a7b75SChris Wilson 		pr_err("i915_gem_evict_for_node returned err=%d\n",
225f40a7b75SChris Wilson 		       err);
226f40a7b75SChris Wilson 		goto cleanup;
227f40a7b75SChris Wilson 	}
228f40a7b75SChris Wilson 
229f40a7b75SChris Wilson cleanup:
2302271a223STvrtko Ursulin 	cleanup_objects(ggtt, &objects);
231f40a7b75SChris Wilson 	return err;
232f40a7b75SChris Wilson }
233f40a7b75SChris Wilson 
mock_color_adjust(const struct drm_mm_node * node,unsigned long color,u64 * start,u64 * end)234fceb4303SMatthew Auld static void mock_color_adjust(const struct drm_mm_node *node,
235fceb4303SMatthew Auld 			      unsigned long color,
236fceb4303SMatthew Auld 			      u64 *start,
237fceb4303SMatthew Auld 			      u64 *end)
238fceb4303SMatthew Auld {
239fceb4303SMatthew Auld }
240fceb4303SMatthew Auld 
igt_evict_for_cache_color(void * arg)241fceb4303SMatthew Auld static int igt_evict_for_cache_color(void *arg)
242fceb4303SMatthew Auld {
2432271a223STvrtko Ursulin 	struct intel_gt *gt = arg;
2442271a223STvrtko Ursulin 	struct i915_ggtt *ggtt = gt->ggtt;
245fceb4303SMatthew Auld 	const unsigned long flags = PIN_OFFSET_FIXED;
246fceb4303SMatthew Auld 	struct drm_mm_node target = {
247fceb4303SMatthew Auld 		.start = I915_GTT_PAGE_SIZE * 2,
248fceb4303SMatthew Auld 		.size = I915_GTT_PAGE_SIZE,
249*9275277dSFei Yang 		.color = i915_gem_get_pat_index(gt->i915, I915_CACHE_LLC),
250fceb4303SMatthew Auld 	};
251fceb4303SMatthew Auld 	struct drm_i915_gem_object *obj;
252fceb4303SMatthew Auld 	struct i915_vma *vma;
253480cd6ddSChris Wilson 	LIST_HEAD(objects);
254fceb4303SMatthew Auld 	int err;
255fceb4303SMatthew Auld 
25633dd8899SMatthew Auld 	/*
25733dd8899SMatthew Auld 	 * Currently the use of color_adjust for the GGTT is limited to cache
25833dd8899SMatthew Auld 	 * coloring and guard pages, and so the presence of mm.color_adjust for
25933dd8899SMatthew Auld 	 * the GGTT is assumed to be i915_ggtt_color_adjust, hence using a mock
26033dd8899SMatthew Auld 	 * color adjust will work just fine for our purposes.
261fceb4303SMatthew Auld 	 */
26282ad6443SChris Wilson 	ggtt->vm.mm.color_adjust = mock_color_adjust;
26333dd8899SMatthew Auld 	GEM_BUG_ON(!i915_vm_has_cache_coloring(&ggtt->vm));
264fceb4303SMatthew Auld 
2652271a223STvrtko Ursulin 	obj = i915_gem_object_create_internal(gt->i915, I915_GTT_PAGE_SIZE);
266fceb4303SMatthew Auld 	if (IS_ERR(obj)) {
267fceb4303SMatthew Auld 		err = PTR_ERR(obj);
268fceb4303SMatthew Auld 		goto cleanup;
269fceb4303SMatthew Auld 	}
270a679f58dSChris Wilson 	i915_gem_object_set_cache_coherency(obj, I915_CACHE_LLC);
271480cd6ddSChris Wilson 	quirk_add(obj, &objects);
272fceb4303SMatthew Auld 
273fceb4303SMatthew Auld 	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
274fceb4303SMatthew Auld 				       I915_GTT_PAGE_SIZE | flags);
275fceb4303SMatthew Auld 	if (IS_ERR(vma)) {
276fceb4303SMatthew Auld 		pr_err("[0]i915_gem_object_ggtt_pin failed\n");
277fceb4303SMatthew Auld 		err = PTR_ERR(vma);
278fceb4303SMatthew Auld 		goto cleanup;
279fceb4303SMatthew Auld 	}
280fceb4303SMatthew Auld 
2812271a223STvrtko Ursulin 	obj = i915_gem_object_create_internal(gt->i915, I915_GTT_PAGE_SIZE);
282fceb4303SMatthew Auld 	if (IS_ERR(obj)) {
283fceb4303SMatthew Auld 		err = PTR_ERR(obj);
284fceb4303SMatthew Auld 		goto cleanup;
285fceb4303SMatthew Auld 	}
286a679f58dSChris Wilson 	i915_gem_object_set_cache_coherency(obj, I915_CACHE_LLC);
287480cd6ddSChris Wilson 	quirk_add(obj, &objects);
288fceb4303SMatthew Auld 
289fceb4303SMatthew Auld 	/* Neighbouring; same colour - should fit */
290fceb4303SMatthew Auld 	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
291fceb4303SMatthew Auld 				       (I915_GTT_PAGE_SIZE * 2) | flags);
292fceb4303SMatthew Auld 	if (IS_ERR(vma)) {
293fceb4303SMatthew Auld 		pr_err("[1]i915_gem_object_ggtt_pin failed\n");
294fceb4303SMatthew Auld 		err = PTR_ERR(vma);
295fceb4303SMatthew Auld 		goto cleanup;
296fceb4303SMatthew Auld 	}
297fceb4303SMatthew Auld 
298fceb4303SMatthew Auld 	i915_vma_unpin(vma);
299fceb4303SMatthew Auld 
300fceb4303SMatthew Auld 	/* Remove just the second vma */
3012850748eSChris Wilson 	mutex_lock(&ggtt->vm.mutex);
3027e00897bSMaarten Lankhorst 	err = i915_gem_evict_for_node(&ggtt->vm, NULL, &target, 0);
3032850748eSChris Wilson 	mutex_unlock(&ggtt->vm.mutex);
304fceb4303SMatthew Auld 	if (err) {
305fceb4303SMatthew Auld 		pr_err("[0]i915_gem_evict_for_node returned err=%d\n", err);
306fceb4303SMatthew Auld 		goto cleanup;
307fceb4303SMatthew Auld 	}
308fceb4303SMatthew Auld 
309fceb4303SMatthew Auld 	/* Attempt to remove the first *pinned* vma, by removing the (empty)
310fceb4303SMatthew Auld 	 * neighbour -- this should fail.
311fceb4303SMatthew Auld 	 */
312*9275277dSFei Yang 	target.color = i915_gem_get_pat_index(gt->i915, I915_CACHE_L3_LLC);
313fceb4303SMatthew Auld 
3142850748eSChris Wilson 	mutex_lock(&ggtt->vm.mutex);
3157e00897bSMaarten Lankhorst 	err = i915_gem_evict_for_node(&ggtt->vm, NULL, &target, 0);
3162850748eSChris Wilson 	mutex_unlock(&ggtt->vm.mutex);
317fceb4303SMatthew Auld 	if (!err) {
318fceb4303SMatthew Auld 		pr_err("[1]i915_gem_evict_for_node returned err=%d\n", err);
319fceb4303SMatthew Auld 		err = -EINVAL;
320fceb4303SMatthew Auld 		goto cleanup;
321fceb4303SMatthew Auld 	}
322fceb4303SMatthew Auld 
323fceb4303SMatthew Auld 	err = 0;
324fceb4303SMatthew Auld 
325fceb4303SMatthew Auld cleanup:
3262271a223STvrtko Ursulin 	unpin_ggtt(ggtt);
3272271a223STvrtko Ursulin 	cleanup_objects(ggtt, &objects);
32882ad6443SChris Wilson 	ggtt->vm.mm.color_adjust = NULL;
329fceb4303SMatthew Auld 	return err;
330fceb4303SMatthew Auld }
331fceb4303SMatthew Auld 
igt_evict_vm(void * arg)332f40a7b75SChris Wilson static int igt_evict_vm(void *arg)
333f40a7b75SChris Wilson {
3342271a223STvrtko Ursulin 	struct intel_gt *gt = arg;
3352271a223STvrtko Ursulin 	struct i915_ggtt *ggtt = gt->ggtt;
3366945c53bSMaarten Lankhorst 	struct i915_gem_ww_ctx ww;
337480cd6ddSChris Wilson 	LIST_HEAD(objects);
338f40a7b75SChris Wilson 	int err;
339f40a7b75SChris Wilson 
340f40a7b75SChris Wilson 	/* Fill the GGTT with pinned objects and try to evict everything. */
341f40a7b75SChris Wilson 
3422271a223STvrtko Ursulin 	err = populate_ggtt(ggtt, &objects);
343f40a7b75SChris Wilson 	if (err)
344f40a7b75SChris Wilson 		goto cleanup;
345f40a7b75SChris Wilson 
346f40a7b75SChris Wilson 	/* Everything is pinned, nothing should happen */
3472850748eSChris Wilson 	mutex_lock(&ggtt->vm.mutex);
348801fa7a8SMatthew Auld 	err = i915_gem_evict_vm(&ggtt->vm, NULL, NULL);
3492850748eSChris Wilson 	mutex_unlock(&ggtt->vm.mutex);
350f40a7b75SChris Wilson 	if (err) {
351f40a7b75SChris Wilson 		pr_err("i915_gem_evict_vm on a full GGTT returned err=%d]\n",
352f40a7b75SChris Wilson 		       err);
353f40a7b75SChris Wilson 		goto cleanup;
354f40a7b75SChris Wilson 	}
355f40a7b75SChris Wilson 
3562271a223STvrtko Ursulin 	unpin_ggtt(ggtt);
357f40a7b75SChris Wilson 
3586945c53bSMaarten Lankhorst 	for_i915_gem_ww(&ww, err, false) {
3592850748eSChris Wilson 		mutex_lock(&ggtt->vm.mutex);
360801fa7a8SMatthew Auld 		err = i915_gem_evict_vm(&ggtt->vm, &ww, NULL);
3612850748eSChris Wilson 		mutex_unlock(&ggtt->vm.mutex);
3626945c53bSMaarten Lankhorst 	}
3636945c53bSMaarten Lankhorst 
364f40a7b75SChris Wilson 	if (err) {
365f40a7b75SChris Wilson 		pr_err("i915_gem_evict_vm on a full GGTT returned err=%d]\n",
366f40a7b75SChris Wilson 		       err);
367f40a7b75SChris Wilson 		goto cleanup;
368f40a7b75SChris Wilson 	}
369f40a7b75SChris Wilson 
370f40a7b75SChris Wilson cleanup:
3712271a223STvrtko Ursulin 	cleanup_objects(ggtt, &objects);
372f40a7b75SChris Wilson 	return err;
373f40a7b75SChris Wilson }
374f40a7b75SChris Wilson 
igt_evict_contexts(void * arg)3759c1477e8SChris Wilson static int igt_evict_contexts(void *arg)
3769c1477e8SChris Wilson {
3779c1477e8SChris Wilson 	const u64 PRETEND_GGTT_SIZE = 16ull << 20;
3782271a223STvrtko Ursulin 	struct intel_gt *gt = arg;
3792271a223STvrtko Ursulin 	struct i915_ggtt *ggtt = gt->ggtt;
3802271a223STvrtko Ursulin 	struct drm_i915_private *i915 = gt->i915;
3819c1477e8SChris Wilson 	struct intel_engine_cs *engine;
3829c1477e8SChris Wilson 	enum intel_engine_id id;
3839c1477e8SChris Wilson 	struct reserved {
3849c1477e8SChris Wilson 		struct drm_mm_node node;
3859c1477e8SChris Wilson 		struct reserved *next;
3869c1477e8SChris Wilson 	} *reserved = NULL;
387c9d08cc3SChris Wilson 	intel_wakeref_t wakeref;
3889c1477e8SChris Wilson 	struct drm_mm_node hole;
3899c1477e8SChris Wilson 	unsigned long count;
3909c1477e8SChris Wilson 	int err;
3919c1477e8SChris Wilson 
3929c1477e8SChris Wilson 	/*
3939c1477e8SChris Wilson 	 * The purpose of this test is to verify that we will trigger an
3949c1477e8SChris Wilson 	 * eviction in the GGTT when constructing a request that requires
3959c1477e8SChris Wilson 	 * additional space in the GGTT for pinning the context. This space
3969c1477e8SChris Wilson 	 * is not directly tied to the request so reclaiming it requires
3979c1477e8SChris Wilson 	 * extra work.
3989c1477e8SChris Wilson 	 *
3999c1477e8SChris Wilson 	 * As such this test is only meaningful for full-ppgtt environments
4009c1477e8SChris Wilson 	 * where the GTT space of the request is separate from the GGTT
4019c1477e8SChris Wilson 	 * allocation required to build the request.
4029c1477e8SChris Wilson 	 */
4034bdafb9dSChris Wilson 	if (!HAS_FULL_PPGTT(i915))
4049c1477e8SChris Wilson 		return 0;
4059c1477e8SChris Wilson 
406d858d569SDaniele Ceraolo Spurio 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
4079c1477e8SChris Wilson 
4089c1477e8SChris Wilson 	/* Reserve a block so that we know we have enough to fit a few rq */
4099c1477e8SChris Wilson 	memset(&hole, 0, sizeof(hole));
4102271a223STvrtko Ursulin 	mutex_lock(&ggtt->vm.mutex);
4117e00897bSMaarten Lankhorst 	err = i915_gem_gtt_insert(&ggtt->vm, NULL, &hole,
4129c1477e8SChris Wilson 				  PRETEND_GGTT_SIZE, 0, I915_COLOR_UNEVICTABLE,
4132271a223STvrtko Ursulin 				  0, ggtt->vm.total,
4149c1477e8SChris Wilson 				  PIN_NOEVICT);
4159c1477e8SChris Wilson 	if (err)
4169c1477e8SChris Wilson 		goto out_locked;
4179c1477e8SChris Wilson 
4189c1477e8SChris Wilson 	/* Make the GGTT appear small by filling it with unevictable nodes */
4199c1477e8SChris Wilson 	count = 0;
4209c1477e8SChris Wilson 	do {
4219c1477e8SChris Wilson 		struct reserved *r;
4229c1477e8SChris Wilson 
4232271a223STvrtko Ursulin 		mutex_unlock(&ggtt->vm.mutex);
4249c1477e8SChris Wilson 		r = kcalloc(1, sizeof(*r), GFP_KERNEL);
4252271a223STvrtko Ursulin 		mutex_lock(&ggtt->vm.mutex);
4269c1477e8SChris Wilson 		if (!r) {
4279c1477e8SChris Wilson 			err = -ENOMEM;
4289c1477e8SChris Wilson 			goto out_locked;
4299c1477e8SChris Wilson 		}
4309c1477e8SChris Wilson 
4317e00897bSMaarten Lankhorst 		if (i915_gem_gtt_insert(&ggtt->vm, NULL, &r->node,
4329c1477e8SChris Wilson 					1ul << 20, 0, I915_COLOR_UNEVICTABLE,
4332271a223STvrtko Ursulin 					0, ggtt->vm.total,
4349c1477e8SChris Wilson 					PIN_NOEVICT)) {
4359c1477e8SChris Wilson 			kfree(r);
4369c1477e8SChris Wilson 			break;
4379c1477e8SChris Wilson 		}
4389c1477e8SChris Wilson 
4399c1477e8SChris Wilson 		r->next = reserved;
4409c1477e8SChris Wilson 		reserved = r;
4419c1477e8SChris Wilson 
4429c1477e8SChris Wilson 		count++;
4439c1477e8SChris Wilson 	} while (1);
4449c1477e8SChris Wilson 	drm_mm_remove_node(&hole);
4452271a223STvrtko Ursulin 	mutex_unlock(&ggtt->vm.mutex);
4469c1477e8SChris Wilson 	pr_info("Filled GGTT with %lu 1MiB nodes\n", count);
4479c1477e8SChris Wilson 
4489c1477e8SChris Wilson 	/* Overfill the GGTT with context objects and so try to evict one. */
4492271a223STvrtko Ursulin 	for_each_engine(engine, gt, id) {
4509c1477e8SChris Wilson 		struct i915_sw_fence fence;
451393211e1SMatthew Brost 		struct i915_request *last = NULL;
4529c1477e8SChris Wilson 
4539c1477e8SChris Wilson 		count = 0;
4549c1477e8SChris Wilson 		onstack_fence_init(&fence);
4559c1477e8SChris Wilson 		do {
45657f62622SChris Wilson 			struct intel_context *ce;
457e61e0f51SChris Wilson 			struct i915_request *rq;
4589c1477e8SChris Wilson 
45957f62622SChris Wilson 			ce = intel_context_create(engine);
46057f62622SChris Wilson 			if (IS_ERR(ce))
4619c1477e8SChris Wilson 				break;
4629c1477e8SChris Wilson 
4639c1477e8SChris Wilson 			/* We will need some GGTT space for the rq's context */
4649c1477e8SChris Wilson 			igt_evict_ctl.fail_if_busy = true;
46557f62622SChris Wilson 			rq = intel_context_create_request(ce);
4669c1477e8SChris Wilson 			igt_evict_ctl.fail_if_busy = false;
46757f62622SChris Wilson 			intel_context_put(ce);
4689c1477e8SChris Wilson 
4699c1477e8SChris Wilson 			if (IS_ERR(rq)) {
4709c1477e8SChris Wilson 				/* When full, fail_if_busy will trigger EBUSY */
4719c1477e8SChris Wilson 				if (PTR_ERR(rq) != -EBUSY) {
4722935ed53SChris Wilson 					pr_err("Unexpected error from request alloc (on %s): %d\n",
4732935ed53SChris Wilson 					       engine->name,
4749c1477e8SChris Wilson 					       (int)PTR_ERR(rq));
4759c1477e8SChris Wilson 					err = PTR_ERR(rq);
4769c1477e8SChris Wilson 				}
4779c1477e8SChris Wilson 				break;
4789c1477e8SChris Wilson 			}
4799c1477e8SChris Wilson 
4809c1477e8SChris Wilson 			/* Keep every request/ctx pinned until we are full */
4819c1477e8SChris Wilson 			err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
4829c1477e8SChris Wilson 							       &fence,
4839c1477e8SChris Wilson 							       GFP_KERNEL);
4849c1477e8SChris Wilson 			if (err < 0)
4859c1477e8SChris Wilson 				break;
4869c1477e8SChris Wilson 
487e61e0f51SChris Wilson 			i915_request_add(rq);
4889c1477e8SChris Wilson 			count++;
489393211e1SMatthew Brost 			if (last)
490393211e1SMatthew Brost 				i915_request_put(last);
491393211e1SMatthew Brost 			last = i915_request_get(rq);
4929c1477e8SChris Wilson 			err = 0;
4939c1477e8SChris Wilson 		} while(1);
4949c1477e8SChris Wilson 		onstack_fence_fini(&fence);
4959c1477e8SChris Wilson 		pr_info("Submitted %lu contexts/requests on %s\n",
4969c1477e8SChris Wilson 			count, engine->name);
4979c1477e8SChris Wilson 		if (err)
4989c1477e8SChris Wilson 			break;
499393211e1SMatthew Brost 		if (last) {
500393211e1SMatthew Brost 			if (i915_request_wait(last, 0, HZ) < 0) {
501393211e1SMatthew Brost 				err = -EIO;
502393211e1SMatthew Brost 				i915_request_put(last);
503393211e1SMatthew Brost 				pr_err("Failed waiting for last request (on %s)",
504393211e1SMatthew Brost 				       engine->name);
505393211e1SMatthew Brost 				break;
506393211e1SMatthew Brost 			}
507393211e1SMatthew Brost 			i915_request_put(last);
508393211e1SMatthew Brost 		}
509393211e1SMatthew Brost 		err = intel_gt_wait_for_idle(engine->gt, HZ * 3);
510393211e1SMatthew Brost 		if (err) {
511725859b9STejas Upadhyay 			gt_err(engine->gt, "Failed to idle GT (on %s)",
512725859b9STejas Upadhyay 			       engine->name);
513393211e1SMatthew Brost 			break;
514393211e1SMatthew Brost 		}
5159c1477e8SChris Wilson 	}
5169c1477e8SChris Wilson 
5172271a223STvrtko Ursulin 	mutex_lock(&ggtt->vm.mutex);
5189c1477e8SChris Wilson out_locked:
5197e805762SChris Wilson 	if (igt_flush_test(i915))
5201422768fSChris Wilson 		err = -EIO;
5219c1477e8SChris Wilson 	while (reserved) {
5229c1477e8SChris Wilson 		struct reserved *next = reserved->next;
5239c1477e8SChris Wilson 
5249c1477e8SChris Wilson 		drm_mm_remove_node(&reserved->node);
5259c1477e8SChris Wilson 		kfree(reserved);
5269c1477e8SChris Wilson 
5279c1477e8SChris Wilson 		reserved = next;
5289c1477e8SChris Wilson 	}
5299c1477e8SChris Wilson 	if (drm_mm_node_allocated(&hole))
5309c1477e8SChris Wilson 		drm_mm_remove_node(&hole);
5312271a223STvrtko Ursulin 	mutex_unlock(&ggtt->vm.mutex);
532d858d569SDaniele Ceraolo Spurio 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
5339c1477e8SChris Wilson 
5349c1477e8SChris Wilson 	return err;
5359c1477e8SChris Wilson }
5369c1477e8SChris Wilson 
i915_gem_evict_mock_selftests(void)537f40a7b75SChris Wilson int i915_gem_evict_mock_selftests(void)
538f40a7b75SChris Wilson {
539f40a7b75SChris Wilson 	static const struct i915_subtest tests[] = {
540f40a7b75SChris Wilson 		SUBTEST(igt_evict_something),
541f40a7b75SChris Wilson 		SUBTEST(igt_evict_for_vma),
542fceb4303SMatthew Auld 		SUBTEST(igt_evict_for_cache_color),
543f40a7b75SChris Wilson 		SUBTEST(igt_evict_vm),
544f40a7b75SChris Wilson 		SUBTEST(igt_overcommit),
545f40a7b75SChris Wilson 	};
546f40a7b75SChris Wilson 	struct drm_i915_private *i915;
547c9d08cc3SChris Wilson 	intel_wakeref_t wakeref;
548d4225a53SChris Wilson 	int err = 0;
549f40a7b75SChris Wilson 
550f40a7b75SChris Wilson 	i915 = mock_gem_device();
551f40a7b75SChris Wilson 	if (!i915)
552f40a7b75SChris Wilson 		return -ENOMEM;
553f40a7b75SChris Wilson 
554c447ff7dSDaniele Ceraolo Spurio 	with_intel_runtime_pm(&i915->runtime_pm, wakeref)
5558c2699faSAndi Shyti 		err = i915_subtests(tests, to_gt(i915));
556c9d08cc3SChris Wilson 
55782be0d75SDaniel Vetter 	mock_destroy_device(i915);
558f40a7b75SChris Wilson 	return err;
559f40a7b75SChris Wilson }
5609c1477e8SChris Wilson 
i915_gem_evict_live_selftests(struct drm_i915_private * i915)5619c1477e8SChris Wilson int i915_gem_evict_live_selftests(struct drm_i915_private *i915)
5629c1477e8SChris Wilson {
5639c1477e8SChris Wilson 	static const struct i915_subtest tests[] = {
5649c1477e8SChris Wilson 		SUBTEST(igt_evict_contexts),
5659c1477e8SChris Wilson 	};
5669c1477e8SChris Wilson 
5678c2699faSAndi Shyti 	if (intel_gt_is_wedged(to_gt(i915)))
5687783decfSChris Wilson 		return 0;
5697783decfSChris Wilson 
5708c2699faSAndi Shyti 	return intel_gt_live_subtests(tests, to_gt(i915));
5719c1477e8SChris Wilson }
572