From 1df6a2ebd75067aefbdf07482bf8e3d0584e04ee Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 30 Sep 2010 12:36:45 +0200 Subject: drm/ttm: Fix two race conditions + fix busy codepaths This fixes a race pointed out by Dave Airlie where we don't take a buffer object about to be destroyed off the LRU lists properly. It also fixes a rare case where a buffer object could be destroyed in the middle of an accelerated eviction. The patch also adds a utility function that can be used to prematurely release GPU memory space usage of an object waiting to be destroyed. For example during eviction or swapout. The above mentioned commit didn't queue the buffer on the delayed destroy list under some rare circumstances. It also didn't completely honor the remove_all parameter. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=615505 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591061 Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- include/drm/ttm/ttm_bo_api.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/drm') diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 267a86c74e2e..2040e6c4f172 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -246,9 +246,11 @@ struct ttm_buffer_object { atomic_t reserved; - /** * Members protected by the bo::lock + * In addition, setting sync_obj to anything else + * than NULL requires bo::reserved to be held. This allows for + * checking NULL while reserved but not holding bo::lock. */ void *sync_obj_arg; -- cgit v1.2.3 From c9220b0f7cbd1d2272426aa81a72ae2f6582bb71 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 8 Oct 2010 08:57:10 +1000 Subject: drm/ttm: add unlocked variant of new manager put node. We need the unlocked variant for the new codepath introduced to fix the race condition in master recently. Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 13 ++++++++++--- drivers/gpu/drm/ttm/ttm_bo_manager.c | 10 ++++++++++ include/drm/ttm/ttm_bo_driver.h | 4 ++++ 3 files changed, 24 insertions(+), 3 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 1e9bb2156dcf..5ef0103bd0b6 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -464,9 +464,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo) spin_lock(&glob->lru_lock); } - if (bo->mem.mm_node) { - ttm_bo_mem_put(bo, &bo->mem); - } + ttm_bo_mem_put_locked(bo, &bo->mem); atomic_set(&bo->reserved, 0); wake_up_all(&bo->event_queue); @@ -791,6 +789,15 @@ void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) } EXPORT_SYMBOL(ttm_bo_mem_put); +void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type]; + + if (mem->mm_node) + (*man->func->put_node_locked)(man, mem); +} +EXPORT_SYMBOL(ttm_bo_mem_put_locked); + /** * Repeatedly evict memory from the LRU for @mem_type until we create enough * space, or we've evicted everything and there isn't enough space. diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c index 7410c190c891..35c97b20bdae 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_manager.c +++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c @@ -90,6 +90,15 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, } } +static void ttm_bo_man_put_node_locked(struct ttm_mem_type_manager *man, + struct ttm_mem_reg *mem) +{ + if (mem->mm_node) { + drm_mm_put_block(mem->mm_node); + mem->mm_node = NULL; + } +} + static int ttm_bo_man_init(struct ttm_mem_type_manager *man, unsigned long p_size) { @@ -143,6 +152,7 @@ const struct ttm_mem_type_manager_func ttm_bo_manager_func = { ttm_bo_man_takedown, ttm_bo_man_get_node, ttm_bo_man_put_node, + ttm_bo_man_put_node_locked, ttm_bo_man_debug }; EXPORT_SYMBOL(ttm_bo_manager_func); diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index e3371dbe6a10..d0ff529fedde 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -214,6 +214,8 @@ struct ttm_mem_type_manager_func { struct ttm_mem_reg *mem); void (*put_node)(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem); + void (*put_node_locked)(struct ttm_mem_type_manager *man, + struct ttm_mem_reg *mem); void (*debug)(struct ttm_mem_type_manager *man, const char *prefix); }; @@ -667,6 +669,8 @@ extern int ttm_bo_mem_space(struct ttm_buffer_object *bo, extern void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); +extern void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem); /** * ttm_bo_wait_for_cpu -- cgit v1.2.3 From 21c74a8ea8b47eb6c3c621e36578f6e27f65c5c7 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Wed, 13 Oct 2010 14:09:44 -0500 Subject: drm, kdb, kms: Change mode_set_base_atomic() enter argument to be an enum The enter argument as implemented by commit 413d45d3627 (drm, kdb, kms: Add an enter argument to mode_set_base_atomic() API) should be more descriptive as to what it does vs just passing 1 and 0 around. There is no runtime behavior change as a result of this patch. Reported-by: Jesse Barnes Signed-off-by: Jason Wessel CC: David Airlie CC: dri-devel@lists.freedesktop.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 5 ++--- drivers/gpu/drm/i915/intel_display.c | 5 +++-- drivers/gpu/drm/nouveau/nv04_crtc.c | 4 ++-- drivers/gpu/drm/nouveau/nv50_crtc.c | 2 +- drivers/gpu/drm/radeon/atombios_crtc.c | 2 +- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 2 +- drivers/gpu/drm/radeon/radeon_mode.h | 7 +++++-- include/drm/drm_crtc_helper.h | 7 ++++++- 8 files changed, 21 insertions(+), 13 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 8208e190faaa..d2849e4ea4d0 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -289,8 +289,7 @@ int drm_fb_helper_debug_enter(struct fb_info *info) mode_set->fb, mode_set->x, mode_set->y, - 1); - + ENTER_ATOMIC_MODE_SET); } } @@ -336,7 +335,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) drm_fb_helper_restore_lut_atomic(mode_set->crtc); funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, - crtc->y, 0); + crtc->y, LEAVE_ATOMIC_MODE_SET); } return 0; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9109c00f3ead..96d08a9f3aaa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1492,7 +1492,7 @@ err_unpin: /* Assume fb object is pinned & idle & fenced and just update base pointers */ static int intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, int enter) + int x, int y, enum mode_set_atomic state) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1614,7 +1614,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, atomic_read(&obj_priv->pending_flip) == 0); } - ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, 0); + ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, + LEAVE_ATOMIC_MODE_SET); if (ret) { i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 17f7cf0c11a8..c71abc2a34d5 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -860,12 +860,12 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, static int nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, int enter) + int x, int y, enum mode_set_atomic state) { struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; struct drm_device *dev = dev_priv->dev; - if (enter) + if (state == ENTER_ATOMIC_MODE_SET) nouveau_fbcon_save_disable_accel(dev); else nouveau_fbcon_restore_accel(dev); diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index ba91befd3734..16380d52cd88 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -708,7 +708,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, static int nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, int enter) + int x, int y, enum mode_set_atomic state) { return nv50_crtc_do_mode_set_base(crtc, fb, x, y, true, true); } diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 176f424975ac..df2b6f2b35f8 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1270,7 +1270,7 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, int enter) + int x, int y, enum mode_set_atomic state) { struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 326843ec51f6..ace2e6384d40 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -353,7 +353,7 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, int enter) + int x, int y, enum mode_set_atomic state) { return radeon_crtc_do_set_base(crtc, fb, x, y, 1); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index f99e12daa81d..61b9243db217 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -526,7 +527,8 @@ extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, int enter); + int x, int y, + enum mode_set_atomic state); extern int atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -538,7 +540,8 @@ extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, int enter); + int x, int y, + enum mode_set_atomic state); extern int radeon_crtc_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, int atomic); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 6a9f3935ea0b..73b071203dcc 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -39,6 +39,11 @@ #include +enum mode_set_atomic { + LEAVE_ATOMIC_MODE_SET, + ENTER_ATOMIC_MODE_SET, +}; + struct drm_crtc_helper_funcs { /* * Control power levels on the CRTC. If the mode passed in is @@ -62,7 +67,7 @@ struct drm_crtc_helper_funcs { struct drm_framebuffer *old_fb); int (*mode_set_base_atomic)(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, - int is_enter); + enum mode_set_atomic); /* reload the current crtc LUT */ void (*load_lut)(struct drm_crtc *crtc); -- cgit v1.2.3