xref: /dflybsd-src/sys/dev/drm/i915/i915_gem_gtt.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright © 2010 Daniel Vetter
3ba55f2f5SFrançois Tigeot  * Copyright © 2011-2014 Intel Corporation
4e3adcf8fSFrançois Tigeot  *
5e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
6e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
7e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
8e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
10e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
11e3adcf8fSFrançois Tigeot  *
12e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
13e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
14e3adcf8fSFrançois Tigeot  * Software.
15e3adcf8fSFrançois Tigeot  *
16e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21e3adcf8fSFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22e3adcf8fSFrançois Tigeot  * IN THE SOFTWARE.
23e3adcf8fSFrançois Tigeot  *
24e3adcf8fSFrançois Tigeot  */
25e3adcf8fSFrançois Tigeot 
26a85cb24fSFrançois Tigeot #include <linux/slab.h> /* fault-inject.h is not standalone! */
27a85cb24fSFrançois Tigeot 
28a85cb24fSFrançois Tigeot #include <linux/fault-inject.h>
29a85cb24fSFrançois Tigeot #include <linux/log2.h>
30a85cb24fSFrançois Tigeot #include <linux/random.h>
31ba55f2f5SFrançois Tigeot #include <linux/seq_file.h>
3245a22cb3SFrançois Tigeot #include <linux/stop_machine.h>
33a85cb24fSFrançois Tigeot 
34a85cb24fSFrançois Tigeot #include <asm/set_memory.h>
35a85cb24fSFrançois Tigeot 
3618e26a6dSFrançois Tigeot #include <drm/drmP.h>
375c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
38a85cb24fSFrançois Tigeot 
39e3adcf8fSFrançois Tigeot #include "i915_drv.h"
40477eb7f9SFrançois Tigeot #include "i915_vgpu.h"
41477eb7f9SFrançois Tigeot #include "i915_trace.h"
42e3adcf8fSFrançois Tigeot #include "intel_drv.h"
434be47400SFrançois Tigeot #include "intel_frontbuffer.h"
44e3adcf8fSFrançois Tigeot 
451e12ee3bSFrançois Tigeot #define I915_GFP_DMA (GFP_KERNEL | __GFP_HIGHMEM)
461e12ee3bSFrançois Tigeot 
472c9916cdSFrançois Tigeot /**
482c9916cdSFrançois Tigeot  * DOC: Global GTT views
492c9916cdSFrançois Tigeot  *
502c9916cdSFrançois Tigeot  * Background and previous state
512c9916cdSFrançois Tigeot  *
522c9916cdSFrançois Tigeot  * Historically objects could exists (be bound) in global GTT space only as
532c9916cdSFrançois Tigeot  * singular instances with a view representing all of the object's backing pages
542c9916cdSFrançois Tigeot  * in a linear fashion. This view will be called a normal view.
552c9916cdSFrançois Tigeot  *
562c9916cdSFrançois Tigeot  * To support multiple views of the same object, where the number of mapped
572c9916cdSFrançois Tigeot  * pages is not equal to the backing store, or where the layout of the pages
582c9916cdSFrançois Tigeot  * is not linear, concept of a GGTT view was added.
592c9916cdSFrançois Tigeot  *
602c9916cdSFrançois Tigeot  * One example of an alternative view is a stereo display driven by a single
612c9916cdSFrançois Tigeot  * image. In this case we would have a framebuffer looking like this
622c9916cdSFrançois Tigeot  * (2x2 pages):
632c9916cdSFrançois Tigeot  *
642c9916cdSFrançois Tigeot  *    12
652c9916cdSFrançois Tigeot  *    34
662c9916cdSFrançois Tigeot  *
672c9916cdSFrançois Tigeot  * Above would represent a normal GGTT view as normally mapped for GPU or CPU
682c9916cdSFrançois Tigeot  * rendering. In contrast, fed to the display engine would be an alternative
692c9916cdSFrançois Tigeot  * view which could look something like this:
702c9916cdSFrançois Tigeot  *
712c9916cdSFrançois Tigeot  *   1212
722c9916cdSFrançois Tigeot  *   3434
732c9916cdSFrançois Tigeot  *
742c9916cdSFrançois Tigeot  * In this example both the size and layout of pages in the alternative view is
752c9916cdSFrançois Tigeot  * different from the normal view.
762c9916cdSFrançois Tigeot  *
772c9916cdSFrançois Tigeot  * Implementation and usage
782c9916cdSFrançois Tigeot  *
792c9916cdSFrançois Tigeot  * GGTT views are implemented using VMAs and are distinguished via enum
802c9916cdSFrançois Tigeot  * i915_ggtt_view_type and struct i915_ggtt_view.
812c9916cdSFrançois Tigeot  *
822c9916cdSFrançois Tigeot  * A new flavour of core GEM functions which work with GGTT bound objects were
83477eb7f9SFrançois Tigeot  * added with the _ggtt_ infix, and sometimes with _view postfix to avoid
84477eb7f9SFrançois Tigeot  * renaming  in large amounts of code. They take the struct i915_ggtt_view
85477eb7f9SFrançois Tigeot  * parameter encapsulating all metadata required to implement a view.
862c9916cdSFrançois Tigeot  *
872c9916cdSFrançois Tigeot  * As a helper for callers which are only interested in the normal view,
882c9916cdSFrançois Tigeot  * globally const i915_ggtt_view_normal singleton instance exists. All old core
892c9916cdSFrançois Tigeot  * GEM API functions, the ones not taking the view parameter, are operating on,
902c9916cdSFrançois Tigeot  * or with the normal GGTT view.
912c9916cdSFrançois Tigeot  *
922c9916cdSFrançois Tigeot  * Code wanting to add or use a new GGTT view needs to:
932c9916cdSFrançois Tigeot  *
942c9916cdSFrançois Tigeot  * 1. Add a new enum with a suitable name.
952c9916cdSFrançois Tigeot  * 2. Extend the metadata in the i915_ggtt_view structure if required.
962c9916cdSFrançois Tigeot  * 3. Add support to i915_get_vma_pages().
972c9916cdSFrançois Tigeot  *
982c9916cdSFrançois Tigeot  * New views are required to build a scatter-gather table from within the
992c9916cdSFrançois Tigeot  * i915_get_vma_pages function. This table is stored in the vma.ggtt_view and
1002c9916cdSFrançois Tigeot  * exists for the lifetime of an VMA.
1012c9916cdSFrançois Tigeot  *
1022c9916cdSFrançois Tigeot  * Core API is designed to have copy semantics which means that passed in
1032c9916cdSFrançois Tigeot  * struct i915_ggtt_view does not need to be persistent (left around after
1042c9916cdSFrançois Tigeot  * calling the core API functions).
1052c9916cdSFrançois Tigeot  *
1062c9916cdSFrançois Tigeot  */
1072c9916cdSFrançois Tigeot 
10819c468b4SFrançois Tigeot static int
10919c468b4SFrançois Tigeot i915_get_ggtt_vma_pages(struct i915_vma *vma);
11019c468b4SFrançois Tigeot 
gen6_ggtt_invalidate(struct drm_i915_private * dev_priv)111a85cb24fSFrançois Tigeot static void gen6_ggtt_invalidate(struct drm_i915_private *dev_priv)
112a85cb24fSFrançois Tigeot {
113a85cb24fSFrançois Tigeot 	/* Note that as an uncached mmio write, this should flush the
114a85cb24fSFrançois Tigeot 	 * WCB of the writes into the GGTT before it triggers the invalidate.
115a85cb24fSFrançois Tigeot 	 */
116a85cb24fSFrançois Tigeot 	I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
117a85cb24fSFrançois Tigeot }
118a85cb24fSFrançois Tigeot 
guc_ggtt_invalidate(struct drm_i915_private * dev_priv)119a85cb24fSFrançois Tigeot static void guc_ggtt_invalidate(struct drm_i915_private *dev_priv)
120a85cb24fSFrançois Tigeot {
121a85cb24fSFrançois Tigeot 	gen6_ggtt_invalidate(dev_priv);
122a85cb24fSFrançois Tigeot 	I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
123a85cb24fSFrançois Tigeot }
124a85cb24fSFrançois Tigeot 
gmch_ggtt_invalidate(struct drm_i915_private * dev_priv)125a85cb24fSFrançois Tigeot static void gmch_ggtt_invalidate(struct drm_i915_private *dev_priv)
126a85cb24fSFrançois Tigeot {
127a85cb24fSFrançois Tigeot 	intel_gtt_chipset_flush();
128a85cb24fSFrançois Tigeot }
129a85cb24fSFrançois Tigeot 
i915_ggtt_invalidate(struct drm_i915_private * i915)130a85cb24fSFrançois Tigeot static inline void i915_ggtt_invalidate(struct drm_i915_private *i915)
131a85cb24fSFrançois Tigeot {
132a85cb24fSFrançois Tigeot 	i915->ggtt.invalidate(i915);
133a85cb24fSFrançois Tigeot }
1342c9916cdSFrançois Tigeot 
intel_sanitize_enable_ppgtt(struct drm_i915_private * dev_priv,int enable_ppgtt)1351487f786SFrançois Tigeot int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
1361487f786SFrançois Tigeot 			       	int enable_ppgtt)
13724edb884SFrançois Tigeot {
1382c9916cdSFrançois Tigeot 	bool has_full_ppgtt;
139aee94f86SFrançois Tigeot 	bool has_full_48bit_ppgtt;
1402c9916cdSFrançois Tigeot 
141*3f2dd94aSFrançois Tigeot 	if (!dev_priv->info.has_aliasing_ppgtt)
142*3f2dd94aSFrançois Tigeot 		return 0;
143*3f2dd94aSFrançois Tigeot 
144a85cb24fSFrançois Tigeot 	has_full_ppgtt = dev_priv->info.has_full_ppgtt;
145a85cb24fSFrançois Tigeot 	has_full_48bit_ppgtt = dev_priv->info.has_full_48bit_ppgtt;
1462c9916cdSFrançois Tigeot 
1471e12ee3bSFrançois Tigeot 	if (intel_vgpu_active(dev_priv)) {
148*3f2dd94aSFrançois Tigeot 		/* GVT-g has no support for 32bit ppgtt */
1491e12ee3bSFrançois Tigeot 		has_full_ppgtt = false;
150*3f2dd94aSFrançois Tigeot 		has_full_48bit_ppgtt = intel_vgpu_has_full_48bit_ppgtt(dev_priv);
1511e12ee3bSFrançois Tigeot 	}
152477eb7f9SFrançois Tigeot 
1532c9916cdSFrançois Tigeot 	/*
1542c9916cdSFrançois Tigeot 	 * We don't allow disabling PPGTT for gen9+ as it's a requirement for
1552c9916cdSFrançois Tigeot 	 * execlists, the sole mechanism available to submit work.
1562c9916cdSFrançois Tigeot 	 */
1571487f786SFrançois Tigeot 	if (enable_ppgtt == 0 && INTEL_GEN(dev_priv) < 9)
15824edb884SFrançois Tigeot 		return 0;
15924edb884SFrançois Tigeot 
16024edb884SFrançois Tigeot 	if (enable_ppgtt == 1)
16124edb884SFrançois Tigeot 		return 1;
16224edb884SFrançois Tigeot 
1632c9916cdSFrançois Tigeot 	if (enable_ppgtt == 2 && has_full_ppgtt)
16424edb884SFrançois Tigeot 		return 2;
16524edb884SFrançois Tigeot 
166aee94f86SFrançois Tigeot 	if (enable_ppgtt == 3 && has_full_48bit_ppgtt)
167aee94f86SFrançois Tigeot 		return 3;
168aee94f86SFrançois Tigeot 
169ba55f2f5SFrançois Tigeot 	/* Disable ppgtt on SNB if VT-d is on. */
170*3f2dd94aSFrançois Tigeot 	if (IS_GEN6(dev_priv) && intel_vtd_active()) {
171ba55f2f5SFrançois Tigeot 		DRM_INFO("Disabling PPGTT because VT-d is on\n");
17224edb884SFrançois Tigeot 		return 0;
173ba55f2f5SFrançois Tigeot 	}
174f4e1c372SFrançois Tigeot 
17524edb884SFrançois Tigeot 	/* Early VLV doesn't have this */
176303bf270SFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) && dev_priv->drm.pdev->revision < 0xb) {
17724edb884SFrançois Tigeot 		DRM_DEBUG_DRIVER("disabling PPGTT on pre-B3 step VLV\n");
17824edb884SFrançois Tigeot 		return 0;
17924edb884SFrançois Tigeot 	}
18024edb884SFrançois Tigeot 
181*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8 && i915_modparams.enable_execlists) {
182*3f2dd94aSFrançois Tigeot 		if (has_full_48bit_ppgtt)
183*3f2dd94aSFrançois Tigeot 			return 3;
184*3f2dd94aSFrançois Tigeot 
185*3f2dd94aSFrançois Tigeot 		if (has_full_ppgtt)
186*3f2dd94aSFrançois Tigeot 			return 2;
187*3f2dd94aSFrançois Tigeot 	}
188*3f2dd94aSFrançois Tigeot 
189*3f2dd94aSFrançois Tigeot 	return 1;
190ba55f2f5SFrançois Tigeot }
1919edbd4a0SFrançois Tigeot 
ppgtt_bind_vma(struct i915_vma * vma,enum i915_cache_level cache_level,u32 unused)19219c468b4SFrançois Tigeot static int ppgtt_bind_vma(struct i915_vma *vma,
193ba55f2f5SFrançois Tigeot 			  enum i915_cache_level cache_level,
19419c468b4SFrançois Tigeot 			  u32 unused)
19519c468b4SFrançois Tigeot {
196a85cb24fSFrançois Tigeot 	u32 pte_flags;
197a85cb24fSFrançois Tigeot 	int ret;
198a85cb24fSFrançois Tigeot 
199a85cb24fSFrançois Tigeot 	if (!(vma->flags & I915_VMA_LOCAL_BIND)) {
200a85cb24fSFrançois Tigeot 		ret = vma->vm->allocate_va_range(vma->vm, vma->node.start,
201a85cb24fSFrançois Tigeot 						 vma->size);
202a85cb24fSFrançois Tigeot 		if (ret)
203a85cb24fSFrançois Tigeot 			return ret;
204a85cb24fSFrançois Tigeot 	}
2059edbd4a0SFrançois Tigeot 
20619c468b4SFrançois Tigeot 	/* Currently applicable only to VLV */
207a85cb24fSFrançois Tigeot 	pte_flags = 0;
20819c468b4SFrançois Tigeot 	if (vma->obj->gt_ro)
20919c468b4SFrançois Tigeot 		pte_flags |= PTE_READ_ONLY;
21019c468b4SFrançois Tigeot 
211*3f2dd94aSFrançois Tigeot 	vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
21219c468b4SFrançois Tigeot 
21319c468b4SFrançois Tigeot 	return 0;
21419c468b4SFrançois Tigeot }
21519c468b4SFrançois Tigeot 
ppgtt_unbind_vma(struct i915_vma * vma)21619c468b4SFrançois Tigeot static void ppgtt_unbind_vma(struct i915_vma *vma)
21719c468b4SFrançois Tigeot {
218a85cb24fSFrançois Tigeot 	vma->vm->clear_range(vma->vm, vma->node.start, vma->size);
21919c468b4SFrançois Tigeot }
22019c468b4SFrançois Tigeot 
ppgtt_set_pages(struct i915_vma * vma)221*3f2dd94aSFrançois Tigeot static int ppgtt_set_pages(struct i915_vma *vma)
222*3f2dd94aSFrançois Tigeot {
223*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(vma->pages);
224*3f2dd94aSFrançois Tigeot 
225*3f2dd94aSFrançois Tigeot 	vma->pages = vma->obj->mm.pages;
226*3f2dd94aSFrançois Tigeot 
227*3f2dd94aSFrançois Tigeot 	vma->page_sizes = vma->obj->mm.page_sizes;
228*3f2dd94aSFrançois Tigeot 
229*3f2dd94aSFrançois Tigeot 	return 0;
230*3f2dd94aSFrançois Tigeot }
231*3f2dd94aSFrançois Tigeot 
clear_pages(struct i915_vma * vma)232*3f2dd94aSFrançois Tigeot static void clear_pages(struct i915_vma *vma)
233*3f2dd94aSFrançois Tigeot {
234*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(!vma->pages);
235*3f2dd94aSFrançois Tigeot 
236*3f2dd94aSFrançois Tigeot 	if (vma->pages != vma->obj->mm.pages) {
237*3f2dd94aSFrançois Tigeot 		sg_free_table(vma->pages);
238*3f2dd94aSFrançois Tigeot 		kfree(vma->pages);
239*3f2dd94aSFrançois Tigeot 	}
240*3f2dd94aSFrançois Tigeot 	vma->pages = NULL;
241*3f2dd94aSFrançois Tigeot 
242*3f2dd94aSFrançois Tigeot 	memset(&vma->page_sizes, 0, sizeof(vma->page_sizes));
243*3f2dd94aSFrançois Tigeot }
244*3f2dd94aSFrançois Tigeot 
gen8_pte_encode(dma_addr_t addr,enum i915_cache_level level)24519c468b4SFrançois Tigeot static gen8_pte_t gen8_pte_encode(dma_addr_t addr,
2461e12ee3bSFrançois Tigeot 				  enum i915_cache_level level)
2479edbd4a0SFrançois Tigeot {
2481e12ee3bSFrançois Tigeot 	gen8_pte_t pte = _PAGE_PRESENT | _PAGE_RW;
2499edbd4a0SFrançois Tigeot 	pte |= addr;
250ba55f2f5SFrançois Tigeot 
251ba55f2f5SFrançois Tigeot 	switch (level) {
252ba55f2f5SFrançois Tigeot 	case I915_CACHE_NONE:
253*3f2dd94aSFrançois Tigeot 		pte |= PPAT_UNCACHED;
254ba55f2f5SFrançois Tigeot 		break;
255ba55f2f5SFrançois Tigeot 	case I915_CACHE_WT:
256*3f2dd94aSFrançois Tigeot 		pte |= PPAT_DISPLAY_ELLC;
257ba55f2f5SFrançois Tigeot 		break;
258ba55f2f5SFrançois Tigeot 	default:
259*3f2dd94aSFrançois Tigeot 		pte |= PPAT_CACHED;
260ba55f2f5SFrançois Tigeot 		break;
261ba55f2f5SFrançois Tigeot 	}
262ba55f2f5SFrançois Tigeot 
2639edbd4a0SFrançois Tigeot 	return pte;
2649edbd4a0SFrançois Tigeot }
2659edbd4a0SFrançois Tigeot 
gen8_pde_encode(const dma_addr_t addr,const enum i915_cache_level level)266a05eeebfSFrançois Tigeot static gen8_pde_t gen8_pde_encode(const dma_addr_t addr,
267a05eeebfSFrançois Tigeot 				  const enum i915_cache_level level)
268e3adcf8fSFrançois Tigeot {
269477eb7f9SFrançois Tigeot 	gen8_pde_t pde = _PAGE_PRESENT | _PAGE_RW;
2709edbd4a0SFrançois Tigeot 	pde |= addr;
2719edbd4a0SFrançois Tigeot 	if (level != I915_CACHE_NONE)
272*3f2dd94aSFrançois Tigeot 		pde |= PPAT_CACHED_PDE;
2739edbd4a0SFrançois Tigeot 	else
274*3f2dd94aSFrançois Tigeot 		pde |= PPAT_UNCACHED;
2759edbd4a0SFrançois Tigeot 	return pde;
2769edbd4a0SFrançois Tigeot }
2779edbd4a0SFrançois Tigeot 
278352ff8bdSFrançois Tigeot #define gen8_pdpe_encode gen8_pde_encode
279352ff8bdSFrançois Tigeot #define gen8_pml4e_encode gen8_pde_encode
280352ff8bdSFrançois Tigeot 
snb_pte_encode(dma_addr_t addr,enum i915_cache_level level,u32 unused)281477eb7f9SFrançois Tigeot static gen6_pte_t snb_pte_encode(dma_addr_t addr,
2829edbd4a0SFrançois Tigeot 				 enum i915_cache_level level,
2831e12ee3bSFrançois Tigeot 				 u32 unused)
2849edbd4a0SFrançois Tigeot {
2851e12ee3bSFrançois Tigeot 	gen6_pte_t pte = GEN6_PTE_VALID;
286f4e1c372SFrançois Tigeot 	pte |= GEN6_PTE_ADDR_ENCODE(addr);
287f4e1c372SFrançois Tigeot 
288f4e1c372SFrançois Tigeot 	switch (level) {
2899edbd4a0SFrançois Tigeot 	case I915_CACHE_L3_LLC:
2909edbd4a0SFrançois Tigeot 	case I915_CACHE_LLC:
2919edbd4a0SFrançois Tigeot 		pte |= GEN6_PTE_CACHE_LLC;
2929edbd4a0SFrançois Tigeot 		break;
2939edbd4a0SFrançois Tigeot 	case I915_CACHE_NONE:
2949edbd4a0SFrançois Tigeot 		pte |= GEN6_PTE_UNCACHED;
2959edbd4a0SFrançois Tigeot 		break;
2969edbd4a0SFrançois Tigeot 	default:
2972c9916cdSFrançois Tigeot 		MISSING_CASE(level);
2989edbd4a0SFrançois Tigeot 	}
2999edbd4a0SFrançois Tigeot 
3009edbd4a0SFrançois Tigeot 	return pte;
3019edbd4a0SFrançois Tigeot }
3029edbd4a0SFrançois Tigeot 
ivb_pte_encode(dma_addr_t addr,enum i915_cache_level level,u32 unused)303477eb7f9SFrançois Tigeot static gen6_pte_t ivb_pte_encode(dma_addr_t addr,
3049edbd4a0SFrançois Tigeot 				 enum i915_cache_level level,
3051e12ee3bSFrançois Tigeot 				 u32 unused)
3069edbd4a0SFrançois Tigeot {
3071e12ee3bSFrançois Tigeot 	gen6_pte_t pte = GEN6_PTE_VALID;
3089edbd4a0SFrançois Tigeot 	pte |= GEN6_PTE_ADDR_ENCODE(addr);
3099edbd4a0SFrançois Tigeot 
3109edbd4a0SFrançois Tigeot 	switch (level) {
3119edbd4a0SFrançois Tigeot 	case I915_CACHE_L3_LLC:
3129edbd4a0SFrançois Tigeot 		pte |= GEN7_PTE_CACHE_L3_LLC;
313f4e1c372SFrançois Tigeot 		break;
314f4e1c372SFrançois Tigeot 	case I915_CACHE_LLC:
315f4e1c372SFrançois Tigeot 		pte |= GEN6_PTE_CACHE_LLC;
316f4e1c372SFrançois Tigeot 		break;
317f4e1c372SFrançois Tigeot 	case I915_CACHE_NONE:
318f4e1c372SFrançois Tigeot 		pte |= GEN6_PTE_UNCACHED;
319f4e1c372SFrançois Tigeot 		break;
320f4e1c372SFrançois Tigeot 	default:
3212c9916cdSFrançois Tigeot 		MISSING_CASE(level);
322f4e1c372SFrançois Tigeot 	}
323f4e1c372SFrançois Tigeot 
324f4e1c372SFrançois Tigeot 	return pte;
325f4e1c372SFrançois Tigeot }
326f4e1c372SFrançois Tigeot 
byt_pte_encode(dma_addr_t addr,enum i915_cache_level level,u32 flags)327477eb7f9SFrançois Tigeot static gen6_pte_t byt_pte_encode(dma_addr_t addr,
3289edbd4a0SFrançois Tigeot 				 enum i915_cache_level level,
3291e12ee3bSFrançois Tigeot 				 u32 flags)
3305d0b1887SFrançois Tigeot {
3311e12ee3bSFrançois Tigeot 	gen6_pte_t pte = GEN6_PTE_VALID;
3325d0b1887SFrançois Tigeot 	pte |= GEN6_PTE_ADDR_ENCODE(addr);
3335d0b1887SFrançois Tigeot 
33424edb884SFrançois Tigeot 	if (!(flags & PTE_READ_ONLY))
3355d0b1887SFrançois Tigeot 		pte |= BYT_PTE_WRITEABLE;
3365d0b1887SFrançois Tigeot 
3375d0b1887SFrançois Tigeot 	if (level != I915_CACHE_NONE)
3385d0b1887SFrançois Tigeot 		pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES;
3395d0b1887SFrançois Tigeot 
3405d0b1887SFrançois Tigeot 	return pte;
3415d0b1887SFrançois Tigeot }
3425d0b1887SFrançois Tigeot 
hsw_pte_encode(dma_addr_t addr,enum i915_cache_level level,u32 unused)343477eb7f9SFrançois Tigeot static gen6_pte_t hsw_pte_encode(dma_addr_t addr,
3449edbd4a0SFrançois Tigeot 				 enum i915_cache_level level,
3451e12ee3bSFrançois Tigeot 				 u32 unused)
3465d0b1887SFrançois Tigeot {
3471e12ee3bSFrançois Tigeot 	gen6_pte_t pte = GEN6_PTE_VALID;
3489edbd4a0SFrançois Tigeot 	pte |= HSW_PTE_ADDR_ENCODE(addr);
3495d0b1887SFrançois Tigeot 
3505d0b1887SFrançois Tigeot 	if (level != I915_CACHE_NONE)
3519edbd4a0SFrançois Tigeot 		pte |= HSW_WB_LLC_AGE3;
3525d0b1887SFrançois Tigeot 
3535d0b1887SFrançois Tigeot 	return pte;
3545d0b1887SFrançois Tigeot }
3555d0b1887SFrançois Tigeot 
iris_pte_encode(dma_addr_t addr,enum i915_cache_level level,u32 unused)356477eb7f9SFrançois Tigeot static gen6_pte_t iris_pte_encode(dma_addr_t addr,
3579edbd4a0SFrançois Tigeot 				  enum i915_cache_level level,
3581e12ee3bSFrançois Tigeot 				  u32 unused)
3599edbd4a0SFrançois Tigeot {
3601e12ee3bSFrançois Tigeot 	gen6_pte_t pte = GEN6_PTE_VALID;
3619edbd4a0SFrançois Tigeot 	pte |= HSW_PTE_ADDR_ENCODE(addr);
3629edbd4a0SFrançois Tigeot 
3639edbd4a0SFrançois Tigeot 	switch (level) {
3649edbd4a0SFrançois Tigeot 	case I915_CACHE_NONE:
3659edbd4a0SFrançois Tigeot 		break;
3669edbd4a0SFrançois Tigeot 	case I915_CACHE_WT:
3679edbd4a0SFrançois Tigeot 		pte |= HSW_WT_ELLC_LLC_AGE3;
3689edbd4a0SFrançois Tigeot 		break;
3699edbd4a0SFrançois Tigeot 	default:
3709edbd4a0SFrançois Tigeot 		pte |= HSW_WB_ELLC_LLC_AGE3;
3719edbd4a0SFrançois Tigeot 		break;
3729edbd4a0SFrançois Tigeot 	}
3739edbd4a0SFrançois Tigeot 
3749edbd4a0SFrançois Tigeot 	return pte;
3759edbd4a0SFrançois Tigeot }
3769edbd4a0SFrançois Tigeot 
vm_alloc_page(struct i915_address_space * vm,gfp_t gfp)377a85cb24fSFrançois Tigeot static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp)
378477eb7f9SFrançois Tigeot {
379*3f2dd94aSFrançois Tigeot 	struct pagevec *pvec = &vm->free_pages;
380477eb7f9SFrançois Tigeot 
381a85cb24fSFrançois Tigeot 	if (I915_SELFTEST_ONLY(should_fail(&vm->fault_attr, 1)))
382a85cb24fSFrançois Tigeot 		i915_gem_shrink_all(vm->i915);
383a85cb24fSFrançois Tigeot 
384*3f2dd94aSFrançois Tigeot 	if (likely(pvec->nr))
385*3f2dd94aSFrançois Tigeot 		return pvec->pages[--pvec->nr];
386*3f2dd94aSFrançois Tigeot 
387*3f2dd94aSFrançois Tigeot 	if (!vm->pt_kmap_wc)
388*3f2dd94aSFrançois Tigeot 		return alloc_page(gfp);
389*3f2dd94aSFrançois Tigeot 
390*3f2dd94aSFrançois Tigeot 	/* A placeholder for a specific mutex to guard the WC stash */
391*3f2dd94aSFrançois Tigeot 	lockdep_assert_held(&vm->i915->drm.struct_mutex);
392*3f2dd94aSFrançois Tigeot 
393*3f2dd94aSFrançois Tigeot 	/* Look in our global stash of WC pages... */
394*3f2dd94aSFrançois Tigeot 	pvec = &vm->i915->mm.wc_stash;
395*3f2dd94aSFrançois Tigeot 	if (likely(pvec->nr))
396*3f2dd94aSFrançois Tigeot 		return pvec->pages[--pvec->nr];
397*3f2dd94aSFrançois Tigeot 
398*3f2dd94aSFrançois Tigeot 	/* Otherwise batch allocate pages to amoritize cost of set_pages_wc. */
399*3f2dd94aSFrançois Tigeot 	do {
400*3f2dd94aSFrançois Tigeot 		struct page *page;
401a85cb24fSFrançois Tigeot 
402a85cb24fSFrançois Tigeot 		page = alloc_page(gfp);
403*3f2dd94aSFrançois Tigeot 		if (unlikely(!page))
404*3f2dd94aSFrançois Tigeot 			break;
405*3f2dd94aSFrançois Tigeot 
406*3f2dd94aSFrançois Tigeot 		pvec->pages[pvec->nr++] = page;
407*3f2dd94aSFrançois Tigeot 	} while (pagevec_space(pvec));
408*3f2dd94aSFrançois Tigeot 
409*3f2dd94aSFrançois Tigeot 	if (unlikely(!pvec->nr))
410a85cb24fSFrançois Tigeot 		return NULL;
411a85cb24fSFrançois Tigeot 
412*3f2dd94aSFrançois Tigeot 	set_pages_array_wc(pvec->pages, pvec->nr);
413a85cb24fSFrançois Tigeot 
414*3f2dd94aSFrançois Tigeot 	return pvec->pages[--pvec->nr];
415a85cb24fSFrançois Tigeot }
416a85cb24fSFrançois Tigeot 
vm_free_pages_release(struct i915_address_space * vm,bool immediate)417*3f2dd94aSFrançois Tigeot static void vm_free_pages_release(struct i915_address_space *vm,
418*3f2dd94aSFrançois Tigeot 				  bool immediate)
419a85cb24fSFrançois Tigeot {
420*3f2dd94aSFrançois Tigeot 	struct pagevec *pvec = &vm->free_pages;
421a85cb24fSFrançois Tigeot 
422*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(!pagevec_count(pvec));
423a85cb24fSFrançois Tigeot 
424*3f2dd94aSFrançois Tigeot 	if (vm->pt_kmap_wc) {
425*3f2dd94aSFrançois Tigeot 		struct pagevec *stash = &vm->i915->mm.wc_stash;
426*3f2dd94aSFrançois Tigeot 
427*3f2dd94aSFrançois Tigeot 		/* When we use WC, first fill up the global stash and then
428*3f2dd94aSFrançois Tigeot 		 * only if full immediately free the overflow.
429*3f2dd94aSFrançois Tigeot 		 */
430*3f2dd94aSFrançois Tigeot 
431*3f2dd94aSFrançois Tigeot 		lockdep_assert_held(&vm->i915->drm.struct_mutex);
432*3f2dd94aSFrançois Tigeot 		if (pagevec_space(stash)) {
433*3f2dd94aSFrançois Tigeot 			do {
434*3f2dd94aSFrançois Tigeot 				stash->pages[stash->nr++] =
435*3f2dd94aSFrançois Tigeot 					pvec->pages[--pvec->nr];
436*3f2dd94aSFrançois Tigeot 				if (!pvec->nr)
437*3f2dd94aSFrançois Tigeot 					return;
438*3f2dd94aSFrançois Tigeot 			} while (pagevec_space(stash));
439*3f2dd94aSFrançois Tigeot 
440*3f2dd94aSFrançois Tigeot 			/* As we have made some room in the VM's free_pages,
441*3f2dd94aSFrançois Tigeot 			 * we can wait for it to fill again. Unless we are
442*3f2dd94aSFrançois Tigeot 			 * inside i915_address_space_fini() and must
443*3f2dd94aSFrançois Tigeot 			 * immediately release the pages!
444*3f2dd94aSFrançois Tigeot 			 */
445*3f2dd94aSFrançois Tigeot 			if (!immediate)
446*3f2dd94aSFrançois Tigeot 				return;
447*3f2dd94aSFrançois Tigeot 		}
448*3f2dd94aSFrançois Tigeot 
449*3f2dd94aSFrançois Tigeot 		set_pages_array_wb(pvec->pages, pvec->nr);
450*3f2dd94aSFrançois Tigeot 	}
451*3f2dd94aSFrançois Tigeot 
452*3f2dd94aSFrançois Tigeot 	__pagevec_release(pvec);
453a85cb24fSFrançois Tigeot }
454a85cb24fSFrançois Tigeot 
vm_free_page(struct i915_address_space * vm,struct page * page)455a85cb24fSFrançois Tigeot static void vm_free_page(struct i915_address_space *vm, struct page *page)
456a85cb24fSFrançois Tigeot {
457a85cb24fSFrançois Tigeot 	if (!pagevec_add(&vm->free_pages, page))
458*3f2dd94aSFrançois Tigeot 		vm_free_pages_release(vm, false);
459a85cb24fSFrançois Tigeot }
460a85cb24fSFrançois Tigeot 
__setup_page_dma(struct i915_address_space * vm,struct i915_page_dma * p,gfp_t gfp)461a85cb24fSFrançois Tigeot static int __setup_page_dma(struct i915_address_space *vm,
462a85cb24fSFrançois Tigeot 			    struct i915_page_dma *p,
463a85cb24fSFrançois Tigeot 			    gfp_t gfp)
464a85cb24fSFrançois Tigeot {
465a85cb24fSFrançois Tigeot 	p->page = vm_alloc_page(vm, gfp | __GFP_NOWARN | __GFP_NORETRY);
466a85cb24fSFrançois Tigeot 	if (unlikely(!p->page))
467477eb7f9SFrançois Tigeot 		return -ENOMEM;
468477eb7f9SFrançois Tigeot 
469a85cb24fSFrançois Tigeot 	p->daddr = dma_map_page(vm->dma, p->page, 0, PAGE_SIZE,
470a85cb24fSFrançois Tigeot 				PCI_DMA_BIDIRECTIONAL);
471a85cb24fSFrançois Tigeot 	if (unlikely(dma_mapping_error(vm->dma, p->daddr))) {
472a85cb24fSFrançois Tigeot 		vm_free_page(vm, p->page);
473a85cb24fSFrançois Tigeot 		return -ENOMEM;
474a05eeebfSFrançois Tigeot 	}
475a05eeebfSFrançois Tigeot 
476477eb7f9SFrançois Tigeot 	return 0;
477477eb7f9SFrançois Tigeot }
478477eb7f9SFrançois Tigeot 
setup_page_dma(struct i915_address_space * vm,struct i915_page_dma * p)479a85cb24fSFrançois Tigeot static int setup_page_dma(struct i915_address_space *vm,
4804be47400SFrançois Tigeot 			  struct i915_page_dma *p)
481477eb7f9SFrançois Tigeot {
482a85cb24fSFrançois Tigeot 	return __setup_page_dma(vm, p, I915_GFP_DMA);
483a05eeebfSFrançois Tigeot }
484a05eeebfSFrançois Tigeot 
cleanup_page_dma(struct i915_address_space * vm,struct i915_page_dma * p)485a85cb24fSFrançois Tigeot static void cleanup_page_dma(struct i915_address_space *vm,
4864be47400SFrançois Tigeot 			     struct i915_page_dma *p)
487a05eeebfSFrançois Tigeot {
488a85cb24fSFrançois Tigeot 	dma_unmap_page(vm->dma, p->daddr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
489a85cb24fSFrançois Tigeot 	vm_free_page(vm, p->page);
490477eb7f9SFrançois Tigeot }
491477eb7f9SFrançois Tigeot 
492a85cb24fSFrançois Tigeot #define kmap_atomic_px(px) kmap_atomic(px_base(px)->page)
493a85cb24fSFrançois Tigeot 
494a85cb24fSFrançois Tigeot #define setup_px(vm, px) setup_page_dma((vm), px_base(px))
495a85cb24fSFrançois Tigeot #define cleanup_px(vm, px) cleanup_page_dma((vm), px_base(px))
496a85cb24fSFrançois Tigeot #define fill_px(ppgtt, px, v) fill_page_dma((vm), px_base(px), (v))
497a85cb24fSFrançois Tigeot #define fill32_px(ppgtt, px, v) fill_page_dma_32((vm), px_base(px), (v))
498a85cb24fSFrançois Tigeot 
fill_page_dma(struct i915_address_space * vm,struct i915_page_dma * p,const u64 val)499a85cb24fSFrançois Tigeot static void fill_page_dma(struct i915_address_space *vm,
500a85cb24fSFrançois Tigeot 			  struct i915_page_dma *p,
501a85cb24fSFrançois Tigeot 			  const u64 val)
502477eb7f9SFrançois Tigeot {
503a85cb24fSFrançois Tigeot 	u64 * const vaddr = kmap_atomic(p->page);
504a05eeebfSFrançois Tigeot 
505*3f2dd94aSFrançois Tigeot 	memset64(vaddr, val, PAGE_SIZE / sizeof(val));
506a05eeebfSFrançois Tigeot 
507a85cb24fSFrançois Tigeot 	kunmap_atomic(vaddr);
508a05eeebfSFrançois Tigeot }
509a05eeebfSFrançois Tigeot 
fill_page_dma_32(struct i915_address_space * vm,struct i915_page_dma * p,const u32 v)510a85cb24fSFrançois Tigeot static void fill_page_dma_32(struct i915_address_space *vm,
511a85cb24fSFrançois Tigeot 			     struct i915_page_dma *p,
512a85cb24fSFrançois Tigeot 			     const u32 v)
513a05eeebfSFrançois Tigeot {
514a85cb24fSFrançois Tigeot 	fill_page_dma(vm, p, (u64)v << 32 | v);
515a05eeebfSFrançois Tigeot }
516a05eeebfSFrançois Tigeot 
5171e12ee3bSFrançois Tigeot static int
setup_scratch_page(struct i915_address_space * vm,gfp_t gfp)518a85cb24fSFrançois Tigeot setup_scratch_page(struct i915_address_space *vm, gfp_t gfp)
519a05eeebfSFrançois Tigeot {
520*3f2dd94aSFrançois Tigeot 	struct page *page = NULL;
521*3f2dd94aSFrançois Tigeot 	dma_addr_t addr;
522*3f2dd94aSFrançois Tigeot 	int order;
523*3f2dd94aSFrançois Tigeot 
524*3f2dd94aSFrançois Tigeot 	/*
525*3f2dd94aSFrançois Tigeot 	 * In order to utilize 64K pages for an object with a size < 2M, we will
526*3f2dd94aSFrançois Tigeot 	 * need to support a 64K scratch page, given that every 16th entry for a
527*3f2dd94aSFrançois Tigeot 	 * page-table operating in 64K mode must point to a properly aligned 64K
528*3f2dd94aSFrançois Tigeot 	 * region, including any PTEs which happen to point to scratch.
529*3f2dd94aSFrançois Tigeot 	 *
530*3f2dd94aSFrançois Tigeot 	 * This is only relevant for the 48b PPGTT where we support
531*3f2dd94aSFrançois Tigeot 	 * huge-gtt-pages, see also i915_vma_insert().
532*3f2dd94aSFrançois Tigeot 	 *
533*3f2dd94aSFrançois Tigeot 	 * TODO: we should really consider write-protecting the scratch-page and
534*3f2dd94aSFrançois Tigeot 	 * sharing between ppgtt
535*3f2dd94aSFrançois Tigeot 	 */
536*3f2dd94aSFrançois Tigeot 	if (i915_vm_is_48bit(vm) &&
537*3f2dd94aSFrançois Tigeot 	    HAS_PAGE_SIZES(vm->i915, I915_GTT_PAGE_SIZE_64K)) {
538*3f2dd94aSFrançois Tigeot 		order = get_order(I915_GTT_PAGE_SIZE_64K);
539*3f2dd94aSFrançois Tigeot 		page = alloc_pages(gfp | __GFP_ZERO | __GFP_NOWARN, order);
540*3f2dd94aSFrançois Tigeot 		if (page) {
541*3f2dd94aSFrançois Tigeot 			addr = dma_map_page(vm->dma, page, 0,
542*3f2dd94aSFrançois Tigeot 					    I915_GTT_PAGE_SIZE_64K,
543*3f2dd94aSFrançois Tigeot 					    PCI_DMA_BIDIRECTIONAL);
544*3f2dd94aSFrançois Tigeot 			if (unlikely(dma_mapping_error(vm->dma, addr))) {
545*3f2dd94aSFrançois Tigeot 				__free_pages(page, order);
546*3f2dd94aSFrançois Tigeot 				page = NULL;
547*3f2dd94aSFrançois Tigeot 			}
548*3f2dd94aSFrançois Tigeot 
549*3f2dd94aSFrançois Tigeot 			if (!IS_ALIGNED(addr, I915_GTT_PAGE_SIZE_64K)) {
550*3f2dd94aSFrançois Tigeot 				dma_unmap_page(vm->dma, addr,
551*3f2dd94aSFrançois Tigeot 					       I915_GTT_PAGE_SIZE_64K,
552*3f2dd94aSFrançois Tigeot 					       PCI_DMA_BIDIRECTIONAL);
553*3f2dd94aSFrançois Tigeot 				__free_pages(page, order);
554*3f2dd94aSFrançois Tigeot 				page = NULL;
555*3f2dd94aSFrançois Tigeot 			}
556*3f2dd94aSFrançois Tigeot 		}
557*3f2dd94aSFrançois Tigeot 	}
558*3f2dd94aSFrançois Tigeot 
559*3f2dd94aSFrançois Tigeot 	if (!page) {
560*3f2dd94aSFrançois Tigeot 		order = 0;
561*3f2dd94aSFrançois Tigeot 		page = alloc_page(gfp | __GFP_ZERO);
562*3f2dd94aSFrançois Tigeot 		if (unlikely(!page))
563*3f2dd94aSFrançois Tigeot 			return -ENOMEM;
564*3f2dd94aSFrançois Tigeot 
565*3f2dd94aSFrançois Tigeot 		addr = dma_map_page(vm->dma, page, 0, PAGE_SIZE,
566*3f2dd94aSFrançois Tigeot 				    PCI_DMA_BIDIRECTIONAL);
567*3f2dd94aSFrançois Tigeot 		if (unlikely(dma_mapping_error(vm->dma, addr))) {
568*3f2dd94aSFrançois Tigeot 			__free_page(page);
569*3f2dd94aSFrançois Tigeot 			return -ENOMEM;
570*3f2dd94aSFrançois Tigeot 		}
571*3f2dd94aSFrançois Tigeot 	}
572*3f2dd94aSFrançois Tigeot 
573*3f2dd94aSFrançois Tigeot 	vm->scratch_page.page = page;
574*3f2dd94aSFrançois Tigeot 	vm->scratch_page.daddr = addr;
575*3f2dd94aSFrançois Tigeot 	vm->scratch_page.order = order;
576*3f2dd94aSFrançois Tigeot 
577*3f2dd94aSFrançois Tigeot 	return 0;
578a05eeebfSFrançois Tigeot }
579a05eeebfSFrançois Tigeot 
cleanup_scratch_page(struct i915_address_space * vm)580a85cb24fSFrançois Tigeot static void cleanup_scratch_page(struct i915_address_space *vm)
581a05eeebfSFrançois Tigeot {
582*3f2dd94aSFrançois Tigeot 	struct i915_page_dma *p = &vm->scratch_page;
583*3f2dd94aSFrançois Tigeot 
584*3f2dd94aSFrançois Tigeot 	dma_unmap_page(vm->dma, p->daddr, BIT(p->order) << PAGE_SHIFT,
585*3f2dd94aSFrançois Tigeot 		       PCI_DMA_BIDIRECTIONAL);
586*3f2dd94aSFrançois Tigeot 	__free_pages(p->page, p->order);
587a05eeebfSFrançois Tigeot }
588a05eeebfSFrançois Tigeot 
alloc_pt(struct i915_address_space * vm)589a85cb24fSFrançois Tigeot static struct i915_page_table *alloc_pt(struct i915_address_space *vm)
59019c468b4SFrançois Tigeot {
59119c468b4SFrançois Tigeot 	struct i915_page_table *pt;
592477eb7f9SFrançois Tigeot 
593a85cb24fSFrançois Tigeot 	pt = kmalloc(sizeof(*pt), M_DRM, GFP_KERNEL | __GFP_NOWARN);
594a85cb24fSFrançois Tigeot 	if (unlikely(!pt))
595477eb7f9SFrançois Tigeot 		return ERR_PTR(-ENOMEM);
596477eb7f9SFrançois Tigeot 
597a85cb24fSFrançois Tigeot 	if (unlikely(setup_px(vm, pt))) {
598477eb7f9SFrançois Tigeot 		kfree(pt);
599a85cb24fSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
600477eb7f9SFrançois Tigeot 	}
601477eb7f9SFrançois Tigeot 
602a85cb24fSFrançois Tigeot 	pt->used_ptes = 0;
603a85cb24fSFrançois Tigeot 	return pt;
604a85cb24fSFrançois Tigeot }
605a85cb24fSFrançois Tigeot 
free_pt(struct i915_address_space * vm,struct i915_page_table * pt)606a85cb24fSFrançois Tigeot static void free_pt(struct i915_address_space *vm, struct i915_page_table *pt)
607a05eeebfSFrançois Tigeot {
608a85cb24fSFrançois Tigeot 	cleanup_px(vm, pt);
609a05eeebfSFrançois Tigeot 	kfree(pt);
610a05eeebfSFrançois Tigeot }
611a05eeebfSFrançois Tigeot 
gen8_initialize_pt(struct i915_address_space * vm,struct i915_page_table * pt)612a05eeebfSFrançois Tigeot static void gen8_initialize_pt(struct i915_address_space *vm,
613a05eeebfSFrançois Tigeot 			       struct i915_page_table *pt)
614477eb7f9SFrançois Tigeot {
615a85cb24fSFrançois Tigeot 	fill_px(vm, pt,
616a85cb24fSFrançois Tigeot 		gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC));
617477eb7f9SFrançois Tigeot }
618477eb7f9SFrançois Tigeot 
gen6_initialize_pt(struct i915_address_space * vm,struct i915_page_table * pt)619a05eeebfSFrançois Tigeot static void gen6_initialize_pt(struct i915_address_space *vm,
620a05eeebfSFrançois Tigeot 			       struct i915_page_table *pt)
621a05eeebfSFrançois Tigeot {
622a85cb24fSFrançois Tigeot 	fill32_px(vm, pt,
623a85cb24fSFrançois Tigeot 		  vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0));
624a05eeebfSFrançois Tigeot }
625a05eeebfSFrançois Tigeot 
alloc_pd(struct i915_address_space * vm)626a85cb24fSFrançois Tigeot static struct i915_page_directory *alloc_pd(struct i915_address_space *vm)
627477eb7f9SFrançois Tigeot {
62819c468b4SFrançois Tigeot 	struct i915_page_directory *pd;
629477eb7f9SFrançois Tigeot 
630a85cb24fSFrançois Tigeot 	pd = kzalloc(sizeof(*pd), GFP_KERNEL | __GFP_NOWARN);
631a85cb24fSFrançois Tigeot 	if (unlikely(!pd))
632477eb7f9SFrançois Tigeot 		return ERR_PTR(-ENOMEM);
633477eb7f9SFrançois Tigeot 
634a85cb24fSFrançois Tigeot 	if (unlikely(setup_px(vm, pd))) {
63519c468b4SFrançois Tigeot 		kfree(pd);
636a85cb24fSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
637477eb7f9SFrançois Tigeot 	}
638477eb7f9SFrançois Tigeot 
639a85cb24fSFrançois Tigeot 	pd->used_pdes = 0;
640a85cb24fSFrançois Tigeot 	return pd;
641a85cb24fSFrançois Tigeot }
642a85cb24fSFrançois Tigeot 
free_pd(struct i915_address_space * vm,struct i915_page_directory * pd)643a85cb24fSFrançois Tigeot static void free_pd(struct i915_address_space *vm,
6444be47400SFrançois Tigeot 		    struct i915_page_directory *pd)
645a05eeebfSFrançois Tigeot {
646a85cb24fSFrançois Tigeot 	cleanup_px(vm, pd);
647a05eeebfSFrançois Tigeot 	kfree(pd);
648a05eeebfSFrançois Tigeot }
649a05eeebfSFrançois Tigeot 
gen8_initialize_pd(struct i915_address_space * vm,struct i915_page_directory * pd)650a05eeebfSFrançois Tigeot static void gen8_initialize_pd(struct i915_address_space *vm,
651a05eeebfSFrançois Tigeot 			       struct i915_page_directory *pd)
652a05eeebfSFrançois Tigeot {
653a85cb24fSFrançois Tigeot 	unsigned int i;
654a05eeebfSFrançois Tigeot 
655a85cb24fSFrançois Tigeot 	fill_px(vm, pd,
656a85cb24fSFrançois Tigeot 		gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC));
657a85cb24fSFrançois Tigeot 	for (i = 0; i < I915_PDES; i++)
658a85cb24fSFrançois Tigeot 		pd->page_table[i] = vm->scratch_pt;
659a05eeebfSFrançois Tigeot }
660a05eeebfSFrançois Tigeot 
__pdp_init(struct i915_address_space * vm,struct i915_page_directory_pointer * pdp)661a85cb24fSFrançois Tigeot static int __pdp_init(struct i915_address_space *vm,
662352ff8bdSFrançois Tigeot 		      struct i915_page_directory_pointer *pdp)
663352ff8bdSFrançois Tigeot {
664a85cb24fSFrançois Tigeot 	const unsigned int pdpes = i915_pdpes_per_pdp(vm);
665a85cb24fSFrançois Tigeot 	unsigned int i;
666352ff8bdSFrançois Tigeot 
667a85cb24fSFrançois Tigeot 	pdp->page_directory = kmalloc_array(pdpes, sizeof(*pdp->page_directory),
668a85cb24fSFrançois Tigeot 					    GFP_KERNEL | __GFP_NOWARN);
669a85cb24fSFrançois Tigeot 	if (unlikely(!pdp->page_directory))
670352ff8bdSFrançois Tigeot 		return -ENOMEM;
671352ff8bdSFrançois Tigeot 
672a85cb24fSFrançois Tigeot 	for (i = 0; i < pdpes; i++)
673a85cb24fSFrançois Tigeot 		pdp->page_directory[i] = vm->scratch_pd;
674352ff8bdSFrançois Tigeot 
675352ff8bdSFrançois Tigeot 	return 0;
676352ff8bdSFrançois Tigeot }
677352ff8bdSFrançois Tigeot 
__pdp_fini(struct i915_page_directory_pointer * pdp)678352ff8bdSFrançois Tigeot static void __pdp_fini(struct i915_page_directory_pointer *pdp)
679352ff8bdSFrançois Tigeot {
680352ff8bdSFrançois Tigeot 	kfree(pdp->page_directory);
681352ff8bdSFrançois Tigeot 	pdp->page_directory = NULL;
682352ff8bdSFrançois Tigeot }
683352ff8bdSFrançois Tigeot 
use_4lvl(const struct i915_address_space * vm)684a85cb24fSFrançois Tigeot static inline bool use_4lvl(const struct i915_address_space *vm)
685a85cb24fSFrançois Tigeot {
686a85cb24fSFrançois Tigeot 	return i915_vm_is_48bit(vm);
687a85cb24fSFrançois Tigeot }
688a85cb24fSFrançois Tigeot 
689a85cb24fSFrançois Tigeot static struct i915_page_directory_pointer *
alloc_pdp(struct i915_address_space * vm)690a85cb24fSFrançois Tigeot alloc_pdp(struct i915_address_space *vm)
691352ff8bdSFrançois Tigeot {
692352ff8bdSFrançois Tigeot 	struct i915_page_directory_pointer *pdp;
693352ff8bdSFrançois Tigeot 	int ret = -ENOMEM;
694352ff8bdSFrançois Tigeot 
695a85cb24fSFrançois Tigeot 	WARN_ON(!use_4lvl(vm));
696352ff8bdSFrançois Tigeot 
697352ff8bdSFrançois Tigeot 	pdp = kzalloc(sizeof(*pdp), GFP_KERNEL);
698352ff8bdSFrançois Tigeot 	if (!pdp)
699352ff8bdSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
700352ff8bdSFrançois Tigeot 
701a85cb24fSFrançois Tigeot 	ret = __pdp_init(vm, pdp);
702352ff8bdSFrançois Tigeot 	if (ret)
703352ff8bdSFrançois Tigeot 		goto fail_bitmap;
704352ff8bdSFrançois Tigeot 
705a85cb24fSFrançois Tigeot 	ret = setup_px(vm, pdp);
706352ff8bdSFrançois Tigeot 	if (ret)
707352ff8bdSFrançois Tigeot 		goto fail_page_m;
708352ff8bdSFrançois Tigeot 
709352ff8bdSFrançois Tigeot 	return pdp;
710352ff8bdSFrançois Tigeot 
711352ff8bdSFrançois Tigeot fail_page_m:
712352ff8bdSFrançois Tigeot 	__pdp_fini(pdp);
713352ff8bdSFrançois Tigeot fail_bitmap:
714352ff8bdSFrançois Tigeot 	kfree(pdp);
715352ff8bdSFrançois Tigeot 
716352ff8bdSFrançois Tigeot 	return ERR_PTR(ret);
717352ff8bdSFrançois Tigeot }
718352ff8bdSFrançois Tigeot 
free_pdp(struct i915_address_space * vm,struct i915_page_directory_pointer * pdp)719a85cb24fSFrançois Tigeot static void free_pdp(struct i915_address_space *vm,
720352ff8bdSFrançois Tigeot 		     struct i915_page_directory_pointer *pdp)
721352ff8bdSFrançois Tigeot {
722352ff8bdSFrançois Tigeot 	__pdp_fini(pdp);
723a85cb24fSFrançois Tigeot 
724a85cb24fSFrançois Tigeot 	if (!use_4lvl(vm))
725a85cb24fSFrançois Tigeot 		return;
726a85cb24fSFrançois Tigeot 
727a85cb24fSFrançois Tigeot 	cleanup_px(vm, pdp);
728352ff8bdSFrançois Tigeot 	kfree(pdp);
729352ff8bdSFrançois Tigeot }
730352ff8bdSFrançois Tigeot 
gen8_initialize_pdp(struct i915_address_space * vm,struct i915_page_directory_pointer * pdp)731352ff8bdSFrançois Tigeot static void gen8_initialize_pdp(struct i915_address_space *vm,
732352ff8bdSFrançois Tigeot 				struct i915_page_directory_pointer *pdp)
733352ff8bdSFrançois Tigeot {
734352ff8bdSFrançois Tigeot 	gen8_ppgtt_pdpe_t scratch_pdpe;
735352ff8bdSFrançois Tigeot 
736352ff8bdSFrançois Tigeot 	scratch_pdpe = gen8_pdpe_encode(px_dma(vm->scratch_pd), I915_CACHE_LLC);
737352ff8bdSFrançois Tigeot 
738a85cb24fSFrançois Tigeot 	fill_px(vm, pdp, scratch_pdpe);
739352ff8bdSFrançois Tigeot }
740352ff8bdSFrançois Tigeot 
gen8_initialize_pml4(struct i915_address_space * vm,struct i915_pml4 * pml4)741352ff8bdSFrançois Tigeot static void gen8_initialize_pml4(struct i915_address_space *vm,
742352ff8bdSFrançois Tigeot 				 struct i915_pml4 *pml4)
743352ff8bdSFrançois Tigeot {
744a85cb24fSFrançois Tigeot 	unsigned int i;
745352ff8bdSFrançois Tigeot 
746a85cb24fSFrançois Tigeot 	fill_px(vm, pml4,
747a85cb24fSFrançois Tigeot 		gen8_pml4e_encode(px_dma(vm->scratch_pdp), I915_CACHE_LLC));
748a85cb24fSFrançois Tigeot 	for (i = 0; i < GEN8_PML4ES_PER_PML4; i++)
749a85cb24fSFrançois Tigeot 		pml4->pdps[i] = vm->scratch_pdp;
750352ff8bdSFrançois Tigeot }
751352ff8bdSFrançois Tigeot 
7529edbd4a0SFrançois Tigeot /* Broadwell Page Directory Pointer Descriptors */
gen8_write_pdp(struct drm_i915_gem_request * req,unsigned entry,dma_addr_t addr)753a05eeebfSFrançois Tigeot static int gen8_write_pdp(struct drm_i915_gem_request *req,
75419c468b4SFrançois Tigeot 			  unsigned entry,
75519c468b4SFrançois Tigeot 			  dma_addr_t addr)
7569edbd4a0SFrançois Tigeot {
7578621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
758a85cb24fSFrançois Tigeot 	u32 *cs;
7599edbd4a0SFrançois Tigeot 
7609edbd4a0SFrançois Tigeot 	BUG_ON(entry >= 4);
7619edbd4a0SFrançois Tigeot 
762a85cb24fSFrançois Tigeot 	cs = intel_ring_begin(req, 6);
763a85cb24fSFrançois Tigeot 	if (IS_ERR(cs))
764a85cb24fSFrançois Tigeot 		return PTR_ERR(cs);
7659edbd4a0SFrançois Tigeot 
766a85cb24fSFrançois Tigeot 	*cs++ = MI_LOAD_REGISTER_IMM(1);
767a85cb24fSFrançois Tigeot 	*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(engine, entry));
768a85cb24fSFrançois Tigeot 	*cs++ = upper_32_bits(addr);
769a85cb24fSFrançois Tigeot 	*cs++ = MI_LOAD_REGISTER_IMM(1);
770a85cb24fSFrançois Tigeot 	*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(engine, entry));
771a85cb24fSFrançois Tigeot 	*cs++ = lower_32_bits(addr);
772a85cb24fSFrançois Tigeot 	intel_ring_advance(req, cs);
7739edbd4a0SFrançois Tigeot 
7749edbd4a0SFrançois Tigeot 	return 0;
7759edbd4a0SFrançois Tigeot }
7769edbd4a0SFrançois Tigeot 
gen8_mm_switch_3lvl(struct i915_hw_ppgtt * ppgtt,struct drm_i915_gem_request * req)777a85cb24fSFrançois Tigeot static int gen8_mm_switch_3lvl(struct i915_hw_ppgtt *ppgtt,
778a05eeebfSFrançois Tigeot 			       struct drm_i915_gem_request *req)
7799edbd4a0SFrançois Tigeot {
780ba55f2f5SFrançois Tigeot 	int i, ret;
7819edbd4a0SFrançois Tigeot 
782a85cb24fSFrançois Tigeot 	for (i = GEN8_3LVL_PDPES - 1; i >= 0; i--) {
783a05eeebfSFrançois Tigeot 		const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
784a05eeebfSFrançois Tigeot 
785a05eeebfSFrançois Tigeot 		ret = gen8_write_pdp(req, i, pd_daddr);
7869edbd4a0SFrançois Tigeot 		if (ret)
7879edbd4a0SFrançois Tigeot 			return ret;
7889edbd4a0SFrançois Tigeot 	}
7899edbd4a0SFrançois Tigeot 
790ba55f2f5SFrançois Tigeot 	return 0;
791ba55f2f5SFrançois Tigeot }
792ba55f2f5SFrançois Tigeot 
gen8_mm_switch_4lvl(struct i915_hw_ppgtt * ppgtt,struct drm_i915_gem_request * req)793a85cb24fSFrançois Tigeot static int gen8_mm_switch_4lvl(struct i915_hw_ppgtt *ppgtt,
794352ff8bdSFrançois Tigeot 			       struct drm_i915_gem_request *req)
795352ff8bdSFrançois Tigeot {
796352ff8bdSFrançois Tigeot 	return gen8_write_pdp(req, 0, px_dma(&ppgtt->pml4));
797352ff8bdSFrançois Tigeot }
798352ff8bdSFrançois Tigeot 
7994be47400SFrançois Tigeot /* PDE TLBs are a pain to invalidate on GEN8+. When we modify
8004be47400SFrançois Tigeot  * the page table structures, we mark them dirty so that
8014be47400SFrançois Tigeot  * context switching/execlist queuing code takes extra steps
8024be47400SFrançois Tigeot  * to ensure that tlbs are flushed.
8034be47400SFrançois Tigeot  */
mark_tlbs_dirty(struct i915_hw_ppgtt * ppgtt)8044be47400SFrançois Tigeot static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt)
8054be47400SFrançois Tigeot {
806a85cb24fSFrançois Tigeot 	ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.i915)->ring_mask;
8074be47400SFrançois Tigeot }
8084be47400SFrançois Tigeot 
8091e12ee3bSFrançois Tigeot /* Removes entries from a single page table, releasing it if it's empty.
8101e12ee3bSFrançois Tigeot  * Caller can use the return value to update higher-level entries.
8111e12ee3bSFrançois Tigeot  */
gen8_ppgtt_clear_pt(struct i915_address_space * vm,struct i915_page_table * pt,u64 start,u64 length)8121e12ee3bSFrançois Tigeot static bool gen8_ppgtt_clear_pt(struct i915_address_space *vm,
8131e12ee3bSFrançois Tigeot 				struct i915_page_table *pt,
814a85cb24fSFrançois Tigeot 				u64 start, u64 length)
8159edbd4a0SFrançois Tigeot {
8161e12ee3bSFrançois Tigeot 	unsigned int num_entries = gen8_pte_count(start, length);
8174be47400SFrançois Tigeot 	unsigned int pte = gen8_pte_index(start);
8184be47400SFrançois Tigeot 	unsigned int pte_end = pte + num_entries;
819a85cb24fSFrançois Tigeot 	const gen8_pte_t scratch_pte =
820a85cb24fSFrançois Tigeot 		gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC);
821a85cb24fSFrançois Tigeot 	gen8_pte_t *vaddr;
822477eb7f9SFrançois Tigeot 
823a85cb24fSFrançois Tigeot 	GEM_BUG_ON(num_entries > pt->used_ptes);
8249edbd4a0SFrançois Tigeot 
825a85cb24fSFrançois Tigeot 	pt->used_ptes -= num_entries;
826a85cb24fSFrançois Tigeot 	if (!pt->used_ptes)
8271e12ee3bSFrançois Tigeot 		return true;
8289edbd4a0SFrançois Tigeot 
829a85cb24fSFrançois Tigeot 	vaddr = kmap_atomic_px(pt);
8304be47400SFrançois Tigeot 	while (pte < pte_end)
831a85cb24fSFrançois Tigeot 		vaddr[pte++] = scratch_pte;
832a85cb24fSFrançois Tigeot 	kunmap_atomic(vaddr);
8339edbd4a0SFrançois Tigeot 
8341e12ee3bSFrançois Tigeot 	return false;
8351e12ee3bSFrançois Tigeot }
8361e12ee3bSFrançois Tigeot 
gen8_ppgtt_set_pde(struct i915_address_space * vm,struct i915_page_directory * pd,struct i915_page_table * pt,unsigned int pde)837a85cb24fSFrançois Tigeot static void gen8_ppgtt_set_pde(struct i915_address_space *vm,
838a85cb24fSFrançois Tigeot 			       struct i915_page_directory *pd,
839a85cb24fSFrançois Tigeot 			       struct i915_page_table *pt,
840a85cb24fSFrançois Tigeot 			       unsigned int pde)
841a85cb24fSFrançois Tigeot {
842a85cb24fSFrançois Tigeot 	gen8_pde_t *vaddr;
843a85cb24fSFrançois Tigeot 
844a85cb24fSFrançois Tigeot 	pd->page_table[pde] = pt;
845a85cb24fSFrançois Tigeot 
846a85cb24fSFrançois Tigeot 	vaddr = kmap_atomic_px(pd);
847a85cb24fSFrançois Tigeot 	vaddr[pde] = gen8_pde_encode(px_dma(pt), I915_CACHE_LLC);
848a85cb24fSFrançois Tigeot 	kunmap_atomic(vaddr);
849a85cb24fSFrançois Tigeot }
850a85cb24fSFrançois Tigeot 
gen8_ppgtt_clear_pd(struct i915_address_space * vm,struct i915_page_directory * pd,u64 start,u64 length)8511e12ee3bSFrançois Tigeot static bool gen8_ppgtt_clear_pd(struct i915_address_space *vm,
8521e12ee3bSFrançois Tigeot 				struct i915_page_directory *pd,
853a85cb24fSFrançois Tigeot 				u64 start, u64 length)
8541e12ee3bSFrançois Tigeot {
8551e12ee3bSFrançois Tigeot 	struct i915_page_table *pt;
856a85cb24fSFrançois Tigeot 	u32 pde;
8571e12ee3bSFrançois Tigeot 
8581e12ee3bSFrançois Tigeot 	gen8_for_each_pde(pt, pd, start, length, pde) {
859a85cb24fSFrançois Tigeot 		GEM_BUG_ON(pt == vm->scratch_pt);
8601e12ee3bSFrançois Tigeot 
861a85cb24fSFrançois Tigeot 		if (!gen8_ppgtt_clear_pt(vm, pt, start, length))
862a85cb24fSFrançois Tigeot 			continue;
863a85cb24fSFrançois Tigeot 
864a85cb24fSFrançois Tigeot 		gen8_ppgtt_set_pde(vm, pd, vm->scratch_pt, pde);
865a85cb24fSFrançois Tigeot 		GEM_BUG_ON(!pd->used_pdes);
866a85cb24fSFrançois Tigeot 		pd->used_pdes--;
867a85cb24fSFrançois Tigeot 
868a85cb24fSFrançois Tigeot 		free_pt(vm, pt);
8691e12ee3bSFrançois Tigeot 	}
8701e12ee3bSFrançois Tigeot 
871a85cb24fSFrançois Tigeot 	return !pd->used_pdes;
872a85cb24fSFrançois Tigeot }
8731e12ee3bSFrançois Tigeot 
gen8_ppgtt_set_pdpe(struct i915_address_space * vm,struct i915_page_directory_pointer * pdp,struct i915_page_directory * pd,unsigned int pdpe)874a85cb24fSFrançois Tigeot static void gen8_ppgtt_set_pdpe(struct i915_address_space *vm,
875a85cb24fSFrançois Tigeot 				struct i915_page_directory_pointer *pdp,
876a85cb24fSFrançois Tigeot 				struct i915_page_directory *pd,
877a85cb24fSFrançois Tigeot 				unsigned int pdpe)
878a85cb24fSFrançois Tigeot {
879a85cb24fSFrançois Tigeot 	gen8_ppgtt_pdpe_t *vaddr;
880a85cb24fSFrançois Tigeot 
881a85cb24fSFrançois Tigeot 	pdp->page_directory[pdpe] = pd;
882a85cb24fSFrançois Tigeot 	if (!use_4lvl(vm))
883a85cb24fSFrançois Tigeot 		return;
884a85cb24fSFrançois Tigeot 
885a85cb24fSFrançois Tigeot 	vaddr = kmap_atomic_px(pdp);
886a85cb24fSFrançois Tigeot 	vaddr[pdpe] = gen8_pdpe_encode(px_dma(pd), I915_CACHE_LLC);
887a85cb24fSFrançois Tigeot 	kunmap_atomic(vaddr);
8881e12ee3bSFrançois Tigeot }
8891e12ee3bSFrançois Tigeot 
8901e12ee3bSFrançois Tigeot /* Removes entries from a single page dir pointer, releasing it if it's empty.
8911e12ee3bSFrançois Tigeot  * Caller can use the return value to update higher-level entries
8921e12ee3bSFrançois Tigeot  */
gen8_ppgtt_clear_pdp(struct i915_address_space * vm,struct i915_page_directory_pointer * pdp,u64 start,u64 length)8931e12ee3bSFrançois Tigeot static bool gen8_ppgtt_clear_pdp(struct i915_address_space *vm,
8941e12ee3bSFrançois Tigeot 				 struct i915_page_directory_pointer *pdp,
895a85cb24fSFrançois Tigeot 				 u64 start, u64 length)
8961e12ee3bSFrançois Tigeot {
8971e12ee3bSFrançois Tigeot 	struct i915_page_directory *pd;
898a85cb24fSFrançois Tigeot 	unsigned int pdpe;
8991e12ee3bSFrançois Tigeot 
9001e12ee3bSFrançois Tigeot 	gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
901a85cb24fSFrançois Tigeot 		GEM_BUG_ON(pd == vm->scratch_pd);
9021e12ee3bSFrançois Tigeot 
903a85cb24fSFrançois Tigeot 		if (!gen8_ppgtt_clear_pd(vm, pd, start, length))
904a85cb24fSFrançois Tigeot 			continue;
905a85cb24fSFrançois Tigeot 
906a85cb24fSFrançois Tigeot 		gen8_ppgtt_set_pdpe(vm, pdp, vm->scratch_pd, pdpe);
907a85cb24fSFrançois Tigeot 		GEM_BUG_ON(!pdp->used_pdpes);
908a85cb24fSFrançois Tigeot 		pdp->used_pdpes--;
909a85cb24fSFrançois Tigeot 
910a85cb24fSFrançois Tigeot 		free_pd(vm, pd);
9111e12ee3bSFrançois Tigeot 	}
9121e12ee3bSFrançois Tigeot 
913a85cb24fSFrançois Tigeot 	return !pdp->used_pdpes;
914a85cb24fSFrançois Tigeot }
9154be47400SFrançois Tigeot 
gen8_ppgtt_clear_3lvl(struct i915_address_space * vm,u64 start,u64 length)916a85cb24fSFrançois Tigeot static void gen8_ppgtt_clear_3lvl(struct i915_address_space *vm,
917a85cb24fSFrançois Tigeot 				  u64 start, u64 length)
918a85cb24fSFrançois Tigeot {
919a85cb24fSFrançois Tigeot 	gen8_ppgtt_clear_pdp(vm, &i915_vm_to_ppgtt(vm)->pdp, start, length);
920a85cb24fSFrançois Tigeot }
9211e12ee3bSFrançois Tigeot 
gen8_ppgtt_set_pml4e(struct i915_pml4 * pml4,struct i915_page_directory_pointer * pdp,unsigned int pml4e)922a85cb24fSFrançois Tigeot static void gen8_ppgtt_set_pml4e(struct i915_pml4 *pml4,
923a85cb24fSFrançois Tigeot 				 struct i915_page_directory_pointer *pdp,
924a85cb24fSFrançois Tigeot 				 unsigned int pml4e)
925a85cb24fSFrançois Tigeot {
926a85cb24fSFrançois Tigeot 	gen8_ppgtt_pml4e_t *vaddr;
927a85cb24fSFrançois Tigeot 
928a85cb24fSFrançois Tigeot 	pml4->pdps[pml4e] = pdp;
929a85cb24fSFrançois Tigeot 
930a85cb24fSFrançois Tigeot 	vaddr = kmap_atomic_px(pml4);
931a85cb24fSFrançois Tigeot 	vaddr[pml4e] = gen8_pml4e_encode(px_dma(pdp), I915_CACHE_LLC);
932a85cb24fSFrançois Tigeot 	kunmap_atomic(vaddr);
9331e12ee3bSFrançois Tigeot }
9341e12ee3bSFrançois Tigeot 
9351e12ee3bSFrançois Tigeot /* Removes entries from a single pml4.
9361e12ee3bSFrançois Tigeot  * This is the top-level structure in 4-level page tables used on gen8+.
9371e12ee3bSFrançois Tigeot  * Empty entries are always scratch pml4e.
9381e12ee3bSFrançois Tigeot  */
gen8_ppgtt_clear_4lvl(struct i915_address_space * vm,u64 start,u64 length)939a85cb24fSFrançois Tigeot static void gen8_ppgtt_clear_4lvl(struct i915_address_space *vm,
940a85cb24fSFrançois Tigeot 				  u64 start, u64 length)
9411e12ee3bSFrançois Tigeot {
9421e12ee3bSFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
943a85cb24fSFrançois Tigeot 	struct i915_pml4 *pml4 = &ppgtt->pml4;
9441e12ee3bSFrançois Tigeot 	struct i915_page_directory_pointer *pdp;
945a85cb24fSFrançois Tigeot 	unsigned int pml4e;
9461e12ee3bSFrançois Tigeot 
947a85cb24fSFrançois Tigeot 	GEM_BUG_ON(!use_4lvl(vm));
9481e12ee3bSFrançois Tigeot 
9491e12ee3bSFrançois Tigeot 	gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) {
950a85cb24fSFrançois Tigeot 		GEM_BUG_ON(pdp == vm->scratch_pdp);
9511e12ee3bSFrançois Tigeot 
952a85cb24fSFrançois Tigeot 		if (!gen8_ppgtt_clear_pdp(vm, pdp, start, length))
953a85cb24fSFrançois Tigeot 			continue;
954a85cb24fSFrançois Tigeot 
955a85cb24fSFrançois Tigeot 		gen8_ppgtt_set_pml4e(pml4, vm->scratch_pdp, pml4e);
956a85cb24fSFrançois Tigeot 
957a85cb24fSFrançois Tigeot 		free_pdp(vm, pdp);
9589edbd4a0SFrançois Tigeot 	}
9599edbd4a0SFrançois Tigeot }
9609edbd4a0SFrançois Tigeot 
961*3f2dd94aSFrançois Tigeot static inline struct sgt_dma {
962a85cb24fSFrançois Tigeot 	struct scatterlist *sg;
963a85cb24fSFrançois Tigeot 	dma_addr_t dma, max;
sgt_dma(struct i915_vma * vma)964*3f2dd94aSFrançois Tigeot } sgt_dma(struct i915_vma *vma) {
965*3f2dd94aSFrançois Tigeot 	struct scatterlist *sg = vma->pages->sgl;
966*3f2dd94aSFrançois Tigeot 	dma_addr_t addr = sg_dma_address(sg);
967*3f2dd94aSFrançois Tigeot 	return (struct sgt_dma) { sg, addr, addr + sg->length };
968*3f2dd94aSFrançois Tigeot }
969a85cb24fSFrançois Tigeot 
970a85cb24fSFrançois Tigeot struct gen8_insert_pte {
971a85cb24fSFrançois Tigeot 	u16 pml4e;
972a85cb24fSFrançois Tigeot 	u16 pdpe;
973a85cb24fSFrançois Tigeot 	u16 pde;
974a85cb24fSFrançois Tigeot 	u16 pte;
975a85cb24fSFrançois Tigeot };
976a85cb24fSFrançois Tigeot 
gen8_insert_pte(u64 start)977a85cb24fSFrançois Tigeot static __always_inline struct gen8_insert_pte gen8_insert_pte(u64 start)
978352ff8bdSFrançois Tigeot {
979a85cb24fSFrançois Tigeot 	return (struct gen8_insert_pte) {
980a85cb24fSFrançois Tigeot 		 gen8_pml4e_index(start),
981a85cb24fSFrançois Tigeot 		 gen8_pdpe_index(start),
982a85cb24fSFrançois Tigeot 		 gen8_pde_index(start),
983a85cb24fSFrançois Tigeot 		 gen8_pte_index(start),
984a85cb24fSFrançois Tigeot 	};
985352ff8bdSFrançois Tigeot }
986352ff8bdSFrançois Tigeot 
987a85cb24fSFrançois Tigeot static __always_inline bool
gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt * ppgtt,struct i915_page_directory_pointer * pdp,struct sgt_dma * iter,struct gen8_insert_pte * idx,enum i915_cache_level cache_level)988a85cb24fSFrançois Tigeot gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt,
989352ff8bdSFrançois Tigeot 			      struct i915_page_directory_pointer *pdp,
990a85cb24fSFrançois Tigeot 			      struct sgt_dma *iter,
991a85cb24fSFrançois Tigeot 			      struct gen8_insert_pte *idx,
992352ff8bdSFrançois Tigeot 			      enum i915_cache_level cache_level)
9939edbd4a0SFrançois Tigeot {
994a85cb24fSFrançois Tigeot 	struct i915_page_directory *pd;
995a85cb24fSFrançois Tigeot 	const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level);
996a85cb24fSFrançois Tigeot 	gen8_pte_t *vaddr;
997a85cb24fSFrançois Tigeot 	bool ret;
9989edbd4a0SFrançois Tigeot 
999a85cb24fSFrançois Tigeot 	GEM_BUG_ON(idx->pdpe >= i915_pdpes_per_pdp(&ppgtt->base));
1000a85cb24fSFrançois Tigeot 	pd = pdp->page_directory[idx->pdpe];
1001a85cb24fSFrançois Tigeot 	vaddr = kmap_atomic_px(pd->page_table[idx->pde]);
1002a85cb24fSFrançois Tigeot 	do {
1003a85cb24fSFrançois Tigeot 		vaddr[idx->pte] = pte_encode | iter->dma;
10049edbd4a0SFrançois Tigeot 
1005a85cb24fSFrançois Tigeot 		iter->dma += PAGE_SIZE;
1006a85cb24fSFrançois Tigeot 		if (iter->dma >= iter->max) {
1007a85cb24fSFrançois Tigeot 			iter->sg = __sg_next(iter->sg);
1008a85cb24fSFrançois Tigeot 			if (!iter->sg) {
1009a85cb24fSFrançois Tigeot 				ret = false;
1010352ff8bdSFrançois Tigeot 				break;
10119edbd4a0SFrançois Tigeot 			}
1012a05eeebfSFrançois Tigeot 
1013a85cb24fSFrançois Tigeot 			iter->dma = sg_dma_address(iter->sg);
1014a85cb24fSFrançois Tigeot 			iter->max = iter->dma + iter->sg->length;
1015ba55f2f5SFrançois Tigeot 		}
1016ba55f2f5SFrançois Tigeot 
1017a85cb24fSFrançois Tigeot 		if (++idx->pte == GEN8_PTES) {
1018a85cb24fSFrançois Tigeot 			idx->pte = 0;
1019a85cb24fSFrançois Tigeot 
1020a85cb24fSFrançois Tigeot 			if (++idx->pde == I915_PDES) {
1021a85cb24fSFrançois Tigeot 				idx->pde = 0;
1022a85cb24fSFrançois Tigeot 
1023a85cb24fSFrançois Tigeot 				/* Limited by sg length for 3lvl */
1024a85cb24fSFrançois Tigeot 				if (++idx->pdpe == GEN8_PML4ES_PER_PML4) {
1025a85cb24fSFrançois Tigeot 					idx->pdpe = 0;
1026a85cb24fSFrançois Tigeot 					ret = true;
1027a85cb24fSFrançois Tigeot 					break;
1028a85cb24fSFrançois Tigeot 				}
1029a85cb24fSFrançois Tigeot 
1030a85cb24fSFrançois Tigeot 				GEM_BUG_ON(idx->pdpe >= i915_pdpes_per_pdp(&ppgtt->base));
1031a85cb24fSFrançois Tigeot 				pd = pdp->page_directory[idx->pdpe];
1032a85cb24fSFrançois Tigeot 			}
1033a85cb24fSFrançois Tigeot 
1034a85cb24fSFrançois Tigeot 			kunmap_atomic(vaddr);
1035a85cb24fSFrançois Tigeot 			vaddr = kmap_atomic_px(pd->page_table[idx->pde]);
1036a85cb24fSFrançois Tigeot 		}
1037a85cb24fSFrançois Tigeot 	} while (1);
1038a85cb24fSFrançois Tigeot 	kunmap_atomic(vaddr);
1039a85cb24fSFrançois Tigeot 
1040a85cb24fSFrançois Tigeot 	return ret;
1041a85cb24fSFrançois Tigeot }
1042a85cb24fSFrançois Tigeot 
gen8_ppgtt_insert_3lvl(struct i915_address_space * vm,struct i915_vma * vma,enum i915_cache_level cache_level,u32 unused)1043a85cb24fSFrançois Tigeot static void gen8_ppgtt_insert_3lvl(struct i915_address_space *vm,
1044*3f2dd94aSFrançois Tigeot 				   struct i915_vma *vma,
1045352ff8bdSFrançois Tigeot 				   enum i915_cache_level cache_level,
1046352ff8bdSFrançois Tigeot 				   u32 unused)
1047352ff8bdSFrançois Tigeot {
10488621f407SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
1049*3f2dd94aSFrançois Tigeot 	struct sgt_dma iter = sgt_dma(vma);
1050*3f2dd94aSFrançois Tigeot 	struct gen8_insert_pte idx = gen8_insert_pte(vma->node.start);
1051352ff8bdSFrançois Tigeot 
1052a85cb24fSFrançois Tigeot 	gen8_ppgtt_insert_pte_entries(ppgtt, &ppgtt->pdp, &iter, &idx,
1053352ff8bdSFrançois Tigeot 				      cache_level);
1054*3f2dd94aSFrançois Tigeot 
1055*3f2dd94aSFrançois Tigeot 	vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
1056*3f2dd94aSFrançois Tigeot }
1057*3f2dd94aSFrançois Tigeot 
gen8_ppgtt_insert_huge_entries(struct i915_vma * vma,struct i915_page_directory_pointer ** pdps,struct sgt_dma * iter,enum i915_cache_level cache_level)1058*3f2dd94aSFrançois Tigeot static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma,
1059*3f2dd94aSFrançois Tigeot 					   struct i915_page_directory_pointer **pdps,
1060*3f2dd94aSFrançois Tigeot 					   struct sgt_dma *iter,
1061*3f2dd94aSFrançois Tigeot 					   enum i915_cache_level cache_level)
1062*3f2dd94aSFrançois Tigeot {
1063*3f2dd94aSFrançois Tigeot 	const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level);
1064*3f2dd94aSFrançois Tigeot 	u64 start = vma->node.start;
1065*3f2dd94aSFrançois Tigeot 	dma_addr_t rem = iter->sg->length;
1066*3f2dd94aSFrançois Tigeot 
1067*3f2dd94aSFrançois Tigeot 	do {
1068*3f2dd94aSFrançois Tigeot 		struct gen8_insert_pte idx = gen8_insert_pte(start);
1069*3f2dd94aSFrançois Tigeot 		struct i915_page_directory_pointer *pdp = pdps[idx.pml4e];
1070*3f2dd94aSFrançois Tigeot 		struct i915_page_directory *pd = pdp->page_directory[idx.pdpe];
1071*3f2dd94aSFrançois Tigeot 		unsigned int page_size;
1072*3f2dd94aSFrançois Tigeot 		bool maybe_64K = false;
1073*3f2dd94aSFrançois Tigeot 		gen8_pte_t encode = pte_encode;
1074*3f2dd94aSFrançois Tigeot 		gen8_pte_t *vaddr;
1075*3f2dd94aSFrançois Tigeot 		u16 index, max;
1076*3f2dd94aSFrançois Tigeot 
1077*3f2dd94aSFrançois Tigeot 		if (vma->page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
1078*3f2dd94aSFrançois Tigeot 		    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
1079*3f2dd94aSFrançois Tigeot 		    rem >= I915_GTT_PAGE_SIZE_2M && !idx.pte) {
1080*3f2dd94aSFrançois Tigeot 			index = idx.pde;
1081*3f2dd94aSFrançois Tigeot 			max = I915_PDES;
1082*3f2dd94aSFrançois Tigeot 			page_size = I915_GTT_PAGE_SIZE_2M;
1083*3f2dd94aSFrançois Tigeot 
1084*3f2dd94aSFrançois Tigeot 			encode |= GEN8_PDE_PS_2M;
1085*3f2dd94aSFrançois Tigeot 
1086*3f2dd94aSFrançois Tigeot 			vaddr = kmap_atomic_px(pd);
1087*3f2dd94aSFrançois Tigeot 		} else {
1088*3f2dd94aSFrançois Tigeot 			struct i915_page_table *pt = pd->page_table[idx.pde];
1089*3f2dd94aSFrançois Tigeot 
1090*3f2dd94aSFrançois Tigeot 			index = idx.pte;
1091*3f2dd94aSFrançois Tigeot 			max = GEN8_PTES;
1092*3f2dd94aSFrançois Tigeot 			page_size = I915_GTT_PAGE_SIZE;
1093*3f2dd94aSFrançois Tigeot 
1094*3f2dd94aSFrançois Tigeot 			if (!index &&
1095*3f2dd94aSFrançois Tigeot 			    vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
1096*3f2dd94aSFrançois Tigeot 			    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
1097*3f2dd94aSFrançois Tigeot 			    (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
1098*3f2dd94aSFrançois Tigeot 			     rem >= (max - index) << PAGE_SHIFT))
1099*3f2dd94aSFrançois Tigeot 				maybe_64K = true;
1100*3f2dd94aSFrançois Tigeot 
1101*3f2dd94aSFrançois Tigeot 			vaddr = kmap_atomic_px(pt);
1102*3f2dd94aSFrançois Tigeot 		}
1103*3f2dd94aSFrançois Tigeot 
1104*3f2dd94aSFrançois Tigeot 		do {
1105*3f2dd94aSFrançois Tigeot 			GEM_BUG_ON(iter->sg->length < page_size);
1106*3f2dd94aSFrançois Tigeot 			vaddr[index++] = encode | iter->dma;
1107*3f2dd94aSFrançois Tigeot 
1108*3f2dd94aSFrançois Tigeot 			start += page_size;
1109*3f2dd94aSFrançois Tigeot 			iter->dma += page_size;
1110*3f2dd94aSFrançois Tigeot 			rem -= page_size;
1111*3f2dd94aSFrançois Tigeot 			if (iter->dma >= iter->max) {
1112*3f2dd94aSFrançois Tigeot 				iter->sg = __sg_next(iter->sg);
1113*3f2dd94aSFrançois Tigeot 				if (!iter->sg)
1114*3f2dd94aSFrançois Tigeot 					break;
1115*3f2dd94aSFrançois Tigeot 
1116*3f2dd94aSFrançois Tigeot 				rem = iter->sg->length;
1117*3f2dd94aSFrançois Tigeot 				iter->dma = sg_dma_address(iter->sg);
1118*3f2dd94aSFrançois Tigeot 				iter->max = iter->dma + rem;
1119*3f2dd94aSFrançois Tigeot 
1120*3f2dd94aSFrançois Tigeot 				if (maybe_64K && index < max &&
1121*3f2dd94aSFrançois Tigeot 				    !(IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
1122*3f2dd94aSFrançois Tigeot 				      (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
1123*3f2dd94aSFrançois Tigeot 				       rem >= (max - index) << PAGE_SHIFT)))
1124*3f2dd94aSFrançois Tigeot 					maybe_64K = false;
1125*3f2dd94aSFrançois Tigeot 
1126*3f2dd94aSFrançois Tigeot 				if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
1127*3f2dd94aSFrançois Tigeot 					break;
1128*3f2dd94aSFrançois Tigeot 			}
1129*3f2dd94aSFrançois Tigeot 		} while (rem >= page_size && index < max);
1130*3f2dd94aSFrançois Tigeot 
1131*3f2dd94aSFrançois Tigeot 		kunmap_atomic(vaddr);
1132*3f2dd94aSFrançois Tigeot 
1133*3f2dd94aSFrançois Tigeot 		/*
1134*3f2dd94aSFrançois Tigeot 		 * Is it safe to mark the 2M block as 64K? -- Either we have
1135*3f2dd94aSFrançois Tigeot 		 * filled whole page-table with 64K entries, or filled part of
1136*3f2dd94aSFrançois Tigeot 		 * it and have reached the end of the sg table and we have
1137*3f2dd94aSFrançois Tigeot 		 * enough padding.
1138*3f2dd94aSFrançois Tigeot 		 */
1139*3f2dd94aSFrançois Tigeot 		if (maybe_64K &&
1140*3f2dd94aSFrançois Tigeot 		    (index == max ||
1141*3f2dd94aSFrançois Tigeot 		     (i915_vm_has_scratch_64K(vma->vm) &&
1142*3f2dd94aSFrançois Tigeot 		      !iter->sg && IS_ALIGNED(vma->node.start +
1143*3f2dd94aSFrançois Tigeot 					      vma->node.size,
1144*3f2dd94aSFrançois Tigeot 					      I915_GTT_PAGE_SIZE_2M)))) {
1145*3f2dd94aSFrançois Tigeot 			vaddr = kmap_atomic_px(pd);
1146*3f2dd94aSFrançois Tigeot 			vaddr[idx.pde] |= GEN8_PDE_IPS_64K;
1147*3f2dd94aSFrançois Tigeot 			kunmap_atomic(vaddr);
1148*3f2dd94aSFrançois Tigeot 			page_size = I915_GTT_PAGE_SIZE_64K;
1149*3f2dd94aSFrançois Tigeot 		}
1150*3f2dd94aSFrançois Tigeot 
1151*3f2dd94aSFrançois Tigeot 		vma->page_sizes.gtt |= page_size;
1152*3f2dd94aSFrançois Tigeot 	} while (iter->sg);
1153352ff8bdSFrançois Tigeot }
1154352ff8bdSFrançois Tigeot 
gen8_ppgtt_insert_4lvl(struct i915_address_space * vm,struct i915_vma * vma,enum i915_cache_level cache_level,u32 unused)1155a85cb24fSFrançois Tigeot static void gen8_ppgtt_insert_4lvl(struct i915_address_space *vm,
1156*3f2dd94aSFrançois Tigeot 				   struct i915_vma *vma,
1157a85cb24fSFrançois Tigeot 				   enum i915_cache_level cache_level,
1158a85cb24fSFrançois Tigeot 				   u32 unused)
1159a85cb24fSFrançois Tigeot {
1160a85cb24fSFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
1161*3f2dd94aSFrançois Tigeot 	struct sgt_dma iter = sgt_dma(vma);
1162a85cb24fSFrançois Tigeot 	struct i915_page_directory_pointer **pdps = ppgtt->pml4.pdps;
1163a85cb24fSFrançois Tigeot 
1164*3f2dd94aSFrançois Tigeot 	if (vma->page_sizes.sg > I915_GTT_PAGE_SIZE) {
1165*3f2dd94aSFrançois Tigeot 		gen8_ppgtt_insert_huge_entries(vma, pdps, &iter, cache_level);
1166*3f2dd94aSFrançois Tigeot 	} else {
1167*3f2dd94aSFrançois Tigeot 		struct gen8_insert_pte idx = gen8_insert_pte(vma->node.start);
1168*3f2dd94aSFrançois Tigeot 
1169*3f2dd94aSFrançois Tigeot 		while (gen8_ppgtt_insert_pte_entries(ppgtt, pdps[idx.pml4e++],
1170*3f2dd94aSFrançois Tigeot 						     &iter, &idx, cache_level))
1171a85cb24fSFrançois Tigeot 			GEM_BUG_ON(idx.pml4e >= GEN8_PML4ES_PER_PML4);
1172*3f2dd94aSFrançois Tigeot 
1173*3f2dd94aSFrançois Tigeot 		vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
1174*3f2dd94aSFrançois Tigeot 	}
1175a85cb24fSFrançois Tigeot }
1176a85cb24fSFrançois Tigeot 
gen8_free_page_tables(struct i915_address_space * vm,struct i915_page_directory * pd)1177a85cb24fSFrançois Tigeot static void gen8_free_page_tables(struct i915_address_space *vm,
117819c468b4SFrançois Tigeot 				  struct i915_page_directory *pd)
117919c468b4SFrançois Tigeot {
118019c468b4SFrançois Tigeot 	int i;
118119c468b4SFrançois Tigeot 
1182a05eeebfSFrançois Tigeot 	if (!px_page(pd))
1183ba55f2f5SFrançois Tigeot 		return;
1184ba55f2f5SFrançois Tigeot 
1185a85cb24fSFrançois Tigeot 	for (i = 0; i < I915_PDES; i++) {
1186a85cb24fSFrançois Tigeot 		if (pd->page_table[i] != vm->scratch_pt)
1187a85cb24fSFrançois Tigeot 			free_pt(vm, pd->page_table[i]);
1188477eb7f9SFrançois Tigeot 	}
1189ba55f2f5SFrançois Tigeot }
1190ba55f2f5SFrançois Tigeot 
gen8_init_scratch(struct i915_address_space * vm)1191a05eeebfSFrançois Tigeot static int gen8_init_scratch(struct i915_address_space *vm)
1192a05eeebfSFrançois Tigeot {
11931487f786SFrançois Tigeot 	int ret;
1194a05eeebfSFrançois Tigeot 
1195a85cb24fSFrançois Tigeot 	ret = setup_scratch_page(vm, I915_GFP_DMA);
11961e12ee3bSFrançois Tigeot 	if (ret)
11971e12ee3bSFrançois Tigeot 		return ret;
1198a05eeebfSFrançois Tigeot 
1199a85cb24fSFrançois Tigeot 	vm->scratch_pt = alloc_pt(vm);
1200a05eeebfSFrançois Tigeot 	if (IS_ERR(vm->scratch_pt)) {
12011487f786SFrançois Tigeot 		ret = PTR_ERR(vm->scratch_pt);
12021487f786SFrançois Tigeot 		goto free_scratch_page;
1203a05eeebfSFrançois Tigeot 	}
1204a05eeebfSFrançois Tigeot 
1205a85cb24fSFrançois Tigeot 	vm->scratch_pd = alloc_pd(vm);
1206a05eeebfSFrançois Tigeot 	if (IS_ERR(vm->scratch_pd)) {
12071487f786SFrançois Tigeot 		ret = PTR_ERR(vm->scratch_pd);
12081487f786SFrançois Tigeot 		goto free_pt;
1209a05eeebfSFrançois Tigeot 	}
1210a05eeebfSFrançois Tigeot 
1211a85cb24fSFrançois Tigeot 	if (use_4lvl(vm)) {
1212a85cb24fSFrançois Tigeot 		vm->scratch_pdp = alloc_pdp(vm);
1213352ff8bdSFrançois Tigeot 		if (IS_ERR(vm->scratch_pdp)) {
12141487f786SFrançois Tigeot 			ret = PTR_ERR(vm->scratch_pdp);
12151487f786SFrançois Tigeot 			goto free_pd;
1216352ff8bdSFrançois Tigeot 		}
1217352ff8bdSFrançois Tigeot 	}
1218352ff8bdSFrançois Tigeot 
1219a05eeebfSFrançois Tigeot 	gen8_initialize_pt(vm, vm->scratch_pt);
1220a05eeebfSFrançois Tigeot 	gen8_initialize_pd(vm, vm->scratch_pd);
1221a85cb24fSFrançois Tigeot 	if (use_4lvl(vm))
1222352ff8bdSFrançois Tigeot 		gen8_initialize_pdp(vm, vm->scratch_pdp);
1223352ff8bdSFrançois Tigeot 
1224352ff8bdSFrançois Tigeot 	return 0;
12251487f786SFrançois Tigeot 
12261487f786SFrançois Tigeot free_pd:
1227a85cb24fSFrançois Tigeot 	free_pd(vm, vm->scratch_pd);
12281487f786SFrançois Tigeot free_pt:
1229a85cb24fSFrançois Tigeot 	free_pt(vm, vm->scratch_pt);
12301487f786SFrançois Tigeot free_scratch_page:
1231a85cb24fSFrançois Tigeot 	cleanup_scratch_page(vm);
12321487f786SFrançois Tigeot 
12331487f786SFrançois Tigeot 	return ret;
1234352ff8bdSFrançois Tigeot }
1235352ff8bdSFrançois Tigeot 
gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt * ppgtt,bool create)1236352ff8bdSFrançois Tigeot static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create)
1237352ff8bdSFrançois Tigeot {
1238a85cb24fSFrançois Tigeot 	struct i915_address_space *vm = &ppgtt->base;
1239a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = vm->i915;
1240352ff8bdSFrançois Tigeot 	enum vgt_g2v_type msg;
1241352ff8bdSFrançois Tigeot 	int i;
1242352ff8bdSFrançois Tigeot 
1243a85cb24fSFrançois Tigeot 	if (use_4lvl(vm)) {
1244a85cb24fSFrançois Tigeot 		const u64 daddr = px_dma(&ppgtt->pml4);
1245352ff8bdSFrançois Tigeot 
1246aee94f86SFrançois Tigeot 		I915_WRITE(vgtif_reg(pdp[0].lo), lower_32_bits(daddr));
1247aee94f86SFrançois Tigeot 		I915_WRITE(vgtif_reg(pdp[0].hi), upper_32_bits(daddr));
1248352ff8bdSFrançois Tigeot 
1249352ff8bdSFrançois Tigeot 		msg = (create ? VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
1250352ff8bdSFrançois Tigeot 				VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY);
1251352ff8bdSFrançois Tigeot 	} else {
1252a85cb24fSFrançois Tigeot 		for (i = 0; i < GEN8_3LVL_PDPES; i++) {
1253a85cb24fSFrançois Tigeot 			const u64 daddr = i915_page_dir_dma_addr(ppgtt, i);
1254352ff8bdSFrançois Tigeot 
1255aee94f86SFrançois Tigeot 			I915_WRITE(vgtif_reg(pdp[i].lo), lower_32_bits(daddr));
1256aee94f86SFrançois Tigeot 			I915_WRITE(vgtif_reg(pdp[i].hi), upper_32_bits(daddr));
1257352ff8bdSFrançois Tigeot 		}
1258352ff8bdSFrançois Tigeot 
1259352ff8bdSFrançois Tigeot 		msg = (create ? VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
1260352ff8bdSFrançois Tigeot 				VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY);
1261352ff8bdSFrançois Tigeot 	}
1262352ff8bdSFrançois Tigeot 
1263352ff8bdSFrançois Tigeot 	I915_WRITE(vgtif_reg(g2v_notify), msg);
1264a05eeebfSFrançois Tigeot 
1265a05eeebfSFrançois Tigeot 	return 0;
1266a05eeebfSFrançois Tigeot }
1267a05eeebfSFrançois Tigeot 
gen8_free_scratch(struct i915_address_space * vm)1268a05eeebfSFrançois Tigeot static void gen8_free_scratch(struct i915_address_space *vm)
1269a05eeebfSFrançois Tigeot {
1270a85cb24fSFrançois Tigeot 	if (use_4lvl(vm))
1271a85cb24fSFrançois Tigeot 		free_pdp(vm, vm->scratch_pdp);
1272a85cb24fSFrançois Tigeot 	free_pd(vm, vm->scratch_pd);
1273a85cb24fSFrançois Tigeot 	free_pt(vm, vm->scratch_pt);
1274a85cb24fSFrançois Tigeot 	cleanup_scratch_page(vm);
1275a05eeebfSFrançois Tigeot }
1276a05eeebfSFrançois Tigeot 
gen8_ppgtt_cleanup_3lvl(struct i915_address_space * vm,struct i915_page_directory_pointer * pdp)1277a85cb24fSFrançois Tigeot static void gen8_ppgtt_cleanup_3lvl(struct i915_address_space *vm,
1278352ff8bdSFrançois Tigeot 				    struct i915_page_directory_pointer *pdp)
1279352ff8bdSFrançois Tigeot {
1280a85cb24fSFrançois Tigeot 	const unsigned int pdpes = i915_pdpes_per_pdp(vm);
1281352ff8bdSFrançois Tigeot 	int i;
1282352ff8bdSFrançois Tigeot 
1283a85cb24fSFrançois Tigeot 	for (i = 0; i < pdpes; i++) {
1284a85cb24fSFrançois Tigeot 		if (pdp->page_directory[i] == vm->scratch_pd)
1285352ff8bdSFrançois Tigeot 			continue;
1286352ff8bdSFrançois Tigeot 
1287a85cb24fSFrançois Tigeot 		gen8_free_page_tables(vm, pdp->page_directory[i]);
1288a85cb24fSFrançois Tigeot 		free_pd(vm, pdp->page_directory[i]);
1289352ff8bdSFrançois Tigeot 	}
1290352ff8bdSFrançois Tigeot 
1291a85cb24fSFrançois Tigeot 	free_pdp(vm, pdp);
1292352ff8bdSFrançois Tigeot }
1293352ff8bdSFrançois Tigeot 
gen8_ppgtt_cleanup_4lvl(struct i915_hw_ppgtt * ppgtt)1294352ff8bdSFrançois Tigeot static void gen8_ppgtt_cleanup_4lvl(struct i915_hw_ppgtt *ppgtt)
1295352ff8bdSFrançois Tigeot {
1296352ff8bdSFrançois Tigeot 	int i;
1297352ff8bdSFrançois Tigeot 
1298a85cb24fSFrançois Tigeot 	for (i = 0; i < GEN8_PML4ES_PER_PML4; i++) {
1299a85cb24fSFrançois Tigeot 		if (ppgtt->pml4.pdps[i] == ppgtt->base.scratch_pdp)
1300352ff8bdSFrançois Tigeot 			continue;
1301352ff8bdSFrançois Tigeot 
1302a85cb24fSFrançois Tigeot 		gen8_ppgtt_cleanup_3lvl(&ppgtt->base, ppgtt->pml4.pdps[i]);
1303352ff8bdSFrançois Tigeot 	}
1304352ff8bdSFrançois Tigeot 
1305a85cb24fSFrançois Tigeot 	cleanup_px(&ppgtt->base, &ppgtt->pml4);
1306352ff8bdSFrançois Tigeot }
1307352ff8bdSFrançois Tigeot 
gen8_ppgtt_cleanup(struct i915_address_space * vm)13089edbd4a0SFrançois Tigeot static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
13099edbd4a0SFrançois Tigeot {
1310a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = vm->i915;
13118621f407SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
13129edbd4a0SFrançois Tigeot 
13134be47400SFrançois Tigeot 	if (intel_vgpu_active(dev_priv))
1314352ff8bdSFrançois Tigeot 		gen8_ppgtt_notify_vgt(ppgtt, false);
131519c468b4SFrançois Tigeot 
1316a85cb24fSFrançois Tigeot 	if (use_4lvl(vm))
1317352ff8bdSFrançois Tigeot 		gen8_ppgtt_cleanup_4lvl(ppgtt);
1318a85cb24fSFrançois Tigeot 	else
1319a85cb24fSFrançois Tigeot 		gen8_ppgtt_cleanup_3lvl(&ppgtt->base, &ppgtt->pdp);
13209edbd4a0SFrançois Tigeot 
1321a05eeebfSFrançois Tigeot 	gen8_free_scratch(vm);
132219c468b4SFrançois Tigeot }
1323ba55f2f5SFrançois Tigeot 
gen8_ppgtt_alloc_pd(struct i915_address_space * vm,struct i915_page_directory * pd,u64 start,u64 length)1324a85cb24fSFrançois Tigeot static int gen8_ppgtt_alloc_pd(struct i915_address_space *vm,
132519c468b4SFrançois Tigeot 			       struct i915_page_directory *pd,
1326a85cb24fSFrançois Tigeot 			       u64 start, u64 length)
132719c468b4SFrançois Tigeot {
132819c468b4SFrançois Tigeot 	struct i915_page_table *pt;
1329a85cb24fSFrançois Tigeot 	u64 from = start;
1330a85cb24fSFrançois Tigeot 	unsigned int pde;
133119c468b4SFrançois Tigeot 
1332aee94f86SFrançois Tigeot 	gen8_for_each_pde(pt, pd, start, length, pde) {
1333*3f2dd94aSFrançois Tigeot 		int count = gen8_pte_count(start, length);
1334*3f2dd94aSFrançois Tigeot 
1335a85cb24fSFrançois Tigeot 		if (pt == vm->scratch_pt) {
1336a85cb24fSFrançois Tigeot 			pt = alloc_pt(vm);
133719c468b4SFrançois Tigeot 			if (IS_ERR(pt))
1338a85cb24fSFrançois Tigeot 				goto unwind;
133919c468b4SFrançois Tigeot 
1340*3f2dd94aSFrançois Tigeot 			if (count < GEN8_PTES || intel_vgpu_active(vm->i915))
1341352ff8bdSFrançois Tigeot 				gen8_initialize_pt(vm, pt);
1342a85cb24fSFrançois Tigeot 
1343a85cb24fSFrançois Tigeot 			gen8_ppgtt_set_pde(vm, pd, pt, pde);
1344a85cb24fSFrançois Tigeot 			pd->used_pdes++;
1345a85cb24fSFrançois Tigeot 			GEM_BUG_ON(pd->used_pdes > I915_PDES);
1346ba55f2f5SFrançois Tigeot 		}
1347ba55f2f5SFrançois Tigeot 
1348*3f2dd94aSFrançois Tigeot 		pt->used_ptes += count;
1349a85cb24fSFrançois Tigeot 	}
1350ba55f2f5SFrançois Tigeot 	return 0;
1351ba55f2f5SFrançois Tigeot 
1352a85cb24fSFrançois Tigeot unwind:
1353a85cb24fSFrançois Tigeot 	gen8_ppgtt_clear_pd(vm, pd, from, start - from);
1354ba55f2f5SFrançois Tigeot 	return -ENOMEM;
1355ba55f2f5SFrançois Tigeot }
1356ba55f2f5SFrançois Tigeot 
gen8_ppgtt_alloc_pdp(struct i915_address_space * vm,struct i915_page_directory_pointer * pdp,u64 start,u64 length)1357a85cb24fSFrançois Tigeot static int gen8_ppgtt_alloc_pdp(struct i915_address_space *vm,
135819c468b4SFrançois Tigeot 				struct i915_page_directory_pointer *pdp,
1359a85cb24fSFrançois Tigeot 				u64 start, u64 length)
136019c468b4SFrançois Tigeot {
136119c468b4SFrançois Tigeot 	struct i915_page_directory *pd;
1362a85cb24fSFrançois Tigeot 	u64 from = start;
1363a85cb24fSFrançois Tigeot 	unsigned int pdpe;
1364ba55f2f5SFrançois Tigeot 	int ret;
1365ba55f2f5SFrançois Tigeot 
1366aee94f86SFrançois Tigeot 	gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
1367a85cb24fSFrançois Tigeot 		if (pd == vm->scratch_pd) {
1368a85cb24fSFrançois Tigeot 			pd = alloc_pd(vm);
1369a85cb24fSFrançois Tigeot 			if (IS_ERR(pd))
1370a85cb24fSFrançois Tigeot 				goto unwind;
1371a85cb24fSFrançois Tigeot 
1372a85cb24fSFrançois Tigeot 			gen8_initialize_pd(vm, pd);
1373a85cb24fSFrançois Tigeot 			gen8_ppgtt_set_pdpe(vm, pdp, pd, pdpe);
1374a85cb24fSFrançois Tigeot 			pdp->used_pdpes++;
1375a85cb24fSFrançois Tigeot 			GEM_BUG_ON(pdp->used_pdpes > i915_pdpes_per_pdp(vm));
1376a85cb24fSFrançois Tigeot 
1377a85cb24fSFrançois Tigeot 			mark_tlbs_dirty(i915_vm_to_ppgtt(vm));
137819c468b4SFrançois Tigeot 		}
137919c468b4SFrançois Tigeot 
1380a85cb24fSFrançois Tigeot 		ret = gen8_ppgtt_alloc_pd(vm, pd, start, length);
1381a85cb24fSFrançois Tigeot 		if (unlikely(ret))
1382a85cb24fSFrançois Tigeot 			goto unwind_pd;
138319c468b4SFrançois Tigeot 	}
138419c468b4SFrançois Tigeot 
138519c468b4SFrançois Tigeot 	return 0;
138619c468b4SFrançois Tigeot 
1387a85cb24fSFrançois Tigeot unwind_pd:
1388a85cb24fSFrançois Tigeot 	if (!pd->used_pdes) {
1389a85cb24fSFrançois Tigeot 		gen8_ppgtt_set_pdpe(vm, pdp, vm->scratch_pd, pdpe);
1390a85cb24fSFrançois Tigeot 		GEM_BUG_ON(!pdp->used_pdpes);
1391a85cb24fSFrançois Tigeot 		pdp->used_pdpes--;
1392a85cb24fSFrançois Tigeot 		free_pd(vm, pd);
1393a85cb24fSFrançois Tigeot 	}
1394a85cb24fSFrançois Tigeot unwind:
1395a85cb24fSFrançois Tigeot 	gen8_ppgtt_clear_pdp(vm, pdp, from, start - from);
1396a85cb24fSFrançois Tigeot 	return -ENOMEM;
139719c468b4SFrançois Tigeot }
139819c468b4SFrançois Tigeot 
gen8_ppgtt_alloc_3lvl(struct i915_address_space * vm,u64 start,u64 length)1399a85cb24fSFrançois Tigeot static int gen8_ppgtt_alloc_3lvl(struct i915_address_space *vm,
1400a85cb24fSFrançois Tigeot 				 u64 start, u64 length)
1401352ff8bdSFrançois Tigeot {
1402a85cb24fSFrançois Tigeot 	return gen8_ppgtt_alloc_pdp(vm,
1403a85cb24fSFrançois Tigeot 				    &i915_vm_to_ppgtt(vm)->pdp, start, length);
1404a85cb24fSFrançois Tigeot }
1405a85cb24fSFrançois Tigeot 
gen8_ppgtt_alloc_4lvl(struct i915_address_space * vm,u64 start,u64 length)1406a85cb24fSFrançois Tigeot static int gen8_ppgtt_alloc_4lvl(struct i915_address_space *vm,
1407a85cb24fSFrançois Tigeot 				 u64 start, u64 length)
1408a85cb24fSFrançois Tigeot {
14098621f407SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
1410a85cb24fSFrançois Tigeot 	struct i915_pml4 *pml4 = &ppgtt->pml4;
1411352ff8bdSFrançois Tigeot 	struct i915_page_directory_pointer *pdp;
1412a85cb24fSFrançois Tigeot 	u64 from = start;
1413a85cb24fSFrançois Tigeot 	u32 pml4e;
1414a85cb24fSFrançois Tigeot 	int ret;
1415352ff8bdSFrançois Tigeot 
1416aee94f86SFrançois Tigeot 	gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) {
1417a85cb24fSFrançois Tigeot 		if (pml4->pdps[pml4e] == vm->scratch_pdp) {
1418a85cb24fSFrançois Tigeot 			pdp = alloc_pdp(vm);
1419a85cb24fSFrançois Tigeot 			if (IS_ERR(pdp))
1420a85cb24fSFrançois Tigeot 				goto unwind;
1421352ff8bdSFrançois Tigeot 
1422a85cb24fSFrançois Tigeot 			gen8_initialize_pdp(vm, pdp);
1423a85cb24fSFrançois Tigeot 			gen8_ppgtt_set_pml4e(pml4, pdp, pml4e);
1424352ff8bdSFrançois Tigeot 		}
1425352ff8bdSFrançois Tigeot 
1426a85cb24fSFrançois Tigeot 		ret = gen8_ppgtt_alloc_pdp(vm, pdp, start, length);
1427a85cb24fSFrançois Tigeot 		if (unlikely(ret))
1428a85cb24fSFrançois Tigeot 			goto unwind_pdp;
1429a85cb24fSFrançois Tigeot 	}
1430352ff8bdSFrançois Tigeot 
1431352ff8bdSFrançois Tigeot 	return 0;
1432352ff8bdSFrançois Tigeot 
1433a85cb24fSFrançois Tigeot unwind_pdp:
1434a85cb24fSFrançois Tigeot 	if (!pdp->used_pdpes) {
1435a85cb24fSFrançois Tigeot 		gen8_ppgtt_set_pml4e(pml4, vm->scratch_pdp, pml4e);
1436a85cb24fSFrançois Tigeot 		free_pdp(vm, pdp);
1437a85cb24fSFrançois Tigeot 	}
1438a85cb24fSFrançois Tigeot unwind:
1439a85cb24fSFrançois Tigeot 	gen8_ppgtt_clear_4lvl(vm, from, start - from);
1440a85cb24fSFrançois Tigeot 	return -ENOMEM;
1441352ff8bdSFrançois Tigeot }
1442352ff8bdSFrançois Tigeot 
gen8_dump_pdp(struct i915_hw_ppgtt * ppgtt,struct i915_page_directory_pointer * pdp,u64 start,u64 length,gen8_pte_t scratch_pte,struct seq_file * m)1443a85cb24fSFrançois Tigeot static void gen8_dump_pdp(struct i915_hw_ppgtt *ppgtt,
1444a85cb24fSFrançois Tigeot 			  struct i915_page_directory_pointer *pdp,
1445a85cb24fSFrançois Tigeot 			  u64 start, u64 length,
1446352ff8bdSFrançois Tigeot 			  gen8_pte_t scratch_pte,
1447352ff8bdSFrançois Tigeot 			  struct seq_file *m)
1448352ff8bdSFrançois Tigeot {
1449a85cb24fSFrançois Tigeot 	struct i915_address_space *vm = &ppgtt->base;
1450352ff8bdSFrançois Tigeot 	struct i915_page_directory *pd;
1451a85cb24fSFrançois Tigeot 	u32 pdpe;
1452352ff8bdSFrançois Tigeot 
1453aee94f86SFrançois Tigeot 	gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
1454352ff8bdSFrançois Tigeot 		struct i915_page_table *pt;
1455a85cb24fSFrançois Tigeot 		u64 pd_len = length;
1456a85cb24fSFrançois Tigeot 		u64 pd_start = start;
1457a85cb24fSFrançois Tigeot 		u32 pde;
1458352ff8bdSFrançois Tigeot 
1459a85cb24fSFrançois Tigeot 		if (pdp->page_directory[pdpe] == ppgtt->base.scratch_pd)
1460352ff8bdSFrançois Tigeot 			continue;
1461352ff8bdSFrançois Tigeot 
1462352ff8bdSFrançois Tigeot 		seq_printf(m, "\tPDPE #%d\n", pdpe);
1463aee94f86SFrançois Tigeot 		gen8_for_each_pde(pt, pd, pd_start, pd_len, pde) {
1464a85cb24fSFrançois Tigeot 			u32 pte;
1465352ff8bdSFrançois Tigeot 			gen8_pte_t *pt_vaddr;
1466352ff8bdSFrançois Tigeot 
1467a85cb24fSFrançois Tigeot 			if (pd->page_table[pde] == ppgtt->base.scratch_pt)
1468352ff8bdSFrançois Tigeot 				continue;
1469352ff8bdSFrançois Tigeot 
1470a85cb24fSFrançois Tigeot 			pt_vaddr = kmap_atomic_px(pt);
1471352ff8bdSFrançois Tigeot 			for (pte = 0; pte < GEN8_PTES; pte += 4) {
1472a85cb24fSFrançois Tigeot 				u64 va = (pdpe << GEN8_PDPE_SHIFT |
1473a85cb24fSFrançois Tigeot 					  pde << GEN8_PDE_SHIFT |
1474a85cb24fSFrançois Tigeot 					  pte << GEN8_PTE_SHIFT);
1475352ff8bdSFrançois Tigeot 				int i;
1476352ff8bdSFrançois Tigeot 				bool found = false;
1477352ff8bdSFrançois Tigeot 
1478352ff8bdSFrançois Tigeot 				for (i = 0; i < 4; i++)
1479352ff8bdSFrançois Tigeot 					if (pt_vaddr[pte + i] != scratch_pte)
1480352ff8bdSFrançois Tigeot 						found = true;
1481352ff8bdSFrançois Tigeot 				if (!found)
1482352ff8bdSFrançois Tigeot 					continue;
1483352ff8bdSFrançois Tigeot 
14844be47400SFrançois Tigeot 				seq_printf(m, "\t\t0x%llx [%03d,%03d,%04d]: =", va, pdpe, pde, pte);
1485352ff8bdSFrançois Tigeot 				for (i = 0; i < 4; i++) {
1486352ff8bdSFrançois Tigeot 					if (pt_vaddr[pte + i] != scratch_pte)
14874be47400SFrançois Tigeot 						seq_printf(m, " %llx", pt_vaddr[pte + i]);
1488352ff8bdSFrançois Tigeot 					else
1489352ff8bdSFrançois Tigeot 						seq_puts(m, "  SCRATCH ");
1490352ff8bdSFrançois Tigeot 				}
1491352ff8bdSFrançois Tigeot 				seq_puts(m, "\n");
1492352ff8bdSFrançois Tigeot 			}
1493352ff8bdSFrançois Tigeot 			kunmap_atomic(pt_vaddr);
1494352ff8bdSFrançois Tigeot 		}
1495352ff8bdSFrançois Tigeot 	}
1496352ff8bdSFrançois Tigeot }
1497352ff8bdSFrançois Tigeot 
gen8_dump_ppgtt(struct i915_hw_ppgtt * ppgtt,struct seq_file * m)1498352ff8bdSFrançois Tigeot static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
1499352ff8bdSFrançois Tigeot {
1500352ff8bdSFrançois Tigeot 	struct i915_address_space *vm = &ppgtt->base;
1501a85cb24fSFrançois Tigeot 	const gen8_pte_t scratch_pte =
1502a85cb24fSFrançois Tigeot 		gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC);
1503a85cb24fSFrançois Tigeot 	u64 start = 0, length = ppgtt->base.total;
1504352ff8bdSFrançois Tigeot 
1505a85cb24fSFrançois Tigeot 	if (use_4lvl(vm)) {
1506a85cb24fSFrançois Tigeot 		u64 pml4e;
1507352ff8bdSFrançois Tigeot 		struct i915_pml4 *pml4 = &ppgtt->pml4;
1508352ff8bdSFrançois Tigeot 		struct i915_page_directory_pointer *pdp;
1509352ff8bdSFrançois Tigeot 
1510aee94f86SFrançois Tigeot 		gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) {
1511a85cb24fSFrançois Tigeot 			if (pml4->pdps[pml4e] == ppgtt->base.scratch_pdp)
1512352ff8bdSFrançois Tigeot 				continue;
1513352ff8bdSFrançois Tigeot 
15144be47400SFrançois Tigeot 			seq_printf(m, "    PML4E #%llu\n", pml4e);
1515a85cb24fSFrançois Tigeot 			gen8_dump_pdp(ppgtt, pdp, start, length, scratch_pte, m);
1516352ff8bdSFrançois Tigeot 		}
1517a85cb24fSFrançois Tigeot 	} else {
1518a85cb24fSFrançois Tigeot 		gen8_dump_pdp(ppgtt, &ppgtt->pdp, start, length, scratch_pte, m);
1519352ff8bdSFrançois Tigeot 	}
1520352ff8bdSFrançois Tigeot }
1521352ff8bdSFrançois Tigeot 
gen8_preallocate_top_level_pdp(struct i915_hw_ppgtt * ppgtt)1522a85cb24fSFrançois Tigeot static int gen8_preallocate_top_level_pdp(struct i915_hw_ppgtt *ppgtt)
1523352ff8bdSFrançois Tigeot {
1524a85cb24fSFrançois Tigeot 	struct i915_address_space *vm = &ppgtt->base;
1525a85cb24fSFrançois Tigeot 	struct i915_page_directory_pointer *pdp = &ppgtt->pdp;
1526a85cb24fSFrançois Tigeot 	struct i915_page_directory *pd;
1527a85cb24fSFrançois Tigeot 	u64 start = 0, length = ppgtt->base.total;
1528a85cb24fSFrançois Tigeot 	u64 from = start;
1529a85cb24fSFrançois Tigeot 	unsigned int pdpe;
1530352ff8bdSFrançois Tigeot 
1531a85cb24fSFrançois Tigeot 	gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
1532a85cb24fSFrançois Tigeot 		pd = alloc_pd(vm);
1533a85cb24fSFrançois Tigeot 		if (IS_ERR(pd))
1534a85cb24fSFrançois Tigeot 			goto unwind;
1535352ff8bdSFrançois Tigeot 
1536a85cb24fSFrançois Tigeot 		gen8_initialize_pd(vm, pd);
1537a85cb24fSFrançois Tigeot 		gen8_ppgtt_set_pdpe(vm, pdp, pd, pdpe);
1538a85cb24fSFrançois Tigeot 		pdp->used_pdpes++;
1539a85cb24fSFrançois Tigeot 	}
1540352ff8bdSFrançois Tigeot 
1541a85cb24fSFrançois Tigeot 	pdp->used_pdpes++; /* never remove */
1542a85cb24fSFrançois Tigeot 	return 0;
1543352ff8bdSFrançois Tigeot 
1544a85cb24fSFrançois Tigeot unwind:
1545a85cb24fSFrançois Tigeot 	start -= from;
1546a85cb24fSFrançois Tigeot 	gen8_for_each_pdpe(pd, pdp, from, start, pdpe) {
1547a85cb24fSFrançois Tigeot 		gen8_ppgtt_set_pdpe(vm, pdp, vm->scratch_pd, pdpe);
1548a85cb24fSFrançois Tigeot 		free_pd(vm, pd);
1549a85cb24fSFrançois Tigeot 	}
1550a85cb24fSFrançois Tigeot 	pdp->used_pdpes = 0;
1551a85cb24fSFrançois Tigeot 	return -ENOMEM;
1552352ff8bdSFrançois Tigeot }
1553352ff8bdSFrançois Tigeot 
155419c468b4SFrançois Tigeot /*
155519c468b4SFrançois Tigeot  * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
155619c468b4SFrançois Tigeot  * with a net effect resembling a 2-level page table in normal x86 terms. Each
155719c468b4SFrançois Tigeot  * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
155819c468b4SFrançois Tigeot  * space.
155919c468b4SFrançois Tigeot  *
156019c468b4SFrançois Tigeot  */
gen8_ppgtt_init(struct i915_hw_ppgtt * ppgtt)156119c468b4SFrançois Tigeot static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
1562ba55f2f5SFrançois Tigeot {
1563a85cb24fSFrançois Tigeot 	struct i915_address_space *vm = &ppgtt->base;
1564a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = vm->i915;
1565a05eeebfSFrançois Tigeot 	int ret;
1566ba55f2f5SFrançois Tigeot 
1567a85cb24fSFrançois Tigeot 	ppgtt->base.total = USES_FULL_48BIT_PPGTT(dev_priv) ?
1568a85cb24fSFrançois Tigeot 		1ULL << 48 :
1569a85cb24fSFrançois Tigeot 		1ULL << 32;
1570a85cb24fSFrançois Tigeot 
1571a85cb24fSFrançois Tigeot 	/* There are only few exceptions for gen >=6. chv and bxt.
1572a85cb24fSFrançois Tigeot 	 * And we are not sure about the latter so play safe for now.
1573a85cb24fSFrançois Tigeot 	 */
1574a85cb24fSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv) || IS_BROXTON(dev_priv))
1575a85cb24fSFrançois Tigeot 		ppgtt->base.pt_kmap_wc = true;
15769edbd4a0SFrançois Tigeot 
1577*3f2dd94aSFrançois Tigeot 	ret = gen8_init_scratch(&ppgtt->base);
1578*3f2dd94aSFrançois Tigeot 	if (ret) {
1579*3f2dd94aSFrançois Tigeot 		ppgtt->base.total = 0;
1580*3f2dd94aSFrançois Tigeot 		return ret;
1581*3f2dd94aSFrançois Tigeot 	}
1582*3f2dd94aSFrançois Tigeot 
1583a85cb24fSFrançois Tigeot 	if (use_4lvl(vm)) {
1584a85cb24fSFrançois Tigeot 		ret = setup_px(&ppgtt->base, &ppgtt->pml4);
1585352ff8bdSFrançois Tigeot 		if (ret)
1586352ff8bdSFrançois Tigeot 			goto free_scratch;
1587352ff8bdSFrançois Tigeot 
1588352ff8bdSFrançois Tigeot 		gen8_initialize_pml4(&ppgtt->base, &ppgtt->pml4);
1589352ff8bdSFrançois Tigeot 
1590a85cb24fSFrançois Tigeot 		ppgtt->switch_mm = gen8_mm_switch_4lvl;
1591a85cb24fSFrançois Tigeot 		ppgtt->base.allocate_va_range = gen8_ppgtt_alloc_4lvl;
1592a85cb24fSFrançois Tigeot 		ppgtt->base.insert_entries = gen8_ppgtt_insert_4lvl;
1593a85cb24fSFrançois Tigeot 		ppgtt->base.clear_range = gen8_ppgtt_clear_4lvl;
1594352ff8bdSFrançois Tigeot 	} else {
1595a85cb24fSFrançois Tigeot 		ret = __pdp_init(&ppgtt->base, &ppgtt->pdp);
1596352ff8bdSFrançois Tigeot 		if (ret)
1597352ff8bdSFrançois Tigeot 			goto free_scratch;
1598352ff8bdSFrançois Tigeot 
15994be47400SFrançois Tigeot 		if (intel_vgpu_active(dev_priv)) {
1600a85cb24fSFrançois Tigeot 			ret = gen8_preallocate_top_level_pdp(ppgtt);
1601a85cb24fSFrançois Tigeot 			if (ret) {
1602a85cb24fSFrançois Tigeot 				__pdp_fini(&ppgtt->pdp);
1603352ff8bdSFrançois Tigeot 				goto free_scratch;
1604352ff8bdSFrançois Tigeot 			}
1605352ff8bdSFrançois Tigeot 		}
1606352ff8bdSFrançois Tigeot 
1607a85cb24fSFrançois Tigeot 		ppgtt->switch_mm = gen8_mm_switch_3lvl;
1608a85cb24fSFrançois Tigeot 		ppgtt->base.allocate_va_range = gen8_ppgtt_alloc_3lvl;
1609a85cb24fSFrançois Tigeot 		ppgtt->base.insert_entries = gen8_ppgtt_insert_3lvl;
1610a85cb24fSFrançois Tigeot 		ppgtt->base.clear_range = gen8_ppgtt_clear_3lvl;
1611a85cb24fSFrançois Tigeot 	}
1612a85cb24fSFrançois Tigeot 
16134be47400SFrançois Tigeot 	if (intel_vgpu_active(dev_priv))
1614352ff8bdSFrançois Tigeot 		gen8_ppgtt_notify_vgt(ppgtt, true);
1615ba55f2f5SFrançois Tigeot 
1616a85cb24fSFrançois Tigeot 	ppgtt->base.cleanup = gen8_ppgtt_cleanup;
1617a85cb24fSFrançois Tigeot 	ppgtt->base.unbind_vma = ppgtt_unbind_vma;
1618a85cb24fSFrançois Tigeot 	ppgtt->base.bind_vma = ppgtt_bind_vma;
1619*3f2dd94aSFrançois Tigeot 	ppgtt->base.set_pages = ppgtt_set_pages;
1620*3f2dd94aSFrançois Tigeot 	ppgtt->base.clear_pages = clear_pages;
1621a85cb24fSFrançois Tigeot 	ppgtt->debug_dump = gen8_dump_ppgtt;
1622a85cb24fSFrançois Tigeot 
16239edbd4a0SFrançois Tigeot 	return 0;
1624352ff8bdSFrançois Tigeot 
1625352ff8bdSFrançois Tigeot free_scratch:
1626352ff8bdSFrançois Tigeot 	gen8_free_scratch(&ppgtt->base);
1627352ff8bdSFrançois Tigeot 	return ret;
16289edbd4a0SFrançois Tigeot }
16299edbd4a0SFrançois Tigeot 
gen6_dump_ppgtt(struct i915_hw_ppgtt * ppgtt,struct seq_file * m)1630ba55f2f5SFrançois Tigeot static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
1631ba55f2f5SFrançois Tigeot {
1632ba55f2f5SFrançois Tigeot 	struct i915_address_space *vm = &ppgtt->base;
163319c468b4SFrançois Tigeot 	struct i915_page_table *unused;
1634477eb7f9SFrançois Tigeot 	gen6_pte_t scratch_pte;
1635a85cb24fSFrançois Tigeot 	u32 pd_entry, pte, pde;
1636a85cb24fSFrançois Tigeot 	u32 start = 0, length = ppgtt->base.total;
1637ba55f2f5SFrançois Tigeot 
16381e12ee3bSFrançois Tigeot 	scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
16391e12ee3bSFrançois Tigeot 				     I915_CACHE_LLC, 0);
1640ba55f2f5SFrançois Tigeot 
16411487f786SFrançois Tigeot 	gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde) {
1642ba55f2f5SFrançois Tigeot 		u32 expected;
1643477eb7f9SFrançois Tigeot 		gen6_pte_t *pt_vaddr;
1644a05eeebfSFrançois Tigeot 		const dma_addr_t pt_addr = px_dma(ppgtt->pd.page_table[pde]);
164519c468b4SFrançois Tigeot 		pd_entry = readl(ppgtt->pd_addr + pde);
1646ba55f2f5SFrançois Tigeot 		expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID);
1647ba55f2f5SFrançois Tigeot 
1648ba55f2f5SFrançois Tigeot 		if (pd_entry != expected)
1649ba55f2f5SFrançois Tigeot 			seq_printf(m, "\tPDE #%d mismatch: Actual PDE: %x Expected PDE: %x\n",
1650ba55f2f5SFrançois Tigeot 				   pde,
1651ba55f2f5SFrançois Tigeot 				   pd_entry,
1652ba55f2f5SFrançois Tigeot 				   expected);
1653ba55f2f5SFrançois Tigeot 		seq_printf(m, "\tPDE: %x\n", pd_entry);
1654ba55f2f5SFrançois Tigeot 
1655a85cb24fSFrançois Tigeot 		pt_vaddr = kmap_atomic_px(ppgtt->pd.page_table[pde]);
1656a05eeebfSFrançois Tigeot 
1657477eb7f9SFrançois Tigeot 		for (pte = 0; pte < GEN6_PTES; pte+=4) {
1658ba55f2f5SFrançois Tigeot 			unsigned long va =
1659477eb7f9SFrançois Tigeot 				(pde * PAGE_SIZE * GEN6_PTES) +
1660ba55f2f5SFrançois Tigeot 				(pte * PAGE_SIZE);
1661ba55f2f5SFrançois Tigeot 			int i;
1662ba55f2f5SFrançois Tigeot 			bool found = false;
1663ba55f2f5SFrançois Tigeot 			for (i = 0; i < 4; i++)
1664ba55f2f5SFrançois Tigeot 				if (pt_vaddr[pte + i] != scratch_pte)
1665ba55f2f5SFrançois Tigeot 					found = true;
1666ba55f2f5SFrançois Tigeot 			if (!found)
1667ba55f2f5SFrançois Tigeot 				continue;
1668ba55f2f5SFrançois Tigeot 
1669ba55f2f5SFrançois Tigeot 			seq_printf(m, "\t\t0x%lx [%03d,%04d]: =", va, pde, pte);
1670ba55f2f5SFrançois Tigeot 			for (i = 0; i < 4; i++) {
1671ba55f2f5SFrançois Tigeot 				if (pt_vaddr[pte + i] != scratch_pte)
1672ba55f2f5SFrançois Tigeot 					seq_printf(m, " %08x", pt_vaddr[pte + i]);
1673ba55f2f5SFrançois Tigeot 				else
1674477eb7f9SFrançois Tigeot 					seq_puts(m, "  SCRATCH ");
1675ba55f2f5SFrançois Tigeot 			}
1676477eb7f9SFrançois Tigeot 			seq_puts(m, "\n");
1677ba55f2f5SFrançois Tigeot 		}
1678a85cb24fSFrançois Tigeot 		kunmap_atomic(pt_vaddr);
1679ba55f2f5SFrançois Tigeot 	}
1680ba55f2f5SFrançois Tigeot }
1681ba55f2f5SFrançois Tigeot 
1682477eb7f9SFrançois Tigeot /* Write pde (index) from the page directory @pd to the page table @pt */
gen6_write_pde(const struct i915_hw_ppgtt * ppgtt,const unsigned int pde,const struct i915_page_table * pt)1683a85cb24fSFrançois Tigeot static inline void gen6_write_pde(const struct i915_hw_ppgtt *ppgtt,
1684a85cb24fSFrançois Tigeot 				  const unsigned int pde,
1685a85cb24fSFrançois Tigeot 				  const struct i915_page_table *pt)
16869edbd4a0SFrançois Tigeot {
1687477eb7f9SFrançois Tigeot 	/* Caller needs to make sure the write completes if necessary */
1688a85cb24fSFrançois Tigeot 	writel_relaxed(GEN6_PDE_ADDR_ENCODE(px_dma(pt)) | GEN6_PDE_VALID,
1689a85cb24fSFrançois Tigeot 		       ppgtt->pd_addr + pde);
16909edbd4a0SFrançois Tigeot }
1691477eb7f9SFrançois Tigeot 
1692477eb7f9SFrançois Tigeot /* Write all the page tables found in the ppgtt structure to incrementing page
1693477eb7f9SFrançois Tigeot  * directories. */
gen6_write_page_range(struct i915_hw_ppgtt * ppgtt,u32 start,u32 length)1694a85cb24fSFrançois Tigeot static void gen6_write_page_range(struct i915_hw_ppgtt *ppgtt,
1695a85cb24fSFrançois Tigeot 				  u32 start, u32 length)
1696477eb7f9SFrançois Tigeot {
169719c468b4SFrançois Tigeot 	struct i915_page_table *pt;
1698a85cb24fSFrançois Tigeot 	unsigned int pde;
1699477eb7f9SFrançois Tigeot 
1700a85cb24fSFrançois Tigeot 	gen6_for_each_pde(pt, &ppgtt->pd, start, length, pde)
1701a85cb24fSFrançois Tigeot 		gen6_write_pde(ppgtt, pde, pt);
1702477eb7f9SFrançois Tigeot 
1703a85cb24fSFrançois Tigeot 	mark_tlbs_dirty(ppgtt);
1704a85cb24fSFrançois Tigeot 	wmb();
17059edbd4a0SFrançois Tigeot }
17069edbd4a0SFrançois Tigeot 
get_pd_offset(struct i915_hw_ppgtt * ppgtt)1707a85cb24fSFrançois Tigeot static inline u32 get_pd_offset(struct i915_hw_ppgtt *ppgtt)
17088e26cdf6SFrançois Tigeot {
1709a85cb24fSFrançois Tigeot 	GEM_BUG_ON(ppgtt->pd.base.ggtt_offset & 0x3f);
1710a85cb24fSFrançois Tigeot 	return ppgtt->pd.base.ggtt_offset << 10;
1711ba55f2f5SFrançois Tigeot }
17128e26cdf6SFrançois Tigeot 
hsw_mm_switch(struct i915_hw_ppgtt * ppgtt,struct drm_i915_gem_request * req)1713ba55f2f5SFrançois Tigeot static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
1714a05eeebfSFrançois Tigeot 			 struct drm_i915_gem_request *req)
1715ba55f2f5SFrançois Tigeot {
17168621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1717a85cb24fSFrançois Tigeot 	u32 *cs;
17188e26cdf6SFrançois Tigeot 
1719ba55f2f5SFrançois Tigeot 	/* NB: TLBs must be flushed and invalidated before a switch */
1720a85cb24fSFrançois Tigeot 	cs = intel_ring_begin(req, 6);
1721a85cb24fSFrançois Tigeot 	if (IS_ERR(cs))
1722a85cb24fSFrançois Tigeot 		return PTR_ERR(cs);
17238e26cdf6SFrançois Tigeot 
1724a85cb24fSFrançois Tigeot 	*cs++ = MI_LOAD_REGISTER_IMM(2);
1725a85cb24fSFrançois Tigeot 	*cs++ = i915_mmio_reg_offset(RING_PP_DIR_DCLV(engine));
1726a85cb24fSFrançois Tigeot 	*cs++ = PP_DIR_DCLV_2G;
1727a85cb24fSFrançois Tigeot 	*cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine));
1728a85cb24fSFrançois Tigeot 	*cs++ = get_pd_offset(ppgtt);
1729a85cb24fSFrançois Tigeot 	*cs++ = MI_NOOP;
1730a85cb24fSFrançois Tigeot 	intel_ring_advance(req, cs);
1731ba55f2f5SFrançois Tigeot 
1732ba55f2f5SFrançois Tigeot 	return 0;
1733ba55f2f5SFrançois Tigeot }
1734ba55f2f5SFrançois Tigeot 
gen7_mm_switch(struct i915_hw_ppgtt * ppgtt,struct drm_i915_gem_request * req)1735ba55f2f5SFrançois Tigeot static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
1736a05eeebfSFrançois Tigeot 			  struct drm_i915_gem_request *req)
1737ba55f2f5SFrançois Tigeot {
17388621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1739a85cb24fSFrançois Tigeot 	u32 *cs;
1740ba55f2f5SFrançois Tigeot 
1741ba55f2f5SFrançois Tigeot 	/* NB: TLBs must be flushed and invalidated before a switch */
1742a85cb24fSFrançois Tigeot 	cs = intel_ring_begin(req, 6);
1743a85cb24fSFrançois Tigeot 	if (IS_ERR(cs))
1744a85cb24fSFrançois Tigeot 		return PTR_ERR(cs);
1745ba55f2f5SFrançois Tigeot 
1746a85cb24fSFrançois Tigeot 	*cs++ = MI_LOAD_REGISTER_IMM(2);
1747a85cb24fSFrançois Tigeot 	*cs++ = i915_mmio_reg_offset(RING_PP_DIR_DCLV(engine));
1748a85cb24fSFrançois Tigeot 	*cs++ = PP_DIR_DCLV_2G;
1749a85cb24fSFrançois Tigeot 	*cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine));
1750a85cb24fSFrançois Tigeot 	*cs++ = get_pd_offset(ppgtt);
1751a85cb24fSFrançois Tigeot 	*cs++ = MI_NOOP;
1752a85cb24fSFrançois Tigeot 	intel_ring_advance(req, cs);
1753ba55f2f5SFrançois Tigeot 
1754ba55f2f5SFrançois Tigeot 	return 0;
1755ba55f2f5SFrançois Tigeot }
1756ba55f2f5SFrançois Tigeot 
gen6_mm_switch(struct i915_hw_ppgtt * ppgtt,struct drm_i915_gem_request * req)1757ba55f2f5SFrançois Tigeot static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
1758a05eeebfSFrançois Tigeot 			  struct drm_i915_gem_request *req)
1759ba55f2f5SFrançois Tigeot {
17608621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1761303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = req->i915;
1762ba55f2f5SFrançois Tigeot 
17638621f407SFrançois Tigeot 	I915_WRITE(RING_PP_DIR_DCLV(engine), PP_DIR_DCLV_2G);
17648621f407SFrançois Tigeot 	I915_WRITE(RING_PP_DIR_BASE(engine), get_pd_offset(ppgtt));
1765ba55f2f5SFrançois Tigeot 	return 0;
1766ba55f2f5SFrançois Tigeot }
1767ba55f2f5SFrançois Tigeot 
gen8_ppgtt_enable(struct drm_i915_private * dev_priv)17684be47400SFrançois Tigeot static void gen8_ppgtt_enable(struct drm_i915_private *dev_priv)
1769ba55f2f5SFrançois Tigeot {
17708621f407SFrançois Tigeot 	struct intel_engine_cs *engine;
17711e12ee3bSFrançois Tigeot 	enum intel_engine_id id;
1772ba55f2f5SFrançois Tigeot 
17731e12ee3bSFrançois Tigeot 	for_each_engine(engine, dev_priv, id) {
17744be47400SFrançois Tigeot 		u32 four_level = USES_FULL_48BIT_PPGTT(dev_priv) ?
17754be47400SFrançois Tigeot 				 GEN8_GFX_PPGTT_48B : 0;
17768621f407SFrançois Tigeot 		I915_WRITE(RING_MODE_GEN7(engine),
1777352ff8bdSFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE | four_level));
17781b13d190SFrançois Tigeot 	}
1779ba55f2f5SFrançois Tigeot }
1780ba55f2f5SFrançois Tigeot 
gen7_ppgtt_enable(struct drm_i915_private * dev_priv)17814be47400SFrançois Tigeot static void gen7_ppgtt_enable(struct drm_i915_private *dev_priv)
1782ba55f2f5SFrançois Tigeot {
17838621f407SFrançois Tigeot 	struct intel_engine_cs *engine;
1784a85cb24fSFrançois Tigeot 	u32 ecochk, ecobits;
17851e12ee3bSFrançois Tigeot 	enum intel_engine_id id;
17868e26cdf6SFrançois Tigeot 
17878e26cdf6SFrançois Tigeot 	ecobits = I915_READ(GAC_ECO_BITS);
17888e26cdf6SFrançois Tigeot 	I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
17898e26cdf6SFrançois Tigeot 
17908e26cdf6SFrançois Tigeot 	ecochk = I915_READ(GAM_ECOCHK);
17911e12ee3bSFrançois Tigeot 	if (IS_HASWELL(dev_priv)) {
17928e26cdf6SFrançois Tigeot 		ecochk |= ECOCHK_PPGTT_WB_HSW;
17938e26cdf6SFrançois Tigeot 	} else {
17948e26cdf6SFrançois Tigeot 		ecochk |= ECOCHK_PPGTT_LLC_IVB;
17958e26cdf6SFrançois Tigeot 		ecochk &= ~ECOCHK_PPGTT_GFDT_IVB;
17968e26cdf6SFrançois Tigeot 	}
17978e26cdf6SFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, ecochk);
17988e26cdf6SFrançois Tigeot 
17991e12ee3bSFrançois Tigeot 	for_each_engine(engine, dev_priv, id) {
1800ba55f2f5SFrançois Tigeot 		/* GFX_MODE is per-ring on gen7+ */
18018621f407SFrançois Tigeot 		I915_WRITE(RING_MODE_GEN7(engine),
18028e26cdf6SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
18031b13d190SFrançois Tigeot 	}
18048e26cdf6SFrançois Tigeot }
1805ba55f2f5SFrançois Tigeot 
gen6_ppgtt_enable(struct drm_i915_private * dev_priv)18064be47400SFrançois Tigeot static void gen6_ppgtt_enable(struct drm_i915_private *dev_priv)
1807ba55f2f5SFrançois Tigeot {
1808a85cb24fSFrançois Tigeot 	u32 ecochk, gab_ctl, ecobits;
1809ba55f2f5SFrançois Tigeot 
1810ba55f2f5SFrançois Tigeot 	ecobits = I915_READ(GAC_ECO_BITS);
1811ba55f2f5SFrançois Tigeot 	I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
1812ba55f2f5SFrançois Tigeot 		   ECOBITS_PPGTT_CACHE64B);
1813ba55f2f5SFrançois Tigeot 
1814ba55f2f5SFrançois Tigeot 	gab_ctl = I915_READ(GAB_CTL);
1815ba55f2f5SFrançois Tigeot 	I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
1816ba55f2f5SFrançois Tigeot 
1817ba55f2f5SFrançois Tigeot 	ecochk = I915_READ(GAM_ECOCHK);
1818ba55f2f5SFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
1819ba55f2f5SFrançois Tigeot 
1820ba55f2f5SFrançois Tigeot 	I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
18218e26cdf6SFrançois Tigeot }
18228e26cdf6SFrançois Tigeot 
1823f4e1c372SFrançois Tigeot /* PPGTT support for Sandybdrige/Gen6 and later */
gen6_ppgtt_clear_range(struct i915_address_space * vm,u64 start,u64 length)18249edbd4a0SFrançois Tigeot static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
1825a85cb24fSFrançois Tigeot 				   u64 start, u64 length)
1826f4e1c372SFrançois Tigeot {
18278621f407SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
1828a85cb24fSFrançois Tigeot 	unsigned int first_entry = start >> PAGE_SHIFT;
1829a85cb24fSFrançois Tigeot 	unsigned int pde = first_entry / GEN6_PTES;
1830a85cb24fSFrançois Tigeot 	unsigned int pte = first_entry % GEN6_PTES;
1831a85cb24fSFrançois Tigeot 	unsigned int num_entries = length >> PAGE_SHIFT;
1832a85cb24fSFrançois Tigeot 	gen6_pte_t scratch_pte =
1833a85cb24fSFrançois Tigeot 		vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0);
1834e3adcf8fSFrançois Tigeot 
1835e3adcf8fSFrançois Tigeot 	while (num_entries) {
1836a85cb24fSFrançois Tigeot 		struct i915_page_table *pt = ppgtt->pd.page_table[pde++];
1837a85cb24fSFrançois Tigeot 		unsigned int end = min(pte + num_entries, GEN6_PTES);
1838a85cb24fSFrançois Tigeot 		gen6_pte_t *vaddr;
1839e3adcf8fSFrançois Tigeot 
1840a85cb24fSFrançois Tigeot 		num_entries -= end - pte;
1841e3adcf8fSFrançois Tigeot 
1842a85cb24fSFrançois Tigeot 		/* Note that the hw doesn't support removing PDE on the fly
1843a85cb24fSFrançois Tigeot 		 * (they are cached inside the context with no means to
1844a85cb24fSFrançois Tigeot 		 * invalidate the cache), so we can only reset the PTE
1845a85cb24fSFrançois Tigeot 		 * entries back to scratch.
1846a85cb24fSFrançois Tigeot 		 */
1847e3adcf8fSFrançois Tigeot 
1848a85cb24fSFrançois Tigeot 		vaddr = kmap_atomic_px(pt);
1849a85cb24fSFrançois Tigeot 		do {
1850a85cb24fSFrançois Tigeot 			vaddr[pte++] = scratch_pte;
1851a85cb24fSFrançois Tigeot 		} while (pte < end);
1852a85cb24fSFrançois Tigeot 		kunmap_atomic(vaddr);
1853e3adcf8fSFrançois Tigeot 
1854a85cb24fSFrançois Tigeot 		pte = 0;
1855e3adcf8fSFrançois Tigeot 	}
1856e3adcf8fSFrançois Tigeot }
1857e3adcf8fSFrançois Tigeot 
gen6_ppgtt_insert_entries(struct i915_address_space * vm,struct i915_vma * vma,enum i915_cache_level cache_level,u32 flags)18589edbd4a0SFrançois Tigeot static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
1859*3f2dd94aSFrançois Tigeot 				      struct i915_vma *vma,
1860a85cb24fSFrançois Tigeot 				      enum i915_cache_level cache_level,
1861a85cb24fSFrançois Tigeot 				      u32 flags)
1862e3adcf8fSFrançois Tigeot {
18638621f407SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
1864*3f2dd94aSFrançois Tigeot 	unsigned first_entry = vma->node.start >> PAGE_SHIFT;
1865477eb7f9SFrançois Tigeot 	unsigned act_pt = first_entry / GEN6_PTES;
1866477eb7f9SFrançois Tigeot 	unsigned act_pte = first_entry % GEN6_PTES;
1867a85cb24fSFrançois Tigeot 	const u32 pte_encode = vm->pte_encode(0, cache_level, flags);
1868*3f2dd94aSFrançois Tigeot 	struct sgt_dma iter = sgt_dma(vma);
1869a85cb24fSFrançois Tigeot 	gen6_pte_t *vaddr;
1870a2fdbec6SFrançois Tigeot 
1871a85cb24fSFrançois Tigeot 	vaddr = kmap_atomic_px(ppgtt->pd.page_table[act_pt]);
1872a85cb24fSFrançois Tigeot 	do {
1873a85cb24fSFrançois Tigeot 		vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma);
1874a2fdbec6SFrançois Tigeot 
1875a85cb24fSFrançois Tigeot 		iter.dma += PAGE_SIZE;
1876a85cb24fSFrançois Tigeot 		if (iter.dma == iter.max) {
1877a85cb24fSFrançois Tigeot 			iter.sg = __sg_next(iter.sg);
1878a85cb24fSFrançois Tigeot 			if (!iter.sg)
1879a85cb24fSFrançois Tigeot 				break;
1880a85cb24fSFrançois Tigeot 
1881a85cb24fSFrançois Tigeot 			iter.dma = sg_dma_address(iter.sg);
1882a85cb24fSFrançois Tigeot 			iter.max = iter.dma + iter.sg->length;
1883a85cb24fSFrançois Tigeot 		}
1884477eb7f9SFrançois Tigeot 
1885477eb7f9SFrançois Tigeot 		if (++act_pte == GEN6_PTES) {
1886a85cb24fSFrançois Tigeot 			kunmap_atomic(vaddr);
1887a85cb24fSFrançois Tigeot 			vaddr = kmap_atomic_px(ppgtt->pd.page_table[++act_pt]);
18889edbd4a0SFrançois Tigeot 			act_pte = 0;
1889a2fdbec6SFrançois Tigeot 		}
1890a85cb24fSFrançois Tigeot 	} while (1);
1891a85cb24fSFrançois Tigeot 	kunmap_atomic(vaddr);
1892*3f2dd94aSFrançois Tigeot 
1893*3f2dd94aSFrançois Tigeot 	vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
1894a2fdbec6SFrançois Tigeot }
1895477eb7f9SFrançois Tigeot 
gen6_alloc_va_range(struct i915_address_space * vm,u64 start,u64 length)1896477eb7f9SFrançois Tigeot static int gen6_alloc_va_range(struct i915_address_space *vm,
1897a85cb24fSFrançois Tigeot 			       u64 start, u64 length)
1898477eb7f9SFrançois Tigeot {
18998621f407SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
190019c468b4SFrançois Tigeot 	struct i915_page_table *pt;
1901a85cb24fSFrançois Tigeot 	u64 from = start;
1902a85cb24fSFrançois Tigeot 	unsigned int pde;
1903a85cb24fSFrançois Tigeot 	bool flush = false;
1904477eb7f9SFrançois Tigeot 
19051487f786SFrançois Tigeot 	gen6_for_each_pde(pt, &ppgtt->pd, start, length, pde) {
1906a85cb24fSFrançois Tigeot 		if (pt == vm->scratch_pt) {
1907a85cb24fSFrançois Tigeot 			pt = alloc_pt(vm);
1908a85cb24fSFrançois Tigeot 			if (IS_ERR(pt))
1909477eb7f9SFrançois Tigeot 				goto unwind_out;
1910477eb7f9SFrançois Tigeot 
1911477eb7f9SFrançois Tigeot 			gen6_initialize_pt(vm, pt);
1912477eb7f9SFrançois Tigeot 			ppgtt->pd.page_table[pde] = pt;
1913a85cb24fSFrançois Tigeot 			gen6_write_pde(ppgtt, pde, pt);
1914a85cb24fSFrançois Tigeot 			flush = true;
1915a85cb24fSFrançois Tigeot 		}
1916477eb7f9SFrançois Tigeot 	}
1917477eb7f9SFrançois Tigeot 
1918a85cb24fSFrançois Tigeot 	if (flush) {
1919477eb7f9SFrançois Tigeot 		mark_tlbs_dirty(ppgtt);
1920a85cb24fSFrançois Tigeot 		wmb();
1921a85cb24fSFrançois Tigeot 	}
1922a85cb24fSFrançois Tigeot 
1923477eb7f9SFrançois Tigeot 	return 0;
1924477eb7f9SFrançois Tigeot 
1925477eb7f9SFrançois Tigeot unwind_out:
1926a85cb24fSFrançois Tigeot 	gen6_ppgtt_clear_range(vm, from, start);
1927a85cb24fSFrançois Tigeot 	return -ENOMEM;
1928ba55f2f5SFrançois Tigeot }
1929ba55f2f5SFrançois Tigeot 
gen6_init_scratch(struct i915_address_space * vm)1930a05eeebfSFrançois Tigeot static int gen6_init_scratch(struct i915_address_space *vm)
1931a05eeebfSFrançois Tigeot {
19321e12ee3bSFrançois Tigeot 	int ret;
1933a05eeebfSFrançois Tigeot 
1934a85cb24fSFrançois Tigeot 	ret = setup_scratch_page(vm, I915_GFP_DMA);
19351e12ee3bSFrançois Tigeot 	if (ret)
19361e12ee3bSFrançois Tigeot 		return ret;
1937a05eeebfSFrançois Tigeot 
1938a85cb24fSFrançois Tigeot 	vm->scratch_pt = alloc_pt(vm);
1939a05eeebfSFrançois Tigeot 	if (IS_ERR(vm->scratch_pt)) {
1940a85cb24fSFrançois Tigeot 		cleanup_scratch_page(vm);
1941a05eeebfSFrançois Tigeot 		return PTR_ERR(vm->scratch_pt);
1942a05eeebfSFrançois Tigeot 	}
1943a05eeebfSFrançois Tigeot 
1944a05eeebfSFrançois Tigeot 	gen6_initialize_pt(vm, vm->scratch_pt);
1945a05eeebfSFrançois Tigeot 
1946a05eeebfSFrançois Tigeot 	return 0;
1947a05eeebfSFrançois Tigeot }
1948a05eeebfSFrançois Tigeot 
gen6_free_scratch(struct i915_address_space * vm)1949a05eeebfSFrançois Tigeot static void gen6_free_scratch(struct i915_address_space *vm)
1950a05eeebfSFrançois Tigeot {
1951a85cb24fSFrançois Tigeot 	free_pt(vm, vm->scratch_pt);
1952a85cb24fSFrançois Tigeot 	cleanup_scratch_page(vm);
1953a05eeebfSFrançois Tigeot }
1954a05eeebfSFrançois Tigeot 
gen6_ppgtt_cleanup(struct i915_address_space * vm)1955ba55f2f5SFrançois Tigeot static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
1956ba55f2f5SFrançois Tigeot {
19578621f407SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
19581487f786SFrançois Tigeot 	struct i915_page_directory *pd = &ppgtt->pd;
195919c468b4SFrançois Tigeot 	struct i915_page_table *pt;
1960a85cb24fSFrançois Tigeot 	u32 pde;
196119c468b4SFrançois Tigeot 
1962ba55f2f5SFrançois Tigeot 	drm_mm_remove_node(&ppgtt->node);
1963ba55f2f5SFrançois Tigeot 
19641487f786SFrançois Tigeot 	gen6_for_all_pdes(pt, pd, pde)
1965a05eeebfSFrançois Tigeot 		if (pt != vm->scratch_pt)
1966a85cb24fSFrançois Tigeot 			free_pt(vm, pt);
196719c468b4SFrançois Tigeot 
1968a05eeebfSFrançois Tigeot 	gen6_free_scratch(vm);
1969ba55f2f5SFrançois Tigeot }
1970ba55f2f5SFrançois Tigeot 
gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt * ppgtt)1971ba55f2f5SFrançois Tigeot static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
1972a2fdbec6SFrançois Tigeot {
1973a05eeebfSFrançois Tigeot 	struct i915_address_space *vm = &ppgtt->base;
1974a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = ppgtt->base.i915;
19758621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
1976ba55f2f5SFrançois Tigeot 	int ret;
1977e3adcf8fSFrançois Tigeot 
1978ba55f2f5SFrançois Tigeot 	/* PPGTT PDEs reside in the GGTT and consists of 512 entries. The
1979ba55f2f5SFrançois Tigeot 	 * allocator works in address space sizes, so it's multiplied by page
1980ba55f2f5SFrançois Tigeot 	 * size. We allocate at the top of the GTT to avoid fragmentation.
1981ba55f2f5SFrançois Tigeot 	 */
19828621f407SFrançois Tigeot 	BUG_ON(!drm_mm_initialized(&ggtt->base.mm));
1983477eb7f9SFrançois Tigeot 
1984a05eeebfSFrançois Tigeot 	ret = gen6_init_scratch(vm);
1985a05eeebfSFrançois Tigeot 	if (ret)
1986a05eeebfSFrançois Tigeot 		return ret;
1987477eb7f9SFrançois Tigeot 
1988a85cb24fSFrançois Tigeot 	ret = i915_gem_gtt_insert(&ggtt->base, &ppgtt->node,
1989ba55f2f5SFrançois Tigeot 				  GEN6_PD_SIZE, GEN6_PD_ALIGN,
1990a85cb24fSFrançois Tigeot 				  I915_COLOR_UNEVICTABLE,
19918621f407SFrançois Tigeot 				  0, ggtt->base.total,
1992a85cb24fSFrançois Tigeot 				  PIN_HIGH);
1993ba55f2f5SFrançois Tigeot 	if (ret)
1994477eb7f9SFrançois Tigeot 		goto err_out;
1995e3adcf8fSFrançois Tigeot 
19968621f407SFrançois Tigeot 	if (ppgtt->node.start < ggtt->mappable_end)
1997ba55f2f5SFrançois Tigeot 		DRM_DEBUG("Forced to use aperture for PDEs\n");
1998ba55f2f5SFrançois Tigeot 
1999a85cb24fSFrançois Tigeot 	ppgtt->pd.base.ggtt_offset =
2000a85cb24fSFrançois Tigeot 		ppgtt->node.start / PAGE_SIZE * sizeof(gen6_pte_t);
2001a85cb24fSFrançois Tigeot 
2002a85cb24fSFrançois Tigeot 	ppgtt->pd_addr = (gen6_pte_t __iomem *)ggtt->gsm +
2003a85cb24fSFrançois Tigeot 		ppgtt->pd.base.ggtt_offset / sizeof(gen6_pte_t);
2004a85cb24fSFrançois Tigeot 
2005ba55f2f5SFrançois Tigeot 	return 0;
2006477eb7f9SFrançois Tigeot 
2007477eb7f9SFrançois Tigeot err_out:
2008a05eeebfSFrançois Tigeot 	gen6_free_scratch(vm);
2009477eb7f9SFrançois Tigeot 	return ret;
2010ba55f2f5SFrançois Tigeot }
2011ba55f2f5SFrançois Tigeot 
gen6_ppgtt_alloc(struct i915_hw_ppgtt * ppgtt)2012ba55f2f5SFrançois Tigeot static int gen6_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt)
2013ba55f2f5SFrançois Tigeot {
2014477eb7f9SFrançois Tigeot 	return gen6_ppgtt_allocate_page_directories(ppgtt);
2015e3adcf8fSFrançois Tigeot }
2016e3adcf8fSFrançois Tigeot 
gen6_scratch_va_range(struct i915_hw_ppgtt * ppgtt,u64 start,u64 length)2017477eb7f9SFrançois Tigeot static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt,
2018a85cb24fSFrançois Tigeot 				  u64 start, u64 length)
2019ba55f2f5SFrançois Tigeot {
202019c468b4SFrançois Tigeot 	struct i915_page_table *unused;
2021a85cb24fSFrançois Tigeot 	u32 pde;
20229edbd4a0SFrançois Tigeot 
20231487f786SFrançois Tigeot 	gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde)
2024a05eeebfSFrançois Tigeot 		ppgtt->pd.page_table[pde] = ppgtt->base.scratch_pt;
20259edbd4a0SFrançois Tigeot }
2026ba55f2f5SFrançois Tigeot 
gen6_ppgtt_init(struct i915_hw_ppgtt * ppgtt)2027056b1c44SFrançois Tigeot static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
2028ba55f2f5SFrançois Tigeot {
2029a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = ppgtt->base.i915;
20308621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
2031ba55f2f5SFrançois Tigeot 	int ret;
2032ba55f2f5SFrançois Tigeot 
20338621f407SFrançois Tigeot 	ppgtt->base.pte_encode = ggtt->base.pte_encode;
20341e12ee3bSFrançois Tigeot 	if (intel_vgpu_active(dev_priv) || IS_GEN6(dev_priv))
2035ba55f2f5SFrançois Tigeot 		ppgtt->switch_mm = gen6_mm_switch;
20361e12ee3bSFrançois Tigeot 	else if (IS_HASWELL(dev_priv))
2037ba55f2f5SFrançois Tigeot 		ppgtt->switch_mm = hsw_mm_switch;
20381e12ee3bSFrançois Tigeot 	else if (IS_GEN7(dev_priv))
2039ba55f2f5SFrançois Tigeot 		ppgtt->switch_mm = gen7_mm_switch;
2040303bf270SFrançois Tigeot 	else
2041ba55f2f5SFrançois Tigeot 		BUG();
2042ba55f2f5SFrançois Tigeot 
2043ba55f2f5SFrançois Tigeot 	ret = gen6_ppgtt_alloc(ppgtt);
2044ba55f2f5SFrançois Tigeot 	if (ret)
2045ba55f2f5SFrançois Tigeot 		return ret;
2046ba55f2f5SFrançois Tigeot 
2047a85cb24fSFrançois Tigeot 	ppgtt->base.total = I915_PDES * GEN6_PTES * PAGE_SIZE;
2048a85cb24fSFrançois Tigeot 
2049a85cb24fSFrançois Tigeot 	gen6_scratch_va_range(ppgtt, 0, ppgtt->base.total);
2050a85cb24fSFrançois Tigeot 	gen6_write_page_range(ppgtt, 0, ppgtt->base.total);
2051a85cb24fSFrançois Tigeot 
2052a85cb24fSFrançois Tigeot 	ret = gen6_alloc_va_range(&ppgtt->base, 0, ppgtt->base.total);
2053a85cb24fSFrançois Tigeot 	if (ret) {
2054a85cb24fSFrançois Tigeot 		gen6_ppgtt_cleanup(&ppgtt->base);
2055a85cb24fSFrançois Tigeot 		return ret;
2056a85cb24fSFrançois Tigeot 	}
2057a85cb24fSFrançois Tigeot 
2058ba55f2f5SFrançois Tigeot 	ppgtt->base.clear_range = gen6_ppgtt_clear_range;
2059ba55f2f5SFrançois Tigeot 	ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
206019c468b4SFrançois Tigeot 	ppgtt->base.unbind_vma = ppgtt_unbind_vma;
206119c468b4SFrançois Tigeot 	ppgtt->base.bind_vma = ppgtt_bind_vma;
2062*3f2dd94aSFrançois Tigeot 	ppgtt->base.set_pages = ppgtt_set_pages;
2063*3f2dd94aSFrançois Tigeot 	ppgtt->base.clear_pages = clear_pages;
2064ba55f2f5SFrançois Tigeot 	ppgtt->base.cleanup = gen6_ppgtt_cleanup;
2065ba55f2f5SFrançois Tigeot 	ppgtt->debug_dump = gen6_dump_ppgtt;
2066ba55f2f5SFrançois Tigeot 
2067f77dbd6cSFrançois Tigeot 	DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n",
2068ba55f2f5SFrançois Tigeot 			 ppgtt->node.size >> 20,
2069ba55f2f5SFrançois Tigeot 			 ppgtt->node.start / PAGE_SIZE);
2070ba55f2f5SFrançois Tigeot 
2071a85cb24fSFrançois Tigeot 	DRM_DEBUG_DRIVER("Adding PPGTT at offset %x\n",
2072a05eeebfSFrançois Tigeot 			 ppgtt->pd.base.ggtt_offset << 10);
20731b13d190SFrançois Tigeot 
2074ba55f2f5SFrançois Tigeot 	return 0;
2075ba55f2f5SFrançois Tigeot }
2076ba55f2f5SFrançois Tigeot 
__hw_ppgtt_init(struct i915_hw_ppgtt * ppgtt,struct drm_i915_private * dev_priv)207771f41f3eSFrançois Tigeot static int __hw_ppgtt_init(struct i915_hw_ppgtt *ppgtt,
207871f41f3eSFrançois Tigeot 			   struct drm_i915_private *dev_priv)
2079a2fdbec6SFrançois Tigeot {
2080a85cb24fSFrançois Tigeot 	ppgtt->base.i915 = dev_priv;
2081a85cb24fSFrançois Tigeot 	ppgtt->base.dma = &dev_priv->drm.pdev->dev;
2082a2fdbec6SFrançois Tigeot 
208371f41f3eSFrançois Tigeot 	if (INTEL_INFO(dev_priv)->gen < 8)
2084056b1c44SFrançois Tigeot 		return gen6_ppgtt_init(ppgtt);
20858e26cdf6SFrançois Tigeot 	else
208619c468b4SFrançois Tigeot 		return gen8_ppgtt_init(ppgtt);
20871b13d190SFrançois Tigeot }
2088a05eeebfSFrançois Tigeot 
i915_address_space_init(struct i915_address_space * vm,struct drm_i915_private * dev_priv,const char * name)2089352ff8bdSFrançois Tigeot static void i915_address_space_init(struct i915_address_space *vm,
20904be47400SFrançois Tigeot 				    struct drm_i915_private *dev_priv,
20914be47400SFrançois Tigeot 				    const char *name)
2092352ff8bdSFrançois Tigeot {
20934be47400SFrançois Tigeot 	i915_gem_timeline_init(dev_priv, &vm->timeline, name);
2094a85cb24fSFrançois Tigeot 
2095a85cb24fSFrançois Tigeot 	drm_mm_init(&vm->mm, 0, vm->total);
2096a85cb24fSFrançois Tigeot 	vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
2097a85cb24fSFrançois Tigeot 
2098352ff8bdSFrançois Tigeot 	INIT_LIST_HEAD(&vm->active_list);
2099352ff8bdSFrançois Tigeot 	INIT_LIST_HEAD(&vm->inactive_list);
210071f41f3eSFrançois Tigeot 	INIT_LIST_HEAD(&vm->unbound_list);
2101a85cb24fSFrançois Tigeot 
2102352ff8bdSFrançois Tigeot 	list_add_tail(&vm->global_link, &dev_priv->vm_list);
2103a85cb24fSFrançois Tigeot 	pagevec_init(&vm->free_pages);
2104352ff8bdSFrançois Tigeot }
2105352ff8bdSFrançois Tigeot 
i915_address_space_fini(struct i915_address_space * vm)21064be47400SFrançois Tigeot static void i915_address_space_fini(struct i915_address_space *vm)
2107c0e85e96SFrançois Tigeot {
2108a85cb24fSFrançois Tigeot 	if (pagevec_count(&vm->free_pages))
2109*3f2dd94aSFrançois Tigeot 		vm_free_pages_release(vm, true);
2110a85cb24fSFrançois Tigeot 
21114be47400SFrançois Tigeot 	i915_gem_timeline_fini(&vm->timeline);
21124be47400SFrançois Tigeot 	drm_mm_takedown(&vm->mm);
21134be47400SFrançois Tigeot 	list_del(&vm->global_link);
21144be47400SFrançois Tigeot }
2115c0e85e96SFrançois Tigeot 
gtt_write_workarounds(struct drm_i915_private * dev_priv)21164be47400SFrançois Tigeot static void gtt_write_workarounds(struct drm_i915_private *dev_priv)
21174be47400SFrançois Tigeot {
2118c0e85e96SFrançois Tigeot 	/* This function is for gtt related workarounds. This function is
2119c0e85e96SFrançois Tigeot 	 * called on driver load and after a GPU reset, so you can place
2120c0e85e96SFrançois Tigeot 	 * workarounds here even if they get overwritten by GPU reset.
2121c0e85e96SFrançois Tigeot 	 */
2122*3f2dd94aSFrançois Tigeot 	/* WaIncreaseDefaultTLBEntries:chv,bdw,skl,bxt,kbl,glk,cfl,cnl */
21231e12ee3bSFrançois Tigeot 	if (IS_BROADWELL(dev_priv))
2124c0e85e96SFrançois Tigeot 		I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_BDW);
21251e12ee3bSFrançois Tigeot 	else if (IS_CHERRYVIEW(dev_priv))
2126c0e85e96SFrançois Tigeot 		I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_CHV);
2127*3f2dd94aSFrançois Tigeot 	else if (IS_GEN9_BC(dev_priv) || IS_GEN10(dev_priv))
2128c0e85e96SFrançois Tigeot 		I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_SKL);
2129a85cb24fSFrançois Tigeot 	else if (IS_GEN9_LP(dev_priv))
2130c0e85e96SFrançois Tigeot 		I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_BXT);
2131*3f2dd94aSFrançois Tigeot 
2132*3f2dd94aSFrançois Tigeot 	/*
2133*3f2dd94aSFrançois Tigeot 	 * To support 64K PTEs we need to first enable the use of the
2134*3f2dd94aSFrançois Tigeot 	 * Intermediate-Page-Size(IPS) bit of the PDE field via some magical
2135*3f2dd94aSFrançois Tigeot 	 * mmio, otherwise the page-walker will simply ignore the IPS bit. This
2136*3f2dd94aSFrançois Tigeot 	 * shouldn't be needed after GEN10.
2137*3f2dd94aSFrançois Tigeot 	 *
2138*3f2dd94aSFrançois Tigeot 	 * 64K pages were first introduced from BDW+, although technically they
2139*3f2dd94aSFrançois Tigeot 	 * only *work* from gen9+. For pre-BDW we instead have the option for
2140*3f2dd94aSFrançois Tigeot 	 * 32K pages, but we don't currently have any support for it in our
2141*3f2dd94aSFrançois Tigeot 	 * driver.
2142*3f2dd94aSFrançois Tigeot 	 */
2143*3f2dd94aSFrançois Tigeot 	if (HAS_PAGE_SIZES(dev_priv, I915_GTT_PAGE_SIZE_64K) &&
2144*3f2dd94aSFrançois Tigeot 	    INTEL_GEN(dev_priv) <= 10)
2145*3f2dd94aSFrançois Tigeot 		I915_WRITE(GEN8_GAMW_ECO_DEV_RW_IA,
2146*3f2dd94aSFrançois Tigeot 			   I915_READ(GEN8_GAMW_ECO_DEV_RW_IA) |
2147*3f2dd94aSFrançois Tigeot 			   GAMW_ECO_ENABLE_64K_IPS_FIELD);
2148c0e85e96SFrançois Tigeot }
2149c0e85e96SFrançois Tigeot 
i915_ppgtt_init_hw(struct drm_i915_private * dev_priv)21504be47400SFrançois Tigeot int i915_ppgtt_init_hw(struct drm_i915_private *dev_priv)
21511b13d190SFrançois Tigeot {
21524be47400SFrançois Tigeot 	gtt_write_workarounds(dev_priv);
2153c0e85e96SFrançois Tigeot 
21541b13d190SFrançois Tigeot 	/* In the case of execlists, PPGTT is enabled by the context descriptor
21551b13d190SFrançois Tigeot 	 * and the PDPs are contained within the context itself.  We don't
21561b13d190SFrançois Tigeot 	 * need to do anything here. */
2157*3f2dd94aSFrançois Tigeot 	if (i915_modparams.enable_execlists)
21581b13d190SFrançois Tigeot 		return 0;
21591b13d190SFrançois Tigeot 
21604be47400SFrançois Tigeot 	if (!USES_PPGTT(dev_priv))
21611b13d190SFrançois Tigeot 		return 0;
21621b13d190SFrançois Tigeot 
21631e12ee3bSFrançois Tigeot 	if (IS_GEN6(dev_priv))
21644be47400SFrançois Tigeot 		gen6_ppgtt_enable(dev_priv);
21651e12ee3bSFrançois Tigeot 	else if (IS_GEN7(dev_priv))
21664be47400SFrançois Tigeot 		gen7_ppgtt_enable(dev_priv);
21674be47400SFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 8)
21684be47400SFrançois Tigeot 		gen8_ppgtt_enable(dev_priv);
21691b13d190SFrançois Tigeot 	else
21704be47400SFrançois Tigeot 		MISSING_CASE(INTEL_GEN(dev_priv));
21711b13d190SFrançois Tigeot 
2172a05eeebfSFrançois Tigeot 	return 0;
21739edbd4a0SFrançois Tigeot }
2174a2fdbec6SFrançois Tigeot 
21751b13d190SFrançois Tigeot struct i915_hw_ppgtt *
i915_ppgtt_create(struct drm_i915_private * dev_priv,struct drm_i915_file_private * fpriv,const char * name)217671f41f3eSFrançois Tigeot i915_ppgtt_create(struct drm_i915_private *dev_priv,
21774be47400SFrançois Tigeot 		  struct drm_i915_file_private *fpriv,
21784be47400SFrançois Tigeot 		  const char *name)
21791b13d190SFrançois Tigeot {
21801b13d190SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt;
21811b13d190SFrançois Tigeot 	int ret;
21821b13d190SFrançois Tigeot 
21831b13d190SFrançois Tigeot 	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
21841b13d190SFrançois Tigeot 	if (!ppgtt)
21851b13d190SFrançois Tigeot 		return ERR_PTR(-ENOMEM);
21861b13d190SFrançois Tigeot 
2187a85cb24fSFrançois Tigeot 	ret = __hw_ppgtt_init(ppgtt, dev_priv);
21881b13d190SFrançois Tigeot 	if (ret) {
21891b13d190SFrançois Tigeot 		kfree(ppgtt);
21901b13d190SFrançois Tigeot 		return ERR_PTR(ret);
21911b13d190SFrançois Tigeot 	}
21921b13d190SFrançois Tigeot 
2193a85cb24fSFrançois Tigeot 	kref_init(&ppgtt->ref);
2194a85cb24fSFrançois Tigeot 	i915_address_space_init(&ppgtt->base, dev_priv, name);
2195a85cb24fSFrançois Tigeot 	ppgtt->base.file = fpriv;
2196a85cb24fSFrançois Tigeot 
21972c9916cdSFrançois Tigeot 	trace_i915_ppgtt_create(&ppgtt->base);
21982c9916cdSFrançois Tigeot 
21991b13d190SFrançois Tigeot 	return ppgtt;
22001b13d190SFrançois Tigeot }
22011b13d190SFrançois Tigeot 
i915_ppgtt_close(struct i915_address_space * vm)2202a85cb24fSFrançois Tigeot void i915_ppgtt_close(struct i915_address_space *vm)
2203a85cb24fSFrançois Tigeot {
2204a85cb24fSFrançois Tigeot 	struct list_head *phases[] = {
2205a85cb24fSFrançois Tigeot 		&vm->active_list,
2206a85cb24fSFrançois Tigeot 		&vm->inactive_list,
2207a85cb24fSFrançois Tigeot 		&vm->unbound_list,
2208a85cb24fSFrançois Tigeot 		NULL,
2209a85cb24fSFrançois Tigeot 	}, **phase;
2210a85cb24fSFrançois Tigeot 
2211a85cb24fSFrançois Tigeot 	GEM_BUG_ON(vm->closed);
2212a85cb24fSFrançois Tigeot 	vm->closed = true;
2213a85cb24fSFrançois Tigeot 
2214a85cb24fSFrançois Tigeot 	for (phase = phases; *phase; phase++) {
2215a85cb24fSFrançois Tigeot 		struct i915_vma *vma, *vn;
2216a85cb24fSFrançois Tigeot 
2217a85cb24fSFrançois Tigeot 		list_for_each_entry_safe(vma, vn, *phase, vm_link)
2218a85cb24fSFrançois Tigeot 			if (!i915_vma_is_closed(vma))
2219a85cb24fSFrançois Tigeot 				i915_vma_close(vma);
2220a85cb24fSFrançois Tigeot 	}
2221a85cb24fSFrançois Tigeot }
2222a85cb24fSFrançois Tigeot 
i915_ppgtt_release(struct kref * kref)22231b13d190SFrançois Tigeot void i915_ppgtt_release(struct kref *kref)
22241b13d190SFrançois Tigeot {
22251b13d190SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt =
22261b13d190SFrançois Tigeot 		container_of(kref, struct i915_hw_ppgtt, ref);
22271b13d190SFrançois Tigeot 
22282c9916cdSFrançois Tigeot 	trace_i915_ppgtt_release(&ppgtt->base);
22292c9916cdSFrançois Tigeot 
223071f41f3eSFrançois Tigeot 	/* vmas should already be unbound and destroyed */
22311b13d190SFrançois Tigeot 	WARN_ON(!list_empty(&ppgtt->base.active_list));
22321b13d190SFrançois Tigeot 	WARN_ON(!list_empty(&ppgtt->base.inactive_list));
223371f41f3eSFrançois Tigeot 	WARN_ON(!list_empty(&ppgtt->base.unbound_list));
22341b13d190SFrançois Tigeot 
22351b13d190SFrançois Tigeot 	ppgtt->base.cleanup(&ppgtt->base);
2236a85cb24fSFrançois Tigeot 	i915_address_space_fini(&ppgtt->base);
22371b13d190SFrançois Tigeot 	kfree(ppgtt);
22381b13d190SFrançois Tigeot }
2239a2fdbec6SFrançois Tigeot 
2240a2fdbec6SFrançois Tigeot /* Certain Gen5 chipsets require require idling the GPU before
2241a2fdbec6SFrançois Tigeot  * unmapping anything from the GTT when VT-d is enabled.
2242a2fdbec6SFrançois Tigeot  */
needs_idle_maps(struct drm_i915_private * dev_priv)224371f41f3eSFrançois Tigeot static bool needs_idle_maps(struct drm_i915_private *dev_priv)
2244a2fdbec6SFrançois Tigeot {
2245a2fdbec6SFrançois Tigeot 	/* Query intel_iommu to see if we need the workaround. Presumably that
2246a2fdbec6SFrançois Tigeot 	 * was loaded first.
2247a2fdbec6SFrançois Tigeot 	 */
2248*3f2dd94aSFrançois Tigeot 	return IS_GEN5(dev_priv) && IS_MOBILE(dev_priv) && intel_vtd_active();
2249a2fdbec6SFrançois Tigeot }
2250a2fdbec6SFrançois Tigeot 
i915_check_and_clear_faults(struct drm_i915_private * dev_priv)22511487f786SFrançois Tigeot void i915_check_and_clear_faults(struct drm_i915_private *dev_priv)
22529edbd4a0SFrançois Tigeot {
22538621f407SFrançois Tigeot 	struct intel_engine_cs *engine;
22541e12ee3bSFrançois Tigeot 	enum intel_engine_id id;
22559edbd4a0SFrançois Tigeot 
22561487f786SFrançois Tigeot 	if (INTEL_INFO(dev_priv)->gen < 6)
22579edbd4a0SFrançois Tigeot 		return;
22589edbd4a0SFrançois Tigeot 
22591e12ee3bSFrançois Tigeot 	for_each_engine(engine, dev_priv, id) {
22609edbd4a0SFrançois Tigeot 		u32 fault_reg;
22618621f407SFrançois Tigeot 		fault_reg = I915_READ(RING_FAULT_REG(engine));
22629edbd4a0SFrançois Tigeot 		if (fault_reg & RING_FAULT_VALID) {
22639edbd4a0SFrançois Tigeot 			DRM_DEBUG_DRIVER("Unexpected fault\n"
2264d653c727SFrançois Tigeot 					 "\tAddr: 0x%08ux\n"
22659edbd4a0SFrançois Tigeot 					 "\tAddress space: %s\n"
22669edbd4a0SFrançois Tigeot 					 "\tSource ID: %d\n"
22679edbd4a0SFrançois Tigeot 					 "\tType: %d\n",
2268d653c727SFrançois Tigeot 					 fault_reg & LINUX_PAGE_MASK,
22699edbd4a0SFrançois Tigeot 					 fault_reg & RING_FAULT_GTTSEL_MASK ? "GGTT" : "PPGTT",
22709edbd4a0SFrançois Tigeot 					 RING_FAULT_SRCID(fault_reg),
22719edbd4a0SFrançois Tigeot 					 RING_FAULT_FAULT_TYPE(fault_reg));
22728621f407SFrançois Tigeot 			I915_WRITE(RING_FAULT_REG(engine),
22739edbd4a0SFrançois Tigeot 				   fault_reg & ~RING_FAULT_VALID);
22749edbd4a0SFrançois Tigeot 		}
22759edbd4a0SFrançois Tigeot 	}
22761e12ee3bSFrançois Tigeot 
22771e12ee3bSFrançois Tigeot 	/* Engine specific init may not have been done till this point. */
22781e12ee3bSFrançois Tigeot 	if (dev_priv->engine[RCS])
22791e12ee3bSFrançois Tigeot 		POSTING_READ(RING_FAULT_REG(dev_priv->engine[RCS]));
22809edbd4a0SFrançois Tigeot }
22819edbd4a0SFrançois Tigeot 
i915_gem_suspend_gtt_mappings(struct drm_i915_private * dev_priv)22824be47400SFrançois Tigeot void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv)
22839edbd4a0SFrançois Tigeot {
22848621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
22859edbd4a0SFrançois Tigeot 
22869edbd4a0SFrançois Tigeot 	/* Don't bother messing with faults pre GEN6 as we have little
22879edbd4a0SFrançois Tigeot 	 * documentation supporting that it's a good idea.
22889edbd4a0SFrançois Tigeot 	 */
22894be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 6)
22909edbd4a0SFrançois Tigeot 		return;
22919edbd4a0SFrançois Tigeot 
22921487f786SFrançois Tigeot 	i915_check_and_clear_faults(dev_priv);
22939edbd4a0SFrançois Tigeot 
2294a85cb24fSFrançois Tigeot 	ggtt->base.clear_range(&ggtt->base, 0, ggtt->base.total);
229524edb884SFrançois Tigeot 
2296a85cb24fSFrançois Tigeot 	i915_ggtt_invalidate(dev_priv);
22979edbd4a0SFrançois Tigeot }
22989edbd4a0SFrançois Tigeot 
i915_gem_gtt_prepare_pages(struct drm_i915_gem_object * obj,struct sg_table * pages)22994be47400SFrançois Tigeot int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
23004be47400SFrançois Tigeot 			       struct sg_table *pages)
23010b869d8aSFrançois Tigeot {
2302a85cb24fSFrançois Tigeot 	do {
23034be47400SFrançois Tigeot 		if (dma_map_sg(&obj->base.dev->pdev->dev,
23044be47400SFrançois Tigeot 			       pages->sgl, pages->nents,
23050b869d8aSFrançois Tigeot 			       PCI_DMA_BIDIRECTIONAL))
23060b869d8aSFrançois Tigeot 			return 0;
23074be47400SFrançois Tigeot 
2308a85cb24fSFrançois Tigeot 		/* If the DMA remap fails, one cause can be that we have
2309a85cb24fSFrançois Tigeot 		 * too many objects pinned in a small remapping table,
2310a85cb24fSFrançois Tigeot 		 * such as swiotlb. Incrementally purge all other objects and
2311a85cb24fSFrançois Tigeot 		 * try again - if there are no more pages to remove from
2312a85cb24fSFrançois Tigeot 		 * the DMA remapper, i915_gem_shrink will return 0.
2313a85cb24fSFrançois Tigeot 		 */
2314a85cb24fSFrançois Tigeot 		GEM_BUG_ON(obj->mm.pages == pages);
2315a85cb24fSFrançois Tigeot 	} while (i915_gem_shrink(to_i915(obj->base.dev),
2316*3f2dd94aSFrançois Tigeot 				 obj->base.size >> PAGE_SHIFT, NULL,
2317a85cb24fSFrançois Tigeot 				 I915_SHRINK_BOUND |
2318a85cb24fSFrançois Tigeot 				 I915_SHRINK_UNBOUND |
2319a85cb24fSFrançois Tigeot 				 I915_SHRINK_ACTIVE));
2320a85cb24fSFrançois Tigeot 
23214be47400SFrançois Tigeot 	return -ENOSPC;
23220b869d8aSFrançois Tigeot }
23230b869d8aSFrançois Tigeot 
gen8_set_pte(void __iomem * addr,gen8_pte_t pte)232419c468b4SFrançois Tigeot static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
2325e3adcf8fSFrançois Tigeot {
23269edbd4a0SFrançois Tigeot 	writeq(pte, addr);
23277cbd1a46SFrançois Tigeot }
2328e3adcf8fSFrançois Tigeot 
gen8_ggtt_insert_page(struct i915_address_space * vm,dma_addr_t addr,u64 offset,enum i915_cache_level level,u32 unused)23291487f786SFrançois Tigeot static void gen8_ggtt_insert_page(struct i915_address_space *vm,
23301487f786SFrançois Tigeot 				  dma_addr_t addr,
2331a85cb24fSFrançois Tigeot 				  u64 offset,
23321487f786SFrançois Tigeot 				  enum i915_cache_level level,
23331487f786SFrançois Tigeot 				  u32 unused)
23341487f786SFrançois Tigeot {
2335a85cb24fSFrançois Tigeot 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
23361487f786SFrançois Tigeot 	gen8_pte_t __iomem *pte =
2337a85cb24fSFrançois Tigeot 		(gen8_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
23381487f786SFrançois Tigeot 
23391e12ee3bSFrançois Tigeot 	gen8_set_pte(pte, gen8_pte_encode(addr, level));
23401487f786SFrançois Tigeot 
2341a85cb24fSFrançois Tigeot 	ggtt->invalidate(vm->i915);
23421487f786SFrançois Tigeot }
23431487f786SFrançois Tigeot 
gen8_ggtt_insert_entries(struct i915_address_space * vm,struct i915_vma * vma,enum i915_cache_level level,u32 unused)23449edbd4a0SFrançois Tigeot static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
2345*3f2dd94aSFrançois Tigeot 				     struct i915_vma *vma,
2346a85cb24fSFrançois Tigeot 				     enum i915_cache_level level,
2347a85cb24fSFrançois Tigeot 				     u32 unused)
23489edbd4a0SFrançois Tigeot {
23491487f786SFrançois Tigeot 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
23501487f786SFrançois Tigeot 	struct sgt_iter sgt_iter;
23511487f786SFrançois Tigeot 	gen8_pte_t __iomem *gtt_entries;
2352a85cb24fSFrançois Tigeot 	const gen8_pte_t pte_encode = gen8_pte_encode(0, level);
23531487f786SFrançois Tigeot 	dma_addr_t addr;
2354aee94f86SFrançois Tigeot 
2355a85cb24fSFrançois Tigeot 	gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm;
2356*3f2dd94aSFrançois Tigeot 	gtt_entries += vma->node.start >> PAGE_SHIFT;
2357*3f2dd94aSFrançois Tigeot 	for_each_sgt_dma(addr, sgt_iter, vma->pages)
2358a85cb24fSFrançois Tigeot 		gen8_set_pte(gtt_entries++, pte_encode | addr);
23591487f786SFrançois Tigeot 
2360a85cb24fSFrançois Tigeot 	wmb();
23617cbd1a46SFrançois Tigeot 
23627cbd1a46SFrançois Tigeot 	/* This next bit makes the above posting read even more important. We
23637cbd1a46SFrançois Tigeot 	 * want to flush the TLBs only after we're certain all the PTE updates
23647cbd1a46SFrançois Tigeot 	 * have finished.
23657cbd1a46SFrançois Tigeot 	 */
2366a85cb24fSFrançois Tigeot 	ggtt->invalidate(vm->i915);
2367a2fdbec6SFrançois Tigeot }
2368a2fdbec6SFrançois Tigeot 
gen6_ggtt_insert_page(struct i915_address_space * vm,dma_addr_t addr,u64 offset,enum i915_cache_level level,u32 flags)23691487f786SFrançois Tigeot static void gen6_ggtt_insert_page(struct i915_address_space *vm,
23701487f786SFrançois Tigeot 				  dma_addr_t addr,
2371a85cb24fSFrançois Tigeot 				  u64 offset,
23721487f786SFrançois Tigeot 				  enum i915_cache_level level,
23731487f786SFrançois Tigeot 				  u32 flags)
23741487f786SFrançois Tigeot {
2375a85cb24fSFrançois Tigeot 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
23761487f786SFrançois Tigeot 	gen6_pte_t __iomem *pte =
2377a85cb24fSFrançois Tigeot 		(gen6_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
23781487f786SFrançois Tigeot 
23791e12ee3bSFrançois Tigeot 	iowrite32(vm->pte_encode(addr, level, flags), pte);
23801487f786SFrançois Tigeot 
2381a85cb24fSFrançois Tigeot 	ggtt->invalidate(vm->i915);
23821487f786SFrançois Tigeot }
23831487f786SFrançois Tigeot 
23849edbd4a0SFrançois Tigeot /*
23859edbd4a0SFrançois Tigeot  * Binds an object into the global gtt with the specified cache level. The object
23869edbd4a0SFrançois Tigeot  * will be accessible to the GPU via commands whose operands reference offsets
23879edbd4a0SFrançois Tigeot  * within the global GTT as well as accessible by the GPU through the GMADR
23889edbd4a0SFrançois Tigeot  * mapped BAR (dev_priv->mm.gtt->gtt).
23899edbd4a0SFrançois Tigeot  */
gen6_ggtt_insert_entries(struct i915_address_space * vm,struct i915_vma * vma,enum i915_cache_level level,u32 flags)23909edbd4a0SFrançois Tigeot static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
2391*3f2dd94aSFrançois Tigeot 				     struct i915_vma *vma,
2392a85cb24fSFrançois Tigeot 				     enum i915_cache_level level,
2393a85cb24fSFrançois Tigeot 				     u32 flags)
2394a2fdbec6SFrançois Tigeot {
23951487f786SFrançois Tigeot 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
2396a85cb24fSFrançois Tigeot 	gen6_pte_t __iomem *entries = (gen6_pte_t __iomem *)ggtt->gsm;
2397*3f2dd94aSFrançois Tigeot 	unsigned int i = vma->node.start >> PAGE_SHIFT;
2398a85cb24fSFrançois Tigeot 	struct sgt_iter iter;
23991487f786SFrançois Tigeot 	dma_addr_t addr;
2400*3f2dd94aSFrançois Tigeot 	for_each_sgt_dma(addr, iter, vma->pages)
2401a85cb24fSFrançois Tigeot 		iowrite32(vm->pte_encode(addr, level, flags), &entries[i++]);
2402a85cb24fSFrançois Tigeot 	wmb();
24039edbd4a0SFrançois Tigeot 
24049edbd4a0SFrançois Tigeot 	/* This next bit makes the above posting read even more important. We
24059edbd4a0SFrançois Tigeot 	 * want to flush the TLBs only after we're certain all the PTE updates
24069edbd4a0SFrançois Tigeot 	 * have finished.
24079edbd4a0SFrançois Tigeot 	 */
2408a85cb24fSFrançois Tigeot 	ggtt->invalidate(vm->i915);
24099edbd4a0SFrançois Tigeot }
24109edbd4a0SFrançois Tigeot 
nop_clear_range(struct i915_address_space * vm,u64 start,u64 length)24111487f786SFrançois Tigeot static void nop_clear_range(struct i915_address_space *vm,
2412a85cb24fSFrançois Tigeot 			    u64 start, u64 length)
24131487f786SFrançois Tigeot {
24141487f786SFrançois Tigeot }
24151487f786SFrançois Tigeot 
gen8_ggtt_clear_range(struct i915_address_space * vm,u64 start,u64 length)24169edbd4a0SFrançois Tigeot static void gen8_ggtt_clear_range(struct i915_address_space *vm,
2417a85cb24fSFrançois Tigeot 				  u64 start, u64 length)
24189edbd4a0SFrançois Tigeot {
24191487f786SFrançois Tigeot 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
2420ba55f2f5SFrançois Tigeot 	unsigned first_entry = start >> PAGE_SHIFT;
2421ba55f2f5SFrançois Tigeot 	unsigned num_entries = length >> PAGE_SHIFT;
2422a85cb24fSFrançois Tigeot 	const gen8_pte_t scratch_pte =
2423a85cb24fSFrançois Tigeot 		gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC);
2424a85cb24fSFrançois Tigeot 	gen8_pte_t __iomem *gtt_base =
24258621f407SFrançois Tigeot 		(gen8_pte_t __iomem *)ggtt->gsm + first_entry;
24268621f407SFrançois Tigeot 	const int max_entries = ggtt_total_entries(ggtt) - first_entry;
24279edbd4a0SFrançois Tigeot 	int i;
24289edbd4a0SFrançois Tigeot 
24299edbd4a0SFrançois Tigeot 	if (WARN(num_entries > max_entries,
24309edbd4a0SFrançois Tigeot 		 "First entry = %d; Num entries = %d (max=%d)\n",
24319edbd4a0SFrançois Tigeot 		 first_entry, num_entries, max_entries))
24329edbd4a0SFrançois Tigeot 		num_entries = max_entries;
24339edbd4a0SFrançois Tigeot 
24349edbd4a0SFrançois Tigeot 	for (i = 0; i < num_entries; i++)
24359edbd4a0SFrançois Tigeot 		gen8_set_pte(&gtt_base[i], scratch_pte);
2436a85cb24fSFrançois Tigeot }
2437a85cb24fSFrançois Tigeot 
bxt_vtd_ggtt_wa(struct i915_address_space * vm)2438a85cb24fSFrançois Tigeot static void bxt_vtd_ggtt_wa(struct i915_address_space *vm)
2439a85cb24fSFrançois Tigeot {
2440a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = vm->i915;
2441a85cb24fSFrançois Tigeot 
2442a85cb24fSFrançois Tigeot 	/*
2443a85cb24fSFrançois Tigeot 	 * Make sure the internal GAM fifo has been cleared of all GTT
2444a85cb24fSFrançois Tigeot 	 * writes before exiting stop_machine(). This guarantees that
2445a85cb24fSFrançois Tigeot 	 * any aperture accesses waiting to start in another process
2446a85cb24fSFrançois Tigeot 	 * cannot back up behind the GTT writes causing a hang.
2447a85cb24fSFrançois Tigeot 	 * The register can be any arbitrary GAM register.
2448a85cb24fSFrançois Tigeot 	 */
2449a85cb24fSFrançois Tigeot 	POSTING_READ(GFX_FLSH_CNTL_GEN6);
2450a85cb24fSFrançois Tigeot }
2451a85cb24fSFrançois Tigeot 
2452a85cb24fSFrançois Tigeot struct insert_page {
2453a85cb24fSFrançois Tigeot 	struct i915_address_space *vm;
2454a85cb24fSFrançois Tigeot 	dma_addr_t addr;
2455a85cb24fSFrançois Tigeot 	u64 offset;
2456a85cb24fSFrançois Tigeot 	enum i915_cache_level level;
2457a85cb24fSFrançois Tigeot };
2458a85cb24fSFrançois Tigeot 
bxt_vtd_ggtt_insert_page__cb(void * _arg)2459a85cb24fSFrançois Tigeot static int bxt_vtd_ggtt_insert_page__cb(void *_arg)
2460a85cb24fSFrançois Tigeot {
2461a85cb24fSFrançois Tigeot 	struct insert_page *arg = _arg;
2462a85cb24fSFrançois Tigeot 
2463a85cb24fSFrançois Tigeot 	gen8_ggtt_insert_page(arg->vm, arg->addr, arg->offset, arg->level, 0);
2464a85cb24fSFrançois Tigeot 	bxt_vtd_ggtt_wa(arg->vm);
2465a85cb24fSFrançois Tigeot 
2466a85cb24fSFrançois Tigeot 	return 0;
2467a85cb24fSFrançois Tigeot }
2468a85cb24fSFrançois Tigeot 
bxt_vtd_ggtt_insert_page__BKL(struct i915_address_space * vm,dma_addr_t addr,u64 offset,enum i915_cache_level level,u32 unused)2469a85cb24fSFrançois Tigeot static void bxt_vtd_ggtt_insert_page__BKL(struct i915_address_space *vm,
2470a85cb24fSFrançois Tigeot 					  dma_addr_t addr,
2471a85cb24fSFrançois Tigeot 					  u64 offset,
2472a85cb24fSFrançois Tigeot 					  enum i915_cache_level level,
2473a85cb24fSFrançois Tigeot 					  u32 unused)
2474a85cb24fSFrançois Tigeot {
2475a85cb24fSFrançois Tigeot 	struct insert_page arg = { vm, addr, offset, level };
2476a85cb24fSFrançois Tigeot 
2477a85cb24fSFrançois Tigeot 	stop_machine(bxt_vtd_ggtt_insert_page__cb, &arg, NULL);
2478a85cb24fSFrançois Tigeot }
2479a85cb24fSFrançois Tigeot 
2480a85cb24fSFrançois Tigeot struct insert_entries {
2481a85cb24fSFrançois Tigeot 	struct i915_address_space *vm;
2482*3f2dd94aSFrançois Tigeot 	struct i915_vma *vma;
2483a85cb24fSFrançois Tigeot 	enum i915_cache_level level;
2484a85cb24fSFrançois Tigeot };
2485a85cb24fSFrançois Tigeot 
bxt_vtd_ggtt_insert_entries__cb(void * _arg)2486a85cb24fSFrançois Tigeot static int bxt_vtd_ggtt_insert_entries__cb(void *_arg)
2487a85cb24fSFrançois Tigeot {
2488a85cb24fSFrançois Tigeot 	struct insert_entries *arg = _arg;
2489a85cb24fSFrançois Tigeot 
2490*3f2dd94aSFrançois Tigeot 	gen8_ggtt_insert_entries(arg->vm, arg->vma, arg->level, 0);
2491a85cb24fSFrançois Tigeot 	bxt_vtd_ggtt_wa(arg->vm);
2492a85cb24fSFrançois Tigeot 
2493a85cb24fSFrançois Tigeot 	return 0;
2494a85cb24fSFrançois Tigeot }
2495a85cb24fSFrançois Tigeot 
bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space * vm,struct i915_vma * vma,enum i915_cache_level level,u32 unused)2496a85cb24fSFrançois Tigeot static void bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space *vm,
2497*3f2dd94aSFrançois Tigeot 					     struct i915_vma *vma,
2498a85cb24fSFrançois Tigeot 					     enum i915_cache_level level,
2499a85cb24fSFrançois Tigeot 					     u32 unused)
2500a85cb24fSFrançois Tigeot {
2501*3f2dd94aSFrançois Tigeot 	struct insert_entries arg = { vm, vma, level };
2502a85cb24fSFrançois Tigeot 
2503a85cb24fSFrançois Tigeot 	stop_machine(bxt_vtd_ggtt_insert_entries__cb, &arg, NULL);
2504a85cb24fSFrançois Tigeot }
2505a85cb24fSFrançois Tigeot 
2506a85cb24fSFrançois Tigeot struct clear_range {
2507a85cb24fSFrançois Tigeot 	struct i915_address_space *vm;
2508a85cb24fSFrançois Tigeot 	u64 start;
2509a85cb24fSFrançois Tigeot 	u64 length;
2510a85cb24fSFrançois Tigeot };
2511a85cb24fSFrançois Tigeot 
bxt_vtd_ggtt_clear_range__cb(void * _arg)2512a85cb24fSFrançois Tigeot static int bxt_vtd_ggtt_clear_range__cb(void *_arg)
2513a85cb24fSFrançois Tigeot {
2514a85cb24fSFrançois Tigeot 	struct clear_range *arg = _arg;
2515a85cb24fSFrançois Tigeot 
2516a85cb24fSFrançois Tigeot 	gen8_ggtt_clear_range(arg->vm, arg->start, arg->length);
2517a85cb24fSFrançois Tigeot 	bxt_vtd_ggtt_wa(arg->vm);
2518a85cb24fSFrançois Tigeot 
2519a85cb24fSFrançois Tigeot 	return 0;
2520a85cb24fSFrançois Tigeot }
2521a85cb24fSFrançois Tigeot 
bxt_vtd_ggtt_clear_range__BKL(struct i915_address_space * vm,u64 start,u64 length)2522a85cb24fSFrançois Tigeot static void bxt_vtd_ggtt_clear_range__BKL(struct i915_address_space *vm,
2523a85cb24fSFrançois Tigeot 					  u64 start,
2524a85cb24fSFrançois Tigeot 					  u64 length)
2525a85cb24fSFrançois Tigeot {
2526a85cb24fSFrançois Tigeot 	struct clear_range arg = { vm, start, length };
2527a85cb24fSFrançois Tigeot 
2528a85cb24fSFrançois Tigeot 	stop_machine(bxt_vtd_ggtt_clear_range__cb, &arg, NULL);
25299edbd4a0SFrançois Tigeot }
25309edbd4a0SFrançois Tigeot 
gen6_ggtt_clear_range(struct i915_address_space * vm,u64 start,u64 length)25319edbd4a0SFrançois Tigeot static void gen6_ggtt_clear_range(struct i915_address_space *vm,
2532a85cb24fSFrançois Tigeot 				  u64 start, u64 length)
25339edbd4a0SFrançois Tigeot {
25341487f786SFrançois Tigeot 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
2535ba55f2f5SFrançois Tigeot 	unsigned first_entry = start >> PAGE_SHIFT;
2536ba55f2f5SFrançois Tigeot 	unsigned num_entries = length >> PAGE_SHIFT;
2537477eb7f9SFrançois Tigeot 	gen6_pte_t scratch_pte, __iomem *gtt_base =
25388621f407SFrançois Tigeot 		(gen6_pte_t __iomem *)ggtt->gsm + first_entry;
25398621f407SFrançois Tigeot 	const int max_entries = ggtt_total_entries(ggtt) - first_entry;
2540a2fdbec6SFrançois Tigeot 	int i;
2541a2fdbec6SFrançois Tigeot 
2542a2fdbec6SFrançois Tigeot 	if (WARN(num_entries > max_entries,
2543a2fdbec6SFrançois Tigeot 		 "First entry = %d; Num entries = %d (max=%d)\n",
2544a2fdbec6SFrançois Tigeot 		 first_entry, num_entries, max_entries))
2545a2fdbec6SFrançois Tigeot 		num_entries = max_entries;
2546a2fdbec6SFrançois Tigeot 
25471e12ee3bSFrançois Tigeot 	scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
25481e12ee3bSFrançois Tigeot 				     I915_CACHE_LLC, 0);
25499edbd4a0SFrançois Tigeot 
2550a2fdbec6SFrançois Tigeot 	for (i = 0; i < num_entries; i++)
2551a2fdbec6SFrançois Tigeot 		iowrite32(scratch_pte, &gtt_base[i]);
2552a2fdbec6SFrançois Tigeot }
2553a2fdbec6SFrançois Tigeot 
i915_ggtt_insert_page(struct i915_address_space * vm,dma_addr_t addr,u64 offset,enum i915_cache_level cache_level,u32 unused)25541487f786SFrançois Tigeot static void i915_ggtt_insert_page(struct i915_address_space *vm,
25551487f786SFrançois Tigeot 				  dma_addr_t addr,
2556a85cb24fSFrançois Tigeot 				  u64 offset,
25571487f786SFrançois Tigeot 				  enum i915_cache_level cache_level,
25581487f786SFrançois Tigeot 				  u32 unused)
25591487f786SFrançois Tigeot {
25601487f786SFrançois Tigeot 	unsigned int flags = (cache_level == I915_CACHE_NONE) ?
25611487f786SFrançois Tigeot 		AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
25621487f786SFrançois Tigeot 
25631487f786SFrançois Tigeot 	intel_gtt_insert_page(addr, offset >> PAGE_SHIFT, flags);
25641487f786SFrançois Tigeot }
25651487f786SFrançois Tigeot 
i915_ggtt_insert_entries(struct i915_address_space * vm,struct i915_vma * vma,enum i915_cache_level cache_level,u32 unused)25667ec9f8e5SFrançois Tigeot static void i915_ggtt_insert_entries(struct i915_address_space *vm,
2567*3f2dd94aSFrançois Tigeot 				     struct i915_vma *vma,
2568a85cb24fSFrançois Tigeot 				     enum i915_cache_level cache_level,
2569a85cb24fSFrançois Tigeot 				     u32 unused)
2570a2fdbec6SFrançois Tigeot {
2571a2fdbec6SFrançois Tigeot 	unsigned int flags = (cache_level == I915_CACHE_NONE) ?
2572a2fdbec6SFrançois Tigeot 		AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
2573a2fdbec6SFrançois Tigeot 
2574*3f2dd94aSFrançois Tigeot 	intel_gtt_insert_sg_entries(vma->pages, vma->node.start >> PAGE_SHIFT,
2575*3f2dd94aSFrançois Tigeot 				    flags);
2576a2fdbec6SFrançois Tigeot }
2577a2fdbec6SFrançois Tigeot 
i915_ggtt_clear_range(struct i915_address_space * vm,u64 start,u64 length)25789edbd4a0SFrançois Tigeot static void i915_ggtt_clear_range(struct i915_address_space *vm,
2579a85cb24fSFrançois Tigeot 				  u64 start, u64 length)
2580a2fdbec6SFrançois Tigeot {
25814be47400SFrançois Tigeot 	intel_gtt_clear_range(start >> PAGE_SHIFT, length >> PAGE_SHIFT);
2582a2fdbec6SFrançois Tigeot }
25837cbd1a46SFrançois Tigeot 
ggtt_bind_vma(struct i915_vma * vma,enum i915_cache_level cache_level,u32 flags)258419c468b4SFrançois Tigeot static int ggtt_bind_vma(struct i915_vma *vma,
2585ba55f2f5SFrançois Tigeot 			 enum i915_cache_level cache_level,
2586ba55f2f5SFrançois Tigeot 			 u32 flags)
2587e3adcf8fSFrançois Tigeot {
2588a85cb24fSFrançois Tigeot 	struct drm_i915_private *i915 = vma->vm->i915;
2589352ff8bdSFrançois Tigeot 	struct drm_i915_gem_object *obj = vma->obj;
2590a85cb24fSFrançois Tigeot 	u32 pte_flags;
2591352ff8bdSFrançois Tigeot 
2592352ff8bdSFrançois Tigeot 	/* Currently applicable only to VLV */
2593a85cb24fSFrançois Tigeot 	pte_flags = 0;
2594352ff8bdSFrançois Tigeot 	if (obj->gt_ro)
2595352ff8bdSFrançois Tigeot 		pte_flags |= PTE_READ_ONLY;
2596352ff8bdSFrançois Tigeot 
25974be47400SFrançois Tigeot 	intel_runtime_pm_get(i915);
2598*3f2dd94aSFrançois Tigeot 	vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
25994be47400SFrançois Tigeot 	intel_runtime_pm_put(i915);
2600352ff8bdSFrançois Tigeot 
2601*3f2dd94aSFrançois Tigeot 	vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
2602*3f2dd94aSFrançois Tigeot 
2603352ff8bdSFrançois Tigeot 	/*
2604352ff8bdSFrançois Tigeot 	 * Without aliasing PPGTT there's no difference between
2605352ff8bdSFrançois Tigeot 	 * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally
2606352ff8bdSFrançois Tigeot 	 * upgrade to both bound if we bind either to avoid double-binding.
2607352ff8bdSFrançois Tigeot 	 */
260871f41f3eSFrançois Tigeot 	vma->flags |= I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND;
2609352ff8bdSFrançois Tigeot 
2610352ff8bdSFrançois Tigeot 	return 0;
2611352ff8bdSFrançois Tigeot }
2612352ff8bdSFrançois Tigeot 
ggtt_unbind_vma(struct i915_vma * vma)2613a85cb24fSFrançois Tigeot static void ggtt_unbind_vma(struct i915_vma *vma)
2614a85cb24fSFrançois Tigeot {
2615a85cb24fSFrançois Tigeot 	struct drm_i915_private *i915 = vma->vm->i915;
2616a85cb24fSFrançois Tigeot 
2617a85cb24fSFrançois Tigeot 	intel_runtime_pm_get(i915);
2618a85cb24fSFrançois Tigeot 	vma->vm->clear_range(vma->vm, vma->node.start, vma->size);
2619a85cb24fSFrançois Tigeot 	intel_runtime_pm_put(i915);
2620a85cb24fSFrançois Tigeot }
2621a85cb24fSFrançois Tigeot 
aliasing_gtt_bind_vma(struct i915_vma * vma,enum i915_cache_level cache_level,u32 flags)2622352ff8bdSFrançois Tigeot static int aliasing_gtt_bind_vma(struct i915_vma *vma,
2623352ff8bdSFrançois Tigeot 				 enum i915_cache_level cache_level,
2624352ff8bdSFrançois Tigeot 				 u32 flags)
2625352ff8bdSFrançois Tigeot {
2626a85cb24fSFrançois Tigeot 	struct drm_i915_private *i915 = vma->vm->i915;
26278621f407SFrançois Tigeot 	u32 pte_flags;
26287ec9f8e5SFrançois Tigeot 	int ret;
26297ec9f8e5SFrançois Tigeot 
263024edb884SFrançois Tigeot 	/* Currently applicable only to VLV */
26318621f407SFrançois Tigeot 	pte_flags = 0;
26328621f407SFrançois Tigeot 	if (vma->obj->gt_ro)
263319c468b4SFrançois Tigeot 		pte_flags |= PTE_READ_ONLY;
263424edb884SFrançois Tigeot 
2635a85cb24fSFrançois Tigeot 	if (flags & I915_VMA_LOCAL_BIND) {
2636a85cb24fSFrançois Tigeot 		struct i915_hw_ppgtt *appgtt = i915->mm.aliasing_ppgtt;
2637a85cb24fSFrançois Tigeot 
2638a85cb24fSFrançois Tigeot 		if (!(vma->flags & I915_VMA_LOCAL_BIND) &&
2639a85cb24fSFrançois Tigeot 		    appgtt->base.allocate_va_range) {
2640a85cb24fSFrançois Tigeot 			ret = appgtt->base.allocate_va_range(&appgtt->base,
2641a85cb24fSFrançois Tigeot 							     vma->node.start,
2642a85cb24fSFrançois Tigeot 							     vma->size);
2643a85cb24fSFrançois Tigeot 			if (ret)
2644*3f2dd94aSFrançois Tigeot 				return ret;
2645a85cb24fSFrançois Tigeot 		}
2646a85cb24fSFrançois Tigeot 
2647*3f2dd94aSFrançois Tigeot 		appgtt->base.insert_entries(&appgtt->base, vma, cache_level,
2648*3f2dd94aSFrançois Tigeot 					    pte_flags);
2649a85cb24fSFrançois Tigeot 	}
2650477eb7f9SFrançois Tigeot 
265171f41f3eSFrançois Tigeot 	if (flags & I915_VMA_GLOBAL_BIND) {
26524be47400SFrançois Tigeot 		intel_runtime_pm_get(i915);
2653*3f2dd94aSFrançois Tigeot 		vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
26544be47400SFrançois Tigeot 		intel_runtime_pm_put(i915);
2655ba55f2f5SFrançois Tigeot 	}
2656e3adcf8fSFrançois Tigeot 
265719c468b4SFrançois Tigeot 	return 0;
2658ba55f2f5SFrançois Tigeot }
2659ba55f2f5SFrançois Tigeot 
aliasing_gtt_unbind_vma(struct i915_vma * vma)2660a85cb24fSFrançois Tigeot static void aliasing_gtt_unbind_vma(struct i915_vma *vma)
2661ba55f2f5SFrançois Tigeot {
2662a85cb24fSFrançois Tigeot 	struct drm_i915_private *i915 = vma->vm->i915;
2663ba55f2f5SFrançois Tigeot 
26644be47400SFrançois Tigeot 	if (vma->flags & I915_VMA_GLOBAL_BIND) {
26654be47400SFrançois Tigeot 		intel_runtime_pm_get(i915);
2666a85cb24fSFrançois Tigeot 		vma->vm->clear_range(vma->vm, vma->node.start, vma->size);
26674be47400SFrançois Tigeot 		intel_runtime_pm_put(i915);
26684be47400SFrançois Tigeot 	}
2669f192107fSFrançois Tigeot 
2670a85cb24fSFrançois Tigeot 	if (vma->flags & I915_VMA_LOCAL_BIND) {
2671a85cb24fSFrançois Tigeot 		struct i915_address_space *vm = &i915->mm.aliasing_ppgtt->base;
2672a85cb24fSFrançois Tigeot 
2673a85cb24fSFrançois Tigeot 		vm->clear_range(vm, vma->node.start, vma->size);
2674a85cb24fSFrançois Tigeot 	}
2675ba55f2f5SFrançois Tigeot }
2676ba55f2f5SFrançois Tigeot 
i915_gem_gtt_finish_pages(struct drm_i915_gem_object * obj,struct sg_table * pages)26774be47400SFrançois Tigeot void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,
26784be47400SFrançois Tigeot 			       struct sg_table *pages)
2679f192107fSFrançois Tigeot {
26801e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
26811e12ee3bSFrançois Tigeot 	struct device *kdev = &dev_priv->drm.pdev->dev;
268271f41f3eSFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
2683f192107fSFrançois Tigeot 
268471f41f3eSFrançois Tigeot 	if (unlikely(ggtt->do_idle_maps)) {
2685a85cb24fSFrançois Tigeot 		if (i915_gem_wait_for_idle(dev_priv, 0)) {
268671f41f3eSFrançois Tigeot 			DRM_ERROR("Failed to wait for idle; VT'd may hang.\n");
268771f41f3eSFrançois Tigeot 			/* Wait a bit, in hopes it avoids the hang */
268871f41f3eSFrançois Tigeot 			udelay(10);
268971f41f3eSFrançois Tigeot 		}
269071f41f3eSFrançois Tigeot 	}
2691f192107fSFrançois Tigeot 
26924be47400SFrançois Tigeot 	dma_unmap_sg(kdev, pages->sgl, pages->nents, PCI_DMA_BIDIRECTIONAL);
2693f192107fSFrançois Tigeot }
2694d1c259eeSFrançois Tigeot 
ggtt_set_pages(struct i915_vma * vma)2695*3f2dd94aSFrançois Tigeot static int ggtt_set_pages(struct i915_vma *vma)
2696*3f2dd94aSFrançois Tigeot {
2697*3f2dd94aSFrançois Tigeot 	int ret;
2698*3f2dd94aSFrançois Tigeot 
2699*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(vma->pages);
2700*3f2dd94aSFrançois Tigeot 
2701*3f2dd94aSFrançois Tigeot 	ret = i915_get_ggtt_vma_pages(vma);
2702*3f2dd94aSFrançois Tigeot 	if (ret)
2703*3f2dd94aSFrançois Tigeot 		return ret;
2704*3f2dd94aSFrançois Tigeot 
2705*3f2dd94aSFrançois Tigeot 	vma->page_sizes = vma->obj->mm.page_sizes;
2706*3f2dd94aSFrançois Tigeot 
2707*3f2dd94aSFrançois Tigeot 	return 0;
2708*3f2dd94aSFrançois Tigeot }
2709*3f2dd94aSFrançois Tigeot 
i915_gtt_color_adjust(const struct drm_mm_node * node,unsigned long color,u64 * start,u64 * end)2710a85cb24fSFrançois Tigeot static void i915_gtt_color_adjust(const struct drm_mm_node *node,
2711d1c259eeSFrançois Tigeot 				  unsigned long color,
27122c9916cdSFrançois Tigeot 				  u64 *start,
27132c9916cdSFrançois Tigeot 				  u64 *end)
2714d1c259eeSFrançois Tigeot {
2715a85cb24fSFrançois Tigeot 	if (node->allocated && node->color != color)
2716a85cb24fSFrançois Tigeot 		*start += I915_GTT_PAGE_SIZE;
2717d1c259eeSFrançois Tigeot 
2718a85cb24fSFrançois Tigeot 	/* Also leave a space between the unallocated reserved node after the
2719a85cb24fSFrançois Tigeot 	 * GTT and any objects within the GTT, i.e. we use the color adjustment
2720a85cb24fSFrançois Tigeot 	 * to insert a guard page to prevent prefetches crossing over the
2721a85cb24fSFrançois Tigeot 	 * GTT boundary.
2722a85cb24fSFrançois Tigeot 	 */
2723a85cb24fSFrançois Tigeot 	node = list_next_entry(node, node_list);
2724a85cb24fSFrançois Tigeot 	if (node->color != color)
2725a85cb24fSFrançois Tigeot 		*end -= I915_GTT_PAGE_SIZE;
2726a85cb24fSFrançois Tigeot }
2727a85cb24fSFrançois Tigeot 
i915_gem_init_aliasing_ppgtt(struct drm_i915_private * i915)2728a85cb24fSFrançois Tigeot int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915)
2729a85cb24fSFrançois Tigeot {
2730a85cb24fSFrançois Tigeot 	struct i915_ggtt *ggtt = &i915->ggtt;
2731a85cb24fSFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt;
2732a85cb24fSFrançois Tigeot 	int err;
2733a85cb24fSFrançois Tigeot 
2734a85cb24fSFrançois Tigeot 	ppgtt = i915_ppgtt_create(i915, ERR_PTR(-EPERM), "[alias]");
2735a85cb24fSFrançois Tigeot 	if (IS_ERR(ppgtt))
2736a85cb24fSFrançois Tigeot 		return PTR_ERR(ppgtt);
2737a85cb24fSFrançois Tigeot 
2738a85cb24fSFrançois Tigeot 	if (WARN_ON(ppgtt->base.total < ggtt->base.total)) {
2739a85cb24fSFrançois Tigeot 		err = -ENODEV;
2740a85cb24fSFrançois Tigeot 		goto err_ppgtt;
2741a85cb24fSFrançois Tigeot 	}
2742a85cb24fSFrançois Tigeot 
2743a85cb24fSFrançois Tigeot 	if (ppgtt->base.allocate_va_range) {
2744a85cb24fSFrançois Tigeot 		/* Note we only pre-allocate as far as the end of the global
2745a85cb24fSFrançois Tigeot 		 * GTT. On 48b / 4-level page-tables, the difference is very,
2746a85cb24fSFrançois Tigeot 		 * very significant! We have to preallocate as GVT/vgpu does
2747a85cb24fSFrançois Tigeot 		 * not like the page directory disappearing.
2748a85cb24fSFrançois Tigeot 		 */
2749a85cb24fSFrançois Tigeot 		err = ppgtt->base.allocate_va_range(&ppgtt->base,
2750a85cb24fSFrançois Tigeot 						    0, ggtt->base.total);
2751a85cb24fSFrançois Tigeot 		if (err)
2752a85cb24fSFrançois Tigeot 			goto err_ppgtt;
2753a85cb24fSFrançois Tigeot 	}
2754a85cb24fSFrançois Tigeot 
2755a85cb24fSFrançois Tigeot 	i915->mm.aliasing_ppgtt = ppgtt;
2756a85cb24fSFrançois Tigeot 
2757a85cb24fSFrançois Tigeot 	WARN_ON(ggtt->base.bind_vma != ggtt_bind_vma);
2758a85cb24fSFrançois Tigeot 	ggtt->base.bind_vma = aliasing_gtt_bind_vma;
2759a85cb24fSFrançois Tigeot 
2760a85cb24fSFrançois Tigeot 	WARN_ON(ggtt->base.unbind_vma != ggtt_unbind_vma);
2761a85cb24fSFrançois Tigeot 	ggtt->base.unbind_vma = aliasing_gtt_unbind_vma;
2762a85cb24fSFrançois Tigeot 
2763a85cb24fSFrançois Tigeot 	return 0;
2764a85cb24fSFrançois Tigeot 
2765a85cb24fSFrançois Tigeot err_ppgtt:
2766a85cb24fSFrançois Tigeot 	i915_ppgtt_put(ppgtt);
2767a85cb24fSFrançois Tigeot 	return err;
2768a85cb24fSFrançois Tigeot }
2769a85cb24fSFrançois Tigeot 
i915_gem_fini_aliasing_ppgtt(struct drm_i915_private * i915)2770a85cb24fSFrançois Tigeot void i915_gem_fini_aliasing_ppgtt(struct drm_i915_private *i915)
2771a85cb24fSFrançois Tigeot {
2772a85cb24fSFrançois Tigeot 	struct i915_ggtt *ggtt = &i915->ggtt;
2773a85cb24fSFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt;
2774a85cb24fSFrançois Tigeot 
2775a85cb24fSFrançois Tigeot 	ppgtt = fetch_and_zero(&i915->mm.aliasing_ppgtt);
2776a85cb24fSFrançois Tigeot 	if (!ppgtt)
2777a85cb24fSFrançois Tigeot 		return;
2778a85cb24fSFrançois Tigeot 
2779a85cb24fSFrançois Tigeot 	i915_ppgtt_put(ppgtt);
2780a85cb24fSFrançois Tigeot 
2781a85cb24fSFrançois Tigeot 	ggtt->base.bind_vma = ggtt_bind_vma;
2782a85cb24fSFrançois Tigeot 	ggtt->base.unbind_vma = ggtt_unbind_vma;
2783d1c259eeSFrançois Tigeot }
27849edbd4a0SFrançois Tigeot 
i915_gem_init_ggtt(struct drm_i915_private * dev_priv)278571f41f3eSFrançois Tigeot int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
2786d1c259eeSFrançois Tigeot {
2787a2fdbec6SFrançois Tigeot 	/* Let GEM Manage all of the aperture.
2788a2fdbec6SFrançois Tigeot 	 *
2789a2fdbec6SFrançois Tigeot 	 * However, leave one page at the end still bound to the scratch page.
2790a2fdbec6SFrançois Tigeot 	 * There are a number of places where the hardware apparently prefetches
2791a2fdbec6SFrançois Tigeot 	 * past the end of the object, and we've seen multiple hangs with the
2792a2fdbec6SFrançois Tigeot 	 * GPU head pointer stuck in a batchbuffer bound at the last page of the
2793a2fdbec6SFrançois Tigeot 	 * aperture.  One page should be enough to keep any prefetching inside
2794a2fdbec6SFrançois Tigeot 	 * of the aperture.
2795a2fdbec6SFrançois Tigeot 	 */
27968621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
27979edbd4a0SFrançois Tigeot 	unsigned long hole_start, hole_end;
279871f41f3eSFrançois Tigeot 	struct drm_mm_node *entry;
27991b13d190SFrançois Tigeot 	int ret;
280071f41f3eSFrançois Tigeot 	unsigned long mappable = min(ggtt->base.total, ggtt->mappable_end);
2801477eb7f9SFrançois Tigeot 
28021487f786SFrançois Tigeot 	ret = intel_vgt_balloon(dev_priv);
2803477eb7f9SFrançois Tigeot 	if (ret)
2804477eb7f9SFrançois Tigeot 		return ret;
2805477eb7f9SFrançois Tigeot 
28061e12ee3bSFrançois Tigeot 	/* Reserve a mappable slot for our lockless error capture */
2807a85cb24fSFrançois Tigeot 	ret = drm_mm_insert_node_in_range(&ggtt->base.mm, &ggtt->error_capture,
2808a85cb24fSFrançois Tigeot 					  PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE,
28091e12ee3bSFrançois Tigeot 					  0, ggtt->mappable_end,
2810a85cb24fSFrançois Tigeot 					  DRM_MM_INSERT_LOW);
28111e12ee3bSFrançois Tigeot 	if (ret)
28121e12ee3bSFrançois Tigeot 		return ret;
28131e12ee3bSFrançois Tigeot 
28149edbd4a0SFrançois Tigeot 	/* Clear any non-preallocated blocks */
28158621f407SFrançois Tigeot 	drm_mm_for_each_hole(entry, &ggtt->base.mm, hole_start, hole_end) {
28169edbd4a0SFrançois Tigeot 		DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
28179edbd4a0SFrançois Tigeot 			      hole_start, hole_end);
28188621f407SFrançois Tigeot 		ggtt->base.clear_range(&ggtt->base, hole_start,
28191e12ee3bSFrançois Tigeot 				       hole_end - hole_start);
28209edbd4a0SFrançois Tigeot 	}
2821cb170299SFrançois Tigeot 
2822310880c6SSascha Wildner #ifdef __DragonFly__
282371f41f3eSFrançois Tigeot 	DRM_INFO("taking over the fictitious range 0x%llx-0x%llx\n",
282471f41f3eSFrançois Tigeot 	    dev_priv->ggtt.mappable_base, dev_priv->ggtt.mappable_end);
282571f41f3eSFrançois Tigeot 	vm_phys_fictitious_reg_range(dev_priv->ggtt.mappable_base,
282671f41f3eSFrançois Tigeot 	     dev_priv->ggtt.mappable_base + mappable, VM_MEMATTR_WRITE_COMBINING);
2827310880c6SSascha Wildner #endif
28289edbd4a0SFrançois Tigeot 
28299edbd4a0SFrançois Tigeot 	/* And finally clear the reserved guard page */
283071f41f3eSFrançois Tigeot 	ggtt->base.clear_range(&ggtt->base,
28311e12ee3bSFrançois Tigeot 			       ggtt->base.total - PAGE_SIZE, PAGE_SIZE);
28321b13d190SFrançois Tigeot 
283371f41f3eSFrançois Tigeot 	if (USES_PPGTT(dev_priv) && !USES_FULL_PPGTT(dev_priv)) {
2834a85cb24fSFrançois Tigeot 		ret = i915_gem_init_aliasing_ppgtt(dev_priv);
2835a85cb24fSFrançois Tigeot 		if (ret)
28361e12ee3bSFrançois Tigeot 			goto err;
2837477eb7f9SFrançois Tigeot 	}
28381b13d190SFrançois Tigeot 
28391b13d190SFrançois Tigeot 	return 0;
28401e12ee3bSFrançois Tigeot 
28411e12ee3bSFrançois Tigeot err:
28421e12ee3bSFrançois Tigeot 	drm_mm_remove_node(&ggtt->error_capture);
28431e12ee3bSFrançois Tigeot 	return ret;
2844a2fdbec6SFrançois Tigeot }
2845a2fdbec6SFrançois Tigeot 
28468621f407SFrançois Tigeot /**
28478621f407SFrançois Tigeot  * i915_ggtt_cleanup_hw - Clean up GGTT hardware initialization
284871f41f3eSFrançois Tigeot  * @dev_priv: i915 device
28498621f407SFrançois Tigeot  */
i915_ggtt_cleanup_hw(struct drm_i915_private * dev_priv)285071f41f3eSFrançois Tigeot void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv)
28511b13d190SFrançois Tigeot {
28528621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
2853a85cb24fSFrançois Tigeot 	struct i915_vma *vma, *vn;
2854*3f2dd94aSFrançois Tigeot 	struct pagevec *pvec;
28551b13d190SFrançois Tigeot 
2856a85cb24fSFrançois Tigeot 	ggtt->base.closed = true;
2857a85cb24fSFrançois Tigeot 
2858a85cb24fSFrançois Tigeot 	mutex_lock(&dev_priv->drm.struct_mutex);
2859a85cb24fSFrançois Tigeot 	WARN_ON(!list_empty(&ggtt->base.active_list));
2860a85cb24fSFrançois Tigeot 	list_for_each_entry_safe(vma, vn, &ggtt->base.inactive_list, vm_link)
2861a85cb24fSFrançois Tigeot 		WARN_ON(i915_vma_unbind(vma));
2862a85cb24fSFrançois Tigeot 	mutex_unlock(&dev_priv->drm.struct_mutex);
28631b13d190SFrançois Tigeot 
286471f41f3eSFrançois Tigeot 	i915_gem_cleanup_stolen(&dev_priv->drm);
2865c0e85e96SFrançois Tigeot 
2866a85cb24fSFrançois Tigeot 	mutex_lock(&dev_priv->drm.struct_mutex);
2867a85cb24fSFrançois Tigeot 	i915_gem_fini_aliasing_ppgtt(dev_priv);
2868a85cb24fSFrançois Tigeot 
28691e12ee3bSFrançois Tigeot 	if (drm_mm_node_allocated(&ggtt->error_capture))
28701e12ee3bSFrançois Tigeot 		drm_mm_remove_node(&ggtt->error_capture);
28711e12ee3bSFrançois Tigeot 
28728621f407SFrançois Tigeot 	if (drm_mm_initialized(&ggtt->base.mm)) {
28731487f786SFrançois Tigeot 		intel_vgt_deballoon(dev_priv);
28744be47400SFrançois Tigeot 		i915_address_space_fini(&ggtt->base);
28751b13d190SFrançois Tigeot 	}
28761b13d190SFrançois Tigeot 
28778621f407SFrançois Tigeot 	ggtt->base.cleanup(&ggtt->base);
2878*3f2dd94aSFrançois Tigeot 
2879*3f2dd94aSFrançois Tigeot 	pvec = &dev_priv->mm.wc_stash;
2880*3f2dd94aSFrançois Tigeot 	if (pvec->nr) {
2881*3f2dd94aSFrançois Tigeot 		set_pages_array_wb(pvec->pages, pvec->nr);
2882*3f2dd94aSFrançois Tigeot 		__pagevec_release(pvec);
2883*3f2dd94aSFrançois Tigeot 	}
2884*3f2dd94aSFrançois Tigeot 
2885a85cb24fSFrançois Tigeot 	mutex_unlock(&dev_priv->drm.struct_mutex);
288671f41f3eSFrançois Tigeot 
288771f41f3eSFrançois Tigeot 	arch_phys_wc_del(ggtt->mtrr);
28881e12ee3bSFrançois Tigeot 	io_mapping_fini(&ggtt->mappable);
28891b13d190SFrançois Tigeot }
28901b13d190SFrançois Tigeot 
gen6_get_total_gtt_size(u16 snb_gmch_ctl)289119c468b4SFrançois Tigeot static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
28929edbd4a0SFrançois Tigeot {
28939edbd4a0SFrançois Tigeot 	snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT;
28949edbd4a0SFrançois Tigeot 	snb_gmch_ctl &= SNB_GMCH_GGMS_MASK;
28959edbd4a0SFrançois Tigeot 	return snb_gmch_ctl << 20;
28969edbd4a0SFrançois Tigeot }
28979edbd4a0SFrançois Tigeot 
gen8_get_total_gtt_size(u16 bdw_gmch_ctl)289819c468b4SFrançois Tigeot static unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
28999edbd4a0SFrançois Tigeot {
29009edbd4a0SFrançois Tigeot 	bdw_gmch_ctl >>= BDW_GMCH_GGMS_SHIFT;
29019edbd4a0SFrançois Tigeot 	bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK;
29029edbd4a0SFrançois Tigeot 	if (bdw_gmch_ctl)
29039edbd4a0SFrançois Tigeot 		bdw_gmch_ctl = 1 << bdw_gmch_ctl;
2904ba55f2f5SFrançois Tigeot 
2905ba55f2f5SFrançois Tigeot #ifdef CONFIG_X86_32
2906ba55f2f5SFrançois Tigeot 	/* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * PAGE_SIZE */
2907ba55f2f5SFrançois Tigeot 	if (bdw_gmch_ctl > 4)
2908ba55f2f5SFrançois Tigeot 		bdw_gmch_ctl = 4;
2909ba55f2f5SFrançois Tigeot #endif
29109edbd4a0SFrançois Tigeot 
29119edbd4a0SFrançois Tigeot 	return bdw_gmch_ctl << 20;
29129edbd4a0SFrançois Tigeot }
29139edbd4a0SFrançois Tigeot 
chv_get_total_gtt_size(u16 gmch_ctrl)291419c468b4SFrançois Tigeot static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl)
2915ba55f2f5SFrançois Tigeot {
2916ba55f2f5SFrançois Tigeot 	gmch_ctrl >>= SNB_GMCH_GGMS_SHIFT;
2917ba55f2f5SFrançois Tigeot 	gmch_ctrl &= SNB_GMCH_GGMS_MASK;
2918ba55f2f5SFrançois Tigeot 
2919ba55f2f5SFrançois Tigeot 	if (gmch_ctrl)
2920ba55f2f5SFrançois Tigeot 		return 1 << (20 + gmch_ctrl);
2921ba55f2f5SFrançois Tigeot 
2922ba55f2f5SFrançois Tigeot 	return 0;
2923ba55f2f5SFrançois Tigeot }
2924ba55f2f5SFrançois Tigeot 
gen6_get_stolen_size(u16 snb_gmch_ctl)292519c468b4SFrançois Tigeot static size_t gen6_get_stolen_size(u16 snb_gmch_ctl)
29269edbd4a0SFrançois Tigeot {
29279edbd4a0SFrançois Tigeot 	snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT;
29289edbd4a0SFrançois Tigeot 	snb_gmch_ctl &= SNB_GMCH_GMS_MASK;
2929*3f2dd94aSFrançois Tigeot 	return (size_t)snb_gmch_ctl << 25; /* 32 MB units */
29309edbd4a0SFrançois Tigeot }
29319edbd4a0SFrançois Tigeot 
gen8_get_stolen_size(u16 bdw_gmch_ctl)293219c468b4SFrançois Tigeot static size_t gen8_get_stolen_size(u16 bdw_gmch_ctl)
29339edbd4a0SFrançois Tigeot {
29349edbd4a0SFrançois Tigeot 	bdw_gmch_ctl >>= BDW_GMCH_GMS_SHIFT;
29359edbd4a0SFrançois Tigeot 	bdw_gmch_ctl &= BDW_GMCH_GMS_MASK;
2936*3f2dd94aSFrançois Tigeot 	return (size_t)bdw_gmch_ctl << 25; /* 32 MB units */
29379edbd4a0SFrançois Tigeot }
29389edbd4a0SFrançois Tigeot 
chv_get_stolen_size(u16 gmch_ctrl)2939ba55f2f5SFrançois Tigeot static size_t chv_get_stolen_size(u16 gmch_ctrl)
2940ba55f2f5SFrançois Tigeot {
2941ba55f2f5SFrançois Tigeot 	gmch_ctrl >>= SNB_GMCH_GMS_SHIFT;
2942ba55f2f5SFrançois Tigeot 	gmch_ctrl &= SNB_GMCH_GMS_MASK;
2943ba55f2f5SFrançois Tigeot 
2944ba55f2f5SFrançois Tigeot 	/*
2945ba55f2f5SFrançois Tigeot 	 * 0x0  to 0x10: 32MB increments starting at 0MB
2946ba55f2f5SFrançois Tigeot 	 * 0x11 to 0x16: 4MB increments starting at 8MB
2947ba55f2f5SFrançois Tigeot 	 * 0x17 to 0x1d: 4MB increments start at 36MB
2948ba55f2f5SFrançois Tigeot 	 */
2949ba55f2f5SFrançois Tigeot 	if (gmch_ctrl < 0x11)
2950*3f2dd94aSFrançois Tigeot 		return (size_t)gmch_ctrl << 25;
2951ba55f2f5SFrançois Tigeot 	else if (gmch_ctrl < 0x17)
2952*3f2dd94aSFrançois Tigeot 		return (size_t)(gmch_ctrl - 0x11 + 2) << 22;
2953ba55f2f5SFrançois Tigeot 	else
2954*3f2dd94aSFrançois Tigeot 		return (size_t)(gmch_ctrl - 0x17 + 9) << 22;
2955ba55f2f5SFrançois Tigeot }
2956ba55f2f5SFrançois Tigeot 
gen9_get_stolen_size(u16 gen9_gmch_ctl)29572c9916cdSFrançois Tigeot static size_t gen9_get_stolen_size(u16 gen9_gmch_ctl)
29582c9916cdSFrançois Tigeot {
29592c9916cdSFrançois Tigeot 	gen9_gmch_ctl >>= BDW_GMCH_GMS_SHIFT;
29602c9916cdSFrançois Tigeot 	gen9_gmch_ctl &= BDW_GMCH_GMS_MASK;
29612c9916cdSFrançois Tigeot 
29622c9916cdSFrançois Tigeot 	if (gen9_gmch_ctl < 0xf0)
2963*3f2dd94aSFrançois Tigeot 		return (size_t)gen9_gmch_ctl << 25; /* 32 MB units */
29642c9916cdSFrançois Tigeot 	else
29652c9916cdSFrançois Tigeot 		/* 4MB increments starting at 0xf0 for 4MB */
2966*3f2dd94aSFrançois Tigeot 		return (size_t)(gen9_gmch_ctl - 0xf0 + 1) << 22;
29672c9916cdSFrançois Tigeot }
29682c9916cdSFrançois Tigeot 
ggtt_probe_common(struct i915_ggtt * ggtt,u64 size)296971f41f3eSFrançois Tigeot static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
29709edbd4a0SFrançois Tigeot {
2971a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = ggtt->base.i915;
2972a85cb24fSFrançois Tigeot 	struct pci_dev *pdev = dev_priv->drm.pdev;
297371f41f3eSFrançois Tigeot 	phys_addr_t phys_addr;
29741e12ee3bSFrançois Tigeot 	int ret;
29759edbd4a0SFrançois Tigeot 
29769edbd4a0SFrançois Tigeot 	/* For Modern GENs the PTEs and register space are split in the BAR */
297771f41f3eSFrançois Tigeot 	phys_addr = pci_resource_start(pdev, 0) + pci_resource_len(pdev, 0) / 2;
29789edbd4a0SFrançois Tigeot 
297919c468b4SFrançois Tigeot 	/*
2980*3f2dd94aSFrançois Tigeot 	 * On BXT+/CNL+ writes larger than 64 bit to the GTT pagetable range
2981*3f2dd94aSFrançois Tigeot 	 * will be dropped. For WC mappings in general we have 64 byte burst
2982*3f2dd94aSFrançois Tigeot 	 * writes when the WC buffer is flushed, so we can't use it, but have to
298319c468b4SFrançois Tigeot 	 * resort to an uncached mapping. The WC issue is easily caught by the
298419c468b4SFrançois Tigeot 	 * readback check when writing GTT PTE entries.
298519c468b4SFrançois Tigeot 	 */
2986*3f2dd94aSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv) || INTEL_GEN(dev_priv) >= 10)
298771f41f3eSFrançois Tigeot 		ggtt->gsm = ioremap_nocache(phys_addr, size);
298819c468b4SFrançois Tigeot 	else
298971f41f3eSFrançois Tigeot 		ggtt->gsm = ioremap_wc(phys_addr, size);
29908621f407SFrançois Tigeot 	if (!ggtt->gsm) {
299171f41f3eSFrançois Tigeot 		DRM_ERROR("Failed to map the ggtt page table\n");
29929edbd4a0SFrançois Tigeot 		return -ENOMEM;
29939edbd4a0SFrançois Tigeot 	}
29949edbd4a0SFrançois Tigeot 
2995a85cb24fSFrançois Tigeot 	ret = setup_scratch_page(&ggtt->base, GFP_DMA32);
29961e12ee3bSFrançois Tigeot 	if (ret) {
29979edbd4a0SFrançois Tigeot 		DRM_ERROR("Scratch setup failed\n");
29989edbd4a0SFrançois Tigeot 		/* iounmap will also get called at remove, but meh */
29998621f407SFrançois Tigeot 		iounmap(ggtt->gsm);
30001e12ee3bSFrançois Tigeot 		return ret;
30019edbd4a0SFrançois Tigeot 	}
30029edbd4a0SFrançois Tigeot 
3003a05eeebfSFrançois Tigeot 	return 0;
30049edbd4a0SFrançois Tigeot }
30059edbd4a0SFrançois Tigeot 
3006*3f2dd94aSFrançois Tigeot static struct intel_ppat_entry *
__alloc_ppat_entry(struct intel_ppat * ppat,unsigned int index,u8 value)3007*3f2dd94aSFrançois Tigeot __alloc_ppat_entry(struct intel_ppat *ppat, unsigned int index, u8 value)
3008*3f2dd94aSFrançois Tigeot {
3009*3f2dd94aSFrançois Tigeot 	struct intel_ppat_entry *entry = &ppat->entries[index];
3010*3f2dd94aSFrançois Tigeot 
3011*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(index >= ppat->max_entries);
3012*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(test_bit(index, ppat->used));
3013*3f2dd94aSFrançois Tigeot 
3014*3f2dd94aSFrançois Tigeot 	entry->ppat = ppat;
3015*3f2dd94aSFrançois Tigeot 	entry->value = value;
3016*3f2dd94aSFrançois Tigeot 	kref_init(&entry->ref);
3017*3f2dd94aSFrançois Tigeot 	set_bit(index, ppat->used);
3018*3f2dd94aSFrançois Tigeot 	set_bit(index, ppat->dirty);
3019*3f2dd94aSFrançois Tigeot 
3020*3f2dd94aSFrançois Tigeot 	return entry;
3021*3f2dd94aSFrançois Tigeot }
3022*3f2dd94aSFrançois Tigeot 
__free_ppat_entry(struct intel_ppat_entry * entry)3023*3f2dd94aSFrançois Tigeot static void __free_ppat_entry(struct intel_ppat_entry *entry)
3024*3f2dd94aSFrançois Tigeot {
3025*3f2dd94aSFrançois Tigeot 	struct intel_ppat *ppat = entry->ppat;
3026*3f2dd94aSFrançois Tigeot 	unsigned int index = entry - ppat->entries;
3027*3f2dd94aSFrançois Tigeot 
3028*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(index >= ppat->max_entries);
3029*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(!test_bit(index, ppat->used));
3030*3f2dd94aSFrançois Tigeot 
3031*3f2dd94aSFrançois Tigeot 	entry->value = ppat->clear_value;
3032*3f2dd94aSFrançois Tigeot 	clear_bit(index, ppat->used);
3033*3f2dd94aSFrançois Tigeot 	set_bit(index, ppat->dirty);
3034*3f2dd94aSFrançois Tigeot }
3035*3f2dd94aSFrançois Tigeot 
3036*3f2dd94aSFrançois Tigeot /**
3037*3f2dd94aSFrançois Tigeot  * intel_ppat_get - get a usable PPAT entry
3038*3f2dd94aSFrançois Tigeot  * @i915: i915 device instance
3039*3f2dd94aSFrançois Tigeot  * @value: the PPAT value required by the caller
3040*3f2dd94aSFrançois Tigeot  *
3041*3f2dd94aSFrançois Tigeot  * The function tries to search if there is an existing PPAT entry which
3042*3f2dd94aSFrançois Tigeot  * matches with the required value. If perfectly matched, the existing PPAT
3043*3f2dd94aSFrançois Tigeot  * entry will be used. If only partially matched, it will try to check if
3044*3f2dd94aSFrançois Tigeot  * there is any available PPAT index. If yes, it will allocate a new PPAT
3045*3f2dd94aSFrançois Tigeot  * index for the required entry and update the HW. If not, the partially
3046*3f2dd94aSFrançois Tigeot  * matched entry will be used.
3047*3f2dd94aSFrançois Tigeot  */
3048*3f2dd94aSFrançois Tigeot const struct intel_ppat_entry *
intel_ppat_get(struct drm_i915_private * i915,u8 value)3049*3f2dd94aSFrançois Tigeot intel_ppat_get(struct drm_i915_private *i915, u8 value)
3050*3f2dd94aSFrançois Tigeot {
3051*3f2dd94aSFrançois Tigeot 	struct intel_ppat *ppat = &i915->ppat;
3052*3f2dd94aSFrançois Tigeot 	struct intel_ppat_entry *entry;
3053*3f2dd94aSFrançois Tigeot 	unsigned int scanned, best_score;
3054*3f2dd94aSFrançois Tigeot 	int i;
3055*3f2dd94aSFrançois Tigeot 
3056*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(!ppat->max_entries);
3057*3f2dd94aSFrançois Tigeot 
3058*3f2dd94aSFrançois Tigeot 	scanned = best_score = 0;
3059*3f2dd94aSFrançois Tigeot 	for_each_set_bit(i, ppat->used, ppat->max_entries) {
3060*3f2dd94aSFrançois Tigeot 		unsigned int score;
3061*3f2dd94aSFrançois Tigeot 
3062*3f2dd94aSFrançois Tigeot 		score = ppat->match(ppat->entries[i].value, value);
3063*3f2dd94aSFrançois Tigeot 		if (score > best_score) {
3064*3f2dd94aSFrançois Tigeot 			entry = &ppat->entries[i];
3065*3f2dd94aSFrançois Tigeot 			if (score == INTEL_PPAT_PERFECT_MATCH) {
3066*3f2dd94aSFrançois Tigeot 				kref_get(&entry->ref);
3067*3f2dd94aSFrançois Tigeot 				return entry;
3068*3f2dd94aSFrançois Tigeot 			}
3069*3f2dd94aSFrançois Tigeot 			best_score = score;
3070*3f2dd94aSFrançois Tigeot 		}
3071*3f2dd94aSFrançois Tigeot 		scanned++;
3072*3f2dd94aSFrançois Tigeot 	}
3073*3f2dd94aSFrançois Tigeot 
3074*3f2dd94aSFrançois Tigeot 	if (scanned == ppat->max_entries) {
3075*3f2dd94aSFrançois Tigeot 		if (!best_score)
3076*3f2dd94aSFrançois Tigeot 			return ERR_PTR(-ENOSPC);
3077*3f2dd94aSFrançois Tigeot 
3078*3f2dd94aSFrançois Tigeot 		kref_get(&entry->ref);
3079*3f2dd94aSFrançois Tigeot 		return entry;
3080*3f2dd94aSFrançois Tigeot 	}
3081*3f2dd94aSFrançois Tigeot 
3082*3f2dd94aSFrançois Tigeot 	i = find_first_zero_bit(ppat->used, ppat->max_entries);
3083*3f2dd94aSFrançois Tigeot 	entry = __alloc_ppat_entry(ppat, i, value);
3084*3f2dd94aSFrançois Tigeot 	ppat->update_hw(i915);
3085*3f2dd94aSFrançois Tigeot 	return entry;
3086*3f2dd94aSFrançois Tigeot }
3087*3f2dd94aSFrançois Tigeot 
release_ppat(struct kref * kref)3088*3f2dd94aSFrançois Tigeot static void release_ppat(struct kref *kref)
3089*3f2dd94aSFrançois Tigeot {
3090*3f2dd94aSFrançois Tigeot 	struct intel_ppat_entry *entry =
3091*3f2dd94aSFrançois Tigeot 		container_of(kref, struct intel_ppat_entry, ref);
3092*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *i915 = entry->ppat->i915;
3093*3f2dd94aSFrançois Tigeot 
3094*3f2dd94aSFrançois Tigeot 	__free_ppat_entry(entry);
3095*3f2dd94aSFrançois Tigeot 	entry->ppat->update_hw(i915);
3096*3f2dd94aSFrançois Tigeot }
3097*3f2dd94aSFrançois Tigeot 
3098*3f2dd94aSFrançois Tigeot /**
3099*3f2dd94aSFrançois Tigeot  * intel_ppat_put - put back the PPAT entry got from intel_ppat_get()
3100*3f2dd94aSFrançois Tigeot  * @entry: an intel PPAT entry
3101*3f2dd94aSFrançois Tigeot  *
3102*3f2dd94aSFrançois Tigeot  * Put back the PPAT entry got from intel_ppat_get(). If the PPAT index of the
3103*3f2dd94aSFrançois Tigeot  * entry is dynamically allocated, its reference count will be decreased. Once
3104*3f2dd94aSFrançois Tigeot  * the reference count becomes into zero, the PPAT index becomes free again.
3105*3f2dd94aSFrançois Tigeot  */
intel_ppat_put(const struct intel_ppat_entry * entry)3106*3f2dd94aSFrançois Tigeot void intel_ppat_put(const struct intel_ppat_entry *entry)
3107*3f2dd94aSFrançois Tigeot {
3108*3f2dd94aSFrançois Tigeot 	struct intel_ppat *ppat = entry->ppat;
3109*3f2dd94aSFrançois Tigeot 	unsigned int index = entry - ppat->entries;
3110*3f2dd94aSFrançois Tigeot 
3111*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(!ppat->max_entries);
3112*3f2dd94aSFrançois Tigeot 
3113*3f2dd94aSFrançois Tigeot 	kref_put(&ppat->entries[index].ref, release_ppat);
3114*3f2dd94aSFrançois Tigeot }
3115*3f2dd94aSFrançois Tigeot 
cnl_private_pat_update_hw(struct drm_i915_private * dev_priv)3116*3f2dd94aSFrançois Tigeot static void cnl_private_pat_update_hw(struct drm_i915_private *dev_priv)
3117*3f2dd94aSFrançois Tigeot {
3118*3f2dd94aSFrançois Tigeot 	struct intel_ppat *ppat = &dev_priv->ppat;
3119*3f2dd94aSFrançois Tigeot 	int i;
3120*3f2dd94aSFrançois Tigeot 
3121*3f2dd94aSFrançois Tigeot 	for_each_set_bit(i, ppat->dirty, ppat->max_entries) {
3122*3f2dd94aSFrançois Tigeot 		I915_WRITE(GEN10_PAT_INDEX(i), ppat->entries[i].value);
3123*3f2dd94aSFrançois Tigeot 		clear_bit(i, ppat->dirty);
3124*3f2dd94aSFrançois Tigeot 	}
3125*3f2dd94aSFrançois Tigeot }
3126*3f2dd94aSFrançois Tigeot 
bdw_private_pat_update_hw(struct drm_i915_private * dev_priv)3127*3f2dd94aSFrançois Tigeot static void bdw_private_pat_update_hw(struct drm_i915_private *dev_priv)
3128*3f2dd94aSFrançois Tigeot {
3129*3f2dd94aSFrançois Tigeot 	struct intel_ppat *ppat = &dev_priv->ppat;
3130*3f2dd94aSFrançois Tigeot 	u64 pat = 0;
3131*3f2dd94aSFrançois Tigeot 	int i;
3132*3f2dd94aSFrançois Tigeot 
3133*3f2dd94aSFrançois Tigeot 	for (i = 0; i < ppat->max_entries; i++)
3134*3f2dd94aSFrançois Tigeot 		pat |= GEN8_PPAT(i, ppat->entries[i].value);
3135*3f2dd94aSFrançois Tigeot 
3136*3f2dd94aSFrançois Tigeot 	bitmap_clear(ppat->dirty, 0, ppat->max_entries);
3137*3f2dd94aSFrançois Tigeot 
3138*3f2dd94aSFrançois Tigeot 	I915_WRITE(GEN8_PRIVATE_PAT_LO, lower_32_bits(pat));
3139*3f2dd94aSFrançois Tigeot 	I915_WRITE(GEN8_PRIVATE_PAT_HI, upper_32_bits(pat));
3140*3f2dd94aSFrançois Tigeot }
3141*3f2dd94aSFrançois Tigeot 
bdw_private_pat_match(u8 src,u8 dst)3142*3f2dd94aSFrançois Tigeot static unsigned int bdw_private_pat_match(u8 src, u8 dst)
3143*3f2dd94aSFrançois Tigeot {
3144*3f2dd94aSFrançois Tigeot 	unsigned int score = 0;
3145*3f2dd94aSFrançois Tigeot 	enum {
3146*3f2dd94aSFrançois Tigeot 		AGE_MATCH = BIT(0),
3147*3f2dd94aSFrançois Tigeot 		TC_MATCH = BIT(1),
3148*3f2dd94aSFrançois Tigeot 		CA_MATCH = BIT(2),
3149*3f2dd94aSFrançois Tigeot 	};
3150*3f2dd94aSFrançois Tigeot 
3151*3f2dd94aSFrançois Tigeot 	/* Cache attribute has to be matched. */
3152*3f2dd94aSFrançois Tigeot 	if (GEN8_PPAT_GET_CA(src) != GEN8_PPAT_GET_CA(dst))
3153*3f2dd94aSFrançois Tigeot 		return 0;
3154*3f2dd94aSFrançois Tigeot 
3155*3f2dd94aSFrançois Tigeot 	score |= CA_MATCH;
3156*3f2dd94aSFrançois Tigeot 
3157*3f2dd94aSFrançois Tigeot 	if (GEN8_PPAT_GET_TC(src) == GEN8_PPAT_GET_TC(dst))
3158*3f2dd94aSFrançois Tigeot 		score |= TC_MATCH;
3159*3f2dd94aSFrançois Tigeot 
3160*3f2dd94aSFrançois Tigeot 	if (GEN8_PPAT_GET_AGE(src) == GEN8_PPAT_GET_AGE(dst))
3161*3f2dd94aSFrançois Tigeot 		score |= AGE_MATCH;
3162*3f2dd94aSFrançois Tigeot 
3163*3f2dd94aSFrançois Tigeot 	if (score == (AGE_MATCH | TC_MATCH | CA_MATCH))
3164*3f2dd94aSFrançois Tigeot 		return INTEL_PPAT_PERFECT_MATCH;
3165*3f2dd94aSFrançois Tigeot 
3166*3f2dd94aSFrançois Tigeot 	return score;
3167*3f2dd94aSFrançois Tigeot }
3168*3f2dd94aSFrançois Tigeot 
chv_private_pat_match(u8 src,u8 dst)3169*3f2dd94aSFrançois Tigeot static unsigned int chv_private_pat_match(u8 src, u8 dst)
3170*3f2dd94aSFrançois Tigeot {
3171*3f2dd94aSFrançois Tigeot 	return (CHV_PPAT_GET_SNOOP(src) == CHV_PPAT_GET_SNOOP(dst)) ?
3172*3f2dd94aSFrançois Tigeot 		INTEL_PPAT_PERFECT_MATCH : 0;
3173*3f2dd94aSFrançois Tigeot }
3174*3f2dd94aSFrançois Tigeot 
cnl_setup_private_ppat(struct intel_ppat * ppat)3175*3f2dd94aSFrançois Tigeot static void cnl_setup_private_ppat(struct intel_ppat *ppat)
3176*3f2dd94aSFrançois Tigeot {
3177*3f2dd94aSFrançois Tigeot 	ppat->max_entries = 8;
3178*3f2dd94aSFrançois Tigeot 	ppat->update_hw = cnl_private_pat_update_hw;
3179*3f2dd94aSFrançois Tigeot 	ppat->match = bdw_private_pat_match;
3180*3f2dd94aSFrançois Tigeot 	ppat->clear_value = GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3);
3181*3f2dd94aSFrançois Tigeot 
3182*3f2dd94aSFrançois Tigeot 	/* XXX: spec is unclear if this is still needed for CNL+ */
3183*3f2dd94aSFrançois Tigeot 	if (!USES_PPGTT(ppat->i915)) {
3184*3f2dd94aSFrançois Tigeot 		__alloc_ppat_entry(ppat, 0, GEN8_PPAT_UC);
3185*3f2dd94aSFrançois Tigeot 		return;
3186*3f2dd94aSFrançois Tigeot 	}
3187*3f2dd94aSFrançois Tigeot 
3188*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 0, GEN8_PPAT_WB | GEN8_PPAT_LLC);
3189*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 1, GEN8_PPAT_WC | GEN8_PPAT_LLCELLC);
3190*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 2, GEN8_PPAT_WT | GEN8_PPAT_LLCELLC);
3191*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 3, GEN8_PPAT_UC);
3192*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 4, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(0));
3193*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 5, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(1));
3194*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 6, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(2));
3195*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 7, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3));
3196*3f2dd94aSFrançois Tigeot }
3197*3f2dd94aSFrançois Tigeot 
31989edbd4a0SFrançois Tigeot /* The GGTT and PPGTT need a private PPAT setup in order to handle cacheability
31999edbd4a0SFrançois Tigeot  * bits. When using advanced contexts each context stores its own PAT, but
32009edbd4a0SFrançois Tigeot  * writing this data shouldn't be harmful even in those cases. */
bdw_setup_private_ppat(struct intel_ppat * ppat)3201*3f2dd94aSFrançois Tigeot static void bdw_setup_private_ppat(struct intel_ppat *ppat)
32029edbd4a0SFrançois Tigeot {
3203*3f2dd94aSFrançois Tigeot 	ppat->max_entries = 8;
3204*3f2dd94aSFrançois Tigeot 	ppat->update_hw = bdw_private_pat_update_hw;
3205*3f2dd94aSFrançois Tigeot 	ppat->match = bdw_private_pat_match;
3206*3f2dd94aSFrançois Tigeot 	ppat->clear_value = GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3);
32079edbd4a0SFrançois Tigeot 
3208*3f2dd94aSFrançois Tigeot 	if (!USES_PPGTT(ppat->i915)) {
3209a6e033d9SFrançois Tigeot 		/* Spec: "For GGTT, there is NO pat_sel[2:0] from the entry,
3210a6e033d9SFrançois Tigeot 		 * so RTL will always use the value corresponding to
3211a6e033d9SFrançois Tigeot 		 * pat_sel = 000".
3212a6e033d9SFrançois Tigeot 		 * So let's disable cache for GGTT to avoid screen corruptions.
3213a6e033d9SFrançois Tigeot 		 * MOCS still can be used though.
3214a6e033d9SFrançois Tigeot 		 * - System agent ggtt writes (i.e. cpu gtt mmaps) already work
3215a6e033d9SFrançois Tigeot 		 * before this patch, i.e. the same uncached + snooping access
3216a6e033d9SFrançois Tigeot 		 * like on gen6/7 seems to be in effect.
3217a6e033d9SFrançois Tigeot 		 * - So this just fixes blitter/render access. Again it looks
3218a6e033d9SFrançois Tigeot 		 * like it's not just uncached access, but uncached + snooping.
3219a6e033d9SFrançois Tigeot 		 * So we can still hold onto all our assumptions wrt cpu
3220a6e033d9SFrançois Tigeot 		 * clflushing on LLC machines.
3221a6e033d9SFrançois Tigeot 		 */
3222*3f2dd94aSFrançois Tigeot 		__alloc_ppat_entry(ppat, 0, GEN8_PPAT_UC);
3223*3f2dd94aSFrançois Tigeot 		return;
32249edbd4a0SFrançois Tigeot 	}
32259edbd4a0SFrançois Tigeot 
3226*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 0, GEN8_PPAT_WB | GEN8_PPAT_LLC);      /* for normal objects, no eLLC */
3227*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 1, GEN8_PPAT_WC | GEN8_PPAT_LLCELLC);  /* for something pointing to ptes? */
3228*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 2, GEN8_PPAT_WT | GEN8_PPAT_LLCELLC);  /* for scanout with eLLC */
3229*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 3, GEN8_PPAT_UC);                      /* Uncached objects, mostly for scanout */
3230*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 4, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(0));
3231*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 5, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(1));
3232*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 6, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(2));
3233*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 7, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3));
3234*3f2dd94aSFrançois Tigeot }
3235*3f2dd94aSFrançois Tigeot 
chv_setup_private_ppat(struct intel_ppat * ppat)3236*3f2dd94aSFrançois Tigeot static void chv_setup_private_ppat(struct intel_ppat *ppat)
3237ba55f2f5SFrançois Tigeot {
3238*3f2dd94aSFrançois Tigeot 	ppat->max_entries = 8;
3239*3f2dd94aSFrançois Tigeot 	ppat->update_hw = bdw_private_pat_update_hw;
3240*3f2dd94aSFrançois Tigeot 	ppat->match = chv_private_pat_match;
3241*3f2dd94aSFrançois Tigeot 	ppat->clear_value = CHV_PPAT_SNOOP;
3242ba55f2f5SFrançois Tigeot 
3243ba55f2f5SFrançois Tigeot 	/*
3244ba55f2f5SFrançois Tigeot 	 * Map WB on BDW to snooped on CHV.
3245ba55f2f5SFrançois Tigeot 	 *
3246ba55f2f5SFrançois Tigeot 	 * Only the snoop bit has meaning for CHV, the rest is
3247ba55f2f5SFrançois Tigeot 	 * ignored.
3248ba55f2f5SFrançois Tigeot 	 *
32492c9916cdSFrançois Tigeot 	 * The hardware will never snoop for certain types of accesses:
32502c9916cdSFrançois Tigeot 	 * - CPU GTT (GMADR->GGTT->no snoop->memory)
32512c9916cdSFrançois Tigeot 	 * - PPGTT page tables
32522c9916cdSFrançois Tigeot 	 * - some other special cycles
32532c9916cdSFrançois Tigeot 	 *
32542c9916cdSFrançois Tigeot 	 * As with BDW, we also need to consider the following for GT accesses:
32552c9916cdSFrançois Tigeot 	 * "For GGTT, there is NO pat_sel[2:0] from the entry,
32562c9916cdSFrançois Tigeot 	 * so RTL will always use the value corresponding to
32572c9916cdSFrançois Tigeot 	 * pat_sel = 000".
32582c9916cdSFrançois Tigeot 	 * Which means we must set the snoop bit in PAT entry 0
32592c9916cdSFrançois Tigeot 	 * in order to keep the global status page working.
3260ba55f2f5SFrançois Tigeot 	 */
3261ba55f2f5SFrançois Tigeot 
3262*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 0, CHV_PPAT_SNOOP);
3263*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 1, 0);
3264*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 2, 0);
3265*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 3, 0);
3266*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 4, CHV_PPAT_SNOOP);
3267*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 5, CHV_PPAT_SNOOP);
3268*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 6, CHV_PPAT_SNOOP);
3269*3f2dd94aSFrançois Tigeot 	__alloc_ppat_entry(ppat, 7, CHV_PPAT_SNOOP);
3270ba55f2f5SFrançois Tigeot }
3271ba55f2f5SFrançois Tigeot 
gen6_gmch_remove(struct i915_address_space * vm)327271f41f3eSFrançois Tigeot static void gen6_gmch_remove(struct i915_address_space *vm)
32739edbd4a0SFrançois Tigeot {
327471f41f3eSFrançois Tigeot 	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
32759edbd4a0SFrançois Tigeot 
327671f41f3eSFrançois Tigeot 	iounmap(ggtt->gsm);
3277a85cb24fSFrançois Tigeot 	cleanup_scratch_page(vm);
3278ba55f2f5SFrançois Tigeot }
3279ba55f2f5SFrançois Tigeot 
setup_private_pat(struct drm_i915_private * dev_priv)3280*3f2dd94aSFrançois Tigeot static void setup_private_pat(struct drm_i915_private *dev_priv)
3281*3f2dd94aSFrançois Tigeot {
3282*3f2dd94aSFrançois Tigeot 	struct intel_ppat *ppat = &dev_priv->ppat;
3283*3f2dd94aSFrançois Tigeot 	int i;
3284*3f2dd94aSFrançois Tigeot 
3285*3f2dd94aSFrançois Tigeot 	ppat->i915 = dev_priv;
3286*3f2dd94aSFrançois Tigeot 
3287*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 10)
3288*3f2dd94aSFrançois Tigeot 		cnl_setup_private_ppat(ppat);
3289*3f2dd94aSFrançois Tigeot 	else if (IS_CHERRYVIEW(dev_priv) || IS_GEN9_LP(dev_priv))
3290*3f2dd94aSFrançois Tigeot 		chv_setup_private_ppat(ppat);
3291*3f2dd94aSFrançois Tigeot 	else
3292*3f2dd94aSFrançois Tigeot 		bdw_setup_private_ppat(ppat);
3293*3f2dd94aSFrançois Tigeot 
3294*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(ppat->max_entries > INTEL_MAX_PPAT_ENTRIES);
3295*3f2dd94aSFrançois Tigeot 
3296*3f2dd94aSFrançois Tigeot 	for_each_clear_bit(i, ppat->used, ppat->max_entries) {
3297*3f2dd94aSFrançois Tigeot 		ppat->entries[i].value = ppat->clear_value;
3298*3f2dd94aSFrançois Tigeot 		ppat->entries[i].ppat = ppat;
3299*3f2dd94aSFrançois Tigeot 		set_bit(i, ppat->dirty);
3300*3f2dd94aSFrançois Tigeot 	}
3301*3f2dd94aSFrançois Tigeot 
3302*3f2dd94aSFrançois Tigeot 	ppat->update_hw(dev_priv);
3303*3f2dd94aSFrançois Tigeot }
3304*3f2dd94aSFrançois Tigeot 
gen8_gmch_probe(struct i915_ggtt * ggtt)330571f41f3eSFrançois Tigeot static int gen8_gmch_probe(struct i915_ggtt *ggtt)
330671f41f3eSFrançois Tigeot {
3307a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = ggtt->base.i915;
330871f41f3eSFrançois Tigeot 	struct pci_dev *pdev = dev_priv->drm.pdev;
330971f41f3eSFrançois Tigeot 	unsigned int size;
331071f41f3eSFrançois Tigeot 	u16 snb_gmch_ctl;
3311*3f2dd94aSFrançois Tigeot 	int err;
33129edbd4a0SFrançois Tigeot 
331371f41f3eSFrançois Tigeot 	/* TODO: We're not aware of mappable constraints on gen8 yet */
331471f41f3eSFrançois Tigeot 	ggtt->mappable_base = pci_resource_start(pdev, 2);
331571f41f3eSFrançois Tigeot 	ggtt->mappable_end = pci_resource_len(pdev, 2);
331671f41f3eSFrançois Tigeot 
3317*3f2dd94aSFrançois Tigeot 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(39));
3318*3f2dd94aSFrançois Tigeot 	if (!err)
3319*3f2dd94aSFrançois Tigeot 		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(39));
3320*3f2dd94aSFrançois Tigeot 	if (err)
3321*3f2dd94aSFrançois Tigeot 		DRM_ERROR("Can't set DMA mask/consistent mask (%d)\n", err);
332271f41f3eSFrançois Tigeot 
332371f41f3eSFrançois Tigeot 	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
332471f41f3eSFrançois Tigeot 
332571f41f3eSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
332671f41f3eSFrançois Tigeot 		ggtt->stolen_size = gen9_get_stolen_size(snb_gmch_ctl);
332771f41f3eSFrançois Tigeot 		size = gen8_get_total_gtt_size(snb_gmch_ctl);
332871f41f3eSFrançois Tigeot 	} else if (IS_CHERRYVIEW(dev_priv)) {
332971f41f3eSFrançois Tigeot 		ggtt->stolen_size = chv_get_stolen_size(snb_gmch_ctl);
333071f41f3eSFrançois Tigeot 		size = chv_get_total_gtt_size(snb_gmch_ctl);
333171f41f3eSFrançois Tigeot 	} else {
333271f41f3eSFrançois Tigeot 		ggtt->stolen_size = gen8_get_stolen_size(snb_gmch_ctl);
333371f41f3eSFrançois Tigeot 		size = gen8_get_total_gtt_size(snb_gmch_ctl);
333471f41f3eSFrançois Tigeot 	}
333571f41f3eSFrançois Tigeot 
333671f41f3eSFrançois Tigeot 	ggtt->base.total = (size / sizeof(gen8_pte_t)) << PAGE_SHIFT;
333771f41f3eSFrançois Tigeot 	ggtt->base.cleanup = gen6_gmch_remove;
33388621f407SFrançois Tigeot 	ggtt->base.bind_vma = ggtt_bind_vma;
33398621f407SFrançois Tigeot 	ggtt->base.unbind_vma = ggtt_unbind_vma;
3340*3f2dd94aSFrançois Tigeot 	ggtt->base.set_pages = ggtt_set_pages;
3341*3f2dd94aSFrançois Tigeot 	ggtt->base.clear_pages = clear_pages;
33421487f786SFrançois Tigeot 	ggtt->base.insert_page = gen8_ggtt_insert_page;
33431487f786SFrançois Tigeot 	ggtt->base.clear_range = nop_clear_range;
3344303bf270SFrançois Tigeot 	if (!USES_FULL_PPGTT(dev_priv) || intel_scanout_needs_vtd_wa(dev_priv))
33451487f786SFrançois Tigeot 		ggtt->base.clear_range = gen8_ggtt_clear_range;
33461487f786SFrançois Tigeot 
33471487f786SFrançois Tigeot 	ggtt->base.insert_entries = gen8_ggtt_insert_entries;
3348a85cb24fSFrançois Tigeot 
3349a85cb24fSFrançois Tigeot 	/* Serialize GTT updates with aperture access on BXT if VT-d is on. */
3350a85cb24fSFrançois Tigeot 	if (intel_ggtt_update_needs_vtd_wa(dev_priv)) {
3351a85cb24fSFrançois Tigeot 		ggtt->base.insert_entries = bxt_vtd_ggtt_insert_entries__BKL;
3352a85cb24fSFrançois Tigeot 		ggtt->base.insert_page    = bxt_vtd_ggtt_insert_page__BKL;
3353a85cb24fSFrançois Tigeot 		if (ggtt->base.clear_range != nop_clear_range)
3354a85cb24fSFrançois Tigeot 			ggtt->base.clear_range = bxt_vtd_ggtt_clear_range__BKL;
3355a85cb24fSFrançois Tigeot 	}
3356a85cb24fSFrançois Tigeot 
3357*3f2dd94aSFrançois Tigeot 	/* Serialize GTT updates with aperture access on BXT if VT-d is on. */
3358*3f2dd94aSFrançois Tigeot 	if (intel_ggtt_update_needs_vtd_wa(dev_priv)) {
3359*3f2dd94aSFrançois Tigeot 		ggtt->base.insert_entries = bxt_vtd_ggtt_insert_entries__BKL;
3360*3f2dd94aSFrançois Tigeot 		ggtt->base.insert_page    = bxt_vtd_ggtt_insert_page__BKL;
3361*3f2dd94aSFrançois Tigeot 		if (ggtt->base.clear_range != nop_clear_range)
3362*3f2dd94aSFrançois Tigeot 			ggtt->base.clear_range = bxt_vtd_ggtt_clear_range__BKL;
3363*3f2dd94aSFrançois Tigeot 	}
3364*3f2dd94aSFrançois Tigeot 
3365a85cb24fSFrançois Tigeot 	ggtt->invalidate = gen6_ggtt_invalidate;
3366aee94f86SFrançois Tigeot 
3367*3f2dd94aSFrançois Tigeot 	setup_private_pat(dev_priv);
3368*3f2dd94aSFrançois Tigeot 
336971f41f3eSFrançois Tigeot 	return ggtt_probe_common(ggtt, size);
33709edbd4a0SFrançois Tigeot }
33719edbd4a0SFrançois Tigeot 
gen6_gmch_probe(struct i915_ggtt * ggtt)33728621f407SFrançois Tigeot static int gen6_gmch_probe(struct i915_ggtt *ggtt)
33735d0b1887SFrançois Tigeot {
3374a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = ggtt->base.i915;
337571f41f3eSFrançois Tigeot 	struct pci_dev *pdev = dev_priv->drm.pdev;
337671f41f3eSFrançois Tigeot 	unsigned int size;
33775d0b1887SFrançois Tigeot 	u16 snb_gmch_ctl;
3378*3f2dd94aSFrançois Tigeot 	int err;
33795d0b1887SFrançois Tigeot 
338071f41f3eSFrançois Tigeot 	ggtt->mappable_base = pci_resource_start(pdev, 2);
338171f41f3eSFrançois Tigeot 	ggtt->mappable_end = pci_resource_len(pdev, 2);
33825d0b1887SFrançois Tigeot 
33835d0b1887SFrançois Tigeot 	/* 64/512MB is the current min/max we actually know of, but this is just
33845d0b1887SFrançois Tigeot 	 * a coarse sanity check.
33855d0b1887SFrançois Tigeot 	 */
338671f41f3eSFrançois Tigeot 	if (ggtt->mappable_end < (64<<20) || ggtt->mappable_end > (512<<20)) {
33878621f407SFrançois Tigeot 		DRM_ERROR("Unknown GMADR size (%llx)\n", ggtt->mappable_end);
33885d0b1887SFrançois Tigeot 		return -ENXIO;
33895d0b1887SFrançois Tigeot 	}
33905d0b1887SFrançois Tigeot 
3391*3f2dd94aSFrançois Tigeot 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
3392*3f2dd94aSFrançois Tigeot 	if (!err)
3393*3f2dd94aSFrançois Tigeot 		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
3394*3f2dd94aSFrançois Tigeot 	if (err)
3395*3f2dd94aSFrançois Tigeot 		DRM_ERROR("Can't set DMA mask/consistent mask (%d)\n", err);
339671f41f3eSFrançois Tigeot 	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
33975d0b1887SFrançois Tigeot 
33988621f407SFrançois Tigeot 	ggtt->stolen_size = gen6_get_stolen_size(snb_gmch_ctl);
33995d0b1887SFrançois Tigeot 
340071f41f3eSFrançois Tigeot 	size = gen6_get_total_gtt_size(snb_gmch_ctl);
340171f41f3eSFrançois Tigeot 	ggtt->base.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT;
34025d0b1887SFrançois Tigeot 
34038621f407SFrançois Tigeot 	ggtt->base.clear_range = gen6_ggtt_clear_range;
34041487f786SFrançois Tigeot 	ggtt->base.insert_page = gen6_ggtt_insert_page;
34058621f407SFrançois Tigeot 	ggtt->base.insert_entries = gen6_ggtt_insert_entries;
34068621f407SFrançois Tigeot 	ggtt->base.bind_vma = ggtt_bind_vma;
34078621f407SFrançois Tigeot 	ggtt->base.unbind_vma = ggtt_unbind_vma;
3408*3f2dd94aSFrançois Tigeot 	ggtt->base.set_pages = ggtt_set_pages;
3409*3f2dd94aSFrançois Tigeot 	ggtt->base.clear_pages = clear_pages;
341071f41f3eSFrançois Tigeot 	ggtt->base.cleanup = gen6_gmch_remove;
34119edbd4a0SFrançois Tigeot 
3412a85cb24fSFrançois Tigeot 	ggtt->invalidate = gen6_ggtt_invalidate;
3413a85cb24fSFrançois Tigeot 
341471f41f3eSFrançois Tigeot 	if (HAS_EDRAM(dev_priv))
341571f41f3eSFrançois Tigeot 		ggtt->base.pte_encode = iris_pte_encode;
341671f41f3eSFrançois Tigeot 	else if (IS_HASWELL(dev_priv))
341771f41f3eSFrançois Tigeot 		ggtt->base.pte_encode = hsw_pte_encode;
341871f41f3eSFrançois Tigeot 	else if (IS_VALLEYVIEW(dev_priv))
341971f41f3eSFrançois Tigeot 		ggtt->base.pte_encode = byt_pte_encode;
342071f41f3eSFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 7)
342171f41f3eSFrançois Tigeot 		ggtt->base.pte_encode = ivb_pte_encode;
342271f41f3eSFrançois Tigeot 	else
342371f41f3eSFrançois Tigeot 		ggtt->base.pte_encode = snb_pte_encode;
342471f41f3eSFrançois Tigeot 
342571f41f3eSFrançois Tigeot 	return ggtt_probe_common(ggtt, size);
34265d0b1887SFrançois Tigeot }
34275d0b1887SFrançois Tigeot 
i915_gmch_remove(struct i915_address_space * vm)342871f41f3eSFrançois Tigeot static void i915_gmch_remove(struct i915_address_space *vm)
34295d0b1887SFrançois Tigeot {
343071f41f3eSFrançois Tigeot 	intel_gmch_remove();
34319edbd4a0SFrançois Tigeot }
34325d0b1887SFrançois Tigeot 
i915_gmch_probe(struct i915_ggtt * ggtt)34338621f407SFrançois Tigeot static int i915_gmch_probe(struct i915_ggtt *ggtt)
34345d0b1887SFrançois Tigeot {
3435a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = ggtt->base.i915;
34369edbd4a0SFrançois Tigeot #if 0
34379edbd4a0SFrançois Tigeot 	int ret;
34389edbd4a0SFrançois Tigeot 
3439303bf270SFrançois Tigeot 	ret = intel_gmch_probe(dev_priv->bridge_dev, dev_priv->drm.pdev, NULL);
34409edbd4a0SFrançois Tigeot 	if (!ret) {
34419edbd4a0SFrançois Tigeot 		DRM_ERROR("failed to set up gmch\n");
34429edbd4a0SFrançois Tigeot 		return -EIO;
34439edbd4a0SFrançois Tigeot 	}
34449edbd4a0SFrançois Tigeot #endif
34459edbd4a0SFrançois Tigeot 
3446a85cb24fSFrançois Tigeot 	intel_gtt_get(&ggtt->base.total,
3447a85cb24fSFrançois Tigeot 		      &ggtt->stolen_size,
3448a85cb24fSFrançois Tigeot 		      &ggtt->mappable_base,
3449a85cb24fSFrançois Tigeot 		      &ggtt->mappable_end);
34509edbd4a0SFrançois Tigeot 
345171f41f3eSFrançois Tigeot 	ggtt->do_idle_maps = needs_idle_maps(dev_priv);
34521487f786SFrançois Tigeot 	ggtt->base.insert_page = i915_ggtt_insert_page;
34538621f407SFrançois Tigeot 	ggtt->base.insert_entries = i915_ggtt_insert_entries;
34548621f407SFrançois Tigeot 	ggtt->base.clear_range = i915_ggtt_clear_range;
34558621f407SFrançois Tigeot 	ggtt->base.bind_vma = ggtt_bind_vma;
34568621f407SFrançois Tigeot 	ggtt->base.unbind_vma = ggtt_unbind_vma;
3457*3f2dd94aSFrançois Tigeot 	ggtt->base.set_pages = ggtt_set_pages;
3458*3f2dd94aSFrançois Tigeot 	ggtt->base.clear_pages = clear_pages;
345971f41f3eSFrançois Tigeot 	ggtt->base.cleanup = i915_gmch_remove;
34609edbd4a0SFrançois Tigeot 
3461a85cb24fSFrançois Tigeot 	ggtt->invalidate = gmch_ggtt_invalidate;
3462a85cb24fSFrançois Tigeot 
34638621f407SFrançois Tigeot 	if (unlikely(ggtt->do_idle_maps))
34649edbd4a0SFrançois Tigeot 		DRM_INFO("applying Ironlake quirks for intel_iommu\n");
34659edbd4a0SFrançois Tigeot 
34665d0b1887SFrançois Tigeot 	return 0;
34675d0b1887SFrançois Tigeot }
34685d0b1887SFrançois Tigeot 
34698621f407SFrançois Tigeot /**
347071f41f3eSFrançois Tigeot  * i915_ggtt_probe_hw - Probe GGTT hardware location
347171f41f3eSFrançois Tigeot  * @dev_priv: i915 device
34728621f407SFrançois Tigeot  */
i915_ggtt_probe_hw(struct drm_i915_private * dev_priv)347371f41f3eSFrançois Tigeot int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv)
34740b869d8aSFrançois Tigeot {
34758621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
34769edbd4a0SFrançois Tigeot 	int ret;
34770b869d8aSFrançois Tigeot 
3478a85cb24fSFrançois Tigeot 	ggtt->base.i915 = dev_priv;
3479a85cb24fSFrançois Tigeot 	ggtt->base.dma = &dev_priv->drm.pdev->dev;
34808621f407SFrançois Tigeot 
348171f41f3eSFrançois Tigeot 	if (INTEL_GEN(dev_priv) <= 5)
348271f41f3eSFrançois Tigeot 		ret = i915_gmch_probe(ggtt);
348371f41f3eSFrançois Tigeot 	else if (INTEL_GEN(dev_priv) < 8)
348471f41f3eSFrançois Tigeot 		ret = gen6_gmch_probe(ggtt);
34859edbd4a0SFrançois Tigeot 	else
348671f41f3eSFrançois Tigeot 		ret = gen8_gmch_probe(ggtt);
34879edbd4a0SFrançois Tigeot 	if (ret)
34889edbd4a0SFrançois Tigeot 		return ret;
34890b869d8aSFrançois Tigeot 
3490a85cb24fSFrançois Tigeot 	/* Trim the GGTT to fit the GuC mappable upper range (when enabled).
3491a85cb24fSFrançois Tigeot 	 * This is easier than doing range restriction on the fly, as we
3492a85cb24fSFrançois Tigeot 	 * currently don't have any bits spare to pass in this upper
3493a85cb24fSFrançois Tigeot 	 * restriction!
3494a85cb24fSFrançois Tigeot 	 */
3495*3f2dd94aSFrançois Tigeot 	if (HAS_GUC(dev_priv) && i915_modparams.enable_guc_loading) {
3496a85cb24fSFrançois Tigeot 		ggtt->base.total = min_t(u64, ggtt->base.total, GUC_GGTT_TOP);
3497a85cb24fSFrançois Tigeot 		ggtt->mappable_end = min(ggtt->mappable_end, ggtt->base.total);
3498a85cb24fSFrançois Tigeot 	}
3499a85cb24fSFrançois Tigeot 
35008621f407SFrançois Tigeot 	if ((ggtt->base.total - 1) >> 32) {
35018621f407SFrançois Tigeot 		DRM_ERROR("We never expected a Global GTT with more than 32bits"
35028621f407SFrançois Tigeot 			  " of address space! Found %lldM!\n",
35038621f407SFrançois Tigeot 			  ggtt->base.total >> 20);
35048621f407SFrançois Tigeot 		ggtt->base.total = 1ULL << 32;
35058621f407SFrançois Tigeot 		ggtt->mappable_end = min(ggtt->mappable_end, ggtt->base.total);
35068621f407SFrançois Tigeot 	}
35078621f407SFrançois Tigeot 
350871f41f3eSFrançois Tigeot 	if (ggtt->mappable_end > ggtt->base.total) {
350971f41f3eSFrançois Tigeot 		DRM_ERROR("mappable aperture extends past end of GGTT,"
351071f41f3eSFrançois Tigeot 			  " aperture=%llx, total=%llx\n",
351171f41f3eSFrançois Tigeot 			  ggtt->mappable_end, ggtt->base.total);
351271f41f3eSFrançois Tigeot 		ggtt->mappable_end = ggtt->base.total;
351371f41f3eSFrançois Tigeot 	}
3514c0e85e96SFrançois Tigeot 
35155d0b1887SFrançois Tigeot 	/* GMADR is the PCI mmio aperture into the global GTT. */
3516f77dbd6cSFrançois Tigeot 	DRM_INFO("Memory usable by graphics device = %lluM\n",
35178621f407SFrançois Tigeot 		 ggtt->base.total >> 20);
35188621f407SFrançois Tigeot 	DRM_DEBUG_DRIVER("GMADR size = %lldM\n", ggtt->mappable_end >> 20);
3519a85cb24fSFrançois Tigeot 	DRM_DEBUG_DRIVER("GTT stolen size = %uM\n", ggtt->stolen_size >> 20);
3520*3f2dd94aSFrançois Tigeot 	if (intel_vtd_active())
3521ba55f2f5SFrançois Tigeot 		DRM_INFO("VT-d active for gfx access\n");
3522a2fdbec6SFrançois Tigeot 
35230b869d8aSFrançois Tigeot 	return 0;
352471f41f3eSFrançois Tigeot }
352571f41f3eSFrançois Tigeot 
352671f41f3eSFrançois Tigeot /**
352771f41f3eSFrançois Tigeot  * i915_ggtt_init_hw - Initialize GGTT hardware
352871f41f3eSFrançois Tigeot  * @dev_priv: i915 device
352971f41f3eSFrançois Tigeot  */
i915_ggtt_init_hw(struct drm_i915_private * dev_priv)353071f41f3eSFrançois Tigeot int i915_ggtt_init_hw(struct drm_i915_private *dev_priv)
353171f41f3eSFrançois Tigeot {
353271f41f3eSFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
353371f41f3eSFrançois Tigeot 	int ret;
353471f41f3eSFrançois Tigeot 
353571f41f3eSFrançois Tigeot 	INIT_LIST_HEAD(&dev_priv->vm_list);
353671f41f3eSFrançois Tigeot 
3537a85cb24fSFrançois Tigeot 	/* Note that we use page colouring to enforce a guard page at the
3538a85cb24fSFrançois Tigeot 	 * end of the address space. This is required as the CS may prefetch
3539a85cb24fSFrançois Tigeot 	 * beyond the end of the batch buffer, across the page boundary,
3540a85cb24fSFrançois Tigeot 	 * and beyond the end of the GTT if we do not provide a guard.
354171f41f3eSFrançois Tigeot 	 */
35424be47400SFrançois Tigeot 	mutex_lock(&dev_priv->drm.struct_mutex);
35434be47400SFrançois Tigeot 	i915_address_space_init(&ggtt->base, dev_priv, "[global]");
3544a85cb24fSFrançois Tigeot 	if (!HAS_LLC(dev_priv) && !USES_PPGTT(dev_priv))
354571f41f3eSFrançois Tigeot 		ggtt->base.mm.color_adjust = i915_gtt_color_adjust;
35464be47400SFrançois Tigeot 	mutex_unlock(&dev_priv->drm.struct_mutex);
354771f41f3eSFrançois Tigeot 
35481e12ee3bSFrançois Tigeot 	if (!io_mapping_init_wc(&dev_priv->ggtt.mappable,
35491e12ee3bSFrançois Tigeot 				dev_priv->ggtt.mappable_base,
35501e12ee3bSFrançois Tigeot 				dev_priv->ggtt.mappable_end)) {
355171f41f3eSFrançois Tigeot 		ret = -EIO;
355271f41f3eSFrançois Tigeot 		goto out_gtt_cleanup;
355371f41f3eSFrançois Tigeot 	}
355471f41f3eSFrançois Tigeot 
355571f41f3eSFrançois Tigeot 	ggtt->mtrr = arch_phys_wc_add(ggtt->mappable_base, ggtt->mappable_end);
355671f41f3eSFrançois Tigeot 
355771f41f3eSFrançois Tigeot 	/*
355871f41f3eSFrançois Tigeot 	 * Initialise stolen early so that we may reserve preallocated
355971f41f3eSFrançois Tigeot 	 * objects for the BIOS to KMS transition.
356071f41f3eSFrançois Tigeot 	 */
35614be47400SFrançois Tigeot 	ret = i915_gem_init_stolen(dev_priv);
356271f41f3eSFrançois Tigeot 	if (ret)
356371f41f3eSFrançois Tigeot 		goto out_gtt_cleanup;
356471f41f3eSFrançois Tigeot 
356571f41f3eSFrançois Tigeot 	return 0;
3566c0e85e96SFrançois Tigeot 
3567c0e85e96SFrançois Tigeot out_gtt_cleanup:
35688621f407SFrançois Tigeot 	ggtt->base.cleanup(&ggtt->base);
3569c0e85e96SFrançois Tigeot 	return ret;
35700b869d8aSFrançois Tigeot }
3571ba55f2f5SFrançois Tigeot 
i915_ggtt_enable_hw(struct drm_i915_private * dev_priv)357271f41f3eSFrançois Tigeot int i915_ggtt_enable_hw(struct drm_i915_private *dev_priv)
35738621f407SFrançois Tigeot {
357471f41f3eSFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 6 && !intel_enable_gtt())
35758621f407SFrançois Tigeot 		return -EIO;
35768621f407SFrançois Tigeot 
35778621f407SFrançois Tigeot 	return 0;
35788621f407SFrançois Tigeot }
35798621f407SFrançois Tigeot 
i915_ggtt_enable_guc(struct drm_i915_private * i915)3580a85cb24fSFrançois Tigeot void i915_ggtt_enable_guc(struct drm_i915_private *i915)
3581a85cb24fSFrançois Tigeot {
3582*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(i915->ggtt.invalidate != gen6_ggtt_invalidate);
3583*3f2dd94aSFrançois Tigeot 
3584a85cb24fSFrançois Tigeot 	i915->ggtt.invalidate = guc_ggtt_invalidate;
3585a85cb24fSFrançois Tigeot }
3586a85cb24fSFrançois Tigeot 
i915_ggtt_disable_guc(struct drm_i915_private * i915)3587a85cb24fSFrançois Tigeot void i915_ggtt_disable_guc(struct drm_i915_private *i915)
3588a85cb24fSFrançois Tigeot {
3589*3f2dd94aSFrançois Tigeot 	/* We should only be called after i915_ggtt_enable_guc() */
3590*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(i915->ggtt.invalidate != guc_ggtt_invalidate);
3591*3f2dd94aSFrançois Tigeot 
3592a85cb24fSFrançois Tigeot 	i915->ggtt.invalidate = gen6_ggtt_invalidate;
3593a85cb24fSFrançois Tigeot }
3594a85cb24fSFrançois Tigeot 
i915_gem_restore_gtt_mappings(struct drm_i915_private * dev_priv)35954be47400SFrançois Tigeot void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
359619c468b4SFrançois Tigeot {
35978621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
35981e12ee3bSFrançois Tigeot 	struct drm_i915_gem_object *obj, *on;
359919c468b4SFrançois Tigeot 
36001487f786SFrançois Tigeot 	i915_check_and_clear_faults(dev_priv);
360119c468b4SFrançois Tigeot 
360219c468b4SFrançois Tigeot 	/* First fill our portion of the GTT with scratch pages */
3603a85cb24fSFrançois Tigeot 	ggtt->base.clear_range(&ggtt->base, 0, ggtt->base.total);
360419c468b4SFrançois Tigeot 
36051e12ee3bSFrançois Tigeot 	ggtt->base.closed = true; /* skip rewriting PTE on VMA unbind */
36061e12ee3bSFrançois Tigeot 
36071e12ee3bSFrançois Tigeot 	/* clflush objects bound into the GGTT and rebind them. */
3608*3f2dd94aSFrançois Tigeot 	list_for_each_entry_safe(obj, on, &dev_priv->mm.bound_list, mm.link) {
36091e12ee3bSFrançois Tigeot 		bool ggtt_bound = false;
36101e12ee3bSFrançois Tigeot 		struct i915_vma *vma;
36111e12ee3bSFrançois Tigeot 
3612c0e85e96SFrançois Tigeot 		list_for_each_entry(vma, &obj->vma_list, obj_link) {
36138621f407SFrançois Tigeot 			if (vma->vm != &ggtt->base)
361419c468b4SFrançois Tigeot 				continue;
361519c468b4SFrançois Tigeot 
36161e12ee3bSFrançois Tigeot 			if (!i915_vma_unbind(vma))
36171e12ee3bSFrançois Tigeot 				continue;
36181e12ee3bSFrançois Tigeot 
3619056b1c44SFrançois Tigeot 			WARN_ON(i915_vma_bind(vma, obj->cache_level,
3620056b1c44SFrançois Tigeot 					      PIN_UPDATE));
36211e12ee3bSFrançois Tigeot 			ggtt_bound = true;
362219c468b4SFrançois Tigeot 		}
362319c468b4SFrançois Tigeot 
36241e12ee3bSFrançois Tigeot 		if (ggtt_bound)
36251487f786SFrançois Tigeot 			WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false));
3626056b1c44SFrançois Tigeot 	}
3627a05eeebfSFrançois Tigeot 
36281e12ee3bSFrançois Tigeot 	ggtt->base.closed = false;
36291e12ee3bSFrançois Tigeot 
36304be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
3631*3f2dd94aSFrançois Tigeot 		struct intel_ppat *ppat = &dev_priv->ppat;
363219c468b4SFrançois Tigeot 
3633*3f2dd94aSFrançois Tigeot 		bitmap_set(ppat->dirty, 0, ppat->max_entries);
3634*3f2dd94aSFrançois Tigeot 		dev_priv->ppat.update_hw(dev_priv);
363519c468b4SFrançois Tigeot 		return;
363619c468b4SFrançois Tigeot 	}
363719c468b4SFrançois Tigeot 
36384be47400SFrançois Tigeot 	if (USES_PPGTT(dev_priv)) {
36398621f407SFrançois Tigeot 		struct i915_address_space *vm;
36408621f407SFrançois Tigeot 
364119c468b4SFrançois Tigeot 		list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
36428621f407SFrançois Tigeot 			struct i915_hw_ppgtt *ppgtt;
364319c468b4SFrançois Tigeot 
364471f41f3eSFrançois Tigeot 			if (i915_is_ggtt(vm))
364519c468b4SFrançois Tigeot 				ppgtt = dev_priv->mm.aliasing_ppgtt;
36468621f407SFrançois Tigeot 			else
36478621f407SFrançois Tigeot 				ppgtt = i915_vm_to_ppgtt(vm);
364819c468b4SFrançois Tigeot 
3649a85cb24fSFrançois Tigeot 			gen6_write_page_range(ppgtt, 0, ppgtt->base.total);
365019c468b4SFrançois Tigeot 		}
365119c468b4SFrançois Tigeot 	}
365219c468b4SFrançois Tigeot 
3653a85cb24fSFrançois Tigeot 	i915_ggtt_invalidate(dev_priv);
3654477eb7f9SFrançois Tigeot }
3655477eb7f9SFrançois Tigeot 
3656352ff8bdSFrançois Tigeot static struct scatterlist *
rotate_pages(const dma_addr_t * in,unsigned int offset,unsigned int width,unsigned int height,unsigned int stride,struct sg_table * st,struct scatterlist * sg)3657c0e85e96SFrançois Tigeot rotate_pages(const dma_addr_t *in, unsigned int offset,
3658352ff8bdSFrançois Tigeot 	     unsigned int width, unsigned int height,
3659c0e85e96SFrançois Tigeot 	     unsigned int stride,
3660352ff8bdSFrançois Tigeot 	     struct sg_table *st, struct scatterlist *sg)
3661477eb7f9SFrançois Tigeot {
3662477eb7f9SFrançois Tigeot 	unsigned int column, row;
3663477eb7f9SFrançois Tigeot 	unsigned int src_idx;
3664477eb7f9SFrançois Tigeot 
3665477eb7f9SFrançois Tigeot 	for (column = 0; column < width; column++) {
3666c0e85e96SFrançois Tigeot 		src_idx = stride * (height - 1) + column;
3667477eb7f9SFrançois Tigeot 		for (row = 0; row < height; row++) {
3668477eb7f9SFrançois Tigeot 			st->nents++;
3669477eb7f9SFrançois Tigeot 			/* We don't need the pages, but need to initialize
3670477eb7f9SFrançois Tigeot 			 * the entries so the sg list can be happily traversed.
3671477eb7f9SFrançois Tigeot 			 * The only thing we need are DMA addresses.
3672477eb7f9SFrançois Tigeot 			 */
3673477eb7f9SFrançois Tigeot 			sg_set_page(sg, NULL, PAGE_SIZE, 0);
3674352ff8bdSFrançois Tigeot 			sg_dma_address(sg) = in[offset + src_idx];
3675477eb7f9SFrançois Tigeot 			sg_dma_len(sg) = PAGE_SIZE;
3676477eb7f9SFrançois Tigeot 			sg = sg_next(sg);
3677c0e85e96SFrançois Tigeot 			src_idx -= stride;
3678477eb7f9SFrançois Tigeot 		}
3679477eb7f9SFrançois Tigeot 	}
3680352ff8bdSFrançois Tigeot 
3681352ff8bdSFrançois Tigeot 	return sg;
3682477eb7f9SFrançois Tigeot }
3683477eb7f9SFrançois Tigeot 
3684a85cb24fSFrançois Tigeot static noinline struct sg_table *
intel_rotate_pages(struct intel_rotation_info * rot_info,struct drm_i915_gem_object * obj)3685a85cb24fSFrançois Tigeot intel_rotate_pages(struct intel_rotation_info *rot_info,
3686477eb7f9SFrançois Tigeot 		   struct drm_i915_gem_object *obj)
3687477eb7f9SFrançois Tigeot {
3688a85cb24fSFrançois Tigeot 	const unsigned long n_pages = obj->base.size / PAGE_SIZE;
36891e12ee3bSFrançois Tigeot 	unsigned int size = intel_rotation_info_size(rot_info);
36901487f786SFrançois Tigeot 	struct sgt_iter sgt_iter;
36911487f786SFrançois Tigeot 	dma_addr_t dma_addr;
3692477eb7f9SFrançois Tigeot 	unsigned long i;
3693477eb7f9SFrançois Tigeot 	dma_addr_t *page_addr_list;
3694477eb7f9SFrançois Tigeot 	struct sg_table *st;
3695352ff8bdSFrançois Tigeot 	struct scatterlist *sg;
3696477eb7f9SFrançois Tigeot 	int ret = -ENOMEM;
3697477eb7f9SFrançois Tigeot 
3698477eb7f9SFrançois Tigeot 	/* Allocate a temporary list of source pages for random access. */
3699*3f2dd94aSFrançois Tigeot 	page_addr_list = kvmalloc_array(n_pages,
3700bf017597SFrançois Tigeot 					sizeof(dma_addr_t),
3701*3f2dd94aSFrançois Tigeot 					GFP_KERNEL);
3702477eb7f9SFrançois Tigeot 	if (!page_addr_list)
3703477eb7f9SFrançois Tigeot 		return ERR_PTR(ret);
3704477eb7f9SFrançois Tigeot 
3705477eb7f9SFrançois Tigeot 	/* Allocate target SG list. */
3706bf017597SFrançois Tigeot 	st = kmalloc(sizeof(*st), M_DRM, GFP_KERNEL);
3707477eb7f9SFrançois Tigeot 	if (!st)
3708477eb7f9SFrançois Tigeot 		goto err_st_alloc;
3709477eb7f9SFrançois Tigeot 
37101e12ee3bSFrançois Tigeot 	ret = sg_alloc_table(st, size, GFP_KERNEL);
3711477eb7f9SFrançois Tigeot 	if (ret)
3712477eb7f9SFrançois Tigeot 		goto err_sg_alloc;
3713477eb7f9SFrançois Tigeot 
3714477eb7f9SFrançois Tigeot 	/* Populate source page list from the object. */
3715477eb7f9SFrançois Tigeot 	i = 0;
37164be47400SFrançois Tigeot 	for_each_sgt_dma(dma_addr, sgt_iter, obj->mm.pages)
37171487f786SFrançois Tigeot 		page_addr_list[i++] = dma_addr;
3718477eb7f9SFrançois Tigeot 
37191487f786SFrançois Tigeot 	GEM_BUG_ON(i != n_pages);
37208621f407SFrançois Tigeot 	st->nents = 0;
37218621f407SFrançois Tigeot 	sg = st->sgl;
37228621f407SFrançois Tigeot 
37231e12ee3bSFrançois Tigeot 	for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) {
37241e12ee3bSFrançois Tigeot 		sg = rotate_pages(page_addr_list, rot_info->plane[i].offset,
37251e12ee3bSFrançois Tigeot 				  rot_info->plane[i].width, rot_info->plane[i].height,
37261e12ee3bSFrançois Tigeot 				  rot_info->plane[i].stride, st, sg);
3727352ff8bdSFrançois Tigeot 	}
3728477eb7f9SFrançois Tigeot 
37291e12ee3bSFrançois Tigeot 	DRM_DEBUG_KMS("Created rotated page mapping for object size %zu (%ux%u tiles, %u pages)\n",
37301e12ee3bSFrançois Tigeot 		      obj->base.size, rot_info->plane[0].width, rot_info->plane[0].height, size);
3731477eb7f9SFrançois Tigeot 
3732*3f2dd94aSFrançois Tigeot 	kvfree(page_addr_list);
3733477eb7f9SFrançois Tigeot 
3734477eb7f9SFrançois Tigeot 	return st;
3735477eb7f9SFrançois Tigeot 
3736477eb7f9SFrançois Tigeot err_sg_alloc:
3737477eb7f9SFrançois Tigeot 	kfree(st);
3738477eb7f9SFrançois Tigeot err_st_alloc:
3739*3f2dd94aSFrançois Tigeot 	kvfree(page_addr_list);
3740477eb7f9SFrançois Tigeot 
37411e12ee3bSFrançois Tigeot 	DRM_DEBUG_KMS("Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n",
37421e12ee3bSFrançois Tigeot 		      obj->base.size, rot_info->plane[0].width, rot_info->plane[0].height, size);
37431e12ee3bSFrançois Tigeot 
3744477eb7f9SFrançois Tigeot 	return ERR_PTR(ret);
3745477eb7f9SFrançois Tigeot }
374619c468b4SFrançois Tigeot 
3747a85cb24fSFrançois Tigeot static noinline struct sg_table *
intel_partial_pages(const struct i915_ggtt_view * view,struct drm_i915_gem_object * obj)374819c468b4SFrançois Tigeot intel_partial_pages(const struct i915_ggtt_view *view,
374919c468b4SFrançois Tigeot 		    struct drm_i915_gem_object *obj)
375019c468b4SFrançois Tigeot {
375119c468b4SFrançois Tigeot 	struct sg_table *st;
37524be47400SFrançois Tigeot 	struct scatterlist *sg, *iter;
3753a85cb24fSFrançois Tigeot 	unsigned int count = view->partial.size;
37544be47400SFrançois Tigeot 	unsigned int offset;
375519c468b4SFrançois Tigeot 	int ret = -ENOMEM;
375619c468b4SFrançois Tigeot 
3757bf017597SFrançois Tigeot 	st = kmalloc(sizeof(*st), M_DRM, GFP_KERNEL);
375819c468b4SFrançois Tigeot 	if (!st)
375919c468b4SFrançois Tigeot 		goto err_st_alloc;
376019c468b4SFrançois Tigeot 
37614be47400SFrançois Tigeot 	ret = sg_alloc_table(st, count, GFP_KERNEL);
376219c468b4SFrançois Tigeot 	if (ret)
376319c468b4SFrançois Tigeot 		goto err_sg_alloc;
376419c468b4SFrançois Tigeot 
3765a85cb24fSFrançois Tigeot 	iter = i915_gem_object_get_sg(obj, view->partial.offset, &offset);
37664be47400SFrançois Tigeot 	GEM_BUG_ON(!iter);
37674be47400SFrançois Tigeot 
376819c468b4SFrançois Tigeot 	sg = st->sgl;
376919c468b4SFrançois Tigeot 	st->nents = 0;
37704be47400SFrançois Tigeot 	do {
37714be47400SFrançois Tigeot 		unsigned int len;
377219c468b4SFrançois Tigeot 
37734be47400SFrançois Tigeot 		len = min(iter->length - (offset << PAGE_SHIFT),
37744be47400SFrançois Tigeot 			  count << PAGE_SHIFT);
37754be47400SFrançois Tigeot 		sg_set_page(sg, NULL, len, 0);
37764be47400SFrançois Tigeot 		sg_dma_address(sg) =
37774be47400SFrançois Tigeot 			sg_dma_address(iter) + (offset << PAGE_SHIFT);
37784be47400SFrançois Tigeot 		sg_dma_len(sg) = len;
377919c468b4SFrançois Tigeot 
378019c468b4SFrançois Tigeot 		st->nents++;
37814be47400SFrançois Tigeot 		count -= len >> PAGE_SHIFT;
37824be47400SFrançois Tigeot 		if (count == 0) {
37834be47400SFrançois Tigeot 			sg_mark_end(sg);
37844be47400SFrançois Tigeot 			return st;
378519c468b4SFrançois Tigeot 		}
378619c468b4SFrançois Tigeot 
37874be47400SFrançois Tigeot 		sg = __sg_next(sg);
37884be47400SFrançois Tigeot 		iter = __sg_next(iter);
37894be47400SFrançois Tigeot 		offset = 0;
37904be47400SFrançois Tigeot 	} while (1);
379119c468b4SFrançois Tigeot 
379219c468b4SFrançois Tigeot err_sg_alloc:
379319c468b4SFrançois Tigeot 	kfree(st);
379419c468b4SFrançois Tigeot err_st_alloc:
379519c468b4SFrançois Tigeot 	return ERR_PTR(ret);
379619c468b4SFrançois Tigeot }
3797477eb7f9SFrançois Tigeot 
379819c468b4SFrançois Tigeot static int
i915_get_ggtt_vma_pages(struct i915_vma * vma)3799477eb7f9SFrançois Tigeot i915_get_ggtt_vma_pages(struct i915_vma *vma)
3800477eb7f9SFrançois Tigeot {
3801a85cb24fSFrançois Tigeot 	int ret;
3802477eb7f9SFrançois Tigeot 
38034be47400SFrançois Tigeot 	/* The vma->pages are only valid within the lifespan of the borrowed
38044be47400SFrançois Tigeot 	 * obj->mm.pages. When the obj->mm.pages sg_table is regenerated, so
38054be47400SFrançois Tigeot 	 * must be the vma->pages. A simple rule is that vma->pages must only
38064be47400SFrançois Tigeot 	 * be accessed when the obj->mm.pages are pinned.
38074be47400SFrançois Tigeot 	 */
38084be47400SFrançois Tigeot 	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(vma->obj));
38094be47400SFrançois Tigeot 
3810a85cb24fSFrançois Tigeot 	switch (vma->ggtt_view.type) {
3811a85cb24fSFrançois Tigeot 	case I915_GGTT_VIEW_NORMAL:
3812a85cb24fSFrançois Tigeot 		vma->pages = vma->obj->mm.pages;
38132c9916cdSFrançois Tigeot 		return 0;
38142c9916cdSFrançois Tigeot 
3815a85cb24fSFrançois Tigeot 	case I915_GGTT_VIEW_ROTATED:
38161e12ee3bSFrançois Tigeot 		vma->pages =
3817a85cb24fSFrançois Tigeot 			intel_rotate_pages(&vma->ggtt_view.rotated, vma->obj);
3818a85cb24fSFrançois Tigeot 		break;
3819a85cb24fSFrançois Tigeot 
3820a85cb24fSFrançois Tigeot 	case I915_GGTT_VIEW_PARTIAL:
38211e12ee3bSFrançois Tigeot 		vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj);
3822a85cb24fSFrançois Tigeot 		break;
3823a85cb24fSFrançois Tigeot 
3824a85cb24fSFrançois Tigeot 	default:
38252c9916cdSFrançois Tigeot 		WARN_ONCE(1, "GGTT view %u not implemented!\n",
38262c9916cdSFrançois Tigeot 			  vma->ggtt_view.type);
3827a85cb24fSFrançois Tigeot 		return -EINVAL;
3828a85cb24fSFrançois Tigeot 	}
38292c9916cdSFrançois Tigeot 
3830a85cb24fSFrançois Tigeot 	ret = 0;
3831a85cb24fSFrançois Tigeot 	if (unlikely(IS_ERR(vma->pages))) {
38321e12ee3bSFrançois Tigeot 		ret = PTR_ERR(vma->pages);
38331e12ee3bSFrançois Tigeot 		vma->pages = NULL;
3834477eb7f9SFrançois Tigeot 		DRM_ERROR("Failed to get pages for VMA view type %u (%d)!\n",
3835477eb7f9SFrançois Tigeot 			  vma->ggtt_view.type, ret);
38362c9916cdSFrançois Tigeot 	}
3837477eb7f9SFrançois Tigeot 	return ret;
38382c9916cdSFrançois Tigeot }
38392c9916cdSFrançois Tigeot 
3840a85cb24fSFrançois Tigeot /**
3841a85cb24fSFrançois Tigeot  * i915_gem_gtt_reserve - reserve a node in an address_space (GTT)
3842a85cb24fSFrançois Tigeot  * @vm: the &struct i915_address_space
3843a85cb24fSFrançois Tigeot  * @node: the &struct drm_mm_node (typically i915_vma.mode)
3844a85cb24fSFrançois Tigeot  * @size: how much space to allocate inside the GTT,
3845a85cb24fSFrançois Tigeot  *        must be #I915_GTT_PAGE_SIZE aligned
3846a85cb24fSFrançois Tigeot  * @offset: where to insert inside the GTT,
3847a85cb24fSFrançois Tigeot  *          must be #I915_GTT_MIN_ALIGNMENT aligned, and the node
3848a85cb24fSFrançois Tigeot  *          (@offset + @size) must fit within the address space
3849a85cb24fSFrançois Tigeot  * @color: color to apply to node, if this node is not from a VMA,
3850a85cb24fSFrançois Tigeot  *         color must be #I915_COLOR_UNEVICTABLE
3851a85cb24fSFrançois Tigeot  * @flags: control search and eviction behaviour
3852a85cb24fSFrançois Tigeot  *
3853a85cb24fSFrançois Tigeot  * i915_gem_gtt_reserve() tries to insert the @node at the exact @offset inside
3854a85cb24fSFrançois Tigeot  * the address space (using @size and @color). If the @node does not fit, it
3855a85cb24fSFrançois Tigeot  * tries to evict any overlapping nodes from the GTT, including any
3856a85cb24fSFrançois Tigeot  * neighbouring nodes if the colors do not match (to ensure guard pages between
3857a85cb24fSFrançois Tigeot  * differing domains). See i915_gem_evict_for_node() for the gory details
3858a85cb24fSFrançois Tigeot  * on the eviction algorithm. #PIN_NONBLOCK may used to prevent waiting on
3859a85cb24fSFrançois Tigeot  * evicting active overlapping objects, and any overlapping node that is pinned
3860a85cb24fSFrançois Tigeot  * or marked as unevictable will also result in failure.
3861a85cb24fSFrançois Tigeot  *
3862a85cb24fSFrançois Tigeot  * Returns: 0 on success, -ENOSPC if no suitable hole is found, -EINTR if
3863a85cb24fSFrançois Tigeot  * asked to wait for eviction and interrupted.
3864a85cb24fSFrançois Tigeot  */
i915_gem_gtt_reserve(struct i915_address_space * vm,struct drm_mm_node * node,u64 size,u64 offset,unsigned long color,unsigned int flags)3865a85cb24fSFrançois Tigeot int i915_gem_gtt_reserve(struct i915_address_space *vm,
3866a85cb24fSFrançois Tigeot 			 struct drm_mm_node *node,
3867a85cb24fSFrançois Tigeot 			 u64 size, u64 offset, unsigned long color,
3868a85cb24fSFrançois Tigeot 			 unsigned int flags)
3869a85cb24fSFrançois Tigeot {
3870a85cb24fSFrançois Tigeot 	int err;
3871a85cb24fSFrançois Tigeot 
3872a85cb24fSFrançois Tigeot 	GEM_BUG_ON(!size);
3873a85cb24fSFrançois Tigeot 	GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
3874a85cb24fSFrançois Tigeot 	GEM_BUG_ON(!IS_ALIGNED(offset, I915_GTT_MIN_ALIGNMENT));
3875a85cb24fSFrançois Tigeot 	GEM_BUG_ON(range_overflows(offset, size, vm->total));
3876a85cb24fSFrançois Tigeot 	GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base);
3877a85cb24fSFrançois Tigeot 	GEM_BUG_ON(drm_mm_node_allocated(node));
3878a85cb24fSFrançois Tigeot 
3879a85cb24fSFrançois Tigeot 	node->size = size;
3880a85cb24fSFrançois Tigeot 	node->start = offset;
3881a85cb24fSFrançois Tigeot 	node->color = color;
3882a85cb24fSFrançois Tigeot 
3883a85cb24fSFrançois Tigeot 	err = drm_mm_reserve_node(&vm->mm, node);
3884a85cb24fSFrançois Tigeot 	if (err != -ENOSPC)
3885a85cb24fSFrançois Tigeot 		return err;
3886a85cb24fSFrançois Tigeot 
3887*3f2dd94aSFrançois Tigeot 	if (flags & PIN_NOEVICT)
3888*3f2dd94aSFrançois Tigeot 		return -ENOSPC;
3889*3f2dd94aSFrançois Tigeot 
3890a85cb24fSFrançois Tigeot 	err = i915_gem_evict_for_node(vm, node, flags);
3891a85cb24fSFrançois Tigeot 	if (err == 0)
3892a85cb24fSFrançois Tigeot 		err = drm_mm_reserve_node(&vm->mm, node);
3893a85cb24fSFrançois Tigeot 
3894a85cb24fSFrançois Tigeot 	return err;
3895a85cb24fSFrançois Tigeot }
3896a85cb24fSFrançois Tigeot 
random_offset(u64 start,u64 end,u64 len,u64 align)3897a85cb24fSFrançois Tigeot static u64 random_offset(u64 start, u64 end, u64 len, u64 align)
3898a85cb24fSFrançois Tigeot {
3899a85cb24fSFrançois Tigeot 	u64 range, addr;
3900a85cb24fSFrançois Tigeot 
3901a85cb24fSFrançois Tigeot 	GEM_BUG_ON(range_overflows(start, len, end));
3902a85cb24fSFrançois Tigeot 	GEM_BUG_ON(round_up(start, align) > round_down(end - len, align));
3903a85cb24fSFrançois Tigeot 
3904a85cb24fSFrançois Tigeot 	range = round_down(end - len, align) - round_up(start, align);
3905a85cb24fSFrançois Tigeot 	if (range) {
3906a85cb24fSFrançois Tigeot 		if (sizeof(unsigned long) == sizeof(u64)) {
3907a85cb24fSFrançois Tigeot 			addr = get_random_long();
3908a85cb24fSFrançois Tigeot 		} else {
3909a85cb24fSFrançois Tigeot 			addr = get_random_int();
3910a85cb24fSFrançois Tigeot 			if (range > U32_MAX) {
3911a85cb24fSFrançois Tigeot 				addr <<= 32;
3912a85cb24fSFrançois Tigeot 				addr |= get_random_int();
3913a85cb24fSFrançois Tigeot 			}
3914a85cb24fSFrançois Tigeot 		}
3915a85cb24fSFrançois Tigeot 		div64_u64_rem(addr, range, &addr);
3916a85cb24fSFrançois Tigeot 		start += addr;
3917a85cb24fSFrançois Tigeot 	}
3918a85cb24fSFrançois Tigeot 
3919a85cb24fSFrançois Tigeot 	return round_up(start, align);
3920a85cb24fSFrançois Tigeot }
3921a85cb24fSFrançois Tigeot 
3922a85cb24fSFrançois Tigeot /**
3923a85cb24fSFrançois Tigeot  * i915_gem_gtt_insert - insert a node into an address_space (GTT)
3924a85cb24fSFrançois Tigeot  * @vm: the &struct i915_address_space
3925a85cb24fSFrançois Tigeot  * @node: the &struct drm_mm_node (typically i915_vma.node)
3926a85cb24fSFrançois Tigeot  * @size: how much space to allocate inside the GTT,
3927a85cb24fSFrançois Tigeot  *        must be #I915_GTT_PAGE_SIZE aligned
3928a85cb24fSFrançois Tigeot  * @alignment: required alignment of starting offset, may be 0 but
3929a85cb24fSFrançois Tigeot  *             if specified, this must be a power-of-two and at least
3930a85cb24fSFrançois Tigeot  *             #I915_GTT_MIN_ALIGNMENT
3931a85cb24fSFrançois Tigeot  * @color: color to apply to node
3932a85cb24fSFrançois Tigeot  * @start: start of any range restriction inside GTT (0 for all),
3933a85cb24fSFrançois Tigeot  *         must be #I915_GTT_PAGE_SIZE aligned
3934a85cb24fSFrançois Tigeot  * @end: end of any range restriction inside GTT (U64_MAX for all),
3935a85cb24fSFrançois Tigeot  *       must be #I915_GTT_PAGE_SIZE aligned if not U64_MAX
3936a85cb24fSFrançois Tigeot  * @flags: control search and eviction behaviour
3937a85cb24fSFrançois Tigeot  *
3938a85cb24fSFrançois Tigeot  * i915_gem_gtt_insert() first searches for an available hole into which
3939a85cb24fSFrançois Tigeot  * is can insert the node. The hole address is aligned to @alignment and
3940a85cb24fSFrançois Tigeot  * its @size must then fit entirely within the [@start, @end] bounds. The
3941a85cb24fSFrançois Tigeot  * nodes on either side of the hole must match @color, or else a guard page
3942a85cb24fSFrançois Tigeot  * will be inserted between the two nodes (or the node evicted). If no
3943a85cb24fSFrançois Tigeot  * suitable hole is found, first a victim is randomly selected and tested
3944a85cb24fSFrançois Tigeot  * for eviction, otherwise then the LRU list of objects within the GTT
3945a85cb24fSFrançois Tigeot  * is scanned to find the first set of replacement nodes to create the hole.
3946a85cb24fSFrançois Tigeot  * Those old overlapping nodes are evicted from the GTT (and so must be
3947a85cb24fSFrançois Tigeot  * rebound before any future use). Any node that is currently pinned cannot
3948a85cb24fSFrançois Tigeot  * be evicted (see i915_vma_pin()). Similar if the node's VMA is currently
3949a85cb24fSFrançois Tigeot  * active and #PIN_NONBLOCK is specified, that node is also skipped when
3950a85cb24fSFrançois Tigeot  * searching for an eviction candidate. See i915_gem_evict_something() for
3951a85cb24fSFrançois Tigeot  * the gory details on the eviction algorithm.
3952a85cb24fSFrançois Tigeot  *
3953a85cb24fSFrançois Tigeot  * Returns: 0 on success, -ENOSPC if no suitable hole is found, -EINTR if
3954a85cb24fSFrançois Tigeot  * asked to wait for eviction and interrupted.
3955a85cb24fSFrançois Tigeot  */
i915_gem_gtt_insert(struct i915_address_space * vm,struct drm_mm_node * node,u64 size,u64 alignment,unsigned long color,u64 start,u64 end,unsigned int flags)3956a85cb24fSFrançois Tigeot int i915_gem_gtt_insert(struct i915_address_space *vm,
3957a85cb24fSFrançois Tigeot 			struct drm_mm_node *node,
3958a85cb24fSFrançois Tigeot 			u64 size, u64 alignment, unsigned long color,
3959a85cb24fSFrançois Tigeot 			u64 start, u64 end, unsigned int flags)
3960a85cb24fSFrançois Tigeot {
3961a85cb24fSFrançois Tigeot 	enum drm_mm_insert_mode mode;
3962a85cb24fSFrançois Tigeot 	u64 offset;
3963a85cb24fSFrançois Tigeot 	int err;
3964a85cb24fSFrançois Tigeot 
3965a85cb24fSFrançois Tigeot 	lockdep_assert_held(&vm->i915->drm.struct_mutex);
3966a85cb24fSFrançois Tigeot 	GEM_BUG_ON(!size);
3967a85cb24fSFrançois Tigeot 	GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
3968a85cb24fSFrançois Tigeot 	GEM_BUG_ON(alignment && !is_power_of_2(alignment));
3969a85cb24fSFrançois Tigeot 	GEM_BUG_ON(alignment && !IS_ALIGNED(alignment, I915_GTT_MIN_ALIGNMENT));
3970a85cb24fSFrançois Tigeot 	GEM_BUG_ON(start >= end);
3971a85cb24fSFrançois Tigeot 	GEM_BUG_ON(start > 0  && !IS_ALIGNED(start, I915_GTT_PAGE_SIZE));
3972a85cb24fSFrançois Tigeot 	GEM_BUG_ON(end < U64_MAX && !IS_ALIGNED(end, I915_GTT_PAGE_SIZE));
3973a85cb24fSFrançois Tigeot 	GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base);
3974a85cb24fSFrançois Tigeot 	GEM_BUG_ON(drm_mm_node_allocated(node));
3975a85cb24fSFrançois Tigeot 
3976a85cb24fSFrançois Tigeot 	if (unlikely(range_overflows(start, size, end)))
3977a85cb24fSFrançois Tigeot 		return -ENOSPC;
3978a85cb24fSFrançois Tigeot 
3979a85cb24fSFrançois Tigeot 	if (unlikely(round_up(start, alignment) > round_down(end - size, alignment)))
3980a85cb24fSFrançois Tigeot 		return -ENOSPC;
3981a85cb24fSFrançois Tigeot 
3982a85cb24fSFrançois Tigeot 	mode = DRM_MM_INSERT_BEST;
3983a85cb24fSFrançois Tigeot 	if (flags & PIN_HIGH)
3984a85cb24fSFrançois Tigeot 		mode = DRM_MM_INSERT_HIGH;
3985a85cb24fSFrançois Tigeot 	if (flags & PIN_MAPPABLE)
3986a85cb24fSFrançois Tigeot 		mode = DRM_MM_INSERT_LOW;
3987a85cb24fSFrançois Tigeot 
3988a85cb24fSFrançois Tigeot 	/* We only allocate in PAGE_SIZE/GTT_PAGE_SIZE (4096) chunks,
3989a85cb24fSFrançois Tigeot 	 * so we know that we always have a minimum alignment of 4096.
3990a85cb24fSFrançois Tigeot 	 * The drm_mm range manager is optimised to return results
3991a85cb24fSFrançois Tigeot 	 * with zero alignment, so where possible use the optimal
3992a85cb24fSFrançois Tigeot 	 * path.
3993a85cb24fSFrançois Tigeot 	 */
3994a85cb24fSFrançois Tigeot 	BUILD_BUG_ON(I915_GTT_MIN_ALIGNMENT > I915_GTT_PAGE_SIZE);
3995a85cb24fSFrançois Tigeot 	if (alignment <= I915_GTT_MIN_ALIGNMENT)
3996a85cb24fSFrançois Tigeot 		alignment = 0;
3997a85cb24fSFrançois Tigeot 
3998a85cb24fSFrançois Tigeot 	err = drm_mm_insert_node_in_range(&vm->mm, node,
3999a85cb24fSFrançois Tigeot 					  size, alignment, color,
4000a85cb24fSFrançois Tigeot 					  start, end, mode);
4001a85cb24fSFrançois Tigeot 	if (err != -ENOSPC)
4002a85cb24fSFrançois Tigeot 		return err;
4003a85cb24fSFrançois Tigeot 
4004*3f2dd94aSFrançois Tigeot 	if (flags & PIN_NOEVICT)
4005*3f2dd94aSFrançois Tigeot 		return -ENOSPC;
4006*3f2dd94aSFrançois Tigeot 
4007a85cb24fSFrançois Tigeot 	/* No free space, pick a slot at random.
4008a85cb24fSFrançois Tigeot 	 *
4009a85cb24fSFrançois Tigeot 	 * There is a pathological case here using a GTT shared between
4010a85cb24fSFrançois Tigeot 	 * mmap and GPU (i.e. ggtt/aliasing_ppgtt but not full-ppgtt):
4011a85cb24fSFrançois Tigeot 	 *
4012a85cb24fSFrançois Tigeot 	 *    |<-- 256 MiB aperture -->||<-- 1792 MiB unmappable -->|
4013a85cb24fSFrançois Tigeot 	 *         (64k objects)             (448k objects)
4014a85cb24fSFrançois Tigeot 	 *
4015a85cb24fSFrançois Tigeot 	 * Now imagine that the eviction LRU is ordered top-down (just because
4016a85cb24fSFrançois Tigeot 	 * pathology meets real life), and that we need to evict an object to
4017a85cb24fSFrançois Tigeot 	 * make room inside the aperture. The eviction scan then has to walk
4018a85cb24fSFrançois Tigeot 	 * the 448k list before it finds one within range. And now imagine that
4019a85cb24fSFrançois Tigeot 	 * it has to search for a new hole between every byte inside the memcpy,
4020a85cb24fSFrançois Tigeot 	 * for several simultaneous clients.
4021a85cb24fSFrançois Tigeot 	 *
4022a85cb24fSFrançois Tigeot 	 * On a full-ppgtt system, if we have run out of available space, there
4023a85cb24fSFrançois Tigeot 	 * will be lots and lots of objects in the eviction list! Again,
4024a85cb24fSFrançois Tigeot 	 * searching that LRU list may be slow if we are also applying any
4025a85cb24fSFrançois Tigeot 	 * range restrictions (e.g. restriction to low 4GiB) and so, for
4026a85cb24fSFrançois Tigeot 	 * simplicity and similarilty between different GTT, try the single
4027a85cb24fSFrançois Tigeot 	 * random replacement first.
4028a85cb24fSFrançois Tigeot 	 */
4029a85cb24fSFrançois Tigeot 	offset = random_offset(start, end,
4030a85cb24fSFrançois Tigeot 			       size, alignment ?: I915_GTT_MIN_ALIGNMENT);
4031a85cb24fSFrançois Tigeot 	err = i915_gem_gtt_reserve(vm, node, size, offset, color, flags);
4032a85cb24fSFrançois Tigeot 	if (err != -ENOSPC)
4033a85cb24fSFrançois Tigeot 		return err;
4034a85cb24fSFrançois Tigeot 
4035a85cb24fSFrançois Tigeot 	/* Randomly selected placement is pinned, do a search */
4036a85cb24fSFrançois Tigeot 	err = i915_gem_evict_something(vm, size, alignment, color,
4037a85cb24fSFrançois Tigeot 				       start, end, flags);
4038a85cb24fSFrançois Tigeot 	if (err)
4039a85cb24fSFrançois Tigeot 		return err;
4040a85cb24fSFrançois Tigeot 
4041a85cb24fSFrançois Tigeot 	return drm_mm_insert_node_in_range(&vm->mm, node,
4042a85cb24fSFrançois Tigeot 					   size, alignment, color,
4043a85cb24fSFrançois Tigeot 					   start, end, DRM_MM_INSERT_EVICT);
4044a85cb24fSFrançois Tigeot }
4045a85cb24fSFrançois Tigeot 
4046a85cb24fSFrançois Tigeot #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
4047a85cb24fSFrançois Tigeot #include "selftests/mock_gtt.c"
4048a85cb24fSFrançois Tigeot #include "selftests/i915_gem_gtt.c"
4049a85cb24fSFrançois Tigeot #endif
4050