Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT
2 : : /*
3 : : * Copyright © 2020 Intel Corporation
4 : : */
5 : :
6 : : #include <linux/log2.h>
7 : :
8 : : #include "gen8_ppgtt.h"
9 : : #include "i915_scatterlist.h"
10 : : #include "i915_trace.h"
11 : : #include "i915_vgpu.h"
12 : : #include "intel_gt.h"
13 : : #include "intel_gtt.h"
14 : :
15 : 0 : static u64 gen8_pde_encode(const dma_addr_t addr,
16 : : const enum i915_cache_level level)
17 : : {
18 : 0 : u64 pde = addr | _PAGE_PRESENT | _PAGE_RW;
19 : :
20 [ # # ]: 0 : if (level != I915_CACHE_NONE)
21 : : pde |= PPAT_CACHED_PDE;
22 : : else
23 : 0 : pde |= PPAT_UNCACHED;
24 : :
25 : 0 : return pde;
26 : : }
27 : :
28 : 0 : static void gen8_ppgtt_notify_vgt(struct i915_ppgtt *ppgtt, bool create)
29 : : {
30 : 0 : struct drm_i915_private *i915 = ppgtt->vm.i915;
31 : 0 : struct intel_uncore *uncore = ppgtt->vm.gt->uncore;
32 : 0 : enum vgt_g2v_type msg;
33 : 0 : int i;
34 : :
35 [ # # ]: 0 : if (create)
36 : 0 : atomic_inc(px_used(ppgtt->pd)); /* never remove */
37 : : else
38 : 0 : atomic_dec(px_used(ppgtt->pd));
39 : :
40 : 0 : mutex_lock(&i915->vgpu.lock);
41 : :
42 [ # # ]: 0 : if (i915_vm_is_4lvl(&ppgtt->vm)) {
43 : 0 : const u64 daddr = px_dma(ppgtt->pd);
44 : :
45 : 0 : intel_uncore_write(uncore,
46 : : vgtif_reg(pdp[0].lo), lower_32_bits(daddr));
47 : 0 : intel_uncore_write(uncore,
48 : 0 : vgtif_reg(pdp[0].hi), upper_32_bits(daddr));
49 : :
50 : 0 : msg = create ?
51 [ # # ]: 0 : VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
52 : : VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY;
53 : : } else {
54 [ # # ]: 0 : for (i = 0; i < GEN8_3LVL_PDPES; i++) {
55 [ # # ]: 0 : const u64 daddr = i915_page_dir_dma_addr(ppgtt, i);
56 : :
57 : 0 : intel_uncore_write(uncore,
58 : 0 : vgtif_reg(pdp[i].lo),
59 : : lower_32_bits(daddr));
60 : 0 : intel_uncore_write(uncore,
61 : 0 : vgtif_reg(pdp[i].hi),
62 : 0 : upper_32_bits(daddr));
63 : : }
64 : :
65 : 0 : msg = create ?
66 [ # # ]: 0 : VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
67 : : VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY;
68 : : }
69 : :
70 : : /* g2v_notify atomically (via hv trap) consumes the message packet. */
71 : 0 : intel_uncore_write(uncore, vgtif_reg(g2v_notify), msg);
72 : :
73 : 0 : mutex_unlock(&i915->vgpu.lock);
74 : 0 : }
75 : :
76 : : /* Index shifts into the pagetable are offset by GEN8_PTE_SHIFT [12] */
77 : : #define GEN8_PAGE_SIZE (SZ_4K) /* page and page-directory sizes are the same */
78 : : #define GEN8_PTE_SHIFT (ilog2(GEN8_PAGE_SIZE))
79 : : #define GEN8_PDES (GEN8_PAGE_SIZE / sizeof(u64))
80 : : #define gen8_pd_shift(lvl) ((lvl) * ilog2(GEN8_PDES))
81 : : #define gen8_pd_index(i, lvl) i915_pde_index((i), gen8_pd_shift(lvl))
82 : : #define __gen8_pte_shift(lvl) (GEN8_PTE_SHIFT + gen8_pd_shift(lvl))
83 : : #define __gen8_pte_index(a, lvl) i915_pde_index((a), __gen8_pte_shift(lvl))
84 : :
85 : : #define as_pd(x) container_of((x), typeof(struct i915_page_directory), pt)
86 : :
87 : : static inline unsigned int
88 : 0 : gen8_pd_range(u64 start, u64 end, int lvl, unsigned int *idx)
89 : : {
90 : 0 : const int shift = gen8_pd_shift(lvl);
91 : 0 : const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);
92 : :
93 : 0 : GEM_BUG_ON(start >= end);
94 : 0 : end += ~mask >> gen8_pd_shift(1);
95 : :
96 : 0 : *idx = i915_pde_index(start, shift);
97 [ # # # # ]: 0 : if ((start ^ end) & mask)
98 : 0 : return GEN8_PDES - *idx;
99 : : else
100 : 0 : return i915_pde_index(end, shift) - *idx;
101 : : }
102 : :
103 : 0 : static inline bool gen8_pd_contains(u64 start, u64 end, int lvl)
104 : : {
105 : 0 : const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);
106 : :
107 : 0 : GEM_BUG_ON(start >= end);
108 [ # # # # ]: 0 : return (start ^ end) & mask && (start & ~mask) == 0;
109 : : }
110 : :
111 : 0 : static inline unsigned int gen8_pt_count(u64 start, u64 end)
112 : : {
113 : 0 : GEM_BUG_ON(start >= end);
114 : 0 : if ((start ^ end) >> gen8_pd_shift(1))
115 : 0 : return GEN8_PDES - (start & (GEN8_PDES - 1));
116 : : else
117 : 0 : return end - start;
118 : : }
119 : :
120 : : static inline unsigned int
121 : 0 : gen8_pd_top_count(const struct i915_address_space *vm)
122 : : {
123 : 0 : unsigned int shift = __gen8_pte_shift(vm->top);
124 : 0 : return (vm->total + (1ull << shift) - 1) >> shift;
125 : : }
126 : :
127 : : static inline struct i915_page_directory *
128 : 0 : gen8_pdp_for_page_index(struct i915_address_space * const vm, const u64 idx)
129 : : {
130 : 0 : struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
131 : :
132 [ # # # # ]: 0 : if (vm->top == 2)
133 : 0 : return ppgtt->pd;
134 : : else
135 : 0 : return i915_pd_entry(ppgtt->pd, gen8_pd_index(idx, vm->top));
136 : : }
137 : :
138 : : static inline struct i915_page_directory *
139 : 0 : gen8_pdp_for_page_address(struct i915_address_space * const vm, const u64 addr)
140 : : {
141 : 0 : return gen8_pdp_for_page_index(vm, addr >> GEN8_PTE_SHIFT);
142 : : }
143 : :
144 : 0 : static void __gen8_ppgtt_cleanup(struct i915_address_space *vm,
145 : : struct i915_page_directory *pd,
146 : : int count, int lvl)
147 : : {
148 [ # # ]: 0 : if (lvl) {
149 : 0 : void **pde = pd->entry;
150 : :
151 : 0 : do {
152 [ # # ]: 0 : if (!*pde)
153 : 0 : continue;
154 : :
155 : 0 : __gen8_ppgtt_cleanup(vm, *pde, GEN8_PDES, lvl - 1);
156 [ # # ]: 0 : } while (pde++, --count);
157 : : }
158 : :
159 : 0 : free_px(vm, pd);
160 : 0 : }
161 : :
162 : 0 : static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
163 : : {
164 [ # # ]: 0 : struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
165 : :
166 [ # # ]: 0 : if (intel_vgpu_active(vm->i915))
167 : 0 : gen8_ppgtt_notify_vgt(ppgtt, false);
168 : :
169 : 0 : __gen8_ppgtt_cleanup(vm, ppgtt->pd, gen8_pd_top_count(vm), vm->top);
170 : 0 : free_scratch(vm);
171 : 0 : }
172 : :
173 : 0 : static u64 __gen8_ppgtt_clear(struct i915_address_space * const vm,
174 : : struct i915_page_directory * const pd,
175 : : u64 start, const u64 end, int lvl)
176 : : {
177 : 0 : const struct i915_page_scratch * const scratch = &vm->scratch[lvl];
178 : 0 : unsigned int idx, len;
179 : :
180 : 0 : GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);
181 : :
182 [ # # ]: 0 : len = gen8_pd_range(start, end, lvl--, &idx);
183 : : DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
184 : : __func__, vm, lvl + 1, start, end,
185 : 0 : idx, len, atomic_read(px_used(pd)));
186 : 0 : GEM_BUG_ON(!len || len >= atomic_read(px_used(pd)));
187 : :
188 : 0 : do {
189 : 0 : struct i915_page_table *pt = pd->entry[idx];
190 : :
191 [ # # # # ]: 0 : if (atomic_fetch_inc(&pt->used) >> gen8_pd_shift(1) &&
192 : : gen8_pd_contains(start, end, lvl)) {
193 : : DBG("%s(%p):{ lvl:%d, idx:%d, start:%llx, end:%llx } removing pd\n",
194 : 0 : __func__, vm, lvl + 1, idx, start, end);
195 : 0 : clear_pd_entry(pd, idx, scratch);
196 : 0 : __gen8_ppgtt_cleanup(vm, as_pd(pt), I915_PDES, lvl);
197 : 0 : start += (u64)I915_PDES << gen8_pd_shift(lvl);
198 : 0 : continue;
199 : : }
200 : :
201 [ # # ]: 0 : if (lvl) {
202 : 0 : start = __gen8_ppgtt_clear(vm, as_pd(pt),
203 : : start, end, lvl);
204 : : } else {
205 : 0 : unsigned int count;
206 : 0 : u64 *vaddr;
207 : :
208 [ # # ]: 0 : count = gen8_pt_count(start, end);
209 : : DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } removing pte\n",
210 : : __func__, vm, lvl, start, end,
211 : : gen8_pd_index(start, 0), count,
212 : 0 : atomic_read(&pt->used));
213 : 0 : GEM_BUG_ON(!count || count >= atomic_read(&pt->used));
214 : :
215 : 0 : vaddr = kmap_atomic_px(pt);
216 : 0 : memset64(vaddr + gen8_pd_index(start, 0),
217 : : vm->scratch[0].encode,
218 : : count);
219 : 0 : kunmap_atomic(vaddr);
220 : :
221 : 0 : atomic_sub(count, &pt->used);
222 : 0 : start += count;
223 : : }
224 : :
225 [ # # ]: 0 : if (release_pd_entry(pd, idx, pt, scratch))
226 : 0 : free_px(vm, pt);
227 [ # # ]: 0 : } while (idx++, --len);
228 : :
229 : 0 : return start;
230 : : }
231 : :
232 : 0 : static void gen8_ppgtt_clear(struct i915_address_space *vm,
233 : : u64 start, u64 length)
234 : : {
235 : 0 : GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
236 : 0 : GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
237 : 0 : GEM_BUG_ON(range_overflows(start, length, vm->total));
238 : :
239 : 0 : start >>= GEN8_PTE_SHIFT;
240 : 0 : length >>= GEN8_PTE_SHIFT;
241 : 0 : GEM_BUG_ON(length == 0);
242 : :
243 : 0 : __gen8_ppgtt_clear(vm, i915_vm_to_ppgtt(vm)->pd,
244 : 0 : start, start + length, vm->top);
245 : 0 : }
246 : :
247 : 0 : static int __gen8_ppgtt_alloc(struct i915_address_space * const vm,
248 : : struct i915_page_directory * const pd,
249 : : u64 * const start, const u64 end, int lvl)
250 : : {
251 : 0 : const struct i915_page_scratch * const scratch = &vm->scratch[lvl];
252 : 0 : struct i915_page_table *alloc = NULL;
253 : 0 : unsigned int idx, len;
254 : 0 : int ret = 0;
255 : :
256 : 0 : GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);
257 : :
258 [ # # ]: 0 : len = gen8_pd_range(*start, end, lvl--, &idx);
259 : : DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
260 : : __func__, vm, lvl + 1, *start, end,
261 : 0 : idx, len, atomic_read(px_used(pd)));
262 : 0 : GEM_BUG_ON(!len || (idx + len - 1) >> gen8_pd_shift(1));
263 : :
264 : 0 : spin_lock(&pd->lock);
265 : 0 : GEM_BUG_ON(!atomic_read(px_used(pd))); /* Must be pinned! */
266 : 0 : do {
267 : 0 : struct i915_page_table *pt = pd->entry[idx];
268 : :
269 [ # # ]: 0 : if (!pt) {
270 : 0 : spin_unlock(&pd->lock);
271 : :
272 : : DBG("%s(%p):{ lvl:%d, idx:%d } allocating new tree\n",
273 : 0 : __func__, vm, lvl + 1, idx);
274 : :
275 : 0 : pt = fetch_and_zero(&alloc);
276 [ # # ]: 0 : if (lvl) {
277 [ # # ]: 0 : if (!pt) {
278 : 0 : pt = &alloc_pd(vm)->pt;
279 [ # # ]: 0 : if (IS_ERR(pt)) {
280 : 0 : ret = PTR_ERR(pt);
281 : 0 : goto out;
282 : : }
283 : : }
284 : :
285 : 0 : fill_px(pt, vm->scratch[lvl].encode);
286 : : } else {
287 [ # # ]: 0 : if (!pt) {
288 : 0 : pt = alloc_pt(vm);
289 [ # # ]: 0 : if (IS_ERR(pt)) {
290 : 0 : ret = PTR_ERR(pt);
291 : 0 : goto out;
292 : : }
293 : : }
294 : :
295 [ # # # # ]: 0 : if (intel_vgpu_active(vm->i915) ||
296 [ # # ]: 0 : gen8_pt_count(*start, end) < I915_PDES)
297 : 0 : fill_px(pt, vm->scratch[lvl].encode);
298 : : }
299 : :
300 : 0 : spin_lock(&pd->lock);
301 [ # # ]: 0 : if (likely(!pd->entry[idx]))
302 : 0 : set_pd_entry(pd, idx, pt);
303 : : else
304 : : alloc = pt, pt = pd->entry[idx];
305 : : }
306 : :
307 [ # # ]: 0 : if (lvl) {
308 : 0 : atomic_inc(&pt->used);
309 : 0 : spin_unlock(&pd->lock);
310 : :
311 : 0 : ret = __gen8_ppgtt_alloc(vm, as_pd(pt),
312 : : start, end, lvl);
313 [ # # ]: 0 : if (unlikely(ret)) {
314 [ # # ]: 0 : if (release_pd_entry(pd, idx, pt, scratch))
315 : 0 : free_px(vm, pt);
316 : 0 : goto out;
317 : : }
318 : :
319 : 0 : spin_lock(&pd->lock);
320 : 0 : atomic_dec(&pt->used);
321 : 0 : GEM_BUG_ON(!atomic_read(&pt->used));
322 : : } else {
323 [ # # ]: 0 : unsigned int count = gen8_pt_count(*start, end);
324 : :
325 : : DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } inserting pte\n",
326 : : __func__, vm, lvl, *start, end,
327 : : gen8_pd_index(*start, 0), count,
328 : 0 : atomic_read(&pt->used));
329 : :
330 : 0 : atomic_add(count, &pt->used);
331 : : /* All other pdes may be simultaneously removed */
332 : 0 : GEM_BUG_ON(atomic_read(&pt->used) > NALLOC * I915_PDES);
333 : 0 : *start += count;
334 : : }
335 [ # # ]: 0 : } while (idx++, --len);
336 : 0 : spin_unlock(&pd->lock);
337 : 0 : out:
338 [ # # ]: 0 : if (alloc)
339 : 0 : free_px(vm, alloc);
340 : 0 : return ret;
341 : : }
342 : :
343 : 0 : static int gen8_ppgtt_alloc(struct i915_address_space *vm,
344 : : u64 start, u64 length)
345 : : {
346 : 0 : u64 from;
347 : 0 : int err;
348 : :
349 : 0 : GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
350 : 0 : GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
351 : 0 : GEM_BUG_ON(range_overflows(start, length, vm->total));
352 : :
353 : 0 : start >>= GEN8_PTE_SHIFT;
354 : 0 : length >>= GEN8_PTE_SHIFT;
355 : 0 : GEM_BUG_ON(length == 0);
356 : 0 : from = start;
357 : :
358 : 0 : err = __gen8_ppgtt_alloc(vm, i915_vm_to_ppgtt(vm)->pd,
359 : 0 : &start, start + length, vm->top);
360 [ # # # # ]: 0 : if (unlikely(err && from != start))
361 : 0 : __gen8_ppgtt_clear(vm, i915_vm_to_ppgtt(vm)->pd,
362 : 0 : from, start, vm->top);
363 : :
364 : 0 : return err;
365 : : }
366 : :
367 : : static __always_inline u64
368 : 0 : gen8_ppgtt_insert_pte(struct i915_ppgtt *ppgtt,
369 : : struct i915_page_directory *pdp,
370 : : struct sgt_dma *iter,
371 : : u64 idx,
372 : : enum i915_cache_level cache_level,
373 : : u32 flags)
374 : : {
375 : 0 : struct i915_page_directory *pd;
376 : 0 : const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags);
377 : 0 : gen8_pte_t *vaddr;
378 : :
379 : 0 : pd = i915_pd_entry(pdp, gen8_pd_index(idx, 2));
380 : 0 : vaddr = kmap_atomic_px(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
381 : 0 : do {
382 : 0 : GEM_BUG_ON(iter->sg->length < I915_GTT_PAGE_SIZE);
383 [ # # ]: 0 : vaddr[gen8_pd_index(idx, 0)] = pte_encode | iter->dma;
384 : :
385 : 0 : iter->dma += I915_GTT_PAGE_SIZE;
386 [ # # ]: 0 : if (iter->dma >= iter->max) {
387 [ # # ]: 0 : iter->sg = __sg_next(iter->sg);
388 [ # # ]: 0 : if (!iter->sg) {
389 : : idx = 0;
390 : : break;
391 : : }
392 : :
393 : 0 : iter->dma = sg_dma_address(iter->sg);
394 : 0 : iter->max = iter->dma + iter->sg->length;
395 : : }
396 : :
397 [ # # ]: 0 : if (gen8_pd_index(++idx, 0) == 0) {
398 [ # # ]: 0 : if (gen8_pd_index(idx, 1) == 0) {
399 : : /* Limited by sg length for 3lvl */
400 [ # # ]: 0 : if (gen8_pd_index(idx, 2) == 0)
401 : : break;
402 : :
403 : 0 : pd = pdp->entry[gen8_pd_index(idx, 2)];
404 : : }
405 : :
406 : 0 : kunmap_atomic(vaddr);
407 : 0 : vaddr = kmap_atomic_px(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
408 : : }
409 : : } while (1);
410 : 0 : kunmap_atomic(vaddr);
411 : :
412 : 0 : return idx;
413 : : }
414 : :
415 : 0 : static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
416 : : struct sgt_dma *iter,
417 : : enum i915_cache_level cache_level,
418 : : u32 flags)
419 : : {
420 : 0 : const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags);
421 : 0 : u64 start = vma->node.start;
422 : 0 : dma_addr_t rem = iter->sg->length;
423 : :
424 : 0 : GEM_BUG_ON(!i915_vm_is_4lvl(vma->vm));
425 : :
426 : 0 : do {
427 : 0 : struct i915_page_directory * const pdp =
428 [ # # ]: 0 : gen8_pdp_for_page_address(vma->vm, start);
429 [ # # ]: 0 : struct i915_page_directory * const pd =
430 [ # # ]: 0 : i915_pd_entry(pdp, __gen8_pte_index(start, 2));
431 : 0 : gen8_pte_t encode = pte_encode;
432 : 0 : unsigned int maybe_64K = -1;
433 : 0 : unsigned int page_size;
434 : 0 : gen8_pte_t *vaddr;
435 : 0 : u16 index;
436 : :
437 [ # # ]: 0 : if (vma->page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
438 [ # # # # ]: 0 : IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
439 [ # # ]: 0 : rem >= I915_GTT_PAGE_SIZE_2M &&
440 : : !__gen8_pte_index(start, 0)) {
441 : 0 : index = __gen8_pte_index(start, 1);
442 : 0 : encode |= GEN8_PDE_PS_2M;
443 : 0 : page_size = I915_GTT_PAGE_SIZE_2M;
444 : :
445 : 0 : vaddr = kmap_atomic_px(pd);
446 : : } else {
447 [ # # ]: 0 : struct i915_page_table *pt =
448 [ # # ]: 0 : i915_pt_entry(pd, __gen8_pte_index(start, 1));
449 : :
450 : 0 : index = __gen8_pte_index(start, 0);
451 : 0 : page_size = I915_GTT_PAGE_SIZE;
452 : :
453 [ # # # # ]: 0 : if (!index &&
454 : 0 : vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
455 [ # # ]: 0 : IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
456 [ # # # # ]: 0 : (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
457 : : rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE))
458 : 0 : maybe_64K = __gen8_pte_index(start, 1);
459 : :
460 : 0 : vaddr = kmap_atomic_px(pt);
461 : : }
462 : :
463 : 0 : do {
464 : 0 : GEM_BUG_ON(iter->sg->length < page_size);
465 : 0 : vaddr[index++] = encode | iter->dma;
466 : :
467 : 0 : start += page_size;
468 : 0 : iter->dma += page_size;
469 : 0 : rem -= page_size;
470 [ # # ]: 0 : if (iter->dma >= iter->max) {
471 [ # # ]: 0 : iter->sg = __sg_next(iter->sg);
472 [ # # ]: 0 : if (!iter->sg)
473 : : break;
474 : :
475 : 0 : rem = iter->sg->length;
476 : 0 : iter->dma = sg_dma_address(iter->sg);
477 : 0 : iter->max = iter->dma + rem;
478 : :
479 [ # # ]: 0 : if (maybe_64K != -1 && index < I915_PDES &&
480 [ # # # # ]: 0 : !(IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
481 : 0 : (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
482 [ # # ]: 0 : rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE)))
483 : 0 : maybe_64K = -1;
484 : :
485 [ # # ]: 0 : if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
486 : : break;
487 : : }
488 [ # # # # ]: 0 : } while (rem >= page_size && index < I915_PDES);
489 : :
490 : 0 : kunmap_atomic(vaddr);
491 : :
492 : : /*
493 : : * Is it safe to mark the 2M block as 64K? -- Either we have
494 : : * filled whole page-table with 64K entries, or filled part of
495 : : * it and have reached the end of the sg table and we have
496 : : * enough padding.
497 : : */
498 [ # # # # ]: 0 : if (maybe_64K != -1 &&
499 [ # # ]: 0 : (index == I915_PDES ||
500 [ # # ]: 0 : (i915_vm_has_scratch_64K(vma->vm) &&
501 [ # # # # ]: 0 : !iter->sg && IS_ALIGNED(vma->node.start +
502 : : vma->node.size,
503 : : I915_GTT_PAGE_SIZE_2M)))) {
504 : 0 : vaddr = kmap_atomic_px(pd);
505 : 0 : vaddr[maybe_64K] |= GEN8_PDE_IPS_64K;
506 : 0 : kunmap_atomic(vaddr);
507 : 0 : page_size = I915_GTT_PAGE_SIZE_64K;
508 : :
509 : : /*
510 : : * We write all 4K page entries, even when using 64K
511 : : * pages. In order to verify that the HW isn't cheating
512 : : * by using the 4K PTE instead of the 64K PTE, we want
513 : : * to remove all the surplus entries. If the HW skipped
514 : : * the 64K PTE, it will read/write into the scratch page
515 : : * instead - which we detect as missing results during
516 : : * selftests.
517 : : */
518 : 0 : if (I915_SELFTEST_ONLY(vma->vm->scrub_64K)) {
519 : : u16 i;
520 : :
521 : : encode = vma->vm->scratch[0].encode;
522 : : vaddr = kmap_atomic_px(i915_pt_entry(pd, maybe_64K));
523 : :
524 : : for (i = 1; i < index; i += 16)
525 : : memset64(vaddr + i, encode, 15);
526 : :
527 : 0 : kunmap_atomic(vaddr);
528 : : }
529 : : }
530 : :
531 : 0 : vma->page_sizes.gtt |= page_size;
532 [ # # ]: 0 : } while (iter->sg);
533 : 0 : }
534 : :
535 : 0 : static void gen8_ppgtt_insert(struct i915_address_space *vm,
536 : : struct i915_vma *vma,
537 : : enum i915_cache_level cache_level,
538 : : u32 flags)
539 : : {
540 [ # # ]: 0 : struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
541 [ # # ]: 0 : struct sgt_dma iter = sgt_dma(vma);
542 : :
543 [ # # ]: 0 : if (vma->page_sizes.sg > I915_GTT_PAGE_SIZE) {
544 : 0 : gen8_ppgtt_insert_huge(vma, &iter, cache_level, flags);
545 : : } else {
546 : 0 : u64 idx = vma->node.start >> GEN8_PTE_SHIFT;
547 : :
548 : 0 : do {
549 [ # # ]: 0 : struct i915_page_directory * const pdp =
550 : : gen8_pdp_for_page_index(vm, idx);
551 : :
552 : 0 : idx = gen8_ppgtt_insert_pte(ppgtt, pdp, &iter, idx,
553 : : cache_level, flags);
554 [ # # ]: 0 : } while (idx);
555 : :
556 : 0 : vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
557 : : }
558 : 0 : }
559 : :
560 : 0 : static int gen8_init_scratch(struct i915_address_space *vm)
561 : : {
562 : 0 : int ret;
563 : 0 : int i;
564 : :
565 : : /*
566 : : * If everybody agrees to not to write into the scratch page,
567 : : * we can reuse it for all vm, keeping contexts and processes separate.
568 : : */
569 [ # # # # : 0 : if (vm->has_read_only && vm->gt->vm && !i915_is_ggtt(vm->gt->vm)) {
# # ]
570 : 0 : struct i915_address_space *clone = vm->gt->vm;
571 : :
572 : 0 : GEM_BUG_ON(!clone->has_read_only);
573 : :
574 : 0 : vm->scratch_order = clone->scratch_order;
575 : 0 : memcpy(vm->scratch, clone->scratch, sizeof(vm->scratch));
576 : 0 : px_dma(&vm->scratch[0]) = 0; /* no xfer of ownership */
577 : 0 : return 0;
578 : : }
579 : :
580 : 0 : ret = setup_scratch_page(vm, __GFP_HIGHMEM);
581 [ # # ]: 0 : if (ret)
582 : : return ret;
583 : :
584 : 0 : vm->scratch[0].encode =
585 : 0 : gen8_pte_encode(px_dma(&vm->scratch[0]),
586 : 0 : I915_CACHE_LLC, vm->has_read_only);
587 : :
588 [ # # ]: 0 : for (i = 1; i <= vm->top; i++) {
589 [ # # ]: 0 : if (unlikely(setup_page_dma(vm, px_base(&vm->scratch[i]))))
590 : 0 : goto free_scratch;
591 : :
592 : 0 : fill_px(&vm->scratch[i], vm->scratch[i - 1].encode);
593 : 0 : vm->scratch[i].encode =
594 : 0 : gen8_pde_encode(px_dma(&vm->scratch[i]),
595 : : I915_CACHE_LLC);
596 : : }
597 : :
598 : : return 0;
599 : :
600 : : free_scratch:
601 : 0 : free_scratch(vm);
602 : 0 : return -ENOMEM;
603 : : }
604 : :
605 : 0 : static int gen8_preallocate_top_level_pdp(struct i915_ppgtt *ppgtt)
606 : : {
607 : 0 : struct i915_address_space *vm = &ppgtt->vm;
608 : 0 : struct i915_page_directory *pd = ppgtt->pd;
609 : 0 : unsigned int idx;
610 : :
611 : 0 : GEM_BUG_ON(vm->top != 2);
612 : 0 : GEM_BUG_ON(gen8_pd_top_count(vm) != GEN8_3LVL_PDPES);
613 : :
614 [ # # ]: 0 : for (idx = 0; idx < GEN8_3LVL_PDPES; idx++) {
615 : 0 : struct i915_page_directory *pde;
616 : :
617 : 0 : pde = alloc_pd(vm);
618 [ # # ]: 0 : if (IS_ERR(pde))
619 : 0 : return PTR_ERR(pde);
620 : :
621 : 0 : fill_px(pde, vm->scratch[1].encode);
622 : 0 : set_pd_entry(pd, idx, pde);
623 : 0 : atomic_inc(px_used(pde)); /* keep pinned */
624 : : }
625 : 0 : wmb();
626 : :
627 : 0 : return 0;
628 : : }
629 : :
630 : : static struct i915_page_directory *
631 : 0 : gen8_alloc_top_pd(struct i915_address_space *vm)
632 : : {
633 : 0 : const unsigned int count = gen8_pd_top_count(vm);
634 : 0 : struct i915_page_directory *pd;
635 : :
636 : 0 : GEM_BUG_ON(count > ARRAY_SIZE(pd->entry));
637 : :
638 : 0 : pd = __alloc_pd(offsetof(typeof(*pd), entry[count]));
639 [ # # ]: 0 : if (unlikely(!pd))
640 : : return ERR_PTR(-ENOMEM);
641 : :
642 [ # # ]: 0 : if (unlikely(setup_page_dma(vm, px_base(pd)))) {
643 : 0 : kfree(pd);
644 : 0 : return ERR_PTR(-ENOMEM);
645 : : }
646 : :
647 : 0 : fill_page_dma(px_base(pd), vm->scratch[vm->top].encode, count);
648 : 0 : atomic_inc(px_used(pd)); /* mark as pinned */
649 : 0 : return pd;
650 : : }
651 : :
652 : : /*
653 : : * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
654 : : * with a net effect resembling a 2-level page table in normal x86 terms. Each
655 : : * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
656 : : * space.
657 : : *
658 : : */
659 : 0 : struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt)
660 : : {
661 : 0 : struct i915_ppgtt *ppgtt;
662 : 0 : int err;
663 : :
664 : 0 : ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
665 [ # # ]: 0 : if (!ppgtt)
666 : : return ERR_PTR(-ENOMEM);
667 : :
668 : 0 : ppgtt_init(ppgtt, gt);
669 [ # # ]: 0 : ppgtt->vm.top = i915_vm_is_4lvl(&ppgtt->vm) ? 3 : 2;
670 : :
671 : : /*
672 : : * From bdw, there is hw support for read-only pages in the PPGTT.
673 : : *
674 : : * Gen11 has HSDES#:1807136187 unresolved. Disable ro support
675 : : * for now.
676 : : *
677 : : * Gen12 has inherited the same read-only fault issue from gen11.
678 : : */
679 : 0 : ppgtt->vm.has_read_only = !IS_GEN_RANGE(gt->i915, 11, 12);
680 : :
681 : : /*
682 : : * There are only few exceptions for gen >=6. chv and bxt.
683 : : * And we are not sure about the latter so play safe for now.
684 : : */
685 [ # # # # ]: 0 : if (IS_CHERRYVIEW(gt->i915) || IS_BROXTON(gt->i915))
686 : 0 : ppgtt->vm.pt_kmap_wc = true;
687 : :
688 : 0 : err = gen8_init_scratch(&ppgtt->vm);
689 [ # # ]: 0 : if (err)
690 : 0 : goto err_free;
691 : :
692 : 0 : ppgtt->pd = gen8_alloc_top_pd(&ppgtt->vm);
693 [ # # ]: 0 : if (IS_ERR(ppgtt->pd)) {
694 : 0 : err = PTR_ERR(ppgtt->pd);
695 : 0 : goto err_free_scratch;
696 : : }
697 : :
698 [ # # ]: 0 : if (!i915_vm_is_4lvl(&ppgtt->vm)) {
699 : 0 : err = gen8_preallocate_top_level_pdp(ppgtt);
700 [ # # ]: 0 : if (err)
701 : 0 : goto err_free_pd;
702 : : }
703 : :
704 : 0 : ppgtt->vm.bind_async_flags = I915_VMA_LOCAL_BIND;
705 : 0 : ppgtt->vm.insert_entries = gen8_ppgtt_insert;
706 : 0 : ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc;
707 : 0 : ppgtt->vm.clear_range = gen8_ppgtt_clear;
708 : :
709 [ # # ]: 0 : if (intel_vgpu_active(gt->i915))
710 : 0 : gen8_ppgtt_notify_vgt(ppgtt, true);
711 : :
712 : 0 : ppgtt->vm.cleanup = gen8_ppgtt_cleanup;
713 : :
714 : 0 : return ppgtt;
715 : :
716 : : err_free_pd:
717 : 0 : __gen8_ppgtt_cleanup(&ppgtt->vm, ppgtt->pd,
718 : 0 : gen8_pd_top_count(&ppgtt->vm), ppgtt->vm.top);
719 : 0 : err_free_scratch:
720 : 0 : free_scratch(&ppgtt->vm);
721 : 0 : err_free:
722 : 0 : kfree(ppgtt);
723 : 0 : return ERR_PTR(err);
724 : : }
|