1c349dbc7Sjsg /*
2c349dbc7Sjsg * SPDX-License-Identifier: MIT
3c349dbc7Sjsg *
4c349dbc7Sjsg * Copyright © 2017 Intel Corporation
5c349dbc7Sjsg */
6c349dbc7Sjsg
7c349dbc7Sjsg #include <linux/prime_numbers.h>
81bb76ff1Sjsg #include <linux/string_helpers.h>
91bb76ff1Sjsg #include <linux/swap.h>
10c349dbc7Sjsg
11c349dbc7Sjsg #include "i915_selftest.h"
12c349dbc7Sjsg
131bb76ff1Sjsg #include "gem/i915_gem_internal.h"
14c349dbc7Sjsg #include "gem/i915_gem_lmem.h"
15c349dbc7Sjsg #include "gem/i915_gem_pm.h"
161bb76ff1Sjsg #include "gem/i915_gem_region.h"
17c349dbc7Sjsg
18c349dbc7Sjsg #include "gt/intel_gt.h"
19c349dbc7Sjsg
20c349dbc7Sjsg #include "igt_gem_utils.h"
21c349dbc7Sjsg #include "mock_context.h"
22c349dbc7Sjsg
23c349dbc7Sjsg #include "selftests/mock_drm.h"
24c349dbc7Sjsg #include "selftests/mock_gem_device.h"
25c349dbc7Sjsg #include "selftests/mock_region.h"
26c349dbc7Sjsg #include "selftests/i915_random.h"
27c349dbc7Sjsg
hugepage_ctx(struct drm_i915_private * i915,struct file * file)281bb76ff1Sjsg static struct i915_gem_context *hugepage_ctx(struct drm_i915_private *i915,
291bb76ff1Sjsg struct file *file)
301bb76ff1Sjsg {
311bb76ff1Sjsg struct i915_gem_context *ctx = live_context(i915, file);
321bb76ff1Sjsg struct i915_address_space *vm;
331bb76ff1Sjsg
341bb76ff1Sjsg if (IS_ERR(ctx))
351bb76ff1Sjsg return ctx;
361bb76ff1Sjsg
371bb76ff1Sjsg vm = ctx->vm;
381bb76ff1Sjsg if (vm)
391bb76ff1Sjsg WRITE_ONCE(vm->scrub_64K, true);
401bb76ff1Sjsg
411bb76ff1Sjsg return ctx;
421bb76ff1Sjsg }
431bb76ff1Sjsg
44c349dbc7Sjsg static const unsigned int page_sizes[] = {
45c349dbc7Sjsg I915_GTT_PAGE_SIZE_2M,
46c349dbc7Sjsg I915_GTT_PAGE_SIZE_64K,
47c349dbc7Sjsg I915_GTT_PAGE_SIZE_4K,
48c349dbc7Sjsg };
49c349dbc7Sjsg
get_largest_page_size(struct drm_i915_private * i915,u64 rem)50c349dbc7Sjsg static unsigned int get_largest_page_size(struct drm_i915_private *i915,
51c349dbc7Sjsg u64 rem)
52c349dbc7Sjsg {
53c349dbc7Sjsg int i;
54c349dbc7Sjsg
55c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(page_sizes); ++i) {
56c349dbc7Sjsg unsigned int page_size = page_sizes[i];
57c349dbc7Sjsg
58c349dbc7Sjsg if (HAS_PAGE_SIZES(i915, page_size) && rem >= page_size)
59c349dbc7Sjsg return page_size;
60c349dbc7Sjsg }
61c349dbc7Sjsg
62c349dbc7Sjsg return 0;
63c349dbc7Sjsg }
64c349dbc7Sjsg
huge_pages_free_pages(struct sg_table * st)65c349dbc7Sjsg static void huge_pages_free_pages(struct sg_table *st)
66c349dbc7Sjsg {
67c349dbc7Sjsg struct scatterlist *sg;
68c349dbc7Sjsg
69c349dbc7Sjsg for (sg = st->sgl; sg; sg = __sg_next(sg)) {
70c349dbc7Sjsg if (sg_page(sg))
71c349dbc7Sjsg __free_pages(sg_page(sg), get_order(sg->length));
72c349dbc7Sjsg }
73c349dbc7Sjsg
74c349dbc7Sjsg sg_free_table(st);
75c349dbc7Sjsg kfree(st);
76c349dbc7Sjsg }
77c349dbc7Sjsg
get_huge_pages(struct drm_i915_gem_object * obj)78c349dbc7Sjsg static int get_huge_pages(struct drm_i915_gem_object *obj)
79c349dbc7Sjsg {
80c349dbc7Sjsg #define GFP (GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY)
81c349dbc7Sjsg unsigned int page_mask = obj->mm.page_mask;
82c349dbc7Sjsg struct sg_table *st;
83c349dbc7Sjsg struct scatterlist *sg;
84c349dbc7Sjsg unsigned int sg_page_sizes;
85c349dbc7Sjsg u64 rem;
86c349dbc7Sjsg
87*f005ef32Sjsg /* restricted by sg_alloc_table */
88*f005ef32Sjsg if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
89*f005ef32Sjsg return -E2BIG;
90*f005ef32Sjsg
91c349dbc7Sjsg st = kmalloc(sizeof(*st), GFP);
92c349dbc7Sjsg if (!st)
93c349dbc7Sjsg return -ENOMEM;
94c349dbc7Sjsg
95c349dbc7Sjsg if (sg_alloc_table(st, obj->base.size >> PAGE_SHIFT, GFP)) {
96c349dbc7Sjsg kfree(st);
97c349dbc7Sjsg return -ENOMEM;
98c349dbc7Sjsg }
99c349dbc7Sjsg
100c349dbc7Sjsg rem = obj->base.size;
101c349dbc7Sjsg sg = st->sgl;
102c349dbc7Sjsg st->nents = 0;
103c349dbc7Sjsg sg_page_sizes = 0;
104c349dbc7Sjsg
105c349dbc7Sjsg /*
106c349dbc7Sjsg * Our goal here is simple, we want to greedily fill the object from
107c349dbc7Sjsg * largest to smallest page-size, while ensuring that we use *every*
108c349dbc7Sjsg * page-size as per the given page-mask.
109c349dbc7Sjsg */
110c349dbc7Sjsg do {
111c349dbc7Sjsg unsigned int bit = ilog2(page_mask);
112c349dbc7Sjsg unsigned int page_size = BIT(bit);
113c349dbc7Sjsg int order = get_order(page_size);
114c349dbc7Sjsg
115c349dbc7Sjsg do {
116c349dbc7Sjsg struct vm_page *page;
117c349dbc7Sjsg
118*f005ef32Sjsg GEM_BUG_ON(order > MAX_ORDER);
119c349dbc7Sjsg page = alloc_pages(GFP | __GFP_ZERO, order);
120c349dbc7Sjsg if (!page)
121c349dbc7Sjsg goto err;
122c349dbc7Sjsg
123c349dbc7Sjsg sg_set_page(sg, page, page_size, 0);
124c349dbc7Sjsg sg_page_sizes |= page_size;
125c349dbc7Sjsg st->nents++;
126c349dbc7Sjsg
127c349dbc7Sjsg rem -= page_size;
128c349dbc7Sjsg if (!rem) {
129c349dbc7Sjsg sg_mark_end(sg);
130c349dbc7Sjsg break;
131c349dbc7Sjsg }
132c349dbc7Sjsg
133c349dbc7Sjsg sg = __sg_next(sg);
134c349dbc7Sjsg } while ((rem - ((page_size-1) & page_mask)) >= page_size);
135c349dbc7Sjsg
136c349dbc7Sjsg page_mask &= (page_size-1);
137c349dbc7Sjsg } while (page_mask);
138c349dbc7Sjsg
139c349dbc7Sjsg if (i915_gem_gtt_prepare_pages(obj, st))
140c349dbc7Sjsg goto err;
141c349dbc7Sjsg
142c349dbc7Sjsg GEM_BUG_ON(sg_page_sizes != obj->mm.page_mask);
143*f005ef32Sjsg __i915_gem_object_set_pages(obj, st);
144c349dbc7Sjsg
145c349dbc7Sjsg return 0;
146c349dbc7Sjsg
147c349dbc7Sjsg err:
148c349dbc7Sjsg sg_set_page(sg, NULL, 0, 0);
149c349dbc7Sjsg sg_mark_end(sg);
150c349dbc7Sjsg huge_pages_free_pages(st);
151c349dbc7Sjsg
152c349dbc7Sjsg return -ENOMEM;
153c349dbc7Sjsg }
154c349dbc7Sjsg
put_huge_pages(struct drm_i915_gem_object * obj,struct sg_table * pages)155c349dbc7Sjsg static void put_huge_pages(struct drm_i915_gem_object *obj,
156c349dbc7Sjsg struct sg_table *pages)
157c349dbc7Sjsg {
158c349dbc7Sjsg i915_gem_gtt_finish_pages(obj, pages);
159c349dbc7Sjsg huge_pages_free_pages(pages);
160c349dbc7Sjsg
161c349dbc7Sjsg obj->mm.dirty = false;
1621bb76ff1Sjsg
1631bb76ff1Sjsg __start_cpu_write(obj);
164c349dbc7Sjsg }
165c349dbc7Sjsg
166c349dbc7Sjsg static const struct drm_i915_gem_object_ops huge_page_ops = {
167ad8b1aafSjsg .name = "huge-gem",
1685ca02815Sjsg .flags = I915_GEM_OBJECT_IS_SHRINKABLE,
169c349dbc7Sjsg .get_pages = get_huge_pages,
170c349dbc7Sjsg .put_pages = put_huge_pages,
171c349dbc7Sjsg };
172c349dbc7Sjsg
173c349dbc7Sjsg static struct drm_i915_gem_object *
huge_pages_object(struct drm_i915_private * i915,u64 size,unsigned int page_mask)174c349dbc7Sjsg huge_pages_object(struct drm_i915_private *i915,
175c349dbc7Sjsg u64 size,
176c349dbc7Sjsg unsigned int page_mask)
177c349dbc7Sjsg {
178c349dbc7Sjsg static struct lock_class_key lock_class;
179c349dbc7Sjsg struct drm_i915_gem_object *obj;
1801bb76ff1Sjsg unsigned int cache_level;
181c349dbc7Sjsg
182c349dbc7Sjsg GEM_BUG_ON(!size);
183c349dbc7Sjsg GEM_BUG_ON(!IS_ALIGNED(size, BIT(__ffs(page_mask))));
184c349dbc7Sjsg
185c349dbc7Sjsg if (size >> PAGE_SHIFT > INT_MAX)
186c349dbc7Sjsg return ERR_PTR(-E2BIG);
187c349dbc7Sjsg
188c349dbc7Sjsg if (overflows_type(size, obj->base.size))
189c349dbc7Sjsg return ERR_PTR(-E2BIG);
190c349dbc7Sjsg
191c349dbc7Sjsg obj = i915_gem_object_alloc();
192c349dbc7Sjsg if (!obj)
193c349dbc7Sjsg return ERR_PTR(-ENOMEM);
194c349dbc7Sjsg
195c349dbc7Sjsg drm_gem_private_object_init(&i915->drm, &obj->base, size);
1965ca02815Sjsg i915_gem_object_init(obj, &huge_page_ops, &lock_class, 0);
1975ca02815Sjsg obj->mem_flags |= I915_BO_FLAG_STRUCT_PAGE;
198c349dbc7Sjsg i915_gem_object_set_volatile(obj);
199c349dbc7Sjsg
200c349dbc7Sjsg obj->write_domain = I915_GEM_DOMAIN_CPU;
201c349dbc7Sjsg obj->read_domains = I915_GEM_DOMAIN_CPU;
2021bb76ff1Sjsg
2031bb76ff1Sjsg cache_level = HAS_LLC(i915) ? I915_CACHE_LLC : I915_CACHE_NONE;
2041bb76ff1Sjsg i915_gem_object_set_cache_coherency(obj, cache_level);
205c349dbc7Sjsg
206c349dbc7Sjsg obj->mm.page_mask = page_mask;
207c349dbc7Sjsg
208c349dbc7Sjsg return obj;
209c349dbc7Sjsg }
210c349dbc7Sjsg
fake_get_huge_pages(struct drm_i915_gem_object * obj)211c349dbc7Sjsg static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
212c349dbc7Sjsg {
213c349dbc7Sjsg struct drm_i915_private *i915 = to_i915(obj->base.dev);
214c349dbc7Sjsg const u64 max_len = rounddown_pow_of_two(UINT_MAX);
215c349dbc7Sjsg struct sg_table *st;
216c349dbc7Sjsg struct scatterlist *sg;
217c349dbc7Sjsg u64 rem;
218c349dbc7Sjsg
219*f005ef32Sjsg /* restricted by sg_alloc_table */
220*f005ef32Sjsg if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
221*f005ef32Sjsg return -E2BIG;
222*f005ef32Sjsg
223c349dbc7Sjsg st = kmalloc(sizeof(*st), GFP);
224c349dbc7Sjsg if (!st)
225c349dbc7Sjsg return -ENOMEM;
226c349dbc7Sjsg
227c349dbc7Sjsg if (sg_alloc_table(st, obj->base.size >> PAGE_SHIFT, GFP)) {
228c349dbc7Sjsg kfree(st);
229c349dbc7Sjsg return -ENOMEM;
230c349dbc7Sjsg }
231c349dbc7Sjsg
232c349dbc7Sjsg /* Use optimal page sized chunks to fill in the sg table */
233c349dbc7Sjsg rem = obj->base.size;
234c349dbc7Sjsg sg = st->sgl;
235c349dbc7Sjsg st->nents = 0;
236c349dbc7Sjsg do {
237c349dbc7Sjsg unsigned int page_size = get_largest_page_size(i915, rem);
238c349dbc7Sjsg unsigned int len = min(page_size * div_u64(rem, page_size),
239c349dbc7Sjsg max_len);
240c349dbc7Sjsg
241c349dbc7Sjsg GEM_BUG_ON(!page_size);
242c349dbc7Sjsg
243c349dbc7Sjsg sg->offset = 0;
244c349dbc7Sjsg sg->length = len;
245c349dbc7Sjsg sg_dma_len(sg) = len;
246c349dbc7Sjsg sg_dma_address(sg) = page_size;
247c349dbc7Sjsg
248c349dbc7Sjsg st->nents++;
249c349dbc7Sjsg
250c349dbc7Sjsg rem -= len;
251c349dbc7Sjsg if (!rem) {
252c349dbc7Sjsg sg_mark_end(sg);
253c349dbc7Sjsg break;
254c349dbc7Sjsg }
255c349dbc7Sjsg
256c349dbc7Sjsg sg = sg_next(sg);
257c349dbc7Sjsg } while (1);
258c349dbc7Sjsg
259c349dbc7Sjsg i915_sg_trim(st);
260c349dbc7Sjsg
261*f005ef32Sjsg __i915_gem_object_set_pages(obj, st);
262c349dbc7Sjsg
263c349dbc7Sjsg return 0;
264c349dbc7Sjsg }
265c349dbc7Sjsg
fake_get_huge_pages_single(struct drm_i915_gem_object * obj)266c349dbc7Sjsg static int fake_get_huge_pages_single(struct drm_i915_gem_object *obj)
267c349dbc7Sjsg {
268c349dbc7Sjsg struct drm_i915_private *i915 = to_i915(obj->base.dev);
269c349dbc7Sjsg struct sg_table *st;
270c349dbc7Sjsg struct scatterlist *sg;
271c349dbc7Sjsg unsigned int page_size;
272c349dbc7Sjsg
273c349dbc7Sjsg st = kmalloc(sizeof(*st), GFP);
274c349dbc7Sjsg if (!st)
275c349dbc7Sjsg return -ENOMEM;
276c349dbc7Sjsg
277c349dbc7Sjsg if (sg_alloc_table(st, 1, GFP)) {
278c349dbc7Sjsg kfree(st);
279c349dbc7Sjsg return -ENOMEM;
280c349dbc7Sjsg }
281c349dbc7Sjsg
282c349dbc7Sjsg sg = st->sgl;
283c349dbc7Sjsg st->nents = 1;
284c349dbc7Sjsg
285c349dbc7Sjsg page_size = get_largest_page_size(i915, obj->base.size);
286c349dbc7Sjsg GEM_BUG_ON(!page_size);
287c349dbc7Sjsg
288c349dbc7Sjsg sg->offset = 0;
289c349dbc7Sjsg sg->length = obj->base.size;
290c349dbc7Sjsg sg_dma_len(sg) = obj->base.size;
291c349dbc7Sjsg sg_dma_address(sg) = page_size;
292c349dbc7Sjsg
293*f005ef32Sjsg __i915_gem_object_set_pages(obj, st);
294c349dbc7Sjsg
295c349dbc7Sjsg return 0;
296c349dbc7Sjsg #undef GFP
297c349dbc7Sjsg }
298c349dbc7Sjsg
fake_free_huge_pages(struct drm_i915_gem_object * obj,struct sg_table * pages)299c349dbc7Sjsg static void fake_free_huge_pages(struct drm_i915_gem_object *obj,
300c349dbc7Sjsg struct sg_table *pages)
301c349dbc7Sjsg {
302c349dbc7Sjsg sg_free_table(pages);
303c349dbc7Sjsg kfree(pages);
304c349dbc7Sjsg }
305c349dbc7Sjsg
fake_put_huge_pages(struct drm_i915_gem_object * obj,struct sg_table * pages)306c349dbc7Sjsg static void fake_put_huge_pages(struct drm_i915_gem_object *obj,
307c349dbc7Sjsg struct sg_table *pages)
308c349dbc7Sjsg {
309c349dbc7Sjsg fake_free_huge_pages(obj, pages);
310c349dbc7Sjsg obj->mm.dirty = false;
311c349dbc7Sjsg }
312c349dbc7Sjsg
313c349dbc7Sjsg static const struct drm_i915_gem_object_ops fake_ops = {
314ad8b1aafSjsg .name = "fake-gem",
315c349dbc7Sjsg .flags = I915_GEM_OBJECT_IS_SHRINKABLE,
316c349dbc7Sjsg .get_pages = fake_get_huge_pages,
317c349dbc7Sjsg .put_pages = fake_put_huge_pages,
318c349dbc7Sjsg };
319c349dbc7Sjsg
320c349dbc7Sjsg static const struct drm_i915_gem_object_ops fake_ops_single = {
321ad8b1aafSjsg .name = "fake-gem",
322c349dbc7Sjsg .flags = I915_GEM_OBJECT_IS_SHRINKABLE,
323c349dbc7Sjsg .get_pages = fake_get_huge_pages_single,
324c349dbc7Sjsg .put_pages = fake_put_huge_pages,
325c349dbc7Sjsg };
326c349dbc7Sjsg
327c349dbc7Sjsg static struct drm_i915_gem_object *
fake_huge_pages_object(struct drm_i915_private * i915,u64 size,bool single)328c349dbc7Sjsg fake_huge_pages_object(struct drm_i915_private *i915, u64 size, bool single)
329c349dbc7Sjsg {
330c349dbc7Sjsg static struct lock_class_key lock_class;
331c349dbc7Sjsg struct drm_i915_gem_object *obj;
332c349dbc7Sjsg
333c349dbc7Sjsg GEM_BUG_ON(!size);
334c349dbc7Sjsg GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
335c349dbc7Sjsg
336c349dbc7Sjsg if (size >> PAGE_SHIFT > UINT_MAX)
337c349dbc7Sjsg return ERR_PTR(-E2BIG);
338c349dbc7Sjsg
339c349dbc7Sjsg if (overflows_type(size, obj->base.size))
340c349dbc7Sjsg return ERR_PTR(-E2BIG);
341c349dbc7Sjsg
342c349dbc7Sjsg obj = i915_gem_object_alloc();
343c349dbc7Sjsg if (!obj)
344c349dbc7Sjsg return ERR_PTR(-ENOMEM);
345c349dbc7Sjsg
346c349dbc7Sjsg drm_gem_private_object_init(&i915->drm, &obj->base, size);
347c349dbc7Sjsg
348c349dbc7Sjsg if (single)
3495ca02815Sjsg i915_gem_object_init(obj, &fake_ops_single, &lock_class, 0);
350c349dbc7Sjsg else
3515ca02815Sjsg i915_gem_object_init(obj, &fake_ops, &lock_class, 0);
352c349dbc7Sjsg
353c349dbc7Sjsg i915_gem_object_set_volatile(obj);
354c349dbc7Sjsg
355c349dbc7Sjsg obj->write_domain = I915_GEM_DOMAIN_CPU;
356c349dbc7Sjsg obj->read_domains = I915_GEM_DOMAIN_CPU;
357*f005ef32Sjsg obj->pat_index = i915_gem_get_pat_index(i915, I915_CACHE_NONE);
358c349dbc7Sjsg
359c349dbc7Sjsg return obj;
360c349dbc7Sjsg }
361c349dbc7Sjsg
igt_check_page_sizes(struct i915_vma * vma)362c349dbc7Sjsg static int igt_check_page_sizes(struct i915_vma *vma)
363c349dbc7Sjsg {
364c349dbc7Sjsg struct drm_i915_private *i915 = vma->vm->i915;
3651bb76ff1Sjsg unsigned int supported = RUNTIME_INFO(i915)->page_sizes;
366c349dbc7Sjsg struct drm_i915_gem_object *obj = vma->obj;
367c349dbc7Sjsg int err;
368c349dbc7Sjsg
369c349dbc7Sjsg /* We have to wait for the async bind to complete before our asserts */
370c349dbc7Sjsg err = i915_vma_sync(vma);
371c349dbc7Sjsg if (err)
372c349dbc7Sjsg return err;
373c349dbc7Sjsg
374c349dbc7Sjsg if (!HAS_PAGE_SIZES(i915, vma->page_sizes.sg)) {
375c349dbc7Sjsg pr_err("unsupported page_sizes.sg=%u, supported=%u\n",
376c349dbc7Sjsg vma->page_sizes.sg & ~supported, supported);
377c349dbc7Sjsg err = -EINVAL;
378c349dbc7Sjsg }
379c349dbc7Sjsg
3801bb76ff1Sjsg if (!HAS_PAGE_SIZES(i915, vma->resource->page_sizes_gtt)) {
381c349dbc7Sjsg pr_err("unsupported page_sizes.gtt=%u, supported=%u\n",
3821bb76ff1Sjsg vma->resource->page_sizes_gtt & ~supported, supported);
383c349dbc7Sjsg err = -EINVAL;
384c349dbc7Sjsg }
385c349dbc7Sjsg
386c349dbc7Sjsg if (vma->page_sizes.phys != obj->mm.page_sizes.phys) {
387c349dbc7Sjsg pr_err("vma->page_sizes.phys(%u) != obj->mm.page_sizes.phys(%u)\n",
388c349dbc7Sjsg vma->page_sizes.phys, obj->mm.page_sizes.phys);
389c349dbc7Sjsg err = -EINVAL;
390c349dbc7Sjsg }
391c349dbc7Sjsg
392c349dbc7Sjsg if (vma->page_sizes.sg != obj->mm.page_sizes.sg) {
393c349dbc7Sjsg pr_err("vma->page_sizes.sg(%u) != obj->mm.page_sizes.sg(%u)\n",
394c349dbc7Sjsg vma->page_sizes.sg, obj->mm.page_sizes.sg);
395c349dbc7Sjsg err = -EINVAL;
396c349dbc7Sjsg }
397c349dbc7Sjsg
3985ca02815Sjsg /*
3995ca02815Sjsg * The dma-api is like a box of chocolates when it comes to the
4005ca02815Sjsg * alignment of dma addresses, however for LMEM we have total control
4015ca02815Sjsg * and so can guarantee alignment, likewise when we allocate our blocks
4025ca02815Sjsg * they should appear in descending order, and if we know that we align
4035ca02815Sjsg * to the largest page size for the GTT address, we should be able to
4045ca02815Sjsg * assert that if we see 2M physical pages then we should also get 2M
4055ca02815Sjsg * GTT pages. If we don't then something might be wrong in our
4065ca02815Sjsg * construction of the backing pages.
4075ca02815Sjsg *
4085ca02815Sjsg * Maintaining alignment is required to utilise huge pages in the ppGGT.
4095ca02815Sjsg */
4105ca02815Sjsg if (i915_gem_object_is_lmem(obj) &&
411*f005ef32Sjsg IS_ALIGNED(i915_vma_offset(vma), SZ_2M) &&
4125ca02815Sjsg vma->page_sizes.sg & SZ_2M &&
4131bb76ff1Sjsg vma->resource->page_sizes_gtt < SZ_2M) {
4145ca02815Sjsg pr_err("gtt pages mismatch for LMEM, expected 2M GTT pages, sg(%u), gtt(%u)\n",
4151bb76ff1Sjsg vma->page_sizes.sg, vma->resource->page_sizes_gtt);
416c349dbc7Sjsg err = -EINVAL;
417c349dbc7Sjsg }
418c349dbc7Sjsg
419c349dbc7Sjsg return err;
420c349dbc7Sjsg }
421c349dbc7Sjsg
igt_mock_exhaust_device_supported_pages(void * arg)422c349dbc7Sjsg static int igt_mock_exhaust_device_supported_pages(void *arg)
423c349dbc7Sjsg {
424c349dbc7Sjsg struct i915_ppgtt *ppgtt = arg;
425c349dbc7Sjsg struct drm_i915_private *i915 = ppgtt->vm.i915;
4261bb76ff1Sjsg unsigned int saved_mask = RUNTIME_INFO(i915)->page_sizes;
427c349dbc7Sjsg struct drm_i915_gem_object *obj;
428c349dbc7Sjsg struct i915_vma *vma;
429c349dbc7Sjsg int i, j, single;
430c349dbc7Sjsg int err;
431c349dbc7Sjsg
432c349dbc7Sjsg /*
433c349dbc7Sjsg * Sanity check creating objects with every valid page support
434c349dbc7Sjsg * combination for our mock device.
435c349dbc7Sjsg */
436c349dbc7Sjsg
437c349dbc7Sjsg for (i = 1; i < BIT(ARRAY_SIZE(page_sizes)); i++) {
438ad8b1aafSjsg unsigned int combination = SZ_4K; /* Required for ppGTT */
439c349dbc7Sjsg
440c349dbc7Sjsg for (j = 0; j < ARRAY_SIZE(page_sizes); j++) {
441c349dbc7Sjsg if (i & BIT(j))
442c349dbc7Sjsg combination |= page_sizes[j];
443c349dbc7Sjsg }
444c349dbc7Sjsg
4451bb76ff1Sjsg RUNTIME_INFO(i915)->page_sizes = combination;
446c349dbc7Sjsg
447c349dbc7Sjsg for (single = 0; single <= 1; ++single) {
448c349dbc7Sjsg obj = fake_huge_pages_object(i915, combination, !!single);
449c349dbc7Sjsg if (IS_ERR(obj)) {
450c349dbc7Sjsg err = PTR_ERR(obj);
451c349dbc7Sjsg goto out_device;
452c349dbc7Sjsg }
453c349dbc7Sjsg
454c349dbc7Sjsg if (obj->base.size != combination) {
455c349dbc7Sjsg pr_err("obj->base.size=%zu, expected=%u\n",
456c349dbc7Sjsg obj->base.size, combination);
457c349dbc7Sjsg err = -EINVAL;
458c349dbc7Sjsg goto out_put;
459c349dbc7Sjsg }
460c349dbc7Sjsg
461c349dbc7Sjsg vma = i915_vma_instance(obj, &ppgtt->vm, NULL);
462c349dbc7Sjsg if (IS_ERR(vma)) {
463c349dbc7Sjsg err = PTR_ERR(vma);
464c349dbc7Sjsg goto out_put;
465c349dbc7Sjsg }
466c349dbc7Sjsg
467c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, PIN_USER);
468c349dbc7Sjsg if (err)
469ad8b1aafSjsg goto out_put;
470c349dbc7Sjsg
471c349dbc7Sjsg err = igt_check_page_sizes(vma);
472c349dbc7Sjsg
473c349dbc7Sjsg if (vma->page_sizes.sg != combination) {
474c349dbc7Sjsg pr_err("page_sizes.sg=%u, expected=%u\n",
475c349dbc7Sjsg vma->page_sizes.sg, combination);
476c349dbc7Sjsg err = -EINVAL;
477c349dbc7Sjsg }
478c349dbc7Sjsg
479c349dbc7Sjsg i915_vma_unpin(vma);
480c349dbc7Sjsg i915_gem_object_put(obj);
481c349dbc7Sjsg
482c349dbc7Sjsg if (err)
483c349dbc7Sjsg goto out_device;
484c349dbc7Sjsg }
485c349dbc7Sjsg }
486c349dbc7Sjsg
487c349dbc7Sjsg goto out_device;
488c349dbc7Sjsg
489c349dbc7Sjsg out_put:
490c349dbc7Sjsg i915_gem_object_put(obj);
491c349dbc7Sjsg out_device:
4921bb76ff1Sjsg RUNTIME_INFO(i915)->page_sizes = saved_mask;
493c349dbc7Sjsg
494c349dbc7Sjsg return err;
495c349dbc7Sjsg }
496c349dbc7Sjsg
igt_mock_memory_region_huge_pages(void * arg)497c349dbc7Sjsg static int igt_mock_memory_region_huge_pages(void *arg)
498c349dbc7Sjsg {
499c349dbc7Sjsg const unsigned int flags[] = { 0, I915_BO_ALLOC_CONTIGUOUS };
500c349dbc7Sjsg struct i915_ppgtt *ppgtt = arg;
501c349dbc7Sjsg struct drm_i915_private *i915 = ppgtt->vm.i915;
5021bb76ff1Sjsg unsigned long supported = RUNTIME_INFO(i915)->page_sizes;
503c349dbc7Sjsg struct intel_memory_region *mem;
504c349dbc7Sjsg struct drm_i915_gem_object *obj;
505c349dbc7Sjsg struct i915_vma *vma;
506c349dbc7Sjsg int bit;
507c349dbc7Sjsg int err = 0;
508c349dbc7Sjsg
5091bb76ff1Sjsg mem = mock_region_create(i915, 0, SZ_2G, I915_GTT_PAGE_SIZE_4K, 0, 0);
510c349dbc7Sjsg if (IS_ERR(mem)) {
511c349dbc7Sjsg pr_err("%s failed to create memory region\n", __func__);
512c349dbc7Sjsg return PTR_ERR(mem);
513c349dbc7Sjsg }
514c349dbc7Sjsg
515c349dbc7Sjsg for_each_set_bit(bit, &supported, ilog2(I915_GTT_MAX_PAGE_SIZE) + 1) {
516c349dbc7Sjsg unsigned int page_size = BIT(bit);
517c349dbc7Sjsg resource_size_t phys;
518c349dbc7Sjsg int i;
519c349dbc7Sjsg
520c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(flags); ++i) {
5215ca02815Sjsg obj = i915_gem_object_create_region(mem,
5225ca02815Sjsg page_size, page_size,
523c349dbc7Sjsg flags[i]);
524c349dbc7Sjsg if (IS_ERR(obj)) {
525c349dbc7Sjsg err = PTR_ERR(obj);
526c349dbc7Sjsg goto out_region;
527c349dbc7Sjsg }
528c349dbc7Sjsg
529c349dbc7Sjsg vma = i915_vma_instance(obj, &ppgtt->vm, NULL);
530c349dbc7Sjsg if (IS_ERR(vma)) {
531c349dbc7Sjsg err = PTR_ERR(vma);
532c349dbc7Sjsg goto out_put;
533c349dbc7Sjsg }
534c349dbc7Sjsg
535c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, PIN_USER);
536c349dbc7Sjsg if (err)
537ad8b1aafSjsg goto out_put;
538c349dbc7Sjsg
539c349dbc7Sjsg err = igt_check_page_sizes(vma);
540c349dbc7Sjsg if (err)
541c349dbc7Sjsg goto out_unpin;
542c349dbc7Sjsg
543c349dbc7Sjsg phys = i915_gem_object_get_dma_address(obj, 0);
544c349dbc7Sjsg if (!IS_ALIGNED(phys, page_size)) {
545c349dbc7Sjsg pr_err("%s addr misaligned(%pa) page_size=%u\n",
546c349dbc7Sjsg __func__, &phys, page_size);
547c349dbc7Sjsg err = -EINVAL;
548c349dbc7Sjsg goto out_unpin;
549c349dbc7Sjsg }
550c349dbc7Sjsg
5511bb76ff1Sjsg if (vma->resource->page_sizes_gtt != page_size) {
552c349dbc7Sjsg pr_err("%s page_sizes.gtt=%u, expected=%u\n",
5531bb76ff1Sjsg __func__, vma->resource->page_sizes_gtt,
554c349dbc7Sjsg page_size);
555c349dbc7Sjsg err = -EINVAL;
556c349dbc7Sjsg goto out_unpin;
557c349dbc7Sjsg }
558c349dbc7Sjsg
559c349dbc7Sjsg i915_vma_unpin(vma);
560c349dbc7Sjsg __i915_gem_object_put_pages(obj);
561c349dbc7Sjsg i915_gem_object_put(obj);
562c349dbc7Sjsg }
563c349dbc7Sjsg }
564c349dbc7Sjsg
565c349dbc7Sjsg goto out_region;
566c349dbc7Sjsg
567c349dbc7Sjsg out_unpin:
568c349dbc7Sjsg i915_vma_unpin(vma);
569c349dbc7Sjsg out_put:
570c349dbc7Sjsg i915_gem_object_put(obj);
571c349dbc7Sjsg out_region:
5721bb76ff1Sjsg intel_memory_region_destroy(mem);
573c349dbc7Sjsg return err;
574c349dbc7Sjsg }
575c349dbc7Sjsg
igt_mock_ppgtt_misaligned_dma(void * arg)576c349dbc7Sjsg static int igt_mock_ppgtt_misaligned_dma(void *arg)
577c349dbc7Sjsg {
578c349dbc7Sjsg struct i915_ppgtt *ppgtt = arg;
579c349dbc7Sjsg struct drm_i915_private *i915 = ppgtt->vm.i915;
5801bb76ff1Sjsg unsigned long supported = RUNTIME_INFO(i915)->page_sizes;
581c349dbc7Sjsg struct drm_i915_gem_object *obj;
582c349dbc7Sjsg int bit;
583c349dbc7Sjsg int err;
584c349dbc7Sjsg
585c349dbc7Sjsg /*
586c349dbc7Sjsg * Sanity check dma misalignment for huge pages -- the dma addresses we
587c349dbc7Sjsg * insert into the paging structures need to always respect the page
588c349dbc7Sjsg * size alignment.
589c349dbc7Sjsg */
590c349dbc7Sjsg
591c349dbc7Sjsg bit = ilog2(I915_GTT_PAGE_SIZE_64K);
592c349dbc7Sjsg
593c349dbc7Sjsg for_each_set_bit_from(bit, &supported,
594c349dbc7Sjsg ilog2(I915_GTT_MAX_PAGE_SIZE) + 1) {
595c349dbc7Sjsg IGT_TIMEOUT(end_time);
596c349dbc7Sjsg unsigned int page_size = BIT(bit);
597c349dbc7Sjsg unsigned int flags = PIN_USER | PIN_OFFSET_FIXED;
598c349dbc7Sjsg unsigned int offset;
599c349dbc7Sjsg unsigned int size =
600c349dbc7Sjsg round_up(page_size, I915_GTT_PAGE_SIZE_2M) << 1;
601c349dbc7Sjsg struct i915_vma *vma;
602c349dbc7Sjsg
603c349dbc7Sjsg obj = fake_huge_pages_object(i915, size, true);
604c349dbc7Sjsg if (IS_ERR(obj))
605c349dbc7Sjsg return PTR_ERR(obj);
606c349dbc7Sjsg
607c349dbc7Sjsg if (obj->base.size != size) {
608c349dbc7Sjsg pr_err("obj->base.size=%zu, expected=%u\n",
609c349dbc7Sjsg obj->base.size, size);
610c349dbc7Sjsg err = -EINVAL;
611c349dbc7Sjsg goto out_put;
612c349dbc7Sjsg }
613c349dbc7Sjsg
6145ca02815Sjsg err = i915_gem_object_pin_pages_unlocked(obj);
615c349dbc7Sjsg if (err)
616c349dbc7Sjsg goto out_put;
617c349dbc7Sjsg
618c349dbc7Sjsg /* Force the page size for this object */
619c349dbc7Sjsg obj->mm.page_sizes.sg = page_size;
620c349dbc7Sjsg
621c349dbc7Sjsg vma = i915_vma_instance(obj, &ppgtt->vm, NULL);
622c349dbc7Sjsg if (IS_ERR(vma)) {
623c349dbc7Sjsg err = PTR_ERR(vma);
624c349dbc7Sjsg goto out_unpin;
625c349dbc7Sjsg }
626c349dbc7Sjsg
627c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, flags);
628ad8b1aafSjsg if (err)
629c349dbc7Sjsg goto out_unpin;
630c349dbc7Sjsg
631c349dbc7Sjsg
632c349dbc7Sjsg err = igt_check_page_sizes(vma);
633c349dbc7Sjsg
6341bb76ff1Sjsg if (vma->resource->page_sizes_gtt != page_size) {
635c349dbc7Sjsg pr_err("page_sizes.gtt=%u, expected %u\n",
6361bb76ff1Sjsg vma->resource->page_sizes_gtt, page_size);
637c349dbc7Sjsg err = -EINVAL;
638c349dbc7Sjsg }
639c349dbc7Sjsg
640c349dbc7Sjsg i915_vma_unpin(vma);
641c349dbc7Sjsg
642ad8b1aafSjsg if (err)
643c349dbc7Sjsg goto out_unpin;
644c349dbc7Sjsg
645c349dbc7Sjsg /*
646c349dbc7Sjsg * Try all the other valid offsets until the next
647c349dbc7Sjsg * boundary -- should always fall back to using 4K
648c349dbc7Sjsg * pages.
649c349dbc7Sjsg */
650c349dbc7Sjsg for (offset = 4096; offset < page_size; offset += 4096) {
6511bb76ff1Sjsg err = i915_vma_unbind_unlocked(vma);
652ad8b1aafSjsg if (err)
653c349dbc7Sjsg goto out_unpin;
654c349dbc7Sjsg
655c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, flags | offset);
656ad8b1aafSjsg if (err)
657c349dbc7Sjsg goto out_unpin;
658c349dbc7Sjsg
659c349dbc7Sjsg err = igt_check_page_sizes(vma);
660c349dbc7Sjsg
6611bb76ff1Sjsg if (vma->resource->page_sizes_gtt != I915_GTT_PAGE_SIZE_4K) {
662c349dbc7Sjsg pr_err("page_sizes.gtt=%u, expected %llu\n",
6631bb76ff1Sjsg vma->resource->page_sizes_gtt,
6641bb76ff1Sjsg I915_GTT_PAGE_SIZE_4K);
665c349dbc7Sjsg err = -EINVAL;
666c349dbc7Sjsg }
667c349dbc7Sjsg
668c349dbc7Sjsg i915_vma_unpin(vma);
669c349dbc7Sjsg
670ad8b1aafSjsg if (err)
671c349dbc7Sjsg goto out_unpin;
672c349dbc7Sjsg
673c349dbc7Sjsg if (igt_timeout(end_time,
674c349dbc7Sjsg "%s timed out at offset %x with page-size %x\n",
675c349dbc7Sjsg __func__, offset, page_size))
676c349dbc7Sjsg break;
677c349dbc7Sjsg }
678c349dbc7Sjsg
6795ca02815Sjsg i915_gem_object_lock(obj, NULL);
680c349dbc7Sjsg i915_gem_object_unpin_pages(obj);
681c349dbc7Sjsg __i915_gem_object_put_pages(obj);
6825ca02815Sjsg i915_gem_object_unlock(obj);
683c349dbc7Sjsg i915_gem_object_put(obj);
684c349dbc7Sjsg }
685c349dbc7Sjsg
686c349dbc7Sjsg return 0;
687c349dbc7Sjsg
688c349dbc7Sjsg out_unpin:
6895ca02815Sjsg i915_gem_object_lock(obj, NULL);
690c349dbc7Sjsg i915_gem_object_unpin_pages(obj);
6915ca02815Sjsg i915_gem_object_unlock(obj);
692c349dbc7Sjsg out_put:
693c349dbc7Sjsg i915_gem_object_put(obj);
694c349dbc7Sjsg
695c349dbc7Sjsg return err;
696c349dbc7Sjsg }
697c349dbc7Sjsg
close_object_list(struct list_head * objects)698*f005ef32Sjsg static void close_object_list(struct list_head *objects)
699c349dbc7Sjsg {
700c349dbc7Sjsg struct drm_i915_gem_object *obj, *on;
701c349dbc7Sjsg
702c349dbc7Sjsg list_for_each_entry_safe(obj, on, objects, st_link) {
703c349dbc7Sjsg list_del(&obj->st_link);
7045ca02815Sjsg i915_gem_object_lock(obj, NULL);
705c349dbc7Sjsg i915_gem_object_unpin_pages(obj);
706c349dbc7Sjsg __i915_gem_object_put_pages(obj);
7075ca02815Sjsg i915_gem_object_unlock(obj);
708c349dbc7Sjsg i915_gem_object_put(obj);
709c349dbc7Sjsg }
710c349dbc7Sjsg }
711c349dbc7Sjsg
igt_ppgtt_huge_fill(void * arg)712*f005ef32Sjsg static int igt_ppgtt_huge_fill(void *arg)
713c349dbc7Sjsg {
714*f005ef32Sjsg struct drm_i915_private *i915 = arg;
715*f005ef32Sjsg unsigned int supported = RUNTIME_INFO(i915)->page_sizes;
716*f005ef32Sjsg bool has_pte64 = GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50);
717*f005ef32Sjsg struct i915_address_space *vm;
718*f005ef32Sjsg struct i915_gem_context *ctx;
719*f005ef32Sjsg unsigned long max_pages;
720c349dbc7Sjsg unsigned long page_num;
721*f005ef32Sjsg struct file *file;
722c349dbc7Sjsg bool single = false;
723c349dbc7Sjsg DRM_LIST_HEAD(objects);
724c349dbc7Sjsg IGT_TIMEOUT(end_time);
725c349dbc7Sjsg int err = -ENODEV;
726c349dbc7Sjsg
727*f005ef32Sjsg if (supported == I915_GTT_PAGE_SIZE_4K)
728*f005ef32Sjsg return 0;
729*f005ef32Sjsg
730*f005ef32Sjsg file = mock_file(i915);
731*f005ef32Sjsg if (IS_ERR(file))
732*f005ef32Sjsg return PTR_ERR(file);
733*f005ef32Sjsg
734*f005ef32Sjsg ctx = hugepage_ctx(i915, file);
735*f005ef32Sjsg if (IS_ERR(ctx)) {
736*f005ef32Sjsg err = PTR_ERR(ctx);
737*f005ef32Sjsg goto out;
738*f005ef32Sjsg }
739*f005ef32Sjsg vm = i915_gem_context_get_eb_vm(ctx);
740*f005ef32Sjsg max_pages = vm->total >> PAGE_SHIFT;
741*f005ef32Sjsg
742c349dbc7Sjsg for_each_prime_number_from(page_num, 1, max_pages) {
743c349dbc7Sjsg struct drm_i915_gem_object *obj;
744c349dbc7Sjsg u64 size = page_num << PAGE_SHIFT;
745c349dbc7Sjsg struct i915_vma *vma;
746c349dbc7Sjsg unsigned int expected_gtt = 0;
747c349dbc7Sjsg int i;
748c349dbc7Sjsg
749c349dbc7Sjsg obj = fake_huge_pages_object(i915, size, single);
750c349dbc7Sjsg if (IS_ERR(obj)) {
751c349dbc7Sjsg err = PTR_ERR(obj);
752c349dbc7Sjsg break;
753c349dbc7Sjsg }
754c349dbc7Sjsg
755c349dbc7Sjsg if (obj->base.size != size) {
756c349dbc7Sjsg pr_err("obj->base.size=%zd, expected=%llu\n",
757c349dbc7Sjsg obj->base.size, size);
758c349dbc7Sjsg i915_gem_object_put(obj);
759c349dbc7Sjsg err = -EINVAL;
760c349dbc7Sjsg break;
761c349dbc7Sjsg }
762c349dbc7Sjsg
7635ca02815Sjsg err = i915_gem_object_pin_pages_unlocked(obj);
764c349dbc7Sjsg if (err) {
765c349dbc7Sjsg i915_gem_object_put(obj);
766c349dbc7Sjsg break;
767c349dbc7Sjsg }
768c349dbc7Sjsg
769c349dbc7Sjsg list_add(&obj->st_link, &objects);
770c349dbc7Sjsg
771*f005ef32Sjsg vma = i915_vma_instance(obj, vm, NULL);
772c349dbc7Sjsg if (IS_ERR(vma)) {
773c349dbc7Sjsg err = PTR_ERR(vma);
774c349dbc7Sjsg break;
775c349dbc7Sjsg }
776c349dbc7Sjsg
777*f005ef32Sjsg /* vma start must be aligned to BIT(21) to allow 2M PTEs */
778*f005ef32Sjsg err = i915_vma_pin(vma, 0, BIT(21), PIN_USER);
779c349dbc7Sjsg if (err)
780c349dbc7Sjsg break;
781c349dbc7Sjsg
782c349dbc7Sjsg err = igt_check_page_sizes(vma);
783c349dbc7Sjsg if (err) {
784c349dbc7Sjsg i915_vma_unpin(vma);
785c349dbc7Sjsg break;
786c349dbc7Sjsg }
787c349dbc7Sjsg
788c349dbc7Sjsg /*
789c349dbc7Sjsg * Figure out the expected gtt page size knowing that we go from
790c349dbc7Sjsg * largest to smallest page size sg chunks, and that we align to
791c349dbc7Sjsg * the largest page size.
792c349dbc7Sjsg */
793c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(page_sizes); ++i) {
794c349dbc7Sjsg unsigned int page_size = page_sizes[i];
795c349dbc7Sjsg
796c349dbc7Sjsg if (HAS_PAGE_SIZES(i915, page_size) &&
797c349dbc7Sjsg size >= page_size) {
798c349dbc7Sjsg expected_gtt |= page_size;
799c349dbc7Sjsg size &= page_size-1;
800c349dbc7Sjsg }
801c349dbc7Sjsg }
802c349dbc7Sjsg
803c349dbc7Sjsg GEM_BUG_ON(!expected_gtt);
804c349dbc7Sjsg GEM_BUG_ON(size);
805c349dbc7Sjsg
806*f005ef32Sjsg if (!has_pte64 && (obj->base.size < I915_GTT_PAGE_SIZE_2M ||
807*f005ef32Sjsg expected_gtt & I915_GTT_PAGE_SIZE_2M))
808c349dbc7Sjsg expected_gtt &= ~I915_GTT_PAGE_SIZE_64K;
809c349dbc7Sjsg
810c349dbc7Sjsg i915_vma_unpin(vma);
811c349dbc7Sjsg
812*f005ef32Sjsg if (!has_pte64 && vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K) {
813c349dbc7Sjsg if (!IS_ALIGNED(vma->node.start,
814c349dbc7Sjsg I915_GTT_PAGE_SIZE_2M)) {
815c349dbc7Sjsg pr_err("node.start(%llx) not aligned to 2M\n",
816c349dbc7Sjsg vma->node.start);
817c349dbc7Sjsg err = -EINVAL;
818c349dbc7Sjsg break;
819c349dbc7Sjsg }
820c349dbc7Sjsg
821c349dbc7Sjsg if (!IS_ALIGNED(vma->node.size,
822c349dbc7Sjsg I915_GTT_PAGE_SIZE_2M)) {
823c349dbc7Sjsg pr_err("node.size(%llx) not aligned to 2M\n",
824c349dbc7Sjsg vma->node.size);
825c349dbc7Sjsg err = -EINVAL;
826c349dbc7Sjsg break;
827c349dbc7Sjsg }
828c349dbc7Sjsg }
829c349dbc7Sjsg
8301bb76ff1Sjsg if (vma->resource->page_sizes_gtt != expected_gtt) {
831*f005ef32Sjsg pr_err("gtt=%#x, expected=%#x, size=0x%zx, single=%s\n",
8321bb76ff1Sjsg vma->resource->page_sizes_gtt, expected_gtt,
8331bb76ff1Sjsg obj->base.size, str_yes_no(!!single));
834c349dbc7Sjsg err = -EINVAL;
835c349dbc7Sjsg break;
836c349dbc7Sjsg }
837c349dbc7Sjsg
838c349dbc7Sjsg if (igt_timeout(end_time,
839c349dbc7Sjsg "%s timed out at size %zd\n",
840c349dbc7Sjsg __func__, obj->base.size))
841c349dbc7Sjsg break;
842c349dbc7Sjsg
843c349dbc7Sjsg single = !single;
844c349dbc7Sjsg }
845c349dbc7Sjsg
846*f005ef32Sjsg close_object_list(&objects);
847c349dbc7Sjsg
848c349dbc7Sjsg if (err == -ENOMEM || err == -ENOSPC)
849c349dbc7Sjsg err = 0;
850c349dbc7Sjsg
851*f005ef32Sjsg i915_vm_put(vm);
852*f005ef32Sjsg out:
853*f005ef32Sjsg fput(file);
854c349dbc7Sjsg return err;
855c349dbc7Sjsg }
856c349dbc7Sjsg
igt_ppgtt_64K(void * arg)857*f005ef32Sjsg static int igt_ppgtt_64K(void *arg)
858c349dbc7Sjsg {
859*f005ef32Sjsg struct drm_i915_private *i915 = arg;
860*f005ef32Sjsg bool has_pte64 = GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50);
861c349dbc7Sjsg struct drm_i915_gem_object *obj;
862*f005ef32Sjsg struct i915_address_space *vm;
863*f005ef32Sjsg struct i915_gem_context *ctx;
864*f005ef32Sjsg struct file *file;
865c349dbc7Sjsg const struct object_info {
866c349dbc7Sjsg unsigned int size;
867c349dbc7Sjsg unsigned int gtt;
868c349dbc7Sjsg unsigned int offset;
869c349dbc7Sjsg } objects[] = {
870c349dbc7Sjsg /* Cases with forced padding/alignment */
871c349dbc7Sjsg {
872c349dbc7Sjsg .size = SZ_64K,
873c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_64K,
874c349dbc7Sjsg .offset = 0,
875c349dbc7Sjsg },
876c349dbc7Sjsg {
877c349dbc7Sjsg .size = SZ_64K + SZ_4K,
878c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_4K,
879c349dbc7Sjsg .offset = 0,
880c349dbc7Sjsg },
881c349dbc7Sjsg {
882c349dbc7Sjsg .size = SZ_64K - SZ_4K,
883c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_4K,
884c349dbc7Sjsg .offset = 0,
885c349dbc7Sjsg },
886c349dbc7Sjsg {
887c349dbc7Sjsg .size = SZ_2M,
888c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_64K,
889c349dbc7Sjsg .offset = 0,
890c349dbc7Sjsg },
891c349dbc7Sjsg {
892c349dbc7Sjsg .size = SZ_2M - SZ_4K,
893c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_4K,
894c349dbc7Sjsg .offset = 0,
895c349dbc7Sjsg },
896c349dbc7Sjsg {
897c349dbc7Sjsg .size = SZ_2M + SZ_4K,
898c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_64K | I915_GTT_PAGE_SIZE_4K,
899c349dbc7Sjsg .offset = 0,
900c349dbc7Sjsg },
901c349dbc7Sjsg {
902c349dbc7Sjsg .size = SZ_2M + SZ_64K,
903c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_64K,
904c349dbc7Sjsg .offset = 0,
905c349dbc7Sjsg },
906c349dbc7Sjsg {
907c349dbc7Sjsg .size = SZ_2M - SZ_64K,
908c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_64K,
909c349dbc7Sjsg .offset = 0,
910c349dbc7Sjsg },
911c349dbc7Sjsg /* Try without any forced padding/alignment */
912c349dbc7Sjsg {
913c349dbc7Sjsg .size = SZ_64K,
914c349dbc7Sjsg .offset = SZ_2M,
915c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_4K,
916c349dbc7Sjsg },
917c349dbc7Sjsg {
918c349dbc7Sjsg .size = SZ_128K,
919c349dbc7Sjsg .offset = SZ_2M - SZ_64K,
920c349dbc7Sjsg .gtt = I915_GTT_PAGE_SIZE_4K,
921c349dbc7Sjsg },
922c349dbc7Sjsg };
923c349dbc7Sjsg struct i915_vma *vma;
924c349dbc7Sjsg int i, single;
925c349dbc7Sjsg int err;
926c349dbc7Sjsg
927c349dbc7Sjsg /*
928c349dbc7Sjsg * Sanity check some of the trickiness with 64K pages -- either we can
929c349dbc7Sjsg * safely mark the whole page-table(2M block) as 64K, or we have to
930c349dbc7Sjsg * always fallback to 4K.
931c349dbc7Sjsg */
932c349dbc7Sjsg
933c349dbc7Sjsg if (!HAS_PAGE_SIZES(i915, I915_GTT_PAGE_SIZE_64K))
934c349dbc7Sjsg return 0;
935c349dbc7Sjsg
936*f005ef32Sjsg file = mock_file(i915);
937*f005ef32Sjsg if (IS_ERR(file))
938*f005ef32Sjsg return PTR_ERR(file);
939*f005ef32Sjsg
940*f005ef32Sjsg ctx = hugepage_ctx(i915, file);
941*f005ef32Sjsg if (IS_ERR(ctx)) {
942*f005ef32Sjsg err = PTR_ERR(ctx);
943*f005ef32Sjsg goto out;
944*f005ef32Sjsg }
945*f005ef32Sjsg vm = i915_gem_context_get_eb_vm(ctx);
946*f005ef32Sjsg
947c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(objects); ++i) {
948c349dbc7Sjsg unsigned int size = objects[i].size;
949c349dbc7Sjsg unsigned int expected_gtt = objects[i].gtt;
950c349dbc7Sjsg unsigned int offset = objects[i].offset;
951c349dbc7Sjsg unsigned int flags = PIN_USER;
952c349dbc7Sjsg
953*f005ef32Sjsg /*
954*f005ef32Sjsg * For modern GTT models, the requirements for marking a page-table
955*f005ef32Sjsg * as 64K have been relaxed. Account for this.
956*f005ef32Sjsg */
957*f005ef32Sjsg if (has_pte64) {
958*f005ef32Sjsg expected_gtt = 0;
959*f005ef32Sjsg if (size >= SZ_64K)
960*f005ef32Sjsg expected_gtt |= I915_GTT_PAGE_SIZE_64K;
961*f005ef32Sjsg if (size & (SZ_64K - 1))
962*f005ef32Sjsg expected_gtt |= I915_GTT_PAGE_SIZE_4K;
963*f005ef32Sjsg }
964*f005ef32Sjsg
965c349dbc7Sjsg for (single = 0; single <= 1; single++) {
966c349dbc7Sjsg obj = fake_huge_pages_object(i915, size, !!single);
967*f005ef32Sjsg if (IS_ERR(obj)) {
968*f005ef32Sjsg err = PTR_ERR(obj);
969*f005ef32Sjsg goto out_vm;
970*f005ef32Sjsg }
971c349dbc7Sjsg
9725ca02815Sjsg err = i915_gem_object_pin_pages_unlocked(obj);
973c349dbc7Sjsg if (err)
974c349dbc7Sjsg goto out_object_put;
975c349dbc7Sjsg
976c349dbc7Sjsg /*
977c349dbc7Sjsg * Disable 2M pages -- We only want to use 64K/4K pages
978c349dbc7Sjsg * for this test.
979c349dbc7Sjsg */
980c349dbc7Sjsg obj->mm.page_sizes.sg &= ~I915_GTT_PAGE_SIZE_2M;
981c349dbc7Sjsg
982*f005ef32Sjsg vma = i915_vma_instance(obj, vm, NULL);
983c349dbc7Sjsg if (IS_ERR(vma)) {
984c349dbc7Sjsg err = PTR_ERR(vma);
985c349dbc7Sjsg goto out_object_unpin;
986c349dbc7Sjsg }
987c349dbc7Sjsg
988c349dbc7Sjsg if (offset)
989c349dbc7Sjsg flags |= PIN_OFFSET_FIXED | offset;
990c349dbc7Sjsg
991c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, flags);
992c349dbc7Sjsg if (err)
993ad8b1aafSjsg goto out_object_unpin;
994c349dbc7Sjsg
995c349dbc7Sjsg err = igt_check_page_sizes(vma);
996c349dbc7Sjsg if (err)
997c349dbc7Sjsg goto out_vma_unpin;
998c349dbc7Sjsg
999*f005ef32Sjsg if (!has_pte64 && !offset &&
1000*f005ef32Sjsg vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K) {
1001c349dbc7Sjsg if (!IS_ALIGNED(vma->node.start,
1002c349dbc7Sjsg I915_GTT_PAGE_SIZE_2M)) {
1003c349dbc7Sjsg pr_err("node.start(%llx) not aligned to 2M\n",
1004c349dbc7Sjsg vma->node.start);
1005c349dbc7Sjsg err = -EINVAL;
1006c349dbc7Sjsg goto out_vma_unpin;
1007c349dbc7Sjsg }
1008c349dbc7Sjsg
1009c349dbc7Sjsg if (!IS_ALIGNED(vma->node.size,
1010c349dbc7Sjsg I915_GTT_PAGE_SIZE_2M)) {
1011c349dbc7Sjsg pr_err("node.size(%llx) not aligned to 2M\n",
1012c349dbc7Sjsg vma->node.size);
1013c349dbc7Sjsg err = -EINVAL;
1014c349dbc7Sjsg goto out_vma_unpin;
1015c349dbc7Sjsg }
1016c349dbc7Sjsg }
1017c349dbc7Sjsg
10181bb76ff1Sjsg if (vma->resource->page_sizes_gtt != expected_gtt) {
1019*f005ef32Sjsg pr_err("gtt=%#x, expected=%#x, i=%d, single=%s offset=%#x size=%#x\n",
10201bb76ff1Sjsg vma->resource->page_sizes_gtt,
1021*f005ef32Sjsg expected_gtt, i, str_yes_no(!!single),
1022*f005ef32Sjsg offset, size);
1023c349dbc7Sjsg err = -EINVAL;
1024c349dbc7Sjsg goto out_vma_unpin;
1025c349dbc7Sjsg }
1026c349dbc7Sjsg
1027c349dbc7Sjsg i915_vma_unpin(vma);
10285ca02815Sjsg i915_gem_object_lock(obj, NULL);
1029c349dbc7Sjsg i915_gem_object_unpin_pages(obj);
1030c349dbc7Sjsg __i915_gem_object_put_pages(obj);
10315ca02815Sjsg i915_gem_object_unlock(obj);
1032c349dbc7Sjsg i915_gem_object_put(obj);
10331bb76ff1Sjsg
10341bb76ff1Sjsg i915_gem_drain_freed_objects(i915);
1035c349dbc7Sjsg }
1036c349dbc7Sjsg }
1037c349dbc7Sjsg
1038*f005ef32Sjsg goto out_vm;
1039c349dbc7Sjsg
1040c349dbc7Sjsg out_vma_unpin:
1041c349dbc7Sjsg i915_vma_unpin(vma);
1042c349dbc7Sjsg out_object_unpin:
10435ca02815Sjsg i915_gem_object_lock(obj, NULL);
1044c349dbc7Sjsg i915_gem_object_unpin_pages(obj);
10455ca02815Sjsg i915_gem_object_unlock(obj);
1046c349dbc7Sjsg out_object_put:
1047c349dbc7Sjsg i915_gem_object_put(obj);
1048*f005ef32Sjsg out_vm:
1049*f005ef32Sjsg i915_vm_put(vm);
1050*f005ef32Sjsg out:
1051*f005ef32Sjsg fput(file);
1052c349dbc7Sjsg return err;
1053c349dbc7Sjsg }
1054c349dbc7Sjsg
gpu_write(struct intel_context * ce,struct i915_vma * vma,u32 dw,u32 val)1055c349dbc7Sjsg static int gpu_write(struct intel_context *ce,
1056c349dbc7Sjsg struct i915_vma *vma,
1057c349dbc7Sjsg u32 dw,
1058c349dbc7Sjsg u32 val)
1059c349dbc7Sjsg {
1060c349dbc7Sjsg int err;
1061c349dbc7Sjsg
1062ad8b1aafSjsg i915_gem_object_lock(vma->obj, NULL);
1063c349dbc7Sjsg err = i915_gem_object_set_to_gtt_domain(vma->obj, true);
1064c349dbc7Sjsg i915_gem_object_unlock(vma->obj);
1065c349dbc7Sjsg if (err)
1066c349dbc7Sjsg return err;
1067c349dbc7Sjsg
1068c349dbc7Sjsg return igt_gpu_fill_dw(ce, vma, dw * sizeof(u32),
1069c349dbc7Sjsg vma->size >> PAGE_SHIFT, val);
1070c349dbc7Sjsg }
1071c349dbc7Sjsg
1072c349dbc7Sjsg static int
__cpu_check_shmem(struct drm_i915_gem_object * obj,u32 dword,u32 val)1073c349dbc7Sjsg __cpu_check_shmem(struct drm_i915_gem_object *obj, u32 dword, u32 val)
1074c349dbc7Sjsg {
1075c349dbc7Sjsg unsigned int needs_flush;
1076c349dbc7Sjsg unsigned long n;
1077c349dbc7Sjsg int err;
1078c349dbc7Sjsg
1079ad8b1aafSjsg i915_gem_object_lock(obj, NULL);
1080c349dbc7Sjsg err = i915_gem_object_prepare_read(obj, &needs_flush);
1081c349dbc7Sjsg if (err)
1082ad8b1aafSjsg goto err_unlock;
1083c349dbc7Sjsg
1084c349dbc7Sjsg for (n = 0; n < obj->base.size >> PAGE_SHIFT; ++n) {
1085c349dbc7Sjsg u32 *ptr = kmap_atomic(i915_gem_object_get_page(obj, n));
1086c349dbc7Sjsg
1087c349dbc7Sjsg if (needs_flush & CLFLUSH_BEFORE)
1088c349dbc7Sjsg drm_clflush_virt_range(ptr, PAGE_SIZE);
1089c349dbc7Sjsg
1090c349dbc7Sjsg if (ptr[dword] != val) {
1091c349dbc7Sjsg pr_err("n=%lu ptr[%u]=%u, val=%u\n",
1092c349dbc7Sjsg n, dword, ptr[dword], val);
1093c349dbc7Sjsg kunmap_atomic(ptr);
1094c349dbc7Sjsg err = -EINVAL;
1095c349dbc7Sjsg break;
1096c349dbc7Sjsg }
1097c349dbc7Sjsg
1098c349dbc7Sjsg kunmap_atomic(ptr);
1099c349dbc7Sjsg }
1100c349dbc7Sjsg
1101c349dbc7Sjsg i915_gem_object_finish_access(obj);
1102ad8b1aafSjsg err_unlock:
1103ad8b1aafSjsg i915_gem_object_unlock(obj);
1104c349dbc7Sjsg
1105c349dbc7Sjsg return err;
1106c349dbc7Sjsg }
1107c349dbc7Sjsg
__cpu_check_vmap(struct drm_i915_gem_object * obj,u32 dword,u32 val)1108c349dbc7Sjsg static int __cpu_check_vmap(struct drm_i915_gem_object *obj, u32 dword, u32 val)
1109c349dbc7Sjsg {
1110c349dbc7Sjsg unsigned long n = obj->base.size >> PAGE_SHIFT;
1111c349dbc7Sjsg u32 *ptr;
1112c349dbc7Sjsg int err;
1113c349dbc7Sjsg
1114c349dbc7Sjsg err = i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT);
1115c349dbc7Sjsg if (err)
1116c349dbc7Sjsg return err;
1117c349dbc7Sjsg
11185ca02815Sjsg ptr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC);
1119c349dbc7Sjsg if (IS_ERR(ptr))
1120c349dbc7Sjsg return PTR_ERR(ptr);
1121c349dbc7Sjsg
1122c349dbc7Sjsg ptr += dword;
1123c349dbc7Sjsg while (n--) {
1124c349dbc7Sjsg if (*ptr != val) {
1125c349dbc7Sjsg pr_err("base[%u]=%08x, val=%08x\n",
1126c349dbc7Sjsg dword, *ptr, val);
1127c349dbc7Sjsg err = -EINVAL;
1128c349dbc7Sjsg break;
1129c349dbc7Sjsg }
1130c349dbc7Sjsg
1131c349dbc7Sjsg ptr += PAGE_SIZE / sizeof(*ptr);
1132c349dbc7Sjsg }
1133c349dbc7Sjsg
1134c349dbc7Sjsg i915_gem_object_unpin_map(obj);
1135c349dbc7Sjsg return err;
1136c349dbc7Sjsg }
1137c349dbc7Sjsg
cpu_check(struct drm_i915_gem_object * obj,u32 dword,u32 val)1138c349dbc7Sjsg static int cpu_check(struct drm_i915_gem_object *obj, u32 dword, u32 val)
1139c349dbc7Sjsg {
1140c349dbc7Sjsg if (i915_gem_object_has_struct_page(obj))
1141c349dbc7Sjsg return __cpu_check_shmem(obj, dword, val);
1142c349dbc7Sjsg else
1143c349dbc7Sjsg return __cpu_check_vmap(obj, dword, val);
1144c349dbc7Sjsg }
1145c349dbc7Sjsg
__igt_write_huge(struct intel_context * ce,struct drm_i915_gem_object * obj,u64 size,u64 offset,u32 dword,u32 val)1146c349dbc7Sjsg static int __igt_write_huge(struct intel_context *ce,
1147c349dbc7Sjsg struct drm_i915_gem_object *obj,
1148c349dbc7Sjsg u64 size, u64 offset,
1149c349dbc7Sjsg u32 dword, u32 val)
1150c349dbc7Sjsg {
1151c349dbc7Sjsg unsigned int flags = PIN_USER | PIN_OFFSET_FIXED;
1152c349dbc7Sjsg struct i915_vma *vma;
1153c349dbc7Sjsg int err;
1154c349dbc7Sjsg
1155c349dbc7Sjsg vma = i915_vma_instance(obj, ce->vm, NULL);
1156c349dbc7Sjsg if (IS_ERR(vma))
1157c349dbc7Sjsg return PTR_ERR(vma);
1158c349dbc7Sjsg
1159c349dbc7Sjsg err = i915_vma_pin(vma, size, 0, flags | offset);
1160c349dbc7Sjsg if (err) {
1161c349dbc7Sjsg /*
1162c349dbc7Sjsg * The ggtt may have some pages reserved so
1163c349dbc7Sjsg * refrain from erroring out.
1164c349dbc7Sjsg */
1165c349dbc7Sjsg if (err == -ENOSPC && i915_is_ggtt(ce->vm))
1166c349dbc7Sjsg err = 0;
1167c349dbc7Sjsg
1168ad8b1aafSjsg return err;
1169c349dbc7Sjsg }
1170c349dbc7Sjsg
1171c349dbc7Sjsg err = igt_check_page_sizes(vma);
1172c349dbc7Sjsg if (err)
1173c349dbc7Sjsg goto out_vma_unpin;
1174c349dbc7Sjsg
1175c349dbc7Sjsg err = gpu_write(ce, vma, dword, val);
1176c349dbc7Sjsg if (err) {
1177c349dbc7Sjsg pr_err("gpu-write failed at offset=%llx\n", offset);
1178c349dbc7Sjsg goto out_vma_unpin;
1179c349dbc7Sjsg }
1180c349dbc7Sjsg
1181c349dbc7Sjsg err = cpu_check(obj, dword, val);
1182c349dbc7Sjsg if (err) {
1183c349dbc7Sjsg pr_err("cpu-check failed at offset=%llx\n", offset);
1184c349dbc7Sjsg goto out_vma_unpin;
1185c349dbc7Sjsg }
1186c349dbc7Sjsg
1187c349dbc7Sjsg out_vma_unpin:
1188c349dbc7Sjsg i915_vma_unpin(vma);
1189c349dbc7Sjsg return err;
1190c349dbc7Sjsg }
1191c349dbc7Sjsg
igt_write_huge(struct drm_i915_private * i915,struct drm_i915_gem_object * obj)11921bb76ff1Sjsg static int igt_write_huge(struct drm_i915_private *i915,
1193c349dbc7Sjsg struct drm_i915_gem_object *obj)
1194c349dbc7Sjsg {
1195c349dbc7Sjsg struct i915_gem_engines *engines;
1196c349dbc7Sjsg struct i915_gem_engines_iter it;
1197c349dbc7Sjsg struct intel_context *ce;
1198c349dbc7Sjsg I915_RND_STATE(prng);
1199c349dbc7Sjsg IGT_TIMEOUT(end_time);
1200c349dbc7Sjsg unsigned int max_page_size;
1201c349dbc7Sjsg unsigned int count;
12021bb76ff1Sjsg struct i915_gem_context *ctx;
12031bb76ff1Sjsg struct file *file;
1204c349dbc7Sjsg u64 max;
1205c349dbc7Sjsg u64 num;
1206c349dbc7Sjsg u64 size;
1207c349dbc7Sjsg int *order;
1208c349dbc7Sjsg int i, n;
1209c349dbc7Sjsg int err = 0;
1210c349dbc7Sjsg
12111bb76ff1Sjsg file = mock_file(i915);
12121bb76ff1Sjsg if (IS_ERR(file))
12131bb76ff1Sjsg return PTR_ERR(file);
12141bb76ff1Sjsg
12151bb76ff1Sjsg ctx = hugepage_ctx(i915, file);
12161bb76ff1Sjsg if (IS_ERR(ctx)) {
12171bb76ff1Sjsg err = PTR_ERR(ctx);
12181bb76ff1Sjsg goto out;
12191bb76ff1Sjsg }
12201bb76ff1Sjsg
1221c349dbc7Sjsg GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
1222c349dbc7Sjsg
1223c349dbc7Sjsg size = obj->base.size;
1224*f005ef32Sjsg if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
1225*f005ef32Sjsg !HAS_64K_PAGES(i915))
1226c349dbc7Sjsg size = round_up(size, I915_GTT_PAGE_SIZE_2M);
1227c349dbc7Sjsg
1228c349dbc7Sjsg n = 0;
1229c349dbc7Sjsg count = 0;
1230c349dbc7Sjsg max = U64_MAX;
1231c349dbc7Sjsg for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
1232c349dbc7Sjsg count++;
1233c349dbc7Sjsg if (!intel_engine_can_store_dword(ce->engine))
1234c349dbc7Sjsg continue;
1235c349dbc7Sjsg
1236c349dbc7Sjsg max = min(max, ce->vm->total);
1237c349dbc7Sjsg n++;
1238c349dbc7Sjsg }
1239c349dbc7Sjsg i915_gem_context_unlock_engines(ctx);
1240c349dbc7Sjsg if (!n)
12411bb76ff1Sjsg goto out;
1242c349dbc7Sjsg
1243c349dbc7Sjsg /*
1244c349dbc7Sjsg * To keep things interesting when alternating between engines in our
1245c349dbc7Sjsg * randomized order, lets also make feeding to the same engine a few
1246c349dbc7Sjsg * times in succession a possibility by enlarging the permutation array.
1247c349dbc7Sjsg */
1248c349dbc7Sjsg order = i915_random_order(count * count, &prng);
1249f2191f77Sjsg if (!order) {
1250f2191f77Sjsg err = -ENOMEM;
1251f2191f77Sjsg goto out;
1252f2191f77Sjsg }
1253c349dbc7Sjsg
1254c349dbc7Sjsg max_page_size = rounddown_pow_of_two(obj->mm.page_sizes.sg);
1255c349dbc7Sjsg max = div_u64(max - size, max_page_size);
1256c349dbc7Sjsg
1257c349dbc7Sjsg /*
1258c349dbc7Sjsg * Try various offsets in an ascending/descending fashion until we
1259c349dbc7Sjsg * timeout -- we want to avoid issues hidden by effectively always using
1260c349dbc7Sjsg * offset = 0.
1261c349dbc7Sjsg */
1262c349dbc7Sjsg i = 0;
1263c349dbc7Sjsg engines = i915_gem_context_lock_engines(ctx);
1264c349dbc7Sjsg for_each_prime_number_from(num, 0, max) {
1265c349dbc7Sjsg u64 offset_low = num * max_page_size;
1266c349dbc7Sjsg u64 offset_high = (max - num) * max_page_size;
1267c349dbc7Sjsg u32 dword = offset_in_page(num) / 4;
1268c349dbc7Sjsg struct intel_context *ce;
1269c349dbc7Sjsg
1270c349dbc7Sjsg ce = engines->engines[order[i] % engines->num_engines];
1271c349dbc7Sjsg i = (i + 1) % (count * count);
1272c349dbc7Sjsg if (!ce || !intel_engine_can_store_dword(ce->engine))
1273c349dbc7Sjsg continue;
1274c349dbc7Sjsg
1275c349dbc7Sjsg /*
1276c349dbc7Sjsg * In order to utilize 64K pages we need to both pad the vma
1277c349dbc7Sjsg * size and ensure the vma offset is at the start of the pt
1278c349dbc7Sjsg * boundary, however to improve coverage we opt for testing both
1279c349dbc7Sjsg * aligned and unaligned offsets.
1280*f005ef32Sjsg *
1281*f005ef32Sjsg * With PS64 this is no longer the case, but to ensure we
1282*f005ef32Sjsg * sometimes get the compact layout for smaller objects, apply
1283*f005ef32Sjsg * the round_up anyway.
1284c349dbc7Sjsg */
1285c349dbc7Sjsg if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K)
1286c349dbc7Sjsg offset_low = round_down(offset_low,
1287c349dbc7Sjsg I915_GTT_PAGE_SIZE_2M);
1288c349dbc7Sjsg
1289c349dbc7Sjsg err = __igt_write_huge(ce, obj, size, offset_low,
1290c349dbc7Sjsg dword, num + 1);
1291c349dbc7Sjsg if (err)
1292c349dbc7Sjsg break;
1293c349dbc7Sjsg
1294c349dbc7Sjsg err = __igt_write_huge(ce, obj, size, offset_high,
1295c349dbc7Sjsg dword, num + 1);
1296c349dbc7Sjsg if (err)
1297c349dbc7Sjsg break;
1298c349dbc7Sjsg
1299c349dbc7Sjsg if (igt_timeout(end_time,
1300c349dbc7Sjsg "%s timed out on %s, offset_low=%llx offset_high=%llx, max_page_size=%x\n",
1301c349dbc7Sjsg __func__, ce->engine->name, offset_low, offset_high,
1302c349dbc7Sjsg max_page_size))
1303c349dbc7Sjsg break;
1304c349dbc7Sjsg }
1305c349dbc7Sjsg i915_gem_context_unlock_engines(ctx);
1306c349dbc7Sjsg
1307c349dbc7Sjsg kfree(order);
1308c349dbc7Sjsg
13091bb76ff1Sjsg out:
13101bb76ff1Sjsg fput(file);
1311c349dbc7Sjsg return err;
1312c349dbc7Sjsg }
1313c349dbc7Sjsg
1314c349dbc7Sjsg typedef struct drm_i915_gem_object *
1315c349dbc7Sjsg (*igt_create_fn)(struct drm_i915_private *i915, u32 size, u32 flags);
1316c349dbc7Sjsg
igt_can_allocate_thp(struct drm_i915_private * i915)1317c349dbc7Sjsg static inline bool igt_can_allocate_thp(struct drm_i915_private *i915)
1318c349dbc7Sjsg {
1319c349dbc7Sjsg return i915->mm.gemfs && has_transparent_hugepage();
1320c349dbc7Sjsg }
1321c349dbc7Sjsg
1322c349dbc7Sjsg static struct drm_i915_gem_object *
igt_create_shmem(struct drm_i915_private * i915,u32 size,u32 flags)1323c349dbc7Sjsg igt_create_shmem(struct drm_i915_private *i915, u32 size, u32 flags)
1324c349dbc7Sjsg {
1325c349dbc7Sjsg if (!igt_can_allocate_thp(i915)) {
1326c349dbc7Sjsg pr_info("%s missing THP support, skipping\n", __func__);
1327c349dbc7Sjsg return ERR_PTR(-ENODEV);
1328c349dbc7Sjsg }
1329c349dbc7Sjsg
1330c349dbc7Sjsg return i915_gem_object_create_shmem(i915, size);
1331c349dbc7Sjsg }
1332c349dbc7Sjsg
1333c349dbc7Sjsg static struct drm_i915_gem_object *
igt_create_internal(struct drm_i915_private * i915,u32 size,u32 flags)1334c349dbc7Sjsg igt_create_internal(struct drm_i915_private *i915, u32 size, u32 flags)
1335c349dbc7Sjsg {
1336c349dbc7Sjsg return i915_gem_object_create_internal(i915, size);
1337c349dbc7Sjsg }
1338c349dbc7Sjsg
1339c349dbc7Sjsg static struct drm_i915_gem_object *
igt_create_system(struct drm_i915_private * i915,u32 size,u32 flags)1340c349dbc7Sjsg igt_create_system(struct drm_i915_private *i915, u32 size, u32 flags)
1341c349dbc7Sjsg {
1342c349dbc7Sjsg return huge_pages_object(i915, size, size);
1343c349dbc7Sjsg }
1344c349dbc7Sjsg
1345c349dbc7Sjsg static struct drm_i915_gem_object *
igt_create_local(struct drm_i915_private * i915,u32 size,u32 flags)1346c349dbc7Sjsg igt_create_local(struct drm_i915_private *i915, u32 size, u32 flags)
1347c349dbc7Sjsg {
1348c349dbc7Sjsg return i915_gem_object_create_lmem(i915, size, flags);
1349c349dbc7Sjsg }
1350c349dbc7Sjsg
igt_random_size(struct rnd_state * prng,u32 min_page_size,u32 max_page_size)1351c349dbc7Sjsg static u32 igt_random_size(struct rnd_state *prng,
1352c349dbc7Sjsg u32 min_page_size,
1353c349dbc7Sjsg u32 max_page_size)
1354c349dbc7Sjsg {
1355c349dbc7Sjsg u64 mask;
1356c349dbc7Sjsg u32 size;
1357c349dbc7Sjsg
1358c349dbc7Sjsg GEM_BUG_ON(!is_power_of_2(min_page_size));
1359c349dbc7Sjsg GEM_BUG_ON(!is_power_of_2(max_page_size));
1360c349dbc7Sjsg GEM_BUG_ON(min_page_size < PAGE_SIZE);
1361c349dbc7Sjsg GEM_BUG_ON(min_page_size > max_page_size);
1362c349dbc7Sjsg
1363ad8b1aafSjsg mask = ((max_page_size << 1ULL) - 1) & LINUX_PAGE_MASK;
1364c349dbc7Sjsg size = prandom_u32_state(prng) & mask;
1365c349dbc7Sjsg if (size < min_page_size)
1366c349dbc7Sjsg size |= min_page_size;
1367c349dbc7Sjsg
1368c349dbc7Sjsg return size;
1369c349dbc7Sjsg }
1370c349dbc7Sjsg
igt_ppgtt_smoke_huge(void * arg)1371c349dbc7Sjsg static int igt_ppgtt_smoke_huge(void *arg)
1372c349dbc7Sjsg {
13731bb76ff1Sjsg struct drm_i915_private *i915 = arg;
1374c349dbc7Sjsg struct drm_i915_gem_object *obj;
1375c349dbc7Sjsg I915_RND_STATE(prng);
1376c349dbc7Sjsg struct {
1377c349dbc7Sjsg igt_create_fn fn;
1378c349dbc7Sjsg u32 min;
1379c349dbc7Sjsg u32 max;
1380c349dbc7Sjsg } backends[] = {
1381c349dbc7Sjsg { igt_create_internal, SZ_64K, SZ_2M, },
1382c349dbc7Sjsg { igt_create_shmem, SZ_64K, SZ_32M, },
1383c349dbc7Sjsg { igt_create_local, SZ_64K, SZ_1G, },
1384c349dbc7Sjsg };
1385c349dbc7Sjsg int err;
1386c349dbc7Sjsg int i;
1387c349dbc7Sjsg
1388c349dbc7Sjsg /*
1389c349dbc7Sjsg * Sanity check that the HW uses huge pages correctly through our
1390c349dbc7Sjsg * various backends -- ensure that our writes land in the right place.
1391c349dbc7Sjsg */
1392c349dbc7Sjsg
1393c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(backends); ++i) {
1394c349dbc7Sjsg u32 min = backends[i].min;
1395c349dbc7Sjsg u32 max = backends[i].max;
1396c349dbc7Sjsg u32 size = max;
13971bb76ff1Sjsg
1398c349dbc7Sjsg try_again:
1399c349dbc7Sjsg size = igt_random_size(&prng, min, rounddown_pow_of_two(size));
1400c349dbc7Sjsg
1401c349dbc7Sjsg obj = backends[i].fn(i915, size, 0);
1402c349dbc7Sjsg if (IS_ERR(obj)) {
1403c349dbc7Sjsg err = PTR_ERR(obj);
1404c349dbc7Sjsg if (err == -E2BIG) {
1405c349dbc7Sjsg size >>= 1;
1406c349dbc7Sjsg goto try_again;
1407c349dbc7Sjsg } else if (err == -ENODEV) {
1408c349dbc7Sjsg err = 0;
1409c349dbc7Sjsg continue;
1410c349dbc7Sjsg }
1411c349dbc7Sjsg
1412c349dbc7Sjsg return err;
1413c349dbc7Sjsg }
1414c349dbc7Sjsg
14155ca02815Sjsg err = i915_gem_object_pin_pages_unlocked(obj);
1416c349dbc7Sjsg if (err) {
14171bb76ff1Sjsg if (err == -ENXIO || err == -E2BIG || err == -ENOMEM) {
1418c349dbc7Sjsg i915_gem_object_put(obj);
1419c349dbc7Sjsg size >>= 1;
1420c349dbc7Sjsg goto try_again;
1421c349dbc7Sjsg }
1422c349dbc7Sjsg goto out_put;
1423c349dbc7Sjsg }
1424c349dbc7Sjsg
1425c349dbc7Sjsg if (obj->mm.page_sizes.phys < min) {
1426c349dbc7Sjsg pr_info("%s unable to allocate huge-page(s) with size=%u, i=%d\n",
1427c349dbc7Sjsg __func__, size, i);
1428c349dbc7Sjsg err = -ENOMEM;
1429c349dbc7Sjsg goto out_unpin;
1430c349dbc7Sjsg }
1431c349dbc7Sjsg
14321bb76ff1Sjsg err = igt_write_huge(i915, obj);
1433c349dbc7Sjsg if (err) {
1434c349dbc7Sjsg pr_err("%s write-huge failed with size=%u, i=%d\n",
1435c349dbc7Sjsg __func__, size, i);
1436c349dbc7Sjsg }
1437c349dbc7Sjsg out_unpin:
14385ca02815Sjsg i915_gem_object_lock(obj, NULL);
1439c349dbc7Sjsg i915_gem_object_unpin_pages(obj);
1440c349dbc7Sjsg __i915_gem_object_put_pages(obj);
14415ca02815Sjsg i915_gem_object_unlock(obj);
1442c349dbc7Sjsg out_put:
1443c349dbc7Sjsg i915_gem_object_put(obj);
1444c349dbc7Sjsg
1445c349dbc7Sjsg if (err == -ENOMEM || err == -ENXIO)
1446c349dbc7Sjsg err = 0;
1447c349dbc7Sjsg
1448c349dbc7Sjsg if (err)
1449c349dbc7Sjsg break;
1450c349dbc7Sjsg
1451c349dbc7Sjsg cond_resched();
1452c349dbc7Sjsg }
1453c349dbc7Sjsg
1454c349dbc7Sjsg return err;
1455c349dbc7Sjsg }
1456c349dbc7Sjsg
igt_ppgtt_sanity_check(void * arg)1457c349dbc7Sjsg static int igt_ppgtt_sanity_check(void *arg)
1458c349dbc7Sjsg {
14591bb76ff1Sjsg struct drm_i915_private *i915 = arg;
14601bb76ff1Sjsg unsigned int supported = RUNTIME_INFO(i915)->page_sizes;
1461c349dbc7Sjsg struct {
1462c349dbc7Sjsg igt_create_fn fn;
1463c349dbc7Sjsg unsigned int flags;
1464c349dbc7Sjsg } backends[] = {
1465c349dbc7Sjsg { igt_create_system, 0, },
14665ca02815Sjsg { igt_create_local, 0, },
1467c349dbc7Sjsg { igt_create_local, I915_BO_ALLOC_CONTIGUOUS, },
1468c349dbc7Sjsg };
1469c349dbc7Sjsg struct {
1470c349dbc7Sjsg u32 size;
1471c349dbc7Sjsg u32 pages;
1472c349dbc7Sjsg } combos[] = {
1473c349dbc7Sjsg { SZ_64K, SZ_64K },
1474c349dbc7Sjsg { SZ_2M, SZ_2M },
1475c349dbc7Sjsg { SZ_2M, SZ_64K },
1476c349dbc7Sjsg { SZ_2M - SZ_64K, SZ_64K },
1477c349dbc7Sjsg { SZ_2M - SZ_4K, SZ_64K | SZ_4K },
1478c349dbc7Sjsg { SZ_2M + SZ_4K, SZ_64K | SZ_4K },
1479c349dbc7Sjsg { SZ_2M + SZ_4K, SZ_2M | SZ_4K },
1480c349dbc7Sjsg { SZ_2M + SZ_64K, SZ_2M | SZ_64K },
1481*f005ef32Sjsg { SZ_2M + SZ_64K, SZ_64K },
1482c349dbc7Sjsg };
1483c349dbc7Sjsg int i, j;
1484c349dbc7Sjsg int err;
1485c349dbc7Sjsg
1486c349dbc7Sjsg if (supported == I915_GTT_PAGE_SIZE_4K)
1487c349dbc7Sjsg return 0;
1488c349dbc7Sjsg
1489c349dbc7Sjsg /*
1490c349dbc7Sjsg * Sanity check that the HW behaves with a limited set of combinations.
1491c349dbc7Sjsg * We already have a bunch of randomised testing, which should give us
1492c349dbc7Sjsg * a decent amount of variation between runs, however we should keep
1493c349dbc7Sjsg * this to limit the chances of introducing a temporary regression, by
1494c349dbc7Sjsg * testing the most obvious cases that might make something blow up.
1495c349dbc7Sjsg */
1496c349dbc7Sjsg
1497c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(backends); ++i) {
1498c349dbc7Sjsg for (j = 0; j < ARRAY_SIZE(combos); ++j) {
1499c349dbc7Sjsg struct drm_i915_gem_object *obj;
1500c349dbc7Sjsg u32 size = combos[j].size;
1501c349dbc7Sjsg u32 pages = combos[j].pages;
1502c349dbc7Sjsg
1503c349dbc7Sjsg obj = backends[i].fn(i915, size, backends[i].flags);
1504c349dbc7Sjsg if (IS_ERR(obj)) {
1505c349dbc7Sjsg err = PTR_ERR(obj);
1506c349dbc7Sjsg if (err == -ENODEV) {
1507c349dbc7Sjsg pr_info("Device lacks local memory, skipping\n");
1508c349dbc7Sjsg err = 0;
1509c349dbc7Sjsg break;
1510c349dbc7Sjsg }
1511c349dbc7Sjsg
1512c349dbc7Sjsg return err;
1513c349dbc7Sjsg }
1514c349dbc7Sjsg
15155ca02815Sjsg err = i915_gem_object_pin_pages_unlocked(obj);
1516c349dbc7Sjsg if (err) {
1517c349dbc7Sjsg i915_gem_object_put(obj);
1518c349dbc7Sjsg goto out;
1519c349dbc7Sjsg }
1520c349dbc7Sjsg
1521c349dbc7Sjsg GEM_BUG_ON(pages > obj->base.size);
1522c349dbc7Sjsg pages = pages & supported;
1523c349dbc7Sjsg
1524c349dbc7Sjsg if (pages)
1525c349dbc7Sjsg obj->mm.page_sizes.sg = pages;
1526c349dbc7Sjsg
15271bb76ff1Sjsg err = igt_write_huge(i915, obj);
1528c349dbc7Sjsg
15295ca02815Sjsg i915_gem_object_lock(obj, NULL);
1530c349dbc7Sjsg i915_gem_object_unpin_pages(obj);
1531c349dbc7Sjsg __i915_gem_object_put_pages(obj);
15325ca02815Sjsg i915_gem_object_unlock(obj);
1533c349dbc7Sjsg i915_gem_object_put(obj);
1534c349dbc7Sjsg
1535c349dbc7Sjsg if (err) {
1536c349dbc7Sjsg pr_err("%s write-huge failed with size=%u pages=%u i=%d, j=%d\n",
1537c349dbc7Sjsg __func__, size, pages, i, j);
1538c349dbc7Sjsg goto out;
1539c349dbc7Sjsg }
1540c349dbc7Sjsg }
1541c349dbc7Sjsg
1542c349dbc7Sjsg cond_resched();
1543c349dbc7Sjsg }
1544c349dbc7Sjsg
1545c349dbc7Sjsg out:
1546c349dbc7Sjsg if (err == -ENOMEM)
1547c349dbc7Sjsg err = 0;
1548c349dbc7Sjsg
1549c349dbc7Sjsg return err;
1550c349dbc7Sjsg }
1551c349dbc7Sjsg
igt_ppgtt_compact(void * arg)15521bb76ff1Sjsg static int igt_ppgtt_compact(void *arg)
15531bb76ff1Sjsg {
15541bb76ff1Sjsg struct drm_i915_private *i915 = arg;
15551bb76ff1Sjsg struct drm_i915_gem_object *obj;
15561bb76ff1Sjsg int err;
15571bb76ff1Sjsg
15581bb76ff1Sjsg /*
15591bb76ff1Sjsg * Simple test to catch issues with compact 64K pages -- since the pt is
15601bb76ff1Sjsg * compacted to 256B that gives us 32 entries per pt, however since the
15611bb76ff1Sjsg * backing page for the pt is 4K, any extra entries we might incorrectly
15621bb76ff1Sjsg * write out should be ignored by the HW. If ever hit such a case this
15631bb76ff1Sjsg * test should catch it since some of our writes would land in scratch.
15641bb76ff1Sjsg */
15651bb76ff1Sjsg
15661bb76ff1Sjsg if (!HAS_64K_PAGES(i915)) {
15671bb76ff1Sjsg pr_info("device lacks compact 64K page support, skipping\n");
15681bb76ff1Sjsg return 0;
15691bb76ff1Sjsg }
15701bb76ff1Sjsg
15711bb76ff1Sjsg if (!HAS_LMEM(i915)) {
15721bb76ff1Sjsg pr_info("device lacks LMEM support, skipping\n");
15731bb76ff1Sjsg return 0;
15741bb76ff1Sjsg }
15751bb76ff1Sjsg
15761bb76ff1Sjsg /* We want the range to cover multiple page-table boundaries. */
15771bb76ff1Sjsg obj = i915_gem_object_create_lmem(i915, SZ_4M, 0);
15781bb76ff1Sjsg if (IS_ERR(obj))
15791bb76ff1Sjsg return PTR_ERR(obj);
15801bb76ff1Sjsg
15811bb76ff1Sjsg err = i915_gem_object_pin_pages_unlocked(obj);
15821bb76ff1Sjsg if (err)
15831bb76ff1Sjsg goto out_put;
15841bb76ff1Sjsg
15851bb76ff1Sjsg if (obj->mm.page_sizes.phys < I915_GTT_PAGE_SIZE_64K) {
15861bb76ff1Sjsg pr_info("LMEM compact unable to allocate huge-page(s)\n");
15871bb76ff1Sjsg goto out_unpin;
15881bb76ff1Sjsg }
15891bb76ff1Sjsg
15901bb76ff1Sjsg /*
15911bb76ff1Sjsg * Disable 2M GTT pages by forcing the page-size to 64K for the GTT
15921bb76ff1Sjsg * insertion.
15931bb76ff1Sjsg */
15941bb76ff1Sjsg obj->mm.page_sizes.sg = I915_GTT_PAGE_SIZE_64K;
15951bb76ff1Sjsg
15961bb76ff1Sjsg err = igt_write_huge(i915, obj);
15971bb76ff1Sjsg if (err)
15981bb76ff1Sjsg pr_err("LMEM compact write-huge failed\n");
15991bb76ff1Sjsg
16001bb76ff1Sjsg out_unpin:
16011bb76ff1Sjsg i915_gem_object_unpin_pages(obj);
16021bb76ff1Sjsg out_put:
16031bb76ff1Sjsg i915_gem_object_put(obj);
16041bb76ff1Sjsg
16051bb76ff1Sjsg if (err == -ENOMEM)
16061bb76ff1Sjsg err = 0;
16071bb76ff1Sjsg
16081bb76ff1Sjsg return err;
16091bb76ff1Sjsg }
16101bb76ff1Sjsg
igt_ppgtt_mixed(void * arg)1611*f005ef32Sjsg static int igt_ppgtt_mixed(void *arg)
1612*f005ef32Sjsg {
1613*f005ef32Sjsg struct drm_i915_private *i915 = arg;
1614*f005ef32Sjsg const unsigned long flags = PIN_OFFSET_FIXED | PIN_USER;
1615*f005ef32Sjsg struct drm_i915_gem_object *obj, *on;
1616*f005ef32Sjsg struct i915_gem_engines *engines;
1617*f005ef32Sjsg struct i915_gem_engines_iter it;
1618*f005ef32Sjsg struct i915_address_space *vm;
1619*f005ef32Sjsg struct i915_gem_context *ctx;
1620*f005ef32Sjsg struct intel_context *ce;
1621*f005ef32Sjsg struct file *file;
1622*f005ef32Sjsg I915_RND_STATE(prng);
1623*f005ef32Sjsg LIST_HEAD(objects);
1624*f005ef32Sjsg struct intel_memory_region *mr;
1625*f005ef32Sjsg struct i915_vma *vma;
1626*f005ef32Sjsg unsigned int count;
1627*f005ef32Sjsg u32 i, addr;
1628*f005ef32Sjsg int *order;
1629*f005ef32Sjsg int n, err;
1630*f005ef32Sjsg
1631*f005ef32Sjsg /*
1632*f005ef32Sjsg * Sanity check mixing 4K and 64K pages within the same page-table via
1633*f005ef32Sjsg * the new PS64 TLB hint.
1634*f005ef32Sjsg */
1635*f005ef32Sjsg
1636*f005ef32Sjsg if (!HAS_64K_PAGES(i915)) {
1637*f005ef32Sjsg pr_info("device lacks PS64, skipping\n");
1638*f005ef32Sjsg return 0;
1639*f005ef32Sjsg }
1640*f005ef32Sjsg
1641*f005ef32Sjsg file = mock_file(i915);
1642*f005ef32Sjsg if (IS_ERR(file))
1643*f005ef32Sjsg return PTR_ERR(file);
1644*f005ef32Sjsg
1645*f005ef32Sjsg ctx = hugepage_ctx(i915, file);
1646*f005ef32Sjsg if (IS_ERR(ctx)) {
1647*f005ef32Sjsg err = PTR_ERR(ctx);
1648*f005ef32Sjsg goto out;
1649*f005ef32Sjsg }
1650*f005ef32Sjsg vm = i915_gem_context_get_eb_vm(ctx);
1651*f005ef32Sjsg
1652*f005ef32Sjsg i = 0;
1653*f005ef32Sjsg addr = 0;
1654*f005ef32Sjsg do {
1655*f005ef32Sjsg u32 sz;
1656*f005ef32Sjsg
1657*f005ef32Sjsg sz = i915_prandom_u32_max_state(SZ_4M, &prng);
1658*f005ef32Sjsg sz = max_t(u32, sz, SZ_4K);
1659*f005ef32Sjsg
1660*f005ef32Sjsg mr = i915->mm.regions[INTEL_REGION_LMEM_0];
1661*f005ef32Sjsg if (i & 1)
1662*f005ef32Sjsg mr = i915->mm.regions[INTEL_REGION_SMEM];
1663*f005ef32Sjsg
1664*f005ef32Sjsg obj = i915_gem_object_create_region(mr, sz, 0, 0);
1665*f005ef32Sjsg if (IS_ERR(obj)) {
1666*f005ef32Sjsg err = PTR_ERR(obj);
1667*f005ef32Sjsg goto out_vm;
1668*f005ef32Sjsg }
1669*f005ef32Sjsg
1670*f005ef32Sjsg list_add_tail(&obj->st_link, &objects);
1671*f005ef32Sjsg
1672*f005ef32Sjsg vma = i915_vma_instance(obj, vm, NULL);
1673*f005ef32Sjsg if (IS_ERR(vma)) {
1674*f005ef32Sjsg err = PTR_ERR(vma);
1675*f005ef32Sjsg goto err_put;
1676*f005ef32Sjsg }
1677*f005ef32Sjsg
1678*f005ef32Sjsg addr = round_up(addr, mr->min_page_size);
1679*f005ef32Sjsg err = i915_vma_pin(vma, 0, 0, addr | flags);
1680*f005ef32Sjsg if (err)
1681*f005ef32Sjsg goto err_put;
1682*f005ef32Sjsg
1683*f005ef32Sjsg if (mr->type == INTEL_MEMORY_LOCAL &&
1684*f005ef32Sjsg (vma->resource->page_sizes_gtt & I915_GTT_PAGE_SIZE_4K)) {
1685*f005ef32Sjsg err = -EINVAL;
1686*f005ef32Sjsg goto err_put;
1687*f005ef32Sjsg }
1688*f005ef32Sjsg
1689*f005ef32Sjsg addr += obj->base.size;
1690*f005ef32Sjsg i++;
1691*f005ef32Sjsg } while (addr <= SZ_16M);
1692*f005ef32Sjsg
1693*f005ef32Sjsg n = 0;
1694*f005ef32Sjsg count = 0;
1695*f005ef32Sjsg for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
1696*f005ef32Sjsg count++;
1697*f005ef32Sjsg if (!intel_engine_can_store_dword(ce->engine))
1698*f005ef32Sjsg continue;
1699*f005ef32Sjsg
1700*f005ef32Sjsg n++;
1701*f005ef32Sjsg }
1702*f005ef32Sjsg i915_gem_context_unlock_engines(ctx);
1703*f005ef32Sjsg if (!n)
1704*f005ef32Sjsg goto err_put;
1705*f005ef32Sjsg
1706*f005ef32Sjsg order = i915_random_order(count * count, &prng);
1707*f005ef32Sjsg if (!order) {
1708*f005ef32Sjsg err = -ENOMEM;
1709*f005ef32Sjsg goto err_put;
1710*f005ef32Sjsg }
1711*f005ef32Sjsg
1712*f005ef32Sjsg i = 0;
1713*f005ef32Sjsg addr = 0;
1714*f005ef32Sjsg engines = i915_gem_context_lock_engines(ctx);
1715*f005ef32Sjsg list_for_each_entry(obj, &objects, st_link) {
1716*f005ef32Sjsg u32 rnd = i915_prandom_u32_max_state(UINT_MAX, &prng);
1717*f005ef32Sjsg
1718*f005ef32Sjsg addr = round_up(addr, obj->mm.region->min_page_size);
1719*f005ef32Sjsg
1720*f005ef32Sjsg ce = engines->engines[order[i] % engines->num_engines];
1721*f005ef32Sjsg i = (i + 1) % (count * count);
1722*f005ef32Sjsg if (!ce || !intel_engine_can_store_dword(ce->engine))
1723*f005ef32Sjsg continue;
1724*f005ef32Sjsg
1725*f005ef32Sjsg err = __igt_write_huge(ce, obj, obj->base.size, addr, 0, rnd);
1726*f005ef32Sjsg if (err)
1727*f005ef32Sjsg break;
1728*f005ef32Sjsg
1729*f005ef32Sjsg err = __igt_write_huge(ce, obj, obj->base.size, addr,
1730*f005ef32Sjsg offset_in_page(rnd) / sizeof(u32), rnd + 1);
1731*f005ef32Sjsg if (err)
1732*f005ef32Sjsg break;
1733*f005ef32Sjsg
1734*f005ef32Sjsg err = __igt_write_huge(ce, obj, obj->base.size, addr,
1735*f005ef32Sjsg (PAGE_SIZE / sizeof(u32)) - 1,
1736*f005ef32Sjsg rnd + 2);
1737*f005ef32Sjsg if (err)
1738*f005ef32Sjsg break;
1739*f005ef32Sjsg
1740*f005ef32Sjsg addr += obj->base.size;
1741*f005ef32Sjsg
1742*f005ef32Sjsg cond_resched();
1743*f005ef32Sjsg }
1744*f005ef32Sjsg
1745*f005ef32Sjsg i915_gem_context_unlock_engines(ctx);
1746*f005ef32Sjsg kfree(order);
1747*f005ef32Sjsg err_put:
1748*f005ef32Sjsg list_for_each_entry_safe(obj, on, &objects, st_link) {
1749*f005ef32Sjsg list_del(&obj->st_link);
1750*f005ef32Sjsg i915_gem_object_put(obj);
1751*f005ef32Sjsg }
1752*f005ef32Sjsg out_vm:
1753*f005ef32Sjsg i915_vm_put(vm);
1754*f005ef32Sjsg out:
1755*f005ef32Sjsg fput(file);
1756*f005ef32Sjsg return err;
1757*f005ef32Sjsg }
1758*f005ef32Sjsg
igt_tmpfs_fallback(void * arg)1759c349dbc7Sjsg static int igt_tmpfs_fallback(void *arg)
1760c349dbc7Sjsg {
17611bb76ff1Sjsg struct drm_i915_private *i915 = arg;
17621bb76ff1Sjsg struct i915_address_space *vm;
17631bb76ff1Sjsg struct i915_gem_context *ctx;
1764c349dbc7Sjsg struct vfsmount *gemfs = i915->mm.gemfs;
1765c349dbc7Sjsg struct drm_i915_gem_object *obj;
1766c349dbc7Sjsg struct i915_vma *vma;
17671bb76ff1Sjsg struct file *file;
1768c349dbc7Sjsg u32 *vaddr;
1769c349dbc7Sjsg int err = 0;
1770c349dbc7Sjsg
17711bb76ff1Sjsg file = mock_file(i915);
17721bb76ff1Sjsg if (IS_ERR(file))
17731bb76ff1Sjsg return PTR_ERR(file);
17741bb76ff1Sjsg
17751bb76ff1Sjsg ctx = hugepage_ctx(i915, file);
17761bb76ff1Sjsg if (IS_ERR(ctx)) {
17771bb76ff1Sjsg err = PTR_ERR(ctx);
17781bb76ff1Sjsg goto out;
17791bb76ff1Sjsg }
17801bb76ff1Sjsg vm = i915_gem_context_get_eb_vm(ctx);
17811bb76ff1Sjsg
1782c349dbc7Sjsg /*
1783c349dbc7Sjsg * Make sure that we don't burst into a ball of flames upon falling back
1784c349dbc7Sjsg * to tmpfs, which we rely on if on the off-chance we encouter a failure
1785c349dbc7Sjsg * when setting up gemfs.
1786c349dbc7Sjsg */
1787c349dbc7Sjsg
1788c349dbc7Sjsg i915->mm.gemfs = NULL;
1789c349dbc7Sjsg
1790c349dbc7Sjsg obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
1791c349dbc7Sjsg if (IS_ERR(obj)) {
1792c349dbc7Sjsg err = PTR_ERR(obj);
1793c349dbc7Sjsg goto out_restore;
1794c349dbc7Sjsg }
1795c349dbc7Sjsg
17965ca02815Sjsg vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB);
1797c349dbc7Sjsg if (IS_ERR(vaddr)) {
1798c349dbc7Sjsg err = PTR_ERR(vaddr);
1799c349dbc7Sjsg goto out_put;
1800c349dbc7Sjsg }
1801c349dbc7Sjsg *vaddr = 0xdeadbeaf;
1802c349dbc7Sjsg
1803c349dbc7Sjsg __i915_gem_object_flush_map(obj, 0, 64);
1804c349dbc7Sjsg i915_gem_object_unpin_map(obj);
1805c349dbc7Sjsg
1806c349dbc7Sjsg vma = i915_vma_instance(obj, vm, NULL);
1807c349dbc7Sjsg if (IS_ERR(vma)) {
1808c349dbc7Sjsg err = PTR_ERR(vma);
1809c349dbc7Sjsg goto out_put;
1810c349dbc7Sjsg }
1811c349dbc7Sjsg
1812c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, PIN_USER);
1813c349dbc7Sjsg if (err)
1814ad8b1aafSjsg goto out_put;
1815c349dbc7Sjsg
1816c349dbc7Sjsg err = igt_check_page_sizes(vma);
1817c349dbc7Sjsg
1818c349dbc7Sjsg i915_vma_unpin(vma);
1819c349dbc7Sjsg out_put:
1820c349dbc7Sjsg i915_gem_object_put(obj);
1821c349dbc7Sjsg out_restore:
1822c349dbc7Sjsg i915->mm.gemfs = gemfs;
1823c349dbc7Sjsg
1824c349dbc7Sjsg i915_vm_put(vm);
18251bb76ff1Sjsg out:
18261bb76ff1Sjsg fput(file);
1827c349dbc7Sjsg return err;
1828c349dbc7Sjsg }
1829c349dbc7Sjsg
igt_shrink_thp(void * arg)1830c349dbc7Sjsg static int igt_shrink_thp(void *arg)
1831c349dbc7Sjsg {
18321bb76ff1Sjsg struct drm_i915_private *i915 = arg;
18331bb76ff1Sjsg struct i915_address_space *vm;
18341bb76ff1Sjsg struct i915_gem_context *ctx;
1835c349dbc7Sjsg struct drm_i915_gem_object *obj;
1836c349dbc7Sjsg struct i915_gem_engines_iter it;
1837c349dbc7Sjsg struct intel_context *ce;
1838c349dbc7Sjsg struct i915_vma *vma;
18391bb76ff1Sjsg struct file *file;
1840c349dbc7Sjsg unsigned int flags = PIN_USER;
1841c349dbc7Sjsg unsigned int n;
18421bb76ff1Sjsg intel_wakeref_t wf;
18431bb76ff1Sjsg bool should_swap;
18441bb76ff1Sjsg int err;
18451bb76ff1Sjsg
18461bb76ff1Sjsg if (!igt_can_allocate_thp(i915)) {
18471bb76ff1Sjsg pr_info("missing THP support, skipping\n");
18481bb76ff1Sjsg return 0;
18491bb76ff1Sjsg }
18501bb76ff1Sjsg
18511bb76ff1Sjsg file = mock_file(i915);
18521bb76ff1Sjsg if (IS_ERR(file))
18531bb76ff1Sjsg return PTR_ERR(file);
18541bb76ff1Sjsg
18551bb76ff1Sjsg ctx = hugepage_ctx(i915, file);
18561bb76ff1Sjsg if (IS_ERR(ctx)) {
18571bb76ff1Sjsg err = PTR_ERR(ctx);
18581bb76ff1Sjsg goto out;
18591bb76ff1Sjsg }
18601bb76ff1Sjsg vm = i915_gem_context_get_eb_vm(ctx);
1861c349dbc7Sjsg
1862c349dbc7Sjsg /*
1863c349dbc7Sjsg * Sanity check shrinking huge-paged object -- make sure nothing blows
1864c349dbc7Sjsg * up.
1865c349dbc7Sjsg */
1866c349dbc7Sjsg
1867c349dbc7Sjsg obj = i915_gem_object_create_shmem(i915, SZ_2M);
1868c349dbc7Sjsg if (IS_ERR(obj)) {
1869c349dbc7Sjsg err = PTR_ERR(obj);
1870c349dbc7Sjsg goto out_vm;
1871c349dbc7Sjsg }
1872c349dbc7Sjsg
1873c349dbc7Sjsg vma = i915_vma_instance(obj, vm, NULL);
1874c349dbc7Sjsg if (IS_ERR(vma)) {
1875c349dbc7Sjsg err = PTR_ERR(vma);
1876c349dbc7Sjsg goto out_put;
1877c349dbc7Sjsg }
1878c349dbc7Sjsg
18791bb76ff1Sjsg wf = intel_runtime_pm_get(&i915->runtime_pm); /* active shrink */
18801bb76ff1Sjsg
1881c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, flags);
1882c349dbc7Sjsg if (err)
18831bb76ff1Sjsg goto out_wf;
1884c349dbc7Sjsg
1885c349dbc7Sjsg if (obj->mm.page_sizes.phys < I915_GTT_PAGE_SIZE_2M) {
1886c349dbc7Sjsg pr_info("failed to allocate THP, finishing test early\n");
1887c349dbc7Sjsg goto out_unpin;
1888c349dbc7Sjsg }
1889c349dbc7Sjsg
1890c349dbc7Sjsg err = igt_check_page_sizes(vma);
1891c349dbc7Sjsg if (err)
1892c349dbc7Sjsg goto out_unpin;
1893c349dbc7Sjsg
1894c349dbc7Sjsg n = 0;
1895c349dbc7Sjsg
1896c349dbc7Sjsg for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
1897c349dbc7Sjsg if (!intel_engine_can_store_dword(ce->engine))
1898c349dbc7Sjsg continue;
1899c349dbc7Sjsg
1900c349dbc7Sjsg err = gpu_write(ce, vma, n++, 0xdeadbeaf);
1901c349dbc7Sjsg if (err)
1902c349dbc7Sjsg break;
1903c349dbc7Sjsg }
1904c349dbc7Sjsg i915_gem_context_unlock_engines(ctx);
19051bb76ff1Sjsg /*
19061bb76ff1Sjsg * Nuke everything *before* we unpin the pages so we can be reasonably
19071bb76ff1Sjsg * sure that when later checking get_nr_swap_pages() that some random
19081bb76ff1Sjsg * leftover object doesn't steal the remaining swap space.
19091bb76ff1Sjsg */
19101bb76ff1Sjsg i915_gem_shrink(NULL, i915, -1UL, NULL,
19111bb76ff1Sjsg I915_SHRINK_BOUND |
19121bb76ff1Sjsg I915_SHRINK_UNBOUND |
19131bb76ff1Sjsg I915_SHRINK_ACTIVE);
1914c349dbc7Sjsg i915_vma_unpin(vma);
1915c349dbc7Sjsg if (err)
191685f9e024Sjsg goto out_wf;
1917c349dbc7Sjsg
1918c349dbc7Sjsg /*
19191bb76ff1Sjsg * Now that the pages are *unpinned* shrinking should invoke
19201bb76ff1Sjsg * shmem to truncate our pages, if we have available swap.
1921c349dbc7Sjsg */
19221bb76ff1Sjsg should_swap = get_nr_swap_pages() > 0;
19231bb76ff1Sjsg i915_gem_shrink(NULL, i915, -1UL, NULL,
19241bb76ff1Sjsg I915_SHRINK_BOUND |
19251bb76ff1Sjsg I915_SHRINK_UNBOUND |
19261bb76ff1Sjsg I915_SHRINK_ACTIVE |
19271bb76ff1Sjsg I915_SHRINK_WRITEBACK);
19281bb76ff1Sjsg if (should_swap == i915_gem_object_has_pages(obj)) {
19291bb76ff1Sjsg pr_err("unexpected pages mismatch, should_swap=%s\n",
19301bb76ff1Sjsg str_yes_no(should_swap));
1931c349dbc7Sjsg err = -EINVAL;
193285f9e024Sjsg goto out_wf;
1933c349dbc7Sjsg }
1934c349dbc7Sjsg
19351bb76ff1Sjsg if (should_swap == (obj->mm.page_sizes.sg || obj->mm.page_sizes.phys)) {
19361bb76ff1Sjsg pr_err("unexpected residual page-size bits, should_swap=%s\n",
19371bb76ff1Sjsg str_yes_no(should_swap));
1938c349dbc7Sjsg err = -EINVAL;
193985f9e024Sjsg goto out_wf;
1940c349dbc7Sjsg }
1941c349dbc7Sjsg
1942c349dbc7Sjsg err = i915_vma_pin(vma, 0, 0, flags);
1943c349dbc7Sjsg if (err)
194485f9e024Sjsg goto out_wf;
1945c349dbc7Sjsg
1946c349dbc7Sjsg while (n--) {
1947c349dbc7Sjsg err = cpu_check(obj, n, 0xdeadbeaf);
1948c349dbc7Sjsg if (err)
1949c349dbc7Sjsg break;
1950c349dbc7Sjsg }
1951c349dbc7Sjsg
1952c349dbc7Sjsg out_unpin:
1953c349dbc7Sjsg i915_vma_unpin(vma);
19541bb76ff1Sjsg out_wf:
19551bb76ff1Sjsg intel_runtime_pm_put(&i915->runtime_pm, wf);
1956c349dbc7Sjsg out_put:
1957c349dbc7Sjsg i915_gem_object_put(obj);
1958c349dbc7Sjsg out_vm:
1959c349dbc7Sjsg i915_vm_put(vm);
19601bb76ff1Sjsg out:
19611bb76ff1Sjsg fput(file);
1962c349dbc7Sjsg return err;
1963c349dbc7Sjsg }
1964c349dbc7Sjsg
i915_gem_huge_page_mock_selftests(void)1965c349dbc7Sjsg int i915_gem_huge_page_mock_selftests(void)
1966c349dbc7Sjsg {
1967c349dbc7Sjsg static const struct i915_subtest tests[] = {
1968c349dbc7Sjsg SUBTEST(igt_mock_exhaust_device_supported_pages),
1969c349dbc7Sjsg SUBTEST(igt_mock_memory_region_huge_pages),
1970c349dbc7Sjsg SUBTEST(igt_mock_ppgtt_misaligned_dma),
1971c349dbc7Sjsg };
1972c349dbc7Sjsg struct drm_i915_private *dev_priv;
1973c349dbc7Sjsg struct i915_ppgtt *ppgtt;
1974c349dbc7Sjsg int err;
1975c349dbc7Sjsg
1976c349dbc7Sjsg dev_priv = mock_gem_device();
1977c349dbc7Sjsg if (!dev_priv)
1978c349dbc7Sjsg return -ENOMEM;
1979c349dbc7Sjsg
1980c349dbc7Sjsg /* Pretend to be a device which supports the 48b PPGTT */
19811bb76ff1Sjsg RUNTIME_INFO(dev_priv)->ppgtt_type = INTEL_PPGTT_FULL;
19821bb76ff1Sjsg RUNTIME_INFO(dev_priv)->ppgtt_size = 48;
1983c349dbc7Sjsg
19841bb76ff1Sjsg ppgtt = i915_ppgtt_create(to_gt(dev_priv), 0);
1985c349dbc7Sjsg if (IS_ERR(ppgtt)) {
1986c349dbc7Sjsg err = PTR_ERR(ppgtt);
1987c349dbc7Sjsg goto out_unlock;
1988c349dbc7Sjsg }
1989c349dbc7Sjsg
1990c349dbc7Sjsg if (!i915_vm_is_4lvl(&ppgtt->vm)) {
1991c349dbc7Sjsg pr_err("failed to create 48b PPGTT\n");
1992c349dbc7Sjsg err = -EINVAL;
1993ad8b1aafSjsg goto out_put;
1994c349dbc7Sjsg }
1995c349dbc7Sjsg
1996c349dbc7Sjsg /* If we were ever hit this then it's time to mock the 64K scratch */
1997c349dbc7Sjsg if (!i915_vm_has_scratch_64K(&ppgtt->vm)) {
1998c349dbc7Sjsg pr_err("PPGTT missing 64K scratch page\n");
1999c349dbc7Sjsg err = -EINVAL;
2000ad8b1aafSjsg goto out_put;
2001c349dbc7Sjsg }
2002c349dbc7Sjsg
2003c349dbc7Sjsg err = i915_subtests(tests, ppgtt);
2004c349dbc7Sjsg
2005ad8b1aafSjsg out_put:
2006c349dbc7Sjsg i915_vm_put(&ppgtt->vm);
2007c349dbc7Sjsg out_unlock:
2008ad8b1aafSjsg mock_destroy_device(dev_priv);
2009c349dbc7Sjsg return err;
2010c349dbc7Sjsg }
2011c349dbc7Sjsg
i915_gem_huge_page_live_selftests(struct drm_i915_private * i915)2012c349dbc7Sjsg int i915_gem_huge_page_live_selftests(struct drm_i915_private *i915)
2013c349dbc7Sjsg {
2014c349dbc7Sjsg static const struct i915_subtest tests[] = {
2015c349dbc7Sjsg SUBTEST(igt_shrink_thp),
2016c349dbc7Sjsg SUBTEST(igt_tmpfs_fallback),
2017c349dbc7Sjsg SUBTEST(igt_ppgtt_smoke_huge),
2018c349dbc7Sjsg SUBTEST(igt_ppgtt_sanity_check),
20191bb76ff1Sjsg SUBTEST(igt_ppgtt_compact),
2020*f005ef32Sjsg SUBTEST(igt_ppgtt_mixed),
2021*f005ef32Sjsg SUBTEST(igt_ppgtt_huge_fill),
2022*f005ef32Sjsg SUBTEST(igt_ppgtt_64K),
2023c349dbc7Sjsg };
2024c349dbc7Sjsg
2025c349dbc7Sjsg if (!HAS_PPGTT(i915)) {
2026c349dbc7Sjsg pr_info("PPGTT not supported, skipping live-selftests\n");
2027c349dbc7Sjsg return 0;
2028c349dbc7Sjsg }
2029c349dbc7Sjsg
20301bb76ff1Sjsg if (intel_gt_is_wedged(to_gt(i915)))
2031c349dbc7Sjsg return 0;
2032c349dbc7Sjsg
20331bb76ff1Sjsg return i915_live_subtests(tests, i915);
2034c349dbc7Sjsg }
2035