gen8_ppgtt.c 26.4 KB
Newer Older
1 2 3 4 5 6 7
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2020 Intel Corporation
 */

#include <linux/log2.h>

8 9
#include "gem/i915_gem_lmem.h"

10 11 12
#include "gen8_ppgtt.h"
#include "i915_scatterlist.h"
#include "i915_trace.h"
13
#include "i915_pvinfo.h"
14 15 16 17 18 19 20
#include "i915_vgpu.h"
#include "intel_gt.h"
#include "intel_gtt.h"

static u64 gen8_pde_encode(const dma_addr_t addr,
			   const enum i915_cache_level level)
{
21
	u64 pde = addr | GEN8_PAGE_PRESENT | GEN8_PAGE_RW;
22 23 24 25 26 27 28 29 30

	if (level != I915_CACHE_NONE)
		pde |= PPAT_CACHED_PDE;
	else
		pde |= PPAT_UNCACHED;

	return pde;
}

31
static u64 gen8_pte_encode(dma_addr_t addr,
32
			   unsigned int pat_index,
33 34
			   u32 flags)
{
35
	gen8_pte_t pte = addr | GEN8_PAGE_PRESENT | GEN8_PAGE_RW;
36 37

	if (unlikely(flags & PTE_READ_ONLY))
38
		pte &= ~GEN8_PAGE_RW;
39

40 41 42
	if (flags & PTE_LM)
		pte |= GEN12_PPGTT_PTE_LM;

43 44 45 46 47 48
	/*
	 * For pre-gen12 platforms pat_index is the same as enum
	 * i915_cache_level, so the switch-case here is still valid.
	 * See translation table defined by LEGACY_CACHELEVEL.
	 */
	switch (pat_index) {
49 50 51 52 53 54 55 56 57 58 59 60 61 62
	case I915_CACHE_NONE:
		pte |= PPAT_UNCACHED;
		break;
	case I915_CACHE_WT:
		pte |= PPAT_DISPLAY_ELLC;
		break;
	default:
		pte |= PPAT_CACHED;
		break;
	}

	return pte;
}

63 64 65
static u64 gen12_pte_encode(dma_addr_t addr,
			    unsigned int pat_index,
			    u32 flags)
66 67 68 69 70 71 72 73 74
{
	gen8_pte_t pte = addr | GEN8_PAGE_PRESENT | GEN8_PAGE_RW;

	if (unlikely(flags & PTE_READ_ONLY))
		pte &= ~GEN8_PAGE_RW;

	if (flags & PTE_LM)
		pte |= GEN12_PPGTT_PTE_LM;

75
	if (pat_index & BIT(0))
76
		pte |= GEN12_PPGTT_PTE_PAT0;
77 78 79 80 81 82 83 84 85

	if (pat_index & BIT(1))
		pte |= GEN12_PPGTT_PTE_PAT1;

	if (pat_index & BIT(2))
		pte |= GEN12_PPGTT_PTE_PAT2;

	if (pat_index & BIT(3))
		pte |= MTL_PPGTT_PTE_PAT3;
86 87 88 89

	return pte;
}

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
static void gen8_ppgtt_notify_vgt(struct i915_ppgtt *ppgtt, bool create)
{
	struct drm_i915_private *i915 = ppgtt->vm.i915;
	struct intel_uncore *uncore = ppgtt->vm.gt->uncore;
	enum vgt_g2v_type msg;
	int i;

	if (create)
		atomic_inc(px_used(ppgtt->pd)); /* never remove */
	else
		atomic_dec(px_used(ppgtt->pd));

	mutex_lock(&i915->vgpu.lock);

	if (i915_vm_is_4lvl(&ppgtt->vm)) {
		const u64 daddr = px_dma(ppgtt->pd);

		intel_uncore_write(uncore,
				   vgtif_reg(pdp[0].lo), lower_32_bits(daddr));
		intel_uncore_write(uncore,
				   vgtif_reg(pdp[0].hi), upper_32_bits(daddr));

		msg = create ?
			VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
			VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY;
	} else {
		for (i = 0; i < GEN8_3LVL_PDPES; i++) {
			const u64 daddr = i915_page_dir_dma_addr(ppgtt, i);

			intel_uncore_write(uncore,
					   vgtif_reg(pdp[i].lo),
					   lower_32_bits(daddr));
			intel_uncore_write(uncore,
					   vgtif_reg(pdp[i].hi),
					   upper_32_bits(daddr));
		}

		msg = create ?
			VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
			VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY;
	}

	/* g2v_notify atomically (via hv trap) consumes the message packet. */
	intel_uncore_write(uncore, vgtif_reg(g2v_notify), msg);

	mutex_unlock(&i915->vgpu.lock);
}

/* Index shifts into the pagetable are offset by GEN8_PTE_SHIFT [12] */
#define GEN8_PAGE_SIZE (SZ_4K) /* page and page-directory sizes are the same */
#define GEN8_PTE_SHIFT (ilog2(GEN8_PAGE_SIZE))
#define GEN8_PDES (GEN8_PAGE_SIZE / sizeof(u64))
#define gen8_pd_shift(lvl) ((lvl) * ilog2(GEN8_PDES))
#define gen8_pd_index(i, lvl) i915_pde_index((i), gen8_pd_shift(lvl))
#define __gen8_pte_shift(lvl) (GEN8_PTE_SHIFT + gen8_pd_shift(lvl))
#define __gen8_pte_index(a, lvl) i915_pde_index((a), __gen8_pte_shift(lvl))

#define as_pd(x) container_of((x), typeof(struct i915_page_directory), pt)

Chris Wilson's avatar
Chris Wilson committed
149
static unsigned int
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
gen8_pd_range(u64 start, u64 end, int lvl, unsigned int *idx)
{
	const int shift = gen8_pd_shift(lvl);
	const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);

	GEM_BUG_ON(start >= end);
	end += ~mask >> gen8_pd_shift(1);

	*idx = i915_pde_index(start, shift);
	if ((start ^ end) & mask)
		return GEN8_PDES - *idx;
	else
		return i915_pde_index(end, shift) - *idx;
}

Chris Wilson's avatar
Chris Wilson committed
165
static bool gen8_pd_contains(u64 start, u64 end, int lvl)
166 167 168 169 170 171 172
{
	const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);

	GEM_BUG_ON(start >= end);
	return (start ^ end) & mask && (start & ~mask) == 0;
}

Chris Wilson's avatar
Chris Wilson committed
173
static unsigned int gen8_pt_count(u64 start, u64 end)
174 175 176 177 178 179 180 181
{
	GEM_BUG_ON(start >= end);
	if ((start ^ end) >> gen8_pd_shift(1))
		return GEN8_PDES - (start & (GEN8_PDES - 1));
	else
		return end - start;
}

Chris Wilson's avatar
Chris Wilson committed
182
static unsigned int gen8_pd_top_count(const struct i915_address_space *vm)
183 184
{
	unsigned int shift = __gen8_pte_shift(vm->top);
185

186 187 188
	return (vm->total + (1ull << shift) - 1) >> shift;
}

Chris Wilson's avatar
Chris Wilson committed
189
static struct i915_page_directory *
190 191 192 193 194 195 196 197 198 199
gen8_pdp_for_page_index(struct i915_address_space * const vm, const u64 idx)
{
	struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);

	if (vm->top == 2)
		return ppgtt->pd;
	else
		return i915_pd_entry(ppgtt->pd, gen8_pd_index(idx, vm->top));
}

Chris Wilson's avatar
Chris Wilson committed
200
static struct i915_page_directory *
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
gen8_pdp_for_page_address(struct i915_address_space * const vm, const u64 addr)
{
	return gen8_pdp_for_page_index(vm, addr >> GEN8_PTE_SHIFT);
}

static void __gen8_ppgtt_cleanup(struct i915_address_space *vm,
				 struct i915_page_directory *pd,
				 int count, int lvl)
{
	if (lvl) {
		void **pde = pd->entry;

		do {
			if (!*pde)
				continue;

			__gen8_ppgtt_cleanup(vm, *pde, GEN8_PDES, lvl - 1);
		} while (pde++, --count);
	}

221
	free_px(vm, &pd->pt, lvl);
222 223 224 225 226 227 228 229 230
}

static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
{
	struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);

	if (intel_vgpu_active(vm->i915))
		gen8_ppgtt_notify_vgt(ppgtt, false);

231 232 233 234
	if (ppgtt->pd)
		__gen8_ppgtt_cleanup(vm, ppgtt->pd,
				     gen8_pd_top_count(vm), vm->top);

235 236 237 238 239 240 241
	free_scratch(vm);
}

static u64 __gen8_ppgtt_clear(struct i915_address_space * const vm,
			      struct i915_page_directory * const pd,
			      u64 start, const u64 end, int lvl)
{
242
	const struct drm_i915_gem_object * const scratch = vm->scratch[lvl];
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
	unsigned int idx, len;

	GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);

	len = gen8_pd_range(start, end, lvl--, &idx);
	DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
	    __func__, vm, lvl + 1, start, end,
	    idx, len, atomic_read(px_used(pd)));
	GEM_BUG_ON(!len || len >= atomic_read(px_used(pd)));

	do {
		struct i915_page_table *pt = pd->entry[idx];

		if (atomic_fetch_inc(&pt->used) >> gen8_pd_shift(1) &&
		    gen8_pd_contains(start, end, lvl)) {
			DBG("%s(%p):{ lvl:%d, idx:%d, start:%llx, end:%llx } removing pd\n",
			    __func__, vm, lvl + 1, idx, start, end);
			clear_pd_entry(pd, idx, scratch);
			__gen8_ppgtt_cleanup(vm, as_pd(pt), I915_PDES, lvl);
			start += (u64)I915_PDES << gen8_pd_shift(lvl);
			continue;
		}

		if (lvl) {
			start = __gen8_ppgtt_clear(vm, as_pd(pt),
						   start, end, lvl);
		} else {
			unsigned int count;
271 272
			unsigned int pte = gen8_pd_index(start, 0);
			unsigned int num_ptes;
273 274 275 276 277 278 279 280 281
			u64 *vaddr;

			count = gen8_pt_count(start, end);
			DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } removing pte\n",
			    __func__, vm, lvl, start, end,
			    gen8_pd_index(start, 0), count,
			    atomic_read(&pt->used));
			GEM_BUG_ON(!count || count >= atomic_read(&pt->used));

282 283 284 285 286 287 288 289
			num_ptes = count;
			if (pt->is_compact) {
				GEM_BUG_ON(num_ptes % 16);
				GEM_BUG_ON(pte % 16);
				num_ptes /= 16;
				pte /= 16;
			}

290
			vaddr = px_vaddr(pt);
291
			memset64(vaddr + pte,
292
				 vm->scratch[0]->encode,
293
				 num_ptes);
294 295 296 297 298 299

			atomic_sub(count, &pt->used);
			start += count;
		}

		if (release_pd_entry(pd, idx, pt, scratch))
300
			free_px(vm, pt, lvl);
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	} while (idx++, --len);

	return start;
}

static void gen8_ppgtt_clear(struct i915_address_space *vm,
			     u64 start, u64 length)
{
	GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
	GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
	GEM_BUG_ON(range_overflows(start, length, vm->total));

	start >>= GEN8_PTE_SHIFT;
	length >>= GEN8_PTE_SHIFT;
	GEM_BUG_ON(length == 0);

	__gen8_ppgtt_clear(vm, i915_vm_to_ppgtt(vm)->pd,
			   start, start + length, vm->top);
}

321 322 323 324
static void __gen8_ppgtt_alloc(struct i915_address_space * const vm,
			       struct i915_vm_pt_stash *stash,
			       struct i915_page_directory * const pd,
			       u64 * const start, const u64 end, int lvl)
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
{
	unsigned int idx, len;

	GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);

	len = gen8_pd_range(*start, end, lvl--, &idx);
	DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
	    __func__, vm, lvl + 1, *start, end,
	    idx, len, atomic_read(px_used(pd)));
	GEM_BUG_ON(!len || (idx + len - 1) >> gen8_pd_shift(1));

	spin_lock(&pd->lock);
	GEM_BUG_ON(!atomic_read(px_used(pd))); /* Must be pinned! */
	do {
		struct i915_page_table *pt = pd->entry[idx];

		if (!pt) {
			spin_unlock(&pd->lock);

			DBG("%s(%p):{ lvl:%d, idx:%d } allocating new tree\n",
			    __func__, vm, lvl + 1, idx);

347
			pt = stash->pt[!!lvl];
348
			__i915_gem_object_pin_pages(pt->base);
349

350
			fill_px(pt, vm->scratch[lvl]->encode);
351 352

			spin_lock(&pd->lock);
353 354 355
			if (likely(!pd->entry[idx])) {
				stash->pt[!!lvl] = pt->stash;
				atomic_set(&pt->used, 0);
356
				set_pd_entry(pd, idx, pt);
357 358 359
			} else {
				pt = pd->entry[idx];
			}
360 361 362 363 364 365
		}

		if (lvl) {
			atomic_inc(&pt->used);
			spin_unlock(&pd->lock);

366 367
			__gen8_ppgtt_alloc(vm, stash,
					   as_pd(pt), start, end, lvl);
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

			spin_lock(&pd->lock);
			atomic_dec(&pt->used);
			GEM_BUG_ON(!atomic_read(&pt->used));
		} else {
			unsigned int count = gen8_pt_count(*start, end);

			DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } inserting pte\n",
			    __func__, vm, lvl, *start, end,
			    gen8_pd_index(*start, 0), count,
			    atomic_read(&pt->used));

			atomic_add(count, &pt->used);
			/* All other pdes may be simultaneously removed */
			GEM_BUG_ON(atomic_read(&pt->used) > NALLOC * I915_PDES);
			*start += count;
		}
	} while (idx++, --len);
	spin_unlock(&pd->lock);
}

389 390 391
static void gen8_ppgtt_alloc(struct i915_address_space *vm,
			     struct i915_vm_pt_stash *stash,
			     u64 start, u64 length)
392 393 394 395 396 397 398 399 400
{
	GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
	GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
	GEM_BUG_ON(range_overflows(start, length, vm->total));

	start >>= GEN8_PTE_SHIFT;
	length >>= GEN8_PTE_SHIFT;
	GEM_BUG_ON(length == 0);

401 402
	__gen8_ppgtt_alloc(vm, stash, i915_vm_to_ppgtt(vm)->pd,
			   &start, start + length, vm->top);
403 404
}

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
static void __gen8_ppgtt_foreach(struct i915_address_space *vm,
				 struct i915_page_directory *pd,
				 u64 *start, u64 end, int lvl,
				 void (*fn)(struct i915_address_space *vm,
					    struct i915_page_table *pt,
					    void *data),
				 void *data)
{
	unsigned int idx, len;

	len = gen8_pd_range(*start, end, lvl--, &idx);

	spin_lock(&pd->lock);
	do {
		struct i915_page_table *pt = pd->entry[idx];

		atomic_inc(&pt->used);
		spin_unlock(&pd->lock);

		if (lvl) {
			__gen8_ppgtt_foreach(vm, as_pd(pt), start, end, lvl,
					     fn, data);
		} else {
			fn(vm, pt, data);
			*start += gen8_pt_count(*start, end);
		}

		spin_lock(&pd->lock);
		atomic_dec(&pt->used);
	} while (idx++, --len);
	spin_unlock(&pd->lock);
}

static void gen8_ppgtt_foreach(struct i915_address_space *vm,
			       u64 start, u64 length,
			       void (*fn)(struct i915_address_space *vm,
					  struct i915_page_table *pt,
					  void *data),
			       void *data)
{
	start >>= GEN8_PTE_SHIFT;
	length >>= GEN8_PTE_SHIFT;

	__gen8_ppgtt_foreach(vm, i915_vm_to_ppgtt(vm)->pd,
			     &start, start + length, vm->top,
			     fn, data);
}

453 454 455 456 457
static __always_inline u64
gen8_ppgtt_insert_pte(struct i915_ppgtt *ppgtt,
		      struct i915_page_directory *pdp,
		      struct sgt_dma *iter,
		      u64 idx,
458
		      unsigned int pat_index,
459 460 461
		      u32 flags)
{
	struct i915_page_directory *pd;
462
	const gen8_pte_t pte_encode = ppgtt->vm.pte_encode(0, pat_index, flags);
463 464 465
	gen8_pte_t *vaddr;

	pd = i915_pd_entry(pdp, gen8_pd_index(idx, 2));
466
	vaddr = px_vaddr(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
467
	do {
468
		GEM_BUG_ON(sg_dma_len(iter->sg) < I915_GTT_PAGE_SIZE);
469
		vaddr[gen8_pd_index(idx, 0)] = pte_encode | iter->dma;
470 471 472 473

		iter->dma += I915_GTT_PAGE_SIZE;
		if (iter->dma >= iter->max) {
			iter->sg = __sg_next(iter->sg);
474
			if (!iter->sg || sg_dma_len(iter->sg) == 0) {
475 476 477 478 479
				idx = 0;
				break;
			}

			iter->dma = sg_dma_address(iter->sg);
480
			iter->max = iter->dma + sg_dma_len(iter->sg);
481 482 483 484 485 486 487 488 489 490 491
		}

		if (gen8_pd_index(++idx, 0) == 0) {
			if (gen8_pd_index(idx, 1) == 0) {
				/* Limited by sg length for 3lvl */
				if (gen8_pd_index(idx, 2) == 0)
					break;

				pd = pdp->entry[gen8_pd_index(idx, 2)];
			}

492
			drm_clflush_virt_range(vaddr, PAGE_SIZE);
493
			vaddr = px_vaddr(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
494 495
		}
	} while (1);
496
	drm_clflush_virt_range(vaddr, PAGE_SIZE);
497 498 499 500

	return idx;
}

501 502 503 504
static void
xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm,
			  struct i915_vma_resource *vma_res,
			  struct sgt_dma *iter,
505
			  unsigned int pat_index,
506 507
			  u32 flags)
{
508
	const gen8_pte_t pte_encode = vm->pte_encode(0, pat_index, flags);
509 510
	unsigned int rem = sg_dma_len(iter->sg);
	u64 start = vma_res->start;
511
	u64 end = start + vma_res->vma_size;
512 513 514 515 516 517 518 519 520 521 522 523 524

	GEM_BUG_ON(!i915_vm_is_4lvl(vm));

	do {
		struct i915_page_directory * const pdp =
			gen8_pdp_for_page_address(vm, start);
		struct i915_page_directory * const pd =
			i915_pd_entry(pdp, __gen8_pte_index(start, 2));
		struct i915_page_table *pt =
			i915_pt_entry(pd, __gen8_pte_index(start, 1));
		gen8_pte_t encode = pte_encode;
		unsigned int page_size;
		gen8_pte_t *vaddr;
525
		u16 index, max, nent, i;
526 527

		max = I915_PDES;
528
		nent = 1;
529 530 531 532 533 534 535 536 537 538 539

		if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
		    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
		    rem >= I915_GTT_PAGE_SIZE_2M &&
		    !__gen8_pte_index(start, 0)) {
			index = __gen8_pte_index(start, 1);
			encode |= GEN8_PDE_PS_2M;
			page_size = I915_GTT_PAGE_SIZE_2M;

			vaddr = px_vaddr(pd);
		} else {
540 541
			index =  __gen8_pte_index(start, 0);
			page_size = I915_GTT_PAGE_SIZE;
542

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
			if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_64K) {
				/*
				 * Device local-memory on these platforms should
				 * always use 64K pages or larger (including GTT
				 * alignment), therefore if we know the whole
				 * page-table needs to be filled we can always
				 * safely use the compact-layout. Otherwise fall
				 * back to the TLB hint with PS64. If this is
				 * system memory we only bother with PS64.
				 */
				if ((encode & GEN12_PPGTT_PTE_LM) &&
				    end - start >= SZ_2M && !index) {
					index = __gen8_pte_index(start, 0) / 16;
					page_size = I915_GTT_PAGE_SIZE_64K;

					max /= 16;

					vaddr = px_vaddr(pd);
					vaddr[__gen8_pte_index(start, 1)] |= GEN12_PDE_64K;

					pt->is_compact = true;
				} else if (IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
					   rem >= I915_GTT_PAGE_SIZE_64K &&
					   !(index % 16)) {
					encode |= GEN12_PTE_PS64;
					page_size = I915_GTT_PAGE_SIZE_64K;
					nent = 16;
				}
571 572 573 574 575 576 577
			}

			vaddr = px_vaddr(pt);
		}

		do {
			GEM_BUG_ON(rem < page_size);
578 579 580 581 582 583

			for (i = 0; i < nent; i++) {
				vaddr[index++] =
					encode | (iter->dma + i *
						  I915_GTT_PAGE_SIZE);
			}
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604

			start += page_size;
			iter->dma += page_size;
			rem -= page_size;
			if (iter->dma >= iter->max) {
				iter->sg = __sg_next(iter->sg);
				if (!iter->sg)
					break;

				rem = sg_dma_len(iter->sg);
				if (!rem)
					break;

				iter->dma = sg_dma_address(iter->sg);
				iter->max = iter->dma + rem;

				if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
					break;
			}
		} while (rem >= page_size && index < max);

605
		drm_clflush_virt_range(vaddr, PAGE_SIZE);
606 607 608 609
		vma_res->page_sizes_gtt |= page_size;
	} while (iter->sg && sg_dma_len(iter->sg));
}

610 611
static void gen8_ppgtt_insert_huge(struct i915_address_space *vm,
				   struct i915_vma_resource *vma_res,
612
				   struct sgt_dma *iter,
613
				   unsigned int pat_index,
614 615
				   u32 flags)
{
616
	const gen8_pte_t pte_encode = vm->pte_encode(0, pat_index, flags);
617
	unsigned int rem = sg_dma_len(iter->sg);
618
	u64 start = vma_res->start;
619

620
	GEM_BUG_ON(!i915_vm_is_4lvl(vm));
621 622 623

	do {
		struct i915_page_directory * const pdp =
624
			gen8_pdp_for_page_address(vm, start);
625 626 627 628 629 630 631 632
		struct i915_page_directory * const pd =
			i915_pd_entry(pdp, __gen8_pte_index(start, 2));
		gen8_pte_t encode = pte_encode;
		unsigned int maybe_64K = -1;
		unsigned int page_size;
		gen8_pte_t *vaddr;
		u16 index;

633
		if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
634 635 636 637 638 639 640
		    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
		    rem >= I915_GTT_PAGE_SIZE_2M &&
		    !__gen8_pte_index(start, 0)) {
			index = __gen8_pte_index(start, 1);
			encode |= GEN8_PDE_PS_2M;
			page_size = I915_GTT_PAGE_SIZE_2M;

641
			vaddr = px_vaddr(pd);
642 643 644 645 646 647 648 649
		} else {
			struct i915_page_table *pt =
				i915_pt_entry(pd, __gen8_pte_index(start, 1));

			index = __gen8_pte_index(start, 0);
			page_size = I915_GTT_PAGE_SIZE;

			if (!index &&
650
			    vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
651 652 653 654 655
			    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
			    (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
			     rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE))
				maybe_64K = __gen8_pte_index(start, 1);

656
			vaddr = px_vaddr(pt);
657 658 659
		}

		do {
660
			GEM_BUG_ON(sg_dma_len(iter->sg) < page_size);
661
			vaddr[index++] = encode | iter->dma;
662 663 664 665 666 667 668 669 670

			start += page_size;
			iter->dma += page_size;
			rem -= page_size;
			if (iter->dma >= iter->max) {
				iter->sg = __sg_next(iter->sg);
				if (!iter->sg)
					break;

671 672 673 674
				rem = sg_dma_len(iter->sg);
				if (!rem)
					break;

675 676 677 678 679 680 681 682 683 684 685 686 687 688
				iter->dma = sg_dma_address(iter->sg);
				iter->max = iter->dma + rem;

				if (maybe_64K != -1 && index < I915_PDES &&
				    !(IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
				      (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
				       rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE)))
					maybe_64K = -1;

				if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
					break;
			}
		} while (rem >= page_size && index < I915_PDES);

689
		drm_clflush_virt_range(vaddr, PAGE_SIZE);
690 691 692 693 694 695 696 697 698

		/*
		 * Is it safe to mark the 2M block as 64K? -- Either we have
		 * filled whole page-table with 64K entries, or filled part of
		 * it and have reached the end of the sg table and we have
		 * enough padding.
		 */
		if (maybe_64K != -1 &&
		    (index == I915_PDES ||
699 700 701
		     (i915_vm_has_scratch_64K(vm) &&
		      !iter->sg && IS_ALIGNED(vma_res->start +
					      vma_res->node_size,
702
					      I915_GTT_PAGE_SIZE_2M)))) {
703
			vaddr = px_vaddr(pd);
704
			vaddr[maybe_64K] |= GEN8_PDE_IPS_64K;
705
			drm_clflush_virt_range(vaddr, PAGE_SIZE);
706 707 708 709 710 711 712 713 714 715 716
			page_size = I915_GTT_PAGE_SIZE_64K;

			/*
			 * We write all 4K page entries, even when using 64K
			 * pages. In order to verify that the HW isn't cheating
			 * by using the 4K PTE instead of the 64K PTE, we want
			 * to remove all the surplus entries. If the HW skipped
			 * the 64K PTE, it will read/write into the scratch page
			 * instead - which we detect as missing results during
			 * selftests.
			 */
717
			if (I915_SELFTEST_ONLY(vm->scrub_64K)) {
718 719
				u16 i;

720
				encode = vm->scratch[0]->encode;
721
				vaddr = px_vaddr(i915_pt_entry(pd, maybe_64K));
722 723 724 725

				for (i = 1; i < index; i += 16)
					memset64(vaddr + i, encode, 15);

726
				drm_clflush_virt_range(vaddr, PAGE_SIZE);
727 728 729
			}
		}

730
		vma_res->page_sizes_gtt |= page_size;
731
	} while (iter->sg && sg_dma_len(iter->sg));
732 733 734
}

static void gen8_ppgtt_insert(struct i915_address_space *vm,
735
			      struct i915_vma_resource *vma_res,
736
			      unsigned int pat_index,
737 738 739
			      u32 flags)
{
	struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
740
	struct sgt_dma iter = sgt_dma(vma_res);
741

742
	if (vma_res->bi.page_sizes.sg > I915_GTT_PAGE_SIZE) {
743
		if (GRAPHICS_VER_FULL(vm->i915) >= IP_VER(12, 50))
744
			xehpsdv_ppgtt_insert_huge(vm, vma_res, &iter, pat_index, flags);
745
		else
746
			gen8_ppgtt_insert_huge(vm, vma_res, &iter, pat_index, flags);
747
	} else  {
748
		u64 idx = vma_res->start >> GEN8_PTE_SHIFT;
749 750 751 752 753 754

		do {
			struct i915_page_directory * const pdp =
				gen8_pdp_for_page_index(vm, idx);

			idx = gen8_ppgtt_insert_pte(ppgtt, pdp, &iter, idx,
755
						    pat_index, flags);
756 757
		} while (idx);

758
		vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
759 760 761
	}
}

762 763 764
static void gen8_ppgtt_insert_entry(struct i915_address_space *vm,
				    dma_addr_t addr,
				    u64 offset,
765
				    unsigned int pat_index,
766 767 768 769 770 771 772
				    u32 flags)
{
	u64 idx = offset >> GEN8_PTE_SHIFT;
	struct i915_page_directory * const pdp =
		gen8_pdp_for_page_index(vm, idx);
	struct i915_page_directory *pd =
		i915_pd_entry(pdp, gen8_pd_index(idx, 2));
773
	struct i915_page_table *pt = i915_pt_entry(pd, gen8_pd_index(idx, 1));
774 775
	gen8_pte_t *vaddr;

776 777 778
	GEM_BUG_ON(pt->is_compact);

	vaddr = px_vaddr(pt);
779
	vaddr[gen8_pd_index(idx, 0)] = vm->pte_encode(addr, pat_index, flags);
780
	drm_clflush_virt_range(&vaddr[gen8_pd_index(idx, 0)], sizeof(*vaddr));
781 782
}

783 784 785
static void __xehpsdv_ppgtt_insert_entry_lm(struct i915_address_space *vm,
					    dma_addr_t addr,
					    u64 offset,
786
					    unsigned int pat_index,
787 788 789 790 791 792 793 794 795 796 797 798 799
					    u32 flags)
{
	u64 idx = offset >> GEN8_PTE_SHIFT;
	struct i915_page_directory * const pdp =
		gen8_pdp_for_page_index(vm, idx);
	struct i915_page_directory *pd =
		i915_pd_entry(pdp, gen8_pd_index(idx, 2));
	struct i915_page_table *pt = i915_pt_entry(pd, gen8_pd_index(idx, 1));
	gen8_pte_t *vaddr;

	GEM_BUG_ON(!IS_ALIGNED(addr, SZ_64K));
	GEM_BUG_ON(!IS_ALIGNED(offset, SZ_64K));

800 801
	/* XXX: we don't strictly need to use this layout */

802 803 804 805 806 807 808
	if (!pt->is_compact) {
		vaddr = px_vaddr(pd);
		vaddr[gen8_pd_index(idx, 1)] |= GEN12_PDE_64K;
		pt->is_compact = true;
	}

	vaddr = px_vaddr(pt);
809
	vaddr[gen8_pd_index(idx, 0) / 16] = vm->pte_encode(addr, pat_index, flags);
810 811 812 813 814
}

static void xehpsdv_ppgtt_insert_entry(struct i915_address_space *vm,
				       dma_addr_t addr,
				       u64 offset,
815
				       unsigned int pat_index,
816 817 818 819
				       u32 flags)
{
	if (flags & PTE_LM)
		return __xehpsdv_ppgtt_insert_entry_lm(vm, addr, offset,
820
						       pat_index, flags);
821

822
	return gen8_ppgtt_insert_entry(vm, addr, offset, pat_index, flags);
823 824
}

825 826
static int gen8_init_scratch(struct i915_address_space *vm)
{
827
	u32 pte_flags;
828 829 830 831 832 833 834 835 836 837 838 839 840
	int ret;
	int i;

	/*
	 * If everybody agrees to not to write into the scratch page,
	 * we can reuse it for all vm, keeping contexts and processes separate.
	 */
	if (vm->has_read_only && vm->gt->vm && !i915_is_ggtt(vm->gt->vm)) {
		struct i915_address_space *clone = vm->gt->vm;

		GEM_BUG_ON(!clone->has_read_only);

		vm->scratch_order = clone->scratch_order;
841 842 843
		for (i = 0; i <= vm->top; i++)
			vm->scratch[i] = i915_gem_object_get(clone->scratch[i]);

844 845 846
		return 0;
	}

847
	ret = setup_scratch_page(vm);
848 849 850
	if (ret)
		return ret;

851 852 853 854
	pte_flags = vm->has_read_only;
	if (i915_gem_object_is_lmem(vm->scratch[0]))
		pte_flags |= PTE_LM;

855
	vm->scratch[0]->encode =
856
		vm->pte_encode(px_dma(vm->scratch[0]),
857 858 859
			       i915_gem_get_pat_index(vm->i915,
						      I915_CACHE_NONE),
			       pte_flags);
860 861

	for (i = 1; i <= vm->top; i++) {
862 863 864
		struct drm_i915_gem_object *obj;

		obj = vm->alloc_pt_dma(vm, I915_GTT_PAGE_SIZE_4K);
865 866
		if (IS_ERR(obj)) {
			ret = PTR_ERR(obj);
867
			goto free_scratch;
868
		}
869

870
		ret = map_pt_dma(vm, obj);
871 872 873 874 875 876
		if (ret) {
			i915_gem_object_put(obj);
			goto free_scratch;
		}

		fill_px(obj, vm->scratch[i - 1]->encode);
877
		obj->encode = gen8_pde_encode(px_dma(obj), I915_CACHE_NONE);
878 879

		vm->scratch[i] = obj;
880 881 882 883 884
	}

	return 0;

free_scratch:
885 886
	while (i--)
		i915_gem_object_put(vm->scratch[i]);
887 888
	vm->scratch[0] = NULL;
	return ret;
889 890 891 892 893 894 895 896 897 898 899 900 901
}

static int gen8_preallocate_top_level_pdp(struct i915_ppgtt *ppgtt)
{
	struct i915_address_space *vm = &ppgtt->vm;
	struct i915_page_directory *pd = ppgtt->pd;
	unsigned int idx;

	GEM_BUG_ON(vm->top != 2);
	GEM_BUG_ON(gen8_pd_top_count(vm) != GEN8_3LVL_PDPES);

	for (idx = 0; idx < GEN8_3LVL_PDPES; idx++) {
		struct i915_page_directory *pde;
902
		int err;
903 904 905 906 907

		pde = alloc_pd(vm);
		if (IS_ERR(pde))
			return PTR_ERR(pde);

908
		err = map_pt_dma(vm, pde->pt.base);
909
		if (err) {
910
			free_pd(vm, pde);
911 912 913 914
			return err;
		}

		fill_px(pde, vm->scratch[1]->encode);
915 916 917 918 919 920 921 922 923 924 925 926 927
		set_pd_entry(pd, idx, pde);
		atomic_inc(px_used(pde)); /* keep pinned */
	}
	wmb();

	return 0;
}

static struct i915_page_directory *
gen8_alloc_top_pd(struct i915_address_space *vm)
{
	const unsigned int count = gen8_pd_top_count(vm);
	struct i915_page_directory *pd;
928
	int err;
929

930
	GEM_BUG_ON(count > I915_PDES);
931

932
	pd = __alloc_pd(count);
933 934 935
	if (unlikely(!pd))
		return ERR_PTR(-ENOMEM);

936 937
	pd->pt.base = vm->alloc_pt_dma(vm, I915_GTT_PAGE_SIZE_4K);
	if (IS_ERR(pd->pt.base)) {
938 939 940
		err = PTR_ERR(pd->pt.base);
		pd->pt.base = NULL;
		goto err_pd;
941 942
	}

943
	err = map_pt_dma(vm, pd->pt.base);
944 945
	if (err)
		goto err_pd;
946 947

	fill_page_dma(px_base(pd), vm->scratch[vm->top]->encode, count);
948 949
	atomic_inc(px_used(pd)); /* mark as pinned */
	return pd;
950 951 952 953

err_pd:
	free_pd(vm, pd);
	return ERR_PTR(err);
954 955 956 957 958 959 960 961 962
}

/*
 * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
 * with a net effect resembling a 2-level page table in normal x86 terms. Each
 * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
 * space.
 *
 */
963 964
struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt,
				     unsigned long lmem_pt_obj_flags)
965
{
966
	struct i915_page_directory *pd;
967 968 969 970 971 972 973
	struct i915_ppgtt *ppgtt;
	int err;

	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
	if (!ppgtt)
		return ERR_PTR(-ENOMEM);

974
	ppgtt_init(ppgtt, gt, lmem_pt_obj_flags);
975
	ppgtt->vm.top = i915_vm_is_4lvl(&ppgtt->vm) ? 3 : 2;
976
	ppgtt->vm.pd_shift = ilog2(SZ_4K * SZ_4K / sizeof(gen8_pte_t));
977 978 979 980 981 982 983 984 985

	/*
	 * From bdw, there is hw support for read-only pages in the PPGTT.
	 *
	 * Gen11 has HSDES#:1807136187 unresolved. Disable ro support
	 * for now.
	 *
	 * Gen12 has inherited the same read-only fault issue from gen11.
	 */
986
	ppgtt->vm.has_read_only = !IS_GRAPHICS_VER(gt->i915, 11, 12);
987

988
	if (HAS_LMEM(gt->i915))
989
		ppgtt->vm.alloc_pt_dma = alloc_pt_lmem;
990
	else
991
		ppgtt->vm.alloc_pt_dma = alloc_pt_dma;
992 993

	/*
994 995 996 997
	 * Using SMEM here instead of LMEM has the advantage of not reserving
	 * high performance memory for a "never" used filler page. It also
	 * removes the device access that would be required to initialise the
	 * scratch page, reducing pressure on an even scarcer resource.
998 999
	 */
	ppgtt->vm.alloc_scratch_dma = alloc_pt_dma;
1000

1001 1002
	if (GRAPHICS_VER(gt->i915) >= 12)
		ppgtt->vm.pte_encode = gen12_pte_encode;
1003 1004
	else
		ppgtt->vm.pte_encode = gen8_pte_encode;
1005 1006 1007

	ppgtt->vm.bind_async_flags = I915_VMA_LOCAL_BIND;
	ppgtt->vm.insert_entries = gen8_ppgtt_insert;
1008 1009 1010 1011
	if (HAS_64K_PAGES(gt->i915))
		ppgtt->vm.insert_page = xehpsdv_ppgtt_insert_entry;
	else
		ppgtt->vm.insert_page = gen8_ppgtt_insert_entry;
1012 1013
	ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc;
	ppgtt->vm.clear_range = gen8_ppgtt_clear;
1014
	ppgtt->vm.foreach = gen8_ppgtt_foreach;
1015
	ppgtt->vm.cleanup = gen8_ppgtt_cleanup;
1016

1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
	err = gen8_init_scratch(&ppgtt->vm);
	if (err)
		goto err_put;

	pd = gen8_alloc_top_pd(&ppgtt->vm);
	if (IS_ERR(pd)) {
		err = PTR_ERR(pd);
		goto err_put;
	}
	ppgtt->pd = pd;

	if (!i915_vm_is_4lvl(&ppgtt->vm)) {
		err = gen8_preallocate_top_level_pdp(ppgtt);
		if (err)
			goto err_put;
	}
1033

1034 1035 1036 1037 1038
	if (intel_vgpu_active(gt->i915))
		gen8_ppgtt_notify_vgt(ppgtt, true);

	return ppgtt;

1039 1040
err_put:
	i915_vm_put(&ppgtt->vm);
1041 1042
	return ERR_PTR(err);
}