From af24465b2eddfcc5296edc830ea5ed86065a4abd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 7 Feb 2007 12:52:23 +0100 Subject: Fix a stray unlock_kernel() in drm_vm.c Add a file for memory move helpers, drm_bo_move.c Implement generic memory move. Cached, no_move and unmapped memory temporarily broken. --- linux-core/Makefile.kernel | 2 +- linux-core/drmP.h | 34 +++-- linux-core/drm_bo.c | 353 +++++++++++++++++++++------------------------ linux-core/drm_bo_move.c | 75 ++++++++++ linux-core/drm_vm.c | 2 +- linux-core/i915_drv.c | 1 + 6 files changed, 264 insertions(+), 203 deletions(-) create mode 100644 linux-core/drm_bo_move.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b531a70f..a6910d73 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,7 +13,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ - drm_fence.o drm_ttm.o drm_bo.o + drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 62efddd9..cdab1cb1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -669,6 +669,16 @@ typedef struct drm_mem_type_manager { void *io_addr; } drm_mem_type_manager_t; +typedef struct drm_bo_mem_reg { + drm_mm_node_t *mm_node; + unsigned long size; + unsigned long num_pages; + uint32_t page_alignment; + uint32_t mem_type; + uint32_t flags; + uint32_t mask; +} drm_bo_mem_reg_t; + /* * buffer object driver */ @@ -685,6 +695,10 @@ typedef struct drm_bo_driver{ int (*init_mem_type)(struct drm_device *dev, uint32_t type, drm_mem_type_manager_t *man); uint32_t (*evict_flags) (struct drm_device *dev, uint32_t type); + int (*move)(struct drm_device *dev, + struct drm_ttm *ttm, int evict, int no_wait, + struct drm_bo_mem_reg *old_mem, + struct drm_bo_mem_reg *new_mem); } drm_bo_driver_t; @@ -999,16 +1013,6 @@ typedef struct drm_fence_object{ uint32_t submitted_flush; } drm_fence_object_t; -typedef struct drm_bo_mem_reg { - drm_mm_node_t *mm_node; - unsigned long size; - unsigned long num_pages; - uint32_t page_alignment; - uint32_t mem_type; - uint32_t flags; - uint32_t mask; -} drm_bo_mem_reg_t; - typedef struct drm_buffer_object{ drm_device_t *dev; @@ -1506,6 +1510,16 @@ extern int drm_fence_buffer_objects(drm_file_t * priv, uint32_t fence_flags, drm_fence_object_t *fence, drm_fence_object_t **used_fence); +/* + * Buffer object memory move helpers. + * drm_bo_move.c + */ + +extern int drm_bo_move_ttm(drm_device_t *dev, + drm_ttm_t *ttm, int evict, + int no_wait, + drm_bo_mem_reg_t *old_mem, + drm_bo_mem_reg_t *new_mem); extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev); extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 16c89f61..3f1e891d 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -78,22 +78,6 @@ static void drm_bo_add_to_lru(drm_buffer_object_t * bo, struct list_head *list; drm_mem_type_manager_t *man; - bo->mem.mem_type = 0; - - switch(bo->mem.flags & DRM_BO_MASK_MEM) { - case DRM_BO_FLAG_MEM_TT: - bo->mem.mem_type = DRM_BO_MEM_TT; - break; - case DRM_BO_FLAG_MEM_VRAM: - bo->mem.mem_type = DRM_BO_MEM_VRAM; - break; - case DRM_BO_FLAG_MEM_LOCAL: - bo->mem.mem_type = DRM_BO_MEM_LOCAL; - break; - default: - BUG_ON(1); - } - man = &bm->man[bo->mem.mem_type]; list = (bo->mem.flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &man->pinned : &man->lru; @@ -101,53 +85,136 @@ static void drm_bo_add_to_lru(drm_buffer_object_t * bo, return; } +static int drm_bo_vm_pre_move(drm_buffer_object_t *bo, + int old_is_pci) +{ +#ifdef DRM_ODD_MM_COMPAT + int ret; + + ret = drm_bo_lock_kmm(bo); + if (ret) { + if (ret == -EAGAIN) + schedule(); + return ret; + } + drm_bo_unmap_virtual(bo); + if (old_is_pci) + drm_bo_finish_unmap(bo); +#else + drm_bo_unmap_virtual(bo); +#endif + return 0; +} + +static void drm_bo_vm_post_move(drm_buffer_object_t *bo) +{ +#ifdef DRM_ODD_MM_COMPAT + int ret; + + ret = drm_bo_remap_bound(bo); + if (ret) { + DRM_ERROR("Failed to remap a bound buffer object.\n" + "\tThis might cause a sigbus later.\n"); + } + drm_bo_unlock_kmm(bo); +#endif +} + /* - * bo locked. + * Call bo->mutex locked. */ -static int drm_move_tt_to_local(drm_buffer_object_t * bo, int evict, - int force_no_move) +static int drm_bo_add_ttm(drm_buffer_object_t * bo) { drm_device_t *dev = bo->dev; int ret = 0; - if (bo->mem.mm_node) { -#ifdef DRM_ODD_MM_COMPAT - mutex_lock(&dev->struct_mutex); - ret = drm_bo_lock_kmm(bo); - if (ret) { - mutex_unlock(&dev->struct_mutex); - if (ret == -EAGAIN) - schedule(); - return ret; - } - drm_bo_unmap_virtual(bo); - drm_bo_finish_unmap(bo); - drm_bo_unlock_kmm(bo); -#else - drm_bo_unmap_virtual(bo); - mutex_lock(&dev->struct_mutex); + bo->ttm = NULL; + + switch (bo->type) { + case drm_bo_type_dc: + bo->ttm = drm_ttm_init(dev, bo->mem.num_pages << PAGE_SHIFT); + if (!bo->ttm) + ret = -ENOMEM; + break; + case drm_bo_type_user: + case drm_bo_type_fake: + break; + default: + DRM_ERROR("Illegal buffer object type\n"); + ret = -EINVAL; + break; + } + + return ret; +} + + +static int drm_bo_handle_move_mem(drm_buffer_object_t *bo, + drm_bo_mem_reg_t *mem, + int evict, + int no_wait) +{ + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + int old_is_pci = drm_mem_reg_is_pci(dev, &bo->mem); + int new_is_pci = drm_mem_reg_is_pci(dev, mem); + drm_mem_type_manager_t *old_man = &bm->man[bo->mem.mem_type]; + drm_mem_type_manager_t *new_man = &bm->man[mem->mem_type]; + int ret = 0; + + + if (old_is_pci || new_is_pci) + ret = drm_bo_vm_pre_move(bo, old_is_pci); + if (ret) + return ret; + + if ((!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) || + !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED)) && + (bo->ttm == NULL)) + ret = drm_bo_add_ttm(bo); + if (ret) + return ret; + + if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && + !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED)) { + ret = drm_bo_move_ttm(dev, bo->ttm, evict, no_wait, + &bo->mem, mem); + } else if (dev->driver->bo_driver->move) { + ret = dev->driver->bo_driver->move(dev, bo->ttm, evict, + no_wait, &bo->mem, mem); + } else { + ret = -EINVAL; + DRM_ERROR("Unsupported function\n"); +#if 0 + ret = drm_bo_move_memcpy(dev, bo->ttm, evict, no_wait, + &bo->mem, mem); + ret = 0; #endif - if (evict) - drm_ttm_evict(bo->ttm); - else - drm_ttm_unbind(bo->ttm); + } - bo->mem.mem_type = DRM_BO_MEM_LOCAL; - if (!(bo->mem.flags & DRM_BO_FLAG_NO_MOVE) || force_no_move) { - drm_mm_put_block(bo->mem.mm_node); - bo->mem.mm_node = NULL; - } - mutex_unlock(&dev->struct_mutex); + if (old_is_pci || new_is_pci) + drm_bo_vm_post_move(bo); + + if (ret) + return ret; + + if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + ret = dev->driver->bo_driver->invalidate_caches(dev, bo->mem.flags); + if (ret) + DRM_ERROR("Can not flush read caches\n"); } + + DRM_FLAG_MASKED(bo->priv_flags, + (evict) ? _DRM_BO_FLAG_EVICTED : 0, + _DRM_BO_FLAG_EVICTED); - bo->mem.flags &= ~DRM_BO_FLAG_MEM_TT; - bo->mem.flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + if (bo->mem.mm_node) + bo->offset = bo->mem.mm_node->start << PAGE_SHIFT; return 0; } - /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -503,12 +570,11 @@ 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) goto out; - if (!(bo->mem.flags & drm_bo_type_flags(mem_type))) - goto out; + if (bo->mem.mem_type != mem_type) ret = drm_bo_wait(bo, 0, 0, no_wait); @@ -520,36 +586,36 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, evict_mem = bo->mem; evict_mem.mask = dev->driver->bo_driver->evict_flags(dev, mem_type); - ret = drm_bo_mem_space(dev, &evict_mem, no_wait); - if (ret && ret != -EAGAIN) { - DRM_ERROR("Failed to find memory space for " - "buffer eviction.\n"); + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed to find memory space for " + "buffer eviction.\n"); goto out; } - if ((mem_type != DRM_BO_MEM_TT) && - (evict_mem.mem_type != DRM_BO_MEM_LOCAL)) { - ret = -EINVAL; - DRM_ERROR("Unsupported memory types for eviction.\n"); + ret = drm_bo_handle_move_mem(bo, &evict_mem, 1, no_wait); + + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Buffer eviction failed\n"); goto out; } - - ret = drm_move_tt_to_local(bo, 1, force_no_move); - if (ret) - goto out; + mutex_lock(&dev->struct_mutex); - list_del_init(&bo->lru); + if (evict_mem.mm_node) { + drm_mm_put_block(evict_mem.mm_node); + evict_mem.mm_node = NULL; + } + list_del(&bo->lru); drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); - if (ret) - goto out; - DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - out: + +out: return ret; } @@ -682,74 +748,6 @@ static int drm_bo_mem_space(drm_device_t *dev, return ret; } - - - -static int drm_move_local_to_tt(drm_buffer_object_t * bo, - drm_bo_mem_reg_t * mem, - int no_wait) -{ - drm_device_t *dev = bo->dev; - int ret = 0; - - bo->mem.mm_node = mem->mm_node; - - DRM_DEBUG("Flipping in to AGP 0x%08lx 0x%08lx\n", - bo->mem.mm_node->start, bo->mem.mm_node->size); - -#ifdef DRM_ODD_MM_COMPAT - mutex_lock(&dev->struct_mutex); - ret = drm_bo_lock_kmm(bo); - if (ret) { - mutex_unlock(&dev->struct_mutex); - goto out_put_unlock; - } -#endif - drm_bo_unmap_virtual(bo); - ret = drm_bind_ttm(bo->ttm, bo->mem.flags & DRM_BO_FLAG_BIND_CACHED, - bo->mem.mm_node->start); - - if (ret) { -#ifdef DRM_ODD_MM_COMPAT - drm_bo_unlock_kmm(bo); - mutex_unlock(&dev->struct_mutex); -#endif - goto out_put_unlock; - } - - if (!(bo->mem.flags & DRM_BO_FLAG_BIND_CACHED)) - bo->mem.flags &= ~DRM_BO_FLAG_CACHED; - bo->mem.flags &= ~DRM_BO_MASK_MEM; - bo->mem.flags |= DRM_BO_FLAG_MEM_TT; - bo->mem.mem_type = DRM_BO_MEM_TT; - bo->offset = bo->mem.mm_node->start << PAGE_SHIFT; - -#ifdef DRM_ODD_MM_COMPAT - ret = drm_bo_remap_bound(bo); - if (ret) { - /* FIXME */ - } - drm_bo_unlock_kmm(bo); - mutex_unlock(&dev->struct_mutex); -#endif - - if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { - ret = dev->driver->bo_driver->invalidate_caches(dev, bo->mem.flags); - if (ret) - DRM_ERROR("Could not flush read caches\n"); - } - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); - - return 0; - -out_put_unlock: - mutex_lock(&dev->struct_mutex); - drm_mm_put_block(bo->mem.mm_node); - bo->mem.mm_node = NULL; - mutex_unlock(&dev->struct_mutex); - return ret; -} - 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) @@ -1249,19 +1247,21 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags, if (ret) return ret; - if (mem.mem_type == DRM_BO_MEM_TT) { - ret = drm_move_local_to_tt(bo, &mem, no_wait); - if (ret) { - mutex_lock(&dev->struct_mutex); - list_del_init(&bo->lru); - drm_bo_add_to_lru(bo, bm); - mutex_unlock(&dev->struct_mutex); - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); - return ret; + ret = drm_bo_handle_move_mem(bo, &mem, 0, no_wait); + + if (ret) { + mutex_lock(&dev->struct_mutex); + if (mem.mm_node) { + drm_mm_put_block(mem.mm_node); + mem.mm_node = NULL; } - } else { - drm_move_tt_to_local(bo, 0, force_no_move); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + list_del_init(&bo->lru); + drm_bo_add_to_lru(bo, bm); + mutex_unlock(&dev->struct_mutex); + return ret; } + return 0; } @@ -1280,11 +1280,6 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, int ret; - if (new_flags & DRM_BO_FLAG_MEM_VRAM) { - DRM_ERROR("Vram support not implemented yet\n"); - return -EINVAL; - } - DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->mem.flags); ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_type); if (ret) { @@ -1341,6 +1336,13 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, } } + + if (bo->mem.mem_type == DRM_BO_MEM_LOCAL && bo->ttm == NULL) { + ret = drm_bo_add_ttm(bo); + if (ret) + return ret; + } + if (move_unfenced) { /* @@ -1453,41 +1455,6 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, return ret; } -/* - * Call bo->mutex locked. - */ - -static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo) -{ - drm_device_t *dev = bo->dev; - int ret = 0; - - bo->ttm = NULL; - bo->map_list.user_token = 0ULL; - - switch (bo->type) { - case drm_bo_type_dc: - mutex_lock(&dev->struct_mutex); - ret = drm_bo_setup_vm_locked(bo); - mutex_unlock(&dev->struct_mutex); - if (ret) - break; - bo->ttm = drm_ttm_init(dev, bo->mem.num_pages << PAGE_SHIFT); - if (!bo->ttm) - ret = -ENOMEM; - break; - case drm_bo_type_user: - case drm_bo_type_fake: - break; - default: - DRM_ERROR("Illegal buffer object type\n"); - ret = -EINVAL; - break; - } - - return ret; -} - /* * Transfer a buffer object's memory and LRU status to a newly * created object. User-space references remains with the old @@ -1591,10 +1558,14 @@ int drm_buffer_object_create(drm_file_t * priv, 1, &new_flags, &bo->mem.mask); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo); - if (ret) - goto out_err; - + + if (bo->type == drm_bo_type_dc) { + mutex_lock(&dev->struct_mutex); + ret = drm_bo_setup_vm_locked(bo); + mutex_unlock(&dev->struct_mutex); + if (ret) + goto out_err; + } ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); if (ret) diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c new file mode 100644 index 00000000..abfa8f80 --- /dev/null +++ b/linux-core/drm_bo_move.c @@ -0,0 +1,75 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, TX., 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 above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * 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. + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" + +int drm_bo_move_ttm(drm_device_t *dev, + drm_ttm_t *ttm, + int evict, + int no_wait, + drm_bo_mem_reg_t *old_mem, + drm_bo_mem_reg_t *new_mem) +{ + uint32_t save_flags = old_mem->flags; + uint32_t save_mask = old_mem->mask; + int ret; + + if (old_mem->mem_type == DRM_BO_MEM_TT) { + + if (evict) + drm_ttm_evict(ttm); + else + drm_ttm_unbind(ttm); + + mutex_lock(&dev->struct_mutex); + drm_mm_put_block(old_mem->mm_node); + mutex_unlock(&dev->struct_mutex); + save_flags |= DRM_BO_FLAG_CACHED; + + } else { + + ret = drm_bind_ttm(ttm, + new_mem->flags & DRM_BO_FLAG_BIND_CACHED, + new_mem->mm_node->start); + if (ret) + return ret; + + if (!(new_mem->flags & DRM_BO_FLAG_BIND_CACHED)) { + save_flags &= ~DRM_BO_FLAG_CACHED; + } + + } + + *old_mem = *new_mem; + new_mem->mm_node = NULL; + old_mem->mask = save_mask; + DRM_MASK_VAL(save_flags, new_mem->flags, DRM_BO_MASK_MEM); + return 0; +} diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 843fc362..416ac4ae 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -513,7 +513,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) /* Length must match exact page count */ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { - unlock_kernel(); return -EINVAL; } @@ -588,6 +587,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) * the AGP mapped at physical address 0 * --BenH. */ + if (!vma->vm_pgoff #if __OS_HAS_AGP && (!dev->agp diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 8c39c249..19b63b7f 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -64,6 +64,7 @@ static drm_bo_driver_t i915_bo_driver = { .invalidate_caches = i915_invalidate_caches, .init_mem_type = i915_init_mem_type, .evict_flags = i915_evict_flags, + .move = NULL, }; #endif -- cgit v1.2.3