1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2023 Intel Corporation
4 */
5
6 #include <linux/align.h>
7
8 #include <drm/drm_managed.h>
9
10 #include "regs/xe_gt_regs.h"
11 #include "regs/xe_mert_regs.h"
12
13 #include "xe_assert.h"
14 #include "xe_bo.h"
15 #include "xe_tlb_inval.h"
16 #include "xe_lmtt.h"
17 #include "xe_map.h"
18 #include "xe_mert.h"
19 #include "xe_mmio.h"
20 #include "xe_res_cursor.h"
21 #include "xe_sriov.h"
22 #include "xe_tile.h"
23 #include "xe_tile_sriov_printk.h"
24
25 /**
26 * DOC: Local Memory Translation Table
27 *
28 * The Local Memory Translation Table (LMTT) provides additional abstraction
29 * when Virtual Function (VF) is accessing device Local Memory (VRAM).
30 *
31 * The Root LMTT Page Directory contains one entry for each VF. Entries are
32 * indexed by the function number (1-based, index 0 is unused).
33 *
34 * See `Two-Level LMTT Structure`_ and `Multi-Level LMTT Structure`_.
35 */
36
37 #define lmtt_assert(lmtt, condition) xe_tile_assert(lmtt_to_tile(lmtt), condition)
38 #define lmtt_debug(lmtt, msg...) xe_tile_sriov_dbg_verbose(lmtt_to_tile(lmtt), "LMTT: " msg)
39
xe_has_multi_level_lmtt(struct xe_device * xe)40 static bool xe_has_multi_level_lmtt(struct xe_device *xe)
41 {
42 return GRAPHICS_VERx100(xe) >= 1260;
43 }
44
lmtt_to_tile(struct xe_lmtt * lmtt)45 static struct xe_tile *lmtt_to_tile(struct xe_lmtt *lmtt)
46 {
47 return container_of(lmtt, struct xe_tile, sriov.pf.lmtt);
48 }
49
lmtt_to_xe(struct xe_lmtt * lmtt)50 static struct xe_device *lmtt_to_xe(struct xe_lmtt *lmtt)
51 {
52 return tile_to_xe(lmtt_to_tile(lmtt));
53 }
54
lmtt_page_size(struct xe_lmtt * lmtt)55 static u64 lmtt_page_size(struct xe_lmtt *lmtt)
56 {
57 return BIT_ULL(lmtt->ops->lmtt_pte_shift(0));
58 }
59
lmtt_pt_alloc(struct xe_lmtt * lmtt,unsigned int level)60 static struct xe_lmtt_pt *lmtt_pt_alloc(struct xe_lmtt *lmtt, unsigned int level)
61 {
62 unsigned int num_entries = level ? lmtt->ops->lmtt_pte_num(level) : 0;
63 struct xe_lmtt_pt *pt;
64 struct xe_bo *bo;
65 int err;
66
67 pt = kzalloc_flex(*pt, entries, num_entries);
68 if (!pt) {
69 err = -ENOMEM;
70 goto out;
71 }
72
73 bo = xe_bo_create_pin_map_novm(lmtt_to_xe(lmtt), lmtt_to_tile(lmtt),
74 PAGE_ALIGN(lmtt->ops->lmtt_pte_size(level) *
75 lmtt->ops->lmtt_pte_num(level)),
76 ttm_bo_type_kernel,
77 XE_BO_FLAG_VRAM_IF_DGFX(lmtt_to_tile(lmtt)) |
78 XE_BO_FLAG_NEEDS_64K, false);
79 if (IS_ERR(bo)) {
80 err = PTR_ERR(bo);
81 goto out_free_pt;
82 }
83
84 lmtt_assert(lmtt, xe_bo_is_vram(bo));
85 lmtt_debug(lmtt, "level=%u addr=%#llx\n", level, (u64)xe_bo_main_addr(bo, XE_PAGE_SIZE));
86
87 xe_map_memset(lmtt_to_xe(lmtt), &bo->vmap, 0, 0, xe_bo_size(bo));
88
89 pt->level = level;
90 pt->bo = bo;
91 return pt;
92
93 out_free_pt:
94 kfree(pt);
95 out:
96 return ERR_PTR(err);
97 }
98
lmtt_pt_free(struct xe_lmtt_pt * pt)99 static void lmtt_pt_free(struct xe_lmtt_pt *pt)
100 {
101 lmtt_debug(&pt->bo->tile->sriov.pf.lmtt, "level=%u addr=%llx\n",
102 pt->level, (u64)xe_bo_main_addr(pt->bo, XE_PAGE_SIZE));
103
104 xe_bo_unpin_map_no_vm(pt->bo);
105 kfree(pt);
106 }
107
lmtt_init_pd(struct xe_lmtt * lmtt)108 static int lmtt_init_pd(struct xe_lmtt *lmtt)
109 {
110 struct xe_lmtt_pt *pd;
111
112 lmtt_assert(lmtt, !lmtt->pd);
113 lmtt_assert(lmtt, lmtt->ops->lmtt_root_pd_level());
114
115 pd = lmtt_pt_alloc(lmtt, lmtt->ops->lmtt_root_pd_level());
116 if (IS_ERR(pd))
117 return PTR_ERR(pd);
118
119 lmtt->pd = pd;
120 return 0;
121 }
122
lmtt_fini_pd(struct xe_lmtt * lmtt)123 static void lmtt_fini_pd(struct xe_lmtt *lmtt)
124 {
125 struct xe_lmtt_pt *pd = lmtt->pd;
126 unsigned int num_entries = lmtt->ops->lmtt_pte_num(pd->level);
127 unsigned int n = 0;
128
129 /* make sure we don't leak */
130 for (n = 0; n < num_entries; n++)
131 lmtt_assert(lmtt, !pd->entries[n]);
132
133 lmtt->pd = NULL;
134 lmtt_pt_free(pd);
135 }
136
fini_lmtt(struct drm_device * drm,void * arg)137 static void fini_lmtt(struct drm_device *drm, void *arg)
138 {
139 struct xe_lmtt *lmtt = arg;
140
141 lmtt_assert(lmtt, !(!!lmtt->ops ^ !!lmtt->pd));
142
143 if (!lmtt->pd)
144 return;
145
146 lmtt_fini_pd(lmtt);
147 lmtt->ops = NULL;
148 }
149
150 /**
151 * xe_lmtt_init - LMTT software initialization.
152 * @lmtt: the &xe_lmtt to initialize
153 *
154 * The LMTT initialization requires two steps.
155 *
156 * The xe_lmtt_init() checks if LMTT is required on current device and selects
157 * and initialize proper variant of the LMTT Root Directory. Currently supported
158 * variants are `Two-Level LMTT Structure`_ and `Multi-Level LMTT Structure`_.
159 *
160 * In next step xe_lmtt_init_hw() will register this directory on the hardware.
161 *
162 * Notes:
163 * The LMTT allocations are managed and will be implicitly released on driver unload.
164 * This function shall be called only once and only when running as a PF driver.
165 * Any LMTT initialization failure should block VFs enabling.
166 *
167 * Return: 0 on success or a negative error code on failure.
168 */
xe_lmtt_init(struct xe_lmtt * lmtt)169 int xe_lmtt_init(struct xe_lmtt *lmtt)
170 {
171 struct xe_device *xe = lmtt_to_xe(lmtt);
172 int err;
173
174 lmtt_assert(lmtt, IS_SRIOV_PF(xe));
175 lmtt_assert(lmtt, !lmtt->ops);
176
177 if (!xe_device_has_lmtt(xe))
178 return 0;
179
180 if (xe_has_multi_level_lmtt(xe))
181 lmtt->ops = &lmtt_ml_ops;
182 else
183 lmtt->ops = &lmtt_2l_ops;
184
185 err = lmtt_init_pd(lmtt);
186 if (unlikely(err))
187 goto fail;
188
189 return drmm_add_action_or_reset(&xe->drm, fini_lmtt, lmtt);
190
191 fail:
192 lmtt->ops = NULL;
193 return err;
194 }
195
lmtt_setup_dir_ptr(struct xe_lmtt * lmtt)196 static void lmtt_setup_dir_ptr(struct xe_lmtt *lmtt)
197 {
198 struct xe_tile *tile = lmtt_to_tile(lmtt);
199 struct xe_device *xe = tile_to_xe(tile);
200 dma_addr_t offset = xe_bo_main_addr(lmtt->pd->bo, XE_PAGE_SIZE);
201 struct xe_gt *gt;
202 u32 config;
203 u8 id;
204
205 lmtt_debug(lmtt, "DIR offset %pad\n", &offset);
206 lmtt_assert(lmtt, xe_bo_is_vram(lmtt->pd->bo));
207 lmtt_assert(lmtt, IS_ALIGNED(offset, SZ_64K));
208
209 config = LMEM_EN | REG_FIELD_PREP(LMTT_DIR_PTR, offset / SZ_64K);
210
211 for_each_gt_on_tile(gt, tile, id)
212 xe_mmio_write32(>->mmio,
213 GRAPHICS_VER(xe) >= 20 ? XE2_LMEM_CFG : LMEM_CFG,
214 config);
215
216 if (xe_device_has_mert(xe) && xe_tile_is_root(tile))
217 xe_mmio_write32(&tile->mmio, MERT_LMEM_CFG, config);
218 }
219
220 /**
221 * xe_lmtt_init_hw - Perform LMTT hardware initialization.
222 * @lmtt: the &xe_lmtt to initialize
223 *
224 * This function is a second step of the LMTT initialization.
225 * This function registers LMTT Root Directory prepared in xe_lmtt_init().
226 *
227 * This function shall be called after every hardware reset.
228 * This function shall be called only when running as a PF driver.
229 */
xe_lmtt_init_hw(struct xe_lmtt * lmtt)230 void xe_lmtt_init_hw(struct xe_lmtt *lmtt)
231 {
232 if (!lmtt->pd)
233 return;
234
235 lmtt_setup_dir_ptr(lmtt);
236 }
237
lmtt_invalidate_hw(struct xe_lmtt * lmtt)238 static int lmtt_invalidate_hw(struct xe_lmtt *lmtt)
239 {
240 struct xe_tlb_inval_fence fences[XE_MAX_GT_PER_TILE];
241 struct xe_tlb_inval_fence *fence = fences;
242 struct xe_tile *tile = lmtt_to_tile(lmtt);
243 struct xe_gt *gt;
244 int result = 0;
245 int err;
246 u8 id;
247
248 for_each_gt_on_tile(gt, tile, id) {
249 xe_tlb_inval_fence_init(>->tlb_inval, fence, true);
250 err = xe_tlb_inval_all(>->tlb_inval, fence);
251 result = result ?: err;
252 fence++;
253 }
254
255 lmtt_debug(lmtt, "num_fences=%d err=%d\n", (int)(fence - fences), result);
256
257 /*
258 * It is fine to wait for all fences, even for those which covers the
259 * invalidation request that failed, as such fence should be already
260 * marked as signaled.
261 */
262 fence = fences;
263 for_each_gt_on_tile(gt, tile, id)
264 xe_tlb_inval_fence_wait(fence++);
265
266 return result;
267 }
268
269 /**
270 * xe_lmtt_invalidate_hw - Invalidate LMTT hardware.
271 * @lmtt: the &xe_lmtt to invalidate
272 *
273 * Send requests to all GuCs on this tile to invalidate all TLBs.
274 * If the platform has a standalone MERT, also invalidate MERT's TLB.
275 *
276 * This function should be called only when running as a PF driver.
277 */
xe_lmtt_invalidate_hw(struct xe_lmtt * lmtt)278 void xe_lmtt_invalidate_hw(struct xe_lmtt *lmtt)
279 {
280 struct xe_tile *tile = lmtt_to_tile(lmtt);
281 struct xe_device *xe = lmtt_to_xe(lmtt);
282 int err;
283
284 lmtt_assert(lmtt, IS_SRIOV_PF(xe));
285
286 err = lmtt_invalidate_hw(lmtt);
287 if (err)
288 xe_tile_sriov_err(tile, "LMTT invalidation failed (%pe)",
289 ERR_PTR(err));
290
291 if (xe_device_has_mert(xe) && xe_tile_is_root(tile)) {
292 err = xe_mert_invalidate_lmtt(xe);
293 if (err)
294 xe_tile_sriov_err(tile, "MERT LMTT invalidation failed (%pe)",
295 ERR_PTR(err));
296 }
297 }
298
lmtt_write_pte(struct xe_lmtt * lmtt,struct xe_lmtt_pt * pt,u64 pte,unsigned int idx)299 static void lmtt_write_pte(struct xe_lmtt *lmtt, struct xe_lmtt_pt *pt,
300 u64 pte, unsigned int idx)
301 {
302 unsigned int level = pt->level;
303
304 lmtt_assert(lmtt, idx <= lmtt->ops->lmtt_pte_num(level));
305 lmtt_debug(lmtt, "WRITE level=%u index=%u pte=%#llx\n", level, idx, pte);
306
307 switch (lmtt->ops->lmtt_pte_size(level)) {
308 case sizeof(u32):
309 lmtt_assert(lmtt, !overflows_type(pte, u32));
310 lmtt_assert(lmtt, !pte || !iosys_map_rd(&pt->bo->vmap, idx * sizeof(u32), u32));
311
312 xe_map_wr(lmtt_to_xe(lmtt), &pt->bo->vmap, idx * sizeof(u32), u32, pte);
313 break;
314 case sizeof(u64):
315 lmtt_assert(lmtt, !pte || !iosys_map_rd(&pt->bo->vmap, idx * sizeof(u64), u64));
316
317 xe_map_wr(lmtt_to_xe(lmtt), &pt->bo->vmap, idx * sizeof(u64), u64, pte);
318 break;
319 default:
320 lmtt_assert(lmtt, !!!"invalid pte size");
321 }
322 }
323
lmtt_destroy_pt(struct xe_lmtt * lmtt,struct xe_lmtt_pt * pd)324 static void lmtt_destroy_pt(struct xe_lmtt *lmtt, struct xe_lmtt_pt *pd)
325 {
326 unsigned int num_entries = pd->level ? lmtt->ops->lmtt_pte_num(pd->level) : 0;
327 struct xe_lmtt_pt *pt;
328 unsigned int i;
329
330 for (i = 0; i < num_entries; i++) {
331 pt = pd->entries[i];
332 pd->entries[i] = NULL;
333 if (!pt)
334 continue;
335
336 lmtt_destroy_pt(lmtt, pt);
337 }
338
339 lmtt_pt_free(pd);
340 }
341
lmtt_drop_pages(struct xe_lmtt * lmtt,unsigned int vfid)342 static void lmtt_drop_pages(struct xe_lmtt *lmtt, unsigned int vfid)
343 {
344 struct xe_lmtt_pt *pd = lmtt->pd;
345 struct xe_lmtt_pt *pt;
346
347 pt = pd->entries[vfid];
348 pd->entries[vfid] = NULL;
349 if (!pt)
350 return;
351
352 lmtt_write_pte(lmtt, pd, LMTT_PTE_INVALID, vfid);
353 lmtt_invalidate_hw(lmtt);
354
355 lmtt_assert(lmtt, pd->level > 0);
356 lmtt_assert(lmtt, pt->level == pd->level - 1);
357 lmtt_destroy_pt(lmtt, pt);
358 }
359
__lmtt_alloc_range(struct xe_lmtt * lmtt,struct xe_lmtt_pt * pd,u64 start,u64 end)360 static int __lmtt_alloc_range(struct xe_lmtt *lmtt, struct xe_lmtt_pt *pd,
361 u64 start, u64 end)
362 {
363 u64 pte_addr_shift = BIT_ULL(lmtt->ops->lmtt_pte_shift(pd->level));
364 u64 offset;
365 int err;
366
367 lmtt_assert(lmtt, pd->level > 0);
368
369 offset = start;
370 while (offset < end) {
371 struct xe_lmtt_pt *pt;
372 u64 next, pde, pt_addr;
373 unsigned int idx;
374
375 pt = lmtt_pt_alloc(lmtt, pd->level - 1);
376 if (IS_ERR(pt))
377 return PTR_ERR(pt);
378
379 pt_addr = xe_bo_main_addr(pt->bo, XE_PAGE_SIZE);
380
381 idx = lmtt->ops->lmtt_pte_index(offset, pd->level);
382 pde = lmtt->ops->lmtt_pte_encode(pt_addr, pd->level);
383
384 lmtt_write_pte(lmtt, pd, pde, idx);
385
386 pd->entries[idx] = pt;
387
388 next = min(end, round_up(offset + 1, pte_addr_shift));
389
390 if (pt->level != 0) {
391 err = __lmtt_alloc_range(lmtt, pt, offset, next);
392 if (err)
393 return err;
394 }
395
396 offset = next;
397 }
398
399 return 0;
400 }
401
lmtt_alloc_range(struct xe_lmtt * lmtt,unsigned int vfid,u64 start,u64 end)402 static int lmtt_alloc_range(struct xe_lmtt *lmtt, unsigned int vfid, u64 start, u64 end)
403 {
404 struct xe_lmtt_pt *pd = lmtt->pd;
405 struct xe_lmtt_pt *pt;
406 u64 pt_addr;
407 u64 pde;
408 int err;
409
410 lmtt_assert(lmtt, pd->level > 0);
411 lmtt_assert(lmtt, vfid <= lmtt->ops->lmtt_pte_num(pd->level));
412 lmtt_assert(lmtt, IS_ALIGNED(start, lmtt_page_size(lmtt)));
413 lmtt_assert(lmtt, IS_ALIGNED(end, lmtt_page_size(lmtt)));
414
415 if (pd->entries[vfid])
416 return -ENOTEMPTY;
417
418 pt = lmtt_pt_alloc(lmtt, pd->level - 1);
419 if (IS_ERR(pt))
420 return PTR_ERR(pt);
421
422 pt_addr = xe_bo_main_addr(pt->bo, XE_PAGE_SIZE);
423
424 pde = lmtt->ops->lmtt_pte_encode(pt_addr, pd->level);
425
426 lmtt_write_pte(lmtt, pd, pde, vfid);
427
428 pd->entries[vfid] = pt;
429
430 if (pt->level != 0) {
431 err = __lmtt_alloc_range(lmtt, pt, start, end);
432 if (err)
433 goto out_free_pt;
434 }
435
436 return 0;
437
438 out_free_pt:
439 lmtt_pt_free(pt);
440 return err;
441 }
442
lmtt_leaf_pt(struct xe_lmtt * lmtt,unsigned int vfid,u64 addr)443 static struct xe_lmtt_pt *lmtt_leaf_pt(struct xe_lmtt *lmtt, unsigned int vfid, u64 addr)
444 {
445 struct xe_lmtt_pt *pd = lmtt->pd;
446 struct xe_lmtt_pt *pt;
447
448 lmtt_assert(lmtt, vfid <= lmtt->ops->lmtt_pte_num(pd->level));
449 pt = pd->entries[vfid];
450
451 while (pt->level) {
452 lmtt_assert(lmtt, lmtt->ops->lmtt_pte_index(addr, pt->level) <=
453 lmtt->ops->lmtt_pte_num(pt->level));
454
455 pt = pt->entries[lmtt->ops->lmtt_pte_index(addr, pt->level)];
456
457 addr >>= lmtt->ops->lmtt_pte_shift(pt->level);
458 }
459
460 lmtt_assert(lmtt, lmtt->ops->lmtt_pte_index(addr, pt->level) <=
461 lmtt->ops->lmtt_pte_num(pt->level));
462 lmtt_assert(lmtt, pt->level != pd->level);
463 lmtt_assert(lmtt, pt->level == 0);
464 return pt;
465 }
466
lmtt_insert_bo(struct xe_lmtt * lmtt,unsigned int vfid,struct xe_bo * bo,u64 start)467 static void lmtt_insert_bo(struct xe_lmtt *lmtt, unsigned int vfid, struct xe_bo *bo, u64 start)
468 {
469 u64 page_size = lmtt_page_size(lmtt);
470 struct xe_res_cursor cur;
471 struct xe_lmtt_pt *pt;
472 u64 addr, vram_offset;
473
474 lmtt_assert(lmtt, IS_ALIGNED(start, page_size));
475 lmtt_assert(lmtt, IS_ALIGNED(xe_bo_size(bo), page_size));
476 lmtt_assert(lmtt, xe_bo_is_vram(bo));
477
478 vram_offset = vram_region_gpu_offset(bo->ttm.resource);
479 xe_res_first(bo->ttm.resource, 0, xe_bo_size(bo), &cur);
480 while (cur.remaining) {
481 addr = xe_res_dma(&cur);
482 addr += vram_offset; /* XXX */
483
484 pt = lmtt_leaf_pt(lmtt, vfid, start);
485
486 lmtt_write_pte(lmtt, pt, lmtt->ops->lmtt_pte_encode(addr, 0),
487 lmtt->ops->lmtt_pte_index(start, 0));
488
489 xe_res_next(&cur, page_size);
490 start += page_size;
491 }
492 }
493
494 /**
495 * xe_lmtt_prepare_pages - Create VF's LMTT Page Tables.
496 * @lmtt: the &xe_lmtt to update
497 * @vfid: the VF identifier (1-based)
498 * @range: top range of LMEM offset to be supported
499 *
500 * This function creates empty LMTT page tables for given VF to support
501 * up to maximum #range LMEM offset. The LMTT page tables created by this
502 * function must be released using xe_lmtt_drop_pages() function.
503 *
504 * Notes:
505 * This function shall be called only after successful LMTT initialization.
506 * See xe_lmtt_init().
507 *
508 * Return: 0 on success or a negative error code on failure.
509 */
xe_lmtt_prepare_pages(struct xe_lmtt * lmtt,unsigned int vfid,u64 range)510 int xe_lmtt_prepare_pages(struct xe_lmtt *lmtt, unsigned int vfid, u64 range)
511 {
512 lmtt_assert(lmtt, lmtt->pd);
513 lmtt_assert(lmtt, vfid);
514
515 return lmtt_alloc_range(lmtt, vfid, 0, range);
516 }
517
518 /**
519 * xe_lmtt_populate_pages - Update VF's LMTT Page Table Entries.
520 * @lmtt: the &xe_lmtt to update
521 * @vfid: the VF identifier (1-based)
522 * @bo: the buffer object with LMEM allocation to be mapped
523 * @offset: the offset at which #bo should be mapped
524 *
525 * This function updates VF's LMTT entries to use given buffer object as a backstore.
526 *
527 * Notes:
528 * This function shall be called only after successful preparation of the
529 * VF's LMTT Page Tables. See xe_lmtt_prepare().
530 *
531 * Return: 0 on success or a negative error code on failure.
532 */
xe_lmtt_populate_pages(struct xe_lmtt * lmtt,unsigned int vfid,struct xe_bo * bo,u64 offset)533 int xe_lmtt_populate_pages(struct xe_lmtt *lmtt, unsigned int vfid, struct xe_bo *bo, u64 offset)
534 {
535 lmtt_assert(lmtt, lmtt->pd);
536 lmtt_assert(lmtt, vfid);
537
538 lmtt_insert_bo(lmtt, vfid, bo, offset);
539 return 0;
540 }
541
542 /**
543 * xe_lmtt_drop_pages - Remove VF's LMTT Pages.
544 * @lmtt: the &xe_lmtt to update
545 * @vfid: the VF identifier (1-based)
546 *
547 * This function removes all LMTT Page Tables prepared by xe_lmtt_prepare_pages().
548 *
549 * This function shall be called only after successful LMTT initialization.
550 * See xe_lmtt_init().
551 */
xe_lmtt_drop_pages(struct xe_lmtt * lmtt,unsigned int vfid)552 void xe_lmtt_drop_pages(struct xe_lmtt *lmtt, unsigned int vfid)
553 {
554 lmtt_assert(lmtt, lmtt->pd);
555 lmtt_assert(lmtt, vfid);
556
557 lmtt_drop_pages(lmtt, vfid);
558 }
559
560 /**
561 * xe_lmtt_estimate_pt_size - Estimate size of LMTT PT allocations.
562 * @lmtt: the &xe_lmtt
563 * @size: the size of the LMEM to be mapped over LMTT (including any offset)
564 *
565 * This function shall be called only by PF.
566 *
567 * Return: size of the PT allocation(s) needed to support given LMEM size.
568 */
xe_lmtt_estimate_pt_size(struct xe_lmtt * lmtt,u64 size)569 u64 xe_lmtt_estimate_pt_size(struct xe_lmtt *lmtt, u64 size)
570 {
571 unsigned int level = 0;
572 u64 pt_size;
573
574 lmtt_assert(lmtt, IS_SRIOV_PF(lmtt_to_xe(lmtt)));
575 lmtt_assert(lmtt, xe_device_has_lmtt(lmtt_to_xe(lmtt)));
576 lmtt_assert(lmtt, lmtt->ops);
577
578 pt_size = PAGE_ALIGN(lmtt->ops->lmtt_pte_size(level) *
579 lmtt->ops->lmtt_pte_num(level));
580
581 while (++level < lmtt->ops->lmtt_root_pd_level()) {
582 pt_size *= lmtt->ops->lmtt_pte_index(size, level) + 1;
583 pt_size += PAGE_ALIGN(lmtt->ops->lmtt_pte_size(level) *
584 lmtt->ops->lmtt_pte_num(level));
585 }
586
587 return pt_size;
588 }
589
590 #if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
591 #include "tests/xe_lmtt_test.c"
592 #endif
593