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