| From 36e2ed3d4176d01b17c16c790931f2b50f60c8aa Mon Sep 17 00:00:00 2001 |
| From: Ben Widawsky <ben@bwidawsk.net> |
| Date: Fri, 5 Jul 2013 14:41:02 -0700 |
| Subject: drm: pre allocate node for create_block |
| |
| For an upcoming patch where we introduce the i915 VMA, it's ideal to |
| have the drm_mm_node as part of the VMA struct (ie. it's pre-allocated). |
| Part of the conversion to VMAs is to kill off obj->gtt_space. Doing this |
| will break a bunch of code, but amongst them are 2 callers of |
| drm_mm_create_block(), both related to stolen memory. |
| |
| It also allows us to embed the drm_mm_node into the object currently |
| which provides a nice transition over to the new code. |
| |
| v2: Reordered to do before ripping out obj->gtt_offset. |
| Some minor cleanups made available because of reordering. |
| |
| v3: s/continue/break on failed stolen node allocation (David) |
| Set obj->gtt_space on failed node allocation (David) |
| Only unref stolen (fix double free) on failed create_stolen (David) |
| Free node, and NULL it in failed create_stolen (David) |
| Add back accidentally removed newline (David) |
| |
| CC: <dri-devel@lists.freedesktop.org> |
| Reviewed-by: David Herrmann <dh.herrmann@gmail.com> |
| Signed-off-by: Ben Widawsky <ben@bwidawsk.net> |
| Acked-by: David Airlie <airlied@linux.ie> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit b3a070cccb9135f8bec63d9f194ddaa422136fb0) |
| (cherry picked from drm-intel-next-queued) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/drm_mm.c | 16 +++++---------- |
| drivers/gpu/drm/i915/i915_gem_gtt.c | 20 ++++++++++++++---- |
| drivers/gpu/drm/i915/i915_gem_stolen.c | 37 +++++++++++++++++++++++++--------- |
| include/drm/drm_mm.h | 9 +++++---- |
| 4 files changed, 53 insertions(+), 29 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c |
| index 7917729ee61d..520f7463bb77 100644 |
| --- a/drivers/gpu/drm/drm_mm.c |
| +++ b/drivers/gpu/drm/drm_mm.c |
| @@ -147,12 +147,10 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, |
| } |
| } |
| |
| -struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, |
| - unsigned long start, |
| - unsigned long size, |
| - bool atomic) |
| +int drm_mm_create_block(struct drm_mm *mm, struct drm_mm_node *node, |
| + unsigned long start, unsigned long size) |
| { |
| - struct drm_mm_node *hole, *node; |
| + struct drm_mm_node *hole; |
| unsigned long end = start + size; |
| unsigned long hole_start; |
| unsigned long hole_end; |
| @@ -161,10 +159,6 @@ struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, |
| if (hole_start > start || hole_end < end) |
| continue; |
| |
| - node = drm_mm_kmalloc(mm, atomic); |
| - if (unlikely(node == NULL)) |
| - return NULL; |
| - |
| node->start = start; |
| node->size = size; |
| node->mm = mm; |
| @@ -184,11 +178,11 @@ struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, |
| node->hole_follows = 1; |
| } |
| |
| - return node; |
| + return 0; |
| } |
| |
| WARN(1, "no hole found for block 0x%lx + 0x%lx\n", start, size); |
| - return NULL; |
| + return -ENOSPC; |
| } |
| EXPORT_SYMBOL(drm_mm_create_block); |
| |
| diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c |
| index 66929eac6367..88180a597c0a 100644 |
| --- a/drivers/gpu/drm/i915/i915_gem_gtt.c |
| +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c |
| @@ -629,14 +629,26 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, |
| |
| /* Mark any preallocated objects as occupied */ |
| list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { |
| + int ret; |
| DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n", |
| obj->gtt_offset, obj->base.size); |
| |
| BUG_ON(obj->gtt_space != I915_GTT_RESERVED); |
| - obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space, |
| - obj->gtt_offset, |
| - obj->base.size, |
| - false); |
| + obj->gtt_space = kzalloc(sizeof(*obj->gtt_space), GFP_KERNEL); |
| + if (!obj->gtt_space) { |
| + DRM_ERROR("Failed to preserve object at offset %x\n", |
| + obj->gtt_offset); |
| + continue; |
| + } |
| + ret = drm_mm_create_block(&dev_priv->mm.gtt_space, |
| + obj->gtt_space, |
| + obj->gtt_offset, |
| + obj->base.size); |
| + if (ret) { |
| + DRM_DEBUG_KMS("Reservation failed\n"); |
| + kfree(obj->gtt_space); |
| + obj->gtt_space = NULL; |
| + } |
| obj->has_global_gtt_mapping = 1; |
| } |
| |
| diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c |
| index f1664f272fc3..fdcc96b636b2 100644 |
| --- a/drivers/gpu/drm/i915/i915_gem_stolen.c |
| +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c |
| @@ -333,6 +333,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct drm_i915_gem_object *obj; |
| struct drm_mm_node *stolen; |
| + int ret; |
| |
| if (!drm_mm_initialized(&dev_priv->mm.stolen)) |
| return NULL; |
| @@ -347,11 +348,15 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, |
| if (WARN_ON(size == 0)) |
| return NULL; |
| |
| - stolen = drm_mm_create_block(&dev_priv->mm.stolen, |
| - stolen_offset, size, |
| - false); |
| - if (stolen == NULL) { |
| + stolen = kzalloc(sizeof(*stolen), GFP_KERNEL); |
| + if (!stolen) |
| + return NULL; |
| + |
| + ret = drm_mm_create_block(&dev_priv->mm.stolen, stolen, stolen_offset, |
| + size); |
| + if (ret) { |
| DRM_DEBUG_KMS("failed to allocate stolen space\n"); |
| + kfree(stolen); |
| return NULL; |
| } |
| |
| @@ -372,13 +377,18 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, |
| * 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) { |
| + obj->gtt_space = kzalloc(sizeof(*obj->gtt_space), GFP_KERNEL); |
| + if (!obj->gtt_space) { |
| + DRM_DEBUG_KMS("-ENOMEM stolen GTT space\n"); |
| + goto unref_out; |
| + } |
| + |
| + ret = drm_mm_create_block(&dev_priv->mm.gtt_space, |
| + obj->gtt_space, |
| + gtt_offset, size); |
| + if (ret) { |
| DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); |
| - drm_gem_object_unreference(&obj->base); |
| - return NULL; |
| + goto free_out; |
| } |
| } else |
| obj->gtt_space = I915_GTT_RESERVED; |
| @@ -390,6 +400,13 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, |
| list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); |
| |
| return obj; |
| + |
| +free_out: |
| + kfree(obj->gtt_space); |
| + obj->gtt_space = NULL; |
| +unref_out: |
| + drm_gem_object_unreference(&obj->base); |
| + return NULL; |
| } |
| |
| void |
| diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h |
| index de9242542f05..00904bfe1355 100644 |
| --- a/include/drm/drm_mm.h |
| +++ b/include/drm/drm_mm.h |
| @@ -138,10 +138,10 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) |
| /* |
| * Basic range manager support (drm_mm.c) |
| */ |
| -extern struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, |
| - unsigned long start, |
| - unsigned long size, |
| - bool atomic); |
| +extern int drm_mm_create_block(struct drm_mm *mm, |
| + struct drm_mm_node *node, |
| + unsigned long start, |
| + unsigned long size); |
| extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, |
| unsigned long size, |
| unsigned alignment, |
| @@ -155,6 +155,7 @@ extern struct drm_mm_node *drm_mm_get_block_range_generic( |
| unsigned long start, |
| unsigned long end, |
| int atomic); |
| + |
| static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent, |
| unsigned long size, |
| unsigned alignment) |
| -- |
| 1.8.5.rc3 |
| |