xref: /linux/drivers/gpu/drm/i915/gem/i915_gem_stolen.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2008-2012 Intel Corporation
4  */
5 
6 #include <linux/errno.h>
7 #include <linux/mutex.h>
8 
9 #include <drm/drm_mm.h>
10 #include <drm/drm_print.h>
11 #include <drm/intel/display_parent_interface.h>
12 #include <drm/intel/i915_drm.h>
13 
14 #include "gem/i915_gem_lmem.h"
15 #include "gem/i915_gem_region.h"
16 #include "gt/intel_gt.h"
17 #include "gt/intel_gt_mcr.h"
18 #include "gt/intel_gt_regs.h"
19 #include "gt/intel_region_lmem.h"
20 #include "i915_drv.h"
21 #include "i915_gem_stolen.h"
22 #include "i915_pci.h"
23 #include "i915_reg.h"
24 #include "i915_utils.h"
25 #include "i915_vgpu.h"
26 #include "intel_mchbar_regs.h"
27 #include "intel_pci_config.h"
28 
29 struct intel_stolen_node {
30 	struct drm_i915_private *i915;
31 	struct drm_mm_node node;
32 };
33 
34 /*
35  * The BIOS typically reserves some of the system's memory for the exclusive
36  * use of the integrated graphics. This memory is no longer available for
37  * use by the OS and so the user finds that his system has less memory
38  * available than he put in. We refer to this memory as stolen.
39  *
40  * The BIOS will allocate its framebuffer from the stolen memory. Our
41  * goal is try to reuse that object for our own fbcon which must always
42  * be available for panics. Anything else we can reuse the stolen memory
43  * for is a boon.
44  */
45 
__i915_gem_stolen_insert_node_in_range(struct drm_i915_private * i915,struct drm_mm_node * node,u64 size,unsigned int alignment,u64 start,u64 end)46 static int __i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915,
47 						  struct drm_mm_node *node, u64 size,
48 						  unsigned int alignment, u64 start, u64 end)
49 {
50 	int ret;
51 
52 	if (!drm_mm_initialized(&i915->mm.stolen))
53 		return -ENODEV;
54 
55 	/* WaSkipStolenMemoryFirstPage:bdw+ */
56 	if (GRAPHICS_VER(i915) >= 8 && start < 4096)
57 		start = 4096;
58 
59 	mutex_lock(&i915->mm.stolen_lock);
60 	ret = drm_mm_insert_node_in_range(&i915->mm.stolen, node,
61 					  size, alignment, 0,
62 					  start, end, DRM_MM_INSERT_BEST);
63 	mutex_unlock(&i915->mm.stolen_lock);
64 
65 	return ret;
66 }
67 
i915_gem_stolen_insert_node_in_range(struct intel_stolen_node * node,u64 size,unsigned int alignment,u64 start,u64 end)68 static int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
69 						unsigned int alignment, u64 start, u64 end)
70 {
71 	return __i915_gem_stolen_insert_node_in_range(node->i915, &node->node,
72 						      size, alignment,
73 						      start, end);
74 }
75 
__i915_gem_stolen_insert_node(struct drm_i915_private * i915,struct drm_mm_node * node,u64 size,unsigned int alignment)76 static int __i915_gem_stolen_insert_node(struct drm_i915_private *i915,
77 					 struct drm_mm_node *node, u64 size,
78 					 unsigned int alignment)
79 {
80 	return __i915_gem_stolen_insert_node_in_range(i915, node,
81 						      size, alignment,
82 						      I915_GEM_STOLEN_BIAS,
83 						      U64_MAX);
84 }
85 
i915_gem_stolen_insert_node(struct intel_stolen_node * node,u64 size,unsigned int alignment)86 static int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size,
87 				       unsigned int alignment)
88 {
89 	return __i915_gem_stolen_insert_node(node->i915, &node->node, size, alignment);
90 }
91 
__i915_gem_stolen_remove_node(struct drm_i915_private * i915,struct drm_mm_node * node)92 static void __i915_gem_stolen_remove_node(struct drm_i915_private *i915,
93 					  struct drm_mm_node *node)
94 {
95 	mutex_lock(&i915->mm.stolen_lock);
96 	drm_mm_remove_node(node);
97 	mutex_unlock(&i915->mm.stolen_lock);
98 }
99 
i915_gem_stolen_remove_node(struct intel_stolen_node * node)100 static void i915_gem_stolen_remove_node(struct intel_stolen_node *node)
101 {
102 	__i915_gem_stolen_remove_node(node->i915, &node->node);
103 }
104 
valid_stolen_size(struct drm_i915_private * i915,struct resource * dsm)105 static bool valid_stolen_size(struct drm_i915_private *i915, struct resource *dsm)
106 {
107 	return (dsm->start != 0 || HAS_LMEMBAR_SMEM_STOLEN(i915)) && dsm->end > dsm->start;
108 }
109 
adjust_stolen(struct drm_i915_private * i915,struct resource * dsm)110 static int adjust_stolen(struct drm_i915_private *i915,
111 			 struct resource *dsm)
112 {
113 	struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
114 	struct intel_uncore *uncore = ggtt->vm.gt->uncore;
115 
116 	if (!valid_stolen_size(i915, dsm))
117 		return -EINVAL;
118 
119 	/*
120 	 * Make sure we don't clobber the GTT if it's within stolen memory
121 	 *
122 	 * TODO: We have yet too encounter the case where the GTT wasn't at the
123 	 * end of stolen. With that assumption we could simplify this.
124 	 */
125 	if (GRAPHICS_VER(i915) <= 4 &&
126 	    !IS_G33(i915) && !IS_PINEVIEW(i915) && !IS_G4X(i915)) {
127 		struct resource stolen[2] = {*dsm, *dsm};
128 		struct resource ggtt_res;
129 		resource_size_t ggtt_start;
130 
131 		ggtt_start = intel_uncore_read(uncore, PGTBL_CTL);
132 		if (GRAPHICS_VER(i915) == 4)
133 			ggtt_start = (ggtt_start & PGTBL_ADDRESS_LO_MASK) |
134 				     (ggtt_start & PGTBL_ADDRESS_HI_MASK) << 28;
135 		else
136 			ggtt_start &= PGTBL_ADDRESS_LO_MASK;
137 
138 		ggtt_res = DEFINE_RES_MEM(ggtt_start, ggtt_total_entries(ggtt) * 4);
139 
140 		if (ggtt_res.start >= stolen[0].start && ggtt_res.start < stolen[0].end)
141 			stolen[0].end = ggtt_res.start;
142 		if (ggtt_res.end > stolen[1].start && ggtt_res.end <= stolen[1].end)
143 			stolen[1].start = ggtt_res.end;
144 
145 		/* Pick the larger of the two chunks */
146 		if (resource_size(&stolen[0]) > resource_size(&stolen[1]))
147 			*dsm = stolen[0];
148 		else
149 			*dsm = stolen[1];
150 
151 		if (stolen[0].start != stolen[1].start ||
152 		    stolen[0].end != stolen[1].end) {
153 			drm_dbg(&i915->drm,
154 				"GTT within stolen memory at %pR\n",
155 				&ggtt_res);
156 			drm_dbg(&i915->drm, "Stolen memory adjusted to %pR\n",
157 				dsm);
158 		}
159 	}
160 
161 	if (!valid_stolen_size(i915, dsm))
162 		return -EINVAL;
163 
164 	return 0;
165 }
166 
request_smem_stolen(struct drm_i915_private * i915,struct resource * dsm)167 static int request_smem_stolen(struct drm_i915_private *i915,
168 			       struct resource *dsm)
169 {
170 	struct resource *r;
171 
172 	/*
173 	 * With stolen lmem, we don't need to request system memory for the
174 	 * address range since it's local to the gpu.
175 	 *
176 	 * Starting MTL, in IGFX devices the stolen memory is exposed via
177 	 * LMEMBAR and shall be considered similar to stolen lmem.
178 	 */
179 	if (HAS_LMEM(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915))
180 		return 0;
181 
182 	/*
183 	 * Verify that nothing else uses this physical address. Stolen
184 	 * memory should be reserved by the BIOS and hidden from the
185 	 * kernel. So if the region is already marked as busy, something
186 	 * is seriously wrong.
187 	 */
188 	r = devm_request_mem_region(i915->drm.dev, dsm->start,
189 				    resource_size(dsm),
190 				    "Graphics Stolen Memory");
191 	if (r == NULL) {
192 		/*
193 		 * One more attempt but this time requesting region from
194 		 * start + 1, as we have seen that this resolves the region
195 		 * conflict with the PCI Bus.
196 		 * This is a BIOS w/a: Some BIOS wrap stolen in the root
197 		 * PCI bus, but have an off-by-one error. Hence retry the
198 		 * reservation starting from 1 instead of 0.
199 		 * There's also BIOS with off-by-one on the other end.
200 		 */
201 		r = devm_request_mem_region(i915->drm.dev, dsm->start + 1,
202 					    resource_size(dsm) - 2,
203 					    "Graphics Stolen Memory");
204 		/*
205 		 * GEN3 firmware likes to smash pci bridges into the stolen
206 		 * range. Apparently this works.
207 		 */
208 		if (!r && GRAPHICS_VER(i915) != 3) {
209 			drm_err(&i915->drm,
210 				"conflict detected with stolen region: %pR\n",
211 				dsm);
212 
213 			return -EBUSY;
214 		}
215 	}
216 
217 	return 0;
218 }
219 
i915_gem_cleanup_stolen(struct drm_i915_private * i915)220 static void i915_gem_cleanup_stolen(struct drm_i915_private *i915)
221 {
222 	if (!drm_mm_initialized(&i915->mm.stolen))
223 		return;
224 
225 	drm_mm_takedown(&i915->mm.stolen);
226 }
227 
g4x_get_stolen_reserved(struct drm_i915_private * i915,struct intel_uncore * uncore,resource_size_t * base,resource_size_t * size)228 static void g4x_get_stolen_reserved(struct drm_i915_private *i915,
229 				    struct intel_uncore *uncore,
230 				    resource_size_t *base,
231 				    resource_size_t *size)
232 {
233 	u32 reg_val = intel_uncore_read(uncore,
234 					IS_GM45(i915) ?
235 					CTG_STOLEN_RESERVED :
236 					ELK_STOLEN_RESERVED);
237 	resource_size_t stolen_top = i915->dsm.stolen.end + 1;
238 
239 	drm_dbg(&i915->drm, "%s_STOLEN_RESERVED = %08x\n",
240 		IS_GM45(i915) ? "CTG" : "ELK", reg_val);
241 
242 	if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0)
243 		return;
244 
245 	/*
246 	 * Whether ILK really reuses the ELK register for this is unclear.
247 	 * Let's see if we catch anyone with this supposedly enabled on ILK.
248 	 */
249 	drm_WARN(&i915->drm, GRAPHICS_VER(i915) == 5,
250 		 "ILK stolen reserved found? 0x%08x\n",
251 		 reg_val);
252 
253 	if (!(reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK))
254 		return;
255 
256 	*base = (reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK) << 16;
257 	drm_WARN_ON(&i915->drm,
258 		    (reg_val & G4X_STOLEN_RESERVED_ADDR1_MASK) < *base);
259 
260 	*size = stolen_top - *base;
261 }
262 
gen6_get_stolen_reserved(struct drm_i915_private * i915,struct intel_uncore * uncore,resource_size_t * base,resource_size_t * size)263 static void gen6_get_stolen_reserved(struct drm_i915_private *i915,
264 				     struct intel_uncore *uncore,
265 				     resource_size_t *base,
266 				     resource_size_t *size)
267 {
268 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
269 
270 	drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
271 
272 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
273 		return;
274 
275 	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
276 
277 	switch (reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK) {
278 	case GEN6_STOLEN_RESERVED_1M:
279 		*size = 1024 * 1024;
280 		break;
281 	case GEN6_STOLEN_RESERVED_512K:
282 		*size = 512 * 1024;
283 		break;
284 	case GEN6_STOLEN_RESERVED_256K:
285 		*size = 256 * 1024;
286 		break;
287 	case GEN6_STOLEN_RESERVED_128K:
288 		*size = 128 * 1024;
289 		break;
290 	default:
291 		*size = 1024 * 1024;
292 		MISSING_CASE(reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK);
293 	}
294 }
295 
vlv_get_stolen_reserved(struct drm_i915_private * i915,struct intel_uncore * uncore,resource_size_t * base,resource_size_t * size)296 static void vlv_get_stolen_reserved(struct drm_i915_private *i915,
297 				    struct intel_uncore *uncore,
298 				    resource_size_t *base,
299 				    resource_size_t *size)
300 {
301 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
302 	resource_size_t stolen_top = i915->dsm.stolen.end + 1;
303 
304 	drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
305 
306 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
307 		return;
308 
309 	switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
310 	default:
311 		MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
312 		fallthrough;
313 	case GEN7_STOLEN_RESERVED_1M:
314 		*size = 1024 * 1024;
315 		break;
316 	}
317 
318 	/*
319 	 * On vlv, the ADDR_MASK portion is left as 0 and HW deduces the
320 	 * reserved location as (top - size).
321 	 */
322 	*base = stolen_top - *size;
323 }
324 
gen7_get_stolen_reserved(struct drm_i915_private * i915,struct intel_uncore * uncore,resource_size_t * base,resource_size_t * size)325 static void gen7_get_stolen_reserved(struct drm_i915_private *i915,
326 				     struct intel_uncore *uncore,
327 				     resource_size_t *base,
328 				     resource_size_t *size)
329 {
330 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
331 
332 	drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
333 
334 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
335 		return;
336 
337 	*base = reg_val & GEN7_STOLEN_RESERVED_ADDR_MASK;
338 
339 	switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
340 	case GEN7_STOLEN_RESERVED_1M:
341 		*size = 1024 * 1024;
342 		break;
343 	case GEN7_STOLEN_RESERVED_256K:
344 		*size = 256 * 1024;
345 		break;
346 	default:
347 		*size = 1024 * 1024;
348 		MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
349 	}
350 }
351 
chv_get_stolen_reserved(struct drm_i915_private * i915,struct intel_uncore * uncore,resource_size_t * base,resource_size_t * size)352 static void chv_get_stolen_reserved(struct drm_i915_private *i915,
353 				    struct intel_uncore *uncore,
354 				    resource_size_t *base,
355 				    resource_size_t *size)
356 {
357 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
358 
359 	drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
360 
361 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
362 		return;
363 
364 	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
365 
366 	switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
367 	case GEN8_STOLEN_RESERVED_1M:
368 		*size = 1024 * 1024;
369 		break;
370 	case GEN8_STOLEN_RESERVED_2M:
371 		*size = 2 * 1024 * 1024;
372 		break;
373 	case GEN8_STOLEN_RESERVED_4M:
374 		*size = 4 * 1024 * 1024;
375 		break;
376 	case GEN8_STOLEN_RESERVED_8M:
377 		*size = 8 * 1024 * 1024;
378 		break;
379 	default:
380 		*size = 8 * 1024 * 1024;
381 		MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK);
382 	}
383 }
384 
bdw_get_stolen_reserved(struct drm_i915_private * i915,struct intel_uncore * uncore,resource_size_t * base,resource_size_t * size)385 static void bdw_get_stolen_reserved(struct drm_i915_private *i915,
386 				    struct intel_uncore *uncore,
387 				    resource_size_t *base,
388 				    resource_size_t *size)
389 {
390 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
391 	resource_size_t stolen_top = i915->dsm.stolen.end + 1;
392 
393 	drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
394 
395 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
396 		return;
397 
398 	if (!(reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK))
399 		return;
400 
401 	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
402 	*size = stolen_top - *base;
403 }
404 
icl_get_stolen_reserved(struct drm_i915_private * i915,struct intel_uncore * uncore,resource_size_t * base,resource_size_t * size)405 static void icl_get_stolen_reserved(struct drm_i915_private *i915,
406 				    struct intel_uncore *uncore,
407 				    resource_size_t *base,
408 				    resource_size_t *size)
409 {
410 	u64 reg_val = intel_uncore_read64(uncore, GEN6_STOLEN_RESERVED);
411 
412 	drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val);
413 
414 	/* Wa_14019821291 */
415 	if (MEDIA_VER_FULL(i915) == IP_VER(13, 0)) {
416 		/*
417 		 * This workaround is primarily implemented by the BIOS.  We
418 		 * just need to figure out whether the BIOS has applied the
419 		 * workaround (meaning the programmed address falls within
420 		 * the DSM) and, if so, reserve that part of the DSM to
421 		 * prevent accidental reuse.  The DSM location should be just
422 		 * below the WOPCM.
423 		 */
424 		u64 gscpsmi_base = intel_uncore_read64_2x32(uncore,
425 							    MTL_GSCPSMI_BASEADDR_LSB,
426 							    MTL_GSCPSMI_BASEADDR_MSB);
427 		if (gscpsmi_base >= i915->dsm.stolen.start &&
428 		    gscpsmi_base < i915->dsm.stolen.end) {
429 			*base = gscpsmi_base;
430 			*size = i915->dsm.stolen.end - gscpsmi_base;
431 			return;
432 		}
433 	}
434 
435 	switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
436 	case GEN8_STOLEN_RESERVED_1M:
437 		*size = 1024 * 1024;
438 		break;
439 	case GEN8_STOLEN_RESERVED_2M:
440 		*size = 2 * 1024 * 1024;
441 		break;
442 	case GEN8_STOLEN_RESERVED_4M:
443 		*size = 4 * 1024 * 1024;
444 		break;
445 	case GEN8_STOLEN_RESERVED_8M:
446 		*size = 8 * 1024 * 1024;
447 		break;
448 	default:
449 		*size = 8 * 1024 * 1024;
450 		MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK);
451 	}
452 
453 	if (HAS_LMEMBAR_SMEM_STOLEN(i915))
454 		/* the base is initialized to stolen top so subtract size to get base */
455 		*base -= *size;
456 	else
457 		*base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK;
458 }
459 
460 /*
461  * Initialize i915->dsm.reserved to contain the reserved space within the Data
462  * Stolen Memory. This is a range on the top of DSM that is reserved, not to
463  * be used by driver, so must be excluded from the region passed to the
464  * allocator later. In the spec this is also called as WOPCM.
465  *
466  * Our expectation is that the reserved space is at the top of the stolen
467  * region, as it has been the case for every platform, and *never* at the
468  * bottom, so the calculation here can be simplified.
469  */
init_reserved_stolen(struct drm_i915_private * i915)470 static int init_reserved_stolen(struct drm_i915_private *i915)
471 {
472 	struct intel_uncore *uncore = &i915->uncore;
473 	resource_size_t reserved_base, stolen_top;
474 	resource_size_t reserved_size;
475 	int ret = 0;
476 
477 	stolen_top = i915->dsm.stolen.end + 1;
478 	reserved_base = stolen_top;
479 	reserved_size = 0;
480 
481 	if (GRAPHICS_VER(i915) >= 11) {
482 		icl_get_stolen_reserved(i915, uncore,
483 					&reserved_base, &reserved_size);
484 	} else if (GRAPHICS_VER(i915) >= 8) {
485 		if (IS_CHERRYVIEW(i915) || IS_BROXTON(i915) || IS_GEMINILAKE(i915))
486 			chv_get_stolen_reserved(i915, uncore,
487 						&reserved_base, &reserved_size);
488 		else
489 			bdw_get_stolen_reserved(i915, uncore,
490 						&reserved_base, &reserved_size);
491 	} else if (GRAPHICS_VER(i915) >= 7) {
492 		if (IS_VALLEYVIEW(i915))
493 			vlv_get_stolen_reserved(i915, uncore,
494 						&reserved_base, &reserved_size);
495 		else
496 			gen7_get_stolen_reserved(i915, uncore,
497 						 &reserved_base, &reserved_size);
498 	} else if (GRAPHICS_VER(i915) >= 6) {
499 		gen6_get_stolen_reserved(i915, uncore,
500 					 &reserved_base, &reserved_size);
501 	} else if (GRAPHICS_VER(i915) >= 5 || IS_G4X(i915)) {
502 		g4x_get_stolen_reserved(i915, uncore,
503 					&reserved_base, &reserved_size);
504 	}
505 
506 	/* No reserved stolen */
507 	if (reserved_base == stolen_top)
508 		goto bail_out;
509 
510 	if (!reserved_base) {
511 		drm_err(&i915->drm,
512 			"inconsistent reservation %pa + %pa; ignoring\n",
513 			&reserved_base, &reserved_size);
514 		ret = -EINVAL;
515 		goto bail_out;
516 	}
517 
518 	i915->dsm.reserved = DEFINE_RES_MEM(reserved_base, reserved_size);
519 
520 	if (!resource_contains(&i915->dsm.stolen, &i915->dsm.reserved)) {
521 		drm_err(&i915->drm,
522 			"Stolen reserved area %pR outside stolen memory %pR\n",
523 			&i915->dsm.reserved, &i915->dsm.stolen);
524 		ret = -EINVAL;
525 		goto bail_out;
526 	}
527 
528 	return 0;
529 
530 bail_out:
531 	i915->dsm.reserved = DEFINE_RES_MEM(reserved_base, 0);
532 
533 	return ret;
534 }
535 
i915_gem_init_stolen(struct intel_memory_region * mem)536 static int i915_gem_init_stolen(struct intel_memory_region *mem)
537 {
538 	struct drm_i915_private *i915 = mem->i915;
539 
540 	mutex_init(&i915->mm.stolen_lock);
541 
542 	if (intel_vgpu_active(i915)) {
543 		drm_notice(&i915->drm,
544 			   "%s, disabling use of stolen memory\n",
545 			   "iGVT-g active");
546 		return -ENOSPC;
547 	}
548 
549 	if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) {
550 		drm_notice(&i915->drm,
551 			   "%s, disabling use of stolen memory\n",
552 			   "DMAR active");
553 		return -ENOSPC;
554 	}
555 
556 	if (adjust_stolen(i915, &mem->region))
557 		return -ENOSPC;
558 
559 	if (request_smem_stolen(i915, &mem->region))
560 		return -ENOSPC;
561 
562 	i915->dsm.stolen = mem->region;
563 
564 	if (init_reserved_stolen(i915))
565 		return -ENOSPC;
566 
567 	/* Exclude the reserved region from driver use */
568 	mem->region.end = i915->dsm.reserved.start - 1;
569 	mem->io = DEFINE_RES_MEM(mem->io.start,
570 				 min(resource_size(&mem->io),
571 				     resource_size(&mem->region)));
572 
573 	i915->dsm.usable_size = resource_size(&mem->region);
574 
575 	drm_dbg(&i915->drm,
576 		"Memory reserved for graphics device: %lluK, usable: %lluK\n",
577 		(u64)resource_size(&i915->dsm.stolen) >> 10,
578 		(u64)i915->dsm.usable_size >> 10);
579 
580 	if (i915->dsm.usable_size == 0)
581 		return -ENOSPC;
582 
583 	/* Basic memrange allocator for stolen space. */
584 	drm_mm_init(&i915->mm.stolen, 0, i915->dsm.usable_size);
585 
586 	/*
587 	 * Access to stolen lmem beyond certain size for MTL A0 stepping
588 	 * would crash the machine. Disable stolen lmem for userspace access
589 	 * by setting usable_size to zero.
590 	 */
591 	if (IS_METEORLAKE(i915) && INTEL_REVID(i915) == 0x0)
592 		i915->dsm.usable_size = 0;
593 
594 	return 0;
595 }
596 
dbg_poison(struct i915_ggtt * ggtt,dma_addr_t addr,resource_size_t size,u8 x)597 static void dbg_poison(struct i915_ggtt *ggtt,
598 		       dma_addr_t addr, resource_size_t size,
599 		       u8 x)
600 {
601 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
602 	if (!drm_mm_node_allocated(&ggtt->error_capture))
603 		return;
604 
605 	if (ggtt->vm.bind_async_flags & I915_VMA_GLOBAL_BIND)
606 		return; /* beware stop_machine() inversion */
607 
608 	GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
609 
610 	mutex_lock(&ggtt->error_mutex);
611 	while (size) {
612 		void __iomem *s;
613 
614 		ggtt->vm.insert_page(&ggtt->vm, addr,
615 				     ggtt->error_capture.start,
616 				     i915_gem_get_pat_index(ggtt->vm.i915,
617 							    I915_CACHE_NONE),
618 				     0);
619 		mb();
620 
621 		s = io_mapping_map_wc(&ggtt->iomap,
622 				      ggtt->error_capture.start,
623 				      PAGE_SIZE);
624 		memset_io(s, x, PAGE_SIZE);
625 		io_mapping_unmap(s);
626 
627 		addr += PAGE_SIZE;
628 		size -= PAGE_SIZE;
629 	}
630 	mb();
631 	ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
632 	mutex_unlock(&ggtt->error_mutex);
633 #endif
634 }
635 
636 static struct sg_table *
i915_pages_create_for_stolen(struct drm_device * dev,resource_size_t offset,resource_size_t size)637 i915_pages_create_for_stolen(struct drm_device *dev,
638 			     resource_size_t offset, resource_size_t size)
639 {
640 	struct drm_i915_private *i915 = to_i915(dev);
641 	struct sg_table *st;
642 	struct scatterlist *sg;
643 
644 	GEM_BUG_ON(range_overflows(offset, size, resource_size(&i915->dsm.stolen)));
645 
646 	/* We hide that we have no struct page backing our stolen object
647 	 * by wrapping the contiguous physical allocation with a fake
648 	 * dma mapping in a single scatterlist.
649 	 */
650 
651 	st = kmalloc_obj(*st);
652 	if (st == NULL)
653 		return ERR_PTR(-ENOMEM);
654 
655 	if (sg_alloc_table(st, 1, GFP_KERNEL)) {
656 		kfree(st);
657 		return ERR_PTR(-ENOMEM);
658 	}
659 
660 	sg = st->sgl;
661 	sg->offset = 0;
662 	sg->length = size;
663 
664 	sg_dma_address(sg) = (dma_addr_t)i915->dsm.stolen.start + offset;
665 	sg_dma_len(sg) = size;
666 
667 	return st;
668 }
669 
i915_gem_object_get_pages_stolen(struct drm_i915_gem_object * obj)670 static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
671 {
672 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
673 	struct sg_table *pages =
674 		i915_pages_create_for_stolen(obj->base.dev,
675 					     obj->stolen->start,
676 					     obj->stolen->size);
677 	if (IS_ERR(pages))
678 		return PTR_ERR(pages);
679 
680 	dbg_poison(to_gt(i915)->ggtt,
681 		   sg_dma_address(pages->sgl),
682 		   sg_dma_len(pages->sgl),
683 		   POISON_INUSE);
684 
685 	__i915_gem_object_set_pages(obj, pages);
686 
687 	return 0;
688 }
689 
i915_gem_object_put_pages_stolen(struct drm_i915_gem_object * obj,struct sg_table * pages)690 static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj,
691 					     struct sg_table *pages)
692 {
693 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
694 	/* Should only be called from i915_gem_object_release_stolen() */
695 
696 	dbg_poison(to_gt(i915)->ggtt,
697 		   sg_dma_address(pages->sgl),
698 		   sg_dma_len(pages->sgl),
699 		   POISON_FREE);
700 
701 	sg_free_table(pages);
702 	kfree(pages);
703 }
704 
705 static void
i915_gem_object_release_stolen(struct drm_i915_gem_object * obj)706 i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
707 {
708 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
709 	struct drm_mm_node *stolen = fetch_and_zero(&obj->stolen);
710 
711 	GEM_BUG_ON(!stolen);
712 	__i915_gem_stolen_remove_node(i915, stolen);
713 	kfree(stolen);
714 
715 	i915_gem_object_release_memory_region(obj);
716 }
717 
718 static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = {
719 	.name = "i915_gem_object_stolen",
720 	.get_pages = i915_gem_object_get_pages_stolen,
721 	.put_pages = i915_gem_object_put_pages_stolen,
722 	.release = i915_gem_object_release_stolen,
723 };
724 
__i915_gem_object_create_stolen(struct intel_memory_region * mem,struct drm_i915_gem_object * obj,struct drm_mm_node * stolen)725 static int __i915_gem_object_create_stolen(struct intel_memory_region *mem,
726 					   struct drm_i915_gem_object *obj,
727 					   struct drm_mm_node *stolen)
728 {
729 	static struct lock_class_key lock_class;
730 	unsigned int cache_level;
731 	unsigned int flags;
732 	int err;
733 
734 	/*
735 	 * Stolen objects are always physically contiguous since we just
736 	 * allocate one big block underneath using the drm_mm range allocator.
737 	 */
738 	flags = I915_BO_ALLOC_CONTIGUOUS;
739 
740 	drm_gem_private_object_init(&mem->i915->drm, &obj->base, stolen->size);
741 	i915_gem_object_init(obj, &i915_gem_object_stolen_ops, &lock_class, flags);
742 
743 	obj->stolen = stolen;
744 	obj->read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT;
745 	cache_level = HAS_LLC(mem->i915) ? I915_CACHE_LLC : I915_CACHE_NONE;
746 	i915_gem_object_set_cache_coherency(obj, cache_level);
747 
748 	if (WARN_ON(!i915_gem_object_trylock(obj, NULL)))
749 		return -EBUSY;
750 
751 	i915_gem_object_init_memory_region(obj, mem);
752 
753 	err = i915_gem_object_pin_pages(obj);
754 	if (err)
755 		i915_gem_object_release_memory_region(obj);
756 	i915_gem_object_unlock(obj);
757 
758 	return err;
759 }
760 
_i915_gem_object_stolen_init(struct intel_memory_region * mem,struct drm_i915_gem_object * obj,resource_size_t offset,resource_size_t size,resource_size_t page_size,unsigned int flags)761 static int _i915_gem_object_stolen_init(struct intel_memory_region *mem,
762 					struct drm_i915_gem_object *obj,
763 					resource_size_t offset,
764 					resource_size_t size,
765 					resource_size_t page_size,
766 					unsigned int flags)
767 {
768 	struct drm_i915_private *i915 = mem->i915;
769 	struct drm_mm_node *stolen;
770 	int ret;
771 
772 	if (!drm_mm_initialized(&i915->mm.stolen))
773 		return -ENODEV;
774 
775 	if (size == 0)
776 		return -EINVAL;
777 
778 	/*
779 	 * With discrete devices, where we lack a mappable aperture there is no
780 	 * possible way to ever access this memory on the CPU side.
781 	 */
782 	if (mem->type == INTEL_MEMORY_STOLEN_LOCAL && !resource_size(&mem->io) &&
783 	    !(flags & I915_BO_ALLOC_GPU_ONLY))
784 		return -ENOSPC;
785 
786 	stolen = kzalloc_obj(*stolen);
787 	if (!stolen)
788 		return -ENOMEM;
789 
790 	if (offset != I915_BO_INVALID_OFFSET) {
791 		drm_dbg(&i915->drm,
792 			"creating preallocated stolen object: stolen_offset=%pa, size=%pa\n",
793 			&offset, &size);
794 
795 		stolen->start = offset;
796 		stolen->size = size;
797 		mutex_lock(&i915->mm.stolen_lock);
798 		ret = drm_mm_reserve_node(&i915->mm.stolen, stolen);
799 		mutex_unlock(&i915->mm.stolen_lock);
800 	} else {
801 		ret = __i915_gem_stolen_insert_node(i915, stolen, size,
802 						    mem->min_page_size);
803 	}
804 	if (ret)
805 		goto err_free;
806 
807 	ret = __i915_gem_object_create_stolen(mem, obj, stolen);
808 	if (ret)
809 		goto err_remove;
810 
811 	return 0;
812 
813 err_remove:
814 	__i915_gem_stolen_remove_node(i915, stolen);
815 err_free:
816 	kfree(stolen);
817 	return ret;
818 }
819 
820 struct drm_i915_gem_object *
i915_gem_object_create_stolen(struct drm_i915_private * i915,resource_size_t size)821 i915_gem_object_create_stolen(struct drm_i915_private *i915,
822 			      resource_size_t size)
823 {
824 	return i915_gem_object_create_region(i915->mm.stolen_region, size, 0, 0);
825 }
826 
init_stolen_smem(struct intel_memory_region * mem)827 static int init_stolen_smem(struct intel_memory_region *mem)
828 {
829 	int err;
830 
831 	/*
832 	 * Initialise stolen early so that we may reserve preallocated
833 	 * objects for the BIOS to KMS transition.
834 	 */
835 	err = i915_gem_init_stolen(mem);
836 	if (err)
837 		drm_dbg(&mem->i915->drm, "Skip stolen region: failed to setup\n");
838 
839 	return 0;
840 }
841 
release_stolen_smem(struct intel_memory_region * mem)842 static int release_stolen_smem(struct intel_memory_region *mem)
843 {
844 	i915_gem_cleanup_stolen(mem->i915);
845 	return 0;
846 }
847 
848 static const struct intel_memory_region_ops i915_region_stolen_smem_ops = {
849 	.init = init_stolen_smem,
850 	.release = release_stolen_smem,
851 	.init_object = _i915_gem_object_stolen_init,
852 };
853 
init_stolen_lmem(struct intel_memory_region * mem)854 static int init_stolen_lmem(struct intel_memory_region *mem)
855 {
856 	int err;
857 
858 	if (GEM_WARN_ON(resource_size(&mem->region) == 0))
859 		return 0;
860 
861 	err = i915_gem_init_stolen(mem);
862 	if (err) {
863 		drm_dbg(&mem->i915->drm, "Skip stolen region: failed to setup\n");
864 		return 0;
865 	}
866 
867 	if (resource_size(&mem->io) &&
868 	    !io_mapping_init_wc(&mem->iomap, mem->io.start, resource_size(&mem->io)))
869 		goto err_cleanup;
870 
871 	return 0;
872 
873 err_cleanup:
874 	i915_gem_cleanup_stolen(mem->i915);
875 	return err;
876 }
877 
release_stolen_lmem(struct intel_memory_region * mem)878 static int release_stolen_lmem(struct intel_memory_region *mem)
879 {
880 	if (resource_size(&mem->io))
881 		io_mapping_fini(&mem->iomap);
882 	i915_gem_cleanup_stolen(mem->i915);
883 	return 0;
884 }
885 
886 static const struct intel_memory_region_ops i915_region_stolen_lmem_ops = {
887 	.init = init_stolen_lmem,
888 	.release = release_stolen_lmem,
889 	.init_object = _i915_gem_object_stolen_init,
890 };
891 
mtl_get_gms_size(struct intel_uncore * uncore)892 static int mtl_get_gms_size(struct intel_uncore *uncore)
893 {
894 	u16 ggc, gms;
895 
896 	ggc = intel_uncore_read16(uncore, GGC);
897 
898 	/* check GGMS, should be fixed 0x3 (8MB) */
899 	if ((ggc & GGMS_MASK) != GGMS_MASK)
900 		return -EIO;
901 
902 	/* return valid GMS value, -EIO if invalid */
903 	gms = REG_FIELD_GET(GMS_MASK, ggc);
904 	switch (gms) {
905 	case 0x0 ... 0x04:
906 		return gms * 32;
907 	case 0xf0 ... 0xfe:
908 		return (gms - 0xf0 + 1) * 4;
909 	default:
910 		MISSING_CASE(gms);
911 		return -EIO;
912 	}
913 }
914 
915 struct intel_memory_region *
i915_gem_stolen_lmem_setup(struct drm_i915_private * i915,u16 type,u16 instance)916 i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type,
917 			   u16 instance)
918 {
919 	struct intel_uncore *uncore = &i915->uncore;
920 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
921 	resource_size_t dsm_size, dsm_base, lmem_size;
922 	struct intel_memory_region *mem;
923 	resource_size_t io_start, io_size;
924 	resource_size_t min_page_size;
925 	int ret;
926 
927 	if (WARN_ON_ONCE(instance))
928 		return ERR_PTR(-ENODEV);
929 
930 	if (!i915_pci_resource_valid(pdev, GEN12_LMEM_BAR))
931 		return ERR_PTR(-ENXIO);
932 
933 	if (HAS_LMEMBAR_SMEM_STOLEN(i915) || IS_DG1(i915)) {
934 		lmem_size = pci_resource_len(pdev, GEN12_LMEM_BAR);
935 	} else {
936 		resource_size_t lmem_range;
937 
938 		lmem_range = intel_gt_mcr_read_any(to_gt(i915), XEHP_TILE0_ADDR_RANGE) & 0xFFFF;
939 		lmem_size = lmem_range >> XEHP_TILE_LMEM_RANGE_SHIFT;
940 		lmem_size *= SZ_1G;
941 	}
942 
943 	if (HAS_LMEMBAR_SMEM_STOLEN(i915)) {
944 		/*
945 		 * MTL dsm size is in GGC register.
946 		 * Also MTL uses offset to GSMBASE in ptes, so i915
947 		 * uses dsm_base = 8MBs to setup stolen region, since
948 		 * DSMBASE = GSMBASE + 8MB.
949 		 */
950 		ret = mtl_get_gms_size(uncore);
951 		if (ret < 0) {
952 			drm_err(&i915->drm, "invalid MTL GGC register setting\n");
953 			return ERR_PTR(ret);
954 		}
955 
956 		dsm_base = SZ_8M;
957 		dsm_size = (resource_size_t)(ret * SZ_1M);
958 
959 		GEM_BUG_ON(pci_resource_len(pdev, GEN12_LMEM_BAR) != SZ_256M);
960 		GEM_BUG_ON((dsm_base + dsm_size) > lmem_size);
961 	} else {
962 		/* Use DSM base address instead for stolen memory */
963 		dsm_base = intel_uncore_read64(uncore, GEN6_DSMBASE) & GEN11_BDSM_MASK;
964 		if (lmem_size < dsm_base) {
965 			drm_dbg(&i915->drm,
966 				"Disabling stolen memory support due to OOB placement: lmem_size = %pa vs dsm_base = %pa\n",
967 				&lmem_size, &dsm_base);
968 			return NULL;
969 		}
970 		dsm_size = ALIGN_DOWN(lmem_size - dsm_base, SZ_1M);
971 	}
972 
973 	if (i915_direct_stolen_access(i915)) {
974 		drm_dbg(&i915->drm, "Using direct DSM access\n");
975 		io_start = intel_uncore_read64(uncore, GEN6_DSMBASE) & GEN11_BDSM_MASK;
976 		io_size = dsm_size;
977 	} else if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) {
978 		io_start = 0;
979 		io_size = 0;
980 	} else {
981 		io_start = pci_resource_start(pdev, GEN12_LMEM_BAR) + dsm_base;
982 		io_size = dsm_size;
983 	}
984 
985 	min_page_size = HAS_64K_PAGES(i915) ? I915_GTT_PAGE_SIZE_64K :
986 						I915_GTT_PAGE_SIZE_4K;
987 
988 	mem = intel_memory_region_create(i915, dsm_base, dsm_size,
989 					 min_page_size,
990 					 io_start, io_size,
991 					 type, instance,
992 					 &i915_region_stolen_lmem_ops);
993 	if (IS_ERR(mem))
994 		return mem;
995 
996 	intel_memory_region_set_name(mem, "stolen-local");
997 
998 	mem->private = true;
999 
1000 	return mem;
1001 }
1002 
1003 struct intel_memory_region*
i915_gem_stolen_smem_setup(struct drm_i915_private * i915,u16 type,u16 instance)1004 i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type,
1005 			   u16 instance)
1006 {
1007 	struct intel_memory_region *mem;
1008 
1009 	mem = intel_memory_region_create(i915,
1010 					 intel_graphics_stolen_res.start,
1011 					 resource_size(&intel_graphics_stolen_res),
1012 					 PAGE_SIZE, 0, 0, type, instance,
1013 					 &i915_region_stolen_smem_ops);
1014 	if (IS_ERR(mem))
1015 		return mem;
1016 
1017 	intel_memory_region_set_name(mem, "stolen-system");
1018 
1019 	mem->private = true;
1020 
1021 	return mem;
1022 }
1023 
i915_gem_object_is_stolen(const struct drm_i915_gem_object * obj)1024 bool i915_gem_object_is_stolen(const struct drm_i915_gem_object *obj)
1025 {
1026 	return obj->ops == &i915_gem_object_stolen_ops;
1027 }
1028 
i915_gem_stolen_initialized(struct drm_device * drm)1029 static bool i915_gem_stolen_initialized(struct drm_device *drm)
1030 {
1031 	struct drm_i915_private *i915 = to_i915(drm);
1032 
1033 	return drm_mm_initialized(&i915->mm.stolen);
1034 }
1035 
i915_gem_stolen_area_address(struct drm_device * drm)1036 static u64 i915_gem_stolen_area_address(struct drm_device *drm)
1037 {
1038 	struct drm_i915_private *i915 = to_i915(drm);
1039 
1040 	return i915->dsm.stolen.start;
1041 }
1042 
i915_gem_stolen_area_size(struct drm_device * drm)1043 static u64 i915_gem_stolen_area_size(struct drm_device *drm)
1044 {
1045 	struct drm_i915_private *i915 = to_i915(drm);
1046 
1047 	return resource_size(&i915->dsm.stolen);
1048 }
1049 
i915_gem_stolen_node_offset(const struct intel_stolen_node * node)1050 static u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node)
1051 {
1052 	return node->node.start;
1053 }
1054 
i915_gem_stolen_node_address(const struct intel_stolen_node * node)1055 static u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node)
1056 {
1057 	struct drm_i915_private *i915 = node->i915;
1058 
1059 	return i915->dsm.stolen.start + i915_gem_stolen_node_offset(node);
1060 }
1061 
i915_gem_stolen_node_allocated(const struct intel_stolen_node * node)1062 static bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node)
1063 {
1064 	return drm_mm_node_allocated(&node->node);
1065 }
1066 
i915_gem_stolen_node_size(const struct intel_stolen_node * node)1067 static u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node)
1068 {
1069 	return node->node.size;
1070 }
1071 
i915_gem_stolen_node_alloc(struct drm_device * drm)1072 static struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm)
1073 {
1074 	struct drm_i915_private *i915 = to_i915(drm);
1075 	struct intel_stolen_node *node;
1076 
1077 	node = kzalloc_obj(*node);
1078 	if (!node)
1079 		return NULL;
1080 
1081 	node->i915 = i915;
1082 
1083 	return node;
1084 }
1085 
i915_gem_stolen_node_free(const struct intel_stolen_node * node)1086 static void i915_gem_stolen_node_free(const struct intel_stolen_node *node)
1087 {
1088 	kfree(node);
1089 }
1090 
1091 const struct intel_display_stolen_interface i915_display_stolen_interface = {
1092 	.insert_node_in_range = i915_gem_stolen_insert_node_in_range,
1093 	.insert_node = i915_gem_stolen_insert_node,
1094 	.remove_node = i915_gem_stolen_remove_node,
1095 	.initialized = i915_gem_stolen_initialized,
1096 	.node_allocated = i915_gem_stolen_node_allocated,
1097 	.node_offset = i915_gem_stolen_node_offset,
1098 	.area_address = i915_gem_stolen_area_address,
1099 	.area_size = i915_gem_stolen_area_size,
1100 	.node_address = i915_gem_stolen_node_address,
1101 	.node_size = i915_gem_stolen_node_size,
1102 	.node_alloc = i915_gem_stolen_node_alloc,
1103 	.node_free = i915_gem_stolen_node_free,
1104 };
1105