Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / drivers / gpu / drm / i915 / selftests / i915_gem_context.c
blob56a803d11916e8142d04623876a81d48d03b1a25
1 /*
2 * Copyright © 2017 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
25 #include "../i915_selftest.h"
27 #include "mock_drm.h"
28 #include "huge_gem_object.h"
30 #define DW_PER_PAGE (PAGE_SIZE / sizeof(u32))
32 static struct i915_vma *
33 gpu_fill_dw(struct i915_vma *vma, u64 offset, unsigned long count, u32 value)
35 struct drm_i915_gem_object *obj;
36 const int gen = INTEL_GEN(vma->vm->i915);
37 unsigned long n, size;
38 u32 *cmd;
39 int err;
41 size = (4 * count + 1) * sizeof(u32);
42 size = round_up(size, PAGE_SIZE);
43 obj = i915_gem_object_create_internal(vma->vm->i915, size);
44 if (IS_ERR(obj))
45 return ERR_CAST(obj);
47 cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
48 if (IS_ERR(cmd)) {
49 err = PTR_ERR(cmd);
50 goto err;
53 GEM_BUG_ON(offset + (count - 1) * PAGE_SIZE > vma->node.size);
54 offset += vma->node.start;
56 for (n = 0; n < count; n++) {
57 if (gen >= 8) {
58 *cmd++ = MI_STORE_DWORD_IMM_GEN4;
59 *cmd++ = lower_32_bits(offset);
60 *cmd++ = upper_32_bits(offset);
61 *cmd++ = value;
62 } else if (gen >= 4) {
63 *cmd++ = MI_STORE_DWORD_IMM_GEN4 |
64 (gen < 6 ? 1 << 22 : 0);
65 *cmd++ = 0;
66 *cmd++ = offset;
67 *cmd++ = value;
68 } else {
69 *cmd++ = MI_STORE_DWORD_IMM | 1 << 22;
70 *cmd++ = offset;
71 *cmd++ = value;
73 offset += PAGE_SIZE;
75 *cmd = MI_BATCH_BUFFER_END;
76 i915_gem_object_unpin_map(obj);
78 err = i915_gem_object_set_to_gtt_domain(obj, false);
79 if (err)
80 goto err;
82 vma = i915_vma_instance(obj, vma->vm, NULL);
83 if (IS_ERR(vma)) {
84 err = PTR_ERR(vma);
85 goto err;
88 err = i915_vma_pin(vma, 0, 0, PIN_USER);
89 if (err)
90 goto err;
92 return vma;
94 err:
95 i915_gem_object_put(obj);
96 return ERR_PTR(err);
99 static unsigned long real_page_count(struct drm_i915_gem_object *obj)
101 return huge_gem_object_phys_size(obj) >> PAGE_SHIFT;
104 static unsigned long fake_page_count(struct drm_i915_gem_object *obj)
106 return huge_gem_object_dma_size(obj) >> PAGE_SHIFT;
109 static int gpu_fill(struct drm_i915_gem_object *obj,
110 struct i915_gem_context *ctx,
111 struct intel_engine_cs *engine,
112 unsigned int dw)
114 struct drm_i915_private *i915 = to_i915(obj->base.dev);
115 struct i915_address_space *vm =
116 ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;
117 struct drm_i915_gem_request *rq;
118 struct i915_vma *vma;
119 struct i915_vma *batch;
120 unsigned int flags;
121 int err;
123 GEM_BUG_ON(obj->base.size > vm->total);
124 GEM_BUG_ON(!intel_engine_can_store_dword(engine));
126 vma = i915_vma_instance(obj, vm, NULL);
127 if (IS_ERR(vma))
128 return PTR_ERR(vma);
130 err = i915_gem_object_set_to_gtt_domain(obj, false);
131 if (err)
132 return err;
134 err = i915_vma_pin(vma, 0, 0, PIN_HIGH | PIN_USER);
135 if (err)
136 return err;
138 /* Within the GTT the huge objects maps every page onto
139 * its 1024 real pages (using phys_pfn = dma_pfn % 1024).
140 * We set the nth dword within the page using the nth
141 * mapping via the GTT - this should exercise the GTT mapping
142 * whilst checking that each context provides a unique view
143 * into the object.
145 batch = gpu_fill_dw(vma,
146 (dw * real_page_count(obj)) << PAGE_SHIFT |
147 (dw * sizeof(u32)),
148 real_page_count(obj),
149 dw);
150 if (IS_ERR(batch)) {
151 err = PTR_ERR(batch);
152 goto err_vma;
155 rq = i915_gem_request_alloc(engine, ctx);
156 if (IS_ERR(rq)) {
157 err = PTR_ERR(rq);
158 goto err_batch;
161 flags = 0;
162 if (INTEL_GEN(vm->i915) <= 5)
163 flags |= I915_DISPATCH_SECURE;
165 err = engine->emit_bb_start(rq,
166 batch->node.start, batch->node.size,
167 flags);
168 if (err)
169 goto err_request;
171 i915_vma_move_to_active(batch, rq, 0);
172 i915_gem_object_set_active_reference(batch->obj);
173 i915_vma_unpin(batch);
174 i915_vma_close(batch);
176 i915_vma_move_to_active(vma, rq, 0);
177 i915_vma_unpin(vma);
179 reservation_object_lock(obj->resv, NULL);
180 reservation_object_add_excl_fence(obj->resv, &rq->fence);
181 reservation_object_unlock(obj->resv);
183 __i915_add_request(rq, true);
185 return 0;
187 err_request:
188 __i915_add_request(rq, false);
189 err_batch:
190 i915_vma_unpin(batch);
191 err_vma:
192 i915_vma_unpin(vma);
193 return err;
196 static int cpu_fill(struct drm_i915_gem_object *obj, u32 value)
198 const bool has_llc = HAS_LLC(to_i915(obj->base.dev));
199 unsigned int n, m, need_flush;
200 int err;
202 err = i915_gem_obj_prepare_shmem_write(obj, &need_flush);
203 if (err)
204 return err;
206 for (n = 0; n < real_page_count(obj); n++) {
207 u32 *map;
209 map = kmap_atomic(i915_gem_object_get_page(obj, n));
210 for (m = 0; m < DW_PER_PAGE; m++)
211 map[m] = value;
212 if (!has_llc)
213 drm_clflush_virt_range(map, PAGE_SIZE);
214 kunmap_atomic(map);
217 i915_gem_obj_finish_shmem_access(obj);
218 obj->base.read_domains = I915_GEM_DOMAIN_GTT | I915_GEM_DOMAIN_CPU;
219 obj->base.write_domain = 0;
220 return 0;
223 static int cpu_check(struct drm_i915_gem_object *obj, unsigned int max)
225 unsigned int n, m, needs_flush;
226 int err;
228 err = i915_gem_obj_prepare_shmem_read(obj, &needs_flush);
229 if (err)
230 return err;
232 for (n = 0; n < real_page_count(obj); n++) {
233 u32 *map;
235 map = kmap_atomic(i915_gem_object_get_page(obj, n));
236 if (needs_flush & CLFLUSH_BEFORE)
237 drm_clflush_virt_range(map, PAGE_SIZE);
239 for (m = 0; m < max; m++) {
240 if (map[m] != m) {
241 pr_err("Invalid value at page %d, offset %d: found %x expected %x\n",
242 n, m, map[m], m);
243 err = -EINVAL;
244 goto out_unmap;
248 for (; m < DW_PER_PAGE; m++) {
249 if (map[m] != 0xdeadbeef) {
250 pr_err("Invalid value at page %d, offset %d: found %x expected %x\n",
251 n, m, map[m], 0xdeadbeef);
252 err = -EINVAL;
253 goto out_unmap;
257 out_unmap:
258 kunmap_atomic(map);
259 if (err)
260 break;
263 i915_gem_obj_finish_shmem_access(obj);
264 return err;
267 static int file_add_object(struct drm_file *file,
268 struct drm_i915_gem_object *obj)
270 int err;
272 GEM_BUG_ON(obj->base.handle_count);
274 /* tie the object to the drm_file for easy reaping */
275 err = idr_alloc(&file->object_idr, &obj->base, 1, 0, GFP_KERNEL);
276 if (err < 0)
277 return err;
279 i915_gem_object_get(obj);
280 obj->base.handle_count++;
281 return 0;
284 static struct drm_i915_gem_object *
285 create_test_object(struct i915_gem_context *ctx,
286 struct drm_file *file,
287 struct list_head *objects)
289 struct drm_i915_gem_object *obj;
290 struct i915_address_space *vm =
291 ctx->ppgtt ? &ctx->ppgtt->base : &ctx->i915->ggtt.base;
292 u64 size;
293 int err;
295 size = min(vm->total / 2, 1024ull * DW_PER_PAGE * PAGE_SIZE);
296 size = round_down(size, DW_PER_PAGE * PAGE_SIZE);
298 obj = huge_gem_object(ctx->i915, DW_PER_PAGE * PAGE_SIZE, size);
299 if (IS_ERR(obj))
300 return obj;
302 err = file_add_object(file, obj);
303 i915_gem_object_put(obj);
304 if (err)
305 return ERR_PTR(err);
307 err = cpu_fill(obj, 0xdeadbeef);
308 if (err) {
309 pr_err("Failed to fill object with cpu, err=%d\n",
310 err);
311 return ERR_PTR(err);
314 list_add_tail(&obj->st_link, objects);
315 return obj;
318 static unsigned long max_dwords(struct drm_i915_gem_object *obj)
320 unsigned long npages = fake_page_count(obj);
322 GEM_BUG_ON(!IS_ALIGNED(npages, DW_PER_PAGE));
323 return npages / DW_PER_PAGE;
326 static int igt_ctx_exec(void *arg)
328 struct drm_i915_private *i915 = arg;
329 struct drm_i915_gem_object *obj = NULL;
330 struct drm_file *file;
331 IGT_TIMEOUT(end_time);
332 LIST_HEAD(objects);
333 unsigned long ncontexts, ndwords, dw;
334 bool first_shared_gtt = true;
335 int err = -ENODEV;
337 /* Create a few different contexts (with different mm) and write
338 * through each ctx/mm using the GPU making sure those writes end
339 * up in the expected pages of our obj.
342 file = mock_file(i915);
343 if (IS_ERR(file))
344 return PTR_ERR(file);
346 mutex_lock(&i915->drm.struct_mutex);
348 ncontexts = 0;
349 ndwords = 0;
350 dw = 0;
351 while (!time_after(jiffies, end_time)) {
352 struct intel_engine_cs *engine;
353 struct i915_gem_context *ctx;
354 unsigned int id;
356 if (first_shared_gtt) {
357 ctx = __create_hw_context(i915, file->driver_priv);
358 first_shared_gtt = false;
359 } else {
360 ctx = i915_gem_create_context(i915, file->driver_priv);
362 if (IS_ERR(ctx)) {
363 err = PTR_ERR(ctx);
364 goto out_unlock;
367 for_each_engine(engine, i915, id) {
368 if (!intel_engine_can_store_dword(engine))
369 continue;
371 if (!obj) {
372 obj = create_test_object(ctx, file, &objects);
373 if (IS_ERR(obj)) {
374 err = PTR_ERR(obj);
375 goto out_unlock;
379 intel_runtime_pm_get(i915);
380 err = gpu_fill(obj, ctx, engine, dw);
381 intel_runtime_pm_put(i915);
382 if (err) {
383 pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) in ctx %u [full-ppgtt? %s], err=%d\n",
384 ndwords, dw, max_dwords(obj),
385 engine->name, ctx->hw_id,
386 yesno(!!ctx->ppgtt), err);
387 goto out_unlock;
390 if (++dw == max_dwords(obj)) {
391 obj = NULL;
392 dw = 0;
394 ndwords++;
396 ncontexts++;
398 pr_info("Submitted %lu contexts (across %u engines), filling %lu dwords\n",
399 ncontexts, INTEL_INFO(i915)->num_rings, ndwords);
401 dw = 0;
402 list_for_each_entry(obj, &objects, st_link) {
403 unsigned int rem =
404 min_t(unsigned int, ndwords - dw, max_dwords(obj));
406 err = cpu_check(obj, rem);
407 if (err)
408 break;
410 dw += rem;
413 out_unlock:
414 mutex_unlock(&i915->drm.struct_mutex);
416 mock_file_free(i915, file);
417 return err;
420 static int fake_aliasing_ppgtt_enable(struct drm_i915_private *i915)
422 struct drm_i915_gem_object *obj;
423 int err;
425 err = i915_gem_init_aliasing_ppgtt(i915);
426 if (err)
427 return err;
429 list_for_each_entry(obj, &i915->mm.bound_list, mm.link) {
430 struct i915_vma *vma;
432 vma = i915_vma_instance(obj, &i915->ggtt.base, NULL);
433 if (IS_ERR(vma))
434 continue;
436 vma->flags &= ~I915_VMA_LOCAL_BIND;
439 return 0;
442 static void fake_aliasing_ppgtt_disable(struct drm_i915_private *i915)
444 i915_gem_fini_aliasing_ppgtt(i915);
447 int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv)
449 static const struct i915_subtest tests[] = {
450 SUBTEST(igt_ctx_exec),
452 bool fake_alias = false;
453 int err;
455 /* Install a fake aliasing gtt for exercise */
456 if (USES_PPGTT(dev_priv) && !dev_priv->mm.aliasing_ppgtt) {
457 mutex_lock(&dev_priv->drm.struct_mutex);
458 err = fake_aliasing_ppgtt_enable(dev_priv);
459 mutex_unlock(&dev_priv->drm.struct_mutex);
460 if (err)
461 return err;
463 GEM_BUG_ON(!dev_priv->mm.aliasing_ppgtt);
464 fake_alias = true;
467 err = i915_subtests(tests, dev_priv);
469 if (fake_alias) {
470 mutex_lock(&dev_priv->drm.struct_mutex);
471 fake_aliasing_ppgtt_disable(dev_priv);
472 mutex_unlock(&dev_priv->drm.struct_mutex);
475 return err;