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
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
25 #include "../i915_selftest.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
;
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
);
47 cmd
= i915_gem_object_pin_map(obj
, I915_MAP_WB
);
53 GEM_BUG_ON(offset
+ (count
- 1) * PAGE_SIZE
> vma
->node
.size
);
54 offset
+= vma
->node
.start
;
56 for (n
= 0; n
< count
; n
++) {
58 *cmd
++ = MI_STORE_DWORD_IMM_GEN4
;
59 *cmd
++ = lower_32_bits(offset
);
60 *cmd
++ = upper_32_bits(offset
);
62 } else if (gen
>= 4) {
63 *cmd
++ = MI_STORE_DWORD_IMM_GEN4
|
64 (gen
< 6 ? 1 << 22 : 0);
69 *cmd
++ = MI_STORE_DWORD_IMM
| 1 << 22;
75 *cmd
= MI_BATCH_BUFFER_END
;
76 i915_gem_object_unpin_map(obj
);
78 err
= i915_gem_object_set_to_gtt_domain(obj
, false);
82 vma
= i915_vma_instance(obj
, vma
->vm
, NULL
);
88 err
= i915_vma_pin(vma
, 0, 0, PIN_USER
);
95 i915_gem_object_put(obj
);
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
,
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
;
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
);
130 err
= i915_gem_object_set_to_gtt_domain(obj
, false);
134 err
= i915_vma_pin(vma
, 0, 0, PIN_HIGH
| PIN_USER
);
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
145 batch
= gpu_fill_dw(vma
,
146 (dw
* real_page_count(obj
)) << PAGE_SHIFT
|
148 real_page_count(obj
),
151 err
= PTR_ERR(batch
);
155 rq
= i915_gem_request_alloc(engine
, ctx
);
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
,
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);
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);
188 __i915_add_request(rq
, false);
190 i915_vma_unpin(batch
);
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
;
202 err
= i915_gem_obj_prepare_shmem_write(obj
, &need_flush
);
206 for (n
= 0; n
< real_page_count(obj
); n
++) {
209 map
= kmap_atomic(i915_gem_object_get_page(obj
, n
));
210 for (m
= 0; m
< DW_PER_PAGE
; m
++)
213 drm_clflush_virt_range(map
, PAGE_SIZE
);
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;
223 static int cpu_check(struct drm_i915_gem_object
*obj
, unsigned int max
)
225 unsigned int n
, m
, needs_flush
;
228 err
= i915_gem_obj_prepare_shmem_read(obj
, &needs_flush
);
232 for (n
= 0; n
< real_page_count(obj
); n
++) {
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
++) {
241 pr_err("Invalid value at page %d, offset %d: found %x expected %x\n",
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);
263 i915_gem_obj_finish_shmem_access(obj
);
267 static int file_add_object(struct drm_file
*file
,
268 struct drm_i915_gem_object
*obj
)
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
);
279 i915_gem_object_get(obj
);
280 obj
->base
.handle_count
++;
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
;
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
);
302 err
= file_add_object(file
, obj
);
303 i915_gem_object_put(obj
);
307 err
= cpu_fill(obj
, 0xdeadbeef);
309 pr_err("Failed to fill object with cpu, err=%d\n",
314 list_add_tail(&obj
->st_link
, objects
);
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
);
333 unsigned long ncontexts
, ndwords
, dw
;
334 bool first_shared_gtt
= true;
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
);
344 return PTR_ERR(file
);
346 mutex_lock(&i915
->drm
.struct_mutex
);
351 while (!time_after(jiffies
, end_time
)) {
352 struct intel_engine_cs
*engine
;
353 struct i915_gem_context
*ctx
;
356 if (first_shared_gtt
) {
357 ctx
= __create_hw_context(i915
, file
->driver_priv
);
358 first_shared_gtt
= false;
360 ctx
= i915_gem_create_context(i915
, file
->driver_priv
);
367 for_each_engine(engine
, i915
, id
) {
368 if (!intel_engine_can_store_dword(engine
))
372 obj
= create_test_object(ctx
, file
, &objects
);
379 intel_runtime_pm_get(i915
);
380 err
= gpu_fill(obj
, ctx
, engine
, dw
);
381 intel_runtime_pm_put(i915
);
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
);
390 if (++dw
== max_dwords(obj
)) {
398 pr_info("Submitted %lu contexts (across %u engines), filling %lu dwords\n",
399 ncontexts
, INTEL_INFO(i915
)->num_rings
, ndwords
);
402 list_for_each_entry(obj
, &objects
, st_link
) {
404 min_t(unsigned int, ndwords
- dw
, max_dwords(obj
));
406 err
= cpu_check(obj
, rem
);
414 mutex_unlock(&i915
->drm
.struct_mutex
);
416 mock_file_free(i915
, file
);
420 static int fake_aliasing_ppgtt_enable(struct drm_i915_private
*i915
)
422 struct drm_i915_gem_object
*obj
;
425 err
= i915_gem_init_aliasing_ppgtt(i915
);
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
);
436 vma
->flags
&= ~I915_VMA_LOCAL_BIND
;
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;
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
);
463 GEM_BUG_ON(!dev_priv
->mm
.aliasing_ppgtt
);
467 err
= i915_subtests(tests
, dev_priv
);
470 mutex_lock(&dev_priv
->drm
.struct_mutex
);
471 fake_aliasing_ppgtt_disable(dev_priv
);
472 mutex_unlock(&dev_priv
->drm
.struct_mutex
);