diff options
Diffstat (limited to 'linux-core/drm_bo_move.c')
-rw-r--r-- | linux-core/drm_bo_move.c | 614 |
1 files changed, 0 insertions, 614 deletions
diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c deleted file mode 100644 index d794e985..00000000 --- a/linux-core/drm_bo_move.c +++ /dev/null @@ -1,614 +0,0 @@ -/************************************************************************** - * - * Copyright (c) 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 <thomas-at-tungstengraphics-dot-com> - */ - -#include "drmP.h" - -/** - * Free the old memory node unless it's a pinned region and we - * have not been requested to free also pinned regions. - */ - -static void drm_bo_free_old_node(struct drm_buffer_object *bo) -{ - struct drm_bo_mem_reg *old_mem = &bo->mem; - - if (old_mem->mm_node && (old_mem->mm_node != bo->pinned_node)) { - mutex_lock(&bo->dev->struct_mutex); - drm_mm_put_block(old_mem->mm_node); - mutex_unlock(&bo->dev->struct_mutex); - } - old_mem->mm_node = NULL; -} - -int drm_bo_move_ttm(struct drm_buffer_object *bo, - int evict, int no_wait, struct drm_bo_mem_reg *new_mem) -{ - struct drm_ttm *ttm = bo->ttm; - struct drm_bo_mem_reg *old_mem = &bo->mem; - uint64_t save_flags = old_mem->flags; - uint64_t save_proposed_flags = old_mem->proposed_flags; - int ret; - - if (old_mem->mem_type != DRM_BO_MEM_LOCAL) { - if (evict) - drm_ttm_evict(ttm); - else - drm_ttm_unbind(ttm); - - drm_bo_free_old_node(bo); - DRM_FLAG_MASKED(old_mem->flags, - DRM_BO_FLAG_CACHED | DRM_BO_FLAG_MAPPABLE | - DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEMTYPE); - old_mem->mem_type = DRM_BO_MEM_LOCAL; - save_flags = old_mem->flags; - } - if (new_mem->mem_type != DRM_BO_MEM_LOCAL) { - ret = drm_ttm_bind(ttm, new_mem); - if (ret) - return ret; - } - - *old_mem = *new_mem; - new_mem->mm_node = NULL; - old_mem->proposed_flags = save_proposed_flags; - DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); - return 0; -} -EXPORT_SYMBOL(drm_bo_move_ttm); - -/** - * \c Return a kernel virtual address to the buffer object PCI memory. - * - * \param bo The buffer object. - * \return Failure indication. - * - * Returns -EINVAL if the buffer object is currently not mappable. - * Returns -ENOMEM if the ioremap operation failed. - * Otherwise returns zero. - * - * After a successfull call, bo->iomap contains the virtual address, or NULL - * if the buffer object content is not accessible through PCI space. - * Call bo->mutex locked. - */ - -int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg *mem, - void **virtual) -{ - struct drm_buffer_manager *bm = &dev->bm; - struct drm_mem_type_manager *man = &bm->man[mem->mem_type]; - unsigned long bus_offset; - unsigned long bus_size; - unsigned long bus_base; - int ret; - void *addr; - - *virtual = NULL; - ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, &bus_size); - if (ret || bus_size == 0) - return ret; - - if (!(man->flags & _DRM_FLAG_NEEDS_IOREMAP)) - addr = (void *)(((u8 *) man->io_addr) + bus_offset); - else { - addr = ioremap_nocache(bus_base + bus_offset, bus_size); - if (!addr) - return -ENOMEM; - } - *virtual = addr; - return 0; -} -EXPORT_SYMBOL(drm_mem_reg_ioremap); - -/** - * \c Unmap mapping obtained using drm_bo_ioremap - * - * \param bo The buffer object. - * - * Call bo->mutex locked. - */ - -void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg *mem, - void *virtual) -{ - struct drm_buffer_manager *bm; - struct drm_mem_type_manager *man; - - bm = &dev->bm; - man = &bm->man[mem->mem_type]; - - if (virtual && (man->flags & _DRM_FLAG_NEEDS_IOREMAP)) - iounmap(virtual); -} - -static int drm_copy_io_page(void *dst, void *src, unsigned long page) -{ - uint32_t *dstP = - (uint32_t *) ((unsigned long)dst + (page << PAGE_SHIFT)); - uint32_t *srcP = - (uint32_t *) ((unsigned long)src + (page << PAGE_SHIFT)); - - int i; - for (i = 0; i < PAGE_SIZE / sizeof(uint32_t); ++i) - iowrite32(ioread32(srcP++), dstP++); - return 0; -} - -static int drm_copy_io_ttm_page(struct drm_ttm *ttm, void *src, - unsigned long page) -{ - struct page *d = drm_ttm_get_page(ttm, page); - void *dst; - - if (!d) - return -ENOMEM; - - src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); - dst = kmap(d); - if (!dst) - return -ENOMEM; - - memcpy_fromio(dst, src, PAGE_SIZE); - kunmap(d); - return 0; -} - -static int drm_copy_ttm_io_page(struct drm_ttm *ttm, void *dst, unsigned long page) -{ - struct page *s = drm_ttm_get_page(ttm, page); - void *src; - - if (!s) - return -ENOMEM; - - dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); - src = kmap(s); - if (!src) - return -ENOMEM; - - memcpy_toio(dst, src, PAGE_SIZE); - kunmap(s); - return 0; -} - -int drm_bo_move_memcpy(struct drm_buffer_object *bo, - int evict, int no_wait, struct drm_bo_mem_reg *new_mem) -{ - struct drm_device *dev = bo->dev; - struct drm_mem_type_manager *man = &dev->bm.man[new_mem->mem_type]; - struct drm_ttm *ttm = bo->ttm; - struct drm_bo_mem_reg *old_mem = &bo->mem; - struct drm_bo_mem_reg old_copy = *old_mem; - void *old_iomap; - void *new_iomap; - int ret; - uint64_t save_flags = old_mem->flags; - uint64_t save_proposed_flags = old_mem->proposed_flags; - unsigned long i; - unsigned long page; - unsigned long add = 0; - int dir; - - ret = drm_mem_reg_ioremap(dev, old_mem, &old_iomap); - if (ret) - return ret; - ret = drm_mem_reg_ioremap(dev, new_mem, &new_iomap); - if (ret) - goto out; - - if (old_iomap == NULL && new_iomap == NULL) - goto out2; - if (old_iomap == NULL && ttm == NULL) - goto out2; - - add = 0; - dir = 1; - - if ((old_mem->mem_type == new_mem->mem_type) && - (new_mem->mm_node->start < - old_mem->mm_node->start + old_mem->mm_node->size)) { - dir = -1; - add = new_mem->num_pages - 1; - } - - for (i = 0; i < new_mem->num_pages; ++i) { - page = i * dir + add; - if (old_iomap == NULL) - ret = drm_copy_ttm_io_page(ttm, new_iomap, page); - else if (new_iomap == NULL) - ret = drm_copy_io_ttm_page(ttm, old_iomap, page); - else - ret = drm_copy_io_page(new_iomap, old_iomap, page); - if (ret) - goto out1; - } - mb(); -out2: - drm_bo_free_old_node(bo); - - *old_mem = *new_mem; - new_mem->mm_node = NULL; - old_mem->proposed_flags = save_proposed_flags; - DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); - - if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (ttm != NULL)) { - drm_ttm_unbind(ttm); - drm_ttm_destroy(ttm); - bo->ttm = NULL; - } - -out1: - drm_mem_reg_iounmap(dev, new_mem, new_iomap); -out: - drm_mem_reg_iounmap(dev, &old_copy, old_iomap); - return ret; -} -EXPORT_SYMBOL(drm_bo_move_memcpy); - -/* - * Transfer a buffer object's memory and LRU status to a newly - * created object. User-space references remains with the old - * object. Call bo->mutex locked. - */ - -int drm_buffer_object_transfer(struct drm_buffer_object *bo, - struct drm_buffer_object **new_obj) -{ - struct drm_buffer_object *fbo; - struct drm_device *dev = bo->dev; - struct drm_buffer_manager *bm = &dev->bm; - - fbo = drm_ctl_calloc(1, sizeof(*fbo), DRM_MEM_BUFOBJ); - if (!fbo) - return -ENOMEM; - - *fbo = *bo; - mutex_init(&fbo->mutex); - mutex_lock(&fbo->mutex); - mutex_lock(&dev->struct_mutex); - - DRM_INIT_WAITQUEUE(&bo->event_queue); - INIT_LIST_HEAD(&fbo->ddestroy); - INIT_LIST_HEAD(&fbo->lru); - INIT_LIST_HEAD(&fbo->pinned_lru); - - fbo->fence = drm_fence_reference_locked(bo->fence); - fbo->pinned_node = NULL; - fbo->mem.mm_node->private = (void *)fbo; - atomic_set(&fbo->usage, 1); - atomic_inc(&bm->count); - mutex_unlock(&dev->struct_mutex); - mutex_unlock(&fbo->mutex); - - *new_obj = fbo; - return 0; -} - -/* - * Since move is underway, we need to block signals in this function. - * We cannot restart until it has finished. - */ - -int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, - int evict, int no_wait, uint32_t fence_class, - uint32_t fence_type, uint32_t fence_flags, - struct drm_bo_mem_reg *new_mem) -{ - struct drm_device *dev = bo->dev; - struct drm_mem_type_manager *man = &dev->bm.man[new_mem->mem_type]; - struct drm_bo_mem_reg *old_mem = &bo->mem; - int ret; - uint64_t save_flags = old_mem->flags; - uint64_t save_proposed_flags = old_mem->proposed_flags; - struct drm_buffer_object *old_obj; - - if (bo->fence) - drm_fence_usage_deref_unlocked(&bo->fence); - ret = drm_fence_object_create(dev, fence_class, fence_type, - fence_flags | DRM_FENCE_FLAG_EMIT, - &bo->fence); - bo->fence_type = fence_type; - if (ret) - return ret; - - if (evict || ((bo->mem.mm_node == bo->pinned_node) && - bo->mem.mm_node != NULL)) - { - if (bo->fence) { - (void) drm_fence_object_wait(bo->fence, 0, 1, - bo->fence_type); - drm_fence_usage_deref_unlocked(&bo->fence); - } - drm_bo_free_old_node(bo); - - if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm != NULL)) { - drm_ttm_unbind(bo->ttm); - drm_ttm_destroy(bo->ttm); - bo->ttm = NULL; - } - } else { - - /* This should help pipeline ordinary buffer moves. - * - * Hang old buffer memory on a new buffer object, - * and leave it to be released when the GPU - * operation has completed. - */ - - ret = drm_buffer_object_transfer(bo, &old_obj); - - if (ret) - return ret; - - if (!(man->flags & _DRM_FLAG_MEMTYPE_FIXED)) - old_obj->ttm = NULL; - else - bo->ttm = NULL; - - mutex_lock(&dev->struct_mutex); - list_del_init(&old_obj->lru); - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); - drm_bo_add_to_lru(old_obj); - - drm_bo_usage_deref_locked(&old_obj); - mutex_unlock(&dev->struct_mutex); - - } - - *old_mem = *new_mem; - new_mem->mm_node = NULL; - old_mem->proposed_flags = save_proposed_flags; - DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); - return 0; -} -EXPORT_SYMBOL(drm_bo_move_accel_cleanup); - -int drm_bo_same_page(unsigned long offset, - unsigned long offset2) -{ - return (offset & PAGE_MASK) == (offset2 & PAGE_MASK); -} -EXPORT_SYMBOL(drm_bo_same_page); - -unsigned long drm_bo_offset_end(unsigned long offset, - unsigned long end) -{ - offset = (offset + PAGE_SIZE) & PAGE_MASK; - return (end < offset) ? end : offset; -} -EXPORT_SYMBOL(drm_bo_offset_end); - -static pgprot_t drm_kernel_io_prot(uint32_t map_type) -{ - pgprot_t tmp = PAGE_KERNEL; - -#if defined(__i386__) || defined(__x86_64__) -#ifdef USE_PAT_WC -#warning using pat - if (drm_use_pat() && map_type == _DRM_TTM) { - pgprot_val(tmp) |= _PAGE_PAT; - return tmp; - } -#endif - if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { - pgprot_val(tmp) |= _PAGE_PCD; - pgprot_val(tmp) &= ~_PAGE_PWT; - } -#elif defined(__powerpc__) - pgprot_val(tmp) |= _PAGE_NO_CACHE; - if (map_type == _DRM_REGISTERS) - pgprot_val(tmp) |= _PAGE_GUARDED; -#endif -#if defined(__ia64__) - if (map_type == _DRM_TTM) - tmp = pgprot_writecombine(tmp); - else - tmp = pgprot_noncached(tmp); -#endif - return tmp; -} - -static int drm_bo_ioremap(struct drm_buffer_object *bo, unsigned long bus_base, - unsigned long bus_offset, unsigned long bus_size, - struct drm_bo_kmap_obj *map) -{ - struct drm_device *dev = bo->dev; - struct drm_bo_mem_reg *mem = &bo->mem; - struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; - - if (!(man->flags & _DRM_FLAG_NEEDS_IOREMAP)) { - map->bo_kmap_type = bo_map_premapped; - map->virtual = (void *)(((u8 *) man->io_addr) + bus_offset); - } else { - map->bo_kmap_type = bo_map_iomap; - map->virtual = ioremap_nocache(bus_base + bus_offset, bus_size); - } - return (!map->virtual) ? -ENOMEM : 0; -} - -static int drm_bo_kmap_ttm(struct drm_buffer_object *bo, - unsigned long start_page, unsigned long num_pages, - struct drm_bo_kmap_obj *map) -{ - struct drm_device *dev = bo->dev; - struct drm_bo_mem_reg *mem = &bo->mem; - struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; - pgprot_t prot; - struct drm_ttm *ttm = bo->ttm; - struct page *d; - int i; - - BUG_ON(!ttm); - - if (num_pages == 1 && (mem->flags & DRM_BO_FLAG_CACHED)) { - - /* - * We're mapping a single page, and the desired - * page protection is consistent with the bo. - */ - - map->bo_kmap_type = bo_map_kmap; - map->page = drm_ttm_get_page(ttm, start_page); - map->virtual = kmap(map->page); - } else { - /* - * Populate the part we're mapping; - */ - - for (i = start_page; i < start_page + num_pages; ++i) { - d = drm_ttm_get_page(ttm, i); - if (!d) - return -ENOMEM; - } - - /* - * We need to use vmap to get the desired page protection - * or to make the buffer object look contigous. - */ - - prot = (mem->flags & DRM_BO_FLAG_CACHED) ? - PAGE_KERNEL : - drm_kernel_io_prot(man->drm_bus_maptype); - map->bo_kmap_type = bo_map_vmap; - map->virtual = vmap(ttm->pages + start_page, - num_pages, 0, prot); - } - return (!map->virtual) ? -ENOMEM : 0; -} - -/* - * This function is to be used for kernel mapping of buffer objects. - * It chooses the appropriate mapping method depending on the memory type - * and caching policy the buffer currently has. - * Mapping multiple pages or buffers that live in io memory is a bit slow and - * consumes vmalloc space. Be restrictive with such mappings. - * Mapping single pages usually returns the logical kernel address, - * (which is fast) - * BUG may use slower temporary mappings for high memory pages or - * uncached / write-combined pages. - * - * The function fills in a drm_bo_kmap_obj which can be used to return the - * kernel virtual address of the buffer. - * - * Code servicing a non-priviliged user request is only allowed to map one - * page at a time. We might need to implement a better scheme to stop such - * processes from consuming all vmalloc space. - */ - -int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page, - unsigned long num_pages, struct drm_bo_kmap_obj *map) -{ - int ret; - unsigned long bus_base; - unsigned long bus_offset; - unsigned long bus_size; - - map->virtual = NULL; - - if (num_pages > bo->num_pages) - return -EINVAL; - if (start_page > bo->num_pages) - return -EINVAL; -#if 0 - if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC)) - return -EPERM; -#endif - ret = drm_bo_pci_offset(bo->dev, &bo->mem, &bus_base, - &bus_offset, &bus_size); - - if (ret) - return ret; - - if (bus_size == 0) { - return drm_bo_kmap_ttm(bo, start_page, num_pages, map); - } else { - bus_offset += start_page << PAGE_SHIFT; - bus_size = num_pages << PAGE_SHIFT; - return drm_bo_ioremap(bo, bus_base, bus_offset, bus_size, map); - } -} -EXPORT_SYMBOL(drm_bo_kmap); - -void drm_bo_kunmap(struct drm_bo_kmap_obj *map) -{ - if (!map->virtual) - return; - - switch (map->bo_kmap_type) { - case bo_map_iomap: - iounmap(map->virtual); - break; - case bo_map_vmap: - vunmap(map->virtual); - break; - case bo_map_kmap: - kunmap(map->page); - break; - case bo_map_premapped: - break; - default: - BUG(); - } - map->virtual = NULL; - map->page = NULL; -} -EXPORT_SYMBOL(drm_bo_kunmap); - -int drm_bo_pfn_prot(struct drm_buffer_object *bo, - unsigned long dst_offset, - unsigned long *pfn, - pgprot_t *prot) -{ - struct drm_bo_mem_reg *mem = &bo->mem; - struct drm_device *dev = bo->dev; - unsigned long bus_offset; - unsigned long bus_size; - unsigned long bus_base; - struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; - int ret; - - ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, - &bus_size); - if (ret) - return -EINVAL; - - if (bus_size != 0) - *pfn = (bus_base + bus_offset + dst_offset) >> PAGE_SHIFT; - else if (!bo->ttm) - return -EINVAL; - else - *pfn = page_to_pfn(drm_ttm_get_page(bo->ttm, dst_offset >> PAGE_SHIFT)); - - *prot = (mem->flags & DRM_BO_FLAG_CACHED) ? - PAGE_KERNEL : drm_kernel_io_prot(man->drm_bus_maptype); - - return 0; -} -EXPORT_SYMBOL(drm_bo_pfn_prot); - |