From 4c03030b12bae28dad50d69bd271de632c43ff13 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 18:05:35 +0200 Subject: Checkpoint commit Buffer object code. --- linux-core/drm_bo.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 linux-core/drm_bo.c (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c new file mode 100644 index 00000000..d87cd2a1 --- /dev/null +++ b/linux-core/drm_bo.c @@ -0,0 +1,282 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" + +int drm_fence_buffer_objects(drm_file_t *priv) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry, *next; + uint32_t fence_flags = 0; + int count = 0; + drm_fence_object_t *fence; + int ret; + + mutex_lock(&bm->bm_mutex); + + list_for_each_entry(entry, &bm->unfenced, head) { + BUG_ON(!entry->unfenced); + fence_flags |= entry->fence_flags; + count++; + } + + if (!count) { + mutex_unlock(&bm->bm_mutex); + return 0; + } + + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + + if (!fence) { + mutex_unlock(&bm->bm_mutex); + return -ENOMEM; + } + + ret = drm_fence_object_init(dev, fence_flags, 1, fence); + if (ret) { + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + mutex_unlock(&bm->bm_mutex); + return ret; + } + + list_for_each_entry_safe(entry, next, &bm->unfenced, head) { + BUG_ON(entry->fence); + entry->unfenced = 0; + entry->fence = fence; + list_del_init(&entry->head); + + if (!(entry->flags & DRM_BO_FLAG_NO_EVICT)) { + if (entry->flags & DRM_BO_FLAG_MEM_TT) { + list_add_tail(&entry->head, &bm->tt_lru); + } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { + list_add_tail(&entry->head, &bm->vram_lru); + } + } + } + + mutex_lock(&dev->struct_mutex); + atomic_add(count - 1, &fence->usage); + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&bm->bm_mutex); + return 0; +} + +/* + * bm locked, + * dev locked. + */ + + +static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) +{ + drm_device_t *dev = buf->dev; + drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; + + BUG_ON(!buf->tt); + + if (buf->fence) { + ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, + buf->fence_flags); + if (ret) + return ret; + drm_fence_usage_deref_unlocked(dev, buf->fence); + buf->fence = NULL; + } + + drm_unbind_ttm_region(buf->ttm_region); + drm_mm_put_block(&bm->tt_manager, buf->tt); + buf->tt = NULL; + buf->flags &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_UNCACHED); + buf->flags |= DRM_BO_FLAG_MEM_LOCAL; + + return 0; +} + + +void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) +{ + + drm_buffer_manager_t *bm = &dev->bm; + + BUG_ON(bo->unfenced); + + if (bo->fence) { + if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { + drm_fence_object_flush(dev, bo->fence, bo->fence_flags); + list_add_tail(&bo->ddestroy, &bm->ddestroy); + return; + } else { + drm_fence_usage_deref_locked(dev, bo->fence); + bo->fence = NULL; + } + } + + /* + * Take away from lru lists. + */ + + list_del_init(&bo->head); + + if (bo->tt) { + int ret; + ret = drm_move_tt_to_local(bo, 0); + BUG_ON(ret); + } + if (bo->vram) { + drm_mm_put_block(&bm->vram_manager, bo->vram); + bo->vram = NULL; + } + + /* + * FIXME: Destroy ttm. + */ + + drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); +} + +static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, + int init, uint32_t *n_flags) +{ + uint32_t new_flags; + uint32_t new_props; + + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { + + /* + * We need to move memory. Default preferences are hard-coded + * here. + */ + + new_flags = new_mask & DRM_BO_MASK_MEM; + + if (!new_flags) { + DRM_ERROR("Invalid buffer object memory flags\n"); + return -EINVAL; + } + + if (new_flags & DRM_BO_FLAG_MEM_LOCAL) { + if ((hint & DRM_BO_HINT_AVOID_LOCAL) && + new_flags & (DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_TT)) { + new_flags &= ~DRM_BO_FLAG_MEM_LOCAL; + } else { + new_flags = DRM_BO_FLAG_MEM_LOCAL; + } + } + if (new_flags & DRM_BO_FLAG_MEM_TT) { + if ((hint & DRM_BO_HINT_PREFER_VRAM) && + new_flags & DRM_BO_FLAG_MEM_VRAM) { + new_flags = DRM_BO_FLAG_MEM_VRAM; + } else { + new_flags = DRM_BO_FLAG_MEM_TT; + } + } + } else { + new_flags = flags & DRM_BO_MASK_MEM; + } + + new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_READ); + + if (!new_props) { + DRM_ERROR("Invalid buffer object rwx properties\n"); + return -EINVAL; + } + + new_flags |= new_mask & ~DRM_BO_MASK_MEM; + *n_flags = new_flags; + return 0; +} + + + +#if 0 + +static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); +{ + int ret; + if (tt) { + ret = drm_move_tt_to_local(buf); + } else { + ret = drm_move_vram_to_local(buf); + } + return ret; +} + +int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) +{ + drm_mm_node_t *node; + drm_buffer_manager_t *bm = &dev->bm; + drm_buffer_object_t *bo; + drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; + + lru = (tt) ? &bm->tt_lru : &bm->vram_lru; + + do { + node = drm_mm_search_free(mm, size, 0, 1); + if (node) + break; + + if (lru->next == lru) + break; + + if (tt) { + bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); + } else { + bo = list_entry(lru->next, drm_buffer_object_t, vram_lru); + } + + drm_bo_evict(dev, bo, tt); + } while (1); + + if (!node) { + DRM_ERROR("Out of aperture space\n"); + return -ENOMEM; + } + + node = drm_mm_get_block(node, size, 0); + BUG_ON(!node); + node->private = (void *)buf; + + if (tt) { + buf->tt = node; + } else { + buf->vram = node; + } + return 0; +} +#endif + + + + -- cgit v1.2.3 From 35c8ce6c2945ff09dc52dbc2a7382798ba64c1da Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 19:03:42 +0200 Subject: ttm and buffer objects ioctl stubs. --- linux-core/drm_bo.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d87cd2a1..6a677578 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -277,6 +277,38 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif +static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, void __user *data) +{ + return 0; +} + +int drm_bo_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_bo_arg_t arg; + unsigned long data_ptr; + (void) dev; + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + data_ptr = arg.data_lo; + + if (sizeof(data_ptr) > 4) { + int shift = 32; + data_ptr |= arg.data_hi << shift; + } + + switch(arg.op) { + case drm_op_bo: + return drm_do_bo_ioctl(priv, arg.num_requests, + (void __user *) data_ptr); + case drm_op_ttm: + return drm_ttm_ioctl(priv, arg.num_requests, + (drm_ttm_arg_t __user *) data_ptr); + } + + return 0; +} + -- cgit v1.2.3 From c488e25ceb421c6f84f110d786d9814ac4dba1b2 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 20:03:39 +0200 Subject: More ioctl stubs. Buffer object locking order documentation. --- linux-core/drm_bo.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 6a677578..847b0406 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -31,6 +31,30 @@ #include "drmP.h" +/* + * Buffer object locking policy: + * Lock dev->struct_mutex; + * Increase usage + * Unlock dev->struct_mutex; + * Lock buffer->mutex; + * Do whatever you want; + * Unlock buffer->mutex; + * Decrease usage. Call destruction if zero. + * + * User object visibility ups usage just once, since it has its own + * refcounting. + * + * Destruction: + * lock dev->struct_mutex; + * Verify that usage is zero. Otherwise unlock and continue. + * Destroy object. + * unlock dev->struct_mutex; + * + * Mutex and spinlock locking orders: + * 1.) Buffer mutex + * 2.) Refer to ttm locking orders. + */ + int drm_fence_buffer_objects(drm_file_t *priv) { drm_device_t *dev = priv->head->dev; @@ -277,11 +301,35 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif -static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, void __user *data) +static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, + drm_bo_arg_data_t __user *data) { - return 0; + drm_bo_arg_data_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t rep; + int i, ret; + + for (i=0; i Date: Sun, 27 Aug 2006 19:03:20 +0200 Subject: ttm create / destroy / ref / unref ioctl. --- linux-core/drm_bo.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 847b0406..35d4aba7 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -338,13 +338,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) (void) dev; DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - data_ptr = arg.data_lo; - - if (sizeof(data_ptr) > 4) { - int shift = 32; - data_ptr |= arg.data_hi << shift; - } - + data_ptr = combine_64(arg.data_lo, arg.data_hi); switch(arg.op) { case drm_op_bo: arg.num_requests = drm_do_bo_ioctl(priv, arg.num_requests, -- cgit v1.2.3 From b4b7b997605f88f3ffdcb0cc7cd1271e0cb24073 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 21:16:13 +0200 Subject: Remove the ioctl multiplexing, and instead allow for generic drm ioctls 0x80 - 0xFF. --- linux-core/drm_bo.c | 43 ------------------------------------------- 1 file changed, 43 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 35d4aba7..5eb09839 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -301,34 +301,6 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif -static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, - drm_bo_arg_data_t __user *data) -{ - drm_bo_arg_data_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t rep; - int i, ret; - - for (i=0; i Date: Mon, 28 Aug 2006 10:58:21 +0200 Subject: Checkpoint buffer object IOCTL stub. --- linux-core/drm_bo.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 5eb09839..9661b70f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -306,9 +306,55 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_bo_arg_t arg; - unsigned long data_ptr; - (void) dev; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t rep; + unsigned long next; + drm_user_object_t *uo; + drm_buffer_object_t *entry; + + do { + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + rep.ret = 0; + rep.handled = 0; + switch (req->op) { + case drm_bo_destroy: + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, req->handle); + if (!uo || (uo->type != drm_buffer_type) || uo->owner != priv) { + mutex_unlock(&dev->struct_mutex); + rep.ret = -EINVAL; + break; + } + rep.ret = drm_remove_user_object(priv, uo); + mutex_unlock(&dev->struct_mutex); + break; + case drm_bo_reference: + rep.ret = drm_user_object_ref(priv, req->handle, + drm_buffer_type, &uo); + if (rep.ret) + break; + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, req->handle); + entry = drm_user_object_entry(uo, drm_buffer_object_t, base); + atomic_dec(&entry->usage); + mutex_unlock(&dev->struct_mutex); + break; + case drm_bo_unreference: + rep.ret = drm_user_object_unref(priv, req->handle, + drm_buffer_type); + break; + default: + rep.ret = -EINVAL; + } + next = drm_ul(req->next); + rep.handled = 1; + arg.rep = rep; + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); + data = next; + + } while (data); return 0; + } -- cgit v1.2.3 From 05536a64785223ee8c57556300a14ba9c89837ae Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 13:51:39 +0200 Subject: Buffer object idle and mapping synchronization. --- linux-core/drm_bo.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 9661b70f..0aa0b138 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -302,6 +302,148 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) #endif +/* + * Call dev->struct_mutex locked. + */ + + +drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t *priv, uint32_t handle, + int check_owner) +{ + drm_user_object_t *uo; + drm_buffer_object_t *bo; + + uo = drm_lookup_user_object(priv, handle); + + if (!uo || (uo->type != drm_buffer_type)) + return NULL; + + if (check_owner && priv != uo->owner) { + if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) + return NULL; + } + + bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + atomic_inc(&bo->usage); + return bo; +} + +/* + * Call bo->mutex locked. + * Wait until the buffer is idle. + */ + +static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) +{ + + drm_fence_object_t *fence = bo->fence; + int ret; + + if (fence) { + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + + /* + * Make sure another process doesn't destroy the fence + * object when we release the buffer object mutex. + * We don't need to take the dev->struct_mutex lock here, + * since the fence usage count is at least 1 already. + */ + + atomic_inc(&fence->usage); + mutex_unlock(&bo->mutex); + ret = drm_fence_object_wait(dev, fence, lazy, !lazy, bo->fence_flags); + mutex_lock(&bo->mutex); + if (ret) + return ret; + mutex_lock(&dev->struct_mutex); + drm_fence_usage_deref_locked(dev, fence); + if (bo->fence == fence) { + drm_fence_usage_deref_locked(dev, fence); + bo->fence = NULL; + } + mutex_unlock(&dev->struct_mutex); + } + return 0; +} + +/* + * Call bo->mutex locked. + * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. + */ + +static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) +{ + drm_fence_object_t *fence = bo->fence; + + if (fence) { + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + drm_fence_object_flush(dev, fence, DRM_FENCE_EXE); + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + return 1; + } + return 0; +} + + +/* + * Wait for buffer idle and register that we've mapped the buffer. + */ + + +static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) +{ + drm_buffer_object_t *bo; + drm_device_t *dev = priv->head->dev; + int ret; + + mutex_lock(&dev->struct_mutex); + bo = drm_lookup_buffer_object(priv, handle, 1); + mutex_unlock(&dev->struct_mutex); + + if (!bo) + return -EINVAL; + + mutex_lock(&bo->mutex); + + if (!wait) { + if ((atomic_read(&bo->mapped) == 0) && + drm_bo_busy(dev, bo)) { + mutex_unlock(&bo->mutex); + return -EBUSY; + } + } else { + ret = drm_bo_wait(dev, bo, 0); + if (ret) { + mutex_unlock(&bo->mutex); + return -EBUSY; + } + } + mutex_lock(&dev->struct_mutex); + ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); + mutex_unlock(&dev->struct_mutex); + if (!ret) { + atomic_inc(&bo->mapped); + } + mutex_unlock(&bo->mutex); + + return ret; +} + + + + int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -317,6 +459,11 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_map: + rep.ret = drm_buffer_object_map(priv, req->handle, + !(req->hint & + DRM_BO_HINT_DONT_BLOCK)); + break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, req->handle); -- cgit v1.2.3 From 0d67356de4e0c9e0d068ea9c16cf33df4fd13776 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 16:36:37 +0200 Subject: Proper TTM dereferencing Initial buffer object creation. --- linux-core/drm_bo.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0aa0b138..affee135 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -148,7 +148,7 @@ static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) } -void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) +static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) { drm_buffer_manager_t *bm = &dev->bm; @@ -189,6 +189,31 @@ void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } + +void drm_bo_usage_deref_locked(drm_device_t *dev, drm_buffer_object_t *bo) +{ + if (atomic_dec_and_test(&bo->usage)) { + drm_bo_destroy_locked(dev, bo); + } +} + +void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) +{ + if (atomic_dec_and_test(&bo->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&bo->usage) == 0) + drm_bo_destroy_locked(dev, bo); + mutex_unlock(&dev->struct_mutex); + } +} + +static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) +{ + drm_bo_usage_deref_locked(priv->head->dev, + drm_user_object_entry(uo, drm_buffer_object_t, base)); +} + + static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t *n_flags) { @@ -399,6 +424,9 @@ static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) /* * Wait for buffer idle and register that we've mapped the buffer. + * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, + * so that if the client dies, the mapping is automatically + * unregistered. */ @@ -421,13 +449,15 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { mutex_unlock(&bo->mutex); - return -EBUSY; + ret = -EBUSY; + goto out; } } else { ret = drm_bo_wait(dev, bo, 0); if (ret) { mutex_unlock(&bo->mutex); - return -EBUSY; + ret = -EBUSY; + goto out; } } mutex_lock(&dev->struct_mutex); @@ -438,11 +468,132 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) } mutex_unlock(&bo->mutex); + out: + drm_bo_usage_deref_unlocked(dev,bo); + return ret; +} + + +static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo; + drm_ref_object_t *ro; + int ret = 0; + + mutex_lock(&dev->struct_mutex); + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + ret = -EINVAL; + goto out; + } + + ro = drm_lookup_ref_object(priv, &bo->base, _DRM_REF_TYPE1); + if (!ro) { + ret = -EINVAL; + goto out; + } + + drm_remove_ref_object(priv, ro); + drm_bo_usage_deref_locked(dev, bo); + out: + mutex_unlock(&dev->struct_mutex); return ret; } +/* + * Call struct-sem locked. + */ +static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + + if (atomic_dec_and_test(&bo->mapped)) { + mutex_unlock(&dev->struct_mutex); + mutex_lock(&bo->mutex); + if (atomic_read(&bo->mapped) == 0) { + DRM_WAKEUP(&bo->validate_queue); + } + mutex_unlock(&bo->mutex); + mutex_lock(&dev->struct_mutex); + } +} + +static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo) +{ + return 0; +} + +int drm_buffer_object_create(drm_file_t *priv, + int size, + drm_bo_type_t type, + uint32_t ttm_handle, + uint32_t mask, + uint32_t hint, + void __user *user_pages, + drm_buffer_object_t **buf_obj) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo; + int ret = 0; + uint32_t ttm_flags = 0; + + bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); + + if (!bo) + return -ENOMEM; + + mutex_init(&bo->mutex); + mutex_lock(&bo->mutex); + + atomic_set(&bo->usage, 1); + atomic_set(&bo->mapped, 0); + DRM_INIT_WAITQUEUE(&bo->validate_queue); + INIT_LIST_HEAD(&bo->head); + INIT_LIST_HEAD(&bo->ddestroy); + bo->dev = dev; + + switch(type) { + case drm_bo_type_dc: + ret = drm_ttm_object_create(dev, size, ttm_flags, &bo->ttm_object); + if (ret) + goto out_err; + break; + case drm_bo_type_ttm: + bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); + if (ret) + goto out_err; + break; + case drm_bo_type_user: + bo->user_pages = user_pages; + break; + default: + ret = -EINVAL; + goto out_err; + } + + bo->mask = mask; + bo->mask_hint = hint; + + ret = drm_buffer_object_validate(dev, bo); + if (ret) + goto out_err; + + mutex_unlock(&bo->mutex); + *buf_obj = bo; + return 0; + + out_err: + mutex_unlock(&bo->mutex); + drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + return ret; +} + + int drm_bo_ioctl(DRM_IOCTL_ARGS) { @@ -459,6 +610,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_unmap: + rep.ret = drm_buffer_object_unmap(priv, req->handle); + break; case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, !(req->hint & -- cgit v1.2.3 From 205740647060bc3bdec2b4402a666eb1015932ff Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 17:51:53 +0200 Subject: Buffer object creation. --- linux-core/drm_bo.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index affee135..7f5088fb 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -507,11 +507,14 @@ static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) * Call struct-sem locked. */ -static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo) +static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo, + drm_ref_t action) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + BUG_ON(action != _DRM_REF_TYPE1); + if (atomic_dec_and_test(&bo->mapped)) { mutex_unlock(&dev->struct_mutex); mutex_lock(&bo->mutex); @@ -534,7 +537,7 @@ int drm_buffer_object_create(drm_file_t *priv, uint32_t ttm_handle, uint32_t mask, uint32_t hint, - void __user *user_pages, + unsigned long buffer_start, drm_buffer_object_t **buf_obj) { drm_device_t *dev = priv->head->dev; @@ -569,7 +572,7 @@ int drm_buffer_object_create(drm_file_t *priv, goto out_err; break; case drm_bo_type_user: - bo->user_pages = user_pages; + bo->user_pages = (void __user *)buffer_start; break; default: ret = -EINVAL; @@ -592,6 +595,27 @@ int drm_buffer_object_create(drm_file_t *priv, drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); return ret; } + +static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, + int shareable) +{ + drm_device_t *dev = priv->head->dev; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_add_user_object(priv, &bo->base, shareable); + if (ret) + goto out; + + bo->base.remove = drm_bo_base_deref_locked; + bo->base.type = drm_buffer_type; + bo->base.ref_struct_locked = NULL; + bo->base.unref = drm_buffer_user_object_unmap; + + out: + mutex_unlock(&dev->struct_mutex); + return ret; +} @@ -610,6 +634,22 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_create: { + unsigned long buffer_start = drm_ul(req->buffer_start); + rep.ret = drm_buffer_object_create(priv, drm_ul(req->size), + req->type, req->arg_handle, + req->mask, req->hint, + buffer_start, + &entry); + if (rep.ret) + break; + + rep.ret = drm_bo_add_user_object(priv, entry, req->mask & + DRM_BO_FLAG_SHAREABLE); + if (rep.ret) + drm_bo_usage_deref_unlocked(dev, entry); + break; + } case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; -- cgit v1.2.3 From 279e8d26c6cf7347aa9cb6d50d025a41dff9a5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 10:45:34 +0200 Subject: =?UTF-8?q?64-bit=20IOCTL=20integer=20(Michel=20D=E4nzer=20&=20Bri?= =?UTF-8?q?an=20Paul)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- linux-core/drm_bo.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7f5088fb..23634955 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -531,6 +531,7 @@ static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo return 0; } + int drm_buffer_object_create(drm_file_t *priv, int size, drm_bo_type_t type, @@ -544,6 +545,7 @@ int drm_buffer_object_create(drm_file_t *priv, drm_buffer_object_t *bo; int ret = 0; uint32_t ttm_flags = 0; + drm_ttm_t *ttm; bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); @@ -567,11 +569,35 @@ int drm_buffer_object_create(drm_file_t *priv, goto out_err; break; case drm_bo_type_ttm: + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Illegal buffer object start\n"); + ret = -EINVAL; + } + bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (!bo->num_pages) { + DRM_ERROR("Illegal buffer object size\n"); + ret = -EINVAL; + goto out_err; + } bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); + if (!bo->ttm_object) { + DRM_ERROR("Could not find buffer object TTM\n"); + ret = -EINVAL; + goto out_err; + } + ttm = drm_ttm_from_object(bo->ttm_object); + ret = drm_create_ttm_region(ttm, buffer_start >> PAGE_SHIFT, + bo->num_pages, 0, &bo->ttm_region); if (ret) goto out_err; break; case drm_bo_type_user: + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Illegal buffer object start\n"); + ret = -EINVAL; + goto out_err; + } + bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; bo->user_pages = (void __user *)buffer_start; break; default: @@ -635,8 +661,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.handled = 0; switch (req->op) { case drm_bo_create: { - unsigned long buffer_start = drm_ul(req->buffer_start); - rep.ret = drm_buffer_object_create(priv, drm_ul(req->size), + unsigned long buffer_start = req->buffer_start; + rep.ret = drm_buffer_object_create(priv, req->size, req->type, req->arg_handle, req->mask, req->hint, buffer_start, @@ -687,7 +713,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) default: rep.ret = -EINVAL; } - next = drm_ul(req->next); + next = req->next; rep.handled = 1; arg.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); -- cgit v1.2.3 From 0dedfc2cd03f50b435476e56637b333d345fddbd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 14:52:02 +0200 Subject: Checkpoint ttm addition to buffer objects. --- linux-core/drm_bo.c | 124 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 47 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 23634955..30656060 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -141,8 +141,8 @@ static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; - buf->flags &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_UNCACHED); - buf->flags |= DRM_BO_FLAG_MEM_LOCAL; + buf->flags &= ~(DRM_BO_FLAG_MEM_TT); + buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; return 0; } @@ -531,9 +531,65 @@ static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo return 0; } +/* + * Call bo->mutex locked. + */ + +static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t new_flags, + uint32_t ttm_handle) + +{ + drm_device_t *dev = bo->dev; + drm_ttm_object_t *to = NULL; + drm_ttm_t *ttm; + int ret=0; + uint32_t ttm_flags = 0; + + bo->ttm_object = NULL; + bo->ttm_region = NULL; + + switch(bo->type) { + case drm_bo_type_dc: + mutex_lock(&dev->struct_mutex); + ret = drm_ttm_object_create(dev, bo->num_pages*PAGE_SIZE, + ttm_flags, &to); + mutex_unlock(&dev->struct_mutex); + break; + case drm_bo_type_ttm: + mutex_lock(&dev->struct_mutex); + to = drm_lookup_ttm_object(priv, ttm_handle, 1); + mutex_unlock(&dev->struct_mutex); + if (!to) + ret = -EINVAL; + break; + case drm_bo_type_user: + + break; + default: + ret = -EINVAL; + } + + if (ret) { + return ret; + } + + if (to) { + bo->ttm_object = to; + ttm = drm_ttm_from_object(to); + ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, + bo->num_pages, + new_flags & DRM_BO_FLAG_CACHED, + &bo->ttm_region); + if (ret) { + drm_ttm_object_deref_unlocked(dev, to); + } + } + return ret; +} + int drm_buffer_object_create(drm_file_t *priv, - int size, + unsigned long size, drm_bo_type_t type, uint32_t ttm_handle, uint32_t mask, @@ -544,8 +600,18 @@ int drm_buffer_object_create(drm_file_t *priv, drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; int ret = 0; - uint32_t ttm_flags = 0; - drm_ttm_t *ttm; + uint32_t new_flags; + unsigned long num_pages; + + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Invalid buffer object start.\n"); + return -EINVAL; + } + num_pages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + if (num_pages == 0) { + DRM_ERROR("Illegal buffer object size.\n"); + return -EINVAL; + } bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); @@ -561,50 +627,14 @@ int drm_buffer_object_create(drm_file_t *priv, INIT_LIST_HEAD(&bo->head); INIT_LIST_HEAD(&bo->ddestroy); bo->dev = dev; + bo->type = type; + bo->num_pages = num_pages; + bo->buffer_start = buffer_start; - switch(type) { - case drm_bo_type_dc: - ret = drm_ttm_object_create(dev, size, ttm_flags, &bo->ttm_object); - if (ret) - goto out_err; - break; - case drm_bo_type_ttm: - if (buffer_start & ~PAGE_MASK) { - DRM_ERROR("Illegal buffer object start\n"); - ret = -EINVAL; - } - bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (!bo->num_pages) { - DRM_ERROR("Illegal buffer object size\n"); - ret = -EINVAL; - goto out_err; - } - bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); - if (!bo->ttm_object) { - DRM_ERROR("Could not find buffer object TTM\n"); - ret = -EINVAL; - goto out_err; - } - ttm = drm_ttm_from_object(bo->ttm_object); - ret = drm_create_ttm_region(ttm, buffer_start >> PAGE_SHIFT, - bo->num_pages, 0, &bo->ttm_region); - if (ret) - goto out_err; - break; - case drm_bo_type_user: - if (buffer_start & ~PAGE_MASK) { - DRM_ERROR("Illegal buffer object start\n"); - ret = -EINVAL; - goto out_err; - } - bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - bo->user_pages = (void __user *)buffer_start; - break; - default: - ret = -EINVAL; + ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); + if (ret) goto out_err; - } - + bo->mask = mask; bo->mask_hint = hint; -- cgit v1.2.3 From 23f01c9fe8e6170459fe46ad5fc9757bbe967d96 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 18:40:08 +0200 Subject: Checkpoint commit. Buffer object flags and IOCTL argument list. --- linux-core/drm_bo.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 30656060..55901660 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -214,7 +214,8 @@ static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) } -static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, +static int drm_bo_new_flags(drm_bo_driver_t *driver, + uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t *n_flags) { uint32_t new_flags; @@ -263,6 +264,24 @@ static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, } new_flags |= new_mask & ~DRM_BO_MASK_MEM; + + if (hint & DRM_BO_HINT_BIND_CACHED) { + new_flags |= DRM_BO_FLAG_CACHED; + if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || + ((new_flags & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) + new_flags &= ~DRM_BO_FLAG_CACHED; + } + + if ((new_flags & DRM_BO_FLAG_NO_EVICT) && + ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { + if (flags & DRM_BO_FLAG_CACHED) { + DRM_ERROR("Cannot change caching policy of pinned buffer\n"); + return -EINVAL; + } else { + new_flags &= ~DRM_BO_FLAG_CACHED; + } + } + *n_flags = new_flags; return 0; } @@ -531,11 +550,12 @@ static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo return 0; } + /* * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t new_flags, +static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hint, uint32_t ttm_handle) { @@ -578,7 +598,7 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t ne ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - new_flags & DRM_BO_FLAG_CACHED, + hint & DRM_BO_HINT_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -631,6 +651,10 @@ int drm_buffer_object_create(drm_file_t *priv, bo->num_pages = num_pages; bo->buffer_start = buffer_start; + ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, + 1, &new_flags); + if (ret) + goto out_err; ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); if (ret) goto out_err; -- cgit v1.2.3 From 033bda07e9a4eab5058fb919b375deb57b08b5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 09:57:35 +0200 Subject: Buffer object reply fill in. Lindent of drm_bo.c drm_ttm.c --- linux-core/drm_bo.c | 254 ++++++++++++++++++++++++++++------------------------ 1 file changed, 139 insertions(+), 115 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 55901660..24389447 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,7 +55,7 @@ * 2.) Refer to ttm locking orders. */ -int drm_fence_buffer_objects(drm_file_t *priv) +int drm_fence_buffer_objects(drm_file_t * priv) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -69,7 +69,7 @@ int drm_fence_buffer_objects(drm_file_t *priv) mutex_lock(&bm->bm_mutex); list_for_each_entry(entry, &bm->unfenced, head) { - BUG_ON(!entry->unfenced); + BUG_ON(!entry->unfenced); fence_flags |= entry->fence_flags; count++; } @@ -85,7 +85,7 @@ int drm_fence_buffer_objects(drm_file_t *priv) mutex_unlock(&bm->bm_mutex); return -ENOMEM; } - + ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); @@ -120,24 +120,23 @@ int drm_fence_buffer_objects(drm_file_t *priv) * dev locked. */ - -static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int lazy) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; int ret = 0; - + BUG_ON(!buf->tt); if (buf->fence) { - ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, + ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, buf->fence_flags); if (ret) return ret; drm_fence_usage_deref_unlocked(dev, buf->fence); buf->fence = NULL; } - + drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -147,10 +146,9 @@ static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) return 0; } - -static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) +static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { - + drm_buffer_manager_t *bm = &dev->bm; BUG_ON(bo->unfenced); @@ -189,15 +187,14 @@ static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } - -void drm_bo_usage_deref_locked(drm_device_t *dev, drm_buffer_object_t *bo) +void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { drm_bo_destroy_locked(dev, bo); } } -void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) +void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { mutex_lock(&dev->struct_mutex); @@ -207,20 +204,20 @@ void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) } } -static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) +static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) { - drm_bo_usage_deref_locked(priv->head->dev, - drm_user_object_entry(uo, drm_buffer_object_t, base)); + drm_bo_usage_deref_locked(priv->head->dev, + drm_user_object_entry(uo, drm_buffer_object_t, + base)); } - -static int drm_bo_new_flags(drm_bo_driver_t *driver, +static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t *n_flags) + int init, uint32_t * n_flags) { uint32_t new_flags; uint32_t new_props; - + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { /* @@ -234,10 +231,11 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, DRM_ERROR("Invalid buffer object memory flags\n"); return -EINVAL; } - + if (new_flags & DRM_BO_FLAG_MEM_LOCAL) { - if ((hint & DRM_BO_HINT_AVOID_LOCAL) && - new_flags & (DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_TT)) { + if ((hint & DRM_BO_HINT_AVOID_LOCAL) && + new_flags & (DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_MEM_TT)) { new_flags &= ~DRM_BO_FLAG_MEM_LOCAL; } else { new_flags = DRM_BO_FLAG_MEM_LOCAL; @@ -254,7 +252,7 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, } else { new_flags = flags & DRM_BO_MASK_MEM; } - + new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_READ); @@ -268,14 +266,16 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, if (hint & DRM_BO_HINT_BIND_CACHED) { new_flags |= DRM_BO_FLAG_CACHED; if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || - ((new_flags & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) + ((new_flags & DRM_BO_FLAG_MEM_VRAM) + && !driver->cached_vram)) new_flags &= ~DRM_BO_FLAG_CACHED; } - + if ((new_flags & DRM_BO_FLAG_NO_EVICT) && ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { if (flags & DRM_BO_FLAG_CACHED) { - DRM_ERROR("Cannot change caching policy of pinned buffer\n"); + DRM_ERROR + ("Cannot change caching policy of pinned buffer\n"); return -EINVAL; } else { new_flags &= ~DRM_BO_FLAG_CACHED; @@ -285,12 +285,10 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, *n_flags = new_flags; return 0; } - - #if 0 -static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); +static int drm_bo_evict(drm_device_t * dev, drm_buffer_object_t * buf, int tt); { int ret; if (tt) { @@ -300,8 +298,8 @@ static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); } return ret; } - -int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) + +int drm_bo_alloc_space(drm_device_t * dev, int tt, drm_buffer_object_t * buf) { drm_mm_node_t *node; drm_buffer_manager_t *bm = &dev->bm; @@ -315,13 +313,14 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) if (node) break; - if (lru->next == lru) + if (lru->next == lru) break; if (tt) { bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); } else { - bo = list_entry(lru->next, drm_buffer_object_t, vram_lru); + bo = list_entry(lru->next, drm_buffer_object_t, + vram_lru); } drm_bo_evict(dev, bo, tt); @@ -344,22 +343,20 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) return 0; } #endif - /* * Call dev->struct_mutex locked. */ - -drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t *priv, uint32_t handle, - int check_owner) +drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, + uint32_t handle, int check_owner) { drm_user_object_t *uo; drm_buffer_object_t *bo; uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_buffer_type)) + if (!uo || (uo->type != drm_buffer_type)) return NULL; if (check_owner && priv != uo->owner) { @@ -371,15 +368,15 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t *priv, uint32_t handle, atomic_inc(&bo->usage); return bo; } - + /* * Call bo->mutex locked. * Wait until the buffer is idle. */ -static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) +static int drm_bo_wait(drm_device_t * dev, drm_buffer_object_t * bo, int lazy) { - + drm_fence_object_t *fence = bo->fence; int ret; @@ -399,7 +396,9 @@ static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) atomic_inc(&fence->usage); mutex_unlock(&bo->mutex); - ret = drm_fence_object_wait(dev, fence, lazy, !lazy, bo->fence_flags); + ret = + drm_fence_object_wait(dev, fence, lazy, !lazy, + bo->fence_flags); mutex_lock(&bo->mutex); if (ret) return ret; @@ -410,7 +409,7 @@ static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) bo->fence = NULL; } mutex_unlock(&dev->struct_mutex); - } + } return 0; } @@ -419,7 +418,7 @@ static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. */ -static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) +static int drm_bo_busy(drm_device_t * dev, drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; @@ -439,7 +438,6 @@ static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) } return 0; } - /* * Wait for buffer idle and register that we've mapped the buffer. @@ -448,13 +446,12 @@ static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) * unregistered. */ - -static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) +static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; int ret; - + mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); mutex_unlock(&dev->struct_mutex); @@ -465,8 +462,7 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) mutex_lock(&bo->mutex); if (!wait) { - if ((atomic_read(&bo->mapped) == 0) && - drm_bo_busy(dev, bo)) { + if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { mutex_unlock(&bo->mutex); ret = -EBUSY; goto out; @@ -486,14 +482,13 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) atomic_inc(&bo->mapped); } mutex_unlock(&bo->mutex); - - out: - drm_bo_usage_deref_unlocked(dev,bo); + + out: + drm_bo_usage_deref_unlocked(dev, bo); return ret; } - -static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) +static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; @@ -516,21 +511,22 @@ static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) drm_remove_ref_object(priv, ro); drm_bo_usage_deref_locked(dev, bo); - out: + out: mutex_unlock(&dev->struct_mutex); return ret; } - /* * Call struct-sem locked. */ -static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo, +static void drm_buffer_user_object_unmap(drm_file_t * priv, + drm_user_object_t * uo, drm_ref_t action) { drm_device_t *dev = priv->head->dev; - drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + drm_buffer_object_t *bo = + drm_user_object_entry(uo, drm_buffer_object_t, base); BUG_ON(action != _DRM_REF_TYPE1); @@ -545,33 +541,32 @@ static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo } } -static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo) +static int drm_buffer_object_validate(drm_device_t * dev, + drm_buffer_object_t * bo) { return 0; } - /* * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hint, - uint32_t ttm_handle) - +static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, + uint32_t hint, uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; drm_ttm_t *ttm; - int ret=0; + int ret = 0; uint32_t ttm_flags = 0; bo->ttm_object = NULL; bo->ttm_region = NULL; - switch(bo->type) { + switch (bo->type) { case drm_bo_type_dc: mutex_lock(&dev->struct_mutex); - ret = drm_ttm_object_create(dev, bo->num_pages*PAGE_SIZE, + ret = drm_ttm_object_create(dev, bo->num_pages * PAGE_SIZE, ttm_flags, &to); mutex_unlock(&dev->struct_mutex); break; @@ -579,11 +574,11 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hi mutex_lock(&dev->struct_mutex); to = drm_lookup_ttm_object(priv, ttm_handle, 1); mutex_unlock(&dev->struct_mutex); - if (!to) + if (!to) ret = -EINVAL; break; case drm_bo_type_user: - + case drm_bo_type_fake: break; default: ret = -EINVAL; @@ -597,8 +592,8 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hi bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, - hint & DRM_BO_HINT_BIND_CACHED, + bo->num_pages, + hint & DRM_BO_HINT_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -606,28 +601,27 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hi } return ret; } - -int drm_buffer_object_create(drm_file_t *priv, +int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, uint32_t ttm_handle, uint32_t mask, uint32_t hint, unsigned long buffer_start, - drm_buffer_object_t **buf_obj) + drm_buffer_object_t ** buf_obj) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; int ret = 0; uint32_t new_flags; unsigned long num_pages; - + if (buffer_start & ~PAGE_MASK) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } - num_pages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; if (num_pages == 0) { DRM_ERROR("Illegal buffer object size.\n"); return -EINVAL; @@ -653,14 +647,14 @@ int drm_buffer_object_create(drm_file_t *priv, ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags); - if (ret) + if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); - if (ret) + if (ret) goto out_err; bo->mask = mask; - bo->mask_hint = hint; + bo->hint = hint; ret = drm_buffer_object_validate(dev, bo); if (ret) @@ -669,14 +663,14 @@ int drm_buffer_object_create(drm_file_t *priv, mutex_unlock(&bo->mutex); *buf_obj = bo; return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); - return ret; + return ret; } -static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, +static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo, int shareable) { drm_device_t *dev = priv->head->dev; @@ -691,13 +685,31 @@ static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, bo->base.type = drm_buffer_type; bo->base.ref_struct_locked = NULL; bo->base.unref = drm_buffer_user_object_unmap; - - out: + + out: mutex_unlock(&dev->struct_mutex); return ret; } - - + +static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, + drm_bo_arg_reply_t * rep) +{ + rep->handle = bo->base.hash.key; + rep->flags = bo->flags; + rep->size = bo->num_pages * PAGE_SIZE; + rep->offset = bo->offset; + + if (bo->ttm_object) { + rep->arg_handle = bo->ttm_object->map_list.user_token; + } else { + rep->arg_handle = 0; + } + + rep->map_flags = bo->map_flags; + rep->mask = bo->mask; + rep->hint = bo->hint; + rep->buffer_start = bo->buffer_start; +} int drm_bo_ioctl(DRM_IOCTL_ARGS) { @@ -714,34 +726,45 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { - case drm_bo_create: { - unsigned long buffer_start = req->buffer_start; - rep.ret = drm_buffer_object_create(priv, req->size, - req->type, req->arg_handle, - req->mask, req->hint, - buffer_start, - &entry); - if (rep.ret) + case drm_bo_create:{ + unsigned long buffer_start = req->buffer_start; + rep.ret = + drm_buffer_object_create(priv, req->size, + req->type, + req->arg_handle, + req->mask, + req->hint, + buffer_start, + &entry); + if (rep.ret) + break; + + rep.ret = + drm_bo_add_user_object(priv, entry, + req-> + mask & + DRM_BO_FLAG_SHAREABLE); + if (rep.ret) + drm_bo_usage_deref_unlocked(dev, entry); + + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); break; - - rep.ret = drm_bo_add_user_object(priv, entry, req->mask & - DRM_BO_FLAG_SHAREABLE); - if (rep.ret) - drm_bo_usage_deref_unlocked(dev, entry); - break; - } + } case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; case drm_bo_map: - rep.ret = drm_buffer_object_map(priv, req->handle, - !(req->hint & + rep.ret = drm_buffer_object_map(priv, req->handle, + !(req->hint & DRM_BO_HINT_DONT_BLOCK)); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, req->handle); - if (!uo || (uo->type != drm_buffer_type) || uo->owner != priv) { + if (!uo || (uo->type != drm_buffer_type) + || uo->owner != priv) { mutex_unlock(&dev->struct_mutex); rep.ret = -EINVAL; break; @@ -749,19 +772,24 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_remove_user_object(priv, uo); mutex_unlock(&dev->struct_mutex); break; - case drm_bo_reference: - rep.ret = drm_user_object_ref(priv, req->handle, + case drm_bo_reference: + rep.ret = drm_user_object_ref(priv, req->handle, drm_buffer_type, &uo); if (rep.ret) break; mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, req->handle); - entry = drm_user_object_entry(uo, drm_buffer_object_t, base); + entry = + drm_user_object_entry(uo, drm_buffer_object_t, + base); atomic_dec(&entry->usage); mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); break; case drm_bo_unreference: - rep.ret = drm_user_object_unref(priv, req->handle, + rep.ret = drm_user_object_unref(priv, req->handle, drm_buffer_type); break; default: @@ -777,7 +805,3 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } - - - - -- cgit v1.2.3 From e47a4fda2ef7aada45b7799ad20e8012102dc12e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 13:04:08 +0200 Subject: Memory manager init and takedown. --- linux-core/drm_bo.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 14 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 24389447..5f557d55 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -66,7 +66,7 @@ int drm_fence_buffer_objects(drm_file_t * priv) drm_fence_object_t *fence; int ret; - mutex_lock(&bm->bm_mutex); + mutex_lock(&bm->mutex); list_for_each_entry(entry, &bm->unfenced, head) { BUG_ON(!entry->unfenced); @@ -75,21 +75,21 @@ int drm_fence_buffer_objects(drm_file_t * priv) } if (!count) { - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return 0; } fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); if (!fence) { - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return -ENOMEM; } ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return ret; } @@ -111,7 +111,7 @@ int drm_fence_buffer_objects(drm_file_t * priv) mutex_lock(&dev->struct_mutex); atomic_add(count - 1, &fence->usage); mutex_unlock(&dev->struct_mutex); - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return 0; } @@ -179,11 +179,12 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_mm_put_block(&bm->vram_manager, bo->vram); bo->vram = NULL; } - - /* - * FIXME: Destroy ttm. - */ - + if (bo->ttm_region) { + drm_destroy_ttm_region(bo->ttm_region); + } + if (bo->ttm_object) { + drm_ttm_object_deref_locked(dev, bo->ttm_object); + } drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } @@ -356,8 +357,11 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_buffer_type)) + if (!uo || (uo->type != drm_buffer_type)) { + DRM_ERROR("Could not find buffer object 0x%08x\n", + handle); return NULL; + } if (check_owner && priv != uo->owner) { if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) @@ -541,9 +545,10 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } } -static int drm_buffer_object_validate(drm_device_t * dev, +static int drm_buffer_object_validate(drm_device_t * dev, uint32_t new_flags, drm_buffer_object_t * bo) { + bo->flags = new_flags; return 0; } @@ -574,14 +579,18 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, mutex_lock(&dev->struct_mutex); to = drm_lookup_ttm_object(priv, ttm_handle, 1); mutex_unlock(&dev->struct_mutex); - if (!to) + if (!to) { + DRM_ERROR("Could not find TTM object\n"); ret = -EINVAL; + } break; case drm_bo_type_user: case drm_bo_type_fake: break; default: + DRM_ERROR("Illegal buffer object type\n"); ret = -EINVAL; + break; } if (ret) { @@ -656,7 +665,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->mask = mask; bo->hint = hint; - ret = drm_buffer_object_validate(dev, bo); + ret = drm_buffer_object_validate(dev, new_flags, bo); if (ret) goto out_err; @@ -805,3 +814,89 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } + +static void drm_bo_clean_mm(drm_file_t *priv) +{ +} + + +int drm_mm_init_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + int ret = 0; + drm_mm_init_arg_t arg; + drm_buffer_manager_t *bm = &dev->bm; + drm_bo_driver_t *driver = dev->driver->bo_driver; + + if (!driver) { + DRM_ERROR("Buffer objects is not supported by this driver\n"); + return -EINVAL; + } + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + + switch(arg.req.op) { + case mm_init: + if (bm->initialized) { + DRM_ERROR("Memory manager already initialized\n"); + return -EINVAL; + } + mutex_init(&bm->mutex); + mutex_lock(&bm->mutex); + bm->has_vram = 0; + bm->has_tt = 0; + + if (arg.req.vr_p_size) { + ret = drm_mm_init(&bm->vram_manager, + arg.req.vr_p_offset, + arg.req.vr_p_size); + bm->has_vram = 1; + if (ret) + break; + } + + if (arg.req.tt_p_size) { + ret = drm_mm_init(&bm->tt_manager, + arg.req.tt_p_offset, + arg.req.tt_p_size); + bm->has_tt = 1; + if (ret) { + if (bm->has_vram) + drm_mm_takedown(&bm->vram_manager); + break; + } + } + arg.rep.mm_sarea = 0; + + INIT_LIST_HEAD(&bm->vram_lru); + INIT_LIST_HEAD(&bm->tt_lru); + INIT_LIST_HEAD(&bm->unfenced); + INIT_LIST_HEAD(&bm->ddestroy); + + bm->initialized = 1; + break; + case mm_takedown: + if (!bm->initialized) { + DRM_ERROR("Memory manager was not initialized\n"); + return -EINVAL; + } + mutex_lock(&bm->mutex); + drm_bo_clean_mm(priv); + if (bm->has_vram) + drm_mm_takedown(&bm->vram_manager); + if (bm->has_tt) + drm_mm_takedown(&bm->tt_manager); + bm->initialized = 0; + break; + default: + return -EINVAL; + } + + mutex_unlock(&bm->mutex); + if (ret) + return ret; + + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); + return 0; +} -- cgit v1.2.3 From 14a835be616183e733a2d6a7dcc697b8a6f46caf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 15:08:40 +0200 Subject: Buffer object mapping and mapping synchronization for multiple clients. --- linux-core/drm_bo.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 5f557d55..aa59238f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -513,8 +513,11 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) goto out; } + DRM_ERROR("Removing ref object\n"); drm_remove_ref_object(priv, ro); + DRM_ERROR("Deregistering usage\n"); drm_bo_usage_deref_locked(dev, bo); + DRM_ERROR("Done\n"); out: mutex_unlock(&dev->struct_mutex); return ret; -- cgit v1.2.3 From d39055174b5a487f0d848e1af4c3459fb4261bf1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 17:40:07 +0200 Subject: Remove the buffer object hint field and use it only as an argument. Validate stub. --- linux-core/drm_bo.c | 107 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 93 insertions(+), 14 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index aa59238f..057de9a0 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,6 +55,17 @@ * 2.) Refer to ttm locking orders. */ + +#define DRM_FLAG_MASKED(_old, _new, _mask) {\ +(_old) ^= (((_old) ^ (_new)) & (_mask)); \ +} + +static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, + uint32_t mask) +{ + return old ^ ((old ^ new) & mask); +} + int drm_fence_buffer_objects(drm_file_t * priv) { drm_device_t *dev = priv->head->dev; @@ -243,7 +254,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, } } if (new_flags & DRM_BO_FLAG_MEM_TT) { - if ((hint & DRM_BO_HINT_PREFER_VRAM) && + if ((new_mask & DRM_BO_FLAG_PREFER_VRAM) && new_flags & DRM_BO_FLAG_MEM_VRAM) { new_flags = DRM_BO_FLAG_MEM_VRAM; } else { @@ -264,7 +275,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, new_flags |= new_mask & ~DRM_BO_MASK_MEM; - if (hint & DRM_BO_HINT_BIND_CACHED) { + if (new_mask & DRM_BO_FLAG_BIND_CACHED) { new_flags |= DRM_BO_FLAG_CACHED; if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || ((new_flags & DRM_BO_FLAG_MEM_VRAM) @@ -513,11 +524,8 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) goto out; } - DRM_ERROR("Removing ref object\n"); drm_remove_ref_object(priv, ro); - DRM_ERROR("Deregistering usage\n"); drm_bo_usage_deref_locked(dev, bo); - DRM_ERROR("Done\n"); out: mutex_unlock(&dev->struct_mutex); return ret; @@ -548,19 +556,91 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } } -static int drm_buffer_object_validate(drm_device_t * dev, uint32_t new_flags, - drm_buffer_object_t * bo) +static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, + int no_wait) { - bo->flags = new_flags; return 0; } + +/* + * bo locked. + */ + + +static int drm_buffer_object_validate(drm_buffer_object_t * bo, + uint32_t new_flags, + int move_unfenced, + int no_wait) +{ + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + uint32_t flag_diff = (new_flags ^ bo->flags); + + int ret; + + if (new_flags & DRM_BO_FLAG_MEM_VRAM) { + DRM_ERROR("Vram support not implemented yet\n"); + return -EINVAL; + } + if ((new_flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM)) && + (new_flags & DRM_BO_FLAG_CACHED)) { + DRM_ERROR("Cached binding not implemented yet\n"); + return -EINVAL; + } + + /* + * Check whether we need to move buffer. + */ + + if (flag_diff & DRM_BO_MASK_MEM) { + mutex_lock(&bm->mutex); + ret = drm_bo_move_buffer(bo, new_flags, no_wait); + mutex_unlock(&bm->mutex); + if (ret) + return ret; + } + + if (flag_diff & DRM_BO_FLAG_NO_EVICT) { + mutex_lock(&bm->mutex); + list_del_init(&bo->head); + if (!(new_flags & DRM_BO_FLAG_NO_EVICT)) { + if (new_flags & DRM_BO_FLAG_MEM_TT) { + list_add_tail(&bo->head, &bm->tt_lru); + } else { + list_add_tail(&bo->head, &bm->vram_lru); + } + } + mutex_unlock(&bm->mutex); + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); + } + + if (move_unfenced) { + + /* + * Place on unfenced list. + */ + + mutex_lock(&bm->mutex); + list_del_init(&bo->head); + list_add_tail(&bo->head, &bm->unfenced); + mutex_unlock(&bm->mutex); + } + + /* + * FIXME: Remove below. + */ + + bo->flags = new_flags; + return 0; +} + /* * Call bo->mutex locked. */ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t hint, uint32_t ttm_handle) + uint32_t mask, uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; @@ -605,7 +685,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - hint & DRM_BO_HINT_BIND_CACHED, + mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -661,14 +741,14 @@ int drm_buffer_object_create(drm_file_t * priv, 1, &new_flags); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); + ret = drm_bo_add_ttm(priv, bo, mask, ttm_handle); if (ret) goto out_err; bo->mask = mask; - bo->hint = hint; - ret = drm_buffer_object_validate(dev, new_flags, bo); + ret = drm_buffer_object_validate(bo, new_flags, 0, + hint & DRM_BO_HINT_DONT_BLOCK); if (ret) goto out_err; @@ -719,7 +799,6 @@ static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, rep->map_flags = bo->map_flags; rep->mask = bo->mask; - rep->hint = bo->hint; rep->buffer_start = bo->buffer_start; } -- cgit v1.2.3 From 611662ab287c279a95ae33442325626e0191e2c5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 20:23:40 +0200 Subject: Buffer eviction. Reworked map refcounting so that any process waiting on buffer object unmap will allow in other processes to unmap the buffer object. --- linux-core/drm_bo.c | 151 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 61 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 057de9a0..f3105283 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -127,32 +127,23 @@ int drm_fence_buffer_objects(drm_file_t * priv) } /* - * bm locked, - * dev locked. + * bo locked. */ -static int drm_move_tt_to_local(drm_buffer_object_t * buf, int lazy) +static int drm_move_tt_to_local(drm_buffer_object_t * buf) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; - int ret = 0; BUG_ON(!buf->tt); - if (buf->fence) { - ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, - buf->fence_flags); - if (ret) - return ret; - drm_fence_usage_deref_unlocked(dev, buf->fence); - buf->fence = NULL; - } - + mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; - buf->flags &= ~(DRM_BO_FLAG_MEM_TT); - buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&bm->mutex); return 0; } @@ -183,7 +174,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) if (bo->tt) { int ret; - ret = drm_move_tt_to_local(bo, 0); + ret = drm_move_tt_to_local(bo); BUG_ON(ret); } if (bo->vram) { @@ -389,41 +380,31 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, * Wait until the buffer is idle. */ -static int drm_bo_wait(drm_device_t * dev, drm_buffer_object_t * bo, int lazy) +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) { drm_fence_object_t *fence = bo->fence; int ret; if (fence) { + drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; - } - - /* - * Make sure another process doesn't destroy the fence - * object when we release the buffer object mutex. - * We don't need to take the dev->struct_mutex lock here, - * since the fence usage count is at least 1 already. - */ + } + if (no_wait) + return -EBUSY; - atomic_inc(&fence->usage); - mutex_unlock(&bo->mutex); ret = drm_fence_object_wait(dev, fence, lazy, !lazy, bo->fence_flags); - mutex_lock(&bo->mutex); if (ret) return ret; - mutex_lock(&dev->struct_mutex); - drm_fence_usage_deref_locked(dev, fence); - if (bo->fence == fence) { - drm_fence_usage_deref_locked(dev, fence); - bo->fence = NULL; - } - mutex_unlock(&dev->struct_mutex); + + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + } return 0; } @@ -433,11 +414,12 @@ static int drm_bo_wait(drm_device_t * dev, drm_buffer_object_t * bo, int lazy) * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. */ -static int drm_bo_busy(drm_device_t * dev, drm_buffer_object_t * bo) +static int drm_bo_busy(drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; if (fence) { + drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -476,29 +458,30 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) mutex_lock(&bo->mutex); - if (!wait) { - if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { - mutex_unlock(&bo->mutex); - ret = -EBUSY; - goto out; - } - } else { - ret = drm_bo_wait(dev, bo, 0); + /* + * If this returns true, we are currently unmapped. + * We need to do this test, because unmapping can + * be done without the bo->mutex held. + */ + + if (atomic_inc_and_test(&bo->mapped)) { + ret = drm_bo_wait(bo, 0, !wait); if (ret) { - mutex_unlock(&bo->mutex); - ret = -EBUSY; + atomic_dec(&bo->mapped); goto out; } } + mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); - if (!ret) { - atomic_inc(&bo->mapped); - } - mutex_unlock(&bo->mutex); + if (ret) { + if (atomic_add_negative(-1, &bo->mapped)) + DRM_WAKEUP(&bo->validate_queue); + } out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); return ret; } @@ -539,26 +522,72 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, drm_user_object_t * uo, drm_ref_t action) { - drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo = - drm_user_object_entry(uo, drm_buffer_object_t, base); + drm_user_object_entry(uo, drm_buffer_object_t, base); + + /* + * We DON'T want to take the bo->lock here, because we want to + * hold it when we wait for unmapped buffer. + */ BUG_ON(action != _DRM_REF_TYPE1); - if (atomic_dec_and_test(&bo->mapped)) { - mutex_unlock(&dev->struct_mutex); - mutex_lock(&bo->mutex); - if (atomic_read(&bo->mapped) == 0) { + if (atomic_add_negative(-1, &bo->mapped)) DRM_WAKEUP(&bo->validate_queue); - } - mutex_unlock(&bo->mutex); - mutex_lock(&dev->struct_mutex); - } } +/* + * bo->mutex locked. + */ + + static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, int no_wait) { + int ret = 0; + + /* + * Flush outstanding fences. + */ + + drm_bo_busy(bo); + + /* + * Make sure we're not mapped. + */ + + if (atomic_read(&bo->mapped) >= 0) { + if (no_wait) + return -EBUSY; + else { + DRM_WAIT_ON(ret, bo->validate_queue, 3*DRM_HZ, + atomic_read(&bo->mapped) == -1); + if (ret == -EINTR) + return -EAGAIN; + if (ret) + return ret; + } + } + + /* + * Wait for outstanding fences. + */ + + ret = drm_bo_wait(bo, 0, no_wait); + + if (ret == -EINTR) + return -EAGAIN; + if (ret) + return ret; + + if (new_flags & DRM_BO_FLAG_MEM_TT) { + drm_move_local_to_tt(bo); + } else { + drm_move_tt_to_local(bo); + } + + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_MEM_TT); + return 0; } @@ -728,7 +757,7 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_lock(&bo->mutex); atomic_set(&bo->usage, 1); - atomic_set(&bo->mapped, 0); + atomic_set(&bo->mapped, -1); DRM_INIT_WAITQUEUE(&bo->validate_queue); INIT_LIST_HEAD(&bo->head); INIT_LIST_HEAD(&bo->ddestroy); -- cgit v1.2.3 From 914a77a15aae07cc305cc5da5ad6c7a639cbc121 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 21:30:47 +0200 Subject: Buffer object binding. Some code reordering. --- linux-core/drm_bo.c | 268 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 171 insertions(+), 97 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f3105283..18cfadc5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -126,6 +126,7 @@ int drm_fence_buffer_objects(drm_file_t * priv) return 0; } + /* * bo locked. */ @@ -148,6 +149,8 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) return 0; } + + static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { @@ -197,6 +200,13 @@ void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) } } +static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) +{ + drm_bo_usage_deref_locked(priv->head->dev, + drm_user_object_entry(uo, drm_buffer_object_t, + base)); +} + void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { @@ -207,13 +217,167 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } -static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) + +/* + * Call bo->mutex locked. + * Wait until the buffer is idle. + */ + +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) { - drm_bo_usage_deref_locked(priv->head->dev, - drm_user_object_entry(uo, drm_buffer_object_t, - base)); + + drm_fence_object_t *fence = bo->fence; + int ret; + + if (fence) { + drm_device_t *dev = bo->dev; + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + if (no_wait) + return -EBUSY; + + ret = + drm_fence_object_wait(dev, fence, lazy, !lazy, + bo->fence_flags); + if (ret) + return ret; + + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + + } + return 0; +} + +/* + * No locking required. + */ + +static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) +{ + int ret = 0; + + /* + * Someone might have taken out the buffer before we took the buffer mutex. + */ + + mutex_lock(&bo->mutex); + if (bo->unfenced) + goto out; + if (tt && !bo->tt) + goto out; + if (!tt && !bo->vram) + goto out; + + ret = drm_bo_wait(bo, 0, no_wait); + if (ret) + goto out; + + if (tt) { + ret = drm_move_tt_to_local(bo); + } +#if 0 + else { + ret = drm_move_vram_to_local(bo); + } +#endif +out: + mutex_unlock(&bo->mutex); + return ret; +} + +/* + * buf->mutex locked. + */ + +int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) +{ + drm_device_t *dev = buf->dev; + drm_mm_node_t *node; + drm_buffer_manager_t *bm = &dev->bm; + drm_buffer_object_t *bo; + drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; + struct list_head *lru; + unsigned long size = buf->num_pages; + int ret; + + mutex_lock(&bm->mutex); + do { + node = drm_mm_search_free(mm, size, 0, 1); + if (node) + break; + + lru = (tt) ? &bm->tt_lru : &bm->vram_lru; + if (lru->next == lru) + break; + + bo = list_entry(lru->next, drm_buffer_object_t, head); + + /* + * No need to take dev->struct_mutex here, because bo->usage is at least 1 already, + * since it's on the lru list, and the bm->mutex is held. + */ + + atomic_inc(&bo->usage); + mutex_unlock(&bm->mutex); + ret = drm_bo_evict(bo, tt, no_wait); + drm_bo_usage_deref_unlocked(dev, bo); + if (ret) + return ret; + mutex_lock(&bm->mutex); + } while (1); + + if (!node) { + DRM_ERROR("Out of aperture space\n"); + mutex_lock(&bm->mutex); + return -ENOMEM; + } + + node = drm_mm_get_block(node, size, 0); + mutex_unlock(&bm->mutex); + BUG_ON(!node); + node->private = (void *)buf; + + if (tt) { + buf->tt = node; + } else { + buf->vram = node; + } + return 0; +} + + +static int drm_move_local_to_tt(drm_buffer_object_t *bo, int no_wait) +{ + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + int ret; + + + BUG_ON(bo->tt); + ret = drm_bo_alloc_space(bo, 1, no_wait); + + if (ret) + return ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); + mutex_unlock(&dev->struct_mutex); + + if (ret) { + mutex_lock(&bm->mutex); + drm_mm_put_block(&bm->tt_manager, bo->tt); + mutex_unlock(&bm->mutex); + } + + return ret; } + + static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t * n_flags) @@ -289,64 +453,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, return 0; } -#if 0 - -static int drm_bo_evict(drm_device_t * dev, drm_buffer_object_t * buf, int tt); -{ - int ret; - if (tt) { - ret = drm_move_tt_to_local(buf); - } else { - ret = drm_move_vram_to_local(buf); - } - return ret; -} - -int drm_bo_alloc_space(drm_device_t * dev, int tt, drm_buffer_object_t * buf) -{ - drm_mm_node_t *node; - drm_buffer_manager_t *bm = &dev->bm; - drm_buffer_object_t *bo; - drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; - - lru = (tt) ? &bm->tt_lru : &bm->vram_lru; - - do { - node = drm_mm_search_free(mm, size, 0, 1); - if (node) - break; - - if (lru->next == lru) - break; - - if (tt) { - bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); - } else { - bo = list_entry(lru->next, drm_buffer_object_t, - vram_lru); - } - - drm_bo_evict(dev, bo, tt); - } while (1); - - if (!node) { - DRM_ERROR("Out of aperture space\n"); - return -ENOMEM; - } - - node = drm_mm_get_block(node, size, 0); - BUG_ON(!node); - node->private = (void *)buf; - - if (tt) { - buf->tt = node; - } else { - buf->vram = node; - } - return 0; -} -#endif - /* * Call dev->struct_mutex locked. */ @@ -375,40 +481,6 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, return bo; } -/* - * Call bo->mutex locked. - * Wait until the buffer is idle. - */ - -static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) -{ - - drm_fence_object_t *fence = bo->fence; - int ret; - - if (fence) { - drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; - return 0; - } - if (no_wait) - return -EBUSY; - - ret = - drm_fence_object_wait(dev, fence, lazy, !lazy, - bo->fence_flags); - if (ret) - return ret; - - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; - - } - return 0; -} - /* * Call bo->mutex locked. * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. @@ -581,7 +653,9 @@ static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, return ret; if (new_flags & DRM_BO_FLAG_MEM_TT) { - drm_move_local_to_tt(bo); + ret = drm_move_local_to_tt(bo, no_wait); + if (ret) + return ret; } else { drm_move_tt_to_local(bo); } -- cgit v1.2.3 From ed9de124cc88cee398b7013de6b822bfaa3f397e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 21:31:38 +0200 Subject: Lindenting drm_bo.c and drm_ttm.c --- linux-core/drm_bo.c | 85 ++++++++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 18cfadc5..faa2e007 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,12 +55,11 @@ * 2.) Refer to ttm locking orders. */ - #define DRM_FLAG_MASKED(_old, _new, _mask) {\ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } -static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, +static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, uint32_t mask) { return old ^ ((old ^ new) & mask); @@ -126,7 +125,6 @@ int drm_fence_buffer_objects(drm_file_t * priv) return 0; } - /* * bo locked. */ @@ -149,8 +147,6 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) return 0; } - - static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { @@ -217,7 +213,6 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } - /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -235,7 +230,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; - } + } if (no_wait) return -EBUSY; @@ -244,7 +239,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) bo->fence_flags); if (ret) return ret; - + drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -259,15 +254,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) { int ret = 0; - + /* * Someone might have taken out the buffer before we took the buffer mutex. */ - + mutex_lock(&bo->mutex); if (bo->unfenced) goto out; - if (tt && !bo->tt) + if (tt && !bo->tt) goto out; if (!tt && !bo->vram) goto out; @@ -284,7 +279,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif -out: + out: mutex_unlock(&bo->mutex); return ret; } @@ -315,7 +310,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) break; bo = list_entry(lru->next, drm_buffer_object_t, head); - + /* * No need to take dev->struct_mutex here, because bo->usage is at least 1 already, * since it's on the lru list, and the bm->mutex is held. @@ -349,14 +344,12 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) return 0; } - -static int drm_move_local_to_tt(drm_buffer_object_t *bo, int no_wait) +static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; int ret; - BUG_ON(bo->tt); ret = drm_bo_alloc_space(bo, 1, no_wait); @@ -376,8 +369,6 @@ static int drm_move_local_to_tt(drm_buffer_object_t *bo, int no_wait) return ret; } - - static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t * n_flags) @@ -466,8 +457,7 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, uo = drm_lookup_user_object(priv, handle); if (!uo || (uo->type != drm_buffer_type)) { - DRM_ERROR("Could not find buffer object 0x%08x\n", - handle); + DRM_ERROR("Could not find buffer object 0x%08x\n", handle); return NULL; } @@ -595,7 +585,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, drm_ref_t action) { drm_buffer_object_t *bo = - drm_user_object_entry(uo, drm_buffer_object_t, base); + drm_user_object_entry(uo, drm_buffer_object_t, base); /* * We DON'T want to take the bo->lock here, because we want to @@ -605,15 +595,14 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, BUG_ON(action != _DRM_REF_TYPE1); if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->validate_queue); + DRM_WAKEUP(&bo->validate_queue); } /* * bo->mutex locked. */ - -static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, +static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, int no_wait) { int ret = 0; @@ -627,16 +616,16 @@ static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, /* * Make sure we're not mapped. */ - + if (atomic_read(&bo->mapped) >= 0) { - if (no_wait) + if (no_wait) return -EBUSY; else { - DRM_WAIT_ON(ret, bo->validate_queue, 3*DRM_HZ, + DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, atomic_read(&bo->mapped) == -1); - if (ret == -EINTR) + if (ret == -EINTR) return -EAGAIN; - if (ret) + if (ret) return ret; } } @@ -659,22 +648,19 @@ static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, } else { drm_move_tt_to_local(bo); } - + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_MEM_TT); - + return 0; } - /* * bo locked. */ - static int drm_buffer_object_validate(drm_buffer_object_t * bo, uint32_t new_flags, - int move_unfenced, - int no_wait) + int move_unfenced, int no_wait) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -700,10 +686,10 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, mutex_lock(&bm->mutex); ret = drm_bo_move_buffer(bo, new_flags, no_wait); mutex_unlock(&bm->mutex); - if (ret) + if (ret) return ret; } - + if (flag_diff & DRM_BO_FLAG_NO_EVICT) { mutex_lock(&bm->mutex); list_del_init(&bo->head); @@ -723,7 +709,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, /* * Place on unfenced list. */ - + mutex_lock(&bm->mutex); list_del_init(&bo->head); list_add_tail(&bo->head, &bm->unfenced); @@ -737,7 +723,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, bo->flags = new_flags; return 0; } - + /* * Call bo->mutex locked. */ @@ -850,7 +836,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->mask = mask; - ret = drm_buffer_object_validate(bo, new_flags, 0, + ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); if (ret) goto out_err; @@ -1000,15 +986,14 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) } -static void drm_bo_clean_mm(drm_file_t *priv) +static void drm_bo_clean_mm(drm_file_t * priv) { } - int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; - + int ret = 0; drm_mm_init_arg_t arg; drm_buffer_manager_t *bm = &dev->bm; @@ -1021,7 +1006,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - switch(arg.req.op) { + switch (arg.req.op) { case mm_init: if (bm->initialized) { DRM_ERROR("Memory manager already initialized\n"); @@ -1033,8 +1018,8 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->has_tt = 0; if (arg.req.vr_p_size) { - ret = drm_mm_init(&bm->vram_manager, - arg.req.vr_p_offset, + ret = drm_mm_init(&bm->vram_manager, + arg.req.vr_p_offset, arg.req.vr_p_size); bm->has_vram = 1; if (ret) @@ -1042,8 +1027,8 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } if (arg.req.tt_p_size) { - ret = drm_mm_init(&bm->tt_manager, - arg.req.tt_p_offset, + ret = drm_mm_init(&bm->tt_manager, + arg.req.tt_p_offset, arg.req.tt_p_size); bm->has_tt = 1; if (ret) { @@ -1077,11 +1062,11 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) default: return -EINVAL; } - + mutex_unlock(&bm->mutex); if (ret) return ret; - + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return 0; } -- cgit v1.2.3 From ec8c79b79de6544cc09b5a2c85213a5f30e0d906 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 14:10:13 +0200 Subject: More mapping synchronization. libdrm validate and fencing functions. --- linux-core/drm_bo.c | 163 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 122 insertions(+), 41 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index faa2e007..232120a4 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -256,11 +256,11 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) int ret = 0; /* - * Someone might have taken out the buffer before we took the buffer mutex. + * Someone might have modified the buffer before we took the buffer mutex. */ mutex_lock(&bo->mutex); - if (bo->unfenced) + if (bo->unfenced || (bo->flags & DRM_BO_FLAG_NO_EVICT)) goto out; if (tt && !bo->tt) goto out; @@ -371,17 +371,46 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t * n_flags) + int init, uint32_t * n_flags, + uint32_t *n_mask) { - uint32_t new_flags; + uint32_t new_flags = 0; uint32_t new_props; - if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { + /* + * First adjust the mask. Vram is not supported yet. + */ - /* - * We need to move memory. Default preferences are hard-coded - * here. - */ + new_mask &= ~DRM_BO_FLAG_MEM_VRAM; + + if (new_mask & DRM_BO_FLAG_BIND_CACHED) { + if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && + ((new_mask & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) { + new_mask &= ~DRM_BO_FLAG_BIND_CACHED; + } else { + if (!driver->cached_tt) + new_flags &= DRM_BO_FLAG_MEM_TT; + if (!driver->cached_vram) + new_flags &= DRM_BO_FLAG_MEM_VRAM; + } + } + + if ((new_mask & DRM_BO_FLAG_READ_CACHED) && + !(new_mask & DRM_BO_FLAG_BIND_CACHED)) { + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && + !(new_mask & DRM_BO_FLAG_MEM_LOCAL)) { + DRM_ERROR("Cannot read cached from a pinned VRAM / TT buffer\n"); + return -EINVAL; + } + new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); + } + + /* + * Determine new memory location: + */ + + + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { new_flags = new_mask & DRM_BO_MASK_MEM; @@ -421,17 +450,10 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, new_flags |= new_mask & ~DRM_BO_MASK_MEM; - if (new_mask & DRM_BO_FLAG_BIND_CACHED) { - new_flags |= DRM_BO_FLAG_CACHED; - if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || - ((new_flags & DRM_BO_FLAG_MEM_VRAM) - && !driver->cached_vram)) - new_flags &= ~DRM_BO_FLAG_CACHED; - } - - if ((new_flags & DRM_BO_FLAG_NO_EVICT) && - ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { - if (flags & DRM_BO_FLAG_CACHED) { + if (((flags ^ new_flags) & DRM_BO_FLAG_BIND_CACHED) && + (new_flags & DRM_BO_FLAG_NO_EVICT) && + (flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM))) { + if (!(flags & DRM_BO_FLAG_CACHED)) { DRM_ERROR ("Cannot change caching policy of pinned buffer\n"); return -EINVAL; @@ -441,6 +463,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, } *n_flags = new_flags; + *n_mask = new_mask; return 0; } @@ -498,6 +521,12 @@ static int drm_bo_busy(drm_buffer_object_t * bo) return 0; } + +static int drm_bo_read_cached(drm_buffer_object_t *bo) { + return 0; +} + + /* * Wait for buffer idle and register that we've mapped the buffer. * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, @@ -505,11 +534,12 @@ static int drm_bo_busy(drm_buffer_object_t * bo) * unregistered. */ -static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) +static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, + uint32_t map_flags, int no_wait) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; - int ret; + int ret = 0; mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); @@ -526,14 +556,46 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) * be done without the bo->mutex held. */ - if (atomic_inc_and_test(&bo->mapped)) { - ret = drm_bo_wait(bo, 0, !wait); - if (ret) { - atomic_dec(&bo->mapped); - goto out; + while(1) { + if (atomic_inc_and_test(&bo->mapped)) { + ret = drm_bo_wait(bo, 0, no_wait); + if (ret) { + atomic_dec(&bo->mapped); + goto out; + } + + if ((map_flags & DRM_BO_FLAG_READ) && + (bo->flags & DRM_BO_FLAG_READ_CACHED) && + (!(bo->flags & DRM_BO_FLAG_CACHED))) { + + drm_bo_read_cached(bo); + } + break; + } else { + if ((map_flags & DRM_BO_FLAG_READ) && + (bo->flags & DRM_BO_FLAG_READ_CACHED) && + (!(bo->flags & DRM_BO_FLAG_CACHED))) { + + /* + * We are already mapped with different flags. + * need to wait for unmap. + */ + + if (no_wait) { + ret = -EBUSY; + goto out; + } + DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, + atomic_read(&bo->mapped) == -1); + if (ret == -EINTR) + ret = -EAGAIN; + if (ret) + goto out; + continue; + } } } - + mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); @@ -729,7 +791,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, */ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t mask, uint32_t ttm_handle) + uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; @@ -774,7 +836,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - mask & DRM_BO_FLAG_BIND_CACHED, + bo->mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -827,17 +889,19 @@ int drm_buffer_object_create(drm_file_t * priv, bo->buffer_start = buffer_start; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, - 1, &new_flags); + 1, &new_flags, &bo->mask); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, mask, ttm_handle); + ret = drm_bo_add_ttm(priv, bo, ttm_handle); if (ret) goto out_err; - bo->mask = mask; - +#if 0 ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); +#else + bo->flags = new_flags; +#endif if (ret) goto out_err; @@ -886,7 +950,6 @@ static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, rep->arg_handle = 0; } - rep->map_flags = bo->map_flags; rep->mask = bo->mask; rep->buffer_start = bo->buffer_start; } @@ -902,9 +965,15 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) drm_buffer_object_t *entry; do { - DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, + sizeof(arg)); + + if (arg.handled) { + data = req->next; + continue; + } + rep.ret = 0; - rep.handled = 0; switch (req->op) { case drm_bo_create:{ unsigned long buffer_start = req->buffer_start; @@ -937,8 +1006,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, - !(req->hint & - DRM_BO_HINT_DONT_BLOCK)); + req->mask, + req->hint & + DRM_BO_HINT_DONT_BLOCK); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -976,16 +1046,25 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = -EINVAL; } next = req->next; - rep.handled = 1; + + /* + * A signal interrupted us. Make sure the ioctl is restartable. + */ + + if (rep.ret == -EAGAIN) + return -EAGAIN; + + arg.handled = 1; arg.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); data = next; } while (data); return 0; - } + + static void drm_bo_clean_mm(drm_file_t * priv) { } @@ -1008,10 +1087,12 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) switch (arg.req.op) { case mm_init: +#if 0 if (bm->initialized) { DRM_ERROR("Memory manager already initialized\n"); return -EINVAL; } +#endif mutex_init(&bm->mutex); mutex_lock(&bm->mutex); bm->has_vram = 0; -- cgit v1.2.3 From 03c137c5f8d44c374406efe19c01105fcf34d583 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 15:36:40 +0200 Subject: Remove the buffer manager mutex. Use dev->struct_mutex instead. Add a function to free buffers on hold for destruction if their fence object has expired. Add a timer to periodically call that function when there are buffers pending deletion. --- linux-core/drm_bo.c | 120 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 38 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 232120a4..e2513267 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,11 +59,6 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } -static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, - uint32_t mask) -{ - return old ^ ((old ^ new) & mask); -} int drm_fence_buffer_objects(drm_file_t * priv) { @@ -76,7 +71,7 @@ int drm_fence_buffer_objects(drm_file_t * priv) drm_fence_object_t *fence; int ret; - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); list_for_each_entry(entry, &bm->unfenced, head) { BUG_ON(!entry->unfenced); @@ -85,21 +80,21 @@ int drm_fence_buffer_objects(drm_file_t * priv) } if (!count) { - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return 0; } fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); if (!fence) { - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return -ENOMEM; } ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -118,10 +113,8 @@ int drm_fence_buffer_objects(drm_file_t * priv) } } - mutex_lock(&dev->struct_mutex); atomic_add(count - 1, &fence->usage); mutex_unlock(&dev->struct_mutex); - mutex_unlock(&bm->mutex); return 0; } @@ -136,28 +129,36 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); - mutex_lock(&bm->mutex); mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; mutex_unlock(&dev->struct_mutex); - mutex_unlock(&bm->mutex); return 0; } + + +/* + * Lock dev->struct_mutex + */ + static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { drm_buffer_manager_t *bm = &dev->bm; - BUG_ON(bo->unfenced); - if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); + + if (!timer_pending(&bm->timer)) { + bm->timer.expires = jiffies + 1; + add_timer(&bm->timer); + } + return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -189,6 +190,50 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } +static void drm_bo_delayed_delete(drm_device_t *dev) +{ + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry, *next; + drm_fence_object_t *fence; + + mutex_lock(&dev->struct_mutex); + + list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { + fence = entry->fence; + + if (fence && drm_fence_object_signaled(fence, + entry->fence_flags)) { + drm_fence_usage_deref_locked(dev, fence); + entry->fence = NULL; + } + if (!entry->fence) { + DRM_DEBUG("Destroying delayed buffer object\n"); + list_del(&entry->ddestroy); + drm_bo_destroy_locked(dev, entry); + } + } + + mutex_unlock(&dev->struct_mutex); +} + + +static void +drm_bo_delayed_timer(unsigned long data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_buffer_manager_t *bm = &dev->bm; + + drm_bo_delayed_delete(dev); + mutex_lock(&dev->struct_mutex); + if (!list_empty(&bm->ddestroy) && !timer_pending(&bm->timer)) { + bm->timer.expires = jiffies + 1; + add_timer(&bm->timer); + } + mutex_unlock(&dev->struct_mutex); +} + + void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { @@ -299,7 +344,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) unsigned long size = buf->num_pages; int ret; - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); do { node = drm_mm_search_free(mm, size, 0, 1); if (node) @@ -313,26 +358,26 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) /* * No need to take dev->struct_mutex here, because bo->usage is at least 1 already, - * since it's on the lru list, and the bm->mutex is held. + * since it's on the lru list, and the dev->struct_mutex is held. */ atomic_inc(&bo->usage); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); ret = drm_bo_evict(bo, tt, no_wait); drm_bo_usage_deref_unlocked(dev, bo); if (ret) return ret; - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); } while (1); if (!node) { DRM_ERROR("Out of aperture space\n"); - mutex_lock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return -ENOMEM; } node = drm_mm_get_block(node, size, 0); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); BUG_ON(!node); node->private = (void *)buf; @@ -358,14 +403,10 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); - mutex_unlock(&dev->struct_mutex); - if (ret) { - mutex_lock(&bm->mutex); drm_mm_put_block(&bm->tt_manager, bo->tt); - mutex_unlock(&bm->mutex); } - + mutex_unlock(&dev->struct_mutex); return ret; } @@ -745,15 +786,15 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, */ if (flag_diff & DRM_BO_MASK_MEM) { - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); ret = drm_bo_move_buffer(bo, new_flags, no_wait); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); if (ret) return ret; } if (flag_diff & DRM_BO_FLAG_NO_EVICT) { - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); list_del_init(&bo->head); if (!(new_flags & DRM_BO_FLAG_NO_EVICT)) { if (new_flags & DRM_BO_FLAG_MEM_TT) { @@ -762,7 +803,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, list_add_tail(&bo->head, &bm->vram_lru); } } - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -772,10 +813,10 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Place on unfenced list. */ - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); list_del_init(&bo->head); list_add_tail(&bo->head, &bm->unfenced); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); } /* @@ -860,6 +901,7 @@ int drm_buffer_object_create(drm_file_t * priv, uint32_t new_flags; unsigned long num_pages; + drm_bo_delayed_delete(dev); if (buffer_start & ~PAGE_MASK) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; @@ -976,14 +1018,13 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; switch (req->op) { case drm_bo_create:{ - unsigned long buffer_start = req->buffer_start; rep.ret = drm_buffer_object_create(priv, req->size, req->type, req->arg_handle, req->mask, req->hint, - buffer_start, + req->buffer_start, &entry); if (rep.ret) break; @@ -1093,8 +1134,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } #endif - mutex_init(&bm->mutex); - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); bm->has_vram = 0; bm->has_tt = 0; @@ -1125,6 +1165,10 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); + init_timer(&bm->timer); + bm->timer.function = &drm_bo_delayed_timer; + bm->timer.data = (unsigned long) dev; + bm->initialized = 1; break; case mm_takedown: @@ -1132,7 +1176,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) DRM_ERROR("Memory manager was not initialized\n"); return -EINVAL; } - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); drm_bo_clean_mm(priv); if (bm->has_vram) drm_mm_takedown(&bm->vram_manager); @@ -1144,7 +1188,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); if (ret) return ret; -- cgit v1.2.3 From 44f6d08988a77a640bea40d09cb61eec7566a5ce Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 21:42:29 +0200 Subject: Validation and fencing. --- linux-core/drm_bo.c | 571 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 381 insertions(+), 190 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e2513267..8bca2e32 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,65 +59,6 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } - -int drm_fence_buffer_objects(drm_file_t * priv) -{ - drm_device_t *dev = priv->head->dev; - drm_buffer_manager_t *bm = &dev->bm; - - drm_buffer_object_t *entry, *next; - uint32_t fence_flags = 0; - int count = 0; - drm_fence_object_t *fence; - int ret; - - mutex_lock(&dev->struct_mutex); - - list_for_each_entry(entry, &bm->unfenced, head) { - BUG_ON(!entry->unfenced); - fence_flags |= entry->fence_flags; - count++; - } - - if (!count) { - mutex_unlock(&dev->struct_mutex); - return 0; - } - - fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); - - if (!fence) { - mutex_unlock(&dev->struct_mutex); - return -ENOMEM; - } - - ret = drm_fence_object_init(dev, fence_flags, 1, fence); - if (ret) { - drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); - mutex_unlock(&dev->struct_mutex); - return ret; - } - - list_for_each_entry_safe(entry, next, &bm->unfenced, head) { - BUG_ON(entry->fence); - entry->unfenced = 0; - entry->fence = fence; - list_del_init(&entry->head); - - if (!(entry->flags & DRM_BO_FLAG_NO_EVICT)) { - if (entry->flags & DRM_BO_FLAG_MEM_TT) { - list_add_tail(&entry->head, &bm->tt_lru); - } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { - list_add_tail(&entry->head, &bm->vram_lru); - } - } - } - - atomic_add(count - 1, &fence->usage); - mutex_unlock(&dev->struct_mutex); - return 0; -} - /* * bo locked. */ @@ -135,11 +76,12 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) buf->tt = NULL; mutex_unlock(&dev->struct_mutex); + buf->flags &= ~DRM_BO_MASK_MEM; + buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + return 0; } - - /* * Lock dev->struct_mutex */ @@ -149,6 +91,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); @@ -158,7 +101,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) bm->timer.expires = jiffies + 1; add_timer(&bm->timer); } - + return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -170,7 +113,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * Take away from lru lists. */ - list_del_init(&bo->head); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); if (bo->tt) { int ret; @@ -190,10 +134,10 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } -static void drm_bo_delayed_delete(drm_device_t *dev) +static void drm_bo_delayed_delete(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; - + drm_buffer_object_t *entry, *next; drm_fence_object_t *fence; @@ -202,7 +146,7 @@ static void drm_bo_delayed_delete(drm_device_t *dev) list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { fence = entry->fence; - if (fence && drm_fence_object_signaled(fence, + if (fence && drm_fence_object_signaled(fence, entry->fence_flags)) { drm_fence_usage_deref_locked(dev, fence); entry->fence = NULL; @@ -217,13 +161,11 @@ static void drm_bo_delayed_delete(drm_device_t *dev) mutex_unlock(&dev->struct_mutex); } - -static void -drm_bo_delayed_timer(unsigned long data) +static void drm_bo_delayed_timer(unsigned long data) { - drm_device_t *dev = (drm_device_t *)data; + drm_device_t *dev = (drm_device_t *) data; drm_buffer_manager_t *bm = &dev->bm; - + drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy) && !timer_pending(&bm->timer)) { @@ -233,7 +175,6 @@ drm_bo_delayed_timer(unsigned long data) mutex_unlock(&dev->struct_mutex); } - void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { @@ -258,6 +199,103 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } +int drm_fence_buffer_objects(drm_file_t * priv, + struct list_head *list, + drm_fence_object_t *fence) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry; + uint32_t fence_flags = 0; + int count = 0; + int ret = 0; + struct list_head f_list, *l; + + mutex_lock(&dev->struct_mutex); + + list_for_each_entry(entry, list, head) { + BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); + fence_flags |= entry->fence_flags; + count++; + } + + if (!count) + goto out; + + if (fence) { + if ((fence_flags & fence->type) != fence_flags) { + DRM_ERROR("Given fence doesn't match buffers " + "on unfenced list.\n"); + ret = -EINVAL; + goto out; + } + } else { + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + + if (!fence) { + ret = -ENOMEM; + goto out; + } + + ret = drm_fence_object_init(dev, fence_flags, 1, fence); + + if (ret) { + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + goto out; + } + } + + /* + * Transfer to a private list before we release the dev->struct_mutex; + * This is so we don't get any new unfenced objects while fencing + * these. + */ + + f_list = *list; + INIT_LIST_HEAD(list); + + count = 0; + l = f_list.next; + while(l != &f_list) { + entry = list_entry(l, drm_buffer_object_t, head); + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + mutex_lock(&dev->struct_mutex); + + if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { + count++; + if (entry->fence) + drm_fence_usage_deref_locked(dev, entry->fence); + entry->fence = fence; + DRM_FLAG_MASKED(entry->priv_flags, 0, + _DRM_BO_FLAG_UNFENCED); + DRM_WAKEUP(&entry->event_queue); + list_del_init(&entry->head); + if (entry->flags & DRM_BO_FLAG_NO_EVICT) + list_add_tail(&entry->head, &bm->other); + else if (entry->flags & DRM_BO_FLAG_MEM_TT) + list_add_tail(&entry->head, &bm->tt_lru); + else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) + list_add_tail(&entry->head, &bm->vram_lru); + else + list_add_tail(&entry->head, &bm->other); + } + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_locked(dev, entry); + l = f_list.next; + } + if (!count) + drm_fence_usage_deref_locked(dev, fence); + else if (count > 1) + atomic_add(count - 1, &fence->usage); + out: + mutex_unlock(&dev->struct_mutex); + return ret; +} + + /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -269,6 +307,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) drm_fence_object_t *fence = bo->fence; int ret; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -299,13 +338,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) { int ret = 0; - + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; /* * Someone might have modified the buffer before we took the buffer mutex. */ mutex_lock(&bo->mutex); - if (bo->unfenced || (bo->flags & DRM_BO_FLAG_NO_EVICT)) + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) + || (bo->flags & DRM_BO_FLAG_NO_EVICT)) goto out; if (tt && !bo->tt) goto out; @@ -324,6 +365,12 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, + _DRM_BO_FLAG_EVICTED); out: mutex_unlock(&bo->mutex); return ret; @@ -356,11 +403,6 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) bo = list_entry(lru->next, drm_buffer_object_t, head); - /* - * No need to take dev->struct_mutex here, because bo->usage is at least 1 already, - * since it's on the lru list, and the dev->struct_mutex is held. - */ - atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); ret = drm_bo_evict(bo, tt, no_wait); @@ -407,13 +449,26 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) drm_mm_put_block(&bm->tt_manager, bo->tt); } mutex_unlock(&dev->struct_mutex); - return ret; + if (ret) + return ret; + + if (bo->ttm_region->be->needs_cache_adjust(bo->ttm_region->be)) + bo->flags &= ~DRM_BO_FLAG_CACHED; + bo->flags &= ~DRM_BO_MASK_MEM; + bo->flags |= DRM_BO_FLAG_MEM_TT; + + if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); + DRM_ERROR("Warning: Could not flush read caches\n"); + } + + return 0; } static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t * n_flags, - uint32_t *n_mask) + int init, uint32_t * n_flags, uint32_t * n_mask) { uint32_t new_flags = 0; uint32_t new_props; @@ -426,21 +481,23 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && - ((new_mask & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) { + ((new_mask & DRM_BO_FLAG_MEM_VRAM) + && !driver->cached_vram)) { new_mask &= ~DRM_BO_FLAG_BIND_CACHED; } else { - if (!driver->cached_tt) + if (!driver->cached_tt) new_flags &= DRM_BO_FLAG_MEM_TT; - if (!driver->cached_vram) + if (!driver->cached_vram) new_flags &= DRM_BO_FLAG_MEM_VRAM; } } - - if ((new_mask & DRM_BO_FLAG_READ_CACHED) && + + if ((new_mask & DRM_BO_FLAG_READ_CACHED) && !(new_mask & DRM_BO_FLAG_BIND_CACHED)) { - if ((new_mask & DRM_BO_FLAG_NO_EVICT) && + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && !(new_mask & DRM_BO_FLAG_MEM_LOCAL)) { - DRM_ERROR("Cannot read cached from a pinned VRAM / TT buffer\n"); + DRM_ERROR + ("Cannot read cached from a pinned VRAM / TT buffer\n"); return -EINVAL; } new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); @@ -449,7 +506,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, /* * Determine new memory location: */ - if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { @@ -544,6 +600,7 @@ static int drm_bo_busy(drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -562,12 +619,94 @@ static int drm_bo_busy(drm_buffer_object_t * bo) return 0; } +static int drm_bo_read_cached(drm_buffer_object_t * bo) +{ + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, + _DRM_BO_FLAG_EVICTED); + return 0; +} + +/* + * Wait until a buffer is unmapped. + */ + +static int drm_bo_wait_unmapped(drm_buffer_object_t *bo, int no_wait) +{ + int ret = 0; + + if ((atomic_read(&bo->mapped) >= 0) && no_wait) + return -EBUSY; + + DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, + atomic_read(&bo->mapped) == -1); + + if (ret == -EINTR) + ret = -EAGAIN; + + return ret; +} + +static int drm_bo_check_unfenced(drm_buffer_object_t *bo) +{ + int ret; + + mutex_lock(&bo->mutex); + ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + mutex_unlock(&bo->mutex); + return ret; +} + +/* + * Wait until a buffer, scheduled to be fenced moves off the unfenced list. + * Until then, we cannot really do anything with it except delete it. + * The unfenced list is a PITA, and the operations + * 1) validating + * 2) submitting commands + * 3) fencing + * Should really be an atomic operation. + * We now "solve" this problem by keeping + * the buffer "unfenced" after validating, but before fencing. + */ + +static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, + int eagain_if_wait) +{ + int ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + unsigned long _end = jiffies + 3*DRM_HZ; + + if (ret && no_wait) + return -EBUSY; + else if (!ret) + return 0; + + do { + mutex_unlock(&bo->mutex); + DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, + !drm_bo_check_unfenced(bo)); + mutex_lock(&bo->mutex); + if (ret == -EINTR) + return -EAGAIN; + if (ret) { + DRM_ERROR("Error waiting for buffer to become fenced\n"); + return ret; + } + ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + } while (ret && !time_after_eq(jiffies, _end)); + if (ret) { + DRM_ERROR("Timeout waiting for buffer to become fenced\n"); + return ret; + } + if (eagain_if_wait) + return -EAGAIN; -static int drm_bo_read_cached(drm_buffer_object_t *bo) { return 0; } + + + /* * Wait for buffer idle and register that we've mapped the buffer. * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, @@ -575,7 +714,7 @@ static int drm_bo_read_cached(drm_buffer_object_t *bo) { * unregistered. */ -static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, +static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, uint32_t map_flags, int no_wait) { drm_buffer_object_t *bo; @@ -590,6 +729,9 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; /* * If this returns true, we are currently unmapped. @@ -597,7 +739,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, * be done without the bo->mutex held. */ - while(1) { + while (1) { if (atomic_inc_and_test(&bo->mapped)) { ret = drm_bo_wait(bo, 0, no_wait); if (ret) { @@ -608,41 +750,33 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, if ((map_flags & DRM_BO_FLAG_READ) && (bo->flags & DRM_BO_FLAG_READ_CACHED) && (!(bo->flags & DRM_BO_FLAG_CACHED))) { - drm_bo_read_cached(bo); } break; - } else { - if ((map_flags & DRM_BO_FLAG_READ) && - (bo->flags & DRM_BO_FLAG_READ_CACHED) && - (!(bo->flags & DRM_BO_FLAG_CACHED))) { + } else if ((map_flags & DRM_BO_FLAG_READ) && + (bo->flags & DRM_BO_FLAG_READ_CACHED) && + (!(bo->flags & DRM_BO_FLAG_CACHED))) { + + /* + * We are already mapped with different flags. + * need to wait for unmap. + */ + + ret = drm_bo_wait_unmapped(bo, no_wait); + if (ret) + goto out; - /* - * We are already mapped with different flags. - * need to wait for unmap. - */ - - if (no_wait) { - ret = -EBUSY; - goto out; - } - DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, - atomic_read(&bo->mapped) == -1); - if (ret == -EINTR) - ret = -EAGAIN; - if (ret) - goto out; - continue; - } + continue; } + break; } - + mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); if (ret) { if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->validate_queue); + DRM_WAKEUP(&bo->event_queue); } out: @@ -698,7 +832,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, BUG_ON(action != _DRM_REF_TYPE1); if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->validate_queue); + DRM_WAKEUP(&bo->event_queue); } /* @@ -720,18 +854,9 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Make sure we're not mapped. */ - if (atomic_read(&bo->mapped) >= 0) { - if (no_wait) - return -EBUSY; - else { - DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, - atomic_read(&bo->mapped) == -1); - if (ret == -EINTR) - return -EAGAIN; - if (ret) - return ret; - } - } + ret = drm_bo_wait_unmapped(bo, no_wait); + if (ret) + return ret; /* * Wait for outstanding fences. @@ -752,8 +877,6 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, drm_move_tt_to_local(bo); } - DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_MEM_TT); - return 0; } @@ -768,6 +891,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; uint32_t flag_diff = (new_flags ^ bo->flags); + drm_bo_driver_t *driver = dev->driver->bo_driver; int ret; @@ -785,6 +909,12 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ + ret = driver->fence_type(new_flags, &bo->fence_flags, &bo->fence_class); + if (ret) { + DRM_ERROR("Driver did not support given buffer permissions\n"); + return ret; + } + if (flag_diff & DRM_BO_MASK_MEM) { mutex_lock(&dev->struct_mutex); ret = drm_bo_move_buffer(bo, new_flags, no_wait); @@ -793,40 +923,72 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return ret; } - if (flag_diff & DRM_BO_FLAG_NO_EVICT) { - mutex_lock(&dev->struct_mutex); - list_del_init(&bo->head); - if (!(new_flags & DRM_BO_FLAG_NO_EVICT)) { - if (new_flags & DRM_BO_FLAG_MEM_TT) { - list_add_tail(&bo->head, &bm->tt_lru); - } else { - list_add_tail(&bo->head, &bm->vram_lru); - } - } - mutex_unlock(&dev->struct_mutex); - DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); - } - if (move_unfenced) { /* * Place on unfenced list. */ + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, + _DRM_BO_FLAG_UNFENCED); mutex_lock(&dev->struct_mutex); - list_del_init(&bo->head); + list_del(&bo->head); list_add_tail(&bo->head, &bm->unfenced); mutex_unlock(&dev->struct_mutex); + } else { + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + if (new_flags & DRM_BO_FLAG_NO_EVICT) + list_add_tail(&bo->head, &bm->other); + else if (new_flags & DRM_BO_FLAG_MEM_TT) + list_add_tail(&bo->head, &bm->tt_lru); + else if (new_flags & DRM_BO_FLAG_MEM_VRAM) + list_add_tail(&bo->head, &bm->vram_lru); + else + list_add_tail(&bo->head, &bm->other); + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } - /* - * FIXME: Remove below. - */ - bo->flags = new_flags; return 0; } +static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, + uint32_t flags, uint32_t mask, uint32_t hint) +{ + drm_buffer_object_t *bo; + drm_device_t *dev = priv->head->dev; + int ret; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; + uint32_t new_flags; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + + mutex_lock(&bo->mutex); + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + + if (ret) + goto out; + + ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, + (flags & mask) | (bo->flags & ~mask), hint, + 0, &new_flags, &bo->mask); + + if (ret) + goto out; + + ret = drm_buffer_object_validate(bo, new_flags, !(hint & DRM_BO_HINT_DONT_FENCE), + no_wait); + +out: + mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(dev, bo); + return ret; +} + /* * Call bo->mutex locked. */ @@ -886,6 +1048,10 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, return ret; } + + + + int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, @@ -896,6 +1062,7 @@ int drm_buffer_object_create(drm_file_t * priv, drm_buffer_object_t ** buf_obj) { drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *bo; int ret = 0; uint32_t new_flags; @@ -922,13 +1089,15 @@ int drm_buffer_object_create(drm_file_t * priv, atomic_set(&bo->usage, 1); atomic_set(&bo->mapped, -1); - DRM_INIT_WAITQUEUE(&bo->validate_queue); + DRM_INIT_WAITQUEUE(&bo->event_queue); INIT_LIST_HEAD(&bo->head); + list_add_tail(&bo->head, &bm->other); INIT_LIST_HEAD(&bo->ddestroy); bo->dev = dev; bo->type = type; bo->num_pages = num_pages; bo->buffer_start = buffer_start; + bo->priv_flags = 0; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags, &bo->mask); @@ -938,12 +1107,12 @@ int drm_buffer_object_create(drm_file_t * priv, if (ret) goto out_err; -#if 0 +#if 1 ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); #else bo->flags = new_flags; -#endif +#endif if (ret) goto out_err; @@ -996,6 +1165,12 @@ static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, rep->buffer_start = bo->buffer_start; } +static int drm_bo_lock_test(drm_device_t * dev, struct file *filp) +{ + LOCK_TEST_WITH_RETURN(dev, filp); + return 0; +} + int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -1005,43 +1180,43 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) unsigned long next; drm_user_object_t *uo; drm_buffer_object_t *entry; - + do { - DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, - sizeof(arg)); - + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + if (arg.handled) { - data = req->next; - continue; + data = req->next; + continue; } rep.ret = 0; switch (req->op) { - case drm_bo_create:{ - rep.ret = - drm_buffer_object_create(priv, req->size, - req->type, - req->arg_handle, - req->mask, - req->hint, - req->buffer_start, - &entry); - if (rep.ret) - break; - - rep.ret = - drm_bo_add_user_object(priv, entry, - req-> - mask & - DRM_BO_FLAG_SHAREABLE); - if (rep.ret) - drm_bo_usage_deref_unlocked(dev, entry); - - mutex_lock(&entry->mutex); - drm_bo_fill_rep_arg(entry, &rep); - mutex_unlock(&entry->mutex); + case drm_bo_create: + rep.ret = + drm_buffer_object_create(priv, req->size, + req->type, + req->arg_handle, + req->mask, + req->hint, + req->buffer_start, &entry); + if (rep.ret) break; - } + + rep.ret = + drm_bo_add_user_object(priv, entry, + req-> + mask & + DRM_BO_FLAG_SHAREABLE); + if (rep.ret) + drm_bo_usage_deref_unlocked(dev, entry); + + if (rep.ret) + break; + + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); + break; case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; @@ -1083,6 +1258,20 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_user_object_unref(priv, req->handle, drm_buffer_type); break; + case drm_bo_validate: + rep.ret = drm_bo_lock_test(dev, filp); + if (rep.ret) + break; + rep.ret = + drm_bo_handle_validate(priv, req->handle, req->mask, + req->arg_handle, req->hint); + break; + case drm_bo_fence: + rep.ret = drm_bo_lock_test(dev, filp); + if (rep.ret) + break; + /**/ + break; default: rep.ret = -EINVAL; } @@ -1104,12 +1293,12 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } - - -static void drm_bo_clean_mm(drm_file_t * priv) +int drm_bo_clean_mm(drm_file_t *priv) { + return 0; } + int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -1120,7 +1309,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) drm_bo_driver_t *driver = dev->driver->bo_driver; if (!driver) { - DRM_ERROR("Buffer objects is not supported by this driver\n"); + DRM_ERROR("Buffer objects are not sutt_lru); INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); + INIT_LIST_HEAD(&bm->other); init_timer(&bm->timer); bm->timer.function = &drm_bo_delayed_timer; - bm->timer.data = (unsigned long) dev; - + bm->timer.data = (unsigned long)dev; + bm->initialized = 1; break; case mm_takedown: @@ -1185,6 +1375,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->initialized = 0; break; default: + DRM_ERROR("Function not implemented yet\n"); return -EINVAL; } -- cgit v1.2.3 From 4edb95d6e0a00a9a8885603cab2c99e3c6daa705 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 11:23:21 +0200 Subject: Various bugfixes. --- linux-core/drm_bo.c | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 8bca2e32..dcbf2d91 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -70,14 +70,15 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); + DRM_ERROR("Flipping out of AGP\n"); mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; - mutex_unlock(&dev->struct_mutex); buf->flags &= ~DRM_BO_MASK_MEM; buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + mutex_unlock(&dev->struct_mutex); return 0; } @@ -114,12 +115,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) */ list_del(&bo->head); - list_add_tail(&bo->head, &bm->other); if (bo->tt) { - int ret; - ret = drm_move_tt_to_local(bo); - BUG_ON(ret); + drm_unbind_ttm_region(bo->ttm_region); + drm_mm_put_block(&bm->tt_manager, bo->tt); + bo->tt = NULL; } if (bo->vram) { drm_mm_put_block(&bm->vram_manager, bo->vram); @@ -443,6 +443,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; + DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -458,10 +459,11 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) bo->flags |= DRM_BO_FLAG_MEM_TT; if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + DRM_ERROR("Flush read caches\n"); ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); DRM_ERROR("Warning: Could not flush read caches\n"); } + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); return 0; } @@ -500,7 +502,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, ("Cannot read cached from a pinned VRAM / TT buffer\n"); return -EINVAL; } - new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); } /* @@ -621,10 +622,19 @@ static int drm_bo_busy(drm_buffer_object_t * bo) static int drm_bo_read_cached(drm_buffer_object_t * bo) { + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - return 0; + + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); + return drm_move_tt_to_local(bo); } /* @@ -836,7 +846,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } /* - * bo->mutex locked. + * bo->mutex locked. */ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, @@ -847,13 +857,14 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, /* * Flush outstanding fences. */ - + DRM_ERROR("Flushing fences\n"); drm_bo_busy(bo); /* * Make sure we're not mapped. */ + DRM_ERROR("Wait unmapped\n"); ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) return ret; @@ -862,6 +873,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ + DRM_ERROR("Wait fences\n"); ret = drm_bo_wait(bo, 0, no_wait); if (ret == -EINTR) @@ -909,16 +921,16 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ - ret = driver->fence_type(new_flags, &bo->fence_flags, &bo->fence_class); + ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); + DRM_ERROR("Fence type = 0x%08x\n", bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } if (flag_diff & DRM_BO_MASK_MEM) { - mutex_lock(&dev->struct_mutex); + DRM_ERROR("Calling move buffer\n"); ret = drm_bo_move_buffer(bo, new_flags, no_wait); - mutex_unlock(&dev->struct_mutex); if (ret) return ret; } @@ -946,6 +958,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, list_add_tail(&bo->head, &bm->vram_lru); else list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -1098,9 +1111,10 @@ int drm_buffer_object_create(drm_file_t * priv, bo->num_pages = num_pages; bo->buffer_start = buffer_start; bo->priv_flags = 0; - + bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags, &bo->mask); + DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, ttm_handle); @@ -1309,7 +1323,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) drm_bo_driver_t *driver = dev->driver->bo_driver; if (!driver) { - DRM_ERROR("Buffer objects are not sutt_manager, arg.req.tt_p_offset, arg.req.tt_p_size); -- cgit v1.2.3 From 11f51a9a877d1231551e8c6482a6f70daf380cdd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 15:41:55 +0200 Subject: Bugfixes, Memory allocation optimizations. Buffer manager takedown. --- linux-core/drm_bo.c | 135 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 111 insertions(+), 24 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index dcbf2d91..1c71f345 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -231,7 +231,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { - fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + fence = kmem_cache_alloc(dev->fence_object_cache, GFP_KERNEL); if (!fence) { ret = -ENOMEM; @@ -241,7 +241,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { - drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + kmem_cache_free(dev->fence_object_cache, fence); goto out; } } @@ -468,18 +468,24 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) return 0; } -static int drm_bo_new_flags(drm_bo_driver_t * driver, +static int drm_bo_new_flags(drm_device_t *dev, uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t * n_flags, uint32_t * n_mask) { uint32_t new_flags = 0; uint32_t new_props; + drm_bo_driver_t *driver = dev->driver->bo_driver; + drm_buffer_manager_t *bm = &dev->bm; /* - * First adjust the mask. Vram is not supported yet. + * First adjust the mask. */ - new_mask &= ~DRM_BO_FLAG_MEM_VRAM; + if (!bm->use_vram) + new_mask &= ~DRM_BO_FLAG_MEM_VRAM; + if (!bm->use_tt) + new_mask &= ~DRM_BO_FLAG_MEM_TT; + if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && @@ -986,7 +992,7 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, if (ret) goto out; - ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, + ret = drm_bo_new_flags(dev, bo->flags, (flags & mask) | (bo->flags & ~mask), hint, 0, &new_flags, &bo->mask); @@ -1112,7 +1118,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->buffer_start = buffer_start; bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; - ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, + ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) @@ -1194,7 +1200,12 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) unsigned long next; drm_user_object_t *uo; drm_buffer_object_t *entry; - + + if (!dev->bm.initialized) { + DRM_ERROR("Buffer object manager is not initialized.\n"); + return -EINVAL; + } + do { DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); @@ -1307,9 +1318,87 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } -int drm_bo_clean_mm(drm_file_t *priv) + +/* + * dev->struct_sem locked. + */ + + +static void drm_bo_force_clean(drm_device_t * dev) { - return 0; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry, *next; + int nice_mode = 1; + int ret = 0; + + list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { + if (entry->fence) { + if (nice_mode) { + unsigned long _end = jiffies + 3*DRM_HZ; + do { + ret = drm_bo_wait(entry, 0, 0); + } while ((ret == -EINTR) && + !time_after_eq(jiffies, _end)); + } else { + drm_fence_usage_deref_locked(dev, entry->fence); + entry->fence = NULL; + } + if (entry->fence) { + DRM_ERROR("Detected GPU hang. " + "Removing waiting buffers.\n"); + nice_mode = 0; + drm_fence_usage_deref_locked(dev, entry->fence); + entry->fence = NULL; + } + + } + DRM_DEBUG("Destroying delayed buffer object\n"); + list_del(&entry->ddestroy); + drm_bo_destroy_locked(dev, entry); + } +} + + +int drm_bo_clean_mm(drm_device_t *dev) +{ + drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; + + + mutex_lock(&dev->struct_mutex); + + if (!bm->initialized) + goto out; + + + drm_bo_force_clean(dev); + bm->use_vram = 0; + bm->use_tt = 0; + + if (bm->has_vram) { + if (drm_mm_clean(&bm->vram_manager)) { + drm_mm_takedown(&bm->vram_manager); + bm->has_vram = 0; + } else + ret = -EBUSY; + } + + if (bm->has_tt) { + if (drm_mm_clean(&bm->tt_manager)) { + drm_mm_takedown(&bm->tt_manager); + bm->has_tt = 0; + } else + ret = -EBUSY; + + if (!ret) + bm->initialized = 0; + } + + out: + mutex_unlock(&dev->struct_mutex); + + return ret; } @@ -1331,33 +1420,38 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) switch (arg.req.op) { case mm_init: -#if 0 if (bm->initialized) { DRM_ERROR("Memory manager already initialized\n"); return -EINVAL; } -#endif mutex_lock(&dev->struct_mutex); bm->has_vram = 0; bm->has_tt = 0; - + if (arg.req.vr_p_size) { ret = drm_mm_init(&bm->vram_manager, arg.req.vr_p_offset, arg.req.vr_p_size); bm->has_vram = 1; + /* + * VRAM not supported yet. + */ + + bm->use_vram = 0; if (ret) break; } if (arg.req.tt_p_size) { - DRM_ERROR("Initializing TT 0x%08x 0x%08x\n", + DRM_ERROR("Initializing TT 0x%08x 0x%08x\n", arg.req.tt_p_offset, arg.req.tt_p_size); ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, arg.req.tt_p_size); bm->has_tt = 1; + bm->use_tt = 1; + if (ret) { if (bm->has_vram) drm_mm_takedown(&bm->vram_manager); @@ -1379,17 +1473,10 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->initialized = 1; break; case mm_takedown: - if (!bm->initialized) { - DRM_ERROR("Memory manager was not initialized\n"); - return -EINVAL; + if (drm_bo_clean_mm(dev)) { + DRM_ERROR("Memory manager not clean. " + "Delaying takedown\n"); } - mutex_lock(&dev->struct_mutex); - drm_bo_clean_mm(priv); - if (bm->has_vram) - drm_mm_takedown(&bm->vram_manager); - if (bm->has_tt) - drm_mm_takedown(&bm->tt_manager); - bm->initialized = 0; break; default: DRM_ERROR("Function not implemented yet\n"); -- cgit v1.2.3 From ef8e618cf30ab7dcbe8c7211e0c2508c5520a669 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 16:38:06 +0200 Subject: Export buffer info on map and validate ioctls. Add an info ioctl operation. --- linux-core/drm_bo.c | 115 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 27 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1c71f345..317b5f7a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -598,6 +598,32 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, return bo; } +/* + * Call bo->mutex locked. + * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. + * Doesn't do any fence flushing as opposed to the drm_bo_busy function. + */ + + +static int drm_bo_quick_busy(drm_buffer_object_t *bo) +{ + drm_fence_object_t *fence = bo->fence; + + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + if (fence) { + drm_device_t *dev = bo->dev; + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + return 1; + } + return 0; +} + + /* * Call bo->mutex locked. * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. @@ -719,8 +745,36 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, return 0; } +/* + * Fill in the ioctl reply argument with buffer info. + * Bo locked. + */ +static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, + drm_bo_arg_reply_t * rep) +{ + rep->handle = bo->base.hash.key; + rep->flags = bo->flags; + rep->size = bo->num_pages * PAGE_SIZE; + rep->offset = bo->offset; + + if (bo->ttm_object) { + rep->arg_handle = bo->ttm_object->map_list.user_token; + } else { + rep->arg_handle = 0; + } + + rep->mask = bo->mask; + rep->buffer_start = bo->buffer_start; + rep->fence_flags = bo->fence_flags; + rep->rep_flags = 0; + + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || + drm_bo_quick_busy(bo)) { + DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, DRM_BO_REP_BUSY); + } +} /* @@ -731,7 +785,8 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, */ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, - uint32_t map_flags, int no_wait) + uint32_t map_flags, int no_wait, + drm_bo_arg_reply_t *rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -794,7 +849,8 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, if (atomic_add_negative(-1, &bo->mapped)) DRM_WAKEUP(&bo->event_queue); - } + } else + drm_bo_fill_rep_arg(bo, rep); out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); @@ -973,7 +1029,8 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, } static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, - uint32_t flags, uint32_t mask, uint32_t hint) + uint32_t flags, uint32_t mask, uint32_t hint, + drm_bo_arg_reply_t *rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -1001,13 +1058,33 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, ret = drm_buffer_object_validate(bo, new_flags, !(hint & DRM_BO_HINT_DONT_FENCE), no_wait); + drm_bo_fill_rep_arg(bo, rep); -out: +out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); return ret; } +static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, + drm_bo_arg_reply_t *rep) +{ + drm_buffer_object_t *bo; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + mutex_lock(&bo->mutex); + if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + (void) drm_bo_busy(bo); + drm_bo_fill_rep_arg(bo, rep); + mutex_unlock(&bo->mutex); + return 0; +} + + /* * Call bo->mutex locked. */ @@ -1167,24 +1244,6 @@ static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo, return ret; } -static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, - drm_bo_arg_reply_t * rep) -{ - rep->handle = bo->base.hash.key; - rep->flags = bo->flags; - rep->size = bo->num_pages * PAGE_SIZE; - rep->offset = bo->offset; - - if (bo->ttm_object) { - rep->arg_handle = bo->ttm_object->map_list.user_token; - } else { - rep->arg_handle = 0; - } - - rep->mask = bo->mask; - rep->buffer_start = bo->buffer_start; -} - static int drm_bo_lock_test(drm_device_t * dev, struct file *filp) { LOCK_TEST_WITH_RETURN(dev, filp); @@ -1249,7 +1308,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, req->hint & - DRM_BO_HINT_DONT_BLOCK); + DRM_BO_HINT_DONT_BLOCK, + &rep); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -1289,7 +1349,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; rep.ret = drm_bo_handle_validate(priv, req->handle, req->mask, - req->arg_handle, req->hint); + req->arg_handle, req->hint, + &rep); break; case drm_bo_fence: rep.ret = drm_bo_lock_test(dev, filp); @@ -1297,6 +1358,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; /**/ break; + case drm_bo_info: + rep.ret = drm_bo_handle_info(priv, req->handle, &rep); + break; default: rep.ret = -EINVAL; } @@ -1443,9 +1507,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } if (arg.req.tt_p_size) { - DRM_ERROR("Initializing TT 0x%08x 0x%08x\n", - arg.req.tt_p_offset, - arg.req.tt_p_size); ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, arg.req.tt_p_size); -- cgit v1.2.3 From 405b5d9ca8cc9f6c5c7bb764c684bf74ba7660c6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 18:11:05 +0200 Subject: Flag bit pattern bugfixes. Remove some error messages. --- linux-core/drm_bo.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 317b5f7a..70342ac9 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -70,7 +70,6 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); - DRM_ERROR("Flipping out of AGP\n"); mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); @@ -442,8 +441,9 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - +#ifdef BODEBUG DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); +#endif mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -459,9 +459,9 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) bo->flags |= DRM_BO_FLAG_MEM_TT; if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { - DRM_ERROR("Flush read caches\n"); ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); - DRM_ERROR("Warning: Could not flush read caches\n"); + if (ret) + DRM_ERROR("Warning: Could not flush read caches\n"); } DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); @@ -919,14 +919,12 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, /* * Flush outstanding fences. */ - DRM_ERROR("Flushing fences\n"); drm_bo_busy(bo); /* * Make sure we're not mapped. */ - DRM_ERROR("Wait unmapped\n"); ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) return ret; @@ -935,7 +933,6 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ - DRM_ERROR("Wait fences\n"); ret = drm_bo_wait(bo, 0, no_wait); if (ret == -EINTR) @@ -979,19 +976,21 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return -EINVAL; } - /* - * Check whether we need to move buffer. - */ - +#ifdef BODEBUG + DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", + new_flags, bo->flags); +#endif ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); - DRM_ERROR("Fence type = 0x%08x\n", bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } + /* + * Check whether we need to move buffer. + */ + if (flag_diff & DRM_BO_MASK_MEM) { - DRM_ERROR("Calling move buffer\n"); ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) return ret; @@ -1050,7 +1049,7 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, goto out; ret = drm_bo_new_flags(dev, bo->flags, - (flags & mask) | (bo->flags & ~mask), hint, + (flags & mask) | (bo->mask & ~mask), hint, 0, &new_flags, &bo->mask); if (ret) -- cgit v1.2.3 From a96b61fdc4fc3df50c91ca489f45f12cdad74f69 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 18:11:34 +0200 Subject: Lindent drm_bo.c --- linux-core/drm_bo.c | 118 ++++++++++++++++++++++------------------------------ 1 file changed, 49 insertions(+), 69 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 70342ac9..368ec0c5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -198,9 +198,8 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } -int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, - drm_fence_object_t *fence) +int drm_fence_buffer_objects(drm_file_t * priv, + struct list_head *list, drm_fence_object_t * fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -212,7 +211,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, struct list_head f_list, *l; mutex_lock(&dev->struct_mutex); - + list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; @@ -256,7 +255,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, count = 0; l = f_list.next; - while(l != &f_list) { + while (l != &f_list) { entry = list_entry(l, drm_buffer_object_t, head); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); @@ -265,10 +264,10 @@ int drm_fence_buffer_objects(drm_file_t * priv, if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; - if (entry->fence) + if (entry->fence) drm_fence_usage_deref_locked(dev, entry->fence); entry->fence = fence; - DRM_FLAG_MASKED(entry->priv_flags, 0, + DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); list_del_init(&entry->head); @@ -294,7 +293,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, return ret; } - /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -468,7 +466,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) return 0; } -static int drm_bo_new_flags(drm_device_t *dev, +static int drm_bo_new_flags(drm_device_t * dev, uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t * n_flags, uint32_t * n_mask) { @@ -486,7 +484,6 @@ static int drm_bo_new_flags(drm_device_t *dev, if (!bm->use_tt) new_mask &= ~DRM_BO_FLAG_MEM_TT; - if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && ((new_mask & DRM_BO_FLAG_MEM_VRAM) @@ -604,12 +601,10 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, * Doesn't do any fence flushing as opposed to the drm_bo_busy function. */ - -static int drm_bo_quick_busy(drm_buffer_object_t *bo) +static int drm_bo_quick_busy(drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; @@ -622,7 +617,6 @@ static int drm_bo_quick_busy(drm_buffer_object_t *bo) } return 0; } - /* * Call bo->mutex locked. @@ -656,7 +650,6 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, @@ -673,9 +666,9 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) * Wait until a buffer is unmapped. */ -static int drm_bo_wait_unmapped(drm_buffer_object_t *bo, int no_wait) +static int drm_bo_wait_unmapped(drm_buffer_object_t * bo, int no_wait) { - int ret = 0; + int ret = 0; if ((atomic_read(&bo->mapped) >= 0) && no_wait) return -EBUSY; @@ -685,11 +678,11 @@ static int drm_bo_wait_unmapped(drm_buffer_object_t *bo, int no_wait) if (ret == -EINTR) ret = -EAGAIN; - + return ret; } -static int drm_bo_check_unfenced(drm_buffer_object_t *bo) +static int drm_bo_check_unfenced(drm_buffer_object_t * bo) { int ret; @@ -711,17 +704,17 @@ static int drm_bo_check_unfenced(drm_buffer_object_t *bo) * the buffer "unfenced" after validating, but before fencing. */ -static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, +static int drm_bo_wait_unfenced(drm_buffer_object_t * bo, int no_wait, int eagain_if_wait) { int ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - unsigned long _end = jiffies + 3*DRM_HZ; + unsigned long _end = jiffies + 3 * DRM_HZ; if (ret && no_wait) return -EBUSY; else if (!ret) return 0; - + do { mutex_unlock(&bo->mutex); DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, @@ -730,7 +723,8 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, if (ret == -EINTR) return -EAGAIN; if (ret) { - DRM_ERROR("Error waiting for buffer to become fenced\n"); + DRM_ERROR + ("Error waiting for buffer to become fenced\n"); return ret; } ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); @@ -750,7 +744,6 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, * Bo locked. */ - static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, drm_bo_arg_reply_t * rep) { @@ -770,13 +763,12 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, rep->fence_flags = bo->fence_flags; rep->rep_flags = 0; - if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || - drm_bo_quick_busy(bo)) { - DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, DRM_BO_REP_BUSY); + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { + DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, + DRM_BO_REP_BUSY); } } - /* * Wait for buffer idle and register that we've mapped the buffer. * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, @@ -786,7 +778,7 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, uint32_t map_flags, int no_wait, - drm_bo_arg_reply_t *rep) + drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -827,12 +819,12 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, } else if ((map_flags & DRM_BO_FLAG_READ) && (bo->flags & DRM_BO_FLAG_READ_CACHED) && (!(bo->flags & DRM_BO_FLAG_CACHED))) { - + /* * We are already mapped with different flags. * need to wait for unmap. */ - + ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) goto out; @@ -849,7 +841,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, if (atomic_add_negative(-1, &bo->mapped)) DRM_WAKEUP(&bo->event_queue); - } else + } else drm_bo_fill_rep_arg(bo, rep); out: mutex_unlock(&bo->mutex); @@ -975,10 +967,8 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Cached binding not implemented yet\n"); return -EINVAL; } - #ifdef BODEBUG - DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", - new_flags, bo->flags); + DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); #endif ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); if (ret) { @@ -1029,7 +1019,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, uint32_t flags, uint32_t mask, uint32_t hint, - drm_bo_arg_reply_t *rep) + drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -1048,42 +1038,43 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, if (ret) goto out; - ret = drm_bo_new_flags(dev, bo->flags, + ret = drm_bo_new_flags(dev, bo->flags, (flags & mask) | (bo->mask & ~mask), hint, 0, &new_flags, &bo->mask); if (ret) goto out; - ret = drm_buffer_object_validate(bo, new_flags, !(hint & DRM_BO_HINT_DONT_FENCE), - no_wait); + ret = + drm_buffer_object_validate(bo, new_flags, + !(hint & DRM_BO_HINT_DONT_FENCE), + no_wait); drm_bo_fill_rep_arg(bo, rep); - -out: - + + out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); return ret; } static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, - drm_bo_arg_reply_t *rep) + drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; bo = drm_lookup_buffer_object(priv, handle, 1); if (!bo) { return -EINVAL; - } + } mutex_lock(&bo->mutex); - if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) - (void) drm_bo_busy(bo); + if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + (void)drm_bo_busy(bo); drm_bo_fill_rep_arg(bo, rep); mutex_unlock(&bo->mutex); return 0; } - /* * Call bo->mutex locked. */ @@ -1143,10 +1134,6 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, return ret; } - - - - int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, @@ -1355,8 +1342,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_bo_lock_test(dev, filp); if (rep.ret) break; - /**/ - break; + /**/ break; case drm_bo_info: rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; @@ -1381,12 +1367,10 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } - /* * dev->struct_sem locked. */ - static void drm_bo_force_clean(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; @@ -1398,11 +1382,11 @@ static void drm_bo_force_clean(drm_device_t * dev) list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { if (entry->fence) { if (nice_mode) { - unsigned long _end = jiffies + 3*DRM_HZ; + unsigned long _end = jiffies + 3 * DRM_HZ; do { ret = drm_bo_wait(entry, 0, 0); - } while ((ret == -EINTR) && - !time_after_eq(jiffies, _end)); + } while ((ret == -EINTR) && + !time_after_eq(jiffies, _end)); } else { drm_fence_usage_deref_locked(dev, entry->fence); entry->fence = NULL; @@ -1422,23 +1406,20 @@ static void drm_bo_force_clean(drm_device_t * dev) } } - -int drm_bo_clean_mm(drm_device_t *dev) +int drm_bo_clean_mm(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; int ret = 0; - mutex_lock(&dev->struct_mutex); if (!bm->initialized) goto out; - drm_bo_force_clean(dev); bm->use_vram = 0; bm->use_tt = 0; - + if (bm->has_vram) { if (drm_mm_clean(&bm->vram_manager)) { drm_mm_takedown(&bm->vram_manager); @@ -1451,20 +1432,19 @@ int drm_bo_clean_mm(drm_device_t *dev) if (drm_mm_clean(&bm->tt_manager)) { drm_mm_takedown(&bm->tt_manager); bm->has_tt = 0; - } else + } else ret = -EBUSY; - + if (!ret) bm->initialized = 0; } - out: + out: mutex_unlock(&dev->struct_mutex); return ret; } - int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -1490,7 +1470,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) mutex_lock(&dev->struct_mutex); bm->has_vram = 0; bm->has_tt = 0; - + if (arg.req.vr_p_size) { ret = drm_mm_init(&bm->vram_manager, arg.req.vr_p_offset, @@ -1499,7 +1479,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) /* * VRAM not supported yet. */ - + bm->use_vram = 0; if (ret) break; -- cgit v1.2.3 From a6b8e3eaf49044e135a0b9288192525f301458d5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 16:57:20 +0200 Subject: Make memory caches global so that they can be used with multiple heads. --- linux-core/drm_bo.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 368ec0c5..7f50bacf 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -91,7 +91,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); @@ -229,7 +230,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { - fence = kmem_cache_alloc(dev->fence_object_cache, GFP_KERNEL); + fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) { ret = -ENOMEM; @@ -239,7 +240,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { - kmem_cache_free(dev->fence_object_cache, fence); + kmem_cache_free(drm_cache.fence_object, fence); goto out; } } @@ -1124,8 +1125,9 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, - bo->mask & DRM_BO_FLAG_BIND_CACHED, + bo->num_pages,1, + + /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); -- cgit v1.2.3 From 550f51b4bf9920718aab2c611b15de3020537f92 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 21:50:12 +0200 Subject: Buffer object wait IOCTL operation. Remove option to wait for fence / buffers and block signals. --- linux-core/drm_bo.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7f50bacf..1f0bbba5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -299,7 +299,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, * Wait until the buffer is idle. */ -static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, + int no_wait) { drm_fence_object_t *fence = bo->fence; @@ -317,7 +318,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) return -EBUSY; ret = - drm_fence_object_wait(dev, fence, lazy, !lazy, + drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_flags); if (ret) return ret; @@ -351,7 +352,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) if (!tt && !bo->vram) goto out; - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) goto out; @@ -805,7 +806,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { atomic_dec(&bo->mapped); goto out; @@ -926,7 +927,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret == -EINTR) return -EAGAIN; @@ -1073,6 +1074,34 @@ static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, (void)drm_bo_busy(bo); drm_bo_fill_rep_arg(bo, rep); mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(bo->dev, bo); + return 0; +} + +static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, + uint32_t hint, drm_bo_arg_reply_t * rep) +{ + drm_buffer_object_t *bo; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; + int ret; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + mutex_lock(&bo->mutex); + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; + ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, + 0, no_wait); + if (ret) + goto out; + + drm_bo_fill_rep_arg(bo, rep); +out: + mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(bo->dev, bo); return 0; } @@ -1348,6 +1377,13 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_info: rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; + case drm_bo_wait_idle: + rep.ret = drm_bo_handle_wait(priv, req->handle, + req->hint, &rep); + break; + case drm_bo_ref_fence: + rep.ret = -EINVAL; + DRM_ERROR("Function is not implemented yet.\n"); default: rep.ret = -EINVAL; } @@ -1386,7 +1422,7 @@ static void drm_bo_force_clean(drm_device_t * dev) if (nice_mode) { unsigned long _end = jiffies + 3 * DRM_HZ; do { - ret = drm_bo_wait(entry, 0, 0); + ret = drm_bo_wait(entry, 0, 1, 0); } while ((ret == -EINTR) && !time_after_eq(jiffies, _end)); } else { -- cgit v1.2.3 From 604215396847a7964fd7d68aa89d4f778b3bf22b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 18:00:25 +0200 Subject: Fence all unfenced buffers function. --- linux-core/drm_bo.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1f0bbba5..68af5c31 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -199,8 +199,15 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } +/* + * Note. The caller has to register (if applicable) + * and deregister fence object usage. + */ + int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, drm_fence_object_t * fence) + struct list_head *list, + drm_fence_object_t *fence, + drm_fence_object_t **used_fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -230,19 +237,9 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { - fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); - - if (!fence) { - ret = -ENOMEM; - goto out; - } - - ret = drm_fence_object_init(dev, fence_flags, 1, fence); - - if (ret) { - kmem_cache_free(drm_cache.fence_object, fence); - goto out; - } + ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + if (ret) + goto out; } /* @@ -285,14 +282,14 @@ int drm_fence_buffer_objects(drm_file_t * priv, drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } - if (!count) - drm_fence_usage_deref_locked(dev, fence); - else if (count > 1) - atomic_add(count - 1, &fence->usage); + atomic_add(count, &fence->usage); out: mutex_unlock(&dev->struct_mutex); + *used_fence = fence; return ret; } +EXPORT_SYMBOL(drm_fence_buffer_objects); + /* * Call bo->mutex locked. -- cgit v1.2.3 From 99acb7936660843090ea8a9f22d2d50d9433e0de Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 8 Sep 2006 17:24:38 +0200 Subject: Various bugfixes. --- linux-core/drm_bo.c | 136 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 55 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 68af5c31..74722b1b 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -98,10 +98,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); - if (!timer_pending(&bm->timer)) { - bm->timer.expires = jiffies + 1; - add_timer(&bm->timer); - } + schedule_delayed_work(&bm->wq, 2); return; } else { @@ -109,15 +106,14 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) bo->fence = NULL; } } - /* * Take away from lru lists. */ - list_del(&bo->head); + list_del_init(&bo->head); if (bo->tt) { - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -152,7 +148,9 @@ static void drm_bo_delayed_delete(drm_device_t * dev) entry->fence = NULL; } if (!entry->fence) { - DRM_DEBUG("Destroying delayed buffer object\n"); +#ifdef BODEBUG + DRM_ERROR("Destroying delayed buffer object\n"); +#endif list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); } @@ -161,16 +159,18 @@ static void drm_bo_delayed_delete(drm_device_t * dev) mutex_unlock(&dev->struct_mutex); } -static void drm_bo_delayed_timer(unsigned long data) +static void drm_bo_delayed_workqueue(void *data) { drm_device_t *dev = (drm_device_t *) data; drm_buffer_manager_t *bm = &dev->bm; +#ifdef BODEBUG + DRM_ERROR("Delayed delete Worker\n"); +#endif drm_bo_delayed_delete(dev); - mutex_lock(&dev->struct_mutex); - if (!list_empty(&bm->ddestroy) && !timer_pending(&bm->timer)) { - bm->timer.expires = jiffies + 1; - add_timer(&bm->timer); + mutex_lock(&dev->struct_mutex); + if (!list_empty(&bm->ddestroy)) { + schedule_delayed_work(&bm->wq, 2); } mutex_unlock(&dev->struct_mutex); } @@ -220,14 +220,29 @@ int drm_fence_buffer_objects(drm_file_t * priv, mutex_lock(&dev->struct_mutex); + if (!list) + list = &bm->unfenced; + list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; count++; } - if (!count) + if (!count) { + DRM_ERROR("No buffers to fence\n"); + ret = -EINVAL; goto out; + } + + /* + * Transfer to a local list before we release the dev->struct_mutex; + * This is so we don't get any new unfenced objects while fencing + * these. + */ + + list_add_tail(&f_list, list); + list_del_init(list); if (fence) { if ((fence_flags & fence->type) != fence_flags) { @@ -237,20 +252,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { + mutex_unlock(&dev->struct_mutex); ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + mutex_lock(&dev->struct_mutex); if (ret) goto out; } - /* - * Transfer to a private list before we release the dev->struct_mutex; - * This is so we don't get any new unfenced objects while fencing - * these. - */ - - f_list = *list; - INIT_LIST_HEAD(list); - count = 0; l = f_list.next; while (l != &f_list) { @@ -259,7 +267,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); mutex_lock(&dev->struct_mutex); - + list_del_init(l); if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) @@ -268,7 +276,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); - list_del_init(&entry->head); if (entry->flags & DRM_BO_FLAG_NO_EVICT) list_add_tail(&entry->head, &bm->other); else if (entry->flags & DRM_BO_FLAG_MEM_TT) @@ -277,12 +284,19 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->vram_lru); else list_add_tail(&entry->head, &bm->other); + } else { +#ifdef BODEBUG + DRM_ERROR("Huh? Fenced object on unfenced list\n"); +#endif } mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } atomic_add(count, &fence->usage); +#ifdef BODEBUG + DRM_ERROR("Fenced %d buffers\n", count); +#endif out: mutex_unlock(&dev->struct_mutex); *used_fence = fence; @@ -303,7 +317,6 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, drm_fence_object_t *fence = bo->fence; int ret; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -424,6 +437,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) } else { buf->vram = node; } + buf->offset = node->start * PAGE_SIZE; return 0; } @@ -431,6 +445,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; + drm_ttm_backend_t *be; int ret; BUG_ON(bo->tt); @@ -450,7 +465,8 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - if (bo->ttm_region->be->needs_cache_adjust(bo->ttm_region->be)) + be = bo->ttm_region->be; + if (be->needs_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; bo->flags |= DRM_BO_FLAG_MEM_TT; @@ -458,7 +474,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); if (ret) - DRM_ERROR("Warning: Could not flush read caches\n"); + DRM_ERROR("Could not flush read caches\n"); } DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); @@ -776,12 +792,13 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, */ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, - uint32_t map_flags, int no_wait, + uint32_t map_flags, unsigned hint, drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; int ret = 0; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); @@ -791,9 +808,11 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); - ret = drm_bo_wait_unfenced(bo, no_wait, 0); - if (ret) - goto out; + if (!(hint & DRM_BO_HINT_ALLOW_UNFENCED_MAP)) { + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; + } /* * If this returns true, we are currently unmapped. @@ -979,7 +998,11 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ - if (flag_diff & DRM_BO_MASK_MEM) { + if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { + if (bo->type == drm_bo_type_user) { + DRM_ERROR("User buffers are not implemented yet.\n"); + return -EINVAL; + } ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) return ret; @@ -1151,7 +1174,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages,1, + bo->num_pages, 0, /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ &bo->ttm_region); @@ -1177,9 +1200,11 @@ int drm_buffer_object_create(drm_file_t * priv, int ret = 0; uint32_t new_flags; unsigned long num_pages; - + drm_bo_delayed_delete(dev); - if (buffer_start & ~PAGE_MASK) { + + if ((buffer_start & ~PAGE_MASK) && + (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } @@ -1206,24 +1231,24 @@ int drm_buffer_object_create(drm_file_t * priv, bo->dev = dev; bo->type = type; bo->num_pages = num_pages; - bo->buffer_start = buffer_start; + if (bo->type == drm_bo_type_fake) { + bo->offset = buffer_start; + bo->buffer_start = 0; + } else { + bo->buffer_start = buffer_start; + } bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); - DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, ttm_handle); if (ret) goto out_err; -#if 1 ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); -#else - bo->flags = new_flags; -#endif if (ret) goto out_err; @@ -1268,7 +1293,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t rep; unsigned long next; drm_user_object_t *uo; @@ -1321,8 +1346,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, - req->hint & - DRM_BO_HINT_DONT_BLOCK, + req->hint, &rep); break; case drm_bo_destroy: @@ -1394,10 +1418,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return -EAGAIN; arg.handled = 1; - arg.rep = rep; + arg.d.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); data = next; - } while (data); return 0; } @@ -1409,17 +1432,22 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) static void drm_bo_force_clean(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; - - drm_buffer_object_t *entry, *next; + struct list_head *l; + drm_buffer_object_t *entry; int nice_mode = 1; int ret = 0; - list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { + l = bm->ddestroy.next; + while(l != &bm->ddestroy) { + entry = list_entry(l, drm_buffer_object_t, ddestroy); + list_del(l); if (entry->fence) { if (nice_mode) { unsigned long _end = jiffies + 3 * DRM_HZ; do { + mutex_unlock(&dev->struct_mutex); ret = drm_bo_wait(entry, 0, 1, 0); + mutex_lock(&dev->struct_mutex); } while ((ret == -EINTR) && !time_after_eq(jiffies, _end)); } else { @@ -1436,8 +1464,8 @@ static void drm_bo_force_clean(drm_device_t * dev) } DRM_DEBUG("Destroying delayed buffer object\n"); - list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); + l = bm->ddestroy.next; } } @@ -1541,11 +1569,9 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_LIST_HEAD(&bm->ddestroy); INIT_LIST_HEAD(&bm->other); - init_timer(&bm->timer); - bm->timer.function = &drm_bo_delayed_timer; - bm->timer.data = (unsigned long)dev; - + INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; + break; case mm_takedown: if (drm_bo_clean_mm(dev)) { -- cgit v1.2.3 From 191e284709ee792a32124e96e43d5876406b93dc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 12:01:00 +0200 Subject: More bugfixes. Disable the i915 IRQ turnoff for now since it seems to be causing problems. --- linux-core/drm_bo.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 74722b1b..3a9c2313 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -95,11 +95,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { + drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); - - schedule_delayed_work(&bm->wq, 2); - + schedule_delayed_work(&bm->wq, + ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -113,7 +113,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->head); if (bo->tt) { - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -170,7 +170,7 @@ static void drm_bo_delayed_workqueue(void *data) drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { - schedule_delayed_work(&bm->wq, 2); + schedule_delayed_work(&bm->wq, ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); } mutex_unlock(&dev->struct_mutex); } @@ -822,6 +822,11 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { + if (no_wait && drm_bo_busy(bo)) { + atomic_dec(&bo->mapped); + ret = -EBUSY; + goto out; + } ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { atomic_dec(&bo->mapped); @@ -1174,9 +1179,8 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, 0, - - /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ + bo->num_pages, + bo->mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -1383,6 +1387,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; case drm_bo_validate: rep.ret = drm_bo_lock_test(dev, filp); + if (rep.ret) break; rep.ret = @@ -1571,13 +1576,16 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; - + bm->cur_pages = 0; + bm->max_pages = arg.req.max_locked_pages; break; case mm_takedown: if (drm_bo_clean_mm(dev)) { DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); } + DRM_DEBUG("We have %ld still locked pages\n", + bm->cur_pages); break; default: DRM_ERROR("Function not implemented yet\n"); -- cgit v1.2.3 From 861b26578cd5e497fb506ad5952fa62bd03ea201 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 16:28:34 +0200 Subject: Use lazy fence wait when possible even for RW fences. Saves some CPU. Lindent. --- linux-core/drm_bo.c | 56 ++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 3a9c2313..abad398f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -91,15 +91,16 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); - schedule_delayed_work(&bm->wq, - ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < + 1) ? 1 : DRM_HZ / 100); return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -168,9 +169,10 @@ static void drm_bo_delayed_workqueue(void *data) DRM_ERROR("Delayed delete Worker\n"); #endif drm_bo_delayed_delete(dev); - mutex_lock(&dev->struct_mutex); + mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { - schedule_delayed_work(&bm->wq, ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); } mutex_unlock(&dev->struct_mutex); } @@ -205,9 +207,9 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) */ int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, - drm_fence_object_t *fence, - drm_fence_object_t **used_fence) + struct list_head *list, + drm_fence_object_t * fence, + drm_fence_object_t ** used_fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -226,6 +228,12 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; + if (entry->fence_class != 0) { + DRM_ERROR("Fence class %d is not implemented yet.\n", + entry->fence_class); + ret = -EINVAL; + goto out; + } count++; } @@ -238,7 +246,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, /* * Transfer to a local list before we release the dev->struct_mutex; * This is so we don't get any new unfenced objects while fencing - * these. + * the ones we already have.. */ list_add_tail(&f_list, list); @@ -256,7 +264,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, ret = drm_fence_object_create(dev, fence_flags, 1, &fence); mutex_lock(&dev->struct_mutex); if (ret) - goto out; + goto out; } count = 0; @@ -286,7 +294,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->other); } else { #ifdef BODEBUG - DRM_ERROR("Huh? Fenced object on unfenced list\n"); + DRM_ERROR("Huh? Fenced object on unfenced list\n"); #endif } mutex_unlock(&entry->mutex); @@ -302,8 +310,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, *used_fence = fence; return ret; } -EXPORT_SYMBOL(drm_fence_buffer_objects); +EXPORT_SYMBOL(drm_fence_buffer_objects); /* * Call bo->mutex locked. @@ -822,7 +830,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { - if (no_wait && drm_bo_busy(bo)) { + if (no_wait && drm_bo_busy(bo)) { atomic_dec(&bo->mapped); ret = -EBUSY; goto out; @@ -1109,7 +1117,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, drm_buffer_object_t *bo; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; int ret; - + bo = drm_lookup_buffer_object(priv, handle, 1); if (!bo) { return -EINVAL; @@ -1118,13 +1126,12 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, ret = drm_bo_wait_unfenced(bo, no_wait, 0); if (ret) goto out; - ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, - 0, no_wait); + ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, 0, no_wait); if (ret) goto out; drm_bo_fill_rep_arg(bo, rep); -out: + out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(bo->dev, bo); return 0; @@ -1204,11 +1211,10 @@ int drm_buffer_object_create(drm_file_t * priv, int ret = 0; uint32_t new_flags; unsigned long num_pages; - + drm_bo_delayed_delete(dev); - if ((buffer_start & ~PAGE_MASK) && - (type != drm_bo_type_fake)) { + if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } @@ -1350,8 +1356,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, - req->hint, - &rep); + req->hint, &rep); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -1404,7 +1409,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; case drm_bo_wait_idle: - rep.ret = drm_bo_handle_wait(priv, req->handle, + rep.ret = drm_bo_handle_wait(priv, req->handle, req->hint, &rep); break; case drm_bo_ref_fence: @@ -1443,7 +1448,7 @@ static void drm_bo_force_clean(drm_device_t * dev) int ret = 0; l = bm->ddestroy.next; - while(l != &bm->ddestroy) { + while (l != &bm->ddestroy) { entry = list_entry(l, drm_buffer_object_t, ddestroy); list_del(l); if (entry->fence) { @@ -1584,8 +1589,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); } - DRM_DEBUG("We have %ld still locked pages\n", - bm->cur_pages); + DRM_DEBUG("We have %ld still locked pages\n", bm->cur_pages); break; default: DRM_ERROR("Function not implemented yet\n"); -- cgit v1.2.3 From 9adc9584a7e0b61b16a943720bef31a71faeaef4 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 17:39:44 +0200 Subject: Fix some debug messages. --- linux-core/drm_bo.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index abad398f..f5a25c26 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -149,9 +149,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) entry->fence = NULL; } if (!entry->fence) { -#ifdef BODEBUG - DRM_ERROR("Destroying delayed buffer object\n"); -#endif + DRM_DEBUG("Destroying delayed buffer object\n"); list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); } @@ -165,9 +163,8 @@ static void drm_bo_delayed_workqueue(void *data) drm_device_t *dev = (drm_device_t *) data; drm_buffer_manager_t *bm = &dev->bm; -#ifdef BODEBUG - DRM_ERROR("Delayed delete Worker\n"); -#endif + DRM_DEBUG("Delayed delete Worker\n"); + drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { @@ -292,19 +289,12 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->vram_lru); else list_add_tail(&entry->head, &bm->other); - } else { -#ifdef BODEBUG - DRM_ERROR("Huh? Fenced object on unfenced list\n"); -#endif - } - mutex_unlock(&entry->mutex); + } mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } atomic_add(count, &fence->usage); -#ifdef BODEBUG - DRM_ERROR("Fenced %d buffers\n", count); -#endif + DRM_DEBUG("Fenced %d buffers\n", count); out: mutex_unlock(&dev->struct_mutex); *used_fence = fence; @@ -461,9 +451,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; -#ifdef BODEBUG - DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); -#endif + DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -998,9 +986,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Cached binding not implemented yet\n"); return -EINVAL; } -#ifdef BODEBUG - DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); -#endif + DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); -- cgit v1.2.3 From 49fbeb339c232804866cd548d6023fe559597353 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 15 Sep 2006 11:18:35 +0200 Subject: Some bugfixes. Change the fence object interface somewhat to allow some more flexibility. Make list IOCTLS really restartable. Try to avoid busy-waits in the kernel using immediate return to user-space with an -EAGAIN. --- linux-core/drm_bo.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f5a25c26..858a4cde 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -322,15 +322,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, bo->fence = NULL; return 0; } - if (no_wait) + if (no_wait) { return -EBUSY; - + } ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_flags); - if (ret) - return ret; - + if (ret) + return ret; + drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -360,9 +360,14 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) if (!tt && !bo->vram) goto out; + ret = drm_bo_wait(bo, 0, 0, no_wait); - if (ret) + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed to expire fence before " + "buffer eviction.\n"); goto out; + } if (tt) { ret = drm_move_tt_to_local(bo); @@ -420,7 +425,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) } while (1); if (!node) { - DRM_ERROR("Out of aperture space\n"); + DRM_ERROR("Out of videoram / aperture space\n"); mutex_unlock(&dev->struct_mutex); return -ENOMEM; } @@ -646,7 +651,7 @@ static int drm_bo_busy(drm_buffer_object_t * bo) bo->fence = NULL; return 0; } - drm_fence_object_flush(dev, fence, DRM_FENCE_EXE); + drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE); if (drm_fence_object_signaled(fence, bo->fence_flags)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -981,11 +986,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Vram support not implemented yet\n"); return -EINVAL; } - if ((new_flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM)) && - (new_flags & DRM_BO_FLAG_CACHED)) { - DRM_ERROR("Cached binding not implemented yet\n"); - return -EINVAL; - } + DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); if (ret) { @@ -1003,8 +1004,11 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return -EINVAL; } ret = drm_bo_move_buffer(bo, new_flags, no_wait); - if (ret) + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed moving buffer.\n"); return ret; + } } if (move_unfenced) { @@ -1304,7 +1308,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); if (arg.handled) { - data = req->next; + data = arg.next; continue; } @@ -1404,7 +1408,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) default: rep.ret = -EINVAL; } - next = req->next; + next = arg.next; /* * A signal interrupted us. Make sure the ioctl is restartable. -- cgit v1.2.3 From f613022ceef1814cb734bb3375f01962fd3bcf10 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 15 Sep 2006 16:47:09 +0200 Subject: Allow a "native type" to be associated with a fence sequence. In the intel case, we can associate a flush with a sequence. --- linux-core/drm_bo.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 858a4cde..d176392a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -94,9 +94,9 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); if (bo->fence) { - if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { + if (!drm_fence_object_signaled(bo->fence, bo->fence_type)) { - drm_fence_object_flush(dev, bo->fence, bo->fence_flags); + drm_fence_object_flush(dev, bo->fence, bo->fence_type); list_add_tail(&bo->ddestroy, &bm->ddestroy); schedule_delayed_work(&bm->wq, ((DRM_HZ / 100) < @@ -144,7 +144,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) fence = entry->fence; if (fence && drm_fence_object_signaled(fence, - entry->fence_flags)) { + entry->fence_type)) { drm_fence_usage_deref_locked(dev, fence); entry->fence = NULL; } @@ -205,6 +205,7 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, + uint32_t fence_flags, drm_fence_object_t * fence, drm_fence_object_t ** used_fence) { @@ -212,7 +213,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *entry; - uint32_t fence_flags = 0; + uint32_t fence_type = 0; int count = 0; int ret = 0; struct list_head f_list, *l; @@ -224,7 +225,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); - fence_flags |= entry->fence_flags; + fence_type |= entry->fence_type; if (entry->fence_class != 0) { DRM_ERROR("Fence class %d is not implemented yet.\n", entry->fence_class); @@ -250,7 +251,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_del_init(list); if (fence) { - if ((fence_flags & fence->type) != fence_flags) { + if ((fence_type & fence->type) != fence_type) { DRM_ERROR("Given fence doesn't match buffers " "on unfenced list.\n"); ret = -EINVAL; @@ -258,7 +259,9 @@ int drm_fence_buffer_objects(drm_file_t * priv, } } else { mutex_unlock(&dev->struct_mutex); - ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + ret = drm_fence_object_create(dev, fence_type, + fence_flags | DRM_FENCE_FLAG_EMIT, + &fence); mutex_lock(&dev->struct_mutex); if (ret) goto out; @@ -317,7 +320,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -327,7 +330,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, } ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, - bo->fence_flags); + bo->fence_type); if (ret) return ret; @@ -624,7 +627,7 @@ static int drm_bo_quick_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -646,13 +649,13 @@ static int drm_bo_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; } drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE); - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -776,7 +779,7 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, rep->mask = bo->mask; rep->buffer_start = bo->buffer_start; - rep->fence_flags = bo->fence_flags; + rep->fence_flags = bo->fence_type; rep->rep_flags = 0; if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { @@ -988,7 +991,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, } DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); - ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); + ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_type); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; -- cgit v1.2.3 From ca1b15d645c74e20f638f5a09981bcf02f58caee Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 18 Sep 2006 20:43:31 +0200 Subject: Alternative implementation of page table zeroing using zap page_range. (Disabled for now) Fix bo_wait_idle bug. Remove stray debug message. --- linux-core/drm_bo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d176392a..8e51985e 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1115,6 +1115,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, if (!bo) { return -EINVAL; } + mutex_lock(&bo->mutex); ret = drm_bo_wait_unfenced(bo, no_wait, 0); if (ret) @@ -1124,10 +1125,11 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, goto out; drm_bo_fill_rep_arg(bo, rep); + out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(bo->dev, bo); - return 0; + return ret; } /* -- cgit v1.2.3 From 273eb7833d69db2d72430d5c96c21cebd05c206e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 25 Sep 2006 11:51:08 +0200 Subject: Add /proc filesystem buffer / fence object accounting. Check for NULL pointer in the i915 flush handler. Remove i915_sync_flush declaration. --- linux-core/drm_bo.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 8e51985e..f479c81a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -128,6 +128,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); } + atomic_dec(&bm->count); drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } @@ -140,6 +141,10 @@ static void drm_bo_delayed_delete(drm_device_t * dev) mutex_lock(&dev->struct_mutex); + /* + * FIXME: Lock buffer object mutex. + */ + list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { fence = entry->fence; @@ -1207,7 +1212,7 @@ int drm_buffer_object_create(drm_file_t * priv, uint32_t new_flags; unsigned long num_pages; - drm_bo_delayed_delete(dev); + // drm_bo_delayed_delete(dev); if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); @@ -1259,6 +1264,7 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; + atomic_inc(&bm->count); return 0; out_err: @@ -1576,6 +1582,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; + atomic_set(&bm->count, 0); bm->cur_pages = 0; bm->max_pages = arg.req.max_locked_pages; break; -- cgit v1.2.3 From 235f6fc650e9974211843b9196a903963dae0211 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 09:27:31 +0200 Subject: Adapt to architecture-specific hooks for gatt pages. --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f479c81a..4f1c4173 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1562,7 +1562,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - arg.req.tt_p_size); + 3000 /*arg.req.tt_p_size*/); bm->has_tt = 1; bm->use_tt = 1; -- cgit v1.2.3 From c97149b45be9d0e9385d4c6721aa70dad68a1aa1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 09:31:39 +0200 Subject: Fix tt fixed size that slipped through in previous commit. --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 4f1c4173..f479c81a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1562,7 +1562,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - 3000 /*arg.req.tt_p_size*/); + arg.req.tt_p_size); bm->has_tt = 1; bm->use_tt = 1; -- cgit v1.2.3 From f2c03ecae627df77db25391fe85fcd8a2a4bdc0c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 19:07:55 +0200 Subject: Fix racy buffer object destruction. --- linux-core/drm_bo.c | 64 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 10 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f479c81a..6a3a5020 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -93,6 +93,15 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + /* + * Somone might try to access us through the still active BM lists. + */ + + if (atomic_read(&bo->usage) != 0) + return; + if (!list_empty(&bo->ddestroy)) + return; + if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_type)) { @@ -114,6 +123,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->head); if (bo->tt) { + + /* + * This temporarily unlocks struct_mutex. + */ + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; @@ -136,33 +150,61 @@ static void drm_bo_delayed_delete(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; - drm_buffer_object_t *entry, *next; + drm_buffer_object_t *entry, *nentry; + struct list_head *list, *next; drm_fence_object_t *fence; mutex_lock(&dev->struct_mutex); + list = bm->ddestroy.next; + list_for_each_safe(list, next, &bm->ddestroy) { + entry = list_entry(list, drm_buffer_object_t, ddestroy); + nentry = NULL; - /* - * FIXME: Lock buffer object mutex. - */ + /* + * Another process may claim access to this entry through the + * lru lists. In that case, just skip it. + */ - list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { - fence = entry->fence; + if (atomic_read(&entry->usage) != 0) + continue; + + /* + * Since we're the only users, No need to take the + * bo->mutex to watch the fence. + */ + fence = entry->fence; if (fence && drm_fence_object_signaled(fence, entry->fence_type)) { drm_fence_usage_deref_locked(dev, fence); entry->fence = NULL; } + if (!entry->fence) { + + /* + * Protect the "next" entry against destruction in case + * drm_bo_destroy_locked temporarily releases the + * struct_mutex; + */ + + nentry = NULL; + if (next != &bm->ddestroy) { + nentry = list_entry(next, drm_buffer_object_t, + ddestroy); + atomic_inc(&nentry->usage); + } DRM_DEBUG("Destroying delayed buffer object\n"); - list_del(&entry->ddestroy); + list_del_init(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); - } + if (next != &bm->ddestroy) + atomic_dec(&nentry->usage); + } } - mutex_unlock(&dev->struct_mutex); } + static void drm_bo_delayed_workqueue(void *data) { drm_device_t *dev = (drm_device_t *) data; @@ -1212,7 +1254,7 @@ int drm_buffer_object_create(drm_file_t * priv, uint32_t new_flags; unsigned long num_pages; - // drm_bo_delayed_delete(dev); + drm_bo_delayed_delete(dev); if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); @@ -1241,6 +1283,8 @@ int drm_buffer_object_create(drm_file_t * priv, bo->dev = dev; bo->type = type; bo->num_pages = num_pages; + bo->vram = NULL; + bo->tt = NULL; if (bo->type == drm_bo_type_fake) { bo->offset = buffer_start; bo->buffer_start = 0; -- cgit v1.2.3 From 3802f9adbf9a7e3d5c356f74b0c1ee966476fb97 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Sep 2006 11:15:59 +0200 Subject: Fix buffer manager takedown error. Prepare for the possibility to evict all buffers from vram / agp. This will be used by the X server when, for example, switching vts. --- linux-core/drm_bo.c | 190 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 123 insertions(+), 67 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 6a3a5020..d1989e49 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -120,7 +120,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * Take away from lru lists. */ - list_del_init(&bo->head); + list_del_init(&bo->tt_lru); + list_del_init(&bo->vram_lru); if (bo->tt) { @@ -155,6 +156,9 @@ static void drm_bo_delayed_delete(drm_device_t * dev) drm_fence_object_t *fence; mutex_lock(&dev->struct_mutex); + if (!bm->initialized) + goto out; + list = bm->ddestroy.next; list_for_each_safe(list, next, &bm->ddestroy) { entry = list_entry(list, drm_buffer_object_t, ddestroy); @@ -201,6 +205,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) atomic_dec(&nentry->usage); } } + out: mutex_unlock(&dev->struct_mutex); } @@ -264,13 +269,14 @@ int drm_fence_buffer_objects(drm_file_t * priv, int count = 0; int ret = 0; struct list_head f_list, *l; + struct list_head *q; mutex_lock(&dev->struct_mutex); if (!list) list = &bm->unfenced; - list_for_each_entry(entry, list, head) { + list_for_each_entry(entry, list, tt_lru) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_type |= entry->fence_type; if (entry->fence_class != 0) { @@ -317,12 +323,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, count = 0; l = f_list.next; while (l != &f_list) { - entry = list_entry(l, drm_buffer_object_t, head); + entry = list_entry(l, drm_buffer_object_t, tt_lru); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); mutex_lock(&dev->struct_mutex); list_del_init(l); + list_del_init(&entry->vram_lru); if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) @@ -331,15 +338,19 @@ int drm_fence_buffer_objects(drm_file_t * priv, DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); - if (entry->flags & DRM_BO_FLAG_NO_EVICT) - list_add_tail(&entry->head, &bm->other); - else if (entry->flags & DRM_BO_FLAG_MEM_TT) - list_add_tail(&entry->head, &bm->tt_lru); - else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) - list_add_tail(&entry->head, &bm->vram_lru); - else - list_add_tail(&entry->head, &bm->other); - } mutex_unlock(&entry->mutex); + if (entry->flags & DRM_BO_FLAG_MEM_TT) { + q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->tt_pinned : &bm->tt_lru; + list_add_tail(&entry->tt_lru, q); + } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { + q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->vram_pinned : &bm->vram_lru; + list_add_tail(&entry->vram_lru, q); + } else { + list_add_tail(&entry->tt_lru, &bm->other); + } + } + mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } @@ -389,7 +400,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, } /* - * No locking required. + * bo->mutex locked */ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) @@ -401,16 +412,13 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) * Someone might have modified the buffer before we took the buffer mutex. */ - mutex_lock(&bo->mutex); - if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) - || (bo->flags & DRM_BO_FLAG_NO_EVICT)) + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) goto out; if (tt && !bo->tt) goto out; if (!tt && !bo->vram) goto out; - ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { if (ret != -EAGAIN) @@ -428,13 +436,13 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) } #endif mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - list_add_tail(&bo->head, &bm->other); + list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru); + if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru)) + list_add_tail(&bo->tt_lru, &bm->other); mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); out: - mutex_unlock(&bo->mutex); return ret; } @@ -463,11 +471,17 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) if (lru->next == lru) break; - bo = list_entry(lru->next, drm_buffer_object_t, head); + if (tt) { + bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); + } else { + bo = list_entry(lru->next, drm_buffer_object_t, vram_lru); + } atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); + mutex_lock(&bo->mutex); ret = drm_bo_evict(bo, tt, no_wait); + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); if (ret) return ret; @@ -714,18 +728,16 @@ static int drm_bo_busy(drm_buffer_object_t * bo) static int drm_bo_read_cached(drm_buffer_object_t * bo) { - drm_device_t *dev = bo->dev; - drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, - _DRM_BO_FLAG_EVICTED); - - mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - list_add_tail(&bo->head, &bm->other); - mutex_unlock(&dev->struct_mutex); - return drm_move_tt_to_local(bo); + if (bo->vram) + ret = drm_bo_evict(bo, 0, 1); + if (ret) + return ret; + if (bo->tt) + ret = drm_bo_evict(bo, 1, 1); + return ret; } /* @@ -1070,20 +1082,28 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, _DRM_BO_FLAG_UNFENCED); mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - list_add_tail(&bo->head, &bm->unfenced); + list_del(&bo->tt_lru); + list_add_tail(&bo->tt_lru, &bm->unfenced); + list_del_init(&bo->vram_lru); mutex_unlock(&dev->struct_mutex); } else { + struct list_head *q; + mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - if (new_flags & DRM_BO_FLAG_NO_EVICT) - list_add_tail(&bo->head, &bm->other); - else if (new_flags & DRM_BO_FLAG_MEM_TT) - list_add_tail(&bo->head, &bm->tt_lru); - else if (new_flags & DRM_BO_FLAG_MEM_VRAM) - list_add_tail(&bo->head, &bm->vram_lru); - else - list_add_tail(&bo->head, &bm->other); + list_del_init(&bo->tt_lru); + list_del_init(&bo->vram_lru); + + if (new_flags & DRM_BO_FLAG_MEM_TT) { + q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->tt_pinned : &bm->tt_lru; + list_add_tail(&bo->tt_lru, q); + } else if (new_flags & DRM_BO_FLAG_MEM_VRAM) { + q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->vram_pinned : &bm->vram_lru; + list_add_tail(&bo->vram_lru, q); + } else { + list_add_tail(&bo->tt_lru, &bm->other); + } mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -1277,9 +1297,10 @@ int drm_buffer_object_create(drm_file_t * priv, atomic_set(&bo->usage, 1); atomic_set(&bo->mapped, -1); DRM_INIT_WAITQUEUE(&bo->event_queue); - INIT_LIST_HEAD(&bo->head); - list_add_tail(&bo->head, &bm->other); + INIT_LIST_HEAD(&bo->tt_lru); + INIT_LIST_HEAD(&bo->vram_lru); INIT_LIST_HEAD(&bo->ddestroy); + list_add_tail(&bo->tt_lru, &bm->other); bo->dev = dev; bo->type = type; bo->num_pages = num_pages; @@ -1484,43 +1505,67 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) * dev->struct_sem locked. */ -static void drm_bo_force_clean(drm_device_t * dev) +static void drm_bo_force_list_clean(drm_device_t *dev, + struct list_head *head, int tt) { - drm_buffer_manager_t *bm = &dev->bm; struct list_head *l; drm_buffer_object_t *entry; int nice_mode = 1; - int ret = 0; + int ret; + + l = head->next; + while (l != head) { + if (tt) { + entry = list_entry(l, drm_buffer_object_t, + tt_lru); + } else { + entry = list_entry(l, drm_buffer_object_t, + vram_lru); + } + + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + + /* + * Expire the fence. + */ - l = bm->ddestroy.next; - while (l != &bm->ddestroy) { - entry = list_entry(l, drm_buffer_object_t, ddestroy); - list_del(l); if (entry->fence) { if (nice_mode) { - unsigned long _end = jiffies + 3 * DRM_HZ; + unsigned long _end = jiffies + 3*DRM_HZ; do { - mutex_unlock(&dev->struct_mutex); ret = drm_bo_wait(entry, 0, 1, 0); - mutex_lock(&dev->struct_mutex); - } while ((ret == -EINTR) && - !time_after_eq(jiffies, _end)); - } else { - drm_fence_usage_deref_locked(dev, entry->fence); - entry->fence = NULL; + } while (ret && !time_after_eq(jiffies, _end)); + + if (entry->fence) { + nice_mode = 0; + DRM_ERROR("Detected GPU hang. " + "Evicting waiting buffers\n"); + } } if (entry->fence) { - DRM_ERROR("Detected GPU hang. " - "Removing waiting buffers.\n"); - nice_mode = 0; - drm_fence_usage_deref_locked(dev, entry->fence); + drm_fence_usage_deref_unlocked(dev, entry->fence); entry->fence = NULL; } + } + ret = drm_bo_evict(entry, tt, 0); + if (ret) { + DRM_ERROR("Aargh. Eviction failed.\n"); + } + mutex_unlock(&entry->mutex); + mutex_lock(&dev->struct_mutex); + if (!list_empty(l)) { + list_del_init(l); + if (list_empty(&entry->tt_lru) && + list_empty(&entry->vram_lru)) { + list_add_tail(l, &dev->bm.other); + } } - DRM_DEBUG("Destroying delayed buffer object\n"); - drm_bo_destroy_locked(dev, entry); - l = bm->ddestroy.next; + + drm_bo_usage_deref_locked(dev, entry); + l = head->next; } } @@ -1534,10 +1579,18 @@ int drm_bo_clean_mm(drm_device_t * dev) if (!bm->initialized) goto out; - drm_bo_force_clean(dev); bm->use_vram = 0; bm->use_tt = 0; + /* + * FIXME: Need to handle unfenced list. + */ + + drm_bo_force_list_clean(dev, &bm->tt_lru, 1); + drm_bo_force_list_clean(dev, &bm->tt_pinned, 1); + drm_bo_force_list_clean(dev, &bm->vram_lru, 1); + drm_bo_force_list_clean(dev, &bm->vram_pinned, 1); + if (bm->has_vram) { if (drm_mm_clean(&bm->vram_manager)) { drm_mm_takedown(&bm->vram_manager); @@ -1620,6 +1673,8 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_LIST_HEAD(&bm->vram_lru); INIT_LIST_HEAD(&bm->tt_lru); + INIT_LIST_HEAD(&bm->vram_pinned); + INIT_LIST_HEAD(&bm->tt_pinned); INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); INIT_LIST_HEAD(&bm->other); @@ -1631,6 +1686,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->max_pages = arg.req.max_locked_pages; break; case mm_takedown: + LOCK_TEST_WITH_RETURN(dev, filp); if (drm_bo_clean_mm(dev)) { DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); -- cgit v1.2.3 From f2db76e2f206d2017f710eaddc4b33add4498898 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 13:40:35 +0200 Subject: Big update: Adapt for new functions in the 2.6.19 kernel. Remove the ability to have multiple regions in one TTM. This simplifies a lot of code. Remove the ability to access TTMs from user space. We don't need it anymore without ttm regions. Don't change caching policy for evicted buffers. Instead change it only when the buffer is accessed by the CPU (on the first page fault). This tremendously speeds up eviction rates. Current code is safe for kernels <= 2.6.14. Should also be OK with 2.6.19 and above. --- linux-core/drm_bo.c | 51 ++++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d1989e49..d8cab2ad 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -63,7 +63,7 @@ * bo locked. */ -static int drm_move_tt_to_local(drm_buffer_object_t * buf) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -71,7 +71,10 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); mutex_lock(&dev->struct_mutex); - drm_unbind_ttm_region(buf->ttm_region); + if (evict) + drm_evict_ttm(buf->ttm); + else + drm_unbind_ttm(buf->ttm); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -129,7 +132,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * This temporarily unlocks struct_mutex. */ - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm(bo->ttm); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -137,9 +140,6 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_mm_put_block(&bm->vram_manager, bo->vram); bo->vram = NULL; } - if (bo->ttm_region) { - drm_destroy_ttm_region(bo->ttm_region); - } if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); } @@ -428,7 +428,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) } if (tt) { - ret = drm_move_tt_to_local(bo); + ret = drm_move_tt_to_local(bo, 1); } #if 0 else { @@ -522,7 +522,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); - ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); + ret = drm_bind_ttm(bo->ttm, bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); } @@ -530,7 +530,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - be = bo->ttm_region->be; + be = bo->ttm->be; if (be->needs_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; @@ -1023,7 +1023,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo); + drm_move_tt_to_local(bo, 0); } return 0; @@ -1203,34 +1203,24 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t ttm_handle) +static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; - drm_ttm_t *ttm; int ret = 0; uint32_t ttm_flags = 0; bo->ttm_object = NULL; - bo->ttm_region = NULL; + bo->ttm = NULL; switch (bo->type) { case drm_bo_type_dc: mutex_lock(&dev->struct_mutex); ret = drm_ttm_object_create(dev, bo->num_pages * PAGE_SIZE, + bo->mask & DRM_BO_FLAG_BIND_CACHED, ttm_flags, &to); mutex_unlock(&dev->struct_mutex); break; - case drm_bo_type_ttm: - mutex_lock(&dev->struct_mutex); - to = drm_lookup_ttm_object(priv, ttm_handle, 1); - mutex_unlock(&dev->struct_mutex); - if (!to) { - DRM_ERROR("Could not find TTM object\n"); - ret = -EINVAL; - } - break; case drm_bo_type_user: case drm_bo_type_fake: break; @@ -1246,14 +1236,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, if (to) { bo->ttm_object = to; - ttm = drm_ttm_from_object(to); - ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, - bo->mask & DRM_BO_FLAG_BIND_CACHED, - &bo->ttm_region); - if (ret) { - drm_ttm_object_deref_unlocked(dev, to); - } + bo->ttm = drm_ttm_from_object(to); } return ret; } @@ -1261,7 +1244,6 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, - uint32_t ttm_handle, uint32_t mask, uint32_t hint, unsigned long buffer_start, @@ -1318,7 +1300,7 @@ int drm_buffer_object_create(drm_file_t * priv, 1, &new_flags, &bo->mask); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, ttm_handle); + ret = drm_bo_add_ttm(priv, bo); if (ret) goto out_err; @@ -1394,7 +1376,6 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_buffer_object_create(priv, req->size, req->type, - req->arg_handle, req->mask, req->hint, req->buffer_start, &entry); @@ -1659,7 +1640,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - arg.req.tt_p_size); + 3000 /* arg.req.tt_p_size */); bm->has_tt = 1; bm->use_tt = 1; -- cgit v1.2.3 From 30703893674b3da5b862dee2acd6efca13424398 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 22:21:01 +0200 Subject: Compatibility code for 2.6.15-2.6.18. It is ugly but a little comfort is that it will go away in the mainstream kernel. Some bugfixes, mainly in error paths. --- linux-core/drm_bo.c | 54 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 10 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d8cab2ad..0e2b3fa1 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -67,14 +67,23 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; + int ret; BUG_ON(!buf->tt); mutex_lock(&dev->struct_mutex); if (evict) - drm_evict_ttm(buf->ttm); + ret = drm_evict_ttm(buf->ttm); else - drm_unbind_ttm(buf->ttm); + ret = drm_unbind_ttm(buf->ttm); + + if (ret) { + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) + schedule(); + return ret; + } + drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -126,13 +135,31 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->tt_lru); list_del_init(&bo->vram_lru); - if (bo->tt) { + if (bo->ttm) { + unsigned long _end = jiffies + DRM_HZ; + int ret; /* * This temporarily unlocks struct_mutex. */ + + do { + ret = drm_unbind_ttm(bo->ttm); + if (ret == -EAGAIN) { + mutex_unlock(&dev->struct_mutex); + schedule(); + mutex_lock(&dev->struct_mutex); + } + } while (ret == -EAGAIN && !time_after_eq(jiffies, _end)); + + if (ret) { + DRM_ERROR("Couldn't unbind buffer. " + "Bad. Continuing anyway\n"); + } + } + + if (bo->tt) { - drm_unbind_ttm(bo->ttm); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -435,6 +462,9 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif + if (ret) + goto out; + mutex_lock(&dev->struct_mutex); list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru); if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru)) @@ -442,7 +472,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - out: + out: return ret; } @@ -521,14 +551,18 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); + mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm(bo->ttm, bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); + bo->tt = NULL; } mutex_unlock(&dev->struct_mutex); - if (ret) + + if (ret) { return ret; + } be = bo->ttm->be; if (be->needs_cache_adjust(be)) @@ -1296,6 +1330,7 @@ int drm_buffer_object_create(drm_file_t * priv, } bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + atomic_inc(&bm->count); ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); if (ret) @@ -1311,12 +1346,11 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; - atomic_inc(&bm->count); return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); - drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + drm_bo_usage_deref_unlocked(dev, bo); return ret; } -- cgit v1.2.3 From 10150df02b7062b9975661ccd82b475cd23c8839 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 12 Oct 2006 12:09:16 +0200 Subject: Simplify the AGP backend interface somewhat. Fix buffer bound caching policy changing, Allow on-the-fly changing of caching policy on bound buffers if the hardware supports it. Allow drivers to use driver-specific AGP memory types for TTM AGP pages. Will make AGP drivers much easier to migrate. --- linux-core/drm_bo.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0e2b3fa1..a84734ab 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -553,7 +553,8 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); - ret = drm_bind_ttm(bo->ttm, bo->tt->start); + ret = drm_bind_ttm(bo->ttm, bo->flags & DRM_BO_FLAG_BIND_CACHED, + bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; @@ -565,7 +566,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) } be = bo->ttm->be; - if (be->needs_cache_adjust(be)) + if (be->needs_ub_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; bo->flags |= DRM_BO_FLAG_MEM_TT; @@ -1089,16 +1090,35 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } + + /* + * Move out if we need to change caching policy. + * FIXME: Failing is strictly not needed for NO_MOVE buffers. + * We just have to implement NO_MOVE buffers. + */ + + if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && + !(bo->flags & DRM_BO_FLAG_MEM_LOCAL)) { + if (bo->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { + DRM_ERROR("Cannot change caching policy of " + "pinned buffer.\n"); + return -EINVAL; + } + ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait); + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed moving buffer.\n"); + return ret; + } + } + DRM_MASK_VAL(bo->flags, DRM_BO_FLAG_BIND_CACHED, new_flags); + flag_diff = (new_flags ^ bo->flags); /* * Check whether we need to move buffer. */ if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { - if (bo->type == drm_bo_type_user) { - DRM_ERROR("User buffers are not implemented yet.\n"); - return -EINVAL; - } ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) { if (ret != -EAGAIN) @@ -1251,7 +1271,6 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo) case drm_bo_type_dc: mutex_lock(&dev->struct_mutex); ret = drm_ttm_object_create(dev, bo->num_pages * PAGE_SIZE, - bo->mask & DRM_BO_FLAG_BIND_CACHED, ttm_flags, &to); mutex_unlock(&dev->struct_mutex); break; @@ -1674,7 +1693,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - 3000 /* arg.req.tt_p_size */); + arg.req.tt_p_size); bm->has_tt = 1; bm->use_tt = 1; -- cgit v1.2.3 From 540c64c378daafaad1c3f63faf5af81f39388665 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 12 Oct 2006 16:10:47 +0200 Subject: Bugfixes. --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index a84734ab..c24f8d57 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1718,6 +1718,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) atomic_set(&bm->count, 0); bm->cur_pages = 0; bm->max_pages = arg.req.max_locked_pages; + mutex_unlock(&dev->struct_mutex); break; case mm_takedown: LOCK_TEST_WITH_RETURN(dev, filp); @@ -1732,7 +1733,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } - mutex_unlock(&dev->struct_mutex); if (ret) return ret; -- cgit v1.2.3 From 5881ce1b91034fbdf81dda37a23215cfc1310cdf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:05:37 +0200 Subject: Extend generality for more memory types. Fix up init and destruction code. --- linux-core/drm_bo.c | 566 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 357 insertions(+), 209 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index c24f8d57..20c58f21 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,6 +59,69 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } +static inline uint32_t drm_bo_type_flags(unsigned type) +{ + return (1 << (24 + type)); +} + +static inline drm_buffer_object_t *drm_bo_entry(struct list_head *list, + unsigned type) +{ + switch(type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return list_entry(list, drm_buffer_object_t, lru_ttm); + case DRM_BO_MEM_VRAM: + case DRM_BO_MEM_VRAM_NM: + return list_entry(list, drm_buffer_object_t, lru_card); + default: + BUG_ON(1); + } + return NULL; +} + +static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t *bo, + unsigned type) +{ + switch(type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return bo->node_ttm; + case DRM_BO_MEM_VRAM: + case DRM_BO_MEM_VRAM_NM: + return bo->node_card; + default: + BUG_ON(1); + } + return NULL; +} + +/* + * bo locked. dev->struct_mutex locked. + */ + +static void drm_bo_add_to_lru(drm_buffer_object_t *buf, + drm_buffer_manager_t *bm) +{ + struct list_head *list; + unsigned mem_type; + + if (buf->flags & DRM_BO_FLAG_MEM_TT) { + mem_type = DRM_BO_MEM_TT; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_ttm, list); + } else { + mem_type = DRM_BO_MEM_LOCAL; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_ttm, list); + } + if (buf->flags & DRM_BO_FLAG_MEM_VRAM) { + mem_type = DRM_BO_MEM_VRAM; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_card, list); + } +} + /* * bo locked. */ @@ -69,27 +132,27 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) drm_buffer_manager_t *bm = &dev->bm; int ret; - BUG_ON(!buf->tt); - - mutex_lock(&dev->struct_mutex); - if (evict) - ret = drm_evict_ttm(buf->ttm); - else - ret = drm_unbind_ttm(buf->ttm); + if (buf->node_ttm) { + mutex_lock(&dev->struct_mutex); + if (evict) + ret = drm_evict_ttm(buf->ttm); + else + ret = drm_unbind_ttm(buf->ttm); - if (ret) { + if (ret) { + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) + schedule(); + return ret; + } + + drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], buf->node_ttm); + buf->node_ttm = NULL; mutex_unlock(&dev->struct_mutex); - if (ret == -EAGAIN) - schedule(); - return ret; } - - drm_mm_put_block(&bm->tt_manager, buf->tt); - buf->tt = NULL; - buf->flags &= ~DRM_BO_MASK_MEM; + buf->flags &= ~DRM_BO_FLAG_MEM_TT; buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; - mutex_unlock(&dev->struct_mutex); return 0; } @@ -103,6 +166,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); /* @@ -132,8 +196,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * Take away from lru lists. */ - list_del_init(&bo->tt_lru); - list_del_init(&bo->vram_lru); + list_del_init(&bo->lru_ttm); + list_del_init(&bo->lru_card); if (bo->ttm) { unsigned long _end = jiffies + DRM_HZ; @@ -158,14 +222,15 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) } } - if (bo->tt) { - - drm_mm_put_block(&bm->tt_manager, bo->tt); - bo->tt = NULL; + if (bo->node_ttm) { + drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], + bo->node_ttm); + bo->node_ttm = NULL; } - if (bo->vram) { - drm_mm_put_block(&bm->vram_manager, bo->vram); - bo->vram = NULL; + if (bo->node_card) { + drm_mm_put_block(&bm->manager[DRM_BO_MEM_VRAM], + bo->node_card); + bo->node_card = NULL; } if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); @@ -246,7 +311,7 @@ static void drm_bo_delayed_workqueue(void *data) drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); - if (!list_empty(&bm->ddestroy)) { + if (bm->initialized && !list_empty(&bm->ddestroy)) { schedule_delayed_work(&bm->wq, ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); } @@ -296,14 +361,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, int count = 0; int ret = 0; struct list_head f_list, *l; - struct list_head *q; mutex_lock(&dev->struct_mutex); if (!list) list = &bm->unfenced; - list_for_each_entry(entry, list, tt_lru) { + list_for_each_entry(entry, list, lru_ttm) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_type |= entry->fence_type; if (entry->fence_class != 0) { @@ -316,7 +380,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, } if (!count) { - DRM_ERROR("No buffers to fence\n"); ret = -EINVAL; goto out; } @@ -350,13 +413,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, count = 0; l = f_list.next; while (l != &f_list) { - entry = list_entry(l, drm_buffer_object_t, tt_lru); + entry = list_entry(l, drm_buffer_object_t, lru_ttm); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); mutex_lock(&dev->struct_mutex); list_del_init(l); - list_del_init(&entry->vram_lru); + list_del_init(&entry->lru_card); if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) @@ -365,17 +428,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); - if (entry->flags & DRM_BO_FLAG_MEM_TT) { - q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->tt_pinned : &bm->tt_lru; - list_add_tail(&entry->tt_lru, q); - } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { - q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->vram_pinned : &bm->vram_lru; - list_add_tail(&entry->vram_lru, q); - } else { - list_add_tail(&entry->tt_lru, &bm->other); - } + drm_bo_add_to_lru(entry, bm); } mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); @@ -430,23 +483,24 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, * bo->mutex locked */ -static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) +static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, + int no_wait) { int ret = 0; drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; + /* * Someone might have modified the buffer before we took the buffer mutex. */ - if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) goto out; - if (tt && !bo->tt) - goto out; - if (!tt && !bo->vram) + if (!(bo->flags & drm_bo_type_flags(mem_type))) goto out; ret = drm_bo_wait(bo, 0, 0, no_wait); + if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed to expire fence before " @@ -454,22 +508,26 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) goto out; } - if (tt) { + if (mem_type == DRM_BO_MEM_TT) { ret = drm_move_tt_to_local(bo, 1); + if (ret) + goto out; + mutex_lock(&dev->struct_mutex); + list_del(&bo->lru_ttm); + list_add_tail(&bo->lru_ttm, &bm->lru[DRM_BO_MEM_LOCAL]); + mutex_unlock(&dev->struct_mutex); } #if 0 else { ret = drm_move_vram_to_local(bo); + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->lru_card); + mutex_unlock(&dev->struct_mutex); } #endif if (ret) goto out; - mutex_lock(&dev->struct_mutex); - list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru); - if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru)) - list_add_tail(&bo->tt_lru, &bm->other); - mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); out: @@ -480,13 +538,14 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) * buf->mutex locked. */ -int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) +int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, + int no_wait) { drm_device_t *dev = buf->dev; drm_mm_node_t *node; drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *bo; - drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; + drm_mm_t *mm = &bm->manager[mem_type]; struct list_head *lru; unsigned long size = buf->num_pages; int ret; @@ -497,20 +556,16 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) if (node) break; - lru = (tt) ? &bm->tt_lru : &bm->vram_lru; + lru = &bm->lru[mem_type]; if (lru->next == lru) break; - if (tt) { - bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); - } else { - bo = list_entry(lru->next, drm_buffer_object_t, vram_lru); - } + bo = drm_bo_entry(lru->next, mem_type); atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&bo->mutex); - ret = drm_bo_evict(bo, tt, no_wait); + ret = drm_bo_evict(bo, mem_type, no_wait); mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); if (ret) @@ -529,10 +584,10 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) BUG_ON(!node); node->private = (void *)buf; - if (tt) { - buf->tt = node; + if (mem_type == DRM_BO_MEM_TT) { + buf->node_ttm = node; } else { - buf->vram = node; + buf->node_card = node; } buf->offset = node->start * PAGE_SIZE; return 0; @@ -545,19 +600,19 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) drm_ttm_backend_t *be; int ret; - BUG_ON(bo->tt); + BUG_ON(bo->node_ttm); ret = drm_bo_alloc_space(bo, 1, no_wait); if (ret) return ret; - DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); + DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->node_ttm->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm(bo->ttm, bo->flags & DRM_BO_FLAG_BIND_CACHED, - bo->tt->start); + bo->node_ttm->start); if (ret) { - drm_mm_put_block(&bm->tt_manager, bo->tt); - bo->tt = NULL; + drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], bo->node_ttm); + bo->node_ttm = NULL; } mutex_unlock(&dev->struct_mutex); @@ -589,25 +644,27 @@ static int drm_bo_new_flags(drm_device_t * dev, uint32_t new_props; drm_bo_driver_t *driver = dev->driver->bo_driver; drm_buffer_manager_t *bm = &dev->bm; + unsigned i; /* - * First adjust the mask. + * First adjust the mask to take away nonexistant memory types. */ - if (!bm->use_vram) - new_mask &= ~DRM_BO_FLAG_MEM_VRAM; - if (!bm->use_tt) - new_mask &= ~DRM_BO_FLAG_MEM_TT; + for (i=0; iuse_type[i]) + new_mask &= ~drm_bo_type_flags(i); + } if (new_mask & DRM_BO_FLAG_BIND_CACHED) { - if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && + if (((new_mask & DRM_BO_FLAG_MEM_TT) && + !driver->cached[DRM_BO_MEM_TT]) && ((new_mask & DRM_BO_FLAG_MEM_VRAM) - && !driver->cached_vram)) { + && !driver->cached[DRM_BO_MEM_VRAM])) { new_mask &= ~DRM_BO_FLAG_BIND_CACHED; } else { - if (!driver->cached_tt) + if (!driver->cached[DRM_BO_MEM_TT]) new_flags &= DRM_BO_FLAG_MEM_TT; - if (!driver->cached_vram) + if (!driver->cached[DRM_BO_MEM_VRAM]) new_flags &= DRM_BO_FLAG_MEM_VRAM; } } @@ -766,12 +823,12 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) int ret = 0; BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - if (bo->vram) - ret = drm_bo_evict(bo, 0, 1); + if (bo->node_card) + ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1); if (ret) return ret; - if (bo->tt) - ret = drm_bo_evict(bo, 1, 1); + if (bo->node_ttm) + ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1); return ret; } @@ -1136,28 +1193,16 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, _DRM_BO_FLAG_UNFENCED); mutex_lock(&dev->struct_mutex); - list_del(&bo->tt_lru); - list_add_tail(&bo->tt_lru, &bm->unfenced); - list_del_init(&bo->vram_lru); + list_del(&bo->lru_ttm); + list_add_tail(&bo->lru_ttm, &bm->unfenced); + list_del_init(&bo->lru_card); mutex_unlock(&dev->struct_mutex); } else { - struct list_head *q; mutex_lock(&dev->struct_mutex); - list_del_init(&bo->tt_lru); - list_del_init(&bo->vram_lru); - - if (new_flags & DRM_BO_FLAG_MEM_TT) { - q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->tt_pinned : &bm->tt_lru; - list_add_tail(&bo->tt_lru, q); - } else if (new_flags & DRM_BO_FLAG_MEM_VRAM) { - q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->vram_pinned : &bm->vram_lru; - list_add_tail(&bo->vram_lru, q); - } else { - list_add_tail(&bo->tt_lru, &bm->other); - } + list_del_init(&bo->lru_ttm); + list_del_init(&bo->lru_card); + drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -1332,15 +1377,14 @@ int drm_buffer_object_create(drm_file_t * priv, atomic_set(&bo->usage, 1); atomic_set(&bo->mapped, -1); DRM_INIT_WAITQUEUE(&bo->event_queue); - INIT_LIST_HEAD(&bo->tt_lru); - INIT_LIST_HEAD(&bo->vram_lru); + INIT_LIST_HEAD(&bo->lru_ttm); + INIT_LIST_HEAD(&bo->lru_card); INIT_LIST_HEAD(&bo->ddestroy); - list_add_tail(&bo->tt_lru, &bm->other); bo->dev = dev; bo->type = type; bo->num_pages = num_pages; - bo->vram = NULL; - bo->tt = NULL; + bo->node_card = NULL; + bo->node_ttm = NULL; if (bo->type == drm_bo_type_fake) { bo->offset = buffer_start; bo->buffer_start = 0; @@ -1540,22 +1584,17 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) */ static void drm_bo_force_list_clean(drm_device_t *dev, - struct list_head *head, int tt) + struct list_head *head, + unsigned mem_type) { + drm_buffer_manager_t *bm = &dev->bm; struct list_head *l; drm_buffer_object_t *entry; - int nice_mode = 1; int ret; l = head->next; while (l != head) { - if (tt) { - entry = list_entry(l, drm_buffer_object_t, - tt_lru); - } else { - entry = list_entry(l, drm_buffer_object_t, - vram_lru); - } + entry = drm_bo_entry(l, mem_type); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); @@ -1566,89 +1605,200 @@ static void drm_bo_force_list_clean(drm_device_t *dev, */ if (entry->fence) { - if (nice_mode) { + if (bm->nice_mode) { unsigned long _end = jiffies + 3*DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); } while (ret && !time_after_eq(jiffies, _end)); if (entry->fence) { - nice_mode = 0; - DRM_ERROR("Detected GPU hang. " + bm->nice_mode = 0; + DRM_ERROR("Detected GPU hang or " + "fence manager was taken down. " "Evicting waiting buffers\n"); } } + if (entry->fence) { - drm_fence_usage_deref_unlocked(dev, entry->fence); + drm_fence_usage_deref_unlocked(dev, + entry->fence); entry->fence = NULL; } } - ret = drm_bo_evict(entry, tt, 0); + ret = drm_bo_evict(entry, mem_type, 0); if (ret) { DRM_ERROR("Aargh. Eviction failed.\n"); } mutex_unlock(&entry->mutex); mutex_lock(&dev->struct_mutex); - if (!list_empty(l)) { - list_del_init(l); - if (list_empty(&entry->tt_lru) && - list_empty(&entry->vram_lru)) { - list_add_tail(l, &dev->bm.other); - } - } - drm_bo_usage_deref_locked(dev, entry); l = head->next; } } -int drm_bo_clean_mm(drm_device_t * dev) +int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) { drm_buffer_manager_t *bm = &dev->bm; - int ret = 0; + int ret = -EINVAL; - mutex_lock(&dev->struct_mutex); + if (mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", mem_type); + return ret; + } - if (!bm->initialized) - goto out; + if (!bm->has_type[mem_type]) { + DRM_ERROR("Trying to take down uninitialized " + "memory manager type\n"); + return ret; + } + bm->use_type[mem_type] = 0; + bm->has_type[mem_type] = 0; - bm->use_vram = 0; - bm->use_tt = 0; + ret = 0; + if (mem_type > 0) { + drm_bo_force_list_clean(dev, &bm->lru[mem_type], 1); + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], 1); - /* - * FIXME: Need to handle unfenced list. - */ + if (drm_mm_clean(&bm->manager[mem_type])) { + drm_mm_takedown(&bm->manager[mem_type]); + } else { + ret = -EBUSY; + } + } - drm_bo_force_list_clean(dev, &bm->tt_lru, 1); - drm_bo_force_list_clean(dev, &bm->tt_pinned, 1); - drm_bo_force_list_clean(dev, &bm->vram_lru, 1); - drm_bo_force_list_clean(dev, &bm->vram_pinned, 1); + return ret; +} - if (bm->has_vram) { - if (drm_mm_clean(&bm->vram_manager)) { - drm_mm_takedown(&bm->vram_manager); - bm->has_vram = 0; - } else - ret = -EBUSY; +static int drm_bo_init_mm(drm_device_t *dev, + unsigned type, + unsigned long p_offset, + unsigned long p_size) +{ + drm_buffer_manager_t *bm = &dev->bm; + int ret = -EINVAL; + + if (type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", type); + return ret; + } + if (bm->has_type[type]) { + DRM_ERROR("Memory manager already initialized for type %d\n", + type); + return ret; } - if (bm->has_tt) { - if (drm_mm_clean(&bm->tt_manager)) { - drm_mm_takedown(&bm->tt_manager); - bm->has_tt = 0; - } else - ret = -EBUSY; + ret = 0; + if (type != DRM_BO_MEM_LOCAL) { + if (!p_size) { + DRM_ERROR("Zero size memory manager type %d\n", type); + return ret; + } + ret = drm_mm_init(&bm->manager[type],p_offset, p_size); + if (ret) + return ret; + } + bm->has_type[type] = 1; + bm->use_type[type] = 1; + + INIT_LIST_HEAD(&bm->lru[type]); + INIT_LIST_HEAD(&bm->pinned[type]); + + return 0; +} + - if (!ret) - bm->initialized = 0; +/* + * call dev->struct_mutex locked; + */ + +static void drm_bo_release_unfenced(drm_buffer_manager_t *bm) +{ + struct list_head *list, *next; + + list_for_each_safe(list, next, &bm->unfenced) { + list_del(list); + list_add_tail(list, &bm->lru[0]); } +} - out: +int drm_bo_driver_finish(drm_device_t *dev) +{ + drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; + unsigned i = DRM_BO_MEM_TYPES; + + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + + if (!bm->initialized) + goto out; + drm_bo_release_unfenced(bm); + + while(i--) { + if (bm->has_type[i]) { + bm->use_type[i] = 0; + if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) { + ret = -EBUSY; + DRM_ERROR("DRM memory manager type %d " + "is not clean.\n", i); + } + bm->has_type[i] = 0; + } + } mutex_unlock(&dev->struct_mutex); + drm_bo_delayed_delete(dev); + mutex_lock(&dev->struct_mutex); + bm->initialized = 0; + mutex_unlock(&dev->struct_mutex); + if (!cancel_delayed_work(&bm->wq)) { + flush_scheduled_work(); + } + mutex_lock(&dev->struct_mutex); + out: + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->bm.init_mutex); + return ret; +} + + +int drm_bo_driver_init(drm_device_t *dev) +{ + drm_bo_driver_t *driver = dev->driver->bo_driver; + drm_buffer_manager_t *bm = &dev->bm; + int ret = -EINVAL; + struct sysinfo si; + + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + if (!driver) + goto out_unlock; + + /* + * Initialize the system memory buffer type. + * Other types need to be driver / IOCTL initialized. + */ + ret = drm_bo_init_mm(dev, 0, 0, 0); + if (ret) + goto out_unlock; + + INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); + bm->initialized = 1; + bm->nice_mode = 1; + atomic_set(&bm->count, 0); + bm->cur_pages = 0; + si_meminfo(&si); + bm->max_pages = si.totalram >> 1; + INIT_LIST_HEAD(&bm->unfenced); + INIT_LIST_HEAD(&bm->ddestroy); + out_unlock: + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->bm.init_mutex); return ret; } +EXPORT_SYMBOL(drm_bo_driver_init); + int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { @@ -1668,71 +1818,69 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) switch (arg.req.op) { case mm_init: - if (bm->initialized) { - DRM_ERROR("Memory manager already initialized\n"); - return -EINVAL; - } + ret = -EINVAL; + mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); - bm->has_vram = 0; - bm->has_tt = 0; - - if (arg.req.vr_p_size) { - ret = drm_mm_init(&bm->vram_manager, - arg.req.vr_p_offset, - arg.req.vr_p_size); - bm->has_vram = 1; - /* - * VRAM not supported yet. - */ - - bm->use_vram = 0; - if (ret) - break; + if (!bm->initialized) { + DRM_ERROR("DRM memory manager was not initialized.\n"); + break; } - - if (arg.req.tt_p_size) { - ret = drm_mm_init(&bm->tt_manager, - arg.req.tt_p_offset, - arg.req.tt_p_size); - bm->has_tt = 1; - bm->use_tt = 1; - - if (ret) { - if (bm->has_vram) - drm_mm_takedown(&bm->vram_manager); - break; - } + if (arg.req.mem_type == 0) { + DRM_ERROR("System memory buffers already initialized.\n"); + break; } - arg.rep.mm_sarea = 0; - - INIT_LIST_HEAD(&bm->vram_lru); - INIT_LIST_HEAD(&bm->tt_lru); - INIT_LIST_HEAD(&bm->vram_pinned); - INIT_LIST_HEAD(&bm->tt_pinned); - INIT_LIST_HEAD(&bm->unfenced); - INIT_LIST_HEAD(&bm->ddestroy); - INIT_LIST_HEAD(&bm->other); - - INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); - bm->initialized = 1; - atomic_set(&bm->count, 0); - bm->cur_pages = 0; - bm->max_pages = arg.req.max_locked_pages; - mutex_unlock(&dev->struct_mutex); + ret = drm_bo_init_mm(dev, arg.req.mem_type, + arg.req.p_offset, + arg.req.p_size); break; case mm_takedown: LOCK_TEST_WITH_RETURN(dev, filp); - if (drm_bo_clean_mm(dev)) { - DRM_ERROR("Memory manager not clean. " - "Delaying takedown\n"); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = -EINVAL; + if (!bm->initialized) { + DRM_ERROR("DRM memory manager was not initialized\n"); + break; + } + if (arg.req.mem_type == 0) { + DRM_ERROR("No takedown for System memory buffers.\n"); + break; + } + ret = 0; + if (drm_bo_clean_mm(dev, arg.req.mem_type)) { + DRM_ERROR("Memory manager type %d not clean. " + "Delaying takedown\n", arg.req.mem_type); } - DRM_DEBUG("We have %ld still locked pages\n", bm->cur_pages); break; + case mm_set_max_pages: { + struct sysinfo si; + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + if (arg.req.p_size < bm->cur_pages) { + DRM_ERROR("Cannot currently decrease max number of " + "locked pages below the number currently " + "locked.\n"); + ret = -EINVAL; + break; + } + si_meminfo(&si); + if (arg.req.p_size > si.totalram) { + DRM_ERROR("Cannot set max number of locked pages " + "to %lu since the total number of RAM pages " + "is %lu.\n", (unsigned long) arg.req.p_size, + (unsigned long) si.totalram); + ret = -EINVAL; + break; + } + bm->max_pages = arg.req.p_size; + } default: DRM_ERROR("Function not implemented yet\n"); return -EINVAL; } + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->bm.init_mutex); if (ret) return ret; -- cgit v1.2.3 From db5c671e86c3db8c99ce5a4954632248e6f849aa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:28:48 +0200 Subject: Remove the memory manager parameter from the put_block function, as this makes the client code a lot cleaner. Prepare buffer manager for lock and unlock calls. --- linux-core/drm_bo.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 20c58f21..67e90247 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -126,10 +126,10 @@ static void drm_bo_add_to_lru(drm_buffer_object_t *buf, * bo locked. */ -static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict, + int force_no_move) { drm_device_t *dev = buf->dev; - drm_buffer_manager_t *bm = &dev->bm; int ret; if (buf->node_ttm) { @@ -146,8 +146,11 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) return ret; } - drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], buf->node_ttm); - buf->node_ttm = NULL; + if (!(buf->flags & DRM_BO_FLAG_NO_MOVE) || + force_no_move) { + drm_mm_put_block(buf->node_ttm); + buf->node_ttm = NULL; + } mutex_unlock(&dev->struct_mutex); } @@ -223,13 +226,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) } if (bo->node_ttm) { - drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], - bo->node_ttm); + drm_mm_put_block(bo->node_ttm); bo->node_ttm = NULL; } if (bo->node_card) { - drm_mm_put_block(&bm->manager[DRM_BO_MEM_VRAM], - bo->node_card); + drm_mm_put_block(bo->node_card); bo->node_card = NULL; } if (bo->ttm_object) { @@ -484,7 +485,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, */ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, - int no_wait) + int no_wait, int force_no_move) { int ret = 0; drm_device_t *dev = bo->dev; @@ -509,7 +510,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, } if (mem_type == DRM_BO_MEM_TT) { - ret = drm_move_tt_to_local(bo, 1); + ret = drm_move_tt_to_local(bo, 1, force_no_move); if (ret) goto out; mutex_lock(&dev->struct_mutex); @@ -565,7 +566,8 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&bo->mutex); - ret = drm_bo_evict(bo, mem_type, no_wait); + BUG_ON(bo->flags & DRM_BO_FLAG_NO_MOVE); + ret = drm_bo_evict(bo, mem_type, no_wait, 0); mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); if (ret) @@ -596,22 +598,23 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) { drm_device_t *dev = bo->dev; - drm_buffer_manager_t *bm = &dev->bm; drm_ttm_backend_t *be; int ret; - BUG_ON(bo->node_ttm); - ret = drm_bo_alloc_space(bo, 1, no_wait); + if (!(bo->node_ttm && (bo->flags & DRM_BO_FLAG_NO_MOVE))) { + BUG_ON(bo->node_ttm); + ret = drm_bo_alloc_space(bo, DRM_BO_MEM_TT, no_wait); + if (ret) + return ret; + } - if (ret) - return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->node_ttm->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm(bo->ttm, bo->flags & DRM_BO_FLAG_BIND_CACHED, bo->node_ttm->start); if (ret) { - drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], bo->node_ttm); + drm_mm_put_block(bo->node_ttm); bo->node_ttm = NULL; } mutex_unlock(&dev->struct_mutex); @@ -824,11 +827,11 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (bo->node_card) - ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1); + ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1, 0); if (ret) return ret; if (bo->node_ttm) - ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1); + ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1, 0); return ret; } @@ -1115,7 +1118,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo, 0); + drm_move_tt_to_local(bo, 0, 1); } return 0; @@ -1625,7 +1628,7 @@ static void drm_bo_force_list_clean(drm_device_t *dev, entry->fence = NULL; } } - ret = drm_bo_evict(entry, mem_type, 0); + ret = drm_bo_evict(entry, mem_type, 0, 1); if (ret) { DRM_ERROR("Aargh. Eviction failed.\n"); } -- cgit v1.2.3 From 5443dbe35f182b9286a96d24d29037d5cb625e3d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 16:00:25 +0200 Subject: Implement mm_lock and mm_unlock functions. The mm_lock function is used when leaving vt. It evicts _all_ buffers. Buffers with the DRM_BO_NO_MOVE attribute set will be guaranteed to get the same offset when / if they are rebound. --- linux-core/drm_bo.c | 188 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 138 insertions(+), 50 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 67e90247..f671a046 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -514,8 +514,8 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, if (ret) goto out; mutex_lock(&dev->struct_mutex); - list_del(&bo->lru_ttm); - list_add_tail(&bo->lru_ttm, &bm->lru[DRM_BO_MEM_LOCAL]); + list_del_init(&bo->lru_ttm); + drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); } #if 0 @@ -658,6 +658,11 @@ static int drm_bo_new_flags(drm_device_t * dev, new_mask &= ~drm_bo_type_flags(i); } + if ((new_mask & DRM_BO_FLAG_NO_EVICT ) && !DRM_SUSER(DRM_CURPROC)) { + DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged " + "processes\n"); + return -EPERM; + } if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached[DRM_BO_MEM_TT]) && @@ -1085,7 +1090,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, */ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, - int no_wait) + int no_wait, int force_no_move) { int ret = 0; @@ -1118,7 +1123,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo, 0, 1); + drm_move_tt_to_local(bo, 0, force_no_move); } return 0; @@ -1153,8 +1158,6 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, /* * Move out if we need to change caching policy. - * FIXME: Failing is strictly not needed for NO_MOVE buffers. - * We just have to implement NO_MOVE buffers. */ if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && @@ -1164,7 +1167,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, "pinned buffer.\n"); return -EINVAL; } - ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait); + ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait, 0); if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed moving buffer.\n"); @@ -1174,12 +1177,31 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_MASK_VAL(bo->flags, DRM_BO_FLAG_BIND_CACHED, new_flags); flag_diff = (new_flags ^ bo->flags); + /* + * Check whether we dropped no_move policy, and in that case, + * release reserved manager regions. + */ + + if ((flag_diff & DRM_BO_FLAG_NO_MOVE) && + !(new_flags & DRM_BO_FLAG_NO_MOVE)) { + mutex_lock(&dev->struct_mutex); + if (bo->node_ttm) { + drm_mm_put_block(bo->node_ttm); + bo->node_ttm = NULL; + } + if (bo->node_card) { + drm_mm_put_block(bo->node_card); + bo->node_card = NULL; + } + mutex_unlock(&dev->struct_mutex); + } + /* * Check whether we need to move buffer. */ if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { - ret = drm_bo_move_buffer(bo, new_flags, no_wait); + ret = drm_bo_move_buffer(bo, new_flags, no_wait, 1); if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed moving buffer.\n"); @@ -1207,7 +1229,6 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, list_del_init(&bo->lru_card); drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); - DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } bo->flags = new_flags; @@ -1586,34 +1607,51 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) * dev->struct_sem locked. */ -static void drm_bo_force_list_clean(drm_device_t *dev, - struct list_head *head, - unsigned mem_type) +static int drm_bo_force_list_clean(drm_device_t *dev, + struct list_head *head, + unsigned mem_type, + int force_no_move, + int allow_errors) { drm_buffer_manager_t *bm = &dev->bm; - struct list_head *l; + struct list_head *list, *next, *prev; drm_buffer_object_t *entry; int ret; + int clean; - l = head->next; - while (l != head) { - entry = drm_bo_entry(l, mem_type); - + retry: + clean = 1; + list_for_each_safe(list, next, head) { + prev = list->prev; + entry = drm_bo_entry(list, mem_type); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); + mutex_lock(&dev->struct_mutex); - /* - * Expire the fence. - */ + if (prev != list->prev || next != list->next) { + mutex_unlock(&entry->mutex); + goto retry; + } + if (drm_bo_mm_node(entry, mem_type)) { + clean = 0; - if (entry->fence) { - if (bm->nice_mode) { + /* + * Expire the fence. + */ + + mutex_unlock(&dev->struct_mutex); + if (entry->fence && bm->nice_mode) { unsigned long _end = jiffies + 3*DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); + if (ret && allow_errors) { + if (ret == -EINTR) + ret = -EAGAIN; + goto out_err; + } } while (ret && !time_after_eq(jiffies, _end)); - + if (entry->fence) { bm->nice_mode = 0; DRM_ERROR("Detected GPU hang or " @@ -1621,23 +1659,47 @@ static void drm_bo_force_list_clean(drm_device_t *dev, "Evicting waiting buffers\n"); } } - if (entry->fence) { - drm_fence_usage_deref_unlocked(dev, - entry->fence); + drm_fence_usage_deref_unlocked(dev, entry->fence); entry->fence = NULL; } - } - ret = drm_bo_evict(entry, mem_type, 0, 1); - if (ret) { - DRM_ERROR("Aargh. Eviction failed.\n"); + + DRM_MASK_VAL(entry->priv_flags, _DRM_BO_FLAG_UNFENCED, 0); + + if (force_no_move) { + DRM_MASK_VAL(entry->flags, DRM_BO_FLAG_NO_MOVE, 0); + } + if (entry->flags & DRM_BO_FLAG_NO_EVICT) { + DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " + "cleanup. Removing flag and evicting.\n"); + entry->flags &= ~DRM_BO_FLAG_NO_EVICT; + entry->mask &= ~DRM_BO_FLAG_NO_EVICT; + } + + ret = drm_bo_evict(entry, mem_type, 1, force_no_move); + if (ret) { + if (allow_errors) { + goto out_err; + } else { + DRM_ERROR("Aargh. Eviction failed.\n"); + } + } + mutex_lock(&dev->struct_mutex); } mutex_unlock(&entry->mutex); - mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(dev, entry); - l = head->next; + if (prev != list->prev || next != list->next) { + goto retry; + } } + if (!clean) + goto retry; + return 0; + out_err: + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_unlocked(dev, entry); + mutex_lock(&dev->struct_mutex); + return ret; } int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) @@ -1660,8 +1722,21 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) ret = 0; if (mem_type > 0) { - drm_bo_force_list_clean(dev, &bm->lru[mem_type], 1); - drm_bo_force_list_clean(dev, &bm->pinned[mem_type], 1); + + /* + * Throw out unfenced buffers. + */ + + drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 1, 0); + + /* + * Throw out evicted no-move buffers. + */ + + drm_bo_force_list_clean(dev, &bm->pinned[DRM_BO_MEM_LOCAL], + mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 1, 0); if (drm_mm_clean(&bm->manager[mem_type])) { drm_mm_takedown(&bm->manager[mem_type]); @@ -1673,6 +1748,22 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) return ret; } +static int drm_bo_lock_mm(drm_device_t *dev, unsigned mem_type) +{ + int ret; + drm_buffer_manager_t *bm = &dev->bm; + + ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); + if (ret) + return ret; + ret = drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 0, 1); + if (ret) + return ret; + ret = drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 0, 1); + return ret; +} + + static int drm_bo_init_mm(drm_device_t *dev, unsigned type, unsigned long p_offset, @@ -1711,20 +1802,6 @@ static int drm_bo_init_mm(drm_device_t *dev, } -/* - * call dev->struct_mutex locked; - */ - -static void drm_bo_release_unfenced(drm_buffer_manager_t *bm) -{ - struct list_head *list, *next; - - list_for_each_safe(list, next, &bm->unfenced) { - list_del(list); - list_add_tail(list, &bm->lru[0]); - } -} - int drm_bo_driver_finish(drm_device_t *dev) { drm_buffer_manager_t *bm = &dev->bm; @@ -1736,7 +1813,6 @@ int drm_bo_driver_finish(drm_device_t *dev) if (!bm->initialized) goto out; - drm_bo_release_unfenced(bm); while(i--) { if (bm->has_type[i]) { @@ -1877,6 +1953,18 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } bm->max_pages = arg.req.p_size; } + case mm_lock: + LOCK_TEST_WITH_RETURN(dev, filp); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = drm_bo_lock_mm(dev, arg.req.mem_type); + break; + case mm_unlock: + LOCK_TEST_WITH_RETURN(dev, filp); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = 0; + break; default: DRM_ERROR("Function not implemented yet\n"); return -EINVAL; -- cgit v1.2.3 From d515936ea7f98f6aaa9217699796beadef9d664b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:40:57 +0200 Subject: Add memory usage accounting to avoid DOS problems. --- linux-core/drm_bo.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f671a046..fb900982 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -237,7 +237,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_ttm_object_deref_locked(dev, bo->ttm_object); } atomic_dec(&bm->count); - drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } static void drm_bo_delayed_delete(drm_device_t * dev) @@ -1390,7 +1390,7 @@ int drm_buffer_object_create(drm_file_t * priv, return -EINVAL; } - bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); + bo = drm_ctl_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); if (!bo) return -ENOMEM; @@ -1752,6 +1752,12 @@ static int drm_bo_lock_mm(drm_device_t *dev, unsigned mem_type) { int ret; drm_buffer_manager_t *bm = &dev->bm; + + if (mem_type == 0 || mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory manager memory type %u,\n", + mem_type); + return -EINVAL; + } ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); if (ret) -- cgit v1.2.3 From 89b944179856fadf8667587eff142129c2c6b826 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:57:06 +0200 Subject: Lindent. --- linux-core/drm_bo.c | 249 +++++++++++++++++++++++++++------------------------- 1 file changed, 129 insertions(+), 120 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index fb900982..e8e8a274 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -67,7 +67,7 @@ static inline uint32_t drm_bo_type_flags(unsigned type) static inline drm_buffer_object_t *drm_bo_entry(struct list_head *list, unsigned type) { - switch(type) { + switch (type) { case DRM_BO_MEM_LOCAL: case DRM_BO_MEM_TT: return list_entry(list, drm_buffer_object_t, lru_ttm); @@ -80,10 +80,10 @@ static inline drm_buffer_object_t *drm_bo_entry(struct list_head *list, return NULL; } -static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t *bo, +static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t * bo, unsigned type) { - switch(type) { + switch (type) { case DRM_BO_MEM_LOCAL: case DRM_BO_MEM_TT: return bo->node_ttm; @@ -95,29 +95,38 @@ static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t *bo, } return NULL; } - + /* * bo locked. dev->struct_mutex locked. */ -static void drm_bo_add_to_lru(drm_buffer_object_t *buf, - drm_buffer_manager_t *bm) +static void drm_bo_add_to_lru(drm_buffer_object_t * buf, + drm_buffer_manager_t * bm) { struct list_head *list; unsigned mem_type; if (buf->flags & DRM_BO_FLAG_MEM_TT) { mem_type = DRM_BO_MEM_TT; - list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list = + (buf-> + flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? + &bm->pinned[mem_type] : &bm->lru[mem_type]; list_add_tail(&buf->lru_ttm, list); } else { mem_type = DRM_BO_MEM_LOCAL; - list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list = + (buf-> + flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? + &bm->pinned[mem_type] : &bm->lru[mem_type]; list_add_tail(&buf->lru_ttm, list); } if (buf->flags & DRM_BO_FLAG_MEM_VRAM) { mem_type = DRM_BO_MEM_VRAM; - list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list = + (buf-> + flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? + &bm->pinned[mem_type] : &bm->lru[mem_type]; list_add_tail(&buf->lru_card, list); } } @@ -145,9 +154,8 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict, schedule(); return ret; } - - if (!(buf->flags & DRM_BO_FLAG_NO_MOVE) || - force_no_move) { + + if (!(buf->flags & DRM_BO_FLAG_NO_MOVE) || force_no_move) { drm_mm_put_block(buf->node_ttm); buf->node_ttm = NULL; } @@ -169,14 +177,13 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); /* * Somone might try to access us through the still active BM lists. */ - if (atomic_read(&bo->usage) != 0) + if (atomic_read(&bo->usage) != 0) return; if (!list_empty(&bo->ddestroy)) return; @@ -209,7 +216,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) /* * This temporarily unlocks struct_mutex. */ - + do { ret = drm_unbind_ttm(bo->ttm); if (ret == -EAGAIN) { @@ -224,7 +231,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) "Bad. Continuing anyway\n"); } } - + if (bo->node_ttm) { drm_mm_put_block(bo->node_ttm); bo->node_ttm = NULL; @@ -249,8 +256,8 @@ static void drm_bo_delayed_delete(drm_device_t * dev) drm_fence_object_t *fence; mutex_lock(&dev->struct_mutex); - if (!bm->initialized) - goto out; + if (!bm->initialized) + goto out; list = bm->ddestroy.next; list_for_each_safe(list, next, &bm->ddestroy) { @@ -264,7 +271,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) if (atomic_read(&entry->usage) != 0) continue; - + /* * Since we're the only users, No need to take the * bo->mutex to watch the fence. @@ -284,10 +291,10 @@ static void drm_bo_delayed_delete(drm_device_t * dev) * drm_bo_destroy_locked temporarily releases the * struct_mutex; */ - - nentry = NULL; + + nentry = NULL; if (next != &bm->ddestroy) { - nentry = list_entry(next, drm_buffer_object_t, + nentry = list_entry(next, drm_buffer_object_t, ddestroy); atomic_inc(&nentry->usage); } @@ -296,13 +303,12 @@ static void drm_bo_delayed_delete(drm_device_t * dev) drm_bo_destroy_locked(dev, entry); if (next != &bm->ddestroy) atomic_dec(&nentry->usage); - } + } } - out: + out: mutex_unlock(&dev->struct_mutex); } - static void drm_bo_delayed_workqueue(void *data) { drm_device_t *dev = (drm_device_t *) data; @@ -403,8 +409,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, } } else { mutex_unlock(&dev->struct_mutex); - ret = drm_fence_object_create(dev, fence_type, - fence_flags | DRM_FENCE_FLAG_EMIT, + ret = drm_fence_object_create(dev, fence_type, + fence_flags | DRM_FENCE_FLAG_EMIT, &fence); mutex_lock(&dev->struct_mutex); if (ret) @@ -470,9 +476,9 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_type); - if (ret) - return ret; - + if (ret) + return ret; + drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -484,7 +490,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, * bo->mutex locked */ -static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, +static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, int no_wait, int force_no_move) { int ret = 0; @@ -495,7 +501,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, * Someone might have modified the buffer before we took the buffer mutex. */ - if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) goto out; if (!(bo->flags & drm_bo_type_flags(mem_type))) goto out; @@ -531,7 +537,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - out: + out: return ret; } @@ -539,7 +545,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, * buf->mutex locked. */ -int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, +int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, int no_wait) { drm_device_t *dev = buf->dev; @@ -601,7 +607,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) drm_ttm_backend_t *be; int ret; - if (!(bo->node_ttm && (bo->flags & DRM_BO_FLAG_NO_MOVE))) { + if (!(bo->node_ttm && (bo->flags & DRM_BO_FLAG_NO_MOVE))) { BUG_ON(bo->node_ttm); ret = drm_bo_alloc_space(bo, DRM_BO_MEM_TT, no_wait); if (ret) @@ -653,18 +659,19 @@ static int drm_bo_new_flags(drm_device_t * dev, * First adjust the mask to take away nonexistant memory types. */ - for (i=0; iuse_type[i]) new_mask &= ~drm_bo_type_flags(i); } - if ((new_mask & DRM_BO_FLAG_NO_EVICT ) && !DRM_SUSER(DRM_CURPROC)) { - DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged " - "processes\n"); + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { + DRM_ERROR + ("DRM_BO_FLAG_NO_EVICT is only available to priviliged " + "processes\n"); return -EPERM; } if (new_mask & DRM_BO_FLAG_BIND_CACHED) { - if (((new_mask & DRM_BO_FLAG_MEM_TT) && + if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached[DRM_BO_MEM_TT]) && ((new_mask & DRM_BO_FLAG_MEM_VRAM) && !driver->cached[DRM_BO_MEM_VRAM])) { @@ -831,12 +838,12 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) int ret = 0; BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - if (bo->node_card) + if (bo->node_card) ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1, 0); if (ret) return ret; if (bo->node_ttm) - ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1, 0); + ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1, 0); return ret; } @@ -1155,18 +1162,18 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } - + /* * Move out if we need to change caching policy. */ - if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && + if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && !(bo->flags & DRM_BO_FLAG_MEM_LOCAL)) { if (bo->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { DRM_ERROR("Cannot change caching policy of " "pinned buffer.\n"); return -EINVAL; - } + } ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait, 0); if (ret) { if (ret != -EAGAIN) @@ -1182,7 +1189,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * release reserved manager regions. */ - if ((flag_diff & DRM_BO_FLAG_NO_MOVE) && + if ((flag_diff & DRM_BO_FLAG_NO_MOVE) && !(new_flags & DRM_BO_FLAG_NO_MOVE)) { mutex_lock(&dev->struct_mutex); if (bo->node_ttm) { @@ -1434,10 +1441,10 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(dev, bo); + drm_bo_usage_deref_unlocked(dev, bo); return ret; } @@ -1607,11 +1614,10 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) * dev->struct_sem locked. */ -static int drm_bo_force_list_clean(drm_device_t *dev, - struct list_head *head, +static int drm_bo_force_list_clean(drm_device_t * dev, + struct list_head *head, unsigned mem_type, - int force_no_move, - int allow_errors) + int force_no_move, int allow_errors) { drm_buffer_manager_t *bm = &dev->bm; struct list_head *list, *next, *prev; @@ -1619,11 +1625,11 @@ static int drm_bo_force_list_clean(drm_device_t *dev, int ret; int clean; - retry: + retry: clean = 1; list_for_each_safe(list, next, head) { prev = list->prev; - entry = drm_bo_entry(list, mem_type); + entry = drm_bo_entry(list, mem_type); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); @@ -1639,10 +1645,10 @@ static int drm_bo_force_list_clean(drm_device_t *dev, /* * Expire the fence. */ - + mutex_unlock(&dev->struct_mutex); if (entry->fence && bm->nice_mode) { - unsigned long _end = jiffies + 3*DRM_HZ; + unsigned long _end = jiffies + 3 * DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); if (ret && allow_errors) { @@ -1651,7 +1657,7 @@ static int drm_bo_force_list_clean(drm_device_t *dev, goto out_err; } } while (ret && !time_after_eq(jiffies, _end)); - + if (entry->fence) { bm->nice_mode = 0; DRM_ERROR("Detected GPU hang or " @@ -1660,14 +1666,17 @@ static int drm_bo_force_list_clean(drm_device_t *dev, } } if (entry->fence) { - drm_fence_usage_deref_unlocked(dev, entry->fence); + drm_fence_usage_deref_unlocked(dev, + entry->fence); entry->fence = NULL; } - DRM_MASK_VAL(entry->priv_flags, _DRM_BO_FLAG_UNFENCED, 0); + DRM_MASK_VAL(entry->priv_flags, _DRM_BO_FLAG_UNFENCED, + 0); if (force_no_move) { - DRM_MASK_VAL(entry->flags, DRM_BO_FLAG_NO_MOVE, 0); + DRM_MASK_VAL(entry->flags, DRM_BO_FLAG_NO_MOVE, + 0); } if (entry->flags & DRM_BO_FLAG_NO_EVICT) { DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " @@ -1690,12 +1699,12 @@ static int drm_bo_force_list_clean(drm_device_t *dev, drm_bo_usage_deref_locked(dev, entry); if (prev != list->prev || next != list->next) { goto retry; - } + } } if (!clean) goto retry; return 0; - out_err: + out_err: mutex_unlock(&entry->mutex); drm_bo_usage_deref_unlocked(dev, entry); mutex_lock(&dev->struct_mutex); @@ -1715,7 +1724,7 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) if (!bm->has_type[mem_type]) { DRM_ERROR("Trying to take down uninitialized " "memory manager type\n"); - return ret; + return ret; } bm->use_type[mem_type] = 0; bm->has_type[mem_type] = 0; @@ -1733,10 +1742,12 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) * Throw out evicted no-move buffers. */ - drm_bo_force_list_clean(dev, &bm->pinned[DRM_BO_MEM_LOCAL], + drm_bo_force_list_clean(dev, &bm->pinned[DRM_BO_MEM_LOCAL], mem_type, 1, 0); - drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 1, 0); - drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 1, + 0); + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 1, + 0); if (drm_mm_clean(&bm->manager[mem_type])) { drm_mm_takedown(&bm->manager[mem_type]); @@ -1748,32 +1759,30 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) return ret; } -static int drm_bo_lock_mm(drm_device_t *dev, unsigned mem_type) +static int drm_bo_lock_mm(drm_device_t * dev, unsigned mem_type) { int ret; drm_buffer_manager_t *bm = &dev->bm; if (mem_type == 0 || mem_type >= DRM_BO_MEM_TYPES) { - DRM_ERROR("Illegal memory manager memory type %u,\n", - mem_type); + DRM_ERROR("Illegal memory manager memory type %u,\n", mem_type); return -EINVAL; } - - ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); - if (ret) + + ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); + if (ret) return ret; - ret = drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 0, 1); + ret = drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 0, 1); if (ret) return ret; - ret = drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 0, 1); + ret = + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 0, 1); return ret; } - -static int drm_bo_init_mm(drm_device_t *dev, +static int drm_bo_init_mm(drm_device_t * dev, unsigned type, - unsigned long p_offset, - unsigned long p_size) + unsigned long p_offset, unsigned long p_size) { drm_buffer_manager_t *bm = &dev->bm; int ret = -EINVAL; @@ -1794,7 +1803,7 @@ static int drm_bo_init_mm(drm_device_t *dev, DRM_ERROR("Zero size memory manager type %d\n", type); return ret; } - ret = drm_mm_init(&bm->manager[type],p_offset, p_size); + ret = drm_mm_init(&bm->manager[type], p_offset, p_size); if (ret) return ret; } @@ -1807,8 +1816,7 @@ static int drm_bo_init_mm(drm_device_t *dev, return 0; } - -int drm_bo_driver_finish(drm_device_t *dev) +int drm_bo_driver_finish(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; int ret = 0; @@ -1817,10 +1825,10 @@ int drm_bo_driver_finish(drm_device_t *dev) mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); - if (!bm->initialized) + if (!bm->initialized) goto out; - while(i--) { + while (i--) { if (bm->has_type[i]) { bm->use_type[i] = 0; if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) { @@ -1840,25 +1848,24 @@ int drm_bo_driver_finish(drm_device_t *dev) flush_scheduled_work(); } mutex_lock(&dev->struct_mutex); - out: + out: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->bm.init_mutex); return ret; } - -int drm_bo_driver_init(drm_device_t *dev) +int drm_bo_driver_init(drm_device_t * dev) { drm_bo_driver_t *driver = dev->driver->bo_driver; drm_buffer_manager_t *bm = &dev->bm; int ret = -EINVAL; struct sysinfo si; - + mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); if (!driver) goto out_unlock; - + /* * Initialize the system memory buffer type. * Other types need to be driver / IOCTL initialized. @@ -1876,14 +1883,14 @@ int drm_bo_driver_init(drm_device_t *dev) si_meminfo(&si); bm->max_pages = si.totalram >> 1; INIT_LIST_HEAD(&bm->unfenced); - INIT_LIST_HEAD(&bm->ddestroy); - out_unlock: + INIT_LIST_HEAD(&bm->ddestroy); + out_unlock: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->bm.init_mutex); return ret; } -EXPORT_SYMBOL(drm_bo_driver_init); +EXPORT_SYMBOL(drm_bo_driver_init); int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { @@ -1911,15 +1918,15 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) break; } if (arg.req.mem_type == 0) { - DRM_ERROR("System memory buffers already initialized.\n"); + DRM_ERROR + ("System memory buffers already initialized.\n"); break; } - ret = drm_bo_init_mm(dev, arg.req.mem_type, - arg.req.p_offset, - arg.req.p_size); + ret = drm_bo_init_mm(dev, arg.req.mem_type, + arg.req.p_offset, arg.req.p_size); break; case mm_takedown: - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); ret = -EINVAL; @@ -1937,36 +1944,38 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) "Delaying takedown\n", arg.req.mem_type); } break; - case mm_set_max_pages: { - struct sysinfo si; - mutex_lock(&dev->bm.init_mutex); - mutex_lock(&dev->struct_mutex); - if (arg.req.p_size < bm->cur_pages) { - DRM_ERROR("Cannot currently decrease max number of " - "locked pages below the number currently " - "locked.\n"); - ret = -EINVAL; - break; - } - si_meminfo(&si); - if (arg.req.p_size > si.totalram) { - DRM_ERROR("Cannot set max number of locked pages " - "to %lu since the total number of RAM pages " - "is %lu.\n", (unsigned long) arg.req.p_size, - (unsigned long) si.totalram); - ret = -EINVAL; - break; + case mm_set_max_pages:{ + struct sysinfo si; + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + if (arg.req.p_size < bm->cur_pages) { + DRM_ERROR + ("Cannot currently decrease max number of " + "locked pages below the number currently " + "locked.\n"); + ret = -EINVAL; + break; + } + si_meminfo(&si); + if (arg.req.p_size > si.totalram) { + DRM_ERROR + ("Cannot set max number of locked pages " + "to %lu since the total number of RAM pages " + "is %lu.\n", (unsigned long)arg.req.p_size, + (unsigned long)si.totalram); + ret = -EINVAL; + break; + } + bm->max_pages = arg.req.p_size; } - bm->max_pages = arg.req.p_size; - } case mm_lock: - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); ret = drm_bo_lock_mm(dev, arg.req.mem_type); break; case mm_unlock: - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); ret = 0; -- cgit v1.2.3 From c34faf224b959bf61e4c3eb29c66a12edbd31841 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 20:03:26 +0200 Subject: Remove max number of locked pages check and call, since that is now handled by the memory accounting. --- linux-core/drm_bo.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'linux-core/drm_bo.c') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e8e8a274..b8ee6c15 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1859,7 +1859,6 @@ int drm_bo_driver_init(drm_device_t * dev) drm_bo_driver_t *driver = dev->driver->bo_driver; drm_buffer_manager_t *bm = &dev->bm; int ret = -EINVAL; - struct sysinfo si; mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); @@ -1880,8 +1879,6 @@ int drm_bo_driver_init(drm_device_t * dev) bm->nice_mode = 1; atomic_set(&bm->count, 0); bm->cur_pages = 0; - si_meminfo(&si); - bm->max_pages = si.totalram >> 1; INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); out_unlock: @@ -1944,30 +1941,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) "Delaying takedown\n", arg.req.mem_type); } break; - case mm_set_max_pages:{ - struct sysinfo si; - mutex_lock(&dev->bm.init_mutex); - mutex_lock(&dev->struct_mutex); - if (arg.req.p_size < bm->cur_pages) { - DRM_ERROR - ("Cannot currently decrease max number of " - "locked pages below the number currently " - "locked.\n"); - ret = -EINVAL; - break; - } - si_meminfo(&si); - if (arg.req.p_size > si.totalram) { - DRM_ERROR - ("Cannot set max number of locked pages " - "to %lu since the total number of RAM pages " - "is %lu.\n", (unsigned long)arg.req.p_size, - (unsigned long)si.totalram); - ret = -EINVAL; - break; - } - bm->max_pages = arg.req.p_size; - } case mm_lock: LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); -- cgit v1.2.3