Home | History | Annotate | Line # | Download | only in gem
      1 /*	$NetBSD: i915_gem_stolen.c,v 1.7 2024/01/19 22:24:38 riastradh Exp $	*/
      2 
      3 /*
      4  * SPDX-License-Identifier: MIT
      5  *
      6  * Copyright  2008-2012 Intel Corporation
      7  */
      8 
      9 #include <sys/cdefs.h>
     10 __KERNEL_RCSID(0, "$NetBSD: i915_gem_stolen.c,v 1.7 2024/01/19 22:24:38 riastradh Exp $");
     11 
     12 #include <linux/errno.h>
     13 #include <linux/mutex.h>
     14 
     15 #include <drm/drm_mm.h>
     16 #include <drm/i915_drm.h>
     17 
     18 #include "gem/i915_gem_region.h"
     19 #include "i915_drv.h"
     20 #include "i915_gem_stolen.h"
     21 
     22 #include <linux/nbsd-namespace.h>
     23 
     24 /*
     25  * The BIOS typically reserves some of the system's memory for the exclusive
     26  * use of the integrated graphics. This memory is no longer available for
     27  * use by the OS and so the user finds that his system has less memory
     28  * available than he put in. We refer to this memory as stolen.
     29  *
     30  * The BIOS will allocate its framebuffer from the stolen memory. Our
     31  * goal is try to reuse that object for our own fbcon which must always
     32  * be available for panics. Anything else we can reuse the stolen memory
     33  * for is a boon.
     34  */
     35 
     36 int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915,
     37 					 struct drm_mm_node *node, u64 size,
     38 					 unsigned alignment, u64 start, u64 end)
     39 {
     40 	int ret;
     41 
     42 	if (!drm_mm_initialized(&i915->mm.stolen))
     43 		return -ENODEV;
     44 
     45 	/* WaSkipStolenMemoryFirstPage:bdw+ */
     46 	if (INTEL_GEN(i915) >= 8 && start < 4096)
     47 		start = 4096;
     48 
     49 	mutex_lock(&i915->mm.stolen_lock);
     50 	ret = drm_mm_insert_node_in_range(&i915->mm.stolen, node,
     51 					  size, alignment, 0,
     52 					  start, end, DRM_MM_INSERT_BEST);
     53 	mutex_unlock(&i915->mm.stolen_lock);
     54 
     55 	return ret;
     56 }
     57 
     58 int i915_gem_stolen_insert_node(struct drm_i915_private *i915,
     59 				struct drm_mm_node *node, u64 size,
     60 				unsigned alignment)
     61 {
     62 	return i915_gem_stolen_insert_node_in_range(i915, node, size,
     63 						    alignment, 0, U64_MAX);
     64 }
     65 
     66 void i915_gem_stolen_remove_node(struct drm_i915_private *i915,
     67 				 struct drm_mm_node *node)
     68 {
     69 	mutex_lock(&i915->mm.stolen_lock);
     70 	drm_mm_remove_node(node);
     71 	mutex_unlock(&i915->mm.stolen_lock);
     72 }
     73 
     74 static int i915_adjust_stolen(struct drm_i915_private *i915,
     75 			      struct resource *dsm)
     76 {
     77 	struct i915_ggtt *ggtt = &i915->ggtt;
     78 	struct intel_uncore *uncore = ggtt->vm.gt->uncore;
     79 	struct resource *r;
     80 
     81 	if (dsm->start == 0 || dsm->end <= dsm->start)
     82 		return -EINVAL;
     83 
     84 	/*
     85 	 * TODO: We have yet too encounter the case where the GTT wasn't at the
     86 	 * end of stolen. With that assumption we could simplify this.
     87 	 */
     88 
     89 	/* Make sure we don't clobber the GTT if it's within stolen memory */
     90 	if (INTEL_GEN(i915) <= 4 &&
     91 	    !IS_G33(i915) && !IS_PINEVIEW(i915) && !IS_G4X(i915)) {
     92 		struct resource stolen[2] = {*dsm, *dsm};
     93 		struct resource ggtt_res;
     94 		resource_size_t ggtt_start;
     95 
     96 		ggtt_start = intel_uncore_read(uncore, PGTBL_CTL);
     97 		if (IS_GEN(i915, 4))
     98 			ggtt_start = (ggtt_start & PGTBL_ADDRESS_LO_MASK) |
     99 				     (ggtt_start & PGTBL_ADDRESS_HI_MASK) << 28;
    100 		else
    101 			ggtt_start &= PGTBL_ADDRESS_LO_MASK;
    102 
    103 		ggtt_res =
    104 			(struct resource) DEFINE_RES_MEM(ggtt_start,
    105 							 ggtt_total_entries(ggtt) * 4);
    106 
    107 		if (ggtt_res.start >= stolen[0].start && ggtt_res.start < stolen[0].end)
    108 			stolen[0].end = ggtt_res.start;
    109 		if (ggtt_res.end > stolen[1].start && ggtt_res.end <= stolen[1].end)
    110 			stolen[1].start = ggtt_res.end;
    111 
    112 		/* Pick the larger of the two chunks */
    113 		if (resource_size(&stolen[0]) > resource_size(&stolen[1]))
    114 			*dsm = stolen[0];
    115 		else
    116 			*dsm = stolen[1];
    117 
    118 		if (stolen[0].start != stolen[1].start ||
    119 		    stolen[0].end != stolen[1].end) {
    120 			DRM_DEBUG_DRIVER("GTT within stolen memory at %pR\n", &ggtt_res);
    121 			DRM_DEBUG_DRIVER("Stolen memory adjusted to %pR\n", dsm);
    122 		}
    123 	}
    124 
    125 #ifdef __NetBSD__		/* XXX */
    126 	__USE(r);
    127 #else
    128 	/*
    129 	 * Verify that nothing else uses this physical address. Stolen
    130 	 * memory should be reserved by the BIOS and hidden from the
    131 	 * kernel. So if the region is already marked as busy, something
    132 	 * is seriously wrong.
    133 	 */
    134 	r = devm_request_mem_region(i915->drm.dev, dsm->start,
    135 				    resource_size(dsm),
    136 				    "Graphics Stolen Memory");
    137 	if (r == NULL) {
    138 		/*
    139 		 * One more attempt but this time requesting region from
    140 		 * start + 1, as we have seen that this resolves the region
    141 		 * conflict with the PCI Bus.
    142 		 * This is a BIOS w/a: Some BIOS wrap stolen in the root
    143 		 * PCI bus, but have an off-by-one error. Hence retry the
    144 		 * reservation starting from 1 instead of 0.
    145 		 * There's also BIOS with off-by-one on the other end.
    146 		 */
    147 		r = devm_request_mem_region(i915->drm.dev, dsm->start + 1,
    148 					    resource_size(dsm) - 2,
    149 					    "Graphics Stolen Memory");
    150 		/*
    151 		 * GEN3 firmware likes to smash pci bridges into the stolen
    152 		 * range. Apparently this works.
    153 		 */
    154 		if (!r && !IS_GEN(i915, 3)) {
    155 			DRM_ERROR("conflict detected with stolen region: %pR\n",
    156 				  dsm);
    157 
    158 			return -EBUSY;
    159 		}
    160 	}
    161 #endif
    162 
    163 	return 0;
    164 }
    165 
    166 static void i915_gem_cleanup_stolen(struct drm_i915_private *i915)
    167 {
    168 	if (!drm_mm_initialized(&i915->mm.stolen))
    169 		return;
    170 
    171 	mutex_destroy(&i915->mm.stolen_lock);
    172 	drm_mm_takedown(&i915->mm.stolen);
    173 }
    174 
    175 static void g4x_get_stolen_reserved(struct drm_i915_private *i915,
    176 				    struct intel_uncore *uncore,
    177 				    resource_size_t *base,
    178 				    resource_size_t *size)
    179 {
    180 	u32 reg_val = intel_uncore_read(uncore,
    181 					IS_GM45(i915) ?
    182 					CTG_STOLEN_RESERVED :
    183 					ELK_STOLEN_RESERVED);
    184 	resource_size_t stolen_top = i915->dsm.end + 1;
    185 
    186 	DRM_DEBUG_DRIVER("%s_STOLEN_RESERVED = %08x\n",
    187 			 IS_GM45(i915) ? "CTG" : "ELK", reg_val);
    188 
    189 	if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0)
    190 		return;
    191 
    192 	/*
    193 	 * Whether ILK really reuses the ELK register for this is unclear.
    194 	 * Let's see if we catch anyone with this supposedly enabled on ILK.
    195 	 */
    196 	WARN(IS_GEN(i915, 5), "ILK stolen reserved found? 0x%08x\n",
    197 	     reg_val);
    198 
    199 	if (!(reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK))
    200 		return;
    201 
    202 	if (!(reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK))
    203 		return;
    204 
    205 	*base = (reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK) << 16;
    206 	WARN_ON((reg_val & G4X_STOLEN_RESERVED_ADDR1_MASK) < *base);
    207 
    208 	*size = stolen_top - *base;
    209 }
    210 
    211 static void gen6_get_stolen_reserved(struct drm_i915_private *i915,
    212 				     struct intel_uncore *uncore,
    213 				     resource_size_t *base,
    214 				     resource_size_t *size)
    215 {
    216 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
    217 
    218 	DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val);
    219 
    220 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
    221 		return;
    222 
    223 	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
    224 
    225 	switch (reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK) {
    226 	case GEN6_STOLEN_RESERVED_1M:
    227 		*size = 1024 * 1024;
    228 		break;
    229 	case GEN6_STOLEN_RESERVED_512K:
    230 		*size = 512 * 1024;
    231 		break;
    232 	case GEN6_STOLEN_RESERVED_256K:
    233 		*size = 256 * 1024;
    234 		break;
    235 	case GEN6_STOLEN_RESERVED_128K:
    236 		*size = 128 * 1024;
    237 		break;
    238 	default:
    239 		*size = 1024 * 1024;
    240 		MISSING_CASE(reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK);
    241 	}
    242 }
    243 
    244 static void vlv_get_stolen_reserved(struct drm_i915_private *i915,
    245 				    struct intel_uncore *uncore,
    246 				    resource_size_t *base,
    247 				    resource_size_t *size)
    248 {
    249 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
    250 	resource_size_t stolen_top = i915->dsm.end + 1;
    251 
    252 	DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val);
    253 
    254 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
    255 		return;
    256 
    257 	switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
    258 	default:
    259 		MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
    260 		/* fall through */
    261 	case GEN7_STOLEN_RESERVED_1M:
    262 		*size = 1024 * 1024;
    263 		break;
    264 	}
    265 
    266 	/*
    267 	 * On vlv, the ADDR_MASK portion is left as 0 and HW deduces the
    268 	 * reserved location as (top - size).
    269 	 */
    270 	*base = stolen_top - *size;
    271 }
    272 
    273 static void gen7_get_stolen_reserved(struct drm_i915_private *i915,
    274 				     struct intel_uncore *uncore,
    275 				     resource_size_t *base,
    276 				     resource_size_t *size)
    277 {
    278 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
    279 
    280 	DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val);
    281 
    282 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
    283 		return;
    284 
    285 	*base = reg_val & GEN7_STOLEN_RESERVED_ADDR_MASK;
    286 
    287 	switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
    288 	case GEN7_STOLEN_RESERVED_1M:
    289 		*size = 1024 * 1024;
    290 		break;
    291 	case GEN7_STOLEN_RESERVED_256K:
    292 		*size = 256 * 1024;
    293 		break;
    294 	default:
    295 		*size = 1024 * 1024;
    296 		MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
    297 	}
    298 }
    299 
    300 static void chv_get_stolen_reserved(struct drm_i915_private *i915,
    301 				    struct intel_uncore *uncore,
    302 				    resource_size_t *base,
    303 				    resource_size_t *size)
    304 {
    305 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
    306 
    307 	DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val);
    308 
    309 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
    310 		return;
    311 
    312 	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
    313 
    314 	switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
    315 	case GEN8_STOLEN_RESERVED_1M:
    316 		*size = 1024 * 1024;
    317 		break;
    318 	case GEN8_STOLEN_RESERVED_2M:
    319 		*size = 2 * 1024 * 1024;
    320 		break;
    321 	case GEN8_STOLEN_RESERVED_4M:
    322 		*size = 4 * 1024 * 1024;
    323 		break;
    324 	case GEN8_STOLEN_RESERVED_8M:
    325 		*size = 8 * 1024 * 1024;
    326 		break;
    327 	default:
    328 		*size = 8 * 1024 * 1024;
    329 		MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK);
    330 	}
    331 }
    332 
    333 static void bdw_get_stolen_reserved(struct drm_i915_private *i915,
    334 				    struct intel_uncore *uncore,
    335 				    resource_size_t *base,
    336 				    resource_size_t *size)
    337 {
    338 	u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
    339 	resource_size_t stolen_top = i915->dsm.end + 1;
    340 
    341 	DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val);
    342 
    343 	if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE))
    344 		return;
    345 
    346 	if (!(reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK))
    347 		return;
    348 
    349 	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
    350 	*size = stolen_top - *base;
    351 }
    352 
    353 static void icl_get_stolen_reserved(struct drm_i915_private *i915,
    354 				    struct intel_uncore *uncore,
    355 				    resource_size_t *base,
    356 				    resource_size_t *size)
    357 {
    358 	u64 reg_val = intel_uncore_read64(uncore, GEN6_STOLEN_RESERVED);
    359 
    360 	DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = 0x%016"PRIx64"\n", reg_val);
    361 
    362 	*base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK;
    363 
    364 	switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
    365 	case GEN8_STOLEN_RESERVED_1M:
    366 		*size = 1024 * 1024;
    367 		break;
    368 	case GEN8_STOLEN_RESERVED_2M:
    369 		*size = 2 * 1024 * 1024;
    370 		break;
    371 	case GEN8_STOLEN_RESERVED_4M:
    372 		*size = 4 * 1024 * 1024;
    373 		break;
    374 	case GEN8_STOLEN_RESERVED_8M:
    375 		*size = 8 * 1024 * 1024;
    376 		break;
    377 	default:
    378 		*size = 8 * 1024 * 1024;
    379 		MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK);
    380 	}
    381 }
    382 
    383 static int i915_gem_init_stolen(struct drm_i915_private *i915)
    384 {
    385 	struct intel_uncore *uncore = &i915->uncore;
    386 	resource_size_t reserved_base, stolen_top;
    387 	resource_size_t reserved_total, reserved_size;
    388 
    389 	mutex_init(&i915->mm.stolen_lock);
    390 
    391 	if (intel_vgpu_active(i915)) {
    392 		dev_notice(i915->drm.dev,
    393 			   "%s, disabling use of stolen memory\n",
    394 			   "iGVT-g active");
    395 		return 0;
    396 	}
    397 
    398 	if (intel_vtd_active() && INTEL_GEN(i915) < 8) {
    399 		dev_notice(i915->drm.dev,
    400 			   "%s, disabling use of stolen memory\n",
    401 			   "DMAR active");
    402 		return 0;
    403 	}
    404 
    405 	if (resource_size(&intel_graphics_stolen_res) == 0)
    406 		return 0;
    407 
    408 	i915->dsm = intel_graphics_stolen_res;
    409 
    410 	if (i915_adjust_stolen(i915, &i915->dsm))
    411 		return 0;
    412 
    413 	GEM_BUG_ON(i915->dsm.start == 0);
    414 	GEM_BUG_ON(i915->dsm.end <= i915->dsm.start);
    415 
    416 	stolen_top = i915->dsm.end + 1;
    417 	reserved_base = stolen_top;
    418 	reserved_size = 0;
    419 
    420 	switch (INTEL_GEN(i915)) {
    421 	case 2:
    422 	case 3:
    423 		break;
    424 	case 4:
    425 		if (!IS_G4X(i915))
    426 			break;
    427 		/* fall through */
    428 	case 5:
    429 		g4x_get_stolen_reserved(i915, uncore,
    430 					&reserved_base, &reserved_size);
    431 		break;
    432 	case 6:
    433 		gen6_get_stolen_reserved(i915, uncore,
    434 					 &reserved_base, &reserved_size);
    435 		break;
    436 	case 7:
    437 		if (IS_VALLEYVIEW(i915))
    438 			vlv_get_stolen_reserved(i915, uncore,
    439 						&reserved_base, &reserved_size);
    440 		else
    441 			gen7_get_stolen_reserved(i915, uncore,
    442 						 &reserved_base, &reserved_size);
    443 		break;
    444 	case 8:
    445 	case 9:
    446 	case 10:
    447 		if (IS_LP(i915))
    448 			chv_get_stolen_reserved(i915, uncore,
    449 						&reserved_base, &reserved_size);
    450 		else
    451 			bdw_get_stolen_reserved(i915, uncore,
    452 						&reserved_base, &reserved_size);
    453 		break;
    454 	default:
    455 		MISSING_CASE(INTEL_GEN(i915));
    456 		/* fall-through */
    457 	case 11:
    458 	case 12:
    459 		icl_get_stolen_reserved(i915, uncore,
    460 					&reserved_base,
    461 					&reserved_size);
    462 		break;
    463 	}
    464 
    465 	/*
    466 	 * Our expectation is that the reserved space is at the top of the
    467 	 * stolen region and *never* at the bottom. If we see !reserved_base,
    468 	 * it likely means we failed to read the registers correctly.
    469 	 */
    470 	if (!reserved_base) {
    471 		DRM_ERROR("inconsistent reservation %pa + %pa; ignoring\n",
    472 			  &reserved_base, &reserved_size);
    473 		reserved_base = stolen_top;
    474 		reserved_size = 0;
    475 	}
    476 
    477 	i915->dsm_reserved =
    478 		(struct resource)DEFINE_RES_MEM(reserved_base, reserved_size);
    479 
    480 	if (!resource_contains(&i915->dsm, &i915->dsm_reserved)) {
    481 		DRM_ERROR("Stolen reserved area %pR outside stolen memory %pR\n",
    482 			  &i915->dsm_reserved, &i915->dsm);
    483 		return 0;
    484 	}
    485 
    486 	/* It is possible for the reserved area to end before the end of stolen
    487 	 * memory, so just consider the start. */
    488 	reserved_total = stolen_top - reserved_base;
    489 
    490 	DRM_DEBUG_DRIVER("Memory reserved for graphics device: %"PRIu64"K, usable: %"PRIu64"K\n",
    491 			 (u64)resource_size(&i915->dsm) >> 10,
    492 			 ((u64)resource_size(&i915->dsm) - reserved_total) >> 10);
    493 
    494 	i915->stolen_usable_size =
    495 		resource_size(&i915->dsm) - reserved_total;
    496 
    497 	/* Basic memrange allocator for stolen space. */
    498 	drm_mm_init(&i915->mm.stolen, 0, i915->stolen_usable_size);
    499 
    500 	return 0;
    501 }
    502 
    503 static struct sg_table *
    504 i915_pages_create_for_stolen(struct drm_device *dev,
    505 			     resource_size_t offset, resource_size_t size)
    506 {
    507 	struct drm_i915_private *i915 = to_i915(dev);
    508 	struct sg_table *st;
    509 	struct scatterlist *sg;
    510 #ifdef __NetBSD__
    511 	bus_dma_tag_t dmat = i915->drm.dmat;
    512 	bus_dma_segment_t *seg = NULL;
    513 	int nseg = 0, i;
    514 	bool loaded = false;
    515 	int ret;
    516 #endif
    517 
    518 	GEM_BUG_ON(range_overflows(offset, size, resource_size(&i915->dsm)));
    519 
    520 	/* We hide that we have no struct page backing our stolen object
    521 	 * by wrapping the contiguous physical allocation with a fake
    522 	 * dma mapping in a single scatterlist.
    523 	 */
    524 
    525 	st = kmalloc(sizeof(*st), GFP_KERNEL);
    526 	if (st == NULL)
    527 		return ERR_PTR(-ENOMEM);
    528 
    529 #ifdef __NetBSD__
    530 	KASSERT((size % PAGE_SIZE) == 0);
    531 	nseg = size / PAGE_SIZE;
    532 	seg = kmem_alloc(nseg * sizeof(seg[0]), KM_SLEEP);
    533 
    534 	/*
    535 	 * XXX x86 bus_dmamap_load_raw fails to respect the maxsegsz we
    536 	 * pass to bus_dmamap_create, so we have to create page-sized
    537 	 * segments to begin with.
    538 	 */
    539 	for (i = 0; i < nseg; i++) {
    540 		seg[i].ds_addr = (bus_addr_t)i915->dsm.start + offset +
    541 		    i*PAGE_SIZE;
    542 		seg[i].ds_len = PAGE_SIZE;
    543 	}
    544 
    545 	sg = NULL;
    546 
    547 	ret = sg_alloc_table_from_bus_dmamem(st, dmat, seg, nseg, GFP_KERNEL);
    548 	if (ret) {
    549 		DRM_ERROR("failed to alloc sg table for stolen object: %d\n",
    550 		    ret);
    551 		ret = -ENOMEM;
    552 		goto out;
    553 	}
    554 	sg = st->sgl;
    555 
    556 	/* XXX errno NetBSD->Linux */
    557 	ret = -bus_dmamap_create(dmat, size, nseg, PAGE_SIZE, 0,
    558 	    BUS_DMA_WAITOK, &st->sgl->sg_dmamap);
    559 	if (ret) {
    560 		DRM_ERROR("failed to create DMA map for stolen object: %d\n",
    561 		    ret);
    562 		st->sgl->sg_dmamap = NULL;
    563 		goto out;
    564 	}
    565 	st->sgl->sg_dmat = dmat;
    566 
    567 	/* XXX errno NetBSD->Liux */
    568 	ret = -bus_dmamap_load_raw(dmat, st->sgl->sg_dmamap, seg, nseg, size,
    569 	    BUS_DMA_WAITOK);
    570 	if (ret) {
    571 		DRM_ERROR("failed to load DMA map for stolen object: %d\n",
    572 		    ret);
    573 		goto out;
    574 	}
    575 	loaded = true;
    576 
    577 out:	kmem_free(seg, nseg * sizeof(seg[0]));
    578 	if (ret) {
    579 		if (loaded)
    580 			bus_dmamap_unload(dmat, st->sgl->sg_dmamap);
    581 		if (sg && sg->sg_dmamap)
    582 			bus_dmamap_destroy(dmat, sg->sg_dmamap);
    583 		if (sg)
    584 			sg_free_table(st);
    585 		kfree(st);
    586 		return ERR_PTR(ret);
    587 	}
    588 #else
    589 	if (sg_alloc_table(st, 1, GFP_KERNEL)) {
    590 		kfree(st);
    591 		return ERR_PTR(-ENOMEM);
    592 	}
    593 
    594 	sg = st->sgl;
    595 	sg->offset = 0;
    596 	sg->length = size;
    597 
    598 	sg_dma_address(sg) = (dma_addr_t)i915->dsm.start + offset;
    599 	sg_dma_len(sg) = size;
    600 #endif
    601 
    602 	return st;
    603 }
    604 
    605 static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
    606 {
    607 	struct sg_table *pages =
    608 		i915_pages_create_for_stolen(obj->base.dev,
    609 					     obj->stolen->start,
    610 					     obj->stolen->size);
    611 	if (IS_ERR(pages))
    612 		return PTR_ERR(pages);
    613 
    614 	__i915_gem_object_set_pages(obj, pages, obj->stolen->size);
    615 
    616 	return 0;
    617 }
    618 
    619 static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj,
    620 					     struct sg_table *pages)
    621 {
    622 	/* Should only be called from i915_gem_object_release_stolen() */
    623 #ifdef __NetBSD__
    624 	bus_dmamap_unload(obj->base.dev->dmat, pages->sgl->sg_dmamap);
    625 #endif
    626 	sg_free_table(pages);
    627 	kfree(pages);
    628 }
    629 
    630 static void
    631 i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
    632 {
    633 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
    634 	struct drm_mm_node *stolen = fetch_and_zero(&obj->stolen);
    635 
    636 	GEM_BUG_ON(!stolen);
    637 
    638 	i915_gem_object_release_memory_region(obj);
    639 
    640 	i915_gem_stolen_remove_node(i915, stolen);
    641 	kfree(stolen);
    642 }
    643 
    644 static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = {
    645 	.get_pages = i915_gem_object_get_pages_stolen,
    646 	.put_pages = i915_gem_object_put_pages_stolen,
    647 	.release = i915_gem_object_release_stolen,
    648 };
    649 
    650 static struct drm_i915_gem_object *
    651 __i915_gem_object_create_stolen(struct intel_memory_region *mem,
    652 				struct drm_mm_node *stolen)
    653 {
    654 	static struct lock_class_key lock_class;
    655 	struct drm_i915_gem_object *obj;
    656 	unsigned int cache_level;
    657 	int err = -ENOMEM;
    658 
    659 	obj = i915_gem_object_alloc();
    660 	if (!obj)
    661 		goto err;
    662 
    663 	drm_gem_private_object_init(&mem->i915->drm, &obj->base, stolen->size);
    664 	i915_gem_object_init(obj, &i915_gem_object_stolen_ops, &lock_class);
    665 
    666 	obj->stolen = stolen;
    667 	obj->read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT;
    668 	cache_level = HAS_LLC(mem->i915) ? I915_CACHE_LLC : I915_CACHE_NONE;
    669 	i915_gem_object_set_cache_coherency(obj, cache_level);
    670 
    671 	err = i915_gem_object_pin_pages(obj);
    672 	if (err)
    673 		goto cleanup;
    674 
    675 	i915_gem_object_init_memory_region(obj, mem, 0);
    676 
    677 	return obj;
    678 
    679 cleanup:
    680 	i915_gem_object_free(obj);
    681 err:
    682 	return ERR_PTR(err);
    683 }
    684 
    685 static struct drm_i915_gem_object *
    686 _i915_gem_object_create_stolen(struct intel_memory_region *mem,
    687 			       resource_size_t size,
    688 			       unsigned int flags)
    689 {
    690 	struct drm_i915_private *i915 = mem->i915;
    691 	struct drm_i915_gem_object *obj;
    692 	struct drm_mm_node *stolen;
    693 	int ret;
    694 
    695 	if (!drm_mm_initialized(&i915->mm.stolen))
    696 		return ERR_PTR(-ENODEV);
    697 
    698 	if (size == 0)
    699 		return ERR_PTR(-EINVAL);
    700 
    701 	stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
    702 	if (!stolen)
    703 		return ERR_PTR(-ENOMEM);
    704 
    705 	ret = i915_gem_stolen_insert_node(i915, stolen, size, 4096);
    706 	if (ret) {
    707 		obj = ERR_PTR(ret);
    708 		goto err_free;
    709 	}
    710 
    711 	obj = __i915_gem_object_create_stolen(mem, stolen);
    712 	if (IS_ERR(obj))
    713 		goto err_remove;
    714 
    715 	return obj;
    716 
    717 err_remove:
    718 	i915_gem_stolen_remove_node(i915, stolen);
    719 err_free:
    720 	kfree(stolen);
    721 	return obj;
    722 }
    723 
    724 struct drm_i915_gem_object *
    725 i915_gem_object_create_stolen(struct drm_i915_private *i915,
    726 			      resource_size_t size)
    727 {
    728 	return i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_STOLEN],
    729 					     size, I915_BO_ALLOC_CONTIGUOUS);
    730 }
    731 
    732 static int init_stolen(struct intel_memory_region *mem)
    733 {
    734 	intel_memory_region_set_name(mem, "stolen");
    735 
    736 	/*
    737 	 * Initialise stolen early so that we may reserve preallocated
    738 	 * objects for the BIOS to KMS transition.
    739 	 */
    740 	return i915_gem_init_stolen(mem->i915);
    741 }
    742 
    743 static void release_stolen(struct intel_memory_region *mem)
    744 {
    745 	i915_gem_cleanup_stolen(mem->i915);
    746 }
    747 
    748 static const struct intel_memory_region_ops i915_region_stolen_ops = {
    749 	.init = init_stolen,
    750 	.release = release_stolen,
    751 	.create_object = _i915_gem_object_create_stolen,
    752 };
    753 
    754 struct intel_memory_region *i915_gem_stolen_setup(struct drm_i915_private *i915)
    755 {
    756 	return intel_memory_region_create(i915,
    757 					  intel_graphics_stolen_res.start,
    758 					  resource_size(&intel_graphics_stolen_res),
    759 					  PAGE_SIZE, 0,
    760 					  &i915_region_stolen_ops);
    761 }
    762 
    763 struct drm_i915_gem_object *
    764 i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *i915,
    765 					       resource_size_t stolen_offset,
    766 					       resource_size_t gtt_offset,
    767 					       resource_size_t size)
    768 {
    769 	struct intel_memory_region *mem = i915->mm.regions[INTEL_REGION_STOLEN];
    770 	struct i915_ggtt *ggtt = &i915->ggtt;
    771 	struct drm_i915_gem_object *obj;
    772 	struct drm_mm_node *stolen;
    773 	struct i915_vma *vma;
    774 	int ret;
    775 
    776 	if (!drm_mm_initialized(&i915->mm.stolen))
    777 		return ERR_PTR(-ENODEV);
    778 
    779 	DRM_DEBUG_DRIVER("creating preallocated stolen object: stolen_offset=%pa, gtt_offset=%pa, size=%pa\n",
    780 			 &stolen_offset, &gtt_offset, &size);
    781 
    782 	/* KISS and expect everything to be page-aligned */
    783 	if (WARN_ON(size == 0) ||
    784 	    WARN_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE)) ||
    785 	    WARN_ON(!IS_ALIGNED(stolen_offset, I915_GTT_MIN_ALIGNMENT)))
    786 		return ERR_PTR(-EINVAL);
    787 
    788 	stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
    789 	if (!stolen)
    790 		return ERR_PTR(-ENOMEM);
    791 
    792 	stolen->start = stolen_offset;
    793 	stolen->size = size;
    794 	mutex_lock(&i915->mm.stolen_lock);
    795 	ret = drm_mm_reserve_node(&i915->mm.stolen, stolen);
    796 	mutex_unlock(&i915->mm.stolen_lock);
    797 	if (ret) {
    798 		DRM_DEBUG_DRIVER("failed to allocate stolen space\n");
    799 		kfree(stolen);
    800 		return ERR_PTR(ret);
    801 	}
    802 
    803 	obj = __i915_gem_object_create_stolen(mem, stolen);
    804 	if (IS_ERR(obj)) {
    805 		DRM_DEBUG_DRIVER("failed to allocate stolen object\n");
    806 		i915_gem_stolen_remove_node(i915, stolen);
    807 		kfree(stolen);
    808 		return obj;
    809 	}
    810 
    811 	/* Some objects just need physical mem from stolen space */
    812 	if (gtt_offset == I915_GTT_OFFSET_NONE)
    813 		return obj;
    814 
    815 	ret = i915_gem_object_pin_pages(obj);
    816 	if (ret)
    817 		goto err;
    818 
    819 	vma = i915_vma_instance(obj, &ggtt->vm, NULL);
    820 	if (IS_ERR(vma)) {
    821 		ret = PTR_ERR(vma);
    822 		goto err_pages;
    823 	}
    824 
    825 	/* To simplify the initialisation sequence between KMS and GTT,
    826 	 * we allow construction of the stolen object prior to
    827 	 * setting up the GTT space. The actual reservation will occur
    828 	 * later.
    829 	 */
    830 	mutex_lock(&ggtt->vm.mutex);
    831 	ret = i915_gem_gtt_reserve(&ggtt->vm, &vma->node,
    832 				   size, gtt_offset, obj->cache_level,
    833 				   0);
    834 	if (ret) {
    835 		DRM_DEBUG_DRIVER("failed to allocate stolen GTT space\n");
    836 		mutex_unlock(&ggtt->vm.mutex);
    837 		goto err_pages;
    838 	}
    839 
    840 	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
    841 
    842 	GEM_BUG_ON(vma->pages);
    843 	vma->pages = obj->mm.pages;
    844 	atomic_set(&vma->pages_count, I915_VMA_PAGES_ACTIVE);
    845 
    846 	set_bit(I915_VMA_GLOBAL_BIND_BIT, __i915_vma_flags(vma));
    847 	__i915_vma_set_map_and_fenceable(vma);
    848 
    849 	list_add_tail(&vma->vm_link, &ggtt->vm.bound_list);
    850 	mutex_unlock(&ggtt->vm.mutex);
    851 
    852 	GEM_BUG_ON(i915_gem_object_is_shrinkable(obj));
    853 	atomic_inc(&obj->bind_count);
    854 
    855 	return obj;
    856 
    857 err_pages:
    858 	i915_gem_object_unpin_pages(obj);
    859 err:
    860 	i915_gem_object_put(obj);
    861 	return ERR_PTR(ret);
    862 }
    863