1cf586021SChris Wilson // SPDX-License-Identifier: MIT
2cf586021SChris Wilson /*
3cf586021SChris Wilson * Copyright © 2020 Intel Corporation
4cf586021SChris Wilson */
5cf586021SChris Wilson
694ce0d65SChris Wilson #include <linux/sort.h>
794ce0d65SChris Wilson
8b508d01fSJani Nikula #include "gem/i915_gem_internal.h"
9d09aa852SJani Nikula #include "gem/i915_gem_lmem.h"
10b508d01fSJani Nikula
11e288e178SMatthew Auld #include "selftests/igt_spinner.h"
12cf586021SChris Wilson #include "selftests/i915_random.h"
13cf586021SChris Wilson
14cf586021SChris Wilson static const unsigned int sizes[] = {
15cf586021SChris Wilson SZ_4K,
16cf586021SChris Wilson SZ_64K,
17cf586021SChris Wilson SZ_2M,
18cf586021SChris Wilson CHUNK_SZ - SZ_4K,
19cf586021SChris Wilson CHUNK_SZ,
20cf586021SChris Wilson CHUNK_SZ + SZ_4K,
21cf586021SChris Wilson SZ_64M,
22cf586021SChris Wilson };
23cf586021SChris Wilson
24cf586021SChris Wilson static struct drm_i915_gem_object *
create_lmem_or_internal(struct drm_i915_private * i915,size_t size)25cf586021SChris Wilson create_lmem_or_internal(struct drm_i915_private *i915, size_t size)
26cf586021SChris Wilson {
27cf586021SChris Wilson struct drm_i915_gem_object *obj;
28cf586021SChris Wilson
29cf586021SChris Wilson obj = i915_gem_object_create_lmem(i915, size, 0);
30cf586021SChris Wilson if (!IS_ERR(obj))
31cf586021SChris Wilson return obj;
32cf586021SChris Wilson
33cf586021SChris Wilson return i915_gem_object_create_internal(i915, size);
34cf586021SChris Wilson }
35cf586021SChris Wilson
copy(struct intel_migrate * migrate,int (* fn)(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * src,struct drm_i915_gem_object * dst,struct i915_request ** out),u32 sz,struct rnd_state * prng)36cf586021SChris Wilson static int copy(struct intel_migrate *migrate,
37cf586021SChris Wilson int (*fn)(struct intel_migrate *migrate,
38cf586021SChris Wilson struct i915_gem_ww_ctx *ww,
39cf586021SChris Wilson struct drm_i915_gem_object *src,
40cf586021SChris Wilson struct drm_i915_gem_object *dst,
41cf586021SChris Wilson struct i915_request **out),
42cf586021SChris Wilson u32 sz, struct rnd_state *prng)
43cf586021SChris Wilson {
44cf586021SChris Wilson struct drm_i915_private *i915 = migrate->context->engine->i915;
45cf586021SChris Wilson struct drm_i915_gem_object *src, *dst;
46cf586021SChris Wilson struct i915_request *rq;
47cf586021SChris Wilson struct i915_gem_ww_ctx ww;
48cf586021SChris Wilson u32 *vaddr;
49cf586021SChris Wilson int err = 0;
50cf586021SChris Wilson int i;
51cf586021SChris Wilson
52cf586021SChris Wilson src = create_lmem_or_internal(i915, sz);
53cf586021SChris Wilson if (IS_ERR(src))
54cf586021SChris Wilson return 0;
55cf586021SChris Wilson
5697c8ef44SMatthew Auld sz = src->base.size;
57cf586021SChris Wilson dst = i915_gem_object_create_internal(i915, sz);
58cf586021SChris Wilson if (IS_ERR(dst))
59cf586021SChris Wilson goto err_free_src;
60cf586021SChris Wilson
61cf586021SChris Wilson for_i915_gem_ww(&ww, err, true) {
62cf586021SChris Wilson err = i915_gem_object_lock(src, &ww);
63cf586021SChris Wilson if (err)
64cf586021SChris Wilson continue;
65cf586021SChris Wilson
66cf586021SChris Wilson err = i915_gem_object_lock(dst, &ww);
67cf586021SChris Wilson if (err)
68cf586021SChris Wilson continue;
69cf586021SChris Wilson
70cf586021SChris Wilson vaddr = i915_gem_object_pin_map(src, I915_MAP_WC);
71cf586021SChris Wilson if (IS_ERR(vaddr)) {
72cf586021SChris Wilson err = PTR_ERR(vaddr);
73cf586021SChris Wilson continue;
74cf586021SChris Wilson }
75cf586021SChris Wilson
76cf586021SChris Wilson for (i = 0; i < sz / sizeof(u32); i++)
77cf586021SChris Wilson vaddr[i] = i;
78cf586021SChris Wilson i915_gem_object_flush_map(src);
79cf586021SChris Wilson
80cf586021SChris Wilson vaddr = i915_gem_object_pin_map(dst, I915_MAP_WC);
81cf586021SChris Wilson if (IS_ERR(vaddr)) {
82cf586021SChris Wilson err = PTR_ERR(vaddr);
83cf586021SChris Wilson goto unpin_src;
84cf586021SChris Wilson }
85cf586021SChris Wilson
86cf586021SChris Wilson for (i = 0; i < sz / sizeof(u32); i++)
87cf586021SChris Wilson vaddr[i] = ~i;
88cf586021SChris Wilson i915_gem_object_flush_map(dst);
89cf586021SChris Wilson
90cf586021SChris Wilson err = fn(migrate, &ww, src, dst, &rq);
91cf586021SChris Wilson if (!err)
92cf586021SChris Wilson continue;
93cf586021SChris Wilson
94cf586021SChris Wilson if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
95cf586021SChris Wilson pr_err("%ps failed, size: %u\n", fn, sz);
96cf586021SChris Wilson if (rq) {
97cf586021SChris Wilson i915_request_wait(rq, 0, HZ);
98cf586021SChris Wilson i915_request_put(rq);
99cf586021SChris Wilson }
100cf586021SChris Wilson i915_gem_object_unpin_map(dst);
101cf586021SChris Wilson unpin_src:
102cf586021SChris Wilson i915_gem_object_unpin_map(src);
103cf586021SChris Wilson }
104cf586021SChris Wilson if (err)
105cf586021SChris Wilson goto err_out;
106cf586021SChris Wilson
107cf586021SChris Wilson if (rq) {
108cf586021SChris Wilson if (i915_request_wait(rq, 0, HZ) < 0) {
109cf586021SChris Wilson pr_err("%ps timed out, size: %u\n", fn, sz);
110cf586021SChris Wilson err = -ETIME;
111cf586021SChris Wilson }
112cf586021SChris Wilson i915_request_put(rq);
113cf586021SChris Wilson }
114cf586021SChris Wilson
115cf586021SChris Wilson for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
116cf586021SChris Wilson int x = i * 1024 + i915_prandom_u32_max_state(1024, prng);
117cf586021SChris Wilson
118cf586021SChris Wilson if (vaddr[x] != x) {
119cf586021SChris Wilson pr_err("%ps failed, size: %u, offset: %zu\n",
120cf586021SChris Wilson fn, sz, x * sizeof(u32));
121cf586021SChris Wilson igt_hexdump(vaddr + i * 1024, 4096);
122cf586021SChris Wilson err = -EINVAL;
123cf586021SChris Wilson }
124cf586021SChris Wilson }
125cf586021SChris Wilson
126cf586021SChris Wilson i915_gem_object_unpin_map(dst);
127cf586021SChris Wilson i915_gem_object_unpin_map(src);
128cf586021SChris Wilson
129cf586021SChris Wilson err_out:
130cf586021SChris Wilson i915_gem_object_put(dst);
131cf586021SChris Wilson err_free_src:
132cf586021SChris Wilson i915_gem_object_put(src);
133cf586021SChris Wilson
134cf586021SChris Wilson return err;
135cf586021SChris Wilson }
136cf586021SChris Wilson
intel_context_copy_ccs(struct intel_context * ce,const struct i915_deps * deps,struct scatterlist * sg,unsigned int pat_index,bool write_to_ccs,struct i915_request ** out)137c8f8a748SRamalingam C static int intel_context_copy_ccs(struct intel_context *ce,
138c8f8a748SRamalingam C const struct i915_deps *deps,
139c8f8a748SRamalingam C struct scatterlist *sg,
1409275277dSFei Yang unsigned int pat_index,
141c8f8a748SRamalingam C bool write_to_ccs,
142c8f8a748SRamalingam C struct i915_request **out)
143c8f8a748SRamalingam C {
144c8f8a748SRamalingam C u8 src_access = write_to_ccs ? DIRECT_ACCESS : INDIRECT_ACCESS;
145c8f8a748SRamalingam C u8 dst_access = write_to_ccs ? INDIRECT_ACCESS : DIRECT_ACCESS;
146c8f8a748SRamalingam C struct sgt_dma it = sg_sgt(sg);
147c8f8a748SRamalingam C struct i915_request *rq;
148c8f8a748SRamalingam C u32 offset;
149c8f8a748SRamalingam C int err;
150c8f8a748SRamalingam C
151c8f8a748SRamalingam C GEM_BUG_ON(ce->vm != ce->engine->gt->migrate.context->vm);
152c8f8a748SRamalingam C *out = NULL;
153c8f8a748SRamalingam C
154c8f8a748SRamalingam C GEM_BUG_ON(ce->ring->size < SZ_64K);
155c8f8a748SRamalingam C
156c8f8a748SRamalingam C offset = 0;
157c8f8a748SRamalingam C if (HAS_64K_PAGES(ce->engine->i915))
158c8f8a748SRamalingam C offset = CHUNK_SZ;
159c8f8a748SRamalingam C
160c8f8a748SRamalingam C do {
161c8f8a748SRamalingam C int len;
162c8f8a748SRamalingam C
163c8f8a748SRamalingam C rq = i915_request_create(ce);
164c8f8a748SRamalingam C if (IS_ERR(rq)) {
165c8f8a748SRamalingam C err = PTR_ERR(rq);
166c8f8a748SRamalingam C goto out_ce;
167c8f8a748SRamalingam C }
168c8f8a748SRamalingam C
169c8f8a748SRamalingam C if (deps) {
170c8f8a748SRamalingam C err = i915_request_await_deps(rq, deps);
171c8f8a748SRamalingam C if (err)
172c8f8a748SRamalingam C goto out_rq;
173c8f8a748SRamalingam C
174c8f8a748SRamalingam C if (rq->engine->emit_init_breadcrumb) {
175c8f8a748SRamalingam C err = rq->engine->emit_init_breadcrumb(rq);
176c8f8a748SRamalingam C if (err)
177c8f8a748SRamalingam C goto out_rq;
178c8f8a748SRamalingam C }
179c8f8a748SRamalingam C
180c8f8a748SRamalingam C deps = NULL;
181c8f8a748SRamalingam C }
182c8f8a748SRamalingam C
183c8f8a748SRamalingam C /* The PTE updates + clear must not be interrupted. */
184c8f8a748SRamalingam C err = emit_no_arbitration(rq);
185c8f8a748SRamalingam C if (err)
186c8f8a748SRamalingam C goto out_rq;
187c8f8a748SRamalingam C
1889275277dSFei Yang len = emit_pte(rq, &it, pat_index, true, offset, CHUNK_SZ);
189c8f8a748SRamalingam C if (len <= 0) {
190c8f8a748SRamalingam C err = len;
191c8f8a748SRamalingam C goto out_rq;
192c8f8a748SRamalingam C }
193c8f8a748SRamalingam C
194c8f8a748SRamalingam C err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
195c8f8a748SRamalingam C if (err)
196c8f8a748SRamalingam C goto out_rq;
197c8f8a748SRamalingam C
198c8f8a748SRamalingam C err = emit_copy_ccs(rq, offset, dst_access,
199c8f8a748SRamalingam C offset, src_access, len);
200c8f8a748SRamalingam C if (err)
201c8f8a748SRamalingam C goto out_rq;
202c8f8a748SRamalingam C
203c8f8a748SRamalingam C err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
204c8f8a748SRamalingam C
205c8f8a748SRamalingam C /* Arbitration is re-enabled between requests. */
206c8f8a748SRamalingam C out_rq:
207c8f8a748SRamalingam C if (*out)
208c8f8a748SRamalingam C i915_request_put(*out);
209c8f8a748SRamalingam C *out = i915_request_get(rq);
210c8f8a748SRamalingam C i915_request_add(rq);
211c8f8a748SRamalingam C if (err || !it.sg || !sg_dma_len(it.sg))
212c8f8a748SRamalingam C break;
213c8f8a748SRamalingam C
214c8f8a748SRamalingam C cond_resched();
215c8f8a748SRamalingam C } while (1);
216c8f8a748SRamalingam C
217c8f8a748SRamalingam C out_ce:
218c8f8a748SRamalingam C return err;
219c8f8a748SRamalingam C }
220c8f8a748SRamalingam C
221c8f8a748SRamalingam C static int
intel_migrate_ccs_copy(struct intel_migrate * m,struct i915_gem_ww_ctx * ww,const struct i915_deps * deps,struct scatterlist * sg,unsigned int pat_index,bool write_to_ccs,struct i915_request ** out)222c8f8a748SRamalingam C intel_migrate_ccs_copy(struct intel_migrate *m,
223c8f8a748SRamalingam C struct i915_gem_ww_ctx *ww,
224c8f8a748SRamalingam C const struct i915_deps *deps,
225c8f8a748SRamalingam C struct scatterlist *sg,
2269275277dSFei Yang unsigned int pat_index,
227c8f8a748SRamalingam C bool write_to_ccs,
228c8f8a748SRamalingam C struct i915_request **out)
229c8f8a748SRamalingam C {
230c8f8a748SRamalingam C struct intel_context *ce;
231c8f8a748SRamalingam C int err;
232c8f8a748SRamalingam C
233c8f8a748SRamalingam C *out = NULL;
234c8f8a748SRamalingam C if (!m->context)
235c8f8a748SRamalingam C return -ENODEV;
236c8f8a748SRamalingam C
237c8f8a748SRamalingam C ce = intel_migrate_create_context(m);
238c8f8a748SRamalingam C if (IS_ERR(ce))
239c8f8a748SRamalingam C ce = intel_context_get(m->context);
240c8f8a748SRamalingam C GEM_BUG_ON(IS_ERR(ce));
241c8f8a748SRamalingam C
242c8f8a748SRamalingam C err = intel_context_pin_ww(ce, ww);
243c8f8a748SRamalingam C if (err)
244c8f8a748SRamalingam C goto out;
245c8f8a748SRamalingam C
2469275277dSFei Yang err = intel_context_copy_ccs(ce, deps, sg, pat_index,
247c8f8a748SRamalingam C write_to_ccs, out);
248c8f8a748SRamalingam C
249c8f8a748SRamalingam C intel_context_unpin(ce);
250c8f8a748SRamalingam C out:
251c8f8a748SRamalingam C intel_context_put(ce);
252c8f8a748SRamalingam C return err;
253c8f8a748SRamalingam C }
254c8f8a748SRamalingam C
clear(struct intel_migrate * migrate,int (* fn)(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out),u32 sz,struct rnd_state * prng)255563baae1SChris Wilson static int clear(struct intel_migrate *migrate,
256563baae1SChris Wilson int (*fn)(struct intel_migrate *migrate,
257563baae1SChris Wilson struct i915_gem_ww_ctx *ww,
258563baae1SChris Wilson struct drm_i915_gem_object *obj,
259563baae1SChris Wilson u32 value,
260563baae1SChris Wilson struct i915_request **out),
261563baae1SChris Wilson u32 sz, struct rnd_state *prng)
262563baae1SChris Wilson {
263563baae1SChris Wilson struct drm_i915_private *i915 = migrate->context->engine->i915;
264563baae1SChris Wilson struct drm_i915_gem_object *obj;
265563baae1SChris Wilson struct i915_request *rq;
266563baae1SChris Wilson struct i915_gem_ww_ctx ww;
267c8f8a748SRamalingam C u32 *vaddr, val = 0;
268c8f8a748SRamalingam C bool ccs_cap = false;
269563baae1SChris Wilson int err = 0;
270563baae1SChris Wilson int i;
271563baae1SChris Wilson
272563baae1SChris Wilson obj = create_lmem_or_internal(i915, sz);
273563baae1SChris Wilson if (IS_ERR(obj))
274563baae1SChris Wilson return 0;
275563baae1SChris Wilson
276a785d3a8SRamalingam C /* Consider the rounded up memory too */
277a785d3a8SRamalingam C sz = obj->base.size;
278a785d3a8SRamalingam C
279c8f8a748SRamalingam C if (HAS_FLAT_CCS(i915) && i915_gem_object_is_lmem(obj))
280c8f8a748SRamalingam C ccs_cap = true;
281c8f8a748SRamalingam C
282563baae1SChris Wilson for_i915_gem_ww(&ww, err, true) {
283c8f8a748SRamalingam C int ccs_bytes, ccs_bytes_per_chunk;
284c8f8a748SRamalingam C
285563baae1SChris Wilson err = i915_gem_object_lock(obj, &ww);
286563baae1SChris Wilson if (err)
287563baae1SChris Wilson continue;
288563baae1SChris Wilson
289563baae1SChris Wilson vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
290563baae1SChris Wilson if (IS_ERR(vaddr)) {
291563baae1SChris Wilson err = PTR_ERR(vaddr);
292563baae1SChris Wilson continue;
293563baae1SChris Wilson }
294563baae1SChris Wilson
295563baae1SChris Wilson for (i = 0; i < sz / sizeof(u32); i++)
296563baae1SChris Wilson vaddr[i] = ~i;
297563baae1SChris Wilson i915_gem_object_flush_map(obj);
298563baae1SChris Wilson
299c8f8a748SRamalingam C if (ccs_cap && !val) {
300c8f8a748SRamalingam C /* Write the obj data into ccs surface */
301c8f8a748SRamalingam C err = intel_migrate_ccs_copy(migrate, &ww, NULL,
302c8f8a748SRamalingam C obj->mm.pages->sgl,
3039275277dSFei Yang obj->pat_index,
304c8f8a748SRamalingam C true, &rq);
305c8f8a748SRamalingam C if (rq && !err) {
306c8f8a748SRamalingam C if (i915_request_wait(rq, 0, HZ) < 0) {
307c8f8a748SRamalingam C pr_err("%ps timed out, size: %u\n",
308c8f8a748SRamalingam C fn, sz);
309c8f8a748SRamalingam C err = -ETIME;
310563baae1SChris Wilson }
311c8f8a748SRamalingam C i915_request_put(rq);
312c8f8a748SRamalingam C rq = NULL;
313563baae1SChris Wilson }
314563baae1SChris Wilson if (err)
315c8f8a748SRamalingam C continue;
316c8f8a748SRamalingam C }
317563baae1SChris Wilson
318c8f8a748SRamalingam C err = fn(migrate, &ww, obj, val, &rq);
319c8f8a748SRamalingam C if (rq && !err) {
320563baae1SChris Wilson if (i915_request_wait(rq, 0, HZ) < 0) {
321563baae1SChris Wilson pr_err("%ps timed out, size: %u\n", fn, sz);
322563baae1SChris Wilson err = -ETIME;
323563baae1SChris Wilson }
324563baae1SChris Wilson i915_request_put(rq);
325c8f8a748SRamalingam C rq = NULL;
326563baae1SChris Wilson }
327c8f8a748SRamalingam C if (err)
328c8f8a748SRamalingam C continue;
329563baae1SChris Wilson
330c8f8a748SRamalingam C i915_gem_object_flush_map(obj);
331c8f8a748SRamalingam C
332c8f8a748SRamalingam C /* Verify the set/clear of the obj mem */
333563baae1SChris Wilson for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
334c8f8a748SRamalingam C int x = i * 1024 +
335c8f8a748SRamalingam C i915_prandom_u32_max_state(1024, prng);
336563baae1SChris Wilson
337c8f8a748SRamalingam C if (vaddr[x] != val) {
338c8f8a748SRamalingam C pr_err("%ps failed, (%u != %u), offset: %zu\n",
339c8f8a748SRamalingam C fn, vaddr[x], val, x * sizeof(u32));
340563baae1SChris Wilson igt_hexdump(vaddr + i * 1024, 4096);
341563baae1SChris Wilson err = -EINVAL;
342563baae1SChris Wilson }
343563baae1SChris Wilson }
344c8f8a748SRamalingam C if (err)
345c8f8a748SRamalingam C continue;
346c8f8a748SRamalingam C
347c8f8a748SRamalingam C if (ccs_cap && !val) {
348c8f8a748SRamalingam C for (i = 0; i < sz / sizeof(u32); i++)
349c8f8a748SRamalingam C vaddr[i] = ~i;
350c8f8a748SRamalingam C i915_gem_object_flush_map(obj);
351c8f8a748SRamalingam C
352c8f8a748SRamalingam C err = intel_migrate_ccs_copy(migrate, &ww, NULL,
353c8f8a748SRamalingam C obj->mm.pages->sgl,
3549275277dSFei Yang obj->pat_index,
355c8f8a748SRamalingam C false, &rq);
356c8f8a748SRamalingam C if (rq && !err) {
357c8f8a748SRamalingam C if (i915_request_wait(rq, 0, HZ) < 0) {
358c8f8a748SRamalingam C pr_err("%ps timed out, size: %u\n",
359c8f8a748SRamalingam C fn, sz);
360c8f8a748SRamalingam C err = -ETIME;
361c8f8a748SRamalingam C }
362c8f8a748SRamalingam C i915_request_put(rq);
363c8f8a748SRamalingam C rq = NULL;
364c8f8a748SRamalingam C }
365c8f8a748SRamalingam C if (err)
366c8f8a748SRamalingam C continue;
367c8f8a748SRamalingam C
368c8f8a748SRamalingam C ccs_bytes = GET_CCS_BYTES(i915, sz);
369c8f8a748SRamalingam C ccs_bytes_per_chunk = GET_CCS_BYTES(i915, CHUNK_SZ);
370c8f8a748SRamalingam C i915_gem_object_flush_map(obj);
371c8f8a748SRamalingam C
372c8f8a748SRamalingam C for (i = 0; !err && i < DIV_ROUND_UP(ccs_bytes, PAGE_SIZE); i++) {
373c8f8a748SRamalingam C int offset = ((i * PAGE_SIZE) /
374c8f8a748SRamalingam C ccs_bytes_per_chunk) * CHUNK_SZ / sizeof(u32);
375c8f8a748SRamalingam C int ccs_bytes_left = (ccs_bytes - i * PAGE_SIZE) / sizeof(u32);
376c8f8a748SRamalingam C int x = i915_prandom_u32_max_state(min_t(int, 1024,
377c8f8a748SRamalingam C ccs_bytes_left), prng);
378c8f8a748SRamalingam C
379c8f8a748SRamalingam C if (vaddr[offset + x]) {
380c8f8a748SRamalingam C pr_err("%ps ccs clearing failed, offset: %ld/%d\n",
381c8f8a748SRamalingam C fn, i * PAGE_SIZE + x * sizeof(u32), ccs_bytes);
382c8f8a748SRamalingam C igt_hexdump(vaddr + offset,
383c8f8a748SRamalingam C min_t(int, 4096,
384c8f8a748SRamalingam C ccs_bytes_left * sizeof(u32)));
385c8f8a748SRamalingam C err = -EINVAL;
386c8f8a748SRamalingam C }
387c8f8a748SRamalingam C }
388c8f8a748SRamalingam C
389c8f8a748SRamalingam C if (err)
390c8f8a748SRamalingam C continue;
391c8f8a748SRamalingam C }
392c8f8a748SRamalingam C i915_gem_object_unpin_map(obj);
393c8f8a748SRamalingam C }
394c8f8a748SRamalingam C
395c8f8a748SRamalingam C if (err) {
396c8f8a748SRamalingam C if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
397c8f8a748SRamalingam C pr_err("%ps failed, size: %u\n", fn, sz);
398c8f8a748SRamalingam C if (rq && err != -EINVAL) {
399c8f8a748SRamalingam C i915_request_wait(rq, 0, HZ);
400c8f8a748SRamalingam C i915_request_put(rq);
401c8f8a748SRamalingam C }
402563baae1SChris Wilson
403563baae1SChris Wilson i915_gem_object_unpin_map(obj);
404c8f8a748SRamalingam C }
405563baae1SChris Wilson
406c8f8a748SRamalingam C i915_gem_object_put(obj);
407563baae1SChris Wilson return err;
408563baae1SChris Wilson }
409563baae1SChris Wilson
__migrate_copy(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * src,struct drm_i915_gem_object * dst,struct i915_request ** out)410cf586021SChris Wilson static int __migrate_copy(struct intel_migrate *migrate,
411cf586021SChris Wilson struct i915_gem_ww_ctx *ww,
412cf586021SChris Wilson struct drm_i915_gem_object *src,
413cf586021SChris Wilson struct drm_i915_gem_object *dst,
414cf586021SChris Wilson struct i915_request **out)
415cf586021SChris Wilson {
416cf586021SChris Wilson return intel_migrate_copy(migrate, ww, NULL,
4179275277dSFei Yang src->mm.pages->sgl, src->pat_index,
418cf586021SChris Wilson i915_gem_object_is_lmem(src),
4199275277dSFei Yang dst->mm.pages->sgl, dst->pat_index,
420cf586021SChris Wilson i915_gem_object_is_lmem(dst),
421cf586021SChris Wilson out);
422cf586021SChris Wilson }
423cf586021SChris Wilson
__global_copy(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * src,struct drm_i915_gem_object * dst,struct i915_request ** out)424cf586021SChris Wilson static int __global_copy(struct intel_migrate *migrate,
425cf586021SChris Wilson struct i915_gem_ww_ctx *ww,
426cf586021SChris Wilson struct drm_i915_gem_object *src,
427cf586021SChris Wilson struct drm_i915_gem_object *dst,
428cf586021SChris Wilson struct i915_request **out)
429cf586021SChris Wilson {
430cf586021SChris Wilson return intel_context_migrate_copy(migrate->context, NULL,
4319275277dSFei Yang src->mm.pages->sgl, src->pat_index,
432cf586021SChris Wilson i915_gem_object_is_lmem(src),
4339275277dSFei Yang dst->mm.pages->sgl, dst->pat_index,
434cf586021SChris Wilson i915_gem_object_is_lmem(dst),
435cf586021SChris Wilson out);
436cf586021SChris Wilson }
437cf586021SChris Wilson
438cf586021SChris Wilson static int
migrate_copy(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)439cf586021SChris Wilson migrate_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
440cf586021SChris Wilson {
441cf586021SChris Wilson return copy(migrate, __migrate_copy, sz, prng);
442cf586021SChris Wilson }
443cf586021SChris Wilson
444cf586021SChris Wilson static int
global_copy(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)445cf586021SChris Wilson global_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
446cf586021SChris Wilson {
447cf586021SChris Wilson return copy(migrate, __global_copy, sz, prng);
448cf586021SChris Wilson }
449cf586021SChris Wilson
__migrate_clear(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out)450563baae1SChris Wilson static int __migrate_clear(struct intel_migrate *migrate,
451563baae1SChris Wilson struct i915_gem_ww_ctx *ww,
452563baae1SChris Wilson struct drm_i915_gem_object *obj,
453563baae1SChris Wilson u32 value,
454563baae1SChris Wilson struct i915_request **out)
455563baae1SChris Wilson {
456563baae1SChris Wilson return intel_migrate_clear(migrate, ww, NULL,
457563baae1SChris Wilson obj->mm.pages->sgl,
4589275277dSFei Yang obj->pat_index,
459563baae1SChris Wilson i915_gem_object_is_lmem(obj),
460563baae1SChris Wilson value, out);
461563baae1SChris Wilson }
462563baae1SChris Wilson
__global_clear(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out)463563baae1SChris Wilson static int __global_clear(struct intel_migrate *migrate,
464563baae1SChris Wilson struct i915_gem_ww_ctx *ww,
465563baae1SChris Wilson struct drm_i915_gem_object *obj,
466563baae1SChris Wilson u32 value,
467563baae1SChris Wilson struct i915_request **out)
468563baae1SChris Wilson {
469563baae1SChris Wilson return intel_context_migrate_clear(migrate->context, NULL,
470563baae1SChris Wilson obj->mm.pages->sgl,
4719275277dSFei Yang obj->pat_index,
472563baae1SChris Wilson i915_gem_object_is_lmem(obj),
473563baae1SChris Wilson value, out);
474563baae1SChris Wilson }
475563baae1SChris Wilson
476563baae1SChris Wilson static int
migrate_clear(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)477563baae1SChris Wilson migrate_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
478563baae1SChris Wilson {
479563baae1SChris Wilson return clear(migrate, __migrate_clear, sz, prng);
480563baae1SChris Wilson }
481563baae1SChris Wilson
482563baae1SChris Wilson static int
global_clear(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)483563baae1SChris Wilson global_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
484563baae1SChris Wilson {
485563baae1SChris Wilson return clear(migrate, __global_clear, sz, prng);
486563baae1SChris Wilson }
487563baae1SChris Wilson
live_migrate_copy(void * arg)488cf586021SChris Wilson static int live_migrate_copy(void *arg)
489cf586021SChris Wilson {
490f7f0ca57SMatthew Auld struct intel_gt *gt = arg;
491f7f0ca57SMatthew Auld struct intel_migrate *migrate = >->migrate;
492cf586021SChris Wilson struct drm_i915_private *i915 = migrate->context->engine->i915;
493cf586021SChris Wilson I915_RND_STATE(prng);
494cf586021SChris Wilson int i;
495cf586021SChris Wilson
496cf586021SChris Wilson for (i = 0; i < ARRAY_SIZE(sizes); i++) {
497cf586021SChris Wilson int err;
498cf586021SChris Wilson
499cf586021SChris Wilson err = migrate_copy(migrate, sizes[i], &prng);
500cf586021SChris Wilson if (err == 0)
501cf586021SChris Wilson err = global_copy(migrate, sizes[i], &prng);
502cf586021SChris Wilson i915_gem_drain_freed_objects(i915);
503cf586021SChris Wilson if (err)
504cf586021SChris Wilson return err;
505cf586021SChris Wilson }
506cf586021SChris Wilson
507cf586021SChris Wilson return 0;
508cf586021SChris Wilson }
509cf586021SChris Wilson
live_migrate_clear(void * arg)510563baae1SChris Wilson static int live_migrate_clear(void *arg)
511563baae1SChris Wilson {
512f7f0ca57SMatthew Auld struct intel_gt *gt = arg;
513f7f0ca57SMatthew Auld struct intel_migrate *migrate = >->migrate;
514563baae1SChris Wilson struct drm_i915_private *i915 = migrate->context->engine->i915;
515563baae1SChris Wilson I915_RND_STATE(prng);
516563baae1SChris Wilson int i;
517563baae1SChris Wilson
518563baae1SChris Wilson for (i = 0; i < ARRAY_SIZE(sizes); i++) {
519563baae1SChris Wilson int err;
520563baae1SChris Wilson
521563baae1SChris Wilson err = migrate_clear(migrate, sizes[i], &prng);
522563baae1SChris Wilson if (err == 0)
523563baae1SChris Wilson err = global_clear(migrate, sizes[i], &prng);
524563baae1SChris Wilson
525563baae1SChris Wilson i915_gem_drain_freed_objects(i915);
526563baae1SChris Wilson if (err)
527563baae1SChris Wilson return err;
528563baae1SChris Wilson }
529563baae1SChris Wilson
530563baae1SChris Wilson return 0;
531563baae1SChris Wilson }
532563baae1SChris Wilson
533e288e178SMatthew Auld struct spinner_timer {
534e288e178SMatthew Auld struct timer_list timer;
535e288e178SMatthew Auld struct igt_spinner spin;
536e288e178SMatthew Auld };
537e288e178SMatthew Auld
spinner_kill(struct timer_list * timer)538e288e178SMatthew Auld static void spinner_kill(struct timer_list *timer)
539e288e178SMatthew Auld {
540e288e178SMatthew Auld struct spinner_timer *st = from_timer(st, timer, timer);
541e288e178SMatthew Auld
542e288e178SMatthew Auld igt_spinner_end(&st->spin);
543e288e178SMatthew Auld pr_info("%s\n", __func__);
544e288e178SMatthew Auld }
545e288e178SMatthew Auld
live_emit_pte_full_ring(void * arg)546e288e178SMatthew Auld static int live_emit_pte_full_ring(void *arg)
547e288e178SMatthew Auld {
548e288e178SMatthew Auld struct intel_gt *gt = arg;
549e288e178SMatthew Auld struct intel_migrate *migrate = >->migrate;
550e288e178SMatthew Auld struct drm_i915_private *i915 = migrate->context->engine->i915;
551e288e178SMatthew Auld struct drm_i915_gem_object *obj;
552e288e178SMatthew Auld struct intel_context *ce;
553e288e178SMatthew Auld struct i915_request *rq, *prev;
554e288e178SMatthew Auld struct spinner_timer st;
555e288e178SMatthew Auld struct sgt_dma it;
556e288e178SMatthew Auld int len, sz, err;
557e288e178SMatthew Auld u32 *cs;
558e288e178SMatthew Auld
559e288e178SMatthew Auld /*
560e288e178SMatthew Auld * Simple regression test to check that we don't trample the
561e288e178SMatthew Auld * rq->reserved_space when returning from emit_pte(), if the ring is
562e288e178SMatthew Auld * nearly full.
563e288e178SMatthew Auld */
564e288e178SMatthew Auld
565e288e178SMatthew Auld if (igt_spinner_init(&st.spin, to_gt(i915)))
566e288e178SMatthew Auld return -ENOMEM;
567e288e178SMatthew Auld
568e288e178SMatthew Auld obj = i915_gem_object_create_internal(i915, 2 * PAGE_SIZE);
569e288e178SMatthew Auld if (IS_ERR(obj)) {
570e288e178SMatthew Auld err = PTR_ERR(obj);
571e288e178SMatthew Auld goto out_spinner;
572e288e178SMatthew Auld }
573e288e178SMatthew Auld
574e288e178SMatthew Auld err = i915_gem_object_pin_pages_unlocked(obj);
575e288e178SMatthew Auld if (err)
576e288e178SMatthew Auld goto out_obj;
577e288e178SMatthew Auld
578e288e178SMatthew Auld ce = intel_migrate_create_context(migrate);
579e288e178SMatthew Auld if (IS_ERR(ce)) {
580e288e178SMatthew Auld err = PTR_ERR(ce);
581e288e178SMatthew Auld goto out_obj;
582e288e178SMatthew Auld }
583e288e178SMatthew Auld
584e288e178SMatthew Auld ce->ring_size = SZ_4K; /* Not too big */
585e288e178SMatthew Auld
586e288e178SMatthew Auld err = intel_context_pin(ce);
587e288e178SMatthew Auld if (err)
588e288e178SMatthew Auld goto out_put;
589e288e178SMatthew Auld
590e288e178SMatthew Auld rq = igt_spinner_create_request(&st.spin, ce, MI_ARB_CHECK);
591e288e178SMatthew Auld if (IS_ERR(rq)) {
592e288e178SMatthew Auld err = PTR_ERR(rq);
593e288e178SMatthew Auld goto out_unpin;
594e288e178SMatthew Auld }
595e288e178SMatthew Auld
596e288e178SMatthew Auld i915_request_add(rq);
597e288e178SMatthew Auld if (!igt_wait_for_spinner(&st.spin, rq)) {
598e288e178SMatthew Auld err = -EIO;
599e288e178SMatthew Auld goto out_unpin;
600e288e178SMatthew Auld }
601e288e178SMatthew Auld
602e288e178SMatthew Auld /*
603e288e178SMatthew Auld * Fill the rest of the ring leaving I915_EMIT_PTE_NUM_DWORDS +
604e288e178SMatthew Auld * ring->reserved_space at the end. To actually emit the PTEs we require
605e288e178SMatthew Auld * slightly more than I915_EMIT_PTE_NUM_DWORDS, since our object size is
606e288e178SMatthew Auld * greater than PAGE_SIZE. The correct behaviour is to wait for more
607e288e178SMatthew Auld * ring space in emit_pte(), otherwise we trample on the reserved_space
608e288e178SMatthew Auld * resulting in crashes when later submitting the rq.
609e288e178SMatthew Auld */
610e288e178SMatthew Auld
611e288e178SMatthew Auld prev = NULL;
612e288e178SMatthew Auld do {
613e288e178SMatthew Auld if (prev)
614e288e178SMatthew Auld i915_request_add(rq);
615e288e178SMatthew Auld
616e288e178SMatthew Auld rq = i915_request_create(ce);
617e288e178SMatthew Auld if (IS_ERR(rq)) {
618e288e178SMatthew Auld err = PTR_ERR(rq);
619e288e178SMatthew Auld goto out_unpin;
620e288e178SMatthew Auld }
621e288e178SMatthew Auld
622e288e178SMatthew Auld sz = (rq->ring->space - rq->reserved_space) / sizeof(u32) -
623e288e178SMatthew Auld I915_EMIT_PTE_NUM_DWORDS;
624e288e178SMatthew Auld sz = min_t(u32, sz, (SZ_1K - rq->reserved_space) / sizeof(u32) -
625e288e178SMatthew Auld I915_EMIT_PTE_NUM_DWORDS);
626e288e178SMatthew Auld cs = intel_ring_begin(rq, sz);
627e288e178SMatthew Auld if (IS_ERR(cs)) {
628e288e178SMatthew Auld err = PTR_ERR(cs);
629e288e178SMatthew Auld goto out_rq;
630e288e178SMatthew Auld }
631e288e178SMatthew Auld
632e288e178SMatthew Auld memset32(cs, MI_NOOP, sz);
633e288e178SMatthew Auld cs += sz;
634e288e178SMatthew Auld intel_ring_advance(rq, cs);
635e288e178SMatthew Auld
636e288e178SMatthew Auld pr_info("%s emit=%u sz=%d\n", __func__, rq->ring->emit, sz);
637e288e178SMatthew Auld
638e288e178SMatthew Auld prev = rq;
639e288e178SMatthew Auld } while (rq->ring->space > (rq->reserved_space +
640e288e178SMatthew Auld I915_EMIT_PTE_NUM_DWORDS * sizeof(u32)));
641e288e178SMatthew Auld
642e288e178SMatthew Auld timer_setup_on_stack(&st.timer, spinner_kill, 0);
643e288e178SMatthew Auld mod_timer(&st.timer, jiffies + 2 * HZ);
644e288e178SMatthew Auld
645e288e178SMatthew Auld /*
646e288e178SMatthew Auld * This should wait for the spinner to be killed, otherwise we should go
647e288e178SMatthew Auld * down in flames when doing i915_request_add().
648e288e178SMatthew Auld */
649e288e178SMatthew Auld pr_info("%s emite_pte ring space=%u\n", __func__, rq->ring->space);
650e288e178SMatthew Auld it = sg_sgt(obj->mm.pages->sgl);
6519275277dSFei Yang len = emit_pte(rq, &it, obj->pat_index, false, 0, CHUNK_SZ);
652e288e178SMatthew Auld if (!len) {
653e288e178SMatthew Auld err = -EINVAL;
654e288e178SMatthew Auld goto out_rq;
655e288e178SMatthew Auld }
656e288e178SMatthew Auld if (len < 0) {
657e288e178SMatthew Auld err = len;
658e288e178SMatthew Auld goto out_rq;
659e288e178SMatthew Auld }
660e288e178SMatthew Auld
661e288e178SMatthew Auld out_rq:
662e288e178SMatthew Auld i915_request_add(rq); /* GEM_BUG_ON(rq->reserved_space > ring->space)? */
663e288e178SMatthew Auld del_timer_sync(&st.timer);
664e288e178SMatthew Auld destroy_timer_on_stack(&st.timer);
665e288e178SMatthew Auld out_unpin:
666e288e178SMatthew Auld intel_context_unpin(ce);
667e288e178SMatthew Auld out_put:
668e288e178SMatthew Auld intel_context_put(ce);
669e288e178SMatthew Auld out_obj:
670e288e178SMatthew Auld i915_gem_object_put(obj);
671e288e178SMatthew Auld out_spinner:
672e288e178SMatthew Auld igt_spinner_fini(&st.spin);
673e288e178SMatthew Auld return err;
674e288e178SMatthew Auld }
675e288e178SMatthew Auld
676cf586021SChris Wilson struct threaded_migrate {
677cf586021SChris Wilson struct intel_migrate *migrate;
678cf586021SChris Wilson struct task_struct *tsk;
679cf586021SChris Wilson struct rnd_state prng;
680cf586021SChris Wilson };
681cf586021SChris Wilson
threaded_migrate(struct intel_migrate * migrate,int (* fn)(void * arg),unsigned int flags)682cf586021SChris Wilson static int threaded_migrate(struct intel_migrate *migrate,
683cf586021SChris Wilson int (*fn)(void *arg),
684cf586021SChris Wilson unsigned int flags)
685cf586021SChris Wilson {
686cf586021SChris Wilson const unsigned int n_cpus = num_online_cpus() + 1;
687cf586021SChris Wilson struct threaded_migrate *thread;
688cf586021SChris Wilson I915_RND_STATE(prng);
689cf586021SChris Wilson unsigned int i;
690cf586021SChris Wilson int err = 0;
691cf586021SChris Wilson
692cf586021SChris Wilson thread = kcalloc(n_cpus, sizeof(*thread), GFP_KERNEL);
693cf586021SChris Wilson if (!thread)
694cf586021SChris Wilson return 0;
695cf586021SChris Wilson
696cf586021SChris Wilson for (i = 0; i < n_cpus; ++i) {
697cf586021SChris Wilson struct task_struct *tsk;
698cf586021SChris Wilson
699cf586021SChris Wilson thread[i].migrate = migrate;
700cf586021SChris Wilson thread[i].prng =
701cf586021SChris Wilson I915_RND_STATE_INITIALIZER(prandom_u32_state(&prng));
702cf586021SChris Wilson
703cf586021SChris Wilson tsk = kthread_run(fn, &thread[i], "igt-%d", i);
704cf586021SChris Wilson if (IS_ERR(tsk)) {
705cf586021SChris Wilson err = PTR_ERR(tsk);
706cf586021SChris Wilson break;
707cf586021SChris Wilson }
708cf586021SChris Wilson
709cf586021SChris Wilson get_task_struct(tsk);
710cf586021SChris Wilson thread[i].tsk = tsk;
711cf586021SChris Wilson }
712cf586021SChris Wilson
713cf586021SChris Wilson msleep(10); /* start all threads before we kthread_stop() */
714cf586021SChris Wilson
715cf586021SChris Wilson for (i = 0; i < n_cpus; ++i) {
716cf586021SChris Wilson struct task_struct *tsk = thread[i].tsk;
717cf586021SChris Wilson int status;
718cf586021SChris Wilson
719cf586021SChris Wilson if (IS_ERR_OR_NULL(tsk))
720cf586021SChris Wilson continue;
721cf586021SChris Wilson
722*a9da6ddaSAndreas Gruenbacher status = kthread_stop_put(tsk);
723cf586021SChris Wilson if (status && !err)
724cf586021SChris Wilson err = status;
725cf586021SChris Wilson }
726cf586021SChris Wilson
727cf586021SChris Wilson kfree(thread);
728cf586021SChris Wilson return err;
729cf586021SChris Wilson }
730cf586021SChris Wilson
__thread_migrate_copy(void * arg)731cf586021SChris Wilson static int __thread_migrate_copy(void *arg)
732cf586021SChris Wilson {
733cf586021SChris Wilson struct threaded_migrate *tm = arg;
734cf586021SChris Wilson
735cf586021SChris Wilson return migrate_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
736cf586021SChris Wilson }
737cf586021SChris Wilson
thread_migrate_copy(void * arg)738cf586021SChris Wilson static int thread_migrate_copy(void *arg)
739cf586021SChris Wilson {
740f7f0ca57SMatthew Auld struct intel_gt *gt = arg;
741f7f0ca57SMatthew Auld struct intel_migrate *migrate = >->migrate;
742f7f0ca57SMatthew Auld
743f7f0ca57SMatthew Auld return threaded_migrate(migrate, __thread_migrate_copy, 0);
744cf586021SChris Wilson }
745cf586021SChris Wilson
__thread_global_copy(void * arg)746cf586021SChris Wilson static int __thread_global_copy(void *arg)
747cf586021SChris Wilson {
748cf586021SChris Wilson struct threaded_migrate *tm = arg;
749cf586021SChris Wilson
750cf586021SChris Wilson return global_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
751cf586021SChris Wilson }
752cf586021SChris Wilson
thread_global_copy(void * arg)753cf586021SChris Wilson static int thread_global_copy(void *arg)
754cf586021SChris Wilson {
755f7f0ca57SMatthew Auld struct intel_gt *gt = arg;
756f7f0ca57SMatthew Auld struct intel_migrate *migrate = >->migrate;
757f7f0ca57SMatthew Auld
758f7f0ca57SMatthew Auld return threaded_migrate(migrate, __thread_global_copy, 0);
759cf586021SChris Wilson }
760cf586021SChris Wilson
__thread_migrate_clear(void * arg)761563baae1SChris Wilson static int __thread_migrate_clear(void *arg)
762563baae1SChris Wilson {
763563baae1SChris Wilson struct threaded_migrate *tm = arg;
764563baae1SChris Wilson
765563baae1SChris Wilson return migrate_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
766563baae1SChris Wilson }
767563baae1SChris Wilson
__thread_global_clear(void * arg)768563baae1SChris Wilson static int __thread_global_clear(void *arg)
769563baae1SChris Wilson {
770563baae1SChris Wilson struct threaded_migrate *tm = arg;
771563baae1SChris Wilson
772563baae1SChris Wilson return global_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
773563baae1SChris Wilson }
774563baae1SChris Wilson
thread_migrate_clear(void * arg)775563baae1SChris Wilson static int thread_migrate_clear(void *arg)
776563baae1SChris Wilson {
777f7f0ca57SMatthew Auld struct intel_gt *gt = arg;
778f7f0ca57SMatthew Auld struct intel_migrate *migrate = >->migrate;
779f7f0ca57SMatthew Auld
780f7f0ca57SMatthew Auld return threaded_migrate(migrate, __thread_migrate_clear, 0);
781563baae1SChris Wilson }
782563baae1SChris Wilson
thread_global_clear(void * arg)783563baae1SChris Wilson static int thread_global_clear(void *arg)
784563baae1SChris Wilson {
785f7f0ca57SMatthew Auld struct intel_gt *gt = arg;
786f7f0ca57SMatthew Auld struct intel_migrate *migrate = >->migrate;
787f7f0ca57SMatthew Auld
788f7f0ca57SMatthew Auld return threaded_migrate(migrate, __thread_global_clear, 0);
789563baae1SChris Wilson }
790563baae1SChris Wilson
intel_migrate_live_selftests(struct drm_i915_private * i915)791cf586021SChris Wilson int intel_migrate_live_selftests(struct drm_i915_private *i915)
792cf586021SChris Wilson {
793cf586021SChris Wilson static const struct i915_subtest tests[] = {
794cf586021SChris Wilson SUBTEST(live_migrate_copy),
795563baae1SChris Wilson SUBTEST(live_migrate_clear),
796e288e178SMatthew Auld SUBTEST(live_emit_pte_full_ring),
797cf586021SChris Wilson SUBTEST(thread_migrate_copy),
798563baae1SChris Wilson SUBTEST(thread_migrate_clear),
799cf586021SChris Wilson SUBTEST(thread_global_copy),
800563baae1SChris Wilson SUBTEST(thread_global_clear),
801cf586021SChris Wilson };
802c14adcbdSMichał Winiarski struct intel_gt *gt = to_gt(i915);
803cf586021SChris Wilson
80494ce0d65SChris Wilson if (!gt->migrate.context)
805cf586021SChris Wilson return 0;
806cf586021SChris Wilson
807f7f0ca57SMatthew Auld return intel_gt_live_subtests(tests, gt);
80894ce0d65SChris Wilson }
809cf586021SChris Wilson
81094ce0d65SChris Wilson static struct drm_i915_gem_object *
create_init_lmem_internal(struct intel_gt * gt,size_t sz,bool try_lmem)81194ce0d65SChris Wilson create_init_lmem_internal(struct intel_gt *gt, size_t sz, bool try_lmem)
81294ce0d65SChris Wilson {
81394ce0d65SChris Wilson struct drm_i915_gem_object *obj = NULL;
81494ce0d65SChris Wilson int err;
81594ce0d65SChris Wilson
81694ce0d65SChris Wilson if (try_lmem)
81794ce0d65SChris Wilson obj = i915_gem_object_create_lmem(gt->i915, sz, 0);
81894ce0d65SChris Wilson
81994ce0d65SChris Wilson if (IS_ERR_OR_NULL(obj)) {
82094ce0d65SChris Wilson obj = i915_gem_object_create_internal(gt->i915, sz);
82194ce0d65SChris Wilson if (IS_ERR(obj))
82294ce0d65SChris Wilson return obj;
82394ce0d65SChris Wilson }
82494ce0d65SChris Wilson
825d8be1357SMaarten Lankhorst i915_gem_object_trylock(obj, NULL);
82694ce0d65SChris Wilson err = i915_gem_object_pin_pages(obj);
82794ce0d65SChris Wilson if (err) {
82894ce0d65SChris Wilson i915_gem_object_unlock(obj);
82994ce0d65SChris Wilson i915_gem_object_put(obj);
83094ce0d65SChris Wilson return ERR_PTR(err);
83194ce0d65SChris Wilson }
83294ce0d65SChris Wilson
83394ce0d65SChris Wilson return obj;
83494ce0d65SChris Wilson }
83594ce0d65SChris Wilson
wrap_ktime_compare(const void * A,const void * B)83694ce0d65SChris Wilson static int wrap_ktime_compare(const void *A, const void *B)
83794ce0d65SChris Wilson {
83894ce0d65SChris Wilson const ktime_t *a = A, *b = B;
83994ce0d65SChris Wilson
84094ce0d65SChris Wilson return ktime_compare(*a, *b);
84194ce0d65SChris Wilson }
84294ce0d65SChris Wilson
__perf_clear_blt(struct intel_context * ce,struct scatterlist * sg,unsigned int pat_index,bool is_lmem,size_t sz)84394ce0d65SChris Wilson static int __perf_clear_blt(struct intel_context *ce,
84494ce0d65SChris Wilson struct scatterlist *sg,
8459275277dSFei Yang unsigned int pat_index,
84694ce0d65SChris Wilson bool is_lmem,
84794ce0d65SChris Wilson size_t sz)
84894ce0d65SChris Wilson {
84994ce0d65SChris Wilson ktime_t t[5];
85094ce0d65SChris Wilson int pass;
85194ce0d65SChris Wilson int err = 0;
85294ce0d65SChris Wilson
85394ce0d65SChris Wilson for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
85494ce0d65SChris Wilson struct i915_request *rq;
85594ce0d65SChris Wilson ktime_t t0, t1;
85694ce0d65SChris Wilson
85794ce0d65SChris Wilson t0 = ktime_get();
85894ce0d65SChris Wilson
8599275277dSFei Yang err = intel_context_migrate_clear(ce, NULL, sg, pat_index,
86094ce0d65SChris Wilson is_lmem, 0, &rq);
86194ce0d65SChris Wilson if (rq) {
86294ce0d65SChris Wilson if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
86394ce0d65SChris Wilson err = -EIO;
86494ce0d65SChris Wilson i915_request_put(rq);
86594ce0d65SChris Wilson }
86694ce0d65SChris Wilson if (err)
86794ce0d65SChris Wilson break;
86894ce0d65SChris Wilson
86994ce0d65SChris Wilson t1 = ktime_get();
87094ce0d65SChris Wilson t[pass] = ktime_sub(t1, t0);
87194ce0d65SChris Wilson }
87294ce0d65SChris Wilson if (err)
873cf586021SChris Wilson return err;
87494ce0d65SChris Wilson
87594ce0d65SChris Wilson sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
87694ce0d65SChris Wilson pr_info("%s: %zd KiB fill: %lld MiB/s\n",
87794ce0d65SChris Wilson ce->engine->name, sz >> 10,
87894ce0d65SChris Wilson div64_u64(mul_u32_u32(4 * sz,
87994ce0d65SChris Wilson 1000 * 1000 * 1000),
88094ce0d65SChris Wilson t[1] + 2 * t[2] + t[3]) >> 20);
88194ce0d65SChris Wilson return 0;
88294ce0d65SChris Wilson }
88394ce0d65SChris Wilson
perf_clear_blt(void * arg)88494ce0d65SChris Wilson static int perf_clear_blt(void *arg)
88594ce0d65SChris Wilson {
88694ce0d65SChris Wilson struct intel_gt *gt = arg;
88794ce0d65SChris Wilson static const unsigned long sizes[] = {
88894ce0d65SChris Wilson SZ_4K,
88994ce0d65SChris Wilson SZ_64K,
89094ce0d65SChris Wilson SZ_2M,
89194ce0d65SChris Wilson SZ_64M
89294ce0d65SChris Wilson };
89394ce0d65SChris Wilson int i;
89494ce0d65SChris Wilson
89594ce0d65SChris Wilson for (i = 0; i < ARRAY_SIZE(sizes); i++) {
89694ce0d65SChris Wilson struct drm_i915_gem_object *dst;
89794ce0d65SChris Wilson int err;
89894ce0d65SChris Wilson
89994ce0d65SChris Wilson dst = create_init_lmem_internal(gt, sizes[i], true);
90094ce0d65SChris Wilson if (IS_ERR(dst))
90194ce0d65SChris Wilson return PTR_ERR(dst);
90294ce0d65SChris Wilson
90394ce0d65SChris Wilson err = __perf_clear_blt(gt->migrate.context,
90494ce0d65SChris Wilson dst->mm.pages->sgl,
9059275277dSFei Yang i915_gem_get_pat_index(gt->i915,
9069275277dSFei Yang I915_CACHE_NONE),
90794ce0d65SChris Wilson i915_gem_object_is_lmem(dst),
90894ce0d65SChris Wilson sizes[i]);
90994ce0d65SChris Wilson
91094ce0d65SChris Wilson i915_gem_object_unlock(dst);
91194ce0d65SChris Wilson i915_gem_object_put(dst);
91294ce0d65SChris Wilson if (err)
91394ce0d65SChris Wilson return err;
91494ce0d65SChris Wilson }
91594ce0d65SChris Wilson
91694ce0d65SChris Wilson return 0;
91794ce0d65SChris Wilson }
91894ce0d65SChris Wilson
__perf_copy_blt(struct intel_context * ce,struct scatterlist * src,unsigned int src_pat_index,bool src_is_lmem,struct scatterlist * dst,unsigned int dst_pat_index,bool dst_is_lmem,size_t sz)91994ce0d65SChris Wilson static int __perf_copy_blt(struct intel_context *ce,
92094ce0d65SChris Wilson struct scatterlist *src,
9219275277dSFei Yang unsigned int src_pat_index,
92294ce0d65SChris Wilson bool src_is_lmem,
92394ce0d65SChris Wilson struct scatterlist *dst,
9249275277dSFei Yang unsigned int dst_pat_index,
92594ce0d65SChris Wilson bool dst_is_lmem,
92694ce0d65SChris Wilson size_t sz)
92794ce0d65SChris Wilson {
92894ce0d65SChris Wilson ktime_t t[5];
92994ce0d65SChris Wilson int pass;
93094ce0d65SChris Wilson int err = 0;
93194ce0d65SChris Wilson
93294ce0d65SChris Wilson for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
93394ce0d65SChris Wilson struct i915_request *rq;
93494ce0d65SChris Wilson ktime_t t0, t1;
93594ce0d65SChris Wilson
93694ce0d65SChris Wilson t0 = ktime_get();
93794ce0d65SChris Wilson
93894ce0d65SChris Wilson err = intel_context_migrate_copy(ce, NULL,
9399275277dSFei Yang src, src_pat_index,
94094ce0d65SChris Wilson src_is_lmem,
9419275277dSFei Yang dst, dst_pat_index,
94294ce0d65SChris Wilson dst_is_lmem,
94394ce0d65SChris Wilson &rq);
94494ce0d65SChris Wilson if (rq) {
94594ce0d65SChris Wilson if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
94694ce0d65SChris Wilson err = -EIO;
94794ce0d65SChris Wilson i915_request_put(rq);
94894ce0d65SChris Wilson }
94994ce0d65SChris Wilson if (err)
95094ce0d65SChris Wilson break;
95194ce0d65SChris Wilson
95294ce0d65SChris Wilson t1 = ktime_get();
95394ce0d65SChris Wilson t[pass] = ktime_sub(t1, t0);
95494ce0d65SChris Wilson }
95594ce0d65SChris Wilson if (err)
95694ce0d65SChris Wilson return err;
95794ce0d65SChris Wilson
95894ce0d65SChris Wilson sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
95994ce0d65SChris Wilson pr_info("%s: %zd KiB copy: %lld MiB/s\n",
96094ce0d65SChris Wilson ce->engine->name, sz >> 10,
96194ce0d65SChris Wilson div64_u64(mul_u32_u32(4 * sz,
96294ce0d65SChris Wilson 1000 * 1000 * 1000),
96394ce0d65SChris Wilson t[1] + 2 * t[2] + t[3]) >> 20);
96494ce0d65SChris Wilson return 0;
96594ce0d65SChris Wilson }
96694ce0d65SChris Wilson
perf_copy_blt(void * arg)96794ce0d65SChris Wilson static int perf_copy_blt(void *arg)
96894ce0d65SChris Wilson {
96994ce0d65SChris Wilson struct intel_gt *gt = arg;
97094ce0d65SChris Wilson static const unsigned long sizes[] = {
97194ce0d65SChris Wilson SZ_4K,
97294ce0d65SChris Wilson SZ_64K,
97394ce0d65SChris Wilson SZ_2M,
97494ce0d65SChris Wilson SZ_64M
97594ce0d65SChris Wilson };
97694ce0d65SChris Wilson int i;
97794ce0d65SChris Wilson
97894ce0d65SChris Wilson for (i = 0; i < ARRAY_SIZE(sizes); i++) {
97994ce0d65SChris Wilson struct drm_i915_gem_object *src, *dst;
980ae686e22SMatthew Auld size_t sz;
98194ce0d65SChris Wilson int err;
98294ce0d65SChris Wilson
98394ce0d65SChris Wilson src = create_init_lmem_internal(gt, sizes[i], true);
98494ce0d65SChris Wilson if (IS_ERR(src))
98594ce0d65SChris Wilson return PTR_ERR(src);
98694ce0d65SChris Wilson
987ae686e22SMatthew Auld sz = src->base.size;
988ae686e22SMatthew Auld dst = create_init_lmem_internal(gt, sz, false);
98994ce0d65SChris Wilson if (IS_ERR(dst)) {
99094ce0d65SChris Wilson err = PTR_ERR(dst);
99194ce0d65SChris Wilson goto err_src;
99294ce0d65SChris Wilson }
99394ce0d65SChris Wilson
99494ce0d65SChris Wilson err = __perf_copy_blt(gt->migrate.context,
99594ce0d65SChris Wilson src->mm.pages->sgl,
9969275277dSFei Yang i915_gem_get_pat_index(gt->i915,
9979275277dSFei Yang I915_CACHE_NONE),
99894ce0d65SChris Wilson i915_gem_object_is_lmem(src),
99994ce0d65SChris Wilson dst->mm.pages->sgl,
10009275277dSFei Yang i915_gem_get_pat_index(gt->i915,
10019275277dSFei Yang I915_CACHE_NONE),
100294ce0d65SChris Wilson i915_gem_object_is_lmem(dst),
1003ae686e22SMatthew Auld sz);
100494ce0d65SChris Wilson
100594ce0d65SChris Wilson i915_gem_object_unlock(dst);
100694ce0d65SChris Wilson i915_gem_object_put(dst);
100794ce0d65SChris Wilson err_src:
100894ce0d65SChris Wilson i915_gem_object_unlock(src);
100994ce0d65SChris Wilson i915_gem_object_put(src);
101094ce0d65SChris Wilson if (err)
101194ce0d65SChris Wilson return err;
101294ce0d65SChris Wilson }
101394ce0d65SChris Wilson
101494ce0d65SChris Wilson return 0;
101594ce0d65SChris Wilson }
101694ce0d65SChris Wilson
intel_migrate_perf_selftests(struct drm_i915_private * i915)101794ce0d65SChris Wilson int intel_migrate_perf_selftests(struct drm_i915_private *i915)
101894ce0d65SChris Wilson {
101994ce0d65SChris Wilson static const struct i915_subtest tests[] = {
102094ce0d65SChris Wilson SUBTEST(perf_clear_blt),
102194ce0d65SChris Wilson SUBTEST(perf_copy_blt),
102294ce0d65SChris Wilson };
1023c14adcbdSMichał Winiarski struct intel_gt *gt = to_gt(i915);
102494ce0d65SChris Wilson
102594ce0d65SChris Wilson if (intel_gt_is_wedged(gt))
102694ce0d65SChris Wilson return 0;
102794ce0d65SChris Wilson
102894ce0d65SChris Wilson if (!gt->migrate.context)
102994ce0d65SChris Wilson return 0;
103094ce0d65SChris Wilson
103194ce0d65SChris Wilson return intel_gt_live_subtests(tests, gt);
1032cf586021SChris Wilson }
1033