[Intel-gfx] [PATCH 15/17] drm/i915: Introduce i915_gem_object_create_for_stolen()

Chris Wilson chris at chris-wilson.co.uk
Sat Apr 21 18:35:59 CEST 2012


Wrap a preallocated region of stolen memory within an ordinary GEM
object. (For example for preserving the BIOS framebuffer.)

In order to hide that the object has no backing struct pages, we create
a fake dma mapping for the contiguous physical allocation.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h        |   10 +++
 drivers/gpu/drm/i915/i915_gem.c        |    5 +-
 drivers/gpu/drm/i915/i915_gem_gtt.c    |    2 +-
 drivers/gpu/drm/i915/i915_gem_stolen.c |  112 ++++++++++++++++++++++++++++++++
 4 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d98b903..d2784b4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -833,6 +833,8 @@ struct drm_i915_gem_object {
 
 	/** Current space allocated to this object in the GTT, if any. */
 	struct drm_mm_node *gtt_space;
+	/** Stolen memory for this object, if any. */
+	struct drm_mm_node *stolen_space;
 	struct list_head gtt_list;
 
 	/** This object's place on the active/flushing/inactive lists */
@@ -1337,6 +1339,8 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
 void i915_gem_free_all_phys_object(struct drm_device *dev);
 void i915_gem_release(struct drm_device *dev, struct drm_file *file);
 
+void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, size_t size);
+
 uint32_t
 i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
 				    uint32_t size,
@@ -1375,6 +1379,12 @@ int i915_gem_evict_everything(struct drm_device *dev);
 int i915_gem_init_stolen(struct drm_device *dev);
 int i915_gem_stolen_setup_compression(struct drm_device *dev);
 void i915_gem_cleanup_stolen(struct drm_device *dev);
+struct drm_gem_object *
+i915_gem_object_create_for_stolen(struct drm_device *dev,
+				  u32 stolen_offset,
+				  u32 gtt_offset,
+				  u32 size);
+void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj);
 
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index e2bd828..b353619 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -73,8 +73,7 @@ static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
 }
 
 /* some bookkeeping */
-static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
-				  size_t size)
+void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, size_t size)
 {
 	dev_priv->mm.object_count++;
 	dev_priv->mm.object_memory += size;
@@ -3530,6 +3529,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 	i915_gem_object_put_pages_gtt(obj);
 	i915_gem_object_free_mmap_offset(obj);
 
+	i915_gem_object_release_stolen(obj);
+
 	drm_gem_object_release(&obj->base);
 	i915_gem_info_remove_obj(dev_priv, obj->base.size);
 
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index fbdaf5a..d9074b4 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -398,7 +398,7 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
 
 	interruptible = do_idling(dev_priv);
 
-	if (obj->sg_list) {
+	if (obj->sg_list && !obj->stolen_space) {
 		intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
 		obj->sg_list = NULL;
 	}
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 25e846a..f99326b 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -216,3 +216,115 @@ int i915_gem_init_stolen(struct drm_device *dev)
 
 	return 0;
 }
+
+/* Permanently reserve the GTT space for the lifetime of the stolen object */
+struct drm_gem_object *
+i915_gem_object_create_for_stolen(struct drm_device *dev,
+				  u32 stolen_offset,
+				  u32 gtt_offset,
+				  u32 size)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_gem_object *obj;
+	struct sg_table st;
+
+	DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n",
+			stolen_offset, gtt_offset, size);
+	if (size == 0)
+		return NULL;
+
+	if (sg_alloc_table(&st, 1, GFP_KERNEL))
+		goto cleanup_sg;
+
+	/* We hide that we have no struct page backing our stolen object
+	 * by wrapping the contiguous physical allocation with a fake
+	 * dma mapping in a single scatterlist.
+	 */
+	st.sgl->page_link = 0;
+	st.sgl->offset = stolen_offset;
+	st.sgl->length = size;
+	sg_dma_address(st.sgl) = i915_stolen_to_phys(dev, stolen_offset);
+	sg_dma_len(st.sgl) = size;
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+	if (obj == NULL)
+		goto cleanup_sg;
+
+	if (drm_gem_private_object_init(dev, &obj->base, size) != 0)
+		goto cleanup_obj;
+
+	i915_gem_info_add_obj(dev_priv, size);
+
+	obj->base.write_domain = I915_GEM_DOMAIN_GTT;
+	obj->base.read_domains = I915_GEM_DOMAIN_GTT;
+	obj->cache_level = I915_CACHE_NONE;
+
+	obj->fence_reg = I915_FENCE_REG_NONE;
+	INIT_LIST_HEAD(&obj->ring_list);
+	INIT_LIST_HEAD(&obj->exec_list);
+	INIT_LIST_HEAD(&obj->gpu_write_list);
+	obj->madv = I915_MADV_WILLNEED;
+
+	obj->sg_list = st.sgl;
+	obj->num_sg = 1;
+
+	/* To simplify the initialisation sequence between KMS and GTT,
+	 * we allow construction of the stolen object prior to
+	 * setting up the GTT space. The actual reservation will occur
+	 * later.
+	 */
+	if (drm_mm_initialized(&dev_priv->mm.gtt_space)) {
+		obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
+						     gtt_offset, size,
+						     false);
+		if (obj->gtt_space == NULL)
+			goto cleanup_obj;
+	} else
+		obj->gtt_space = I915_GTT_RESERVED;
+
+	obj->gtt_offset = gtt_offset;
+	obj->has_global_gtt_mapping = 1;
+
+	obj->stolen_space = drm_mm_create_block(&dev_priv->mm.stolen,
+						stolen_offset, size,
+						false);
+	if (obj->stolen_space == NULL)
+		goto cleanup_gtt;
+
+	obj->pin_count = 1;
+	obj->pin_mappable = true;
+	obj->map_and_fenceable = true;
+
+	list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list);
+	list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+
+	return &obj->base;
+
+cleanup_gtt:
+	drm_mm_put_block(obj->gtt_space);
+cleanup_obj:
+	kfree(obj);
+cleanup_sg:
+	sg_free_table(&st);
+	return NULL;
+}
+
+void
+i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
+{
+	if (obj->stolen_space) {
+		drm_mm_put_block(obj->stolen_space);
+		obj->stolen_space = NULL;
+	}
+
+	if (obj->sg_list) {
+		struct sg_table st;
+
+		st.sgl = obj->sg_list;
+		st.orig_nents = st.nents = obj->num_sg;
+
+		sg_free_table(&st);
+
+		obj->sg_list = NULL;
+	}
+}
-- 
1.7.10




More information about the Intel-gfx mailing list