xref: /openbmc/linux/drivers/gpu/drm/i915/gt/intel_ggtt.c (revision bc247253)
12c86e55dSMatthew Auld // SPDX-License-Identifier: MIT
22c86e55dSMatthew Auld /*
32c86e55dSMatthew Auld  * Copyright © 2020 Intel Corporation
42c86e55dSMatthew Auld  */
52c86e55dSMatthew Auld 
62c86e55dSMatthew Auld #include <asm/set_memory.h>
78801eb48SChen Zhou #include <asm/smp.h>
89ce07d94SLucas De Marchi #include <linux/types.h>
99ce07d94SLucas De Marchi #include <linux/stop_machine.h>
102c86e55dSMatthew Auld 
1183d2bdb6SJani Nikula #include <drm/i915_drm.h>
129ce07d94SLucas De Marchi #include <drm/intel-gtt.h>
1383d2bdb6SJani Nikula 
14e762bdf5SMatthew Auld #include "gem/i915_gem_lmem.h"
15e762bdf5SMatthew Auld 
169ce07d94SLucas De Marchi #include "intel_ggtt_gmch.h"
172c86e55dSMatthew Auld #include "intel_gt.h"
180d6419e9SMatt Roper #include "intel_gt_regs.h"
196bba2b30SPiotr Piórkowski #include "intel_pci_config.h"
202c86e55dSMatthew Auld #include "i915_drv.h"
211bba7323SPiotr Piórkowski #include "i915_pci.h"
222c86e55dSMatthew Auld #include "i915_scatterlist.h"
23a7f46d5bSTvrtko Ursulin #include "i915_utils.h"
242c86e55dSMatthew Auld #include "i915_vgpu.h"
252c86e55dSMatthew Auld 
262c86e55dSMatthew Auld #include "intel_gtt.h"
2733e7a975SVille Syrjälä #include "gen8_ppgtt.h"
282c86e55dSMatthew Auld 
292ef6efa7SThomas Hellström static inline bool suspend_retains_ptes(struct i915_address_space *vm)
302ef6efa7SThomas Hellström {
312ef6efa7SThomas Hellström 	return GRAPHICS_VER(vm->i915) >= 8 &&
322ef6efa7SThomas Hellström 		!HAS_LMEM(vm->i915) &&
332ef6efa7SThomas Hellström 		vm->is_ggtt;
342ef6efa7SThomas Hellström }
352ef6efa7SThomas Hellström 
362c86e55dSMatthew Auld static void i915_ggtt_color_adjust(const struct drm_mm_node *node,
372c86e55dSMatthew Auld 				   unsigned long color,
382c86e55dSMatthew Auld 				   u64 *start,
392c86e55dSMatthew Auld 				   u64 *end)
402c86e55dSMatthew Auld {
412c86e55dSMatthew Auld 	if (i915_node_color_differs(node, color))
422c86e55dSMatthew Auld 		*start += I915_GTT_PAGE_SIZE;
432c86e55dSMatthew Auld 
442c86e55dSMatthew Auld 	/*
452c86e55dSMatthew Auld 	 * Also leave a space between the unallocated reserved node after the
462c86e55dSMatthew Auld 	 * GTT and any objects within the GTT, i.e. we use the color adjustment
472c86e55dSMatthew Auld 	 * to insert a guard page to prevent prefetches crossing over the
482c86e55dSMatthew Auld 	 * GTT boundary.
492c86e55dSMatthew Auld 	 */
502c86e55dSMatthew Auld 	node = list_next_entry(node, node_list);
512c86e55dSMatthew Auld 	if (node->color != color)
522c86e55dSMatthew Auld 		*end -= I915_GTT_PAGE_SIZE;
532c86e55dSMatthew Auld }
542c86e55dSMatthew Auld 
552c86e55dSMatthew Auld static int ggtt_init_hw(struct i915_ggtt *ggtt)
562c86e55dSMatthew Auld {
572c86e55dSMatthew Auld 	struct drm_i915_private *i915 = ggtt->vm.i915;
582c86e55dSMatthew Auld 
592c86e55dSMatthew Auld 	i915_address_space_init(&ggtt->vm, VM_CLASS_GGTT);
602c86e55dSMatthew Auld 
612c86e55dSMatthew Auld 	ggtt->vm.is_ggtt = true;
622c86e55dSMatthew Auld 
632c86e55dSMatthew Auld 	/* Only VLV supports read-only GGTT mappings */
642c86e55dSMatthew Auld 	ggtt->vm.has_read_only = IS_VALLEYVIEW(i915);
652c86e55dSMatthew Auld 
662c86e55dSMatthew Auld 	if (!HAS_LLC(i915) && !HAS_PPGTT(i915))
672c86e55dSMatthew Auld 		ggtt->vm.mm.color_adjust = i915_ggtt_color_adjust;
682c86e55dSMatthew Auld 
692c86e55dSMatthew Auld 	if (ggtt->mappable_end) {
702c86e55dSMatthew Auld 		if (!io_mapping_init_wc(&ggtt->iomap,
712c86e55dSMatthew Auld 					ggtt->gmadr.start,
722c86e55dSMatthew Auld 					ggtt->mappable_end)) {
732c86e55dSMatthew Auld 			ggtt->vm.cleanup(&ggtt->vm);
742c86e55dSMatthew Auld 			return -EIO;
752c86e55dSMatthew Auld 		}
762c86e55dSMatthew Auld 
772c86e55dSMatthew Auld 		ggtt->mtrr = arch_phys_wc_add(ggtt->gmadr.start,
782c86e55dSMatthew Auld 					      ggtt->mappable_end);
792c86e55dSMatthew Auld 	}
802c86e55dSMatthew Auld 
81f899f786SChris Wilson 	intel_ggtt_init_fences(ggtt);
822c86e55dSMatthew Auld 
832c86e55dSMatthew Auld 	return 0;
842c86e55dSMatthew Auld }
852c86e55dSMatthew Auld 
862c86e55dSMatthew Auld /**
872c86e55dSMatthew Auld  * i915_ggtt_init_hw - Initialize GGTT hardware
882c86e55dSMatthew Auld  * @i915: i915 device
892c86e55dSMatthew Auld  */
902c86e55dSMatthew Auld int i915_ggtt_init_hw(struct drm_i915_private *i915)
912c86e55dSMatthew Auld {
922c86e55dSMatthew Auld 	int ret;
932c86e55dSMatthew Auld 
942c86e55dSMatthew Auld 	/*
952c86e55dSMatthew Auld 	 * Note that we use page colouring to enforce a guard page at the
962c86e55dSMatthew Auld 	 * end of the address space. This is required as the CS may prefetch
972c86e55dSMatthew Auld 	 * beyond the end of the batch buffer, across the page boundary,
982c86e55dSMatthew Auld 	 * and beyond the end of the GTT if we do not provide a guard.
992c86e55dSMatthew Auld 	 */
100848915c3SMichał Winiarski 	ret = ggtt_init_hw(to_gt(i915)->ggtt);
1012c86e55dSMatthew Auld 	if (ret)
1022c86e55dSMatthew Auld 		return ret;
1032c86e55dSMatthew Auld 
1042c86e55dSMatthew Auld 	return 0;
1052c86e55dSMatthew Auld }
1062c86e55dSMatthew Auld 
1072ef6efa7SThomas Hellström /*
1082ef6efa7SThomas Hellström  * Return the value of the last GGTT pte cast to an u64, if
1092ef6efa7SThomas Hellström  * the system is supposed to retain ptes across resume. 0 otherwise.
1102ef6efa7SThomas Hellström  */
1112ef6efa7SThomas Hellström static u64 read_last_pte(struct i915_address_space *vm)
1122ef6efa7SThomas Hellström {
1132ef6efa7SThomas Hellström 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
1142ef6efa7SThomas Hellström 	gen8_pte_t __iomem *ptep;
1152ef6efa7SThomas Hellström 
1162ef6efa7SThomas Hellström 	if (!suspend_retains_ptes(vm))
1172ef6efa7SThomas Hellström 		return 0;
1182ef6efa7SThomas Hellström 
1192ef6efa7SThomas Hellström 	GEM_BUG_ON(GRAPHICS_VER(vm->i915) < 8);
1202ef6efa7SThomas Hellström 	ptep = (typeof(ptep))ggtt->gsm + (ggtt_total_entries(ggtt) - 1);
1212ef6efa7SThomas Hellström 	return readq(ptep);
1222ef6efa7SThomas Hellström }
1232ef6efa7SThomas Hellström 
1248d2f683fSImre Deak /**
1258d2f683fSImre Deak  * i915_ggtt_suspend_vm - Suspend the memory mappings for a GGTT or DPT VM
1268d2f683fSImre Deak  * @vm: The VM to suspend the mappings for
1278d2f683fSImre Deak  *
1288d2f683fSImre Deak  * Suspend the memory mappings for all objects mapped to HW via the GGTT or a
1298d2f683fSImre Deak  * DPT page table.
1308d2f683fSImre Deak  */
1318d2f683fSImre Deak void i915_ggtt_suspend_vm(struct i915_address_space *vm)
1322c86e55dSMatthew Auld {
133bffa18ddSChris Wilson 	struct i915_vma *vma, *vn;
134e1a7ab4fSThomas Hellström 	int save_skip_rewrite;
135e3793468SChris Wilson 
1368d2f683fSImre Deak 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
1378d2f683fSImre Deak 
1380f341974SMaarten Lankhorst retry:
1390f341974SMaarten Lankhorst 	i915_gem_drain_freed_objects(vm->i915);
1400f341974SMaarten Lankhorst 
1418d2f683fSImre Deak 	mutex_lock(&vm->mutex);
142bffa18ddSChris Wilson 
143e1a7ab4fSThomas Hellström 	/*
144e1a7ab4fSThomas Hellström 	 * Skip rewriting PTE on VMA unbind.
145e1a7ab4fSThomas Hellström 	 * FIXME: Use an argument to i915_vma_unbind() instead?
146e1a7ab4fSThomas Hellström 	 */
147e1a7ab4fSThomas Hellström 	save_skip_rewrite = vm->skip_pte_rewrite;
148e1a7ab4fSThomas Hellström 	vm->skip_pte_rewrite = true;
149bffa18ddSChris Wilson 
1508d2f683fSImre Deak 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
1510f341974SMaarten Lankhorst 		struct drm_i915_gem_object *obj = vma->obj;
152e3793468SChris Wilson 
1530f341974SMaarten Lankhorst 		GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
1540f341974SMaarten Lankhorst 
1550f341974SMaarten Lankhorst 		if (i915_vma_is_pinned(vma) || !i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND))
156bffa18ddSChris Wilson 			continue;
157bffa18ddSChris Wilson 
1580f341974SMaarten Lankhorst 		/* unlikely to race when GPU is idle, so no worry about slowpath.. */
1590f341974SMaarten Lankhorst 		if (WARN_ON(!i915_gem_object_trylock(obj, NULL))) {
1600f341974SMaarten Lankhorst 			/*
1610f341974SMaarten Lankhorst 			 * No dead objects should appear here, GPU should be
1620f341974SMaarten Lankhorst 			 * completely idle, and userspace suspended
1630f341974SMaarten Lankhorst 			 */
1640f341974SMaarten Lankhorst 			i915_gem_object_get(obj);
1650f341974SMaarten Lankhorst 
1660f341974SMaarten Lankhorst 			mutex_unlock(&vm->mutex);
1670f341974SMaarten Lankhorst 
1680f341974SMaarten Lankhorst 			i915_gem_object_lock(obj, NULL);
169e1a7ab4fSThomas Hellström 			GEM_WARN_ON(i915_vma_unbind(vma));
1700f341974SMaarten Lankhorst 			i915_gem_object_unlock(obj);
1710f341974SMaarten Lankhorst 			i915_gem_object_put(obj);
172e1a7ab4fSThomas Hellström 
173e1a7ab4fSThomas Hellström 			vm->skip_pte_rewrite = save_skip_rewrite;
1740f341974SMaarten Lankhorst 			goto retry;
1750f341974SMaarten Lankhorst 		}
1760f341974SMaarten Lankhorst 
177bffa18ddSChris Wilson 		if (!i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) {
1780f341974SMaarten Lankhorst 			i915_vma_wait_for_bind(vma);
1790f341974SMaarten Lankhorst 
1802f6b90daSThomas Hellström 			__i915_vma_evict(vma, false);
181bffa18ddSChris Wilson 			drm_mm_remove_node(&vma->node);
182bffa18ddSChris Wilson 		}
1830f341974SMaarten Lankhorst 
1840f341974SMaarten Lankhorst 		i915_gem_object_unlock(obj);
185bffa18ddSChris Wilson 	}
186bffa18ddSChris Wilson 
1872ef6efa7SThomas Hellström 	if (!suspend_retains_ptes(vm))
1888d2f683fSImre Deak 		vm->clear_range(vm, 0, vm->total);
1892ef6efa7SThomas Hellström 	else
1902ef6efa7SThomas Hellström 		i915_vm_to_ggtt(vm)->probed_pte = read_last_pte(vm);
191bffa18ddSChris Wilson 
192e1a7ab4fSThomas Hellström 	vm->skip_pte_rewrite = save_skip_rewrite;
1938d2f683fSImre Deak 
1948d2f683fSImre Deak 	mutex_unlock(&vm->mutex);
1958d2f683fSImre Deak }
1968d2f683fSImre Deak 
1978d2f683fSImre Deak void i915_ggtt_suspend(struct i915_ggtt *ggtt)
1988d2f683fSImre Deak {
1998d2f683fSImre Deak 	i915_ggtt_suspend_vm(&ggtt->vm);
2008d2f683fSImre Deak 	ggtt->invalidate(ggtt);
2012c86e55dSMatthew Auld 
2022c86e55dSMatthew Auld 	intel_gt_check_and_clear_faults(ggtt->vm.gt);
2032c86e55dSMatthew Auld }
2042c86e55dSMatthew Auld 
2052c86e55dSMatthew Auld void gen6_ggtt_invalidate(struct i915_ggtt *ggtt)
2062c86e55dSMatthew Auld {
2072c86e55dSMatthew Auld 	struct intel_uncore *uncore = ggtt->vm.gt->uncore;
2082c86e55dSMatthew Auld 
2092c86e55dSMatthew Auld 	spin_lock_irq(&uncore->lock);
2102c86e55dSMatthew Auld 	intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
2112c86e55dSMatthew Auld 	intel_uncore_read_fw(uncore, GFX_FLSH_CNTL_GEN6);
2122c86e55dSMatthew Auld 	spin_unlock_irq(&uncore->lock);
2132c86e55dSMatthew Auld }
2142c86e55dSMatthew Auld 
2159ce07d94SLucas De Marchi static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt)
2162c86e55dSMatthew Auld {
2172c86e55dSMatthew Auld 	struct intel_uncore *uncore = ggtt->vm.gt->uncore;
2182c86e55dSMatthew Auld 
2192c86e55dSMatthew Auld 	/*
2202c86e55dSMatthew Auld 	 * Note that as an uncached mmio write, this will flush the
2212c86e55dSMatthew Auld 	 * WCB of the writes into the GGTT before it triggers the invalidate.
2222c86e55dSMatthew Auld 	 */
2232c86e55dSMatthew Auld 	intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
2242c86e55dSMatthew Auld }
2252c86e55dSMatthew Auld 
2262c86e55dSMatthew Auld static void guc_ggtt_invalidate(struct i915_ggtt *ggtt)
2272c86e55dSMatthew Auld {
2282c86e55dSMatthew Auld 	struct intel_uncore *uncore = ggtt->vm.gt->uncore;
2292c86e55dSMatthew Auld 	struct drm_i915_private *i915 = ggtt->vm.i915;
2302c86e55dSMatthew Auld 
2312c86e55dSMatthew Auld 	gen8_ggtt_invalidate(ggtt);
2322c86e55dSMatthew Auld 
233c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) >= 12)
2342c86e55dSMatthew Auld 		intel_uncore_write_fw(uncore, GEN12_GUC_TLB_INV_CR,
2352c86e55dSMatthew Auld 				      GEN12_GUC_TLB_INV_CR_INVALIDATE);
2362c86e55dSMatthew Auld 	else
2372c86e55dSMatthew Auld 		intel_uncore_write_fw(uncore, GEN8_GTCR, GEN8_GTCR_INVALIDATE);
2382c86e55dSMatthew Auld }
2392c86e55dSMatthew Auld 
24033e7a975SVille Syrjälä u64 gen8_ggtt_pte_encode(dma_addr_t addr,
24169edc390SDaniele Ceraolo Spurio 			 enum i915_cache_level level,
24269edc390SDaniele Ceraolo Spurio 			 u32 flags)
24369edc390SDaniele Ceraolo Spurio {
2445f978167SMichael Cheng 	gen8_pte_t pte = addr | GEN8_PAGE_PRESENT;
245e762bdf5SMatthew Auld 
246e762bdf5SMatthew Auld 	if (flags & PTE_LM)
247e762bdf5SMatthew Auld 		pte |= GEN12_GGTT_PTE_LM;
248e762bdf5SMatthew Auld 
249e762bdf5SMatthew Auld 	return pte;
25069edc390SDaniele Ceraolo Spurio }
25169edc390SDaniele Ceraolo Spurio 
2529ce07d94SLucas De Marchi static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
2539ce07d94SLucas De Marchi {
2549ce07d94SLucas De Marchi 	writeq(pte, addr);
2559ce07d94SLucas De Marchi }
2569ce07d94SLucas De Marchi 
2579ce07d94SLucas De Marchi static void gen8_ggtt_insert_page(struct i915_address_space *vm,
2589ce07d94SLucas De Marchi 				  dma_addr_t addr,
2599ce07d94SLucas De Marchi 				  u64 offset,
2609ce07d94SLucas De Marchi 				  enum i915_cache_level level,
2619ce07d94SLucas De Marchi 				  u32 flags)
2629ce07d94SLucas De Marchi {
2639ce07d94SLucas De Marchi 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
2649ce07d94SLucas De Marchi 	gen8_pte_t __iomem *pte =
2659ce07d94SLucas De Marchi 		(gen8_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE;
2669ce07d94SLucas De Marchi 
2679ce07d94SLucas De Marchi 	gen8_set_pte(pte, gen8_ggtt_pte_encode(addr, level, flags));
2689ce07d94SLucas De Marchi 
2699ce07d94SLucas De Marchi 	ggtt->invalidate(ggtt);
2709ce07d94SLucas De Marchi }
2719ce07d94SLucas De Marchi 
2729ce07d94SLucas De Marchi static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
2739ce07d94SLucas De Marchi 				     struct i915_vma_resource *vma_res,
2749ce07d94SLucas De Marchi 				     enum i915_cache_level level,
2759ce07d94SLucas De Marchi 				     u32 flags)
2769ce07d94SLucas De Marchi {
2779ce07d94SLucas De Marchi 	const gen8_pte_t pte_encode = gen8_ggtt_pte_encode(0, level, flags);
2789ce07d94SLucas De Marchi 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
2799ce07d94SLucas De Marchi 	gen8_pte_t __iomem *gte;
2809ce07d94SLucas De Marchi 	gen8_pte_t __iomem *end;
2819ce07d94SLucas De Marchi 	struct sgt_iter iter;
2829ce07d94SLucas De Marchi 	dma_addr_t addr;
2839ce07d94SLucas De Marchi 
2849ce07d94SLucas De Marchi 	/*
2859ce07d94SLucas De Marchi 	 * Note that we ignore PTE_READ_ONLY here. The caller must be careful
2869ce07d94SLucas De Marchi 	 * not to allow the user to override access to a read only page.
2879ce07d94SLucas De Marchi 	 */
2889ce07d94SLucas De Marchi 
2899ce07d94SLucas De Marchi 	gte = (gen8_pte_t __iomem *)ggtt->gsm;
2909ce07d94SLucas De Marchi 	gte += vma_res->start / I915_GTT_PAGE_SIZE;
2919ce07d94SLucas De Marchi 	end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE;
2929ce07d94SLucas De Marchi 
2939ce07d94SLucas De Marchi 	for_each_sgt_daddr(addr, iter, vma_res->bi.pages)
2949ce07d94SLucas De Marchi 		gen8_set_pte(gte++, pte_encode | addr);
2959ce07d94SLucas De Marchi 	GEM_BUG_ON(gte > end);
2969ce07d94SLucas De Marchi 
2979ce07d94SLucas De Marchi 	/* Fill the allocated but "unused" space beyond the end of the buffer */
2989ce07d94SLucas De Marchi 	while (gte < end)
2999ce07d94SLucas De Marchi 		gen8_set_pte(gte++, vm->scratch[0]->encode);
3009ce07d94SLucas De Marchi 
3019ce07d94SLucas De Marchi 	/*
3029ce07d94SLucas De Marchi 	 * We want to flush the TLBs only after we're certain all the PTE
3039ce07d94SLucas De Marchi 	 * updates have finished.
3049ce07d94SLucas De Marchi 	 */
3059ce07d94SLucas De Marchi 	ggtt->invalidate(ggtt);
3069ce07d94SLucas De Marchi }
3079ce07d94SLucas De Marchi 
3089ce07d94SLucas De Marchi static void gen6_ggtt_insert_page(struct i915_address_space *vm,
3099ce07d94SLucas De Marchi 				  dma_addr_t addr,
3109ce07d94SLucas De Marchi 				  u64 offset,
3119ce07d94SLucas De Marchi 				  enum i915_cache_level level,
3129ce07d94SLucas De Marchi 				  u32 flags)
3139ce07d94SLucas De Marchi {
3149ce07d94SLucas De Marchi 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
3159ce07d94SLucas De Marchi 	gen6_pte_t __iomem *pte =
3169ce07d94SLucas De Marchi 		(gen6_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE;
3179ce07d94SLucas De Marchi 
3189ce07d94SLucas De Marchi 	iowrite32(vm->pte_encode(addr, level, flags), pte);
3199ce07d94SLucas De Marchi 
3209ce07d94SLucas De Marchi 	ggtt->invalidate(ggtt);
3219ce07d94SLucas De Marchi }
3229ce07d94SLucas De Marchi 
3239ce07d94SLucas De Marchi /*
3249ce07d94SLucas De Marchi  * Binds an object into the global gtt with the specified cache level.
3259ce07d94SLucas De Marchi  * The object will be accessible to the GPU via commands whose operands
3269ce07d94SLucas De Marchi  * reference offsets within the global GTT as well as accessible by the GPU
3279ce07d94SLucas De Marchi  * through the GMADR mapped BAR (i915->mm.gtt->gtt).
3289ce07d94SLucas De Marchi  */
3299ce07d94SLucas De Marchi static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
3309ce07d94SLucas De Marchi 				     struct i915_vma_resource *vma_res,
3319ce07d94SLucas De Marchi 				     enum i915_cache_level level,
3329ce07d94SLucas De Marchi 				     u32 flags)
3339ce07d94SLucas De Marchi {
3349ce07d94SLucas De Marchi 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
3359ce07d94SLucas De Marchi 	gen6_pte_t __iomem *gte;
3369ce07d94SLucas De Marchi 	gen6_pte_t __iomem *end;
3379ce07d94SLucas De Marchi 	struct sgt_iter iter;
3389ce07d94SLucas De Marchi 	dma_addr_t addr;
3399ce07d94SLucas De Marchi 
3409ce07d94SLucas De Marchi 	gte = (gen6_pte_t __iomem *)ggtt->gsm;
3419ce07d94SLucas De Marchi 	gte += vma_res->start / I915_GTT_PAGE_SIZE;
3429ce07d94SLucas De Marchi 	end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE;
3439ce07d94SLucas De Marchi 
3449ce07d94SLucas De Marchi 	for_each_sgt_daddr(addr, iter, vma_res->bi.pages)
3459ce07d94SLucas De Marchi 		iowrite32(vm->pte_encode(addr, level, flags), gte++);
3469ce07d94SLucas De Marchi 	GEM_BUG_ON(gte > end);
3479ce07d94SLucas De Marchi 
3489ce07d94SLucas De Marchi 	/* Fill the allocated but "unused" space beyond the end of the buffer */
3499ce07d94SLucas De Marchi 	while (gte < end)
3509ce07d94SLucas De Marchi 		iowrite32(vm->scratch[0]->encode, gte++);
3519ce07d94SLucas De Marchi 
3529ce07d94SLucas De Marchi 	/*
3539ce07d94SLucas De Marchi 	 * We want to flush the TLBs only after we're certain all the PTE
3549ce07d94SLucas De Marchi 	 * updates have finished.
3559ce07d94SLucas De Marchi 	 */
3569ce07d94SLucas De Marchi 	ggtt->invalidate(ggtt);
3579ce07d94SLucas De Marchi }
3589ce07d94SLucas De Marchi 
3599ce07d94SLucas De Marchi static void nop_clear_range(struct i915_address_space *vm,
3609ce07d94SLucas De Marchi 			    u64 start, u64 length)
3619ce07d94SLucas De Marchi {
3629ce07d94SLucas De Marchi }
3639ce07d94SLucas De Marchi 
3649ce07d94SLucas De Marchi static void gen8_ggtt_clear_range(struct i915_address_space *vm,
3659ce07d94SLucas De Marchi 				  u64 start, u64 length)
3669ce07d94SLucas De Marchi {
3679ce07d94SLucas De Marchi 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
3689ce07d94SLucas De Marchi 	unsigned int first_entry = start / I915_GTT_PAGE_SIZE;
3699ce07d94SLucas De Marchi 	unsigned int num_entries = length / I915_GTT_PAGE_SIZE;
3709ce07d94SLucas De Marchi 	const gen8_pte_t scratch_pte = vm->scratch[0]->encode;
3719ce07d94SLucas De Marchi 	gen8_pte_t __iomem *gtt_base =
3729ce07d94SLucas De Marchi 		(gen8_pte_t __iomem *)ggtt->gsm + first_entry;
3739ce07d94SLucas De Marchi 	const int max_entries = ggtt_total_entries(ggtt) - first_entry;
3749ce07d94SLucas De Marchi 	int i;
3759ce07d94SLucas De Marchi 
3769ce07d94SLucas De Marchi 	if (WARN(num_entries > max_entries,
3779ce07d94SLucas De Marchi 		 "First entry = %d; Num entries = %d (max=%d)\n",
3789ce07d94SLucas De Marchi 		 first_entry, num_entries, max_entries))
3799ce07d94SLucas De Marchi 		num_entries = max_entries;
3809ce07d94SLucas De Marchi 
3819ce07d94SLucas De Marchi 	for (i = 0; i < num_entries; i++)
3829ce07d94SLucas De Marchi 		gen8_set_pte(&gtt_base[i], scratch_pte);
3839ce07d94SLucas De Marchi }
3849ce07d94SLucas De Marchi 
3859ce07d94SLucas De Marchi static void bxt_vtd_ggtt_wa(struct i915_address_space *vm)
3869ce07d94SLucas De Marchi {
3879ce07d94SLucas De Marchi 	/*
3889ce07d94SLucas De Marchi 	 * Make sure the internal GAM fifo has been cleared of all GTT
3899ce07d94SLucas De Marchi 	 * writes before exiting stop_machine(). This guarantees that
3909ce07d94SLucas De Marchi 	 * any aperture accesses waiting to start in another process
3919ce07d94SLucas De Marchi 	 * cannot back up behind the GTT writes causing a hang.
3929ce07d94SLucas De Marchi 	 * The register can be any arbitrary GAM register.
3939ce07d94SLucas De Marchi 	 */
3949ce07d94SLucas De Marchi 	intel_uncore_posting_read_fw(vm->gt->uncore, GFX_FLSH_CNTL_GEN6);
3959ce07d94SLucas De Marchi }
3969ce07d94SLucas De Marchi 
3979ce07d94SLucas De Marchi struct insert_page {
3989ce07d94SLucas De Marchi 	struct i915_address_space *vm;
3999ce07d94SLucas De Marchi 	dma_addr_t addr;
4009ce07d94SLucas De Marchi 	u64 offset;
4019ce07d94SLucas De Marchi 	enum i915_cache_level level;
4029ce07d94SLucas De Marchi };
4039ce07d94SLucas De Marchi 
4049ce07d94SLucas De Marchi static int bxt_vtd_ggtt_insert_page__cb(void *_arg)
4059ce07d94SLucas De Marchi {
4069ce07d94SLucas De Marchi 	struct insert_page *arg = _arg;
4079ce07d94SLucas De Marchi 
4089ce07d94SLucas De Marchi 	gen8_ggtt_insert_page(arg->vm, arg->addr, arg->offset, arg->level, 0);
4099ce07d94SLucas De Marchi 	bxt_vtd_ggtt_wa(arg->vm);
4109ce07d94SLucas De Marchi 
4119ce07d94SLucas De Marchi 	return 0;
4129ce07d94SLucas De Marchi }
4139ce07d94SLucas De Marchi 
4149ce07d94SLucas De Marchi static void bxt_vtd_ggtt_insert_page__BKL(struct i915_address_space *vm,
4159ce07d94SLucas De Marchi 					  dma_addr_t addr,
4169ce07d94SLucas De Marchi 					  u64 offset,
4179ce07d94SLucas De Marchi 					  enum i915_cache_level level,
4189ce07d94SLucas De Marchi 					  u32 unused)
4199ce07d94SLucas De Marchi {
4209ce07d94SLucas De Marchi 	struct insert_page arg = { vm, addr, offset, level };
4219ce07d94SLucas De Marchi 
4229ce07d94SLucas De Marchi 	stop_machine(bxt_vtd_ggtt_insert_page__cb, &arg, NULL);
4239ce07d94SLucas De Marchi }
4249ce07d94SLucas De Marchi 
4259ce07d94SLucas De Marchi struct insert_entries {
4269ce07d94SLucas De Marchi 	struct i915_address_space *vm;
4279ce07d94SLucas De Marchi 	struct i915_vma_resource *vma_res;
4289ce07d94SLucas De Marchi 	enum i915_cache_level level;
4299ce07d94SLucas De Marchi 	u32 flags;
4309ce07d94SLucas De Marchi };
4319ce07d94SLucas De Marchi 
4329ce07d94SLucas De Marchi static int bxt_vtd_ggtt_insert_entries__cb(void *_arg)
4339ce07d94SLucas De Marchi {
4349ce07d94SLucas De Marchi 	struct insert_entries *arg = _arg;
4359ce07d94SLucas De Marchi 
4369ce07d94SLucas De Marchi 	gen8_ggtt_insert_entries(arg->vm, arg->vma_res, arg->level, arg->flags);
4379ce07d94SLucas De Marchi 	bxt_vtd_ggtt_wa(arg->vm);
4389ce07d94SLucas De Marchi 
4399ce07d94SLucas De Marchi 	return 0;
4409ce07d94SLucas De Marchi }
4419ce07d94SLucas De Marchi 
4429ce07d94SLucas De Marchi static void bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space *vm,
4439ce07d94SLucas De Marchi 					     struct i915_vma_resource *vma_res,
4449ce07d94SLucas De Marchi 					     enum i915_cache_level level,
4459ce07d94SLucas De Marchi 					     u32 flags)
4469ce07d94SLucas De Marchi {
4479ce07d94SLucas De Marchi 	struct insert_entries arg = { vm, vma_res, level, flags };
4489ce07d94SLucas De Marchi 
4499ce07d94SLucas De Marchi 	stop_machine(bxt_vtd_ggtt_insert_entries__cb, &arg, NULL);
4509ce07d94SLucas De Marchi }
4519ce07d94SLucas De Marchi 
4529ce07d94SLucas De Marchi static void gen6_ggtt_clear_range(struct i915_address_space *vm,
4539ce07d94SLucas De Marchi 				  u64 start, u64 length)
4549ce07d94SLucas De Marchi {
4559ce07d94SLucas De Marchi 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
4569ce07d94SLucas De Marchi 	unsigned int first_entry = start / I915_GTT_PAGE_SIZE;
4579ce07d94SLucas De Marchi 	unsigned int num_entries = length / I915_GTT_PAGE_SIZE;
4589ce07d94SLucas De Marchi 	gen6_pte_t scratch_pte, __iomem *gtt_base =
4599ce07d94SLucas De Marchi 		(gen6_pte_t __iomem *)ggtt->gsm + first_entry;
4609ce07d94SLucas De Marchi 	const int max_entries = ggtt_total_entries(ggtt) - first_entry;
4619ce07d94SLucas De Marchi 	int i;
4629ce07d94SLucas De Marchi 
4639ce07d94SLucas De Marchi 	if (WARN(num_entries > max_entries,
4649ce07d94SLucas De Marchi 		 "First entry = %d; Num entries = %d (max=%d)\n",
4659ce07d94SLucas De Marchi 		 first_entry, num_entries, max_entries))
4669ce07d94SLucas De Marchi 		num_entries = max_entries;
4679ce07d94SLucas De Marchi 
4689ce07d94SLucas De Marchi 	scratch_pte = vm->scratch[0]->encode;
4699ce07d94SLucas De Marchi 	for (i = 0; i < num_entries; i++)
4709ce07d94SLucas De Marchi 		iowrite32(scratch_pte, &gtt_base[i]);
4719ce07d94SLucas De Marchi }
4729ce07d94SLucas De Marchi 
4737a5c9223SCasey Bowman void intel_ggtt_bind_vma(struct i915_address_space *vm,
474cd0452aaSChris Wilson 			 struct i915_vm_pt_stash *stash,
47539a2bd34SThomas Hellström 			 struct i915_vma_resource *vma_res,
4762c86e55dSMatthew Auld 			 enum i915_cache_level cache_level,
4772c86e55dSMatthew Auld 			 u32 flags)
4782c86e55dSMatthew Auld {
4792c86e55dSMatthew Auld 	u32 pte_flags;
4802c86e55dSMatthew Auld 
48139a2bd34SThomas Hellström 	if (vma_res->bound_flags & (~flags & I915_VMA_BIND_MASK))
482cd0452aaSChris Wilson 		return;
483bf0840cdSChris Wilson 
48439a2bd34SThomas Hellström 	vma_res->bound_flags |= flags;
48539a2bd34SThomas Hellström 
4862c86e55dSMatthew Auld 	/* Applicable to VLV (gen8+ do not support RO in the GGTT) */
4872c86e55dSMatthew Auld 	pte_flags = 0;
48839a2bd34SThomas Hellström 	if (vma_res->bi.readonly)
4892c86e55dSMatthew Auld 		pte_flags |= PTE_READ_ONLY;
49039a2bd34SThomas Hellström 	if (vma_res->bi.lmem)
491e762bdf5SMatthew Auld 		pte_flags |= PTE_LM;
4922c86e55dSMatthew Auld 
49339a2bd34SThomas Hellström 	vm->insert_entries(vm, vma_res, cache_level, pte_flags);
49439a2bd34SThomas Hellström 	vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
4952c86e55dSMatthew Auld }
4962c86e55dSMatthew Auld 
4977a5c9223SCasey Bowman void intel_ggtt_unbind_vma(struct i915_address_space *vm,
49839a2bd34SThomas Hellström 			   struct i915_vma_resource *vma_res)
4992c86e55dSMatthew Auld {
50039a2bd34SThomas Hellström 	vm->clear_range(vm, vma_res->start, vma_res->vma_size);
5012c86e55dSMatthew Auld }
5022c86e55dSMatthew Auld 
5032c86e55dSMatthew Auld static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt)
5042c86e55dSMatthew Auld {
5052c86e55dSMatthew Auld 	u64 size;
5062c86e55dSMatthew Auld 	int ret;
5072c86e55dSMatthew Auld 
50834bbfde6SDaniele Ceraolo Spurio 	if (!intel_uc_uses_guc(&ggtt->vm.gt->uc))
5092c86e55dSMatthew Auld 		return 0;
5102c86e55dSMatthew Auld 
5112c86e55dSMatthew Auld 	GEM_BUG_ON(ggtt->vm.total <= GUC_GGTT_TOP);
5122c86e55dSMatthew Auld 	size = ggtt->vm.total - GUC_GGTT_TOP;
5132c86e55dSMatthew Auld 
5147e00897bSMaarten Lankhorst 	ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw, size,
5152c86e55dSMatthew Auld 				   GUC_GGTT_TOP, I915_COLOR_UNEVICTABLE,
5162c86e55dSMatthew Auld 				   PIN_NOEVICT);
5172c86e55dSMatthew Auld 	if (ret)
51852ce7074SWambui Karuga 		drm_dbg(&ggtt->vm.i915->drm,
51952ce7074SWambui Karuga 			"Failed to reserve top of GGTT for GuC\n");
5202c86e55dSMatthew Auld 
5212c86e55dSMatthew Auld 	return ret;
5222c86e55dSMatthew Auld }
5232c86e55dSMatthew Auld 
5242c86e55dSMatthew Auld static void ggtt_release_guc_top(struct i915_ggtt *ggtt)
5252c86e55dSMatthew Auld {
5262c86e55dSMatthew Auld 	if (drm_mm_node_allocated(&ggtt->uc_fw))
5272c86e55dSMatthew Auld 		drm_mm_remove_node(&ggtt->uc_fw);
5282c86e55dSMatthew Auld }
5292c86e55dSMatthew Auld 
5302c86e55dSMatthew Auld static void cleanup_init_ggtt(struct i915_ggtt *ggtt)
5312c86e55dSMatthew Auld {
5322c86e55dSMatthew Auld 	ggtt_release_guc_top(ggtt);
5332c86e55dSMatthew Auld 	if (drm_mm_node_allocated(&ggtt->error_capture))
5342c86e55dSMatthew Auld 		drm_mm_remove_node(&ggtt->error_capture);
535742379c0SChris Wilson 	mutex_destroy(&ggtt->error_mutex);
5362c86e55dSMatthew Auld }
5372c86e55dSMatthew Auld 
5382c86e55dSMatthew Auld static int init_ggtt(struct i915_ggtt *ggtt)
5392c86e55dSMatthew Auld {
5402c86e55dSMatthew Auld 	/*
5412c86e55dSMatthew Auld 	 * Let GEM Manage all of the aperture.
5422c86e55dSMatthew Auld 	 *
5432c86e55dSMatthew Auld 	 * However, leave one page at the end still bound to the scratch page.
5442c86e55dSMatthew Auld 	 * There are a number of places where the hardware apparently prefetches
5452c86e55dSMatthew Auld 	 * past the end of the object, and we've seen multiple hangs with the
5462c86e55dSMatthew Auld 	 * GPU head pointer stuck in a batchbuffer bound at the last page of the
5472c86e55dSMatthew Auld 	 * aperture.  One page should be enough to keep any prefetching inside
5482c86e55dSMatthew Auld 	 * of the aperture.
5492c86e55dSMatthew Auld 	 */
5502c86e55dSMatthew Auld 	unsigned long hole_start, hole_end;
5512c86e55dSMatthew Auld 	struct drm_mm_node *entry;
5522c86e55dSMatthew Auld 	int ret;
5532c86e55dSMatthew Auld 
5542ef6efa7SThomas Hellström 	ggtt->pte_lost = true;
5552ef6efa7SThomas Hellström 
5562c86e55dSMatthew Auld 	/*
5572c86e55dSMatthew Auld 	 * GuC requires all resources that we're sharing with it to be placed in
5582c86e55dSMatthew Auld 	 * non-WOPCM memory. If GuC is not present or not in use we still need a
5592c86e55dSMatthew Auld 	 * small bias as ring wraparound at offset 0 sometimes hangs. No idea
5602c86e55dSMatthew Auld 	 * why.
5612c86e55dSMatthew Auld 	 */
5622c86e55dSMatthew Auld 	ggtt->pin_bias = max_t(u32, I915_GTT_PAGE_SIZE,
5632c86e55dSMatthew Auld 			       intel_wopcm_guc_size(&ggtt->vm.i915->wopcm));
5642c86e55dSMatthew Auld 
5652c86e55dSMatthew Auld 	ret = intel_vgt_balloon(ggtt);
5662c86e55dSMatthew Auld 	if (ret)
5672c86e55dSMatthew Auld 		return ret;
5682c86e55dSMatthew Auld 
569742379c0SChris Wilson 	mutex_init(&ggtt->error_mutex);
5702c86e55dSMatthew Auld 	if (ggtt->mappable_end) {
571489140b5SChris Wilson 		/*
572489140b5SChris Wilson 		 * Reserve a mappable slot for our lockless error capture.
573489140b5SChris Wilson 		 *
574489140b5SChris Wilson 		 * We strongly prefer taking address 0x0 in order to protect
575489140b5SChris Wilson 		 * other critical buffers against accidental overwrites,
576489140b5SChris Wilson 		 * as writing to address 0 is a very common mistake.
577489140b5SChris Wilson 		 *
578489140b5SChris Wilson 		 * Since 0 may already be in use by the system (e.g. the BIOS
579489140b5SChris Wilson 		 * framebuffer), we let the reservation fail quietly and hope
580489140b5SChris Wilson 		 * 0 remains reserved always.
581489140b5SChris Wilson 		 *
582489140b5SChris Wilson 		 * If we fail to reserve 0, and then fail to find any space
583489140b5SChris Wilson 		 * for an error-capture, remain silent. We can afford not
584489140b5SChris Wilson 		 * to reserve an error_capture node as we have fallback
585489140b5SChris Wilson 		 * paths, and we trust that 0 will remain reserved. However,
586489140b5SChris Wilson 		 * the only likely reason for failure to insert is a driver
587489140b5SChris Wilson 		 * bug, which we expect to cause other failures...
588489140b5SChris Wilson 		 */
589489140b5SChris Wilson 		ggtt->error_capture.size = I915_GTT_PAGE_SIZE;
590489140b5SChris Wilson 		ggtt->error_capture.color = I915_COLOR_UNEVICTABLE;
591489140b5SChris Wilson 		if (drm_mm_reserve_node(&ggtt->vm.mm, &ggtt->error_capture))
592489140b5SChris Wilson 			drm_mm_insert_node_in_range(&ggtt->vm.mm,
5932c86e55dSMatthew Auld 						    &ggtt->error_capture,
594489140b5SChris Wilson 						    ggtt->error_capture.size, 0,
595489140b5SChris Wilson 						    ggtt->error_capture.color,
5962c86e55dSMatthew Auld 						    0, ggtt->mappable_end,
5972c86e55dSMatthew Auld 						    DRM_MM_INSERT_LOW);
5982c86e55dSMatthew Auld 	}
599489140b5SChris Wilson 	if (drm_mm_node_allocated(&ggtt->error_capture))
600489140b5SChris Wilson 		drm_dbg(&ggtt->vm.i915->drm,
601489140b5SChris Wilson 			"Reserved GGTT:[%llx, %llx] for use by error capture\n",
602489140b5SChris Wilson 			ggtt->error_capture.start,
603489140b5SChris Wilson 			ggtt->error_capture.start + ggtt->error_capture.size);
6042c86e55dSMatthew Auld 
6052c86e55dSMatthew Auld 	/*
6062c86e55dSMatthew Auld 	 * The upper portion of the GuC address space has a sizeable hole
6072c86e55dSMatthew Auld 	 * (several MB) that is inaccessible by GuC. Reserve this range within
6082c86e55dSMatthew Auld 	 * GGTT as it can comfortably hold GuC/HuC firmware images.
6092c86e55dSMatthew Auld 	 */
6102c86e55dSMatthew Auld 	ret = ggtt_reserve_guc_top(ggtt);
6112c86e55dSMatthew Auld 	if (ret)
6122c86e55dSMatthew Auld 		goto err;
6132c86e55dSMatthew Auld 
6142c86e55dSMatthew Auld 	/* Clear any non-preallocated blocks */
6152c86e55dSMatthew Auld 	drm_mm_for_each_hole(entry, &ggtt->vm.mm, hole_start, hole_end) {
616489140b5SChris Wilson 		drm_dbg(&ggtt->vm.i915->drm,
61752ce7074SWambui Karuga 			"clearing unused GTT space: [%lx, %lx]\n",
6182c86e55dSMatthew Auld 			hole_start, hole_end);
6192c86e55dSMatthew Auld 		ggtt->vm.clear_range(&ggtt->vm, hole_start,
6202c86e55dSMatthew Auld 				     hole_end - hole_start);
6212c86e55dSMatthew Auld 	}
6222c86e55dSMatthew Auld 
6232c86e55dSMatthew Auld 	/* And finally clear the reserved guard page */
6242c86e55dSMatthew Auld 	ggtt->vm.clear_range(&ggtt->vm, ggtt->vm.total - PAGE_SIZE, PAGE_SIZE);
6252c86e55dSMatthew Auld 
6262c86e55dSMatthew Auld 	return 0;
6272c86e55dSMatthew Auld 
6282c86e55dSMatthew Auld err:
6292c86e55dSMatthew Auld 	cleanup_init_ggtt(ggtt);
6302c86e55dSMatthew Auld 	return ret;
6312c86e55dSMatthew Auld }
6322c86e55dSMatthew Auld 
633cd0452aaSChris Wilson static void aliasing_gtt_bind_vma(struct i915_address_space *vm,
634cd0452aaSChris Wilson 				  struct i915_vm_pt_stash *stash,
63539a2bd34SThomas Hellström 				  struct i915_vma_resource *vma_res,
6362c86e55dSMatthew Auld 				  enum i915_cache_level cache_level,
6372c86e55dSMatthew Auld 				  u32 flags)
6382c86e55dSMatthew Auld {
6392c86e55dSMatthew Auld 	u32 pte_flags;
6402c86e55dSMatthew Auld 
6412c86e55dSMatthew Auld 	/* Currently applicable only to VLV */
6422c86e55dSMatthew Auld 	pte_flags = 0;
64339a2bd34SThomas Hellström 	if (vma_res->bi.readonly)
6442c86e55dSMatthew Auld 		pte_flags |= PTE_READ_ONLY;
6452c86e55dSMatthew Auld 
646cd0452aaSChris Wilson 	if (flags & I915_VMA_LOCAL_BIND)
647cd0452aaSChris Wilson 		ppgtt_bind_vma(&i915_vm_to_ggtt(vm)->alias->vm,
64839a2bd34SThomas Hellström 			       stash, vma_res, cache_level, flags);
6492c86e55dSMatthew Auld 
650c0e60347SChris Wilson 	if (flags & I915_VMA_GLOBAL_BIND)
65139a2bd34SThomas Hellström 		vm->insert_entries(vm, vma_res, cache_level, pte_flags);
65239a2bd34SThomas Hellström 
65339a2bd34SThomas Hellström 	vma_res->bound_flags |= flags;
6542c86e55dSMatthew Auld }
6552c86e55dSMatthew Auld 
65612b07256SChris Wilson static void aliasing_gtt_unbind_vma(struct i915_address_space *vm,
65739a2bd34SThomas Hellström 				    struct i915_vma_resource *vma_res)
6582c86e55dSMatthew Auld {
65939a2bd34SThomas Hellström 	if (vma_res->bound_flags & I915_VMA_GLOBAL_BIND)
66039a2bd34SThomas Hellström 		vm->clear_range(vm, vma_res->start, vma_res->vma_size);
6612c86e55dSMatthew Auld 
66239a2bd34SThomas Hellström 	if (vma_res->bound_flags & I915_VMA_LOCAL_BIND)
66339a2bd34SThomas Hellström 		ppgtt_unbind_vma(&i915_vm_to_ggtt(vm)->alias->vm, vma_res);
6642c86e55dSMatthew Auld }
6652c86e55dSMatthew Auld 
6662c86e55dSMatthew Auld static int init_aliasing_ppgtt(struct i915_ggtt *ggtt)
6672c86e55dSMatthew Auld {
668cd0452aaSChris Wilson 	struct i915_vm_pt_stash stash = {};
6692c86e55dSMatthew Auld 	struct i915_ppgtt *ppgtt;
6702c86e55dSMatthew Auld 	int err;
6712c86e55dSMatthew Auld 
672a259cc14SThomas Hellström 	ppgtt = i915_ppgtt_create(ggtt->vm.gt, 0);
6732c86e55dSMatthew Auld 	if (IS_ERR(ppgtt))
6742c86e55dSMatthew Auld 		return PTR_ERR(ppgtt);
6752c86e55dSMatthew Auld 
6762c86e55dSMatthew Auld 	if (GEM_WARN_ON(ppgtt->vm.total < ggtt->vm.total)) {
6772c86e55dSMatthew Auld 		err = -ENODEV;
6782c86e55dSMatthew Auld 		goto err_ppgtt;
6792c86e55dSMatthew Auld 	}
6802c86e55dSMatthew Auld 
681cd0452aaSChris Wilson 	err = i915_vm_alloc_pt_stash(&ppgtt->vm, &stash, ggtt->vm.total);
682cd0452aaSChris Wilson 	if (err)
683cd0452aaSChris Wilson 		goto err_ppgtt;
684cd0452aaSChris Wilson 
68526ad4f8bSMaarten Lankhorst 	i915_gem_object_lock(ppgtt->vm.scratch[0], NULL);
686529b9ec8SMatthew Auld 	err = i915_vm_map_pt_stash(&ppgtt->vm, &stash);
68726ad4f8bSMaarten Lankhorst 	i915_gem_object_unlock(ppgtt->vm.scratch[0]);
68889351925SChris Wilson 	if (err)
68989351925SChris Wilson 		goto err_stash;
69089351925SChris Wilson 
6912c86e55dSMatthew Auld 	/*
6922c86e55dSMatthew Auld 	 * Note we only pre-allocate as far as the end of the global
6932c86e55dSMatthew Auld 	 * GTT. On 48b / 4-level page-tables, the difference is very,
6942c86e55dSMatthew Auld 	 * very significant! We have to preallocate as GVT/vgpu does
6952c86e55dSMatthew Auld 	 * not like the page directory disappearing.
6962c86e55dSMatthew Auld 	 */
697cd0452aaSChris Wilson 	ppgtt->vm.allocate_va_range(&ppgtt->vm, &stash, 0, ggtt->vm.total);
6982c86e55dSMatthew Auld 
6992c86e55dSMatthew Auld 	ggtt->alias = ppgtt;
7002c86e55dSMatthew Auld 	ggtt->vm.bind_async_flags |= ppgtt->vm.bind_async_flags;
7012c86e55dSMatthew Auld 
7027a5c9223SCasey Bowman 	GEM_BUG_ON(ggtt->vm.vma_ops.bind_vma != intel_ggtt_bind_vma);
7032c86e55dSMatthew Auld 	ggtt->vm.vma_ops.bind_vma = aliasing_gtt_bind_vma;
7042c86e55dSMatthew Auld 
7057a5c9223SCasey Bowman 	GEM_BUG_ON(ggtt->vm.vma_ops.unbind_vma != intel_ggtt_unbind_vma);
7062c86e55dSMatthew Auld 	ggtt->vm.vma_ops.unbind_vma = aliasing_gtt_unbind_vma;
7072c86e55dSMatthew Auld 
708cd0452aaSChris Wilson 	i915_vm_free_pt_stash(&ppgtt->vm, &stash);
7092c86e55dSMatthew Auld 	return 0;
7102c86e55dSMatthew Auld 
71189351925SChris Wilson err_stash:
71289351925SChris Wilson 	i915_vm_free_pt_stash(&ppgtt->vm, &stash);
7132c86e55dSMatthew Auld err_ppgtt:
7142c86e55dSMatthew Auld 	i915_vm_put(&ppgtt->vm);
7152c86e55dSMatthew Auld 	return err;
7162c86e55dSMatthew Auld }
7172c86e55dSMatthew Auld 
7182c86e55dSMatthew Auld static void fini_aliasing_ppgtt(struct i915_ggtt *ggtt)
7192c86e55dSMatthew Auld {
7202c86e55dSMatthew Auld 	struct i915_ppgtt *ppgtt;
7212c86e55dSMatthew Auld 
7222c86e55dSMatthew Auld 	ppgtt = fetch_and_zero(&ggtt->alias);
7232c86e55dSMatthew Auld 	if (!ppgtt)
7242c86e55dSMatthew Auld 		return;
7252c86e55dSMatthew Auld 
7262c86e55dSMatthew Auld 	i915_vm_put(&ppgtt->vm);
7272c86e55dSMatthew Auld 
7287a5c9223SCasey Bowman 	ggtt->vm.vma_ops.bind_vma   = intel_ggtt_bind_vma;
7297a5c9223SCasey Bowman 	ggtt->vm.vma_ops.unbind_vma = intel_ggtt_unbind_vma;
7302c86e55dSMatthew Auld }
7312c86e55dSMatthew Auld 
7322c86e55dSMatthew Auld int i915_init_ggtt(struct drm_i915_private *i915)
7332c86e55dSMatthew Auld {
7342c86e55dSMatthew Auld 	int ret;
7352c86e55dSMatthew Auld 
736848915c3SMichał Winiarski 	ret = init_ggtt(to_gt(i915)->ggtt);
7372c86e55dSMatthew Auld 	if (ret)
7382c86e55dSMatthew Auld 		return ret;
7392c86e55dSMatthew Auld 
7402c86e55dSMatthew Auld 	if (INTEL_PPGTT(i915) == INTEL_PPGTT_ALIASING) {
741848915c3SMichał Winiarski 		ret = init_aliasing_ppgtt(to_gt(i915)->ggtt);
7422c86e55dSMatthew Auld 		if (ret)
743848915c3SMichał Winiarski 			cleanup_init_ggtt(to_gt(i915)->ggtt);
7442c86e55dSMatthew Auld 	}
7452c86e55dSMatthew Auld 
7462c86e55dSMatthew Auld 	return 0;
7472c86e55dSMatthew Auld }
7482c86e55dSMatthew Auld 
7492c86e55dSMatthew Auld static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
7502c86e55dSMatthew Auld {
7512c86e55dSMatthew Auld 	struct i915_vma *vma, *vn;
7522c86e55dSMatthew Auld 
7532c86e55dSMatthew Auld 	flush_workqueue(ggtt->vm.i915->wq);
7540f341974SMaarten Lankhorst 	i915_gem_drain_freed_objects(ggtt->vm.i915);
7552c86e55dSMatthew Auld 
7562c86e55dSMatthew Auld 	mutex_lock(&ggtt->vm.mutex);
7572c86e55dSMatthew Auld 
758e1a7ab4fSThomas Hellström 	ggtt->vm.skip_pte_rewrite = true;
759e1a7ab4fSThomas Hellström 
7600f341974SMaarten Lankhorst 	list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) {
7610f341974SMaarten Lankhorst 		struct drm_i915_gem_object *obj = vma->obj;
7620f341974SMaarten Lankhorst 		bool trylock;
7630f341974SMaarten Lankhorst 
7640f341974SMaarten Lankhorst 		trylock = i915_gem_object_trylock(obj, NULL);
7650f341974SMaarten Lankhorst 		WARN_ON(!trylock);
7660f341974SMaarten Lankhorst 
7672c86e55dSMatthew Auld 		WARN_ON(__i915_vma_unbind(vma));
7680f341974SMaarten Lankhorst 		if (trylock)
7690f341974SMaarten Lankhorst 			i915_gem_object_unlock(obj);
7700f341974SMaarten Lankhorst 	}
7712c86e55dSMatthew Auld 
7722c86e55dSMatthew Auld 	if (drm_mm_node_allocated(&ggtt->error_capture))
7732c86e55dSMatthew Auld 		drm_mm_remove_node(&ggtt->error_capture);
774742379c0SChris Wilson 	mutex_destroy(&ggtt->error_mutex);
7752c86e55dSMatthew Auld 
7762c86e55dSMatthew Auld 	ggtt_release_guc_top(ggtt);
7772c86e55dSMatthew Auld 	intel_vgt_deballoon(ggtt);
7782c86e55dSMatthew Auld 
7792c86e55dSMatthew Auld 	ggtt->vm.cleanup(&ggtt->vm);
7802c86e55dSMatthew Auld 
7812c86e55dSMatthew Auld 	mutex_unlock(&ggtt->vm.mutex);
7822c86e55dSMatthew Auld 	i915_address_space_fini(&ggtt->vm);
7832c86e55dSMatthew Auld 
7842c86e55dSMatthew Auld 	arch_phys_wc_del(ggtt->mtrr);
7852c86e55dSMatthew Auld 
7862c86e55dSMatthew Auld 	if (ggtt->iomap.size)
7872c86e55dSMatthew Auld 		io_mapping_fini(&ggtt->iomap);
7882c86e55dSMatthew Auld }
7892c86e55dSMatthew Auld 
7902c86e55dSMatthew Auld /**
7912c86e55dSMatthew Auld  * i915_ggtt_driver_release - Clean up GGTT hardware initialization
7922c86e55dSMatthew Auld  * @i915: i915 device
7932c86e55dSMatthew Auld  */
7942c86e55dSMatthew Auld void i915_ggtt_driver_release(struct drm_i915_private *i915)
7952c86e55dSMatthew Auld {
796848915c3SMichał Winiarski 	struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
7972c86e55dSMatthew Auld 
7980b6bc81dSChris Wilson 	fini_aliasing_ppgtt(ggtt);
7992c86e55dSMatthew Auld 
8000b6bc81dSChris Wilson 	intel_ggtt_fini_fences(ggtt);
8010b6bc81dSChris Wilson 	ggtt_cleanup_hw(ggtt);
8022c86e55dSMatthew Auld }
8032c86e55dSMatthew Auld 
8044d8151aeSThomas Hellström /**
8054d8151aeSThomas Hellström  * i915_ggtt_driver_late_release - Cleanup of GGTT that needs to be done after
8064d8151aeSThomas Hellström  * all free objects have been drained.
8074d8151aeSThomas Hellström  * @i915: i915 device
8084d8151aeSThomas Hellström  */
8094d8151aeSThomas Hellström void i915_ggtt_driver_late_release(struct drm_i915_private *i915)
8104d8151aeSThomas Hellström {
811848915c3SMichał Winiarski 	struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
8124d8151aeSThomas Hellström 
8134d8151aeSThomas Hellström 	GEM_WARN_ON(kref_read(&ggtt->vm.resv_ref) != 1);
8144d8151aeSThomas Hellström 	dma_resv_fini(&ggtt->vm._resv);
8154d8151aeSThomas Hellström }
8164d8151aeSThomas Hellström 
8179ce07d94SLucas De Marchi static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
8189ce07d94SLucas De Marchi {
8199ce07d94SLucas De Marchi 	snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT;
8209ce07d94SLucas De Marchi 	snb_gmch_ctl &= SNB_GMCH_GGMS_MASK;
8219ce07d94SLucas De Marchi 	return snb_gmch_ctl << 20;
8229ce07d94SLucas De Marchi }
8239ce07d94SLucas De Marchi 
8249ce07d94SLucas De Marchi static unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
8259ce07d94SLucas De Marchi {
8269ce07d94SLucas De Marchi 	bdw_gmch_ctl >>= BDW_GMCH_GGMS_SHIFT;
8279ce07d94SLucas De Marchi 	bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK;
8289ce07d94SLucas De Marchi 	if (bdw_gmch_ctl)
8299ce07d94SLucas De Marchi 		bdw_gmch_ctl = 1 << bdw_gmch_ctl;
8309ce07d94SLucas De Marchi 
8319ce07d94SLucas De Marchi #ifdef CONFIG_X86_32
8329ce07d94SLucas De Marchi 	/* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * I915_GTT_PAGE_SIZE */
8339ce07d94SLucas De Marchi 	if (bdw_gmch_ctl > 4)
8349ce07d94SLucas De Marchi 		bdw_gmch_ctl = 4;
8359ce07d94SLucas De Marchi #endif
8369ce07d94SLucas De Marchi 
8379ce07d94SLucas De Marchi 	return bdw_gmch_ctl << 20;
8389ce07d94SLucas De Marchi }
8399ce07d94SLucas De Marchi 
8409ce07d94SLucas De Marchi static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl)
8419ce07d94SLucas De Marchi {
8429ce07d94SLucas De Marchi 	gmch_ctrl >>= SNB_GMCH_GGMS_SHIFT;
8439ce07d94SLucas De Marchi 	gmch_ctrl &= SNB_GMCH_GGMS_MASK;
8449ce07d94SLucas De Marchi 
8459ce07d94SLucas De Marchi 	if (gmch_ctrl)
8469ce07d94SLucas De Marchi 		return 1 << (20 + gmch_ctrl);
8479ce07d94SLucas De Marchi 
8489ce07d94SLucas De Marchi 	return 0;
8499ce07d94SLucas De Marchi }
8509ce07d94SLucas De Marchi 
8519ce07d94SLucas De Marchi static unsigned int gen6_gttmmadr_size(struct drm_i915_private *i915)
8529ce07d94SLucas De Marchi {
8539ce07d94SLucas De Marchi 	/*
8549ce07d94SLucas De Marchi 	 * GEN6: GTTMMADR size is 4MB and GTTADR starts at 2MB offset
8559ce07d94SLucas De Marchi 	 * GEN8: GTTMMADR size is 16MB and GTTADR starts at 8MB offset
8569ce07d94SLucas De Marchi 	 */
8579ce07d94SLucas De Marchi 	GEM_BUG_ON(GRAPHICS_VER(i915) < 6);
8589ce07d94SLucas De Marchi 	return (GRAPHICS_VER(i915) < 8) ? SZ_4M : SZ_16M;
8599ce07d94SLucas De Marchi }
8609ce07d94SLucas De Marchi 
8619ce07d94SLucas De Marchi static unsigned int gen6_gttadr_offset(struct drm_i915_private *i915)
8629ce07d94SLucas De Marchi {
8639ce07d94SLucas De Marchi 	return gen6_gttmmadr_size(i915) / 2;
8649ce07d94SLucas De Marchi }
8659ce07d94SLucas De Marchi 
8669ce07d94SLucas De Marchi static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
8679ce07d94SLucas De Marchi {
8689ce07d94SLucas De Marchi 	struct drm_i915_private *i915 = ggtt->vm.i915;
8699ce07d94SLucas De Marchi 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
8709ce07d94SLucas De Marchi 	phys_addr_t phys_addr;
8719ce07d94SLucas De Marchi 	u32 pte_flags;
8729ce07d94SLucas De Marchi 	int ret;
8739ce07d94SLucas De Marchi 
8746bba2b30SPiotr Piórkowski 	GEM_WARN_ON(pci_resource_len(pdev, GTTMMADR_BAR) != gen6_gttmmadr_size(i915));
8756bba2b30SPiotr Piórkowski 	phys_addr = pci_resource_start(pdev, GTTMMADR_BAR) + gen6_gttadr_offset(i915);
8769ce07d94SLucas De Marchi 
8779ce07d94SLucas De Marchi 	/*
8789ce07d94SLucas De Marchi 	 * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range
8799ce07d94SLucas De Marchi 	 * will be dropped. For WC mappings in general we have 64 byte burst
8809ce07d94SLucas De Marchi 	 * writes when the WC buffer is flushed, so we can't use it, but have to
8819ce07d94SLucas De Marchi 	 * resort to an uncached mapping. The WC issue is easily caught by the
8829ce07d94SLucas De Marchi 	 * readback check when writing GTT PTE entries.
8839ce07d94SLucas De Marchi 	 */
8849ce07d94SLucas De Marchi 	if (IS_GEN9_LP(i915) || GRAPHICS_VER(i915) >= 11)
8859ce07d94SLucas De Marchi 		ggtt->gsm = ioremap(phys_addr, size);
8869ce07d94SLucas De Marchi 	else
8879ce07d94SLucas De Marchi 		ggtt->gsm = ioremap_wc(phys_addr, size);
8889ce07d94SLucas De Marchi 	if (!ggtt->gsm) {
8899ce07d94SLucas De Marchi 		drm_err(&i915->drm, "Failed to map the ggtt page table\n");
8909ce07d94SLucas De Marchi 		return -ENOMEM;
8919ce07d94SLucas De Marchi 	}
8929ce07d94SLucas De Marchi 
8939ce07d94SLucas De Marchi 	kref_init(&ggtt->vm.resv_ref);
8949ce07d94SLucas De Marchi 	ret = setup_scratch_page(&ggtt->vm);
8959ce07d94SLucas De Marchi 	if (ret) {
8969ce07d94SLucas De Marchi 		drm_err(&i915->drm, "Scratch setup failed\n");
8979ce07d94SLucas De Marchi 		/* iounmap will also get called at remove, but meh */
8989ce07d94SLucas De Marchi 		iounmap(ggtt->gsm);
8999ce07d94SLucas De Marchi 		return ret;
9009ce07d94SLucas De Marchi 	}
9019ce07d94SLucas De Marchi 
9029ce07d94SLucas De Marchi 	pte_flags = 0;
9039ce07d94SLucas De Marchi 	if (i915_gem_object_is_lmem(ggtt->vm.scratch[0]))
9049ce07d94SLucas De Marchi 		pte_flags |= PTE_LM;
9059ce07d94SLucas De Marchi 
9069ce07d94SLucas De Marchi 	ggtt->vm.scratch[0]->encode =
9079ce07d94SLucas De Marchi 		ggtt->vm.pte_encode(px_dma(ggtt->vm.scratch[0]),
9089ce07d94SLucas De Marchi 				    I915_CACHE_NONE, pte_flags);
9099ce07d94SLucas De Marchi 
9109ce07d94SLucas De Marchi 	return 0;
9119ce07d94SLucas De Marchi }
9129ce07d94SLucas De Marchi 
9139ce07d94SLucas De Marchi static void gen6_gmch_remove(struct i915_address_space *vm)
9149ce07d94SLucas De Marchi {
9159ce07d94SLucas De Marchi 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
9169ce07d94SLucas De Marchi 
9179ce07d94SLucas De Marchi 	iounmap(ggtt->gsm);
9189ce07d94SLucas De Marchi 	free_scratch(vm);
9199ce07d94SLucas De Marchi }
9209ce07d94SLucas De Marchi 
9219ce07d94SLucas De Marchi static struct resource pci_resource(struct pci_dev *pdev, int bar)
9222c86e55dSMatthew Auld {
9232c86e55dSMatthew Auld 	return (struct resource)DEFINE_RES_MEM(pci_resource_start(pdev, bar),
9242c86e55dSMatthew Auld 					       pci_resource_len(pdev, bar));
9252c86e55dSMatthew Auld }
9262c86e55dSMatthew Auld 
9279ce07d94SLucas De Marchi static int gen8_gmch_probe(struct i915_ggtt *ggtt)
9289ce07d94SLucas De Marchi {
9299ce07d94SLucas De Marchi 	struct drm_i915_private *i915 = ggtt->vm.i915;
9309ce07d94SLucas De Marchi 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
9319ce07d94SLucas De Marchi 	unsigned int size;
9329ce07d94SLucas De Marchi 	u16 snb_gmch_ctl;
9339ce07d94SLucas De Marchi 
934dbb2ffbfSAravind Iddamsetty 	if (!HAS_LMEM(i915) && !HAS_BAR2_SMEM_STOLEN(i915)) {
9351bba7323SPiotr Piórkowski 		if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR))
9361bba7323SPiotr Piórkowski 			return -ENXIO;
9371bba7323SPiotr Piórkowski 
9386bba2b30SPiotr Piórkowski 		ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR);
9399ce07d94SLucas De Marchi 		ggtt->mappable_end = resource_size(&ggtt->gmadr);
9409ce07d94SLucas De Marchi 	}
9419ce07d94SLucas De Marchi 
9429ce07d94SLucas De Marchi 	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
9439ce07d94SLucas De Marchi 	if (IS_CHERRYVIEW(i915))
9449ce07d94SLucas De Marchi 		size = chv_get_total_gtt_size(snb_gmch_ctl);
9459ce07d94SLucas De Marchi 	else
9469ce07d94SLucas De Marchi 		size = gen8_get_total_gtt_size(snb_gmch_ctl);
9479ce07d94SLucas De Marchi 
9489ce07d94SLucas De Marchi 	ggtt->vm.alloc_pt_dma = alloc_pt_dma;
9499ce07d94SLucas De Marchi 	ggtt->vm.alloc_scratch_dma = alloc_pt_dma;
9509ce07d94SLucas De Marchi 	ggtt->vm.lmem_pt_obj_flags = I915_BO_ALLOC_PM_EARLY;
9519ce07d94SLucas De Marchi 
9529ce07d94SLucas De Marchi 	ggtt->vm.total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE;
9539ce07d94SLucas De Marchi 	ggtt->vm.cleanup = gen6_gmch_remove;
9549ce07d94SLucas De Marchi 	ggtt->vm.insert_page = gen8_ggtt_insert_page;
9559ce07d94SLucas De Marchi 	ggtt->vm.clear_range = nop_clear_range;
9569ce07d94SLucas De Marchi 	if (intel_scanout_needs_vtd_wa(i915))
9579ce07d94SLucas De Marchi 		ggtt->vm.clear_range = gen8_ggtt_clear_range;
9589ce07d94SLucas De Marchi 
9599ce07d94SLucas De Marchi 	ggtt->vm.insert_entries = gen8_ggtt_insert_entries;
9609ce07d94SLucas De Marchi 
9619ce07d94SLucas De Marchi 	/*
9629ce07d94SLucas De Marchi 	 * Serialize GTT updates with aperture access on BXT if VT-d is on,
9639ce07d94SLucas De Marchi 	 * and always on CHV.
9649ce07d94SLucas De Marchi 	 */
9659ce07d94SLucas De Marchi 	if (intel_vm_no_concurrent_access_wa(i915)) {
9669ce07d94SLucas De Marchi 		ggtt->vm.insert_entries = bxt_vtd_ggtt_insert_entries__BKL;
9679ce07d94SLucas De Marchi 		ggtt->vm.insert_page    = bxt_vtd_ggtt_insert_page__BKL;
968a0696856SNirmoy Das 
969a0696856SNirmoy Das 		/*
970a0696856SNirmoy Das 		 * Calling stop_machine() version of GGTT update function
971a0696856SNirmoy Das 		 * at error capture/reset path will raise lockdep warning.
972a0696856SNirmoy Das 		 * Allow calling gen8_ggtt_insert_* directly at reset path
973a0696856SNirmoy Das 		 * which is safe from parallel GGTT updates.
974a0696856SNirmoy Das 		 */
975a0696856SNirmoy Das 		ggtt->vm.raw_insert_page = gen8_ggtt_insert_page;
976a0696856SNirmoy Das 		ggtt->vm.raw_insert_entries = gen8_ggtt_insert_entries;
977a0696856SNirmoy Das 
9789ce07d94SLucas De Marchi 		ggtt->vm.bind_async_flags =
9799ce07d94SLucas De Marchi 			I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND;
9809ce07d94SLucas De Marchi 	}
9819ce07d94SLucas De Marchi 
9829ce07d94SLucas De Marchi 	ggtt->invalidate = gen8_ggtt_invalidate;
9839ce07d94SLucas De Marchi 
9849ce07d94SLucas De Marchi 	ggtt->vm.vma_ops.bind_vma    = intel_ggtt_bind_vma;
9859ce07d94SLucas De Marchi 	ggtt->vm.vma_ops.unbind_vma  = intel_ggtt_unbind_vma;
9869ce07d94SLucas De Marchi 
9879ce07d94SLucas De Marchi 	ggtt->vm.pte_encode = gen8_ggtt_pte_encode;
9889ce07d94SLucas De Marchi 
9899ce07d94SLucas De Marchi 	setup_private_pat(ggtt->vm.gt->uncore);
9909ce07d94SLucas De Marchi 
9919ce07d94SLucas De Marchi 	return ggtt_probe_common(ggtt, size);
9929ce07d94SLucas De Marchi }
9939ce07d94SLucas De Marchi 
9949ce07d94SLucas De Marchi static u64 snb_pte_encode(dma_addr_t addr,
9959ce07d94SLucas De Marchi 			  enum i915_cache_level level,
9969ce07d94SLucas De Marchi 			  u32 flags)
9979ce07d94SLucas De Marchi {
9989ce07d94SLucas De Marchi 	gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID;
9999ce07d94SLucas De Marchi 
10009ce07d94SLucas De Marchi 	switch (level) {
10019ce07d94SLucas De Marchi 	case I915_CACHE_L3_LLC:
10029ce07d94SLucas De Marchi 	case I915_CACHE_LLC:
10039ce07d94SLucas De Marchi 		pte |= GEN6_PTE_CACHE_LLC;
10049ce07d94SLucas De Marchi 		break;
10059ce07d94SLucas De Marchi 	case I915_CACHE_NONE:
10069ce07d94SLucas De Marchi 		pte |= GEN6_PTE_UNCACHED;
10079ce07d94SLucas De Marchi 		break;
10089ce07d94SLucas De Marchi 	default:
10099ce07d94SLucas De Marchi 		MISSING_CASE(level);
10109ce07d94SLucas De Marchi 	}
10119ce07d94SLucas De Marchi 
10129ce07d94SLucas De Marchi 	return pte;
10139ce07d94SLucas De Marchi }
10149ce07d94SLucas De Marchi 
10159ce07d94SLucas De Marchi static u64 ivb_pte_encode(dma_addr_t addr,
10169ce07d94SLucas De Marchi 			  enum i915_cache_level level,
10179ce07d94SLucas De Marchi 			  u32 flags)
10189ce07d94SLucas De Marchi {
10199ce07d94SLucas De Marchi 	gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID;
10209ce07d94SLucas De Marchi 
10219ce07d94SLucas De Marchi 	switch (level) {
10229ce07d94SLucas De Marchi 	case I915_CACHE_L3_LLC:
10239ce07d94SLucas De Marchi 		pte |= GEN7_PTE_CACHE_L3_LLC;
10249ce07d94SLucas De Marchi 		break;
10259ce07d94SLucas De Marchi 	case I915_CACHE_LLC:
10269ce07d94SLucas De Marchi 		pte |= GEN6_PTE_CACHE_LLC;
10279ce07d94SLucas De Marchi 		break;
10289ce07d94SLucas De Marchi 	case I915_CACHE_NONE:
10299ce07d94SLucas De Marchi 		pte |= GEN6_PTE_UNCACHED;
10309ce07d94SLucas De Marchi 		break;
10319ce07d94SLucas De Marchi 	default:
10329ce07d94SLucas De Marchi 		MISSING_CASE(level);
10339ce07d94SLucas De Marchi 	}
10349ce07d94SLucas De Marchi 
10359ce07d94SLucas De Marchi 	return pte;
10369ce07d94SLucas De Marchi }
10379ce07d94SLucas De Marchi 
10389ce07d94SLucas De Marchi static u64 byt_pte_encode(dma_addr_t addr,
10399ce07d94SLucas De Marchi 			  enum i915_cache_level level,
10409ce07d94SLucas De Marchi 			  u32 flags)
10419ce07d94SLucas De Marchi {
10429ce07d94SLucas De Marchi 	gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID;
10439ce07d94SLucas De Marchi 
10449ce07d94SLucas De Marchi 	if (!(flags & PTE_READ_ONLY))
10459ce07d94SLucas De Marchi 		pte |= BYT_PTE_WRITEABLE;
10469ce07d94SLucas De Marchi 
10479ce07d94SLucas De Marchi 	if (level != I915_CACHE_NONE)
10489ce07d94SLucas De Marchi 		pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES;
10499ce07d94SLucas De Marchi 
10509ce07d94SLucas De Marchi 	return pte;
10519ce07d94SLucas De Marchi }
10529ce07d94SLucas De Marchi 
10539ce07d94SLucas De Marchi static u64 hsw_pte_encode(dma_addr_t addr,
10549ce07d94SLucas De Marchi 			  enum i915_cache_level level,
10559ce07d94SLucas De Marchi 			  u32 flags)
10569ce07d94SLucas De Marchi {
10579ce07d94SLucas De Marchi 	gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID;
10589ce07d94SLucas De Marchi 
10599ce07d94SLucas De Marchi 	if (level != I915_CACHE_NONE)
10609ce07d94SLucas De Marchi 		pte |= HSW_WB_LLC_AGE3;
10619ce07d94SLucas De Marchi 
10629ce07d94SLucas De Marchi 	return pte;
10639ce07d94SLucas De Marchi }
10649ce07d94SLucas De Marchi 
10659ce07d94SLucas De Marchi static u64 iris_pte_encode(dma_addr_t addr,
10669ce07d94SLucas De Marchi 			   enum i915_cache_level level,
10679ce07d94SLucas De Marchi 			   u32 flags)
10689ce07d94SLucas De Marchi {
10699ce07d94SLucas De Marchi 	gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID;
10709ce07d94SLucas De Marchi 
10719ce07d94SLucas De Marchi 	switch (level) {
10729ce07d94SLucas De Marchi 	case I915_CACHE_NONE:
10739ce07d94SLucas De Marchi 		break;
10749ce07d94SLucas De Marchi 	case I915_CACHE_WT:
10759ce07d94SLucas De Marchi 		pte |= HSW_WT_ELLC_LLC_AGE3;
10769ce07d94SLucas De Marchi 		break;
10779ce07d94SLucas De Marchi 	default:
10789ce07d94SLucas De Marchi 		pte |= HSW_WB_ELLC_LLC_AGE3;
10799ce07d94SLucas De Marchi 		break;
10809ce07d94SLucas De Marchi 	}
10819ce07d94SLucas De Marchi 
10829ce07d94SLucas De Marchi 	return pte;
10839ce07d94SLucas De Marchi }
10849ce07d94SLucas De Marchi 
10859ce07d94SLucas De Marchi static int gen6_gmch_probe(struct i915_ggtt *ggtt)
10869ce07d94SLucas De Marchi {
10879ce07d94SLucas De Marchi 	struct drm_i915_private *i915 = ggtt->vm.i915;
10889ce07d94SLucas De Marchi 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
10899ce07d94SLucas De Marchi 	unsigned int size;
10909ce07d94SLucas De Marchi 	u16 snb_gmch_ctl;
10919ce07d94SLucas De Marchi 
10921bba7323SPiotr Piórkowski 	if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR))
10931bba7323SPiotr Piórkowski 		return -ENXIO;
10941bba7323SPiotr Piórkowski 
10956bba2b30SPiotr Piórkowski 	ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR);
10969ce07d94SLucas De Marchi 	ggtt->mappable_end = resource_size(&ggtt->gmadr);
10979ce07d94SLucas De Marchi 
10989ce07d94SLucas De Marchi 	/*
10999ce07d94SLucas De Marchi 	 * 64/512MB is the current min/max we actually know of, but this is
11009ce07d94SLucas De Marchi 	 * just a coarse sanity check.
11019ce07d94SLucas De Marchi 	 */
11029ce07d94SLucas De Marchi 	if (ggtt->mappable_end < (64 << 20) ||
11039ce07d94SLucas De Marchi 	    ggtt->mappable_end > (512 << 20)) {
11049ce07d94SLucas De Marchi 		drm_err(&i915->drm, "Unknown GMADR size (%pa)\n",
11059ce07d94SLucas De Marchi 			&ggtt->mappable_end);
11069ce07d94SLucas De Marchi 		return -ENXIO;
11079ce07d94SLucas De Marchi 	}
11089ce07d94SLucas De Marchi 
11099ce07d94SLucas De Marchi 	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
11109ce07d94SLucas De Marchi 
11119ce07d94SLucas De Marchi 	size = gen6_get_total_gtt_size(snb_gmch_ctl);
11129ce07d94SLucas De Marchi 	ggtt->vm.total = (size / sizeof(gen6_pte_t)) * I915_GTT_PAGE_SIZE;
11139ce07d94SLucas De Marchi 
11149ce07d94SLucas De Marchi 	ggtt->vm.alloc_pt_dma = alloc_pt_dma;
11159ce07d94SLucas De Marchi 	ggtt->vm.alloc_scratch_dma = alloc_pt_dma;
11169ce07d94SLucas De Marchi 
11179ce07d94SLucas De Marchi 	ggtt->vm.clear_range = nop_clear_range;
11189ce07d94SLucas De Marchi 	if (!HAS_FULL_PPGTT(i915) || intel_scanout_needs_vtd_wa(i915))
11199ce07d94SLucas De Marchi 		ggtt->vm.clear_range = gen6_ggtt_clear_range;
11209ce07d94SLucas De Marchi 	ggtt->vm.insert_page = gen6_ggtt_insert_page;
11219ce07d94SLucas De Marchi 	ggtt->vm.insert_entries = gen6_ggtt_insert_entries;
11229ce07d94SLucas De Marchi 	ggtt->vm.cleanup = gen6_gmch_remove;
11239ce07d94SLucas De Marchi 
11249ce07d94SLucas De Marchi 	ggtt->invalidate = gen6_ggtt_invalidate;
11259ce07d94SLucas De Marchi 
11269ce07d94SLucas De Marchi 	if (HAS_EDRAM(i915))
11279ce07d94SLucas De Marchi 		ggtt->vm.pte_encode = iris_pte_encode;
11289ce07d94SLucas De Marchi 	else if (IS_HASWELL(i915))
11299ce07d94SLucas De Marchi 		ggtt->vm.pte_encode = hsw_pte_encode;
11309ce07d94SLucas De Marchi 	else if (IS_VALLEYVIEW(i915))
11319ce07d94SLucas De Marchi 		ggtt->vm.pte_encode = byt_pte_encode;
11329ce07d94SLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 7)
11339ce07d94SLucas De Marchi 		ggtt->vm.pte_encode = ivb_pte_encode;
11349ce07d94SLucas De Marchi 	else
11359ce07d94SLucas De Marchi 		ggtt->vm.pte_encode = snb_pte_encode;
11369ce07d94SLucas De Marchi 
11379ce07d94SLucas De Marchi 	ggtt->vm.vma_ops.bind_vma    = intel_ggtt_bind_vma;
11389ce07d94SLucas De Marchi 	ggtt->vm.vma_ops.unbind_vma  = intel_ggtt_unbind_vma;
11399ce07d94SLucas De Marchi 
11409ce07d94SLucas De Marchi 	return ggtt_probe_common(ggtt, size);
11419ce07d94SLucas De Marchi }
11429ce07d94SLucas De Marchi 
11432c86e55dSMatthew Auld static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt)
11442c86e55dSMatthew Auld {
11452c86e55dSMatthew Auld 	struct drm_i915_private *i915 = gt->i915;
11462c86e55dSMatthew Auld 	int ret;
11472c86e55dSMatthew Auld 
11482c86e55dSMatthew Auld 	ggtt->vm.gt = gt;
11492c86e55dSMatthew Auld 	ggtt->vm.i915 = i915;
1150e322551fSThomas Zimmermann 	ggtt->vm.dma = i915->drm.dev;
11514d8151aeSThomas Hellström 	dma_resv_init(&ggtt->vm._resv);
11522c86e55dSMatthew Auld 
11539ce07d94SLucas De Marchi 	if (GRAPHICS_VER(i915) >= 8)
11549ce07d94SLucas De Marchi 		ret = gen8_gmch_probe(ggtt);
11559ce07d94SLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 6)
11569ce07d94SLucas De Marchi 		ret = gen6_gmch_probe(ggtt);
11572c86e55dSMatthew Auld 	else
11589ce07d94SLucas De Marchi 		ret = intel_ggtt_gmch_probe(ggtt);
11599ce07d94SLucas De Marchi 
116026ad4f8bSMaarten Lankhorst 	if (ret) {
11614d8151aeSThomas Hellström 		dma_resv_fini(&ggtt->vm._resv);
11622c86e55dSMatthew Auld 		return ret;
116326ad4f8bSMaarten Lankhorst 	}
11642c86e55dSMatthew Auld 
11652c86e55dSMatthew Auld 	if ((ggtt->vm.total - 1) >> 32) {
116636034c95SWambui Karuga 		drm_err(&i915->drm,
116736034c95SWambui Karuga 			"We never expected a Global GTT with more than 32bits"
11682c86e55dSMatthew Auld 			" of address space! Found %lldM!\n",
11692c86e55dSMatthew Auld 			ggtt->vm.total >> 20);
11702c86e55dSMatthew Auld 		ggtt->vm.total = 1ULL << 32;
11712c86e55dSMatthew Auld 		ggtt->mappable_end =
11722c86e55dSMatthew Auld 			min_t(u64, ggtt->mappable_end, ggtt->vm.total);
11732c86e55dSMatthew Auld 	}
11742c86e55dSMatthew Auld 
11752c86e55dSMatthew Auld 	if (ggtt->mappable_end > ggtt->vm.total) {
117636034c95SWambui Karuga 		drm_err(&i915->drm,
117736034c95SWambui Karuga 			"mappable aperture extends past end of GGTT,"
11782c86e55dSMatthew Auld 			" aperture=%pa, total=%llx\n",
11792c86e55dSMatthew Auld 			&ggtt->mappable_end, ggtt->vm.total);
11802c86e55dSMatthew Auld 		ggtt->mappable_end = ggtt->vm.total;
11812c86e55dSMatthew Auld 	}
11822c86e55dSMatthew Auld 
11832c86e55dSMatthew Auld 	/* GMADR is the PCI mmio aperture into the global GTT. */
118436034c95SWambui Karuga 	drm_dbg(&i915->drm, "GGTT size = %lluM\n", ggtt->vm.total >> 20);
118536034c95SWambui Karuga 	drm_dbg(&i915->drm, "GMADR size = %lluM\n",
118636034c95SWambui Karuga 		(u64)ggtt->mappable_end >> 20);
118736034c95SWambui Karuga 	drm_dbg(&i915->drm, "DSM size = %lluM\n",
11882c86e55dSMatthew Auld 		(u64)resource_size(&intel_graphics_stolen_res) >> 20);
11892c86e55dSMatthew Auld 
11902c86e55dSMatthew Auld 	return 0;
11912c86e55dSMatthew Auld }
11922c86e55dSMatthew Auld 
11932c86e55dSMatthew Auld /**
11942c86e55dSMatthew Auld  * i915_ggtt_probe_hw - Probe GGTT hardware location
11952c86e55dSMatthew Auld  * @i915: i915 device
11962c86e55dSMatthew Auld  */
11972c86e55dSMatthew Auld int i915_ggtt_probe_hw(struct drm_i915_private *i915)
11982c86e55dSMatthew Auld {
11992c86e55dSMatthew Auld 	int ret;
12002c86e55dSMatthew Auld 
1201848915c3SMichał Winiarski 	ret = ggtt_probe_hw(to_gt(i915)->ggtt, to_gt(i915));
12022c86e55dSMatthew Auld 	if (ret)
12032c86e55dSMatthew Auld 		return ret;
12042c86e55dSMatthew Auld 
1205a7f46d5bSTvrtko Ursulin 	if (i915_vtd_active(i915))
1206dc483ba5SJani Nikula 		drm_info(&i915->drm, "VT-d active for gfx access\n");
12072c86e55dSMatthew Auld 
12082c86e55dSMatthew Auld 	return 0;
12092c86e55dSMatthew Auld }
12102c86e55dSMatthew Auld 
12112c86e55dSMatthew Auld int i915_ggtt_enable_hw(struct drm_i915_private *i915)
12122c86e55dSMatthew Auld {
12139ce07d94SLucas De Marchi 	if (GRAPHICS_VER(i915) < 6)
12149ce07d94SLucas De Marchi 		return intel_ggtt_gmch_enable_hw(i915);
12159ce07d94SLucas De Marchi 
12169ce07d94SLucas De Marchi 	return 0;
12172c86e55dSMatthew Auld }
12182c86e55dSMatthew Auld 
12192c86e55dSMatthew Auld void i915_ggtt_enable_guc(struct i915_ggtt *ggtt)
12202c86e55dSMatthew Auld {
12212c86e55dSMatthew Auld 	GEM_BUG_ON(ggtt->invalidate != gen8_ggtt_invalidate);
12222c86e55dSMatthew Auld 
12232c86e55dSMatthew Auld 	ggtt->invalidate = guc_ggtt_invalidate;
12242c86e55dSMatthew Auld 
12252c86e55dSMatthew Auld 	ggtt->invalidate(ggtt);
12262c86e55dSMatthew Auld }
12272c86e55dSMatthew Auld 
12282c86e55dSMatthew Auld void i915_ggtt_disable_guc(struct i915_ggtt *ggtt)
12292c86e55dSMatthew Auld {
12302c86e55dSMatthew Auld 	/* XXX Temporary pardon for error unload */
12312c86e55dSMatthew Auld 	if (ggtt->invalidate == gen8_ggtt_invalidate)
12322c86e55dSMatthew Auld 		return;
12332c86e55dSMatthew Auld 
12342c86e55dSMatthew Auld 	/* We should only be called after i915_ggtt_enable_guc() */
12352c86e55dSMatthew Auld 	GEM_BUG_ON(ggtt->invalidate != guc_ggtt_invalidate);
12362c86e55dSMatthew Auld 
12372c86e55dSMatthew Auld 	ggtt->invalidate = gen8_ggtt_invalidate;
12382c86e55dSMatthew Auld 
12392c86e55dSMatthew Auld 	ggtt->invalidate(ggtt);
12402c86e55dSMatthew Auld }
12412c86e55dSMatthew Auld 
12428d2f683fSImre Deak /**
12438d2f683fSImre Deak  * i915_ggtt_resume_vm - Restore the memory mappings for a GGTT or DPT VM
12448d2f683fSImre Deak  * @vm: The VM to restore the mappings for
12458d2f683fSImre Deak  *
12468d2f683fSImre Deak  * Restore the memory mappings for all objects mapped to HW via the GGTT or a
12478d2f683fSImre Deak  * DPT page table.
12488d2f683fSImre Deak  *
12498d2f683fSImre Deak  * Returns %true if restoring the mapping for any object that was in a write
12508d2f683fSImre Deak  * domain before suspend.
12518d2f683fSImre Deak  */
12528d2f683fSImre Deak bool i915_ggtt_resume_vm(struct i915_address_space *vm)
12532c86e55dSMatthew Auld {
125480e5351dSChris Wilson 	struct i915_vma *vma;
12558d2f683fSImre Deak 	bool write_domain_objs = false;
12562ef6efa7SThomas Hellström 	bool retained_ptes;
12572c86e55dSMatthew Auld 
12588d2f683fSImre Deak 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
12592c86e55dSMatthew Auld 
12602ef6efa7SThomas Hellström 	/*
12612ef6efa7SThomas Hellström 	 * First fill our portion of the GTT with scratch pages if
12622ef6efa7SThomas Hellström 	 * they were not retained across suspend.
12632ef6efa7SThomas Hellström 	 */
12642ef6efa7SThomas Hellström 	retained_ptes = suspend_retains_ptes(vm) &&
12652ef6efa7SThomas Hellström 		!i915_vm_to_ggtt(vm)->pte_lost &&
12662ef6efa7SThomas Hellström 		!GEM_WARN_ON(i915_vm_to_ggtt(vm)->probed_pte != read_last_pte(vm));
12672ef6efa7SThomas Hellström 
12682ef6efa7SThomas Hellström 	if (!retained_ptes)
12698d2f683fSImre Deak 		vm->clear_range(vm, 0, vm->total);
12702c86e55dSMatthew Auld 
12712c86e55dSMatthew Auld 	/* clflush objects bound into the GGTT and rebind them. */
12728d2f683fSImre Deak 	list_for_each_entry(vma, &vm->bound_list, vm_link) {
12732c86e55dSMatthew Auld 		struct drm_i915_gem_object *obj = vma->obj;
1274cd0452aaSChris Wilson 		unsigned int was_bound =
1275cd0452aaSChris Wilson 			atomic_read(&vma->flags) & I915_VMA_BIND_MASK;
12762c86e55dSMatthew Auld 
1277cd0452aaSChris Wilson 		GEM_BUG_ON(!was_bound);
1278*bc247253SThomas Hellström 		if (!retained_ptes) {
1279*bc247253SThomas Hellström 			/*
1280*bc247253SThomas Hellström 			 * Clear the bound flags of the vma resource to allow
1281*bc247253SThomas Hellström 			 * ptes to be repopulated.
1282*bc247253SThomas Hellström 			 */
1283*bc247253SThomas Hellström 			vma->resource->bound_flags = 0;
1284647bfd26STvrtko Ursulin 			vma->ops->bind_vma(vm, NULL, vma->resource,
12852c86e55dSMatthew Auld 					   obj ? obj->cache_level : 0,
1286cd0452aaSChris Wilson 					   was_bound);
1287*bc247253SThomas Hellström 		}
12882c86e55dSMatthew Auld 		if (obj) { /* only used during resume => exclusive access */
12898d2f683fSImre Deak 			write_domain_objs |= fetch_and_zero(&obj->write_domain);
12902c86e55dSMatthew Auld 			obj->read_domains |= I915_GEM_DOMAIN_GTT;
12912c86e55dSMatthew Auld 		}
12922c86e55dSMatthew Auld 	}
12932c86e55dSMatthew Auld 
12948d2f683fSImre Deak 	return write_domain_objs;
12958d2f683fSImre Deak }
12968d2f683fSImre Deak 
12978d2f683fSImre Deak void i915_ggtt_resume(struct i915_ggtt *ggtt)
12988d2f683fSImre Deak {
12998d2f683fSImre Deak 	bool flush;
13008d2f683fSImre Deak 
13018d2f683fSImre Deak 	intel_gt_check_and_clear_faults(ggtt->vm.gt);
13028d2f683fSImre Deak 
13038d2f683fSImre Deak 	flush = i915_ggtt_resume_vm(&ggtt->vm);
13048d2f683fSImre Deak 
13052c86e55dSMatthew Auld 	ggtt->invalidate(ggtt);
13062c86e55dSMatthew Auld 
13072c86e55dSMatthew Auld 	if (flush)
13082c86e55dSMatthew Auld 		wbinvd_on_all_cpus();
13092c86e55dSMatthew Auld 
1310c816723bSLucas De Marchi 	if (GRAPHICS_VER(ggtt->vm.i915) >= 8)
13112c86e55dSMatthew Auld 		setup_private_pat(ggtt->vm.gt->uncore);
1312dec9cf9eSChris Wilson 
1313dec9cf9eSChris Wilson 	intel_ggtt_restore_fences(ggtt);
13142c86e55dSMatthew Auld }
13152ef6efa7SThomas Hellström 
13162ef6efa7SThomas Hellström void i915_ggtt_mark_pte_lost(struct drm_i915_private *i915, bool val)
13172ef6efa7SThomas Hellström {
13182ef6efa7SThomas Hellström 	to_gt(i915)->ggtt->pte_lost = val;
13192ef6efa7SThomas Hellström }
1320