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